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 int
55 threadmaybackground(void)
56 {
57 return 1;
58 }
60 void
61 threadmain(int argc, char *argv[])
62 {
63 int dofork;
64 int rem;
65 void (*fn)(void*);
67 dofork = 1;
68 rem = 0;
69 ns = nil;
70 srv = "plumb";
72 ARGBEGIN{
73 case 'd':
74 debug = 1;
75 break;
76 case 'f':
77 dofork = 0;
78 break;
79 case 'n': /* name of remote namespace */
80 ns = EARGF(usage());
81 break;
82 case 'p':
83 prog = EARGF(usage());
84 break;
85 case 's': /* name of service */
86 srv = EARGF(usage());
87 break;
88 case 'R':
89 rem = 1;
90 break;
91 case 'x':
92 export = 1;
93 break;
94 }ARGEND
96 if(debug){
97 char *dbgfile;
99 if(rem)
100 dbgfile = smprint("/tmp/%s.export.debug", getuser());
101 else
102 dbgfile = smprint("/tmp/%s.import.debug", getuser());
103 dfd = create(dbgfile, OWRITE, 0664);
104 free(dbgfile);
105 fmtinstall('F', fcallfmt);
109 if(rem){
110 netfd[0] = 0;
111 netfd[1] = 1;
112 write(1, "OK", 2);
113 }else{
114 if(argc != 1)
115 usage();
116 addr = argv[0];
117 /* connect to remote service */
118 netfd[0] = netfd[1] = call(addr, ns, srv);
121 fn = localside;
122 if(rem+export == 1)
123 fn = remoteside;
125 if(rem || !dofork)
126 fn(nil);
127 else
128 proccreate(fn, nil, Stack);
132 void
133 localside(void *arg)
135 USED(arg);
137 /* start a loal service */
138 srvfd = post(srv);
140 /* threads to shuffle messages each way */
141 srv_to_net[0] = srvfd;
142 srv_to_net[1] = netfd[1];
143 proccreate(shuffle, srv_to_net, Stack);
144 net_to_srv[0] = netfd[0];
145 net_to_srv[1] = srvfd;
146 shuffle(net_to_srv);
149 /* post a local service */
150 int
151 post(char *srv)
153 int p[2];
155 if(pipe(p) < 0)
156 fatal("can't create pipe: %r");
158 /* 0 will be server end, 1 will be client end */
159 if(post9pservice(p[1], srv, nil) < 0)
160 fatal("post9pservice plumb: %r");
161 close(p[1]);
163 return p[0];
166 /* start a stub on the remote server */
167 int
168 call(char *rsys, char *ns, char *srv)
170 int p[2];
171 int ac;
172 char *av[12];
173 char buf[2];
175 if(pipe(p) < 0)
176 fatal("can't create pipe: %r");
177 ac = 0;
178 av[ac++] = REXEXEC;
179 av[ac++] = rsys;
180 av[ac++] = prog;
181 if(debug)
182 av[ac++] = "-d";
183 av[ac++] = "-R";
184 if(ns != nil){
185 av[ac++] = "-n";
186 av[ac++] = ns;
188 av[ac++] = "-s";
189 av[ac++] = srv;
190 if(export)
191 av[ac++] = "-x";
192 av[ac] = 0;
194 if(debug){
195 fprint(dfd, "execing ");
196 for(ac = 0; av[ac]; ac++)
197 fprint(dfd, " %s", av[ac]);
198 fprint(dfd, "\n");
201 switch(fork()){
202 case -1:
203 fatal("%r");
204 case 0:
205 dup(p[1], 0);
206 dup(p[1], 1);
207 close(p[0]);
208 close(p[1]);
209 execvp(REXEXEC, av);
210 fatal("can't exec %s", REXEXEC);
211 default:
212 break;
214 close(p[1]);
216 /* ignore crap that might come out of the .profile */
217 /* keep reading till we have an "OK" */
218 if(read(p[0], &buf[0], 1) != 1)
219 fatal("EOF");
220 for(;;){
221 if(read(p[0], &buf[1], 1) != 1)
222 fatal("EOF");
223 if(strncmp(buf, "OK", 2) == 0)
224 break;
225 buf[0] = buf[1];
227 if(debug)
228 fprint(dfd, "got OK\n");
230 return p[0];
233 enum
235 BLEN=16*1024
236 };
238 void
239 shuffle(void *arg)
241 int *fd;
242 char *buf, *tbuf;
243 int n;
244 Fcall *t;
246 fd = (int*)arg;
247 buf = emalloc(BLEN+1);
248 t = nil;
249 tbuf = nil;
250 for(;;){
251 n = read9pmsg(fd[0], buf, BLEN);
252 if(n <= 0){
253 if(debug)
254 fprint(dfd, "%d->%d read returns %d: %r\n", fd[0], fd[1], n);
255 break;
257 if(debug){
258 if(t == nil)
259 t = emalloc(sizeof(Fcall));
260 if(tbuf == nil)
261 tbuf = emalloc(BLEN+1);
262 memmove(tbuf, buf, n); /* because convM2S is destructive */
263 if(convM2S((uchar*)tbuf, n, t) != n)
264 fprint(dfd, "%d->%d convert error in convM2S", fd[0], fd[1]);
265 else
266 fprint(dfd, "%d->%d %F\n", fd[0], fd[1], t);
268 if(write(fd[1], buf, n) != n)
269 break;
271 threadexitsall(0);
274 void
275 remoteside(void *v)
277 int srv_to_net[2];
278 int net_to_srv[2];
279 char *addr;
280 int srvfd;
282 if(ns == nil)
283 ns = getns();
285 addr = smprint("unix!%s/%s", ns, srv);
286 if(addr == nil)
287 fatal("%r");
288 if(debug)
289 fprint(dfd, "remoteside starting %s\n", addr);
291 srvfd = dial(addr, 0, 0, 0);
292 if(srvfd < 0)
293 fatal("dial %s: %r", addr);
294 if(debug)
295 fprint(dfd, "remoteside dial %s succeeded\n", addr);
296 fcntl(srvfd, F_SETFL, FD_CLOEXEC);
298 /* threads to shuffle messages each way */
299 srv_to_net[0] = srvfd;
300 srv_to_net[1] = netfd[1];
301 proccreate(shuffle, srv_to_net, Stack);
302 net_to_srv[0] = netfd[0];
303 net_to_srv[1] = srvfd;
304 shuffle(net_to_srv);
306 threadexitsall(0);
309 void*
310 emalloc(int size)
312 void *x;
314 x = malloc(size);
315 if(x == nil)
316 fatal("allocation fails: %r");
317 return x;