From mboxrd@z Thu Jan 1 00:00:00 1970 Message-ID: To: 9fans@cse.psu.edu Subject: Re: [9fans] watch command From: YAMANASHI Takeshi <9.nashi@gmail.com> Date: Wed, 20 Apr 2005 10:55:09 +0900 MIME-Version: 1.0 Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit Topicbox-Message-UUID: 3dfce87c-ead0-11e9-9d60-3106f5b1d025 Anyway, it's here: % mk install % watchfs main.c "cat /n/watch/ctl" will block until a change has been made to /n/watch/data/main.c. KNOWN BUGS: - it doesn't care about Tflush yet. - it only accepts files in the current directory. # To unbundle, run this file echo mkfile sed 's/.//' >mkfile <<'//GO.SYSIN DD mkfile' -main.c <<'//GO.SYSIN DD main.c' -#include -#include -#include -#include -#include -#include <9p.h> - -int dbg; - -char *uname; -Channel *cctl, *cctlwait; -Channel *pctl, *pctlwait; -Channel *creq; - -typedef struct Watchfile Watchfile; -struct Watchfile { - Ref; - Qid qid; - int fd; - char *name; - int dirty; -}; - -Watchfile wtab[10]; -int nw; - -void wtopen(Req*); -void wtread(Req*); -void wtwrite(Req*); -void wtdestroyfid(Fid*); -void takedown(Srv*); - -enum{ - Qdata= 0, - Qctl= 1, - - STACK = 8192, -}; - -int chatty9p; -Srv fs = { - .open= wtopen, - .read= wtread, - .write= wtwrite, - .destroyfid = wtdestroyfid, - .end= takedown, -}; - -static void -dumpQid(Dir *d) -{ - ulong path; - path = d->qid.path; - fprint(2, "name=%s qid=%lux\n", d->name, path); -} - -static void -dumpWF(void) -{ - int i; - - for(i=0; ifid->qid.path; - switch(path){ - case Qctl: - case Qdata: - respond(r, nil); - return; - } - - /* data/... */ - wf = findtab(path); - if(wf == nil){ - respond(r, "no file"); - return; - } - if(dbg) - fprint(2, "wtopen: %s %ld fd %d\n", wf->name, wf->ref, wf->fd); - - incref(wf); - if(wf->fd < 0){ - wf->fd = open(wf->name, r->ifcall.mode); - wf->dirty = 0; - } - if(r->ifcall.mode&OTRUNC) - r->fid->file->length = 0; - respond(r, nil); -} - -void -wtread(Req *r) -{ - char buf[512]; - int n; - ulong path; - Watchfile *wf; - - path = r->fid->qid.path; - switch(path){ - case Qdata: - case Qctl: - sendp(creq, r); - return; - } - - /* data/... */ - wf = findtab(r->fid->qid.path); - if(wf == nil){ - respond(r, "no such qid"); - return; - } - if(wf->fd < 0){ - respond(r, "no fd"); - return; - } - if(dbg) - fprint(2, "wtread: %s ref %ld fd %d\n", wf->name, wf->ref, wf->fd); - n = pread(wf->fd, r->ofcall.data, r->ifcall.count, r->ifcall.offset); - if(n < 0){ - rerrstr(buf, sizeof buf); - respond(r, buf); - return; - } - r->ofcall.count = n; - respond(r, nil); -} - -void -wtwrite(Req *r) -{ - char buf[512]; - int n; - ulong path; - vlong offset; - Watchfile *wf; - - path = r->fid->qid.path; - offset = r->ifcall.offset; - - switch(path){ - case Qdata: - case Qctl: - snprint(buf, sizeof buf, "not yet %lux", path); - respond(r, buf); - return; - } - - /* data/... */ - wf = findtab(path); - if(wf == nil){ - respond(r, "no such qid"); - return; - } - if(dbg) - fprint(2, "wtwrite: %s ref %ld fd %d\n", wf->name, wf->ref, wf->fd); - - if(wf->fd < 0){ - respond(r, "no fd"); - return; - } - - n = pwrite(wf->fd, r->ifcall.data, r->ifcall.count, r->ifcall.offset); - if(n < 0){ - rerrstr(buf, sizeof buf); - respond(r, buf); - return; - } - if(n+offset >= r->fid->file->length) - r->fid->file->length = n+offset; - wf->dirty++; - r->ofcall.count = n; - respond(r, nil); - -} - -void -wtdestroyfid(Fid *fid) -{ - ulong path; - Watchfile *wf; - - path = fid->qid.path; - wf = findtab(path); - if(wf == nil) - return; - - if(dbg) - fprint(2, "wtdestroyfid: %s ref %ld fd %d\n", wf->name, wf->ref, wf->fd); - - if(wf->fd >= 0){ - if(decref(wf) == 0){ - if(wf->dirty){ - sendp(cctl, wf); - recvp(cctlwait); - } - close(wf->fd); - wf->fd = -1; - wf->dirty = 0; - } - } -} - -Tree * -inittree(char **argv) -{ - Tree *tree; - File *df; - - tree = alloctree(uname, uname, DMDIR|0555, nil); - df = createfile(tree->root, "data", uname, DMDIR|0555, nil); - createfile(tree->root, "ctl", uname, 0660, nil); - - for(;*argv;argv++){ - File *f; - Dir *d; - d = dirstat(*argv); - if(d == nil) - continue; - if(dbg) - fprint(2, "dir: name %s len %lld\n", d->name, d->length); - f = createfile(df, *argv, uname, 0660, nil); - wtab[nw].qid = f->qid; - wtab[nw].name = estrdup9p(*argv); - wtab[nw].fd = -1; - f->length = d->length; - nw++; - } - - return tree; -} - -static void -pollthread(void*) -{ - for(;;){ - sleep(1); - } -} - -static void -ctlthread(void*) -{ - int i, np = 0; - Alt a[4]; - Req *r, *rtab[10]; - Watchfile *wf; - - threadsetname("ctlthread"); - - a[0].op = CHANRCV; - a[0].c = creq; - a[0].v = &r; - a[1].op = CHANRCV; - a[1].c = cctl; - a[1].v = &wf; - a[2].op = CHANRCV; - a[2].c = pctl; - a[2].v = &wf; - a[3].op = CHANEND; - - for(;;){ - switch(alt(a)){ - case 0: /* creq: someone tries to read ctl */ - rtab[np++] = r; - break; - - case 1: /* cctl: ready to serve ctl */ - for(i=0; iofcall.data, r->ifcall.count, - "%s %llud\n", wf->name, wf->qid.path); - r->ofcall.count = strlen(r->ofcall.data); - respond(r, nil); - } - np = 0; - sendp(cctlwait, 0); - break; - - case 2: /* pctl: poll says modified */ - for(i=0; iofcall.data, r->ifcall.count, - "%s %llud\n", wf->name, wf->qid.path); - r->ofcall.count = strlen(r->ofcall.data); - respond(r, nil); - } - np = 0; - sendp(pctlwait, 0); - break; - - default: - break; - } - } -} - -void -initctl(void) -{ - cctl = chancreate(sizeof(void*), 0); - cctlwait = chancreate(sizeof(void*), 0); - pctl = chancreate(sizeof(void*), 0); - pctlwait = chancreate(sizeof(void*), 0); - creq = chancreate(sizeof(void*), 0); - procrfork(ctlthread, nil, STACK, RFNAMEG); - procrfork(pollthread, nil, STACK, RFNAMEG); -} - -void -usage(void) -{ - fprint(2, "usage: watchfs files...\n"); -} - -void -threadmain(int argc, char *argv[]) -{ - - ARGBEGIN{ - case 'd': - dbg++; - break; - case 'D': - chatty9p++; - break; - }ARGEND; - - uname = getuser(); - - fs.tree = inittree(&argv[0]); - if(dbg) - dumpWF(); - - initctl(); - threadpostmountsrv(&fs, nil, "/n/watch", MREPL|MCREATE); - threadexits(0); -} - -void -takedown(Srv*) -{ - threadexitsall("done"); -} - - - - //GO.SYSIN DD main.c