diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/execnet/fs.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/execnet/fs.c')
-rwxr-xr-x | sys/src/cmd/execnet/fs.c | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/sys/src/cmd/execnet/fs.c b/sys/src/cmd/execnet/fs.c new file mode 100755 index 000000000..7f734358b --- /dev/null +++ b/sys/src/cmd/execnet/fs.c @@ -0,0 +1,451 @@ +/* + * ``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; + ulong 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; +} + +ulong time0; + +static void +fillstat(Dir *d, ulong 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, "%ud", 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; + ulong path; + + path = r->fid->qid.path; + switch(TYPE(path)){ + default: + snprint(e, sizeof e, "bug in execnet path=%lux", 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, "%ud", 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]; + ulong path; + + path = r->fid->qid.path; + switch(TYPE(path)){ + default: + snprint(e, sizeof e, "bug in execnet path=%lux", 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) +{ + ulong 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; + ulong 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 }; + ulong 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=%lux\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*) +{ + ulong 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, +}; |