commit 1ab0f6f00bbbb313ddc79f3905546124363079d6 from: rsc date: Fri Jan 07 20:41:13 2005 UTC new program from presotto commit - 8953da378543c597229958fc2c39e0986594d017 commit + 1ab0f6f00bbbb313ddc79f3905546124363079d6 blob - /dev/null blob + 88d7c532ce46ea3898d72690320ca47f220a9cf1 (mode 644) --- /dev/null +++ src/cmd/import.c @@ -0,0 +1,302 @@ +#include +#include +#include +#include +#include + +int debug; +int dfd; +int srvfd; +int netfd; +int srv_to_net[2]; +int net_to_srv[2]; +char *srv; +char *addr; +char *ns; + +void shuffle(void *arg); +int post(char *srv); +void remoteside(char *ns, char *srv); +int call(char *rsys, char *ns, char *srv); +void* emalloc(int size); +void runproc(void *arg); + +char *REXEXEC = "ssh"; +char *prog = "import"; + +enum +{ + Stack= 32*1024, +}; + +void +usage(void) +{ + fprint(2, "usage: %s [-s service] [-n remote-ns] [-fd] [-p remote-prog] remote-system\n", argv0); + exits("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 : "", buf); + threadexitsall("fatal"); +} + +void +threadmain(int argc, char *argv[]) +{ + int dofork; + int rem; + + 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; + }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); + } + + // is this the remote side? + if(rem){ + if(srv == nil) + fatal("-R requires -s"); + remoteside(ns, srv); + threadexitsall(0); + } + + if(argc != 1) + usage(); + + addr = argv[0]; + + if(dofork) + proccreate(runproc, nil, Stack); + else + runproc(nil); +} + +void +runproc(void *arg) +{ + USED(arg); + + // start a loal service and connect to remote service + srvfd = post(srv); + netfd = call(addr, ns, srv); + + // threads to shuffle messages each way + srv_to_net[0] = srvfd; + srv_to_net[1] = netfd; + proccreate(shuffle, srv_to_net, Stack); + net_to_srv[0] = netfd; + 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], "plumb") < 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; + 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(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; + } +} + +void +remoteside(char *ns, char *srv) +{ + 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); + + write(1, "OK", 2); + + /* threads to shuffle messages each way */ + srv_to_net[0] = srvfd; + srv_to_net[1] = 1; + proccreate(shuffle, srv_to_net, Stack); + net_to_srv[0] = 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; +}