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