Esempio n. 1
0
    def __init__(self,
                 node,
                 argv,
                 executable=None,
                 stdin=None,
                 stdout=None,
                 stderr=None,
                 bufsize=0,
                 shell=False,
                 cwd=None,
                 env=None,
                 user=None):
        """As in Subprocess, `node' specifies the nemu Node to run in.

        The `stdin', `stdout', and `stderr' parameters also accept the special
        values subprocess.PIPE or subprocess.STDOUT. Check the stdlib's
        subprocess module for more details. `bufsize' specifies the buffer size
        for the buffered IO provided for PIPE'd descriptors.
        """

        self.stdin = self.stdout = self.stderr = None
        self._pid = self._returncode = None
        fdmap = {"stdin": stdin, "stdout": stdout, "stderr": stderr}
        # if PIPE: all should be closed at the end
        for k, v in fdmap.items():
            if v == None:
                continue
            if v == PIPE:
                r, w = os.pipe()
                if k == "stdin":
                    self.stdin = os.fdopen(w, 'wb', bufsize)
                    fdmap[k] = r
                else:
                    setattr(self, k, os.fdopen(r, 'rb', bufsize))
                    fdmap[k] = w
            elif isinstance(v, int):
                pass
            else:
                fdmap[k] = v.fileno()
        if stderr == STDOUT:
            fdmap['stderr'] = fdmap['stdout']

        super(Popen, self).__init__(node,
                                    argv,
                                    executable=executable,
                                    stdin=fdmap['stdin'],
                                    stdout=fdmap['stdout'],
                                    stderr=fdmap['stderr'],
                                    shell=shell,
                                    cwd=cwd,
                                    env=env,
                                    user=user)

        # Close pipes, they have been dup()ed to the child
        for k, v in fdmap.items():
            if getattr(self, k) != None:
                eintr_wrapper(os.close, v)
Esempio n. 2
0
    def __init__(self, node, argv, executable = None,
            stdin = None, stdout = None, stderr = None, bufsize = 0,
            shell = False, cwd = None, env = None, user = None):
        """As in Subprocess, `node' specifies the nemu Node to run in.

        The `stdin', `stdout', and `stderr' parameters also accept the special
        values subprocess.PIPE or subprocess.STDOUT. Check the stdlib's
        subprocess module for more details. `bufsize' specifies the buffer size
        for the buffered IO provided for PIPE'd descriptors.
        """

        self.stdin = self.stdout = self.stderr = None
        self._pid = self._returncode = None
        fdmap = { "stdin": stdin, "stdout": stdout, "stderr": stderr }
        # if PIPE: all should be closed at the end
        for k, v in fdmap.items():
            if v == None:
                continue
            if v == PIPE:
                r, w = os.pipe()
                if k == "stdin":
                    self.stdin = os.fdopen(w, 'wb', bufsize)
                    fdmap[k] = r
                else:
                    setattr(self, k, os.fdopen(r, 'rb', bufsize))
                    fdmap[k] = w
            elif isinstance(v, int):
                pass
            else:
                fdmap[k] = v.fileno()
        if stderr == STDOUT:
            fdmap['stderr'] = fdmap['stdout']

        super(Popen, self).__init__(node, argv, executable = executable,
                stdin = fdmap['stdin'], stdout = fdmap['stdout'],
                stderr = fdmap['stderr'],
                shell = shell, cwd = cwd, env = env, user = user)

        # Close pipes, they have been dup()ed to the child
        for k, v in fdmap.items():
            if getattr(self, k) != None:
                eintr_wrapper(os.close, v)
Esempio n. 3
0
def wait(pid):
    """Wait for process to die and return the exit code."""
    return eintr_wrapper(os.waitpid, pid, 0)[1]
