blob: 4ae99afd895ae1b89757b29f9274a8019fbda961 [file] [log] [blame]
rscb8c14082003-11-23 17:58:26 +00001#include <u.h>
2#include <libc.h>
3#include <bio.h>
4#include <regexp.h>
5#include <thread.h>
rscb8c14082003-11-23 17:58:26 +00006#include <fcall.h>
7#include <plumb.h>
8#include "plumber.h"
9
10enum
11{
rsc32f69c32003-12-11 17:48:38 +000012 Stack = 32*1024
rscb8c14082003-11-23 17:58:26 +000013};
14
15typedef struct Dirtab Dirtab;
16typedef struct Fid Fid;
17typedef struct Holdq Holdq;
18typedef struct Readreq Readreq;
19typedef struct Sendreq Sendreq;
20
21struct Dirtab
22{
23 char *name;
24 uchar type;
25 uint qid;
26 uint perm;
27 int nopen; /* #fids open on this port */
28 Fid *fopen;
29 Holdq *holdq;
30 Readreq *readq;
31 Sendreq *sendq;
32};
33
34struct Fid
35{
36 int fid;
37 int busy;
38 int open;
39 int mode;
40 Qid qid;
41 Dirtab *dir;
42 long offset; /* zeroed at beginning of each message, read or write */
43 char *writebuf; /* partial message written so far; offset tells how much */
44 Fid *next;
45 Fid *nextopen;
46};
47
48struct Readreq
49{
50 Fid *fid;
51 Fcall *fcall;
52 uchar *buf;
53 Readreq *next;
54};
55
56struct Sendreq
57{
58 int nfid; /* number of fids that should receive this message */
59 int nleft; /* number left that haven't received it */
60 Fid **fid; /* fid[nfid] */
61 Plumbmsg *msg;
62 char *pack; /* plumbpack()ed message */
63 int npack; /* length of pack */
64 Sendreq *next;
65};
66
67struct Holdq
68{
69 Plumbmsg *msg;
70 Holdq *next;
71};
72
73struct /* needed because incref() doesn't return value */
74{
rsc32f69c32003-12-11 17:48:38 +000075 Lock lk;
76 int ref;
rscb8c14082003-11-23 17:58:26 +000077} rulesref;
78
79enum
80{
rscb8c14082003-11-23 17:58:26 +000081 NDIR = 50,
82 Nhash = 16,
83
84 Qdir = 0,
85 Qrules = 1,
86 Qsend = 2,
87 Qport = 3,
88 NQID = Qport
89};
90
91static Dirtab dir[NDIR] =
92{
93 { ".", QTDIR, Qdir, 0500|DMDIR },
94 { "rules", QTFILE, Qrules, 0600 },
rsccbeb0b22006-04-01 19:24:03 +000095 { "send", QTFILE, Qsend, 0200 }
rscb8c14082003-11-23 17:58:26 +000096};
97static int ndir = NQID;
98
99static int srvfd;
rsc8ad51792004-03-25 23:03:57 +0000100#define clock plumbclock /* SunOS name clash */
rscb8c14082003-11-23 17:58:26 +0000101static int clock;
102static Fid *fids[Nhash];
103static QLock readlock;
104static QLock queue;
rscb8c14082003-11-23 17:58:26 +0000105static int messagesize = 8192+IOHDRSZ; /* good start */
106
107static void fsysproc(void*);
108static void fsysrespond(Fcall*, uchar*, char*);
109static Fid* newfid(int);
110
111static Fcall* fsysflush(Fcall*, uchar*, Fid*);
112static Fcall* fsysversion(Fcall*, uchar*, Fid*);
113static Fcall* fsysauth(Fcall*, uchar*, Fid*);
114static Fcall* fsysattach(Fcall*, uchar*, Fid*);
115static Fcall* fsyswalk(Fcall*, uchar*, Fid*);
116static Fcall* fsysopen(Fcall*, uchar*, Fid*);
117static Fcall* fsyscreate(Fcall*, uchar*, Fid*);
118static Fcall* fsysread(Fcall*, uchar*, Fid*);
119static Fcall* fsyswrite(Fcall*, uchar*, Fid*);
120static Fcall* fsysclunk(Fcall*, uchar*, Fid*);
121static Fcall* fsysremove(Fcall*, uchar*, Fid*);
122static Fcall* fsysstat(Fcall*, uchar*, Fid*);
123static Fcall* fsyswstat(Fcall*, uchar*, Fid*);
124
rscbe22ae22004-03-26 01:59:35 +0000125Fcall* (*fcall[Tmax])(Fcall*, uchar*, Fid*);
126
127static void
128initfcall(void)
rscb8c14082003-11-23 17:58:26 +0000129{
rscbe22ae22004-03-26 01:59:35 +0000130 fcall[Tflush] = fsysflush;
131 fcall[Tversion] = fsysversion;
132 fcall[Tauth] = fsysauth;
133 fcall[Tattach] = fsysattach;
134 fcall[Twalk] = fsyswalk;
135 fcall[Topen] = fsysopen;
136 fcall[Tcreate] = fsyscreate;
137 fcall[Tread] = fsysread;
138 fcall[Twrite] = fsyswrite;
139 fcall[Tclunk] = fsysclunk;
140 fcall[Tremove]= fsysremove;
141 fcall[Tstat] = fsysstat;
142 fcall[Twstat] = fsyswstat;
143}
rscb8c14082003-11-23 17:58:26 +0000144
145char Ebadfcall[] = "bad fcall type";
146char Eperm[] = "permission denied";
147char Enomem[] = "malloc failed for buffer";
148char Enotdir[] = "not a directory";
149char Enoexist[] = "plumb file does not exist";
150char Eisdir[] = "file is a directory";
151char Ebadmsg[] = "bad plumb message format";
152char Enosuchport[] ="no such plumb port";
153char Enoport[] = "couldn't find destination for message";
154char Einuse[] = "file already open";
155
156/*
157 * Add new port. A no-op if port already exists or is the null string
158 */
159void
160addport(char *port)
161{
162 int i;
163
164 if(port == nil)
165 return;
166 for(i=NQID; i<ndir; i++)
167 if(strcmp(port, dir[i].name) == 0)
168 return;
169 if(i == NDIR){
170 fprint(2, "plumb: too many ports; max %d\n", NDIR);
171 return;
172 }
173 ndir++;
174 dir[i].name = estrdup(port);
175 dir[i].qid = i;
176 dir[i].perm = 0400;
177 nports++;
178 ports = erealloc(ports, nports*sizeof(char*));
179 ports[nports-1] = dir[i].name;
180}
181
182static ulong
183getclock(void)
184{
rsc32f69c32003-12-11 17:48:38 +0000185 return time(0);
rscb8c14082003-11-23 17:58:26 +0000186}
187
188void
189startfsys(void)
190{
rsc32f69c32003-12-11 17:48:38 +0000191 int p[2];
rscb8c14082003-11-23 17:58:26 +0000192
193 fmtinstall('F', fcallfmt);
rscb8c14082003-11-23 17:58:26 +0000194 clock = getclock();
195 if(pipe(p) < 0)
196 error("can't create pipe: %r");
197 /* 0 will be server end, 1 will be client end */
198 srvfd = p[0];
rsc32f69c32003-12-11 17:48:38 +0000199 if(post9pservice(p[1], "plumb") < 0)
200 sysfatal("post9pservice plumb: %r");
rscb8c14082003-11-23 17:58:26 +0000201 close(p[1]);
rscf4b26b62005-01-04 22:17:10 +0000202 proccreate(fsysproc, nil, Stack);
rscb8c14082003-11-23 17:58:26 +0000203}
204
205static void
rsc32f69c32003-12-11 17:48:38 +0000206fsysproc(void *v)
rscb8c14082003-11-23 17:58:26 +0000207{
208 int n;
209 Fcall *t;
210 Fid *f;
211 uchar *buf;
212
rsc32f69c32003-12-11 17:48:38 +0000213 USED(v);
rscbe22ae22004-03-26 01:59:35 +0000214 initfcall();
rscb8c14082003-11-23 17:58:26 +0000215 t = nil;
216 for(;;){
217 buf = malloc(messagesize); /* avoid memset of emalloc */
218 if(buf == nil)
219 error("malloc failed: %r");
220 qlock(&readlock);
rscf9979092004-12-26 02:10:47 +0000221 n = read9pmsg(srvfd, buf, messagesize);
rscb8c14082003-11-23 17:58:26 +0000222 if(n <= 0){
223 if(n < 0)
224 error("i/o error on server channel");
225 threadexitsall("unmounted");
226 }
rscf9979092004-12-26 02:10:47 +0000227 /*
228 * can give false positive (create an extra fsysproc) once in a while,
229 * but no false negatives, so good enough. once we have one extra
230 * we'll never have more.
231 */
232 if(readlock.waiting.head == nil) /* no other processes waiting to read; start one */
233 proccreate(fsysproc, nil, Stack);
rscb8c14082003-11-23 17:58:26 +0000234 qunlock(&readlock);
235 if(t == nil)
236 t = emalloc(sizeof(Fcall));
237 if(convM2S(buf, n, t) != n)
238 error("convert error in convM2S");
rsc32f69c32003-12-11 17:48:38 +0000239 if(debug)
rscb8c14082003-11-23 17:58:26 +0000240 fprint(2, "<= %F\n", t);
wkja8763862004-07-09 01:54:06 +0000241 if(fcall[t->type] == 0)
rscb8c14082003-11-23 17:58:26 +0000242 fsysrespond(t, buf, Ebadfcall);
243 else{
244 if(t->type==Tversion || t->type==Tauth)
245 f = nil;
246 else
247 f = newfid(t->fid);
248 t = (*fcall[t->type])(t, buf, f);
249 }
250 }
251}
252
253static void
254fsysrespond(Fcall *t, uchar *buf, char *err)
255{
256 int n;
257
258 if(err){
259 t->type = Rerror;
260 t->ename = err;
261 }else
262 t->type++;
263 if(buf == nil)
264 buf = emalloc(messagesize);
265 n = convS2M(t, buf, messagesize);
266 if(n < 0)
267 error("convert error in convS2M");
268 if(write(srvfd, buf, n) != n)
269 error("write error in respond");
rsc32f69c32003-12-11 17:48:38 +0000270 if(debug)
rscb8c14082003-11-23 17:58:26 +0000271 fprint(2, "=> %F\n", t);
272 free(buf);
273}
274
275static
276Fid*
277newfid(int fid)
278{
279 Fid *f, *ff, **fh;
280
281 qlock(&queue);
282 ff = nil;
283 fh = &fids[fid&(Nhash-1)];
284 for(f=*fh; f; f=f->next)
285 if(f->fid == fid)
286 goto Return;
287 else if(ff==nil && !f->busy)
288 ff = f;
289 if(ff){
290 ff->fid = fid;
291 f = ff;
292 goto Return;
293 }
294 f = emalloc(sizeof *f);
295 f->fid = fid;
296 f->next = *fh;
297 *fh = f;
298 Return:
299 qunlock(&queue);
300 return f;
301}
302
303static uint
304dostat(Dirtab *dir, uchar *buf, uint nbuf, uint clock)
305{
306 Dir d;
307
308 d.qid.type = dir->type;
309 d.qid.path = dir->qid;
310 d.qid.vers = 0;
311 d.mode = dir->perm;
312 d.length = 0; /* would be nice to do better */
313 d.name = dir->name;
314 d.uid = user;
315 d.gid = user;
316 d.muid = user;
317 d.atime = clock;
318 d.mtime = clock;
319 return convD2M(&d, buf, nbuf);
320}
321
322static void
323queuesend(Dirtab *d, Plumbmsg *m)
324{
325 Sendreq *s, *t;
326 Fid *f;
327 int i;
328
329 s = emalloc(sizeof(Sendreq));
330 s->nfid = d->nopen;
331 s->nleft = s->nfid;
332 s->fid = emalloc(s->nfid*sizeof(Fid*));
333 i = 0;
334 /* build array of fids open on this channel */
335 for(f=d->fopen; f!=nil; f=f->nextopen)
336 s->fid[i++] = f;
337 s->msg = m;
338 s->next = nil;
339 /* link to end of queue; drainqueue() searches in sender order so this implements a FIFO */
340 for(t=d->sendq; t!=nil; t=t->next)
341 if(t->next == nil)
342 break;
343 if(t == nil)
344 d->sendq = s;
345 else
346 t->next = s;
347}
348
349static void
350queueread(Dirtab *d, Fcall *t, uchar *buf, Fid *f)
351{
352 Readreq *r;
353
354 r = emalloc(sizeof(Readreq));
355 r->fcall = t;
356 r->buf = buf;
357 r->fid = f;
358 r->next = d->readq;
359 d->readq = r;
360}
361
362static void
363drainqueue(Dirtab *d)
364{
365 Readreq *r, *nextr, *prevr;
366 Sendreq *s, *nexts, *prevs;
367 int i, n;
368
369 prevs = nil;
370 for(s=d->sendq; s!=nil; s=nexts){
371 nexts = s->next;
372 for(i=0; i<s->nfid; i++){
373 prevr = nil;
374 for(r=d->readq; r!=nil; r=nextr){
375 nextr = r->next;
376 if(r->fid == s->fid[i]){
377 /* pack the message if necessary */
378 if(s->pack == nil)
379 s->pack = plumbpack(s->msg, &s->npack);
380 /* exchange the stuff... */
381 r->fcall->data = s->pack+r->fid->offset;
382 n = s->npack - r->fid->offset;
383 if(n > messagesize-IOHDRSZ)
384 n = messagesize-IOHDRSZ;
385 if(n > r->fcall->count)
386 n = r->fcall->count;
387 r->fcall->count = n;
388 fsysrespond(r->fcall, r->buf, nil);
389 r->fid->offset += n;
390 if(r->fid->offset >= s->npack){
391 /* message transferred; delete this fid from send queue */
392 r->fid->offset = 0;
393 s->fid[i] = nil;
394 s->nleft--;
395 }
396 /* delete read request from queue */
397 if(prevr)
398 prevr->next = r->next;
399 else
400 d->readq = r->next;
401 free(r->fcall);
402 free(r);
403 break;
404 }else
405 prevr = r;
406 }
407 }
408 /* if no fids left, delete this send from queue */
409 if(s->nleft == 0){
410 free(s->fid);
411 plumbfree(s->msg);
412 free(s->pack);
413 if(prevs)
414 prevs->next = s->next;
415 else
416 d->sendq = s->next;
417 free(s);
418 }else
419 prevs = s;
420 }
421}
422
423/* can't flush a send because they are always answered synchronously */
424static void
425flushqueue(Dirtab *d, int oldtag)
426{
427 Readreq *r, *prevr;
428
429 prevr = nil;
430 for(r=d->readq; r!=nil; r=r->next){
431 if(oldtag == r->fcall->tag){
432 /* delete read request from queue */
433 if(prevr)
434 prevr->next = r->next;
435 else
436 d->readq = r->next;
437 free(r->fcall);
438 free(r->buf);
439 free(r);
440 return;
441 }
442 prevr = r;
443 }
444}
445
446/* remove messages awaiting delivery to now-closing fid */
447static void
448removesenders(Dirtab *d, Fid *fid)
449{
450 Sendreq *s, *nexts, *prevs;
451 int i;
452
453 prevs = nil;
454 for(s=d->sendq; s!=nil; s=nexts){
455 nexts = s->next;
456 for(i=0; i<s->nfid; i++)
457 if(fid == s->fid[i]){
458 /* delete this fid from send queue */
459 s->fid[i] = nil;
460 s->nleft--;
461 break;
462 }
463 /* if no fids left, delete this send from queue */
464 if(s->nleft == 0){
465 free(s->fid);
466 plumbfree(s->msg);
467 free(s->pack);
468 if(prevs)
469 prevs->next = s->next;
470 else
471 d->sendq = s->next;
472 free(s);
473 }else
474 prevs = s;
475 }
476}
477
478static void
479hold(Plumbmsg *m, Dirtab *d)
480{
481 Holdq *h, *q;
482
483 h = emalloc(sizeof(Holdq));
484 h->msg = m;
485 /* add to end of queue */
486 if(d->holdq == nil)
487 d->holdq = h;
488 else{
489 for(q=d->holdq; q->next!=nil; q=q->next)
490 ;
491 q->next = h;
492 }
493}
494
495static void
496queueheld(Dirtab *d)
497{
498 Holdq *h;
499
500 while(d->holdq != nil){
501 h = d->holdq;
502 d->holdq = h->next;
503 queuesend(d, h->msg);
504 /* no need to drain queue because we know no-one is reading yet */
505 free(h);
506 }
507}
508
509static void
510dispose(Fcall *t, uchar *buf, Plumbmsg *m, Ruleset *rs, Exec *e)
511{
512 int i;
513 char *err;
514
515 qlock(&queue);
516 err = nil;
517 if(m->dst==nil || m->dst[0]=='\0'){
518 err = Enoport;
519 if(rs != nil)
520 err = startup(rs, e);
521 plumbfree(m);
522 }else
523 for(i=NQID; i<ndir; i++)
524 if(strcmp(m->dst, dir[i].name) == 0){
525 if(dir[i].nopen == 0){
526 err = startup(rs, e);
527 if(e!=nil && e->holdforclient)
528 hold(m, &dir[i]);
529 else
530 plumbfree(m);
531 }else{
532 queuesend(&dir[i], m);
533 drainqueue(&dir[i]);
534 }
535 break;
536 }
537 freeexec(e);
538 qunlock(&queue);
539 fsysrespond(t, buf, err);
540 free(t);
541}
542
543static Fcall*
rsc32f69c32003-12-11 17:48:38 +0000544fsysversion(Fcall *t, uchar *buf, Fid *fid)
rscb8c14082003-11-23 17:58:26 +0000545{
rsc32f69c32003-12-11 17:48:38 +0000546 USED(fid);
547
rscb8c14082003-11-23 17:58:26 +0000548 if(t->msize < 256){
549 fsysrespond(t, buf, "version: message size too small");
550 return t;
551 }
552 if(t->msize < messagesize)
553 messagesize = t->msize;
554 t->msize = messagesize;
555 if(strncmp(t->version, "9P2000", 6) != 0){
556 fsysrespond(t, buf, "unrecognized 9P version");
557 return t;
558 }
559 t->version = "9P2000";
560 fsysrespond(t, buf, nil);
561 return t;
562}
563
564static Fcall*
rsc32f69c32003-12-11 17:48:38 +0000565fsysauth(Fcall *t, uchar *buf, Fid *fid)
rscb8c14082003-11-23 17:58:26 +0000566{
rsc32f69c32003-12-11 17:48:38 +0000567 USED(fid);
rscb8c14082003-11-23 17:58:26 +0000568 fsysrespond(t, buf, "plumber: authentication not required");
569 return t;
570}
571
572static Fcall*
573fsysattach(Fcall *t, uchar *buf, Fid *f)
574{
575 Fcall out;
576
577 if(strcmp(t->uname, user) != 0){
578 fsysrespond(&out, buf, Eperm);
579 return t;
580 }
581 f->busy = 1;
582 f->open = 0;
583 f->qid.type = QTDIR;
584 f->qid.path = Qdir;
585 f->qid.vers = 0;
586 f->dir = dir;
587 memset(&out, 0, sizeof(Fcall));
588 out.type = t->type;
589 out.tag = t->tag;
590 out.fid = f->fid;
591 out.qid = f->qid;
592 fsysrespond(&out, buf, nil);
593 return t;
594}
595
596static Fcall*
rsc32f69c32003-12-11 17:48:38 +0000597fsysflush(Fcall *t, uchar *buf, Fid *fid)
rscb8c14082003-11-23 17:58:26 +0000598{
599 int i;
600
rsc32f69c32003-12-11 17:48:38 +0000601 USED(fid);
rscb8c14082003-11-23 17:58:26 +0000602 qlock(&queue);
603 for(i=NQID; i<ndir; i++)
604 flushqueue(&dir[i], t->oldtag);
605 qunlock(&queue);
606 fsysrespond(t, buf, nil);
607 return t;
608}
609
610static Fcall*
611fsyswalk(Fcall *t, uchar *buf, Fid *f)
612{
613 Fcall out;
614 Fid *nf;
615 ulong path;
616 Dirtab *d, *dir;
617 Qid q;
618 int i;
619 uchar type;
620 char *err;
621
622 if(f->open){
623 fsysrespond(t, buf, "clone of an open fid");
624 return t;
625 }
626
627 nf = nil;
628 if(t->fid != t->newfid){
629 nf = newfid(t->newfid);
630 if(nf->busy){
631 fsysrespond(t, buf, "clone to a busy fid");
632 return t;
633 }
634 nf->busy = 1;
635 nf->open = 0;
636 nf->dir = f->dir;
637 nf->qid = f->qid;
638 f = nf; /* walk f */
639 }
640
641 out.nwqid = 0;
642 err = nil;
643 dir = f->dir;
644 q = f->qid;
645
646 if(t->nwname > 0){
647 for(i=0; i<t->nwname; i++){
648 if((q.type & QTDIR) == 0){
649 err = Enotdir;
650 break;
651 }
652 if(strcmp(t->wname[i], "..") == 0){
653 type = QTDIR;
654 path = Qdir;
655 Accept:
656 q.type = type;
657 q.vers = 0;
658 q.path = path;
659 out.wqid[out.nwqid++] = q;
660 continue;
661 }
662 d = dir;
663 d++; /* skip '.' */
664 for(; d->name; d++)
665 if(strcmp(t->wname[i], d->name) == 0){
666 type = d->type;
667 path = d->qid;
668 dir = d;
669 goto Accept;
670 }
671 err = Enoexist;
672 break;
673 }
674 }
675
676 out.type = t->type;
677 out.tag = t->tag;
678 if(err!=nil || out.nwqid<t->nwname){
679 if(nf)
680 nf->busy = 0;
681 }else if(out.nwqid == t->nwname){
682 f->qid = q;
683 f->dir = dir;
684 }
685
686 fsysrespond(&out, buf, err);
687 return t;
688}
689
690static Fcall*
691fsysopen(Fcall *t, uchar *buf, Fid *f)
692{
693 int m, clearrules, mode;
694
695 clearrules = 0;
696 if(t->mode & OTRUNC){
697 if(f->qid.path != Qrules)
698 goto Deny;
699 clearrules = 1;
700 }
701 /* can't truncate anything, so just disregard */
702 mode = t->mode & ~(OTRUNC|OCEXEC);
703 /* can't execute or remove anything */
704 if(mode==OEXEC || (mode&ORCLOSE))
705 goto Deny;
706 switch(mode){
707 default:
708 goto Deny;
709 case OREAD:
710 m = 0400;
711 break;
712 case OWRITE:
713 m = 0200;
714 break;
715 case ORDWR:
716 m = 0600;
717 break;
718 }
719 if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
720 goto Deny;
721 if(f->qid.path==Qrules && (mode==OWRITE || mode==ORDWR)){
rsc32f69c32003-12-11 17:48:38 +0000722 lock(&rulesref.lk);
rscb8c14082003-11-23 17:58:26 +0000723 if(rulesref.ref++ != 0){
724 rulesref.ref--;
rsc32f69c32003-12-11 17:48:38 +0000725 unlock(&rulesref.lk);
rscb8c14082003-11-23 17:58:26 +0000726 fsysrespond(t, buf, Einuse);
727 return t;
728 }
rsc32f69c32003-12-11 17:48:38 +0000729 unlock(&rulesref.lk);
rscb8c14082003-11-23 17:58:26 +0000730 }
731 if(clearrules){
732 writerules(nil, 0);
733 rules[0] = nil;
734 }
735 t->qid = f->qid;
736 t->iounit = 0;
737 qlock(&queue);
738 f->mode = mode;
739 f->open = 1;
740 f->dir->nopen++;
741 f->nextopen = f->dir->fopen;
742 f->dir->fopen = f;
743 queueheld(f->dir);
744 qunlock(&queue);
745 fsysrespond(t, buf, nil);
746 return t;
747
748 Deny:
749 fsysrespond(t, buf, Eperm);
750 return t;
751}
752
753static Fcall*
rsc32f69c32003-12-11 17:48:38 +0000754fsyscreate(Fcall *t, uchar *buf, Fid *fid)
rscb8c14082003-11-23 17:58:26 +0000755{
rsc32f69c32003-12-11 17:48:38 +0000756 USED(fid);
rscb8c14082003-11-23 17:58:26 +0000757 fsysrespond(t, buf, Eperm);
758 return t;
759}
760
761static Fcall*
762fsysreadrules(Fcall *t, uchar *buf)
763{
764 char *p;
765 int n;
766
767 p = printrules();
768 n = strlen(p);
769 t->data = p;
770 if(t->offset >= n)
771 t->count = 0;
772 else{
773 t->data = p+t->offset;
774 if(t->offset+t->count > n)
775 t->count = n-t->offset;
776 }
777 fsysrespond(t, buf, nil);
778 free(p);
779 return t;
780}
781
782static Fcall*
783fsysread(Fcall *t, uchar *buf, Fid *f)
784{
785 uchar *b;
786 int i, n, o, e;
787 uint len;
788 Dirtab *d;
789 uint clock;
790
791 if(f->qid.path != Qdir){
792 if(f->qid.path == Qrules)
793 return fsysreadrules(t, buf);
794 /* read from port */
795 if(f->qid.path < NQID){
796 fsysrespond(t, buf, "internal error: unknown read port");
797 return t;
798 }
799 qlock(&queue);
800 queueread(f->dir, t, buf, f);
801 drainqueue(f->dir);
802 qunlock(&queue);
803 return nil;
804 }
805 o = t->offset;
806 e = t->offset+t->count;
807 clock = getclock();
808 b = malloc(messagesize-IOHDRSZ);
809 if(b == nil){
810 fsysrespond(t, buf, Enomem);
811 return t;
812 }
813 n = 0;
814 d = dir;
815 d++; /* first entry is '.' */
816 for(i=0; d->name!=nil && i<e; i+=len){
817 len = dostat(d, b+n, messagesize-IOHDRSZ-n, clock);
818 if(len <= BIT16SZ)
819 break;
820 if(i >= o)
821 n += len;
822 d++;
823 }
824 t->data = (char*)b;
825 t->count = n;
826 fsysrespond(t, buf, nil);
827 free(b);
828 return t;
829}
830
831static Fcall*
832fsyswrite(Fcall *t, uchar *buf, Fid *f)
833{
834 Plumbmsg *m;
835 int i, n;
836 long count;
837 char *data;
838 Exec *e;
839
840 switch((int)f->qid.path){
841 case Qdir:
842 fsysrespond(t, buf, Eisdir);
843 return t;
844 case Qrules:
845 clock = getclock();
846 fsysrespond(t, buf, writerules(t->data, t->count));
847 return t;
848 case Qsend:
849 if(f->offset == 0){
850 data = t->data;
851 count = t->count;
852 }else{
853 /* partial message already assembled */
854 f->writebuf = erealloc(f->writebuf, f->offset + t->count);
855 memmove(f->writebuf+f->offset, t->data, t->count);
856 data = f->writebuf;
857 count = f->offset+t->count;
858 }
859 m = plumbunpackpartial(data, count, &n);
860 if(m == nil){
861 if(n == 0){
862 f->offset = 0;
863 free(f->writebuf);
864 f->writebuf = nil;
865 fsysrespond(t, buf, Ebadmsg);
866 return t;
867 }
868 /* can read more... */
869 if(f->offset == 0){
870 f->writebuf = emalloc(t->count);
871 memmove(f->writebuf, t->data, t->count);
872 }
873 /* else buffer has already been grown */
874 f->offset += t->count;
875 fsysrespond(t, buf, nil);
876 return t;
877 }
878 /* release partial buffer */
879 f->offset = 0;
880 free(f->writebuf);
881 f->writebuf = nil;
882 for(i=0; rules[i]; i++)
883 if((e=matchruleset(m, rules[i])) != nil){
884 dispose(t, buf, m, rules[i], e);
885 return nil;
886 }
887 if(m->dst != nil){
888 dispose(t, buf, m, nil, nil);
889 return nil;
890 }
891 fsysrespond(t, buf, "no matching plumb rule");
892 return t;
893 }
894 fsysrespond(t, buf, "internal error: write to unknown file");
895 return t;
896}
897
898static Fcall*
899fsysstat(Fcall *t, uchar *buf, Fid *f)
900{
901 t->stat = emalloc(messagesize-IOHDRSZ);
902 t->nstat = dostat(f->dir, t->stat, messagesize-IOHDRSZ, clock);
903 fsysrespond(t, buf, nil);
904 free(t->stat);
905 t->stat = nil;
906 return t;
907}
908
909static Fcall*
rsc32f69c32003-12-11 17:48:38 +0000910fsyswstat(Fcall *t, uchar *buf, Fid *fid)
rscb8c14082003-11-23 17:58:26 +0000911{
rsc32f69c32003-12-11 17:48:38 +0000912 USED(fid);
rscb8c14082003-11-23 17:58:26 +0000913 fsysrespond(t, buf, Eperm);
914 return t;
915}
916
917static Fcall*
rsc32f69c32003-12-11 17:48:38 +0000918fsysremove(Fcall *t, uchar *buf, Fid *fid)
rscb8c14082003-11-23 17:58:26 +0000919{
rsc32f69c32003-12-11 17:48:38 +0000920 USED(fid);
rscb8c14082003-11-23 17:58:26 +0000921 fsysrespond(t, buf, Eperm);
922 return t;
923}
924
925static Fcall*
926fsysclunk(Fcall *t, uchar *buf, Fid *f)
927{
928 Fid *prev, *p;
929 Dirtab *d;
930
931 qlock(&queue);
932 if(f->open){
933 d = f->dir;
934 d->nopen--;
935 if(d->qid==Qrules && (f->mode==OWRITE || f->mode==ORDWR)){
936 /*
937 * just to be sure last rule is parsed; error messages will be lost, though,
938 * unless last write ended with a blank line
939 */
940 writerules(nil, 0);
rsc32f69c32003-12-11 17:48:38 +0000941 lock(&rulesref.lk);
rscb8c14082003-11-23 17:58:26 +0000942 rulesref.ref--;
rsc32f69c32003-12-11 17:48:38 +0000943 unlock(&rulesref.lk);
rscb8c14082003-11-23 17:58:26 +0000944 }
945 prev = nil;
946 for(p=d->fopen; p; p=p->nextopen){
947 if(p == f){
948 if(prev)
949 prev->nextopen = f->nextopen;
950 else
951 d->fopen = f->nextopen;
952 removesenders(d, f);
953 break;
954 }
955 prev = p;
956 }
957 }
958 f->busy = 0;
959 f->open = 0;
960 f->offset = 0;
961 if(f->writebuf != nil){
962 free(f->writebuf);
963 f->writebuf = nil;
964 }
965 qunlock(&queue);
966 fsysrespond(t, buf, nil);
967 return t;
968}