URI:
       timport.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       timport.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 }