From c12022fd8c434860accb237b9bad9bd7cd9ed2db Mon Sep 17 00:00:00 2001 From: Jacob Moody Date: Wed, 15 Jun 2022 06:42:05 +0000 Subject: [PATCH] =?UTF-8?q?skel(3)=20=E2=86=92=20skelfs(4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original intention was to put devskel in to the kernel to detach what it provides from devsrv. That is not a good reason, just move it to userspace. auth/box has been changed to exec skelfs instead of relying on '#z'. --- sys/man/3/skel | 35 ------ sys/man/4/skelfs | 65 ++++++++++ sys/src/9/pc/pc | 1 - sys/src/9/pc64/pc64 | 1 - sys/src/9/port/devskel.c | 239 ------------------------------------- sys/src/cmd/auth/box.c | 42 +++++-- sys/src/cmd/skelfs.c | 251 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 351 insertions(+), 283 deletions(-) delete mode 100644 sys/man/3/skel create mode 100644 sys/man/4/skelfs delete mode 100644 sys/src/9/port/devskel.c create mode 100644 sys/src/cmd/skelfs.c diff --git a/sys/man/3/skel b/sys/man/3/skel deleted file mode 100644 index cc8dfbc17..000000000 --- a/sys/man/3/skel +++ /dev/null @@ -1,35 +0,0 @@ -.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/man/4/skelfs b/sys/man/4/skelfs new file mode 100644 index 000000000..7168c92f3 --- /dev/null +++ b/sys/man/4/skelfs @@ -0,0 +1,65 @@ +.TH SKELFS 4 +.SH NAME +skelfs \- build directory skeletons +.SH SYNOPSIS +.B skelfs +[ +.B -i +] +[ +.B -t +.I mode +] +[ +.B -s +.I service +] +[ +.I mnt +] +.SH DESCRIPTION +.I Skelfs +generates directory skeletons +to assist in building namespaces. +Skeletons are generated on demand +by walking through the root directory. +A skeleon is a directory containing a single empty child. +The name of this child is defined by the first walk taken +away from the root. For example the hierarchy for a skeleton +named 'echo' would be: +.PP +.EX + / + /echo/ + /echo/echo +.EE +.PP +The +.I mode +dictates what form the innermost child file takes. The +.B file +and +.B dir +modes cause the child to be an empty file or directory +respecively. The +.B empty +mode instead serves no skeletons, causing the root +directory to always be empty. +A client may override the mode by providing +its own selection as an attach option. If a +mode is not provided, +.B file +is assumed. +.PP +The skeletons generated by +.I skelfs +are anonmyous. Clients will never see the +skeletons of other clients, nor can a client revisit +a previous skeleton. +.PP +.SH "SEE ALSO" +.B auth/box +in +.IR auth (8). +.SH SOURCE +.B /sys/src/cmd/skelfs.c diff --git a/sys/src/9/pc/pc b/sys/src/9/pc/pc index 3581fe207..2cacee652 100644 --- a/sys/src/9/pc/pc +++ b/sys/src/9/pc/pc @@ -18,7 +18,6 @@ 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 e78a2d47f..bafda3d72 100644 --- a/sys/src/9/pc64/pc64 +++ b/sys/src/9/pc64/pc64 @@ -41,7 +41,6 @@ dev segment vmx dtracy - skel link # devpccard pci diff --git a/sys/src/9/port/devskel.c b/sys/src/9/port/devskel.c deleted file mode 100644 index 90aa2dae6..000000000 --- a/sys/src/9/port/devskel.c +++ /dev/null @@ -1,239 +0,0 @@ -#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 { - RWlock; - int ref; - char name[KNAMELEN]; - char mode; -}; - -struct -{ - QLock; - ulong path; -} skelalloc; - -enum{ - Qroot, - Qdir, - Qskel, -}; - -static Chan* -skelattach(char *spec) -{ - Chan *c; - Skel *f; - uvlong path; - - c = devattach('z', spec); - - f = mallocz(sizeof *f, 1); - if(f == nil) - exhausted("memory"); - if(waserror()){ - free(f); - nexterror(); - } - - if(spec == nil) - f->mode = 'f'; - else - f->mode = spec[0]; - - eqlock(&skelalloc); - path = skelalloc.path++; - qunlock(&skelalloc); - - poperror(); - mkqid(&c->qid, NETQID(path, Qroot), path, QTDIR); - f->ref = 1; - c->aux = f; - return c; -} - -static int -step(Chan *c, Dir *dp, int direction) -{ - Skel *f; - Qid qid; - ulong perm; - int path; - char *name; - - perm = 0555|DMDIR; - path = NETTYPE(c->qid.path); - f = c->aux; - rlock(f); - if(waserror()){ - runlock(f); - return -1; - } - name = f->name; - - path += direction; - if(!f->name[0] && path > Qroot) - error(Enonexist); - - switch(path){ - case Qroot-1: - 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: - error(Enonexist); - } - - qid.vers = NETID(c->qid.path); - qid.path = NETQID(qid.vers, qid.path); - devdir(c, qid, name, 0, eve, perm, dp); - runlock(f); - poperror(); - return 1; -} - - -static int -skelgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp) -{ - Skel *f; - - switch(s){ - case DEVDOTDOT: - break; - case 0: - s++; - break; - default: - return -1; - } - f = c->aux; - if(name && NETTYPE(c->qid.path) == Qroot){ - wlock(f); - if(!f->name[0] && f->mode != 'e') - utfecpy(f->name, &f->name[sizeof f->name-1], name); - wunlock(f); - } - - return step(c, dp, s); -} - -static Walkqid* -skelwalk(Chan *c, Chan *nc, char **name, int nname) -{ - Walkqid *wq; - Skel *f; - - wq = devwalk(c, nc, name, nname, nil, 0, skelgen); - if(wq == nil || wq->clone == nil) - return wq; - - f = c->aux; - wlock(f); - if(f->ref <= 0) - panic("devskel ref"); - f->ref++; - wunlock(f); - 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; - wlock(f); - f->ref--; - if(f->ref == 0){ - wunlock(f); - free(f); - } else - wunlock(f); -} - -static long -skelread(Chan *c, void *va, long n, vlong) -{ - return devdirread(c, va, n, nil, 0, skelgen); -} - -static long -skelwrite(Chan*, void*, long, vlong) -{ - error(Ebadusefd); - return -1; -} - -static int -skelstat(Chan *c, uchar *db, int n) -{ - Dir dir; - - if(step(c, &dir, 0) < 0) - error(Enonexist); - - 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, -}; diff --git a/sys/src/cmd/auth/box.c b/sys/src/cmd/auth/box.c index 30eedce7d..4f01e43de 100644 --- a/sys/src/cmd/auth/box.c +++ b/sys/src/cmd/auth/box.c @@ -29,7 +29,7 @@ binderr(char *new, char *old, int flag) dash[1] = 'a'; break; } - print("bind %s %s %s\n", dash, new, old); + fprint(2, "bind %s %s %s\n", dash, new, old); } if(bind(new, old, flag) < 0) sysfatal("bind: %r"); @@ -72,10 +72,10 @@ sandbox(char **names, int *flags, int nname) Dir *d; int i, j, n; - snprint(rootskel, sizeof rootskel, "#zd/newroot.%d", getpid()); + snprint(rootskel, sizeof rootskel, "/mnt/d/newroot.%d", getpid()); binderr(rootskel, "/", MBEFORE); - newroot = rootskel + strlen("#zd"); + newroot = rootskel + strlen("/mnt/d"); for(j = 0; j < nname; j++){ if(names[j] == nil) @@ -97,9 +97,9 @@ sandbox(char **names, int *flags, int nname) if(d == nil) continue; if(d->mode & DMDIR) - snprint(skel, sizeof skel, "#zd/%s", parts[i]); + snprint(skel, sizeof skel, "/mnt/d/%s", parts[i]); else - snprint(skel, sizeof skel, "#zf/%s", parts[i]); + snprint(skel, sizeof skel, "/mnt/f/%s", parts[i]); free(d); binderr(skel, dir, MBEFORE); } @@ -108,6 +108,31 @@ sandbox(char **names, int *flags, int nname) binderr(newroot, "/", MREPL); } +void +skelfs(void) +{ + int p[2]; + int dfd; + + pipe(p); + switch(rfork(RFFDG|RFREND|RFPROC|RFNAMEG)){ + case -1: + sysfatal("fork"); + case 0: + close(p[1]); + dup(p[0], 0); + dup(p[0], 1); + execl("/bin/skelfs", "skelfs", debug > 1 ? "-Di" : "-i", nil); + sysfatal("exec /bin/skelfs: %r"); + } + close(p[0]); + dfd = dup(p[1], -1); + if(mount(p[1], -1, "/mnt/f", MREPL, "file") < 0) + sysfatal("/mnt/f mount setup: %r"); + if(mount(dfd, -1, "/mnt/d", MREPL, "dir") < 0) + sysfatal("/mnt/d mount setup: %r"); +} + void usage(void) { @@ -129,8 +154,10 @@ main(int argc, char **argv) nparts = 0; memset(devs, 0, sizeof devs); ARGBEGIN{ + case 'D': + debug++; case 'd': - debug = 1; + debug++; break; case 'r': parts[nparts] = EARGF(usage()); @@ -164,6 +191,7 @@ main(int argc, char **argv) argv[0] = b; rfork(RFNAMEG|RFFDG); + skelfs(); dfd = open("/dev/drivers", OWRITE|OCEXEC); if(dfd < 0) sysfatal("could not /dev/drivers: %r"); @@ -172,7 +200,7 @@ main(int argc, char **argv) sandbox(parts, mflags, nparts); if(debug) - print("chdev %s\n", devs); + fprint(2, "chdev %s\n", devs); if(devs[0] != '\0'){ if(fprint(dfd, "chdev & %s", devs) <= 0) diff --git a/sys/src/cmd/skelfs.c b/sys/src/cmd/skelfs.c new file mode 100644 index 000000000..137e19397 --- /dev/null +++ b/sys/src/cmd/skelfs.c @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include <9p.h> + +typedef struct Skel Skel; +struct Skel { + char name[64]; + char mode; +}; + +static uvlong sessions; +static char defmode; + +enum{ + Qroot, + Qdir, + Qskel, +}; + +#define qtype(x) (((ulong)x)&0x1f) +#define qsess(x) ((((ulong)x))>>5) +#define mkqid(i,t) ((((ulong)i)<<5)|(t)) + +static int +step(Fid *f, int way, Qid *res, Dir *dp) +{ + Skel *s; + int path; + char *name; + ulong perm; + + s = f->aux; + name = s->name; + perm = 0550|DMDIR; + path = qtype(f->qid.path) + way; + if(!name[0] && way > 0) + return -1; + + if(path < 0) + goto Root; + switch(path){ + Root: + case Qroot: + name = "/"; + /* fallthrough */ + case Qdir: + res->type = QTDIR; + break; + case Qskel: + switch(s->mode){ + case 'd': + res->type = QTDIR; + break; + case 'f': + default: + res->type = QTFILE; + perm = 0; + break; + } + break; + default: + return -1; + } + res->vers = qsess(f->qid.path); + res->path = mkqid(res->vers, path); + if(dp){ + dp->mode = perm; + dp->name = estrdup9p(name); + dp->uid = estrdup9p("sys"); + dp->gid = estrdup9p("sys"); + dp->qid = *res; + dp->length = 0; + } + return 1; +} + +static int +dirgen(int i, Dir *d, void *a) +{ + Fid *f; + Qid q; + + if(i > 0) + return -1; + f = a; + return step(f, 1, &q, d); +} + +static void +fidclunk(Fid *fid) +{ + free(fid->aux); +} + +static char* +fsclone(Fid *old, Fid *new, void*) +{ + Skel *s, *s2; + + s = old->aux; + s2 = emalloc9p(sizeof *s2); + if(s2 == nil) + return "out of memory"; + memset(s2, 0, sizeof *s2); + + s2->mode = s->mode; + utfecpy(s2->name, &s2->name[sizeof s2->name-1], s->name); + new->aux = s2; + return nil; +} + +static char* +fswalk1(Fid *old, char *name, void*) +{ + Skel *s; + + if(strcmp("..", name) == 0){ + step(old, -1, &old->qid, nil); + return nil; + } + + s = old->aux; + if(!s->name[0] && qtype(old->qid.path) == Qroot && s->mode != 'e'){ + utfecpy(s->name, &s->name[sizeof s->name-1], name); + old->qid.vers = sessions++; + old->qid.path = mkqid(old->qid.vers, qtype(old->qid.path)); + } else if(strcmp(name, s->name) != 0) + return "does not exist"; + + if(step(old, 1, &old->qid, nil) < 0) + return "does not exist"; + + return nil; +} + +static void +fswalk(Req *r) +{ + walkandclone(r, fswalk1, fsclone, nil); +} + +static void +fsattach(Req *r) +{ + Skel s; + Fid root; + char *spec; + Qid *q; + + spec = r->ifcall.aname; + if(spec && spec[0] != '\0') + s.mode = spec[0]; + else + s.mode = defmode; + + q = &r->fid->qid; + q->vers = sessions++; + q->path = mkqid(q->vers, Qroot); + q->type = QTDIR; + r->ofcall.qid = *q; + + s.name[0] = '\0'; + root.aux = &s; + respond(r, fsclone(&root, r->fid, nil)); +} + +static void +fsstat(Req *r) +{ + Qid q; + + if(step(r->fid, 0, &q, &r->d) < 0) + respond(r, "does not exist"); + respond(r, nil); +} + +static void +fsread(Req *r) +{ + dirread9p(r, dirgen, r->fid); + respond(r, nil); +} + +static void +fsopen(Req *r) +{ + r->ofcall.mode = r->ifcall.mode; + if(r->ifcall.mode != OREAD) + respond(r, "permission denied"); + else + respond(r, nil); +} + +Srv fs= +{ +.attach= fsattach, +.open= fsopen, +.read= fsread, +.stat= fsstat, +.walk= fswalk, +.destroyfid= fidclunk +}; + +void +usage(void) +{ + fprint(2, "usage: %s [ -Di ] [ -s service ] [ -t mode ] [ mntpt ]\n", argv0); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + char *s, *mode; + int stdio; + + s = nil; + stdio = 0; + defmode = 'f'; + ARGBEGIN{ + case 'D': + chatty9p++; + break; + case 's': + s = EARGF(usage()); + break; + case 'i': + stdio = 1; + break; + case 't': + mode = EARGF(usage()); + defmode = mode[0]; + break; + default: + usage(); + }ARGEND + + if(argc > 1) + usage(); + + if(stdio == 0){ + postmountsrv(&fs, s, argc ? argv[0] : "/mnt/skel", MREPL); + exits(nil); + } + fs.infd = 0; + fs.outfd = 1; + srv(&fs); + exits(nil); +}