@@ -178,7 +178,7 @@ def __init__(self, pid, fd):
178
178
@classmethod
179
179
def spawn (
180
180
cls , argv , cwd = None , env = None , echo = True , preexec_fn = None ,
181
- dimensions = (24 , 80 )):
181
+ dimensions = (24 , 80 ), pass_fds = () ):
182
182
'''Start the given command in a child process in a pseudo terminal.
183
183
184
184
This does all the fork/exec type of stuff for a pty, and returns an
@@ -190,6 +190,10 @@ def spawn(
190
190
191
191
Dimensions of the psuedoterminal used for the subprocess can be
192
192
specified as a tuple (rows, cols), or the default (24, 80) will be used.
193
+
194
+ By default, all file descriptors except 0, 1 and 2 are closed. This
195
+ behavior can be overridden with pass_fds, a list of file descriptors to
196
+ keep open between the parent and the child.
193
197
'''
194
198
# Note that it is difficult for this method to fail.
195
199
# You cannot detect if the child process cannot start.
@@ -255,12 +259,14 @@ def spawn(
255
259
256
260
# Do not allow child to inherit open file descriptors from parent,
257
261
# with the exception of the exec_err_pipe_write of the pipe
262
+ # and pass_fds.
258
263
# Impose ceiling on max_fd: AIX bugfix for users with unlimited
259
264
# nofiles where resource.RLIMIT_NOFILE is 2^63-1 and os.closerange()
260
265
# occasionally raises out of range error
261
266
max_fd = min (1048576 , resource .getrlimit (resource .RLIMIT_NOFILE )[0 ])
262
- os .closerange (3 , exec_err_pipe_write )
263
- os .closerange (exec_err_pipe_write + 1 , max_fd )
267
+ spass_fds = sorted (set (pass_fds ) | {exec_err_pipe_write })
268
+ for pair in zip ([2 ] + spass_fds , spass_fds + [max_fd ]):
269
+ os .closerange (pair [0 ]+ 1 , pair [1 ])
264
270
265
271
if cwd is not None :
266
272
os .chdir (cwd )
0 commit comments