Replace getstatusoutput with unicode safe Popen.
authorZac Medico <zmedico@gentoo.org>
Wed, 12 Sep 2012 06:24:44 +0000 (23:24 -0700)
committerZac Medico <zmedico@gentoo.org>
Wed, 12 Sep 2012 06:24:44 +0000 (23:24 -0700)
This fixes potential issues similar to those reported in bug #310789.

pym/portage/__init__.py
pym/portage/checksum.py
pym/portage/data.py
pym/portage/tests/lint/test_bash_syntax.py
pym/portage/tests/lint/test_import_modules.py
pym/portage/util/__init__.py

index 43c5af30ec60f3088c8618ca43160d6005d1debd..97352b2734180a4134df1a29d261ca505da78d25 100644 (file)
@@ -1,5 +1,5 @@
 # portage.py -- core Portage functionality
-# Copyright 1998-2011 Gentoo Foundation
+# Copyright 1998-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 VERSION="HEAD"
@@ -16,14 +16,6 @@ try:
                errno.ESTALE = -1
        import re
        import types
-
-       # Try the commands module first, since this allows us to eliminate
-       # the subprocess module from the baseline imports under python2.
-       try:
-               from commands import getstatusoutput as subprocess_getstatusoutput
-       except ImportError:
-               from subprocess import getstatusoutput as subprocess_getstatusoutput
-
        import platform
 
        # Temporarily delete these imports, to ensure that only the
@@ -114,6 +106,7 @@ try:
                        'cpv_getkey@getCPFromCPV,endversion_keys,' + \
                        'suffix_value@endversion,pkgcmp,pkgsplit,vercmp,ververify',
                'portage.xpak',
+               'subprocess',
                'time',
        )
 
@@ -354,8 +347,16 @@ if platform.system() in ('FreeBSD',):
 
                @classmethod
                def chflags(cls, path, flags, opts=""):
-                       cmd = 'chflags %s %o %s' % (opts, flags, _shell_quote(path))
-                       status, output = subprocess_getstatusoutput(cmd)
+                       cmd = ['chflags', opts, flags, path]
+                       encoding = _encodings['fs']
+                       if sys.hexversion < 0x3000000 or sys.hexversion >= 0x3020000:
+                               # Python 3.1 does not support bytes in Popen args.
+                               cmd = [_unicode_encode(x, encoding=encoding, errors='strict')
+                                       for x in cmd]
+                       proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                               stderr=subprocess.STDOUT)
+                       output = proc.communicate()[0]
+                       status = proc.wait()
                        if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
                                return
                        # Try to generate an ENOENT error if appropriate.
@@ -368,6 +369,7 @@ if platform.system() in ('FreeBSD',):
                                raise portage.exception.CommandNotFound('chflags')
                        # Now we're not sure exactly why it failed or what
                        # the real errno was, so just report EPERM.
+                       output = _unicode_decode(output, encoding=encoding)
                        e = OSError(errno.EPERM, output)
                        e.errno = errno.EPERM
                        e.filename = path
@@ -547,11 +549,19 @@ if VERSION == 'HEAD':
                        if VERSION is not self:
                                return VERSION
                        if os.path.isdir(os.path.join(PORTAGE_BASE_PATH, '.git')):
-                               status, output = subprocess_getstatusoutput((
-                                       "cd %s ; git describe --tags || exit $? ; " + \
+                               encoding = _encodings['fs']
+                               cmd = [BASH_BINARY, "-c", ("cd %s ; git describe --tags || exit $? ; " + \
                                        "if [ -n \"`git diff-index --name-only --diff-filter=M HEAD`\" ] ; " + \
                                        "then echo modified ; git rev-list --format=%%ct -n 1 HEAD ; fi ; " + \
-                                       "exit 0") % _shell_quote(PORTAGE_BASE_PATH))
+                                       "exit 0") % _shell_quote(PORTAGE_BASE_PATH)]
+                               if sys.hexversion < 0x3000000 or sys.hexversion >= 0x3020000:
+                                       # Python 3.1 does not support bytes in Popen args.
+                                       cmd = [_unicode_encode(x, encoding=encoding, errors='strict')
+                                               for x in cmd]
+                               proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                                       stderr=subprocess.STDOUT)
+                               output = _unicode_decode(proc.communicate()[0], encoding=encoding)
+                               status = proc.wait()
                                if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
                                        output_lines = output.splitlines()
                                        if output_lines:
index 144e6336f3e53f811262686692d6629b483b9eec..30a9234e169df099115e844d2ce14f63dedb4ed9 100644 (file)
@@ -10,6 +10,8 @@ from portage import _encodings
 from portage import _unicode_encode
 import errno
 import stat
+import sys
+import subprocess
 import tempfile
 
 #dict of all available hash functions
@@ -163,11 +165,18 @@ hashfunc_map["size"] = getsize
 
 prelink_capable = False
 if os.path.exists(PRELINK_BINARY):
-       results = portage.subprocess_getstatusoutput(
-               "%s --version > /dev/null 2>&1" % (PRELINK_BINARY,))
-       if (results[0] >> 8) == 0:
+       cmd = [PRELINK_BINARY, "--version"]
+       if sys.hexversion < 0x3000000 or sys.hexversion >= 0x3020000:
+               # Python 3.1 does not support bytes in Popen args.
+               cmd = [_unicode_encode(x, encoding=_encodings['fs'], errors='strict')
+                       for x in cmd]
+       proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+               stderr=subprocess.STDOUT)
+       proc.communicate()
+       status = proc.wait()
+       if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
                prelink_capable=1
-       del results
+       del cmd, proc, status
 
 def is_prelinkable_elf(filename):
        f = _open_file(filename)
