OK, turing.

<- leave blank

Mon Jun 20 01:07:18 EDT 2022

From: Rob Pike <robpike@gmail.com>
Date: Sun, 19 Jun 2022 17:50:57 +1000
To: Angelo Papenhoff <aap@papnet.eu>
Message-ID-Hash: QJVSPPAZSG5HQWLUKRM7PPGTEKEJI7IF
CC: The Eunuchs Hysterical Society <tuhs@tuhs.org>
Subject: [TUHS] Re: forgotten versions
Archived-At:
<https://www.tuhs.org/mailman3/hyperkitty/list/tuhs@tuhs.org/message/QJVSPPAZSG5HQWLUKRM7PPGTEKEJI7IF/>

The VAX Plan 9 kernel isn't worth anything.  It never worked, was never
used, and was abandoned completely when better SMP machines started
appearing.  The VAX code wasn't even ported, as I remember it; Ken and I
started over from scratch with a pair of 4-core SGI machines with MIPS CPUs
and wackadoo synchronization hardware.

-rob


On Sat, Jun 18, 2022 at 5:05 PM Angelo Papenhoff <aap@papnet.eu> wrote:

> To make people more aware of post-v7 Research UNIX it would be great if
> you could actually run all of them in a simulator and have the manuals
> available.
>
> V8 is working perfectly in simh and there's blit (jerq) emulation as well.
> DMD 5620 emulation should be possible as well with Seth Morabito's
> emulator, but as far as I understand it needs a different ROM that we
> don't have a dump of.  (I've had a real 5620 connected to my laptop
> running v8 in simh, it worked perfectly)
>
> V9 exists as a port to Sun-3 and it can actually be booted apparently.
> The source seems incomplete, but the VAX kernel source seems to be
> included as well.  Maybe it could be gotten to run in simh on a VAX
> in some form or another?
>
> V10 exists but not as anything that boots.  I think getting this to work
> would be the holy grail but also requires quite a bit of effort.
> I don't know if the V8 and V10 file systems are compatible, but if that
> is the case one could probably start by bootstrapping from V8.
> It also includes the multilevel-secure IX system and software for the
> 630 MTG terminal.
>
>
> As for the manual...
>
> The V8 files have the man pages but not much of the documents.
>
> The V9 files seem to have neither.
>
> The V10 files have both the man pages and the documents but I have not
> yet tried to troff any of this.
>
> Since I know at least the V10 manual to be a work of art and beauty I
> think it should be available to everyone.  I have not seen the physical
> V8 and V9 manuals, but if they look anything like the V10 one, they too
> deserve to be available to the public.
>
>
> Does anyone have a plan of attack?  I'd gladly join some effort to make
> the research systems more visible or available again (but probably don't
> have the motivation to do so alone).
>
> Angelo/aap
>




Mon Jun 20 01:06:58 EDT 2022
To: tuhs@tuhs.org
Date: Sun, 19 Jun 2022 20:44:14 -0400 (EDT)
From: norman@oclsc.org (Norman Wilson)
Message-ID-Hash: QI6YBGQXFI6OG7CKXNRXDHSURM7W2UFP
Subject: [TUHS] Re: RFS (was Re: Re: forgotten versions)
Archived-At:
<https://www.tuhs.org/mailman3/hyperkitty/list/tuhs@tuhs.org/message/QI6YBGQXFI6OG7CKXNRXDHSURM7W2UFP/>

I don't know the exact history of RFS a la System V, but I
don't think it was Peter Weinberger's stuff, and it certainly
wasn't his code.  Nor his name: he called his first version
neta and his second netb (he knew it would be changing and
allowed for it in the name from the start).

I don't remember us ever calling it RFS, or even remote
file systems, inside 1127; we called it network file systems
(never NFS because the Sun stuff existed by then).

