blob: acba60258b46f7c5c7d368932aebd33b4d71809c [file] [log] [blame]
Guido van Rossum54f22ed2000-02-04 15:10:34 +00001"""Spawn a command with pipes to its stdin, stdout, and optionally stderr.
2
3The normal os.popen(cmd, mode) call spawns a shell command and provides a
4file interface to just the input or output of the process depending on
5whether mode is 'r' or 'w'. This module provides the functions popen2(cmd)
6and popen3(cmd) which return two or three pipes to the spawned command.
7"""
8
Guido van Rossum9a22de11995-01-12 12:29:47 +00009import os
10import sys
Guido van Rossum9a22de11995-01-12 12:29:47 +000011
Skip Montanaro57fd45e2002-03-12 19:48:03 +000012__all__ = ["popen2", "popen3", "popen4"]
Skip Montanaro352674d2001-02-07 23:14:30 +000013
Martin v. Löwisf563c8b2003-10-06 21:34:33 +000014try:
15 MAXFD = os.sysconf('SC_OPEN_MAX')
16except (AttributeError, ValueError):
17 MAXFD = 256
Guido van Rossum9a22de11995-01-12 12:29:47 +000018
Guido van Rossum0357d021997-08-11 03:27:24 +000019_active = []
20
21def _cleanup():
22 for inst in _active[:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000023 inst.poll()
Guido van Rossum0357d021997-08-11 03:27:24 +000024
25class Popen3:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000026 """Class representing a child process. Normally instances are created
27 by the factory functions popen2() and popen3()."""
28
Fred Draked75e63a2000-09-28 19:07:53 +000029 sts = -1 # Child not completed yet
30
Fred Drakeb5aa4072003-07-07 21:36:19 +000031 def __init__(self, cmd, capturestderr=False, bufsize=-1):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000032 """The parameter 'cmd' is the shell command to execute in a
33 sub-process. The 'capturestderr' flag, if true, specifies that
34 the object should capture standard error output of the child process.
35 The default is false. If the 'bufsize' parameter is specified, it
36 specifies the size of the I/O buffers to/from the child process."""
Fred Draked75e63a2000-09-28 19:07:53 +000037 _cleanup()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000038 p2cread, p2cwrite = os.pipe()
39 c2pread, c2pwrite = os.pipe()
40 if capturestderr:
41 errout, errin = os.pipe()
42 self.pid = os.fork()
43 if self.pid == 0:
44 # Child
Fred Draked75e63a2000-09-28 19:07:53 +000045 os.dup2(p2cread, 0)
46 os.dup2(c2pwrite, 1)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000047 if capturestderr:
Fred Draked75e63a2000-09-28 19:07:53 +000048 os.dup2(errin, 2)
49 self._run_child(cmd)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000050 os.close(p2cread)
51 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
52 os.close(c2pwrite)
53 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
54 if capturestderr:
55 os.close(errin)
56 self.childerr = os.fdopen(errout, 'r', bufsize)
57 else:
58 self.childerr = None
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000059 _active.append(self)
Guido van Rossum54f22ed2000-02-04 15:10:34 +000060
Fred Draked75e63a2000-09-28 19:07:53 +000061 def _run_child(self, cmd):
Walter Dörwald65230a22002-06-03 15:58:32 +000062 if isinstance(cmd, basestring):
Fred Draked75e63a2000-09-28 19:07:53 +000063 cmd = ['/bin/sh', '-c', cmd]
64 for i in range(3, MAXFD):
65 try:
66 os.close(i)
Skip Montanaro1c90d7a2002-03-24 20:48:26 +000067 except OSError:
Fred Draked75e63a2000-09-28 19:07:53 +000068 pass
69 try:
70 os.execvp(cmd[0], cmd)
71 finally:
72 os._exit(1)
73
Guido van Rossum0357d021997-08-11 03:27:24 +000074 def poll(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000075 """Return the exit status of the child process if it has finished,
76 or -1 if it hasn't finished yet."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000077 if self.sts < 0:
78 try:
79 pid, sts = os.waitpid(self.pid, os.WNOHANG)
80 if pid == self.pid:
81 self.sts = sts
82 _active.remove(self)
83 except os.error:
84 pass
85 return self.sts
Guido van Rossum54f22ed2000-02-04 15:10:34 +000086
Guido van Rossum0357d021997-08-11 03:27:24 +000087 def wait(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000088 """Wait for and return the exit status of the child process."""
Guido van Rossum3800ef72003-06-02 19:12:01 +000089 if self.sts < 0:
90 pid, sts = os.waitpid(self.pid, 0)
91 if pid == self.pid:
92 self.sts = sts
93 _active.remove(self)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000094 return self.sts
Guido van Rossumcaa9f231997-04-21 14:15:55 +000095
Fred Drake31f182e2000-08-28 17:20:05 +000096
Fred Draked75e63a2000-09-28 19:07:53 +000097class Popen4(Popen3):
98 childerr = None
99
100 def __init__(self, cmd, bufsize=-1):
101 _cleanup()
102 p2cread, p2cwrite = os.pipe()
103 c2pread, c2pwrite = os.pipe()
104 self.pid = os.fork()
105 if self.pid == 0:
106 # Child
107 os.dup2(p2cread, 0)
108 os.dup2(c2pwrite, 1)
109 os.dup2(c2pwrite, 2)
110 self._run_child(cmd)
111 os.close(p2cread)
112 self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
113 os.close(c2pwrite)
114 self.fromchild = os.fdopen(c2pread, 'r', bufsize)
115 _active.append(self)
116
117
Andrew MacIntyre5cef5712002-02-24 05:32:32 +0000118if sys.platform[:3] == "win" or sys.platform == "os2emx":
Fred Draked75e63a2000-09-28 19:07:53 +0000119 # Some things don't make sense on non-Unix platforms.
Tim Petersd2152182000-10-03 23:07:13 +0000120 del Popen3, Popen4
Fred Draked75e63a2000-09-28 19:07:53 +0000121
122 def popen2(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000123 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
124 specified, it sets the buffer size for the I/O pipes. The file objects
125 (child_stdout, child_stdin) are returned."""
126 w, r = os.popen2(cmd, mode, bufsize)
127 return r, w
Guido van Rossumcaa9f231997-04-21 14:15:55 +0000128
Fred Draked75e63a2000-09-28 19:07:53 +0000129 def popen3(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000130 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
131 specified, it sets the buffer size for the I/O pipes. The file objects
132 (child_stdout, child_stdin, child_stderr) are returned."""
133 w, r, e = os.popen3(cmd, mode, bufsize)
134 return r, w, e
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000135
Fred Draked75e63a2000-09-28 19:07:53 +0000136 def popen4(cmd, bufsize=-1, mode='t'):
Fredrik Lundh9ac81f62000-07-09 23:35:24 +0000137 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
138 specified, it sets the buffer size for the I/O pipes. The file objects
139 (child_stdout_stderr, child_stdin) are returned."""
140 w, r = os.popen4(cmd, mode, bufsize)
141 return r, w
142else:
Fred Draked75e63a2000-09-28 19:07:53 +0000143 def popen2(cmd, bufsize=-1, mode='t'):
144 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
145 specified, it sets the buffer size for the I/O pipes. The file objects
146 (child_stdout, child_stdin) are returned."""
Fred Drakeb5aa4072003-07-07 21:36:19 +0000147 inst = Popen3(cmd, False, bufsize)
Fred Draked75e63a2000-09-28 19:07:53 +0000148 return inst.fromchild, inst.tochild
149
150 def popen3(cmd, bufsize=-1, mode='t'):
151 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
152 specified, it sets the buffer size for the I/O pipes. The file objects
153 (child_stdout, child_stdin, child_stderr) are returned."""
Fred Drakeb5aa4072003-07-07 21:36:19 +0000154 inst = Popen3(cmd, True, bufsize)
Fred Draked75e63a2000-09-28 19:07:53 +0000155 return inst.fromchild, inst.tochild, inst.childerr
156
157 def popen4(cmd, bufsize=-1, mode='t'):
158 """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is
159 specified, it sets the buffer size for the I/O pipes. The file objects
160 (child_stdout_stderr, child_stdin) are returned."""
161 inst = Popen4(cmd, bufsize)
162 return inst.fromchild, inst.tochild
Guido van Rossum0357d021997-08-11 03:27:24 +0000163
Skip Montanaro352674d2001-02-07 23:14:30 +0000164 __all__.extend(["Popen3", "Popen4"])
Tim Peters658cba62001-02-09 20:06:00 +0000165
Guido van Rossum0357d021997-08-11 03:27:24 +0000166def _test():
Tim Peters84f28db2000-08-20 05:57:36 +0000167 cmd = "cat"
Tim Peters36208572000-09-01 20:38:55 +0000168 teststr = "ab cd\n"
Tim Peters84f28db2000-08-20 05:57:36 +0000169 if os.name == "nt":
170 cmd = "more"
Tim Peters36208572000-09-01 20:38:55 +0000171 # "more" doesn't act the same way across Windows flavors,
172 # sometimes adding an extra newline at the start or the
173 # end. So we strip whitespace off both ends for comparison.
174 expected = teststr.strip()
Guido van Rossum0357d021997-08-11 03:27:24 +0000175 print "testing popen2..."
Tim Peters84f28db2000-08-20 05:57:36 +0000176 r, w = popen2(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000177 w.write(teststr)
178 w.close()
Tim Peters36208572000-09-01 20:38:55 +0000179 got = r.read()
180 if got.strip() != expected:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000181 raise ValueError("wrote %r read %r" % (teststr, got))
Guido van Rossum0357d021997-08-11 03:27:24 +0000182 print "testing popen3..."
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000183 try:
Tim Peters84f28db2000-08-20 05:57:36 +0000184 r, w, e = popen3([cmd])
Fredrik Lundhbb7eeff2000-07-09 17:59:32 +0000185 except:
Tim Peters84f28db2000-08-20 05:57:36 +0000186 r, w, e = popen3(cmd)
Guido van Rossum0357d021997-08-11 03:27:24 +0000187 w.write(teststr)
188 w.close()
Tim Peters36208572000-09-01 20:38:55 +0000189 got = r.read()
190 if got.strip() != expected:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000191 raise ValueError("wrote %r read %r" % (teststr, got))
Tim Peters36208572000-09-01 20:38:55 +0000192 got = e.read()
193 if got:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000194 raise ValueError("unexected %r on stderr" % (got,))
Guido van Rossum068d5721999-04-20 12:27:31 +0000195 for inst in _active[:]:
196 inst.wait()
Tim Peters36208572000-09-01 20:38:55 +0000197 if _active:
198 raise ValueError("_active not empty")
Guido van Rossum0357d021997-08-11 03:27:24 +0000199 print "All OK"
200
201if __name__ == '__main__':
202 _test()