xref: /plan9/sys/src/cmd/exportfs/exportsrv.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <auth.h>
43e12c5d1SDavid du Colombier #include <fcall.h>
53e12c5d1SDavid du Colombier #define Extern	extern
63e12c5d1SDavid du Colombier #include "exportfs.h"
73e12c5d1SDavid du Colombier 
8*9a747e4fSDavid du Colombier char Ebadfid[] = "Bad fid";
9*9a747e4fSDavid du Colombier char Enotdir[] = "Not a directory";
10*9a747e4fSDavid du Colombier char Edupfid[] = "Fid already in use";
11*9a747e4fSDavid du Colombier char Eopen[] = "Fid already opened";
12*9a747e4fSDavid du Colombier char Exmnt[] = "Cannot .. past mount point";
13*9a747e4fSDavid du Colombier char Emip[] = "Mount in progress";
14*9a747e4fSDavid du Colombier char Enopsmt[] = "Out of pseudo mount points";
15*9a747e4fSDavid du Colombier char Enomem[] = "No memory";
16*9a747e4fSDavid du Colombier char Eversion[] = "Bad 9P2000 version";
17*9a747e4fSDavid du Colombier 
18*9a747e4fSDavid du Colombier ulong messagesize;
193e12c5d1SDavid du Colombier 
203e12c5d1SDavid du Colombier void
21*9a747e4fSDavid du Colombier Xversion(Fsrpc *t)
223e12c5d1SDavid du Colombier {
23*9a747e4fSDavid du Colombier 	Fcall rhdr;
243e12c5d1SDavid du Colombier 
25*9a747e4fSDavid du Colombier 	if(t->work.msize > messagesize)
26*9a747e4fSDavid du Colombier 		t->work.msize = messagesize;
27*9a747e4fSDavid du Colombier 	messagesize = t->work.msize;
28*9a747e4fSDavid du Colombier 	if(strncmp(t->work.version, "9P2000", 6) != 0){
29*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, Eversion);
30*9a747e4fSDavid du Colombier 		return;
31*9a747e4fSDavid du Colombier 	}
32*9a747e4fSDavid du Colombier 	rhdr.version = "9P2000";
33*9a747e4fSDavid du Colombier 	rhdr.msize = t->work.msize;
34*9a747e4fSDavid du Colombier 	reply(&t->work, &rhdr, 0);
35*9a747e4fSDavid du Colombier 	t->busy = 0;
363e12c5d1SDavid du Colombier }
373e12c5d1SDavid du Colombier 
383e12c5d1SDavid du Colombier void
39*9a747e4fSDavid du Colombier Xauth(Fsrpc *t)
403e12c5d1SDavid du Colombier {
41*9a747e4fSDavid du Colombier 	Fcall rhdr;
423e12c5d1SDavid du Colombier 
43*9a747e4fSDavid du Colombier 	reply(&t->work, &rhdr, "exportfs: no authentication required");
44*9a747e4fSDavid du Colombier 	t->busy = 0;
453e12c5d1SDavid du Colombier }
463e12c5d1SDavid du Colombier 
473e12c5d1SDavid du Colombier void
48*9a747e4fSDavid du Colombier Xflush(Fsrpc *t)
493e12c5d1SDavid du Colombier {
50*9a747e4fSDavid du Colombier 	Fsrpc *w, *e;
51*9a747e4fSDavid du Colombier 	Fcall rhdr;
523e12c5d1SDavid du Colombier 
533e12c5d1SDavid du Colombier 	e = &Workq[Nr_workbufs];
543e12c5d1SDavid du Colombier 
55*9a747e4fSDavid du Colombier 	for(w = Workq; w < e; w++) {
56*9a747e4fSDavid du Colombier 		if(w->work.tag == t->work.oldtag) {
57*9a747e4fSDavid du Colombier 			DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint);
58*9a747e4fSDavid du Colombier 			if(w->busy && w->pid) {
59*9a747e4fSDavid du Colombier 				w->flushtag = t->work.tag;
60*9a747e4fSDavid du Colombier 				DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
61*9a747e4fSDavid du Colombier 				if(w->canint)
62*9a747e4fSDavid du Colombier 					postnote(PNPROC, w->pid, "flush");
63*9a747e4fSDavid du Colombier 				t->busy = 0;
643e12c5d1SDavid du Colombier 				return;
653e12c5d1SDavid du Colombier 			}
663e12c5d1SDavid du Colombier 		}
673e12c5d1SDavid du Colombier 	}
683e12c5d1SDavid du Colombier 
69*9a747e4fSDavid du Colombier 	reply(&t->work, &rhdr, 0);
707dd7cddfSDavid du Colombier 	DEBUG(DFD, "\tflush reply\n");
71*9a747e4fSDavid du Colombier 	t->busy = 0;
723e12c5d1SDavid du Colombier }
733e12c5d1SDavid du Colombier 
743e12c5d1SDavid du Colombier void
75*9a747e4fSDavid du Colombier Xattach(Fsrpc *t)
763e12c5d1SDavid du Colombier {
77*9a747e4fSDavid du Colombier 	int i, nfd;
78*9a747e4fSDavid du Colombier 	Fcall rhdr;
793e12c5d1SDavid du Colombier 	Fid *f;
80*9a747e4fSDavid du Colombier 	char buf[128];
813e12c5d1SDavid du Colombier 
82*9a747e4fSDavid du Colombier 	f = newfid(t->work.fid);
833e12c5d1SDavid du Colombier 	if(f == 0) {
84*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, Ebadfid);
85*9a747e4fSDavid du Colombier 		t->busy = 0;
863e12c5d1SDavid du Colombier 		return;
873e12c5d1SDavid du Colombier 	}
883e12c5d1SDavid du Colombier 
89*9a747e4fSDavid du Colombier 	if(srvfd >= 0){
90*9a747e4fSDavid du Colombier 		if(psmpt == 0){
91*9a747e4fSDavid du Colombier 		Nomount:
92*9a747e4fSDavid du Colombier 			reply(&t->work, &rhdr, Enopsmt);
93*9a747e4fSDavid du Colombier 			t->busy = 0;
94*9a747e4fSDavid du Colombier 			freefid(t->work.fid);
95*9a747e4fSDavid du Colombier 			return;
96*9a747e4fSDavid du Colombier 		}
97*9a747e4fSDavid du Colombier 		for(i=0; i<Npsmpt; i++)
98*9a747e4fSDavid du Colombier 			if(psmap[i] == 0)
99*9a747e4fSDavid du Colombier 				break;
100*9a747e4fSDavid du Colombier 		if(i >= Npsmpt)
101*9a747e4fSDavid du Colombier 			goto Nomount;
102*9a747e4fSDavid du Colombier 		sprint(buf, "%d", i);
103*9a747e4fSDavid du Colombier 		f->f = file(psmpt, buf);
104*9a747e4fSDavid du Colombier 		if(f->f == nil)
105*9a747e4fSDavid du Colombier 			goto Nomount;
106*9a747e4fSDavid du Colombier 		sprint(buf, "/mnt/exportfs/%d", i);
107*9a747e4fSDavid du Colombier 		nfd = dup(srvfd, -1);
108*9a747e4fSDavid du Colombier 		if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
109*9a747e4fSDavid du Colombier 			errstr(buf, sizeof buf);
110*9a747e4fSDavid du Colombier 			reply(&t->work, &rhdr, buf);
111*9a747e4fSDavid du Colombier 			t->busy = 0;
112*9a747e4fSDavid du Colombier 			freefid(t->work.fid);
113*9a747e4fSDavid du Colombier 			close(nfd);
114*9a747e4fSDavid du Colombier 			return;
115*9a747e4fSDavid du Colombier 		}
116*9a747e4fSDavid du Colombier 		psmap[i] = 1;
117*9a747e4fSDavid du Colombier 		f->mid = i;
118*9a747e4fSDavid du Colombier 	}else{
1193e12c5d1SDavid du Colombier 		f->f = root;
1207dd7cddfSDavid du Colombier 		f->f->ref++;
1213e12c5d1SDavid du Colombier 	}
1223e12c5d1SDavid du Colombier 
123*9a747e4fSDavid du Colombier 	rhdr.qid = f->f->qid;
124*9a747e4fSDavid du Colombier 	reply(&t->work, &rhdr, 0);
125*9a747e4fSDavid du Colombier 	t->busy = 0;
126*9a747e4fSDavid du Colombier }
127*9a747e4fSDavid du Colombier 
128*9a747e4fSDavid du Colombier Fid*
129*9a747e4fSDavid du Colombier clonefid(Fid *f, int new)
1303e12c5d1SDavid du Colombier {
131*9a747e4fSDavid du Colombier 	Fid *n;
1323e12c5d1SDavid du Colombier 
133*9a747e4fSDavid du Colombier 	n = newfid(new);
1343e12c5d1SDavid du Colombier 	if(n == 0) {
135*9a747e4fSDavid du Colombier 		n = getfid(new);
136219b2ee8SDavid du Colombier 		if(n == 0)
137219b2ee8SDavid du Colombier 			fatal("inconsistent fids");
138219b2ee8SDavid du Colombier 		if(n->fid >= 0)
139219b2ee8SDavid du Colombier 			close(n->fid);
140*9a747e4fSDavid du Colombier 		freefid(new);
141*9a747e4fSDavid du Colombier 		n = newfid(new);
142219b2ee8SDavid du Colombier 		if(n == 0)
143219b2ee8SDavid du Colombier 			fatal("inconsistent fids2");
1443e12c5d1SDavid du Colombier 	}
1453e12c5d1SDavid du Colombier 	n->f = f->f;
1467dd7cddfSDavid du Colombier 	n->f->ref++;
147*9a747e4fSDavid du Colombier 	return n;
1483e12c5d1SDavid du Colombier }
1493e12c5d1SDavid du Colombier 
150*9a747e4fSDavid du Colombier void
151*9a747e4fSDavid du Colombier Xwalk(Fsrpc *t)
1523e12c5d1SDavid du Colombier {
153*9a747e4fSDavid du Colombier 	char err[ERRMAX], *e;
154*9a747e4fSDavid du Colombier 	Fcall rhdr;
155*9a747e4fSDavid du Colombier 	Fid *f, *nf;
156*9a747e4fSDavid du Colombier 	File *wf;
157*9a747e4fSDavid du Colombier 	int i;
1583e12c5d1SDavid du Colombier 
159*9a747e4fSDavid du Colombier 	f = getfid(t->work.fid);
1603e12c5d1SDavid du Colombier 	if(f == 0) {
161*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, Ebadfid);
162*9a747e4fSDavid du Colombier 		t->busy = 0;
163*9a747e4fSDavid du Colombier 		return;
1643e12c5d1SDavid du Colombier 	}
1653e12c5d1SDavid du Colombier 
166*9a747e4fSDavid du Colombier 	nf = nil;
167*9a747e4fSDavid du Colombier 	if(t->work.newfid != t->work.fid){
168*9a747e4fSDavid du Colombier 		nf = clonefid(f, t->work.newfid);
169*9a747e4fSDavid du Colombier 		f = nf;
170*9a747e4fSDavid du Colombier 	}
171*9a747e4fSDavid du Colombier 
172*9a747e4fSDavid du Colombier 	rhdr.nwqid = 0;
173*9a747e4fSDavid du Colombier 	e = nil;
174*9a747e4fSDavid du Colombier 	for(i=0; i<t->work.nwname; i++){
175*9a747e4fSDavid du Colombier 		if(i == MAXWELEM){
176*9a747e4fSDavid du Colombier 			e = "Too many path elements";
177*9a747e4fSDavid du Colombier 			break;
178*9a747e4fSDavid du Colombier 		}
179*9a747e4fSDavid du Colombier 
180*9a747e4fSDavid du Colombier 		if(strcmp(t->work.wname[i], "..") == 0) {
1817dd7cddfSDavid du Colombier 			if(f->f->parent == nil) {
182*9a747e4fSDavid du Colombier 				e = Exmnt;
183*9a747e4fSDavid du Colombier 				break;
1843e12c5d1SDavid du Colombier 			}
185*9a747e4fSDavid du Colombier 			wf = f->f->parent;
186*9a747e4fSDavid du Colombier 			wf->ref++;
187*9a747e4fSDavid du Colombier 			goto Accept;
1883e12c5d1SDavid du Colombier 		}
1893e12c5d1SDavid du Colombier 
190*9a747e4fSDavid du Colombier 		wf = file(f->f, t->work.wname[i]);
191*9a747e4fSDavid du Colombier 		if(wf == 0){
192*9a747e4fSDavid du Colombier 			errstr(err, sizeof err);
193*9a747e4fSDavid du Colombier 			e = err;
194*9a747e4fSDavid du Colombier 			break;
195*9a747e4fSDavid du Colombier 		}
196*9a747e4fSDavid du Colombier     Accept:
197*9a747e4fSDavid du Colombier 		freefile(f->f);
198*9a747e4fSDavid du Colombier 		rhdr.wqid[rhdr.nwqid++] = wf->qid;
199*9a747e4fSDavid du Colombier 		f->f = wf;
200*9a747e4fSDavid du Colombier 		continue;
2013e12c5d1SDavid du Colombier 	}
2023e12c5d1SDavid du Colombier 
203*9a747e4fSDavid du Colombier 	if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
204*9a747e4fSDavid du Colombier 		freefid(t->work.newfid);
205*9a747e4fSDavid du Colombier 	if(rhdr.nwqid > 0)
206*9a747e4fSDavid du Colombier 		e = nil;
207*9a747e4fSDavid du Colombier 	reply(&t->work, &rhdr, e);
208*9a747e4fSDavid du Colombier 	t->busy = 0;
2097dd7cddfSDavid du Colombier }
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier void
212*9a747e4fSDavid du Colombier Xclunk(Fsrpc *t)
2137dd7cddfSDavid du Colombier {
214*9a747e4fSDavid du Colombier 	Fcall rhdr;
2153e12c5d1SDavid du Colombier 	Fid *f;
2163e12c5d1SDavid du Colombier 
217*9a747e4fSDavid du Colombier 	f = getfid(t->work.fid);
2183e12c5d1SDavid du Colombier 	if(f == 0) {
219*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, Ebadfid);
220*9a747e4fSDavid du Colombier 		t->busy = 0;
2213e12c5d1SDavid du Colombier 		return;
2223e12c5d1SDavid du Colombier 	}
2233e12c5d1SDavid du Colombier 
2243e12c5d1SDavid du Colombier 	if(f->fid >= 0)
2253e12c5d1SDavid du Colombier 		close(f->fid);
2263e12c5d1SDavid du Colombier 
227*9a747e4fSDavid du Colombier 	freefid(t->work.fid);
228*9a747e4fSDavid du Colombier 	reply(&t->work, &rhdr, 0);
229*9a747e4fSDavid du Colombier 	t->busy = 0;
2303e12c5d1SDavid du Colombier }
2313e12c5d1SDavid du Colombier 
2323e12c5d1SDavid du Colombier void
233*9a747e4fSDavid du Colombier Xstat(Fsrpc *t)
2343e12c5d1SDavid du Colombier {
235*9a747e4fSDavid du Colombier 	char err[ERRMAX], *path;
236*9a747e4fSDavid du Colombier 	Fcall rhdr;
2373e12c5d1SDavid du Colombier 	Fid *f;
238*9a747e4fSDavid du Colombier 	Dir *d;
2393e12c5d1SDavid du Colombier 	int s;
240*9a747e4fSDavid du Colombier 	uchar *statbuf;
2413e12c5d1SDavid du Colombier 
242*9a747e4fSDavid du Colombier 	f = getfid(t->work.fid);
2433e12c5d1SDavid du Colombier 	if(f == 0) {
244*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, Ebadfid);
245*9a747e4fSDavid du Colombier 		t->busy = 0;
2463e12c5d1SDavid du Colombier 		return;
2473e12c5d1SDavid du Colombier 	}
2483e12c5d1SDavid du Colombier 	if(f->fid >= 0)
249*9a747e4fSDavid du Colombier 		d = dirfstat(f->fid);
2503e12c5d1SDavid du Colombier 	else {
251*9a747e4fSDavid du Colombier 		path = makepath(f->f, "");
252*9a747e4fSDavid du Colombier 		d = dirstat(path);
253*9a747e4fSDavid du Colombier 		free(path);
2543e12c5d1SDavid du Colombier 	}
2553e12c5d1SDavid du Colombier 
256*9a747e4fSDavid du Colombier 	if(d == nil) {
257*9a747e4fSDavid du Colombier 		errstr(err, sizeof err);
258*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, err);
259*9a747e4fSDavid du Colombier 		t->busy = 0;
2603e12c5d1SDavid du Colombier 		return;
2613e12c5d1SDavid du Colombier 	}
262*9a747e4fSDavid du Colombier 
263*9a747e4fSDavid du Colombier 	d->qid.path = f->f->qidt->uniqpath;
264*9a747e4fSDavid du Colombier 	s = sizeD2M(d);
265*9a747e4fSDavid du Colombier 	statbuf = emallocz(s);
266*9a747e4fSDavid du Colombier 	s = convD2M(d, statbuf, s);
267*9a747e4fSDavid du Colombier 	free(d);
268*9a747e4fSDavid du Colombier 	rhdr.nstat = s;
269*9a747e4fSDavid du Colombier 	rhdr.stat = statbuf;
270*9a747e4fSDavid du Colombier 	reply(&t->work, &rhdr, 0);
271*9a747e4fSDavid du Colombier 	free(statbuf);
272*9a747e4fSDavid du Colombier 	t->busy = 0;
273*9a747e4fSDavid du Colombier }
274*9a747e4fSDavid du Colombier 
275*9a747e4fSDavid du Colombier static int
276*9a747e4fSDavid du Colombier getiounit(int fd)
277*9a747e4fSDavid du Colombier {
278*9a747e4fSDavid du Colombier 	int n;
279*9a747e4fSDavid du Colombier 
280*9a747e4fSDavid du Colombier 	n = iounit(fd);
281*9a747e4fSDavid du Colombier 	if(n > messagesize-IOHDRSZ)
282*9a747e4fSDavid du Colombier 		n = messagesize-IOHDRSZ;
283*9a747e4fSDavid du Colombier 	return n;
2843e12c5d1SDavid du Colombier }
2853e12c5d1SDavid du Colombier 
2863e12c5d1SDavid du Colombier void
287*9a747e4fSDavid du Colombier Xcreate(Fsrpc *t)
2883e12c5d1SDavid du Colombier {
289*9a747e4fSDavid du Colombier 	char err[ERRMAX], *path;
290*9a747e4fSDavid du Colombier 	Fcall rhdr;
2913e12c5d1SDavid du Colombier 	Fid *f;
2923e12c5d1SDavid du Colombier 	File *nf;
2933e12c5d1SDavid du Colombier 
294*9a747e4fSDavid du Colombier 	f = getfid(t->work.fid);
2953e12c5d1SDavid du Colombier 	if(f == 0) {
296*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, Ebadfid);
297*9a747e4fSDavid du Colombier 		t->busy = 0;
2983e12c5d1SDavid du Colombier 		return;
2993e12c5d1SDavid du Colombier 	}
3003e12c5d1SDavid du Colombier 
3013e12c5d1SDavid du Colombier 
302*9a747e4fSDavid du Colombier 	path = makepath(f->f, t->work.name);
303*9a747e4fSDavid du Colombier 	f->fid = create(path, t->work.mode, t->work.perm);
304*9a747e4fSDavid du Colombier 	free(path);
3053e12c5d1SDavid du Colombier 	if(f->fid < 0) {
306*9a747e4fSDavid du Colombier 		errstr(err, sizeof err);
307*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, err);
308*9a747e4fSDavid du Colombier 		t->busy = 0;
3093e12c5d1SDavid du Colombier 		return;
3103e12c5d1SDavid du Colombier 	}
3113e12c5d1SDavid du Colombier 
312*9a747e4fSDavid du Colombier 	nf = file(f->f, t->work.name);
3133e12c5d1SDavid du Colombier 	if(nf == 0) {
314*9a747e4fSDavid du Colombier 		errstr(err, sizeof err);
315*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, err);
316*9a747e4fSDavid du Colombier 		t->busy = 0;
3173e12c5d1SDavid du Colombier 		return;
3183e12c5d1SDavid du Colombier 	}
3193e12c5d1SDavid du Colombier 
320*9a747e4fSDavid du Colombier 	f->mode = t->work.mode;
3217dd7cddfSDavid du Colombier 	freefile(f->f);
3223e12c5d1SDavid du Colombier 	f->f = nf;
323*9a747e4fSDavid du Colombier 	rhdr.qid = f->f->qid;
324*9a747e4fSDavid du Colombier 	rhdr.iounit = getiounit(f->fid);
325*9a747e4fSDavid du Colombier 	reply(&t->work, &rhdr, 0);
326*9a747e4fSDavid du Colombier 	t->busy = 0;
3273e12c5d1SDavid du Colombier }
3283e12c5d1SDavid du Colombier 
3293e12c5d1SDavid du Colombier void
330*9a747e4fSDavid du Colombier Xremove(Fsrpc *t)
3313e12c5d1SDavid du Colombier {
332*9a747e4fSDavid du Colombier 	char err[ERRMAX], *path;
333*9a747e4fSDavid du Colombier 	Fcall rhdr;
3343e12c5d1SDavid du Colombier 	Fid *f;
3353e12c5d1SDavid du Colombier 
336*9a747e4fSDavid du Colombier 	f = getfid(t->work.fid);
3373e12c5d1SDavid du Colombier 	if(f == 0) {
338*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, Ebadfid);
339*9a747e4fSDavid du Colombier 		t->busy = 0;
3403e12c5d1SDavid du Colombier 		return;
3413e12c5d1SDavid du Colombier 	}
3423e12c5d1SDavid du Colombier 
343*9a747e4fSDavid du Colombier 	path = makepath(f->f, "");
3447dd7cddfSDavid du Colombier 	DEBUG(DFD, "\tremove: %s\n", path);
3453e12c5d1SDavid du Colombier 	if(remove(path) < 0) {
346*9a747e4fSDavid du Colombier 		free(path);
347*9a747e4fSDavid du Colombier 		errstr(err, sizeof err);
348*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, err);
349*9a747e4fSDavid du Colombier 		t->busy = 0;
3503e12c5d1SDavid du Colombier 		return;
3513e12c5d1SDavid du Colombier 	}
352*9a747e4fSDavid du Colombier 	free(path);
3533e12c5d1SDavid du Colombier 
3547dd7cddfSDavid du Colombier 	f->f->inval = 1;
3553e12c5d1SDavid du Colombier 	if(f->fid >= 0)
3563e12c5d1SDavid du Colombier 		close(f->fid);
357*9a747e4fSDavid du Colombier 	freefid(t->work.fid);
3583e12c5d1SDavid du Colombier 
359*9a747e4fSDavid du Colombier 	reply(&t->work, &rhdr, 0);
360*9a747e4fSDavid du Colombier 	t->busy = 0;
3613e12c5d1SDavid du Colombier }
3623e12c5d1SDavid du Colombier 
3633e12c5d1SDavid du Colombier void
364*9a747e4fSDavid du Colombier Xwstat(Fsrpc *t)
3653e12c5d1SDavid du Colombier {
366*9a747e4fSDavid du Colombier 	char err[ERRMAX], *path;
367*9a747e4fSDavid du Colombier 	Fcall rhdr;
3683e12c5d1SDavid du Colombier 	Fid *f;
3693e12c5d1SDavid du Colombier 	int s;
370*9a747e4fSDavid du Colombier 	char *strings;
371*9a747e4fSDavid du Colombier 	Dir d;
3723e12c5d1SDavid du Colombier 
373*9a747e4fSDavid du Colombier 	f = getfid(t->work.fid);
3743e12c5d1SDavid du Colombier 	if(f == 0) {
375*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, Ebadfid);
376*9a747e4fSDavid du Colombier 		t->busy = 0;
3773e12c5d1SDavid du Colombier 		return;
3783e12c5d1SDavid du Colombier 	}
379*9a747e4fSDavid du Colombier 	strings = emallocz(t->work.nstat);	/* ample */
380*9a747e4fSDavid du Colombier 	if(convM2D(t->work.stat, t->work.nstat, &d, strings) < 0){
381*9a747e4fSDavid du Colombier 		rerrstr(err, sizeof err);
382*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, err);
383*9a747e4fSDavid du Colombier 		t->busy = 0;
384*9a747e4fSDavid du Colombier 		free(strings);
385*9a747e4fSDavid du Colombier 		return;
386*9a747e4fSDavid du Colombier 	}
387*9a747e4fSDavid du Colombier 
3883e12c5d1SDavid du Colombier 	if(f->fid >= 0)
389*9a747e4fSDavid du Colombier 		s = dirfwstat(f->fid, &d);
3903e12c5d1SDavid du Colombier 	else {
391*9a747e4fSDavid du Colombier 		path = makepath(f->f, "");
392*9a747e4fSDavid du Colombier 		s = dirwstat(path, &d);
393*9a747e4fSDavid du Colombier 		free(path);
3943e12c5d1SDavid du Colombier 	}
3953e12c5d1SDavid du Colombier 	if(s < 0) {
396*9a747e4fSDavid du Colombier 		rerrstr(err, sizeof err);
397*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, err);
3983e12c5d1SDavid du Colombier 	}
399219b2ee8SDavid du Colombier 	else {
400219b2ee8SDavid du Colombier 		/* wstat may really be rename */
401*9a747e4fSDavid du Colombier 		if(strcmp(d.name, f->f->name)!=0){
402*9a747e4fSDavid du Colombier 			free(f->f->name);
403*9a747e4fSDavid du Colombier 			f->f->name = estrdup(d.name);
404219b2ee8SDavid du Colombier 		}
405*9a747e4fSDavid du Colombier 		reply(&t->work, &rhdr, 0);
4063e12c5d1SDavid du Colombier 	}
407*9a747e4fSDavid du Colombier 	free(strings);
408*9a747e4fSDavid du Colombier 	t->busy = 0;
4093e12c5d1SDavid du Colombier }
4103e12c5d1SDavid du Colombier 
4113e12c5d1SDavid du Colombier void
4123e12c5d1SDavid du Colombier slave(Fsrpc *f)
4133e12c5d1SDavid du Colombier {
4143e12c5d1SDavid du Colombier 	Proc *p;
415*9a747e4fSDavid du Colombier 	int pid;
4163e12c5d1SDavid du Colombier 	static int nproc;
4173e12c5d1SDavid du Colombier 
4183e12c5d1SDavid du Colombier 	for(;;) {
4193e12c5d1SDavid du Colombier 		for(p = Proclist; p; p = p->next) {
4203e12c5d1SDavid du Colombier 			if(p->busy == 0) {
4213e12c5d1SDavid du Colombier 				f->pid = p->pid;
4223e12c5d1SDavid du Colombier 				p->busy = 1;
4233e12c5d1SDavid du Colombier 				pid = rendezvous(p->pid, (ulong)f);
4243e12c5d1SDavid du Colombier 				if(pid != p->pid)
4253e12c5d1SDavid du Colombier 					fatal("rendezvous sync fail");
4263e12c5d1SDavid du Colombier 				return;
4273e12c5d1SDavid du Colombier 			}
4283e12c5d1SDavid du Colombier 		}
4293e12c5d1SDavid du Colombier 
4303e12c5d1SDavid du Colombier 		if(++nproc > MAXPROC)
4313e12c5d1SDavid du Colombier 			fatal("too many procs");
4323e12c5d1SDavid du Colombier 
4333e12c5d1SDavid du Colombier 		pid = rfork(RFPROC|RFMEM);
4343e12c5d1SDavid du Colombier 		switch(pid) {
4353e12c5d1SDavid du Colombier 		case -1:
4363e12c5d1SDavid du Colombier 			fatal("rfork");
4373e12c5d1SDavid du Colombier 
4383e12c5d1SDavid du Colombier 		case 0:
4393e12c5d1SDavid du Colombier 			blockingslave();
4403e12c5d1SDavid du Colombier 			fatal("slave");
4413e12c5d1SDavid du Colombier 
4423e12c5d1SDavid du Colombier 		default:
4433e12c5d1SDavid du Colombier 			p = malloc(sizeof(Proc));
4443e12c5d1SDavid du Colombier 			if(p == 0)
4453e12c5d1SDavid du Colombier 				fatal("out of memory");
4463e12c5d1SDavid du Colombier 
4473e12c5d1SDavid du Colombier 			p->busy = 0;
4483e12c5d1SDavid du Colombier 			p->pid = pid;
4493e12c5d1SDavid du Colombier 			p->next = Proclist;
4503e12c5d1SDavid du Colombier 			Proclist = p;
4513e12c5d1SDavid du Colombier 
4523e12c5d1SDavid du Colombier 			rendezvous(pid, (ulong)p);
4533e12c5d1SDavid du Colombier 		}
4543e12c5d1SDavid du Colombier 	}
4553e12c5d1SDavid du Colombier }
4563e12c5d1SDavid du Colombier 
4573e12c5d1SDavid du Colombier void
4583e12c5d1SDavid du Colombier blockingslave(void)
4593e12c5d1SDavid du Colombier {
4603e12c5d1SDavid du Colombier 	Fsrpc *p;
461*9a747e4fSDavid du Colombier 	Fcall rhdr;
4623e12c5d1SDavid du Colombier 	Proc *m;
4633e12c5d1SDavid du Colombier 	int pid;
4643e12c5d1SDavid du Colombier 
4653e12c5d1SDavid du Colombier 	notify(flushaction);
4663e12c5d1SDavid du Colombier 
4673e12c5d1SDavid du Colombier 	pid = getpid();
4683e12c5d1SDavid du Colombier 
4693e12c5d1SDavid du Colombier 	m = (Proc*)rendezvous(pid, 0);
4703e12c5d1SDavid du Colombier 
4713e12c5d1SDavid du Colombier 	for(;;) {
4723e12c5d1SDavid du Colombier 		p = (Fsrpc*)rendezvous(pid, pid);
4733e12c5d1SDavid du Colombier 		if((int)p == ~0)			/* Interrupted */
4743e12c5d1SDavid du Colombier 			continue;
4753e12c5d1SDavid du Colombier 
4767dd7cddfSDavid du Colombier 		DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid);
4773e12c5d1SDavid du Colombier 		if(p->flushtag != NOTAG)
4783e12c5d1SDavid du Colombier 			goto flushme;
4793e12c5d1SDavid du Colombier 
4803e12c5d1SDavid du Colombier 		switch(p->work.type) {
4813e12c5d1SDavid du Colombier 		case Tread:
4823e12c5d1SDavid du Colombier 			slaveread(p);
4833e12c5d1SDavid du Colombier 			break;
4843e12c5d1SDavid du Colombier 
4853e12c5d1SDavid du Colombier 		case Twrite:
4863e12c5d1SDavid du Colombier 			slavewrite(p);
4873e12c5d1SDavid du Colombier 			break;
4883e12c5d1SDavid du Colombier 
4893e12c5d1SDavid du Colombier 		case Topen:
4903e12c5d1SDavid du Colombier 			slaveopen(p);
4913e12c5d1SDavid du Colombier 			break;
4923e12c5d1SDavid du Colombier 
4933e12c5d1SDavid du Colombier 		default:
494*9a747e4fSDavid du Colombier 			reply(&p->work, &rhdr, "exportfs: slave type error");
4953e12c5d1SDavid du Colombier 		}
4963e12c5d1SDavid du Colombier 		if(p->flushtag != NOTAG) {
4973e12c5d1SDavid du Colombier flushme:
4983e12c5d1SDavid du Colombier 			p->work.type = Tflush;
4993e12c5d1SDavid du Colombier 			p->work.tag = p->flushtag;
500*9a747e4fSDavid du Colombier 			reply(&p->work, &rhdr, 0);
5013e12c5d1SDavid du Colombier 		}
5023e12c5d1SDavid du Colombier 		p->busy = 0;
5033e12c5d1SDavid du Colombier 		m->busy = 0;
5043e12c5d1SDavid du Colombier 	}
5053e12c5d1SDavid du Colombier }
5063e12c5d1SDavid du Colombier 
507*9a747e4fSDavid du Colombier int
508*9a747e4fSDavid du Colombier openmount(int sfd)
509219b2ee8SDavid du Colombier {
510*9a747e4fSDavid du Colombier 	int p[2];
511*9a747e4fSDavid du Colombier 	char *arg[10], fdbuf[20], mbuf[20];
512219b2ee8SDavid du Colombier 
513*9a747e4fSDavid du Colombier 	if(pipe(p) < 0)
514*9a747e4fSDavid du Colombier 		return -1;
515219b2ee8SDavid du Colombier 
516*9a747e4fSDavid du Colombier 	switch(rfork(RFPROC|RFMEM|RFNOWAIT|RFNAMEG|RFFDG)){
517*9a747e4fSDavid du Colombier 	case -1:
518*9a747e4fSDavid du Colombier 		return -1;
519*9a747e4fSDavid du Colombier 
520*9a747e4fSDavid du Colombier 	default:
521*9a747e4fSDavid du Colombier 		close(sfd);
522*9a747e4fSDavid du Colombier 		close(p[0]);
523*9a747e4fSDavid du Colombier 		return p[1];
524*9a747e4fSDavid du Colombier 
525*9a747e4fSDavid du Colombier 	case 0:
526219b2ee8SDavid du Colombier 		break;
527219b2ee8SDavid du Colombier 	}
528219b2ee8SDavid du Colombier 
529*9a747e4fSDavid du Colombier 	close(p[1]);
530219b2ee8SDavid du Colombier 
531*9a747e4fSDavid du Colombier 	arg[0] = "exportfs";
532*9a747e4fSDavid du Colombier 	snprint(fdbuf, sizeof fdbuf, "-S/fd/%d", sfd);
533*9a747e4fSDavid du Colombier 	arg[1] = fdbuf;
534*9a747e4fSDavid du Colombier 	snprint(mbuf, sizeof mbuf, "-m%lud", messagesize-IOHDRSZ);
535*9a747e4fSDavid du Colombier 	arg[2] = mbuf;
536*9a747e4fSDavid du Colombier 	arg[3] = nil;
537219b2ee8SDavid du Colombier 
538*9a747e4fSDavid du Colombier 	close(0);
539*9a747e4fSDavid du Colombier 	close(1);
540*9a747e4fSDavid du Colombier 	dup(p[0], 0);
541*9a747e4fSDavid du Colombier 	dup(p[0], 1);
542*9a747e4fSDavid du Colombier 	exec("/bin/exportfs", arg);
543*9a747e4fSDavid du Colombier 	_exits("whoops: exec failed");
544*9a747e4fSDavid du Colombier 	return -1;
545219b2ee8SDavid du Colombier }
546219b2ee8SDavid du Colombier 
5473e12c5d1SDavid du Colombier void
5483e12c5d1SDavid du Colombier slaveopen(Fsrpc *p)
5493e12c5d1SDavid du Colombier {
550*9a747e4fSDavid du Colombier 	char err[ERRMAX], *path;
551*9a747e4fSDavid du Colombier 	Fcall *work, rhdr;
5523e12c5d1SDavid du Colombier 	Fid *f;
553*9a747e4fSDavid du Colombier 	Dir *d;
5543e12c5d1SDavid du Colombier 
5553e12c5d1SDavid du Colombier 	work = &p->work;
5563e12c5d1SDavid du Colombier 
5573e12c5d1SDavid du Colombier 	f = getfid(work->fid);
5583e12c5d1SDavid du Colombier 	if(f == 0) {
559*9a747e4fSDavid du Colombier 		reply(work, &rhdr, Ebadfid);
5603e12c5d1SDavid du Colombier 		return;
5613e12c5d1SDavid du Colombier 	}
5623e12c5d1SDavid du Colombier 	if(f->fid >= 0) {
5633e12c5d1SDavid du Colombier 		close(f->fid);
5643e12c5d1SDavid du Colombier 		f->fid = -1;
5653e12c5d1SDavid du Colombier 	}
5663e12c5d1SDavid du Colombier 
567*9a747e4fSDavid du Colombier 	path = makepath(f->f, "");
5687dd7cddfSDavid du Colombier 	DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
5693e12c5d1SDavid du Colombier 
5703e12c5d1SDavid du Colombier 	p->canint = 1;
571*9a747e4fSDavid du Colombier 	if(p->flushtag != NOTAG){
572*9a747e4fSDavid du Colombier 		free(path);
5733e12c5d1SDavid du Colombier 		return;
574*9a747e4fSDavid du Colombier 	}
5753e12c5d1SDavid du Colombier 	/* There is a race here I ignore because there are no locks */
5763e12c5d1SDavid du Colombier 	f->fid = open(path, work->mode);
577*9a747e4fSDavid du Colombier 	free(path);
5783e12c5d1SDavid du Colombier 	p->canint = 0;
579*9a747e4fSDavid du Colombier 	if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
580*9a747e4fSDavid du Colombier 	Error:
581*9a747e4fSDavid du Colombier 		errstr(err, sizeof err);
582*9a747e4fSDavid du Colombier 		reply(work, &rhdr, err);
5833e12c5d1SDavid du Colombier 		return;
5843e12c5d1SDavid du Colombier 	}
585*9a747e4fSDavid du Colombier 	f->f->qid = d->qid;
586*9a747e4fSDavid du Colombier 	free(d);
587*9a747e4fSDavid du Colombier 	if(f->f->qid.type & QTMOUNT){	/* fork new exportfs for this */
588*9a747e4fSDavid du Colombier 		f->fid = openmount(f->fid);
589*9a747e4fSDavid du Colombier 		if(f->fid < 0)
590*9a747e4fSDavid du Colombier 			goto Error;
591*9a747e4fSDavid du Colombier 	}
5923e12c5d1SDavid du Colombier 
5937dd7cddfSDavid du Colombier 	DEBUG(DFD, "\topen: fd %d\n", f->fid);
5943e12c5d1SDavid du Colombier 	f->mode = work->mode;
595*9a747e4fSDavid du Colombier 	rhdr.iounit = getiounit(f->fid);
596*9a747e4fSDavid du Colombier 	rhdr.qid = f->f->qid;
597*9a747e4fSDavid du Colombier 	reply(work, &rhdr, 0);
5983e12c5d1SDavid du Colombier }
5993e12c5d1SDavid du Colombier 
6003e12c5d1SDavid du Colombier void
6013e12c5d1SDavid du Colombier slaveread(Fsrpc *p)
6023e12c5d1SDavid du Colombier {
6033e12c5d1SDavid du Colombier 	Fid *f;
6043e12c5d1SDavid du Colombier 	int n, r;
605*9a747e4fSDavid du Colombier 	Fcall *work, rhdr;
606*9a747e4fSDavid du Colombier 	char *data, err[ERRMAX];
6073e12c5d1SDavid du Colombier 
6083e12c5d1SDavid du Colombier 	work = &p->work;
6093e12c5d1SDavid du Colombier 
6103e12c5d1SDavid du Colombier 	f = getfid(work->fid);
6113e12c5d1SDavid du Colombier 	if(f == 0) {
612*9a747e4fSDavid du Colombier 		reply(work, &rhdr, Ebadfid);
6133e12c5d1SDavid du Colombier 		return;
6143e12c5d1SDavid du Colombier 	}
6153e12c5d1SDavid du Colombier 
616*9a747e4fSDavid du Colombier 	n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
6173e12c5d1SDavid du Colombier 	p->canint = 1;
6183e12c5d1SDavid du Colombier 	if(p->flushtag != NOTAG)
6193e12c5d1SDavid du Colombier 		return;
620*9a747e4fSDavid du Colombier 	data = malloc(n);
621*9a747e4fSDavid du Colombier 	if(data == nil)
622*9a747e4fSDavid du Colombier 		fatal(Enomem);
623*9a747e4fSDavid du Colombier 
624*9a747e4fSDavid du Colombier 	/* can't just call pread, since directories must update the offset */
625*9a747e4fSDavid du Colombier 	r = pread(f->fid, data, n, work->offset);
6263e12c5d1SDavid du Colombier 	p->canint = 0;
6273e12c5d1SDavid du Colombier 	if(r < 0) {
628*9a747e4fSDavid du Colombier 		free(data);
629*9a747e4fSDavid du Colombier 		errstr(err, sizeof err);
630*9a747e4fSDavid du Colombier 		reply(work, &rhdr, err);
6313e12c5d1SDavid du Colombier 		return;
6323e12c5d1SDavid du Colombier 	}
6333e12c5d1SDavid du Colombier 
6347dd7cddfSDavid du Colombier 	DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
6353e12c5d1SDavid du Colombier 
636*9a747e4fSDavid du Colombier 	rhdr.data = data;
637*9a747e4fSDavid du Colombier 	rhdr.count = r;
638*9a747e4fSDavid du Colombier 	reply(work, &rhdr, 0);
639*9a747e4fSDavid du Colombier 	free(data);
6403e12c5d1SDavid du Colombier }
6413e12c5d1SDavid du Colombier 
6423e12c5d1SDavid du Colombier void
6433e12c5d1SDavid du Colombier slavewrite(Fsrpc *p)
6443e12c5d1SDavid du Colombier {
645*9a747e4fSDavid du Colombier 	char err[ERRMAX];
646*9a747e4fSDavid du Colombier 	Fcall *work, rhdr;
6473e12c5d1SDavid du Colombier 	Fid *f;
6483e12c5d1SDavid du Colombier 	int n;
6493e12c5d1SDavid du Colombier 
6503e12c5d1SDavid du Colombier 	work = &p->work;
6513e12c5d1SDavid du Colombier 
6523e12c5d1SDavid du Colombier 	f = getfid(work->fid);
6533e12c5d1SDavid du Colombier 	if(f == 0) {
654*9a747e4fSDavid du Colombier 		reply(work, &rhdr, Ebadfid);
6553e12c5d1SDavid du Colombier 		return;
6563e12c5d1SDavid du Colombier 	}
6573e12c5d1SDavid du Colombier 
658*9a747e4fSDavid du Colombier 	n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
6593e12c5d1SDavid du Colombier 	p->canint = 1;
6603e12c5d1SDavid du Colombier 	if(p->flushtag != NOTAG)
6613e12c5d1SDavid du Colombier 		return;
662*9a747e4fSDavid du Colombier 	n = pwrite(f->fid, work->data, n, work->offset);
6633e12c5d1SDavid du Colombier 	p->canint = 0;
6643e12c5d1SDavid du Colombier 	if(n < 0) {
665*9a747e4fSDavid du Colombier 		errstr(err, sizeof err);
666*9a747e4fSDavid du Colombier 		reply(work, &rhdr, err);
6673e12c5d1SDavid du Colombier 		return;
6683e12c5d1SDavid du Colombier 	}
6693e12c5d1SDavid du Colombier 
6707dd7cddfSDavid du Colombier 	DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
6713e12c5d1SDavid du Colombier 
672*9a747e4fSDavid du Colombier 	rhdr.count = n;
673*9a747e4fSDavid du Colombier 	reply(work, &rhdr, 0);
6743e12c5d1SDavid du Colombier }
6753e12c5d1SDavid du Colombier 
6763e12c5d1SDavid du Colombier void
6773e12c5d1SDavid du Colombier reopen(Fid *f)
6783e12c5d1SDavid du Colombier {
6793e12c5d1SDavid du Colombier 	USED(f);
6803e12c5d1SDavid du Colombier 	fatal("reopen");
6813e12c5d1SDavid du Colombier }
6823e12c5d1SDavid du Colombier 
6833e12c5d1SDavid du Colombier void
6843e12c5d1SDavid du Colombier flushaction(void *a, char *cause)
6853e12c5d1SDavid du Colombier {
6863e12c5d1SDavid du Colombier 	USED(a);
6873e12c5d1SDavid du Colombier 	if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
6883e12c5d1SDavid du Colombier 		fprint(2, "exportsrv: note: %s\n", cause);
6893e12c5d1SDavid du Colombier 		exits("noted");
6903e12c5d1SDavid du Colombier 	}
6913e12c5d1SDavid du Colombier 	if(strncmp(cause, "kill", 4) == 0)
6923e12c5d1SDavid du Colombier 		noted(NDFLT);
6933e12c5d1SDavid du Colombier 
6943e12c5d1SDavid du Colombier 	noted(NCONT);
6953e12c5d1SDavid du Colombier }
696