|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <regexp.h> | 
|  | #include <thread.h> | 
|  | #include <fcall.h> | 
|  |  | 
|  | int debug; | 
|  | int dfd; | 
|  | int srvfd; | 
|  | int netfd[2]; | 
|  | int srv_to_net[2]; | 
|  | int net_to_srv[2]; | 
|  | char *srv; | 
|  | char	*addr; | 
|  | char *ns; | 
|  | int export; | 
|  |  | 
|  | void	shuffle(void *arg); | 
|  | int	post(char *srv); | 
|  | void	remoteside(void*); | 
|  | int	call(char *rsys, char *ns, char *srv); | 
|  | void*	emalloc(int size); | 
|  | void	localside(void*); | 
|  |  | 
|  | char *REXEXEC = "ssh"; | 
|  | char *prog = "import"; | 
|  |  | 
|  | enum | 
|  | { | 
|  | Stack= 32*1024 | 
|  | }; | 
|  |  | 
|  | void | 
|  | usage(void) | 
|  | { | 
|  | fprint(2, "usage: %s [-df] [-s service] [-n remote-ns] [-p remote-prog] remote-system\n", argv0); | 
|  | threadexitsall("usage"); | 
|  | } | 
|  |  | 
|  | void | 
|  | fatal(char *fmt, ...) | 
|  | { | 
|  | char buf[256]; | 
|  | va_list arg; | 
|  |  | 
|  | va_start(arg, fmt); | 
|  | vseprint(buf, buf+sizeof buf, fmt, arg); | 
|  | va_end(arg); | 
|  |  | 
|  | fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf); | 
|  | threadexitsall("fatal"); | 
|  | } | 
|  |  | 
|  | void | 
|  | threadmain(int argc, char *argv[]) | 
|  | { | 
|  | int dofork; | 
|  | int rem; | 
|  | void (*fn)(void*); | 
|  |  | 
|  | dofork = 1; | 
|  | rem = 0; | 
|  | ns = nil; | 
|  | srv = "plumb"; | 
|  |  | 
|  | ARGBEGIN{ | 
|  | case 'd': | 
|  | debug = 1; | 
|  | break; | 
|  | case 'f': | 
|  | dofork = 0; | 
|  | break; | 
|  | case 'n':	/* name of remote namespace */ | 
|  | ns = EARGF(usage()); | 
|  | break; | 
|  | case 'p': | 
|  | prog = EARGF(usage()); | 
|  | break; | 
|  | case 's':	/* name of service */ | 
|  | srv = EARGF(usage()); | 
|  | break; | 
|  | case 'R': | 
|  | rem = 1; | 
|  | break; | 
|  | case 'x': | 
|  | export = 1; | 
|  | break; | 
|  | }ARGEND | 
|  |  | 
|  | if(debug){ | 
|  | char *dbgfile; | 
|  |  | 
|  | if(rem) | 
|  | dbgfile = smprint("/tmp/%s.export.debug", getuser()); | 
|  | else | 
|  | dbgfile = smprint("/tmp/%s.import.debug", getuser()); | 
|  | dfd = create(dbgfile, OWRITE, 0664); | 
|  | free(dbgfile); | 
|  | fmtinstall('F', fcallfmt); | 
|  | } | 
|  |  | 
|  |  | 
|  | if(rem){ | 
|  | netfd[0] = 0; | 
|  | netfd[1] = 1; | 
|  | write(1, "OK", 2); | 
|  | }else{ | 
|  | if(argc != 1) | 
|  | usage(); | 
|  | addr = argv[0]; | 
|  | /* connect to remote service */ | 
|  | netfd[0] = netfd[1] = call(addr, ns, srv); | 
|  | } | 
|  |  | 
|  | fn = localside; | 
|  | if(rem+export == 1) | 
|  | fn = remoteside; | 
|  |  | 
|  | if(rem || !dofork) | 
|  | fn(nil); | 
|  | else | 
|  | proccreate(fn, nil, Stack); | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | localside(void *arg) | 
|  | { | 
|  | USED(arg); | 
|  |  | 
|  | /* start a loal service */ | 
|  | srvfd = post(srv); | 
|  |  | 
|  | /* threads to shuffle messages each way */ | 
|  | srv_to_net[0] = srvfd; | 
|  | srv_to_net[1] = netfd[1]; | 
|  | proccreate(shuffle, srv_to_net, Stack); | 
|  | net_to_srv[0] = netfd[0]; | 
|  | net_to_srv[1] = srvfd; | 
|  | shuffle(net_to_srv); | 
|  | } | 
|  |  | 
|  | /* post a local service */ | 
|  | int | 
|  | post(char *srv) | 
|  | { | 
|  | int p[2]; | 
|  |  | 
|  | if(pipe(p) < 0) | 
|  | fatal("can't create pipe: %r"); | 
|  |  | 
|  | /* 0 will be server end, 1 will be client end */ | 
|  | if(post9pservice(p[1], srv, nil) < 0) | 
|  | fatal("post9pservice plumb: %r"); | 
|  | close(p[1]); | 
|  |  | 
|  | return p[0]; | 
|  | } | 
|  |  | 
|  | /* start a stub on the remote server */ | 
|  | int | 
|  | call(char *rsys, char *ns, char *srv) | 
|  | { | 
|  | int p[2]; | 
|  | int ac; | 
|  | char *av[12]; | 
|  | char buf[2]; | 
|  |  | 
|  | if(pipe(p) < 0) | 
|  | fatal("can't create pipe: %r"); | 
|  | ac = 0; | 
|  | av[ac++] = REXEXEC; | 
|  | av[ac++] = rsys; | 
|  | av[ac++] = prog; | 
|  | if(debug) | 
|  | av[ac++] = "-d"; | 
|  | av[ac++] = "-R"; | 
|  | if(ns != nil){ | 
|  | av[ac++] = "-n"; | 
|  | av[ac++] = ns; | 
|  | } | 
|  | av[ac++] = "-s"; | 
|  | av[ac++] = srv; | 
|  | if(export) | 
|  | av[ac++] = "-x"; | 
|  | av[ac] = 0; | 
|  |  | 
|  | if(debug){ | 
|  | fprint(dfd, "execing "); | 
|  | for(ac = 0; av[ac]; ac++) | 
|  | fprint(dfd, " %s", av[ac]); | 
|  | fprint(dfd, "\n"); | 
|  | } | 
|  |  | 
|  | switch(fork()){ | 
|  | case -1: | 
|  | fatal("%r"); | 
|  | case 0: | 
|  | dup(p[1], 0); | 
|  | dup(p[1], 1); | 
|  | close(p[0]); | 
|  | close(p[1]); | 
|  | execvp(REXEXEC, av); | 
|  | fatal("can't exec %s", REXEXEC); | 
|  | default: | 
|  | break; | 
|  | } | 
|  | close(p[1]); | 
|  |  | 
|  | /* ignore crap that might come out of the .profile */ | 
|  | /* keep reading till we have an "OK" */ | 
|  | if(read(p[0], &buf[0], 1) != 1) | 
|  | fatal("EOF"); | 
|  | for(;;){ | 
|  | if(read(p[0], &buf[1], 1) != 1) | 
|  | fatal("EOF"); | 
|  | if(strncmp(buf, "OK", 2) == 0) | 
|  | break; | 
|  | buf[0] = buf[1]; | 
|  | } | 
|  | if(debug) | 
|  | fprint(dfd, "got OK\n"); | 
|  |  | 
|  | return p[0]; | 
|  | } | 
|  |  | 
|  | enum | 
|  | { | 
|  | BLEN=16*1024 | 
|  | }; | 
|  |  | 
|  | void | 
|  | shuffle(void *arg) | 
|  | { | 
|  | int *fd; | 
|  | char *buf, *tbuf; | 
|  | int n; | 
|  | Fcall *t; | 
|  |  | 
|  | fd = (int*)arg; | 
|  | buf = emalloc(BLEN+1); | 
|  | t = nil; | 
|  | tbuf = nil; | 
|  | for(;;){ | 
|  | n = read9pmsg(fd[0], buf, BLEN); | 
|  | if(n <= 0){ | 
|  | if(debug) | 
|  | fprint(dfd, "%d->%d read returns %d: %r\n", fd[0], fd[1], n); | 
|  | break; | 
|  | } | 
|  | if(debug){ | 
|  | if(t == nil) | 
|  | t = emalloc(sizeof(Fcall)); | 
|  | if(tbuf == nil) | 
|  | tbuf = emalloc(BLEN+1); | 
|  | memmove(tbuf, buf, n);	/* because convM2S is destructive */ | 
|  | if(convM2S((uchar*)tbuf, n, t) != n) | 
|  | fprint(dfd, "%d->%d convert error in convM2S", fd[0], fd[1]); | 
|  | else | 
|  | fprint(dfd, "%d->%d %F\n", fd[0], fd[1], t); | 
|  | } | 
|  | if(write(fd[1], buf, n) != n) | 
|  | break; | 
|  | } | 
|  | threadexitsall(0); | 
|  | } | 
|  |  | 
|  | void | 
|  | remoteside(void *v) | 
|  | { | 
|  | int srv_to_net[2]; | 
|  | int net_to_srv[2]; | 
|  | char *addr; | 
|  | int srvfd; | 
|  |  | 
|  | if(ns == nil) | 
|  | ns = getns(); | 
|  |  | 
|  | addr = smprint("unix!%s/%s", ns, srv); | 
|  | if(addr == nil) | 
|  | fatal("%r"); | 
|  | if(debug) | 
|  | fprint(dfd, "remoteside starting %s\n", addr); | 
|  |  | 
|  | srvfd = dial(addr, 0, 0, 0); | 
|  | if(srvfd < 0) | 
|  | fatal("dial %s: %r", addr); | 
|  | if(debug) | 
|  | fprint(dfd, "remoteside dial %s succeeded\n", addr); | 
|  | fcntl(srvfd, F_SETFL, FD_CLOEXEC); | 
|  |  | 
|  | /* threads to shuffle messages each way */ | 
|  | srv_to_net[0] = srvfd; | 
|  | srv_to_net[1] = netfd[1]; | 
|  | proccreate(shuffle, srv_to_net, Stack); | 
|  | net_to_srv[0] = netfd[0]; | 
|  | net_to_srv[1] = srvfd; | 
|  | shuffle(net_to_srv); | 
|  |  | 
|  | threadexitsall(0); | 
|  | } | 
|  |  | 
|  | void* | 
|  | emalloc(int size) | 
|  | { | 
|  | void *x; | 
|  |  | 
|  | x = malloc(size); | 
|  | if(x == nil) | 
|  | fatal("allocation fails: %r"); | 
|  | return x; | 
|  | } |