// Put // 8c -w actionfs.c && 8l actionfs.8 && mv 8.out /usr/maht/bin/386/actionfs #include #include #include #include #include <9p.h> #include #include typedef struct Path Path; struct Path { Qid qid; char *name; Path *next; }; Reprog *freg; Path *root = nil; int nmatches; int client = 0; static void fsattach(Req *r) { r->ofcall.qid = (Qid){0, ++client, QTDIR}; r->fid->qid = r->ofcall.qid; respond(r, nil); } static void print_qid(Qid *q) { print("p %x v %d f %x\n", q->path, q->vers, q->type); } static void print_matches(Resub *matches) { if(!matches) { print("No match\n"); return; } char *bit; int i, k; for(i = 0; i < nmatches; i++) { k = (matches[i].ep - matches[i].sp) + 1; bit = (char*)malloc(k); strecpy(bit, bit + k, matches[i].sp); free(bit); } print("\n"); } static void print_path(Path *p) { print("Name: %s\n", p->name); print_qid(&p->qid); print("Next: %x\n", p->next); } static Resub* re(char *txt) { Resub* matches = (Resub*)calloc(nmatches, sizeof(Resub)); if(regexec(freg, txt, matches, nmatches)) return matches; free(matches); return nil; } static Path* find_path(Qid *qid) { Path *p; for(p = root; p; p = p->next) if(qid->path == p->qid.path) break; return p; } static Path* find_prev_path(Qid *qid) { Path *p; for(p = root; p; p = p->next) { if(p->next && (qid->path == p->next->qid.path)) break; } return p; } static Qid* find_qid(char *name) { Path *p; Resub *m; for(p = root; p; p = p->next) if(strcmp(name, p->name) == 0) return &p->qid; if(!(m = re(name))) return nil; free(m); p = (Path*)mallocz(sizeof(Path), 1); p->qid.path = root ? root->qid.path +1 : 1; p->qid.vers = 0; p->next = root; p->name = strdup(name); root = p; return &root->qid; } static char* fswalk1(Fid *fid, char *name, Qid *qid) { Qid *q; if(!(q = find_qid(name))) return "Not Found"; q->vers++; memcpy(qid, q, sizeof(Qid)); memcpy(&fid->qid, q, sizeof(Qid)); return nil; } static void fsstat(Req *r) { Path *p; Dir *d = &r->d; memset(d, 0, sizeof *d); d->uid = strdup("inband"); d->gid = strdup("inband"); p = find_path(&r->fid->qid); d->name = strdup(p->name); d->mode = 0444; memcpy(&d->qid, &(r->fid->qid), sizeof(Qid)); d->length = 0; respond(r, nil); } char ** build_argv(int fd, char *name) { char **argv = malloc(sizeof(char*) * (nmatches + 3)); if(fd > 0) argv[0] = smprint("action-read"); else argv[0] = smprint("action-write"); argv[1] = smprint("%d", abs(fd)); Resub *matches = re(name); int i, j, k; for(i = 0, j = 2; i < nmatches; i++, j++) { k = (matches[i].ep - matches[i].sp) + 1; argv[j] = (char*)mallocz(k + 1, 1); strecpy(argv[j], argv[j] + k, matches[i].sp); } argv[j] = nil; return argv; } static char * do_action(char *action, int fd, Path *p) { char **argv = build_argv(fd, p->name); char *error = nil; int i; switch(fork()) { case 0 : exec(action, argv); error = "exec failed"; break; case -1 : error = "fork failed"; break; default : wait(); for(i = 0; i < nmatches+2; i++) free(argv[i]); free(argv); break; } return error; } static void fsopen(Req *r) { int fd; switch(r->ifcall.mode & 1) { // discard OTRUNC etc. case OREAD : fd = create(tmpnam(nil), ORDWR|ORCLOSE, 0600); if(fd < 1) { // assume fd 0 is taken ! respond(r, "/tmp/$file create failed"); return; } break; case OWRITE : fd = create(tmpnam(nil), ORDWR|ORCLOSE, 0600); if(fd < 1) { // assume fd 0 is taken ! respond(r, "/tmp/$file create failed"); return; } fd = -fd; break; default : respond(r, "permission denied"); return; } r->fid->aux = (void*)fd; Path *p = find_path(&r->fid->qid); char *error = nil; if(fd > 0) error = do_action("/bin/action-read", fd, p); respond(r, error); } static void remove_path(Path *p) { Path *pp; pp = find_prev_path(&p->qid); if(pp) pp->next = p->next; else root = nil; free(p->name); free(p); } static void fsclose(Fid *fid) { if(fid->aux) close(abs((int)fid->aux)); Path *p = find_path(&fid->qid); if(p && p->qid.path) // p *should* always be non null if(--p->qid.vers == 0) remove_path(p); } static void fsclunk(Fid *fid) { Path *p = find_path(&fid->qid); if((int)fid->aux < 0) { seek(abs((int)fid->aux), 0, 0); do_action("/bin/action-write", (int)fid->aux, p); } if(fid->aux) close(abs((int)fid->aux)); if(p && p->qid.path) // p *should* always be non null if(--p->qid.vers == 0) remove_path(p); } static void fsread(Req *r) { seek((int)r->fid->aux, r->ifcall.offset, 0); int k = read((int)r->fid->aux, r->ofcall.data, r->ifcall.count); if(k < 0) respond(r, "Read failed"); r->ofcall.count = k; respond(r, nil); } static void fswrite(Req *r) { seek(abs((int)r->fid->aux), r->ifcall.offset, 0); int k = write(abs((int)r->fid->aux), r->ifcall.data, r->ifcall.count); if(k < 0) respond(r, "Write failed"); r->ofcall.count = k; respond(r, nil); } Srv numsrv = { .attach= fsattach, .walk1= fswalk1, .open= fsopen, .read= fsread, .write= fswrite, .stat= fsstat, .destroyfid = fsclunk, }; static int num_matches(char *txt){ int i = 0; char *p; for(p = txt; p ; i++) { p = strchr(p, '('); if(p) p++; } return i ? i : 1; } extern int chatty9p; void main(int argc, char **argv) { char *mtpt, *service; char *reg; ARGBEGIN{ case 'D': chatty9p++; break; }ARGEND if(argc == 1) reg = argv[0]; else reg = ".*"; nmatches = num_matches(reg); freg = regcomp(reg); mtpt = "/n/actionfs"; service = "actionfs"; chdir("/tmp"); postmountsrv(&numsrv, service, mtpt, MREPL); exits(nil); }