/* * exportfs - Export a plan 9 name space across a network */ #include #include #include #include #define Extern #include "exportfs.h" void (*fcalls[])(Fsrpc*) = { [Tnop] Xnop, [Tsession] Xsession, [Tflush] Xflush, [Tattach] Xattach, [Tclone] Xclone, [Twalk] Xwalk, [Topen] slave, [Tcreate] Xcreate, [Tclunk] Xclunk, [Tread] slave, [Twrite] slave, [Tremove] Xremove, [Tstat] Xstat, [Twstat] Xwstat, [Tclwalk] Xclwalk, [Tauth] Xauth, }; void main(int argc, char **argv) { char buf[128]; Fsrpc *r; int n; char *dbfile; char *ctlfile; char *errp, user[NAMELEN]; dbfile = "/tmp/exportdb"; ctlfile = 0; ARGBEGIN{ case 'a': if(errp = srvauth(user)) fatal(errp); if(errp = newns(user, 0)) fatal(errp); putenv("service", "exportfs"); break; case 'c': ctlfile = ARGF(); break; case 'd': dbg++; break; case 'f': dbfile = ARGF(); break; }ARGEND USED(argc, argv); if(dbg) { n = create(dbfile, OWRITE|OTRUNC, 0666); dup(n, 2); close(n); } rfork(RFNOTEG); Workq = malloc(sizeof(Fsrpc)*Nr_workbufs); fhash = malloc(sizeof(Fid*)*FHASHSIZE); if(Workq == 0 || fhash == 0) fatal("no initial memory"); memset(Workq, 0, sizeof(Fsrpc)*Nr_workbufs); fmtinstall('F', fcallconv); /* * Get tree to serve from network connection, check we can get there and * ack the connection */ n = read(0, buf, sizeof(buf)); if(n < 0 || chdir(buf) < 0) { errstr(buf); write(0, buf, strlen(buf)); exits(buf); } /* * take ownership of the network connection and * push the fcall line discipline */ if(ctlfile) pushfcall(ctlfile); initroot(); DEBUG(2, "exportfs: %s\n", buf); if(write(0, "OK", 2) != 2) fatal("open ack write"); /* * Start serving file requests from the network */ for(;;) { r = getsbuf(); if(r == 0) fatal("Out of service buffers"); do n = read(0, r->buf, sizeof(r->buf)); while(n == 0); if(n < 0) fatal("server read"); if(convM2S(r->buf, &r->work, n) == 0) fatal("format error"); DEBUG(2, "%F\n", &r->work, &r->work); (fcalls[r->work.type])(r); } } void reply(Fcall *r, Fcall *t, char *err) { char data[MAXFDATA+MAXMSG]; int n; t->tag = r->tag; t->fid = r->fid; if(err) { t->type = Rerror; strncpy(t->ename, err, ERRLEN); } else t->type = r->type + 1; DEBUG(2, "\t%F\n", t); n = convS2M(t, data); if(write(0, data, n)!=n) fatal("mount write"); } Fid * getfid(int nr) { Fid *f; for(f = fidhash(nr); f; f = f->next) if(f->nr == nr) return f; return 0; } int freefid(int nr) { Fid *f, **l; l = &fidhash(nr); for(f = *l; f; f = f->next) { if(f->nr == nr) { *l = f->next; f->next = fidfree; fidfree = f; return 1; } l = &f->next; } return 0; } Fid * newfid(int nr) { Fid *new, **l; int i; l = &fidhash(nr); for(new = *l; new; new = new->next) if(new->nr == nr) return 0; if(fidfree == 0) { fidfree = malloc(sizeof(Fid) * Fidchunk); if(fidfree == 0) fatal("out of memory"); for(i = 0; i < Fidchunk-1; i++) fidfree[i].next = &fidfree[i+1]; fidfree[Fidchunk-1].next = 0; } new = fidfree; fidfree = new->next; memset(new, 0, sizeof(Fid)); new->next = *l; *l = new; new->nr = nr; new->fid = -1; return new; } Fsrpc * getsbuf(void) { static int ap; int look; Fsrpc *wb; for(look = 0; look < Nr_workbufs; look++) { if(++ap == Nr_workbufs) ap = 0; if(Workq[ap].busy == 0) break; } if(look == Nr_workbufs) fatal("No more work buffers"); wb = &Workq[ap]; wb->pid = 0; wb->canint = 0; wb->flushtag = NOTAG; wb->busy = 1; return wb; } char * strcatalloc(char *p, char *n) { char *v; v = realloc(p, strlen(p)+strlen(n)+1); if(v == 0) fatal("no memory"); strcat(v, n); return v; } File * file(File *parent, char *name) { char buf[128]; File *f, *new; Dir dir; DEBUG(2, "\tfile: 0x%x %s name %s\n", parent, parent->name, name); for(f = parent->child; f; f = f->childlist) if(strcmp(name, f->name) == 0) return f; makepath(buf, parent, name); if(dirstat(buf, &dir) < 0) return 0; new = malloc(sizeof(File)); if(new == 0) fatal("no memory"); memset(new, 0, sizeof(File)); strcpy(new->name, name); new->qid.vers = dir.qid.vers; new->qid.path = (dir.qid.path&CHDIR)|++qid; new->parent = parent; new->childlist = parent->child; parent->child = new; return new; } void initroot(void) { Dir dir; root = malloc(sizeof(File)); if(root == 0) fatal("no memory"); memset(root, 0, sizeof(File)); strcpy(root->name, "."); if(dirstat(root->name, &dir) < 0) fatal("root stat"); root->qid.vers = dir.qid.vers; root->qid.path = (dir.qid.path&CHDIR)|++qid; } void makepath(char *s, File *p, char *name) { char *c, *seg[100]; int i; seg[0] = name; for(i = 1; i < 100 && p; i++, p = p->parent) seg[i] = p->name; while(i--) { for(c = seg[i]; *c; c++) *s++ = *c; *s++ = '/'; } while(s[-1] == '/') s--; *s = '\0'; } void fatal(char *s) { char buf[128]; Proc *m; sprint(buf, "exportfs: %r: %s", s); /* Clear away the slave children */ for(m = Proclist; m; m = m->next) postnote(m->pid, "kill"); exits(buf); } char *pushmsg = "push fcall"; void pushfcall(char *ctl) { int cfd; Dir dir; if(dirfstat(0, &dir) < 0){ fprint(2, "dirfstat(0) failed: %r\n"); return; } memmove(dir.uid, getuser(), NAMELEN); if(dirfwstat(1, &dir) < 0){ fprint(2, "dirfwstat(1) failed: %r\n"); return; } cfd = open(ctl, ORDWR); if(cfd < 0){ fprint(2, "open(%s0) failed: %r\n", ctl); return; } if(write(cfd, pushmsg, strlen(pushmsg)) < 0){ fprint(2, "%s failed: %r\n", pushmsg); return; } close(cfd); }