Ejemplo n.º 1
0
 def _subprocess(args, cwd, env, expected, debug):
     os.chdir(cwd)
     os.environ.update(env)
     portage.const.EPREFIX = env["PORTAGE_OVERRIDE_EPREFIX"]
     if debug:
         args = ["-vvvv"] + args
     repoman_vars = _repoman_init(["repoman"] + args)
     if repoman_vars.exitcode is not None:
         return {"returncode": repoman_vars.exitcode}
     result = _repoman_scan(*repoman_vars)
     returncode = _handle_result(*repoman_vars, result)
     qawarnings = repoman_vars.vcs_settings.qatracker.qawarnings
     warns = collections.defaultdict(list)
     fails = collections.defaultdict(list)
     for qacat, issues in repoman_vars.vcs_settings.qatracker.fails.items():
         if qacat in qawarnings:
             warns[qacat].extend(issues)
         else:
             fails[qacat].extend(issues)
     result = {"returncode": returncode}
     if fails:
         result["fails"] = fails
     if warns:
         result["warns"] = warns
     return result
Ejemplo n.º 2
0
def binTestsInit():
	binTestsCleanup()
	global basedir, env
	basedir = tempfile.mkdtemp()
	env = os.environ.copy()
	env["D"] = os.path.join(basedir, "image")
	env["T"] = os.path.join(basedir, "temp")
	env["S"] = os.path.join(basedir, "workdir")
	env["PF"] = "portage-tests-0.09-r1"
	env["PATH"] = bindir + ":" + env["PATH"]
	env["PORTAGE_BIN_PATH"] = bindir
	env["PORTAGE_PYM_PATH"] = pymdir
	os.mkdir(env["D"])
	os.mkdir(env["T"])
	os.mkdir(env["S"])
	os.chdir(env["S"])
Ejemplo n.º 3
0
def xpand(myid, mydest):
    myindex = myid[0]
    mydata = myid[1]
    try:
        origdir = os.getcwd()
    except SystemExit as e:
        raise
    except:
        os.chdir("/")
        origdir = "/"
    os.chdir(mydest)
    myindexlen = len(myindex)
    startpos = 0
    while ((startpos + 8) < myindexlen):
        namelen = decodeint(myindex[startpos:startpos + 4])
        datapos = decodeint(myindex[startpos + 4 + namelen:startpos + 8 +
                                    namelen])
        datalen = decodeint(myindex[startpos + 8 + namelen:startpos + 12 +
                                    namelen])
        myname = myindex[startpos + 4:startpos + 4 + namelen]
        dirname = os.path.dirname(myname)
        if dirname:
            if not os.path.exists(dirname):
                os.makedirs(dirname)
        mydat = open(
            _unicode_encode(myname, encoding=_encodings['fs'],
                            errors='strict'), 'wb')
        mydat.write(mydata[datapos:datapos + datalen])
        mydat.close()
        startpos = startpos + namelen + 12
    os.chdir(origdir)
Ejemplo n.º 4
0
def xpand(myid,mydest):
	myindex=myid[0]
	mydata=myid[1]
	try:
		origdir=os.getcwd()
	except SystemExit as e:
		raise
	except:
		os.chdir("/")
		origdir="/"
	os.chdir(mydest)
	myindexlen=len(myindex)
	startpos=0
	while ((startpos+8)<myindexlen):
		namelen=decodeint(myindex[startpos:startpos+4])
		datapos=decodeint(myindex[startpos+4+namelen:startpos+8+namelen]);
		datalen=decodeint(myindex[startpos+8+namelen:startpos+12+namelen]);
		myname=myindex[startpos+4:startpos+4+namelen]
		dirname=os.path.dirname(myname)
		if dirname:
			if not os.path.exists(dirname):
				os.makedirs(dirname)
		mydat = open(_unicode_encode(myname,
			encoding=_encodings['fs'], errors='strict'), 'wb')
		mydat.write(mydata[datapos:datapos+datalen])
		mydat.close()
		startpos=startpos+namelen+12
	os.chdir(origdir)
