diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2011-01-03 18:23:55 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2011-01-03 18:23:55 (GMT) |
commit | c9c83ba8969c166f617da24c6af54a479373adf9 (patch) | |
tree | cb3e91db6e838110339f8f16ee9c77c52a68ffec /Lib/subprocess.py | |
parent | 63ebe1c3093bd40ea5a7e1a225ea0355f13563b4 (diff) | |
download | cpython-c9c83ba8969c166f617da24c6af54a479373adf9.zip cpython-c9c83ba8969c166f617da24c6af54a479373adf9.tar.gz cpython-c9c83ba8969c166f617da24c6af54a479373adf9.tar.bz2 |
Issue #10806, issue #9905: Fix subprocess pipes when some of the standard
file descriptors (0, 1, 2) are closed in the parent process. Initial
patch by Ross Lagerwall.
Diffstat (limited to 'Lib/subprocess.py')
-rw-r--r-- | Lib/subprocess.py | 52 |
1 files changed, 27 insertions, 25 deletions
diff --git a/Lib/subprocess.py b/Lib/subprocess.py index c12898d..7d3f77f 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -393,22 +393,22 @@ else: # POSIX defines PIPE_BUF as >= 512. _PIPE_BUF = getattr(select, 'PIPE_BUF', 512) + _FD_CLOEXEC = getattr(fcntl, 'FD_CLOEXEC', 1) + + def _set_cloexec(fd, cloexec): + old = fcntl.fcntl(fd, fcntl.F_GETFD) + if cloexec: + fcntl.fcntl(fd, fcntl.F_SETFD, old | _FD_CLOEXEC) + else: + fcntl.fcntl(fd, fcntl.F_SETFD, old & ~_FD_CLOEXEC) + if _posixsubprocess: _create_pipe = _posixsubprocess.cloexec_pipe else: def _create_pipe(): - try: - cloexec_flag = fcntl.FD_CLOEXEC - except AttributeError: - cloexec_flag = 1 - fds = os.pipe() - - old = fcntl.fcntl(fds[0], fcntl.F_GETFD) - fcntl.fcntl(fds[0], fcntl.F_SETFD, old | cloexec_flag) - old = fcntl.fcntl(fds[1], fcntl.F_GETFD) - fcntl.fcntl(fds[1], fcntl.F_SETFD, old | cloexec_flag) - + _set_cloexec(fds[0], True) + _set_cloexec(fds[1], True) return fds __all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "getstatusoutput", @@ -1194,23 +1194,25 @@ class Popen(object): os.close(errpipe_read) # Dup fds for child - if p2cread != -1: - os.dup2(p2cread, 0) - if c2pwrite != -1: - os.dup2(c2pwrite, 1) - if errwrite != -1: - os.dup2(errwrite, 2) + def _dup2(a, b): + # dup2() removes the CLOEXEC flag but + # we must do it ourselves if dup2() + # would be a no-op (issue #10806). + if a == b: + _set_cloexec(a, False) + elif a != -1: + os.dup2(a, b) + _dup2(p2cread, 0) + _dup2(c2pwrite, 1) + _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. - if p2cread != -1 and p2cread not in (0,): - os.close(p2cread) - if (c2pwrite != -1 and - c2pwrite not in (p2cread, 1)): - os.close(c2pwrite) - if (errwrite != -1 and - errwrite not in (p2cread, c2pwrite, 2)): - os.close(errwrite) + closed = set() + for fd in [p2cread, c2pwrite, errwrite]: + if fd > 2 and fd not in closed: + os.close(fd) + closed.add(fd) # Close all other fds, if asked for if close_fds: |