diff --git a/sys/man/3/skel b/sys/man/3/skel new file mode 100644 index 000000000..cc8dfbc17 --- /dev/null +++ b/sys/man/3/skel @@ -0,0 +1,35 @@ +.TH SKEL 3 +.SH NAME +skel \- skeleton builder +.SH SYNOPSIS +.B bind #z/\fIskel\fR +.I dir +.PP +.B bind #zd/\fIskel\fR +.I dir +.PP +.B bind #ze/ +.I dir +.SH DESCRIPTION +.PP +This device serves a single child directory with a single empty child +file. The name of these files is determined by the first walk away +from the root. After which, the hierarchy for that attached session +becomes stable. The +.B d +attach option causes the child file to be an empty directory. The +.B e +attach option presents a completly empty root directory. +.SH EXAMPLES +Skeleton files can be used for constructing arbitrary bind targets. +.EX +.IP +bind -b '#zd/newroot' / +bind '#zd/bin' /newroot +bind '#z/walk' /newroot/bin +bind /bin/walk /newroot/bin/walk +bind /newroot / +walk / +.EE +.SH SOURCE +.B /sys/src/9/port/devskel.c diff --git a/sys/src/9/pc/pc b/sys/src/9/pc/pc index 2cacee652..3581fe207 100644 --- a/sys/src/9/pc/pc +++ b/sys/src/9/pc/pc @@ -18,6 +18,7 @@ dev kprof fs dtracy + skel ether netif bridge netif log diff --git a/sys/src/9/pc64/pc64 b/sys/src/9/pc64/pc64 index bafda3d72..e78a2d47f 100644 --- a/sys/src/9/pc64/pc64 +++ b/sys/src/9/pc64/pc64 @@ -41,6 +41,7 @@ dev segment vmx dtracy + skel link # devpccard pci diff --git a/sys/src/9/port/devskel.c b/sys/src/9/port/devskel.c new file mode 100644 index 000000000..95e5b6038 --- /dev/null +++ b/sys/src/9/port/devskel.c @@ -0,0 +1,237 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "netif.h" + +typedef struct Skel Skel; +struct Skel { + int ref; + QLock lk; + char name[KNAMELEN]; + char mode; +}; + +struct +{ + QLock lk; + ulong path; +} skelalloc; + +enum{ + Qroot, + Qdir, + Qskel, +}; + +static Chan* +skelattach(char *spec) +{ + Chan *c; + Skel *f; + uvlong path; + + c = devattach('z', spec); + + f = smalloc(sizeof *f); + if(spec != nil && spec[0] != '\0' && strchr("de", spec[0]) != nil) + f->mode = spec[0]; + else + f->mode = 'f'; + + f->ref = 1; + + qlock(&skelalloc.lk); + path = skelalloc.path++; + qunlock(&skelalloc.lk); + + mkqid(&c->qid, NETQID(path, Qroot), 0, QTDIR); + c->aux = f; + return c; +} + +static int +step(Chan *c, Dir *dp, int direction) +{ + Skel *f; + Qid qid; + ulong perm; + uvlong path; + char *name; + + perm = 0555|DMDIR; + path = NETTYPE(c->qid.path); + f = c->aux; + name = f->name; + + path += direction; + if(!f->name[0] && path != Qroot) + return -1; + + switch(path){ + case Qroot: + mkqid(&qid, Qroot, 0, QTDIR); + name = "#z"; + break; + case Qdir: + mkqid(&qid, Qdir, 0, QTDIR); + break; + case Qskel: + switch(f->mode){ + case 'd': + mkqid(&qid, Qskel, 0, QTDIR); + break; + case 'f': + default: + mkqid(&qid, Qskel, 0, QTFILE); + perm = 0666; + break; + } + break; + default: + return -1; + } + + qid.path = NETQID(NETID(c->qid.path), qid.path); + devdir(c, qid, name, 0, eve, perm, dp); + return 1; +} + + +static int +skelgen(Chan *c, char *name, Dirtab *, int, int s, Dir *dp) +{ + Skel *f; + + f = c->aux; + //First walk away from root + if(name && !f->name[0] && f->mode != 'e' && NETTYPE(c->qid.path) == Qroot) + utfecpy(f->name, &f->name[sizeof f->name-1], name); + + if(s != DEVDOTDOT) + s++; + + return step(c, dp, s); +} + +static Walkqid* +skelwalk(Chan *c, Chan *nc, char **name, int nname) +{ + Walkqid *wq; + Skel *f; + + f = c->aux; + qlock(&f->lk); + if(waserror()){ + qunlock(&f->lk); + nexterror(); + } + + wq = devwalk(c, nc, name, nname, nil, 0, skelgen); + if(wq != nil && wq->clone != nil && wq->clone != c){ + if(f->ref <= 0) + panic("devskel ref"); + f->ref++; + } + qunlock(&f->lk); + poperror(); + return wq; +} + +static Chan* +skelopen(Chan *c, int omode) +{ + if(!(c->qid.type & QTDIR)) + error(Eperm); + if(omode != OREAD) + error(Ebadarg); + + c->mode = omode; + c->flag |= COPEN; + c->offset = 0; + return c; +} + +static void +skelclose(Chan *c) +{ + Skel *f; + + f = c->aux; + qlock(&f->lk); + f->ref--; + if(f->ref == 0){ + qunlock(&f->lk); + free(f); + } else + qunlock(&f->lk); +} + +static long +skelread(Chan *c, void *va, long n, vlong) +{ + Skel *f; + long nout; + + if(!(c->qid.type & QTDIR)) + error(Eperm); + + f = c->aux; + qlock(&f->lk); + if(waserror()){ + qunlock(&f->lk); + nexterror(); + } + nout = devdirread(c, va, n, nil, 0, skelgen); + qunlock(&f->lk); + poperror(); + return nout; +} + +static long +skelwrite(Chan *, void *, long, vlong) +{ + error(Eperm); + return 0; +} + +static int +skelstat(Chan *c, uchar *db, int n) +{ + Skel *f; + Dir dir; + + f = c->aux; + qlock(&f->lk); + step(c, &dir, 0); + qunlock(&f->lk); + + n = convD2M(&dir, db, n); + if(n < BIT16SZ) + error(Eshortstat); + return n; +} + +Dev skeldevtab = { + 'z', + "skel", + + devreset, + devinit, + devshutdown, + skelattach, + skelwalk, + skelstat, + skelopen, + devcreate, + skelclose, + skelread, + devbread, + skelwrite, + devbwrite, + devremove, + devwstat, +};