Esempio n. 1
0
 def __init__(self, args, stdin=None, stdout=None):
     self.returncode = None
     self.stdout = None
     self.stdin = None
     # TODO: stderr
     file_actions = posix_spawn.FileActions()
     if stdout is not None:
         # child's stdout, child 2 parent pipe
         c2pread, c2pwrite = os.pipe()
         # attach child's stdout to writing en of c2p pipe
         file_actions.add_dup2(c2pwrite, 1)
         # close other end
         file_actions.add_close(c2pread)
     if stdin is not None:
         # child's stdin, parent to child pipe
         p2cread, p2cwrite = os.pipe()
         # attach child's stdin to reading en of p2c pipe
         file_actions.add_dup2(p2cread, 0)
         # close other end
         file_actions.add_close(p2cwrite)
     self.pid = posix_spawn.posix_spawnp(args[0],
                                         args,
                                         file_actions=file_actions)
     if stdout is not None:
         self.stdout = os.fdopen(c2pread)
         os.close(c2pwrite)
     if stdin is not None:
         self.stdin = os.fdopen(p2cwrite, 'w')
         os.close(p2cread)
Esempio n. 2
0
def call(*args):
    cmd = []
    if isinstance(args[0], str):
        if len(args) == 1:
            # oversimplified splitting of arguments,
            # TODO: care about use of simple and double quotes
            cmd = args[0].split()
        else:
            cmd = args
    elif isinstance(args[0], list) and len(args) == 1:
        cmd = args[0]
    else:
        raise Exception("Wrong arguments passed to subprocess.call")
    pid = posix_spawn.posix_spawnp(cmd[0], cmd)
    return os.waitpid(pid, 0)
Esempio n. 3
0
    def __execute_child(self, args, executable, preexec_fn, close_fds, cwd,
                        env, universal_newlines, startupinfo, creationflags,
                        shell, p2cread, p2cwrite, c2pread, c2pwrite, errread,
                        errwrite):
        """
        Executes the program using posix_spawn().

        This is based on the method from the superclass but the
        posix_spawn API forces a number of changes.  In particular:

        * When using fork() FDs are manipulated in the child process
          after the fork, but before the program is exec()ed.  With
          posix_spawn() this is done by passing a data-structure to
          the posix_spawn() call, which describes the FD manipulations
          to perform.

        * The fork() version waits until after the fork before
          unsetting the non-blocking flag on the FDs that the child
          has inherited.  In the posix_spawn() version, we cannot
          do that after the fork so we dup the FDs in advance and
          unset the flag on the duped FD, which we then pass to the
          child.
        """

        if preexec_fn is not None:
            raise NotImplementedError("preexec_fn not supported")
        if close_fds:
            raise NotImplementedError("close_fds not implemented")
        if cwd:
            raise NotImplementedError(
                "cwd not implemented")  # pragma: no cover
        if universal_newlines:
            raise NotImplementedError()  # pragma: no cover
        assert startupinfo is None and creationflags == 0

        _log.debug("Pipes: p2c %s, %s; c2p %s, %s; err %s, %s", p2cread,
                   p2cwrite, c2pread, c2pwrite, errread, errwrite)

        if isinstance(args, types.StringTypes):
            args = [args]
        else:
            args = [a.encode("ascii") for a in args]

        if shell:
            args = ["/bin/sh", "-c"] + args
            if executable:
                args[0] = executable

        if executable is None:
            executable = args[0]

        self._loop.install_sigchld()

        # The FileActions object is an ordered list of FD operations for
        # posix_spawn to do in the child process before it execs the new
        # program.
        file_actions = FileActions()

        # In the child, close parent's pipe ends.
        if p2cwrite is not None:
            file_actions.add_close(p2cwrite)
        if c2pread is not None:
            file_actions.add_close(c2pread)
        if errread is not None:
            file_actions.add_close(errread)

        # When duping fds, if there arises a situation where one of the fds
        # is either 0, 1 or 2, it is possible that it is overwritten (#12607).
        fds_to_close_in_parent = []
        if c2pwrite == 0:
            c2pwrite = os.dup(c2pwrite)
            fds_to_close_in_parent.append(c2pwrite)
        if errwrite == 0 or errwrite == 1:
            errwrite = os.dup(errwrite)
            fds_to_close_in_parent.append(errwrite)

        # Dup stdin/out/err FDs in child.
        def _dup2(dup_from, dup_to):
            if dup_from is None:
                # Pass through the existing FD.
                dup_from = dup_to
            # Need to take a dup so we can remove the non-blocking flag
            a_dup = os.dup(dup_from)
            _log.debug("Duped %s as %s", dup_from, a_dup)
            fds_to_close_in_parent.append(a_dup)
            self._remove_nonblock_flag(a_dup)
            file_actions.add_dup2(a_dup, dup_to)

        _dup2(p2cread, 0)
        _dup2(c2pwrite, 1)
        _dup2(errwrite, 2)

        # Close pipe fds in the child.  Make sure we don't close the same fd
        # more than once, or standard fds.
        for fd in set([p2cread, c2pwrite, errwrite]):
            if fd > 2:
                file_actions.add_close(fd)

        gc_was_enabled = gc.isenabled()
        # FIXME Does this bug apply to posix_spawn version?
        try:
            # Disable gc to avoid bug where gc -> file_dealloc ->
            # write to stderr -> hang.  http://bugs.python.org/issue1336
            gc.disable()
            self.pid = posix_spawnp(
                executable,
                args,
                file_actions=file_actions,
                env=env,
            )
        except:
            if gc_was_enabled:
                gc.enable()
            raise
        finally:
            for fd in fds_to_close_in_parent:
                os.close(fd)

        # Capture the SIGCHILD.
        self._watcher = self._loop.child(self.pid)
        self._watcher.start(self._on_child, self._watcher)

        if gc_was_enabled:
            gc.enable()

        # Close the Child's pipe ends in the parent.
        if p2cread is not None and p2cwrite is not None:
            os.close(p2cread)
        if c2pwrite is not None and c2pread is not None:
            os.close(c2pwrite)
        if errwrite is not None and errread is not None:
            os.close(errwrite)
