Blob


1 #include "std.h"
2 #include "dat.h"
4 enum
5 {
6 Qroot,
7 Qfactotum,
8 Qrpc,
9 Qkeylist,
10 Qprotolist,
11 Qconfirm,
12 Qlog,
13 Qctl,
14 Qneedkey,
15 Qconv,
16 };
18 Qid
19 mkqid(int type, int path)
20 {
21 Qid q;
23 q.type = type;
24 q.path = path;
25 q.vers = 0;
26 return q;
27 }
29 static struct
30 {
31 char *name;
32 int qidpath;
33 ulong perm;
34 } dirtab[] = {
35 /* positions of confirm and needkey known below */
36 "confirm", Qconfirm, 0600|DMEXCL,
37 "needkey", Qneedkey, 0600|DMEXCL,
38 "ctl", Qctl, 0600,
39 "rpc", Qrpc, 0666,
40 "proto", Qprotolist, 0444,
41 "log", Qlog, 0600|DMEXCL,
42 "conv", Qconv, 0400,
43 };
45 static void
46 fillstat(Dir *dir, char *name, int type, int path, ulong perm)
47 {
48 dir->name = estrdup(name);
49 dir->uid = estrdup(owner);
50 dir->gid = estrdup(owner);
51 dir->mode = perm;
52 dir->length = 0;
53 dir->qid = mkqid(type, path);
54 dir->atime = time(0);
55 dir->mtime = time(0);
56 dir->muid = estrdup("");
57 }
59 static int
60 rootdirgen(int n, Dir *dir, void *v)
61 {
62 USED(v);
64 if(n > 0)
65 return -1;
67 fillstat(dir, factname, QTDIR, Qfactotum, DMDIR|0555);
68 return 0;
69 }
71 static int
72 fsdirgen(int n, Dir *dir, void *v)
73 {
74 USED(v);
76 if(n >= nelem(dirtab))
77 return -1;
78 fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm);
79 return 0;
80 }
82 static char*
83 fswalk1(Fid *fid, char *name, Qid *qid)
84 {
85 int i;
87 switch((int)fid->qid.path){
88 default:
89 return "fswalk1: cannot happen";
90 case Qroot:
91 if(strcmp(name, factname) == 0){
92 *qid = mkqid(QTDIR, Qfactotum);
93 fid->qid = *qid;
94 return nil;
95 }
96 if(strcmp(name, "..") == 0){
97 *qid = fid->qid;
98 return nil;
99 }
100 return "not found";
101 case Qfactotum:
102 for(i=0; i<nelem(dirtab); i++)
103 if(strcmp(name, dirtab[i].name) == 0){
104 *qid = mkqid(0, dirtab[i].qidpath);
105 fid->qid = *qid;
106 return nil;
108 if(strcmp(name, "..") == 0){
109 *qid = mkqid(QTDIR, Qroot);
110 fid->qid = *qid;
111 return nil;
113 return "not found";
117 static void
118 fsstat(Req *r)
120 int i, path;
122 path = r->fid->qid.path;
123 switch(path){
124 case Qroot:
125 fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR);
126 break;
127 case Qfactotum:
128 fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR);
129 break;
130 default:
131 for(i=0; i<nelem(dirtab); i++)
132 if(dirtab[i].qidpath == path){
133 fillstat(&r->d, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm);
134 goto Break2;
136 respond(r, "file not found");
137 break;
139 Break2:
140 respond(r, nil);
143 static int
144 readlist(int off, int (*gen)(int, char*, uint), Req *r)
146 char *a, *ea;
147 int n;
149 a = r->ofcall.data;
150 ea = a+r->ifcall.count;
151 for(;;){
152 n = (*gen)(off, a, ea-a);
153 if(n == 0){
154 r->ofcall.count = a - (char*)r->ofcall.data;
155 return off;
157 a += n;
158 off++;
160 return -1; /* not reached */
163 static int
164 keylist(int i, char *a, uint nn)
166 int n;
167 char buf[512];
168 Key *k;
170 if(i >= ring.nkey)
171 return 0;
173 k = ring.key[i];
174 k->attr = sortattr(k->attr);
175 n = snprint(buf, sizeof buf, "key %A %N\n", k->attr, k->privattr);
176 if(n >= sizeof(buf)-5)
177 strcpy(buf+sizeof(buf)-5, "...\n");
178 n = strlen(buf);
179 if(n > nn)
180 return 0;
181 memmove(a, buf, n);
182 return n;
185 static int
186 protolist(int i, char *a, uint n)
188 if(prototab[i] == nil)
189 return 0;
190 if(strlen(prototab[i]->name)+1 > n)
191 return 0;
192 n = strlen(prototab[i]->name)+1;
193 memmove(a, prototab[i]->name, n-1);
194 a[n-1] = '\n';
195 return n;
198 /* BUG this is O(n^2) to fill in the list */
199 static int
200 convlist(int i, char *a, uint nn)
202 Conv *c;
203 char buf[512];
204 int n;
206 for(c=conv; c && i-- > 0; c=c->next)
209 if(c == nil)
210 return 0;
212 if(c->state)
213 n = snprint(buf, sizeof buf, "conv state=%q %A\n", c->state, c->attr);
214 else
215 n = snprint(buf, sizeof buf, "conv state=closed err=%q\n", c->err);
217 if(n >= sizeof(buf)-5)
218 strcpy(buf+sizeof(buf)-5, "...\n");
219 n = strlen(buf);
220 if(n > nn)
221 return 0;
222 memmove(a, buf, n);
223 return n;
226 static void
227 fskickreply(Conv *c)
229 Req *r;
231 if(c->hangup){
232 if(c->req){
233 respond(c->req, "hangup");
234 c->req = nil;
236 return;
239 if(!c->req || !c->nreply)
240 return;
242 r = c->req;
243 r->ofcall.count = c->nreply;
244 r->ofcall.data = c->reply;
245 if(r->ofcall.count > r->ifcall.count)
246 r->ofcall.count = r->ifcall.count;
247 respond(r, nil);
248 c->req = nil;
249 c->nreply = 0;
252 /*
253 * Some of the file system work happens in the fs proc, but
254 * fsopen, fsread, fswrite, fsdestroyfid, and fsflush happen in
255 * the main proc so that they can access the various shared
256 * data structures without worrying about locking.
257 */
258 static int inuse[nelem(dirtab)];
259 int *confirminuse = &inuse[0];
260 int *needkeyinuse = &inuse[1];
261 static void
262 fsopen(Req *r)
264 int i, *inusep, perm;
265 static int need[4] = { 4, 2, 6, 1 };
266 Conv *c;
268 inusep = nil;
269 perm = 5; /* directory */
270 for(i=0; i<nelem(dirtab); i++)
271 if(dirtab[i].qidpath == r->fid->qid.path){
272 if(dirtab[i].perm & DMEXCL)
273 inusep = &inuse[i];
274 if(strcmp(r->fid->uid, owner) == 0)
275 perm = dirtab[i].perm>>6;
276 else
277 perm = dirtab[i].perm;
278 break;
281 if((r->ifcall.mode&~(OMASK|OTRUNC))
282 || (need[r->ifcall.mode&3] & ~perm)){
283 respond(r, "permission denied");
284 return;
287 if(inusep){
288 if(*inusep){
289 respond(r, "file in use");
290 return;
292 *inusep = 1;
295 if(r->fid->qid.path == Qrpc){
296 if((c = convalloc(r->fid->uid)) == nil){
297 char e[ERRMAX];
299 rerrstr(e, sizeof e);
300 respond(r, e);
301 return;
303 c->kickreply = fskickreply;
304 r->fid->aux = c;
307 respond(r, nil);
310 static void
311 fsread(Req *r)
313 Conv *c;
315 switch((int)r->fid->qid.path){
316 default:
317 respond(r, "fsread: cannot happen");
318 break;
319 case Qroot:
320 dirread9p(r, rootdirgen, nil);
321 respond(r, nil);
322 break;
323 case Qfactotum:
324 dirread9p(r, fsdirgen, nil);
325 respond(r, nil);
326 break;
327 case Qrpc:
328 c = r->fid->aux;
329 if(c->rpc.op == RpcUnknown){
330 respond(r, "no rpc pending");
331 break;
333 if(c->req){
334 respond(r, "read already pending");
335 break;
337 c->req = r;
338 if(c->nreply)
339 (*c->kickreply)(c);
340 else
341 rpcexec(c);
342 break;
343 case Qconfirm:
344 confirmread(r);
345 break;
346 case Qlog:
347 logread(r);
348 break;
349 case Qctl:
350 r->fid->aux = (void*)readlist((int)r->fid->aux, keylist, r);
351 respond(r, nil);
352 break;
353 case Qneedkey:
354 needkeyread(r);
355 break;
356 case Qprotolist:
357 r->fid->aux = (void*)readlist((int)r->fid->aux, protolist, r);
358 respond(r, nil);
359 break;
360 case Qconv:
361 r->fid->aux = (void*)readlist((int)r->fid->aux, convlist, r);
362 respond(r, nil);
363 break;
367 static void
368 fswrite(Req *r)
370 int ret;
371 char err[ERRMAX], *s;
372 int (*strfn)(char*);
374 switch((int)r->fid->qid.path){
375 default:
376 respond(r, "fswrite: cannot happen");
377 break;
378 case Qrpc:
379 if(rpcwrite(r->fid->aux, r->ifcall.data, r->ifcall.count) < 0){
380 rerrstr(err, sizeof err);
381 respond(r, err);
382 }else{
383 r->ofcall.count = r->ifcall.count;
384 respond(r, nil);
386 break;
387 case Qneedkey:
388 strfn = needkeywrite;
389 goto string;
390 case Qctl:
391 strfn = ctlwrite;
392 goto string;
393 case Qconfirm:
394 strfn = confirmwrite;
395 string:
396 s = emalloc(r->ifcall.count+1);
397 memmove(s, r->ifcall.data, r->ifcall.count);
398 s[r->ifcall.count] = '\0';
399 ret = (*strfn)(s);
400 free(s);
401 if(ret < 0){
402 rerrstr(err, sizeof err);
403 respond(r, err);
404 }else{
405 r->ofcall.count = r->ifcall.count;
406 respond(r, nil);
408 break;
412 static void
413 fsflush(Req *r)
415 confirmflush(r);
416 logflush(r);
419 static void
420 fsdestroyfid(Fid *fid)
422 if(fid->qid.path == Qrpc){
423 convhangup(fid->aux);
424 convclose(fid->aux);
428 static Channel *creq;
429 static Channel *cfid, *cfidr;
431 static void
432 fsreqthread(void *v)
434 Req *r;
436 USED(v);
438 creq = chancreate(sizeof(Req*), 0);
440 while((r = recvp(creq)) != nil){
441 switch(r->ifcall.type){
442 default:
443 respond(r, "bug in fsreqthread");
444 break;
445 case Topen:
446 fsopen(r);
447 break;
448 case Tread:
449 fsread(r);
450 break;
451 case Twrite:
452 fswrite(r);
453 break;
454 case Tflush:
455 fsflush(r);
456 break;
461 static void
462 fsclunkthread(void *v)
464 Fid *f;
466 USED(v);
467 cfid = chancreate(sizeof(Fid*), 0);
468 cfidr = chancreate(sizeof(Fid*), 0);
470 while((f = recvp(cfid)) != nil){
471 fsdestroyfid(f);
472 sendp(cfidr, 0);
476 static void
477 fsproc(void *v)
479 USED(v);
481 threadcreate(fsreqthread, nil, STACK);
482 threadcreate(fsclunkthread, nil, STACK);
483 threadexits(nil);
486 static void
487 fsattach(Req *r)
489 static int first = 1;
491 if(first){
492 proccreate(fsproc, nil, STACK);
493 first = 0;
496 r->fid->qid = mkqid(QTDIR, Qroot);
497 r->ofcall.qid = r->fid->qid;
498 respond(r, nil);
501 static void
502 fssend(Req *r)
504 sendp(creq, r);
507 static void
508 fssendclunk(Fid *f)
510 sendp(cfid, f);
511 recvp(cfidr);
514 Srv fs = {
515 .attach= fsattach,
516 .walk1= fswalk1,
517 .open= fssend,
518 .read= fssend,
519 .write= fssend,
520 .stat= fsstat,
521 .flush= fssend,
522 .destroyfid= fssendclunk,
523 };