/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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; voidfatal(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 */voidaddreq(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;} Qidparentqid(Qid q){ if(q.type & QTDIR) return (Qid){QID(0, Textern), 0, QTDIR}; else return (Qid){QID(0, Ttopdir), 0, QTDIR};} intfsdirgen(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 */intfsreopen(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;} voidchange(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 */voidconsole(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);Lines 1–500 of 1299. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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);