Esempio n. 4
0
    def __execute_child(self, args, executable, preexec_fn, close_fds,
                        cwd, env, universal_newlines,
                        startupinfo, creationflags, shell,
                        p2cread, p2cwrite,
                        c2pread, c2pwrite,
                        errread, errwrite):
        """
        Executes the program using posix_spawn().

        This is based on the method from the superclass but the
        posix_spawn API forces a number of changes.  In particular:

        * When using fork() FDs are manipulated in the child process
          after the fork, but before the program is exec()ed.  With
          posix_spawn() this is done by passing a data-structure to
          the posix_spawn() call, which describes the FD manipulations
          to perform.

        * The fork() version waits until after the fork before
          unsetting the non-blocking flag on the FDs that the child
          has inherited.  In the posix_spawn() version, we cannot
          do that after the fork so we dup the FDs in advance and
          unset the flag on the duped FD, which we then pass to the
          child.
        """

        if preexec_fn is not None:
            raise NotImplementedError("preexec_fn not supported")
        if close_fds:
            raise NotImplementedError("close_fds not implemented")
        if cwd:
            raise NotImplementedError("cwd not implemented")  # pragma: no cover
        if universal_newlines:
            raise NotImplementedError()  # pragma: no cover
        assert startupinfo is None and creationflags == 0

        _log.debug("Pipes: p2c %s, %s; c2p %s, %s; err %s, %s",
                   p2cread, p2cwrite,
                   c2pread, c2pwrite,
                   errread, errwrite)

        if isinstance(args, types.StringTypes):
            args = [args]
        else:
            args = [a.encode("ascii") for a in args]

        if shell:
            args = ["/bin/sh", "-c"] + args
            if executable:
                args[0] = executable

        if executable is None:
            executable = args[0]

        self._loop.install_sigchld()

        # The FileActions object is an ordered list of FD operations for
        # posix_spawn to do in the child process before it execs the new
        # program.
        file_actions = FileActions()

        # In the child, close parent's pipe ends.
        if p2cwrite is not None:
            file_actions.add_close(p2cwrite)
        if c2pread is not None:
            file_actions.add_close(c2pread)
        if errread is not None:
            file_actions.add_close(errread)

        # When duping fds, if there arises a situation where one of the fds
        # is either 0, 1 or 2, it is possible that it is overwritten (#12607).
        fds_to_close_in_parent = []
        if c2pwrite == 0:
            c2pwrite = os.dup(c2pwrite)
            fds_to_close_in_parent.append(c2pwrite)
        if errwrite == 0 or errwrite == 1:
            errwrite = os.dup(errwrite)
            fds_to_close_in_parent.append(errwrite)

        # Dup stdin/out/err FDs in child.
        def _dup2(dup_from, dup_to):
            if dup_from is None:
                # Pass through the existing FD.
                dup_from = dup_to
            # Need to take a dup so we can remove the non-blocking flag
            a_dup = os.dup(dup_from)
            _log.debug("Duped %s as %s", dup_from, a_dup)
            fds_to_close_in_parent.append(a_dup)
            self._remove_nonblock_flag(a_dup)
            file_actions.add_dup2(a_dup, dup_to)
        _dup2(p2cread, 0)
        _dup2(c2pwrite, 1)
        _dup2(errwrite, 2)

        # Close pipe fds in the child.  Make sure we don't close the same fd
        # more than once, or standard fds.
        for fd in set([p2cread, c2pwrite, errwrite]):
            if fd > 2:
                file_actions.add_close(fd)

        gc_was_enabled = gc.isenabled()
        # FIXME Does this bug apply to posix_spawn version?
        try:
            # Disable gc to avoid bug where gc -> file_dealloc ->
            # write to stderr -> hang.  http://bugs.python.org/issue1336
            gc.disable()
            self.pid = posix_spawnp(
                executable,
                args,
                file_actions=file_actions,
                env=env,
            )
        except:
            if gc_was_enabled:
                gc.enable()
            raise
        finally:
            for fd in fds_to_close_in_parent:
                os.close(fd)

        # Capture the SIGCHILD.
        self._watcher = self._loop.child(self.pid)
        self._watcher.start(self._on_child, self._watcher)

        if gc_was_enabled:
            gc.enable()

        # Close the Child's pipe ends in the parent.
        if p2cread is not None and p2cwrite is not None:
            os.close(p2cread)
        if c2pwrite is not None and c2pread is not None:
            os.close(c2pwrite)
        if errwrite is not None and errread is not None:
            os.close(errwrite)
Esempio n. 5
0
 def test_echo_is_on_path(self):
     pid = posix_spawnp(b"echo", [b"echo", b"hello world"])
     assert exits(pid) == 0
 def test_echo_is_on_path(self):
     pid = posix_spawnp(b"echo", [b"echo", b"hello world"])
     assert exits(pid) == 0