summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pym/portage.py56
1 files changed, 50 insertions, 6 deletions
diff --git a/pym/portage.py b/pym/portage.py
index 9c5277feb..6891a42ea 100644
--- a/pym/portage.py
+++ b/pym/portage.py
@@ -2164,6 +2164,29 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, **keyw
env=mysettings.environ()
keywords["opt_name"]="[%s]" % mysettings["PF"]
+ # The default policy for the sesandbox domain only allows entry (via exec)
+ # from shells and from binaries that belong to portage (the number of entry
+ # points is minimized). The "tee" binary is not among the allowed entry
+ # points, so it is spawned outside of the sesandbox domain and reads from a
+ # pipe between two domains.
+ logfile = keywords.get("logfile")
+ mypids = []
+ pw = None
+ if logfile:
+ del keywords["logfile"]
+ fd_pipes = keywords.get("fd_pipes")
+ if fd_pipes is None:
+ fd_pipes = {0:0, 1:1, 2:2}
+ if 1 not in fd_pipes or 2 not in fd_pipes:
+ raise ValueError(fd_pipes)
+ pr, pw = os.pipe()
+ mypids.extend(portage_exec.spawn(('tee', '-i', '-a', logfile),
+ returnpid=True, fd_pipes={0:pr, 1:fd_pipes[1], 2:fd_pipes[2]}))
+ os.close(pr)
+ fd_pipes[1] = pw
+ fd_pipes[2] = pw
+ keywords["fd_pipes"] = fd_pipes
+
features = mysettings.features
# XXX: Negative RESTRICT word
droppriv=(droppriv and ("userpriv" in features) and not \
@@ -2189,12 +2212,33 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, **keyw
con = con.replace(mysettings["PORTAGE_T"], mysettings["PORTAGE_SANDBOX_T"])
selinux.setexec(con)
- retval = spawn_func(mystring, env=env, **keywords)
-
- if sesandbox:
- selinux.setexec(None)
-
- return retval
+ returnpid = keywords.get("returnpid")
+ keywords["returnpid"] = True
+ try:
+ mypids.extend(spawn_func(mystring, env=env, **keywords))
+ finally:
+ if pw:
+ os.close(pw)
+ if sesandbox:
+ selinux.setexec(None)
+
+ if returnpid:
+ return mypids
+
+ while mypids:
+ pid = mypids.pop(0)
+ retval = os.waitpid(pid, 0)[1]
+ portage_exec.spawned_pids.remove(pid)
+ if retval != os.EX_OK:
+ for pid in mypids:
+ if os.waitpid(pid, os.WNOHANG) == (0,0):
+ os.kill(pid, signal.SIGTERM)
+ os.waitpid(pid, 0)
+ portage_exec.spawned_pids.remove(pid)
+ if retval & 0xff:
+ return (retval & 0xff) << 8
+ return retval >> 8
+ return os.EX_OK
def fetch(myuris, mysettings, listonly=0, fetchonly=0, locks_in_subdir=".locks",use_locks=1, try_mirrors=1):
"fetch files. Will use digest file if available."