For bug #162404, spawn tee outside the sesandbox domain so that it reads from a pipe...
authorZac Medico <zmedico@gentoo.org>
Wed, 17 Jan 2007 21:42:10 +0000 (21:42 -0000)
committerZac Medico <zmedico@gentoo.org>
Wed, 17 Jan 2007 21:42:10 +0000 (21:42 -0000)
svn path=/main/trunk/; revision=5690

pym/portage.py

index 9c5277feb9dbab4d98b6326f30f50bc343791cf6..6891a42ea258a89099b2ce04c294591df028ab3e 100644 (file)
@@ -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."