@@ -608,7 +608,8 @@ def __init__(self, args, bufsize=0, executable=None,
608
608
preexec_fn = None , close_fds = None , shell = False ,
609
609
cwd = None , env = None , universal_newlines = False ,
610
610
startupinfo = None , creationflags = 0 ,
611
- restore_signals = True , start_new_session = False ):
611
+ restore_signals = True , start_new_session = False ,
612
+ pass_fds = ()):
612
613
"""Create new Popen instance."""
613
614
_cleanup ()
614
615
@@ -644,6 +645,9 @@ def __init__(self, args, bufsize=0, executable=None,
644
645
raise ValueError ("creationflags is only supported on Windows "
645
646
"platforms" )
646
647
648
+ if pass_fds and not close_fds :
649
+ raise ValueError ("pass_fds requires close_fds=True." )
650
+
647
651
self .stdin = None
648
652
self .stdout = None
649
653
self .stderr = None
@@ -671,7 +675,7 @@ def __init__(self, args, bufsize=0, executable=None,
671
675
errread , errwrite ) = self ._get_handles (stdin , stdout , stderr )
672
676
673
677
self ._execute_child (args , executable , preexec_fn , close_fds ,
674
- cwd , env , universal_newlines ,
678
+ pass_fds , cwd , env , universal_newlines ,
675
679
startupinfo , creationflags , shell ,
676
680
p2cread , p2cwrite ,
677
681
c2pread , c2pwrite ,
@@ -848,14 +852,16 @@ def _find_w9xpopen(self):
848
852
849
853
850
854
def _execute_child (self , args , executable , preexec_fn , close_fds ,
851
- cwd , env , universal_newlines ,
855
+ pass_fds , cwd , env , universal_newlines ,
852
856
startupinfo , creationflags , shell ,
853
857
p2cread , p2cwrite ,
854
858
c2pread , c2pwrite ,
855
859
errread , errwrite ,
856
860
unused_restore_signals , unused_start_new_session ):
857
861
"""Execute program (MS Windows version)"""
858
862
863
+ assert not pass_fds , "pass_fds not yet supported on Windows"
864
+
859
865
if not isinstance (args , str ):
860
866
args = list2cmdline (args )
861
867
@@ -1075,8 +1081,19 @@ def _close_fds(self, but):
1075
1081
os .closerange (but + 1 , MAXFD )
1076
1082
1077
1083
1084
+ def _close_all_but_a_sorted_few_fds (self , fds_to_keep ):
1085
+ # precondition: fds_to_keep must be sorted and unique
1086
+ start_fd = 3
1087
+ for fd in fds_to_keep :
1088
+ if fd > start_fd :
1089
+ os .closerange (start_fd , fd )
1090
+ start_fd = fd + 1
1091
+ if start_fd <= MAXFD :
1092
+ os .closerange (start_fd , MAXFD )
1093
+
1094
+
1078
1095
def _execute_child (self , args , executable , preexec_fn , close_fds ,
1079
- cwd , env , universal_newlines ,
1096
+ pass_fds , cwd , env , universal_newlines ,
1080
1097
startupinfo , creationflags , shell ,
1081
1098
p2cread , p2cwrite ,
1082
1099
c2pread , c2pwrite ,
@@ -1124,9 +1141,11 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
1124
1141
executable_list = tuple (
1125
1142
os .path .join (os .fsencode (dir ), executable )
1126
1143
for dir in os .get_exec_path (env ))
1144
+ fds_to_keep = set (pass_fds )
1145
+ fds_to_keep .add (errpipe_write )
1127
1146
self .pid = _posixsubprocess .fork_exec (
1128
1147
args , executable_list ,
1129
- close_fds , cwd , env_list ,
1148
+ close_fds , sorted ( fds_to_keep ), cwd , env_list ,
1130
1149
p2cread , p2cwrite , c2pread , c2pwrite ,
1131
1150
errread , errwrite ,
1132
1151
errpipe_read , errpipe_write ,
@@ -1180,7 +1199,14 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
1180
1199
1181
1200
# Close all other fds, if asked for
1182
1201
if close_fds :
1183
- self ._close_fds (but = errpipe_write )
1202
+ if pass_fds :
1203
+ fds_to_keep = set (pass_fds )
1204
+ fds_to_keep .add (errpipe_write )
1205
+ self ._close_all_but_a_sorted_few_fds (
1206
+ sorted (fds_to_keep ))
1207
+ else :
1208
+ self ._close_fds (but = errpipe_write )
1209
+
1184
1210
1185
1211
if cwd is not None :
1186
1212
os .chdir (cwd )
0 commit comments