17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <regexp.h>
57dd7cddfSDavid du Colombier #include <thread.h>
67dd7cddfSDavid du Colombier #include <auth.h>
77dd7cddfSDavid du Colombier #include <fcall.h>
87dd7cddfSDavid du Colombier #include <plumb.h>
97dd7cddfSDavid du Colombier #include "plumber.h"
107dd7cddfSDavid du Colombier
117dd7cddfSDavid du Colombier enum
127dd7cddfSDavid du Colombier {
13*da091934SDavid du Colombier Stack = 16*1024
147dd7cddfSDavid du Colombier };
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier typedef struct Dirtab Dirtab;
177dd7cddfSDavid du Colombier typedef struct Fid Fid;
187dd7cddfSDavid du Colombier typedef struct Holdq Holdq;
197dd7cddfSDavid du Colombier typedef struct Readreq Readreq;
207dd7cddfSDavid du Colombier typedef struct Sendreq Sendreq;
217dd7cddfSDavid du Colombier
227dd7cddfSDavid du Colombier struct Dirtab
237dd7cddfSDavid du Colombier {
247dd7cddfSDavid du Colombier char *name;
259a747e4fSDavid du Colombier uchar type;
267dd7cddfSDavid du Colombier uint qid;
277dd7cddfSDavid du Colombier uint perm;
287dd7cddfSDavid du Colombier int nopen; /* #fids open on this port */
297dd7cddfSDavid du Colombier Fid *fopen;
307dd7cddfSDavid du Colombier Holdq *holdq;
317dd7cddfSDavid du Colombier Readreq *readq;
327dd7cddfSDavid du Colombier Sendreq *sendq;
337dd7cddfSDavid du Colombier };
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier struct Fid
367dd7cddfSDavid du Colombier {
377dd7cddfSDavid du Colombier int fid;
387dd7cddfSDavid du Colombier int busy;
397dd7cddfSDavid du Colombier int open;
407dd7cddfSDavid du Colombier int mode;
417dd7cddfSDavid du Colombier Qid qid;
427dd7cddfSDavid du Colombier Dirtab *dir;
437dd7cddfSDavid du Colombier long offset; /* zeroed at beginning of each message, read or write */
447dd7cddfSDavid du Colombier char *writebuf; /* partial message written so far; offset tells how much */
457dd7cddfSDavid du Colombier Fid *next;
467dd7cddfSDavid du Colombier Fid *nextopen;
477dd7cddfSDavid du Colombier };
487dd7cddfSDavid du Colombier
497dd7cddfSDavid du Colombier struct Readreq
507dd7cddfSDavid du Colombier {
517dd7cddfSDavid du Colombier Fid *fid;
527dd7cddfSDavid du Colombier Fcall *fcall;
539a747e4fSDavid du Colombier uchar *buf;
547dd7cddfSDavid du Colombier Readreq *next;
557dd7cddfSDavid du Colombier };
567dd7cddfSDavid du Colombier
577dd7cddfSDavid du Colombier struct Sendreq
587dd7cddfSDavid du Colombier {
597dd7cddfSDavid du Colombier int nfid; /* number of fids that should receive this message */
607dd7cddfSDavid du Colombier int nleft; /* number left that haven't received it */
617dd7cddfSDavid du Colombier Fid **fid; /* fid[nfid] */
627dd7cddfSDavid du Colombier Plumbmsg *msg;
637dd7cddfSDavid du Colombier char *pack; /* plumbpack()ed message */
647dd7cddfSDavid du Colombier int npack; /* length of pack */
657dd7cddfSDavid du Colombier Sendreq *next;
667dd7cddfSDavid du Colombier };
677dd7cddfSDavid du Colombier
687dd7cddfSDavid du Colombier struct Holdq
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier Plumbmsg *msg;
717dd7cddfSDavid du Colombier Holdq *next;
727dd7cddfSDavid du Colombier };
737dd7cddfSDavid du Colombier
747dd7cddfSDavid du Colombier struct /* needed because incref() doesn't return value */
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier Lock;
777dd7cddfSDavid du Colombier int ref;
787dd7cddfSDavid du Colombier } rulesref;
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier enum
817dd7cddfSDavid du Colombier {
827dd7cddfSDavid du Colombier DEBUG = 0,
837dd7cddfSDavid du Colombier NDIR = 50,
847dd7cddfSDavid du Colombier Nhash = 16,
857dd7cddfSDavid du Colombier
867dd7cddfSDavid du Colombier Qdir = 0,
877dd7cddfSDavid du Colombier Qrules = 1,
887dd7cddfSDavid du Colombier Qsend = 2,
897dd7cddfSDavid du Colombier Qport = 3,
907dd7cddfSDavid du Colombier NQID = Qport
917dd7cddfSDavid du Colombier };
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier static Dirtab dir[NDIR] =
947dd7cddfSDavid du Colombier {
959a747e4fSDavid du Colombier { ".", QTDIR, Qdir, 0500|DMDIR },
969a747e4fSDavid du Colombier { "rules", QTFILE, Qrules, 0600 },
979a747e4fSDavid du Colombier { "send", QTFILE, Qsend, 0200 },
987dd7cddfSDavid du Colombier };
997dd7cddfSDavid du Colombier static int ndir = NQID;
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier static int srvfd;
1029a747e4fSDavid du Colombier static int srvclosefd; /* rock for end of pipe to close */
1037dd7cddfSDavid du Colombier static int clockfd;
1047dd7cddfSDavid du Colombier static int clock;
1057dd7cddfSDavid du Colombier static Fid *fids[Nhash];
1067dd7cddfSDavid du Colombier static QLock readlock;
1077dd7cddfSDavid du Colombier static QLock queue;
1087dd7cddfSDavid du Colombier static char srvfile[128];
1099a747e4fSDavid du Colombier static int messagesize = 8192+IOHDRSZ; /* good start */
1107dd7cddfSDavid du Colombier
1117dd7cddfSDavid du Colombier static void fsysproc(void*);
1129a747e4fSDavid du Colombier static void fsysrespond(Fcall*, uchar*, char*);
1137dd7cddfSDavid du Colombier static Fid* newfid(int);
1147dd7cddfSDavid du Colombier
1159a747e4fSDavid du Colombier static Fcall* fsysflush(Fcall*, uchar*, Fid*);
1169a747e4fSDavid du Colombier static Fcall* fsysversion(Fcall*, uchar*, Fid*);
1179a747e4fSDavid du Colombier static Fcall* fsysauth(Fcall*, uchar*, Fid*);
1189a747e4fSDavid du Colombier static Fcall* fsysattach(Fcall*, uchar*, Fid*);
1199a747e4fSDavid du Colombier static Fcall* fsyswalk(Fcall*, uchar*, Fid*);
1209a747e4fSDavid du Colombier static Fcall* fsysopen(Fcall*, uchar*, Fid*);
1219a747e4fSDavid du Colombier static Fcall* fsyscreate(Fcall*, uchar*, Fid*);
1229a747e4fSDavid du Colombier static Fcall* fsysread(Fcall*, uchar*, Fid*);
1239a747e4fSDavid du Colombier static Fcall* fsyswrite(Fcall*, uchar*, Fid*);
1249a747e4fSDavid du Colombier static Fcall* fsysclunk(Fcall*, uchar*, Fid*);
1259a747e4fSDavid du Colombier static Fcall* fsysremove(Fcall*, uchar*, Fid*);
1269a747e4fSDavid du Colombier static Fcall* fsysstat(Fcall*, uchar*, Fid*);
1279a747e4fSDavid du Colombier static Fcall* fsyswstat(Fcall*, uchar*, Fid*);
1287dd7cddfSDavid du Colombier
1299a747e4fSDavid du Colombier Fcall* (*fcall[Tmax])(Fcall*, uchar*, Fid*) =
1307dd7cddfSDavid du Colombier {
1317dd7cddfSDavid du Colombier [Tflush] = fsysflush,
1329a747e4fSDavid du Colombier [Tversion] = fsysversion,
1339a747e4fSDavid du Colombier [Tauth] = fsysauth,
1347dd7cddfSDavid du Colombier [Tattach] = fsysattach,
1357dd7cddfSDavid du Colombier [Twalk] = fsyswalk,
1367dd7cddfSDavid du Colombier [Topen] = fsysopen,
1377dd7cddfSDavid du Colombier [Tcreate] = fsyscreate,
1387dd7cddfSDavid du Colombier [Tread] = fsysread,
1397dd7cddfSDavid du Colombier [Twrite] = fsyswrite,
1407dd7cddfSDavid du Colombier [Tclunk] = fsysclunk,
1417dd7cddfSDavid du Colombier [Tremove]= fsysremove,
1427dd7cddfSDavid du Colombier [Tstat] = fsysstat,
1437dd7cddfSDavid du Colombier [Twstat] = fsyswstat,
1447dd7cddfSDavid du Colombier };
1457dd7cddfSDavid du Colombier
1467dd7cddfSDavid du Colombier char Ebadfcall[] = "bad fcall type";
1477dd7cddfSDavid du Colombier char Eperm[] = "permission denied";
1487dd7cddfSDavid du Colombier char Enomem[] = "malloc failed for buffer";
1497dd7cddfSDavid du Colombier char Enotdir[] = "not a directory";
1507dd7cddfSDavid du Colombier char Enoexist[] = "plumb file does not exist";
1517dd7cddfSDavid du Colombier char Eisdir[] = "file is a directory";
1527dd7cddfSDavid du Colombier char Ebadmsg[] = "bad plumb message format";
1537dd7cddfSDavid du Colombier char Enosuchport[] ="no such plumb port";
1547dd7cddfSDavid du Colombier char Enoport[] = "couldn't find destination for message";
1557dd7cddfSDavid du Colombier char Einuse[] = "file already open";
1567dd7cddfSDavid du Colombier
1577dd7cddfSDavid du Colombier /*
1587dd7cddfSDavid du Colombier * Add new port. A no-op if port already exists or is the null string
1597dd7cddfSDavid du Colombier */
1607dd7cddfSDavid du Colombier void
addport(char * port)1617dd7cddfSDavid du Colombier addport(char *port)
1627dd7cddfSDavid du Colombier {
1637dd7cddfSDavid du Colombier int i;
1647dd7cddfSDavid du Colombier
1657dd7cddfSDavid du Colombier if(port == nil)
1667dd7cddfSDavid du Colombier return;
1677dd7cddfSDavid du Colombier for(i=NQID; i<ndir; i++)
1687dd7cddfSDavid du Colombier if(strcmp(port, dir[i].name) == 0)
1697dd7cddfSDavid du Colombier return;
1707dd7cddfSDavid du Colombier if(i == NDIR){
1717dd7cddfSDavid du Colombier fprint(2, "plumb: too many ports; max %d\n", NDIR);
1727dd7cddfSDavid du Colombier return;
1737dd7cddfSDavid du Colombier }
1747dd7cddfSDavid du Colombier ndir++;
1757dd7cddfSDavid du Colombier dir[i].name = estrdup(port);
1767dd7cddfSDavid du Colombier dir[i].qid = i;
1777dd7cddfSDavid du Colombier dir[i].perm = 0400;
1787dd7cddfSDavid du Colombier nports++;
1797dd7cddfSDavid du Colombier ports = erealloc(ports, nports*sizeof(char*));
1807dd7cddfSDavid du Colombier ports[nports-1] = dir[i].name;
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier static ulong
getclock(void)1847dd7cddfSDavid du Colombier getclock(void)
1857dd7cddfSDavid du Colombier {
1867dd7cddfSDavid du Colombier char buf[32];
1877dd7cddfSDavid du Colombier
1887dd7cddfSDavid du Colombier seek(clockfd, 0, 0);
1897dd7cddfSDavid du Colombier read(clockfd, buf, sizeof buf);
1907dd7cddfSDavid du Colombier return atoi(buf);
1917dd7cddfSDavid du Colombier }
1927dd7cddfSDavid du Colombier
1937dd7cddfSDavid du Colombier void
startfsys(void)1949a747e4fSDavid du Colombier startfsys(void)
1957dd7cddfSDavid du Colombier {
1967dd7cddfSDavid du Colombier int p[2], fd;
1977dd7cddfSDavid du Colombier
1989a747e4fSDavid du Colombier fmtinstall('F', fcallfmt);
1997dd7cddfSDavid du Colombier clockfd = open("/dev/time", OREAD|OCEXEC);
2007dd7cddfSDavid du Colombier clock = getclock();
2017dd7cddfSDavid du Colombier if(pipe(p) < 0)
2027dd7cddfSDavid du Colombier error("can't create pipe: %r");
2037dd7cddfSDavid du Colombier /* 0 will be server end, 1 will be client end */
2047dd7cddfSDavid du Colombier srvfd = p[0];
2059a747e4fSDavid du Colombier srvclosefd = p[1];
2067dd7cddfSDavid du Colombier sprint(srvfile, "/srv/plumb.%s.%d", user, getpid());
2077dd7cddfSDavid du Colombier if(putenv("plumbsrv", srvfile) < 0)
2087dd7cddfSDavid du Colombier error("can't write $plumbsrv: %r");
2097dd7cddfSDavid du Colombier fd = create(srvfile, OWRITE|OCEXEC|ORCLOSE, 0600);
2107dd7cddfSDavid du Colombier if(fd < 0)
2117dd7cddfSDavid du Colombier error("can't create /srv file: %r");
2129a747e4fSDavid du Colombier if(fprint(fd, "%d", p[1]) <= 0)
2137dd7cddfSDavid du Colombier error("can't write /srv/file: %r");
2147dd7cddfSDavid du Colombier /* leave fd open; ORCLOSE will take care of it */
2157dd7cddfSDavid du Colombier
2169a747e4fSDavid du Colombier procrfork(fsysproc, nil, Stack, RFFDG);
2177dd7cddfSDavid du Colombier
2187dd7cddfSDavid du Colombier close(p[0]);
2199a747e4fSDavid du Colombier if(mount(p[1], -1, "/mnt/plumb", MREPL, "") < 0)
2207dd7cddfSDavid du Colombier error("can't mount /mnt/plumb: %r");
2217dd7cddfSDavid du Colombier close(p[1]);
2227dd7cddfSDavid du Colombier }
2237dd7cddfSDavid du Colombier
2247dd7cddfSDavid du Colombier static void
fsysproc(void *)2257dd7cddfSDavid du Colombier fsysproc(void*)
2267dd7cddfSDavid du Colombier {
2277dd7cddfSDavid du Colombier int n;
2287dd7cddfSDavid du Colombier Fcall *t;
2297dd7cddfSDavid du Colombier Fid *f;
2309a747e4fSDavid du Colombier uchar *buf;
2317dd7cddfSDavid du Colombier
2329a747e4fSDavid du Colombier close(srvclosefd);
2339a747e4fSDavid du Colombier srvclosefd = -1;
2347dd7cddfSDavid du Colombier t = nil;
2357dd7cddfSDavid du Colombier for(;;){
2369a747e4fSDavid du Colombier buf = malloc(messagesize); /* avoid memset of emalloc */
2377dd7cddfSDavid du Colombier if(buf == nil)
2387dd7cddfSDavid du Colombier error("malloc failed: %r");
2397dd7cddfSDavid du Colombier qlock(&readlock);
2409a747e4fSDavid du Colombier n = read9pmsg(srvfd, buf, messagesize);
2419a747e4fSDavid du Colombier if(n <= 0){
2429a747e4fSDavid du Colombier if(n < 0)
2437dd7cddfSDavid du Colombier error("i/o error on server channel");
2449a747e4fSDavid du Colombier threadexitsall("unmounted");
2459a747e4fSDavid du Colombier }
2467dd7cddfSDavid du Colombier if(readlock.head == nil) /* no other processes waiting to read; start one */
2477dd7cddfSDavid du Colombier proccreate(fsysproc, nil, Stack);
2487dd7cddfSDavid du Colombier qunlock(&readlock);
2497dd7cddfSDavid du Colombier if(t == nil)
2507dd7cddfSDavid du Colombier t = emalloc(sizeof(Fcall));
2519a747e4fSDavid du Colombier if(convM2S(buf, n, t) != n)
2527dd7cddfSDavid du Colombier error("convert error in convM2S");
2537dd7cddfSDavid du Colombier if(DEBUG)
2549a747e4fSDavid du Colombier fprint(2, "<= %F\n", t);
2557dd7cddfSDavid du Colombier if(fcall[t->type] == nil)
2567dd7cddfSDavid du Colombier fsysrespond(t, buf, Ebadfcall);
2577dd7cddfSDavid du Colombier else{
2589a747e4fSDavid du Colombier if(t->type==Tversion || t->type==Tauth)
2597dd7cddfSDavid du Colombier f = nil;
2607dd7cddfSDavid du Colombier else
2617dd7cddfSDavid du Colombier f = newfid(t->fid);
2627dd7cddfSDavid du Colombier t = (*fcall[t->type])(t, buf, f);
2637dd7cddfSDavid du Colombier }
2647dd7cddfSDavid du Colombier }
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier
2677dd7cddfSDavid du Colombier static void
fsysrespond(Fcall * t,uchar * buf,char * err)2689a747e4fSDavid du Colombier fsysrespond(Fcall *t, uchar *buf, char *err)
2697dd7cddfSDavid du Colombier {
2707dd7cddfSDavid du Colombier int n;
2717dd7cddfSDavid du Colombier
2727dd7cddfSDavid du Colombier if(err){
2737dd7cddfSDavid du Colombier t->type = Rerror;
2749a747e4fSDavid du Colombier t->ename = err;
2757dd7cddfSDavid du Colombier }else
2767dd7cddfSDavid du Colombier t->type++;
2777dd7cddfSDavid du Colombier if(buf == nil)
2789a747e4fSDavid du Colombier buf = emalloc(messagesize);
2799a747e4fSDavid du Colombier n = convS2M(t, buf, messagesize);
2807dd7cddfSDavid du Colombier if(n < 0)
2817dd7cddfSDavid du Colombier error("convert error in convS2M");
2827dd7cddfSDavid du Colombier if(write(srvfd, buf, n) != n)
2837dd7cddfSDavid du Colombier error("write error in respond");
2847dd7cddfSDavid du Colombier if(DEBUG)
2859a747e4fSDavid du Colombier fprint(2, "=> %F\n", t);
2867dd7cddfSDavid du Colombier free(buf);
2877dd7cddfSDavid du Colombier }
2887dd7cddfSDavid du Colombier
2897dd7cddfSDavid du Colombier static
2907dd7cddfSDavid du Colombier Fid*
newfid(int fid)2917dd7cddfSDavid du Colombier newfid(int fid)
2927dd7cddfSDavid du Colombier {
2937dd7cddfSDavid du Colombier Fid *f, *ff, **fh;
2947dd7cddfSDavid du Colombier
2957dd7cddfSDavid du Colombier qlock(&queue);
2967dd7cddfSDavid du Colombier ff = nil;
2977dd7cddfSDavid du Colombier fh = &fids[fid&(Nhash-1)];
2987dd7cddfSDavid du Colombier for(f=*fh; f; f=f->next)
2997dd7cddfSDavid du Colombier if(f->fid == fid)
3007dd7cddfSDavid du Colombier goto Return;
3017dd7cddfSDavid du Colombier else if(ff==nil && !f->busy)
3027dd7cddfSDavid du Colombier ff = f;
3037dd7cddfSDavid du Colombier if(ff){
3047dd7cddfSDavid du Colombier ff->fid = fid;
3057dd7cddfSDavid du Colombier f = ff;
3067dd7cddfSDavid du Colombier goto Return;
3077dd7cddfSDavid du Colombier }
3087dd7cddfSDavid du Colombier f = emalloc(sizeof *f);
3097dd7cddfSDavid du Colombier f->fid = fid;
3107dd7cddfSDavid du Colombier f->next = *fh;
3117dd7cddfSDavid du Colombier *fh = f;
3127dd7cddfSDavid du Colombier Return:
3137dd7cddfSDavid du Colombier qunlock(&queue);
3147dd7cddfSDavid du Colombier return f;
3157dd7cddfSDavid du Colombier }
3167dd7cddfSDavid du Colombier
3179a747e4fSDavid du Colombier static uint
dostat(Dirtab * dir,uchar * buf,uint nbuf,uint clock)3189a747e4fSDavid du Colombier dostat(Dirtab *dir, uchar *buf, uint nbuf, uint clock)
3197dd7cddfSDavid du Colombier {
3207dd7cddfSDavid du Colombier Dir d;
3217dd7cddfSDavid du Colombier
3229a747e4fSDavid du Colombier d.qid.type = dir->type;
3237dd7cddfSDavid du Colombier d.qid.path = dir->qid;
3247dd7cddfSDavid du Colombier d.qid.vers = 0;
3257dd7cddfSDavid du Colombier d.mode = dir->perm;
3267dd7cddfSDavid du Colombier d.length = 0; /* would be nice to do better */
3279a747e4fSDavid du Colombier d.name = dir->name;
3289a747e4fSDavid du Colombier d.uid = user;
3299a747e4fSDavid du Colombier d.gid = user;
3309a747e4fSDavid du Colombier d.muid = user;
3317dd7cddfSDavid du Colombier d.atime = clock;
3327dd7cddfSDavid du Colombier d.mtime = clock;
3339a747e4fSDavid du Colombier return convD2M(&d, buf, nbuf);
3347dd7cddfSDavid du Colombier }
3357dd7cddfSDavid du Colombier
3367dd7cddfSDavid du Colombier static void
queuesend(Dirtab * d,Plumbmsg * m)3377dd7cddfSDavid du Colombier queuesend(Dirtab *d, Plumbmsg *m)
3387dd7cddfSDavid du Colombier {
3397dd7cddfSDavid du Colombier Sendreq *s, *t;
3407dd7cddfSDavid du Colombier Fid *f;
3417dd7cddfSDavid du Colombier int i;
3427dd7cddfSDavid du Colombier
3437dd7cddfSDavid du Colombier s = emalloc(sizeof(Sendreq));
3447dd7cddfSDavid du Colombier s->nfid = d->nopen;
3457dd7cddfSDavid du Colombier s->nleft = s->nfid;
3467dd7cddfSDavid du Colombier s->fid = emalloc(s->nfid*sizeof(Fid*));
3477dd7cddfSDavid du Colombier i = 0;
3487dd7cddfSDavid du Colombier /* build array of fids open on this channel */
3497dd7cddfSDavid du Colombier for(f=d->fopen; f!=nil; f=f->nextopen)
3507dd7cddfSDavid du Colombier s->fid[i++] = f;
3517dd7cddfSDavid du Colombier s->msg = m;
3527dd7cddfSDavid du Colombier s->next = nil;
3537dd7cddfSDavid du Colombier /* link to end of queue; drainqueue() searches in sender order so this implements a FIFO */
3547dd7cddfSDavid du Colombier for(t=d->sendq; t!=nil; t=t->next)
3557dd7cddfSDavid du Colombier if(t->next == nil)
3567dd7cddfSDavid du Colombier break;
3577dd7cddfSDavid du Colombier if(t == nil)
3587dd7cddfSDavid du Colombier d->sendq = s;
3597dd7cddfSDavid du Colombier else
3607dd7cddfSDavid du Colombier t->next = s;
3617dd7cddfSDavid du Colombier }
3627dd7cddfSDavid du Colombier
3637dd7cddfSDavid du Colombier static void
queueread(Dirtab * d,Fcall * t,uchar * buf,Fid * f)3649a747e4fSDavid du Colombier queueread(Dirtab *d, Fcall *t, uchar *buf, Fid *f)
3657dd7cddfSDavid du Colombier {
3667dd7cddfSDavid du Colombier Readreq *r;
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier r = emalloc(sizeof(Readreq));
3697dd7cddfSDavid du Colombier r->fcall = t;
3707dd7cddfSDavid du Colombier r->buf = buf;
3717dd7cddfSDavid du Colombier r->fid = f;
3727dd7cddfSDavid du Colombier r->next = d->readq;
3737dd7cddfSDavid du Colombier d->readq = r;
3747dd7cddfSDavid du Colombier }
3757dd7cddfSDavid du Colombier
3767dd7cddfSDavid du Colombier static void
drainqueue(Dirtab * d)3777dd7cddfSDavid du Colombier drainqueue(Dirtab *d)
3787dd7cddfSDavid du Colombier {
3797dd7cddfSDavid du Colombier Readreq *r, *nextr, *prevr;
3807dd7cddfSDavid du Colombier Sendreq *s, *nexts, *prevs;
3817dd7cddfSDavid du Colombier int i, n;
3827dd7cddfSDavid du Colombier
3837dd7cddfSDavid du Colombier prevs = nil;
3847dd7cddfSDavid du Colombier for(s=d->sendq; s!=nil; s=nexts){
3857dd7cddfSDavid du Colombier nexts = s->next;
3867dd7cddfSDavid du Colombier for(i=0; i<s->nfid; i++){
3877dd7cddfSDavid du Colombier prevr = nil;
3887dd7cddfSDavid du Colombier for(r=d->readq; r!=nil; r=nextr){
3897dd7cddfSDavid du Colombier nextr = r->next;
3907dd7cddfSDavid du Colombier if(r->fid == s->fid[i]){
3917dd7cddfSDavid du Colombier /* pack the message if necessary */
3927dd7cddfSDavid du Colombier if(s->pack == nil)
3937dd7cddfSDavid du Colombier s->pack = plumbpack(s->msg, &s->npack);
3947dd7cddfSDavid du Colombier /* exchange the stuff... */
3957dd7cddfSDavid du Colombier r->fcall->data = s->pack+r->fid->offset;
3967dd7cddfSDavid du Colombier n = s->npack - r->fid->offset;
3979a747e4fSDavid du Colombier if(n > messagesize-IOHDRSZ)
3989a747e4fSDavid du Colombier n = messagesize-IOHDRSZ;
3997dd7cddfSDavid du Colombier if(n > r->fcall->count)
4007dd7cddfSDavid du Colombier n = r->fcall->count;
4017dd7cddfSDavid du Colombier r->fcall->count = n;
4027dd7cddfSDavid du Colombier fsysrespond(r->fcall, r->buf, nil);
4037dd7cddfSDavid du Colombier r->fid->offset += n;
4047dd7cddfSDavid du Colombier if(r->fid->offset >= s->npack){
4057dd7cddfSDavid du Colombier /* message transferred; delete this fid from send queue */
4067dd7cddfSDavid du Colombier r->fid->offset = 0;
4077dd7cddfSDavid du Colombier s->fid[i] = nil;
4087dd7cddfSDavid du Colombier s->nleft--;
4097dd7cddfSDavid du Colombier }
4107dd7cddfSDavid du Colombier /* delete read request from queue */
4117dd7cddfSDavid du Colombier if(prevr)
4127dd7cddfSDavid du Colombier prevr->next = r->next;
4137dd7cddfSDavid du Colombier else
4147dd7cddfSDavid du Colombier d->readq = r->next;
4157dd7cddfSDavid du Colombier free(r->fcall);
4167dd7cddfSDavid du Colombier free(r);
4177dd7cddfSDavid du Colombier break;
4187dd7cddfSDavid du Colombier }else
4197dd7cddfSDavid du Colombier prevr = r;
4207dd7cddfSDavid du Colombier }
4217dd7cddfSDavid du Colombier }
4227dd7cddfSDavid du Colombier /* if no fids left, delete this send from queue */
4237dd7cddfSDavid du Colombier if(s->nleft == 0){
4247dd7cddfSDavid du Colombier free(s->fid);
4257dd7cddfSDavid du Colombier plumbfree(s->msg);
4267dd7cddfSDavid du Colombier free(s->pack);
4277dd7cddfSDavid du Colombier if(prevs)
4287dd7cddfSDavid du Colombier prevs->next = s->next;
4297dd7cddfSDavid du Colombier else
4307dd7cddfSDavid du Colombier d->sendq = s->next;
4317dd7cddfSDavid du Colombier free(s);
4327dd7cddfSDavid du Colombier }else
4337dd7cddfSDavid du Colombier prevs = s;
4347dd7cddfSDavid du Colombier }
4357dd7cddfSDavid du Colombier }
4367dd7cddfSDavid du Colombier
4377dd7cddfSDavid du Colombier /* can't flush a send because they are always answered synchronously */
4387dd7cddfSDavid du Colombier static void
flushqueue(Dirtab * d,int oldtag)4397dd7cddfSDavid du Colombier flushqueue(Dirtab *d, int oldtag)
4407dd7cddfSDavid du Colombier {
4417dd7cddfSDavid du Colombier Readreq *r, *prevr;
4427dd7cddfSDavid du Colombier
4437dd7cddfSDavid du Colombier prevr = nil;
4447dd7cddfSDavid du Colombier for(r=d->readq; r!=nil; r=r->next){
4457dd7cddfSDavid du Colombier if(oldtag == r->fcall->tag){
4467dd7cddfSDavid du Colombier /* delete read request from queue */
4477dd7cddfSDavid du Colombier if(prevr)
4487dd7cddfSDavid du Colombier prevr->next = r->next;
4497dd7cddfSDavid du Colombier else
4507dd7cddfSDavid du Colombier d->readq = r->next;
4517dd7cddfSDavid du Colombier free(r->fcall);
45280ee5cbfSDavid du Colombier free(r->buf);
4537dd7cddfSDavid du Colombier free(r);
4547dd7cddfSDavid du Colombier return;
4557dd7cddfSDavid du Colombier }
4567dd7cddfSDavid du Colombier prevr = r;
4577dd7cddfSDavid du Colombier }
4587dd7cddfSDavid du Colombier }
4597dd7cddfSDavid du Colombier
4607dd7cddfSDavid du Colombier /* remove messages awaiting delivery to now-closing fid */
4617dd7cddfSDavid du Colombier static void
removesenders(Dirtab * d,Fid * fid)4627dd7cddfSDavid du Colombier removesenders(Dirtab *d, Fid *fid)
4637dd7cddfSDavid du Colombier {
4647dd7cddfSDavid du Colombier Sendreq *s, *nexts, *prevs;
4657dd7cddfSDavid du Colombier int i;
4667dd7cddfSDavid du Colombier
4677dd7cddfSDavid du Colombier prevs = nil;
4687dd7cddfSDavid du Colombier for(s=d->sendq; s!=nil; s=nexts){
4697dd7cddfSDavid du Colombier nexts = s->next;
4707dd7cddfSDavid du Colombier for(i=0; i<s->nfid; i++)
4717dd7cddfSDavid du Colombier if(fid == s->fid[i]){
4727dd7cddfSDavid du Colombier /* delete this fid from send queue */
4737dd7cddfSDavid du Colombier s->fid[i] = nil;
4747dd7cddfSDavid du Colombier s->nleft--;
4757dd7cddfSDavid du Colombier break;
4767dd7cddfSDavid du Colombier }
4777dd7cddfSDavid du Colombier /* if no fids left, delete this send from queue */
4787dd7cddfSDavid du Colombier if(s->nleft == 0){
4797dd7cddfSDavid du Colombier free(s->fid);
4807dd7cddfSDavid du Colombier plumbfree(s->msg);
4817dd7cddfSDavid du Colombier free(s->pack);
4827dd7cddfSDavid du Colombier if(prevs)
4837dd7cddfSDavid du Colombier prevs->next = s->next;
4847dd7cddfSDavid du Colombier else
4857dd7cddfSDavid du Colombier d->sendq = s->next;
4867dd7cddfSDavid du Colombier free(s);
4877dd7cddfSDavid du Colombier }else
4887dd7cddfSDavid du Colombier prevs = s;
4897dd7cddfSDavid du Colombier }
4907dd7cddfSDavid du Colombier }
4917dd7cddfSDavid du Colombier
4927dd7cddfSDavid du Colombier static void
hold(Plumbmsg * m,Dirtab * d)4937dd7cddfSDavid du Colombier hold(Plumbmsg *m, Dirtab *d)
4947dd7cddfSDavid du Colombier {
4957dd7cddfSDavid du Colombier Holdq *h, *q;
4967dd7cddfSDavid du Colombier
4977dd7cddfSDavid du Colombier h = emalloc(sizeof(Holdq));
4987dd7cddfSDavid du Colombier h->msg = m;
4997dd7cddfSDavid du Colombier /* add to end of queue */
5007dd7cddfSDavid du Colombier if(d->holdq == nil)
5017dd7cddfSDavid du Colombier d->holdq = h;
5027dd7cddfSDavid du Colombier else{
5037dd7cddfSDavid du Colombier for(q=d->holdq; q->next!=nil; q=q->next)
5047dd7cddfSDavid du Colombier ;
5057dd7cddfSDavid du Colombier q->next = h;
5067dd7cddfSDavid du Colombier }
5077dd7cddfSDavid du Colombier }
5087dd7cddfSDavid du Colombier
5097dd7cddfSDavid du Colombier static void
queueheld(Dirtab * d)5107dd7cddfSDavid du Colombier queueheld(Dirtab *d)
5117dd7cddfSDavid du Colombier {
5127dd7cddfSDavid du Colombier Holdq *h;
5137dd7cddfSDavid du Colombier
5147dd7cddfSDavid du Colombier while(d->holdq != nil){
5157dd7cddfSDavid du Colombier h = d->holdq;
5167dd7cddfSDavid du Colombier d->holdq = h->next;
5177dd7cddfSDavid du Colombier queuesend(d, h->msg);
5187dd7cddfSDavid du Colombier /* no need to drain queue because we know no-one is reading yet */
5197dd7cddfSDavid du Colombier free(h);
5207dd7cddfSDavid du Colombier }
5217dd7cddfSDavid du Colombier }
5227dd7cddfSDavid du Colombier
5237dd7cddfSDavid du Colombier static void
dispose(Fcall * t,uchar * buf,Plumbmsg * m,Ruleset * rs,Exec * e)5249a747e4fSDavid du Colombier dispose(Fcall *t, uchar *buf, Plumbmsg *m, Ruleset *rs, Exec *e)
5257dd7cddfSDavid du Colombier {
5267dd7cddfSDavid du Colombier int i;
5277dd7cddfSDavid du Colombier char *err;
5287dd7cddfSDavid du Colombier
5297dd7cddfSDavid du Colombier qlock(&queue);
5307dd7cddfSDavid du Colombier err = nil;
5317dd7cddfSDavid du Colombier if(m->dst==nil || m->dst[0]=='\0'){
5327dd7cddfSDavid du Colombier err = Enoport;
5337dd7cddfSDavid du Colombier if(rs != nil)
5347dd7cddfSDavid du Colombier err = startup(rs, e);
5357dd7cddfSDavid du Colombier plumbfree(m);
5367dd7cddfSDavid du Colombier }else
5377dd7cddfSDavid du Colombier for(i=NQID; i<ndir; i++)
5387dd7cddfSDavid du Colombier if(strcmp(m->dst, dir[i].name) == 0){
5397dd7cddfSDavid du Colombier if(dir[i].nopen == 0){
5407dd7cddfSDavid du Colombier err = startup(rs, e);
5417dd7cddfSDavid du Colombier if(e!=nil && e->holdforclient)
5427dd7cddfSDavid du Colombier hold(m, &dir[i]);
5437dd7cddfSDavid du Colombier else
5447dd7cddfSDavid du Colombier plumbfree(m);
5457dd7cddfSDavid du Colombier }else{
5467dd7cddfSDavid du Colombier queuesend(&dir[i], m);
5477dd7cddfSDavid du Colombier drainqueue(&dir[i]);
5487dd7cddfSDavid du Colombier }
5497dd7cddfSDavid du Colombier break;
5507dd7cddfSDavid du Colombier }
5517dd7cddfSDavid du Colombier freeexec(e);
5527dd7cddfSDavid du Colombier qunlock(&queue);
5537dd7cddfSDavid du Colombier fsysrespond(t, buf, err);
5547dd7cddfSDavid du Colombier free(t);
5557dd7cddfSDavid du Colombier }
5567dd7cddfSDavid du Colombier
5577dd7cddfSDavid du Colombier static Fcall*
fsysversion(Fcall * t,uchar * buf,Fid *)5589a747e4fSDavid du Colombier fsysversion(Fcall *t, uchar *buf, Fid*)
5597dd7cddfSDavid du Colombier {
5609a747e4fSDavid du Colombier if(t->msize < 256){
5619a747e4fSDavid du Colombier fsysrespond(t, buf, "version: message size too small");
5629a747e4fSDavid du Colombier return t;
5639a747e4fSDavid du Colombier }
5649a747e4fSDavid du Colombier if(t->msize < messagesize)
5659a747e4fSDavid du Colombier messagesize = t->msize;
5669a747e4fSDavid du Colombier t->msize = messagesize;
5679a747e4fSDavid du Colombier if(strncmp(t->version, "9P2000", 6) != 0){
5689a747e4fSDavid du Colombier fsysrespond(t, buf, "unrecognized 9P version");
5699a747e4fSDavid du Colombier return t;
5709a747e4fSDavid du Colombier }
5719a747e4fSDavid du Colombier t->version = "9P2000";
5727dd7cddfSDavid du Colombier fsysrespond(t, buf, nil);
5737dd7cddfSDavid du Colombier return t;
5747dd7cddfSDavid du Colombier }
5757dd7cddfSDavid du Colombier
5767dd7cddfSDavid du Colombier static Fcall*
fsysauth(Fcall * t,uchar * buf,Fid *)5779a747e4fSDavid du Colombier fsysauth(Fcall *t, uchar *buf, Fid*)
5787dd7cddfSDavid du Colombier {
5799a747e4fSDavid du Colombier fsysrespond(t, buf, "plumber: authentication not required");
5807dd7cddfSDavid du Colombier return t;
5817dd7cddfSDavid du Colombier }
5827dd7cddfSDavid du Colombier
5837dd7cddfSDavid du Colombier static Fcall*
fsysattach(Fcall * t,uchar * buf,Fid * f)5849a747e4fSDavid du Colombier fsysattach(Fcall *t, uchar *buf, Fid *f)
5857dd7cddfSDavid du Colombier {
5867dd7cddfSDavid du Colombier Fcall out;
5877dd7cddfSDavid du Colombier
5887dd7cddfSDavid du Colombier if(strcmp(t->uname, user) != 0){
5897dd7cddfSDavid du Colombier fsysrespond(&out, buf, Eperm);
5907dd7cddfSDavid du Colombier return t;
5917dd7cddfSDavid du Colombier }
5927dd7cddfSDavid du Colombier f->busy = 1;
5937dd7cddfSDavid du Colombier f->open = 0;
5949a747e4fSDavid du Colombier f->qid.type = QTDIR;
5959a747e4fSDavid du Colombier f->qid.path = Qdir;
5969a747e4fSDavid du Colombier f->qid.vers = 0;
5977dd7cddfSDavid du Colombier f->dir = dir;
5987dd7cddfSDavid du Colombier memset(&out, 0, sizeof(Fcall));
5997dd7cddfSDavid du Colombier out.type = t->type;
6007dd7cddfSDavid du Colombier out.tag = t->tag;
6017dd7cddfSDavid du Colombier out.fid = f->fid;
6027dd7cddfSDavid du Colombier out.qid = f->qid;
6037dd7cddfSDavid du Colombier fsysrespond(&out, buf, nil);
6047dd7cddfSDavid du Colombier return t;
6057dd7cddfSDavid du Colombier }
6067dd7cddfSDavid du Colombier
6077dd7cddfSDavid du Colombier static Fcall*
fsysflush(Fcall * t,uchar * buf,Fid *)6089a747e4fSDavid du Colombier fsysflush(Fcall *t, uchar *buf, Fid*)
6097dd7cddfSDavid du Colombier {
6107dd7cddfSDavid du Colombier int i;
6117dd7cddfSDavid du Colombier
6127dd7cddfSDavid du Colombier qlock(&queue);
6137dd7cddfSDavid du Colombier for(i=NQID; i<ndir; i++)
6147dd7cddfSDavid du Colombier flushqueue(&dir[i], t->oldtag);
6157dd7cddfSDavid du Colombier qunlock(&queue);
6167dd7cddfSDavid du Colombier fsysrespond(t, buf, nil);
6177dd7cddfSDavid du Colombier return t;
6187dd7cddfSDavid du Colombier }
6197dd7cddfSDavid du Colombier
6207dd7cddfSDavid du Colombier static Fcall*
fsyswalk(Fcall * t,uchar * buf,Fid * f)6219a747e4fSDavid du Colombier fsyswalk(Fcall *t, uchar *buf, Fid *f)
6227dd7cddfSDavid du Colombier {
6239a747e4fSDavid du Colombier Fcall out;
6247dd7cddfSDavid du Colombier Fid *nf;
6259a747e4fSDavid du Colombier ulong path;
6269a747e4fSDavid du Colombier Dirtab *d, *dir;
6279a747e4fSDavid du Colombier Qid q;
6289a747e4fSDavid du Colombier int i;
6299a747e4fSDavid du Colombier uchar type;
6309a747e4fSDavid du Colombier char *err;
6317dd7cddfSDavid du Colombier
6327dd7cddfSDavid du Colombier if(f->open){
6339a747e4fSDavid du Colombier fsysrespond(t, buf, "clone of an open fid");
6347dd7cddfSDavid du Colombier return t;
6357dd7cddfSDavid du Colombier }
6369a747e4fSDavid du Colombier
6379a747e4fSDavid du Colombier nf = nil;
6389a747e4fSDavid du Colombier if(t->fid != t->newfid){
6397dd7cddfSDavid du Colombier nf = newfid(t->newfid);
6409a747e4fSDavid du Colombier if(nf->busy){
6419a747e4fSDavid du Colombier fsysrespond(t, buf, "clone to a busy fid");
6429a747e4fSDavid du Colombier return t;
6439a747e4fSDavid du Colombier }
6447dd7cddfSDavid du Colombier nf->busy = 1;
6457dd7cddfSDavid du Colombier nf->open = 0;
6467dd7cddfSDavid du Colombier nf->dir = f->dir;
6477dd7cddfSDavid du Colombier nf->qid = f->qid;
6489a747e4fSDavid du Colombier f = nf; /* walk f */
6497dd7cddfSDavid du Colombier }
6507dd7cddfSDavid du Colombier
6519a747e4fSDavid du Colombier out.nwqid = 0;
6529a747e4fSDavid du Colombier err = nil;
6539a747e4fSDavid du Colombier dir = f->dir;
6549a747e4fSDavid du Colombier q = f->qid;
6557dd7cddfSDavid du Colombier
6569a747e4fSDavid du Colombier if(t->nwname > 0){
6579a747e4fSDavid du Colombier for(i=0; i<t->nwname; i++){
6589a747e4fSDavid du Colombier if((q.type & QTDIR) == 0){
6599a747e4fSDavid du Colombier err = Enotdir;
6609a747e4fSDavid du Colombier break;
6617dd7cddfSDavid du Colombier }
6629a747e4fSDavid du Colombier if(strcmp(t->wname[i], "..") == 0){
6639a747e4fSDavid du Colombier type = QTDIR;
6649a747e4fSDavid du Colombier path = Qdir;
6659a747e4fSDavid du Colombier Accept:
6669a747e4fSDavid du Colombier q.type = type;
6679a747e4fSDavid du Colombier q.vers = 0;
6689a747e4fSDavid du Colombier q.path = path;
6699a747e4fSDavid du Colombier out.wqid[out.nwqid++] = q;
6709a747e4fSDavid du Colombier continue;
6717dd7cddfSDavid du Colombier }
6727dd7cddfSDavid du Colombier d = dir;
6737dd7cddfSDavid du Colombier d++; /* skip '.' */
6747dd7cddfSDavid du Colombier for(; d->name; d++)
6759a747e4fSDavid du Colombier if(strcmp(t->wname[i], d->name) == 0){
6769a747e4fSDavid du Colombier type = d->type;
6779a747e4fSDavid du Colombier path = d->qid;
6789a747e4fSDavid du Colombier dir = d;
6799a747e4fSDavid du Colombier goto Accept;
6809a747e4fSDavid du Colombier }
6819a747e4fSDavid du Colombier err = Enoexist;
6829a747e4fSDavid du Colombier break;
6839a747e4fSDavid du Colombier }
6847dd7cddfSDavid du Colombier }
6857dd7cddfSDavid du Colombier
6869a747e4fSDavid du Colombier out.type = t->type;
6879a747e4fSDavid du Colombier out.tag = t->tag;
6889a747e4fSDavid du Colombier if(err!=nil || out.nwqid<t->nwname){
6899a747e4fSDavid du Colombier if(nf)
6909a747e4fSDavid du Colombier nf->busy = 0;
6919a747e4fSDavid du Colombier }else if(out.nwqid == t->nwname){
6929a747e4fSDavid du Colombier f->qid = q;
6939a747e4fSDavid du Colombier f->dir = dir;
6949a747e4fSDavid du Colombier }
6957dd7cddfSDavid du Colombier
6969a747e4fSDavid du Colombier fsysrespond(&out, buf, err);
6977dd7cddfSDavid du Colombier return t;
6987dd7cddfSDavid du Colombier }
6997dd7cddfSDavid du Colombier
7007dd7cddfSDavid du Colombier static Fcall*
fsysopen(Fcall * t,uchar * buf,Fid * f)7019a747e4fSDavid du Colombier fsysopen(Fcall *t, uchar *buf, Fid *f)
7027dd7cddfSDavid du Colombier {
7039a747e4fSDavid du Colombier int m, clearrules, mode;
7047dd7cddfSDavid du Colombier
7057dd7cddfSDavid du Colombier clearrules = 0;
7067dd7cddfSDavid du Colombier if(t->mode & OTRUNC){
7077dd7cddfSDavid du Colombier if(f->qid.path != Qrules)
7087dd7cddfSDavid du Colombier goto Deny;
7097dd7cddfSDavid du Colombier clearrules = 1;
7107dd7cddfSDavid du Colombier }
7117dd7cddfSDavid du Colombier /* can't truncate anything, so just disregard */
7129a747e4fSDavid du Colombier mode = t->mode & ~(OTRUNC|OCEXEC);
7137dd7cddfSDavid du Colombier /* can't execute or remove anything */
7149a747e4fSDavid du Colombier if(mode==OEXEC || (mode&ORCLOSE))
7157dd7cddfSDavid du Colombier goto Deny;
7169a747e4fSDavid du Colombier switch(mode){
7177dd7cddfSDavid du Colombier default:
7187dd7cddfSDavid du Colombier goto Deny;
7197dd7cddfSDavid du Colombier case OREAD:
7207dd7cddfSDavid du Colombier m = 0400;
7217dd7cddfSDavid du Colombier break;
7227dd7cddfSDavid du Colombier case OWRITE:
7237dd7cddfSDavid du Colombier m = 0200;
7247dd7cddfSDavid du Colombier break;
7257dd7cddfSDavid du Colombier case ORDWR:
7267dd7cddfSDavid du Colombier m = 0600;
7277dd7cddfSDavid du Colombier break;
7287dd7cddfSDavid du Colombier }
7299a747e4fSDavid du Colombier if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
7307dd7cddfSDavid du Colombier goto Deny;
7319a747e4fSDavid du Colombier if(f->qid.path==Qrules && (mode==OWRITE || mode==ORDWR)){
7327dd7cddfSDavid du Colombier lock(&rulesref);
7337dd7cddfSDavid du Colombier if(rulesref.ref++ != 0){
7347dd7cddfSDavid du Colombier rulesref.ref--;
7357dd7cddfSDavid du Colombier unlock(&rulesref);
7367dd7cddfSDavid du Colombier fsysrespond(t, buf, Einuse);
7377dd7cddfSDavid du Colombier return t;
7387dd7cddfSDavid du Colombier }
7397dd7cddfSDavid du Colombier unlock(&rulesref);
7407dd7cddfSDavid du Colombier }
7417dd7cddfSDavid du Colombier if(clearrules){
7427dd7cddfSDavid du Colombier writerules(nil, 0);
7437dd7cddfSDavid du Colombier rules[0] = nil;
7447dd7cddfSDavid du Colombier }
7457dd7cddfSDavid du Colombier t->qid = f->qid;
7469a747e4fSDavid du Colombier t->iounit = 0;
7477dd7cddfSDavid du Colombier qlock(&queue);
7489a747e4fSDavid du Colombier f->mode = mode;
7497dd7cddfSDavid du Colombier f->open = 1;
7507dd7cddfSDavid du Colombier f->dir->nopen++;
7517dd7cddfSDavid du Colombier f->nextopen = f->dir->fopen;
7527dd7cddfSDavid du Colombier f->dir->fopen = f;
7537dd7cddfSDavid du Colombier queueheld(f->dir);
7547dd7cddfSDavid du Colombier qunlock(&queue);
7557dd7cddfSDavid du Colombier fsysrespond(t, buf, nil);
7567dd7cddfSDavid du Colombier return t;
7577dd7cddfSDavid du Colombier
7587dd7cddfSDavid du Colombier Deny:
7597dd7cddfSDavid du Colombier fsysrespond(t, buf, Eperm);
7607dd7cddfSDavid du Colombier return t;
7617dd7cddfSDavid du Colombier }
7627dd7cddfSDavid du Colombier
7637dd7cddfSDavid du Colombier static Fcall*
fsyscreate(Fcall * t,uchar * buf,Fid *)7649a747e4fSDavid du Colombier fsyscreate(Fcall *t, uchar *buf, Fid*)
7657dd7cddfSDavid du Colombier {
7667dd7cddfSDavid du Colombier fsysrespond(t, buf, Eperm);
7677dd7cddfSDavid du Colombier return t;
7687dd7cddfSDavid du Colombier }
7697dd7cddfSDavid du Colombier
7707dd7cddfSDavid du Colombier static Fcall*
fsysreadrules(Fcall * t,uchar * buf)7719a747e4fSDavid du Colombier fsysreadrules(Fcall *t, uchar *buf)
7727dd7cddfSDavid du Colombier {
7737dd7cddfSDavid du Colombier char *p;
7747dd7cddfSDavid du Colombier int n;
7757dd7cddfSDavid du Colombier
7767dd7cddfSDavid du Colombier p = printrules();
7777dd7cddfSDavid du Colombier n = strlen(p);
7787dd7cddfSDavid du Colombier t->data = p;
7797dd7cddfSDavid du Colombier if(t->offset >= n)
7807dd7cddfSDavid du Colombier t->count = 0;
7817dd7cddfSDavid du Colombier else{
7827dd7cddfSDavid du Colombier t->data = p+t->offset;
7837dd7cddfSDavid du Colombier if(t->offset+t->count > n)
7847dd7cddfSDavid du Colombier t->count = n-t->offset;
7857dd7cddfSDavid du Colombier }
7867dd7cddfSDavid du Colombier fsysrespond(t, buf, nil);
7877dd7cddfSDavid du Colombier free(p);
7887dd7cddfSDavid du Colombier return t;
7897dd7cddfSDavid du Colombier }
7907dd7cddfSDavid du Colombier
7917dd7cddfSDavid du Colombier static Fcall*
fsysread(Fcall * t,uchar * buf,Fid * f)7929a747e4fSDavid du Colombier fsysread(Fcall *t, uchar *buf, Fid *f)
7937dd7cddfSDavid du Colombier {
7949a747e4fSDavid du Colombier uchar *b;
7957dd7cddfSDavid du Colombier int i, n, o, e;
7969a747e4fSDavid du Colombier uint len;
7977dd7cddfSDavid du Colombier Dirtab *d;
7989a747e4fSDavid du Colombier uint clock;
7997dd7cddfSDavid du Colombier
8009a747e4fSDavid du Colombier if(f->qid.path != Qdir){
8017dd7cddfSDavid du Colombier if(f->qid.path == Qrules)
8027dd7cddfSDavid du Colombier return fsysreadrules(t, buf);
8037dd7cddfSDavid du Colombier /* read from port */
8047dd7cddfSDavid du Colombier if(f->qid.path < NQID){
8057dd7cddfSDavid du Colombier fsysrespond(t, buf, "internal error: unknown read port");
8067dd7cddfSDavid du Colombier return t;
8077dd7cddfSDavid du Colombier }
8087dd7cddfSDavid du Colombier qlock(&queue);
8097dd7cddfSDavid du Colombier queueread(f->dir, t, buf, f);
8107dd7cddfSDavid du Colombier drainqueue(f->dir);
8117dd7cddfSDavid du Colombier qunlock(&queue);
8127dd7cddfSDavid du Colombier return nil;
8137dd7cddfSDavid du Colombier }
8147dd7cddfSDavid du Colombier o = t->offset;
8157dd7cddfSDavid du Colombier e = t->offset+t->count;
8169a747e4fSDavid du Colombier clock = getclock();
8179a747e4fSDavid du Colombier b = malloc(messagesize-IOHDRSZ);
8187dd7cddfSDavid du Colombier if(b == nil){
8197dd7cddfSDavid du Colombier fsysrespond(t, buf, Enomem);
8207dd7cddfSDavid du Colombier return t;
8217dd7cddfSDavid du Colombier }
8227dd7cddfSDavid du Colombier n = 0;
8237dd7cddfSDavid du Colombier d = dir;
8247dd7cddfSDavid du Colombier d++; /* first entry is '.' */
8259a747e4fSDavid du Colombier for(i=0; d->name!=nil && i<e; i+=len){
8269a747e4fSDavid du Colombier len = dostat(d, b+n, messagesize-IOHDRSZ-n, clock);
8279a747e4fSDavid du Colombier if(len <= BIT16SZ)
8289a747e4fSDavid du Colombier break;
8299a747e4fSDavid du Colombier if(i >= o)
8309a747e4fSDavid du Colombier n += len;
8317dd7cddfSDavid du Colombier d++;
8327dd7cddfSDavid du Colombier }
8339a747e4fSDavid du Colombier t->data = (char*)b;
8347dd7cddfSDavid du Colombier t->count = n;
8357dd7cddfSDavid du Colombier fsysrespond(t, buf, nil);
8367dd7cddfSDavid du Colombier free(b);
8377dd7cddfSDavid du Colombier return t;
8387dd7cddfSDavid du Colombier }
8397dd7cddfSDavid du Colombier
8407dd7cddfSDavid du Colombier static Fcall*
fsyswrite(Fcall * t,uchar * buf,Fid * f)8419a747e4fSDavid du Colombier fsyswrite(Fcall *t, uchar *buf, Fid *f)
8427dd7cddfSDavid du Colombier {
8437dd7cddfSDavid du Colombier Plumbmsg *m;
8447dd7cddfSDavid du Colombier int i, n;
8457dd7cddfSDavid du Colombier long count;
8467dd7cddfSDavid du Colombier char *data;
8477dd7cddfSDavid du Colombier Exec *e;
8487dd7cddfSDavid du Colombier
8499a747e4fSDavid du Colombier switch((int)f->qid.path){
8509a747e4fSDavid du Colombier case Qdir:
8517dd7cddfSDavid du Colombier fsysrespond(t, buf, Eisdir);
8527dd7cddfSDavid du Colombier return t;
8537dd7cddfSDavid du Colombier case Qrules:
8547dd7cddfSDavid du Colombier clock = getclock();
8557dd7cddfSDavid du Colombier fsysrespond(t, buf, writerules(t->data, t->count));
8567dd7cddfSDavid du Colombier return t;
8577dd7cddfSDavid du Colombier case Qsend:
8587dd7cddfSDavid du Colombier if(f->offset == 0){
8597dd7cddfSDavid du Colombier data = t->data;
8607dd7cddfSDavid du Colombier count = t->count;
8617dd7cddfSDavid du Colombier }else{
8627dd7cddfSDavid du Colombier /* partial message already assembled */
8637dd7cddfSDavid du Colombier f->writebuf = erealloc(f->writebuf, f->offset + t->count);
8647dd7cddfSDavid du Colombier memmove(f->writebuf+f->offset, t->data, t->count);
8657dd7cddfSDavid du Colombier data = f->writebuf;
8667dd7cddfSDavid du Colombier count = f->offset+t->count;
8677dd7cddfSDavid du Colombier }
8687dd7cddfSDavid du Colombier m = plumbunpackpartial(data, count, &n);
8697dd7cddfSDavid du Colombier if(m == nil){
8707dd7cddfSDavid du Colombier if(n == 0){
8717dd7cddfSDavid du Colombier f->offset = 0;
8727dd7cddfSDavid du Colombier free(f->writebuf);
8737dd7cddfSDavid du Colombier f->writebuf = nil;
8747dd7cddfSDavid du Colombier fsysrespond(t, buf, Ebadmsg);
8757dd7cddfSDavid du Colombier return t;
8767dd7cddfSDavid du Colombier }
8777dd7cddfSDavid du Colombier /* can read more... */
8787dd7cddfSDavid du Colombier if(f->offset == 0){
8797dd7cddfSDavid du Colombier f->writebuf = emalloc(t->count);
8807dd7cddfSDavid du Colombier memmove(f->writebuf, t->data, t->count);
8817dd7cddfSDavid du Colombier }
8827dd7cddfSDavid du Colombier /* else buffer has already been grown */
8837dd7cddfSDavid du Colombier f->offset += t->count;
8847dd7cddfSDavid du Colombier fsysrespond(t, buf, nil);
8857dd7cddfSDavid du Colombier return t;
8867dd7cddfSDavid du Colombier }
8877dd7cddfSDavid du Colombier /* release partial buffer */
8887dd7cddfSDavid du Colombier f->offset = 0;
8897dd7cddfSDavid du Colombier free(f->writebuf);
8907dd7cddfSDavid du Colombier f->writebuf = nil;
8917dd7cddfSDavid du Colombier for(i=0; rules[i]; i++)
8927dd7cddfSDavid du Colombier if((e=matchruleset(m, rules[i])) != nil){
8937dd7cddfSDavid du Colombier dispose(t, buf, m, rules[i], e);
8947dd7cddfSDavid du Colombier return nil;
8957dd7cddfSDavid du Colombier }
8967dd7cddfSDavid du Colombier if(m->dst != nil){
8977dd7cddfSDavid du Colombier dispose(t, buf, m, nil, nil);
8987dd7cddfSDavid du Colombier return nil;
8997dd7cddfSDavid du Colombier }
9007dd7cddfSDavid du Colombier fsysrespond(t, buf, "no matching plumb rule");
9017dd7cddfSDavid du Colombier return t;
9027dd7cddfSDavid du Colombier }
9037dd7cddfSDavid du Colombier fsysrespond(t, buf, "internal error: write to unknown file");
9047dd7cddfSDavid du Colombier return t;
9057dd7cddfSDavid du Colombier }
9067dd7cddfSDavid du Colombier
9077dd7cddfSDavid du Colombier static Fcall*
fsysstat(Fcall * t,uchar * buf,Fid * f)9089a747e4fSDavid du Colombier fsysstat(Fcall *t, uchar *buf, Fid *f)
9097dd7cddfSDavid du Colombier {
9109a747e4fSDavid du Colombier t->stat = emalloc(messagesize-IOHDRSZ);
9119a747e4fSDavid du Colombier t->nstat = dostat(f->dir, t->stat, messagesize-IOHDRSZ, clock);
9127dd7cddfSDavid du Colombier fsysrespond(t, buf, nil);
9139a747e4fSDavid du Colombier free(t->stat);
9149a747e4fSDavid du Colombier t->stat = nil;
9157dd7cddfSDavid du Colombier return t;
9167dd7cddfSDavid du Colombier }
9177dd7cddfSDavid du Colombier
9187dd7cddfSDavid du Colombier static Fcall*
fsyswstat(Fcall * t,uchar * buf,Fid *)9199a747e4fSDavid du Colombier fsyswstat(Fcall *t, uchar *buf, Fid*)
9207dd7cddfSDavid du Colombier {
9217dd7cddfSDavid du Colombier fsysrespond(t, buf, Eperm);
9227dd7cddfSDavid du Colombier return t;
9237dd7cddfSDavid du Colombier }
9247dd7cddfSDavid du Colombier
9257dd7cddfSDavid du Colombier static Fcall*
fsysremove(Fcall * t,uchar * buf,Fid *)9269a747e4fSDavid du Colombier fsysremove(Fcall *t, uchar *buf, Fid*)
9277dd7cddfSDavid du Colombier {
9287dd7cddfSDavid du Colombier fsysrespond(t, buf, Eperm);
9297dd7cddfSDavid du Colombier return t;
9307dd7cddfSDavid du Colombier }
9317dd7cddfSDavid du Colombier
9327dd7cddfSDavid du Colombier static Fcall*
fsysclunk(Fcall * t,uchar * buf,Fid * f)9339a747e4fSDavid du Colombier fsysclunk(Fcall *t, uchar *buf, Fid *f)
9347dd7cddfSDavid du Colombier {
9357dd7cddfSDavid du Colombier Fid *prev, *p;
9367dd7cddfSDavid du Colombier Dirtab *d;
9377dd7cddfSDavid du Colombier
9387dd7cddfSDavid du Colombier qlock(&queue);
9397dd7cddfSDavid du Colombier if(f->open){
9407dd7cddfSDavid du Colombier d = f->dir;
9417dd7cddfSDavid du Colombier d->nopen--;
9427dd7cddfSDavid du Colombier if(d->qid==Qrules && (f->mode==OWRITE || f->mode==ORDWR)){
9437dd7cddfSDavid du Colombier /*
9447dd7cddfSDavid du Colombier * just to be sure last rule is parsed; error messages will be lost, though,
9457dd7cddfSDavid du Colombier * unless last write ended with a blank line
9467dd7cddfSDavid du Colombier */
9477dd7cddfSDavid du Colombier writerules(nil, 0);
9487dd7cddfSDavid du Colombier lock(&rulesref);
9497dd7cddfSDavid du Colombier rulesref.ref--;
9507dd7cddfSDavid du Colombier unlock(&rulesref);
9517dd7cddfSDavid du Colombier }
9527dd7cddfSDavid du Colombier prev = nil;
9537dd7cddfSDavid du Colombier for(p=d->fopen; p; p=p->nextopen){
9547dd7cddfSDavid du Colombier if(p == f){
9557dd7cddfSDavid du Colombier if(prev)
9567dd7cddfSDavid du Colombier prev->nextopen = f->nextopen;
9577dd7cddfSDavid du Colombier else
9587dd7cddfSDavid du Colombier d->fopen = f->nextopen;
9597dd7cddfSDavid du Colombier removesenders(d, f);
9607dd7cddfSDavid du Colombier break;
9617dd7cddfSDavid du Colombier }
9627dd7cddfSDavid du Colombier prev = p;
9637dd7cddfSDavid du Colombier }
9647dd7cddfSDavid du Colombier }
9657dd7cddfSDavid du Colombier f->busy = 0;
9667dd7cddfSDavid du Colombier f->open = 0;
9677dd7cddfSDavid du Colombier f->offset = 0;
9687dd7cddfSDavid du Colombier if(f->writebuf != nil){
9697dd7cddfSDavid du Colombier free(f->writebuf);
9707dd7cddfSDavid du Colombier f->writebuf = nil;
9717dd7cddfSDavid du Colombier }
9727dd7cddfSDavid du Colombier qunlock(&queue);
9737dd7cddfSDavid du Colombier fsysrespond(t, buf, nil);
9747dd7cddfSDavid du Colombier return t;
9757dd7cddfSDavid du Colombier }
976