chiark / gitweb /
fishdescriptor: Provide copyright notices and licence statements
[chiark-utils.git] / fishdescriptor / fishdescriptor
index 863cf83660de3e63525c21ce833ad0b69420830c..8abdfffc1f39f5a02823bd9284627d8fad5d6f06 100755 (executable)
@@ -1,16 +1,38 @@
 #!/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
@@ -31,18 +53,18 @@ pending = []
 fdmap = { }
 # fdmap[nominal] = (actual, Donor, there)
 
-last_nominal = None
-
 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)
+    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
+        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:
@@ -69,7 +91,7 @@ def implmement_sockinfo(nominal):
     (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,
@@ -83,7 +105,7 @@ def implmement_sockinfo(nominal):
     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
@@ -111,13 +133,13 @@ def permute_fds_for_exec():
 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)
@@ -125,6 +147,10 @@ def ocb_set_donor(option, opt, value, parser):
 ov = optparse.Values()
 
 def process_args():
+    global ov
+
+    m = None
+    
     def arg_matches(regexp):
         nonlocal m
         m = re.search(regexp, arg)
@@ -134,9 +160,13 @@ def process_args():
 
     op.disable_interspersed_args()
     op.add_option('-p','--pid', type='int', action='callback',
-                  callback='ocb_set_donor')
+                  callback=ocb_set_donor)
+    op.add_option('-D','--debug', action='store_const',
+                  dest='debug', const=sys.stderr)
+    ov.debug = None
 
-    args = sys.argv
+    args = sys.argv[1:]
+    last_nominal = None # None or (nominal,) ie None or (None,) or (int,)
 
     while True:
         (ov, args) = op.parse_args(args=args, values=ov)
@@ -144,38 +174,25 @@ def process_args():
 
         arg = args.pop(0)
 
-        if donor is not None:
+        if donor is None:
             set_donor(int(arg))
         elif arg_matches(r'^(?:(\d+)=)?(\d+)?$'):
             (nominal, there) = m.groups()
             nominal = None if nominal is None else int(nominal)
             there = int(there)
-            pending.append = (nominal,there)
-        elif arg = 'exec':
+            pending.append((nominal,there))
+            last_nominal = (nominal,)
+        elif arg == 'exec':
             if not len(args):
                 op.error("exec needs command to run")
             implement_pending()
             implement_exec(args)
-        elif arg = 'sockinfo':
+        elif arg == 'sockinfo':
             if last_nominal is None:
                 op.error('sockinfo needs a prior fd spec')
             implement_pending()
-            implement_sockinfo(last_nominal)
+            implement_sockinfo(last_nominal[0])
         else:
             op.error("unknown argument/option `%s'" % arg)
 
-    implement_pending()
-    
-
-            there = int(m.group[1])
-            nominal = None if m.group
-
-            ,nominal) = map(int, m.groups())
-            
-
-pid = int(sys.argv[1])
-fds = [int(x) for x in sys.argv[2:]]
-
-d = fishdescriptor.fish.Donor(pid)
-r = d.fish(fds)
-print(repr(r))
+process_args()