void fsysproc(void *v) { int n; Xfid *x; Fid *f; Fcall t; uchar *buf; threadsetname("fsysproc"); USED(v); x = nil; for(;;){ buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */ n = read9pmsg(sfd, buf, messagesize); if(n <= 0){ if(closing) break; error("i/o error on server channel"); } if(x == nil){ sendp(cxfidalloc, nil); x = recvp(cxfidalloc); } x->buf = buf; if(convM2S(buf, n, &x->fcall) != n) error("convert error in convM2S"); if(DEBUG) fprint(2, "%F\n", &x->fcall); if(fcall[x->fcall.type] == nil) x = respond(x, &t, "bad fcall type"); else{ switch(x->fcall.type){ case Tversion: case Tauth: case Tflush: f = nil; break; case Tattach: f = newfid(x->fcall.fid); break; default: f = newfid(x->fcall.fid); if(!f->busy){ x->f = f; x = respond(x, &t, "fid not in use"); continue; } break; } x->f = f; x = (*fcall[x->fcall.type])(x, f); } } }
static void rwalk(Fcall *f) { int i, j; Fcall r; Fid *fidp, *nf; char *err; fidp = newfid(f->fid); if(fidp->node && fidp->node->d.type == Dummynode) { reply(f, "can't walk an address node"); return; } if(f->fid == f->newfid) nf = fidp; else { nf = newfid(f->newfid); nf->busy = 1; nf->node = fidp->node; nf->uid = fidp->uid; nf->name = fidp->name; if(debugfd >= 0) printfid(nf); } err = nil; for(i=0; i<f->nwname; i++) { err = walk(f->wname[i], nf); if(err) break; r.wqid[i] = nf->node->d.qid; } if(i < f->nwname && f->fid != f->newfid) { nf->busy = 0; nf->node = 0; nf->name = 0; nf->uid = 0; } if(i > 0 && i < f->nwname && f->fid == f->newfid) { /* * try to put things back; * we never get this sort of call from the kernel */ for(j=0; j<i; j++) walk("..", nf); } memmove(f->wqid, r.wqid, sizeof f->wqid); f->nwqid = i; if(err && i==0) reply(f, err); else reply(f, 0); }
/* * We don't have to do full permission checking because most files * have restricted semantics: * The ctl file is only writable * All others, including directories, are only readable */ static void ropen(Fcall *f) { Fid *fidp; int mode; fidp = newfid(f->fid); if(debugfd >= 0) printfid(fidp); mode = f->mode&(OREAD|OWRITE|ORDWR); if(fidp->node->d.type == Ctlfile) { if(mode != OWRITE) { reply(f, "permission denied"); return; } } else if (mode != OREAD) { reply(f, "permission denied or operation not supported"); return; } f->qid = fidp->node->d.qid; fidp->open = 1; reply(f, 0); }
/* * creates are only allowed in the "trusted" subdirectory * we also assume that the groupid == the uid */ static void rcreate(Fcall *f) { Fid *fidp; Node *np; fidp = newfid(f->fid); np = fidp->node; if((np->d.mode&DMDIR) == 0) { reply(f, "not a directory"); return; } if(!permitted(fidp, np, AWRITE)) { reply(f, "permission denied"); return; } /* Ignore the supplied mode and force it to be non-writable */ np = newnode(np, f->name, Trustedtemp, 0444, trustedqid++); if(trustedqid >= Qaddrfile) /* wrap QIDs */ trustedqid = Qtrustedfile; cidrparse(&np->ip, f->name); f->qid = np->d.qid; np->d.uid = fidp->uid; np->d.gid = np->d.uid; np->d.muid = np->d.muid; fidp->node = np; fidp->open = 1; reply(f, 0); return; }
void io(void) { char *err; int n, nerr; char buf[ERRMAX]; errstr(buf, sizeof buf); for(nerr=0, buf[0]='\0'; nerr<100; nerr++){ /* * reading from a pipe or a network device * will give an error after a few eof reads * however, we cannot tell the difference * between a zero-length read and an interrupt * on the processes writing to us, * so we wait for the error */ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n==0) continue; if(n < 0){ if(buf[0]=='\0') errstr(buf, sizeof buf); continue; } nerr = 0; buf[0] = '\0'; if(convM2S(mdata, n, &rhdr) != n) error("convert error in convM2S"); if(verbose) fprint(2, "tapefs: <=%F\n", &rhdr);/**/ thdr.data = (char*)mdata + IOHDRSZ; thdr.stat = mdata + IOHDRSZ; if(!fcalls[rhdr.type]) err = "bad fcall type"; else err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); if(err){ thdr.type = Rerror; thdr.ename = err; }else{ thdr.type = rhdr.type + 1; thdr.fid = rhdr.fid; } thdr.tag = rhdr.tag; n = convS2M(&thdr, mdata, messagesize); if(n <= 0) error("convert error in convS2M"); if(verbose) fprint(2, "tapefs: =>%F\n", &thdr);/**/ if(write(mfd[1], mdata, n) != n) error("mount write"); } if(buf[0]=='\0' || strstr(buf, "hungup")) exits(""); fprint(2, "%s: mount read: %s\n", argv0, buf); exits(buf); }
static void rclone(Fcall *f) { Fid *fidp, *nf; fidp = newfid(f->fid); if(fidp->node && fidp->node->d.type == Dummynode) { reply(f, "can't clone an address"); return; } nf = newfid(f->newfid); nf->busy = 1; nf->node = fidp->node; nf->uid = fidp->uid; nf->name = fidp->name; if(debugfd >= 0) printfid(nf); reply(f,0); }
void Xattach(Fsrpc *t) { Fcall rhdr; Fid *f; f = newfid(t->work.fid); if(f == 0) { reply(&t->work, &rhdr, Ebadfid); t->busy = 0; return; } if(srvfd >= 0){ /* if(psmpt == 0){ Nomount: reply(&t->work, &rhdr, Enopsmt); t->busy = 0; freefid(t->work.fid); return; } for(i=0; i<Npsmpt; i++) if(psmap[i] == 0) break; if(i >= Npsmpt) goto Nomount; sprint(buf, "%d", i); f->f = file(psmpt, buf); if(f->f == nil) goto Nomount; sprint(buf, "/mnt/exportfs/%d", i); nfd = dup(srvfd, -1); if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){ errstr(buf, sizeof buf); reply(&t->work, &rhdr, buf); t->busy = 0; freefid(t->work.fid); close(nfd); return; } psmap[i] = 1; f->mid = i; */ }else{ f->f = root; f->f->ref++; } rhdr.qid = f->f->qid; reply(&t->work, &rhdr, 0); t->busy = 0; }
static void rclunk(Fcall *f) { Fid *fidp; fidp = newfid(f->fid); fidp->open = 0; fidp->busy = 0; fidp->node = 0; fidp->name = 0; fidp->uid = 0; reply(f, 0); }
static int remov(int n, Rpccall *cmd, Rpccall *reply) { Session *s; Xfile *xp; Xfid *xf, *newxf; String elem; Fid *nfid; uchar *argptr = cmd->args; uchar *dataptr = reply->results; if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE; argptr += string2S(argptr, &elem); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); if(xf == 0) return error(reply, NFSERR_STALE); xp = xf->xp; if(!(xp->qid.type & QTDIR)) return error(reply, NFSERR_NOTDIR); chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s); if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#') return error(reply, NFSERR_PERM); newxf = xfwalkcr(Twalk, xf, &elem, 0); if(newxf == 0) return error(reply, NFSERR_NOENT); s = xp->s; nfid = newfid(s); setfid(s, newxf->urfid); s->f.newfid = nfid - s->fids; s->f.nwname = 0; if(xmesg(s, Twalk) < 0){ putfid(s, nfid); return error(reply, NFSERR_IO); } s->f.fid = nfid - s->fids; if(xmesg(s, Tremove) < 0){ putfid(s, nfid); return error(reply, NFSERR_PERM); } putfid(s, nfid); xpclear(newxf->xp); PLONG(NFS_OK); chat("OK\n"); return dataptr - (uchar *)reply->results; }
static void rwrite(Fcall *f) { Fid *fidp; int n; char *err, *argv[10]; fidp = newfid(f->fid); if(fidp->node->d.mode & DMDIR) { reply(f, "directories are not writable"); return; } if(fidp->open == 0) { reply(f, "file not open"); return; } if (!permitted(fidp, fidp->node, AWRITE)) { reply(f, "permission denied"); return; } f->data[f->count] = 0; /* the extra byte in rbuf leaves room */ n = tokenize(f->data, argv, 10); err = 0; switch(findkey(argv[0], cmds)) { case RELOAD: getconf(); reload(); break; case RDEBUG: if(n > 1) { debugfd = create(argv[1], OWRITE, 0666); if(debugfd < 0) err = "create failed"; } else debugfd = 2; break; case RNODEBUG: if(debugfd >= 0) close(debugfd); debugfd = -1; break; default: err = "unknown command"; break; } reply(f, err); }
Mfile* copyfid(Mfile *mf, int fid) { Mfile *nmf; nmf = newfid(fid, 1); if(nmf == nil) return nil; nmf->fid = fid; nmf->user = estrdup(mf->user); nmf->qid.type = mf->qid.type; nmf->qid.path = mf->qid.path; nmf->qid.vers = vers++; return nmf; }
static void rstat(Fcall *f) { Fid *fidp; fidp = newfid(f->fid); if (fidp->node->d.type == Dummynode) dummy.d.name = fidp->name; f->stat = (uchar*)rbuf+4+1+2+2; /* knows about stat(5) */ f->nstat = convD2M(&fidp->node->d, f->stat, MAXRPC); if(f->nstat <= BIT16SZ) reply(f, "ratfs: convD2M"); else reply(f, 0); return; }
static void filsysproc(void *arg) { int n; Xfid *x; Fid *f; Fcall t; uint8_t *buf; Filsys *fs; threadsetname("FILSYSPROC"); fs = arg; fs->pid = getpid(); x = nil; for(;;){ buf = emalloc(messagesize+UTFmax); /* UTFmax for appending partial rune in xfidwrite */ n = read9pmsg(fs->sfd, buf, messagesize); if(n <= 0){ yield(); /* if threadexitsall'ing, will not return */ fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n); errorshouldabort = 0; error("eof or i/o error on server channel"); } if(x == nil){ send(fs->cxfidalloc, nil); recv(fs->cxfidalloc, &x); x->fs = fs; } x->buf = buf; if(convM2S(buf, n, x) != n) error("convert error in convM2S"); if(DEBUG) fprint(2, "rio:<-%F\n", &x->Fcall); if(fcall[x->type] == nil) x = filsysrespond(fs, x, &t, Ebadfcall); else{ if(x->type==Tversion || x->type==Tauth) f = nil; else f = newfid(fs, x->fid); x->f = f; x = (*fcall[x->type])(fs, x, f); } firstmessage = 0; } }
void io(void) { char *err; int n; for(;;){ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n <= 0) break; if(convM2S(mdata, n, &rhdr) != n) sysfatal("convM2S conversion error"); if(dflag) fprint(2, "vacfs:<-%F\n", &rhdr); thdr.data = (char*)mdata + IOHDRSZ; if(!fcalls[rhdr.type]) err = "bad fcall type"; else err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); if(err){ thdr.type = Rerror; thdr.ename = err; #ifdef PLAN9PORT thdr.errornum = 0; #endif }else{ thdr.type = rhdr.type + 1; thdr.fid = rhdr.fid; } thdr.tag = rhdr.tag; if(dflag) fprint(2, "vacfs:->%F\n", &thdr); n = convS2M(&thdr, mdata, messagesize); if(n <= BIT16SZ) sysfatal("convS2M conversion error"); if(err) vtfree(err); if(write(mfd[1], mdata, n) != n) sysfatal("mount write: %r"); } }
/* * only directories can be read. everthing else returns EOF. */ static void rread(Fcall *f) { long cnt; Fid *fidp; cnt = f->count; f->count = 0; fidp = newfid(f->fid); f->data = (char*)rbuf+IOHDRSZ; if(fidp->open == 0) { reply(f, "file not open"); return; } if ((fidp->node->d.mode&DMDIR) == 0) { reply(f, 0); /*EOF*/ return; } if(cnt > MAXRPC) cnt = MAXRPC; if(f->offset == 0) fidp->dirindex = 0; switch(fidp->node->d.type) { case Directory: case Addrdir: case Trusted: f->count = dread(fidp, cnt); break; case IPaddr: case Acctaddr: f->count = hread(fidp, cnt); break; default: reply(f, "can't read this type of file"); return; } reply(f, 0); }
Xfid * setuser(Xfile *xp, char *user) { Xfid *xf, *xpf; Session *s; xf = xfid(user, xp, 1); if(xf->urfid) return xf; if(xp->parent==xp || !(xpf = setuser(xp->parent, user))) /* assign = */ return xfid(user, xp, -1); s = xp->s; xf->urfid = newfid(s); xf->urfid->owner = &xf->urfid; setfid(s, xpf->urfid); s->f.newfid = xf->urfid - s->fids; s->f.nwname = 1; s->f.wname[0] = xp->name; if(xmesg(s, Twalk) || s->f.nwqid != 1) return xfid(user, xp, -1); return xf; }
static void rattach(Fcall *f) { Fid *fidp; Dir *d; if((d=dirstat(conffile)) != nil && d->mtime > lastconftime) getconf(); free(d); if((d=dirstat(ctlfile)) != nil && d->mtime > lastctltime) reload(); free(d); cleantrusted(); fidp = newfid(f->fid); fidp->busy = 1; fidp->node = root; fidp->name = root->d.name; fidp->uid = atom(f->uname); f->qid = root->d.qid; reply(f,0); }
/* * no files or directories are removable; this becomes clunk; */ static void rremove(Fcall *f) { Fid *fidp; Node *dir, *np; fidp = newfid(f->fid); /* * only trusted temporary files can be removed * and only by their owner. */ if(fidp->node->d.type != Trustedtemp) { reply(f, "can't be removed"); return; } if(fidp->uid != fidp->node->d.uid) { reply(f, "permission denied"); return; } dir = fidp->node->parent; for(np = dir->children; np; np = np->sibs) if(np->sibs == fidp->node) break; if(np) np->sibs = fidp->node->sibs; else dir->children = fidp->node->sibs; dir->count--; free(fidp->node); fidp->node = 0; fidp->open = 0; fidp->busy = 0; fidp->name = 0; fidp->uid = 0; reply(f, 0); }
char* rwalk(Fid *f) { VacFile *file, *nfile; Fid *nf; int nqid, nwname; Qid qid; char *err = nil; if(f->busy == 0) return Enotexist; nf = nil; if(rhdr.fid != rhdr.newfid){ if(f->open) return vtstrdup(Eisopen); if(f->busy == 0) return vtstrdup(Enotexist); nf = newfid(rhdr.newfid); if(nf->busy) return vtstrdup(Eisopen); nf->busy = 1; nf->open = 0; nf->qid = f->qid; nf->file = vacfileincref(f->file); nf->user = vtstrdup(f->user); f = nf; } nwname = rhdr.nwname; /* easy case */ if(nwname == 0) { thdr.nwqid = 0; return 0; } file = f->file; vacfileincref(file); qid = f->qid; for(nqid = 0; nqid < nwname; nqid++){ if((qid.type & QTDIR) == 0){ err = Enotdir; break; } if(!permf(file, f->user, Pexec)) { err = Eperm; break; } nfile = vacfilewalk(file, rhdr.wname[nqid]); if(nfile == nil) break; vacfiledecref(file); file = nfile; qid.type = QTFILE; if(vacfileisdir(file)) qid.type = QTDIR; qid.vers = vacfilegetmcount(file); qid.path = vacfilegetid(file); thdr.wqid[nqid] = qid; } thdr.nwqid = nqid; if(nqid == nwname){ /* success */ f->qid = thdr.wqid[nqid-1]; vacfiledecref(f->file); f->file = file; return 0; } vacfiledecref(file); if(nf != nil) rclunk(nf); /* only error on the first element */ if(nqid == 0) return vtstrdup(err); return 0; }
char* rwalk(Fid *f) { Fid *nf; Ram *r; char *err; char *name; Ram *dir; int i; nf = nil; if(f->ram->busy == 0) return Enotexist; if(f->open) return Eisopen; if(rhdr.newfid != rhdr.fid){ nf = newfid(rhdr.newfid); nf->busy = 1; nf->open = 0; nf->rclose = 0; nf->ram = f->ram; nf->user = f->user; /* no ref count; the leakage is minor */ f = nf; } thdr.nwqid = 0; err = nil; r = f->ram; if(rhdr.nwname > 0){ for(i=0; i<rhdr.nwname; i++){ if((r->qid.type & QTDIR) == 0){ err = Enotdir; break; } if(r->busy == 0){ err = Enotexist; break; } r->atime = time(0); name = rhdr.wname[i]; dir = r; if(!perm(Pexec)){ err = Eperm; break; } if(strcmp(name, "..") == 0){ r = dir->parent; Accept: if(i == MAXWELEM){ err = "name too long"; break; } thdr.wqid[thdr.nwqid++] = r->qid; continue; } if(!dir->replete) popdir(dir); for(r=dir->child; r; r=r->next) if(r->busy && strcmp(name, r->name)==0) goto Accept; break; /* file not found */ } if(i==0 && err == nil) err = Enotexist; } if(err!=nil || thdr.nwqid<rhdr.nwname){ if(nf){ nf->busy = 0; nf->open = 0; nf->ram = 0; } }else if(thdr.nwqid == rhdr.nwname) f->ram = r; return err; }
static Xfid* filsyswalk(Filsys *fs, Xfid *x, Fid *f) { Fcall t; Fid *nf; int i, id; uint8_t type; uint32_t path; Dirtab *d, *dir; Window *w; char *err; Qid qid; if(f->open) return filsysrespond(fs, x, &t, "walk of open file"); nf = nil; if(x->fid != x->newfid){ /* BUG: check exists */ nf = newfid(fs, x->newfid); if(nf->busy) return filsysrespond(fs, x, &t, "clone to busy fid"); nf->busy = TRUE; nf->open = FALSE; nf->dir = f->dir; nf->qid = f->qid; nf->w = f->w; incref(f->w); nf->nrpart = 0; /* not open, so must be zero */ f = nf; /* walk f */ } t.nwqid = 0; err = nil; /* update f->qid, f->dir only if walk completes */ qid = f->qid; dir = f->dir; if(x->nwname > 0){ for(i=0; i<x->nwname; i++){ if((qid.type & QTDIR) == 0){ err = Enotdir; break; } if(strcmp(x->wname[i], "..") == 0){ type = QTDIR; path = Qdir; dir = dirtab; if(FILE(qid) == Qwsysdir) path = Qwsys; id = 0; Accept: if(i == MAXWELEM){ err = "name too long"; break; } qid.type = type; qid.vers = 0; qid.path = QID(id, path); t.wqid[t.nwqid++] = qid; continue; } if(qid.path == Qwsys){ /* is it a numeric name? */ if(!numeric(x->wname[i])) break; /* yes: it's a directory */ id = atoi(x->wname[i]); qlock(&all); w = wlookid(id); if(w == nil){ qunlock(&all); break; } path = Qwsysdir; type = QTDIR; qunlock(&all); incref(w); sendp(winclosechan, f->w); f->w = w; dir = dirtab; goto Accept; } if(snarffd>=0 && strcmp(x->wname[i], "snarf")==0) break; /* don't serve /dev/snarf if it's provided in the environment */ id = WIN(f->qid); d = dirtab; d++; /* skip '.' */ for(; d->name; d++) if(strcmp(x->wname[i], d->name) == 0){ path = d->qid; type = d->type; dir = d; goto Accept; } break; /* file not found */ } if(i==0 && err==nil) err = Eexist; } if(err!=nil || t.nwqid<x->nwname){ if(nf){ if(nf->w) sendp(winclosechan, nf->w); nf->open = FALSE; nf->busy = FALSE; } }else if(t.nwqid == x->nwname){ f->dir = dir; f->qid = qid; } return filsysrespond(fs, x, &t, err); }
void io(void) { volatile long n; volatile uchar mdata[IOHDRSZ + Maxfdata]; Job *volatile job; Mfile *volatile mf; volatile Request req; memset(&req, 0, sizeof req); /* * a slave process is sometimes forked to wait for replies from other * servers. The master process returns immediately via a longjmp * through 'mret'. */ if(setjmp(req.mret)) putactivity(0); req.isslave = 0; stop = 0; while(!stop){ procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms", stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms); n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n<=0){ dnslog("error reading 9P from %s: %r", mntpt); sleep(2000); /* don't thrash after read error */ return; } stats.qrecvd9prpc++; job = newjob(); if(convM2S(mdata, n, &job->request) != n){ freejob(job); continue; } mf = newfid(job->request.fid, 0); if(debug) dnslog("%F", &job->request); getactivity(&req, 0); req.aborttime = timems() + Maxreqtm; req.from = "9p"; switch(job->request.type){ default: warning("unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: /* &req is handed to dnresolve() */ rwrite(job, mf, &req); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat: rstat(job, mf); break; case Twstat: rwstat(job, mf); break; } freejob(job); /* * slave processes die after replying */ if(req.isslave){ putactivity(0); _exits(0); } putactivity(0); } /* kill any udp server, notifier, etc. processes */ postnote(PNGROUP, getpid(), "die"); sleep(1000); }
/* returns 0 if auth succeeded (or unneeded), -1 otherwise */ int authhostowner(Session *s) { Fid *af, *f; int rv = -1; int afd; AuthInfo *ai; AuthRpc *rpc; /* get a fid to authenticate over */ f = nil; af = newfid(s); s->f.afid = af - s->fids; s->f.uname = getuser(); s->f.aname = s->spec; if(xmesg(s, Tauth)){ /* not needed */ rv = 0; goto out; } quotefmtinstall(); /* just in case */ afd = open("/mnt/factotum/rpc", ORDWR); if(afd < 0){ werrstr("opening /mnt/factotum/rpc: %r"); goto out; } rpc = auth_allocrpc(afd); if(rpc == nil) goto out; ai = authproto(s, af, rpc, auth_getkey, "proto=p9any role=client"); if(ai != nil){ rv = 0; auth_freeAI(ai); } auth_freerpc(rpc); close(afd); /* try attaching with the afid */ chat("attaching as hostowner..."); f = newfid(s); s->f.fid = f - s->fids; s->f.afid = af - s->fids;; s->f.uname = getuser(); s->f.aname = s->spec; if(xmesg(s, Tattach) == 0) rv = 0; out: if(af != nil){ putfid(s, af); s->f.fid = af - s->fids; xmesg(s, Tclunk); } if(f != nil){ putfid(s, f); s->f.fid = f - s->fids; xmesg(s, Tclunk); } return rv; }
void ioproc0(void *v) { long n; Mfile *mf; uchar mdata[IOHDRSZ + Maxfdata]; Request req; Job *job; USED(v); for(;;){ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n <= 0){ syslog(0, logfile, "error reading mntpt: %r"); break; } job = newjob(); if(convM2S(mdata, n, &job->request) != n){ freejob(job); continue; } if(debug) syslog(0, logfile, "%F", &job->request); getactivity(&req); req.aborttime = now + 60; /* don't spend more than 60 seconds */ mf = nil; switch(job->request.type){ case Tversion: case Tauth: case Tflush: break; case Tattach: mf = newfid(job->request.fid, 1); if(mf == nil){ sendmsg(job, "fid in use"); goto skip; } break; default: mf = newfid(job->request.fid, 0); if(mf == nil){ sendmsg(job, "unknown fid"); goto skip; } break; } switch(job->request.type){ default: syslog(1, logfile, "unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: rwrite(job, mf, &req); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat: rstat(job, mf); break; case Twstat: rwstat(job, mf); break; } skip: freejob(job); putactivity(); } }
void srvinit(int fd, char *file, char *addr) { char fdservice[16], *naddr; Session *s; Xfile *xp; Xfid *xf; Fid *f; s = calloc(1, sizeof(Session)); s->spec = ""; s->fd = -1; if(fd >= 0){ s->fd = fd; sprint(fdservice, "/fd/%d", s->fd); s->service = strstore(fdservice); chat("fd = %d\n", s->fd); }else if(file){ chat("file = \"%s\"\n", file); s->service = file; s->fd = open(file, ORDWR); if(s->fd < 0){ clog("can't open %s: %r\n", file); goto error; } }else if(addr){ chat("addr = \"%s\"\n", addr); naddr = netmkaddr(addr, 0, "9fs"); s->service = addr; s->fd = dial(naddr, 0, 0, 0); if(s->fd < 0){ clog("can't dial %s: %r\n", naddr); goto error; } } chat("version..."); s->tag = NOTAG-1; s->f.msize = Maxfdata+IOHDRSZ; s->f.version = "9P2000"; xmesg(s, Tversion); messagesize = IOHDRSZ+s->f.msize; chat("version spec %s size %d\n", s->f.version, s->f.msize); s->tag = 0; chat("authenticate..."); if(authhostowner(s) < 0){ clog("auth failed %r\n"); goto error; } chat("attach as none..."); f = newfid(s); s->f.fid = f - s->fids; s->f.afid = ~0x0UL; s->f.uname = "none"; s->f.aname = s->spec; if(xmesg(s, Tattach)){ clog("attach failed\n"); goto error; } xp = xfile(&s->f.qid, s, 1); s->root = xp; xp->parent = xp; xp->name = "/"; xf = xfid("none", xp, 1); xf->urfid = f; clog("service=%s uid=%s fid=%ld\n", s->service, xf->uid, xf->urfid - s->fids); if(tail) tail->next = s; else head = s; tail = s; return; error: if(s->fd >= 0) close(s->fd); free(s); }
static void *job_thread(void *arg) { struct mfile *mf; struct job *job = arg; spinlock_lock(&dblock); mf = newfid(job->request.fid); if (debug) fprintf(stderr, "CS:%F", &job->request); switch (job->request.type) { default: fprintf(stderr, "CS:unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: rwrite(job, mf); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat: rstat(job, mf); break; case Twstat: rwstat(job, mf); break; } spinlock_unlock(&dblock); freejob(job); if (debug) fprintf(stderr, "CS:Job done\n"); return 0; }
static Xfid* fsyswalk(Xfid *x, Fid *f) { Fcall t; int c, i, j, id; Qid q; uint8_t type; uint32_t path; Fid *nf; Dirtab *d, *dir; Window *w; char *err; nf = nil; w = nil; if(f->open) return respond(x, &t, "walk of open file"); if(x->fid != x->newfid) { nf = newfid(x->newfid); if(nf->busy) return respond(x, &t, "newfid already in use"); nf->busy = TRUE; nf->open = FALSE; nf->mntdir = f->mntdir; if(f->mntdir) f->mntdir->ref++; nf->dir = f->dir; nf->qid = f->qid; nf->w = f->w; nf->nrpart = 0; /* not open, so must be zero */ if(nf->w) incref(nf->w); f = nf; /* walk f */ } t.nwqid = 0; err = nil; dir = nil; id = WIN(f->qid); q = f->qid; if(x->nwname > 0) { for(i=0; i<x->nwname; i++) { if((q.type & QTDIR) == 0) { err = Enotdir; break; } if(strcmp(x->wname[i], "..") == 0) { type = QTDIR; path = Qdir; id = 0; if(w) { winclose(w); w = nil; } Accept: if(i == MAXWELEM) { err = "name too long"; break; } q.type = type; q.vers = 0; q.path = QID(id, path); t.wqid[t.nwqid++] = q; continue; } /* is it a numeric name? */ for(j=0; (c=x->wname[i][j]); j++) if(c<'0' || '9'<c) goto Regular; /* yes: it's a directory */ if(w) /* name has form 27/23; get out before losing w */ break; id = atoi(x->wname[i]); qlock(&row); w = lookid(id, FALSE); if(w == nil) { qunlock(&row); break; } incref(w); /* we'll drop reference at end if there's an error */ path = Qdir; type = QTDIR; qunlock(&row); dir = dirtabw; goto Accept; Regular: // if(FILE(f->qid) == Qacme) /* empty directory */ // break; if(strcmp(x->wname[i], "new") == 0) { if(w) error("w set in walk to new"); sendp(cnewwindow, nil); /* signal newwindowthread */ w = recvp(cnewwindow); /* receive new window */ incref(w); type = QTDIR; path = QID(w->id, Qdir); id = w->id; dir = dirtabw; goto Accept; } if(id == 0) d = dirtab; else d = dirtabw; d++; /* skip '.' */ for(; d->name; d++) if(strcmp(x->wname[i], d->name) == 0) { path = d->qid; type = d->type; dir = d; goto Accept; } break; /* file not found */ } if(i==0 && err == nil) err = Eexist; } if(err!=nil || t.nwqid<x->nwname) { if(nf) { nf->busy = FALSE; fsysdelid(nf->mntdir); } } else if(t.nwqid == x->nwname) { if(w) { f->w = w; w = nil; /* don't drop the reference */ } if(dir) f->dir = dir; f->qid = q; } if(w != nil) winclose(w); return respond(x, &t, err); }
static char *rwalk(struct job *job, struct mfile *mf) { char *err; char **elems; int nelems; int i; struct mfile *nmf; struct qid qid; err = 0; nmf = NULL; elems = job->request.wname; nelems = job->request.nwname; job->reply.nwqid = 0; if (job->request.newfid != job->request.fid) { /* clone fid */ nmf = newfid(job->request.newfid); if (nmf->busy) { nmf = NULL; err = "clone to used channel"; goto send; } *nmf = *mf; nmf->user = estrdup(mf->user); nmf->fid = job->request.newfid; nmf->qid.vers = vers++; mf = nmf; } /* else nmf will be nil */ qid = mf->qid; if (nelems > 0) { /* walk fid */ for (i = 0; i < nelems && i < MAXWELEM; i++) { if ((qid.type & QTDIR) == 0) { err = "not a directory"; break; } if (strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0) { qid.type = QTDIR; qid.path = Qdir; Found: job->reply.wqid[i] = qid; job->reply.nwqid++; continue; } if (strcmp(elems[i], "cs") == 0) { qid.type = QTFILE; qid.path = Qcs; goto Found; } err = "file does not exist"; break; } } send: if (nmf != NULL && (err != NULL || job->reply.nwqid < nelems)) { cleanmf(nmf); free(nmf->user); nmf->user = 0; nmf->busy = 0; nmf->fid = 0; } if (err == NULL) mf->qid = qid; sendmsg(job, err); return err; }