xref: /plan9/sys/src/cmd/execnet/fs.c (revision fb7f0c934c48abaed6040d054ef636408c3c522d)
19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier  * ``Exec'' network device.  Mounted on net, provides /net/exec.
39a747e4fSDavid du Colombier  *
49a747e4fSDavid du Colombier  *	exec				protocol directory
59a747e4fSDavid du Colombier  *		n 				connection directory
69a747e4fSDavid du Colombier  *			ctl				control messages (like connect)
79a747e4fSDavid du Colombier  *			data				data
89a747e4fSDavid du Colombier  *			err				errors
99a747e4fSDavid du Colombier  *			local				local address (pid of command)
109a747e4fSDavid du Colombier  *			remote			remote address (command)
119a747e4fSDavid du Colombier  *			status			status
129a747e4fSDavid du Colombier  */
139a747e4fSDavid du Colombier 
149a747e4fSDavid du Colombier #include <u.h>
159a747e4fSDavid du Colombier #include <libc.h>
169a747e4fSDavid du Colombier #include <fcall.h>
179a747e4fSDavid du Colombier #include <thread.h>
189a747e4fSDavid du Colombier #include <9p.h>
199a747e4fSDavid du Colombier #include "dat.h"
209a747e4fSDavid du Colombier 
219a747e4fSDavid du Colombier int fsdebug;
229a747e4fSDavid du Colombier 
239a747e4fSDavid du Colombier enum
249a747e4fSDavid du Colombier {
259a747e4fSDavid du Colombier 	Qroot,
269a747e4fSDavid du Colombier 	Qexec,
279a747e4fSDavid du Colombier 	Qclone,
289a747e4fSDavid du Colombier 	Qn,
299a747e4fSDavid du Colombier 	Qctl,
309a747e4fSDavid du Colombier 	Qdata,
319a747e4fSDavid du Colombier 	Qlocal,
329a747e4fSDavid du Colombier 	Qremote,
339a747e4fSDavid du Colombier 	Qstatus,
349a747e4fSDavid du Colombier };
359a747e4fSDavid du Colombier 
369a747e4fSDavid du Colombier #define PATH(type, n)	((type)|((n)<<8))
379a747e4fSDavid du Colombier #define TYPE(path)		((int)(path) & 0xFF)
389a747e4fSDavid du Colombier #define NUM(path)		((uint)(path)>>8)
399a747e4fSDavid du Colombier 
409a747e4fSDavid du Colombier typedef struct Tab Tab;
419a747e4fSDavid du Colombier struct Tab
429a747e4fSDavid du Colombier {
439a747e4fSDavid du Colombier 	char *name;
449a747e4fSDavid du Colombier 	ulong mode;
459a747e4fSDavid du Colombier };
469a747e4fSDavid du Colombier 
479a747e4fSDavid du Colombier Tab tab[] =
489a747e4fSDavid du Colombier {
499a747e4fSDavid du Colombier 	"/",		DMDIR|0555,
509a747e4fSDavid du Colombier 	"exec",	DMDIR|0555,
519a747e4fSDavid du Colombier 	"clone",	0666,
529a747e4fSDavid du Colombier 	nil,		DMDIR|0555,
539a747e4fSDavid du Colombier 	"ctl",		0666,
549a747e4fSDavid du Colombier 	"data",	0666,
559a747e4fSDavid du Colombier 	"local",	0444,
569a747e4fSDavid du Colombier 	"remote",	0444,
579a747e4fSDavid du Colombier 	"status",	0444,
589a747e4fSDavid du Colombier };
599a747e4fSDavid du Colombier 
609a747e4fSDavid du Colombier void
setexecname(char * s)619a747e4fSDavid du Colombier setexecname(char *s)
629a747e4fSDavid du Colombier {
639a747e4fSDavid du Colombier 	tab[Qexec].name = s;
649a747e4fSDavid du Colombier }
659a747e4fSDavid du Colombier 
669a747e4fSDavid du Colombier ulong time0;
679a747e4fSDavid du Colombier 
689a747e4fSDavid du Colombier static void
fillstat(Dir * d,ulong path)699a747e4fSDavid du Colombier fillstat(Dir *d, ulong path)
709a747e4fSDavid du Colombier {
719a747e4fSDavid du Colombier 	Tab *t;
729a747e4fSDavid du Colombier 	int type;
739a747e4fSDavid du Colombier 	char buf[32];
749a747e4fSDavid du Colombier 
759a747e4fSDavid du Colombier 	memset(d, 0, sizeof(*d));
769a747e4fSDavid du Colombier 	d->uid = estrdup("exec");
779a747e4fSDavid du Colombier 	d->gid = estrdup("exec");
789a747e4fSDavid du Colombier 	d->qid.path = path;
799a747e4fSDavid du Colombier 	d->atime = d->mtime = time0;
809a747e4fSDavid du Colombier 	d->length = 0;
819a747e4fSDavid du Colombier 
829a747e4fSDavid du Colombier 	type = TYPE(path);
839a747e4fSDavid du Colombier 	t = &tab[type];
849a747e4fSDavid du Colombier 	if(t->name)
859a747e4fSDavid du Colombier 		d->name = estrdup(t->name);
869a747e4fSDavid du Colombier 	else{
879a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "%ud", NUM(path));
889a747e4fSDavid du Colombier 		d->name = estrdup(buf);
899a747e4fSDavid du Colombier 	}
909a747e4fSDavid du Colombier 	d->qid.type = t->mode>>24;
919a747e4fSDavid du Colombier 	d->mode = t->mode;
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier 
949a747e4fSDavid du Colombier static void
fsstat(Req * r)959a747e4fSDavid du Colombier fsstat(Req *r)
969a747e4fSDavid du Colombier {
979a747e4fSDavid du Colombier 	fillstat(&r->d, r->fid->qid.path);
989a747e4fSDavid du Colombier 	respond(r, nil);
999a747e4fSDavid du Colombier }
1009a747e4fSDavid du Colombier 
1019a747e4fSDavid du Colombier static int
rootgen(int i,Dir * d,void *)1029a747e4fSDavid du Colombier rootgen(int i, Dir *d, void*)
1039a747e4fSDavid du Colombier {
1049a747e4fSDavid du Colombier 	if(i < 1){
1059a747e4fSDavid du Colombier 		fillstat(d, PATH(Qexec, 0));
1069a747e4fSDavid du Colombier 		return 0;
1079a747e4fSDavid du Colombier 	}
1089a747e4fSDavid du Colombier 	return -1;
1099a747e4fSDavid du Colombier }
1109a747e4fSDavid du Colombier 
1119a747e4fSDavid du Colombier static int
execgen(int i,Dir * d,void *)1129a747e4fSDavid du Colombier execgen(int i, Dir *d, void*)
1139a747e4fSDavid du Colombier {
1149a747e4fSDavid du Colombier 	if(i < 1){
1159a747e4fSDavid du Colombier 		fillstat(d, PATH(Qclone, 0));
1169a747e4fSDavid du Colombier 		return 0;
1179a747e4fSDavid du Colombier 	}
1189a747e4fSDavid du Colombier 	i -= 1;
1199a747e4fSDavid du Colombier 
1209a747e4fSDavid du Colombier 	if(i < nclient){
1219a747e4fSDavid du Colombier 		fillstat(d, PATH(Qn, i));
1229a747e4fSDavid du Colombier 		return 0;
1239a747e4fSDavid du Colombier 	}
1249a747e4fSDavid du Colombier 	return -1;
1259a747e4fSDavid du Colombier }
1269a747e4fSDavid du Colombier 
1279a747e4fSDavid du Colombier static int
conngen(int i,Dir * d,void * aux)1289a747e4fSDavid du Colombier conngen(int i, Dir *d, void *aux)
1299a747e4fSDavid du Colombier {
1309a747e4fSDavid du Colombier 	Client *c;
1319a747e4fSDavid du Colombier 
1329a747e4fSDavid du Colombier 	c = aux;
1339a747e4fSDavid du Colombier 	i += Qn+1;
1349a747e4fSDavid du Colombier 	if(i <= Qstatus){
1359a747e4fSDavid du Colombier 		fillstat(d, PATH(i, c->num));
1369a747e4fSDavid du Colombier 		return 0;
1379a747e4fSDavid du Colombier 	}
1389a747e4fSDavid du Colombier 	return -1;
1399a747e4fSDavid du Colombier }
1409a747e4fSDavid du Colombier 
1419a747e4fSDavid du Colombier char *statusstr[] =
1429a747e4fSDavid du Colombier {
1439a747e4fSDavid du Colombier 	"Closed",
1449a747e4fSDavid du Colombier 	"Exec",
1459a747e4fSDavid du Colombier 	"Established",
1469a747e4fSDavid du Colombier 	"Hangup",
1479a747e4fSDavid du Colombier };
1489a747e4fSDavid du Colombier 
1499a747e4fSDavid du Colombier static void
fsread(Req * r)1509a747e4fSDavid du Colombier fsread(Req *r)
1519a747e4fSDavid du Colombier {
1529a747e4fSDavid du Colombier 	char e[ERRMAX], *s;
1539a747e4fSDavid du Colombier 	ulong path;
1549a747e4fSDavid du Colombier 
1559a747e4fSDavid du Colombier 	path = r->fid->qid.path;
1569a747e4fSDavid du Colombier 	switch(TYPE(path)){
1579a747e4fSDavid du Colombier 	default:
1589a747e4fSDavid du Colombier 		snprint(e, sizeof e, "bug in execnet path=%lux", path);
1599a747e4fSDavid du Colombier 		respond(r, e);
1609a747e4fSDavid du Colombier 		break;
1619a747e4fSDavid du Colombier 
1629a747e4fSDavid du Colombier 	case Qroot:
1639a747e4fSDavid du Colombier 		dirread9p(r, rootgen, nil);
1649a747e4fSDavid du Colombier 		respond(r, nil);
1659a747e4fSDavid du Colombier 		break;
1669a747e4fSDavid du Colombier 
1679a747e4fSDavid du Colombier 	case Qexec:
1689a747e4fSDavid du Colombier 		dirread9p(r, execgen, nil);
1699a747e4fSDavid du Colombier 		respond(r, nil);
1709a747e4fSDavid du Colombier 		break;
1719a747e4fSDavid du Colombier 
1729a747e4fSDavid du Colombier 	case Qn:
1739a747e4fSDavid du Colombier 		dirread9p(r, conngen, client[NUM(path)]);
1749a747e4fSDavid du Colombier 		respond(r, nil);
1759a747e4fSDavid du Colombier 		break;
1769a747e4fSDavid du Colombier 
1779a747e4fSDavid du Colombier 	case Qctl:
1789a747e4fSDavid du Colombier 		snprint(e, sizeof e, "%ud", NUM(path));
1799a747e4fSDavid du Colombier 		readstr(r, e);
1809a747e4fSDavid du Colombier 		respond(r, nil);
1819a747e4fSDavid du Colombier 		break;
1829a747e4fSDavid du Colombier 
1839a747e4fSDavid du Colombier 	case Qdata:
1849a747e4fSDavid du Colombier 		dataread(r, client[NUM(path)]);
1859a747e4fSDavid du Colombier 		break;
1869a747e4fSDavid du Colombier 
1879a747e4fSDavid du Colombier 	case Qlocal:
1889a747e4fSDavid du Colombier 		snprint(e, sizeof e, "%d", client[NUM(path)]->pid);
1899a747e4fSDavid du Colombier 		readstr(r, e);
1909a747e4fSDavid du Colombier 		respond(r, nil);
1919a747e4fSDavid du Colombier 		break;
1929a747e4fSDavid du Colombier 
1939a747e4fSDavid du Colombier 	case Qremote:
1949a747e4fSDavid du Colombier 		s = client[NUM(path)]->cmd;
1959a747e4fSDavid du Colombier 		if(strlen(s) >= 5)	/* "exec " */
1969a747e4fSDavid du Colombier 			readstr(r, s+5);
1979a747e4fSDavid du Colombier 		else
1989a747e4fSDavid du Colombier 			readstr(r, s);
1999a747e4fSDavid du Colombier 		respond(r, nil);
2009a747e4fSDavid du Colombier 		break;
2019a747e4fSDavid du Colombier 
2029a747e4fSDavid du Colombier 	case Qstatus:
2039a747e4fSDavid du Colombier 		readstr(r, statusstr[client[NUM(path)]->status]);
2049a747e4fSDavid du Colombier 		respond(r, nil);
2059a747e4fSDavid du Colombier 		break;
2069a747e4fSDavid du Colombier 	}
2079a747e4fSDavid du Colombier }
2089a747e4fSDavid du Colombier 
2099a747e4fSDavid du Colombier static void
fswrite(Req * r)2109a747e4fSDavid du Colombier fswrite(Req *r)
2119a747e4fSDavid du Colombier {
2129a747e4fSDavid du Colombier 	char e[ERRMAX];
2139a747e4fSDavid du Colombier 	ulong path;
2149a747e4fSDavid du Colombier 
2159a747e4fSDavid du Colombier 	path = r->fid->qid.path;
2169a747e4fSDavid du Colombier 	switch(TYPE(path)){
2179a747e4fSDavid du Colombier 	default:
2189a747e4fSDavid du Colombier 		snprint(e, sizeof e, "bug in execnet path=%lux", path);
2199a747e4fSDavid du Colombier 		respond(r, e);
2209a747e4fSDavid du Colombier 		break;
2219a747e4fSDavid du Colombier 
2229a747e4fSDavid du Colombier 	case Qctl:
2239a747e4fSDavid du Colombier 		ctlwrite(r, client[NUM(path)]);
2249a747e4fSDavid du Colombier 		break;
2259a747e4fSDavid du Colombier 
2269a747e4fSDavid du Colombier 	case Qdata:
2279a747e4fSDavid du Colombier 		datawrite(r, client[NUM(path)]);
2289a747e4fSDavid du Colombier 		break;
2299a747e4fSDavid du Colombier 	}
2309a747e4fSDavid du Colombier }
2319a747e4fSDavid du Colombier 
2329a747e4fSDavid du Colombier 
2339a747e4fSDavid du Colombier static void
fsflush(Req * r)2349a747e4fSDavid du Colombier fsflush(Req *r)
2359a747e4fSDavid du Colombier {
2369a747e4fSDavid du Colombier 	ulong path;
2379a747e4fSDavid du Colombier 	Req *or;
2389a747e4fSDavid du Colombier 
2399a747e4fSDavid du Colombier 	for(or=r; or->ifcall.type==Tflush; or=or->oldreq)
2409a747e4fSDavid du Colombier 		;
2419a747e4fSDavid du Colombier 
2429a747e4fSDavid du Colombier 	if(or->ifcall.type != Tread && or->ifcall.type != Twrite)
2439a747e4fSDavid du Colombier 		abort();
2449a747e4fSDavid du Colombier 
2459a747e4fSDavid du Colombier 	path = or->fid->qid.path;
2469a747e4fSDavid du Colombier 	if(TYPE(path) != Qdata)
2479a747e4fSDavid du Colombier 		abort();
2489a747e4fSDavid du Colombier 
2499a747e4fSDavid du Colombier 	clientflush(or, client[NUM(path)]);
250*fb7f0c93SDavid du Colombier 	respond(r, nil);
2519a747e4fSDavid du Colombier }
2529a747e4fSDavid du Colombier 
2539a747e4fSDavid du Colombier static void
fsattach(Req * r)2549a747e4fSDavid du Colombier fsattach(Req *r)
2559a747e4fSDavid du Colombier {
2569a747e4fSDavid du Colombier 	if(r->ifcall.aname && r->ifcall.aname[0]){
2579a747e4fSDavid du Colombier 		respond(r, "invalid attach specifier");
2589a747e4fSDavid du Colombier 		return;
2599a747e4fSDavid du Colombier 	}
2609a747e4fSDavid du Colombier 	r->fid->qid.path = PATH(Qroot, 0);
2619a747e4fSDavid du Colombier 	r->fid->qid.type = QTDIR;
2629a747e4fSDavid du Colombier 	r->fid->qid.vers = 0;
2639a747e4fSDavid du Colombier 	r->ofcall.qid = r->fid->qid;
2649a747e4fSDavid du Colombier 	respond(r, nil);
2659a747e4fSDavid du Colombier }
2669a747e4fSDavid du Colombier 
2679a747e4fSDavid du Colombier static char*
fswalk1(Fid * fid,char * name,Qid * qid)2689a747e4fSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid)
2699a747e4fSDavid du Colombier {
2709a747e4fSDavid du Colombier 	char buf[32];
2719a747e4fSDavid du Colombier 	int i, n;
2729a747e4fSDavid du Colombier 	ulong path;
2739a747e4fSDavid du Colombier 
2749a747e4fSDavid du Colombier 	if(!(fid->qid.type&QTDIR))
2759a747e4fSDavid du Colombier 		return "walk in non-directory";
2769a747e4fSDavid du Colombier 
2779a747e4fSDavid du Colombier 	path = fid->qid.path;
2789a747e4fSDavid du Colombier 	if(strcmp(name, "..") == 0){
2799a747e4fSDavid du Colombier 		switch(TYPE(path)){
2809a747e4fSDavid du Colombier 		case Qn:
2819a747e4fSDavid du Colombier 			qid->path = PATH(Qexec, 0);
2829a747e4fSDavid du Colombier 			qid->type = QTDIR;
2839a747e4fSDavid du Colombier 			return nil;
2849a747e4fSDavid du Colombier 		case Qroot:
2859a747e4fSDavid du Colombier 		case Qexec:
2869a747e4fSDavid du Colombier 			qid->path = PATH(Qroot, 0);
2879a747e4fSDavid du Colombier 			qid->type = QTDIR;
2889a747e4fSDavid du Colombier 			return nil;
2899a747e4fSDavid du Colombier 		default:
2909a747e4fSDavid du Colombier 			return "bug in fswalk1";
2919a747e4fSDavid du Colombier 		}
2929a747e4fSDavid du Colombier 	}
2939a747e4fSDavid du Colombier 
2949a747e4fSDavid du Colombier 	i = TYPE(path)+1;
2959a747e4fSDavid du Colombier 	for(; i<nelem(tab); i++){
2969a747e4fSDavid du Colombier 		if(i==Qn){
2979a747e4fSDavid du Colombier 			n = atoi(name);
2989a747e4fSDavid du Colombier 			snprint(buf, sizeof buf, "%d", n);
2999a747e4fSDavid du Colombier 			if(n < nclient && strcmp(buf, name) == 0){
3009a747e4fSDavid du Colombier 				qid->path = PATH(Qn, n);
3019a747e4fSDavid du Colombier 				qid->type = QTDIR;
3029a747e4fSDavid du Colombier 				return nil;
3039a747e4fSDavid du Colombier 			}
3049a747e4fSDavid du Colombier 			break;
3059a747e4fSDavid du Colombier 		}
3069a747e4fSDavid du Colombier 		if(strcmp(tab[i].name, name) == 0){
3079a747e4fSDavid du Colombier 			qid->path = PATH(i, NUM(path));
3089a747e4fSDavid du Colombier 			qid->type = tab[i].mode>>24;
3099a747e4fSDavid du Colombier 			return nil;
3109a747e4fSDavid du Colombier 		}
3119a747e4fSDavid du Colombier 		if(tab[i].mode&DMDIR)
3129a747e4fSDavid du Colombier 			break;
3139a747e4fSDavid du Colombier 	}
3149a747e4fSDavid du Colombier 	return "directory entry not found";
3159a747e4fSDavid du Colombier }
3169a747e4fSDavid du Colombier 
3179a747e4fSDavid du Colombier static void
fsopen(Req * r)3189a747e4fSDavid du Colombier fsopen(Req *r)
3199a747e4fSDavid du Colombier {
3209a747e4fSDavid du Colombier 	static int need[4] = { 4, 2, 6, 1 };
3219a747e4fSDavid du Colombier 	ulong path;
3229a747e4fSDavid du Colombier 	int n;
3239a747e4fSDavid du Colombier 	Tab *t;
3249a747e4fSDavid du Colombier 
3259a747e4fSDavid du Colombier 	/*
3269a747e4fSDavid du Colombier 	 * lib9p already handles the blatantly obvious.
3279a747e4fSDavid du Colombier 	 * we just have to enforce the permissions we have set.
3289a747e4fSDavid du Colombier 	 */
3299a747e4fSDavid du Colombier 	path = r->fid->qid.path;
3309a747e4fSDavid du Colombier 	t = &tab[TYPE(path)];
3319a747e4fSDavid du Colombier 	n = need[r->ifcall.mode&3];
3329a747e4fSDavid du Colombier 	if((n&t->mode) != n){
3339a747e4fSDavid du Colombier 		respond(r, "permission denied");
3349a747e4fSDavid du Colombier 		return;
3359a747e4fSDavid du Colombier 	}
3369a747e4fSDavid du Colombier 
3379a747e4fSDavid du Colombier 	switch(TYPE(path)){
3389a747e4fSDavid du Colombier 	case Qclone:
3399a747e4fSDavid du Colombier 		n = newclient();
3409a747e4fSDavid du Colombier 		path = PATH(Qctl, n);
3419a747e4fSDavid du Colombier 		r->fid->qid.path = path;
3429a747e4fSDavid du Colombier 		r->ofcall.qid.path = path;
3439a747e4fSDavid du Colombier 		if(fsdebug)
3449a747e4fSDavid du Colombier 			fprint(2, "open clone => path=%lux\n", path);
3459a747e4fSDavid du Colombier 		t = &tab[Qctl];
3469a747e4fSDavid du Colombier 		/* fall through */
3479a747e4fSDavid du Colombier 	default:
3489a747e4fSDavid du Colombier 		if(t-tab >= Qn)
3499a747e4fSDavid du Colombier 			client[NUM(path)]->ref++;
3509a747e4fSDavid du Colombier 		respond(r, nil);
3519a747e4fSDavid du Colombier 		break;
3529a747e4fSDavid du Colombier 	}
3539a747e4fSDavid du Colombier }
3549a747e4fSDavid du Colombier 
3559a747e4fSDavid du Colombier Channel *cclunk;
3569a747e4fSDavid du Colombier Channel *cclunkwait;
3579a747e4fSDavid du Colombier Channel *creq;
3589a747e4fSDavid du Colombier Channel *creqwait;
3599a747e4fSDavid du Colombier 
3609a747e4fSDavid du Colombier static void
fsthread(void *)3619a747e4fSDavid du Colombier fsthread(void*)
3629a747e4fSDavid du Colombier {
3639a747e4fSDavid du Colombier 	ulong path;
3649a747e4fSDavid du Colombier 	Alt a[3];
3659a747e4fSDavid du Colombier 	Fid *fid;
3669a747e4fSDavid du Colombier 	Req *r;
3679a747e4fSDavid du Colombier 
3689a747e4fSDavid du Colombier 	threadsetname("fsthread");
3699a747e4fSDavid du Colombier 
3709a747e4fSDavid du Colombier 	a[0].op = CHANRCV;
3719a747e4fSDavid du Colombier 	a[0].c = cclunk;
3729a747e4fSDavid du Colombier 	a[0].v = &fid;
3739a747e4fSDavid du Colombier 	a[1].op = CHANRCV;
3749a747e4fSDavid du Colombier 	a[1].c = creq;
3759a747e4fSDavid du Colombier 	a[1].v = &r;
3769a747e4fSDavid du Colombier 	a[2].op = CHANEND;
3779a747e4fSDavid du Colombier 
3789a747e4fSDavid du Colombier 	for(;;){
3799a747e4fSDavid du Colombier 		switch(alt(a)){
3809a747e4fSDavid du Colombier 		case 0:
3819a747e4fSDavid du Colombier 			path = fid->qid.path;
3829a747e4fSDavid du Colombier 			if(fid->omode != -1 && TYPE(path) >= Qn)
3839a747e4fSDavid du Colombier 				closeclient(client[NUM(path)]);
3849a747e4fSDavid du Colombier 			sendp(cclunkwait, nil);
3859a747e4fSDavid du Colombier 			break;
3869a747e4fSDavid du Colombier 		case 1:
3879a747e4fSDavid du Colombier 			switch(r->ifcall.type){
3889a747e4fSDavid du Colombier 			case Tattach:
3899a747e4fSDavid du Colombier 				fsattach(r);
3909a747e4fSDavid du Colombier 				break;
3919a747e4fSDavid du Colombier 			case Topen:
3929a747e4fSDavid du Colombier 				fsopen(r);
3939a747e4fSDavid du Colombier 				break;
3949a747e4fSDavid du Colombier 			case Tread:
3959a747e4fSDavid du Colombier 				fsread(r);
3969a747e4fSDavid du Colombier 				break;
3979a747e4fSDavid du Colombier 			case Twrite:
3989a747e4fSDavid du Colombier 				fswrite(r);
3999a747e4fSDavid du Colombier 				break;
4009a747e4fSDavid du Colombier 			case Tstat:
4019a747e4fSDavid du Colombier 				fsstat(r);
4029a747e4fSDavid du Colombier 				break;
4039a747e4fSDavid du Colombier 			case Tflush:
4049a747e4fSDavid du Colombier 				fsflush(r);
4059a747e4fSDavid du Colombier 				break;
4069a747e4fSDavid du Colombier 			default:
4079a747e4fSDavid du Colombier 				respond(r, "bug in fsthread");
4089a747e4fSDavid du Colombier 				break;
4099a747e4fSDavid du Colombier 			}
4109a747e4fSDavid du Colombier 			sendp(creqwait, 0);
4119a747e4fSDavid du Colombier 			break;
4129a747e4fSDavid du Colombier 		}
4139a747e4fSDavid du Colombier 	}
4149a747e4fSDavid du Colombier }
4159a747e4fSDavid du Colombier 
4169a747e4fSDavid du Colombier static void
fsdestroyfid(Fid * fid)4179a747e4fSDavid du Colombier fsdestroyfid(Fid *fid)
4189a747e4fSDavid du Colombier {
4199a747e4fSDavid du Colombier 	sendp(cclunk, fid);
4209a747e4fSDavid du Colombier 	recvp(cclunkwait);
4219a747e4fSDavid du Colombier }
4229a747e4fSDavid du Colombier 
4239a747e4fSDavid du Colombier static void
fssend(Req * r)4249a747e4fSDavid du Colombier fssend(Req *r)
4259a747e4fSDavid du Colombier {
4269a747e4fSDavid du Colombier 	sendp(creq, r);
4279a747e4fSDavid du Colombier 	recvp(creqwait);	/* avoids need to deal with spurious flushes */
4289a747e4fSDavid du Colombier }
4299a747e4fSDavid du Colombier 
4309a747e4fSDavid du Colombier void
initfs(void)4319a747e4fSDavid du Colombier initfs(void)
4329a747e4fSDavid du Colombier {
4339a747e4fSDavid du Colombier 	time0 = time(0);
4349a747e4fSDavid du Colombier 	creq = chancreate(sizeof(void*), 0);
4359a747e4fSDavid du Colombier 	creqwait = chancreate(sizeof(void*), 0);
4369a747e4fSDavid du Colombier 	cclunk = chancreate(sizeof(void*), 0);
4379a747e4fSDavid du Colombier 	cclunkwait = chancreate(sizeof(void*), 0);
4389a747e4fSDavid du Colombier 	procrfork(fsthread, nil, STACK, RFNAMEG);
4399a747e4fSDavid du Colombier }
4409a747e4fSDavid du Colombier 
4419a747e4fSDavid du Colombier Srv fs =
4429a747e4fSDavid du Colombier {
4439a747e4fSDavid du Colombier .attach=		fssend,
4449a747e4fSDavid du Colombier .destroyfid=	fsdestroyfid,
4459a747e4fSDavid du Colombier .walk1=		fswalk1,
4469a747e4fSDavid du Colombier .open=		fssend,
4479a747e4fSDavid du Colombier .read=		fssend,
4489a747e4fSDavid du Colombier .write=		fssend,
4499a747e4fSDavid du Colombier .stat=		fssend,
4509a747e4fSDavid du Colombier .flush=		fssend,
4519a747e4fSDavid du Colombier };
452