donor = None
-usage =
-'''
-fishdescriptor [-p|--pid] <pid> <action>... [-p|--pid <pid> <action>...]
+usage = '''fishdescriptor [-p|--pid] <pid> <action>... [-p|--pid <pid> <action>...]
<action>s
[<here-0fd>=]<there-fd>
now attach to <pid>, detaching from previous pid
'''
+pending = []
+# list of (nominal, there) where nominal might be None
+
fdmap = { }
-# fdmap[here] = (actual_fd_number_here, Donor, target_fd)
+# fdmap[nominal] = (actual, Donor, there)
-last_here = None
+last_nominal = None
def implement_pending():
- got_list = donor.fish([x[1] for x in pending])
- assert(len(got_list) = len(pending))
- for (here, there), got in zip(pending, got_list)
- overwriting = fdmap.get(here)
- if overwriting is not None: os.close(overwriting)
- fdmap[here] = (got, Donor, there)
- last_here = here
-
-def implmement_sockinfo(here):
- (fd, tdonor, there) = fdmap[here]
+ actuals = donor.fish([pend[1] for pend in pending])
+ assert(len(actuals) == len(pending))
+ for (nominal, there), actual in zip(pending, actuals)
+ overwriting_info = fdmap.get(nominal)
+ if overwriting_info is not None: os.close(overwriting_info[0])
+ fdmap[nominal] = (actual, Donor, there)
+ last_nominal = nominal
+
+def implmement_sockinfo(nominal):
+ (actual, tdonor, there) = fdmap[nominal]
# socket.fromfd requires the AF. But of course we don't know the AF.
# There isn't a sane way to get it in Python:
# https://utcc.utoronto.ca/~cks/space/blog/python/SocketFromFdMistake
print $family, "\n" or die $!;
'''
famp = subprocess.Popen(
- stdin = fd,
+ stdin = actual,
stdout = subprocess.PIPE,
args = ['perl','-we',perl_script]
)
sock.close()
def permute_fds_for_exec():
- actual_map = { info[0]: intent for intent, info in fdmap.items }
- for intent, (actual, tdonor, intarget) in fdmap.items():
- if intent is not None:
- in_way = actual_map.get(intent)
- if in_way is not None:
- moved = os.dup(intent)
- actual_map[moved] =
+ actual2intended = { info[0]: nominal for nominal, info in fdmap.items }
+ # invariant at the start of each loop iteration:
+ # for each intended (aka `nominal') we have processed:
+ # relevant open-file is only held in fd intended
+ # (unless `nominal' is None in which case it is closed)
+ # for each intended (aka `nominal') we have NOT processed:
+ # relevant open-file is only held in actual
+ # where actual = fdmap[nominal][0]
+ # and where actual2intended[actual] = nominal
+ # we can rely on processing each intended only once,
+ # since they're hash keys
+ # the post-condition is not really a valid state (fdmap
+ # is nonsense) but we call this function just before exec
+ for intended, (actual, tdonor, there) in fdmap.items():
+ if intended == actual:
+ continue
+ if intended is not None:
+ inway_intended = actual2intended.get(intended)
+ if inway_intended is not None:
+ inway_moved = os.dup(intended)
+ actual2intended[inway_moved] = inway_intended
+ fdmap[inway_intented][0] = inway_moved
+ os.dup2(actual, intended)
+ os.close(actual)
def implement_exec(argl):
if donor is not None: donor.detach()
-
+ sys.stdout.flush()
+ permut_fds_for_exec()
+ os.execvp(argl[0], argl)
def set_donor(pid):
global donor
callback='ocb_set_donor')
args = sys.argv
- pending = []
while True:
(ov, args) = op.parse_args(args=args, values=ov)
if donor is not None:
set_donor(int(arg))
elif arg_matches(r'^(?:(\d+)=)?(\d+)?$'):
- (here, there) = m.groups()
- here = None if here is None else int(here)
+ (nominal, there) = m.groups()
+ nominal = None if nominal is None else int(nominal)
there = int(there)
- pending.append = (here,there)
+ pending.append = (nominal,there)
elif arg = 'exec':
if not len(args):
op.error("exec needs command to run")
implement_pending()
implement_exec(args)
elif arg = 'sockinfo':
- if last_here is None:
+ if last_nominal is None:
op.error('sockinfo needs a prior fd spec')
implement_pending()
- implement_sockinfo(last_here)
+ implement_sockinfo(last_nominal)
else:
op.error("unknown argument/option `%s'" % arg)
there = int(m.group[1])
- here = None if m.group
+ nominal = None if m.group
- ,here) = map(int, m.groups())
+ ,nominal) = map(int, m.groups())
pid = int(sys.argv[1])