Ejemplo n.º 5
0
 def unpackinfo(self, mydest):
     """Unpacks all the files from the dataSegment into 'mydest'."""
     if not self.scan():
         return 0
     try:
         origdir = os.getcwd()
     except SystemExit as e:
         raise
     except:
         os.chdir("/")
         origdir = "/"
     a = open(
         _unicode_encode(self.file,
                         encoding=_encodings['fs'],
                         errors='strict'), 'rb')
     if not os.path.exists(mydest):
         os.makedirs(mydest)
     os.chdir(mydest)
     startpos = 0
     while ((startpos + 8) < self.indexsize):
         namelen = decodeint(self.index[startpos:startpos + 4])
         datapos = decodeint(self.index[startpos + 4 + namelen:startpos +
                                        8 + namelen])
         datalen = decodeint(self.index[startpos + 8 + namelen:startpos +
                                        12 + namelen])
         myname = self.index[startpos + 4:startpos + 4 + namelen]
         myname = _unicode_decode(myname,
                                  encoding=_encodings['repo.content'],
                                  errors='replace')
         dirname = os.path.dirname(myname)
         if dirname:
             if not os.path.exists(dirname):
                 os.makedirs(dirname)
         mydat = open(
             _unicode_encode(myname,
                             encoding=_encodings['fs'],
                             errors='strict'), 'wb')
         a.seek(self.datapos + datapos)
         mydat.write(a.read(datalen))
         mydat.close()
         startpos = startpos + namelen + 12
     a.close()
     os.chdir(origdir)
     return 1
Ejemplo n.º 6
0
	def unpackinfo(self,mydest):
		"""Unpacks all the files from the dataSegment into 'mydest'."""
		if not self.scan():
			return 0
		try:
			origdir=os.getcwd()
		except SystemExit as e:
			raise
		except:
			os.chdir("/")
			origdir="/"
		a = open(_unicode_encode(self.file,
			encoding=_encodings['fs'], errors='strict'), 'rb')
		if not os.path.exists(mydest):
			os.makedirs(mydest)
		os.chdir(mydest)
		startpos=0
		while ((startpos+8)<self.indexsize):
			namelen=decodeint(self.index[startpos:startpos+4])
			datapos=decodeint(self.index[startpos+4+namelen:startpos+8+namelen]);
			datalen=decodeint(self.index[startpos+8+namelen:startpos+12+namelen]);
			myname=self.index[startpos+4:startpos+4+namelen]
			myname = _unicode_decode(myname,
				encoding=_encodings['repo.content'], errors='replace')
			dirname=os.path.dirname(myname)
			if dirname:
				if not os.path.exists(dirname):
					os.makedirs(dirname)
			mydat = open(_unicode_encode(myname,
				encoding=_encodings['fs'], errors='strict'), 'wb')
			a.seek(self.datapos+datapos)
			mydat.write(a.read(datalen))
			mydat.close()
			startpos=startpos+namelen+12
		a.close()
		os.chdir(origdir)
		return 1
