123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- /*
- * 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.
- */
- /*
- * ``Exec'' network device. Mounted on net, provides /net/exec.
- *
- * exec protocol directory
- * n connection directory
- * ctl control messages (like connect)
- * data data
- * err errors
- * local local address (pid of command)
- * remote remote address (command)
- * status status
- */
- #include <u.h>
- #include <libc.h>
- #include <fcall.h>
- #include <thread.h>
- #include <9p.h>
- #include "dat.h"
- int fsdebug;
- enum
- {
- Qroot,
- Qexec,
- Qclone,
- Qn,
- Qctl,
- Qdata,
- Qlocal,
- Qremote,
- Qstatus,
- };
- #define PATH(type, n) ((type)|((n)<<8))
- #define TYPE(path) ((int)(path) & 0xFF)
- #define NUM(path) ((uint)(path)>>8)
- typedef struct Tab Tab;
- struct Tab
- {
- char *name;
- uint32_t mode;
- };
- Tab tab[] =
- {
- "/", DMDIR|0555,
- "exec", DMDIR|0555,
- "clone", 0666,
- nil, DMDIR|0555,
- "ctl", 0666,
- "data", 0666,
- "local", 0444,
- "remote", 0444,
- "status", 0444,
- };
- void
- setexecname(char *s)
- {
- tab[Qexec].name = s;
- }
- uint32_t time0;
- static void
- fillstat(Dir *d, uint32_t path)
- {
- Tab *t;
- int type;
- char buf[32];
- memset(d, 0, sizeof(*d));
- d->uid = estrdup("exec");
- d->gid = estrdup("exec");
- d->qid.path = path;
- d->atime = d->mtime = time0;
- d->length = 0;
- type = TYPE(path);
- t = &tab[type];
- if(t->name)
- d->name = estrdup(t->name);
- else{
- snprint(buf, sizeof buf, "%u", NUM(path));
- d->name = estrdup(buf);
- }
- d->qid.type = t->mode>>24;
- d->mode = t->mode;
- }
- static void
- fsstat(Req *r)
- {
- fillstat(&r->d, r->fid->qid.path);
- respond(r, nil);
- }
- static int
- rootgen(int i, Dir *d, void*)
- {
- if(i < 1){
- fillstat(d, PATH(Qexec, 0));
- return 0;
- }
- return -1;
- }
- static int
- execgen(int i, Dir *d, void*)
- {
- if(i < 1){
- fillstat(d, PATH(Qclone, 0));
- return 0;
- }
- i -= 1;
- if(i < nclient){
- fillstat(d, PATH(Qn, i));
- return 0;
- }
- return -1;
- }
- static int
- conngen(int i, Dir *d, void *aux)
- {
- Client *c;
- c = aux;
- i += Qn+1;
- if(i <= Qstatus){
- fillstat(d, PATH(i, c->num));
- return 0;
- }
- return -1;
- }
- char *statusstr[] =
- {
- "Closed",
- "Exec",
- "Established",
- "Hangup",
- };
- static void
- fsread(Req *r)
- {
- char e[ERRMAX], *s;
- uint32_t path;
- path = r->fid->qid.path;
- switch(TYPE(path)){
- default:
- snprint(e, sizeof e, "bug in execnet path=%lx", path);
- respond(r, e);
- break;
- case Qroot:
- dirread9p(r, rootgen, nil);
- respond(r, nil);
- break;
- case Qexec:
- dirread9p(r, execgen, nil);
- respond(r, nil);
- break;
- case Qn:
- dirread9p(r, conngen, client[NUM(path)]);
- respond(r, nil);
- break;
- case Qctl:
- snprint(e, sizeof e, "%u", NUM(path));
- readstr(r, e);
- respond(r, nil);
- break;
- case Qdata:
- dataread(r, client[NUM(path)]);
- break;
- case Qlocal:
- snprint(e, sizeof e, "%d", client[NUM(path)]->pid);
- readstr(r, e);
- respond(r, nil);
- break;
- case Qremote:
- s = client[NUM(path)]->cmd;
- if(strlen(s) >= 5) /* "exec " */
- readstr(r, s+5);
- else
- readstr(r, s);
- respond(r, nil);
- break;
- case Qstatus:
- readstr(r, statusstr[client[NUM(path)]->status]);
- respond(r, nil);
- break;
- }
- }
- static void
- fswrite(Req *r)
- {
- char e[ERRMAX];
- uint32_t path;
- path = r->fid->qid.path;
- switch(TYPE(path)){
- default:
- snprint(e, sizeof e, "bug in execnet path=%lx", path);
- respond(r, e);
- break;
- case Qctl:
- ctlwrite(r, client[NUM(path)]);
- break;
- case Qdata:
- datawrite(r, client[NUM(path)]);
- break;
- }
- }
- static void
- fsflush(Req *r)
- {
- uint32_t path;
- Req *or;
- for(or=r; or->ifcall.type==Tflush; or=or->oldreq)
- ;
- if(or->ifcall.type != Tread && or->ifcall.type != Twrite)
- abort();
- path = or->fid->qid.path;
- if(TYPE(path) != Qdata)
- abort();
- clientflush(or, client[NUM(path)]);
- respond(r, nil);
- }
- static void
- fsattach(Req *r)
- {
- if(r->ifcall.aname && r->ifcall.aname[0]){
- respond(r, "invalid attach specifier");
- return;
- }
- r->fid->qid.path = PATH(Qroot, 0);
- r->fid->qid.type = QTDIR;
- r->fid->qid.vers = 0;
- r->ofcall.qid = r->fid->qid;
- respond(r, nil);
- }
- static char*
- fswalk1(Fid *fid, char *name, Qid *qid)
- {
- char buf[32];
- int i, n;
- uint32_t path;
- if(!(fid->qid.type&QTDIR))
- return "walk in non-directory";
- path = fid->qid.path;
- if(strcmp(name, "..") == 0){
- switch(TYPE(path)){
- case Qn:
- qid->path = PATH(Qexec, 0);
- qid->type = QTDIR;
- return nil;
- case Qroot:
- case Qexec:
- qid->path = PATH(Qroot, 0);
- qid->type = QTDIR;
- return nil;
- default:
- return "bug in fswalk1";
- }
- }
- i = TYPE(path)+1;
- for(; i<nelem(tab); i++){
- if(i==Qn){
- n = atoi(name);
- snprint(buf, sizeof buf, "%d", n);
- if(n < nclient && strcmp(buf, name) == 0){
- qid->path = PATH(Qn, n);
- qid->type = QTDIR;
- return nil;
- }
- break;
- }
- if(strcmp(tab[i].name, name) == 0){
- qid->path = PATH(i, NUM(path));
- qid->type = tab[i].mode>>24;
- return nil;
- }
- if(tab[i].mode&DMDIR)
- break;
- }
- return "directory entry not found";
- }
- static void
- fsopen(Req *r)
- {
- static int need[4] = { 4, 2, 6, 1 };
- uint32_t path;
- int n;
- Tab *t;
- /*
- * lib9p already handles the blatantly obvious.
- * we just have to enforce the permissions we have set.
- */
- path = r->fid->qid.path;
- t = &tab[TYPE(path)];
- n = need[r->ifcall.mode&3];
- if((n&t->mode) != n){
- respond(r, "permission denied");
- return;
- }
- switch(TYPE(path)){
- case Qclone:
- n = newclient();
- path = PATH(Qctl, n);
- r->fid->qid.path = path;
- r->ofcall.qid.path = path;
- if(fsdebug)
- fprint(2, "open clone => path=%lx\n", path);
- t = &tab[Qctl];
- /* fall through */
- default:
- if(t-tab >= Qn)
- client[NUM(path)]->ref++;
- respond(r, nil);
- break;
- }
- }
- Channel *cclunk;
- Channel *cclunkwait;
- Channel *creq;
- Channel *creqwait;
- static void
- fsthread(void*)
- {
- uint32_t path;
- Alt a[3];
- Fid *fid;
- Req *r;
- threadsetname("fsthread");
- a[0].op = CHANRCV;
- a[0].c = cclunk;
- a[0].v = &fid;
- a[1].op = CHANRCV;
- a[1].c = creq;
- a[1].v = &r;
- a[2].op = CHANEND;
- for(;;){
- switch(alt(a)){
- case 0:
- path = fid->qid.path;
- if(fid->omode != -1 && TYPE(path) >= Qn)
- closeclient(client[NUM(path)]);
- sendp(cclunkwait, nil);
- break;
- case 1:
- switch(r->ifcall.type){
- case Tattach:
- fsattach(r);
- break;
- case Topen:
- fsopen(r);
- break;
- case Tread:
- fsread(r);
- break;
- case Twrite:
- fswrite(r);
- break;
- case Tstat:
- fsstat(r);
- break;
- case Tflush:
- fsflush(r);
- break;
- default:
- respond(r, "bug in fsthread");
- break;
- }
- sendp(creqwait, 0);
- break;
- }
- }
- }
- static void
- fsdestroyfid(Fid *fid)
- {
- sendp(cclunk, fid);
- recvp(cclunkwait);
- }
- static void
- fssend(Req *r)
- {
- sendp(creq, r);
- recvp(creqwait); /* avoids need to deal with spurious flushes */
- }
- void
- initfs(void)
- {
- time0 = time(0);
- creq = chancreate(sizeof(void*), 0);
- creqwait = chancreate(sizeof(void*), 0);
- cclunk = chancreate(sizeof(void*), 0);
- cclunkwait = chancreate(sizeof(void*), 0);
- procrfork(fsthread, nil, STACK, RFNAMEG);
- }
- Srv fs =
- {
- .attach= fssend,
- .destroyfid= fsdestroyfid,
- .walk1= fswalk1,
- .open= fssend,
- .read= fssend,
- .write= fssend,
- .stat= fssend,
- .flush= fssend,
- };
|