ref: 785a9258b6f284d369b8e018e7f9dccf682a4479
dir: /fs.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include "dat.h" #include "fns.h" #define Eexist "file does not exist" #define Enodir "not a directory" #define Enotyet "not yet implemented" #define Eoffset "invalid offset" #define Ewrite "write prohibited" #define Ecreate "create prohibited" #define Eremove "remove prohibited" #define Einvalidname "invalid LPA name" Qid qroot; Qid qnew; char *username; enum { Qroot, Qnew, Qsession, Qctl, Qcons, Qlog, Qmodules, Qmodule, Qthreads, Qlpaobj }; enum { Fctl, Fcons, Flog, Fmodules, Fthreads, }; enum { Fnew, Fsession, }; typedef struct Aux Aux; struct Aux { Session *session; Module *module; Symbol *symbol; char *cachestr; }; static Aux * allocaux(void) { Aux *aux = alloc(DataAux); setroot(aux, 1); return aux; } #define QID_TYPE(qid) ((qid.path) & 0xFF) #define QID_PATH(qid) (qid.path >> 8) static Qid mkqid(int type, uvlong id) { Qid qid; qid.vers = 0; qid.path = (type & 0xFF) | (id << 8); switch(type){ case Qroot: case Qsession: case Qmodules: case Qmodule: case Qthreads: qid.type = QTDIR; break; case Qnew: case Qctl: case Qcons: case Qlog: case Qlpaobj: qid.type = QTFILE; break; } if(type == Qcons) qid.type |= QTAPPEND; return qid; } Qid freshobjqid(void) { static int id = 0; Qid qid = mkqid(Qlpaobj, id); id++; return qid; } static void mkfilestat(Dir *d, char *name, Qid qid, ulong mode) { d->uid = estrdup9p(username); d->gid = estrdup9p(username); d->muid = estrdup9p(username); d->mode = mode; d->name = estrdup9p(name); d->qid = qid; } static void mkdirstat(Dir *d, char *name, Qid qid) { d->uid = estrdup9p(username); d->gid = estrdup9p(username); d->muid = estrdup9p(username); d->mode = 0555|DMDIR; d->name = estrdup9p(name); d->qid = qid; } static int roottreegen(int n, Dir *d, void *aux) { Enumeration *sessions = aux; int done = 0; if(n == Fnew) /* new */ mkfilestat(d, "new", qnew, 0444); else{ n -= Fsession; if(n < sessions->count){ Session *s = sessions->items[n]; mkdirstat(d, s->name, s->qsession); }else done = 1; } return done ? -1 : 0; } static int sessiongen(int n, Dir *d, void *aux) { Session *s = aux; int done = 0; switch(n){ case Fctl: mkfilestat(d, "ctl", s->qctl, 0666); break; case Fcons: mkfilestat(d, "cons", s->qctl, DMAPPEND|0555); d->length = s->logsize; break; case Flog: mkfilestat(d, "log", s->qlog, 0444); d->length = s->logsize; break; case Fmodules: mkdirstat(d, "modules", s->qmodules); break; /* case Fthreads: mkdirstat(d, "threads", s->qthreads); break; */ default: done = 1; } return done ? -1 : 0; } static int modulesgen(int n, Dir *d, void *aux) { Enumeration *modules = aux; if(n == modules->count) return -1; Module *m = modules->items[n]; mkdirstat(d, m->name, m->qmodule); return 0; } static int symbolsgen(int n, Dir *d, void *aux) { Enumeration *symbols = aux; if(n == symbols->count) return -1; Symbol *s = symbols->items[n]; mkfilestat(d, s->name, s->qsymbol, 0666); return 0; } static char * requeststr(Req *r) { char *buf; r->ofcall.count = r->ifcall.count; buf = emalloc9p(r->ifcall.count+1); memcpy(buf, r->ifcall.data, r->ifcall.count); buf[r->ifcall.count] = 0; /* make sure it is 0 terminated */ return buf; } static void sessioncons(Req *r) { Aux *aux = r->fid->aux; Session *s = aux->session; srvrelease(r->srv); if(r->ifcall.type == Tread){ qlock(&s->loglock); if(r->ifcall.offset >= s->logsize) rsleep(&s->logwait); readbuf(r, s->log, s->logsize); qunlock(&s->loglock); }else{ /* Twrite */ char *buf = requeststr(r); send(s->input, &buf); } srvacquire(r->srv); } static void sessionlog(Req *r) { Aux *aux = r->fid->aux; Session *s = aux->session; srvrelease(r->srv); qlock(&s->loglock); readbuf(r, s->log, s->logsize); qunlock(&s->loglock); srvacquire(r->srv); } static void sessionctl(Req *r) { Aux *aux = r->fid->aux; Session *s = aux->session; char *buf = requeststr(r); srvrelease(r->srv); systemcmd(s, buf, 1); free(buf); srvacquire(r->srv); } static char * symbolrw(Req *r) { Aux *aux = r->fid->aux; Session *session = aux->session; Symbol *symb = aux->symbol; char *err = nil; if(r->ifcall.type == Tread){ /* Pretty print the value and readstr() it. */ if(aux->cachestr == nil) aux->cachestr = printval(symb->value); readstr(r, aux->cachestr); if(r->ofcall.count == 0){ free(aux->cachestr); aux->cachestr = nil; } }else{ /* Twrite */ char *buf = requeststr(r); void *v = parseval(session, buf, &err); free(buf); if(v && getalloctag(v) == DataFunction){ Function *f = v; if(strcmp(symb->name, f->ast->funcname->name) != 0) err = "Function name must match symbol name"; } if(!err) symset(symb->table, symb->id, v); } return err; } static void fsattach(Req *r) { r->fid->qid = qroot; r->ofcall.qid = r->fid->qid; r->fid->aux = allocaux(); respond(r, nil); } static char * fswalk1(Fid *fid, char *name, Qid *qid) { char *err = nil; Enumeration *e = nil; Aux *aux = fid->aux; Session *s = aux->session; Module *m = aux->module; switch(QID_TYPE(fid->qid)){ case Qroot: if(strcmp(name, "..") == 0) *qid = fid->qid; else if(strcmp(name, "new") == 0) *qid = qnew; else{ int found = 0; e = enumsessions(); for(uvlong i = 0; i < e->count; i++){ Session *s = e->items[i]; if(strcmp(name, s->name) == 0){ *qid = s->qsession; aux->session = s; found = 1; break; } } if(!found) err = Eexist; } break; case Qsession: if(strcmp(name, "..") == 0) *qid = qroot; else if(strcmp(name, "ctl") == 0) *qid = s->qctl; else if(strcmp(name, "cons") == 0) *qid = s->qcons; else if(strcmp(name, "log") == 0) *qid = s->qlog; else if(strcmp(name, "modules") == 0) *qid = s->qmodules; /* else if(strcmp(name, "threads") == 0) *qid = s->qthreads; */ else err = Eexist; break; case Qmodules: if(strcmp(name, "..") == 0) *qid = s->qsession; else{ int found = 0; e = enummodules(s); for(uvlong i = 0; i < e->count && !found; i++){ Module *m = e->items[i]; if(strcmp(name, m->name) == 0){ *qid = m->qmodule; aux->module = m; found = 1; } } if(!found) err = Eexist; } break; case Qmodule: if(strcmp(name, "..") == 0) *qid = m->qsession; else{ int found = 0; e = enumsymbols(m->symtab, 1); for(uvlong i = 0; i < e->count && !found; i++){ Symbol *symb = e->items[i]; if(strcmp(name, symb->name) == 0){ *qid = symb->qsymbol; aux->symbol = symb; found = 1; } } if(!found) err = Eexist; } break; case Qthreads: if(strcmp(name, "..") == 0) *qid = s->qsession; else err = Enotyet; break; default: err = Enodir; break; } if(e != nil) setroot(e, 0); return err; } static char * fsclone(Fid *old, Fid *new) { new->aux = allocaux(); Aux *oldaux = old->aux; Aux *newaux = new->aux; memcpy(newaux, oldaux, sizeof(Aux)); return nil; } static void fsopen(Req *r) { /* TODO check permissions */ char *err = nil; if(QID_TYPE(r->fid->qid) == Qnew){ /* Create a new session */ Session *s = allocsession(); Module *m = addmodule(s, "main"); qnew.vers = s->id; r->fid->qid = qnew; r->ofcall.qid = qnew; s->qsession = mkqid(Qsession, s->id); s->qctl = mkqid(Qctl, s->id); s->qcons = mkqid(Qcons, s->id); s->qlog = mkqid(Qlog, s->id); s->qmodules = mkqid(Qmodules, s->id); s->qthreads = mkqid(Qthreads, s->id); m->qsession = s->qsession; m->qmodule = mkqid(Qmodule, m->id); } respond(r, err); } static void fsstat(Req *r) { Aux *aux = r->fid->aux; Session *s = aux->session; Module *m = aux->module; Symbol *symb = aux->symbol; char *err = nil; switch(QID_TYPE(r->fid->qid)){ case Qroot: mkdirstat(&r->d, "/", qroot); break; case Qnew: roottreegen(Fnew, &r->d, nil); break; case Qsession: mkdirstat(&r->d, s->name, s->qsession); break; case Qctl: sessiongen(Fctl, &r->d, s); break; case Qcons: sessiongen(Fcons, &r->d, s); break; case Qlog: sessiongen(Flog, &r->d, s); break; case Qmodules: sessiongen(Fmodules, &r->d, s); break; case Qmodule: mkdirstat(&r->d, m->name, m->qmodule); break; case Qthreads: sessiongen(Fthreads, &r->d, s); break; case Qlpaobj: mkfilestat(&r->d, symb->name, symb->qsymbol, 0444); break; default: err = Enotyet; } respond(r, err); } static void fsread(Req *r) { char buf[256]; Enumeration *e = nil; Aux *aux = r->fid->aux; char *err = nil; switch(QID_TYPE(r->fid->qid)){ case Qroot: e = enumsessions(); dirread9p(r, roottreegen, e); break; case Qsession: dirread9p(r, sessiongen, aux->session); break; case Qmodules: e = enummodules(aux->session); dirread9p(r, modulesgen, e); break; case Qmodule: e = enumsymbols(aux->module->symtab, 0); dirread9p(r, symbolsgen, e); break; case Qnew: snprint(buf, sizeof(buf), "%uld\n", r->fid->qid.vers); readstr(r, buf); break; case Qcons: sessioncons(r); break; case Qlog: sessionlog(r); break; case Qlpaobj: err = symbolrw(r); break; default: err = Enotyet; break; } if(e != nil) setroot(e, 0); respond(r, err); } static void fswrite(Req *r) { char *err = nil; switch(QID_TYPE(r->fid->qid)){ case Qctl: sessionctl(r); break; case Qcons: sessioncons(r); break; case Qlpaobj: err = symbolrw(r); break; default: err = Ewrite; } respond(r, err); } static void fscreate(Req *r) { char *err = nil; Aux *aux = r->fid->aux; Module *m = aux->module; uvlong symid; Symbol *symb; switch(QID_TYPE(r->fid->qid)){ case Qmodule: /* create a new symbol */ symid = sym(m->symtab, r->ifcall.name); if(symid == -1) err = Einvalidname; symb = symptr(m->symtab, symid); aux->symbol = symb; r->fid->qid = r->ofcall.qid = symb->qsymbol; break; default: err = Ecreate; } respond(r, err); } static void fsremove(Req *r) { char *err; switch(QID_TYPE(r->fid->qid)){ case Qlpaobj: err = Enotyet; break; default: err = Eremove; } respond(r, err); } static void fsdestroyfid(Fid *fid) { if(fid->aux) setroot(fid->aux, 0); } static Srv fs = { .attach = fsattach, .walk1 = fswalk1, .clone = fsclone, .open = fsopen, .stat = fsstat, .read = fsread, .write = fswrite, .create = fscreate, .remove = fsremove, .destroyfid = fsdestroyfid, }; void startfs(char *name, char *mtpt) { char *srvname = smprint("/srv/%s", name); if(access(srvname, AREAD|AWRITE) == 0){ int fd = open(srvname, ORDWR); if(fd < 0) sysfatal("open lpa service"); if(mount(fd, -1, mtpt, MREPL, "") != 0) sysfatal("mount lpa service"); return; } dataspecs[DataAux].size = sizeof(Aux); username = getuser(); qroot = mkqid(Qroot, 0); qnew = mkqid(Qnew, 0); threadpostmountsrv(&fs, name, mtpt, MREPL); }