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.
This commit is contained in:
Fred Drake 2000-09-28 19:07:53 +00:00
parent 38cb9f1f17
commit d75e63a865
1 changed files with 67 additions and 52 deletions

View File

@ -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():