123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287 |
- #include <u.h>
- #include <libc.h>
- #include <auth.h>
- #include <fcall.h>
- #include <bio.h>
- #include <ndb.h>
- #include <thread.h>
- /*
- * This fs presents a 1 level file system. It contains
- * up to three files per console (xxx and xxxctl and xxxstat)
- */
- typedef struct Console Console;
- typedef struct Fid Fid;
- typedef struct Request Request;
- typedef struct Reqlist Reqlist;
- typedef struct Fs Fs;
- enum
- {
- /* last 5 bits of qid.path */
- Textern= 0, /* fake parent of top level */
- Ttopdir, /* top level directory */
- Qctl,
- Qstat,
- Qdata,
- Bufsize= 32*1024, /* chars buffered per reader */
- Maxcons= 64, /* maximum consoles */
- Nhash= 64, /* Fid hash buckets */
- };
- #define TYPE(x) (((ulong)x.path) & 0xf)
- #define CONS(x) ((((ulong)x.path) >> 4)&0xfff)
- #define QID(c, x) (((c)<<4) | (x))
- struct Request
- {
- Request *next;
- Fid *fid;
- Fs *fs;
- Fcall f;
- uchar buf[1];
- };
- struct Reqlist
- {
- Lock;
- Request *first;
- Request *last;
- };
- struct Fid
- {
- Lock;
- Fid *next; /* hash list */
- Fid *cnext; /* list of Fid's on a console */
- int fid;
- int ref;
- int attached;
- int open;
- char *user;
- char mbuf[Bufsize]; /* message */
- int bufn;
- int used;
- Qid qid;
- Console *c;
- char buf[Bufsize];
- char *rp;
- char *wp;
- Reqlist r; /* active read requests */
- };
- struct Console
- {
- Lock;
- char *name;
- char *dev;
- int speed;
- int cronly;
- int ondemand; /* open only on demand */
- int chat; /* chat consoles are special */
- int pid; /* pid of reader */
- int fd;
- int cfd;
- int sfd;
- Fid *flist; /* open fids to broadcast to */
- };
- struct Fs
- {
- Lock;
- int fd; /* to kernel mount point */
- int messagesize;
- Fid *hash[Nhash];
- Console *cons[Maxcons];
- int ncons;
- };
- extern void console(Fs*, char*, char*, int, int, int);
- extern Fs* fsmount(char*);
- extern void fsreader(void*);
- extern void fsrun(void*);
- extern Fid* fsgetfid(Fs*, int);
- extern void fsputfid(Fs*, Fid*);
- extern int fsdirgen(Fs*, Qid, int, Dir*, uchar*, int);
- extern void fsreply(Fs*, Request*, char*);
- extern void fskick(Fs*, Fid*);
- extern int fsreopen(Fs*, Console*);
- extern void fsversion(Fs*, Request*, Fid*);
- extern void fsflush(Fs*, Request*, Fid*);
- extern void fsauth(Fs*, Request*, Fid*);
- extern void fsattach(Fs*, Request*, Fid*);
- extern void fswalk(Fs*, Request*, Fid*);
- extern void fsclwalk(Fs*, Request*, Fid*);
- extern void fsopen(Fs*, Request*, Fid*);
- extern void fscreate(Fs*, Request*, Fid*);
- extern void fsread(Fs*, Request*, Fid*);
- extern void fswrite(Fs*, Request*, Fid*);
- extern void fsclunk(Fs*, Request*, Fid*);
- extern void fsremove(Fs*, Request*, Fid*);
- extern void fsstat(Fs*, Request*, Fid*);
- extern void fswstat(Fs*, Request*, Fid*);
- void (*fcall[])(Fs*, Request*, Fid*) =
- {
- [Tflush] fsflush,
- [Tversion] fsversion,
- [Tauth] fsauth,
- [Tattach] fsattach,
- [Twalk] fswalk,
- [Topen] fsopen,
- [Tcreate] fscreate,
- [Tread] fsread,
- [Twrite] fswrite,
- [Tclunk] fsclunk,
- [Tremove] fsremove,
- [Tstat] fsstat,
- [Twstat] fswstat
- };
- char Eperm[] = "permission denied";
- char Eexist[] = "file does not exist";
- char Enotdir[] = "not a directory";
- char Eisopen[] = "file already open";
- char Ebadcount[] = "bad read/write count";
- char Enofid[] = "no such fid";
- char *consoledb = "/lib/ndb/consoledb";
- char *mntpt = "/mnt/consoles";
- int messagesize = 8192+IOHDRSZ;
- void
- fatal(char *fmt, ...)
- {
- va_list arg;
- char buf[1024];
- write(2, "consolefs: ", 10);
- va_start(arg, fmt);
- vseprint(buf, buf+1024, fmt, arg);
- va_end(arg);
- write(2, buf, strlen(buf));
- write(2, "\n", 1);
- threadexitsall(fmt);
- }
- void*
- emalloc(uint n)
- {
- void *p;
- p = malloc(n);
- if(p == nil)
- fatal("malloc failed: %r");
- memset(p, 0, n);
- return p;
- }
- int debug;
- Ndb *db;
- /*
- * any request that can get queued for a delayed reply
- */
- Request*
- allocreq(Fs *fs, int bufsize)
- {
- Request *r;
- r = emalloc(sizeof(Request)+bufsize);
- r->fs = fs;
- r->next = nil;
- return r;
- }
- /*
- * for maintaining lists of requests
- */
- void
- addreq(Reqlist *l, Request *r)
- {
- lock(l);
- if(l->first == nil)
- l->first = r;
- else
- l->last->next = r;
- l->last = r;
- r->next = nil;
- unlock(l);
- }
- /*
- * remove the first request from a list of requests
- */
- Request*
- remreq(Reqlist *l)
- {
- Request *r;
- lock(l);
- r = l->first;
- if(r != nil)
- l->first = r->next;
- unlock(l);
- return r;
- }
- /*
- * remove a request with the given tag from a list of requests
- */
- Request*
- remtag(Reqlist *l, int tag)
- {
- Request *or, **ll;
- lock(l);
- ll = &l->first;
- for(or = *ll; or; or = or->next){
- if(or->f.tag == tag){
- *ll = or->next;
- unlock(l);
- return or;
- }
- ll = &or->next;
- }
- unlock(l);
- return nil;
- }
- Qid
- parentqid(Qid q)
- {
- if(q.type & QTDIR)
- return (Qid){QID(0, Textern), 0, QTDIR};
- else
- return (Qid){QID(0, Ttopdir), 0, QTDIR};
- }
- int
- fsdirgen(Fs *fs, Qid parent, int i, Dir *d, uchar *buf, int nbuf)
- {
- static char name[64];
- char *p;
- int xcons;
- d->uid = d->gid = d->muid = "network";
- d->length = 0;
- d->atime = time(nil);
- d->mtime = d->atime;
- d->type = 'C';
- d->dev = '0';
- switch(TYPE(parent)){
- case Textern:
- if(i != 0)
- return -1;
- p = "consoles";
- d->mode = DMDIR|0555;
- d->qid.type = QTDIR;
- d->qid.path = QID(0, Ttopdir);
- d->qid.vers = 0;
- break;
- case Ttopdir:
- xcons = i/3;
- if(xcons >= fs->ncons)
- return -1;
- p = fs->cons[xcons]->name;
- switch(i%3){
- case 0:
- if(fs->cons[xcons]->cfd < 0)
- return 0;
- snprint(name, sizeof name, "%sctl", p);
- p = name;
- d->qid.type = QTFILE;
- d->qid.path = QID(xcons, Qctl);
- d->qid.vers = 0;
- break;
- case 1:
- if(fs->cons[xcons]->sfd < 0)
- return 0;
- snprint(name, sizeof name, "%sstat", p);
- p = name;
- d->qid.type = QTFILE;
- d->qid.path = QID(xcons, Qstat);
- d->qid.vers = 0;
- break;
- case 2:
- d->qid.type = QTFILE;
- d->qid.path = QID(xcons, Qdata);
- d->qid.vers = 0;
- break;
- }
- d->mode = 0666;
- break;
- default:
- return -1;
- }
- d->name = p;
- if(buf != nil)
- return convD2M(d, buf, nbuf);
- return 1;
- }
- /*
- * mount the user interface and start a request processor
- */
- Fs*
- fsmount(char *mntpt)
- {
- Fs *fs;
- int pfd[2], srv;
- char buf[32];
- int n;
- static void *v[2];
- fs = emalloc(sizeof(Fs));
- if(pipe(pfd) < 0)
- fatal("opening pipe: %r");
- /* start up the file system process */
- v[0] = fs;
- v[1] = pfd;
- proccreate(fsrun, v, 16*1024);
- /* Typically mounted before /srv exists */
- if(access("#s/consoles", AEXIST) < 0){
- srv = create("#s/consoles", OWRITE, 0666);
- if(srv < 0)
- fatal("post: %r");
- n = sprint(buf, "%d", pfd[1]);
- if(write(srv, buf, n) < 0)
- fatal("write srv: %r");
- close(srv);
- }
- mount(pfd[1], -1, mntpt, MBEFORE, "");
- close(pfd[1]);
- return fs;
- }
- /*
- * reopen a console
- */
- int
- fsreopen(Fs* fs, Console *c)
- {
- char buf[128];
- static void *v[2];
- if(c->pid){
- if(postnote(PNPROC, c->pid, "reopen") != 0)
- fprint(2, "postnote failed: %r\n");
- c->pid = 0;
- }
- if(c->fd >= 0){
- close(c->fd);
- close(c->cfd);
- close(c->sfd);
- c->cfd = -1;
- c->fd = -1;
- c->sfd = -1;
- }
- if(c->flist == nil && c->ondemand)
- return 0;
- c->fd = open(c->dev, ORDWR);
- if(c->fd < 0)
- return -1;
- snprint(buf, sizeof(buf), "%sctl", c->dev);
- c->cfd = open(buf, ORDWR);
- fprint(c->cfd, "b%d", c->speed);
- snprint(buf, sizeof(buf), "%sstat", c->dev);
- c->sfd = open(buf, OREAD);
- v[0] = fs;
- v[1] = c;
- proccreate(fsreader, v, 16*1024);
- return 0;
- }
- void
- change(Fs *fs, Console *c, int doreopen, int speed, int cronly, int ondemand)
- {
- lock(c);
- if(speed != c->speed){
- c->speed = speed;
- doreopen = 1;
- }
- if(ondemand != c->ondemand){
- c->ondemand = ondemand;
- doreopen = 1;
- }
- c->cronly = cronly;
- if(doreopen)
- fsreopen(fs, c);
- unlock(c);
- }
- /*
- * create a console interface
- */
- void
- console(Fs* fs, char *name, char *dev, int speed, int cronly, int ondemand)
- {
- Console *c;
- char *x;
- int i, doreopen;
- if(fs->ncons >= Maxcons)
- fatal("too many consoles, too little time");
- doreopen = 0;
- for(i = 0; i < fs->ncons; i++){
- c = fs->cons[i];
- if(strcmp(name, c->name) == 0){
- if(strcmp(dev, c->dev) != 0){
- /* new device */
- x = c->dev;
- c->dev = strdup(dev);
- free(x);
- doreopen = 1;
- }
- change(fs, c, doreopen, speed, cronly, ondemand);
- return;
- }
- }
- #ifdef sapedoesntlikethis
- /*
- * The code below prevents this from working. I can't
- * think of scenarios where the code below actually helps
- * Sape
- *
- * console=borneo dev=/dev/eia1
- * speed=9600
- * openondemand=1
- * console=tottie dev=/dev/eia1
- * speed=115200
- * openondemand=1
- */
- for(i = 0; i < fs->ncons; i++){
- c = fs->cons[i];
- if(strcmp(dev, c->dev) == 0){
- /* at least a rename */
- x = c->name;
- c->name = strdup(name);
- free(x);
- change(fs, c, doreopen, speed, cronly, ondemand);
- return;
- }
- }
- #endif
- c = emalloc(sizeof(Console));
- fs->cons[fs->ncons] = c;
- fs->ncons++;
- c->name = strdup(name);
- c->dev = strdup(dev);
- if(strcmp(c->dev, "/dev/null") == 0)
- c->chat = 1;
- else
- c->chat = 0;
- c->fd = -1;
- c->cfd = -1;
- c->sfd = -1;
- change(fs, c, 1, speed, cronly, ondemand);
- }
- /*
- * buffer data from console to a client.
- * circular q with writer able to catch up to reader.
- * the reader may miss data but always sees an in order sequence.
- */
- void
- fromconsole(Fid *f, char *p, int n)
- {
- char *rp, *wp, *ep;
- int pass;
- lock(f);
- rp = f->rp;
- wp = f->wp;
- ep = f->buf + sizeof(f->buf);
- pass = 0;
- while(n--){
- *wp++ = *p++;
- if(wp >= ep)
- wp = f->buf;
- if(rp == wp)
- pass = 1;
- }
- f->wp = wp;
- /* we overtook the read pointer, push it up so readers always
- * see the tail of what was written
- */
- if(pass){
- wp++;
- if(wp >= ep)
- f->rp = f->buf;
- else
- f->rp = wp;
- }
- unlock(f);
- }
- /*
- * broadcast a list of members to all listeners
- */
- void
- bcastmembers(Fs *fs, Console *c, char *msg, Fid *f)
- {
- int n;
- Fid *fl;
- char buf[512];
- sprint(buf, "[%s%s", msg, f->user);
- for(fl = c->flist; fl != nil && strlen(buf) + 64 < sizeof(buf); fl = fl->cnext){
- if(f == fl)
- continue;
- strcat(buf, ", ");
- strcat(buf, fl->user);
- }
- strcat(buf, "]\n");
- n = strlen(buf);
- for(fl = c->flist; fl; fl = fl->cnext){
- fromconsole(fl, buf, n);
- fskick(fs, fl);
- }
- }
- void
- handler(void*, char *msg)
- {
- if(strstr(msg, "reopen"))
- noted(NCONT);
- noted(NDFLT);
- }
- /*
- * a process to read console output and broadcast it (one per console)
- */
- void
- fsreader(void *v)
- {
- int n;
- Fid *fl;
- char buf[1024];
- Fs *fs;
- Console *c;
- void **a;
- a = v;
- fs = a[0];
- c = a[1];
- c->pid = getpid();
- notify(handler);
- if(c->chat)
- threadexits(nil);
- for(;;){
- n = read(c->fd, buf, sizeof(buf));
- if(n < 0)
- break;
- lock(c);
- for(fl = c->flist; fl; fl = fl->cnext){
- fromconsole(fl, buf, n);
- fskick(fs, fl);
- }
- unlock(c);
- }
- }
- void
- readdb(Fs *fs)
- {
- Ndbtuple *t, *nt;
- char *dev, *cons;
- int cronly, speed, ondemand;
- ndbreopen(db);
- /* start a listener for each console */
- for(;;){
- t = ndbparse(db);
- if(t == nil)
- break;
- dev = nil;
- cons = nil;
- speed = 9600;
- cronly = 0;
- ondemand = 0;
- for(nt = t; nt; nt = nt->entry){
- if(strcmp(nt->attr, "console") == 0)
- cons = nt->val;
- else if(strcmp(nt->attr, "dev") == 0)
- dev = nt->val;
- else if(strcmp(nt->attr, "speed") == 0)
- speed = atoi(nt->val);
- else if(strcmp(nt->attr, "cronly") == 0)
- cronly = 1;
- else if(strcmp(nt->attr, "openondemand") == 0)
- ondemand = 1;
- }
- if(dev != nil && cons != nil)
- console(fs, cons, dev, speed, cronly, ondemand);
- ndbfree(t);
- }
- }
- int dbmtime;
- /*
- * a request processor (one per Fs)
- */
- void
- fsrun(void *v)
- {
- int n, t;
- Request *r;
- Fid *f;
- Dir *d;
- void **a = v;
- Fs* fs;
- int *pfd;
- fs = a[0];
- pfd = a[1];
- fs->fd = pfd[0];
- for(;;){
- d = dirstat(consoledb);
- if(d != nil && d->mtime != dbmtime){
- dbmtime = d->mtime;
- readdb(fs);
- }
- free(d);
- r = allocreq(fs, messagesize);
- n = read9pmsg(fs->fd, r->buf, messagesize);
- if(n <= 0)
- fatal("unmounted");
- if(convM2S(r->buf, n, &r->f) == 0){
- fprint(2, "can't convert %ux %ux %ux\n", r->buf[0],
- r->buf[1], r->buf[2]);
- free(r);
- continue;
- }
- f = fsgetfid(fs, r->f.fid);
- r->fid = f;
- if(debug)
- fprint(2, "%F path %llux\n", &r->f, f->qid.path);
- t = r->f.type;
- r->f.type++;
- (*fcall[t])(fs, r, f);
- }
- }
- Fid*
- fsgetfid(Fs *fs, int fid)
- {
- Fid *f, *nf;
- lock(fs);
- for(f = fs->hash[fid%Nhash]; f; f = f->next){
- if(f->fid == fid){
- f->ref++;
- unlock(fs);
- return f;
- }
- }
- nf = emalloc(sizeof(Fid));
- nf->next = fs->hash[fid%Nhash];
- fs->hash[fid%Nhash] = nf;
- nf->fid = fid;
- nf->ref = 1;
- nf->wp = nf->buf;
- nf->rp = nf->wp;
- unlock(fs);
- return nf;
- }
- void
- fsputfid(Fs *fs, Fid *f)
- {
- Fid **l, *nf;
- lock(fs);
- if(--f->ref > 0){
- unlock(fs);
- return;
- }
- for(l = &fs->hash[f->fid%Nhash]; nf = *l; l = &nf->next)
- if(nf == f){
- *l = f->next;
- break;
- }
- unlock(fs);
- free(f->user);
- free(f);
- }
- void
- fsauth(Fs *fs, Request *r, Fid*)
- {
- fsreply(fs, r, "consolefs: authentication not required");
- }
- void
- fsversion(Fs *fs, Request *r, Fid*)
- {
- if(r->f.msize < 256){
- fsreply(fs, r, "message size too small");
- return;
- }
- messagesize = r->f.msize;
- if(messagesize > 8192+IOHDRSZ)
- messagesize = 8192+IOHDRSZ;
- r->f.msize = messagesize;
- if(strncmp(r->f.version, "9P2000", 6) != 0){
- fsreply(fs, r, "unrecognized 9P version");
- return;
- }
- r->f.version = "9P2000";
- fsreply(fs, r, nil);
- }
- void
- fsflush(Fs *fs, Request *r, Fid *f)
- {
- Request *or;
- or = remtag(&f->r, r->f.oldtag);
- if(or != nil){
- fsputfid(fs, or->fid);
- free(or);
- }
- fsreply(fs, r, nil);
- }
- void
- fsattach(Fs *fs, Request *r, Fid *f)
- {
- f->qid.type = QTDIR;
- f->qid.path = QID(0, Ttopdir);
- f->qid.vers = 0;
- if(r->f.uname[0])
- f->user = strdup(r->f.uname);
- else
- f->user = strdup("none");
- /* hold down the fid till the clunk */
- f->attached = 1;
- lock(fs);
- f->ref++;
- unlock(fs);
- r->f.qid = f->qid;
- fsreply(fs, r, nil);
- }
- void
- fswalk(Fs *fs, Request *r, Fid *f)
- {
- char *name;
- Dir d;
- int i, n, nqid, nwname;
- Qid qid, wqid[MAXWELEM];
- Fid *nf;
- char *err;
- if(f->attached == 0){
- fsreply(fs, r, Enofid);
- return;
- }
- nf = nil;
- if(r->f.fid != r->f.newfid){
- nf = fsgetfid(fs, r->f.newfid);
- nf->attached = f->attached;
- nf->open = f->open;
- nf->qid = f->qid;
- nf->user = strdup(f->user);
- nf->c = f->c;
- nf->wp = nf->buf;
- nf->rp = nf->wp;
- f = nf;
- }
- qid = f->qid;
- err = nil;
- nwname = r->f.nwname;
- nqid = 0;
- if(nwname > 0){
- for(; err == nil && nqid < nwname; nqid++){
- if(nqid >= MAXWELEM){
- err = "too many name elements";
- break;
- }
- name = r->f.wname[nqid];
- if(strcmp(name, "..") == 0)
- qid = parentqid(qid);
- else if(strcmp(name, ".") != 0){
- for(i = 0; ; i++){
- n = fsdirgen(fs, qid, i, &d, nil, 0);
- if(n < 0){
- err = Eexist;
- break;
- }
- if(n > 0 && strcmp(name, d.name) == 0){
- qid = d.qid;
- break;
- }
- }
- }
- wqid[nqid] = qid;
- }
- if(nf != nil && nqid < nwname)
- fsputfid(fs, nf);
- if(nqid == nwname)
- f->qid = qid;
- }
- memmove(r->f.wqid, wqid, nqid*sizeof(Qid));
- r->f.nwqid = nqid;
- fsreply(fs, r, err);
- }
- int
- ingroup(char *user, char *group)
- {
- Ndbtuple *t, *nt;
- Ndbs s;
- t = ndbsearch(db, &s, "group", group);
- if(t == nil)
- return 0;
- for(nt = t; nt; nt = nt->entry){
- if(strcmp(nt->attr, "uid") == 0)
- if(strcmp(nt->val, user) == 0)
- break;
- }
- ndbfree(t);
- return nt != nil;
- }
- int
- userok(char *u, char *cname)
- {
- Ndbtuple *t, *nt;
- Ndbs s;
- t = ndbsearch(db, &s, "console", cname);
- if(t == nil)
- return 0;
- for(nt = t; nt; nt = nt->entry){
- if(strcmp(nt->attr, "uid") == 0)
- if(strcmp(nt->val, u) == 0)
- break;
- if(strcmp(nt->attr, "gid") == 0)
- if(ingroup(u, nt->val))
- break;
- }
- ndbfree(t);
- return nt != nil;
- }
- int m2p[] ={
- [OREAD] 4,
- [OWRITE] 2,
- [ORDWR] 6
- };
- /*
- * broadcast a message to all listeners
- */
- void
- bcastmsg(Fs *fs, Console *c, char *msg, int n)
- {
- Fid *fl;
- for(fl = c->flist; fl; fl = fl->cnext){
- fromconsole(fl, msg, n);
- fskick(fs, fl);
- }
- }
- void
- fsopen(Fs *fs, Request *r, Fid *f)
- {
- int mode;
- Console *c;
- if(f->attached == 0){
- fsreply(fs, r, Enofid);
- return;
- }
- if(f->open){
- fsreply(fs, r, Eisopen);
- return;
- }
- mode = r->f.mode & 3;
- if((QTDIR & f->qid.type) && mode != OREAD){
- fsreply(fs, r, Eperm);
- return;
- }
- switch(TYPE(f->qid)){
- case Qdata:
- c = fs->cons[CONS(f->qid)];
- if(!userok(f->user, c->name)){
- fsreply(fs, r, Eperm);
- return;
- }
- f->rp = f->buf;
- f->wp = f->buf;
- f->c = c;
- lock(c);
- sprint(f->mbuf, "[%s] ", f->user);
- f->bufn = strlen(f->mbuf);
- f->used = 0;
- f->cnext = c->flist;
- c->flist = f;
- bcastmembers(fs, c, "+", f);
- if(c->pid == 0)
- fsreopen(fs, c);
- unlock(c);
- break;
- case Qctl:
- c = fs->cons[CONS(f->qid)];
- if(!userok(f->user, c->name)){
- fsreply(fs, r, Eperm);
- return;
- }
- f->c = c;
- break;
- case Qstat:
- c = fs->cons[CONS(f->qid)];
- if(!userok(f->user, c->name)){
- fsreply(fs, r, Eperm);
- return;
- }
- f->c = c;
- break;
- }
- f->open = 1;
- r->f.iounit = messagesize-IOHDRSZ;
- r->f.qid = f->qid;
- fsreply(fs, r, nil);
- }
- void
- fscreate(Fs *fs, Request *r, Fid*)
- {
- fsreply(fs, r, Eperm);
- }
- void
- fsread(Fs *fs, Request *r, Fid *f)
- {
- uchar *p, *e;
- int i, m, off;
- vlong offset;
- Dir d;
- char sbuf[ERRMAX];
- if(f->attached == 0){
- fsreply(fs, r, Enofid);
- return;
- }
- if((int)r->f.count < 0){
- fsreply(fs, r, Ebadcount);
- return;
- }
- if(QTDIR & f->qid.type){
- p = r->buf + IOHDRSZ;
- e = p + r->f.count;
- offset = r->f.offset;
- off = 0;
- for(i=0; p<e; i++, off+=m){
- m = fsdirgen(fs, f->qid, i, &d, p, e-p);
- if(m < 0)
- break;
- if(m > BIT16SZ && off >= offset)
- p += m;
- }
- r->f.data = (char*)r->buf + IOHDRSZ;
- r->f.count = (char*)p - r->f.data;
- } else {
- switch(TYPE(f->qid)){
- case Qdata:
- addreq(&f->r, r);
- fskick(fs, f);
- return;
- case Qctl:
- r->f.data = (char*)r->buf+IOHDRSZ;
- r->f.count = 0;
- break;
- case Qstat:
- if(r->f.count > sizeof(sbuf))
- r->f.count = sizeof(sbuf);
- i = pread(f->c->sfd, sbuf, r->f.count, r->f.offset);
- if(i < 0){
- errstr(sbuf, sizeof sbuf);
- fsreply(fs, r, sbuf);
- return;
- }
- r->f.data = sbuf;
- r->f.count = i;
- break;
- default:
- fsreply(fs, r, Eexist);
- return;
- }
- }
- fsreply(fs, r, nil);
- }
- void
- fswrite(Fs *fs, Request *r, Fid *f)
- {
- int i, eol = 0;
- if(f->attached == 0){
- fsreply(fs, r, Enofid);
- return;
- }
- if((int)r->f.count < 0){
- fsreply(fs, r, Ebadcount);
- return;
- }
- if(QTDIR & f->qid.type){
- fsreply(fs, r, Eperm);
- return;
- }
- switch(TYPE(f->qid)){
- default:
- fsreply(fs, r, Eperm);
- return;
- case Qctl:
- write(f->c->cfd, r->f.data, r->f.count);
- break;
- case Qdata:
- for(i = 0; i < r->f.count; i++){
- if(r->f.data[i] == '\n'){
- if(f->c->chat && f->used)
- eol = 1;
- if(f->c->cronly)
- r->f.data[i] = '\r';
- }
- else
- f->used = 1;
- }
- if(f->c->chat){
- fskick(fs, f);
- if(!f->used)
- break;
-
- if(f->bufn + r->f.count > Bufsize){
- r->f.count -= (f->bufn + r->f.count) % Bufsize;
- eol = 1;
- }
- strncat(f->mbuf, r->f.data, r->f.count);
- f->bufn += r->f.count;
- if(eol){
- bcastmsg(fs, f->c, f->mbuf, f->bufn);
- sprint(f->mbuf, "[%s] ", f->user);
- f->bufn = strlen(f->mbuf);
- f->used = 0;
- }
- }
- else
- write(f->c->fd, r->f.data, r->f.count);
- break;
- }
- fsreply(fs, r, nil);
- }
- void
- fsclunk(Fs *fs, Request *r, Fid *f)
- {
- Fid **l, *fl;
- Request *nr;
- if(f->open && TYPE(f->qid) == Qdata){
- while((nr = remreq(&f->r)) != nil){
- fsputfid(fs, f);
- free(nr);
- }
- lock(f->c);
- for(l = &f->c->flist; *l; l = &fl->cnext){
- fl = *l;
- if(fl == f){
- *l = fl->cnext;
- break;
- }
- }
- bcastmembers(fs, f->c, "-", f);
- if(f->c->ondemand && f->c->flist == nil)
- fsreopen(fs, f->c);
- unlock(f->c);
- }
- fsreply(fs, r, nil);
- fsputfid(fs, f);
- }
- void
- fsremove(Fs *fs, Request *r, Fid*)
- {
- fsreply(fs, r, Eperm);
- }
- void
- fsstat(Fs *fs, Request *r, Fid *f)
- {
- int i, n;
- Qid q;
- Dir d;
- q = parentqid(f->qid);
- for(i = 0; ; i++){
- r->f.stat = r->buf+IOHDRSZ;
- n = fsdirgen(fs, q, i, &d, r->f.stat, messagesize-IOHDRSZ);
- if(n < 0){
- fsreply(fs, r, Eexist);
- return;
- }
- r->f.nstat = n;
- if(r->f.nstat > BIT16SZ && d.qid.path == f->qid.path)
- break;
- }
- fsreply(fs, r, nil);
- }
- void
- fswstat(Fs *fs, Request *r, Fid*)
- {
- fsreply(fs, r, Eperm);
- }
- void
- fsreply(Fs *fs, Request *r, char *err)
- {
- int n;
- uchar buf[8192+IOHDRSZ];
- if(err){
- r->f.type = Rerror;
- r->f.ename = err;
- }
- n = convS2M(&r->f, buf, messagesize);
- if(debug)
- fprint(2, "%F path %llux n=%d\n", &r->f, r->fid->qid.path, n);
- fsputfid(fs, r->fid);
- if(write(fs->fd, buf, n) != n)
- fatal("unmounted");
- free(r);
- }
- /*
- * called whenever input or a read request has been received
- */
- void
- fskick(Fs *fs, Fid *f)
- {
- Request *r;
- char *p, *rp, *wp, *ep;
- int i;
- lock(f);
- while(f->rp != f->wp){
- r = remreq(&f->r);
- if(r == nil)
- break;
- p = (char*)r->buf;
- rp = f->rp;
- wp = f->wp;
- ep = &f->buf[Bufsize];
- for(i = 0; i < r->f.count && rp != wp; i++){
- *p++ = *rp++;
- if(rp >= ep)
- rp = f->buf;
- }
- f->rp = rp;
- r->f.data = (char*)r->buf;
- r->f.count = p - (char*)r->buf;
- fsreply(fs, r, nil);
- }
- unlock(f);
- }
- void
- usage(void)
- {
- fprint(2, "usage: consolefs [-d] [-m mount-point] [-c console-db]\n");
- threadexitsall("usage");
- }
- void
- threadmain(int argc, char **argv)
- {
- fmtinstall('F', fcallfmt);
- ARGBEGIN{
- case 'd':
- debug++;
- break;
- case 'c':
- consoledb = ARGF();
- if(consoledb == nil)
- usage();
- break;
- case 'm':
- mntpt = ARGF();
- if(mntpt == nil)
- usage();
- break;
- }ARGEND;
- db = ndbopen(consoledb);
- if(db == nil)
- fatal("can't open %s: %r", consoledb);
- fsmount(mntpt);
- }
|