ref: 6c6f09d989e5db7242365e6844c67b618192f996
dir: /src/execfs/execfs.c/
#include <u.h> #include <libc.h> #include <fcall.h> #include <thread.h> #include <9p.h> #include <bio.h> #include <regexp.h> typedef struct Xrule Xrule; typedef struct Xfile Xfile; struct Xrule { Reprog *re; char *sub; Xrule *next; }; struct Xfile { char *path; char *dest; int fd; }; Xrule *rules; void readrules(char *file) { Biobuf *bio; char *s, *p, *d; if((bio = Bopen(file, OREAD)) == nil) sysfatal("open: %r"); while(s = Brdstr(bio, '\n', 1)){ Xrule *r; p = s; while(strchr("\t ", *p)) p++; d = nil; if(*p != '#'){ if(d = strchr(p, '\t')) *d++ = 0; else if(d = strchr(p, ' ')) *d++ = 0; } if(d == nil){ free(s); continue; } while(strchr("\t ", *d)) d++; r = emalloc9p(sizeof(*r)); if(r->re = regcomp(p)){ r->sub = estrdup9p(d); r->next = rules; rules = r; } else { fprint(2, "regcomp failed: %s\n", p); free(r); } free(s); } Bterm(bio); } char* matchrule(char *path) { Xrule *r; Resub m[16]; char *s; for(r = rules; r; r = r->next){ memset(m, 0, sizeof(m)); if(regexec(r->re, path, m, nelem(m))){ s = emalloc9p(1024); regsub(r->sub, s, 1024, m, nelem(m)); return s; } } return nil; } ulong hash(char *s) { ulong h, t; char c; h = 0; while(c = *s++){ t = h & 0xf8000000; h <<= 5; h ^= t>>27; h ^= (ulong)c; } return h; } void fsattach(Req *req) { Xfile *x; if(req->ifcall.aname && req->ifcall.aname[0]){ respond(req, "invalid attach specifier"); return; } x = emalloc9p(sizeof(*x)); x->path = estrdup9p(""); x->dest = nil; x->fd = -1; req->fid->aux = x; req->fid->qid.path = hash(x->path); req->fid->qid.type = QTDIR; req->fid->qid.vers = 0; req->ofcall.qid = req->fid->qid; respond(req, nil); } char* fswalk1(Fid *fid, char *name, Qid *qid) { Xfile *x; char *p; if(fid->qid.type != QTDIR) return "walk in non-directory"; x = fid->aux; if(strcmp(name, ".") == 0){ } else if(strcmp(name, "..") == 0){ if(p = strrchr(x->path, '/')) *p = 0; } else { p = smprint("%s/%s", x->path, name); free(x->path); x->path = p; } fid->qid.path = hash(x->path); if(x->dest = matchrule(x->path)) fid->qid.type = QTFILE; else fid->qid.type = QTDIR; if(qid) *qid = fid->qid; return nil; } char* fsclone(Fid *old, Fid *new) { Xfile *x; x = emalloc9p(sizeof(*x)); memmove(x, old->aux, sizeof(*x)); if(x->path) x->path = estrdup9p(x->path); if(x->dest) x->dest = estrdup9p(x->dest); new->aux = x; return nil; } void fsstat(Req *req) { Xfile *x; char *p; Dir *d; x = req->fid->aux; d = &req->d; memset(d, 0, sizeof(*d)); d->uid = estrdup9p("execfs"); d->gid = estrdup9p("execfs"); d->atime = d->mtime = time(0); if(p = strrchr(x->path, '/')) d->name = estrdup9p(p+1); else d->name = estrdup9p("/"); if(x->dest){ d->qid.type = QTFILE; d->mode = 0444; }else { d->qid.type = QTDIR; d->mode = DMDIR|0555; } respond(req, nil); } void fsread(Req *req) { int n, pfd[2]; Xfile *x; Srv *srv; x = req->fid->aux; if(x->dest == nil){ req->ofcall.count = 0; respond(req, nil); return; } if(x->fd < 0){ if(pipe(pfd) < 0){ responderror(req); return; } if(rfork(RFPROC|RFNOWAIT|RFFDG|RFREND) == 0){ char *argv[4]; int i; argv[0] = "rc"; argv[1] = "-c"; argv[2] = x->dest; argv[3] = nil; close(0); open("/dev/null", OREAD); dup(pfd[1], 1); dup(pfd[1], 2); for(i=3; i<20; i++) close(i); exec("/bin/rc", argv); exits("exec"); } x->fd = pfd[0]; close(pfd[1]); } srvrelease(srv = req->srv); if((n = read(x->fd, req->ofcall.data, req->ifcall.count)) < 0) responderror(req); else { req->ofcall.count = n; respond(req, nil); } srvacquire(srv); } void fsclunk(Fid *fid) { Xfile *x; if(x = fid->aux){ fid->aux = nil; if(x->fd >= 0) close(x->fd); free(x->path); free(x->dest); free(x); } } Srv fs = { .attach = fsattach, .stat = fsstat, .read = fsread, .walk1 = fswalk1, .clone = fsclone, .destroyfid = fsclunk, }; void usage(void) { fprint(2, "usage: %s [-D] [-m mtpt] [-s srv] rulefile\n", argv0); exits("usage"); } void main(int argc, char *argv[]) { char *srv, *mtpt; srv = nil; mtpt = "/n/execfs"; ARGBEGIN { case 'D': chatty9p++; break; case 'm': mtpt = EARGF(usage()); break; case 's': srv = EARGF(usage()); break; default: usage(); } ARGEND; if(argc != 1) usage(); readrules(*argv); postmountsrv(&fs, srv, mtpt, MREPL); }