plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

import.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 }