# data.py -- Calculated/Discovered Data Values
-# Copyright 1998-2009 Gentoo Foundation
+# Copyright 1998-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
-# $Id$
-import os, sys, pwd, grp, platform
-from portage.const import PORTAGE_GROUPNAME, PORTAGE_USERNAME
+import os, pwd, grp, platform, sys
import portage
portage.proxy.lazyimport.lazyimport(globals(),
'portage.output:colorize',
'portage.util:writemsg',
+ 'subprocess'
)
from portage.localization import _
def lchown(*pos_args, **key_args):
pass
else:
- try:
- import missingos
- lchown = missingos.lchown
- except ImportError:
- def lchown(*pos_args, **key_args):
- writemsg(colorize("BAD", "!!!") + _(
- " It seems that os.lchown does not"
- " exist. Please rebuild python.\n"), noiselevel=-1)
- lchown()
+ def lchown(*pargs, **kwargs):
+ writemsg(colorize("BAD", "!!!") + _(
+ " It seems that os.lchown does not"
+ " 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 *** ")
# If the "wheel" group does not exist then wheelgid falls back to 0.
# If the "portage" group does not exist then portage_uid falls back to wheelgid.
-secpass=0
-
uid=os.getuid()
wheelgid=0
-if uid==0:
- secpass=2
try:
wheelgid=grp.getgrnam("wheel")[2]
except KeyError:
pass
-#Discover the uid and gid of the portage user/group
-try:
- portage_uid = pwd.getpwnam(PORTAGE_USERNAME)[2]
- portage_gid = grp.getgrnam(PORTAGE_GROUPNAME)[2]
- if secpass < 1 and portage_gid in os.getgroups():
- secpass=1
-except KeyError:
- portage_uid=0
- portage_gid=0
- userpriv_groups = [portage_gid]
- writemsg(colorize("BAD",
- _("portage: 'portage' user or group missing.")) + "\n", noiselevel=-1)
- writemsg(_(
- " For the defaults, line 1 goes into passwd, "
- "and 2 into group.\n"), noiselevel=-1)
- writemsg(colorize("GOOD",
- " portage:x:250:250:portage:/var/tmp/portage:/bin/false") \
- + "\n", noiselevel=-1)
- writemsg(colorize("GOOD", " portage::250:portage") + "\n",
- noiselevel=-1)
- portage_group_warning()
-else:
- userpriv_groups = [portage_gid]
- if secpass >= 2:
- # 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.
+# The portage_uid and portage_gid global constants, and others that
+# depend on them are initialized lazily, in order to allow configuration
+# via make.conf. Eventually, these constants may be deprecated in favor
+# of config attributes, since it's conceivable that multiple
+# configurations with different constants could be used simultaneously.
+_initialized_globals = set()
+
+def _get_global(k):
+ if k in _initialized_globals:
+ return globals()[k]
+
+ if k in ('portage_gid', 'portage_uid', 'secpass'):
+ global portage_gid, portage_uid, secpass
+ secpass = 0
+ if uid == 0:
+ secpass = 2
+ elif portage.const.EPREFIX:
+ secpass = 2
+ #Discover the uid and gid of the portage user/group
+ keyerror = False
try:
- from subprocess import getstatusoutput
- except ImportError:
- from commands import getstatusoutput
- mystatus, myoutput = getstatusoutput("id -G portage")
- if mystatus == os.EX_OK:
- for x in myoutput.split():
- try:
- userpriv_groups.append(int(x))
- except ValueError:
- pass
- del x
- userpriv_groups = list(set(userpriv_groups))
- del getstatusoutput, mystatus, myoutput
+ portage_uid = pwd.getpwnam(_get_global('_portage_username')).pw_uid
+ 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(_(
+ " For the defaults, line 1 goes into passwd, "
+ "and 2 into group.\n"), noiselevel=-1)
+ writemsg(colorize("GOOD",
+ " portage:x:250:250:portage:/var/tmp/portage:/bin/false") \
+ + "\n", noiselevel=-1)
+ writemsg(colorize("GOOD", " portage::250:portage") + "\n",
+ noiselevel=-1)
+ portage_group_warning()
+
+ _initialized_globals.add('portage_gid')
+ _initialized_globals.add('portage_uid')
+ _initialized_globals.add('secpass')
+
+ if k == 'portage_gid':
+ return portage_gid
+ elif k == 'portage_uid':
+ return portage_uid
+ elif k == 'secpass':
+ return secpass
+ else:
+ raise AssertionError('unknown name: %s' % k)
+
+ elif k == 'userpriv_groups':
+ v = [portage_gid]
+ if secpass >= 2:
+ # 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.
+ 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:
+ pass
+ v = sorted(set(v))
+
+ # Avoid instantiating portage.settings when the desired
+ # variable is set in os.environ.
+ elif k in ('_portage_grpname', '_portage_username'):
+ v = None
+ 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(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:
+ raise AssertionError('unknown name: %s' % k)
+
+ globals()[k] = v
+ _initialized_globals.add(k)
+ return v
+
+class _GlobalProxy(portage.proxy.objectproxy.ObjectProxy):
+
+ __slots__ = ('_name',)
+
+ def __init__(self, name):
+ portage.proxy.objectproxy.ObjectProxy.__init__(self)
+ object.__setattr__(self, '_name', name)
+
+ def _get_target(self):
+ return _get_global(object.__getattribute__(self, '_name'))
+
+for k in ('portage_gid', 'portage_uid', 'secpass', 'userpriv_groups',
+ '_portage_grpname', '_portage_username'):
+ globals()[k] = _GlobalProxy(k)
+del k
+
+def _init(settings):
+ """
+ Use config variables like PORTAGE_GRPNAME and PORTAGE_USERNAME to
+ initialize global variables. This allows settings to come from make.conf
+ instead of requiring them to be set in the calling environment.
+ """
+ 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')