Ejemplo n.º 7
0
def post_emerge(myaction, myopts, myfiles,
	target_root, trees, mtimedb, retval):
	"""
	Misc. things to run at the end of a merge session.

	Update Info Files
	Update Config Files
	Update News Items
	Commit mtimeDB
	Display preserved libs warnings

	@param myaction: The action returned from parse_opts()
	@type myaction: String
	@param myopts: emerge options
	@type myopts: dict
	@param myfiles: emerge arguments
	@type myfiles: list
	@param target_root: The target EROOT for myaction
	@type target_root: String
	@param trees: A dictionary mapping each ROOT to it's package databases
	@type trees: dict
	@param mtimedb: The mtimeDB to store data needed across merge invocations
	@type mtimedb: MtimeDB class instance
	@param retval: Emerge's return value
	@type retval: Int
	"""

	root_config = trees[target_root]["root_config"]
	vardbapi = trees[target_root]['vartree'].dbapi
	settings = vardbapi.settings
	info_mtimes = mtimedb["info"]

	# Load the most current variables from ${ROOT}/etc/profile.env
	settings.unlock()
	settings.reload()
	settings.regenerate()
	settings.lock()

	config_protect = portage.util.shlex_split(
		settings.get("CONFIG_PROTECT", ""))
	infodirs = settings.get("INFOPATH","").split(":") + \
		settings.get("INFODIR","").split(":")

	os.chdir("/")

	if retval == os.EX_OK:
		exit_msg = " *** exiting successfully."
	else:
		exit_msg = " *** exiting unsuccessfully with status '%s'." % retval
	emergelog("notitles" not in settings.features, exit_msg)

	_flush_elog_mod_echo()

	if not vardbapi._pkgs_changed:
		# GLEP 42 says to display news *after* an emerge --pretend
		if "--pretend" in myopts:
			display_news_notification(root_config, myopts)
		# If vdb state has not changed then there's nothing else to do.
		return

	vdb_path = os.path.join(root_config.settings['EROOT'], portage.VDB_PATH)
	portage.util.ensure_dirs(vdb_path)
	vdb_lock = None
	if os.access(vdb_path, os.W_OK) and not "--pretend" in myopts:
		vardbapi.lock()
		vdb_lock = True

	if vdb_lock:
		try:
			if "noinfo" not in settings.features:
				chk_updated_info_files(target_root,
					infodirs, info_mtimes)
			mtimedb.commit()
		finally:
			if vdb_lock:
				vardbapi.unlock()

	# Explicitly load and prune the PreservedLibsRegistry in order
	# to ensure that we do not display stale data.
	vardbapi._plib_registry.load()

	if vardbapi._plib_registry.hasEntries():
		if "--quiet" in myopts:
			print()
			print(colorize("WARN", "!!!") + " existing preserved libs found")
		else:
			print()
			print(colorize("WARN", "!!!") + " existing preserved libs:")
			display_preserved_libs(vardbapi)
			print("Use " + colorize("GOOD", "emerge @preserved-rebuild") +
				" to rebuild packages using these libraries")

	chk_updated_cfg_files(settings['EROOT'], config_protect)

	display_news_notification(root_config, myopts)

	postemerge = os.path.join(settings["PORTAGE_CONFIGROOT"],
		portage.USER_CONFIG_PATH, "bin", "post_emerge")
	if os.access(postemerge, os.X_OK):
		hook_retval = portage.process.spawn(
						[postemerge], env=settings.environ())
		if hook_retval != os.EX_OK:
			portage.util.writemsg_level(
				" %s spawn failed of %s\n" %
				(colorize("BAD", "*"), postemerge,),
				level=logging.ERROR, noiselevel=-1)

	clean_logs(settings)

	if "--quiet" not in myopts and \
		myaction is None and "@world" in myfiles:
		show_depclean_suggestion()
Ejemplo n.º 8
0
#  - will do as 'dohtml' but filter on .png,.gif,.html,.htm (default filter
#    list is ignored)
# dohtml -x CVS,SCCS,RCS -r <list-of-files-and-directories>
#  - will do as 'dohtml -r', but ignore directories named CVS, SCCS, RCS
#

from __future__ import print_function, unicode_literals

import os as _os
import sys

from portage import _unicode_encode, _unicode_decode, os, shutil
from portage.util import normalize_path, writemsg

# Change back to original cwd _after_ all imports (bug #469338).
os.chdir(os.environ["__PORTAGE_HELPER_CWD"])


def dodir(path):
    try:
        os.makedirs(path, 0o755)
    except OSError:
        if not os.path.isdir(path):
            raise
        os.chmod(path, 0o755)


def dofile(src, dst):
    shutil.copy(src, dst)
    os.chmod(dst, 0o644)
