Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <regexp.h>
4 #include <thread.h>
5 #include <fcall.h>
7 int debug;
8 int dfd;
9 int srvfd;
10 int netfd;
11 int srv_to_net[2];
12 int net_to_srv[2];
13 char *srv;
14 char *addr;
15 char *ns;
17 void shuffle(void *arg);
18 int post(char *srv);
19 void remoteside(char *ns, char *srv);
20 int call(char *rsys, char *ns, char *srv);
21 void* emalloc(int size);
22 void runproc(void *arg);
24 char *REXEXEC = "ssh";
25 char *prog = "import";
27 enum
28 {
29 Stack= 32*1024,
30 };
32 void
33 usage(void)
34 {
35 fprint(2, "usage: %s [-df] [-s service] [-n remote-ns] [-p remote-prog] remote-system\n", argv0);
36 threadexitsall("usage");
37 }
39 void
40 fatal(char *fmt, ...)
41 {
42 char buf[256];
43 va_list arg;
45 va_start(arg, fmt);
46 vseprint(buf, buf+sizeof buf, fmt, arg);
47 va_end(arg);
49 fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
50 threadexitsall("fatal");
51 }
53 void
54 threadmain(int argc, char *argv[])
55 {
56 int dofork;
57 int rem;
59 dofork = 1;
60 rem = 0;
61 ns = nil;
62 srv = "plumb";
64 ARGBEGIN{
65 case 'd':
66 debug = 1;
67 break;
68 case 'f':
69 dofork = 0;
70 break;
71 case 'n': // name of remote namespace
72 ns = EARGF(usage());
73 break;
74 case 'p':
75 prog = EARGF(usage());
76 break;
77 case 's': // name of service
78 srv = EARGF(usage());
79 break;
80 case 'R':
81 rem = 1;
82 break;
83 }ARGEND
85 if(debug){
86 char *dbgfile;
88 if(rem)
89 dbgfile = smprint("/tmp/%s.export.debug", getuser());
90 else
91 dbgfile = smprint("/tmp/%s.import.debug", getuser());
92 dfd = create(dbgfile, OWRITE, 0664);
93 free(dbgfile);
94 fmtinstall('F', fcallfmt);
95 }
97 // is this the remote side?
98 if(rem){
99 if(srv == nil)
100 fatal("-R requires -s");
101 remoteside(ns, srv);
102 threadexitsall(0);
105 if(argc != 1)
106 usage();
108 addr = argv[0];
110 if(dofork)
111 proccreate(runproc, nil, Stack);
112 else
113 runproc(nil);
116 void
117 runproc(void *arg)
119 USED(arg);
121 // start a loal service and connect to remote service
122 srvfd = post(srv);
123 netfd = call(addr, ns, srv);
125 // threads to shuffle messages each way
126 srv_to_net[0] = srvfd;
127 srv_to_net[1] = netfd;
128 proccreate(shuffle, srv_to_net, Stack);
129 net_to_srv[0] = netfd;
130 net_to_srv[1] = srvfd;
131 shuffle(net_to_srv);
134 /* post a local service */
135 int
136 post(char *srv)
138 int p[2];
140 if(pipe(p) < 0)
141 fatal("can't create pipe: %r");
143 /* 0 will be server end, 1 will be client end */
144 if(post9pservice(p[1], "plumb") < 0)
145 fatal("post9pservice plumb: %r");
146 close(p[1]);
148 return p[0];
151 /* start a stub on the remote server */
152 int
153 call(char *rsys, char *ns, char *srv)
155 int p[2];
156 int ac;
157 char *av[12];
158 char buf[2];
160 if(pipe(p) < 0)
161 fatal("can't create pipe: %r");
162 ac = 0;
163 av[ac++] = REXEXEC;
164 av[ac++] = rsys;
165 av[ac++] = prog;
166 if(debug)
167 av[ac++] = "-d";
168 av[ac++] = "-R";
169 if(ns != nil){
170 av[ac++] = "-n";
171 av[ac++] = ns;
173 av[ac++] = "-s";
174 av[ac++] = srv;
175 av[ac] = 0;
177 if(debug){
178 fprint(dfd, "execing ");
179 for(ac = 0; av[ac]; ac++)
180 fprint(dfd, " %s", av[ac]);
181 fprint(dfd, "\n");
184 switch(fork()){
185 case -1:
186 fatal("%r");
187 case 0:
188 dup(p[1], 0);
189 dup(p[1], 1);
190 close(p[0]);
191 close(p[1]);
192 execvp(REXEXEC, av);
193 fatal("can't exec %s", REXEXEC);
194 default:
195 break;
197 close(p[1]);
199 // ignore crap that might come out of the .profile
200 // keep reading till we have an "OK"
201 if(read(p[0], &buf[0], 1) != 1)
202 fatal("EOF");
203 for(;;){
204 if(read(p[0], &buf[1], 1) != 1)
205 fatal("EOF");
206 if(strncmp(buf, "OK", 2) == 0)
207 break;
208 buf[0] = buf[1];
210 if(debug)
211 fprint(dfd, "got OK\n");
213 return p[0];
216 enum
218 BLEN=16*1024
219 };
221 void
222 shuffle(void *arg)
224 int *fd;
225 char *buf, *tbuf;
226 int n;
227 Fcall *t;
229 fd = (int*)arg;
230 buf = emalloc(BLEN+1);
231 t = nil;
232 tbuf = nil;
233 for(;;){
234 n = read9pmsg(fd[0], buf, BLEN);
235 if(n <= 0){
236 if(debug)
237 fprint(dfd, "%d->%d read returns %d: %r\n", fd[0], fd[1], n);
238 break;
240 if(debug){
241 if(t == nil)
242 t = emalloc(sizeof(Fcall));
243 if(tbuf == nil)
244 tbuf = emalloc(BLEN+1);
245 memmove(tbuf, buf, n); // because convM2S is destructive
246 if(convM2S((uchar*)tbuf, n, t) != n)
247 fprint(dfd, "%d->%d convert error in convM2S", fd[0], fd[1]);
248 else
249 fprint(dfd, "%d->%d %F\n", fd[0], fd[1], t);
251 if(write(fd[1], buf, n) != n)
252 break;
256 void
257 remoteside(char *ns, char *srv)
259 int srv_to_net[2];
260 int net_to_srv[2];
261 char *addr;
262 int srvfd;
264 if(ns == nil)
265 ns = getns();
267 addr = smprint("unix!%s/%s", ns, srv);
268 if(addr == nil)
269 fatal("%r");
270 if(debug)
271 fprint(dfd, "remoteside starting %s\n", addr);
273 srvfd = dial(addr, 0, 0, 0);
274 if(srvfd < 0)
275 fatal("dial %s: %r", addr);
276 if(debug)
277 fprint(dfd, "remoteside dial %s succeeded\n", addr);
278 fcntl(srvfd, F_SETFL, FD_CLOEXEC);
280 write(1, "OK", 2);
282 /* threads to shuffle messages each way */
283 srv_to_net[0] = srvfd;
284 srv_to_net[1] = 1;
285 proccreate(shuffle, srv_to_net, Stack);
286 net_to_srv[0] = 0;
287 net_to_srv[1] = srvfd;
288 shuffle(net_to_srv);
290 threadexitsall(0);
293 void*
294 emalloc(int size)
296 void *x;
298 x = malloc(size);
299 if(x == nil)
300 fatal("allocation fails: %r");
301 return x;