Esempio n. 1
0
    def test_close_file(self, tmpdir):
        closefile = tmpdir.join("closefile")
        fa = FileActions()
        fa.add_close(0)

        pid = posix_spawn(executable, [
            executable, b'-c',
            textwrap.dedent("""
                import os
                import sys
                import errno

                try:
                    os.fstat(0)
                except OSError as e:
                    if e.errno == errno.EBADF:
                        with open(sys.argv[1], 'w') as closefile:
                            closefile.write('is closed')
            """).encode('ascii'),
            str(closefile).encode('ascii')
        ],
                          file_actions=fa)

        assert exits(pid) == 0
        assert "is closed" == closefile.read()
Esempio n. 2
0
    def test_close_file(self, tmpdir):
        closefile = tmpdir.join("closefile")
        fa = FileActions()
        fa.add_close(0)

        pid = posix_spawn(executable, [
            executable,
            b'-c',
            textwrap.dedent("""
                import os
                import sys
                import errno

                try:
                    os.fstat(0)
                except OSError as e:
                    if e.errno == errno.EBADF:
                        with open(sys.argv[1], 'w') as closefile:
                            closefile.write('is closed')
            """).encode('ascii'),
            str(closefile).encode('ascii')],
            file_actions=fa
        )

        assert exits(pid) == 0
        assert "is closed" == closefile.read()
Esempio n. 3
0
    def test_close_file(self):
        with tempfile.NamedTemporaryFile(mode=b'r+b') as closefile:
            fa = FileActions()
            self.assertEqual(0, fa.add_close(1))

            pid = posix_spawn(sys.executable, [
                b'python',
                b'-c',
                (b'import sys; '
                 b'open({0!r}, "w").write(str(sys.stdout.closed))'.format(
                    closefile.name))
            ],
            file_actions=fa)

            os.waitpid(pid, 0)
            self.assertIn(b"True", closefile.read())
Esempio n. 4
0
    def test_dup2(self, tmpdir):
        dupfile = tmpdir.join("dupfile")
        with dupfile.open("w") as childfile:
            fa = FileActions()
            fa.add_dup2(childfile.fileno(), 1)

            pid = posix_spawn(executable, [
                executable, b'-c',
                textwrap.dedent("""
                    import sys
                    sys.stdout.write("hello")
                """).encode('ascii')
            ],
                              file_actions=fa)

            assert exits(pid) == 0

        assert "hello" == dupfile.read()
Esempio n. 5
0
    def test_open_file(self, tmpdir):
        outfile = tmpdir.join('outfile')
        fa = FileActions()
        fa.add_open(1,
                    str(outfile).encode('ascii'),
                    os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
                    stat.S_IRUSR | stat.S_IWUSR)

        pid = posix_spawn(executable, [
            executable, b'-c',
            textwrap.dedent("""
                import sys
                sys.stdout.write("hello")
            """).encode('ascii')
        ],
                          file_actions=fa)

        assert exits(pid) == 0
        assert "hello" == outfile.read()
Esempio n. 6
0
    def test_dup2(self, tmpdir):
        dupfile = tmpdir.join("dupfile")
        with dupfile.open("w") as childfile:
            fa = FileActions()
            fa.add_dup2(childfile.fileno(), 1)

            pid = posix_spawn(executable, [
                executable,
                b'-c',
                textwrap.dedent("""
                    import sys
                    sys.stdout.write("hello")
                """).encode('ascii')],
                file_actions=fa
            )

            assert exits(pid) == 0

        assert "hello" == dupfile.read()
Esempio n. 7
0
    def test_open_file(self):
        with tempfile.NamedTemporaryFile(mode=b'r+b') as outfile:
            fa = FileActions()
            self.assertEqual(0, fa.add_open(
                1,
                outfile.name,
                os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
                stat.S_IRUSR | stat.S_IWUSR
            ))

            pid = posix_spawn(sys.executable, [
                b'python',
                b'-c',
                b'print ("hello")',
            ],
            file_actions=fa)

            os.waitpid(pid, 0)
            self.assertIn(b"hello", outfile.read())
Esempio n. 8
0
    def test_open_file(self, tmpdir):
        outfile = tmpdir.join('outfile')
        fa = FileActions()
        fa.add_open(
            1,
            str(outfile).encode('ascii'),
            os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
            stat.S_IRUSR | stat.S_IWUSR
        )

        pid = posix_spawn(executable, [
            executable,
            b'-c',
            textwrap.dedent("""
                import sys
                sys.stdout.write("hello")
            """).encode('ascii')],
            file_actions=fa
        )

        assert exits(pid) == 0
        assert "hello" == outfile.read()
Esempio n. 9
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. 10
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. 11
0
 def test_empty_actions(self):
     fa = FileActions()
     pid = posix_spawn(executable, [executable, b'-c', b'pass'],
                       file_actions=fa)
     assert exits(pid) == 0