def _ensure_dirs(self, path=None): """with path!=None, ensure beyond self.location. otherwise, ensure self.location""" if path: path = os.path.dirname(path) base = self.location else: path = self.location base='/' for dir in path.lstrip(os.path.sep).rstrip(os.path.sep).split(os.path.sep): base = os.path.join(base,dir) if not os.path.exists(base): if self._perms != -1: um = os.umask(0) try: perms = self._perms if perms == -1: perms = 0 perms |= 0o755 os.mkdir(base, perms) if self._gid != -1: os.chown(base, -1, self._gid) finally: if self._perms != -1: os.umask(um)
def __init__(self, settings, logger): self.settings = settings self.logger = logger # Similar to emerge, sync needs a default umask so that created # files have sane permissions. os.umask(0o22) self.module_controller = portage.sync.module_controller self.module_names = self.module_controller.module_names self.hooks = {} for _dir in ["repo.postsync.d", "postsync.d"]: postsync_dir = os.path.join(self.settings["PORTAGE_CONFIGROOT"], portage.USER_CONFIG_PATH, _dir) hooks = OrderedDict() for filepath in util._recursive_file_list(postsync_dir): name = filepath.split(postsync_dir)[1].lstrip(os.sep) if os.access(filepath, os.X_OK): hooks[filepath] = name else: writemsg_level(" %s %s hook: '%s' is not executable\n" % ( warn("*"), _dir, _unicode_decode(name), ), level=logging.WARN, noiselevel=2) self.hooks[_dir] = hooks
def emerge_main(args=None, build_dict=None): """ @param args: command arguments (default: sys.argv[1:]) @type args: list @param build_dict: info of the build_job @type build_dict: dict """ if args is None: args = sys.argv[1:] if build_dict is None: build_dict = {} # Disable color until we're sure that it should be enabled (after # EMERGE_DEFAULT_OPTS has been parsed). portage.output.havecolor = 0 # This first pass is just for options that need to be known as early as # possible, such as --config-root. They will be parsed again later, # together with EMERGE_DEFAULT_OPTS (which may vary depending on the # the value of --config-root). myaction, myopts, myfiles = parse_opts(args, silent=True) if "--debug" in myopts: os.environ["PORTAGE_DEBUG"] = "1" if "--config-root" in myopts: os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] if "--root" in myopts: os.environ["ROOT"] = myopts["--root"] if "--accept-properties" in myopts: os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"] # optimize --help (no need to load config / EMERGE_DEFAULT_OPTS) if myaction == "help": emerge_help() return os.EX_OK elif myaction == "moo": print(COWSAY_MOO % platform.system()) return os.EX_OK # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) if myaction == "sync": portage._sync_disabled_warnings = True settings, trees, mtimedb = load_emerge_config() rval = profile_check(trees, myaction) if rval != os.EX_OK: return rval tmpcmdline = [] if "--ignore-default-opts" not in myopts: tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split()) tmpcmdline.extend(args) myaction, myopts, myfiles = parse_opts(tmpcmdline) return run_action(settings, trees, mtimedb, myaction, myopts, myfiles, build_dict, gc_locals=locals().clear)
def emerge_main(args=None): """ @param args: command arguments (default: sys.argv[1:]) @type args: list """ if args is None: args = sys.argv[1:] portage._disable_legacy_globals() portage._internal_warnings = True # Disable color until we're sure that it should be enabled (after # EMERGE_DEFAULT_OPTS has been parsed). portage.output.havecolor = 0 # This first pass is just for options that need to be known as early as # possible, such as --config-root. They will be parsed again later, # together with EMERGE_DEFAULT_OPTS (which may vary depending on the # the value of --config-root). myaction, myopts, myfiles = parse_opts(args, silent=True) if "--debug" in myopts: os.environ["PORTAGE_DEBUG"] = "1" if "--config-root" in myopts: os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] if "--root" in myopts: os.environ["ROOT"] = myopts["--root"] if "--accept-properties" in myopts: os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"] # optimize --help (no need to load config / EMERGE_DEFAULT_OPTS) if myaction == "help": emerge_help() return os.EX_OK elif myaction == "moo": print(COWSAY_MOO % platform.system()) return os.EX_OK # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) if myaction == "sync": portage._sync_disabled_warnings = True settings, trees, mtimedb = load_emerge_config() rval = profile_check(trees, myaction) if rval != os.EX_OK: return rval tmpcmdline = [] if "--ignore-default-opts" not in myopts: tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split()) tmpcmdline.extend(args) myaction, myopts, myfiles = parse_opts(tmpcmdline) return run_action(settings, trees, mtimedb, myaction, myopts, myfiles, gc_locals=locals().clear)
def __init__(self, settings, logger): self.settings = settings self.logger = logger # Similar to emerge, sync needs a default umask so that created # files have sane permissions. os.umask(0o22) self.module_controller = portage.sync.module_controller self.module_names = self.module_controller.module_names self.hooks = {} for _dir in ["repo.postsync.d", "postsync.d"]: hooks = get_hooks_from_dir(_dir, prefix=self.settings["PORTAGE_CONFIGROOT"]) self.hooks[_dir] = hooks
def _drop_privs_userfetch(settings): """ Drop privileges for userfetch, and update portage.data.secpass to correspond to the new privilege level. """ spawn_kwargs = dict(_userpriv_spawn_kwargs) try: _ensure_distdir(settings, settings['DISTDIR']) except PortageException: if not os.path.isdir(settings['DISTDIR']): raise os.setgid(int(spawn_kwargs['gid'])) os.setgroups(spawn_kwargs['groups']) os.setuid(int(spawn_kwargs['uid'])) os.umask(spawn_kwargs['umask']) portage.data.secpass = 1
def __init__(self, settings, logger): self.settings = settings self.logger = logger # Similar to emerge, sync needs a default umask so that created # files have sane permissions. os.umask(0o22) self.module_controller = portage.sync.module_controller self.module_names = self.module_controller.module_names self.hooks = {} for _dir in ["repo.postsync.d", "postsync.d"]: postsync_dir = os.path.join(self.settings["PORTAGE_CONFIGROOT"], portage.USER_CONFIG_PATH, _dir) hooks = OrderedDict() for filepath in util._recursive_file_list(postsync_dir): name = filepath.split(postsync_dir)[1].lstrip(os.sep) if os.access(filepath, os.X_OK): hooks[filepath] = name else: writemsg_level(" %s %s hook: '%s' is not executable\n" % (warn("*"), _dir, _unicode_decode(name),), level=logging.WARN, noiselevel=2) self.hooks[_dir] = hooks
def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, waiting_msg=None, flags=0): """ If wantnewlockfile is True then this creates a lockfile in the parent directory as the file: '.' + basename + '.portage_lockfile'. """ if not mypath: raise InvalidData(_("Empty path given")) # Since Python 3.4, chown requires int type (no proxies). portage_gid = int(portage.data.portage_gid) # Support for file object or integer file descriptor parameters is # deprecated due to ambiguity in whether or not it's safe to close # the file descriptor, making it prone to "Bad file descriptor" errors # or file descriptor leaks. if isinstance(mypath, basestring) and mypath[-1] == '/': mypath = mypath[:-1] lockfilename_path = mypath if hasattr(mypath, 'fileno'): warnings.warn("portage.locks.lockfile() support for " "file object parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename_path = getattr(mypath, 'name', None) mypath = mypath.fileno() if isinstance(mypath, int): warnings.warn("portage.locks.lockfile() support for integer file " "descriptor parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename = mypath wantnewlockfile = 0 unlinkfile = 0 elif wantnewlockfile: base, tail = os.path.split(mypath) lockfilename = os.path.join(base, "." + tail + ".portage_lockfile") lockfilename_path = lockfilename unlinkfile = 1 else: lockfilename = mypath if isinstance(mypath, basestring): if not os.path.exists(os.path.dirname(mypath)): raise DirectoryNotFound(os.path.dirname(mypath)) preexisting = os.path.exists(lockfilename) old_mask = os.umask(000) try: try: myfd = os.open(lockfilename, os.O_CREAT|os.O_RDWR, 0o660) except OSError as e: func_call = "open('%s')" % lockfilename if e.errno == OperationNotPermitted.errno: raise OperationNotPermitted(func_call) elif e.errno == PermissionDenied.errno: raise PermissionDenied(func_call) elif e.errno == ReadOnlyFileSystem.errno: raise ReadOnlyFileSystem(func_call) else: raise if not preexisting: try: if os.stat(lockfilename).st_gid != portage_gid: os.chown(lockfilename, -1, portage_gid) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE): return lockfile(mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) else: writemsg("%s: chown('%s', -1, %d)\n" % \ (e, lockfilename, portage_gid), noiselevel=-1) writemsg(_("Cannot chown a lockfile: '%s'\n") % \ lockfilename, noiselevel=-1) writemsg(_("Group IDs of current user: %s\n") % \ " ".join(str(n) for n in os.getgroups()), noiselevel=-1) finally: os.umask(old_mask) elif isinstance(mypath, int): myfd = mypath else: raise ValueError(_("Unknown type passed in '%s': '%s'") % \ (type(mypath), mypath)) # try for a non-blocking lock, if it's held, throw a message # we're waiting on lockfile and use a blocking attempt. locking_method = portage._eintr_func_wrapper(_default_lock_fn) try: if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: raise IOError(errno.ENOSYS, "Function not implemented") locking_method(myfd, fcntl.LOCK_EX|fcntl.LOCK_NB) except IOError as e: if not hasattr(e, "errno"): raise if e.errno in (errno.EACCES, errno.EAGAIN, errno.ENOLCK): # resource temp unavailable; eg, someone beat us to the lock. if flags & os.O_NONBLOCK: os.close(myfd) raise TryAgain(mypath) global _quiet if _quiet: out = None else: out = portage.output.EOutput() if waiting_msg is None: if isinstance(mypath, int): waiting_msg = _("waiting for lock on fd %i") % myfd else: waiting_msg = _("waiting for lock on %s") % lockfilename if out is not None: out.ebegin(waiting_msg) # try for the exclusive lock now. enolock_msg_shown = False while True: try: locking_method(myfd, fcntl.LOCK_EX) except EnvironmentError as e: if e.errno == errno.ENOLCK: # This is known to occur on Solaris NFS (see # bug #462694). Assume that the error is due # to temporary exhaustion of record locks, # and loop until one becomes available. if not enolock_msg_shown: enolock_msg_shown = True if isinstance(mypath, int): context_desc = _("Error while waiting " "to lock fd %i") % myfd else: context_desc = _("Error while waiting " "to lock '%s'") % lockfilename writemsg("\n!!! %s: %s\n" % (context_desc, e), noiselevel=-1) time.sleep(_HARDLINK_POLL_LATENCY) continue if out is not None: out.eend(1, str(e)) raise else: break if out is not None: out.eend(os.EX_OK) elif e.errno in (errno.ENOSYS,): # We're not allowed to lock on this FS. if not isinstance(lockfilename, int): # If a file object was passed in, it's not safe # to close the file descriptor because it may # still be in use. os.close(myfd) lockfilename_path = _unicode_decode(lockfilename_path, encoding=_encodings['fs'], errors='strict') if not isinstance(lockfilename_path, basestring): raise link_success = hardlink_lockfile(lockfilename_path, waiting_msg=waiting_msg, flags=flags) if not link_success: raise lockfilename = lockfilename_path locking_method = None myfd = HARDLINK_FD else: raise if isinstance(lockfilename, basestring) and \ myfd != HARDLINK_FD and _fstat_nlink(myfd) == 0: # The file was deleted on us... Keep trying to make one... os.close(myfd) writemsg(_("lockfile recurse\n"), 1) lockfilename, myfd, unlinkfile, locking_method = lockfile( mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) if myfd != HARDLINK_FD: # FD_CLOEXEC is enabled by default in Python >=3.4. if sys.hexversion < 0x3040000: try: fcntl.FD_CLOEXEC except AttributeError: pass else: fcntl.fcntl(myfd, fcntl.F_SETFD, fcntl.fcntl(myfd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC) _open_fds.add(myfd) writemsg(str((lockfilename, myfd, unlinkfile)) + "\n", 1) return (lockfilename, myfd, unlinkfile, locking_method)
def emerge_main(args=None): """ @param args: command arguments (default: sys.argv[1:]) @type args: list """ if args is None: args = sys.argv[1:] args = portage._decode_argv(args) # Use system locale. locale.setlocale(locale.LC_ALL, '') # Disable color until we're sure that it should be enabled (after # EMERGE_DEFAULT_OPTS has been parsed). portage.output.havecolor = 0 # This first pass is just for options that need to be known as early as # possible, such as --config-root. They will be parsed again later, # together with EMERGE_DEFAULT_OPTS (which may vary depending on the # the value of --config-root). myaction, myopts, myfiles = parse_opts(args, silent=True) if "--debug" in myopts: os.environ["PORTAGE_DEBUG"] = "1" if "--config-root" in myopts: os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] if "--root" in myopts: os.environ["ROOT"] = myopts["--root"] if "--prefix" in myopts: os.environ["EPREFIX"] = myopts["--prefix"] if "--accept-properties" in myopts: os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"] if "--accept-restrict" in myopts: os.environ["ACCEPT_RESTRICT"] = myopts["--accept-restrict"] # optimize --help (no need to load config / EMERGE_DEFAULT_OPTS) if myaction == "help": emerge_help() return os.EX_OK elif myaction == "moo": print(COWSAY_MOO % platform.system()) return os.EX_OK # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) if myaction == "sync": portage._sync_mode = True emerge_config = load_emerge_config( action=myaction, args=myfiles, opts=myopts) rval = profile_check(emerge_config.trees, emerge_config.action) if rval != os.EX_OK: return rval tmpcmdline = [] if "--ignore-default-opts" not in myopts: tmpcmdline.extend(portage.util.shlex_split( emerge_config.target_config.settings.get( "EMERGE_DEFAULT_OPTS", ""))) tmpcmdline.extend(args) emerge_config.action, emerge_config.opts, emerge_config.args = \ parse_opts(tmpcmdline) try: return run_action(emerge_config) finally: # Call destructors for our portdbapi instances. for x in emerge_config.trees.values(): if "porttree" in x.lazy_items: continue x["porttree"].dbapi.close_caches()
def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, waiting_msg=None, flags=0): """ If wantnewlockfile is True then this creates a lockfile in the parent directory as the file: '.' + basename + '.portage_lockfile'. """ if not mypath: raise InvalidData(_("Empty path given")) # Support for file object or integer file descriptor parameters is # deprecated due to ambiguity in whether or not it's safe to close # the file descriptor, making it prone to "Bad file descriptor" errors # or file descriptor leaks. if isinstance(mypath, basestring) and mypath[-1] == "/": mypath = mypath[:-1] lockfilename_path = mypath if hasattr(mypath, "fileno"): warnings.warn( "portage.locks.lockfile() support for " "file object parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2, ) lockfilename_path = getattr(mypath, "name", None) mypath = mypath.fileno() if isinstance(mypath, int): warnings.warn( "portage.locks.lockfile() support for integer file " "descriptor parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2, ) lockfilename = mypath wantnewlockfile = 0 unlinkfile = 0 elif wantnewlockfile: base, tail = os.path.split(mypath) lockfilename = os.path.join(base, "." + tail + ".portage_lockfile") lockfilename_path = lockfilename unlinkfile = 1 else: lockfilename = mypath if isinstance(mypath, basestring): if not os.path.exists(os.path.dirname(mypath)): raise DirectoryNotFound(os.path.dirname(mypath)) preexisting = os.path.exists(lockfilename) old_mask = os.umask(000) try: try: myfd = os.open(lockfilename, os.O_CREAT | os.O_RDWR, 0o660) except OSError as e: func_call = "open('%s')" % lockfilename if e.errno == OperationNotPermitted.errno: raise OperationNotPermitted(func_call) elif e.errno == PermissionDenied.errno: raise PermissionDenied(func_call) else: raise if not preexisting: try: if os.stat(lockfilename).st_gid != portage_gid: os.chown(lockfilename, -1, portage_gid) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE): return lockfile( mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags, ) else: writemsg("%s: chown('%s', -1, %d)\n" % (e, lockfilename, portage_gid), noiselevel=-1) writemsg(_("Cannot chown a lockfile: '%s'\n") % lockfilename, noiselevel=-1) writemsg( _("Group IDs of current user: %s\n") % " ".join(str(n) for n in os.getgroups()), noiselevel=-1, ) finally: os.umask(old_mask) elif isinstance(mypath, int): myfd = mypath else: raise ValueError(_("Unknown type passed in '%s': '%s'") % (type(mypath), mypath)) # try for a non-blocking lock, if it's held, throw a message # we're waiting on lockfile and use a blocking attempt. locking_method = _default_lock_fn try: if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: raise IOError(errno.ENOSYS, "Function not implemented") locking_method(myfd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError as e: if not hasattr(e, "errno"): raise if e.errno in (errno.EACCES, errno.EAGAIN): # resource temp unavailable; eg, someone beat us to the lock. if flags & os.O_NONBLOCK: os.close(myfd) raise TryAgain(mypath) global _quiet if _quiet: out = None else: out = portage.output.EOutput() if waiting_msg is None: if isinstance(mypath, int): waiting_msg = _("waiting for lock on fd %i") % myfd else: waiting_msg = _("waiting for lock on %s\n") % lockfilename if out is not None: out.ebegin(waiting_msg) # try for the exclusive lock now. try: locking_method(myfd, fcntl.LOCK_EX) except EnvironmentError as e: if out is not None: out.eend(1, str(e)) raise if out is not None: out.eend(os.EX_OK) elif e.errno in (errno.ENOSYS, errno.ENOLCK): # We're not allowed to lock on this FS. if not isinstance(lockfilename, int): # If a file object was passed in, it's not safe # to close the file descriptor because it may # still be in use. os.close(myfd) lockfilename_path = _unicode_decode(lockfilename_path, encoding=_encodings["fs"], errors="strict") if not isinstance(lockfilename_path, basestring): raise link_success = hardlink_lockfile(lockfilename_path, waiting_msg=waiting_msg, flags=flags) if not link_success: raise lockfilename = lockfilename_path locking_method = None myfd = HARDLINK_FD else: raise if isinstance(lockfilename, basestring) and myfd != HARDLINK_FD and _fstat_nlink(myfd) == 0: # The file was deleted on us... Keep trying to make one... os.close(myfd) writemsg(_("lockfile recurse\n"), 1) lockfilename, myfd, unlinkfile, locking_method = lockfile( mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags ) if myfd != HARDLINK_FD: _open_fds.add(myfd) writemsg(str((lockfilename, myfd, unlinkfile)) + "\n", 1) return (lockfilename, myfd, unlinkfile, locking_method)
def emaint_main(myargv): # Similar to emerge, emaint needs a default umask so that created # files (such as the world file) have sane permissions. os.umask(0o22) module_controller = Modules(namepath="portage.emaint.modules") module_names = module_controller.module_names[:] module_names.insert(0, "all") parser = OptionParser(usage=usage(module_controller), version=portage.VERSION) # add default options parser_options = [] for opt in DEFAULT_OPTIONS: parser_options.append(OptionItem(DEFAULT_OPTIONS[opt], parser)) for mod in module_names[1:]: desc = module_controller.get_func_descriptions(mod) if desc: for opt in desc: parser_options.append(OptionItem(desc[opt], parser)) for opt in parser_options: parser.add_option( opt.short, opt.long, help=opt.help, action=opt.action, type=opt.type, dest=opt.dest, callback=opt.callback, callback_kwargs=opt.callback_kwargs, ) parser.action = None (options, args) = parser.parse_args(args=myargv) # print('options', options, '\nargs', args, '\naction', parser.action) if len(args) != 1: parser.error("Incorrect number of arguments") if args[0] not in module_names: parser.error("%s target is not a known target" % args[0]) if parser.action: action = parser.action else: action = "-c/--check" long_action = action.split("/")[1].lstrip("-") # print("DEBUG: action = ", action, long_action) if args[0] == "all": tasks = [] for m in module_names[1:]: # print("DEBUG: module: %s, functions: " %(m, str(module_controller.get_functions(m)))) if long_action in module_controller.get_functions(m): tasks.append(module_controller.get_class(m)) elif long_action in module_controller.get_functions(args[0]): tasks = [module_controller.get_class(args[0])] else: print("\nERROR: module '%s' does not have option '%s'\n" % (args[0], action)) print(module_opts(module_controller, args[0])) sys.exit(1) func = status = None for opt in parser_options: if opt.check_action(action): status = opt.status func = opt.func break # need to pass the parser options dict to the modules # so they are available if needed. task_opts = options.__dict__ taskmaster = TaskHandler(callback=print_results) taskmaster.run_tasks(tasks, func, status, options=task_opts)
def pre_sync(self, repo): msg = ">>> Syncing repository '%s' into '%s'..." \ % (repo.name, repo.location) self.logger(self.xterm_titles, msg) writemsg_level(msg + "\n") try: st = os.stat(repo.location) except OSError: st = None self.usersync_uid = None spawn_kwargs = {} # Redirect command stderr to stdout, in order to prevent # spurious cron job emails (bug 566132). spawn_kwargs["fd_pipes"] = { 0: sys.__stdin__.fileno(), 1: sys.__stdout__.fileno(), 2: sys.__stdout__.fileno() } spawn_kwargs["env"] = self.settings.environ() if repo.sync_user is not None: def get_sync_user_data(sync_user): user = None group = None home = None logname = None spl = sync_user.split(':', 1) if spl[0]: username = spl[0] try: try: pw = pwd.getpwnam(username) except KeyError: pw = pwd.getpwuid(int(username)) except (ValueError, KeyError): writemsg("!!! User '%s' invalid or does not exist\n" % username, noiselevel=-1) return (logname, user, group, home) user = pw.pw_uid group = pw.pw_gid home = pw.pw_dir logname = pw.pw_name if len(spl) > 1: groupname = spl[1] try: try: gp = grp.getgrnam(groupname) except KeyError: pw = grp.getgrgid(int(groupname)) except (ValueError, KeyError): writemsg("!!! Group '%s' invalid or does not exist\n" % groupname, noiselevel=-1) return (logname, user, group, home) group = gp.gr_gid return (logname, user, group, home) # user or user:group (logname, uid, gid, home) = get_sync_user_data(repo.sync_user) if uid is not None: spawn_kwargs["uid"] = uid self.usersync_uid = uid if gid is not None: spawn_kwargs["gid"] = gid spawn_kwargs["groups"] = [gid] if home is not None: spawn_kwargs["env"]["HOME"] = home if logname is not None: spawn_kwargs["env"]["LOGNAME"] = logname if st is None: perms = {'mode': 0o755} # respect sync-user if set if 'umask' in spawn_kwargs: perms['mode'] &= ~spawn_kwargs['umask'] if 'uid' in spawn_kwargs: perms['uid'] = spawn_kwargs['uid'] if 'gid' in spawn_kwargs: perms['gid'] = spawn_kwargs['gid'] portage.util.ensure_dirs(repo.location, **perms) st = os.stat(repo.location) if (repo.sync_user is None and 'usersync' in self.settings.features and portage.data.secpass >= 2 and (st.st_uid != os.getuid() and st.st_mode & 0o700 or st.st_gid != os.getgid() and st.st_mode & 0o070)): try: pw = pwd.getpwuid(st.st_uid) except KeyError: pass else: # Drop privileges when syncing, in order to match # existing uid/gid settings. self.usersync_uid = st.st_uid spawn_kwargs["uid"] = st.st_uid spawn_kwargs["gid"] = st.st_gid spawn_kwargs["groups"] = [st.st_gid] spawn_kwargs["env"]["HOME"] = pw.pw_dir spawn_kwargs["env"]["LOGNAME"] = pw.pw_name umask = 0o002 if not st.st_mode & 0o020: umask = umask | 0o020 spawn_kwargs["umask"] = umask # override the defaults when sync_umask is set if repo.sync_umask is not None: spawn_kwargs["umask"] = int(repo.sync_umask, 8) self.spawn_kwargs = spawn_kwargs if self.usersync_uid is not None: # PORTAGE_TMPDIR is used below, so validate it and # bail out if necessary. rval = _check_temp_dir(self.settings) if rval != os.EX_OK: return rval os.umask(0o022) return os.EX_OK
def pre_sync(self, repo): msg = ">>> Syncing repository '%s' into '%s'..." % (repo.name, repo.location) self.logger(self.xterm_titles, msg) writemsg_level(msg + "\n") try: st = os.stat(repo.location) except OSError: st = None self.usersync_uid = None spawn_kwargs = {} # Redirect command stderr to stdout, in order to prevent # spurious cron job emails (bug 566132). spawn_kwargs["fd_pipes"] = {0: sys.__stdin__.fileno(), 1: sys.__stdout__.fileno(), 2: sys.__stdout__.fileno()} spawn_kwargs["env"] = self.settings.environ() if repo.sync_user is not None: def get_sync_user_data(sync_user): user = None group = None home = None logname = None spl = sync_user.split(":", 1) if spl[0]: username = spl[0] try: try: pw = pwd.getpwnam(username) except KeyError: pw = pwd.getpwuid(int(username)) except (ValueError, KeyError): writemsg("!!! User '%s' invalid or does not exist\n" % username, noiselevel=-1) return (logname, user, group, home) user = pw.pw_uid group = pw.pw_gid home = pw.pw_dir logname = pw.pw_name if len(spl) > 1: groupname = spl[1] try: try: gp = grp.getgrnam(groupname) except KeyError: pw = grp.getgrgid(int(groupname)) except (ValueError, KeyError): writemsg("!!! Group '%s' invalid or does not exist\n" % groupname, noiselevel=-1) return (logname, user, group, home) group = gp.gr_gid return (logname, user, group, home) # user or user:group (logname, uid, gid, home) = get_sync_user_data(repo.sync_user) if uid is not None: spawn_kwargs["uid"] = uid self.usersync_uid = uid if gid is not None: spawn_kwargs["gid"] = gid spawn_kwargs["groups"] = [gid] if home is not None: spawn_kwargs["env"]["HOME"] = home if logname is not None: spawn_kwargs["env"]["LOGNAME"] = logname if st is None: perms = {"mode": 0o755} # respect sync-user if set if "umask" in spawn_kwargs: perms["mode"] &= ~spawn_kwargs["umask"] if "uid" in spawn_kwargs: perms["uid"] = spawn_kwargs["uid"] if "gid" in spawn_kwargs: perms["gid"] = spawn_kwargs["gid"] portage.util.ensure_dirs(repo.location, **perms) st = os.stat(repo.location) if ( repo.sync_user is None and "usersync" in self.settings.features and portage.data.secpass >= 2 and (st.st_uid != os.getuid() and st.st_mode & 0o700 or st.st_gid != os.getgid() and st.st_mode & 0o070) ): try: pw = pwd.getpwuid(st.st_uid) except KeyError: pass else: # Drop privileges when syncing, in order to match # existing uid/gid settings. self.usersync_uid = st.st_uid spawn_kwargs["uid"] = st.st_uid spawn_kwargs["gid"] = st.st_gid spawn_kwargs["groups"] = [st.st_gid] spawn_kwargs["env"]["HOME"] = pw.pw_dir spawn_kwargs["env"]["LOGNAME"] = pw.pw_name umask = 0o002 if not st.st_mode & 0o020: umask = umask | 0o020 spawn_kwargs["umask"] = umask # override the defaults when sync_umask is set if repo.sync_umask is not None: spawn_kwargs["umask"] = int(repo.sync_umask, 8) self.spawn_kwargs = spawn_kwargs if self.usersync_uid is not None: # PORTAGE_TMPDIR is used below, so validate it and # bail out if necessary. rval = _check_temp_dir(self.settings) if rval != os.EX_OK: return rval os.umask(0o022) return os.EX_OK
def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, cwd, pre_exec, close_fds, unshare_net, unshare_ipc, unshare_mount, unshare_pid, unshare_flags, cgroup): """ Execute a given binary with options @param binary: Name of program to execute @type binary: String @param mycommand: Options for program @type mycommand: String @param opt_name: Name of process (defaults to binary) @type opt_name: String @param fd_pipes: Mapping pipes to destination; { 0:0, 1:1, 2:2 } @type fd_pipes: Dictionary @param env: Key,Value mapping for Environmental Variables @type env: Dictionary @param gid: Group ID to run the process under @type gid: Integer @param groups: Groups the Process should be in. @type groups: List @param uid: User ID to run the process under @type uid: Integer @param umask: an int representing a unix umask (see man chmod for umask details) @type umask: Integer @param cwd: Current working directory @type cwd: String @param pre_exec: A function to be called with no arguments just prior to the exec call. @type pre_exec: callable @param unshare_net: If True, networking will be unshared from the spawned process @type unshare_net: Boolean @param unshare_ipc: If True, IPC will be unshared from the spawned process @type unshare_ipc: Boolean @param unshare_mount: If True, mount namespace will be unshared and mounts will be private to the namespace @type unshare_mount: Boolean @param unshare_pid: If True, PID ns will be unshared from the spawned process @type unshare_pid: Boolean @param unshare_flags: Flags for the unshare(2) function @type unshare_flags: Integer @param cgroup: CGroup path to bind the process to @type cgroup: String @rtype: None @return: Never returns (calls os.execve) """ # If the process we're creating hasn't been given a name # assign it the name of the executable. if not opt_name: if binary is portage._python_interpreter: # NOTE: PyPy 1.7 will die due to "libary path not found" if argv[0] # does not contain the full path of the binary. opt_name = binary else: opt_name = os.path.basename(binary) # Set up the command's argument list. myargs = [opt_name] myargs.extend(mycommand[1:]) # Avoid a potential UnicodeEncodeError from os.execve(). myargs = [_unicode_encode(x, encoding=_encodings['fs'], errors='strict') for x in myargs] # Use default signal handlers in order to avoid problems # killing subprocesses as reported in bug #353239. signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) # Unregister SIGCHLD handler and wakeup_fd for the parent # process's event loop (bug 655656). signal.signal(signal.SIGCHLD, signal.SIG_DFL) try: wakeup_fd = signal.set_wakeup_fd(-1) if wakeup_fd > 0: os.close(wakeup_fd) except (ValueError, OSError): pass # Quiet killing of subprocesses by SIGPIPE (see bug #309001). signal.signal(signal.SIGPIPE, signal.SIG_DFL) # Avoid issues triggered by inheritance of SIGQUIT handler from # the parent process (see bug #289486). signal.signal(signal.SIGQUIT, signal.SIG_DFL) _setup_pipes(fd_pipes, close_fds=close_fds, inheritable=True) # Add to cgroup # it's better to do it from the child since we can guarantee # it is done before we start forking children if cgroup: with open(os.path.join(cgroup, 'cgroup.procs'), 'a') as f: f.write('%d\n' % os.getpid()) # Unshare (while still uid==0) if unshare_net or unshare_ipc or unshare_mount or unshare_pid: filename = find_library("c") if filename is not None: libc = LoadLibrary(filename) if libc is not None: try: # Since a failed unshare call could corrupt process # state, first validate that the call can succeed. # The parent process should call _unshare_validate # before it forks, so that all child processes can # reuse _unshare_validate results that have been # cached by the parent process. errno_value = _unshare_validate(unshare_flags) if errno_value == 0 and libc.unshare(unshare_flags) != 0: errno_value = ctypes.get_errno() if errno_value != 0: involved_features = [] if unshare_ipc: involved_features.append('ipc-sandbox') if unshare_mount: involved_features.append('mount-sandbox') if unshare_net: involved_features.append('network-sandbox') if unshare_pid: involved_features.append('pid-sandbox') writemsg("Unable to unshare: %s (for FEATURES=\"%s\")\n" % ( errno.errorcode.get(errno_value, '?'), ' '.join(involved_features)), noiselevel=-1) else: if unshare_pid: main_child_pid = os.fork() if main_child_pid == 0: # pid namespace requires us to become init binary, myargs = portage._python_interpreter, [ portage._python_interpreter, os.path.join(portage._bin_path, 'pid-ns-init'), _unicode_encode('' if uid is None else str(uid)), _unicode_encode('' if gid is None else str(gid)), _unicode_encode('' if groups is None else ','.join(str(group) for group in groups)), _unicode_encode('' if umask is None else str(umask)), _unicode_encode(','.join(str(fd) for fd in fd_pipes)), binary] + myargs uid = None gid = None groups = None umask = None else: # Execute a supervisor process which will forward # signals to init and forward exit status to the # parent process. The supervisor process runs in # the global pid namespace, so skip /proc remount # and other setup that's intended only for the # init process. binary, myargs = portage._python_interpreter, [ portage._python_interpreter, os.path.join(portage._bin_path, 'pid-ns-init'), str(main_child_pid)] os.execve(binary, myargs, env) if unshare_mount: # mark the whole filesystem as slave to avoid # mounts escaping the namespace s = subprocess.Popen(['mount', '--make-rslave', '/']) mount_ret = s.wait() if mount_ret != 0: # TODO: should it be fatal maybe? writemsg("Unable to mark mounts slave: %d\n" % (mount_ret,), noiselevel=-1) if unshare_pid: # we need at least /proc being slave s = subprocess.Popen(['mount', '--make-slave', '/proc']) mount_ret = s.wait() if mount_ret != 0: # can't proceed with shared /proc writemsg("Unable to mark /proc slave: %d\n" % (mount_ret,), noiselevel=-1) os._exit(1) # mount new /proc for our namespace s = subprocess.Popen(['mount', '-n', '-t', 'proc', 'proc', '/proc']) mount_ret = s.wait() if mount_ret != 0: writemsg("Unable to mount new /proc: %d\n" % (mount_ret,), noiselevel=-1) os._exit(1) if unshare_net: # use 'localhost' to avoid hostname resolution problems try: socket.sethostname('localhost') except Exception as e: writemsg("Unable to set hostname: %s (for FEATURES=\"network-sandbox\")\n" % ( e,), noiselevel=-1) _configure_loopback_interface() except AttributeError: # unshare() not supported by libc pass # Set requested process permissions. if gid: # Cast proxies to int, in case it matters. os.setgid(int(gid)) if groups: os.setgroups(groups) if uid: # Cast proxies to int, in case it matters. os.setuid(int(uid)) if umask: os.umask(umask) if cwd is not None: os.chdir(cwd) if pre_exec: pre_exec() # And switch to the new process. os.execve(binary, myargs, env)
def pre_sync(self, repo): self.settings, self.trees, self.mtimedb = self.emerge_config self.xterm_titles = "notitles" not in self.settings.features msg = ">>> Synchronization of repository '%s' located in '%s'..." \ % (repo.name, repo.location) self.logger(self.xterm_titles, msg) writemsg_level(msg + "\n") try: st = os.stat(repo.location) except OSError: st = None self.usersync_uid = None spawn_kwargs = {} spawn_kwargs["env"] = self.settings.environ() if repo.sync_user is not None: def get_sync_user_data(sync_user): user = None group = None home = None spl = sync_user.split(':', 1) if spl[0]: username = spl[0] try: try: pw = pwd.getpwnam(username) except KeyError: pw = pwd.getpwuid(int(username)) except (ValueError, KeyError): writemsg("!!! User '%s' invalid or does not exist\n" % username, noiselevel=-1) return (user, group, home) user = pw.pw_uid group = pw.pw_gid home = pw.pw_dir if len(spl) > 1: groupname = spl[1] try: try: gp = grp.getgrnam(groupname) except KeyError: pw = grp.getgrgid(int(groupname)) except (ValueError, KeyError): writemsg("!!! Group '%s' invalid or does not exist\n" % groupname, noiselevel=-1) return (user, group, home) group = gp.gr_gid return (user, group, home) # user or user:group (uid, gid, home) = get_sync_user_data(repo.sync_user) if uid is not None: spawn_kwargs["uid"] = uid self.usersync_uid = uid if gid is not None: spawn_kwargs["gid"] = gid spawn_kwargs["groups"] = [gid] if home is not None: spawn_kwargs["env"]["HOME"] = home if st is None: perms = {'mode': 0o755} # respect sync-user if set if 'umask' in spawn_kwargs: perms['mode'] &= ~spawn_kwargs['umask'] if 'uid' in spawn_kwargs: perms['uid'] = spawn_kwargs['uid'] if 'gid' in spawn_kwargs: perms['gid'] = spawn_kwargs['gid'] writemsg_level(">>> '%s' not found, creating it." % _unicode_decode(repo.location)) portage.util.ensure_dirs(repo.location, **perms) st = os.stat(repo.location) if (repo.sync_user is None and 'usersync' in self.settings.features and portage.data.secpass >= 2 and (st.st_uid != os.getuid() and st.st_mode & 0o700 or st.st_gid != os.getgid() and st.st_mode & 0o070)): try: homedir = pwd.getpwuid(st.st_uid).pw_dir except KeyError: pass else: # Drop privileges when syncing, in order to match # existing uid/gid settings. self.usersync_uid = st.st_uid spawn_kwargs["uid"] = st.st_uid spawn_kwargs["gid"] = st.st_gid spawn_kwargs["groups"] = [st.st_gid] spawn_kwargs["env"]["HOME"] = homedir umask = 0o002 if not st.st_mode & 0o020: umask = umask | 0o020 spawn_kwargs["umask"] = umask # override the defaults when sync_umask is set if repo.sync_umask is not None: spawn_kwargs["umask"] = int(repo.sync_umask, 8) self.spawn_kwargs = spawn_kwargs if self.usersync_uid is not None: # PORTAGE_TMPDIR is used below, so validate it and # bail out if necessary. rval = _check_temp_dir(self.settings) if rval != os.EX_OK: return rval os.umask(0o022) return os.EX_OK
def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, waiting_msg=None, flags=0): """ If wantnewlockfile is True then this creates a lockfile in the parent directory as the file: '.' + basename + '.portage_lockfile'. """ import fcntl if not mypath: raise InvalidData(_("Empty path given")) if isinstance(mypath, basestring) and mypath[-1] == '/': mypath = mypath[:-1] if hasattr(mypath, 'fileno'): mypath = mypath.fileno() if isinstance(mypath, int): lockfilename = mypath wantnewlockfile = 0 unlinkfile = 0 elif wantnewlockfile: base, tail = os.path.split(mypath) lockfilename = os.path.join(base, "." + tail + ".portage_lockfile") del base, tail unlinkfile = 1 else: lockfilename = mypath if isinstance(mypath, basestring): if not os.path.exists(os.path.dirname(mypath)): raise DirectoryNotFound(os.path.dirname(mypath)) preexisting = os.path.exists(lockfilename) old_mask = os.umask(000) try: try: myfd = os.open(lockfilename, os.O_CREAT | os.O_RDWR, 0o660) except OSError as e: func_call = "open('%s')" % lockfilename if e.errno == OperationNotPermitted.errno: raise OperationNotPermitted(func_call) elif e.errno == PermissionDenied.errno: raise PermissionDenied(func_call) else: raise if not preexisting: try: if os.stat(lockfilename).st_gid != portage_gid: os.chown(lockfilename, -1, portage_gid) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE): return lockfile(mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) else: writemsg("%s: chown('%s', -1, %d)\n" % \ (e, lockfilename, portage_gid), noiselevel=-1) writemsg(_("Cannot chown a lockfile: '%s'\n") % \ lockfilename, noiselevel=-1) writemsg(_("Group IDs of current user: %s\n") % \ " ".join(str(n) for n in os.getgroups()), noiselevel=-1) finally: os.umask(old_mask) elif isinstance(mypath, int): myfd = mypath else: raise ValueError(_("Unknown type passed in '%s': '%s'") % \ (type(mypath), mypath)) # try for a non-blocking lock, if it's held, throw a message # we're waiting on lockfile and use a blocking attempt. locking_method = fcntl.lockf try: fcntl.lockf(myfd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError as e: if "errno" not in dir(e): raise if e.errno in (errno.EACCES, errno.EAGAIN): # resource temp unavailable; eg, someone beat us to the lock. if flags & os.O_NONBLOCK: raise TryAgain(mypath) global _quiet out = EOutput() out.quiet = _quiet if waiting_msg is None: if isinstance(mypath, int): waiting_msg = _("waiting for lock on fd %i") % myfd else: waiting_msg = _("waiting for lock on %s\n") % lockfilename out.ebegin(waiting_msg) # try for the exclusive lock now. try: fcntl.lockf(myfd, fcntl.LOCK_EX) except EnvironmentError as e: out.eend(1, str(e)) raise out.eend(os.EX_OK) elif e.errno == errno.ENOLCK: # We're not allowed to lock on this FS. os.close(myfd) link_success = False if lockfilename == str(lockfilename): if wantnewlockfile: try: if os.stat(lockfilename)[stat.ST_NLINK] == 1: os.unlink(lockfilename) except OSError: pass link_success = hardlink_lockfile(lockfilename) if not link_success: raise locking_method = None myfd = HARDLINK_FD else: raise if isinstance(lockfilename, basestring) and \ myfd != HARDLINK_FD and _fstat_nlink(myfd) == 0: # The file was deleted on us... Keep trying to make one... os.close(myfd) writemsg(_("lockfile recurse\n"), 1) lockfilename, myfd, unlinkfile, locking_method = lockfile( mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) writemsg(str((lockfilename, myfd, unlinkfile)) + "\n", 1) return (lockfilename, myfd, unlinkfile, locking_method)
def _get_legacy_global(name): constructed = portage._legacy_globals_constructed if name in constructed: return getattr(portage, name) if name == 'portdb': portage.portdb = portage.db[portage.root]["porttree"].dbapi constructed.add(name) return getattr(portage, name) elif name in ('mtimedb', 'mtimedbfile'): portage.mtimedbfile = os.path.join(portage.settings['EROOT'], CACHE_PATH, "mtimedb") constructed.add('mtimedbfile') portage.mtimedb = portage.MtimeDB(portage.mtimedbfile) constructed.add('mtimedb') return getattr(portage, name) # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) kwargs = {} for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT"), ("eprefix", "EPREFIX")): kwargs[k] = os.environ.get(envvar) portage._initializing_globals = True portage.db = portage.create_trees(**kwargs) constructed.add('db') del portage._initializing_globals settings = portage.db[portage.db._target_eroot]["vartree"].settings portage.settings = settings constructed.add('settings') # Since portage.db now uses EROOT for keys instead of ROOT, we make # portage.root refer to EROOT such that it continues to work as a key. portage.root = portage.db._target_eroot constructed.add('root') # COMPATIBILITY # These attributes should not be used within # Portage under any circumstances. portage.archlist = settings.archlist() constructed.add('archlist') portage.features = settings.features constructed.add('features') portage.groups = settings.get("ACCEPT_KEYWORDS", "").split() constructed.add('groups') portage.pkglines = settings.packages constructed.add('pkglines') portage.selinux_enabled = settings.selinux_enabled() constructed.add('selinux_enabled') portage.thirdpartymirrors = settings.thirdpartymirrors() constructed.add('thirdpartymirrors') profiledir = os.path.join(settings["PORTAGE_CONFIGROOT"], PROFILE_PATH) if not os.path.isdir(profiledir): profiledir = None portage.profiledir = profiledir constructed.add('profiledir') return getattr(portage, name)
def emaint_main(myargv): # Similar to emerge, emaint needs a default umask so that created # files (such as the world file) have sane permissions. os.umask(0o22) module_controller = Modules(namepath="portage.emaint.modules") module_names = module_controller.module_names[:] module_names.insert(0, "all") parser = OptionParser(usage=usage(module_controller), version=portage.VERSION) # add default options parser_options = [] for opt in DEFAULT_OPTIONS: parser_options.append(OptionItem(DEFAULT_OPTIONS[opt], parser)) for mod in module_names[1:]: desc = module_controller.get_func_descriptions(mod) if desc: for opt in desc: parser_options.append(OptionItem(desc[opt], parser)) for opt in parser_options: parser.add_option(opt.short, opt.long, help=opt.help, action=opt.action, type=opt.type, dest=opt.dest, callback=opt.callback, callback_kwargs=opt.callback_kwargs) parser.action = None (options, args) = parser.parse_args(args=myargv) #print('options', options, '\nargs', args, '\naction', parser.action) if len(args) != 1: parser.error("Incorrect number of arguments") if args[0] not in module_names: parser.error("%s target is not a known target" % args[0]) if parser.action: action = parser.action else: action = "-c/--check" long_action = action.split('/')[1].lstrip('-') #print("DEBUG: action = ", action, long_action) if args[0] == "all": tasks = [] for m in module_names[1:]: #print("DEBUG: module: %s, functions: " %(m, str(module_controller.get_functions(m)))) if long_action in module_controller.get_functions(m): tasks.append(module_controller.get_class(m)) elif long_action in module_controller.get_functions(args[0]): tasks = [module_controller.get_class(args[0] )] else: print("\nERROR: module '%s' does not have option '%s'\n" %(args[0], action)) print(module_opts(module_controller, args[0])) sys.exit(1) func = status = None for opt in parser_options: if opt.check_action(action): status = opt.status func = opt.func break # need to pass the parser options dict to the modules # so they are available if needed. task_opts = options.__dict__ taskmaster = TaskHandler(callback=print_results) taskmaster.run_tasks(tasks, func, status, options=task_opts)
def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, pre_exec): """ Execute a given binary with options @param binary: Name of program to execute @type binary: String @param mycommand: Options for program @type mycommand: String @param opt_name: Name of process (defaults to binary) @type opt_name: String @param fd_pipes: Mapping pipes to destination; { 0:0, 1:1, 2:2 } @type fd_pipes: Dictionary @param env: Key,Value mapping for Environmental Variables @type env: Dictionary @param gid: Group ID to run the process under @type gid: Integer @param groups: Groups the Process should be in. @type groups: Integer @param uid: User ID to run the process under @type uid: Integer @param umask: an int representing a unix umask (see man chmod for umask details) @type umask: Integer @param pre_exec: A function to be called with no arguments just prior to the exec call. @type pre_exec: callable @rtype: None @returns: Never returns (calls os.execve) """ # If the process we're creating hasn't been given a name # assign it the name of the executable. if not opt_name: opt_name = os.path.basename(binary) # Set up the command's argument list. myargs = [opt_name] myargs.extend(mycommand[1:]) # Set up the command's pipes. my_fds = {} # To protect from cases where direct assignment could # clobber needed fds ({1:2, 2:1}) we first dupe the fds # into unused fds. for fd in fd_pipes: my_fds[fd] = os.dup(fd_pipes[fd]) # Then assign them to what they should be. for fd in my_fds: os.dup2(my_fds[fd], fd) # Then close _all_ fds that haven't been explictly # requested to be kept open. for fd in get_open_fds(): if fd not in my_fds: try: os.close(fd) except OSError: pass # Set requested process permissions. if gid: os.setgid(gid) if groups: os.setgroups(groups) if uid: os.setuid(uid) if umask: os.umask(umask) if pre_exec: pre_exec() # And switch to the new process. os.execve(binary, myargs, env)
def _get_legacy_global(name): constructed = portage._legacy_globals_constructed if name in constructed: return getattr(portage, name) if name == 'portdb': portage.portdb = portage.db[portage.root]["porttree"].dbapi constructed.add(name) return getattr(portage, name) elif name in ('mtimedb', 'mtimedbfile'): portage.mtimedbfile = os.path.join(portage.root, CACHE_PATH, "mtimedb") constructed.add('mtimedbfile') portage.mtimedb = portage.MtimeDB(portage.mtimedbfile) constructed.add('mtimedb') return getattr(portage, name) # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) kwargs = {} for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")): kwargs[k] = os.environ.get(envvar, "/") portage._initializing_globals = True portage.db = portage.create_trees(**kwargs) constructed.add('db') del portage._initializing_globals settings = portage.db["/"]["vartree"].settings for root in portage.db: if root != "/": settings = portage.db[root]["vartree"].settings break portage.output._init(config_root=settings['PORTAGE_CONFIGROOT']) portage.settings = settings constructed.add('settings') portage.root = root constructed.add('root') # COMPATIBILITY # These attributes should not be used within # Portage under any circumstances. portage.archlist = settings.archlist() constructed.add('archlist') portage.features = settings.features constructed.add('features') portage.groups = settings["ACCEPT_KEYWORDS"].split() constructed.add('groups') portage.pkglines = settings.packages constructed.add('pkglines') portage.selinux_enabled = settings.selinux_enabled() constructed.add('selinux_enabled') portage.thirdpartymirrors = settings.thirdpartymirrors() constructed.add('thirdpartymirrors') portage.usedefaults = settings.use_defs constructed.add('usedefaults') profiledir = os.path.join(settings["PORTAGE_CONFIGROOT"], PROFILE_PATH) if not os.path.isdir(profiledir): profiledir = None portage.profiledir = profiledir constructed.add('profiledir') return getattr(portage, name)
def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, cwd, pre_exec, close_fds, unshare_net, unshare_ipc, unshare_mount, unshare_pid, unshare_flags, cgroup): """ Execute a given binary with options @param binary: Name of program to execute @type binary: String @param mycommand: Options for program @type mycommand: String @param opt_name: Name of process (defaults to binary) @type opt_name: String @param fd_pipes: Mapping pipes to destination; { 0:0, 1:1, 2:2 } @type fd_pipes: Dictionary @param env: Key,Value mapping for Environmental Variables @type env: Dictionary @param gid: Group ID to run the process under @type gid: Integer @param groups: Groups the Process should be in. @type groups: List @param uid: User ID to run the process under @type uid: Integer @param umask: an int representing a unix umask (see man chmod for umask details) @type umask: Integer @param cwd: Current working directory @type cwd: String @param pre_exec: A function to be called with no arguments just prior to the exec call. @type pre_exec: callable @param unshare_net: If True, networking will be unshared from the spawned process @type unshare_net: Boolean @param unshare_ipc: If True, IPC will be unshared from the spawned process @type unshare_ipc: Boolean @param unshare_mount: If True, mount namespace will be unshared and mounts will be private to the namespace @type unshare_mount: Boolean @param unshare_pid: If True, PID ns will be unshared from the spawned process @type unshare_pid: Boolean @param unshare_flags: Flags for the unshare(2) function @type unshare_flags: Integer @param cgroup: CGroup path to bind the process to @type cgroup: String @rtype: None @return: Never returns (calls os.execve) """ # If the process we're creating hasn't been given a name # assign it the name of the executable. if not opt_name: if binary is portage._python_interpreter: # NOTE: PyPy 1.7 will die due to "libary path not found" if argv[0] # does not contain the full path of the binary. opt_name = binary else: opt_name = os.path.basename(binary) # Set up the command's argument list. myargs = [opt_name] myargs.extend(mycommand[1:]) # Avoid a potential UnicodeEncodeError from os.execve(). myargs = [_unicode_encode(x, encoding=_encodings['fs'], errors='strict') for x in myargs] # Use default signal handlers in order to avoid problems # killing subprocesses as reported in bug #353239. signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) # Unregister SIGCHLD handler and wakeup_fd for the parent # process's event loop (bug 655656). signal.signal(signal.SIGCHLD, signal.SIG_DFL) try: wakeup_fd = signal.set_wakeup_fd(-1) if wakeup_fd > 0: os.close(wakeup_fd) except (ValueError, OSError): pass # Quiet killing of subprocesses by SIGPIPE (see bug #309001). signal.signal(signal.SIGPIPE, signal.SIG_DFL) # Avoid issues triggered by inheritance of SIGQUIT handler from # the parent process (see bug #289486). signal.signal(signal.SIGQUIT, signal.SIG_DFL) _setup_pipes(fd_pipes, close_fds=close_fds, inheritable=True) # Add to cgroup # it's better to do it from the child since we can guarantee # it is done before we start forking children if cgroup: with open(os.path.join(cgroup, 'cgroup.procs'), 'a') as f: f.write('%d\n' % os.getpid()) # Unshare (while still uid==0) if unshare_net or unshare_ipc or unshare_mount or unshare_pid: filename = find_library("c") if filename is not None: libc = LoadLibrary(filename) if libc is not None: try: # Since a failed unshare call could corrupt process # state, first validate that the call can succeed. # The parent process should call _unshare_validate # before it forks, so that all child processes can # reuse _unshare_validate results that have been # cached by the parent process. errno_value = _unshare_validate(unshare_flags) if errno_value == 0 and libc.unshare(unshare_flags) != 0: errno_value = ctypes.get_errno() if errno_value != 0: writemsg("Unable to unshare: %s\n" % ( errno.errorcode.get(errno_value, '?')), noiselevel=-1) else: if unshare_pid: main_child_pid = os.fork() if main_child_pid == 0: # pid namespace requires us to become init binary, myargs = portage._python_interpreter, [ portage._python_interpreter, os.path.join(portage._bin_path, 'pid-ns-init'), _unicode_encode('' if uid is None else str(uid)), _unicode_encode('' if gid is None else str(gid)), _unicode_encode('' if groups is None else ','.join(str(group) for group in groups)), _unicode_encode('' if umask is None else str(umask)), _unicode_encode(','.join(str(fd) for fd in fd_pipes)), binary] + myargs uid = None gid = None groups = None umask = None else: # Execute a supervisor process which will forward # signals to init and forward exit status to the # parent process. The supervisor process runs in # the global pid namespace, so skip /proc remount # and other setup that's intended only for the # init process. binary, myargs = portage._python_interpreter, [ portage._python_interpreter, os.path.join(portage._bin_path, 'pid-ns-init'), str(main_child_pid)] os.execve(binary, myargs, env) if unshare_mount: # mark the whole filesystem as slave to avoid # mounts escaping the namespace s = subprocess.Popen(['mount', '--make-rslave', '/']) mount_ret = s.wait() if mount_ret != 0: # TODO: should it be fatal maybe? writemsg("Unable to mark mounts slave: %d\n" % (mount_ret,), noiselevel=-1) if unshare_pid: # we need at least /proc being slave s = subprocess.Popen(['mount', '--make-slave', '/proc']) mount_ret = s.wait() if mount_ret != 0: # can't proceed with shared /proc writemsg("Unable to mark /proc slave: %d\n" % (mount_ret,), noiselevel=-1) os._exit(1) # mount new /proc for our namespace s = subprocess.Popen(['mount', '-n', '-t', 'proc', 'proc', '/proc']) mount_ret = s.wait() if mount_ret != 0: writemsg("Unable to mount new /proc: %d\n" % (mount_ret,), noiselevel=-1) os._exit(1) if unshare_net: # 'up' the loopback IFF_UP = 0x1 ifreq = struct.pack('16sh', b'lo', IFF_UP) SIOCSIFFLAGS = 0x8914 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) try: fcntl.ioctl(sock, SIOCSIFFLAGS, ifreq) except IOError as e: writemsg("Unable to enable loopback interface: %s\n" % ( errno.errorcode.get(e.errno, '?')), noiselevel=-1) sock.close() except AttributeError: # unshare() not supported by libc pass # Set requested process permissions. if gid: # Cast proxies to int, in case it matters. os.setgid(int(gid)) if groups: os.setgroups(groups) if uid: # Cast proxies to int, in case it matters. os.setuid(int(uid)) if umask: os.umask(umask) if cwd is not None: os.chdir(cwd) if pre_exec: pre_exec() # And switch to the new process. os.execve(binary, myargs, env)
def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, pre_exec, close_fds, unshare_net, unshare_ipc, cgroup): """ Execute a given binary with options @param binary: Name of program to execute @type binary: String @param mycommand: Options for program @type mycommand: String @param opt_name: Name of process (defaults to binary) @type opt_name: String @param fd_pipes: Mapping pipes to destination; { 0:0, 1:1, 2:2 } @type fd_pipes: Dictionary @param env: Key,Value mapping for Environmental Variables @type env: Dictionary @param gid: Group ID to run the process under @type gid: Integer @param groups: Groups the Process should be in. @type groups: Integer @param uid: User ID to run the process under @type uid: Integer @param umask: an int representing a unix umask (see man chmod for umask details) @type umask: Integer @param pre_exec: A function to be called with no arguments just prior to the exec call. @type pre_exec: callable @param unshare_net: If True, networking will be unshared from the spawned process @type unshare_net: Boolean @param unshare_ipc: If True, IPC will be unshared from the spawned process @type unshare_ipc: Boolean @param cgroup: CGroup path to bind the process to @type cgroup: String @rtype: None @return: Never returns (calls os.execve) """ # If the process we're creating hasn't been given a name # assign it the name of the executable. if not opt_name: if binary is portage._python_interpreter: # NOTE: PyPy 1.7 will die due to "libary path not found" if argv[0] # does not contain the full path of the binary. opt_name = binary else: opt_name = os.path.basename(binary) # Set up the command's argument list. myargs = [opt_name] myargs.extend(mycommand[1:]) # Avoid a potential UnicodeEncodeError from os.execve(). myargs = [ _unicode_encode(x, encoding=_encodings['fs'], errors='strict') for x in myargs ] # Use default signal handlers in order to avoid problems # killing subprocesses as reported in bug #353239. signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) # Quiet killing of subprocesses by SIGPIPE (see bug #309001). signal.signal(signal.SIGPIPE, signal.SIG_DFL) # Avoid issues triggered by inheritance of SIGQUIT handler from # the parent process (see bug #289486). signal.signal(signal.SIGQUIT, signal.SIG_DFL) _setup_pipes(fd_pipes, close_fds=close_fds, inheritable=True) # Add to cgroup # it's better to do it from the child since we can guarantee # it is done before we start forking children if cgroup: with open(os.path.join(cgroup, 'cgroup.procs'), 'a') as f: f.write('%d\n' % os.getpid()) # Unshare (while still uid==0) if unshare_net or unshare_ipc: filename = find_library("c") if filename is not None: libc = LoadLibrary(filename) if libc is not None: CLONE_NEWIPC = 0x08000000 CLONE_NEWNET = 0x40000000 flags = 0 if unshare_net: flags |= CLONE_NEWNET if unshare_ipc: flags |= CLONE_NEWIPC try: if libc.unshare(flags) != 0: writemsg( "Unable to unshare: %s\n" % (errno.errorcode.get(ctypes.get_errno(), '?')), noiselevel=-1) else: if unshare_net: # 'up' the loopback IFF_UP = 0x1 ifreq = struct.pack('16sh', b'lo', IFF_UP) SIOCSIFFLAGS = 0x8914 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) try: fcntl.ioctl(sock, SIOCSIFFLAGS, ifreq) except IOError as e: writemsg( "Unable to enable loopback interface: %s\n" % (errno.errorcode.get(e.errno, '?')), noiselevel=-1) sock.close() except AttributeError: # unshare() not supported by libc pass # Set requested process permissions. if gid: # Cast proxies to int, in case it matters. os.setgid(int(gid)) if groups: os.setgroups(groups) if uid: # Cast proxies to int, in case it matters. os.setuid(int(uid)) if umask: os.umask(umask) if pre_exec: pre_exec() # And switch to the new process. os.execve(binary, myargs, env)
def _get_legacy_global(name): constructed = portage._legacy_globals_constructed if name in constructed: return getattr(portage, name) if name == 'portdb': portage.portdb = portage.db[portage.root]["porttree"].dbapi constructed.add(name) return getattr(portage, name) if name in ('mtimedb', 'mtimedbfile'): portage.mtimedbfile = os.path.join(portage.settings['EROOT'], CACHE_PATH, "mtimedb") constructed.add('mtimedbfile') portage.mtimedb = portage.MtimeDB(portage.mtimedbfile) constructed.add('mtimedb') return getattr(portage, name) # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) kwargs = {} for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT"), ("sysroot", "SYSROOT"), ("eprefix", "EPREFIX")): kwargs[k] = os.environ.get(envvar) portage._initializing_globals = True portage.db = portage.create_trees(**kwargs) constructed.add('db') del portage._initializing_globals settings = portage.db[portage.db._target_eroot]["vartree"].settings portage.settings = settings constructed.add('settings') # Since portage.db now uses EROOT for keys instead of ROOT, we make # portage.root refer to EROOT such that it continues to work as a key. portage.root = portage.db._target_eroot constructed.add('root') # COMPATIBILITY # These attributes should not be used within # Portage under any circumstances. portage.archlist = settings.archlist() constructed.add('archlist') portage.features = settings.features constructed.add('features') portage.groups = settings.get("ACCEPT_KEYWORDS", "").split() constructed.add('groups') portage.pkglines = settings.packages constructed.add('pkglines') portage.selinux_enabled = settings.selinux_enabled() constructed.add('selinux_enabled') portage.thirdpartymirrors = settings.thirdpartymirrors() constructed.add('thirdpartymirrors') profiledir = os.path.join(settings["PORTAGE_CONFIGROOT"], PROFILE_PATH) if not os.path.isdir(profiledir): profiledir = None portage.profiledir = profiledir constructed.add('profiledir') return getattr(portage, name)
def emerge_main(args=None): """ @param args: command arguments (default: sys.argv[1:]) @type args: list """ if args is None: args = sys.argv[1:] args = portage._decode_argv(args) # Use system locale. try: locale.setlocale(locale.LC_ALL, "") except locale.Error as e: writemsg_level("setlocale: %s\n" % e, level=logging.WARN) # Disable color until we're sure that it should be enabled (after # EMERGE_DEFAULT_OPTS has been parsed). portage.output.havecolor = 0 # This first pass is just for options that need to be known as early as # possible, such as --config-root. They will be parsed again later, # together with EMERGE_DEFAULT_OPTS (which may vary depending on the # the value of --config-root). myaction, myopts, myfiles = parse_opts(args, silent=True) if "--debug" in myopts: os.environ["PORTAGE_DEBUG"] = "1" if "--config-root" in myopts: os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] if "--sysroot" in myopts: os.environ["SYSROOT"] = myopts["--sysroot"] if "--root" in myopts: os.environ["ROOT"] = myopts["--root"] if "--prefix" in myopts: os.environ["EPREFIX"] = myopts["--prefix"] if "--accept-properties" in myopts: os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"] if "--accept-restrict" in myopts: os.environ["ACCEPT_RESTRICT"] = myopts["--accept-restrict"] # optimize --help (no need to load config / EMERGE_DEFAULT_OPTS) if myaction == "help": emerge_help() return os.EX_OK if myaction == "moo": print(COWSAY_MOO % platform.system()) return os.EX_OK if myaction == "sync": # need to set this to True now in order for the repository config # loading to allow new repos with non-existent directories portage._sync_mode = True # Verify that /dev/null exists and is a device file as a cheap early # filter for obviously broken /dev/s. try: if os.stat(os.devnull).st_rdev == 0: writemsg_level( "Failed to validate a sane '/dev'.\n" "'/dev/null' is not a device file.\n", level=logging.ERROR, noiselevel=-1) return 1 except OSError: writemsg_level( "Failed to validate a sane '/dev'.\n" "'/dev/null' does not exist.\n", level=logging.ERROR, noiselevel=-1) return 1 # Verify that BASH process substitution works as another cheap early # filter. Process substitution uses '/dev/fd'. with open(os.devnull, 'r+b') as dev_null: fd_pipes = { 0: dev_null.fileno(), 1: dev_null.fileno(), 2: dev_null.fileno(), } if portage.process.spawn_bash("[[ $(< <(echo foo) ) == foo ]]", fd_pipes=fd_pipes) != 0: writemsg_level( "Failed to validate a sane '/dev'.\n" "bash process substitution doesn't work; this may be an " "indication of a broken '/dev/fd'.\n", level=logging.ERROR, noiselevel=-1) return 1 # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) emerge_config = load_emerge_config(action=myaction, args=myfiles, opts=myopts) # Make locale variables from configuration files (make.defaults, make.conf) affect locale of emerge process. for locale_var_name in ("LANGUAGE", "LC_ALL", "LC_ADDRESS", "LC_COLLATE", "LC_CTYPE", "LC_IDENTIFICATION", "LC_MEASUREMENT", "LC_MESSAGES", "LC_MONETARY", "LC_NAME", "LC_NUMERIC", "LC_PAPER", "LC_TELEPHONE", "LC_TIME", "LANG"): locale_var_value = emerge_config.running_config.settings.get( locale_var_name) if locale_var_value is not None: os.environ.setdefault(locale_var_name, locale_var_value) try: locale.setlocale(locale.LC_ALL, "") except locale.Error as e: writemsg_level("setlocale: %s\n" % e, level=logging.WARN) tmpcmdline = [] if "--ignore-default-opts" not in myopts: tmpcmdline.extend( portage.util.shlex_split( emerge_config.target_config.settings.get( "EMERGE_DEFAULT_OPTS", ""))) tmpcmdline.extend(args) emerge_config.action, emerge_config.opts, emerge_config.args = \ parse_opts(tmpcmdline) try: return run_action(emerge_config) finally: # Call destructors for our portdbapi instances. for x in emerge_config.trees.values(): if "porttree" in x.lazy_items: continue x["porttree"].dbapi.close_caches()
def emaint_main(myargv): # Similar to emerge, emaint needs a default umask so that created # files (such as the world file) have sane permissions. os.umask(0o22) module_path = os.path.join((os.path.dirname(os.path.realpath(__file__))), "modules") module_controller = Modules(path=module_path, namepath="portage.emaint.modules") module_names = module_controller.module_names[:] module_names.insert(0, "all") parser = argparse.ArgumentParser(usage=usage(module_controller)) # add default options parser_options = [] for opt in DEFAULT_OPTIONS: parser_options.append(OptionItem(DEFAULT_OPTIONS[opt])) for mod in module_names[1:]: desc = module_controller.get_func_descriptions(mod) if desc: for opt in desc: parser_options.append(OptionItem(desc[opt])) desc = module_controller.get_opt_descriptions(mod) if desc: for opt in desc: parser_options.append(OptionItem(desc[opt])) for opt in parser_options: parser.add_argument(*opt.pargs, **opt.kwargs) options, args = parser.parse_known_args(args=myargv) if options.version: print(portage.VERSION) return os.EX_OK if len(args) != 1: parser.error("Incorrect number of arguments") if args[0] not in module_names: parser.error("%s target is not a known target" % args[0]) check_opt = None func = status = long_action = None for opt in parser_options: if opt.long == '--check': # Default action check_opt = opt if opt.status and getattr(options, opt.target, False): if long_action is not None: parser.error("--%s and %s are exclusive options" % (long_action, opt.long)) status = opt.status func = opt.func long_action = opt.long.lstrip('-') if long_action is None: #print("DEBUG: long_action is None: setting to 'check'") long_action = 'check' func = check_opt.func status = check_opt.status if args[0] == "all": tasks = [] for m in module_names[1:]: #print("DEBUG: module: %s, functions: " % (m, str(module_controller.get_functions(m)))) if long_action in module_controller.get_functions(m): tasks.append(module_controller.get_class(m)) elif long_action in module_controller.get_functions(args[0]): tasks = [module_controller.get_class(args[0])] else: portage.util.writemsg( "\nERROR: module '%s' does not have option '--%s'\n\n" % (args[0], long_action), noiselevel=-1) portage.util.writemsg(module_opts(module_controller, args[0]), noiselevel=-1) sys.exit(1) # need to pass the parser options dict to the modules # so they are available if needed. task_opts = options.__dict__ task_opts['return-messages'] = True taskmaster = TaskHandler(callback=print_results, module_output=sys.stdout) returncodes = taskmaster.run_tasks(tasks, func, status, options=task_opts) sys.exit(False in returncodes)
def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, cwd, pre_exec, close_fds, unshare_net, unshare_ipc, unshare_mount, unshare_pid, cgroup): """ Execute a given binary with options @param binary: Name of program to execute @type binary: String @param mycommand: Options for program @type mycommand: String @param opt_name: Name of process (defaults to binary) @type opt_name: String @param fd_pipes: Mapping pipes to destination; { 0:0, 1:1, 2:2 } @type fd_pipes: Dictionary @param env: Key,Value mapping for Environmental Variables @type env: Dictionary @param gid: Group ID to run the process under @type gid: Integer @param groups: Groups the Process should be in. @type groups: Integer @param uid: User ID to run the process under @type uid: Integer @param umask: an int representing a unix umask (see man chmod for umask details) @type umask: Integer @param cwd: Current working directory @type cwd: String @param pre_exec: A function to be called with no arguments just prior to the exec call. @type pre_exec: callable @param unshare_net: If True, networking will be unshared from the spawned process @type unshare_net: Boolean @param unshare_ipc: If True, IPC will be unshared from the spawned process @type unshare_ipc: Boolean @param unshare_mount: If True, mount namespace will be unshared and mounts will be private to the namespace @type unshare_mount: Boolean @param unshare_pid: If True, PID ns will be unshared from the spawned process @type unshare_pid: Boolean @param cgroup: CGroup path to bind the process to @type cgroup: String @rtype: None @return: Never returns (calls os.execve) """ # If the process we're creating hasn't been given a name # assign it the name of the executable. if not opt_name: if binary is portage._python_interpreter: # NOTE: PyPy 1.7 will die due to "libary path not found" if argv[0] # does not contain the full path of the binary. opt_name = binary else: opt_name = os.path.basename(binary) # Set up the command's argument list. myargs = [opt_name] myargs.extend(mycommand[1:]) # Avoid a potential UnicodeEncodeError from os.execve(). myargs = [ _unicode_encode(x, encoding=_encodings['fs'], errors='strict') for x in myargs ] # Use default signal handlers in order to avoid problems # killing subprocesses as reported in bug #353239. signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) # Unregister SIGCHLD handler and wakeup_fd for the parent # process's event loop (bug 655656). signal.signal(signal.SIGCHLD, signal.SIG_DFL) try: wakeup_fd = signal.set_wakeup_fd(-1) if wakeup_fd > 0: os.close(wakeup_fd) except (ValueError, OSError): pass # Quiet killing of subprocesses by SIGPIPE (see bug #309001). signal.signal(signal.SIGPIPE, signal.SIG_DFL) # Avoid issues triggered by inheritance of SIGQUIT handler from # the parent process (see bug #289486). signal.signal(signal.SIGQUIT, signal.SIG_DFL) _setup_pipes(fd_pipes, close_fds=close_fds, inheritable=True) # Add to cgroup # it's better to do it from the child since we can guarantee # it is done before we start forking children if cgroup: with open(os.path.join(cgroup, 'cgroup.procs'), 'a') as f: f.write('%d\n' % os.getpid()) # Unshare (while still uid==0) if unshare_net or unshare_ipc or unshare_mount or unshare_pid: filename = find_library("c") if filename is not None: libc = LoadLibrary(filename) if libc is not None: # from /usr/include/bits/sched.h CLONE_NEWNS = 0x00020000 CLONE_NEWIPC = 0x08000000 CLONE_NEWPID = 0x20000000 CLONE_NEWNET = 0x40000000 flags = 0 if unshare_net: flags |= CLONE_NEWNET if unshare_ipc: flags |= CLONE_NEWIPC if unshare_mount: # NEWNS = mount namespace flags |= CLONE_NEWNS if unshare_pid: # we also need mount namespace for slave /proc flags |= CLONE_NEWPID | CLONE_NEWNS try: if libc.unshare(flags) != 0: writemsg( "Unable to unshare: %s\n" % (errno.errorcode.get(ctypes.get_errno(), '?')), noiselevel=-1) else: if unshare_pid: # pid namespace requires us to become init fork_ret = os.fork() if fork_ret != 0: os.execv(portage._python_interpreter, [ portage._python_interpreter, os.path.join(portage._bin_path, 'pid-ns-init'), '%s' % fork_ret, ]) if unshare_mount: # mark the whole filesystem as slave to avoid # mounts escaping the namespace s = subprocess.Popen( ['mount', '--make-rslave', '/']) mount_ret = s.wait() if mount_ret != 0: # TODO: should it be fatal maybe? writemsg("Unable to mark mounts slave: %d\n" % (mount_ret, ), noiselevel=-1) if unshare_pid: # we need at least /proc being slave s = subprocess.Popen( ['mount', '--make-slave', '/proc']) mount_ret = s.wait() if mount_ret != 0: # can't proceed with shared /proc writemsg("Unable to mark /proc slave: %d\n" % (mount_ret, ), noiselevel=-1) os._exit(1) # mount new /proc for our namespace s = subprocess.Popen( ['mount', '-t', 'proc', 'proc', '/proc']) mount_ret = s.wait() if mount_ret != 0: writemsg("Unable to mount new /proc: %d\n" % (mount_ret, ), noiselevel=-1) os._exit(1) if unshare_net: # 'up' the loopback IFF_UP = 0x1 ifreq = struct.pack('16sh', b'lo', IFF_UP) SIOCSIFFLAGS = 0x8914 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) try: fcntl.ioctl(sock, SIOCSIFFLAGS, ifreq) except IOError as e: writemsg( "Unable to enable loopback interface: %s\n" % (errno.errorcode.get(e.errno, '?')), noiselevel=-1) sock.close() except AttributeError: # unshare() not supported by libc pass # Set requested process permissions. if gid: # Cast proxies to int, in case it matters. os.setgid(int(gid)) if groups: os.setgroups(groups) if uid: # Cast proxies to int, in case it matters. os.setuid(int(uid)) if umask: os.umask(umask) if cwd is not None: os.chdir(cwd) if pre_exec: pre_exec() # And switch to the new process. os.execve(binary, myargs, env)
def _lockfile_iteration(mypath, wantnewlockfile=False, unlinkfile=False, waiting_msg=None, flags=0): """ Acquire a lock on mypath, without retry. Return None if the lockfile was removed by previous lock holder (caller must retry). @param mypath: lock file path @type mypath: str @param wantnewlockfile: use a separate new lock file @type wantnewlockfile: bool @param unlinkfile: remove lock file prior to unlock @type unlinkfile: bool @param waiting_msg: message to show before blocking @type waiting_msg: str @param flags: lock flags (only supports os.O_NONBLOCK) @type flags: int @rtype: bool @return: unlockfile tuple on success, None if retry is needed """ if not mypath: raise InvalidData(_("Empty path given")) # Since Python 3.4, chown requires int type (no proxies). portage_gid = int(portage.data.portage_gid) # Support for file object or integer file descriptor parameters is # deprecated due to ambiguity in whether or not it's safe to close # the file descriptor, making it prone to "Bad file descriptor" errors # or file descriptor leaks. if isinstance(mypath, basestring) and mypath[-1] == '/': mypath = mypath[:-1] lockfilename_path = mypath if hasattr(mypath, 'fileno'): warnings.warn( "portage.locks.lockfile() support for " "file object parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename_path = getattr(mypath, 'name', None) mypath = mypath.fileno() if isinstance(mypath, int): warnings.warn( "portage.locks.lockfile() support for integer file " "descriptor parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename = mypath wantnewlockfile = 0 unlinkfile = 0 elif wantnewlockfile: base, tail = os.path.split(mypath) lockfilename = os.path.join(base, "." + tail + ".portage_lockfile") lockfilename_path = lockfilename unlinkfile = 1 else: lockfilename = mypath if isinstance(mypath, basestring): if not os.path.exists(os.path.dirname(mypath)): raise DirectoryNotFound(os.path.dirname(mypath)) preexisting = os.path.exists(lockfilename) old_mask = os.umask(000) try: while True: try: myfd = os.open(lockfilename, os.O_CREAT | os.O_RDWR, 0o660) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE) and os.path.isdir( os.path.dirname(lockfilename)): # Retry required for NFS (see bug 636798). continue else: _raise_exc(e) else: break if not preexisting: try: if portage.data.secpass >= 1 and os.stat( lockfilename).st_gid != portage_gid: os.chown(lockfilename, -1, portage_gid) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE): os.close(myfd) return None else: writemsg("%s: chown('%s', -1, %d)\n" % \ (e, lockfilename, portage_gid), noiselevel=-1) writemsg(_("Cannot chown a lockfile: '%s'\n") % \ lockfilename, noiselevel=-1) writemsg(_("Group IDs of current user: %s\n") % \ " ".join(str(n) for n in os.getgroups()), noiselevel=-1) finally: os.umask(old_mask) elif isinstance(mypath, int): myfd = mypath else: raise ValueError(_("Unknown type passed in '%s': '%s'") % \ (type(mypath), mypath)) # try for a non-blocking lock, if it's held, throw a message # we're waiting on lockfile and use a blocking attempt. locking_method = portage._eintr_func_wrapper(_get_lock_fn()) try: if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: raise IOError(errno.ENOSYS, "Function not implemented") locking_method(myfd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError as e: if not hasattr(e, "errno"): raise if e.errno in (errno.EACCES, errno.EAGAIN, errno.ENOLCK): # resource temp unavailable; eg, someone beat us to the lock. if flags & os.O_NONBLOCK: os.close(myfd) raise TryAgain(mypath) global _quiet if _quiet: out = None else: out = portage.output.EOutput() if waiting_msg is None: if isinstance(mypath, int): waiting_msg = _("waiting for lock on fd %i") % myfd else: waiting_msg = _("waiting for lock on %s") % lockfilename if out is not None: out.ebegin(waiting_msg) # try for the exclusive lock now. enolock_msg_shown = False while True: try: locking_method(myfd, fcntl.LOCK_EX) except EnvironmentError as e: if e.errno == errno.ENOLCK: # This is known to occur on Solaris NFS (see # bug #462694). Assume that the error is due # to temporary exhaustion of record locks, # and loop until one becomes available. if not enolock_msg_shown: enolock_msg_shown = True if isinstance(mypath, int): context_desc = _("Error while waiting " "to lock fd %i") % myfd else: context_desc = _("Error while waiting " "to lock '%s'") % lockfilename writemsg("\n!!! %s: %s\n" % (context_desc, e), noiselevel=-1) time.sleep(_HARDLINK_POLL_LATENCY) continue if out is not None: out.eend(1, str(e)) raise else: break if out is not None: out.eend(os.EX_OK) elif e.errno in (errno.ENOSYS, ): # We're not allowed to lock on this FS. if not isinstance(lockfilename, int): # If a file object was passed in, it's not safe # to close the file descriptor because it may # still be in use. os.close(myfd) lockfilename_path = _unicode_decode(lockfilename_path, encoding=_encodings['fs'], errors='strict') if not isinstance(lockfilename_path, basestring): raise link_success = hardlink_lockfile(lockfilename_path, waiting_msg=waiting_msg, flags=flags) if not link_success: raise lockfilename = lockfilename_path locking_method = None myfd = HARDLINK_FD else: raise if isinstance(lockfilename, basestring) and myfd != HARDLINK_FD and unlinkfile: try: removed = _lockfile_was_removed(myfd, lockfilename) except Exception: # Do not leak the file descriptor here. os.close(myfd) raise else: if removed: # Removed by previous lock holder... Caller will retry... os.close(myfd) return None if myfd != HARDLINK_FD: # FD_CLOEXEC is enabled by default in Python >=3.4. if sys.hexversion < 0x3040000: try: fcntl.FD_CLOEXEC except AttributeError: pass else: fcntl.fcntl( myfd, fcntl.F_SETFD, fcntl.fcntl(myfd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC) _open_fds.add(myfd) writemsg(str((lockfilename, myfd, unlinkfile)) + "\n", 1) return (lockfilename, myfd, unlinkfile, locking_method)
def emerge_main(args=None): """ @param args: command arguments (default: sys.argv[1:]) @type args: list """ if args is None: args = sys.argv[1:] args = portage._decode_argv(args) # Use system locale. try: locale.setlocale(locale.LC_ALL, '') except locale.Error as e: writemsg_level("setlocale: %s\n" % e, level=logging.WARN) # Disable color until we're sure that it should be enabled (after # EMERGE_DEFAULT_OPTS has been parsed). portage.output.havecolor = 0 # This first pass is just for options that need to be known as early as # possible, such as --config-root. They will be parsed again later, # together with EMERGE_DEFAULT_OPTS (which may vary depending on the # the value of --config-root). myaction, myopts, myfiles = parse_opts(args, silent=True) if "--debug" in myopts: os.environ["PORTAGE_DEBUG"] = "1" if "--config-root" in myopts: os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] if "--root" in myopts: os.environ["ROOT"] = myopts["--root"] if "--prefix" in myopts: os.environ["EPREFIX"] = myopts["--prefix"] if "--accept-properties" in myopts: os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"] if "--accept-restrict" in myopts: os.environ["ACCEPT_RESTRICT"] = myopts["--accept-restrict"] # optimize --help (no need to load config / EMERGE_DEFAULT_OPTS) if myaction == "help": emerge_help() return os.EX_OK elif myaction == "moo": print(COWSAY_MOO % platform.system()) return os.EX_OK # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) if myaction == "sync": portage._sync_mode = True emerge_config = load_emerge_config(action=myaction, args=myfiles, opts=myopts) rval = profile_check(emerge_config.trees, emerge_config.action) if rval != os.EX_OK: return rval tmpcmdline = [] if "--ignore-default-opts" not in myopts: tmpcmdline.extend( portage.util.shlex_split( emerge_config.target_config.settings.get( "EMERGE_DEFAULT_OPTS", ""))) tmpcmdline.extend(args) emerge_config.action, emerge_config.opts, emerge_config.args = \ parse_opts(tmpcmdline) try: return run_action(emerge_config) finally: # Call destructors for our portdbapi instances. for x in emerge_config.trees.values(): if "porttree" in x.lazy_items: continue x["porttree"].dbapi.close_caches()
from repoman.argparser import parse_args from repoman.qa_data import QAData from repoman.qa_data import format_qa_output, format_qa_output_column from repoman.repos import RepoSettings from repoman.scanner import Scanner from repoman import utilities from repoman.modules.vcs.settings import VCSSettings from repoman import VERSION if sys.hexversion >= 0x3000000: basestring = str bad = create_color_func("BAD") # A sane umask is needed for files that portage creates. os.umask(0o22) LOGLEVEL = logging.WARNING portage.util.initialize_logger(LOGLEVEL) VALID_VERSIONS = [ 1, ] def repoman_main(argv): config_root = os.environ.get("PORTAGE_CONFIGROOT") repoman_settings = portage.config(config_root=config_root, local_config=False) repoman_settings.valid_versions = VALID_VERSIONS
def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, waiting_msg=None, flags=0): """ If wantnewlockfile is True then this creates a lockfile in the parent directory as the file: '.' + basename + '.portage_lockfile'. """ if not mypath: raise InvalidData(_("Empty path given")) # Support for file object or integer file descriptor parameters is # deprecated due to ambiguity in whether or not it's safe to close # the file descriptor, making it prone to "Bad file descriptor" errors # or file descriptor leaks. if isinstance(mypath, basestring) and mypath[-1] == '/': mypath = mypath[:-1] lockfilename_path = mypath if hasattr(mypath, 'fileno'): warnings.warn( "portage.locks.lockfile() support for " "file object parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename_path = getattr(mypath, 'name', None) mypath = mypath.fileno() if isinstance(mypath, int): warnings.warn( "portage.locks.lockfile() support for integer file " "descriptor parameters is deprecated. Use a file path instead.", DeprecationWarning, stacklevel=2) lockfilename = mypath wantnewlockfile = 0 unlinkfile = 0 elif wantnewlockfile: base, tail = os.path.split(mypath) lockfilename = os.path.join(base, "." + tail + ".portage_lockfile") lockfilename_path = lockfilename unlinkfile = 1 else: lockfilename = mypath if isinstance(mypath, basestring): if not os.path.exists(os.path.dirname(mypath)): raise DirectoryNotFound(os.path.dirname(mypath)) preexisting = os.path.exists(lockfilename) old_mask = os.umask(000) try: try: myfd = os.open(lockfilename, os.O_CREAT | os.O_RDWR, 0o660) except OSError as e: func_call = "open('%s')" % lockfilename if e.errno == OperationNotPermitted.errno: raise OperationNotPermitted(func_call) elif e.errno == PermissionDenied.errno: raise PermissionDenied(func_call) else: raise if not preexisting: try: if os.stat(lockfilename).st_gid != portage_gid: os.chown(lockfilename, -1, portage_gid) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE): return lockfile(mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) else: writemsg("%s: chown('%s', -1, %d)\n" % \ (e, lockfilename, portage_gid), noiselevel=-1) writemsg(_("Cannot chown a lockfile: '%s'\n") % \ lockfilename, noiselevel=-1) writemsg(_("Group IDs of current user: %s\n") % \ " ".join(str(n) for n in os.getgroups()), noiselevel=-1) finally: os.umask(old_mask) elif isinstance(mypath, int): myfd = mypath else: raise ValueError(_("Unknown type passed in '%s': '%s'") % \ (type(mypath), mypath)) # try for a non-blocking lock, if it's held, throw a message # we're waiting on lockfile and use a blocking attempt. locking_method = _default_lock_fn try: if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ: raise IOError(errno.ENOSYS, "Function not implemented") locking_method(myfd, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError as e: if not hasattr(e, "errno"): raise if e.errno in (errno.EACCES, errno.EAGAIN): # resource temp unavailable; eg, someone beat us to the lock. if flags & os.O_NONBLOCK: os.close(myfd) raise TryAgain(mypath) global _quiet if _quiet: out = None else: out = portage.output.EOutput() if waiting_msg is None: if isinstance(mypath, int): waiting_msg = _("waiting for lock on fd %i") % myfd else: waiting_msg = _("waiting for lock on %s\n") % lockfilename if out is not None: out.ebegin(waiting_msg) # try for the exclusive lock now. try: locking_method(myfd, fcntl.LOCK_EX) except EnvironmentError as e: if out is not None: out.eend(1, str(e)) raise if out is not None: out.eend(os.EX_OK) elif e.errno in (errno.ENOSYS, errno.ENOLCK): # We're not allowed to lock on this FS. if not isinstance(lockfilename, int): # If a file object was passed in, it's not safe # to close the file descriptor because it may # still be in use. os.close(myfd) lockfilename_path = _unicode_decode(lockfilename_path, encoding=_encodings['fs'], errors='strict') if not isinstance(lockfilename_path, basestring): raise link_success = hardlink_lockfile(lockfilename_path, waiting_msg=waiting_msg, flags=flags) if not link_success: raise lockfilename = lockfilename_path locking_method = None myfd = HARDLINK_FD else: raise if isinstance(lockfilename, basestring) and \ myfd != HARDLINK_FD and _fstat_nlink(myfd) == 0: # The file was deleted on us... Keep trying to make one... os.close(myfd) writemsg(_("lockfile recurse\n"), 1) lockfilename, myfd, unlinkfile, locking_method = lockfile( mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) if myfd != HARDLINK_FD: _open_fds.add(myfd) writemsg(str((lockfilename, myfd, unlinkfile)) + "\n", 1) return (lockfilename, myfd, unlinkfile, locking_method)
def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, pre_exec): """ Execute a given binary with options @param binary: Name of program to execute @type binary: String @param mycommand: Options for program @type mycommand: String @param opt_name: Name of process (defaults to binary) @type opt_name: String @param fd_pipes: Mapping pipes to destination; { 0:0, 1:1, 2:2 } @type fd_pipes: Dictionary @param env: Key,Value mapping for Environmental Variables @type env: Dictionary @param gid: Group ID to run the process under @type gid: Integer @param groups: Groups the Process should be in. @type groups: Integer @param uid: User ID to run the process under @type uid: Integer @param umask: an int representing a unix umask (see man chmod for umask details) @type umask: Integer @param pre_exec: A function to be called with no arguments just prior to the exec call. @type pre_exec: callable @rtype: None @return: Never returns (calls os.execve) """ # If the process we're creating hasn't been given a name # assign it the name of the executable. if not opt_name: if binary is portage._python_interpreter: # NOTE: PyPy 1.7 will die due to "libary path not found" if argv[0] # does not contain the full path of the binary. opt_name = binary else: opt_name = os.path.basename(binary) # Set up the command's argument list. myargs = [opt_name] myargs.extend(mycommand[1:]) # Use default signal handlers in order to avoid problems # killing subprocesses as reported in bug #353239. signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) # Quiet killing of subprocesses by SIGPIPE (see bug #309001). signal.signal(signal.SIGPIPE, signal.SIG_DFL) # Avoid issues triggered by inheritance of SIGQUIT handler from # the parent process (see bug #289486). signal.signal(signal.SIGQUIT, signal.SIG_DFL) _setup_pipes(fd_pipes) # Set requested process permissions. if gid: os.setgid(gid) if groups: os.setgroups(groups) if uid: os.setuid(uid) if umask: os.umask(umask) if pre_exec: pre_exec() # And switch to the new process. os.execve(binary, myargs, env)
def _exec(binary, mycommand, opt_name, fd_pipes, env, gid, groups, uid, umask, pre_exec, close_fds, unshare_net, unshare_ipc, cgroup): """ Execute a given binary with options @param binary: Name of program to execute @type binary: String @param mycommand: Options for program @type mycommand: String @param opt_name: Name of process (defaults to binary) @type opt_name: String @param fd_pipes: Mapping pipes to destination; { 0:0, 1:1, 2:2 } @type fd_pipes: Dictionary @param env: Key,Value mapping for Environmental Variables @type env: Dictionary @param gid: Group ID to run the process under @type gid: Integer @param groups: Groups the Process should be in. @type groups: Integer @param uid: User ID to run the process under @type uid: Integer @param umask: an int representing a unix umask (see man chmod for umask details) @type umask: Integer @param pre_exec: A function to be called with no arguments just prior to the exec call. @type pre_exec: callable @param unshare_net: If True, networking will be unshared from the spawned process @type unshare_net: Boolean @param unshare_ipc: If True, IPC will be unshared from the spawned process @type unshare_ipc: Boolean @param cgroup: CGroup path to bind the process to @type cgroup: String @rtype: None @return: Never returns (calls os.execve) """ # If the process we're creating hasn't been given a name # assign it the name of the executable. if not opt_name: if binary is portage._python_interpreter: # NOTE: PyPy 1.7 will die due to "libary path not found" if argv[0] # does not contain the full path of the binary. opt_name = binary else: opt_name = os.path.basename(binary) # Set up the command's argument list. myargs = [opt_name] myargs.extend(mycommand[1:]) # Avoid a potential UnicodeEncodeError from os.execve(). myargs = [_unicode_encode(x, encoding=_encodings['fs'], errors='strict') for x in myargs] # Use default signal handlers in order to avoid problems # killing subprocesses as reported in bug #353239. signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) # Quiet killing of subprocesses by SIGPIPE (see bug #309001). signal.signal(signal.SIGPIPE, signal.SIG_DFL) # Avoid issues triggered by inheritance of SIGQUIT handler from # the parent process (see bug #289486). signal.signal(signal.SIGQUIT, signal.SIG_DFL) _setup_pipes(fd_pipes, close_fds=close_fds, inheritable=True) # Add to cgroup # it's better to do it from the child since we can guarantee # it is done before we start forking children if cgroup: with open(os.path.join(cgroup, 'cgroup.procs'), 'a') as f: f.write('%d\n' % os.getpid()) # Unshare (while still uid==0) if unshare_net or unshare_ipc: filename = find_library("c") if filename is not None: libc = LoadLibrary(filename) if libc is not None: CLONE_NEWIPC = 0x08000000 CLONE_NEWNET = 0x40000000 flags = 0 if unshare_net: flags |= CLONE_NEWNET if unshare_ipc: flags |= CLONE_NEWIPC try: if libc.unshare(flags) != 0: writemsg("Unable to unshare: %s\n" % ( errno.errorcode.get(ctypes.get_errno(), '?')), noiselevel=-1) else: if unshare_net: # 'up' the loopback IFF_UP = 0x1 ifreq = struct.pack('16sh', b'lo', IFF_UP) SIOCSIFFLAGS = 0x8914 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) try: fcntl.ioctl(sock, SIOCSIFFLAGS, ifreq) except IOError as e: writemsg("Unable to enable loopback interface: %s\n" % ( errno.errorcode.get(e.errno, '?')), noiselevel=-1) sock.close() except AttributeError: # unshare() not supported by libc pass # Set requested process permissions. if gid: # Cast proxies to int, in case it matters. os.setgid(int(gid)) if groups: os.setgroups(groups) if uid: # Cast proxies to int, in case it matters. os.setuid(int(uid)) if umask: os.umask(umask) if pre_exec: pre_exec() # And switch to the new process. os.execve(binary, myargs, env)
def emaint_main(myargv): # Similar to emerge, emaint needs a default umask so that created # files (such as the world file) have sane permissions. os.umask(0o22) module_path = os.path.join( (os.path.dirname( os.path.realpath(__file__))), "modules" ) module_controller = Modules( path=module_path, namepath="portage.emaint.modules") module_names = module_controller.module_names[:] module_names.insert(0, "all") parser = ArgumentParser(usage=usage(module_controller)) # add default options parser_options = [] for opt in DEFAULT_OPTIONS: parser_options.append(OptionItem(DEFAULT_OPTIONS[opt])) for mod in module_names[1:]: desc = module_controller.get_func_descriptions(mod) if desc: for opt in desc: parser_options.append(OptionItem(desc[opt])) desc = module_controller.get_opt_descriptions(mod) if desc: for opt in desc: parser_options.append(OptionItem(desc[opt])) for opt in parser_options: parser.add_argument(*opt.pargs, **opt.kwargs) options, args = parser.parse_known_args(args=myargv) if options.version: print(portage.VERSION) return os.EX_OK if len(args) != 1: parser.error("Incorrect number of arguments") if args[0] not in module_names: parser.error("%s target is not a known target" % args[0]) check_opt = None func = status = long_action = None for opt in parser_options: if opt.long == '--check': # Default action check_opt = opt if opt.status and getattr(options, opt.target, False): if long_action is not None: parser.error("--%s and %s are exclusive options" % (long_action, opt.long)) status = opt.status func = opt.func long_action = opt.long.lstrip('-') if long_action is None: #print("DEBUG: long_action is None: setting to 'check'") long_action = 'check' func = check_opt.func status = check_opt.status if args[0] == "all": tasks = [] for m in module_names[1:]: #print("DEBUG: module: %s, functions: " % (m, str(module_controller.get_functions(m)))) if long_action in module_controller.get_functions(m): tasks.append(module_controller.get_class(m)) elif long_action in module_controller.get_functions(args[0]): tasks = [module_controller.get_class(args[0] )] else: portage.util.writemsg( "\nERROR: module '%s' does not have option '--%s'\n\n" % (args[0], long_action), noiselevel=-1) portage.util.writemsg(module_opts(module_controller, args[0]), noiselevel=-1) sys.exit(1) # need to pass the parser options dict to the modules # so they are available if needed. task_opts = options.__dict__ task_opts['return-messages'] = True taskmaster = TaskHandler(callback=print_results, module_output=sys.stdout) taskmaster.run_tasks(tasks, func, status, options=task_opts)
from repoman.argparser import parse_args from repoman.qa_data import QAData from repoman.qa_data import format_qa_output, format_qa_output_column from repoman.repos import RepoSettings from repoman.scanner import Scanner from repoman import utilities from repoman.modules.vcs.settings import VCSSettings from repoman import VERSION if sys.hexversion >= 0x3000000: basestring = str bad = create_color_func("BAD") # A sane umask is needed for files that portage creates. os.umask(0o22) LOGLEVEL = logging.WARNING portage.util.initialize_logger(LOGLEVEL) VALID_VERSIONS = [1,] def repoman_main(argv): config_root = os.environ.get("PORTAGE_CONFIGROOT") repoman_settings = portage.config(config_root=config_root, local_config=False) repoman_settings.valid_versions = VALID_VERSIONS if repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true") or \ repoman_settings.get('TERM') == 'dumb' or \ not sys.stdout.isatty(): nocolor()
def lockfile(mypath, wantnewlockfile=0, unlinkfile=0, waiting_msg=None, flags=0): """ If wantnewlockfile is True then this creates a lockfile in the parent directory as the file: '.' + basename + '.portage_lockfile'. """ import fcntl if not mypath: raise InvalidData(_("Empty path given")) if isinstance(mypath, basestring) and mypath[-1] == '/': mypath = mypath[:-1] if hasattr(mypath, 'fileno'): mypath = mypath.fileno() if isinstance(mypath, int): lockfilename = mypath wantnewlockfile = 0 unlinkfile = 0 elif wantnewlockfile: base, tail = os.path.split(mypath) lockfilename = os.path.join(base, "." + tail + ".portage_lockfile") del base, tail unlinkfile = 1 else: lockfilename = mypath if isinstance(mypath, basestring): if not os.path.exists(os.path.dirname(mypath)): raise DirectoryNotFound(os.path.dirname(mypath)) preexisting = os.path.exists(lockfilename) old_mask = os.umask(000) try: try: myfd = os.open(lockfilename, os.O_CREAT|os.O_RDWR, 0o660) except OSError as e: func_call = "open('%s')" % lockfilename if e.errno == OperationNotPermitted.errno: raise OperationNotPermitted(func_call) elif e.errno == PermissionDenied.errno: raise PermissionDenied(func_call) else: raise if not preexisting: try: if os.stat(lockfilename).st_gid != portage_gid: os.chown(lockfilename, -1, portage_gid) except OSError as e: if e.errno in (errno.ENOENT, errno.ESTALE): return lockfile(mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) else: writemsg(_("Cannot chown a lockfile: '%s'\n") % \ lockfilename, noiselevel=-1) finally: os.umask(old_mask) elif isinstance(mypath, int): myfd = mypath else: raise ValueError(_("Unknown type passed in '%s': '%s'") % \ (type(mypath), mypath)) # try for a non-blocking lock, if it's held, throw a message # we're waiting on lockfile and use a blocking attempt. locking_method = fcntl.lockf try: fcntl.lockf(myfd,fcntl.LOCK_EX|fcntl.LOCK_NB) except IOError as e: if "errno" not in dir(e): raise if e.errno in (errno.EACCES, errno.EAGAIN): # resource temp unavailable; eg, someone beat us to the lock. if flags & os.O_NONBLOCK: raise TryAgain(mypath) global _quiet out = EOutput() out.quiet = _quiet if waiting_msg is None: if isinstance(mypath, int): waiting_msg = _("waiting for lock on fd %i") % myfd else: waiting_msg = _("waiting for lock on %s\n") % lockfilename out.ebegin(waiting_msg) # try for the exclusive lock now. try: fcntl.lockf(myfd, fcntl.LOCK_EX) except EnvironmentError as e: out.eend(1, str(e)) raise out.eend(os.EX_OK) elif e.errno == errno.ENOLCK: # We're not allowed to lock on this FS. os.close(myfd) link_success = False if lockfilename == str(lockfilename): if wantnewlockfile: try: if os.stat(lockfilename)[stat.ST_NLINK] == 1: os.unlink(lockfilename) except OSError: pass link_success = hardlink_lockfile(lockfilename) if not link_success: raise locking_method = None myfd = HARDLINK_FD else: raise if isinstance(lockfilename, basestring) and \ myfd != HARDLINK_FD and _fstat_nlink(myfd) == 0: # The file was deleted on us... Keep trying to make one... os.close(myfd) writemsg(_("lockfile recurse\n"), 1) lockfilename, myfd, unlinkfile, locking_method = lockfile( mypath, wantnewlockfile=wantnewlockfile, unlinkfile=unlinkfile, waiting_msg=waiting_msg, flags=flags) writemsg(str((lockfilename,myfd,unlinkfile))+"\n",1) return (lockfilename,myfd,unlinkfile,locking_method)
def emerge_main(): global portage # NFC why this is necessary now - genone portage._disable_legacy_globals() # Disable color until we're sure that it should be enabled (after # EMERGE_DEFAULT_OPTS has been parsed). portage.output.havecolor = 0 # This first pass is just for options that need to be known as early as # possible, such as --config-root. They will be parsed again later, # together with EMERGE_DEFAULT_OPTS (which may vary depending on the # the value of --config-root). myaction, myopts, myfiles = parse_opts(sys.argv[1:], silent=True) if "--debug" in myopts: os.environ["PORTAGE_DEBUG"] = "1" if "--config-root" in myopts: os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] if "--root" in myopts: os.environ["ROOT"] = myopts["--root"] if "--accept-properties" in myopts: os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"] # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) settings, trees, mtimedb = load_emerge_config() portdb = trees[settings["ROOT"]]["porttree"].dbapi rval = profile_check(trees, myaction) if rval != os.EX_OK: return rval if myaction not in ('help', 'info', 'version') and \ _global_updates(trees, mtimedb["updates"]): mtimedb.commit() # Reload the whole config from scratch. settings, trees, mtimedb = load_emerge_config(trees=trees) portdb = trees[settings["ROOT"]]["porttree"].dbapi xterm_titles = "notitles" not in settings.features if xterm_titles: xtermTitle("emerge") tmpcmdline = [] if "--ignore-default-opts" not in myopts: tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split()) tmpcmdline.extend(sys.argv[1:]) myaction, myopts, myfiles = parse_opts(tmpcmdline) if "--digest" in myopts: os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest" # Reload the whole config from scratch so that the portdbapi internal # config is updated with new FEATURES. settings, trees, mtimedb = load_emerge_config(trees=trees) portdb = trees[settings["ROOT"]]["porttree"].dbapi adjust_configs(myopts, trees) apply_priorities(settings) if myaction == 'version': writemsg_stdout(getportageversion( settings["PORTDIR"], settings["ROOT"], settings.profile_path, settings["CHOST"], trees[settings["ROOT"]]["vartree"].dbapi) + '\n', noiselevel=-1) return 0 elif myaction == 'help': _emerge.help.help(myopts, portage.output.havecolor) return 0 spinner = stdout_spinner() if "candy" in settings.features: spinner.update = spinner.update_scroll if "--quiet" not in myopts: portage.deprecated_profile_check(settings=settings) repo_name_check(trees) repo_name_duplicate_check(trees) config_protect_check(trees) check_procfs() if "getbinpkg" in settings.features: myopts["--getbinpkg"] = True if "--getbinpkgonly" in myopts: myopts["--getbinpkg"] = True if "--getbinpkgonly" in myopts: myopts["--usepkgonly"] = True if "--getbinpkg" in myopts: myopts["--usepkg"] = True if "--usepkgonly" in myopts: myopts["--usepkg"] = True if "buildpkg" in settings.features or "--buildpkgonly" in myopts: myopts["--buildpkg"] = True if "--buildpkgonly" in myopts: # --buildpkgonly will not merge anything, so # it cancels all binary package options. for opt in ("--getbinpkg", "--getbinpkgonly", "--usepkg", "--usepkgonly"): myopts.pop(opt, None) for mytrees in trees.values(): mydb = mytrees["porttree"].dbapi # Freeze the portdbapi for performance (memoize all xmatch results). mydb.freeze() if "--usepkg" in myopts: # Populate the bintree with current --getbinpkg setting. # This needs to happen before expand_set_arguments(), in case # any sets use the bintree. mytrees["bintree"].populate( getbinpkgs="--getbinpkg" in myopts) del mytrees, mydb if "moo" in myfiles: print(""" Larry loves Gentoo (""" + platform.system() + """) _______________________ < Have you mooed today? > ----------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || """) for x in myfiles: ext = os.path.splitext(x)[1] if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)): print(colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n")) break root_config = trees[settings["ROOT"]]["root_config"] if myaction == "list-sets": writemsg_stdout("".join("%s\n" % s for s in sorted(root_config.sets))) return os.EX_OK ensure_required_sets(trees) # only expand sets for actions taking package arguments oldargs = myfiles[:] if myaction in ("clean", "config", "depclean", "info", "prune", "unmerge", None): myfiles, retval = expand_set_arguments(myfiles, myaction, root_config) if retval != os.EX_OK: return retval # Need to handle empty sets specially, otherwise emerge will react # with the help message for empty argument lists if oldargs and not myfiles: print("emerge: no targets left after set expansion") return 0 if ("--tree" in myopts) and ("--columns" in myopts): print("emerge: can't specify both of \"--tree\" and \"--columns\".") return 1 if '--emptytree' in myopts and '--noreplace' in myopts: writemsg_level("emerge: can't specify both of " + \ "\"--emptytree\" and \"--noreplace\".\n", level=logging.ERROR, noiselevel=-1) return 1 if ("--quiet" in myopts): spinner.update = spinner.update_quiet portage.util.noiselimit = -1 if "--fetch-all-uri" in myopts: myopts["--fetchonly"] = True if "--skipfirst" in myopts and "--resume" not in myopts: myopts["--resume"] = True # Allow -p to remove --ask if "--pretend" in myopts: myopts.pop("--ask", None) # forbid --ask when not in a terminal # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. if ("--ask" in myopts) and (not sys.stdin.isatty()): portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n", noiselevel=-1) return 1 if settings.get("PORTAGE_DEBUG", "") == "1": spinner.update = spinner.update_quiet portage.debug=1 if "python-trace" in settings.features: import portage.debug portage.debug.set_trace(True) if not ("--quiet" in myopts): if '--nospinner' in myopts or \ settings.get('TERM') == 'dumb' or \ not sys.stdout.isatty(): spinner.update = spinner.update_basic if "--debug" in myopts: print("myaction", myaction) print("myopts", myopts) if not myaction and not myfiles and "--resume" not in myopts: _emerge.help.help(myopts, portage.output.havecolor) return 1 pretend = "--pretend" in myopts fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts buildpkgonly = "--buildpkgonly" in myopts # check if root user is the current user for the actions where emerge needs this if portage.secpass < 2: # We've already allowed "--version" and "--help" above. if "--pretend" not in myopts and myaction not in ("search","info"): need_superuser = myaction in ('clean', 'depclean', 'deselect', 'prune', 'unmerge') or not \ (fetchonly or \ (buildpkgonly and secpass >= 1) or \ myaction in ("metadata", "regen") or \ (myaction == "sync" and os.access(settings["PORTDIR"], os.W_OK))) if portage.secpass < 1 or \ need_superuser: if need_superuser: access_desc = "superuser" else: access_desc = "portage group" # Always show portage_group_warning() when only portage group # access is required but the user is not in the portage group. from portage.data import portage_group_warning if "--ask" in myopts: myopts["--pretend"] = True del myopts["--ask"] print(("%s access is required... " + \ "adding --pretend to options\n") % access_desc) if portage.secpass < 1 and not need_superuser: portage_group_warning() else: sys.stderr.write(("emerge: %s access is required\n") \ % access_desc) if portage.secpass < 1 and not need_superuser: portage_group_warning() return 1 disable_emergelog = False for x in ("--pretend", "--fetchonly", "--fetch-all-uri"): if x in myopts: disable_emergelog = True break if myaction in ("search", "info"): disable_emergelog = True if disable_emergelog: """ Disable emergelog for everything except build or unmerge operations. This helps minimize parallel emerge.log entries that can confuse log parsers. We especially want it disabled during parallel-fetch, which uses --resume --fetchonly.""" _emerge.emergelog._disable = True else: if 'EMERGE_LOG_DIR' in settings: try: # At least the parent needs to exist for the lock file. portage.util.ensure_dirs(settings['EMERGE_LOG_DIR']) except portage.exception.PortageException as e: writemsg_level("!!! Error creating directory for " + \ "EMERGE_LOG_DIR='%s':\n!!! %s\n" % \ (settings['EMERGE_LOG_DIR'], e), noiselevel=-1, level=logging.ERROR) else: global _emerge_log_dir _emerge_log_dir = settings['EMERGE_LOG_DIR'] if not "--pretend" in myopts: emergelog(xterm_titles, "Started emerge on: "+\ _unicode_decode( time.strftime("%b %d, %Y %H:%M:%S", time.localtime()), encoding=_encodings['content'], errors='replace')) myelogstr="" if myopts: myelogstr=" ".join(myopts) if myaction: myelogstr+=" "+myaction if myfiles: myelogstr += " " + " ".join(oldargs) emergelog(xterm_titles, " *** emerge " + myelogstr) del oldargs def emergeexitsig(signum, frame): signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_IGN) portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum}) sys.exit(100+signum) signal.signal(signal.SIGINT, emergeexitsig) signal.signal(signal.SIGTERM, emergeexitsig) def emergeexit(): """This gets out final log message in before we quit.""" if "--pretend" not in myopts: emergelog(xterm_titles, " *** terminating.") if xterm_titles: xtermTitleReset() portage.atexit_register(emergeexit) if myaction in ("config", "metadata", "regen", "sync"): if "--pretend" in myopts: sys.stderr.write(("emerge: The '%s' action does " + \ "not support '--pretend'.\n") % myaction) return 1 if "sync" == myaction: return action_sync(settings, trees, mtimedb, myopts, myaction) elif "metadata" == myaction: action_metadata(settings, portdb, myopts) elif myaction=="regen": validate_ebuild_environment(trees) return action_regen(settings, portdb, myopts.get("--jobs"), myopts.get("--load-average")) # HELP action elif "config"==myaction: validate_ebuild_environment(trees) action_config(settings, trees, myopts, myfiles) # SEARCH action elif "search"==myaction: validate_ebuild_environment(trees) action_search(trees[settings["ROOT"]]["root_config"], myopts, myfiles, spinner) elif myaction in ('clean', 'depclean', 'deselect', 'prune', 'unmerge'): validate_ebuild_environment(trees) rval = action_uninstall(settings, trees, mtimedb["ldpath"], myopts, myaction, myfiles, spinner) if not (myaction == 'deselect' or buildpkgonly or fetchonly or pretend): post_emerge(root_config, myopts, mtimedb, rval) return rval elif myaction == 'info': # Ensure atoms are valid before calling unmerge(). vardb = trees[settings["ROOT"]]["vartree"].dbapi portdb = trees[settings["ROOT"]]["porttree"].dbapi bindb = trees[settings["ROOT"]]["bintree"].dbapi valid_atoms = [] for x in myfiles: if is_valid_package_atom(x): try: #look at the installed files first, if there is no match #look at the ebuilds, since EAPI 4 allows running pkg_info #on non-installed packages valid_atom = dep_expand(x, mydb=vardb, settings=settings) if valid_atom.cp.split("/")[0] == "null": valid_atom = dep_expand(x, mydb=portdb, settings=settings) if valid_atom.cp.split("/")[0] == "null" and "--usepkg" in myopts: valid_atom = dep_expand(x, mydb=bindb, settings=settings) valid_atoms.append(valid_atom) except portage.exception.AmbiguousPackageName as e: msg = "The short ebuild name \"" + x + \ "\" is ambiguous. Please specify " + \ "one of the following " + \ "fully-qualified ebuild names instead:" for line in textwrap.wrap(msg, 70): writemsg_level("!!! %s\n" % (line,), level=logging.ERROR, noiselevel=-1) for i in e[0]: writemsg_level(" %s\n" % colorize("INFORM", i), level=logging.ERROR, noiselevel=-1) writemsg_level("\n", level=logging.ERROR, noiselevel=-1) return 1 continue msg = [] msg.append("'%s' is not a valid package atom." % (x,)) msg.append("Please check ebuild(5) for full details.") writemsg_level("".join("!!! %s\n" % line for line in msg), level=logging.ERROR, noiselevel=-1) return 1 return action_info(settings, trees, myopts, valid_atoms) # "update", "system", or just process files: else: validate_ebuild_environment(trees) for x in myfiles: if x.startswith(SETPREFIX) or \ is_valid_package_atom(x): continue if x[:1] == os.sep: continue try: os.lstat(x) continue except OSError: pass msg = [] msg.append("'%s' is not a valid package atom." % (x,)) msg.append("Please check ebuild(5) for full details.") writemsg_level("".join("!!! %s\n" % line for line in msg), level=logging.ERROR, noiselevel=-1) return 1 if "--pretend" not in myopts: display_news_notification(root_config, myopts) retval = action_build(settings, trees, mtimedb, myopts, myaction, myfiles, spinner) root_config = trees[settings["ROOT"]]["root_config"] post_emerge(root_config, myopts, mtimedb, retval) return retval
def emerge_main(args=None): """ @param args: command arguments (default: sys.argv[1:]) @type args: list """ if args is None: args = sys.argv[1:] args = portage._decode_argv(args) # Use system locale. try: locale.setlocale(locale.LC_ALL, "") except locale.Error as e: writemsg_level("setlocale: %s\n" % e, level=logging.WARN) # Disable color until we're sure that it should be enabled (after # EMERGE_DEFAULT_OPTS has been parsed). portage.output.havecolor = 0 # This first pass is just for options that need to be known as early as # possible, such as --config-root. They will be parsed again later, # together with EMERGE_DEFAULT_OPTS (which may vary depending on the # the value of --config-root). myaction, myopts, myfiles = parse_opts(args, silent=True) if "--debug" in myopts: os.environ["PORTAGE_DEBUG"] = "1" if "--config-root" in myopts: os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] if "--sysroot" in myopts: os.environ["SYSROOT"] = myopts["--sysroot"] if "--root" in myopts: os.environ["ROOT"] = myopts["--root"] if "--prefix" in myopts: os.environ["EPREFIX"] = myopts["--prefix"] if "--accept-properties" in myopts: os.environ["ACCEPT_PROPERTIES"] = myopts["--accept-properties"] if "--accept-restrict" in myopts: os.environ["ACCEPT_RESTRICT"] = myopts["--accept-restrict"] # optimize --help (no need to load config / EMERGE_DEFAULT_OPTS) if myaction == "help": emerge_help() return os.EX_OK elif myaction == "moo": print(COWSAY_MOO % platform.system()) return os.EX_OK elif myaction == "sync": # need to set this to True now in order for the repository config # loading to allow new repos with non-existent directories portage._sync_mode = True # Verify that /dev/null exists and is a device file as a cheap early # filter for obviously broken /dev/s. try: if os.stat(os.devnull).st_rdev == 0: writemsg_level("Failed to validate a sane '/dev'.\n" "'/dev/null' is not a device file.\n", level=logging.ERROR, noiselevel=-1) return 1 except OSError: writemsg_level("Failed to validate a sane '/dev'.\n" "'/dev/null' does not exist.\n", level=logging.ERROR, noiselevel=-1) return 1 # Verify that BASH process substitution works as another cheap early # filter. Process substitution uses '/dev/fd'. with open(os.devnull, 'r+b') as dev_null: fd_pipes = { 0: dev_null.fileno(), 1: dev_null.fileno(), 2: dev_null.fileno(), } if portage.process.spawn_bash("[[ $(< <(echo foo) ) == foo ]]", fd_pipes=fd_pipes) != 0: writemsg_level("Failed to validate a sane '/dev'.\n" "bash process substitution doesn't work; this may be an " "indication of a broken '/dev/fd'.\n", level=logging.ERROR, noiselevel=-1) return 1 # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) emerge_config = load_emerge_config( action=myaction, args=myfiles, opts=myopts) # Make locale variables from configuration files (make.defaults, make.conf) affect locale of emerge process. for locale_var_name in ("LANGUAGE", "LC_ALL", "LC_ADDRESS", "LC_COLLATE", "LC_CTYPE", "LC_IDENTIFICATION", "LC_MEASUREMENT", "LC_MESSAGES", "LC_MONETARY", "LC_NAME", "LC_NUMERIC", "LC_PAPER", "LC_TELEPHONE", "LC_TIME", "LANG"): locale_var_value = emerge_config.running_config.settings.get(locale_var_name) if locale_var_value is not None: os.environ.setdefault(locale_var_name, locale_var_value) try: locale.setlocale(locale.LC_ALL, "") except locale.Error as e: writemsg_level("setlocale: %s\n" % e, level=logging.WARN) tmpcmdline = [] if "--ignore-default-opts" not in myopts: tmpcmdline.extend(portage.util.shlex_split( emerge_config.target_config.settings.get( "EMERGE_DEFAULT_OPTS", ""))) tmpcmdline.extend(args) emerge_config.action, emerge_config.opts, emerge_config.args = \ parse_opts(tmpcmdline) try: return run_action(emerge_config) finally: # Call destructors for our portdbapi instances. for x in emerge_config.trees.values(): if "porttree" in x.lazy_items: continue x["porttree"].dbapi.close_caches()
def _get_legacy_global(name): constructed = portage._legacy_globals_constructed if name in constructed: return getattr(portage, name) if name == 'portdb': portage.portdb = portage.db[portage.root]["porttree"].dbapi constructed.add(name) return getattr(portage, name) elif name in ('mtimedb', 'mtimedbfile'): portage.mtimedbfile = os.path.join(portage.root, CACHE_PATH, "mtimedb") constructed.add('mtimedbfile') portage.mtimedb = portage.MtimeDB(portage.mtimedbfile) constructed.add('mtimedb') return getattr(portage, name) # Portage needs to ensure a sane umask for the files it creates. os.umask(0o22) kwargs = {} for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")): kwargs[k] = os.environ.get(envvar) portage._initializing_globals = True portage.db = portage.create_trees(**kwargs) constructed.add('db') del portage._initializing_globals settings = portage.db["/"]["vartree"].settings for root in portage.db: if root != "/": settings = portage.db[root]["vartree"].settings break portage.output._init(config_root=settings['PORTAGE_CONFIGROOT']) portage.settings = settings constructed.add('settings') portage.root = root constructed.add('root') # COMPATIBILITY # These attributes should not be used within # Portage under any circumstances. portage.archlist = settings.archlist() constructed.add('archlist') portage.features = settings.features constructed.add('features') portage.groups = settings["ACCEPT_KEYWORDS"].split() constructed.add('groups') portage.pkglines = settings.packages constructed.add('pkglines') portage.selinux_enabled = settings.selinux_enabled() constructed.add('selinux_enabled') portage.thirdpartymirrors = settings.thirdpartymirrors() constructed.add('thirdpartymirrors') profiledir = os.path.join(settings["PORTAGE_CONFIGROOT"], PROFILE_PATH) if not os.path.isdir(profiledir): profiledir = None portage.profiledir = profiledir constructed.add('profiledir') return getattr(portage, name)