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 enum29 {30 Stack= 32*102431 };33 void34 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 void41 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 void55 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 }ARGEND90 if(debug){91 char *dbgfile;93 if(rem)94 dbgfile = smprint("/tmp/%s.export.debug", getuser());95 else96 dbgfile = smprint("/tmp/%s.import.debug", getuser());97 dfd = create(dbgfile, OWRITE, 0664);98 free(dbgfile);99 fmtinstall('F', fcallfmt);100 }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);113 }115 fn = localside;116 if(rem+export == 1)117 fn = remoteside;119 if(rem || !dofork)120 fn(nil);121 else122 proccreate(fn, nil, Stack);123 }126 void127 localside(void *arg)128 {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);141 }143 /* post a local service */144 int145 post(char *srv)146 {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], "plumb", nil) < 0)154 fatal("post9pservice plumb: %r");155 close(p[1]);157 return p[0];158 }160 /* start a stub on the remote server */161 int162 call(char *rsys, char *ns, char *srv)163 {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;181 }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");193 }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;207 }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];220 }221 if(debug)222 fprint(dfd, "got OK\n");224 return p[0];225 }227 enum228 {229 BLEN=16*1024230 };232 void233 shuffle(void *arg)234 {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;250 }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 else260 fprint(dfd, "%d->%d %F\n", fd[0], fd[1], t);261 }262 if(write(fd[1], buf, n) != n)263 break;264 }265 }267 void268 remoteside(void *v)269 {270 int srv_to_net[2];271 int net_to_srv[2];272 char *addr;273 int srvfd;275 if(ns == nil)276 ns = getns();278 addr = smprint("unix!%s/%s", ns, srv);279 if(addr == nil)280 fatal("%r");281 if(debug)282 fprint(dfd, "remoteside starting %s\n", addr);284 srvfd = dial(addr, 0, 0, 0);285 if(srvfd < 0)286 fatal("dial %s: %r", addr);287 if(debug)288 fprint(dfd, "remoteside dial %s succeeded\n", addr);289 fcntl(srvfd, F_SETFL, FD_CLOEXEC);291 /* threads to shuffle messages each way */292 srv_to_net[0] = srvfd;293 srv_to_net[1] = netfd[1];294 proccreate(shuffle, srv_to_net, Stack);295 net_to_srv[0] = netfd[0];296 net_to_srv[1] = srvfd;297 shuffle(net_to_srv);299 threadexitsall(0);300 }302 void*303 emalloc(int size)304 {305 void *x;307 x = malloc(size);308 if(x == nil)309 fatal("allocation fails: %r");310 return x;311 }