xref: /plan9/sys/src/cmd/exportfs/exportfs.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier  * exportfs - Export a plan 9 name space across a network
33e12c5d1SDavid du Colombier  */
43e12c5d1SDavid du Colombier #include <u.h>
53e12c5d1SDavid du Colombier #include <libc.h>
63e12c5d1SDavid du Colombier #include <auth.h>
7*219b2ee8SDavid du Colombier #include <fcall.h>
83e12c5d1SDavid du Colombier #define Extern
93e12c5d1SDavid du Colombier #include "exportfs.h"
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier void (*fcalls[])(Fsrpc*) =
123e12c5d1SDavid du Colombier {
133e12c5d1SDavid du Colombier 	[Tnop]		Xnop,
143e12c5d1SDavid du Colombier 	[Tsession]	Xsession,
153e12c5d1SDavid du Colombier 	[Tflush]	Xflush,
163e12c5d1SDavid du Colombier 	[Tattach]	Xattach,
173e12c5d1SDavid du Colombier 	[Tclone]	Xclone,
183e12c5d1SDavid du Colombier 	[Twalk]		Xwalk,
193e12c5d1SDavid du Colombier 	[Topen]		slave,
203e12c5d1SDavid du Colombier 	[Tcreate]	Xcreate,
213e12c5d1SDavid du Colombier 	[Tclunk]	Xclunk,
223e12c5d1SDavid du Colombier 	[Tread]		slave,
233e12c5d1SDavid du Colombier 	[Twrite]	slave,
243e12c5d1SDavid du Colombier 	[Tremove]	Xremove,
253e12c5d1SDavid du Colombier 	[Tstat]		Xstat,
263e12c5d1SDavid du Colombier 	[Twstat]	Xwstat,
273e12c5d1SDavid du Colombier 	[Tclwalk]	Xclwalk,
283e12c5d1SDavid du Colombier };
293e12c5d1SDavid du Colombier 
30*219b2ee8SDavid du Colombier int nonone;
31*219b2ee8SDavid du Colombier 
32*219b2ee8SDavid du Colombier void
33*219b2ee8SDavid du Colombier usage(void)
34*219b2ee8SDavid du Colombier {
35*219b2ee8SDavid du Colombier 	fprint(2, "usage: %s [-as] [-c ctlfile]\n", argv0);
36*219b2ee8SDavid du Colombier 	fatal("usage");
37*219b2ee8SDavid du Colombier }
38*219b2ee8SDavid du Colombier 
393e12c5d1SDavid du Colombier void
403e12c5d1SDavid du Colombier main(int argc, char **argv)
413e12c5d1SDavid du Colombier {
423e12c5d1SDavid du Colombier 	char buf[128];
433e12c5d1SDavid du Colombier 	Fsrpc *r;
44bd389b36SDavid du Colombier 	int n, srv;
453e12c5d1SDavid du Colombier 	char *dbfile;
463e12c5d1SDavid du Colombier 	char *ctlfile;
47*219b2ee8SDavid du Colombier 	char user[NAMELEN];
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier 	dbfile = "/tmp/exportdb";
503e12c5d1SDavid du Colombier 	ctlfile = 0;
51bd389b36SDavid du Colombier 	srv = 0;
523e12c5d1SDavid du Colombier 
533e12c5d1SDavid du Colombier 	ARGBEGIN{
543e12c5d1SDavid du Colombier 	case 'a':
55*219b2ee8SDavid du Colombier 		if(srvauth(0, user) < 0)
56*219b2ee8SDavid du Colombier 			fatal("srvauth");
57*219b2ee8SDavid du Colombier 		if(newns(user, 0) < 0)
58*219b2ee8SDavid du Colombier 			fatal("newns");
593e12c5d1SDavid du Colombier 		putenv("service", "exportfs");
603e12c5d1SDavid du Colombier 		break;
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier 	case 'c':
633e12c5d1SDavid du Colombier 		ctlfile = ARGF();
643e12c5d1SDavid du Colombier 		break;
653e12c5d1SDavid du Colombier 
663e12c5d1SDavid du Colombier 	case 'd':
673e12c5d1SDavid du Colombier 		dbg++;
683e12c5d1SDavid du Colombier 		break;
693e12c5d1SDavid du Colombier 
703e12c5d1SDavid du Colombier 	case 'f':
713e12c5d1SDavid du Colombier 		dbfile = ARGF();
723e12c5d1SDavid du Colombier 		break;
733e12c5d1SDavid du Colombier 
74bd389b36SDavid du Colombier 	case 's':
75bd389b36SDavid du Colombier 		srv++;
76bd389b36SDavid du Colombier 		break;
77*219b2ee8SDavid du Colombier 
78*219b2ee8SDavid du Colombier 	default:
79*219b2ee8SDavid du Colombier 		usage();
803e12c5d1SDavid du Colombier 	}ARGEND
813e12c5d1SDavid du Colombier 	USED(argc, argv);
823e12c5d1SDavid du Colombier 
833e12c5d1SDavid du Colombier 	if(dbg) {
843e12c5d1SDavid du Colombier 		n = create(dbfile, OWRITE|OTRUNC, 0666);
853e12c5d1SDavid du Colombier 		dup(n, 2);
863e12c5d1SDavid du Colombier 		close(n);
873e12c5d1SDavid du Colombier 	}
883e12c5d1SDavid du Colombier 
89*219b2ee8SDavid du Colombier 	DEBUG(2, "exportfs: started\n");
90*219b2ee8SDavid du Colombier 
913e12c5d1SDavid du Colombier 	rfork(RFNOTEG);
923e12c5d1SDavid du Colombier 
933e12c5d1SDavid du Colombier 	Workq = malloc(sizeof(Fsrpc)*Nr_workbufs);
943e12c5d1SDavid du Colombier 	fhash = malloc(sizeof(Fid*)*FHASHSIZE);
953e12c5d1SDavid du Colombier 
963e12c5d1SDavid du Colombier 	if(Workq == 0 || fhash == 0)
973e12c5d1SDavid du Colombier 		fatal("no initial memory");
983e12c5d1SDavid du Colombier 
993e12c5d1SDavid du Colombier 	memset(Workq, 0, sizeof(Fsrpc)*Nr_workbufs);
1003e12c5d1SDavid du Colombier 
1013e12c5d1SDavid du Colombier 	fmtinstall('F', fcallconv);
1023e12c5d1SDavid du Colombier 
1033e12c5d1SDavid du Colombier 	/*
104*219b2ee8SDavid du Colombier 	 * Get tree to serve from network connection,
105*219b2ee8SDavid du Colombier 	 * check we can get there and ack the connection
1063e12c5d1SDavid du Colombier  	 */
107*219b2ee8SDavid du Colombier 	if(srv) {
108bd389b36SDavid du Colombier 		chdir("/");
109*219b2ee8SDavid du Colombier 		DEBUG(2, "invoked as server for /");
110*219b2ee8SDavid du Colombier 	}
111bd389b36SDavid du Colombier 	else {
112bd389b36SDavid du Colombier 		buf[0] = 0;
1133e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf));
114bd389b36SDavid du Colombier 		if(n < 0) {
1153e12c5d1SDavid du Colombier 			errstr(buf);
116bd389b36SDavid du Colombier 			fprint(0, "read(0): %s", buf);
117*219b2ee8SDavid du Colombier 			DEBUG(2, "read(0): %s", buf);
1183e12c5d1SDavid du Colombier 			exits(buf);
1193e12c5d1SDavid du Colombier 		}
120*219b2ee8SDavid du Colombier 		buf[n] = 0;
121bd389b36SDavid du Colombier 		if(chdir(buf) < 0) {
122bd389b36SDavid du Colombier 			char ebuf[128];
123bd389b36SDavid du Colombier 			errstr(ebuf);
124bd389b36SDavid du Colombier 			fprint(0, "chdir(%d:\"%s\"): %s", n, buf, ebuf);
125*219b2ee8SDavid du Colombier 			DEBUG(2, "chdir(%d:\"%s\"): %s", n, buf, ebuf);
126bd389b36SDavid du Colombier 			exits(ebuf);
127bd389b36SDavid du Colombier 		}
128bd389b36SDavid du Colombier 	}
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier 	/*
1313e12c5d1SDavid du Colombier 	 * take ownership of the network connection and
1323e12c5d1SDavid du Colombier 	 * push the fcall line discipline
1333e12c5d1SDavid du Colombier 	 */
1343e12c5d1SDavid du Colombier 	if(ctlfile)
1353e12c5d1SDavid du Colombier 		pushfcall(ctlfile);
1363e12c5d1SDavid du Colombier 
137*219b2ee8SDavid du Colombier 	DEBUG(2, "initing root\n");
1383e12c5d1SDavid du Colombier 	initroot();
1393e12c5d1SDavid du Colombier 
1403e12c5d1SDavid du Colombier 	DEBUG(2, "exportfs: %s\n", buf);
1413e12c5d1SDavid du Colombier 
142bd389b36SDavid du Colombier 	if(srv == 0 && write(0, "OK", 2) != 2)
1433e12c5d1SDavid du Colombier 		fatal("open ack write");
1443e12c5d1SDavid du Colombier 
1453e12c5d1SDavid du Colombier 	/*
1463e12c5d1SDavid du Colombier 	 * Start serving file requests from the network
1473e12c5d1SDavid du Colombier 	 */
1483e12c5d1SDavid du Colombier 	for(;;) {
1493e12c5d1SDavid du Colombier 		r = getsbuf();
1503e12c5d1SDavid du Colombier 		if(r == 0)
1513e12c5d1SDavid du Colombier 			fatal("Out of service buffers");
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier 		do
154*219b2ee8SDavid du Colombier 			n = read9p(0, r->buf, sizeof(r->buf));
1553e12c5d1SDavid du Colombier 		while(n == 0);
1563e12c5d1SDavid du Colombier 
1573e12c5d1SDavid du Colombier 		if(n < 0)
1583e12c5d1SDavid du Colombier 			fatal("server read");
1593e12c5d1SDavid du Colombier 
1603e12c5d1SDavid du Colombier 
1613e12c5d1SDavid du Colombier 		if(convM2S(r->buf, &r->work, n) == 0)
1623e12c5d1SDavid du Colombier 			fatal("format error");
1633e12c5d1SDavid du Colombier 
1643e12c5d1SDavid du Colombier 		DEBUG(2, "%F\n", &r->work, &r->work);
1653e12c5d1SDavid du Colombier 		(fcalls[r->work.type])(r);
1663e12c5d1SDavid du Colombier 	}
1673e12c5d1SDavid du Colombier }
1683e12c5d1SDavid du Colombier 
1693e12c5d1SDavid du Colombier void
1703e12c5d1SDavid du Colombier reply(Fcall *r, Fcall *t, char *err)
1713e12c5d1SDavid du Colombier {
1723e12c5d1SDavid du Colombier 	char data[MAXFDATA+MAXMSG];
1733e12c5d1SDavid du Colombier 	int n;
1743e12c5d1SDavid du Colombier 
1753e12c5d1SDavid du Colombier 	t->tag = r->tag;
1763e12c5d1SDavid du Colombier 	t->fid = r->fid;
1773e12c5d1SDavid du Colombier 	if(err) {
1783e12c5d1SDavid du Colombier 		t->type = Rerror;
1793e12c5d1SDavid du Colombier 		strncpy(t->ename, err, ERRLEN);
1803e12c5d1SDavid du Colombier 	}
1813e12c5d1SDavid du Colombier 	else
1823e12c5d1SDavid du Colombier 		t->type = r->type + 1;
1833e12c5d1SDavid du Colombier 
1843e12c5d1SDavid du Colombier 	DEBUG(2, "\t%F\n", t);
1853e12c5d1SDavid du Colombier 
1863e12c5d1SDavid du Colombier 	n = convS2M(t, data);
187*219b2ee8SDavid du Colombier 	if(write9p(0, data, n)!=n)
1883e12c5d1SDavid du Colombier 		fatal("mount write");
1893e12c5d1SDavid du Colombier }
1903e12c5d1SDavid du Colombier 
1913e12c5d1SDavid du Colombier Fid *
1923e12c5d1SDavid du Colombier getfid(int nr)
1933e12c5d1SDavid du Colombier {
1943e12c5d1SDavid du Colombier 	Fid *f;
1953e12c5d1SDavid du Colombier 
1963e12c5d1SDavid du Colombier 	for(f = fidhash(nr); f; f = f->next)
1973e12c5d1SDavid du Colombier 		if(f->nr == nr)
1983e12c5d1SDavid du Colombier 			return f;
1993e12c5d1SDavid du Colombier 
2003e12c5d1SDavid du Colombier 	return 0;
2013e12c5d1SDavid du Colombier }
2023e12c5d1SDavid du Colombier 
2033e12c5d1SDavid du Colombier int
2043e12c5d1SDavid du Colombier freefid(int nr)
2053e12c5d1SDavid du Colombier {
2063e12c5d1SDavid du Colombier 	Fid *f, **l;
207*219b2ee8SDavid du Colombier 	char buf[128];
2083e12c5d1SDavid du Colombier 
2093e12c5d1SDavid du Colombier 	l = &fidhash(nr);
2103e12c5d1SDavid du Colombier 	for(f = *l; f; f = f->next) {
2113e12c5d1SDavid du Colombier 		if(f->nr == nr) {
212*219b2ee8SDavid du Colombier 			if(f->mpend)
213*219b2ee8SDavid du Colombier 				f->mpend->busy = 0;
214*219b2ee8SDavid du Colombier 			if(f->mid) {
215*219b2ee8SDavid du Colombier 				sprint(buf, "/mnt/exportfs/%d", f->mid);
216*219b2ee8SDavid du Colombier 				unmount(0, buf);
217*219b2ee8SDavid du Colombier 				psmap[f->mid] = 0;
218*219b2ee8SDavid du Colombier 			}
2193e12c5d1SDavid du Colombier 			*l = f->next;
2203e12c5d1SDavid du Colombier 			f->next = fidfree;
2213e12c5d1SDavid du Colombier 			fidfree = f;
2223e12c5d1SDavid du Colombier 			return 1;
2233e12c5d1SDavid du Colombier 		}
2243e12c5d1SDavid du Colombier 		l = &f->next;
2253e12c5d1SDavid du Colombier 	}
2263e12c5d1SDavid du Colombier 
2273e12c5d1SDavid du Colombier 	return 0;
2283e12c5d1SDavid du Colombier }
2293e12c5d1SDavid du Colombier 
2303e12c5d1SDavid du Colombier Fid *
2313e12c5d1SDavid du Colombier newfid(int nr)
2323e12c5d1SDavid du Colombier {
2333e12c5d1SDavid du Colombier 	Fid *new, **l;
2343e12c5d1SDavid du Colombier 	int i;
2353e12c5d1SDavid du Colombier 
2363e12c5d1SDavid du Colombier 	l = &fidhash(nr);
2373e12c5d1SDavid du Colombier 	for(new = *l; new; new = new->next)
2383e12c5d1SDavid du Colombier 		if(new->nr == nr)
2393e12c5d1SDavid du Colombier 			return 0;
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier 	if(fidfree == 0) {
2423e12c5d1SDavid du Colombier 		fidfree = malloc(sizeof(Fid) * Fidchunk);
2433e12c5d1SDavid du Colombier 		if(fidfree == 0)
2443e12c5d1SDavid du Colombier 			fatal("out of memory");
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier 		for(i = 0; i < Fidchunk-1; i++)
2473e12c5d1SDavid du Colombier 			fidfree[i].next = &fidfree[i+1];
2483e12c5d1SDavid du Colombier 
2493e12c5d1SDavid du Colombier 		fidfree[Fidchunk-1].next = 0;
2503e12c5d1SDavid du Colombier 	}
2513e12c5d1SDavid du Colombier 
2523e12c5d1SDavid du Colombier 	new = fidfree;
2533e12c5d1SDavid du Colombier 	fidfree = new->next;
2543e12c5d1SDavid du Colombier 
2553e12c5d1SDavid du Colombier 	memset(new, 0, sizeof(Fid));
2563e12c5d1SDavid du Colombier 	new->next = *l;
2573e12c5d1SDavid du Colombier 	*l = new;
2583e12c5d1SDavid du Colombier 	new->nr = nr;
2593e12c5d1SDavid du Colombier 	new->fid = -1;
260*219b2ee8SDavid du Colombier 	new->mpend = 0;
261*219b2ee8SDavid du Colombier 	new->mid = 0;
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier 	return new;
2643e12c5d1SDavid du Colombier }
2653e12c5d1SDavid du Colombier 
2663e12c5d1SDavid du Colombier Fsrpc *
2673e12c5d1SDavid du Colombier getsbuf(void)
2683e12c5d1SDavid du Colombier {
2693e12c5d1SDavid du Colombier 	static int ap;
2703e12c5d1SDavid du Colombier 	int look;
2713e12c5d1SDavid du Colombier 	Fsrpc *wb;
2723e12c5d1SDavid du Colombier 
2733e12c5d1SDavid du Colombier 	for(look = 0; look < Nr_workbufs; look++) {
2743e12c5d1SDavid du Colombier 		if(++ap == Nr_workbufs)
2753e12c5d1SDavid du Colombier 			ap = 0;
2763e12c5d1SDavid du Colombier 		if(Workq[ap].busy == 0)
2773e12c5d1SDavid du Colombier 			break;
2783e12c5d1SDavid du Colombier 	}
2793e12c5d1SDavid du Colombier 
2803e12c5d1SDavid du Colombier 	if(look == Nr_workbufs)
2813e12c5d1SDavid du Colombier 		fatal("No more work buffers");
2823e12c5d1SDavid du Colombier 
2833e12c5d1SDavid du Colombier 	wb = &Workq[ap];
2843e12c5d1SDavid du Colombier 	wb->pid = 0;
2853e12c5d1SDavid du Colombier 	wb->canint = 0;
2863e12c5d1SDavid du Colombier 	wb->flushtag = NOTAG;
2873e12c5d1SDavid du Colombier 	wb->busy = 1;
2883e12c5d1SDavid du Colombier 
2893e12c5d1SDavid du Colombier 	return wb;
2903e12c5d1SDavid du Colombier }
2913e12c5d1SDavid du Colombier 
2923e12c5d1SDavid du Colombier char *
2933e12c5d1SDavid du Colombier strcatalloc(char *p, char *n)
2943e12c5d1SDavid du Colombier {
2953e12c5d1SDavid du Colombier 	char *v;
2963e12c5d1SDavid du Colombier 
2973e12c5d1SDavid du Colombier 	v = realloc(p, strlen(p)+strlen(n)+1);
2983e12c5d1SDavid du Colombier 	if(v == 0)
2993e12c5d1SDavid du Colombier 		fatal("no memory");
3003e12c5d1SDavid du Colombier 	strcat(v, n);
3013e12c5d1SDavid du Colombier 	return v;
3023e12c5d1SDavid du Colombier }
3033e12c5d1SDavid du Colombier 
3043e12c5d1SDavid du Colombier File *
3053e12c5d1SDavid du Colombier file(File *parent, char *name)
3063e12c5d1SDavid du Colombier {
307*219b2ee8SDavid du Colombier 	Dir dir;
3083e12c5d1SDavid du Colombier 	char buf[128];
3093e12c5d1SDavid du Colombier 	File *f, *new;
3103e12c5d1SDavid du Colombier 
3113e12c5d1SDavid du Colombier 	DEBUG(2, "\tfile: 0x%x %s name %s\n", parent, parent->name, name);
3123e12c5d1SDavid du Colombier 
3133e12c5d1SDavid du Colombier 	for(f = parent->child; f; f = f->childlist)
3143e12c5d1SDavid du Colombier 		if(strcmp(name, f->name) == 0)
3153e12c5d1SDavid du Colombier 			return f;
3163e12c5d1SDavid du Colombier 
3173e12c5d1SDavid du Colombier 	makepath(buf, parent, name);
3183e12c5d1SDavid du Colombier 	if(dirstat(buf, &dir) < 0)
3193e12c5d1SDavid du Colombier 		return 0;
3203e12c5d1SDavid du Colombier 
3213e12c5d1SDavid du Colombier 	new = malloc(sizeof(File));
3223e12c5d1SDavid du Colombier 	if(new == 0)
3233e12c5d1SDavid du Colombier 		fatal("no memory");
3243e12c5d1SDavid du Colombier 
3253e12c5d1SDavid du Colombier 	memset(new, 0, sizeof(File));
3263e12c5d1SDavid du Colombier 	strcpy(new->name, name);
3273e12c5d1SDavid du Colombier 	new->qid.vers = dir.qid.vers;
3283e12c5d1SDavid du Colombier 	new->qid.path = (dir.qid.path&CHDIR)|++qid;
3293e12c5d1SDavid du Colombier 
3303e12c5d1SDavid du Colombier 	new->parent = parent;
3313e12c5d1SDavid du Colombier 	new->childlist = parent->child;
3323e12c5d1SDavid du Colombier 	parent->child = new;
3333e12c5d1SDavid du Colombier 
3343e12c5d1SDavid du Colombier 	return new;
3353e12c5d1SDavid du Colombier }
3363e12c5d1SDavid du Colombier 
3373e12c5d1SDavid du Colombier void
3383e12c5d1SDavid du Colombier initroot(void)
3393e12c5d1SDavid du Colombier {
3403e12c5d1SDavid du Colombier 	Dir dir;
3413e12c5d1SDavid du Colombier 
3423e12c5d1SDavid du Colombier 	root = malloc(sizeof(File));
3433e12c5d1SDavid du Colombier 	if(root == 0)
3443e12c5d1SDavid du Colombier 		fatal("no memory");
3453e12c5d1SDavid du Colombier 
3463e12c5d1SDavid du Colombier 	memset(root, 0, sizeof(File));
3473e12c5d1SDavid du Colombier 	strcpy(root->name, ".");
3483e12c5d1SDavid du Colombier 	if(dirstat(root->name, &dir) < 0)
3493e12c5d1SDavid du Colombier 		fatal("root stat");
3503e12c5d1SDavid du Colombier 
3513e12c5d1SDavid du Colombier 	root->qid.vers = dir.qid.vers;
3523e12c5d1SDavid du Colombier 	root->qid.path = (dir.qid.path&CHDIR)|++qid;
353*219b2ee8SDavid du Colombier 
354*219b2ee8SDavid du Colombier 	psmpt = malloc(sizeof(File));
355*219b2ee8SDavid du Colombier 	if(psmpt == 0)
356*219b2ee8SDavid du Colombier 		fatal("no memory");
357*219b2ee8SDavid du Colombier 
358*219b2ee8SDavid du Colombier 	memset(psmpt, 0, sizeof(File));
359*219b2ee8SDavid du Colombier 	strcpy(psmpt->name, "/");
360*219b2ee8SDavid du Colombier 	if(dirstat(psmpt->name, &dir) < 0)
361*219b2ee8SDavid du Colombier 		return;
362*219b2ee8SDavid du Colombier 
363*219b2ee8SDavid du Colombier 	psmpt->qid.vers = dir.qid.vers;
364*219b2ee8SDavid du Colombier 	psmpt->qid.path = (dir.qid.path&CHDIR)|++qid;
365*219b2ee8SDavid du Colombier 
366*219b2ee8SDavid du Colombier 	psmpt = file(psmpt, "mnt");
367*219b2ee8SDavid du Colombier 	if(psmpt == 0)
368*219b2ee8SDavid du Colombier 		return;
369*219b2ee8SDavid du Colombier 	psmpt = file(psmpt, "exportfs");
3703e12c5d1SDavid du Colombier }
3713e12c5d1SDavid du Colombier 
3723e12c5d1SDavid du Colombier void
3733e12c5d1SDavid du Colombier makepath(char *s, File *p, char *name)
3743e12c5d1SDavid du Colombier {
3753e12c5d1SDavid du Colombier 	int i;
376*219b2ee8SDavid du Colombier 	char *c, *seg[256];
3773e12c5d1SDavid du Colombier 
3783e12c5d1SDavid du Colombier 	seg[0] = name;
3793e12c5d1SDavid du Colombier 	for(i = 1; i < 100 && p; i++, p = p->parent)
3803e12c5d1SDavid du Colombier 		seg[i] = p->name;
3813e12c5d1SDavid du Colombier 
3823e12c5d1SDavid du Colombier 	while(i--) {
3833e12c5d1SDavid du Colombier 		for(c = seg[i]; *c; c++)
3843e12c5d1SDavid du Colombier 			*s++ = *c;
3853e12c5d1SDavid du Colombier 		*s++ = '/';
3863e12c5d1SDavid du Colombier 	}
3873e12c5d1SDavid du Colombier 	while(s[-1] == '/')
3883e12c5d1SDavid du Colombier 		s--;
3893e12c5d1SDavid du Colombier 	*s = '\0';
3903e12c5d1SDavid du Colombier }
3913e12c5d1SDavid du Colombier 
3923e12c5d1SDavid du Colombier void
3933e12c5d1SDavid du Colombier fatal(char *s)
3943e12c5d1SDavid du Colombier {
3953e12c5d1SDavid du Colombier 	char buf[128];
3963e12c5d1SDavid du Colombier 	Proc *m;
3973e12c5d1SDavid du Colombier 
3983e12c5d1SDavid du Colombier 	sprint(buf, "exportfs: %r: %s", s);
3993e12c5d1SDavid du Colombier 
4003e12c5d1SDavid du Colombier 	/* Clear away the slave children */
4013e12c5d1SDavid du Colombier 	for(m = Proclist; m; m = m->next)
402*219b2ee8SDavid du Colombier 		postnote(PNPROC, m->pid, "kill");
4033e12c5d1SDavid du Colombier 
404bd389b36SDavid du Colombier 	DEBUG(2, "%s\n", buf);
4053e12c5d1SDavid du Colombier 	exits(buf);
4063e12c5d1SDavid du Colombier }
4073e12c5d1SDavid du Colombier 
408*219b2ee8SDavid du Colombier char pushmsg[] = "push fcall";
4093e12c5d1SDavid du Colombier 
4103e12c5d1SDavid du Colombier void
4113e12c5d1SDavid du Colombier pushfcall(char *ctl)
4123e12c5d1SDavid du Colombier {
4133e12c5d1SDavid du Colombier 	int cfd;
4143e12c5d1SDavid du Colombier 	Dir dir;
4153e12c5d1SDavid du Colombier 
4163e12c5d1SDavid du Colombier 	if(dirfstat(0, &dir) < 0){
4173e12c5d1SDavid du Colombier 		fprint(2, "dirfstat(0) failed: %r\n");
4183e12c5d1SDavid du Colombier 		return;
4193e12c5d1SDavid du Colombier 	}
4203e12c5d1SDavid du Colombier 	memmove(dir.uid, getuser(), NAMELEN);
4213e12c5d1SDavid du Colombier 	if(dirfwstat(1, &dir) < 0){
4223e12c5d1SDavid du Colombier 		fprint(2, "dirfwstat(1) failed: %r\n");
4233e12c5d1SDavid du Colombier 		return;
4243e12c5d1SDavid du Colombier 	}
4253e12c5d1SDavid du Colombier 	cfd = open(ctl, ORDWR);
4263e12c5d1SDavid du Colombier 	if(cfd < 0){
4273e12c5d1SDavid du Colombier 		fprint(2, "open(%s0) failed: %r\n", ctl);
4283e12c5d1SDavid du Colombier 		return;
4293e12c5d1SDavid du Colombier 	}
4303e12c5d1SDavid du Colombier 	if(write(cfd, pushmsg, strlen(pushmsg)) < 0){
4313e12c5d1SDavid du Colombier 		fprint(2, "%s failed: %r\n", pushmsg);
4323e12c5d1SDavid du Colombier 		return;
4333e12c5d1SDavid du Colombier 	}
4343e12c5d1SDavid du Colombier 	close(cfd);
4353e12c5d1SDavid du Colombier }
436