@@ -178,7 +178,7 @@ def __init__(self, pid, fd):
178178 @classmethod
179179 def spawn (
180180 cls , argv , cwd = None , env = None , echo = True , preexec_fn = None ,
181- dimensions = (24 , 80 )):
181+ dimensions = (24 , 80 ), pass_fds = () ):
182182 '''Start the given command in a child process in a pseudo terminal.
183183
184184 This does all the fork/exec type of stuff for a pty, and returns an
@@ -190,6 +190,10 @@ def spawn(
190190
191191 Dimensions of the psuedoterminal used for the subprocess can be
192192 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.
193197 '''
194198 # Note that it is difficult for this method to fail.
195199 # You cannot detect if the child process cannot start.
@@ -255,12 +259,14 @@ def spawn(
255259
256260 # Do not allow child to inherit open file descriptors from parent,
257261 # with the exception of the exec_err_pipe_write of the pipe
262+ # and pass_fds.
258263 # Impose ceiling on max_fd: AIX bugfix for users with unlimited
259264 # nofiles where resource.RLIMIT_NOFILE is 2^63-1 and os.closerange()
260265 # occasionally raises out of range error
261266 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 ])
264270
265271 if cwd is not None :
266272 os .chdir (cwd )
0 commit comments