| #include <vfs.h> | 
 | #include <kfs.h> | 
 | #include <slab.h> | 
 | #include <kmalloc.h> | 
 | #include <kref.h> | 
 | #include <string.h> | 
 | #include <stdio.h> | 
 | #include <assert.h> | 
 | #include <error.h> | 
 | #include <cpio.h> | 
 | #include <pmap.h> | 
 | #include <smp.h> | 
 |  | 
 | struct ds; | 
 |  | 
 | static struct chan *call(char *unused_char_p_t, char *, struct ds *); | 
 | static void _dial_string_parse(char *unused_char_p_t, struct ds *); | 
 |  | 
 | enum { | 
 | 	Maxstring = 128, | 
 | }; | 
 |  | 
 | struct ds { | 
 | 	char buf[Maxstring];		/* dist string */ | 
 | 	char *netdir; | 
 | 	char *proto; | 
 | 	char *rem; | 
 | 	char *local;				/* other args */ | 
 | 	char *dir; | 
 | 	struct chan **ctlp; | 
 | }; | 
 |  | 
 | /* | 
 |  *  the dialstring is of the form '[/net/]proto!dest' | 
 |  */ | 
 | struct chan *chandial(char *dest, char *local, char *dir, struct chan **ctlp) | 
 | { | 
 | 	struct ds ds; | 
 | 	char clone[Maxpath]; | 
 |  | 
 | 	ds.local = local; | 
 | 	ds.dir = dir; | 
 | 	ds.ctlp = ctlp; | 
 |  | 
 | 	_dial_string_parse(dest, &ds); | 
 | 	if (ds.netdir == 0) | 
 | 		ds.netdir = "/net"; | 
 |  | 
 | 	/* no connection server, don't translate */ | 
 | 	snprintf(clone, sizeof(clone), "%s/%s/clone", ds.netdir, ds.proto); | 
 | 	return call(clone, ds.rem, &ds); | 
 | } | 
 |  | 
 | static struct chan *call(char *clone, char *dest, struct ds *ds) | 
 | { | 
 | 	ERRSTACK(2); | 
 | 	int n; | 
 | 	struct chan *dchan, *cchan; | 
 | 	char name[Maxpath], data[Maxpath], *p; | 
 |  | 
 | 	cchan = namec(clone, Aopen, ORDWR, 0); | 
 |  | 
 | 	/* get directory name */ | 
 | 	if (waserror()) { | 
 | 		cclose(cchan); | 
 | 		nexterror(); | 
 | 	} | 
 | 	n = cchan->dev->read(cchan, name, sizeof(name) - 1, 0); | 
 | 	name[n] = 0; | 
 | 	for (p = name; *p == ' '; p++) ; | 
 | 	snprintf(name, sizeof(name), "%lu", strtoul(p, 0, 0)); | 
 | 	p = strrchr(clone, '/'); | 
 | 	*p = 0; | 
 | 	if (ds->dir) | 
 | 		snprintf(ds->dir, Maxpath, "%s/%s", clone, name); | 
 | 	snprintf(data, sizeof(data), "%s/%s/data", clone, name); | 
 |  | 
 | 	/* connect */ | 
 | 	if (ds->local) | 
 | 		snprintf(name, sizeof(name), "connect %s %s", dest, ds->local); | 
 | 	else | 
 | 		snprintf(name, sizeof(name), "connect %s", dest); | 
 | 	cchan->dev->write(cchan, name, strlen(name), 0); | 
 |  | 
 | 	/* open data connection */ | 
 | 	dchan = namec(data, Aopen, ORDWR, 0); | 
 | 	if (ds->ctlp) | 
 | 		*ds->ctlp = cchan; | 
 | 	else | 
 | 		cclose(cchan); | 
 | 	poperror(); | 
 | 	return dchan; | 
 |  | 
 | } | 
 |  | 
 | /* | 
 |  *  parse a dial string | 
 |  */ | 
 | static void _dial_string_parse(char *str, struct ds *ds) | 
 | { | 
 | 	char *p, *p2; | 
 |  | 
 | 	strncpy(ds->buf, str, Maxstring); | 
 | 	ds->buf[Maxstring - 1] = 0; | 
 |  | 
 | 	p = strchr(ds->buf, '!'); | 
 | 	if (p == 0) { | 
 | 		ds->netdir = 0; | 
 | 		ds->proto = "net"; | 
 | 		ds->rem = ds->buf; | 
 | 	} else { | 
 | 		if (*ds->buf != '/' && *ds->buf != '#') { | 
 | 			ds->netdir = 0; | 
 | 			ds->proto = ds->buf; | 
 | 		} else { | 
 | 			for (p2 = p; *p2 != '/'; p2--) ; | 
 | 			*p2++ = 0; | 
 | 			ds->netdir = ds->buf; | 
 | 			ds->proto = p2; | 
 | 		} | 
 | 		*p = 0; | 
 | 		ds->rem = p + 1; | 
 | 	} | 
 | } |