import.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 }