Esempio n. 4
0
def spawn(executable,
          argv=None,
          cwd=None,
          env=None,
          close_fds=False,
          stdin=None,
          stdout=None,
          stderr=None,
          user=None):
    """Internal function that performs all the dirty work for Subprocess, Popen
    and friends. This is executed in the slave process, directly from the
    protocol.Server class.

    Parameters have the same meaning as the stdlib's subprocess.Popen class,
    with one addition: the `user` parameter, if not None, specifies a user name
    to run the command as, after setting its primary and secondary groups. If a
    numerical UID is given, a reverse lookup is performed to find the user name
    and then set correctly the groups.

    When close_fds is True, it closes all file descriptors bigger than 2.  It
    can also be an iterable of file descriptors to close after fork.

    Note that 'std{in,out,err}' must be None, integers, or file objects, PIPE
    is not supported here. Also, the original descriptors are not closed.
    """
    userfd = [stdin, stdout, stderr]
    filtered_userfd = filter(lambda x: x != None and x >= 0, userfd)
    for i in range(3):
        if userfd[i] != None and not isinstance(userfd[i], int):
            userfd[i] = userfd[i].fileno()  # pragma: no cover

    # Verify there is no clash
    assert not (set([0, 1, 2]) & set(filtered_userfd))

    if user != None:
        user, uid, gid = get_user(user)
        home = pwd.getpwuid(uid)[5]
        groups = [x[2] for x in grp.getgrall() if user in x[3]]
        if not env:
            env = dict(os.environ)
        env['HOME'] = home
        env['USER'] = user

    (r, w) = os.pipe()
    pid = os.fork()
    if pid == 0:  # pragma: no cover
        # coverage doesn't seem to understand fork
        try:
            # Set up stdio piping
            for i in range(3):
                if userfd[i] != None and userfd[i] >= 0:
                    os.dup2(userfd[i], i)
                    if userfd[i] != i and userfd[i] not in userfd[0:i]:
                        eintr_wrapper(os.close, userfd[i])  # only in child!

            # Set up special control pipe
            eintr_wrapper(os.close, r)
            flags = fcntl.fcntl(w, fcntl.F_GETFD)
            fcntl.fcntl(w, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)

            if close_fds == True:
                for i in xrange(3, MAXFD):
                    if i != w:
                        try:
                            os.close(i)
                        except:
                            pass
            elif close_fds != False:
                for i in close_fds:
                    os.close(i)

            # changing process group id
            # (it is necessary to kill the forked subprocesses)
            os.setpgrp()

            if user != None:
                # Change user
                os.setgid(gid)
                os.setgroups(groups)
                os.setuid(uid)
            if cwd != None:
                os.chdir(cwd)
            if not argv:
                argv = [executable]
            if '/' in executable:  # Should not search in PATH
                if env != None:
                    os.execve(executable, argv, env)
                else:
                    os.execv(executable, argv)
            else:  # use PATH
                if env != None:
                    os.execvpe(executable, argv, env)
                else:
                    os.execvp(executable, argv)
            raise RuntimeError("Unreachable reached!")
        except:
            try:
                (t, v, tb) = sys.exc_info()
                # Got the child_traceback attribute trick from Python's
                # subprocess.py
                v.child_traceback = "".join(
                    traceback.format_exception(t, v, tb))
                eintr_wrapper(os.write, w, pickle.dumps(v))
                eintr_wrapper(os.close, w)
                #traceback.print_exc()
            except:
                traceback.print_exc()
            os._exit(1)

    eintr_wrapper(os.close, w)

    # read EOF for success, or a string as error info
    s = ""
    while True:
        s1 = eintr_wrapper(os.read, r, 4096)
        if s1 == "":
            break
        s += s1
    eintr_wrapper(os.close, r)

    if s == "":
        return pid

    # It was an error
    eintr_wrapper(os.waitpid, pid, 0)
    exc = pickle.loads(s)
    # XXX: sys.excepthook
    #print exc.child_traceback
    raise exc
Esempio n. 5
0
def wait(pid):
    """Wait for process to die and return the exit code."""
    return eintr_wrapper(os.waitpid, pid, 0)[1]