index c4d967a1bfe169bcce69c986ae638f2069d2fa5d..b922ff8e9939b3fae6971a68b806f7cde1387785 100644 (file)
@@ -1,13 +1,14 @@
 # data.py -- Calculated/Discovered Data Values
-# Copyright 1998-2011 Gentoo Foundation
+# Copyright 1998-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
-import os, pwd, grp, platform
+import os, pwd, grp, platform, sys
 
 import portage
 portage.proxy.lazyimport.lazyimport(globals(),
        'portage.output:colorize',
        'portage.util:writemsg',
+       'subprocess'
 )
 from portage.localization import _
 
@@ -129,10 +130,20 @@ def _get_global(k):
                        # Get a list of group IDs for the portage user. Do not use
                        # grp.getgrall() since it is known to trigger spurious
                        # SIGPIPE problems with nss_ldap.
-                       mystatus, myoutput = \
-                               portage.subprocess_getstatusoutput("id -G %s" % _portage_username)
-                       if mystatus == os.EX_OK:
-                               for x in myoutput.split():
+                       cmd = ["id", "-G", _portage_username]
+                       encoding = portage._encodings['content']
+                       if sys.hexversion < 0x3000000 or sys.hexversion >= 0x3020000:
+                               # Python 3.1 does not support bytes in Popen args.
+                               cmd = [portage._unicode_encode(x,
+                                       encoding=encoding, errors='strict')
+                                       for x in cmd]
+                       proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                               stderr=subprocess.STDOUT)
+                       myoutput = proc.communicate()[0]
+                       status = proc.wait()
+                       if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
+                               for x in portage._unicode_decode(myoutput,
+                                       encoding=encoding, errors='strict').split():
                                        try:
                                                v.append(int(x))
                                        except ValueError:
index 3acea6619480c35156c7fc7e708817f2c5c4d9b7..0d7d35a6d11a84ea0d5c0353314f248a09fe6c62 100644 (file)
@@ -3,13 +3,13 @@
 
 from itertools import chain
 import stat
+import subprocess
+import sys
 
 from portage.const import BASH_BINARY, PORTAGE_BASE_PATH, PORTAGE_BIN_PATH
 from portage.tests import TestCase
 from portage import os
-from portage import subprocess_getstatusoutput
 from portage import _encodings
-from portage import _shell_quote
 from portage import _unicode_decode, _unicode_encode
 
 class BashSyntaxTestCase(TestCase):
@@ -42,7 +42,15 @@ class BashSyntaxTestCase(TestCase):
                                f.close()
                                if line[:2] == '#!' and \
                                        'bash' in line:
-                                       cmd = "%s -n %s" % (_shell_quote(BASH_BINARY), _shell_quote(x))
-                                       status, output = subprocess_getstatusoutput(cmd)
+                                       cmd = [BASH_BINARY, "-n", x]
+                                       if sys.hexversion < 0x3000000 or sys.hexversion >= 0x3020000:
+                                               # Python 3.1 does not support bytes in Popen args.
+                                               cmd = [_unicode_encode(x,
+                                                       encoding=_encodings['fs'], errors='strict') for x in cmd]
+                                       proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                                               stderr=subprocess.STDOUT)
+                                       output = _unicode_decode(proc.communicate()[0],
+                                               encoding=_encodings['fs'])
+                                       status = proc.wait()
                                        self.assertEqual(os.WIFEXITED(status) and \
                                                os.WEXITSTATUS(status) == os.EX_OK, True, msg=output)
index 8d257c5a6af179d36fc878791936aef426e199d0..34261f46460a74872a70b8f1de9140868686c036 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 2011 Gentoo Foundation
+# Copyright 2011-2012 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
 from portage.const import PORTAGE_PYM_PATH
index 951a158a9bfb3e13b46d0fd66d38672594a37f55..fee0bc7d230dc648e7dea8c0b401de7c489054d1 100644 (file)
@@ -31,11 +31,11 @@ import portage
 portage.proxy.lazyimport.lazyimport(globals(),
        'pickle',
        'portage.dep:Atom',
-       'portage.util.listdir:_ignorecvs_dirs'
+       'portage.util.listdir:_ignorecvs_dirs',
+       'subprocess',
 )
 
 from portage import os
-from portage import subprocess_getstatusoutput
 from portage import _encodings
 from portage import _os_merge
 from portage import _unicode_encode
@@ -1589,7 +1589,7 @@ def find_updated_config_files(target_root, config_protect):
        If no configuration files needs to be updated, None is returned
        """
 
-       os = _os_merge
+       encoding = _encodings['fs']
 
        if config_protect:
                # directories with some protect files in them
@@ -1621,10 +1621,17 @@ def find_updated_config_files(target_root, config_protect):
                                mycommand = "find '%s' -maxdepth 1 -name '._cfg????_%s'" % \
                                                os.path.split(x.rstrip(os.path.sep))
                        mycommand += " ! -name '.*~' ! -iname '.*.bak' -print0"
-                       a = subprocess_getstatusoutput(mycommand)
-
-                       if a[0] == 0:
-                               files = a[1].split('\0')
+                       cmd = shlex_split(mycommand)
+                       if sys.hexversion < 0x3000000 or sys.hexversion >= 0x3020000:
+                               # Python 3.1 does not support bytes in Popen args.
+                               cmd = [_unicode_encode(x, encoding=encoding, errors='strict')
+                                       for x in cmd]
+                       proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                               stderr=subprocess.STDOUT)
+                       output = _unicode_decode(proc.communicate()[0], encoding=encoding)
+                       status = proc.wait()
+                       if os.WIFEXITED(status) and os.WEXITSTATUS(status) == os.EX_OK:
+                               files = output.split('\0')
                                # split always produces an empty string as the last element
                                if files and not files[-1]:
                                        del files[-1]