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;11 int srv_to_net[2];12 int net_to_srv[2];13 char *srv;14 char *addr;15 char *ns;17 void shuffle(void *arg);18 int post(char *srv);19 void remoteside(char *ns, char *srv);20 int call(char *rsys, char *ns, char *srv);21 void* emalloc(int size);22 void runproc(void *arg);24 char *REXEXEC = "ssh";25 char *prog = "import";27 enum28 {29 Stack= 32*1024,30 };32 void33 usage(void)34 {35 fprint(2, "usage: %s [-df] [-s service] [-n remote-ns] [-p remote-prog] remote-system\n", argv0);36 exits("usage");37 }39 void40 fatal(char *fmt, ...)41 {42 char buf[256];43 va_list arg;45 va_start(arg, fmt);46 vseprint(buf, buf+sizeof buf, fmt, arg);47 va_end(arg);49 fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);50 threadexitsall("fatal");51 }53 void54 threadmain(int argc, char *argv[])55 {56 int dofork;57 int rem;59 dofork = 1;60 rem = 0;61 ns = nil;62 srv = "plumb";64 ARGBEGIN{65 case 'd':66 debug = 1;67 break;68 case 'f':69 dofork = 0;70 break;71 case 'n': // name of remote namespace72 ns = EARGF(usage());73 break;74 case 'p':75 prog = EARGF(usage());76 break;77 case 's': // name of service78 srv = EARGF(usage());79 break;80 case 'R':81 rem = 1;82 break;83 }ARGEND85 if(debug){86 char *dbgfile;88 if(rem)89 dbgfile = smprint("/tmp/%s.export.debug", getuser());90 else91 dbgfile = smprint("/tmp/%s.import.debug", getuser());92 dfd = create(dbgfile, OWRITE, 0664);93 free(dbgfile);94 fmtinstall('F', fcallfmt);95 }97 // is this the remote side?98 if(rem){99 if(srv == nil)100 fatal("-R requires -s");101 remoteside(ns, srv);102 threadexitsall(0);103 }105 if(argc != 1)106 usage();108 addr = argv[0];110 if(dofork)111 proccreate(runproc, nil, Stack);112 else113 runproc(nil);114 }116 void117 runproc(void *arg)118 {119 USED(arg);121 // start a loal service and connect to remote service122 srvfd = post(srv);123 netfd = call(addr, ns, srv);125 // threads to shuffle messages each way126 srv_to_net[0] = srvfd;127 srv_to_net[1] = netfd;128 proccreate(shuffle, srv_to_net, Stack);129 net_to_srv[0] = netfd;130 net_to_srv[1] = srvfd;131 shuffle(net_to_srv);132 }134 /* post a local service */135 int136 post(char *srv)137 {138 int p[2];140 if(pipe(p) < 0)141 fatal("can't create pipe: %r");143 /* 0 will be server end, 1 will be client end */144 if(post9pservice(p[1], "plumb") < 0)145 fatal("post9pservice plumb: %r");146 close(p[1]);148 return p[0];149 }151 /* start a stub on the remote server */152 int153 call(char *rsys, char *ns, char *srv)154 {155 int p[2];156 int ac;157 char *av[12];158 char buf[2];160 if(pipe(p) < 0)161 fatal("can't create pipe: %r");162 ac = 0;163 av[ac++] = REXEXEC;164 av[ac++] = rsys;165 av[ac++] = prog;166 if(debug)167 av[ac++] = "-d";168 av[ac++] = "-R";169 if(ns != nil){170 av[ac++] = "-n";171 av[ac++] = ns;172 }173 av[ac++] = "-s";174 av[ac++] = srv;175 av[ac] = 0;177 if(debug){178 fprint(dfd, "execing ");179 for(ac = 0; av[ac]; ac++)180 fprint(dfd, " %s", av[ac]);181 fprint(dfd, "\n");182 }184 switch(fork()){185 case -1:186 fatal("%r");187 case 0:188 dup(p[1], 0);189 dup(p[1], 1);190 close(p[0]);191 close(p[1]);192 execvp(REXEXEC, av);193 fatal("can't exec %s", REXEXEC);194 default:195 break;196 }197 close(p[1]);199 // ignore crap that might come out of the .profile200 // keep reading till we have an "OK"201 if(read(p[0], &buf[0], 1) != 1)202 fatal("EOF");203 for(;;){204 if(read(p[0], &buf[1], 1) != 1)205 fatal("EOF");206 if(strncmp(buf, "OK", 2) == 0)207 break;208 buf[0] = buf[1];209 }210 if(debug)211 fprint(dfd, "got OK\n");213 return p[0];214 }216 enum217 {218 BLEN=16*1024219 };221 void222 shuffle(void *arg)223 {224 int *fd;225 char *buf, *tbuf;226 int n;227 Fcall *t;229 fd = (int*)arg;230 buf = emalloc(BLEN+1);231 t = nil;232 tbuf = nil;233 for(;;){234 n = read9pmsg(fd[0], buf, BLEN);235 if(n <= 0){236 if(debug)237 fprint(dfd, "%d->%d read returns %d: %r\n", fd[0], fd[1], n);238 break;239 }240 if(debug){241 if(t == nil)242 t = emalloc(sizeof(Fcall));243 if(tbuf == nil)244 tbuf = emalloc(BLEN+1);245 memmove(tbuf, buf, n); // because convM2S is destructive246 if(convM2S((uchar*)tbuf, n, t) != n)247 fprint(dfd, "%d->%d convert error in convM2S", fd[0], fd[1]);248 else249 fprint(dfd, "%d->%d %F\n", fd[0], fd[1], t);250 }251 if(write(fd[1], buf, n) != n)252 break;253 }254 }256 void257 remoteside(char *ns, char *srv)258 {259 int srv_to_net[2];260 int net_to_srv[2];261 char *addr;262 int srvfd;264 if(ns == nil)265 ns = getns();267 addr = smprint("unix!%s/%s", ns, srv);268 if(addr == nil)269 fatal("%r");270 if(debug)271 fprint(dfd, "remoteside starting %s\n", addr);273 srvfd = dial(addr, 0, 0, 0);274 if(srvfd < 0)275 fatal("dial %s: %r", addr);276 if(debug)277 fprint(dfd, "remoteside dial %s succeeded\n", addr);278 fcntl(srvfd, F_SETFL, FD_CLOEXEC);280 write(1, "OK", 2);282 /* threads to shuffle messages each way */283 srv_to_net[0] = srvfd;284 srv_to_net[1] = 1;285 proccreate(shuffle, srv_to_net, Stack);286 net_to_srv[0] = 0;287 net_to_srv[1] = srvfd;288 shuffle(net_to_srv);290 threadexitsall(0);291 }293 void*294 emalloc(int size)295 {296 void *x;298 x = malloc(size);299 if(x == nil)300 fatal("allocation fails: %r");301 return x;302 }