Esempio n. 6
0
def spawn(executable, argv = None, cwd = None, env = None, close_fds = False,
        stdin = None, stdout = None, stderr = None, user = None):
    """Internal function that performs all the dirty work for Subprocess, Popen
    and friends. This is executed in the slave process, directly from the
    protocol.Server class.

    Parameters have the same meaning as the stdlib's subprocess.Popen class,
    with one addition: the `user` parameter, if not None, specifies a user name
    to run the command as, after setting its primary and secondary groups. If a
    numerical UID is given, a reverse lookup is performed to find the user name
    and then set correctly the groups.

    When close_fds is True, it closes all file descriptors bigger than 2.  It
    can also be an iterable of file descriptors to close after fork.

    Note that 'std{in,out,err}' must be None, integers, or file objects, PIPE
    is not supported here. Also, the original descriptors are not closed.
    """
    userfd = [stdin, stdout, stderr]
    filtered_userfd = filter(lambda x: x != None and x >= 0, userfd)
    for i in range(3):
        if userfd[i] != None and not isinstance(userfd[i], int):
            userfd[i] = userfd[i].fileno() # pragma: no cover

    # Verify there is no clash
    assert not (set([0, 1, 2]) & set(filtered_userfd))

    if user != None:
        user, uid, gid = get_user(user)
        home = pwd.getpwuid(uid)[5]
        groups = [x[2] for x in grp.getgrall() if user in x[3]]
        if not env:
            env = dict(os.environ)
        env['HOME'] = home
        env['USER'] = user

    (r, w) = os.pipe()
    pid = os.fork()
    if pid == 0: # pragma: no cover
        # coverage doesn't seem to understand fork
        try:
            # Set up stdio piping
            for i in range(3):
                if userfd[i] != None and userfd[i] >= 0:
                    os.dup2(userfd[i], i)
                    if userfd[i] != i and userfd[i] not in userfd[0:i]:
                        eintr_wrapper(os.close, userfd[i]) # only in child!

            # Set up special control pipe
            eintr_wrapper(os.close, r)
            flags = fcntl.fcntl(w, fcntl.F_GETFD)
            fcntl.fcntl(w, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)

            if close_fds == True:
                for i in xrange(3, MAXFD):
                    if i != w:
                        try:
                            os.close(i)
                        except:
                            pass
            elif close_fds != False:
                for i in close_fds:
                    os.close(i)

            # changing process group id
            # (it is necessary to kill the forked subprocesses)
            os.setpgrp()

            if user != None:
                # Change user
                os.setgid(gid)
                os.setgroups(groups)
                os.setuid(uid)
            if cwd != None:
                os.chdir(cwd)
            if not argv:
                argv = [ executable ]
            if '/' in executable: # Should not search in PATH
                if env != None:
                    os.execve(executable, argv, env)
                else:
                    os.execv(executable, argv)
            else: # use PATH
                if env != None:
                    os.execvpe(executable, argv, env)
                else:
                    os.execvp(executable, argv)
            raise RuntimeError("Unreachable reached!")
        except:
            try:
                (t, v, tb) = sys.exc_info()
                # Got the child_traceback attribute trick from Python's
                # subprocess.py
                v.child_traceback = "".join(
                        traceback.format_exception(t, v, tb))
                eintr_wrapper(os.write, w, pickle.dumps(v))
                eintr_wrapper(os.close, w)
                #traceback.print_exc()
            except:
                traceback.print_exc()
            os._exit(1)

    eintr_wrapper(os.close, w)

    # read EOF for success, or a string as error info
    s = ""
    while True:
        s1 = eintr_wrapper(os.read, r, 4096)
        if s1 == "":
            break
        s += s1
    eintr_wrapper(os.close, r)

    if s == "":
        return pid

    # It was an error
    eintr_wrapper(os.waitpid, pid, 0)
    exc = pickle.loads(s)
    # XXX: sys.excepthook
    #print exc.child_traceback
    raise exc