shithub: riscv

Download patch

ref: c12022fd8c434860accb237b9bad9bd7cd9ed2db
parent: c7c0ff5db6137662e435d66338cfa4e68c64598e
author: Jacob Moody <moody@posixcafe.org>
date: Wed Jun 15 02:42:05 EDT 2022

skel(3) → skelfs(4)

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'.

--- a/sys/man/3/skel
+++ /dev/null
@@ -1,35 +1,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
--- /dev/null
+++ b/sys/man/4/skelfs
@@ -1,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
--- a/sys/src/9/pc/pc
+++ b/sys/src/9/pc/pc
@@ -18,7 +18,6 @@
 	kprof
 	fs
 	dtracy
-	skel
 
 	ether		netif
 	bridge		netif log
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -41,7 +41,6 @@
 	segment
 	vmx
 	dtracy
-	skel
 
 link
 #	devpccard	pci
--- a/sys/src/9/port/devskel.c
+++ /dev/null
@@ -1,239 +1,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,
-};
--- a/sys/src/cmd/auth/box.c
+++ b/sys/src/cmd/auth/box.c
@@ -29,7 +29,7 @@
 			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 @@
 	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 @@
 			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);
 		}
@@ -109,6 +109,31 @@
 }
 
 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)
 {
 	fprint(2, "usage %s: [ -d ] [ -r file ] [ -c dir ] [ -e devs ] cmd args...\n", argv0);
@@ -129,8 +154,10 @@
 	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 @@
 	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 @@
 	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)
--- /dev/null
+++ b/sys/src/cmd/skelfs.c
@@ -1,0 +1,251 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#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);
+}