4 import fishdescriptor.fish
12 fishdescriptor [-p|--pid] <pid> <action>... [-p|--pid <pid> <action>...]
15 [<here-0fd>=]<there-fd>
16 fish the openfile referenced by descriptor <there-fd> in
17 (the most recent) <pid> and keep a descriptor onto it;
18 and, optionally, give it the number <here-fd> for exec
19 exec <program> [<arg>...]
20 execute a process with each specified <here>
23 calls getsockname/getpeername on the most recent
27 now attach to <pid>, detaching from previous pid
31 # fdmap[here] = (actual_fd_number_here, Donor, target_fd)
35 def implement_pending():
36 got_list = donor.fish([x[1] for x in pending])
37 assert(len(got_list) = len(pending))
38 for (here, there), got in zip(pending, got_list)
39 overwriting = fdmap.get(here)
40 if overwriting is not None: os.close(overwriting)
41 fdmap[here] = (got, Donor, there)
44 def implmement_sockinfo(here):
45 (fd, tdonor, there) = fdmap[here]
46 # socket.fromfd requires the AF. But of course we don't know the AF.
47 # There isn't a sane way to get it in Python:
48 # https://utcc.utoronto.ca/~cks/space/blog/python/SocketFromFdMistake
50 # https://github.com/tiran/socketfromfd
51 # adds a dependency, not portable due to reliance on SO_DOMAIN
52 # call getsockname using ctypes
53 # no sane way to discover how to unpack sa_family_t
58 my $sa = getsockname STDIN;
59 exit 0 if !defined $sa and $!==ENOTSOCK;
60 my $family = sockaddr_family $sa;
61 print $family, "\n" or die $!;
63 famp = subprocess.Popen(
65 stdout = subprocess.PIPE,
66 args = ['perl','-we',perl_script]
68 (output, dummy) = famp.communicate()
71 sock = socket.fromfd(fd, family, 0)
73 print("[%s] %d sockinfo" % (tdonor.pid, there), end='')
74 for f in (lambda: socket.AddressFamily(family).name,
75 lambda: repr(sock.getsockname()),
76 lambda: repr(sock.getpeername())):
78 except Exception as e: info = repr(e)
79 print("\t", info, sep='', end='')
84 def implement_exec(argl):
89 if donor is not None: donor.detach()
90 donor = fishdescriptor.fish.Donor(pid)
92 def ocb_set_donor(option, opt, value, parser):
95 ov = optparse.Values()
98 def arg_matches(regexp):
100 m = re.search(regexp, arg)
103 op = optparse.OptionParser(usage=usage)
105 op.disable_interspersed_args()
106 op.add_option('-p','--pid', type='int', action='callback',
107 callback='ocb_set_donor')
113 (ov, args) = op.parse_args(args=args, values=ov)
114 if not len(args): break
118 if donor is not None:
120 elif arg_matches(r'^(?:(\d+)=)?(\d+)?$'):
121 (here, there) = m.groups()
122 here = None if here is None else int(here)
124 pending.append = (here,there)
127 op.error("exec needs command to run")
130 elif arg = 'sockinfo':
131 if last_here is None:
132 op.error('sockinfo needs a prior fd spec')
134 implement_sockinfo(last_here)
136 op.error("unknown argument/option `%s'" % arg)
141 there = int(m.group[1])
142 here = None if m.group
144 ,here) = map(int, m.groups())
147 pid = int(sys.argv[1])
148 fds = [int(x) for x in sys.argv[2:]]
150 d = fishdescriptor.fish.Donor(pid)