#!/usr/bin/python3
+# This file is part of chiark-utils, a collection of useful programs
+# used on chiark.greenend.org.uk.
+#
+# This file is:
+# Copyright 2018 Citrix Systems Ltd
+#
+# This is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 3, or (at your option) any later version.
+#
+# This is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, consult the Free Software Foundation's
+# website at www.fsf.org, or the GNU Project website at www.gnu.org.
+
import sys
import fishdescriptor.fish
import optparse
import re
+import subprocess
+import socket
+import os
donor = None
usage = '''fishdescriptor [-p|--pid] <pid> <action>... [-p|--pid <pid> <action>...]
<action>s
- [<here-0fd>=]<there-fd>
+ [<here-fd>=]<there-fd>
fish the openfile referenced by descriptor <there-fd> in
(the most recent) <pid> and keep a descriptor onto it;
and, optionally, give it the number <here-fd> for exec
# fdmap[nominal] = (actual, Donor, there)
def implement_pending():
- actuals = donor.fish([pend[1] for pend in pending])
+ try: actuals = donor.fish([pend[1] for pend in pending])
+ except fishdescriptor.fish.Error as e:
+ print('fishdescriptor error: %s' % e, file=sys.stderr)
+ sys.exit(127)
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)
+ fdmap[nominal] = [actual, donor, there]
-def implmement_sockinfo(nominal):
+def implement_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:
(output, dummy) = famp.communicate()
family = int(output)
- sock = socket.fromfd(fd, family, 0)
+ sock = socket.fromfd(actual, family, 0)
print("[%s] %d sockinfo" % (tdonor.pid, there), end='')
for f in (lambda: socket.AddressFamily(family).name,
sock.close()
def permute_fds_for_exec():
- actual2intended = { info[0]: nominal for nominal, info in fdmap.items }
+ 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
if inway_intended is not None:
inway_moved = os.dup(intended)
actual2intended[inway_moved] = inway_intended
- fdmap[inway_intented][0] = inway_moved
+ fdmap[inway_intended][0] = inway_moved
os.dup2(actual, intended)
os.close(actual)
+ del actual2intended[actual]
def implement_exec(argl):
if donor is not None: donor.detach()
sys.stdout.flush()
- permut_fds_for_exec()
+ permute_fds_for_exec()
os.execvp(argl[0], argl)
def set_donor(pid):
global donor
if donor is not None: donor.detach()
- donor = fishdescriptor.fish.Donor(pid)
+ donor = fishdescriptor.fish.Donor(pid, debug=ov.debug)
def ocb_set_donor(option, opt, value, parser):
set_donor(value)
op.disable_interspersed_args()
op.add_option('-p','--pid', type='int', action='callback',
callback=ocb_set_donor)
+ op.add_option('-D','--debug', action='store_const',
+ dest='debug', const=sys.stderr)
+ ov.debug = None
args = sys.argv[1:]
last_nominal = None # None or (nominal,) ie None or (None,) or (int,)
if not len(args): break
arg = args.pop(0)
- print("ARG %s" % arg, file=sys.stderr)
if donor is None:
- print("SET_DONOR", file=sys.stderr)
set_donor(int(arg))
elif arg_matches(r'^(?:(\d+)=)?(\d+)?$'):
(nominal, there) = m.groups()