ref: f801657f77f3923ec2388c25bdcb036c8019ba89
dir: /prog/devicefs.c/
#include <u.h> #include "dat.h" #include "fns.h" #include "mem.h" #include "libkern/kern.h" #include "prog/prog.h" #include "prog/progfns.h" #define DIRSIZE (DFSMSIZE - IOHDRSZ) #define FNLEN 8 typedef struct Fid Fid; struct Fid { u32int fid; uvlong qid; uchar isopen; uchar openm; Fid *next; }; typedef struct DevFsSrv { Queue *din; Queue *dout; char *buf; Fid fidpool; Fcall r; Fcall f; } DevFsSrv; static char Egeneric[] = "server error"; static char Eclient[] = "client error"; static char Eimpl[] = "not implemented"; static char Enoauth[] = "no auth"; static char Eperm[] = "permission denied"; static char Efid[] = "fid error"; static char Eopen[] = "open or mode error"; static char Eseek[] = "bad seek or offset"; /* trees */ typedef struct FileTree FileTree; struct FileTree { uvlong parent; // uvlong path; char* name; u32int perm; }; enum { Qroot = 0, Qdev, Qsysctl, Qcount, }; enum { Qproglo = 100, Qproghi = 200, }; static FileTree tree[] = { /* Qroot */ { Qroot, ".", 0555|DMDIR, }, /* Qdev */ { Qroot, "dev", 0444|DMDIR, }, /* Qsysctl */ { Qdev, "sysctl", 0444, }, }; /* fid operations */ Fid* fid_create(DevFsSrv* srv, u32int fid) { Fid *c, *p, *new; for(c = &srv->fidpool; c != nil; c = c->next) { if(c->fid == fid) return nil; p = c; } new = malloc(sizeof(Fid)); new->fid = fid; p->next = new; return new; } Fid* fid_get(DevFsSrv* srv, u32int fid) { Fid *c; for(c = &srv->fidpool; c != nil; c = c->next) if(c->fid == fid) return c; return nil; } Fid* fid_clunk(DevFsSrv* srv, u32int fid) { Fid *c, *p; if(fid == NOFID) return nil; // can't clunk the sentinel for(c = &srv->fidpool; c != nil && c->fid != fid; c = c->next) p = c; if(c == nil) return nil; p->next = c->next; free(c); return &srv->fidpool; } /* generic replies */ void rerror(DevFsSrv *srv, char *ename) { uint n; srv->r.type = Rerror; srv->r.tag = srv->f.tag; srv->r.ename = ename; n = convS2M(&srv->r, (uchar*)srv->buf, DFSMSIZE); // kprint("devicefs: error %s\n", ename); qwrite(srv->dout, srv->buf, n); } void rreply(DevFsSrv *srv) { uint n; if((n = convS2M(&srv->r, (uchar*)srv->buf, DFSMSIZE)) == 0) { rerror(srv, Egeneric); return; } qwrite(srv->dout, srv->buf, n); } /* generic message handlers */ void devicefs_tversion(DevFsSrv *srv) { srv->r.type = Rversion; srv->r.tag = srv->f.tag; srv->r.msize = DFSMSIZE; srv->r.version = VERSION9P; rreply(srv); } void devicefs_tauth(DevFsSrv *srv) { rerror(srv, Enoauth); } void devicefs_tattach(DevFsSrv *srv) { Fid* fid; // Qid qid; if(srv->f.afid != NOFID) { rerror(srv, Enoauth); return; } if((fid = fid_create(srv, srv->f.fid)) == nil) { rerror(srv, Efid); return; } fid->fid = srv->f.fid; fid->qid = Qroot; srv->r.type = Rattach; srv->r.tag = srv->f.tag; srv->r.qid.path = fid->qid; srv->r.qid.vers = 1; srv->r.qid.type = tree[Qroot].perm >> 24; kprint("devicefs: attached %s", srv->f.uname); rreply(srv); } void devicefs_tflush(DevFsSrv *srv) { rerror(srv, Eimpl); } void devicefs_twalk(DevFsSrv *srv) { Fid *fid, *newfid; Qid qid; if(srv->f.nwname > MAXWELEM) { rerror(srv, Eclient); return; } if((fid = fid_get(srv, srv->f.fid)) == nil) { rerror(srv, Efid); return; } if(srv->f.fid != srv->f.newfid) { if((newfid = fid_create(srv, srv->f.newfid)) == nil) { rerror(srv, Efid); return; } } else newfid = fid; srv->r.type = Rwalk; srv->r.tag = srv->f.tag; srv->r.nwqid = 0; if(srv->f.nwname == 0) { newfid->qid = fid->qid; rreply(srv); return; } qid.path = fid->qid; for(int i = 0; i < srv->f.nwname; i++) { for(int j = 0; j < Qcount; j++) { if(tree[j].parent == qid.path && strcmp(srv->f.wname[i], tree[j].name) == 0) { qid.path = j; qid.vers = 1; qid.type = tree[j].perm >> 24; srv->r.wqid[i] = qid; srv->r.nwqid++; // TODO delegate break; } } if(srv->r.nwqid != i + 1) { srv->r.nwqid++; break; } } if(srv->r.nwqid == srv->f.nwname) newfid->qid = srv->r.wqid[srv->r.nwqid - 1].path; else fid_clunk(srv, newfid->fid); rreply(srv); } void devicefs_topen(DevFsSrv *srv) { Fid* fid; u32int perm; if((fid = fid_get(srv, srv->f.fid)) == nil) { rerror(srv, Efid); return; } if(fid->isopen) { rerror(srv, Eopen); return; } // TODO delegation perm = tree[fid->qid].perm; if((srv->f.mode & 0xf == OREAD) && !(perm & 0400)) { rerror(srv, Eperm); return; } if((srv->f.mode & 0xf == OWRITE) && !(perm & 0200)) { rerror(srv, Eperm); return; } if((srv->f.mode & 0xf == ORDWR) && !(perm & 0200 && perm & 0400)) { rerror(srv, Eperm); return; } if((srv->f.mode & 0xf == OEXEC) && !(perm & 0100 && perm & 0400)) { rerror(srv, Eperm); return; } if(srv->f.mode & ORCLOSE) { rerror(srv, Eperm); return; } if(srv->f.mode & OTRUNC && (!(perm & 0200) || (perm | DMDIR))) { rerror(srv, Eperm); return; } fid->isopen = 1; fid->openm = srv->f.mode & 0xff; srv->r.type = Ropen; srv->r.tag = srv->f.tag; srv->r.qid.path = fid->qid; srv->r.qid.vers = 1; srv->r.qid.type = perm >> 24; srv->r.iounit = DFSIOUNIT; rreply(srv); } void devicefs_tcreate(DevFsSrv *srv) { rerror(srv, Eperm); } void devicefs_tread(DevFsSrv *srv) { Fid* fid; Dir* dir; char *name, *data; u32int perm, n; if((fid = fid_get(srv, srv->f.fid)) == nil) { rerror(srv, Efid); return; } if((!fid->isopen) || (fid->openm & 0xf == OWRITE)) { rerror(srv, Eopen); return; } // TODO delegation name = tree[fid->qid].name; perm = tree[fid->qid].perm; if(perm & DMDIR) { if(srv->f.offset != 0) { rerror(srv, Eperm); return; } data = malloc(DIRSIZE); dir = malloc(sizeof(Dir)); dir->qid.path = fid->qid; dir->qid.vers = 1; dir->qid.type = perm >> 24; dir->mode = perm; dir->atime = 0; dir->mtime = 0; dir->length = FNLEN; dir->name = name; dir->uid = "none"; dir->gid = "none"; dir->muid = "none"; n = convD2M(dir, (uchar*)data, DIRSIZE); if(n == 0) { free(dir); free(data); rerror(srv, Egeneric); return; } srv->r.type = Rread; srv->r.tag = srv->f.tag; srv->r.count = n; srv->r.data = data; rreply(srv); free(dir); free(data); return; } // TODO delegation data = "bye bye"; if(srv->f.offset > 7) rerror(srv, Eseek); srv->r.type = Rread; srv->r.tag = srv->f.tag; srv->r.count = 7 - srv->f.offset; srv->r.data = &data[srv->f.offset]; rreply(srv); } void devicefs_twrite(DevFsSrv *srv) { rerror(srv, Eperm); } void devicefs_tclunk(DevFsSrv *srv) { if(fid_clunk(srv, srv->f.fid) == nil) { rerror(srv, Efid); return; } srv->r.type = Rclunk; srv->r.tag = srv->f.tag; rreply(srv); } void devicefs_tremove(DevFsSrv *srv) { rerror(srv, Eperm); } void devicefs_tstat(DevFsSrv *srv) { Fid* fid; Dir* stat; char *name; uchar *data; u32int perm; uint n; if((fid = fid_get(srv, srv->f.fid)) == nil) { rerror(srv, Efid); return; } // TODO delegation name = tree[fid->qid].name; perm = tree[fid->qid].perm; data = malloc(DIRSIZE); stat = malloc(sizeof(Dir)); stat->qid.path = fid->qid; stat->qid.vers = 1; stat->qid.type = perm >> 24; stat->mode = perm; stat->atime = 0; stat->mtime = 0; stat->length = FNLEN; stat->name = name; stat->uid = "none"; stat->gid = "none"; stat->muid = "none"; n = convD2M(stat, data, DIRSIZE); if(n == 0) { free(stat); free(data); rerror(srv, Egeneric); return; } srv->r.type = Rstat; srv->r.tag = srv->f.tag; srv->r.nstat = n; srv->r.stat = data; rreply(srv); free(stat); free(data); } void devicefs_twstat(DevFsSrv *srv) { rerror(srv, Eperm); } /* program entrypoint */ void devicefs(void *srvptr) { kprint("devicefs: started"); uint n, m; DevFsSrv *srv = srvptr; // start processing messages qflush(srv->din); qflush(srv->dout); kprint("devicefs: serving via UART2"); while(1) { n = BIT32SZ; while(n > 0) // read Tmsg size n -= qread(srv->din, &srv->buf[BIT32SZ - n], n); n = GBIT32(srv->buf); if(n > DFSMSIZE - BIT32SZ) { // drain buffer kprint("devicefs: error: Tmsg too big: %ud", n); while(n > 0) n -= qread(srv->din, srv->buf, (n > DFSMSIZE) ? DFSMSIZE : n); continue; } m = n - BIT32SZ; while(m > 0) m -= qread(srv->din, &srv->buf[n - m], m); if(convM2S((uchar*)srv->buf, n, &srv->f) == 0) { // resulting size? kprint("devicefs: warn: malformed Tmsg"); rerror(srv, Egeneric); continue; } kprint("devicefs: Tmsg type %04x", srv->f.type); switch(srv->f.type) { case Tversion: devicefs_tversion(srv); break; case Tauth: devicefs_tauth(srv); break; case Tattach: devicefs_tattach(srv); break; case Tflush: devicefs_tflush(srv); break; case Twalk: devicefs_twalk(srv); break; case Topen: devicefs_topen(srv); break; case Tcreate: devicefs_tcreate(srv); break; case Tread: devicefs_tread(srv); break; case Twrite: devicefs_twrite(srv); break; case Tclunk: devicefs_tclunk(srv); break; case Tremove: devicefs_tremove(srv); break; case Tstat: devicefs_tstat(srv); break; case Twstat: devicefs_twstat(srv); break; default: kprint("devicefs: warn: wrong Tmsg type: %d", srv->f.type); rerror(srv, Eclient); } // clear data // if(srv->f.uname) free(srv->f.uname); // if(srv->f.aname) free(srv->f.aname); // if(srv->f.name) free(srv->f.name); // if(srv->f.data) free(srv->f.data); // if(srv->f.stat) free(srv->f.stat); // for(int i = 0; i < MAXWELEM; i++) { // if(srv->f.wname[i]) free(srv->f.wname[i]); // } } kprint("devicefs: in queue closed, exiting"); qfree(srv->din); qfree(srv->dout); free(srv); kprint("devicefs: ended"); pexit(nil, 0); } Proc* prog_devicefs(Queue* fsiq, Queue* fsoq) { Proc *fsproc; Egrp *eg; DevFsSrv *srv = malloc(sizeof(DevFsSrv)); srv->din = fsiq; srv->dout = fsoq; srv->buf = malloc(DFSMSIZE); srv->fidpool.fid = NOFID; srv->fidpool.next = nil; fsproc = newprog("devicefs", devicefs, srv, 0, 1280); fsproc->env->egrp = eg; return fsproc; }