Ejemplo n.º 9
0
	def pre_exec():
		os.chdir(env['S'])
Ejemplo n.º 10
0
 def pre_exec():
     os.chdir(env['S'])
Ejemplo n.º 11
0
def post_emerge(myaction, myopts, myfiles, target_root, trees, mtimedb,
                retval):
    """
    Misc. things to run at the end of a merge session.

    Update Info Files
    Update Config Files
    Update News Items
    Commit mtimeDB
    Display preserved libs warnings

    @param myaction: The action returned from parse_opts()
    @type myaction: String
    @param myopts: emerge options
    @type myopts: dict
    @param myfiles: emerge arguments
    @type myfiles: list
    @param target_root: The target EROOT for myaction
    @type target_root: String
    @param trees: A dictionary mapping each ROOT to it's package databases
    @type trees: dict
    @param mtimedb: The mtimeDB to store data needed across merge invocations
    @type mtimedb: MtimeDB class instance
    @param retval: Emerge's return value
    @type retval: Int
    """

    root_config = trees[target_root]["root_config"]
    vardbapi = trees[target_root]["vartree"].dbapi
    settings = vardbapi.settings
    info_mtimes = mtimedb["info"]

    # Load the most current variables from ${ROOT}/etc/profile.env
    settings.unlock()
    settings.reload()
    settings.regenerate()
    settings.lock()

    config_protect = portage.util.shlex_split(
        settings.get("CONFIG_PROTECT", ""))
    infodirs = settings.get("INFOPATH", "").split(":") + settings.get(
        "INFODIR", "").split(":")

    os.chdir("/")

    if retval == os.EX_OK:
        exit_msg = " *** exiting successfully."
    else:
        exit_msg = " *** exiting unsuccessfully with status '%s'." % retval
    emergelog("notitles" not in settings.features, exit_msg)

    _flush_elog_mod_echo()

    if not vardbapi._pkgs_changed:
        # GLEP 42 says to display news *after* an emerge --pretend
        if "--pretend" in myopts:
            display_news_notification(root_config, myopts)
        # If vdb state has not changed then there's nothing else to do.
        return

    vdb_path = os.path.join(root_config.settings["EROOT"], portage.VDB_PATH)
    portage.util.ensure_dirs(vdb_path)
    vdb_lock = None
    if os.access(vdb_path, os.W_OK) and not "--pretend" in myopts:
        vardbapi.lock()
        vdb_lock = True

    if vdb_lock:
        try:
            if "noinfo" not in settings.features:
                chk_updated_info_files(target_root, infodirs, info_mtimes)
            mtimedb.commit()
        finally:
            if vdb_lock:
                vardbapi.unlock()

    # Explicitly load and prune the PreservedLibsRegistry in order
    # to ensure that we do not display stale data.
    vardbapi._plib_registry.load()

    if vardbapi._plib_registry.hasEntries():
        if "--quiet" in myopts:
            print()
            print(colorize("WARN", "!!!") + " existing preserved libs found")
        else:
            print()
            print(colorize("WARN", "!!!") + " existing preserved libs:")
            display_preserved_libs(vardbapi, verbose="--verbose" in myopts)
            print("Use " + colorize("GOOD", "emerge @preserved-rebuild") +
                  " to rebuild packages using these libraries")

    chk_updated_cfg_files(settings["EROOT"], config_protect)

    display_news_notification(root_config, myopts)

    postemerge = os.path.join(settings["PORTAGE_CONFIGROOT"],
                              portage.USER_CONFIG_PATH, "bin", "post_emerge")
    if os.access(postemerge, os.X_OK):
        hook_retval = portage.process.spawn([postemerge],
                                            env=settings.environ())
        if hook_retval != os.EX_OK:
            portage.util.writemsg_level(
                " %s spawn failed of %s\n" % (
                    colorize("BAD", "*"),
                    postemerge,
                ),
                level=logging.ERROR,
                noiselevel=-1,
            )

    clean_logs(settings)

    if "--quiet" not in myopts and myaction is None and "@world" in myfiles:
        show_depclean_suggestion()
