#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" typedef struct Aux Aux; enum { Qroot, Qctl, Qevents, Nfiles = 3, Evsize = 256, Nmon = 10, /* c->dev types */ Droot = 0, Dmon = -1, Debug = 1, }; struct Aux { union { Queue *q; /* root holds the event queue */ Chan *c; /* monitored Chan */ }; ushort type; /* real type for monitored Chan */ }; Chan *monitored[Nmon]; /* monitored Chans, indexed by monitor Chan dev */ Dirtab fopsdir[] = { ".", {Qroot,0,QTDIR}, 0, DMDIR|0500, "ctl", {Qctl}, 0, 0600, "events", {Qevents}, 0, 0600, }; static void fopinit(void) { } #define dbg if(Debug)print void dbgchan(Chan *c) { Aux *a; if(c == nil) return; dbg("chan @ %p %s dev %lud type %d mchan %s", c, chanpath(c), c->dev, c->type, chanpath(c->mchan)); if(c->aux){ a = c->aux; dbg(" aux[ c %s type %d]", chanpath(a->c), a->type); } dbg("\n"); } /* Every root of the tree has a new event queue */ static Chan* fopattach(char *spec) { Chan *c; Queue *q; Aux *a; ulong dev; dev = Droot; /* root fop */ if(spec && *spec) dev = atoi(spec)+1; print("fopattach: spec %s dev %lud\n", spec, dev); c = devattach('O', spec); a = malloc(sizeof(Aux)); if(dev == Droot){ q = qopen(Evsize, 0, 0, 0); /* event queue */ if(q == 0){ free(a); exhausted("memory for queue"); } a->q = q; }else{ a->c = monitored[dev]; print("fopattach: "), dbgchan(a->c); } mkqid(&c->qid, Qroot, 0, QTDIR); c->aux = a; c->dev = dev; return c; } static int fopgen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp) { Qid q; if(i == DEVDOTDOT){ dbg("fopgen: dotdot\n"); devdir(c, c->qid, "#O", 0, eve, DMDIR|0555, dp); return 1; } i++; /* skip . */ if(tab == 0 || i >= ntab) return -1; tab += i; switch((ulong)tab->qid.path){ case Qctl: dbg("fopgen: ctl\n"); break; case Qevents: dbg("fopgen: events\n"); break; default: break; } mkqid(&q, tab->qid.path, 0, QTFILE); devdir(c, q, tab->name, 0, eve, tab->perm, dp); return 1; } static Walkqid* fopwalk(Chan *c, Chan *nc, char **name, int nname) { Chan *mchan, *tc; Walkqid *wq; Aux *a; int i; print(">> fopwalk: "), dbgchan(c); for(i=0; i < nname; i++) dbg("fopwalk: name[%d] %s\n", i, name[i]); switch(c->dev){ case Droot: /* walk to the device's files */ return devwalk(c, nc, name, nname, fopsdir, Nfiles, fopgen); case Dmon: /* walk to the files being monitored */ a = c->aux; dbg("fopwalk: [Dmon] walking via "), dbgchan(a->c); //return nil; /* wq = devtab[a->type]->walk(a->c, nc, name, nname); if(wq == nil){ print("could not walk\n"); return nil; } return wq; */ return devwalk(a->c, nc, name, nname, 0, 0, 0); default: /* * more os less a transition state, we associate * our device, say #O0, with a dir in the namespace */ a = c->aux; print("fopwalk: aux "), dbgchan(a->c); mchan = a->c->mchan; tc = a->c; wq = devwalk(a->c, nc, name, nname, 0, 0, 0); if(wq == nil){ print("could not walk\n"); return nil; } a = malloc(sizeof(Aux)); if(a == nil) exhausted("fopwalk: no memory for Aux"); wq->clone->aux = a; a->type = wq->clone->type; a->c = tc; a->c->type = a->type; /* patch dev for new Chan in order for us to own it */ wq->clone->dev = Dmon; wq->clone->type = c->type; wq->clone->mchan = mchan; return wq; } // not reached return devwalk(c, nc, name, nname, fopsdir, Nfiles, fopgen); } static int fopstat(Chan *c, uchar *db, int n) { Dir dir; Aux *a; dbg(">> fopstat "), dbgchan(c); switch((ulong)c->qid.path){ case Qroot: devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir); break; case Qctl: devdir(c, c->qid, "ctl", 0, eve, 0600, &dir); break; case Qevents: devdir(c, c->qid, "events", qlen((Queue*)c->aux), eve, 0600, &dir); break; default: a = c->aux; return devtab[a->type]->stat(c, db, n); } n = convD2M(&dir, db, n); if(n < BIT16SZ) error(Eshortstat); return n; } static Chan* fopopen(Chan *c, int omode) { print("fopopen\n"); if(c->qid.type == QTDIR){ if(omode != OREAD) error(Eisdir); c->mode = omode; c->flag |= COPEN; c->offset = 0; return c; } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } static void fopclose(Chan*) { print("fopclose\n"); } static long fopread(Chan *c, void *va, long n, vlong off) { Chan *cnew; print("fopread\n"); USED(off); switch((ulong)c->qid.path){ case Qroot: return devdirread(c, va, n, fopsdir, Nfiles, fopgen); case Qctl: /* from sysfile.c:/^bindmount */ monitored[1] = namec("/cfg", Amount, 0, 0); cnew = namec("#O0", Abind, 0, 0); cmount(&cnew, monitored[1], MREPL, nil); // check errors return 0; case Qevents: return qread((Queue*)c->aux, va, n); default: panic("fopread"); } return -1; /* not reached */ } static long fopwrite(Chan *c, void *va, long n, vlong off) { USED(c); USED(va); USED(n); USED(off); print("fopwrite\n"); switch((ulong)c->qid.path){ case Qctl: return qwrite((Queue*)c->aux, va, n); case Qevents: return -1; default: panic("fopwrite"); } return 0; } Dev fopdevtab = { 'O', "fop", devreset, fopinit, devshutdown, fopattach, fopwalk, fopstat, fopopen, devcreate, fopclose, fopread, devbread, fopwrite, devbwrite, devremove, devwstat, };