For those who don't know it, Peter's goal was quite different
from that of NFS.  The idea behind NFS seems always to have
been to mount a remote file system as if it were local, with
a base assumption early on that everything was within the
same administrative domain so it was OK to make assumptions
about userids matching up, and running code as super-user.
Peter described his intent as `I want to be able to use your
disks, and that's a lot simpler if I don't have to get you
to add code to your kernel, or even to run a program as
super-user.' Hence the entirely-user-mode server program,
which could use super-user privileges to afford access as
any user if it had them, but also worked fine when run as
an ordinary user with only that user's file permissions.
We did in fact normally run it as super-user so each of
our 15 or so VAXes could see the file system tree on each
other, but we also occasionally did it otherwise.

That was one reason device files worked as they did, accessing
the device on the server end rather than acting like a local
special file on the client: we didn't care about running
diskless clients, but we did occasionally care about accessing
a remote system's tape drive.

Peter, being a self-described fan of cheap hacks, also wasn't
inclined to spend much time thinking about general abstractions;
in effect he just turned various existing kernel subroutines
(when applied to a network file system) into RPCs.  The
structure of the file system switch was rather UNIX-specific,
reflecting that.

That also means Peter's code was a bit ad-hoc and wonky in
places.  He cleaned it up considerably between neta and netb,
and I did further cleanup later.  I even had a go at a library
to isolate the network protocol from the server proper, converted
the netb server to use it, and made a few demo servers of my own
like one to read and write raw FILES-11 file systems--useful for
working with the console file system on the VAX 8800 series,
which was exported to the host as a block device--and a daemon
to allow a tar archive to be mounted as a read-only file system.

In modern systems, you can do the same sort of things with FUSE,
and set up the same I-want-to-use-your-disks (or I want to get
at my own files from afar without privileges) scheme with sshfs.
I would be very surprised to learn that either of those borrowed
from their ancient cousins in Research UNIX; so far as I know
they're independent inventions.  Either way I'm glad they exist.

Norman Wilson
Toronto ON




Sun Jun 19 22:54:25 EDT 2022
What is this

Sun Jun 19 22:54:07 EDT 2022
help

Sun Jun 19 20:54:03 EDT 2022
diff 990ceeef3bfd9d56e2e6dd39cf5ac185b1a2de08 uncommitted
--- a/sys/src/9/port/devsrv.c
+++ b/sys/src/9/port/devsrv.c
@@ -5,61 +5,220 @@
 #include "fns.h"
 #include "../port/error.h"

+#include "netif.h"

+typedef struct Link Link;
+struct Link
+{
+ void *link;
+ char *name;
+ ulong path;
+};
+
 typedef struct Srv Srv;
 struct Srv
 {
- char *name;
+ Link;
+
	char *owner;
	ulong perm;
	Chan *chan;
- Srv *link;
- ulong path;
 };

-static QLock srvlk;
-static Srv *srv;
-static int qidpath;
+typedef struct Board Board;
+struct Board
+{
+ Link;
+ QLock;

-static Srv*
-srvlookup(char *name, ulong qidpath)
+ Board *parent;
+ Board *child;
+ Srv *srv;
+ long id;
+ int qidpath;
+ int closed;
+ long ref;
+};
+
+struct{
+ QLock;
+ long path;
+} boards;
+
+enum{
+ Qroot,
+ Qclone,
+ Qlease,
+
+ Qend,
+};
+
+Board root;
+
+static char Eexpired[] = "expired lease";
+
+static void*
+lookup(Link *l, char *name, ulong qidpath)
 {
- Srv *sp;
+ Link *lp;

- for(sp = srv; sp != nil; sp = sp->link) {
- if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0))
- return sp;
+ if(qidpath != ~0UL)
+ qidpath = NETTYPE(qidpath);
+ for(lp = l; lp != nil; lp = lp->link){
+ if(qidpath != ~0UL && lp->path == qidpath)
+ return lp;
+ if(name != nil && strcmp(lp->name, name) == 0)
+ return lp;
	}
	return nil;
 }

+static void*
+remove(Link **l, char *name, ulong qidpath)
+{
+ Link *lp;
+ Link **last;
+
+ if(qidpath != ~0UL)
+ qidpath = NETTYPE(qidpath);
+ last = l;
+ for(lp = *l; lp != nil; lp = lp->link){
+ if(qidpath != ~0UL && lp->path == qidpath)
+ break;
+ if(name != nil && strcmp(lp->name, name) == 0)
+ break;
+ last = &lp->link;
+ }
+ if(lp == nil)
+ return nil;
+
+ *last = lp->link;
+ lp->link = nil;
+ return lp;
+}
+
+static void
+boardclunk(Board *b, int close)
+{
+ Srv *sp, *prv;
+ Board *ch;
+
+ /* caller holds a lock */
+ if(b == &root){
+ qunlock(b);
+ return;
+ }
+
+ if(close){
+ assert(b->closed == 0);
+ b->closed++;
+ for(sp = b->srv; sp != nil; sp = prv){
+ prv = sp->link;
+ free(sp->owner);
+ free(sp->name);
+ if(sp->chan != nil)
+ cclose(sp->chan);
+ free(sp);
+ }
+ b->srv = nil;
+ }
+
+ b->ref--;
+ if(b->ref < 0)
+ panic("devsrv: neg ref");
+ /*
+ * Each board other then root is owned
+ * by a single Qlease.  A 'closed' lease
+ * causes the board to no longer function.
+ * However, we may still have copies of that board
+ * on in use channels, so we can't free it just then.
+ * We need to wait until all references to this board
+ * have been clunked.  To accomplish this we only free
+ * leaf nodes, keeping 'closed' parents alive to allow
+ * their bodies to be walked over.  Then when freeing leaf
+ * nodes, we walk up the tree clearing out those waiting for only us.
+ */
+ while(b->closed && b->child == nil && b->ref == 0){
+ //Root should never be closed
+ assert(b->parent != nil);
+ qlock(b->parent);
+ ch = remove((Link**)&b->parent->child, b->name, b->path);
+ assert(ch == b);
+
+ b = ch->parent;
+ free(ch->name);
+ qunlock(ch);
+ free(ch);
+ }
+ qunlock(b);
+}
+
 static int
 srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
 {
	Srv *sp;
+ Board *b, *ch;
	Qid q;

+ if(name != nil && strlen(name) >= sizeof(up->genbuf))
+ return -1;
+
+ b = c->aux;
+ ch = nil;
+ mkqid(&q, ~0L, 0, QTFILE);
+ qlock(b);
+ if(waserror()){
+ qunlock(b);
+ return -1;
+ }
	if(s == DEVDOTDOT){
- devdir(c, c->qid, "#s", 0, eve, 0555, dp);
- return 1;
+ ch = b->parent;
+ if(ch == nil)
+ ch = &root;
+ goto Child;
+
	}
+ if(name != nil){
+ if(strcmp("clone", name) == 0)
+ goto Clone;

- qlock(&srvlk);
- if(name != nil)
- sp = srvlookup(name, -1);
- else {
- for(sp = srv; sp != nil && s > 0; sp = sp->link)
+ sp = lookup(b->srv, name, ~0UL);
+ if(sp == nil)
+ ch = lookup(b->child, name, ~0UL);
+ } else {
+ if(s == 0)
+ goto Clone;
+ s--;
+ for(sp = b->srv; sp != nil && s > 0; sp = sp->link)
			s--;
+ for(ch = b->child; ch != nil && s > 0; ch = ch->link)
+ s--;
	}
- if(sp == nil || (name != nil && (strlen(sp->name) >=
sizeof(up->genbuf)))) {
- qunlock(&srvlk);
- return -1;
- }
- mkqid(&q, sp->path, 0, QTFILE);
- /* make sure name string continues to exist after we release lock */
- kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
- devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
- qunlock(&srvlk);
+ if(sp != nil){
+ kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
+ q.vers = NETID(c->qid.path);
+ q.path = NETQID(q.vers, sp->path);
+ devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
+ } else if(ch != nil){
+Child:
+ kstrcpy(up->genbuf, ch->name, sizeof up->genbuf);
+ q.vers = ch->id;
+ q.path = NETQID(q.vers, ch->path);
+ q.type = QTDIR;
+ devdir(c, q, up->genbuf, 0, eve, 0555|DMDIR, dp);
+ /* dirread's and stats shouldn't alter c->aux */
+ if(name != nil)
+ c->aux = ch;
+ } else if(0){
+Clone:
+ q.vers = NETID(c->qid.path);
+ q.path = NETQID(q.vers, Qclone);
+ devdir(c, q, "clone", 0, eve, 0444, dp);
+ } else
+ error(Enonexist);
+
+ qunlock(b);
+ poperror();
	return 1;
 }

@@ -66,19 +225,38 @@
 static void
 srvinit(void)
 {
- qidpath = 1;
+ root.qidpath = Qend;
+ root.name = "#s";
 }

 static Chan*
 srvattach(char *spec)
 {
- return devattach('s', spec);
+ Chan *c;
+
+ c = devattach('s', spec);
+ c->aux = &root;
+ return c;
 }

 static Walkqid*
 srvwalk(Chan *c, Chan *nc, char **name, int nname)
 {
- return devwalk(c, nc, name, nname, 0, 0, srvgen);
+ Board *b;
+ Walkqid *wq;
+
+ wq = devwalk(c, nc, name, nname, 0, 0, srvgen);
+ if(wq == nil || wq->clone == nil)
+ return wq;
+
+ b = wq->clone->aux;
+ if(b == &root)
+ return wq;
+ qlock(b);
+ b->ref++;
+ //print("incref %ld %ld\n", b->id, b->ref);
+ qunlock(b);
+ return wq;
 }

 static int
@@ -90,12 +268,14 @@
 char*
 srvname(Chan *c)
 {
+ Board *b;
	Srv *sp;
	char *s;

	s = nil;
- qlock(&srvlk);
- for(sp = srv; sp != nil; sp = sp->link) {
+ b = &root;
+ qlock(b);
+ for(sp = b->srv; sp != nil; sp = sp->link) {
		if(sp->chan == c){
			s = malloc(3+strlen(sp->name)+1);
			if(s != nil)
@@ -103,7 +283,7 @@
			break;
		}
	}
- qunlock(&srvlk);
+ qunlock(b);
	return s;
 }

@@ -110,8 +290,10 @@
 static Chan*
 srvopen(Chan *c, int omode)
 {
+ Board *b, *ch;
	Srv *sp;
	Chan *nc;
+ char buf[64];

	if(c->qid.type == QTDIR){
		if(omode & ORCLOSE)
@@ -123,20 +305,49 @@
		c->offset = 0;
		return c;
	}
- qlock(&srvlk);
+ if(omode&OTRUNC)
+ error(Eexist);
+ if(omode&ORCLOSE)
+ error(Eperm);
+
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		nexterror();
	}
+ if(b->closed)
+ error(Eexpired);
+ if(NETTYPE(c->qid.path) == Qclone){
+ ch = smalloc(sizeof *ch);
+ ch->qidpath = Qend;
+ ch->ref = 1;
+ qlock(&boards);
+ ch->id = ++boards.path;
+ qunlock(&boards);
+ //print("new %ld %ld\n", ch->id, ch->ref);

- sp = srvlookup(nil, c->qid.path);
+ ch->parent = b;
+ ch->path = b->qidpath++;
+ snprint(buf, sizeof buf, "%ld", ch->id);
+ kstrdup(&ch->name, buf);
+
+ ch->link = b->child;
+ b->child = ch;
+ c->aux = ch;
+ c->qid.vers = ch->id;
+ c->qid.path = NETQID(ch->id, Qlease);
+
+ poperror();
+ //print("transfer\n");
+ boardclunk(b, 0); //unlock
+ return c;
+ }
+
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil || sp->chan == nil)
		error(Eshutdown);

- if(omode&OTRUNC)
- error(Eexist);
- if(omode&ORCLOSE)
- error(Eperm);
	if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
		error(Eperm);
	devpermcheck(sp->owner, sp->perm, omode);
@@ -144,7 +355,7 @@
	nc = sp->chan;
	incref(nc);

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	cclose(c);
@@ -154,6 +365,7 @@
 static Chan*
 srvcreate(Chan *c, char *name, int omode, ulong perm)
 {
+ Board *b;
	Srv *sp;

	if(openmode(omode) != OWRITE)
@@ -166,27 +378,31 @@
	kstrdup(&sp->name, name);
	kstrdup(&sp->owner, up->user);

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		free(sp->owner);
		free(sp->name);
		free(sp);
		nexterror();
	}
- if(srvlookup(name, -1) != nil)
+ if(b->closed)
+ error(Eexpired);
+ if(lookup(b->srv, name, ~0UL) != nil)
		error(Eexist);

	sp->perm = perm&0777;
- sp->path = qidpath++;
+ sp->path = b->qidpath++;

- c->qid.path = sp->path;
+ c->qid.path = NETQID(b->id, sp->path);
+ c->qid.vers = b->id;
	c->qid.type = QTFILE;

- sp->link = srv;
- srv = sp;
+ sp->link = b->srv;
+ b->srv = sp;

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	c->flag |= COPEN;
@@ -198,22 +414,24 @@
 static void
 srvremove(Chan *c)
 {
- Srv *sp, **l;
+ Board *b;
+ Srv *sp;

	if(c->qid.type == QTDIR)
		error(Eperm);
+ switch(NETTYPE(c->qid.path)){
+ case Qlease:
+ case Qclone:
+ error(Eperm);
+ }

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		nexterror();
	}
- l = &srv;
- for(sp = *l; sp != nil; sp = *l) {
- if(sp->path == c->qid.path)
- break;
- l = &sp->link;
- }
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil)
		error(Enonexist);

@@ -229,10 +447,9 @@
	if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
		error(Eperm);

- *l = sp->link;
- sp->link = nil;
+ remove((Link**)&b->srv, nil, c->qid.path);

- qunlock(&srvlk);
+ boardclunk(b, 0); //unlock
	poperror();

	if(sp->chan != nil)
@@ -245,6 +462,7 @@
 static int
 srvwstat(Chan *c, uchar *dp, int n)
 {
+ Board *b;
	char *strs;
	Srv *sp;
	Dir d;
@@ -251,6 +469,11 @@

	if(c->qid.type & QTDIR)
		error(Eperm);
+ switch(NETTYPE(c->qid.path)){
+ case Qlease:
+ case Qclone:
+ error(Eperm);
+ }

	strs = smalloc(n);
	if(waserror()){
@@ -261,13 +484,16 @@
	if(n == 0)
		error(Eshortstat);

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		nexterror();
	}
+ if(b->closed)
+ error(Eexpired);

- sp = srvlookup(nil, c->qid.path);
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil)
		error(Enonexist);

@@ -286,7 +512,7 @@
	if(d.mode != ~0UL)
		sp->perm = d.mode & 0777;

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	free(strs);
@@ -298,22 +524,42 @@
 static void
 srvclose(Chan *c)
 {
- /*
- * in theory we need to override any changes in removability
- * since open, but since all that's checked is the owner,
- * which is immutable, all is well.
- */
- if(c->flag & CRCLOSE){
+ Board *b;
+ int expired;
+
+ expired = 0;
+ if(NETTYPE(c->qid.path) == Qlease){
+ expired++;
+ } else if(c->flag & CRCLOSE){
+ /*
+ * in theory we need to override any changes in removability
+ * since open, but since all that's checked is the owner,
+ * which is immutable, all is well.
+ */
		if(waserror())
- return;
+ goto Clunk;
		srvremove(c);
		poperror();
+ return;
	}
+Clunk:
+ b = c->aux;
+ qlock(b);
+ boardclunk(b, expired); //unlock
 }

 static long
-srvread(Chan *c, void *va, long n, vlong)
+srvread(Chan *c, void *va, long n, vlong off)
 {
+ Board *b;
+
+ if(NETTYPE(c->qid.path) == Qlease){
+ b = c->aux;
+ qlock(b);
+ n = readstr((ulong)off, va, n, b->name);
+ qunlock(b);
+ return n;
+ }
	isdir(c);
	return devdirread(c, va, n, 0, 0, srvgen);
 }
@@ -321,11 +567,15 @@
 static long
 srvwrite(Chan *c, void *va, long n, vlong)
 {
+ Board *b;
	Srv *sp;
	Chan *c1;
	int fd;
	char buf[32];

+ if(NETTYPE(c->qid.path) == Qlease)
+ error(Eperm);
+
	if(n >= sizeof buf)
		error(Etoobig);
	memmove(buf, va, n); /* so we can NUL-terminate */
@@ -334,15 +584,18 @@

	c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()) {
- qunlock(&srvlk);
+ qunlock(b);
		cclose(c1);
		nexterror();
	}
+ if(b->closed)
+ error(Eexpired);
	if(c1->qid.type & QTAUTH)
		error("cannot post auth file in srv");
- sp = srvlookup(nil, c->qid.path);
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil)
		error(Enonexist);

@@ -351,7 +604,7 @@

	sp->chan = c1;

- qunlock(&srvlk);
+ qunlock(b);
	poperror();
	return n;
 }
@@ -380,12 +633,14 @@
 void
 srvrenameuser(char *old, char *new)
 {
+ Board *b;
	Srv *sp;

- qlock(&srvlk);
- for(sp = srv; sp != nil; sp = sp->link) {
+ b = &root;
+ qlock(b);
+ for(sp = b->srv; sp != nil; sp = sp->link) {
		if(sp->owner != nil && strcmp(old, sp->owner) == 0)
			kstrdup(&sp->owner, new);
	}
- qunlock(&srvlk);
+ qunlock(b);
 }


Sun Jun 19 18:16:39 EDT 2022
diff 990ceeef3bfd9d56e2e6dd39cf5ac185b1a2de08 uncommitted
--- a//sys/src/9/port/devsrv.c
+++ b//sys/src/9/port/devsrv.c
@@ -5,61 +5,221 @@
 #include "fns.h"
 #include "../port/error.h"

+#include "netif.h"

+typedef struct Link Link;
+struct Link
+{
+ void *link;
+ char *name;
+ ulong path;
+};
+
 typedef struct Srv Srv;
 struct Srv
 {
- char *name;
+ Link;
+
	char *owner;
	ulong perm;
	Chan *chan;
- Srv *link;
- ulong path;
 };

-static QLock srvlk;
-static Srv *srv;
-static int qidpath;
+typedef struct Board Board;
+struct Board
+{
+ Link;
+ QLock;

-static Srv*
-srvlookup(char *name, ulong qidpath)
+ Board *parent;
+ Board *child;
+ Srv *srv;
+ long id;
+ int qidpath;
+ int closed;
+ long ref;
+};
+
+struct{
+ QLock;
+ long path;
+} boards;
+
+enum{
+ Qboard,
+ Qclone,
+ Qlease,
+
+ Qend,
+};
+
+Board root;
+
+static void*
+lookup(Link *l, char *name, ulong qidpath)
 {
- Srv *sp;
+ Link *lp;

- for(sp = srv; sp != nil; sp = sp->link) {
- if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0))
- return sp;
+ if(qidpath != ~0UL)
+ qidpath = NETTYPE(qidpath);
+ for(lp = l; lp != nil; lp = lp->link){
+ if(qidpath != ~0UL && lp->path == qidpath)
+ return lp;
+ if(name != nil && strcmp(lp->name, name) == 0)
+ return lp;
	}
	return nil;
 }

+static void*
+remove(Link **l, char *name, ulong qidpath)
+{
+ Link *lp;
+ Link **last;
+
+ if(qidpath != ~0UL)
+ qidpath = NETTYPE(qidpath);
+ last = l;
+ for(lp = *l; lp != nil; lp = lp->link){
+ if(qidpath != ~0UL && lp->path == qidpath)
+ break;
+ if(name != nil && strcmp(lp->name, name) == 0)
+ break;
+ last = &lp->link;
+ }
+ if(lp == nil)
+ return nil;
+
+ *last = lp->link;
+ lp->link = nil;
+ return lp;
+}
+
+static void
+boardclunk(Board *b, int close)
+{
+ Srv *sp, *prv;
+ Board *ch;
+
+ /* caller holds a lock */
+ if(b == &root){
+ qunlock(b);
+ return;
+ }
+
+ if(close){
+ assert(b->closed == 0);
+ b->closed++;
+ for(sp = b->srv; sp != nil; sp = prv){
+ prv = sp->link;
+ free(sp->owner);
+ free(sp->name);
+ if(sp->chan != nil)
+ cclose(sp->chan);
+ free(sp);
+ }
+ b->srv = nil;
+ }
+
+ b->ref--;
+ if(b->ref < 0)
+ panic("devsrv: neg ref");
+ /*
+ * Each board other then root is owned
+ * by a single Qlease.  A 'closed' lease
+ * causes the board to no longer function.
+ * However, we may still have copies of that board
+ * on in use channels, so we can't free it just then.
+ * We need to wait until all references to this board
+ * have been clunked.  To accomplish this we only free
+ * leaf nodes, keeping 'closed' parents alive to allow
+ * their bodies to be walked over.  Then when freeing leaf
+ * nodes, we walk up the tree clearing out those waiting for only us.
+ */
+ while(b->closed && b->child == nil && b->ref == 0){
+ //Root should never be closed
+ assert(b->parent != nil);
+ ch = remove((Link**)&b->parent->child, b->name, b->path);
+ assert(ch == b);
+
+ b = ch->parent;
+ free(ch->name);
+ qunlock(ch);
+ free(ch);
+ if(b == nil)
+ return;
+ qlock(b);
+ }
+ qunlock(b);
+}
+
 static int
 srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
 {
	Srv *sp;
+ Board *b, *ch;
	Qid q;

+ if(name != nil && strlen(name) >= sizeof(up->genbuf))
+ return -1;
+
+ b = c->aux;
+ ch = nil;
+ mkqid(&q, ~0L, 0, QTFILE);
+ qlock(b);
+ if(waserror()){
+ qunlock(b);
+ return -1;
+ }
	if(s == DEVDOTDOT){
- devdir(c, c->qid, "#s", 0, eve, 0555, dp);
- return 1;
+ ch = b->parent;
+ if(ch == nil)
+ ch = &root;
+ goto Child;
+
	}
-
- qlock(&srvlk);
- if(name != nil)
- sp = srvlookup(name, -1);
- else {
- for(sp = srv; sp != nil && s > 0; sp = sp->link)
+ if(name != nil){
+ if(strcmp("clone", name) == 0){
+ goto Clone;
+ } else {
+ sp = lookup(b->srv, name, ~0UL);
+ if(sp == nil)
+ ch = lookup(b->child, name, ~0UL);
+ }
+ } else {
+ if(s == 0)
+ goto Clone;
+ s--;
+ for(sp = b->srv; sp != nil && s > 0; sp = sp->link)
			s--;
+ for(ch = b->child; ch != nil && s > 0; ch = ch->link)
+ s--;
	}
- if(sp == nil || (name != nil && (strlen(sp->name) >=
sizeof(up->genbuf)))) {
- qunlock(&srvlk);
- return -1;
- }
- mkqid(&q, sp->path, 0, QTFILE);
- /* make sure name string continues to exist after we release lock */
- kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
- devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
- qunlock(&srvlk);
+ if(sp != nil){
+ kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
+ q.vers = NETID(c->qid.path);
+ q.path = NETQID(q.vers, sp->path);
+ devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
+ } else if(ch != nil){
+Child:
+ kstrcpy(up->genbuf, ch->name, sizeof up->genbuf);
+ q.vers = ch->id;
+ q.path = NETQID(q.vers, ch->path);
+ q.type = QTDIR;
+ devdir(c, q, up->genbuf, 0, eve, 0555|DMDIR, dp);
+ /* dirread's and stats shouldn't alter c->aux */
+ if(name != nil)
+ c->aux = ch;
+ } else if(0){
+Clone:
+ q.vers = NETID(c->qid.path);
+ q.path = NETQID(q.vers, Qclone);
+ devdir(c, q, "clone", 0, eve, 0444, dp);
+ } else
+ error(Enonexist);
+
+ qunlock(b);
+ poperror();
	return 1;
 }

@@ -66,19 +226,38 @@
 static void
 srvinit(void)
 {
- qidpath = 1;
+ root.qidpath = Qend;
+ root.name = "#s";
 }

 static Chan*
 srvattach(char *spec)
 {
- return devattach('s', spec);
+ Chan *c;
+
+ c = devattach('s', spec);
+ c->aux = &root;
+ return c;
 }

 static Walkqid*
 srvwalk(Chan *c, Chan *nc, char **name, int nname)
 {
- return devwalk(c, nc, name, nname, 0, 0, srvgen);
+ Board *b;
+ Walkqid *wq;
+
+ wq = devwalk(c, nc, name, nname, 0, 0, srvgen);
+ if(wq == nil || wq->clone == nil)
+ return wq;
+
+ b = wq->clone->aux;
+ if(b == &root)
+ return wq;
+ qlock(b);
+ b->ref++;
+ //print("incref %ld %ld\n", b->id, b->ref);
+ qunlock(b);
+ return wq;
 }

 static int
@@ -90,12 +269,14 @@
 char*
 srvname(Chan *c)
 {
+ Board *b;
	Srv *sp;
	char *s;

	s = nil;
- qlock(&srvlk);
- for(sp = srv; sp != nil; sp = sp->link) {
+ b = &root;
+ qlock(b);
+ for(sp = b->srv; sp != nil; sp = sp->link) {
		if(sp->chan == c){
			s = malloc(3+strlen(sp->name)+1);
			if(s != nil)
@@ -103,7 +284,7 @@
			break;
		}
	}
- qunlock(&srvlk);
+ qunlock(b);
	return s;
 }

@@ -110,8 +291,10 @@
 static Chan*
 srvopen(Chan *c, int omode)
 {
+ Board *b, *ch;
	Srv *sp;
	Chan *nc;
+ char buf[64];

	if(c->qid.type == QTDIR){
		if(omode & ORCLOSE)
@@ -123,20 +306,49 @@
		c->offset = 0;
		return c;
	}
- qlock(&srvlk);
+ if(omode&OTRUNC)
+ error(Eexist);
+ if(omode&ORCLOSE)
+ error(Eperm);
+
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		nexterror();
	}
+ if(b->closed)
+ error("expired lease");
+ if(NETTYPE(c->qid.path) == Qclone){
+ ch = smalloc(sizeof *ch);
+ ch->qidpath = Qend;
+ ch->ref = 1;
+ qlock(&boards);
+ ch->id = ++boards.path;
+ qunlock(&boards);
+ //print("new %ld %ld\n", ch->id, ch->ref);

- sp = srvlookup(nil, c->qid.path);
+ ch->parent = b;
+ ch->path = b->qidpath++;
+ snprint(buf, sizeof buf, "%ld", ch->id);
+ kstrdup(&ch->name, buf);
+
+ ch->link = b->child;
+ b->child = ch;
+ c->aux = ch;
+ c->qid.vers = ch->id;
+ c->qid.path = NETQID(ch->id, Qlease);
+
+ poperror();
+ //print("transfer\n");
+ boardclunk(b, 0); //unlock
+ return c;
+ }
+
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil || sp->chan == nil)
		error(Eshutdown);

- if(omode&OTRUNC)
- error(Eexist);
- if(omode&ORCLOSE)
- error(Eperm);
	if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
		error(Eperm);
	devpermcheck(sp->owner, sp->perm, omode);
@@ -144,7 +356,7 @@
	nc = sp->chan;
	incref(nc);

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	cclose(c);
@@ -154,6 +366,7 @@
 static Chan*
 srvcreate(Chan *c, char *name, int omode, ulong perm)
 {
+ Board *b;
	Srv *sp;

	if(openmode(omode) != OWRITE)
@@ -166,27 +379,31 @@
	kstrdup(&sp->name, name);
	kstrdup(&sp->owner, up->user);

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		free(sp->owner);
		free(sp->name);
		free(sp);
		nexterror();
	}
- if(srvlookup(name, -1) != nil)
+ if(b->closed)
+ error("expired lease");
+ if(lookup(b->srv, name, ~0UL) != nil)
		error(Eexist);

	sp->perm = perm&0777;
- sp->path = qidpath++;
+ sp->path = b->qidpath++;

- c->qid.path = sp->path;
+ c->qid.path = NETQID(b->id, sp->path);
+ c->qid.vers = b->id;
	c->qid.type = QTFILE;

- sp->link = srv;
- srv = sp;
+ sp->link = b->srv;
+ b->srv = sp;

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	c->flag |= COPEN;
@@ -198,22 +415,19 @@
 static void
 srvremove(Chan *c)
 {
- Srv *sp, **l;
+ Board *b;
+ Srv *sp;

	if(c->qid.type == QTDIR)
		error(Eperm);

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		nexterror();
	}
- l = &srv;
- for(sp = *l; sp != nil; sp = *l) {
- if(sp->path == c->qid.path)
- break;
- l = &sp->link;
- }
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil)
		error(Enonexist);

@@ -229,10 +443,9 @@
	if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
		error(Eperm);

- *l = sp->link;
- sp->link = nil;
+ remove((Link**)&b->srv, nil, c->qid.path);

- qunlock(&srvlk);
+ boardclunk(b, 0); //unlock
	poperror();

	if(sp->chan != nil)
@@ -245,6 +458,7 @@
 static int
 srvwstat(Chan *c, uchar *dp, int n)
 {
+ Board *b;
	char *strs;
	Srv *sp;
	Dir d;
@@ -261,13 +475,14 @@
	if(n == 0)
		error(Eshortstat);

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		nexterror();
	}

- sp = srvlookup(nil, c->qid.path);
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil)
		error(Enonexist);

@@ -286,7 +501,7 @@
	if(d.mode != ~0UL)
		sp->perm = d.mode & 0777;

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	free(strs);
@@ -298,22 +513,42 @@
 static void
 srvclose(Chan *c)
 {
- /*
- * in theory we need to override any changes in removability
- * since open, but since all that's checked is the owner,
- * which is immutable, all is well.
- */
- if(c->flag & CRCLOSE){
+ Board *b;
+ int expired;
+
+ expired = 0;
+ if(NETTYPE(c->qid.path) == Qlease){
+ expired++;
+ } else if(c->flag & CRCLOSE){
+ /*
+ * in theory we need to override any changes in removability
+ * since open, but since all that's checked is the owner,
+ * which is immutable, all is well.
+ */
		if(waserror())
- return;
+ goto Clunk;
		srvremove(c);
		poperror();
+ return;
	}
+Clunk:
+ b = c->aux;
+ qlock(b);
+ boardclunk(b, expired); //unlock
 }

 static long
-srvread(Chan *c, void *va, long n, vlong)
+srvread(Chan *c, void *va, long n, vlong off)
 {
+ Board *b;
+
+ if(NETTYPE(c->qid.path) == Qlease){
+ b = c->aux;
+ qlock(b);
+ n = readstr((ulong)off, va, n, b->name);
+ qunlock(b);
+ return n;
+ }
	isdir(c);
	return devdirread(c, va, n, 0, 0, srvgen);
 }
@@ -321,6 +556,7 @@
 static long
 srvwrite(Chan *c, void *va, long n, vlong)
 {
+ Board *b;
	Srv *sp;
	Chan *c1;
	int fd;
@@ -334,15 +570,16 @@

	c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()) {
- qunlock(&srvlk);
+ qunlock(b);
		cclose(c1);
		nexterror();
	}
	if(c1->qid.type & QTAUTH)
		error("cannot post auth file in srv");
- sp = srvlookup(nil, c->qid.path);
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil)
		error(Enonexist);

@@ -351,7 +588,7 @@

	sp->chan = c1;

- qunlock(&srvlk);
+ qunlock(b);
	poperror();
	return n;
 }
@@ -380,12 +617,14 @@
 void
 srvrenameuser(char *old, char *new)
 {
+ Board *b;
	Srv *sp;

- qlock(&srvlk);
- for(sp = srv; sp != nil; sp = sp->link) {
+ b = &root;
+ qlock(b);
+ for(sp = b->srv; sp != nil; sp = sp->link) {
		if(sp->owner != nil && strcmp(old, sp->owner) == 0)
			kstrdup(&sp->owner, new);
	}
- qunlock(&srvlk);
+ qunlock(b);
 }


Sun Jun 19 13:48:57 EDT 2022
$ go build

# github.com/signal-golang/textsecure/crayfish
../../go/pkg/mod/github.com/signal-golang/textsecure@v1.10.4-0.20220301204135-53684eb9c15b/crayfish/backend.go:184:3:
unknown field 'Pdeathsig' in struct literal of type syscall.SysProcAttr
# github.com/mutecomm/go-sqlcipher
sqlite3.c:109951:38: warning: implicit conversion from 'long long' to 'double'
changes value from 9223372036854775806 to 9223372036854775808
[-Wimplicit-const-int-float-conversion]
sqlite3.c:109953:46: warning: implicit conversion from 'long long' to 'double'
changes value from 9223372036854775806 to 9223372036854775808
[-Wimplicit-const-int-float-conversion]
# github.com/nanu-c/zkgroup
ld: error: undefined symbol: FFI_AuthCredentialPresentation_checkValidContents
>>> referenced by cgo-gcc-prolog:55
>>>
$WORK/b225/_x002.o:(_cgo_00a37fea2984_Cfunc_FFI_AuthCredentialPresentation_checkValidContents)

ld: error: undefined symbol: FFI_AuthCredentialPresentation_getRedemptionTime
>>> referenced by cgo-gcc-prolog:79
>>>
$WORK/b225/_x002.o:(_cgo_00a37fea2984_Cfunc_FFI_AuthCredentialPresentation_getRedemptionTime)

ld: error: undefined symbol: FFI_AuthCredentialPresentation_getUuidCiphertext
>>> referenced by cgo-gcc-prolog:103
>>>
$WORK/b225/_x002.o:(_cgo_00a37fea2984_Cfunc_FFI_AuthCredentialPresentation_getUuidCiphertext)

ld: error: undefined symbol: FFI_AuthCredentialResponse_checkValidContents
>>> referenced by cgo-gcc-prolog:124
>>>
$WORK/b225/_x002.o:(_cgo_00a37fea2984_Cfunc_FFI_AuthCredentialResponse_checkValidContents)

ld: error: undefined symbol: FFI_AuthCredential_checkValidContents
>>> referenced by cgo-gcc-prolog:145
>>>
$WORK/b225/_x002.o:(_cgo_00a37fea2984_Cfunc_FFI_AuthCredential_checkValidContents)

ld: error: undefined symbol:
FFI_ProfileKeyCredentialPresentation_getProfileKeyCiphertext
>>> referenced by cgo-gcc-prolog:169
>>>
$WORK/b225/_x002.o:(_cgo_00a37fea2984_Cfunc_FFI_ProfileKeyCredentialPresentation_getProfileKeyCiphertext)

ld: error: undefined symbol: FFI_GroupSecretParams_decryptBlob
>>> referenced by cgo-gcc-prolog:61
>>>
$WORK/b225/_x003.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupSecretParams_decryptBlob)

ld: error: undefined symbol: FFI_GroupSecretParams_decryptProfileKey
>>> referenced by cgo-gcc-prolog:91
>>>
$WORK/b225/_x003.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupSecretParams_decryptProfileKey)

ld: error: undefined symbol: FFI_GroupSecretParams_decryptUuid
>>> referenced by cgo-gcc-prolog:118
>>>
$WORK/b225/_x003.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupSecretParams_decryptUuid)

ld: error: undefined symbol: FFI_GroupSecretParams_encryptBlobDeterministic
>>> referenced by cgo-gcc-prolog:148
>>>
$WORK/b225/_x003.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupSecretParams_encryptBlobDeterministic)

ld: error: undefined symbol: FFI_GroupSecretParams_encryptUuid
>>> referenced by cgo-gcc-prolog:175
>>>
$WORK/b225/_x003.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupSecretParams_encryptUuid)

ld: error: undefined symbol:
FFI_ServerPublicParams_createAuthCredentialPresentationDeterministic
>>> referenced by cgo-gcc-prolog:208
>>>
$WORK/b225/_x003.o:(_cgo_00a37fea2984_Cfunc_FFI_ServerPublicParams_createAuthCredentialPresentationDeterministic)

ld: error: undefined symbol: FFI_ServerPublicParams_receiveAuthCredential
>>> referenced by cgo-gcc-prolog:238
>>>
$WORK/b225/_x003.o:(_cgo_00a37fea2984_Cfunc_FFI_ServerPublicParams_receiveAuthCredential)

ld: error: undefined symbol: FFI_GroupPublicParams_getGroupIdentifier
>>> referenced by cgo-gcc-prolog:58
>>>
$WORK/b225/_x005.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupPublicParams_getGroupIdentifier)

ld: error: undefined symbol: FFI_GroupSecretParams_deriveFromMasterKey
>>> referenced by cgo-gcc-prolog:82
>>>
$WORK/b225/_x005.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupSecretParams_deriveFromMasterKey)

ld: error: undefined symbol: FFI_GroupSecretParams_generateDeterministic
>>> referenced by cgo-gcc-prolog:106
>>>
$WORK/b225/_x005.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupSecretParams_generateDeterministic)

ld: error: undefined symbol: FFI_GroupSecretParams_getMasterKey
>>> referenced by cgo-gcc-prolog:130
>>>
$WORK/b225/_x005.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupSecretParams_getMasterKey)

ld: error: undefined symbol: FFI_GroupSecretParams_getPublicParams
>>> referenced by cgo-gcc-prolog:154
>>>
$WORK/b225/_x005.o:(_cgo_00a37fea2984_Cfunc_FFI_GroupSecretParams_getPublicParams)

ld: error: undefined symbol:
FFI_ProfileKeyCredentialPresentation_checkValidContents
>>> referenced by cgo-gcc-prolog:55
>>>
$WORK/b225/_x006.o:(_cgo_00a37fea2984_Cfunc_FFI_ProfileKeyCredentialPresentation_checkValidContents)

ld: error: undefined symbol:
FFI_ProfileKeyCredentialPresentation_getUuidCiphertext
>>> referenced by cgo-gcc-prolog:79
>>>
$WORK/b225/_x006.o:(_cgo_00a37fea2984_Cfunc_FFI_ProfileKeyCredentialPresentation_getUuidCiphertext)

ld: error: too many errors emitted, stopping now (use -error-limit=0 to see all
errors)
cc: error: linker command failed with exit code 1 (use -v to see invocation)



$ go version
go version go1.17.7 openbsd/amd64

$ uname -a
OpenBSD localhost 7.1 GENERIC.MP#3 amd64

Sun Jun 19 12:22:39 EDT 2022
diff 990ceeef3bfd9d56e2e6dd39cf5ac185b1a2de08 uncommitted
--- a/sys/src/9/port/devsrv.c
+++ b/sys/src/9/port/devsrv.c
@@ -5,38 +5,144 @@
 #include "fns.h"
 #include "../port/error.h"

+#include "netif.h"

+typedef struct Link Link;
+struct Link
+{
+ void *link;
+ char *name;
+ ulong path;
+};
+
 typedef struct Srv Srv;
 struct Srv
 {
- char *name;
+ Link;
+
	char *owner;
	ulong perm;
	Chan *chan;
- Srv *link;
- ulong path;
 };

-static QLock srvlk;
-static Srv *srv;
-static int qidpath;
+typedef struct Board Board;
+struct Board
+{
+ Link;
+ QLock;

-static Srv*
-srvlookup(char *name, ulong qidpath)
+ Board *parent;
+ Board *child;
+ Srv *srv;
+ long id;
+ int qidpath;
+ int closed;
+};
+
+struct{
+ QLock;
+ long path;
+} boards;
+
+enum{
+ Qboard,
+ Qclone,
+ Qlease,
+
+ Qend,
+};
+
+Board root;
+
+static void*
+lookup(Link *l, char *name, ulong qidpath)
 {
- Srv *sp;
+ Link *lp;

- for(sp = srv; sp != nil; sp = sp->link) {
- if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0))
- return sp;
+ if(qidpath != ~0UL)
+ qidpath = NETTYPE(qidpath);
+ for(lp = l; lp != nil; lp = lp->link){
+ if(qidpath != ~0UL && lp->path == qidpath)
+ return lp;
+ if(name != nil && strcmp(lp->name, name) == 0)
+ return lp;
	}
	return nil;
 }

+static void*
+remove(Link **l, char *name, ulong qidpath)
+{
+ Link *lp;
+ Link **last;
+
+ if(qidpath != ~0UL)
+ qidpath = NETTYPE(qidpath);
+ last = l;
+ for(lp = *l; lp != nil; lp = lp->link){
+ if(qidpath != ~0UL && lp->path == qidpath)
+ break;
+ if(name != nil && strcmp(lp->name, name) == 0)
+ break;
+ last = &lp->link;
+ }
+ if(lp == nil)
+ return nil;
+
+ *last = lp->link;
+ lp->link = nil;
+ return lp;
+}
+
+static void
+boardclose(Board *b)
+{
+ Srv *sp, *prv;
+ Board *ch;
+
+ assert(b != &root);
+
+ qlock(b);
+ assert(b->closed == 0);
+ b->closed++;
+ for(sp = b->srv; sp != nil; sp = prv){
+ prv = sp->link;
+ free(sp->owner);
+ free(sp->name);
+ if(sp->chan != nil)
+ cclose(sp->chan);
+ free(sp);
+ }
+
+ /*
+ * All children must be walkable from the root.
+ * So any board is kept as long as it's not a leaf.
+ * When a leaf is free'd we walk up the tree and clean
+ * up those patiently waiting for us.
+ */
+ while(b->closed && b->child == nil){
+ //Root should never be closed
+ assert(b->parent != nil);
+ ch = remove((Link**)&b->parent->child, b->name, b->path);
+ assert(ch == b);
+ print("deleted %ld, parent child is now %p\n", ch->id,
ch->parent->child);
+
+ b = ch->parent;
+ free(ch->name);
+ qunlock(ch);
+ free(ch);
+ if(b == nil)
+ return;
+ qlock(b);
+ }
+ qunlock(b);
+}
+
 static int
 srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
 {
	Srv *sp;
+ Board *b, *ch;
	Qid q;

	if(s == DEVDOTDOT){
@@ -43,23 +149,57 @@
		devdir(c, c->qid, "#s", 0, eve, 0555, dp);
		return 1;
	}
+ if(name != nil && strlen(name) >= sizeof(up->genbuf))
+ return -1;

- qlock(&srvlk);
- if(name != nil)
- sp = srvlookup(name, -1);
- else {
- for(sp = srv; sp != nil && s > 0; sp = sp->link)
- s--;
- }
- if(sp == nil || (name != nil && (strlen(sp->name) >=
sizeof(up->genbuf)))) {
- qunlock(&srvlk);
+ b = c->aux;
+ ch = nil;
+ mkqid(&q, ~0L, 0, QTFILE);
+ qlock(b);
+ if(waserror()){
+ qunlock(b);
		return -1;
	}
- mkqid(&q, sp->path, 0, QTFILE);
- /* make sure name string continues to exist after we release lock */
- kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
- devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
- qunlock(&srvlk);
+ if(b->closed)
+ error("expired lease");
+ if(name != nil){
+ if(strcmp("clone", name) == 0){
+ goto Clone;
+ } else {
+ sp = lookup(b->srv, name, ~0UL);
+ if(sp == nil)
+ ch = lookup(b->child, name, ~0UL);
+ }
+ } else {
+ if(s == 0)
+ goto Clone;
+ s--;
+ for(sp = b->srv; sp != nil && s > 0; sp = sp->link)
+ s--;
+ for(ch = b->child; ch != nil && s > 0; ch = ch->link)
+ s--;
+ }
+ if(ch != nil){
+ kstrcpy(up->genbuf, ch->name, sizeof up->genbuf);
+ q.vers = ch->id;
+ q.path = NETQID(q.vers, ch->path);
+ q.type = QTDIR;
+ devdir(c, q, up->genbuf, 0, eve, 0555|DMDIR, dp);
+ } else if(sp != nil){
+ kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
+ q.vers = NETID(c->qid.path);
+ q.path = NETQID(q.vers, sp->path);
+ devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
+ } else if(0){
+Clone:
+ q.vers = NETID(c->qid.path);
+ q.path = NETQID(q.vers, Qclone);
+ devdir(c, q, "clone", 0, eve, 0444, dp);
+ } else
+ error(Enonexist);
+
+ qunlock(b);
+ poperror();
	return 1;
 }

@@ -66,13 +206,17 @@
 static void
 srvinit(void)
 {
- qidpath = 1;
+ root.qidpath = Qend;
 }

 static Chan*
 srvattach(char *spec)
 {
- return devattach('s', spec);
+ Chan *c;
+
+ c = devattach('s', spec);
+ c->aux = &root;
+ return c;
 }

 static Walkqid*
@@ -90,12 +234,14 @@
 char*
 srvname(Chan *c)
 {
+ Board *b;
	Srv *sp;
	char *s;

	s = nil;
- qlock(&srvlk);
- for(sp = srv; sp != nil; sp = sp->link) {
+ b = &root;
+ qlock(b);
+ for(sp = b->srv; sp != nil; sp = sp->link) {
		if(sp->chan == c){
			s = malloc(3+strlen(sp->name)+1);
			if(s != nil)
@@ -103,7 +249,7 @@
			break;
		}
	}
- qunlock(&srvlk);
+ qunlock(b);
	return s;
 }

@@ -110,8 +256,10 @@
 static Chan*
 srvopen(Chan *c, int omode)
 {
+ Board *b, *ch;
	Srv *sp;
	Chan *nc;
+ char buf[64];

	if(c->qid.type == QTDIR){
		if(omode & ORCLOSE)
@@ -123,20 +271,46 @@
		c->offset = 0;
		return c;
	}
- qlock(&srvlk);
+ if(omode&OTRUNC)
+ error(Eexist);
+ if(omode&ORCLOSE)
+ error(Eperm);
+
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		nexterror();
	}
+ if(b->closed)
+ error("expired lease");
+ if(NETTYPE(c->qid.path) == Qclone){
+ ch = smalloc(sizeof *ch);
+ ch->qidpath = Qend;
+ qlock(&boards);
+ ch->id = ++boards.path;
+ qunlock(&boards);

- sp = srvlookup(nil, c->qid.path);
+ ch->parent = b;
+ ch->path = b->qidpath++;
+ snprint(buf, sizeof buf, "%ld", ch->id);
+ kstrdup(&ch->name, buf);
+
+ ch->link = b->child;
+ b->child = ch;
+ c->aux = ch;
+ c->qid.vers = ch->id;
+ c->qid.path = NETQID(ch->id, Qlease);
+
+ poperror();
+ qunlock(b);
+ return c;
+ }
+
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil || sp->chan == nil)
		error(Eshutdown);

- if(omode&OTRUNC)
- error(Eexist);
- if(omode&ORCLOSE)
- error(Eperm);
	if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
		error(Eperm);
	devpermcheck(sp->owner, sp->perm, omode);
@@ -144,7 +318,7 @@
	nc = sp->chan;
	incref(nc);

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	cclose(c);
@@ -154,6 +328,7 @@
 static Chan*
 srvcreate(Chan *c, char *name, int omode, ulong perm)
 {
+ Board *b;
	Srv *sp;

	if(openmode(omode) != OWRITE)
@@ -166,27 +341,31 @@
	kstrdup(&sp->name, name);
	kstrdup(&sp->owner, up->user);

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		free(sp->owner);
		free(sp->name);
		free(sp);
		nexterror();
	}
- if(srvlookup(name, -1) != nil)
+ if(b->closed)
+ error("expired lease");
+ if(lookup(b->srv, name, ~0UL) != nil)
		error(Eexist);

	sp->perm = perm&0777;
- sp->path = qidpath++;
+ sp->path = b->qidpath++;

- c->qid.path = sp->path;
+ c->qid.path = NETQID(b->id, sp->path);
+ c->qid.vers = b->id;
	c->qid.type = QTFILE;

- sp->link = srv;
- srv = sp;
+ sp->link = b->srv;
+ b->srv = sp;

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	c->flag |= COPEN;
@@ -198,22 +377,19 @@
 static void
 srvremove(Chan *c)
 {
- Srv *sp, **l;
+ Board *b;
+ Srv *sp;

	if(c->qid.type == QTDIR)
		error(Eperm);

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		nexterror();
	}
- l = &srv;
- for(sp = *l; sp != nil; sp = *l) {
- if(sp->path == c->qid.path)
- break;
- l = &sp->link;
- }
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil)
		error(Enonexist);

@@ -229,10 +405,9 @@
	if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
		error(Eperm);

- *l = sp->link;
- sp->link = nil;
+ remove((Link**)&b->srv, nil, c->qid.path);

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	if(sp->chan != nil)
@@ -245,6 +420,7 @@
 static int
 srvwstat(Chan *c, uchar *dp, int n)
 {
+ Board *b;
	char *strs;
	Srv *sp;
	Dir d;
@@ -261,13 +437,14 @@
	if(n == 0)
		error(Eshortstat);

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()){
- qunlock(&srvlk);
+ qunlock(b);
		nexterror();
	}

- sp = srvlookup(nil, c->qid.path);
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil)
		error(Enonexist);

@@ -286,7 +463,7 @@
	if(d.mode != ~0UL)
		sp->perm = d.mode & 0777;

- qunlock(&srvlk);
+ qunlock(b);
	poperror();

	free(strs);
@@ -298,6 +475,10 @@
 static void
 srvclose(Chan *c)
 {
+ if(NETTYPE(c->qid.path) == Qlease){
+ boardclose(c->aux);
+ return;
+ }
	/*
	 * in theory we need to override any changes in removability
	 * since open, but since all that's checked is the owner,
@@ -312,8 +493,17 @@
 }

 static long
-srvread(Chan *c, void *va, long n, vlong)
+srvread(Chan *c, void *va, long n, vlong off)
 {
+ Board *b;
+
+ if(NETTYPE(c->qid.path) == Qlease){
+ b = c->aux;
+ qlock(b);
+ n = readstr((ulong)off, va, n, b->name);
+ qunlock(b);
+ return n;
+ }
	isdir(c);
	return devdirread(c, va, n, 0, 0, srvgen);
 }
@@ -321,6 +511,7 @@
 static long
 srvwrite(Chan *c, void *va, long n, vlong)
 {
+ Board *b;
	Srv *sp;
	Chan *c1;
	int fd;
@@ -334,15 +525,16 @@

	c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */

- qlock(&srvlk);
+ b = c->aux;
+ qlock(b);
	if(waserror()) {
- qunlock(&srvlk);
+ qunlock(b);
		cclose(c1);
		nexterror();
	}
	if(c1->qid.type & QTAUTH)
		error("cannot post auth file in srv");
- sp = srvlookup(nil, c->qid.path);
+ sp = lookup(b->srv, nil, c->qid.path);
	if(sp == nil)
		error(Enonexist);

@@ -351,7 +543,7 @@

	sp->chan = c1;

- qunlock(&srvlk);
+ qunlock(b);
	poperror();
	return n;
 }
@@ -380,12 +572,14 @@
 void
 srvrenameuser(char *old, char *new)
 {
+ Board *b;
	Srv *sp;

- qlock(&srvlk);
- for(sp = srv; sp != nil; sp = sp->link) {
+ b = &root;
+ qlock(b);
+ for(sp = b->srv; sp != nil; sp = sp->link) {
		if(sp->owner != nil && strcmp(old, sp->owner) == 0)
			kstrdup(&sp->owner, new);
	}
- qunlock(&srvlk);
+ qunlock(b);
 }


Sun Jun 19 11:27:07 EDT 2022
# plan 9 generated key:

$ openssl asn1parse -i -inform pem -in /home/ori/key.pem
    0:d=0 hl=3 l= 137 cons: SEQUENCE
    3:d=1 hl=3 l= 129 prim: INTEGER
    :E3E47888BBFA4043C313A57C915E5B282EE53C6DE3775D2DD63C01F5B12C81ED40E6CD860B31B9A5A15148657ED9C959C69F260E95F07572BDDE22FB70F497F3CB1EEF3D6C89069C7D2DB3FC1E22F409F91C7F85566D4BF1F5BE41D19A23E73B981A0E2FE3BDF00559C1B8062260904714A2F29B996031633181A9EFFCBA6DB7
  135:d=1 hl=2 l= 3 prim: INTEGER :010001

# openssl generated key
$ openssl asn1parse -i -inform pem -in /home/ori/xkey.pem
    0:d=0 hl=3 l= 159 cons: SEQUENCE
    3:d=1 hl=2 l= 13 cons: SEQUENCE
    5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
   16:d=2 hl=2 l= 0 prim: NULL
   18:d=1 hl=3 l= 141 prim: BIT STRING


Sun Jun 19 11:26:07 EDT 2022
$ openssl rsa -pubin -in /home/ori/key.pem -text
unable to load Public Key
140003161994560:error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong
tag:../crypto/asn1/tasn_dec.c:1149:
140003161994560:error:0D07803A:asn1 encoding routines:asn1_item_embed_d2i:nested
asn1 error:../crypto/asn1/tasn_dec.c:309:Type=X509_ALGOR
140003161994560:error:0D08303A:asn1 encoding
routines:asn1_template_noexp_d2i:nested asn1
error:../crypto/asn1/tasn_dec.c:646:Field=algor, Type=X509_PUBKEY
140003161994560:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1
lib:../crypto/pem/pem_oth.c:33:


Sun Jun 19 10:32:25 EDT 2022
(Message inbox:37)

Date: Sun, 19 Jun 2022 10:22:24 -0400
To: g*******@p*****.xyz
From: o**@o***.dev
Subject: test dkim

From o**@o***.dev Sun Jun 19 09: 29:52 2022
Return-Path: <o**@o***.dev>
X-Original-To: grobe0ba@localhost
Delivered-To: grobe0ba@localhost
Delivered-To: grobe0ba
Delivered-To: g*******@p*****.xyz
X-Rspamd-Server: mars.pulpie.xyz
X-Rspamd-Queue-Id: 19b4e39d
X-Spamd-Result: default: False [3.10 / 15.00];
	 HFILTER_HELO_5(3.00)[grinder];
	 RCVD_NO_TLS_LAST(0.10)[];
	 MIME_GOOD(-0.10)[text/plain];
	 ONCE_RECEIVED(0.10)[];
	 RCVD_COUNT_ONE(0.00)[1];
	 R_SPF_NA(0.00)[no SPF record];
	 FROM_EQ_ENVFROM(0.00)[];
	 R_DKIM_PERMFAIL(0.00)[o***.dev:s=dkim];
	 MIME_TRACE(0.00)[0:+];
	 ASN(0.00)[asn:20473, ipnet:144.202.0.0/20, country:US];
	 MID_RHS_MATCH_FROM(0.00)[];
	 FROM_NO_DN(0.00)[];
	 DMARC_NA(0.00)[o***.dev];
	 RECEIVED_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[144.202.1.203:received];
	 RBL_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[144.202.1.203:from];
	 DKIM_TRACE(0.00)[o***.dev:~];
	 TO_MATCH_ENVRCPT_ALL(0.00)[];
	 TO_DN_NONE(0.00)[];
	 PREVIOUSLY_DELIVERED(0.00)[g*******@p*****.xyz];
	 RCPT_COUNT_ONE(0.00)[1];
	 ARC_NA(0.00)[]
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=o***.dev;
	 h=subject:date:from:to:; s=dkim;
	 bh=hrmT7hi7gUeFUVWiEM5x456NmDDvaVVezXge5qpBOyo=;
	 b=QCptdb4Q4+Ldr7o+B0CZHTGrWrI0IsxbKz00bwK2JEtbdOVxSjT+AmpHR0e5oO2qW9tRNtopGsK5L9gNVNQOh//ptQGLnS/yMQvtFLn4fbK+zm+4HerpYKkRpbfX8vVu6gUxv/2Q+a8kZ02AOnqk7kiRxQC+L3tVsKgxM4Ryjn0=
MIME-Version: 1.0


hows the sig look


prev | next