Ejemplo n.º 12
0
#  - will do as 'dohtml' but filter on .png,.gif,.html,.htm (default filter
#    list is ignored)
# dohtml -x CVS,SCCS,RCS -r <list-of-files-and-directories>
#  - will do as 'dohtml -r', but ignore directories named CVS, SCCS, RCS
#

from __future__ import print_function, unicode_literals

import os as _os
import sys

from portage import _unicode_encode, _unicode_decode, os, shutil
from portage.util import normalize_path, writemsg

# Change back to original cwd _after_ all imports (bug #469338).
os.chdir(os.environ["__PORTAGE_HELPER_CWD"])

def dodir(path):
	try:
		os.makedirs(path, 0o755)
	except OSError:
		if not os.path.isdir(path):
			raise
		os.chmod(path, 0o755)

def dofile(src,dst):
	shutil.copy(src, dst)
	os.chmod(dst, 0o644)

def eqawarn(lines):
	cmd = "source '%s/isolated-functions.sh' ; " % \
Ejemplo n.º 13
0
def post_emerge(root_config, myopts, mtimedb, retval):
	"""
	Misc. things to run at the end of a merge session.

	Update Info Files
	Update Config Files
	Update News Items
	Commit mtimeDB
	Display preserved libs warnings
	Exit Emerge

	@param trees: A dictionary mapping each ROOT to it's package databases
	@type trees: dict
	@param mtimedb: The mtimeDB to store data needed across merge invocations
	@type mtimedb: MtimeDB class instance
	@param retval: Emerge's return value
	@type retval: Int
	@rype: None
	@returns:
	1.  Calls sys.exit(retval)
	"""

	target_root = root_config.root
	trees = { target_root : root_config.trees }
	vardbapi = trees[target_root]["vartree"].dbapi
	settings = vardbapi.settings
	info_mtimes = mtimedb["info"]

	# Load the most current variables from ${ROOT}/etc/profile.env
	settings.unlock()
	settings.reload()
	settings.regenerate()
	settings.lock()

	config_protect = settings.get("CONFIG_PROTECT","").split()
	infodirs = settings.get("INFOPATH","").split(":") + \
		settings.get("INFODIR","").split(":")

	os.chdir("/")

	if retval == os.EX_OK:
		exit_msg = " *** exiting successfully."
	else:
		exit_msg = " *** exiting unsuccessfully with status '%s'." % retval
	emergelog("notitles" not in settings.features, exit_msg)

	_flush_elog_mod_echo()

	if not vardbapi._pkgs_changed:
		display_news_notification(root_config, myopts)
		# If vdb state has not changed then there's nothing else to do.
		sys.exit(retval)

	vdb_path = os.path.join(target_root, portage.VDB_PATH)
	portage.util.ensure_dirs(vdb_path)
	vdb_lock = None
	if os.access(vdb_path, os.W_OK) and not "--pretend" in myopts:
		vdb_lock = portage.locks.lockdir(vdb_path)

	if vdb_lock:
		try:
			if "noinfo" not in settings.features:
				chk_updated_info_files(target_root,
					infodirs, info_mtimes, retval)
			mtimedb.commit()
		finally:
			if vdb_lock:
				portage.locks.unlockdir(vdb_lock)

	chk_updated_cfg_files(target_root, config_protect)

	display_news_notification(root_config, myopts)
	if retval in (None, os.EX_OK) or (not "--pretend" in myopts):
		display_preserved_libs(vardbapi, myopts)	

	sys.exit(retval)
Ejemplo n.º 14
0
 def pre_exec():
     os.chdir(env["S"])
Ejemplo n.º 15
0
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)
Ejemplo n.º 16
0
	def pre_exec():
		os.chdir(env["S"])
Ejemplo n.º 17
0
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)
Ejemplo n.º 18
0
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)