FreeBSD: don't use /dev/fd, bug #478446
[portage.git] / pym / portage / data.py
index cf94ab0cde7233d36fe0560f98d9bfb00e0f1b4d..caf4752ac2b04849ee99ef13d9d2eff379956e8a 100644 (file)
@@ -1,13 +1,14 @@
 # data.py -- Calculated/Discovered Data Values
-# Copyright 1998-2011 Gentoo Foundation
+# Copyright 1998-2013 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 _
 
@@ -31,7 +32,7 @@ if not lchown:
                                " exist.  Please rebuild python.\n"), noiselevel=-1)
                lchown()
 
-lchown = portage._unicode_func_wrapper(lchown)
+lchown = portage._chown_func_wrapper(lchown)
 
 def portage_group_warning():
        warn_prefix = colorize("BAD", "*** WARNING ***  ")
@@ -85,14 +86,27 @@ def _get_global(k):
                elif portage.const.EPREFIX:
                        secpass = 2
                #Discover the uid and gid of the portage user/group
+               keyerror = False
                try:
                        portage_uid = pwd.getpwnam(_get_global('_portage_username')).pw_uid
-                       portage_gid = grp.getgrnam(_get_global('_portage_grpname')).gr_gid
-                       if secpass < 1 and portage_gid in os.getgroups():
-                               secpass = 1
                except KeyError:
+                       keyerror = True
                        portage_uid = 0
+
+               try:
+                       portage_gid = grp.getgrnam(_get_global('_portage_grpname')).gr_gid
+               except KeyError:
+                       keyerror = True
                        portage_gid = 0
+
+               if secpass < 1 and portage_gid in os.getgroups():
+                       secpass = 1
+
+               # Suppress this error message if both PORTAGE_GRPNAME and
+               # PORTAGE_USERNAME are set to "root", for things like
+               # Android (see bug #454060).
+               if keyerror and not (_get_global('_portage_username') == "root" and
+                       _get_global('_portage_grpname') == "root"):
                        writemsg(colorize("BAD",
                                _("portage: 'portage' user or group missing.")) + "\n", noiselevel=-1)
                        writemsg(_(
@@ -124,10 +138,28 @@ 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]
+
+                       if sys.hexversion < 0x3020000 and sys.hexversion >= 0x3000000:
+                               # Python 3.1 _execvp throws TypeError for non-absolute executable
+                               # path passed as bytes (see http://bugs.python.org/issue8513).
+                               fullname = portage.process.find_binary(cmd[0])
+                               if fullname is None:
+                                       globals()[k] = v
+                                       _initialized_globals.add(k)
+                                       return v
+                               cmd[0] = fullname
+
+                       encoding = portage._encodings['content']
+                       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:
@@ -136,20 +168,44 @@ def _get_global(k):
 
        # Avoid instantiating portage.settings when the desired
        # variable is set in os.environ.
-       elif k == '_portage_grpname':
-               v = None
-               if 'PORTAGE_GRPNAME' in os.environ:
-                       v = os.environ['PORTAGE_GRPNAME']
-               elif hasattr(portage, 'settings'):
-                       v = portage.settings.get('PORTAGE_GRPNAME')
-               if v is None:
-                       v = 'portage'
-       elif k == '_portage_username':
+       elif k in ('_portage_grpname', '_portage_username'):
                v = None
-               if 'PORTAGE_USERNAME' in os.environ:
-                       v = os.environ['PORTAGE_USERNAME']
+               if k == '_portage_grpname':
+                       env_key = 'PORTAGE_GRPNAME'
+               else:
+                       env_key = 'PORTAGE_USERNAME'
+
+               if env_key in os.environ:
+                       v = os.environ[env_key]
                elif hasattr(portage, 'settings'):
-                       v = portage.settings.get('PORTAGE_USERNAME')
+                       v = portage.settings.get(env_key)
+               elif portage.const.EPREFIX:
+                       # For prefix environments, default to the UID and GID of
+                       # the top-level EROOT directory. The config class has
+                       # equivalent code, but we also need to do it here if
+                       # _disable_legacy_globals() has been called.
+                       eroot = os.path.join(os.environ.get('ROOT', os.sep),
+                               portage.const.EPREFIX.lstrip(os.sep))
+                       try:
+                               eroot_st = os.stat(eroot)
+                       except OSError:
+                               pass
+                       else:
+                               if k == '_portage_grpname':
+                                       try:
+                                               grp_struct = grp.getgrgid(eroot_st.st_gid)
+                                       except KeyError:
+                                               pass
+                                       else:
+                                               v = grp_struct.gr_name
+                               else:
+                                       try:
+                                               pwd_struct = pwd.getpwuid(eroot_st.st_uid)
+                                       except KeyError:
+                                               pass
+                                       else:
+                                               v = pwd_struct.pw_name
+
                if v is None:
                        v = 'portage'
        else:
@@ -184,10 +240,18 @@ def _init(settings):
        if '_portage_grpname' not in _initialized_globals and \
                '_portage_username' not in _initialized_globals:
 
+               # Prevents "TypeError: expected string" errors
+               # from grp.getgrnam() with PyPy
+               native_string = platform.python_implementation() == 'PyPy'
+
                v = settings.get('PORTAGE_GRPNAME', 'portage')
+               if native_string:
+                       v = portage._native_string(v)
                globals()['_portage_grpname'] = v
                _initialized_globals.add('_portage_grpname')
 
                v = settings.get('PORTAGE_USERNAME', 'portage')
+               if native_string:
+                       v = portage._native_string(v)
                globals()['_portage_username'] = v
                _initialized_globals.add('_portage_username')