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[2];
11 int srv_to_net[2];
12 int net_to_srv[2];
13 char *srv;
14 char *addr;
15 char *ns;
16 int export;
18 void shuffle(void *arg);
19 int post(char *srv);
20 void remoteside(void*);
21 int call(char *rsys, char *ns, char *srv);
22 void* emalloc(int size);
23 void localside(void*);
25 char *REXEXEC = "ssh";
26 char *prog = "import";
28 enum
29 {
30 Stack= 32*1024
31 };
33 void
34 usage(void)
35 {
36 fprint(2, "usage: %s [-df] [-s service] [-n remote-ns] [-p remote-prog] remote-system\n", argv0);
37 threadexitsall("usage");
38 }
40 void
41 fatal(char *fmt, ...)
42 {
43 char buf[256];
44 va_list arg;
46 va_start(arg, fmt);
47 vseprint(buf, buf+sizeof buf, fmt, arg);
48 va_end(arg);
50 fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
51 threadexitsall("fatal");
52 }
54 void
55 threadmain(int argc, char *argv[])
56 {
57 int dofork;
58 int rem;
59 void (*fn)(void*);
61 dofork = 1;
62 rem = 0;
63 ns = nil;
64 srv = "plumb";
66 ARGBEGIN{
67 case 'd':
68 debug = 1;
69 break;
70 case 'f':
71 dofork = 0;
72 break;
73 case 'n': /* name of remote namespace */
74 ns = EARGF(usage());
75 break;
76 case 'p':
77 prog = EARGF(usage());
78 break;
79 case 's': /* name of service */
80 srv = EARGF(usage());
81 break;
82 case 'R':
83 rem = 1;
84 break;
85 case 'x':
86 export = 1;
87 break;
88 }ARGEND
90 if(debug){
91 char *dbgfile;
93 if(rem)
94 dbgfile = smprint("/tmp/%s.export.debug", getuser());
95 else
96 dbgfile = smprint("/tmp/%s.import.debug", getuser());
97 dfd = create(dbgfile, OWRITE, 0664);
98 free(dbgfile);
99 fmtinstall('F', fcallfmt);
103 if(rem){
104 netfd[0] = 0;
105 netfd[1] = 1;
106 write(1, "OK", 2);
107 }else{
108 if(argc != 1)
109 usage();
110 addr = argv[0];
111 /* connect to remote service */
112 netfd[0] = netfd[1] = call(addr, ns, srv);
115 fn = localside;
116 if(rem+export == 1)
117 fn = remoteside;
119 if(rem || !dofork)
120 fn(nil);
121 else
122 proccreate(fn, nil, Stack);
126 void
127 localside(void *arg)
129 USED(arg);
131 /* start a loal service */
132 srvfd = post(srv);
134 /* threads to shuffle messages each way */
135 srv_to_net[0] = srvfd;
136 srv_to_net[1] = netfd[1];
137 proccreate(shuffle, srv_to_net, Stack);
138 net_to_srv[0] = netfd[0];
139 net_to_srv[1] = srvfd;
140 shuffle(net_to_srv);
143 /* post a local service */
144 int
145 post(char *srv)
147 int p[2];
149 if(pipe(p) < 0)
150 fatal("can't create pipe: %r");
152 /* 0 will be server end, 1 will be client end */
153 if(post9pservice(p[1], srv, nil) < 0)
154 fatal("post9pservice plumb: %r");
155 close(p[1]);
157 return p[0];
160 /* start a stub on the remote server */
161 int
162 call(char *rsys, char *ns, char *srv)
164 int p[2];
165 int ac;
166 char *av[12];
167 char buf[2];
169 if(pipe(p) < 0)
170 fatal("can't create pipe: %r");
171 ac = 0;
172 av[ac++] = REXEXEC;
173 av[ac++] = rsys;
174 av[ac++] = prog;
175 if(debug)
176 av[ac++] = "-d";
177 av[ac++] = "-R";
178 if(ns != nil){
179 av[ac++] = "-n";
180 av[ac++] = ns;
182 av[ac++] = "-s";
183 av[ac++] = srv;
184 if(export)
185 av[ac++] = "-x";
186 av[ac] = 0;
188 if(debug){
189 fprint(dfd, "execing ");
190 for(ac = 0; av[ac]; ac++)
191 fprint(dfd, " %s", av[ac]);
192 fprint(dfd, "\n");
195 switch(fork()){
196 case -1:
197 fatal("%r");
198 case 0:
199 dup(p[1], 0);
200 dup(p[1], 1);
201 close(p[0]);
202 close(p[1]);
203 execvp(REXEXEC, av);
204 fatal("can't exec %s", REXEXEC);
205 default:
206 break;
208 close(p[1]);
210 /* ignore crap that might come out of the .profile */
211 /* keep reading till we have an "OK" */
212 if(read(p[0], &buf[0], 1) != 1)
213 fatal("EOF");
214 for(;;){
215 if(read(p[0], &buf[1], 1) != 1)
216 fatal("EOF");
217 if(strncmp(buf, "OK", 2) == 0)
218 break;
219 buf[0] = buf[1];
221 if(debug)
222 fprint(dfd, "got OK\n");
224 return p[0];
227 enum
229 BLEN=16*1024
230 };
232 void
233 shuffle(void *arg)
235 int *fd;
236 char *buf, *tbuf;
237 int n;
238 Fcall *t;
240 fd = (int*)arg;
241 buf = emalloc(BLEN+1);
242 t = nil;
243 tbuf = nil;
244 for(;;){
245 n = read9pmsg(fd[0], buf, BLEN);
246 if(n <= 0){
247 if(debug)
248 fprint(dfd, "%d->%d read returns %d: %r\n", fd[0], fd[1], n);
249 break;
251 if(debug){
252 if(t == nil)
253 t = emalloc(sizeof(Fcall));
254 if(tbuf == nil)
255 tbuf = emalloc(BLEN+1);
256 memmove(tbuf, buf, n); /* because convM2S is destructive */
257 if(convM2S((uchar*)tbuf, n, t) != n)
258 fprint(dfd, "%d->%d convert error in convM2S", fd[0], fd[1]);
259 else
260 fprint(dfd, "%d->%d %F\n", fd[0], fd[1], t);
262 if(write(fd[1], buf, n) != n)
263 break;
265 threadexitsall(0);
268 void
269 remoteside(void *v)
271 int srv_to_net[2];
272 int net_to_srv[2];
273 char *addr;
274 int srvfd;
276 if(ns == nil)
277 ns = getns();
279 addr = smprint("unix!%s/%s", ns, srv);
280 if(addr == nil)
281 fatal("%r");
282 if(debug)
283 fprint(dfd, "remoteside starting %s\n", addr);
285 srvfd = dial(addr, 0, 0, 0);
286 if(srvfd < 0)
287 fatal("dial %s: %r", addr);
288 if(debug)
289 fprint(dfd, "remoteside dial %s succeeded\n", addr);
290 fcntl(srvfd, F_SETFL, FD_CLOEXEC);
292 /* threads to shuffle messages each way */
293 srv_to_net[0] = srvfd;
294 srv_to_net[1] = netfd[1];
295 proccreate(shuffle, srv_to_net, Stack);
296 net_to_srv[0] = netfd[0];
297 net_to_srv[1] = srvfd;
298 shuffle(net_to_srv);
300 threadexitsall(0);
303 void*
304 emalloc(int size)
306 void *x;
308 x = malloc(size);
309 if(x == nil)
310 fatal("allocation fails: %r");
311 return x;