#include #include #include #include #include <9p.h> #include "dat.h" #include "fns.h" typedef struct Aux Aux; struct Aux { int off; }; typedef struct Fs Fs; struct Fs { long inittime; Netlog log; Netlog tlslog; }; static Fs theFs; static char sbuf[1024]; static char tbuf[1024]; typedef struct Tab Tab; struct Tab { char *name; ulong mode; uchar type; // for directories: entries int begin; int end; int parent; }; Tab tab[] = { /* name mode type beg end parent */ /* Qroot */ "/", DMDIR|0555, QTDIR, Qdir, Qdir+1, Qroot, /* in Qroot: */ /* Qdir */ "8021x", DMDIR|0555, QTDIR, Qctl, Qn, Qroot, /* in Qdir: */ /* Qctl */ "ctl", 0666, 0, 0, 0, Qdir, /* Qkeys */ "keys", 0444, 0, 0, 0, Qdir, /* Qlog */ "log", 0444, 0, 0, 0, Qdir, /* Qnote */ "note", 0444, 0, 0, 0, Qdir, /* Qstats */ "stats", 0444, 0, 0, 0, Qdir, /* Qstatus */ "status", 0444, 0, 0, 0, Qdir, /* Qtslog */ "tlslog", 0444, 0, 0, 0, Qdir, }; #define PATH(type, n) ((type)|((n)<<8)) #define TYPE(path) ((int)(path) & 0xFF) #define NUM(path) ((uint)(path)>>8) Channel *fsreqchan; /* chan(Req*) */ Channel *fsreqwaitchan; /* chan(nil) */ Channel *fsclunkchan; /* chan(Fid*) */ Channel *fsclunkwaitchan; /* chan(nil) */ enum { Closed, Open, }; char *statestr[] = { "Closed", "Open", }; typedef struct Reader Reader; struct Reader { int ref; int state; int num; Req *rq; Req **erq; int qid; }; int nreader; Reader **reader; static int newreader(void); static void teardownreader(Netlog*, Reader*); static void queuereq(Reader *, Req *); static int fillstat(ulong qid, Dir *d) { Tab *t; ReadBuf *b; if (qid < 0 || qid >= Qn) return 0; memset(d, 0, sizeof(Dir)); d->uid = "8021x"; d->gid = "8021x"; d->muid = ""; d->qid = (Qid){qid, 0, 0}; d->atime = time(0); d->mtime = theFs.inittime; t = &tab[qid]; d->name = t->name; d->mode = t->mode; d->qid.type = t->type; switch(qid){ case Qstatus: case Qkeys: case Qnote: d->mtime = getChangetime(qid); break; } switch(qid){ case Qkeys: b = getKeysbuf(); d->length = b->ndata; break; case Qnote: b = getNotesbuf(); d->length = b->ndata; break; case Qstatus: getPAEStatus(sbuf, sizeof(sbuf)); d->length = strlen(sbuf); break; } return 1; } static void fsattach(Req *r) { r->fid->qid = (Qid){Qroot, 0, QTDIR}; r->ofcall.qid = r->fid->qid; r->fid->aux = emalloc9p(sizeof(Aux)); respond(r, nil); } static char* fsclone(Fid *old, Fid *new) { Aux *na; na = emalloc9p(sizeof(Aux)); *na = *((Aux*)old->aux); new->aux = na; return nil; } static int lookupqid(char *name, Tab *dir) { Tab *t, *b, *e; if (dir == nil) return -1; if(strcmp(name, "..") == 0) return dir->parent; b = &tab[dir->begin]; e = &tab[dir->end]; for (t = b; t < e; t++) if (strcmp(name, t->name) == 0) return t - &tab[0]; return -1; } static char* fswalk1(Fid *fid, char *name, Qid *qid) { ulong p, i; Tab *t; p = fid->qid.path; if (p < 0 || p >= Qn) return "no such file or directory"; t = &tab[p]; if ((t->type & QTDIR) != QTDIR) return "walk in non-directory"; i = lookupqid(name, t); if (i >= 0){ *qid = (Qid){i, 0, tab[i].type}; return nil; } return "no such file or directory"; } static void readctl(Req *r) { char s[1024]; sprint(s, "802.1x ctl bla\n"); readstr(r, s); } static void fsread(Req *r) { int j, n; Fid *fid; vlong offset; uchar *p, *ep; void *buf; long count; Dir d; Aux *a; ReadBuf *b; ulong path; fid = r->fid; path = fid->qid.path; offset = r->ifcall.offset; count = r->ifcall.count; buf = r->ofcall.data; switch(TYPE(path)) { case Qroot: p = buf; ep = p+count; if(offset == 0) { if(fillstat(Qdir, &d) && (n = convD2M(&d, p, ep-p)) > BIT16SZ) p += n; r->ofcall.count = p-(uchar*)buf; } respond(r, nil); return; case Qdir: p = buf; ep = p+count; a = fid->aux; if(offset == 0) a->off = 2; /* skip root and Qdir */ for(j=a->off; joff = j; r->ofcall.count = p-(uchar*)buf; respond(r, nil); return; case Qkeys: b = getKeysbuf(); readbuf(r, b->data, b->ndata); respond(r, nil); return; case Qlog: a = fid->aux; r->ofcall.count = netlogread(&theFs.log, buf, count, offset, &a->off); if (r->ofcall.count == 0) queuereq(reader[NUM(path)], r); else respond(r, nil); return; case Qtlslog: a = fid->aux; r->ofcall.count = netlogread(&theFs.tlslog, buf, count, offset, &a->off); if (r->ofcall.count == 0) queuereq(reader[NUM(path)], r); else respond(r, nil); return; case Qnote: b = getNotesbuf(); readbuf(r, b->data, b->ndata); respond(r, nil); return; case Qstats: r->ofcall.count = 0; respond(r, nil); return; case Qstatus: getPAEStatus(sbuf, sizeof(sbuf)); readstr(r, sbuf); respond(r, nil); return; case Qctl: readctl(r); respond(r, nil); return; } } static char* writectl(void *v, long count) { USED(v); USED(count); return nil; } static void fswrite(Req *r) { Fid *fid; fid = r->fid; r->ofcall.count = r->ifcall.count; if(fid->qid.path == Qctl) { respond(r, writectl(r->ifcall.data, r->ifcall.count)); return; } respond(r, "permission denied"); return; } static void fsstat(Req *r) { fillstat(TYPE((ulong)r->fid->qid.path), &r->d); r->d.name = estrdup9p(r->d.name); r->d.uid = estrdup9p(r->d.uid); r->d.gid = estrdup9p(r->d.gid); r->d.muid = estrdup9p(r->d.muid); respond(r, nil); } static void fsopen(Req *r) { int omode; Fid *fid; ulong path; int n; Aux *a; Reader *c; fid = r->fid; omode = r->ifcall.mode; r->ofcall.qid = (Qid){fid->qid.path, 0, fid->qid.type}; switch((ulong)fid->qid.path){ case Qctl: if(omode&~(OTRUNC|OREAD|OWRITE|ORDWR)) respond(r, "permission denied"); else respond(r, nil); return; case Qlog: if(omode != OREAD) respond(r, "permission denied"); n = newreader(); c = reader[n]; c->qid = Qlog; c->state = Open; path = PATH(Qlog, n); netlogopen(&theFs.log); r->fid->qid.path = path; r->ofcall.qid.path = path; a = r->fid->aux; a->off = 0; if(chatty9p) fprint(2, "open log => path=%lux\n", path); reader[NUM(path)]->ref++; respond(r, nil); return; case Qtlslog: if(omode != OREAD) respond(r, "permission denied"); n = newreader(); c = reader[n]; c->qid = Qtlslog; c->state = Open; path = PATH(Qtlslog, n); netlogopen(&theFs.tlslog); r->fid->qid.path = path; r->ofcall.qid.path = path; a = r->fid->aux; a->off = 0; debugTLS++; if(chatty9p) fprint(2, "open tlslog => path=%lux debugTLS=%d\n", path, debugTLS); reader[NUM(path)]->ref++; respond(r, nil); return; case Qroot: case Qdir: case Qkeys: case Qnote: case Qstats: case Qstatus: if(omode == OREAD) respond(r, nil); else respond(r, "permission denied"); return; default: respond(r, "no such file or directory"); } } static int newreader(void) { int i; Reader *c; for(i=0; iref==0 && reader[i]->state == Closed) return i; if(nreader%16 == 0) reader = erealloc9p(reader, (nreader+16)*sizeof(reader[0])); c = emalloc9p(sizeof(Reader)); memset(c, 0, sizeof(*c)); c->num = nreader; reader[nreader++] = c; return c->num; } static void queuereq(Reader *c, Req *r) { if(c->rq==nil) c->erq = &c->rq; *c->erq = r; r->aux = nil; c->erq = (Req**)&r->aux; } Req* findreq(Reader *c, Req *r) { Req **l; for(l=&c->rq; *l; l=(Req**)&(*l)->aux){ if(*l == r){ *l = r->aux; if(*l == nil) c->erq = l; return r; } } return nil; } void closereader(Netlog *l, Reader *c) { if(--c->ref) return; if(c->rq != nil) logfatal(0, "ref count reached zero with requests pending (BUG)"); if(c->state != Closed) teardownreader(l, c); } static void teardownreader(Netlog *l, Reader *c) { c->state = Closed; netlogclose(l); } static void fsflush(Req *r) { int i; for(i=0; ioldreq)) respond(r->oldreq, "interrupted"); respond(r, nil); } void handlereader(Netlog *l, int qid) { Req *r; int i; void *buf; long count; vlong offset; Reader *c; Aux *a; // syslog(0, logname, "handlereader %d nreader=%d", qid, nreader); for(i=0; istate], c->qid); if (c->state == Closed) continue; else if (c->qid == qid) { r = c->rq; if(r != nil){ if(r->aux != nil) logfatal(0, "more than one outstanding reader request (BUG)"); offset = r->ifcall.offset; buf = r->ofcall.data; count = r->ifcall.count; a = r->fid->aux; r->ofcall.count = netlogread(l, buf, count, offset, &a->off); if (r->ofcall.count != 0) { c->rq = nil; respond(r, nil); } } } } } static void fsnetproc(void*) { ulong path; Alt a[5]; Fid *fid; Req *r; threadsetname("fsthread"); a[0].op = CHANRCV; a[0].c = fsclunkchan; a[0].v = &fid; a[1].op = CHANRCV; a[1].c = fsreqchan; a[1].v = &r; a[2].op = CHANRCV; a[2].c = theFs.log.ping; a[2].v = nil; a[3].op = CHANRCV; a[3].c = theFs.tlslog.ping; a[3].v = nil; a[4].op = CHANEND; a[4].op = CHANEND; for(;;){ switch(alt(a)){ case 0: path = fid->qid.path; if(fid->aux) { free(fid->aux); fid->aux = 0; } switch(TYPE(path)){ case Qlog: if(chatty9p) fprint(2, "close log => path=%lux\n", path); if(fid->omode != -1) closereader(&theFs.log, reader[NUM(path)]); break; case Qtlslog: if(chatty9p) fprint(2, "close tlslog => path=%lux\n", path); debugTLS--; if(fid->omode != -1) closereader(&theFs.tlslog, reader[NUM(path)]); break; } sendp(fsclunkwaitchan, nil); break; case 1: switch(r->ifcall.type){ case Tattach: fsattach(r); break; case Topen: fsopen(r); break; case Tread: fsread(r); break; case Twrite: fswrite(r); break; case Tstat: fsstat(r); break; case Tflush: fsflush(r); break; default: respond(r, "bug in fsthread"); break; } sendp(fsreqwaitchan, 0); break; case 2: handlereader(&theFs.log, Qlog); break; case 3: handlereader(&theFs.tlslog, Qtlslog); break; } } } static void fssend(Req *r) { sendp(fsreqchan, r); recvp(fsreqwaitchan); /* avoids need to deal with spurious flushes */ } static void fsdestroyfid(Fid *fid) { sendp(fsclunkchan, fid); recvp(fsclunkwaitchan); } static void takedown(Srv*) { threadexitsall("done"); } Srv fs = { .attach= fsattach, .clone= fsclone, .walk1= fswalk1, .open= fsopen, .read= fsread, .write= fswrite, .stat= fsstat, .flush= fssend, .destroyfid= fsdestroyfid, .end= takedown, }; void initFs(void) { theFs.inittime = time(0); fsreqchan = chancreate(sizeof(Req*), 0); fsreqwaitchan = chancreate(sizeof(void*), 0); fsclunkchan = chancreate(sizeof(Fid*), 0); fsclunkwaitchan = chancreate(sizeof(void*), 0); netloginit(&theFs.log); netloginit(&theFs.tlslog); // syslog(0, logname, "initFs &theFs.log=%p &theFs.tlslog=%p", &theFs.log, &theFs.tlslog); procrfork(fsnetproc, nil, 8192, RFNAMEG|RFNOTEG); } int loglog(char *fmt, ...) { int n; va_list arg; va_start(arg, fmt); n = netlog(&theFs.log, fmt, arg); va_end(arg); return n; } int tlslog(char *fmt, ...) { int n; va_list arg; va_start(arg, fmt); n = netlog(&theFs.tlslog, fmt, arg); va_end(arg); return n; }