From d75e63a865b451c24e1a0516744a98d59691b4ff Mon Sep 17 00:00:00 2001 From: Fred Drake Date: Thu, 28 Sep 2000 19:07:53 +0000 Subject: [PATCH] popen4(), class Popen4: popen4() support for Unix. popen2(), popen3(): Reversed order of bufsize and mode parameters to comply with what was here before (Python 1.5.2). class Popen3: Factored the __init__() into a more basic initializer and a helper method, to allow some re-use by the Popen4 class. Use os.dup2() instead of os.dup() to create the proper file descriptors in the child process. This closes SourceForge bug #115330 and partially closes #115353. --- Lib/popen2.py | 119 ++++++++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/Lib/popen2.py b/Lib/popen2.py index 64c34d4cb50..4580f5873ad 100644 --- a/Lib/popen2.py +++ b/Lib/popen2.py @@ -8,7 +8,6 @@ import os import sys -import string MAXFD = 256 # Max number of file descriptors (os.getdtablesize()???) @@ -22,14 +21,15 @@ class Popen3: """Class representing a child process. Normally instances are created by the factory functions popen2() and popen3().""" + sts = -1 # Child not completed yet + def __init__(self, cmd, capturestderr=0, bufsize=-1): """The parameter 'cmd' is the shell command to execute in a sub-process. The 'capturestderr' flag, if true, specifies that the object should capture standard error output of the child process. The default is false. If the 'bufsize' parameter is specified, it specifies the size of the I/O buffers to/from the child process.""" - if type(cmd) == type(''): - cmd = ['/bin/sh', '-c', cmd] + _cleanup() p2cread, p2cwrite = os.pipe() c2pread, c2pwrite = os.pipe() if capturestderr: @@ -37,25 +37,11 @@ def __init__(self, cmd, capturestderr=0, bufsize=-1): self.pid = os.fork() if self.pid == 0: # Child - os.close(0) - os.close(1) - if os.dup(p2cread) <> 0: - sys.stderr.write('popen2: bad read dup\n') - if os.dup(c2pwrite) <> 1: - sys.stderr.write('popen2: bad write dup\n') + os.dup2(p2cread, 0) + os.dup2(c2pwrite, 1) if capturestderr: - os.close(2) - if os.dup(errin) <> 2: pass - for i in range(3, MAXFD): - try: - os.close(i) - except: pass - try: - os.execvp(cmd[0], cmd) - finally: - os._exit(1) - # Shouldn't come here, I guess - os._exit(1) + os.dup2(errin, 2) + self._run_child(cmd) os.close(p2cread) self.tochild = os.fdopen(p2cwrite, 'w', bufsize) os.close(c2pwrite) @@ -65,9 +51,21 @@ def __init__(self, cmd, capturestderr=0, bufsize=-1): self.childerr = os.fdopen(errout, 'r', bufsize) else: self.childerr = None - self.sts = -1 # Child not completed yet _active.append(self) + def _run_child(self, cmd): + if type(cmd) == type(''): + cmd = ['/bin/sh', '-c', cmd] + for i in range(3, MAXFD): + try: + os.close(i) + except: + pass + try: + os.execvp(cmd[0], cmd) + finally: + os._exit(1) + def poll(self): """Return the exit status of the child process if it has finished, or -1 if it hasn't finished yet.""" @@ -90,55 +88,72 @@ def wait(self): return self.sts +class Popen4(Popen3): + childerr = None + + def __init__(self, cmd, bufsize=-1): + _cleanup() + p2cread, p2cwrite = os.pipe() + c2pread, c2pwrite = os.pipe() + self.pid = os.fork() + if self.pid == 0: + # Child + os.dup2(p2cread, 0) + os.dup2(c2pwrite, 1) + os.dup2(c2pwrite, 2) + self._run_child(cmd) + os.close(p2cread) + self.tochild = os.fdopen(p2cwrite, 'w', bufsize) + os.close(c2pwrite) + self.fromchild = os.fdopen(c2pread, 'r', bufsize) + _active.append(self) + + if sys.platform[:3] == "win": - def popen2(cmd, mode='t', bufsize=-1): + # Some things don't make sense on non-Unix platforms. + del Popen3, Popen4, _active, _cleanup + + def popen2(cmd, bufsize=-1, mode='t'): """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is specified, it sets the buffer size for the I/O pipes. The file objects (child_stdout, child_stdin) are returned.""" w, r = os.popen2(cmd, mode, bufsize) return r, w -else: - def popen2(cmd, mode='t', bufsize=-1): - """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is - specified, it sets the buffer size for the I/O pipes. The file objects - (child_stdout, child_stdin) are returned.""" - if type(mode) is type(0) and bufsize == -1: - bufsize = mode - mode = 't' - assert mode in ('t', 'b') - _cleanup() - inst = Popen3(cmd, 0, bufsize) - return inst.fromchild, inst.tochild -if sys.platform[:3] == "win": - def popen3(cmd, mode='t', bufsize=-1): + def popen3(cmd, bufsize=-1, mode='t'): """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is specified, it sets the buffer size for the I/O pipes. The file objects (child_stdout, child_stdin, child_stderr) are returned.""" w, r, e = os.popen3(cmd, mode, bufsize) return r, w, e -else: - def popen3(cmd, mode='t', bufsize=-1): - """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is - specified, it sets the buffer size for the I/O pipes. The file objects - (child_stdout, child_stdin, child_stderr) are returned.""" - if type(mode) is type(0) and bufsize == -1: - bufsize = mode - mode = 't' - assert mode in ('t', 'b') - _cleanup() - inst = Popen3(cmd, 1, bufsize) - return inst.fromchild, inst.tochild, inst.childerr -if sys.platform[:3] == "win": - def popen4(cmd, mode='t', bufsize=-1): + def popen4(cmd, bufsize=-1, mode='t'): """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is specified, it sets the buffer size for the I/O pipes. The file objects (child_stdout_stderr, child_stdin) are returned.""" w, r = os.popen4(cmd, mode, bufsize) return r, w else: - pass # not yet on unix + def popen2(cmd, bufsize=-1, mode='t'): + """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is + specified, it sets the buffer size for the I/O pipes. The file objects + (child_stdout, child_stdin) are returned.""" + inst = Popen3(cmd, 0, bufsize) + return inst.fromchild, inst.tochild + + def popen3(cmd, bufsize=-1, mode='t'): + """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is + specified, it sets the buffer size for the I/O pipes. The file objects + (child_stdout, child_stdin, child_stderr) are returned.""" + inst = Popen3(cmd, 1, bufsize) + return inst.fromchild, inst.tochild, inst.childerr + + def popen4(cmd, bufsize=-1, mode='t'): + """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is + specified, it sets the buffer size for the I/O pipes. The file objects + (child_stdout_stderr, child_stdin) are returned.""" + inst = Popen4(cmd, bufsize) + return inst.fromchild, inst.tochild def _test():