/* Copyright (c) 20XX 9front * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include <9P2000.h> #include <9p.h> #include "dat.h" #include "fns.h" extern Fs *fsmain; static void tauth(Req *req) { if((fsmain->flags & FSNOAUTH) != 0) respond(req, "no authentication required"); else auth9p(req); } static void tattach(Req *req) { Chan *ch; int flags; short uid; if((fsmain->flags & FSNOAUTH) == 0 && authattach(req) < 0) return; if(name2uid(fsmain, req->ifcall.uname, &uid) <= 0){ respond(req, "no such user"); return; } if(req->ifcall.aname == nil || *req->ifcall.aname == 0) flags = 0; else if(strcmp(req->ifcall.aname, "dump") == 0) flags = CHFDUMP|CHFRO; else{ respond(req, Einval); return; } ch = chanattach(fsmain, flags); ch->uid = uid; req->fid->aux = ch; req->fid->qid = ch->loc->Qid; req->ofcall.qid = ch->loc->Qid; respond(req, nil); } static void tqueue(Req *req) { Chan *ch; if((req->fid->qid.type & QTAUTH) != 0){ switch(req->ifcall.type){ case Tread: authread(req); return; case Twrite: authwrite(req); return; default: respond(req, Einval); return; } } ch = req->fid->aux; if(ch == nil){ respond(req, "operation on closed fid"); return; } qlock(&chanqu); req->aux = nil; if(ch->freq == nil) ch->freq = req; if(ch->lreq != nil) ((Req *) ch->lreq)->aux = req; ch->lreq = req; if(ch->qnext == nil && (ch->wflags & CHWBUSY) == 0){ ch->qnext = &readych; ch->qprev = ch->qnext->qprev; ch->qnext->qprev = ch; ch->qprev->qnext = ch; rwakeup(&chanre); } if(req->ifcall.type == Tremove) req->fid->aux = nil; qunlock(&chanqu); } static void tdestroyfid(Fid *fid) { Chan *ch; if((fid->qid.type & QTAUTH) != 0){ authdestroy(fid); return; } qlock(&chanqu); ch = fid->aux; fid->aux = nil; if(ch != nil){ ch->wflags |= CHWCLUNK; if(ch->qnext == nil && (ch->wflags & CHWBUSY) == 0){ ch->qnext = &readych; ch->qprev = ch->qnext->qprev; ch->qnext->qprev = ch; ch->qprev->qnext = ch; rwakeup(&chanre); } } qunlock(&chanqu); } static void tend(Srv* _) { shutdown(); } static Srv mysrv = { .auth = tauth, .attach = tattach, .walk = tqueue, .open = tqueue, .create = tqueue, .read = tqueue, .write = tqueue, .stat = tqueue, .wstat = tqueue, .remove = tqueue, .destroyfid = tdestroyfid, .end = tend, }; void start9p(char *service, char **nets, int stdio) { while(nets && *nets){ mysrv.end = nil; /* disable shutdown */ threadlistensrv(&mysrv, *nets++); } if(stdio){ mysrv.infd = 1; mysrv.outfd = 1; srv(&mysrv); }else threadpostmountsrv(&mysrv, service, nil, 0); } static int twalk(Chan *ch, Fid *fid, Fid *nfid, int n, char **name, Qid *qid) { int i; if(nfid != fid){ if(ch->open != 0){ werrstr("trying to clone an open fid"); return -1; } ch = chanclone(ch); if(ch == nil) return -1; nfid->aux = ch; nfid->qid = ch->loc->Qid; } for(i = 0; i < n; i++){ if(chanwalk(ch, name[i]) <= 0) return i > 0 ? i : -1; qid[i] = ch->loc->Qid; nfid->qid = ch->loc->Qid; } return n; } static void workerproc(void* _) { Chan *ch; Req *req; int rc; Fcall *i, *o; qlock(&chanqu); for(;;){ while(readych.qnext == &readych) rsleep(&chanre); ch = readych.qnext; ch->qnext->qprev = ch->qprev; ch->qprev->qnext = ch->qnext; ch->qprev = nil; ch->qnext = nil; assert((ch->wflags & CHWBUSY) == 0); ch->wflags |= CHWBUSY; while(ch != nil && ch->freq != nil){ req = ch->freq; ch->freq = req->aux; if(ch->lreq == req) ch->lreq = nil; req->aux = nil; qunlock(&chanqu); assert(req->responded == 0); i = &req->ifcall; o = &req->ofcall; switch(req->ifcall.type){ case Twalk: rc = twalk(ch, req->fid, req->newfid, i->nwname, i->wname, o->wqid); if(rc >= 0) o->nwqid = rc; break; case Topen: rc = chanopen(ch, i->mode); break; case Tcreate: rc = chancreat(ch, i->name, i->perm, i->mode); if(rc >= 0){ o->qid = ch->loc->Qid; req->fid->qid = o->qid; } break; case Tread: rc = o->count = chanread(ch, o->data, i->count, i->offset); break; case Twrite: rc = o->count = chanwrite(ch, i->data, i->count, i->offset); break; case Tremove: rc = chanremove(ch); req->fid->aux = ch = nil; break; case Tstat: rc = chanstat(ch, &req->d); break; case Twstat: rc = chanwstat(ch, &req->d); break; default: werrstr(Einval); rc = -1; } if(rc < 0) responderror(req); else respond(req, nil); qlock(&chanqu); } if(ch != nil){ ch->wflags &= ~CHWBUSY; if((ch->wflags & CHWCLUNK) != 0) chanclunk(ch); } } } QLock chanqu; Chan readych; Rendez chanre; void workerinit(void) { int i; readych.qnext = readych.qprev = &readych; chanre.l = &chanqu; for(i = 0; i < NWORKERS; i++) threadcreate(workerproc, nil, mainstacksize); }