xref: /plan9/sys/src/cmd/exportfs/exportfs.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier 
23e12c5d1SDavid du Colombier /*
33e12c5d1SDavid du Colombier  * exportfs - Export a plan 9 name space across a network
43e12c5d1SDavid du Colombier  */
53e12c5d1SDavid du Colombier #include <u.h>
63e12c5d1SDavid du Colombier #include <libc.h>
73e12c5d1SDavid du Colombier #include <auth.h>
8219b2ee8SDavid du Colombier #include <fcall.h>
93e12c5d1SDavid du Colombier #define Extern
103e12c5d1SDavid du Colombier #include "exportfs.h"
113e12c5d1SDavid du Colombier 
12*7dd7cddfSDavid du Colombier #define	QIDMODE	(CHDIR|CHAPPEND|CHEXCL|CHMOUNT)
13*7dd7cddfSDavid du Colombier ulong newqid = ~QIDMODE;
14*7dd7cddfSDavid du Colombier 
153e12c5d1SDavid du Colombier void (*fcalls[])(Fsrpc*) =
163e12c5d1SDavid du Colombier {
173e12c5d1SDavid du Colombier 	[Tnop]		Xnop,
183e12c5d1SDavid du Colombier 	[Tsession]	Xsession,
193e12c5d1SDavid du Colombier 	[Tflush]	Xflush,
203e12c5d1SDavid du Colombier 	[Tattach]	Xattach,
213e12c5d1SDavid du Colombier 	[Tclone]	Xclone,
223e12c5d1SDavid du Colombier 	[Twalk]		Xwalk,
233e12c5d1SDavid du Colombier 	[Topen]		slave,
243e12c5d1SDavid du Colombier 	[Tcreate]	Xcreate,
253e12c5d1SDavid du Colombier 	[Tclunk]	Xclunk,
263e12c5d1SDavid du Colombier 	[Tread]		slave,
273e12c5d1SDavid du Colombier 	[Twrite]	slave,
283e12c5d1SDavid du Colombier 	[Tremove]	Xremove,
293e12c5d1SDavid du Colombier 	[Tstat]		Xstat,
303e12c5d1SDavid du Colombier 	[Twstat]	Xwstat,
313e12c5d1SDavid du Colombier 	[Tclwalk]	Xclwalk,
323e12c5d1SDavid du Colombier };
333e12c5d1SDavid du Colombier 
34*7dd7cddfSDavid du Colombier /* accounting and debugging counters */
35*7dd7cddfSDavid du Colombier int	filecnt;
36*7dd7cddfSDavid du Colombier int	freecnt;
37*7dd7cddfSDavid du Colombier int	qidcnt;
38*7dd7cddfSDavid du Colombier int	qfreecnt;
39*7dd7cddfSDavid du Colombier int	ncollision;
40*7dd7cddfSDavid du Colombier 
41*7dd7cddfSDavid du Colombier int	fflag;
42*7dd7cddfSDavid du Colombier int	netfd;
43*7dd7cddfSDavid du Colombier int	filter(int);
44219b2ee8SDavid du Colombier 
45219b2ee8SDavid du Colombier void
46219b2ee8SDavid du Colombier usage(void)
47219b2ee8SDavid du Colombier {
48219b2ee8SDavid du Colombier 	fprint(2, "usage: %s [-as] [-c ctlfile]\n", argv0);
49219b2ee8SDavid du Colombier 	fatal("usage");
50219b2ee8SDavid du Colombier }
51219b2ee8SDavid du Colombier 
523e12c5d1SDavid du Colombier void
533e12c5d1SDavid du Colombier main(int argc, char **argv)
543e12c5d1SDavid du Colombier {
553e12c5d1SDavid du Colombier 	char buf[128];
563e12c5d1SDavid du Colombier 	Fsrpc *r;
57bd389b36SDavid du Colombier 	int n, srv;
583e12c5d1SDavid du Colombier 	char *dbfile;
59219b2ee8SDavid du Colombier 	char user[NAMELEN];
603e12c5d1SDavid du Colombier 
613e12c5d1SDavid du Colombier 	dbfile = "/tmp/exportdb";
62bd389b36SDavid du Colombier 	srv = 0;
633e12c5d1SDavid du Colombier 
643e12c5d1SDavid du Colombier 	ARGBEGIN{
653e12c5d1SDavid du Colombier 	case 'a':
66*7dd7cddfSDavid du Colombier 	//	fprint(2, "srvauth\n");
67219b2ee8SDavid du Colombier 		if(srvauth(0, user) < 0)
68219b2ee8SDavid du Colombier 			fatal("srvauth");
69*7dd7cddfSDavid du Colombier 	//	fprint(2, "newns\n");
70219b2ee8SDavid du Colombier 		if(newns(user, 0) < 0)
71219b2ee8SDavid du Colombier 			fatal("newns");
723e12c5d1SDavid du Colombier 		putenv("service", "exportfs");
733e12c5d1SDavid du Colombier 		break;
743e12c5d1SDavid du Colombier 
753e12c5d1SDavid du Colombier 	case 'd':
763e12c5d1SDavid du Colombier 		dbg++;
773e12c5d1SDavid du Colombier 		break;
783e12c5d1SDavid du Colombier 
793e12c5d1SDavid du Colombier 	case 'f':
803e12c5d1SDavid du Colombier 		dbfile = ARGF();
813e12c5d1SDavid du Colombier 		break;
823e12c5d1SDavid du Colombier 
83*7dd7cddfSDavid du Colombier 	case 'F':
84*7dd7cddfSDavid du Colombier 		fflag++;
85*7dd7cddfSDavid du Colombier 		break;
86*7dd7cddfSDavid du Colombier 
87bd389b36SDavid du Colombier 	case 's':
88bd389b36SDavid du Colombier 		srv++;
89bd389b36SDavid du Colombier 		break;
90219b2ee8SDavid du Colombier 
91219b2ee8SDavid du Colombier 	default:
92219b2ee8SDavid du Colombier 		usage();
933e12c5d1SDavid du Colombier 	}ARGEND
943e12c5d1SDavid du Colombier 	USED(argc, argv);
953e12c5d1SDavid du Colombier 
963e12c5d1SDavid du Colombier 	if(dbg) {
973e12c5d1SDavid du Colombier 		n = create(dbfile, OWRITE|OTRUNC, 0666);
98*7dd7cddfSDavid du Colombier 		dup(n, DFD);
993e12c5d1SDavid du Colombier 		close(n);
1003e12c5d1SDavid du Colombier 	}
1013e12c5d1SDavid du Colombier 
102*7dd7cddfSDavid du Colombier 	DEBUG(DFD, "exportfs: started\n");
103219b2ee8SDavid du Colombier 
1043e12c5d1SDavid du Colombier 	rfork(RFNOTEG);
1053e12c5d1SDavid du Colombier 
106*7dd7cddfSDavid du Colombier 	Workq = mallocz(sizeof(Fsrpc)*Nr_workbufs, 1);
107*7dd7cddfSDavid du Colombier 	fhash = mallocz(sizeof(Fid*)*FHASHSIZE, 1);
1083e12c5d1SDavid du Colombier 
1093e12c5d1SDavid du Colombier 	if(Workq == 0 || fhash == 0)
1103e12c5d1SDavid du Colombier 		fatal("no initial memory");
1113e12c5d1SDavid du Colombier 
1123e12c5d1SDavid du Colombier 
1133e12c5d1SDavid du Colombier 	fmtinstall('F', fcallconv);
1143e12c5d1SDavid du Colombier 
1153e12c5d1SDavid du Colombier 	/*
116219b2ee8SDavid du Colombier 	 * Get tree to serve from network connection,
117219b2ee8SDavid du Colombier 	 * check we can get there and ack the connection
1183e12c5d1SDavid du Colombier  	 */
119219b2ee8SDavid du Colombier 	if(srv) {
120bd389b36SDavid du Colombier 		chdir("/");
121*7dd7cddfSDavid du Colombier 		DEBUG(DFD, "invoked as server for /");
122219b2ee8SDavid du Colombier 	}
123bd389b36SDavid du Colombier 	else {
124bd389b36SDavid du Colombier 		buf[0] = 0;
1253e12c5d1SDavid du Colombier 		n = read(0, buf, sizeof(buf));
126bd389b36SDavid du Colombier 		if(n < 0) {
1273e12c5d1SDavid du Colombier 			errstr(buf);
128bd389b36SDavid du Colombier 			fprint(0, "read(0): %s", buf);
129*7dd7cddfSDavid du Colombier 			DEBUG(DFD, "read(0): %s", buf);
1303e12c5d1SDavid du Colombier 			exits(buf);
1313e12c5d1SDavid du Colombier 		}
132219b2ee8SDavid du Colombier 		buf[n] = 0;
133bd389b36SDavid du Colombier 		if(chdir(buf) < 0) {
134bd389b36SDavid du Colombier 			char ebuf[128];
135bd389b36SDavid du Colombier 			errstr(ebuf);
136bd389b36SDavid du Colombier 			fprint(0, "chdir(%d:\"%s\"): %s", n, buf, ebuf);
137*7dd7cddfSDavid du Colombier 			DEBUG(DFD, "chdir(%d:\"%s\"): %s", n, buf, ebuf);
138bd389b36SDavid du Colombier 			exits(ebuf);
139bd389b36SDavid du Colombier 		}
140bd389b36SDavid du Colombier 	}
1413e12c5d1SDavid du Colombier 
142*7dd7cddfSDavid du Colombier 	DEBUG(DFD, "initing root\n");
1433e12c5d1SDavid du Colombier 	initroot();
1443e12c5d1SDavid du Colombier 
145*7dd7cddfSDavid du Colombier 	DEBUG(DFD, "exportfs: %s\n", buf);
1463e12c5d1SDavid du Colombier 
147bd389b36SDavid du Colombier 	if(srv == 0 && write(0, "OK", 2) != 2)
1483e12c5d1SDavid du Colombier 		fatal("open ack write");
1493e12c5d1SDavid du Colombier 
1503e12c5d1SDavid du Colombier 	/*
151*7dd7cddfSDavid du Colombier 	 * push the fcall line discipline
152*7dd7cddfSDavid du Colombier 	 */
153*7dd7cddfSDavid du Colombier 	netfd = 0;
154*7dd7cddfSDavid du Colombier 	if(fflag)
155*7dd7cddfSDavid du Colombier 		netfd = filter(netfd);
156*7dd7cddfSDavid du Colombier 
157*7dd7cddfSDavid du Colombier 	/*
1583e12c5d1SDavid du Colombier 	 * Start serving file requests from the network
1593e12c5d1SDavid du Colombier 	 */
1603e12c5d1SDavid du Colombier 	for(;;) {
1613e12c5d1SDavid du Colombier 		r = getsbuf();
1623e12c5d1SDavid du Colombier 		if(r == 0)
1633e12c5d1SDavid du Colombier 			fatal("Out of service buffers");
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier 		do
166*7dd7cddfSDavid du Colombier 			n = read9p(netfd, r->buf, sizeof(r->buf));
1673e12c5d1SDavid du Colombier 		while(n == 0);
1683e12c5d1SDavid du Colombier 
1693e12c5d1SDavid du Colombier 		if(n < 0)
1703e12c5d1SDavid du Colombier 			fatal("server read");
1713e12c5d1SDavid du Colombier 
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier 		if(convM2S(r->buf, &r->work, n) == 0)
1743e12c5d1SDavid du Colombier 			fatal("format error");
1753e12c5d1SDavid du Colombier 
176*7dd7cddfSDavid du Colombier 		DEBUG(DFD, "%F\n", &r->work);
1773e12c5d1SDavid du Colombier 		(fcalls[r->work.type])(r);
1783e12c5d1SDavid du Colombier 	}
1793e12c5d1SDavid du Colombier }
1803e12c5d1SDavid du Colombier 
1813e12c5d1SDavid du Colombier void
1823e12c5d1SDavid du Colombier reply(Fcall *r, Fcall *t, char *err)
1833e12c5d1SDavid du Colombier {
1843e12c5d1SDavid du Colombier 	char data[MAXFDATA+MAXMSG];
1853e12c5d1SDavid du Colombier 	int n;
1863e12c5d1SDavid du Colombier 
1873e12c5d1SDavid du Colombier 	t->tag = r->tag;
1883e12c5d1SDavid du Colombier 	t->fid = r->fid;
1893e12c5d1SDavid du Colombier 	if(err) {
1903e12c5d1SDavid du Colombier 		t->type = Rerror;
1913e12c5d1SDavid du Colombier 		strncpy(t->ename, err, ERRLEN);
1923e12c5d1SDavid du Colombier 	}
1933e12c5d1SDavid du Colombier 	else
1943e12c5d1SDavid du Colombier 		t->type = r->type + 1;
1953e12c5d1SDavid du Colombier 
196*7dd7cddfSDavid du Colombier 	DEBUG(DFD, "\t%F\n", t);
1973e12c5d1SDavid du Colombier 
1983e12c5d1SDavid du Colombier 	n = convS2M(t, data);
199*7dd7cddfSDavid du Colombier 	if(write9p(netfd, data, n)!=n)
2003e12c5d1SDavid du Colombier 		fatal("mount write");
2013e12c5d1SDavid du Colombier }
2023e12c5d1SDavid du Colombier 
2033e12c5d1SDavid du Colombier Fid *
2043e12c5d1SDavid du Colombier getfid(int nr)
2053e12c5d1SDavid du Colombier {
2063e12c5d1SDavid du Colombier 	Fid *f;
2073e12c5d1SDavid du Colombier 
2083e12c5d1SDavid du Colombier 	for(f = fidhash(nr); f; f = f->next)
2093e12c5d1SDavid du Colombier 		if(f->nr == nr)
2103e12c5d1SDavid du Colombier 			return f;
2113e12c5d1SDavid du Colombier 
2123e12c5d1SDavid du Colombier 	return 0;
2133e12c5d1SDavid du Colombier }
2143e12c5d1SDavid du Colombier 
2153e12c5d1SDavid du Colombier int
2163e12c5d1SDavid du Colombier freefid(int nr)
2173e12c5d1SDavid du Colombier {
2183e12c5d1SDavid du Colombier 	Fid *f, **l;
219219b2ee8SDavid du Colombier 	char buf[128];
2203e12c5d1SDavid du Colombier 
2213e12c5d1SDavid du Colombier 	l = &fidhash(nr);
2223e12c5d1SDavid du Colombier 	for(f = *l; f; f = f->next) {
2233e12c5d1SDavid du Colombier 		if(f->nr == nr) {
224219b2ee8SDavid du Colombier 			if(f->mpend)
225219b2ee8SDavid du Colombier 				f->mpend->busy = 0;
226219b2ee8SDavid du Colombier 			if(f->mid) {
227219b2ee8SDavid du Colombier 				sprint(buf, "/mnt/exportfs/%d", f->mid);
228219b2ee8SDavid du Colombier 				unmount(0, buf);
229219b2ee8SDavid du Colombier 				psmap[f->mid] = 0;
230219b2ee8SDavid du Colombier 			}
231*7dd7cddfSDavid du Colombier 			freefile(f->f);
232*7dd7cddfSDavid du Colombier 			f->f = nil;
2333e12c5d1SDavid du Colombier 			*l = f->next;
2343e12c5d1SDavid du Colombier 			f->next = fidfree;
2353e12c5d1SDavid du Colombier 			fidfree = f;
2363e12c5d1SDavid du Colombier 			return 1;
2373e12c5d1SDavid du Colombier 		}
2383e12c5d1SDavid du Colombier 		l = &f->next;
2393e12c5d1SDavid du Colombier 	}
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier 	return 0;
2423e12c5d1SDavid du Colombier }
2433e12c5d1SDavid du Colombier 
2443e12c5d1SDavid du Colombier Fid *
2453e12c5d1SDavid du Colombier newfid(int nr)
2463e12c5d1SDavid du Colombier {
2473e12c5d1SDavid du Colombier 	Fid *new, **l;
2483e12c5d1SDavid du Colombier 	int i;
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier 	l = &fidhash(nr);
2513e12c5d1SDavid du Colombier 	for(new = *l; new; new = new->next)
2523e12c5d1SDavid du Colombier 		if(new->nr == nr)
2533e12c5d1SDavid du Colombier 			return 0;
2543e12c5d1SDavid du Colombier 
2553e12c5d1SDavid du Colombier 	if(fidfree == 0) {
256*7dd7cddfSDavid du Colombier 		fidfree = mallocz(sizeof(Fid) * Fidchunk, 1);
2573e12c5d1SDavid du Colombier 		if(fidfree == 0)
2583e12c5d1SDavid du Colombier 			fatal("out of memory");
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier 		for(i = 0; i < Fidchunk-1; i++)
2613e12c5d1SDavid du Colombier 			fidfree[i].next = &fidfree[i+1];
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier 		fidfree[Fidchunk-1].next = 0;
2643e12c5d1SDavid du Colombier 	}
2653e12c5d1SDavid du Colombier 
2663e12c5d1SDavid du Colombier 	new = fidfree;
2673e12c5d1SDavid du Colombier 	fidfree = new->next;
2683e12c5d1SDavid du Colombier 
2693e12c5d1SDavid du Colombier 	memset(new, 0, sizeof(Fid));
2703e12c5d1SDavid du Colombier 	new->next = *l;
2713e12c5d1SDavid du Colombier 	*l = new;
2723e12c5d1SDavid du Colombier 	new->nr = nr;
2733e12c5d1SDavid du Colombier 	new->fid = -1;
274219b2ee8SDavid du Colombier 	new->mpend = 0;
275219b2ee8SDavid du Colombier 	new->mid = 0;
2763e12c5d1SDavid du Colombier 
2773e12c5d1SDavid du Colombier 	return new;
2783e12c5d1SDavid du Colombier }
2793e12c5d1SDavid du Colombier 
2803e12c5d1SDavid du Colombier Fsrpc *
2813e12c5d1SDavid du Colombier getsbuf(void)
2823e12c5d1SDavid du Colombier {
2833e12c5d1SDavid du Colombier 	static int ap;
284*7dd7cddfSDavid du Colombier 	int look, rounds;
2853e12c5d1SDavid du Colombier 	Fsrpc *wb;
2863e12c5d1SDavid du Colombier 
287*7dd7cddfSDavid du Colombier 	for(rounds = 0; rounds < 10; rounds++) {
2883e12c5d1SDavid du Colombier 		for(look = 0; look < Nr_workbufs; look++) {
2893e12c5d1SDavid du Colombier 			if(++ap == Nr_workbufs)
2903e12c5d1SDavid du Colombier 				ap = 0;
2913e12c5d1SDavid du Colombier 			if(Workq[ap].busy == 0)
2923e12c5d1SDavid du Colombier 				break;
2933e12c5d1SDavid du Colombier 		}
2943e12c5d1SDavid du Colombier 
295*7dd7cddfSDavid du Colombier 		if(look == Nr_workbufs){
296*7dd7cddfSDavid du Colombier 			sleep(10 * rounds);
297*7dd7cddfSDavid du Colombier 			continue;
298*7dd7cddfSDavid du Colombier 		}
2993e12c5d1SDavid du Colombier 
3003e12c5d1SDavid du Colombier 		wb = &Workq[ap];
3013e12c5d1SDavid du Colombier 		wb->pid = 0;
3023e12c5d1SDavid du Colombier 		wb->canint = 0;
3033e12c5d1SDavid du Colombier 		wb->flushtag = NOTAG;
3043e12c5d1SDavid du Colombier 		wb->busy = 1;
3053e12c5d1SDavid du Colombier 
3063e12c5d1SDavid du Colombier 		return wb;
3073e12c5d1SDavid du Colombier 	}
308*7dd7cddfSDavid du Colombier 	fatal("No more work buffers");
309*7dd7cddfSDavid du Colombier 	return nil;
310*7dd7cddfSDavid du Colombier }
3113e12c5d1SDavid du Colombier 
312*7dd7cddfSDavid du Colombier void
313*7dd7cddfSDavid du Colombier freefile(File *f)
3143e12c5d1SDavid du Colombier {
315*7dd7cddfSDavid du Colombier 	File *parent, *child;
3163e12c5d1SDavid du Colombier 
317*7dd7cddfSDavid du Colombier Loop:
318*7dd7cddfSDavid du Colombier 	f->ref--;
319*7dd7cddfSDavid du Colombier 	if(f->ref > 0)
320*7dd7cddfSDavid du Colombier 		return;
321*7dd7cddfSDavid du Colombier 	freecnt++;
322*7dd7cddfSDavid du Colombier 	if(f->ref < 0) abort();
323*7dd7cddfSDavid du Colombier 	DEBUG(DFD, "free %s\n", f->name);
324*7dd7cddfSDavid du Colombier 	/* delete from parent */
325*7dd7cddfSDavid du Colombier 	parent = f->parent;
326*7dd7cddfSDavid du Colombier 	if(parent->child == f)
327*7dd7cddfSDavid du Colombier 		parent->child = f->childlist;
328*7dd7cddfSDavid du Colombier 	else{
329*7dd7cddfSDavid du Colombier 		for(child=parent->child; child->childlist!=f; child=child->childlist)
330*7dd7cddfSDavid du Colombier 			if(child->childlist == nil)
331*7dd7cddfSDavid du Colombier 				fatal("bad child list");
332*7dd7cddfSDavid du Colombier 		child->childlist = f->childlist;
333*7dd7cddfSDavid du Colombier 	}
334*7dd7cddfSDavid du Colombier 	freeqid(f->qidt);
335*7dd7cddfSDavid du Colombier 	free(f);
336*7dd7cddfSDavid du Colombier 	f = parent;
337*7dd7cddfSDavid du Colombier 	if(f != nil)
338*7dd7cddfSDavid du Colombier 		goto Loop;
3393e12c5d1SDavid du Colombier }
3403e12c5d1SDavid du Colombier 
3413e12c5d1SDavid du Colombier File *
3423e12c5d1SDavid du Colombier file(File *parent, char *name)
3433e12c5d1SDavid du Colombier {
344219b2ee8SDavid du Colombier 	Dir dir;
3453e12c5d1SDavid du Colombier 	char buf[128];
346*7dd7cddfSDavid du Colombier 	File *f;
3473e12c5d1SDavid du Colombier 
348*7dd7cddfSDavid du Colombier 	DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
3493e12c5d1SDavid du Colombier 
3503e12c5d1SDavid du Colombier 	makepath(buf, parent, name);
3513e12c5d1SDavid du Colombier 	if(dirstat(buf, &dir) < 0)
352*7dd7cddfSDavid du Colombier 		return nil;
3533e12c5d1SDavid du Colombier 
354*7dd7cddfSDavid du Colombier 	for(f = parent->child; f; f = f->childlist)
355*7dd7cddfSDavid du Colombier 		if(strcmp(name, f->name) == 0)
356*7dd7cddfSDavid du Colombier 			break;
357*7dd7cddfSDavid du Colombier 
358*7dd7cddfSDavid du Colombier 	if(f == nil){
359*7dd7cddfSDavid du Colombier 		f = mallocz(sizeof(File), 1);
360*7dd7cddfSDavid du Colombier 		if(f == 0)
3613e12c5d1SDavid du Colombier 			fatal("no memory");
362*7dd7cddfSDavid du Colombier 		strcpy(f->name, name);
3633e12c5d1SDavid du Colombier 
364*7dd7cddfSDavid du Colombier 		f->parent = parent;
365*7dd7cddfSDavid du Colombier 		f->childlist = parent->child;
366*7dd7cddfSDavid du Colombier 		parent->child = f;
367*7dd7cddfSDavid du Colombier 		parent->ref++;
368*7dd7cddfSDavid du Colombier 		f->ref = 0;
369*7dd7cddfSDavid du Colombier 		filecnt++;
370*7dd7cddfSDavid du Colombier 	}
371*7dd7cddfSDavid du Colombier 	f->ref++;
372*7dd7cddfSDavid du Colombier 	f->qid.vers = dir.qid.vers;
373*7dd7cddfSDavid du Colombier 	f->qidt = uniqueqid(&dir);
374*7dd7cddfSDavid du Colombier 	f->qid.path = f->qidt->uniqpath;
3753e12c5d1SDavid du Colombier 
376*7dd7cddfSDavid du Colombier 	f->inval = 0;
3773e12c5d1SDavid du Colombier 
378*7dd7cddfSDavid du Colombier 
379*7dd7cddfSDavid du Colombier 	return f;
3803e12c5d1SDavid du Colombier }
3813e12c5d1SDavid du Colombier 
3823e12c5d1SDavid du Colombier void
3833e12c5d1SDavid du Colombier initroot(void)
3843e12c5d1SDavid du Colombier {
3853e12c5d1SDavid du Colombier 	Dir dir;
3863e12c5d1SDavid du Colombier 
387*7dd7cddfSDavid du Colombier 	root = mallocz(sizeof(File), 1);
3883e12c5d1SDavid du Colombier 	if(root == 0)
3893e12c5d1SDavid du Colombier 		fatal("no memory");
3903e12c5d1SDavid du Colombier 
3913e12c5d1SDavid du Colombier 	strcpy(root->name, ".");
3923e12c5d1SDavid du Colombier 	if(dirstat(root->name, &dir) < 0)
3933e12c5d1SDavid du Colombier 		fatal("root stat");
3943e12c5d1SDavid du Colombier 
395*7dd7cddfSDavid du Colombier 	root->ref = 1;
3963e12c5d1SDavid du Colombier 	root->qid.vers = dir.qid.vers;
397*7dd7cddfSDavid du Colombier 	root->qidt = uniqueqid(&dir);
398*7dd7cddfSDavid du Colombier 	root->qid.path = root->qidt->uniqpath;
399219b2ee8SDavid du Colombier 
400*7dd7cddfSDavid du Colombier 	psmpt = mallocz(sizeof(File), 1);
401219b2ee8SDavid du Colombier 	if(psmpt == 0)
402219b2ee8SDavid du Colombier 		fatal("no memory");
403219b2ee8SDavid du Colombier 
404219b2ee8SDavid du Colombier 	strcpy(psmpt->name, "/");
405219b2ee8SDavid du Colombier 	if(dirstat(psmpt->name, &dir) < 0)
406219b2ee8SDavid du Colombier 		return;
407219b2ee8SDavid du Colombier 
408*7dd7cddfSDavid du Colombier 	psmpt->ref = 1;
409219b2ee8SDavid du Colombier 	psmpt->qid.vers = dir.qid.vers;
410*7dd7cddfSDavid du Colombier 	psmpt->qidt = uniqueqid(&dir);
411*7dd7cddfSDavid du Colombier 	psmpt->qid.path = psmpt->qidt->uniqpath;
412219b2ee8SDavid du Colombier 
413219b2ee8SDavid du Colombier 	psmpt = file(psmpt, "mnt");
414219b2ee8SDavid du Colombier 	if(psmpt == 0)
415219b2ee8SDavid du Colombier 		return;
416219b2ee8SDavid du Colombier 	psmpt = file(psmpt, "exportfs");
4173e12c5d1SDavid du Colombier }
4183e12c5d1SDavid du Colombier 
4193e12c5d1SDavid du Colombier void
4203e12c5d1SDavid du Colombier makepath(char *s, File *p, char *name)
4213e12c5d1SDavid du Colombier {
4223e12c5d1SDavid du Colombier 	int i;
423219b2ee8SDavid du Colombier 	char *c, *seg[256];
4243e12c5d1SDavid du Colombier 
4253e12c5d1SDavid du Colombier 	seg[0] = name;
4263e12c5d1SDavid du Colombier 	for(i = 1; i < 100 && p; i++, p = p->parent)
4273e12c5d1SDavid du Colombier 		seg[i] = p->name;
4283e12c5d1SDavid du Colombier 
4293e12c5d1SDavid du Colombier 	while(i--) {
4303e12c5d1SDavid du Colombier 		for(c = seg[i]; *c; c++)
4313e12c5d1SDavid du Colombier 			*s++ = *c;
4323e12c5d1SDavid du Colombier 		*s++ = '/';
4333e12c5d1SDavid du Colombier 	}
4343e12c5d1SDavid du Colombier 	while(s[-1] == '/')
4353e12c5d1SDavid du Colombier 		s--;
4363e12c5d1SDavid du Colombier 	*s = '\0';
4373e12c5d1SDavid du Colombier }
4383e12c5d1SDavid du Colombier 
439*7dd7cddfSDavid du Colombier int
440*7dd7cddfSDavid du Colombier qidhash(ulong path)
441*7dd7cddfSDavid du Colombier {
442*7dd7cddfSDavid du Colombier 	int h, n;
443*7dd7cddfSDavid du Colombier 
444*7dd7cddfSDavid du Colombier 	h = 0;
445*7dd7cddfSDavid du Colombier 	for(n=0; n<32; n+=Nqidbits){
446*7dd7cddfSDavid du Colombier 		h ^= path;
447*7dd7cddfSDavid du Colombier 		path >>= Nqidbits;
448*7dd7cddfSDavid du Colombier 	}
449*7dd7cddfSDavid du Colombier 	return h & (Nqidtab-1);
450*7dd7cddfSDavid du Colombier }
451*7dd7cddfSDavid du Colombier 
452*7dd7cddfSDavid du Colombier void
453*7dd7cddfSDavid du Colombier freeqid(Qidtab *q)
454*7dd7cddfSDavid du Colombier {
455*7dd7cddfSDavid du Colombier 	ulong h;
456*7dd7cddfSDavid du Colombier 	Qidtab *l;
457*7dd7cddfSDavid du Colombier 
458*7dd7cddfSDavid du Colombier 	q->ref--;
459*7dd7cddfSDavid du Colombier 	if(q->ref > 0)
460*7dd7cddfSDavid du Colombier 		return;
461*7dd7cddfSDavid du Colombier 	qfreecnt++;
462*7dd7cddfSDavid du Colombier 	h = qidhash(q->path);
463*7dd7cddfSDavid du Colombier 	if(qidtab[h] == q)
464*7dd7cddfSDavid du Colombier 		qidtab[h] = q->next;
465*7dd7cddfSDavid du Colombier 	else{
466*7dd7cddfSDavid du Colombier 		for(l=qidtab[h]; l->next!=q; l=l->next)
467*7dd7cddfSDavid du Colombier 			if(l->next == nil)
468*7dd7cddfSDavid du Colombier 				fatal("bad qid list");
469*7dd7cddfSDavid du Colombier 		l->next = q->next;
470*7dd7cddfSDavid du Colombier 	}
471*7dd7cddfSDavid du Colombier 	free(q);
472*7dd7cddfSDavid du Colombier }
473*7dd7cddfSDavid du Colombier 
474*7dd7cddfSDavid du Colombier Qidtab*
475*7dd7cddfSDavid du Colombier qidlookup(Dir *d)
476*7dd7cddfSDavid du Colombier {
477*7dd7cddfSDavid du Colombier 	ulong h;
478*7dd7cddfSDavid du Colombier 	Qidtab *q;
479*7dd7cddfSDavid du Colombier 
480*7dd7cddfSDavid du Colombier 	h = qidhash(d->qid.path);
481*7dd7cddfSDavid du Colombier 	for(q=qidtab[h]; q!=nil; q=q->next)
482*7dd7cddfSDavid du Colombier 		if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path)
483*7dd7cddfSDavid du Colombier 			return q;
484*7dd7cddfSDavid du Colombier 	return nil;
485*7dd7cddfSDavid du Colombier }
486*7dd7cddfSDavid du Colombier 
487*7dd7cddfSDavid du Colombier int
488*7dd7cddfSDavid du Colombier qidexists(ulong path)
489*7dd7cddfSDavid du Colombier {
490*7dd7cddfSDavid du Colombier 	int h;
491*7dd7cddfSDavid du Colombier 	Qidtab *q;
492*7dd7cddfSDavid du Colombier 
493*7dd7cddfSDavid du Colombier 	for(h=0; h<Nqidtab; h++)
494*7dd7cddfSDavid du Colombier 		for(q=qidtab[h]; q!=nil; q=q->next)
495*7dd7cddfSDavid du Colombier 			if(q->uniqpath == path)
496*7dd7cddfSDavid du Colombier 				return 1;
497*7dd7cddfSDavid du Colombier 	return 0;
498*7dd7cddfSDavid du Colombier }
499*7dd7cddfSDavid du Colombier 
500*7dd7cddfSDavid du Colombier Qidtab*
501*7dd7cddfSDavid du Colombier uniqueqid(Dir *d)
502*7dd7cddfSDavid du Colombier {
503*7dd7cddfSDavid du Colombier 	ulong h, path;
504*7dd7cddfSDavid du Colombier 	Qidtab *q;
505*7dd7cddfSDavid du Colombier 
506*7dd7cddfSDavid du Colombier 	q = qidlookup(d);
507*7dd7cddfSDavid du Colombier 	if(q != nil){
508*7dd7cddfSDavid du Colombier 		q->ref++;
509*7dd7cddfSDavid du Colombier 		return q;
510*7dd7cddfSDavid du Colombier 	}
511*7dd7cddfSDavid du Colombier 	path = d->qid.path;
512*7dd7cddfSDavid du Colombier 	while(qidexists(path)){
513*7dd7cddfSDavid du Colombier 		/* collision: find a new one */
514*7dd7cddfSDavid du Colombier 		ncollision++;
515*7dd7cddfSDavid du Colombier 		DEBUG(DFD, "collision on %s\n", d->name);
516*7dd7cddfSDavid du Colombier 		path = newqid--;
517*7dd7cddfSDavid du Colombier 		if(newqid == 0)
518*7dd7cddfSDavid du Colombier 			newqid = ~QIDMODE;
519*7dd7cddfSDavid du Colombier 		path |= d->qid.path & (CHDIR|CHAPPEND|CHEXCL|CHMOUNT);
520*7dd7cddfSDavid du Colombier 	}
521*7dd7cddfSDavid du Colombier 	q = mallocz(sizeof(Qidtab), 1);
522*7dd7cddfSDavid du Colombier 	if(q == nil)
523*7dd7cddfSDavid du Colombier 		fatal("no memory for qid table");
524*7dd7cddfSDavid du Colombier 	qidcnt++;
525*7dd7cddfSDavid du Colombier 	q->ref = 1;
526*7dd7cddfSDavid du Colombier 	q->type = d->type;
527*7dd7cddfSDavid du Colombier 	q->dev = d->dev;
528*7dd7cddfSDavid du Colombier 	q->path = d->qid.path;
529*7dd7cddfSDavid du Colombier 	q->uniqpath = path;
530*7dd7cddfSDavid du Colombier 	h = qidhash(d->qid.path);
531*7dd7cddfSDavid du Colombier 	q->next = qidtab[h];
532*7dd7cddfSDavid du Colombier 	qidtab[h] = q;
533*7dd7cddfSDavid du Colombier 	return q;
534*7dd7cddfSDavid du Colombier }
535*7dd7cddfSDavid du Colombier 
5363e12c5d1SDavid du Colombier void
5373e12c5d1SDavid du Colombier fatal(char *s)
5383e12c5d1SDavid du Colombier {
5393e12c5d1SDavid du Colombier 	char buf[128];
5403e12c5d1SDavid du Colombier 	Proc *m;
5413e12c5d1SDavid du Colombier 
5423e12c5d1SDavid du Colombier 	sprint(buf, "exportfs: %r: %s", s);
5433e12c5d1SDavid du Colombier 
5443e12c5d1SDavid du Colombier 	/* Clear away the slave children */
5453e12c5d1SDavid du Colombier 	for(m = Proclist; m; m = m->next)
546219b2ee8SDavid du Colombier 		postnote(PNPROC, m->pid, "kill");
5473e12c5d1SDavid du Colombier 
548*7dd7cddfSDavid du Colombier 	DEBUG(DFD, "%s\n", buf);
5493e12c5d1SDavid du Colombier 	exits(buf);
5503e12c5d1SDavid du Colombier }
5513e12c5d1SDavid du Colombier 
552*7dd7cddfSDavid du Colombier /* Network on fd1, mount driver on fd0 */
553*7dd7cddfSDavid du Colombier int
554*7dd7cddfSDavid du Colombier filter(int fd)
5553e12c5d1SDavid du Colombier {
556*7dd7cddfSDavid du Colombier 	int p[2];
5573e12c5d1SDavid du Colombier 
558*7dd7cddfSDavid du Colombier 	if(pipe(p) < 0)
559*7dd7cddfSDavid du Colombier 		fatal("pipe");
560*7dd7cddfSDavid du Colombier 
561*7dd7cddfSDavid du Colombier 	switch(rfork(RFNOWAIT|RFPROC|RFFDG)) {
562*7dd7cddfSDavid du Colombier 	case -1:
563*7dd7cddfSDavid du Colombier 		fatal("rfork record module");
564*7dd7cddfSDavid du Colombier 	case 0:
565*7dd7cddfSDavid du Colombier 		dup(fd, 1);
566*7dd7cddfSDavid du Colombier 		close(fd);
567*7dd7cddfSDavid du Colombier 		dup(p[0], 0);
568*7dd7cddfSDavid du Colombier 		close(p[0]);
569*7dd7cddfSDavid du Colombier 		close(p[1]);
570*7dd7cddfSDavid du Colombier 		execl("/bin/aux/fcall", "fcall", 0);
571*7dd7cddfSDavid du Colombier 		fatal("exec record module");
572*7dd7cddfSDavid du Colombier 	default:
573*7dd7cddfSDavid du Colombier 		close(fd);
574*7dd7cddfSDavid du Colombier 		close(p[0]);
5753e12c5d1SDavid du Colombier 	}
576*7dd7cddfSDavid du Colombier 	return p[1];
5773e12c5d1SDavid du Colombier }
578