xref: /plan9/sys/src/cmd/ratfs/proto.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include "ratfs.h"
2*9a747e4fSDavid du Colombier 
3*9a747e4fSDavid du Colombier /*
4*9a747e4fSDavid du Colombier  *	9P protocol interface
5*9a747e4fSDavid du Colombier  */
6*9a747e4fSDavid du Colombier 
7*9a747e4fSDavid du Colombier enum {
8*9a747e4fSDavid du Colombier 	RELOAD = 0,		/* commands written to ctl file */
9*9a747e4fSDavid du Colombier 	RDEBUG,
10*9a747e4fSDavid du Colombier 	RNODEBUG,
11*9a747e4fSDavid du Colombier 	RNONE,
12*9a747e4fSDavid du Colombier };
13*9a747e4fSDavid du Colombier 
14*9a747e4fSDavid du Colombier static void	rflush(Fcall*),		rnop(Fcall*),
15*9a747e4fSDavid du Colombier 		rauth(Fcall*),	rattach(Fcall*),
16*9a747e4fSDavid du Colombier 		rclone(Fcall*),		rwalk(Fcall*),
17*9a747e4fSDavid du Colombier 		rclwalk(Fcall*),	ropen(Fcall*),
18*9a747e4fSDavid du Colombier 		rcreate(Fcall*),	rread(Fcall*),
19*9a747e4fSDavid du Colombier 		rwrite(Fcall*),		rclunk(Fcall*),
20*9a747e4fSDavid du Colombier 		rremove(Fcall*),	rstat(Fcall*),
21*9a747e4fSDavid du Colombier 		rwstat(Fcall*),	rversion(Fcall*);
22*9a747e4fSDavid du Colombier 
23*9a747e4fSDavid du Colombier static	Fid*	newfid(int);
24*9a747e4fSDavid du Colombier static	void	reply(Fcall*, char*);
25*9a747e4fSDavid du Colombier 
26*9a747e4fSDavid du Colombier static	void 	(*fcalls[])(Fcall*) = {
27*9a747e4fSDavid du Colombier 	[Tversion]	rversion,
28*9a747e4fSDavid du Colombier 	[Tflush]	rflush,
29*9a747e4fSDavid du Colombier 	[Tauth]	rauth,
30*9a747e4fSDavid du Colombier 	[Tattach]	rattach,
31*9a747e4fSDavid du Colombier 	[Twalk]		rwalk,
32*9a747e4fSDavid du Colombier 	[Topen]		ropen,
33*9a747e4fSDavid du Colombier 	[Tcreate]	rcreate,
34*9a747e4fSDavid du Colombier 	[Tread]		rread,
35*9a747e4fSDavid du Colombier 	[Twrite]	rwrite,
36*9a747e4fSDavid du Colombier 	[Tclunk]	rclunk,
37*9a747e4fSDavid du Colombier 	[Tremove]	rremove,
38*9a747e4fSDavid du Colombier 	[Tstat]		rstat,
39*9a747e4fSDavid du Colombier 	[Twstat]	rwstat,
40*9a747e4fSDavid du Colombier };
41*9a747e4fSDavid du Colombier 
42*9a747e4fSDavid du Colombier 
43*9a747e4fSDavid du Colombier static	Keyword cmds[] = {
44*9a747e4fSDavid du Colombier 	"reload",		RELOAD,
45*9a747e4fSDavid du Colombier 	"debug",		RDEBUG,
46*9a747e4fSDavid du Colombier 	"nodebug",		RNODEBUG,
47*9a747e4fSDavid du Colombier 	0,			RNONE,
48*9a747e4fSDavid du Colombier };
49*9a747e4fSDavid du Colombier 
50*9a747e4fSDavid du Colombier /*
51*9a747e4fSDavid du Colombier  *	Main protocol loop
52*9a747e4fSDavid du Colombier  */
53*9a747e4fSDavid du Colombier void
io(void)54*9a747e4fSDavid du Colombier io(void)
55*9a747e4fSDavid du Colombier {
56*9a747e4fSDavid du Colombier 	Fcall	rhdr;
57*9a747e4fSDavid du Colombier 	int n;
58*9a747e4fSDavid du Colombier 
59*9a747e4fSDavid du Colombier 	for(;;){
60*9a747e4fSDavid du Colombier 		n = read9pmsg(srvfd, rbuf, sizeof rbuf-1);
61*9a747e4fSDavid du Colombier 		if(n <= 0)
62*9a747e4fSDavid du Colombier 			fatal("mount read");
63*9a747e4fSDavid du Colombier 		if(convM2S(rbuf, n, &rhdr) == 0){
64*9a747e4fSDavid du Colombier 			if(debugfd >= 0)
65*9a747e4fSDavid du Colombier 				fprint(2, "%s: malformed message\n", argv0);
66*9a747e4fSDavid du Colombier 			continue;
67*9a747e4fSDavid du Colombier 		}
68*9a747e4fSDavid du Colombier 
69*9a747e4fSDavid du Colombier 		if(debugfd >= 0)
70*9a747e4fSDavid du Colombier 			fprint(debugfd, "<-%F\n", &rhdr);/**/
71*9a747e4fSDavid du Colombier 
72*9a747e4fSDavid du Colombier 		if(!fcalls[rhdr.type])
73*9a747e4fSDavid du Colombier 			reply(&rhdr, "bad fcall type");
74*9a747e4fSDavid du Colombier 		else
75*9a747e4fSDavid du Colombier 			(*fcalls[rhdr.type])(&rhdr);
76*9a747e4fSDavid du Colombier 	}
77*9a747e4fSDavid du Colombier }
78*9a747e4fSDavid du Colombier 
79*9a747e4fSDavid du Colombier /*
80*9a747e4fSDavid du Colombier  *	write a protocol reply to the client
81*9a747e4fSDavid du Colombier  */
82*9a747e4fSDavid du Colombier static void
reply(Fcall * r,char * error)83*9a747e4fSDavid du Colombier reply(Fcall *r, char *error)
84*9a747e4fSDavid du Colombier {
85*9a747e4fSDavid du Colombier 	int n;
86*9a747e4fSDavid du Colombier 
87*9a747e4fSDavid du Colombier 	if(error == nil)
88*9a747e4fSDavid du Colombier 		r->type++;
89*9a747e4fSDavid du Colombier 	else {
90*9a747e4fSDavid du Colombier 		r->type = Rerror;
91*9a747e4fSDavid du Colombier 		r->ename = error;
92*9a747e4fSDavid du Colombier 	}
93*9a747e4fSDavid du Colombier 	if(debugfd >= 0)
94*9a747e4fSDavid du Colombier 		fprint(debugfd, "->%F\n", r);/**/
95*9a747e4fSDavid du Colombier 	n = convS2M(r, rbuf, sizeof rbuf);
96*9a747e4fSDavid du Colombier 	if(n == 0)
97*9a747e4fSDavid du Colombier 		sysfatal("convS2M: %r");
98*9a747e4fSDavid du Colombier 	if(write(srvfd, rbuf, n) < 0)
99*9a747e4fSDavid du Colombier 		sysfatal("reply: %r");
100*9a747e4fSDavid du Colombier }
101*9a747e4fSDavid du Colombier 
102*9a747e4fSDavid du Colombier 
103*9a747e4fSDavid du Colombier /*
104*9a747e4fSDavid du Colombier  *  lookup a fid. if not found, create a new one.
105*9a747e4fSDavid du Colombier  */
106*9a747e4fSDavid du Colombier 
107*9a747e4fSDavid du Colombier static Fid*
newfid(int fid)108*9a747e4fSDavid du Colombier newfid(int fid)
109*9a747e4fSDavid du Colombier {
110*9a747e4fSDavid du Colombier 	Fid *f, *ff;
111*9a747e4fSDavid du Colombier 
112*9a747e4fSDavid du Colombier 	static Fid *fids;
113*9a747e4fSDavid du Colombier 
114*9a747e4fSDavid du Colombier 	ff = 0;
115*9a747e4fSDavid du Colombier 	for(f = fids; f; f = f->next){
116*9a747e4fSDavid du Colombier 		if(f->fid == fid){
117*9a747e4fSDavid du Colombier 			if(!f->busy)
118*9a747e4fSDavid du Colombier 				f->node = 0;
119*9a747e4fSDavid du Colombier 			return f;
120*9a747e4fSDavid du Colombier 		} else if(!ff && !f->busy)
121*9a747e4fSDavid du Colombier 			ff = f;
122*9a747e4fSDavid du Colombier 	}
123*9a747e4fSDavid du Colombier 	if(ff == 0){
124*9a747e4fSDavid du Colombier 		ff = mallocz(sizeof(*f), 1);
125*9a747e4fSDavid du Colombier 		ff->next = fids;
126*9a747e4fSDavid du Colombier 		fids = ff;
127*9a747e4fSDavid du Colombier 	}
128*9a747e4fSDavid du Colombier 	ff->node = 0;
129*9a747e4fSDavid du Colombier 	ff->fid = fid;
130*9a747e4fSDavid du Colombier 	return ff;
131*9a747e4fSDavid du Colombier }
132*9a747e4fSDavid du Colombier 
133*9a747e4fSDavid du Colombier static void
rversion(Fcall * f)134*9a747e4fSDavid du Colombier rversion(Fcall *f)
135*9a747e4fSDavid du Colombier {
136*9a747e4fSDavid du Colombier 	f->version = "9P2000";
137*9a747e4fSDavid du Colombier 	if(f->msize > MAXRPC)
138*9a747e4fSDavid du Colombier 		f->msize = MAXRPC;
139*9a747e4fSDavid du Colombier 	reply(f, 0);
140*9a747e4fSDavid du Colombier }
141*9a747e4fSDavid du Colombier 
142*9a747e4fSDavid du Colombier static void
rauth(Fcall * f)143*9a747e4fSDavid du Colombier rauth(Fcall *f)
144*9a747e4fSDavid du Colombier {
145*9a747e4fSDavid du Colombier 	reply(f, "ratfs: authentication not required");
146*9a747e4fSDavid du Colombier }
147*9a747e4fSDavid du Colombier 
148*9a747e4fSDavid du Colombier static void
rflush(Fcall * f)149*9a747e4fSDavid du Colombier rflush(Fcall *f)
150*9a747e4fSDavid du Colombier {
151*9a747e4fSDavid du Colombier 	reply(f, 0);
152*9a747e4fSDavid du Colombier }
153*9a747e4fSDavid du Colombier 
154*9a747e4fSDavid du Colombier static void
rattach(Fcall * f)155*9a747e4fSDavid du Colombier rattach(Fcall *f)
156*9a747e4fSDavid du Colombier {
157*9a747e4fSDavid du Colombier 	Fid *fidp;
158*9a747e4fSDavid du Colombier 	Dir *d;
159*9a747e4fSDavid du Colombier 
160*9a747e4fSDavid du Colombier 	if((d=dirstat(conffile)) != nil && d->mtime > lastconftime)
161*9a747e4fSDavid du Colombier 		getconf();
162*9a747e4fSDavid du Colombier 	free(d);
163*9a747e4fSDavid du Colombier 	if((d=dirstat(ctlfile)) != nil && d->mtime > lastctltime)
164*9a747e4fSDavid du Colombier 		reload();
165*9a747e4fSDavid du Colombier 	free(d);
166*9a747e4fSDavid du Colombier 	cleantrusted();
167*9a747e4fSDavid du Colombier 
168*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
169*9a747e4fSDavid du Colombier 	fidp->busy = 1;
170*9a747e4fSDavid du Colombier 	fidp->node = root;
171*9a747e4fSDavid du Colombier 	fidp->name = root->d.name;
172*9a747e4fSDavid du Colombier 	fidp->uid = atom(f->uname);
173*9a747e4fSDavid du Colombier 	f->qid = root->d.qid;
174*9a747e4fSDavid du Colombier 	reply(f,0);
175*9a747e4fSDavid du Colombier }
176*9a747e4fSDavid du Colombier 
177*9a747e4fSDavid du Colombier static void
rclone(Fcall * f)178*9a747e4fSDavid du Colombier rclone(Fcall *f)
179*9a747e4fSDavid du Colombier {
180*9a747e4fSDavid du Colombier 	Fid *fidp, *nf;
181*9a747e4fSDavid du Colombier 
182*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
183*9a747e4fSDavid du Colombier 	if(fidp->node && fidp->node->d.type == Dummynode){
184*9a747e4fSDavid du Colombier 		reply(f, "can't clone an address");
185*9a747e4fSDavid du Colombier 		return;
186*9a747e4fSDavid du Colombier 	}
187*9a747e4fSDavid du Colombier 	nf = newfid(f->newfid);
188*9a747e4fSDavid du Colombier 	nf->busy = 1;
189*9a747e4fSDavid du Colombier 	nf->node = fidp->node;
190*9a747e4fSDavid du Colombier 	nf->uid = fidp->uid;
191*9a747e4fSDavid du Colombier 	nf->name = fidp->name;
192*9a747e4fSDavid du Colombier 	if(debugfd >= 0)
193*9a747e4fSDavid du Colombier 		printfid(nf);
194*9a747e4fSDavid du Colombier 	reply(f,0);
195*9a747e4fSDavid du Colombier }
196*9a747e4fSDavid du Colombier 
197*9a747e4fSDavid du Colombier static void
rwalk(Fcall * f)198*9a747e4fSDavid du Colombier rwalk(Fcall *f)
199*9a747e4fSDavid du Colombier {
200*9a747e4fSDavid du Colombier 	int i, j;
201*9a747e4fSDavid du Colombier 	Fcall r;
202*9a747e4fSDavid du Colombier 	Fid *fidp, *nf;
203*9a747e4fSDavid du Colombier 	char *err;
204*9a747e4fSDavid du Colombier 
205*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
206*9a747e4fSDavid du Colombier 	if(fidp->node && fidp->node->d.type == Dummynode){
207*9a747e4fSDavid du Colombier 		reply(f, "can't walk an address node");
208*9a747e4fSDavid du Colombier 		return;
209*9a747e4fSDavid du Colombier 	}
210*9a747e4fSDavid du Colombier 	if(f->fid == f->newfid)
211*9a747e4fSDavid du Colombier 		nf = fidp;
212*9a747e4fSDavid du Colombier 	else{
213*9a747e4fSDavid du Colombier 		nf = newfid(f->newfid);
214*9a747e4fSDavid du Colombier 		nf->busy = 1;
215*9a747e4fSDavid du Colombier 		nf->node = fidp->node;
216*9a747e4fSDavid du Colombier 		nf->uid = fidp->uid;
217*9a747e4fSDavid du Colombier 		nf->name = fidp->name;
218*9a747e4fSDavid du Colombier 		if(debugfd >= 0)
219*9a747e4fSDavid du Colombier 			printfid(nf);
220*9a747e4fSDavid du Colombier 	}
221*9a747e4fSDavid du Colombier 
222*9a747e4fSDavid du Colombier 	err = nil;
223*9a747e4fSDavid du Colombier 	for(i=0; i<f->nwname; i++){
224*9a747e4fSDavid du Colombier 		err = walk(f->wname[i], nf);
225*9a747e4fSDavid du Colombier 		if(err)
226*9a747e4fSDavid du Colombier 			break;
227*9a747e4fSDavid du Colombier 		r.wqid[i] = nf->node->d.qid;
228*9a747e4fSDavid du Colombier 	}
229*9a747e4fSDavid du Colombier 
230*9a747e4fSDavid du Colombier 
231*9a747e4fSDavid du Colombier 	if(i < f->nwname && f->fid != f->newfid){
232*9a747e4fSDavid du Colombier 		nf->busy = 0;
233*9a747e4fSDavid du Colombier 		nf->node = 0;
234*9a747e4fSDavid du Colombier 		nf->name = 0;
235*9a747e4fSDavid du Colombier 		nf->uid = 0;
236*9a747e4fSDavid du Colombier 	}
237*9a747e4fSDavid du Colombier 	if(i > 0 && i < f->nwname && f->fid == f->newfid){
238*9a747e4fSDavid du Colombier 		/*
239*9a747e4fSDavid du Colombier 		 * try to put things back;
240*9a747e4fSDavid du Colombier 		 * we never get this sort of call from the kernel
241*9a747e4fSDavid du Colombier 		 */
242*9a747e4fSDavid du Colombier 		for(j=0; j<i; j++)
243*9a747e4fSDavid du Colombier 			walk("..", nf);
244*9a747e4fSDavid du Colombier 	}
245*9a747e4fSDavid du Colombier 	memmove(f->wqid, r.wqid, sizeof f->wqid);
246*9a747e4fSDavid du Colombier 	f->nwqid = i;
247*9a747e4fSDavid du Colombier 	if(err && i==0)
248*9a747e4fSDavid du Colombier 		reply(f, err);
249*9a747e4fSDavid du Colombier 	else
250*9a747e4fSDavid du Colombier 		reply(f, 0);
251*9a747e4fSDavid du Colombier }
252*9a747e4fSDavid du Colombier 
253*9a747e4fSDavid du Colombier /*
254*9a747e4fSDavid du Colombier  *	We don't have to do full permission checking because most files
255*9a747e4fSDavid du Colombier  *	have restricted semantics:
256*9a747e4fSDavid du Colombier  *		The ctl file is only writable
257*9a747e4fSDavid du Colombier  *		All others, including directories, are only readable
258*9a747e4fSDavid du Colombier  */
259*9a747e4fSDavid du Colombier static void
ropen(Fcall * f)260*9a747e4fSDavid du Colombier ropen(Fcall *f)
261*9a747e4fSDavid du Colombier {
262*9a747e4fSDavid du Colombier 	Fid *fidp;
263*9a747e4fSDavid du Colombier 	int mode;
264*9a747e4fSDavid du Colombier 
265*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
266*9a747e4fSDavid du Colombier 
267*9a747e4fSDavid du Colombier 	if(debugfd >= 0)
268*9a747e4fSDavid du Colombier 		printfid(fidp);
269*9a747e4fSDavid du Colombier 
270*9a747e4fSDavid du Colombier 	mode = f->mode&(OREAD|OWRITE|ORDWR);
271*9a747e4fSDavid du Colombier 	if(fidp->node->d.type == Ctlfile) {
272*9a747e4fSDavid du Colombier 		if(mode != OWRITE) {
273*9a747e4fSDavid du Colombier 			reply(f, "permission denied");
274*9a747e4fSDavid du Colombier 			return;
275*9a747e4fSDavid du Colombier 		}
276*9a747e4fSDavid du Colombier 	} else
277*9a747e4fSDavid du Colombier 	if (mode != OREAD) {
278*9a747e4fSDavid du Colombier 		reply(f, "permission denied or operation not supported");
279*9a747e4fSDavid du Colombier 		return;
280*9a747e4fSDavid du Colombier 	}
281*9a747e4fSDavid du Colombier 
282*9a747e4fSDavid du Colombier 	f->qid = fidp->node->d.qid;
283*9a747e4fSDavid du Colombier 	fidp->open = 1;
284*9a747e4fSDavid du Colombier 	reply(f, 0);
285*9a747e4fSDavid du Colombier }
286*9a747e4fSDavid du Colombier 
287*9a747e4fSDavid du Colombier static int
permitted(Fid * fp,Node * np,int mask)288*9a747e4fSDavid du Colombier permitted(Fid *fp, Node *np, int mask)
289*9a747e4fSDavid du Colombier {
290*9a747e4fSDavid du Colombier 	int mode;
291*9a747e4fSDavid du Colombier 
292*9a747e4fSDavid du Colombier 	mode = np->d.mode;
293*9a747e4fSDavid du Colombier 	return (fp->uid==np->d.uid && (mode&(mask<<6)))
294*9a747e4fSDavid du Colombier 		|| (fp->uid==np->d.gid && (mode&(mask<<3)))
295*9a747e4fSDavid du Colombier 		|| (mode&mask);
296*9a747e4fSDavid du Colombier }
297*9a747e4fSDavid du Colombier 
298*9a747e4fSDavid du Colombier /*
299*9a747e4fSDavid du Colombier  *	creates are only allowed in the "trusted" subdirectory
300*9a747e4fSDavid du Colombier  *	we also assume that the groupid == the uid
301*9a747e4fSDavid du Colombier  */
302*9a747e4fSDavid du Colombier static void
rcreate(Fcall * f)303*9a747e4fSDavid du Colombier rcreate(Fcall *f)
304*9a747e4fSDavid du Colombier {
305*9a747e4fSDavid du Colombier 	Fid *fidp;
306*9a747e4fSDavid du Colombier 	Node *np;
307*9a747e4fSDavid du Colombier 
308*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
309*9a747e4fSDavid du Colombier 	np = fidp->node;
310*9a747e4fSDavid du Colombier 	if((np->d.mode&DMDIR) == 0){
311*9a747e4fSDavid du Colombier 		reply(f, "not a directory");
312*9a747e4fSDavid du Colombier 		return;
313*9a747e4fSDavid du Colombier 	}
314*9a747e4fSDavid du Colombier 
315*9a747e4fSDavid du Colombier 	if(!permitted(fidp, np, AWRITE)) {
316*9a747e4fSDavid du Colombier 		reply(f, "permission denied");
317*9a747e4fSDavid du Colombier 		return;
318*9a747e4fSDavid du Colombier 	}
319*9a747e4fSDavid du Colombier 
320*9a747e4fSDavid du Colombier 	/* Ignore the supplied mode and force it to be non-writable */
321*9a747e4fSDavid du Colombier 
322*9a747e4fSDavid du Colombier 	np = newnode(np, f->name, Trustedtemp, 0444, trustedqid++);
323*9a747e4fSDavid du Colombier 	if(trustedqid >= Qaddrfile)			/* wrap QIDs */
324*9a747e4fSDavid du Colombier 		trustedqid = Qtrustedfile;
325*9a747e4fSDavid du Colombier 	cidrparse(&np->ip, f->name);
326*9a747e4fSDavid du Colombier 	f->qid = np->d.qid;
327*9a747e4fSDavid du Colombier 	np->d.uid = fidp->uid;
328*9a747e4fSDavid du Colombier 	np->d.gid = np->d.uid;
329*9a747e4fSDavid du Colombier 	np->d.muid = np->d.muid;
330*9a747e4fSDavid du Colombier 	fidp->node = np;
331*9a747e4fSDavid du Colombier 	fidp->open = 1;
332*9a747e4fSDavid du Colombier 	reply(f, 0);
333*9a747e4fSDavid du Colombier 	return;
334*9a747e4fSDavid du Colombier }
335*9a747e4fSDavid du Colombier 
336*9a747e4fSDavid du Colombier /*
337*9a747e4fSDavid du Colombier  *	only directories can be read.  everthing else returns EOF.
338*9a747e4fSDavid du Colombier  */
339*9a747e4fSDavid du Colombier static void
rread(Fcall * f)340*9a747e4fSDavid du Colombier rread(Fcall *f)
341*9a747e4fSDavid du Colombier {
342*9a747e4fSDavid du Colombier 	long cnt;
343*9a747e4fSDavid du Colombier 	Fid *fidp;
344*9a747e4fSDavid du Colombier 
345*9a747e4fSDavid du Colombier 	cnt = f->count;
346*9a747e4fSDavid du Colombier 	f->count = 0;
347*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
348*9a747e4fSDavid du Colombier 	f->data = (char*)rbuf+IOHDRSZ;
349*9a747e4fSDavid du Colombier 	if(fidp->open == 0) {
350*9a747e4fSDavid du Colombier 		reply(f, "file not open");
351*9a747e4fSDavid du Colombier 		return;
352*9a747e4fSDavid du Colombier 	}
353*9a747e4fSDavid du Colombier 	if ((fidp->node->d.mode&DMDIR) == 0){
354*9a747e4fSDavid du Colombier 		reply(f, 0);				/*EOF*/
355*9a747e4fSDavid du Colombier 		return;
356*9a747e4fSDavid du Colombier 	}
357*9a747e4fSDavid du Colombier 	if(cnt > MAXRPC)
358*9a747e4fSDavid du Colombier 		cnt = MAXRPC;
359*9a747e4fSDavid du Colombier 
360*9a747e4fSDavid du Colombier 	if(f->offset == 0)
361*9a747e4fSDavid du Colombier 		fidp->dirindex = 0;
362*9a747e4fSDavid du Colombier 
363*9a747e4fSDavid du Colombier 	switch(fidp->node->d.type) {
364*9a747e4fSDavid du Colombier 	case Directory:
365*9a747e4fSDavid du Colombier 	case Addrdir:
366*9a747e4fSDavid du Colombier 	case Trusted:
367*9a747e4fSDavid du Colombier 		f->count = dread(fidp, cnt);
368*9a747e4fSDavid du Colombier 		break;
369*9a747e4fSDavid du Colombier 	case IPaddr:
370*9a747e4fSDavid du Colombier 	case Acctaddr:
371*9a747e4fSDavid du Colombier 		f->count = hread(fidp, cnt);
372*9a747e4fSDavid du Colombier 		break;
373*9a747e4fSDavid du Colombier 	default:
374*9a747e4fSDavid du Colombier 		reply(f, "can't read this type of file");
375*9a747e4fSDavid du Colombier 		return;
376*9a747e4fSDavid du Colombier 	}
377*9a747e4fSDavid du Colombier 	reply(f, 0);
378*9a747e4fSDavid du Colombier }
379*9a747e4fSDavid du Colombier 
380*9a747e4fSDavid du Colombier 
381*9a747e4fSDavid du Colombier /*
382*9a747e4fSDavid du Colombier  * 	only the 'ctl' file in the top level directory is writable
383*9a747e4fSDavid du Colombier  */
384*9a747e4fSDavid du Colombier 
385*9a747e4fSDavid du Colombier static void
rwrite(Fcall * f)386*9a747e4fSDavid du Colombier rwrite(Fcall *f)
387*9a747e4fSDavid du Colombier {
388*9a747e4fSDavid du Colombier 	Fid *fidp;
389*9a747e4fSDavid du Colombier 	int n;
390*9a747e4fSDavid du Colombier 	char *err, *argv[10];
391*9a747e4fSDavid du Colombier 
392*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
393*9a747e4fSDavid du Colombier 	if(fidp->node->d.mode & DMDIR){
394*9a747e4fSDavid du Colombier 		reply(f, "directories are not writable");
395*9a747e4fSDavid du Colombier 		return;
396*9a747e4fSDavid du Colombier 	}
397*9a747e4fSDavid du Colombier 	if(fidp->open == 0) {
398*9a747e4fSDavid du Colombier 		reply(f, "file not open");
399*9a747e4fSDavid du Colombier 		return;
400*9a747e4fSDavid du Colombier 	}
401*9a747e4fSDavid du Colombier 
402*9a747e4fSDavid du Colombier 	if (!permitted(fidp, fidp->node, AWRITE)) {
403*9a747e4fSDavid du Colombier 		reply(f, "permission denied");
404*9a747e4fSDavid du Colombier 		return;
405*9a747e4fSDavid du Colombier 	}
406*9a747e4fSDavid du Colombier 
407*9a747e4fSDavid du Colombier 	f->data[f->count] = 0;			/* the extra byte in rbuf leaves room */
408*9a747e4fSDavid du Colombier 	n = tokenize(f->data, argv, 10);
409*9a747e4fSDavid du Colombier 	err = 0;
410*9a747e4fSDavid du Colombier 	switch(findkey(argv[0], cmds)){
411*9a747e4fSDavid du Colombier 	case RELOAD:
412*9a747e4fSDavid du Colombier 		getconf();
413*9a747e4fSDavid du Colombier 		reload();
414*9a747e4fSDavid du Colombier 		break;
415*9a747e4fSDavid du Colombier 	case RDEBUG:
416*9a747e4fSDavid du Colombier 		if(n > 1){
417*9a747e4fSDavid du Colombier 			debugfd = create(argv[1], OWRITE, 0666);
418*9a747e4fSDavid du Colombier 			if(debugfd < 0)
419*9a747e4fSDavid du Colombier 				err = "create failed";
420*9a747e4fSDavid du Colombier 		} else
421*9a747e4fSDavid du Colombier 			debugfd = 2;
422*9a747e4fSDavid du Colombier 		break;
423*9a747e4fSDavid du Colombier 	case RNODEBUG:
424*9a747e4fSDavid du Colombier 		if(debugfd >= 0)
425*9a747e4fSDavid du Colombier 			close(debugfd);
426*9a747e4fSDavid du Colombier 		debugfd = -1;
427*9a747e4fSDavid du Colombier 		break;
428*9a747e4fSDavid du Colombier 	default:
429*9a747e4fSDavid du Colombier 		err = "unknown command";
430*9a747e4fSDavid du Colombier 		break;
431*9a747e4fSDavid du Colombier 	}
432*9a747e4fSDavid du Colombier 	reply(f, err);
433*9a747e4fSDavid du Colombier }
434*9a747e4fSDavid du Colombier 
435*9a747e4fSDavid du Colombier static void
rclunk(Fcall * f)436*9a747e4fSDavid du Colombier rclunk(Fcall *f)
437*9a747e4fSDavid du Colombier {
438*9a747e4fSDavid du Colombier 	Fid *fidp;
439*9a747e4fSDavid du Colombier 
440*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
441*9a747e4fSDavid du Colombier 	fidp->open = 0;
442*9a747e4fSDavid du Colombier 	fidp->busy = 0;
443*9a747e4fSDavid du Colombier 	fidp->node = 0;
444*9a747e4fSDavid du Colombier 	fidp->name = 0;
445*9a747e4fSDavid du Colombier 	fidp->uid = 0;
446*9a747e4fSDavid du Colombier 	reply(f, 0);
447*9a747e4fSDavid du Colombier }
448*9a747e4fSDavid du Colombier 
449*9a747e4fSDavid du Colombier /*
450*9a747e4fSDavid du Colombier  *  no files or directories are removable; this becomes clunk;
451*9a747e4fSDavid du Colombier  */
452*9a747e4fSDavid du Colombier static void
rremove(Fcall * f)453*9a747e4fSDavid du Colombier rremove(Fcall *f)
454*9a747e4fSDavid du Colombier {
455*9a747e4fSDavid du Colombier 	Fid *fidp;
456*9a747e4fSDavid du Colombier 	Node *dir, *np;
457*9a747e4fSDavid du Colombier 
458*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
459*9a747e4fSDavid du Colombier 
460*9a747e4fSDavid du Colombier 	/*
461*9a747e4fSDavid du Colombier 	 * only trusted temporary files can be removed
462*9a747e4fSDavid du Colombier 	 * and only by their owner.
463*9a747e4fSDavid du Colombier 	 */
464*9a747e4fSDavid du Colombier 	if(fidp->node->d.type != Trustedtemp){
465*9a747e4fSDavid du Colombier 		reply(f, "can't be removed");
466*9a747e4fSDavid du Colombier 		return;
467*9a747e4fSDavid du Colombier 	}
468*9a747e4fSDavid du Colombier 	if(fidp->uid != fidp->node->d.uid){
469*9a747e4fSDavid du Colombier 		reply(f, "permission denied");
470*9a747e4fSDavid du Colombier 		return;
471*9a747e4fSDavid du Colombier 	}
472*9a747e4fSDavid du Colombier 	dir = fidp->node->parent;
473*9a747e4fSDavid du Colombier 	for(np = dir->children; np; np = np->sibs)
474*9a747e4fSDavid du Colombier 		if(np->sibs == fidp->node)
475*9a747e4fSDavid du Colombier 			break;
476*9a747e4fSDavid du Colombier 	if(np)
477*9a747e4fSDavid du Colombier 		np->sibs = fidp->node->sibs;
478*9a747e4fSDavid du Colombier 	else
479*9a747e4fSDavid du Colombier 		dir->children = fidp->node->sibs;
480*9a747e4fSDavid du Colombier 	dir->count--;
481*9a747e4fSDavid du Colombier 	free(fidp->node);
482*9a747e4fSDavid du Colombier 	fidp->node = 0;
483*9a747e4fSDavid du Colombier 	fidp->open = 0;
484*9a747e4fSDavid du Colombier 	fidp->busy = 0;
485*9a747e4fSDavid du Colombier 	fidp->name = 0;
486*9a747e4fSDavid du Colombier 	fidp->uid = 0;
487*9a747e4fSDavid du Colombier 	reply(f, 0);
488*9a747e4fSDavid du Colombier }
489*9a747e4fSDavid du Colombier 
490*9a747e4fSDavid du Colombier static void
rstat(Fcall * f)491*9a747e4fSDavid du Colombier rstat(Fcall *f)
492*9a747e4fSDavid du Colombier {
493*9a747e4fSDavid du Colombier 	Fid *fidp;
494*9a747e4fSDavid du Colombier 
495*9a747e4fSDavid du Colombier 	fidp = newfid(f->fid);
496*9a747e4fSDavid du Colombier 	if (fidp->node->d.type == Dummynode)
497*9a747e4fSDavid du Colombier 		dummy.d.name = fidp->name;
498*9a747e4fSDavid du Colombier 	f->stat = (uchar*)rbuf+4+1+2+2;	/* knows about stat(5) */
499*9a747e4fSDavid du Colombier 	f->nstat = convD2M(&fidp->node->d, f->stat, MAXRPC);
500*9a747e4fSDavid du Colombier 	if(f->nstat <= BIT16SZ)
501*9a747e4fSDavid du Colombier 		reply(f, "ratfs: convD2M");
502*9a747e4fSDavid du Colombier 	else
503*9a747e4fSDavid du Colombier 		reply(f, 0);
504*9a747e4fSDavid du Colombier 	return;
505*9a747e4fSDavid du Colombier }
506*9a747e4fSDavid du Colombier 
507*9a747e4fSDavid du Colombier static void
rwstat(Fcall * f)508*9a747e4fSDavid du Colombier rwstat(Fcall *f)
509*9a747e4fSDavid du Colombier {
510*9a747e4fSDavid du Colombier 	reply(f, "wstat not implemented");
511*9a747e4fSDavid du Colombier }
512*9a747e4fSDavid du Colombier 
513