timport.c - plan9port - [fork] Plan 9 from user space
HTML git clone git://src.adamsgaard.dk/plan9port
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
timport.c (5099B)
---
1 #include <u.h>
2 #include <libc.h>
3 #include <regexp.h>
4 #include <thread.h>
5 #include <fcall.h>
6
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;
17
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*);
24
25 char *REXEXEC = "ssh";
26 char *prog = "import";
27
28 enum
29 {
30 Stack= 32*1024
31 };
32
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 }
39
40 void
41 fatal(char *fmt, ...)
42 {
43 char buf[256];
44 va_list arg;
45
46 va_start(arg, fmt);
47 vseprint(buf, buf+sizeof buf, fmt, arg);
48 va_end(arg);
49
50 fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
51 threadexitsall("fatal");
52 }
53
54 int
55 threadmaybackground(void)
56 {
57 return 1;
58 }
59
60 void
61 threadmain(int argc, char *argv[])
62 {
63 int dofork;
64 int rem;
65 void (*fn)(void*);
66
67 dofork = 1;
68 rem = 0;
69 ns = nil;
70 srv = "plumb";
71
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
95
96 if(debug){
97 char *dbgfile;
98
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);
106 }
107
108
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);
119 }
120
121 fn = localside;
122 if(rem+export == 1)
123 fn = remoteside;
124
125 if(rem || !dofork)
126 fn(nil);
127 else
128 proccreate(fn, nil, Stack);
129 }
130
131
132 void
133 localside(void *arg)
134 {
135 USED(arg);
136
137 /* start a loal service */
138 srvfd = post(srv);
139
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);
147 }
148
149 /* post a local service */
150 int
151 post(char *srv)
152 {
153 int p[2];
154
155 if(pipe(p) < 0)
156 fatal("can't create pipe: %r");
157
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]);
162
163 return p[0];
164 }
165
166 /* start a stub on the remote server */
167 int
168 call(char *rsys, char *ns, char *srv)
169 {
170 int p[2];
171 int ac;
172 char *av[12];
173 char buf[2];
174
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;
187 }
188 av[ac++] = "-s";
189 av[ac++] = srv;
190 if(export)
191 av[ac++] = "-x";
192 av[ac] = 0;
193
194 if(debug){
195 fprint(dfd, "execing ");
196 for(ac = 0; av[ac]; ac++)
197 fprint(dfd, " %s", av[ac]);
198 fprint(dfd, "\n");
199 }
200
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;
213 }
214 close(p[1]);
215
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];
226 }
227 if(debug)
228 fprint(dfd, "got OK\n");
229
230 return p[0];
231 }
232
233 enum
234 {
235 BLEN=16*1024
236 };
237
238 void
239 shuffle(void *arg)
240 {
241 int *fd;
242 char *buf, *tbuf;
243 int n;
244 Fcall *t;
245
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;
256 }
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);
267 }
268 if(write(fd[1], buf, n) != n)
269 break;
270 }
271 threadexitsall(0);
272 }
273
274 void
275 remoteside(void *v)
276 {
277 int srv_to_net[2];
278 int net_to_srv[2];
279 char *addr;
280 int srvfd;
281
282 if(ns == nil)
283 ns = getns();
284
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);
290
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);
297
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);
305
306 threadexitsall(0);
307 }
308
309 void*
310 emalloc(int size)
311 {
312 void *x;
313
314 x = malloc(size);
315 if(x == nil)
316 fatal("allocation fails: %r");
317 return x;
318 }