from itertools import chain
import logging
import os as _os
+import platform
import pwd
import re
import signal
"prerm", "setup"
])
+# phases in which networking access is allowed
+_networked_phases = frozenset([
+ # for VCS fetching
+ "unpack",
+ # for IPC
+ "setup", "pretend",
+ "preinst", "postinst", "prerm", "postrm",
+])
+
_phase_func_map = {
"config": "pkg_config",
"setup": "pkg_setup",
if phase in _unsandboxed_phases:
kwargs['free'] = True
+ if phase in _networked_phases:
+ kwargs['networked'] = True
if phase == 'depend':
kwargs['droppriv'] = 'userpriv' in settings.features
if hasattr(mydbapi, 'repositories'):
repo = mydbapi.repositories.get_repo_for_location(mytree)
mysettings['PORTDIR'] = repo.eclass_db.porttrees[0]
- mysettings['PORTDIR_OVERLAY'] = ' '.join(repo.eclass_db.porttrees[1:])
+ mysettings['PORTAGE_ECLASS_LOCATIONS'] = repo.eclass_db.eclass_locations_string
mysettings.configdict["pkg"]["PORTAGE_REPO_NAME"] = repo.name
mysettings["PORTDIR"] = os.path.realpath(mysettings["PORTDIR"])
+ mysettings.pop("PORTDIR_OVERLAY", None)
mysettings["DISTDIR"] = os.path.realpath(mysettings["DISTDIR"])
mysettings["RPMDIR"] = os.path.realpath(mysettings["RPMDIR"])
"fetch", "fetchall", "digest",
"unpack", "prepare", "configure", "compile", "test",
"install", "rpm", "qmerge", "merge",
- "package","unmerge", "manifest"]
+ "package", "unmerge", "manifest", "nofetch"]
if mydo not in validcommands:
validcommands.sort()
return _spawn_phase(mydo, mysettings,
fd_pipes=fd_pipes, returnpid=returnpid)
+ elif mydo == "nofetch":
+
+ if returnpid:
+ writemsg("!!! doebuild: %s\n" %
+ _("returnpid is not supported for phase '%s'\n" % mydo),
+ noiselevel=-1)
+
+ return spawn_nofetch(mydbapi, myebuild, settings=mysettings,
+ fd_pipes=fd_pipes)
+
if tree == "porttree":
if not returnpid:
if "noauto" in mysettings.features:
mysettings.features.discard("noauto")
- # The info phase is special because it uses mkdtemp so and
- # user (not necessarily in the portage group) can run it.
- if mydo not in ('info',) and \
+ # If we are not using a private temp dir, then check access
+ # to the global temp dir.
+ if tmpdir is None and \
mydo not in _doebuild_commands_without_builddir:
rval = _check_temp_dir(mysettings)
if rval != os.EX_OK:
# XXX This would be to replace getstatusoutput completely.
# XXX Issue: cannot block execution. Deadlock condition.
-def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakeroot=0, **keywords):
+def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakeroot=0, networked=0, **keywords):
"""
Spawn a subprocess with extra portage-specific options.
Optiosn include:
@type sesandbox: Boolean
@param fakeroot: Run this command with faked root privileges
@type fakeroot: Boolean
+ @param networked: Run this command with networking access enabled
+ @type networked: Boolean
@param keywords: Extra options encoded as a dict, to be passed to spawn
@type keywords: Dictionary
@rtype: Integer
break
features = mysettings.features
+
+ # Unshare network namespace to keep ebuilds sanitized
+ if not networked and uid == 0 and platform.system() == 'Linux' and "network-sandbox" in features:
+ keywords['unshare_net'] = True
+
# TODO: Enable fakeroot to be used together with droppriv. The
# fake ownership/permissions will have to be converted to real
# permissions in the merge phase.
"umask": 0o02
})
if "userpriv" in features and "userpriv" not in mysettings["PORTAGE_RESTRICT"].split() and secpass >= 2:
- portage_build_uid = portage_uid
- portage_build_gid = portage_gid
+ # Since Python 3.4, getpwuid and getgrgid
+ # require int type (no proxies).
+ portage_build_uid = int(portage_uid)
+ portage_build_gid = int(portage_gid)
if "PORTAGE_BUILD_USER" not in mysettings:
user = None