summaryrefslogtreecommitdiffstats
path: root/py/mock
diff options
context:
space:
mode:
authorMichael E Brown <michael_e_brown@dell.com>2008-01-22 12:32:25 -0600
committerMichael E Brown <michael_e_brown@dell.com>2008-01-22 12:32:25 -0600
commitbeed7f3a868c22a9c75064888c0e3f70dc3b523b (patch)
treea1c1b035ac68303ce8bd5c8c5780b89441aa1f92 /py/mock
parent041b8dac4983ae69dd5f0edbc9522dce662fb798 (diff)
parent78d6a209b8dfe438880e4d62a58693e33693560b (diff)
downloadmock-beed7f3a868c22a9c75064888c0e3f70dc3b523b.tar.gz
mock-beed7f3a868c22a9c75064888c0e3f70dc3b523b.tar.xz
mock-beed7f3a868c22a9c75064888c0e3f70dc3b523b.zip
Merge branch 'master' of /var/ftp/pub/Applications/git/mock
* 'master' of /var/ftp/pub/Applications/git/mock: get rid of one level of shell indirection where possible. revert accidental comment-out of test cleanup that I was using to debug tar problem. add back in dropped '.' to tar cvf command that is causing root cache creation to fail. Add debug logging for running commands. convert mock.util.do() to use subprocess.Popen() rather than raw fork/exec.\nThis cleans up the code considerably. Also, start reducing the places where we use a shell in the subcommand. better unit test error message. mount everything when running chroot command. updated change log added compat symlinks version bump update manpage with new site-defaults ref. the great config file rename. some manpage clarifications and arrangements. clarify info message to make it obvious that root cache is being unpacked. cleanup trailing whitespace. cleanup trailing whitespace. add ability to conditionally enable tmpfs based on minimum ram availability. add initfailed hook so tmpfs plugin can properly unmount tmpfs on failure. make sure we call postbuild hooks even on failure.
Diffstat (limited to 'py/mock')
-rw-r--r--py/mock/backend.py54
-rw-r--r--py/mock/exception.py4
-rw-r--r--py/mock/plugins/ccache.py2
-rw-r--r--py/mock/plugins/root_cache.py12
-rw-r--r--py/mock/plugins/tmpfs.py24
-rw-r--r--py/mock/plugins/yum_cache.py2
-rwxr-xr-xpy/mock/trace_decorator.py8
-rw-r--r--py/mock/util.py249
8 files changed, 189 insertions, 166 deletions
diff --git a/py/mock/backend.py b/py/mock/backend.py
index 9f08c49..7d11532 100644
--- a/py/mock/backend.py
+++ b/py/mock/backend.py
@@ -147,6 +147,14 @@ class Root(object):
decorate(traceLog())
def init(self):
+ try:
+ self._init()
+ except (KeyboardInterrupt, Exception):
+ self._callHooks('initfailed')
+ raise
+
+ decorate(traceLog())
+ def _init(self):
self.state("init")
# NOTE: removed the following stuff vs mock v0:
@@ -276,8 +284,9 @@ class Root(object):
os.mknod( self.makeChrootPath(i[2]), i[0], i[1])
# set context. (only necessary if host running selinux enabled.)
# fails gracefully if chcon not installed.
- mock.util.do("chcon --reference=/%s %s" %
- (i[2], self.makeChrootPath(i[2])), raiseExc=0)
+ mock.util.do(
+ ["chcon", "--reference=/%s"% i[2], self.makeChrootPath(i[2])]
+ , raiseExc=0, shell=False)
os.symlink("/proc/self/fd/0", self.makeChrootPath("dev/stdin"))
os.symlink("/proc/self/fd/1", self.makeChrootPath("dev/stdout"))
@@ -296,9 +305,10 @@ class Root(object):
# bad hack
# comment out decorator here so we dont get double exceptions in the root log
#decorate(traceLog())
- def doChroot(self, command, env="", *args, **kargs):
+ def doChroot(self, command, env="", shell=True, *args, **kargs):
"""execute given command in root"""
- return mock.util.do( command, chrootPath=self.makeChrootPath(), *args, **kargs )
+ return mock.util.do(command, chrootPath=self.makeChrootPath(),
+ shell=shell, *args, **kargs )
decorate(traceLog())
def yumInstall(self, *srpms):
@@ -369,8 +379,8 @@ class Root(object):
os.environ["HOME"] = self.homedir
# Completely/Permanently drop privs while running the following:
self.doChroot(
- "rpm -Uvh --nodeps %s" % (srpmChrootFilename,),
- uidManager=self.uidManager,
+ ["rpm", "-Uvh", "--nodeps", srpmChrootFilename],
+ shell=False,
uid=self.chrootuid,
gid=self.chrootgid,
)
@@ -384,9 +394,9 @@ class Root(object):
chrootspec = spec.replace(self.makeChrootPath(), '') # get rid of rootdir prefix
# Completely/Permanently drop privs while running the following:
self.doChroot(
- "bash --login -c 'rpmbuild -bs --target %s --nodeps %s'" % (self.rpmbuild_arch, chrootspec),
+ ["bash", "--login", "-c", 'rpmbuild -bs --target %s --nodeps %s' % (self.rpmbuild_arch, chrootspec)],
+ shell=False,
logger=self.build_log, timeout=timeout,
- uidManager=self.uidManager,
uid=self.chrootuid,
gid=self.chrootgid,
)
@@ -405,9 +415,9 @@ class Root(object):
self._callHooks('prebuild')
self.doChroot(
- "bash --login -c 'rpmbuild -bb --target %s --nodeps %s'" % (self.rpmbuild_arch, chrootspec),
+ ["bash", "--login", "-c", 'rpmbuild -bb --target %s --nodeps %s' % (self.rpmbuild_arch, chrootspec)],
+ shell=False,
logger=self.build_log, timeout=timeout,
- uidManager=self.uidManager,
uid=self.chrootuid,
gid=self.chrootgid,
)
@@ -425,8 +435,8 @@ class Root(object):
self.uidManager.restorePrivs()
self._umountall()
- # tell caching we are done building
- self._callHooks('postbuild')
+ # tell caching we are done building
+ self._callHooks('postbuild')
# =============
# 'Private' API
@@ -459,14 +469,14 @@ class Root(object):
"""mount 'normal' fs like /dev/ /proc/ /sys"""
for cmd in self.mountCmds:
self.root_log.debug(cmd)
- mock.util.do(cmd)
+ mock.util.do(cmd, shell=True)
decorate(traceLog())
def _umountall(self):
"""umount all mounted chroot fs."""
for cmd in self.umountCmds:
self.root_log.debug(cmd)
- mock.util.do(cmd, raiseExc=0)
+ mock.util.do(cmd, raiseExc=0, shell=True)
decorate(traceLog())
def _yum(self, cmd, returnOutput=0):
@@ -481,7 +491,7 @@ class Root(object):
output = ""
try:
self._callHooks("preyum")
- output = mock.util.do(cmd, returnOutput=returnOutput)
+ output = mock.util.do(cmd, returnOutput=returnOutput, shell=True)
self._callHooks("postyum")
return output
except mock.exception.Error, e:
@@ -494,14 +504,16 @@ class Root(object):
# safe and easy. blow away existing /builddir and completely re-create.
mock.util.rmtree(self.makeChrootPath(self.homedir))
- dets = { 'uid': self.chrootuid, 'gid': self.chrootgid, 'user': self.chrootuser, 'group': self.chrootgroup, 'home': self.homedir }
+ dets = { 'uid': str(self.chrootuid), 'gid': str(self.chrootgid), 'user': self.chrootuser, 'group': self.chrootgroup, 'home': self.homedir }
- self.doChroot('/usr/sbin/userdel -r %(user)s' % dets, raiseExc=False)
- self.doChroot('/usr/sbin/groupdel %(group)s' % dets, raiseExc=False)
+ self.doChroot(['/usr/sbin/userdel', '-r', dets['user']], shell=False, raiseExc=False)
+ self.doChroot(['/usr/sbin/groupdel', dets['group']], shell=False, raiseExc=False)
- self.doChroot('/usr/sbin/groupadd -g %(gid)s %(group)s' % dets)
- self.doChroot(self.useradd % dets)
- self.doChroot("perl -p -i -e 's/^(%s:)!!/$1/;' /etc/passwd" % (self.chrootuser), raiseExc=True)
+ self.doChroot(['/usr/sbin/groupadd', '-g', dets['gid'], dets['group']], shell=False)
+ self.doChroot(self.useradd % dets, shell=True)
+ self.doChroot(
+ ["perl", "-p", "-i", "-e", 's/^(%s:)!!/$1/;' % self.chrootuser, "/etc/passwd"],
+ shell=False, raiseExc=True)
decorate(traceLog())
def _resetLogging(self):
diff --git a/py/mock/exception.py b/py/mock/exception.py
index b6d6282..d02bddb 100644
--- a/py/mock/exception.py
+++ b/py/mock/exception.py
@@ -19,8 +19,8 @@ class Error(Exception):
Exception.__init__(self)
self.msg = msg
self.resultcode = 1
- if status is not None and os.WIFEXITED(status):
- self.resultcode = os.WEXITSTATUS(status)
+ if status is not None:
+ self.resultcode = status
def __str__(self):
return self.msg
diff --git a/py/mock/plugins/ccache.py b/py/mock/plugins/ccache.py
index b5f3c35..04768f2 100644
--- a/py/mock/plugins/ccache.py
+++ b/py/mock/plugins/ccache.py
@@ -39,7 +39,7 @@ class CCache(object):
# ccache itself manages size and settings.
decorate(traceLog())
def _ccacheBuildHook(self):
- self.rootObj.doChroot("ccache -M %s" % self.ccache_opts['max_cache_size'])
+ self.rootObj.doChroot(["ccache", "-M", str(self.ccache_opts['max_cache_size'])], shell=False)
# basic idea here is that we add 'cc', 'gcc', 'g++' shell scripts to
# to /tmp/ccache, which is bind-mounted from a shared location.
diff --git a/py/mock/plugins/root_cache.py b/py/mock/plugins/root_cache.py
index 6e9c60e..9cb0a13 100644
--- a/py/mock/plugins/root_cache.py
+++ b/py/mock/plugins/root_cache.py
@@ -72,9 +72,12 @@ class RootCache(object):
# optimization: dont unpack root cache if chroot was not cleaned
if os.path.exists(self.rootCacheFile) and self.rootObj.chrootWasCleaned:
- self.state("unpacking cache")
+ self.state("unpacking root cache")
self._rootCacheLock()
- mock.util.do("tar xzf %s -C %s" % (self.rootCacheFile, self.rootObj.makeChrootPath()))
+ mock.util.do(
+ ["tar", "xzf", self.rootCacheFile, "-C", self.rootObj.makeChrootPath()],
+ shell=False
+ )
self._rootCacheUnlock()
self.chroot_setup_cmd = "update"
self.rootObj.chrootWasCleaned = False
@@ -85,6 +88,9 @@ class RootCache(object):
if self.rootObj.chrootWasCleaned:
self.state("creating cache")
self._rootCacheLock(shared=0)
- mock.util.do("tar czf %s -C %s ." % (self.rootCacheFile, self.rootObj.makeChrootPath()))
+ mock.util.do(
+ ["tar", "czf", self.rootCacheFile, "-C", self.rootObj.makeChrootPath(), "."],
+ shell=False
+ )
self._rootCacheUnlock()
diff --git a/py/mock/plugins/tmpfs.py b/py/mock/plugins/tmpfs.py
index b725fb9..cf89bc1 100644
--- a/py/mock/plugins/tmpfs.py
+++ b/py/mock/plugins/tmpfs.py
@@ -15,7 +15,16 @@ requires_api_version = "1.0"
# plugin entry point
decorate(traceLog())
def init(rootObj, conf):
- Tmpfs(rootObj, conf)
+ system_ram_bytes = os.sysconf(os.sysconf_names['SC_PAGE_SIZE']) * os.sysconf(os.sysconf_names['SC_PHYS_PAGES'])
+ system_ram_mb = system_ram_bytes / (1024 * 1024)
+ if system_ram_mb > conf['required_ram_mb']:
+ Tmpfs(rootObj, conf)
+ else:
+ getLog().warning("Tmpfs plugin disabled. "
+ "System does not have the required amount of RAM to enable the tmpfs plugin. "
+ "System has %sMB RAM, but the config specifies the minimum required is %sMB RAM. "
+ %
+ (system_ram_mb, conf['required_ram_mb']))
# classes
class Tmpfs(object):
@@ -26,16 +35,19 @@ class Tmpfs(object):
self.conf = conf
rootObj.addHook("preinit", self._tmpfsPreInitHook)
rootObj.addHook("postbuild", self._tmpfsPostBuildHook)
+ rootObj.addHook("initfailed", self._tmpfsPostBuildHook)
decorate(traceLog())
def _tmpfsPreInitHook(self):
getLog().info("mounting tmpfs.")
- mountCmd = "mount -n -t tmpfs mock_chroot_tmpfs %s" % self.rootObj.makeChrootPath()
- mock.util.do(mountCmd)
+ mountCmd = ["mount", "-n", "-t", "tmpfs", "mock_chroot_tmpfs",
+ self.rootObj.makeChrootPath()]
+ mock.util.do(mountCmd, shell=False)
+ decorate(traceLog())
def _tmpfsPostBuildHook(self):
getLog().info("unmounting tmpfs.")
- mountCmd = "umount -n %s" % self.rootObj.makeChrootPath()
- mock.util.do(mountCmd)
-
+ mountCmd = ["umount", "-n", self.rootObj.makeChrootPath()]
+ mock.util.do(mountCmd, shell=False)
+
diff --git a/py/mock/plugins/yum_cache.py b/py/mock/plugins/yum_cache.py
index bcdf465..2e12b3f 100644
--- a/py/mock/plugins/yum_cache.py
+++ b/py/mock/plugins/yum_cache.py
@@ -83,7 +83,7 @@ class YumCache(object):
os.unlink(fullPath)
fullPath = None
break
-
+
if fullPath is None: continue
if file_age_days > self.yum_cache_opts['max_age_days']:
os.unlink(fullPath)
diff --git a/py/mock/trace_decorator.py b/py/mock/trace_decorator.py
index 05c340c..837afd7 100755
--- a/py/mock/trace_decorator.py
+++ b/py/mock/trace_decorator.py
@@ -18,7 +18,7 @@ class getLog(object):
if name is None:
frame = sys._getframe(1)
name = frame.f_globals["__name__"]
-
+
self.name = prefix + name
def __getattr__(self, name):
@@ -44,11 +44,11 @@ def traceLog(log = None):
# can override by passing logger=foo as function parameter.
# make sure this doesnt conflict with one of the parameters
# you are expecting
-
+
filename = os.path.normcase(func.func_code.co_filename)
func_name = func.func_code.co_name
lineno = func.func_code.co_firstlineno
-
+
l2 = kw.get('logger', log)
if l2 is None:
l2 = logging.getLogger("trace.%s" % func.__module__)
@@ -61,7 +61,7 @@ def traceLog(log = None):
for k,v in kw.items():
message = message + "%s=%s" % (k,repr(v))
message = message + ")"
-
+
frame = sys._getframe(2)
doLog(l2, logging.INFO, os.path.normcase(frame.f_code.co_filename), frame.f_lineno, message, args=[], exc_info=None, func=frame.f_code.co_name)
try:
diff --git a/py/mock/util.py b/py/mock/util.py
index 8f3d221..f93f98b 100644
--- a/py/mock/util.py
+++ b/py/mock/util.py
@@ -6,19 +6,41 @@
# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net>
# python library imports
+import ctypes
import os
import os.path
import popen2
import rpm
import rpmUtils
import rpmUtils.transaction
+import select
import shutil
import signal
+import subprocess
import time
# our imports
import mock.exception
from mock.trace_decorator import traceLog, decorate, getLog
+import mock.uid as uid
+
+_libc = ctypes.cdll.LoadLibrary(None)
+_errno = ctypes.c_int.in_dll(_libc, "errno")
+_libc.personality.argtypes = [ctypes.c_ulong]
+_libc.personality.restype = ctypes.c_int
+_libc.unshare.argtypes = [ctypes.c_int,]
+_libc.unshare.restype = ctypes.c_int
+CLONE_NEWNS = 0x00020000
+
+# taken from sys/personality.h
+PER_LINUX32=0x0008
+PER_LINUX=0x0000
+personality_defs = {
+ 'x86_64': PER_LINUX, 'ppc64': PER_LINUX, 'sparc64': PER_LINUX,
+ 'i386': PER_LINUX32, 'i586': PER_LINUX32, 'i686': PER_LINUX32,
+ 'ppc': PER_LINUX32, 'sparc': PER_LINUX32, 'sparcv9': PER_LINUX32,
+ 'ia64' : PER_LINUX, 'alpha' : PER_LINUX,
+}
# classes
class commandTimeoutExpired(mock.exception.Error):
@@ -153,29 +175,6 @@ def uniqReqs(*args):
master.extend(l)
return rpmUtils.miscutils.unique(master)
-decorate(traceLog())
-def condChroot(chrootPath, uidManager=None):
- if chrootPath is not None:
- getLog().debug("chroot %s" % chrootPath)
- if uidManager:
- getLog().debug("elevate privs to run chroot")
- uidManager.becomeUser(0)
- os.chdir(chrootPath)
- os.chroot(chrootPath)
- if uidManager:
- getLog().debug("back to other privs")
- uidManager.restorePrivs()
-
-decorate(traceLog())
-def condDropPrivs(uidManager, uid, gid):
- if uidManager is not None:
- getLog().debug("about to drop privs")
- if uid is not None:
- uidManager.unprivUid = uid
- if gid is not None:
- uidManager.unprivGid = gid
- uidManager.dropPrivsForever()
-
# not traced...
def chomp(line):
if line.endswith("\n"):
@@ -183,131 +182,125 @@ def chomp(line):
else:
return line
-# taken from sys/personality.h
-PER_LINUX32=0x0008
-PER_LINUX=0x0000
-personality_defs = {
- 'x86_64': PER_LINUX, 'ppc64': PER_LINUX, 'sparc64': PER_LINUX,
- 'i386': PER_LINUX32, 'i586': PER_LINUX32, 'i686': PER_LINUX32,
- 'ppc': PER_LINUX32, 'sparc': PER_LINUX32, 'sparcv9': PER_LINUX32,
- 'ia64' : PER_LINUX, 'alpha' : PER_LINUX,
-}
+decorate(traceLog())
+def unshare(flags):
+ getLog().debug("Unsharing. Flags: %s" % flags)
+ try:
+ res = _libc.unshare(flags)
+ if res:
+ raise OSError(_errno.value, os.strerror(_errno.value))
+ except AttributeError, e:
+ pass
-import ctypes
-_libc = ctypes.cdll.LoadLibrary(None)
-_errno = ctypes.c_int.in_dll(_libc, "errno")
-_libc.personality.argtypes = [ctypes.c_ulong]
-_libc.personality.restype = ctypes.c_int
+# these are called in child process, so no logging
+def condChroot(chrootPath):
+ if chrootPath is not None:
+ saved = { "ruid": os.getuid(), "euid": os.geteuid(), }
+ uid.setresuid(0,0,0)
+ os.chdir(chrootPath)
+ os.chroot(chrootPath)
+ uid.setresuid(saved['ruid'], saved['euid'])
+
+def condDropPrivs(uid, gid):
+ if gid is not None:
+ os.setregid(gid, gid)
+ if uid is not None:
+ os.setreuid(uid, uid)
-decorate(traceLog())
def condPersonality(per=None):
if per is None or per in ('noarch',):
return
if personality_defs.get(per, None) is None:
- getLog().warning("Unable to find predefined setarch personality constant for '%s' arch."
- " You may have to manually run setarch."% per)
return
res = _libc.personality(personality_defs[per])
if res == -1:
raise OSError(_errno.value, os.strerror(_errno.value))
- getLog().debug("Ran setarch '%s'" % per)
-CLONE_NEWNS = 0x00020000
-decorate(traceLog())
-def unshare(flags):
- getLog().debug("Unsharing. Flags: %s" % flags)
- try:
- _libc.unshare.argtypes = [ctypes.c_int,]
- _libc.unshare.restype = ctypes.c_int
- res = _libc.unshare(flags)
- if res:
- raise OSError(_errno.value, os.strerror(_errno.value))
- except AttributeError, e:
- pass
+def logOutput(fds, logger, returnOutput=1, start=0, timeout=0):
+ output=""
+ done = 0
+ while not done:
+ if (time.time() - start)>timeout and timeout!=0:
+ done = 1
+ break
+
+ i_rdy,o_rdy,e_rdy = select.select(fds,[],[],1)
+ for s in i_rdy:
+ # this isnt perfect as a whole line of input may not be
+ # ready, but should be "good enough" for now
+ line = s.readline()
+ if line == "":
+ done = 1
+ break
+ logger.debug(chomp(line))
+ if returnOutput:
+ output += line
+ return output
# logger =
# output = [1|0]
# chrootPath
#
-# Warning: this is the function from hell. :(
+# The "Not-as-complicated" version
#
decorate(traceLog())
-def do(command, chrootPath=None, timeout=0, raiseExc=True, returnOutput=0, uidManager=None, uid=None, gid=None, personality=None, *args, **kargs):
- """execute given command outside of chroot"""
+def do(command, shell=False, chrootPath=None, timeout=0, raiseExc=True, returnOutput=0, uid=None, gid=None, personality=None, *args, **kargs):
logger = kargs.get("logger", getLog())
- logger.debug("run cmd timeout(%s): %s" % (timeout, command))
-
- def alarmhandler(signum, stackframe):
- raise commandTimeoutExpired("Timeout(%s) exceeded for command: %s" % (timeout, command))
-
- retval = 0
-
output = ""
- (r, w) = os.pipe()
- pid = os.fork()
- if pid: #parent
- rpid = ret = 0
- os.close(w)
- oldhandler = signal.signal(signal.SIGALRM, alarmhandler)
- # timeout=0 means disable alarm signal. no timeout
- signal.alarm(timeout)
-
- try:
- # read output from child
- r_fh = os.fdopen(r, "r")
- for line in r_fh:
- logger.debug(chomp(line))
-
- if returnOutput:
- output += line
-
- # close read handle, get child return status, etc
- r_fh.close()
- (rpid, ret) = os.waitpid(pid, 0)
- signal.alarm(0)
- signal.signal(signal.SIGALRM, oldhandler)
-
- # kill children for any exception...
- finally:
- try:
- os.kill(-pid, signal.SIGTERM)
- time.sleep(1)
- os.kill(-pid, signal.SIGKILL)
- except OSError:
- pass
- signal.signal(signal.SIGALRM, oldhandler)
-
- # mask and return just return value, plus child output
- if raiseExc and ((os.WIFEXITED(ret) and os.WEXITSTATUS(ret)) or os.WIFSIGNALED(ret)):
- if returnOutput:
- raise mock.exception.Error, ("Command failed: \n # %s\n%s" % (command, output), ret)
- else:
- raise mock.exception.Error, ("Command failed. See logs for output.\n # %s" % (command,), ret)
-
- return output
+ start = time.time()
+ preexec = ChildPreExec(personality, chrootPath, uid, gid)
+ try:
+ child = None
+ logger.debug("Executing command: %s" % command)
+ child = subprocess.Popen(
+ command,
+ shell=shell,
+ bufsize=0, close_fds=True,
+ stdin=open("/dev/null", "r"),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ preexec_fn = preexec,
+ )
+
+ # use select() to poll for output so we dont block
+ output = logOutput([child.stdout, child.stderr],
+ logger, returnOutput, start, timeout)
+
+ except:
+ # kill children if they arent done
+ if child is not None and child.returncode is None:
+ os.kill(-child.pid, 15)
+ os.kill(-child.pid, 9)
+ raise
+
+ # wait until child is done, kill it if it passes timeout
+ while child.poll() is None:
+ if (time.time() - start)>timeout and timeout!=0:
+ os.kill(-child.pid, 15)
+ os.kill(-child.pid, 9)
+ raise commandTimeoutExpired, ("Timeout(%s) expired for command:\n # %s\n%s" % (command, output))
+
+
+ if raiseExc and child.returncode:
+ if returnOutput:
+ raise mock.exception.Error, ("Command failed: \n # %s\n%s" % (command, output), child.returncode)
+ else:
+ raise mock.exception.Error, ("Command failed. See logs for output.\n # %s" % (command,), child.returncode)
+
+ return output
+
+class ChildPreExec(object):
+ def __init__(self, personality, chrootPath, uid, gid):
+ self.personality = personality
+ self.chrootPath = chrootPath
+ self.uid = uid
+ self.gid = gid
+
+ def __call__(self, *args, **kargs):
+ os.setpgrp()
+ condPersonality(self.personality)
+ condChroot(self.chrootPath)
+ condDropPrivs(self.uid, self.gid)
- else: #child
- retval = 255
- try:
- os.close(r)
- # become process group leader so that our parent
- # can kill our children
- os.setpgrp()
-
- condPersonality(personality)
- condChroot(chrootPath, uidManager)
- condDropPrivs(uidManager, uid, gid)
-
- child = popen2.Popen4(command)
- child.tochild.close()
-
- w = os.fdopen(w, "w")
- for line in child.fromchild:
- w.write(line)
- w.flush()
- w.close()
- retval = child.wait()
- finally:
- os._exit(os.WEXITSTATUS(retval))