shithub: drawcpu

Download patch

ref: 94cb585132563082a7db68d7a61bb59e885c5b20
parent: 8b24f795e2bb2a5d169641ed0fda0e99b69e4466
author: halfwit <michaelmisch1985@gmail.com>
date: Sun Dec 28 19:40:37 EST 2025

Update to get much more of a robust runtime

--- a/TODO
+++ b/TODO
@@ -5,6 +5,8 @@
    - [ ] Use ScreenCaptureKit to get at the video/audio. Handle resizes the other direction
  - [ ] gui-wl cannibalize the wayland shims
  - [ ] define the gui interface
+   - [ ] drawinit - initialization
+   - [ ] drawrun(p) - capture for a specific process, ran in `os`/`devcmd`
  - [ ] Fully fledged note handling
  - [x] up->parent integration into /proc
  - [ ] Un-stub stub.c things
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -13,6 +13,7 @@
 	devcap.$O\
 	devcmd.$O\
 	devcons.$O\
+	devdup.$O\
 	devenv.$O\
 	devfs-$(OS).$O\
 	devlfd-$(OS).$O\
@@ -22,6 +23,7 @@
 	devpipe.$O\
 	devproc.$O\
 	devroot.$O\
+	devsrv.$O\
 	devssl.$O\
 	devtab.$O\
 	devtls.$O\
--- a/kern/dat.h
+++ b/kern/dat.h
@@ -186,6 +186,7 @@
 	Chan*	mchan;			/* channel to mounted server */
 	Qid	mqid;			/* qid of root of mount point */
 	Path*	path;
+	char *srvname;
 };
 
 struct Path
--- a/kern/devcmd.c
+++ b/kern/devcmd.c
@@ -655,6 +655,13 @@
 		iprint("XXX %s\n", up->errstr);
 		oscmdkill(t);
 	}
+
+	// TODO: t holds pid
+	// TODO: Spin up kbd/mouse/screen
+	//attachscreen(t);
+	//attachkbd(t)
+	//attachmouse(t);
+
 	n = oscmdwait(t, status, sizeof(status));
 	if(n < 0){
 		oserrstr();
@@ -673,6 +680,7 @@
 			qproduce(c->waitq, status, n);
 	}else
 		closeconv(c);
+	// TODO: Spin down kbd/mouse/screen
 	qunlock(&c->l);
 	pexit("", 0);
 }
--- /dev/null
+++ b/kern/devdup.c
@@ -1,0 +1,143 @@
+#include	"u.h"
+#include	"lib.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+
+/* Qid is (2*fd + (file is ctl))+1 */
+
+static int
+dupgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
+{
+	Fgrp *fgrp = up->fgrp;
+	Chan *f;
+	static int perm[] = { 0400, 0200, 0600, 0 };
+	int p;
+	Qid q;
+
+	if(s == DEVDOTDOT){
+		devdir(c, c->qid, ".", 0, eve, 0555, dp);
+		return 1;
+	}
+	if(s == 0)
+		return 0;
+	s--;
+	if(s/2 > fgrp->maxfd)
+		return -1;
+	if((f=fgrp->fd[s/2]) == nil)
+		return 0;
+	if(s & 1){
+		p = 0400;
+		sprint(up->genbuf, "%dctl", s/2);
+	}else{
+		p = perm[f->mode&3];
+		sprint(up->genbuf, "%d", s/2);
+	}
+	mkqid(&q, s+1, 0, QTFILE);
+	devdir(c, q, up->genbuf, 0, eve, p, dp);
+	return 1;
+}
+
+static Chan*
+dupattach(char *spec)
+{
+	return devattach('d', spec);
+}
+
+static Walkqid*
+dupwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	return devwalk(c, nc, name, nname, (Dirtab *)0, 0, dupgen);
+}
+
+static int
+dupstat(Chan *c, uchar *db, int n)
+{
+	return devstat(c, db, n, (Dirtab *)0, 0L, dupgen);
+}
+
+static Chan*
+dupopen(Chan *c, int omode)
+{
+	Chan *f;
+	int fd, twicefd;
+
+	if(omode & ORCLOSE)
+		error(Eperm);
+	if(c->qid.type & QTDIR){
+		if(omode != 0)
+			error(Eisdir);
+		c->mode = 0;
+		c->flag |= COPEN;
+		c->offset = 0;
+		return c;
+	}
+	if(c->qid.type & QTAUTH)
+		error(Eperm);
+	twicefd = c->qid.path - 1;
+	fd = twicefd/2;
+	if((twicefd & 1)){
+		/* ctl file */
+		f = c;
+		f->mode = openmode(omode);
+		f->flag |= COPEN;
+		f->offset = 0;
+	}else{
+		/* fd file */
+		f = fdtochan(fd, openmode(omode), 0, 1);
+		cclose(c);
+	}
+	return f;
+}
+
+static void
+dupclose(Chan*)
+{
+}
+
+static long
+dupread(Chan *c, void *va, long n, vlong offset)
+{
+	char *a = va;
+	char buf[256];
+	int fd, twicefd;
+
+	if(c->qid.type == QTDIR)
+		return devdirread(c, a, n, (Dirtab *)0, 0L, dupgen);
+	twicefd = c->qid.path - 1;
+	fd = twicefd/2;
+	if(twicefd & 1){
+		c = fdtochan(fd, -1, 0, 1);
+		procfdprint(c, fd, buf, sizeof buf);
+		cclose(c);
+		return readstr((ulong)offset, va, n, buf);
+	}
+	panic("dupread");
+}
+
+static long
+dupwrite(Chan*, void*, long, vlong)
+{
+	error(Eperm);
+}
+
+Dev dupdevtab = {
+	'd',
+	"dup",
+
+	devreset,
+	devinit,
+	devshutdown,
+	dupattach,
+	dupwalk,
+	dupstat,
+	dupopen,
+	devcreate,
+	dupclose,
+	dupread,
+	devbread,
+	dupwrite,
+	devbwrite,
+	devremove,
+	devwstat,
+};
\ No newline at end of file
--- a/kern/devenv.c
+++ b/kern/devenv.c
@@ -366,6 +366,21 @@
 	wunlock(&eg->lk);
 }
 
+/*
+ *  to let the kernel set environment variables
+ */
+void
+ksetenv(char *ename, char *eval, int conf)
+{
+	Chan *c;
+	char buf[2*KNAMELEN];
+	
+	snprint(buf, sizeof(buf), "#e%s/%s", conf?"c":"", ename);
+	c = namec(buf, Acreate, OWRITE, 0666);
+	devtab[c->type]->write(c, eval, strlen(eval), 0);
+	cclose(c);
+}
+
 void
 envcpy(Egrp *to, Egrp *from)
 {
--- a/kern/devroot.c
+++ b/kern/devroot.c
@@ -10,10 +10,13 @@
 	Qboot = 0x1000,
 	Qmnt = 0x2000,
 	Qfactotum,
+	Qroot,
+	Qcpu,
+	Qterm,
 
 	Nrootfiles = 32,
 	Nbootfiles = 32,
-	Nmntfiles = 2,
+	Nmntfiles = 5,
 };
 
 typedef struct Dirlist Dirlist;
@@ -58,6 +61,9 @@
 static Dirtab mntdir[Nmntfiles] = {
 	"mnt",	{Qmnt, 0, QTDIR},	0,		DMDIR|0555,
 	"factotum",	{Qfactotum, 0, QTDIR},	0,	DMDIR|0555,
+	"root", {Qroot, 0, QTDIR}, 0, DMDIR|0555,
+	"cpu", {Qcpu, 0, QTDIR}, 0, DMDIR|0555,
+	"term", {Qterm, 0, QTDIR}, 0, DMDIR|0555,
 };
 static Dirlist mntlist =
 {
@@ -64,7 +70,7 @@
 	Qmnt,
 	mntdir,
 	mntdata,
-	2,
+	5,
 	Nmntfiles
 };
 
@@ -111,17 +117,19 @@
 static void
 rootreset(void)
 {
-	addrootdir("arm");
 	addrootdir("bin");
 	addrootdir("dev");
 	addrootdir("env");
 	addrootdir("fd");
-	addrootdir("rc");
+	addrootdir("mnt");
+	addrootdir("n");
 	addrootdir("net");
 	addrootdir("net.alt");
 	addrootdir("proc");
 	addrootdir("root");
 	addrootdir("srv");
+	addrootdir("shr");
+	addrootdir("tmp");
 }
 
 static Chan*
--- /dev/null
+++ b/kern/devsrv.c
@@ -1,0 +1,685 @@
+#include	"u.h"
+#include	"lib.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+
+#define SRVTYPE(x)	(((uint)x)&0x3)
+#define SRVPATH(x)	(((uvlong)x)>>2)
+#define SRVQID(x, t)	((((uvlong)x)<<2)|((t)&0x3))
+
+typedef struct Link Link;
+struct Link
+{
+	void 	*link;
+	char 	*name;
+	char	*owner;
+	ulong	perm;
+	ulong 	path;
+};
+
+typedef struct Srv Srv;
+struct Srv
+{
+	Link ln;
+	Chan	*chan;
+};
+
+typedef struct Board Board;
+struct Board
+{
+	Link ln;
+	Ref rf;
+
+	int 	closed;	
+	Srv 	*srv;
+
+	/* tree linkage */
+	Board 	*parent;
+	Board 	*child;
+
+	/* all boards list */
+	Board	*prev;
+	Board	*next;
+};
+
+enum{
+	Qsrv,
+	Qclone,
+	Qlease,
+};
+
+static char clone[] = "clone";
+
+static RWLock srvlk;
+static ulong srvpath;
+static Board srvroot;
+
+static void*
+lookup(Link *l, char *name, ulong qidpath)
+{
+	Link *lp;
+
+	if(qidpath != ~0UL){
+		qidpath = SRVPATH(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*
+bremove(Link **l, char *name, ulong qidpath)
+{
+	Link *lp;
+	Link **last;
+
+	if(qidpath != ~0UL){
+		assert(SRVTYPE(qidpath) == Qsrv);
+		qidpath = SRVPATH(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
+freelink(Link *l)
+{
+	free(l->name);
+	free(l->owner);
+	free(l);
+}
+
+/* always called with srvlock wlock'ed */
+static void
+boardclunk(Board *b)
+{
+	Board *ch;
+
+	/* srvroot is not ref-counted nor clunkable */
+	if(b == &srvroot)
+		return;
+
+	if(decref(b))
+		return;
+
+	/*
+	 * All boards must be walkable from root. So a board
+	 * is allowed to sit at zero references as long as it
+	 * still has active children. For leaf nodes we then
+	 * have to walk up the tree to clear now empty parents.
+	 */
+	while(b->closed && b->child == nil){
+		assert(b->srv == nil);
+		assert(b->parent != nil);
+
+		/* unlink from parent board */
+		ch = bremove((Link**)&b->parent->child, b->ln.name, ~0UL);
+		assert(ch == b);
+
+		/* unlink from all boards list */
+		ch->prev->next = ch->next;
+		ch->next->prev = ch->prev;
+
+		b = ch->parent;
+		freelink(ch);
+	}
+}
+
+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);
+	rlock(&srvlk);
+	if(waserror()){
+		runlock(&srvlk);
+		nexterror();
+	}
+	switch(s){
+	case -2: /* dot */
+		ch = b;
+		goto Child;
+	case DEVDOTDOT:
+		ch = b->parent;
+		if(ch == nil)
+			ch = &srvroot;
+		goto Child;
+	}
+	if(name != nil){
+		if(strcmp(name, clone) == 0)
+			goto Clone;
+
+		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->ln.link)
+			s--;
+		for(ch = b->child; ch != nil && s > 0; ch = ch->ln.link)
+			s--;
+	}
+	if(sp != nil){
+		kstrcpy(up->genbuf, sp->ln.name, sizeof up->genbuf);
+		q.path = SRVQID(sp->ln.path, Qsrv);
+		devdir(c, q, up->genbuf, 0, sp->ln.owner, sp->ln.perm, dp);
+	} else if(ch != nil){
+Child:
+		if(name != nil || s == DEVDOTDOT){
+			devpermcheck(ch->ln.owner, ch->ln.perm, OEXEC);
+			c->aux = ch;
+		}
+		kstrcpy(up->genbuf, ch->ln.name, sizeof up->genbuf);
+		q.path = SRVQID(ch->ln.path, Qsrv);
+		q.type = QTDIR;
+		devdir(c, q, up->genbuf, 0, ch->ln.owner, ch->ln.perm|DMDIR, dp);
+	} else if(0){
+Clone:
+		q.path = SRVQID(SRVPATH(c->qid.path), Qclone);
+		devdir(c, q, clone, 0, eve, 0444, dp);
+	} else {
+		runlock(&srvlk);
+		poperror();
+		return -1;
+	}
+
+	runlock(&srvlk);
+	poperror();
+	return 1;
+}
+
+static void
+srvinit(void)
+{
+	srvroot.next = &srvroot;
+	srvroot.prev = &srvroot;
+	srvroot.ln.path = srvpath++;
+	srvroot.ln.name = "#s";
+	srvroot.ln.perm = 0777;
+	kstrdup(&srvroot.ln.owner, eve);
+}
+
+static Chan*
+srvattach(char *spec)
+{
+	Chan *c;
+
+	c = devattach('s', spec);
+	c->aux = &srvroot;
+	return c;
+}
+
+static Walkqid*
+srvwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+	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 == &srvroot)
+		return wq;
+
+	incref(b);
+	return wq;
+}
+
+static int
+srvstat(Chan *c, uchar *db, int n)
+{
+	Dir d;
+
+	/* devstat cheats for dir stats, we care about our dir perms */
+	if(c->qid.type == QTDIR){
+		srvgen(c, nil, nil, 0, -2, &d);
+		n = convD2M(&d, db, n);
+		if(n == 0)
+			error(Ebadarg);
+		return n;
+	}
+
+	return devstat(c, db, n, 0, 0, srvgen);
+}
+
+static Chan*
+srvopen(Chan *c, int omode)
+{
+	Board *b, *ch;
+	Srv *sp;
+	Chan *nc;
+	char buf[64];
+	int mode;
+
+	if(omode&OTRUNC)
+		error(Eexist);
+	if(omode&ORCLOSE)
+		error(Eperm);
+	mode = openmode(omode);
+
+	b = c->aux;
+	if(SRVTYPE(c->qid.path) == Qclone){
+		wlock(&srvlk);
+		if(waserror()){
+			wunlock(&srvlk);
+			nexterror();
+		}
+		if(b->closed)
+			error(Eshutdown);
+		ch = smalloc(sizeof *ch);
+		ch->rf.ref = 1;
+		ch->ln.perm = 0770;
+		do {
+			ch->ln.path = srvpath++;
+			snprint(buf, sizeof buf, "%ld", ch->ln.path);
+		} while(lookup(b->srv, buf, ~0UL) != nil);
+		kstrdup(&ch->ln.name, buf);
+		kstrdup(&ch->ln.owner, up->user);
+
+		/* link to all boards list */
+		ch->next = &srvroot;
+		ch->prev = srvroot.prev;
+		ch->next->prev = ch;
+		ch->prev->next = ch;
+
+		/* link to parent board */
+		ch->parent = b;
+		ch->ln.link = b->child;
+		b->child = ch;
+
+		c->aux = ch;
+		c->qid.path = SRVQID(ch->ln.path, Qlease);
+		c->mode = mode;
+		boardclunk(b);
+		wunlock(&srvlk);
+		poperror();
+		return c;
+	}
+
+	rlock(&srvlk);
+	if(waserror()){
+		runlock(&srvlk);
+		nexterror();
+	}
+	if(c->qid.type == QTDIR){
+		if(omode != OREAD)
+			error(Eisdir);
+		devpermcheck(b->ln.owner, b->ln.perm, omode);
+		c->mode = mode;
+		c->flag |= COPEN;
+		c->offset = 0;
+		runlock(&srvlk);
+		poperror();
+		return c;
+	}
+	if(b->closed)
+		error(Eshutdown);
+
+	sp = lookup(b->srv, nil, c->qid.path);
+	if(sp == nil)
+		error(Eshutdown);
+	nc = sp->chan;
+	if(nc == nil)
+		error(Eshutdown);
+	if(mode != nc->mode && nc->mode != ORDWR)
+		error(Eperm);
+	devpermcheck(sp->ln.owner, sp->ln.perm, omode);
+
+	incref(nc);
+
+	runlock(&srvlk);
+	poperror();
+
+	cclose(c);
+	return nc;
+}
+
+static Chan*
+srvcreate(Chan *c, char *name, int omode, ulong perm)
+{
+	Board *b;
+	Srv *sp;
+
+	if(openmode(omode) != OWRITE)
+		error(Eperm);
+
+	if(strlen(name) >= sizeof(up->genbuf))
+		error(Etoolong);
+
+	if(strcmp(name, clone) == 0)
+		error(Eexist);
+
+	sp = smalloc(sizeof *sp);
+	kstrdup(&sp->ln.name, name);
+	kstrdup(&sp->ln.owner, up->user);
+
+	b = c->aux;
+	wlock(&srvlk);
+	if(waserror()){
+		wunlock(&srvlk);
+		freelink(sp);
+		nexterror();
+	}
+	if(b->closed)
+		error(Eshutdown);
+	devpermcheck(b->ln.owner, b->ln.perm, OWRITE);
+	if(lookup(b->srv, name, ~0UL) != nil)
+		error(Eexist);
+	if(lookup(b->child, name, ~0UL) != nil)
+		error(Eexist);
+
+	sp->ln.perm = perm&0777;
+	sp->ln.path = srvpath++;
+
+	c->qid.path = SRVQID(sp->ln.path, Qsrv);
+	c->qid.type = QTFILE;
+
+	sp->ln.link = b->srv;
+	b->srv = sp;
+
+	wunlock(&srvlk);
+	poperror();
+
+	c->flag |= COPEN;
+	c->mode = OWRITE;
+
+	return c;
+}
+
+static void
+srvremove(Chan *c)
+{
+	Board *b;
+	Srv *sp;
+
+	b = c->aux;
+	wlock(&srvlk);
+	if(waserror()){
+		boardclunk(b);
+		wunlock(&srvlk);
+		nexterror();
+	}
+	if(c->qid.type == QTDIR)
+		error(Eperm);
+	switch(SRVTYPE(c->qid.path)){
+	case Qlease:
+	case Qclone:
+		error(Eperm);
+	}
+
+	sp = lookup(b->srv, nil, c->qid.path);
+	if(sp == nil)
+		error(Enonexist);
+
+	if(strcmp(sp->ln.owner, up->user) != 0 && !iseve())
+		error(Eperm);
+
+	bremove((Link**)&b->srv, nil, c->qid.path);
+
+	boardclunk(b);
+	wunlock(&srvlk);
+	poperror();
+
+	if(sp->chan != nil)
+		cclose(sp->chan);
+	freelink(sp);
+}
+
+static int
+srvwstat(Chan *c, uchar *dp, int n)
+{
+	Board *b, *s;
+	char *strs;
+	Dir d;
+	Link *lp;
+
+	switch(SRVTYPE(c->qid.path)){
+	case Qlease:
+	case Qclone:
+		error(Eperm);
+	}
+	if(c->qid.type == QTDIR && c->aux == &srvroot)
+		error(Eperm);
+
+	strs = smalloc(n);
+	if(waserror()){
+		free(strs);
+		nexterror();
+	}
+	n = convM2D(dp, n, &d, strs);
+	if(n == 0)
+		error(Eshortstat);
+
+	b = c->aux;
+	wlock(&srvlk);
+	if(waserror()){
+		wunlock(&srvlk);
+		nexterror();
+	}
+	if(b->closed)
+		error(Eshutdown);
+
+	if(c->qid.type == QTDIR)
+		lp = b;
+	else
+		lp = lookup(b->srv, nil, c->qid.path);
+	if(lp == nil)
+		error(Enonexist);
+
+	if(strcmp(lp->owner, up->user) != 0 && !iseve())
+		error(Eperm);
+
+	if(d.name != nil && *d.name && strcmp(lp->name, d.name) != 0) {
+		if(strchr(d.name, '/') != nil)
+			error(Ebadchar);
+		if(strlen(d.name) >= sizeof(up->genbuf))
+			error(Etoolong);
+
+		/* Ensure new name doesn't conflict with old names */
+		if(strcmp(d.name, clone) == 0)
+			error(Eexist);
+		if(c->qid.type == QTDIR)
+			s = b->parent;
+		else
+			s = b;
+		if(lookup(s->srv, d.name, ~0UL) != nil)
+			error(Eexist);
+		if(lookup(s->child, d.name, ~0UL) != nil)
+			error(Eexist);
+		kstrdup(&lp->name, d.name);
+	}
+	if(d.uid != nil && *d.uid)
+		kstrdup(&lp->owner, d.uid);
+	if(d.mode != ~0UL)
+		lp->perm = d.mode & 0777;
+
+	wunlock(&srvlk);
+	poperror();
+
+	free(strs);
+	poperror();
+
+	return n;
+}
+
+static void
+srvclose(Chan *c)
+{
+	Srv *sp, *link;
+	Board *b;
+
+	if((c->flag & CRCLOSE) != 0 && SRVTYPE(c->qid.path) != Qlease){
+		/*
+		 * 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;
+		srvremove(c);
+		poperror();
+		return;
+	}
+
+	b = c->aux;
+	if(b == &srvroot)
+		return;
+
+	wlock(&srvlk);
+	if(SRVTYPE(c->qid.path) != Qlease){
+		boardclunk(b);
+		wunlock(&srvlk);
+		return;
+	}
+
+	/* free later after releasing srvlk */
+	sp = b->srv;
+	b->srv = nil;
+	b->closed++;
+	boardclunk(b);
+	wunlock(&srvlk);
+
+	for(; sp != nil; sp = link){
+		link = sp->ln.link;
+		if(sp->chan != nil)
+			cclose(sp->chan);
+		freelink(sp);
+	}
+}
+
+static long
+srvread(Chan *c, void *va, long n, vlong off)
+{
+	Board *b;
+
+	if(SRVTYPE(c->qid.path) == Qlease){
+		b = c->aux;
+		rlock(&srvlk);
+		if(waserror()){
+			runlock(&srvlk);
+			nexterror();
+		}
+		n = readstr((ulong)off, va, n, b->ln.name);
+		runlock(&srvlk);
+		poperror();
+		return n;
+	}
+	isdir(c);
+	return devdirread(c, va, n, 0, 0, srvgen);
+}
+
+static long
+srvwrite(Chan *c, void *va, long n, vlong)
+{
+	Board *b;
+	Srv *sp;
+	Chan *c1;
+	int fd;
+	char buf[32];
+
+	if(SRVTYPE(c->qid.path) == Qlease)
+		error(Eperm);
+
+	if(n >= sizeof buf)
+		error(Etoobig);
+	memmove(buf, va, n);	/* so we can NUL-terminate */
+	buf[n] = 0;
+	fd = strtoul(buf, 0, 0);
+
+	c1 = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */
+
+	b = c->aux;
+	wlock(&srvlk);
+	if(waserror()) {
+		wunlock(&srvlk);
+		cclose(c1);
+		nexterror();
+	}
+	if(b->closed)
+		error(Eshutdown);
+	if(c1->qid.type & QTAUTH)
+		error("cannot post auth file in srv");
+	sp = lookup(b->srv, nil, c->qid.path);
+	if(sp == nil)
+		error(Enonexist);
+
+	if(sp->chan != nil)
+		error(Ebadusefd);
+
+	sp->chan = c1;
+	if(c1->srvname == nil)
+		kstrdup(&c1->srvname, c->path->s);
+
+	wunlock(&srvlk);
+	poperror();
+	return n;
+}
+
+Dev srvdevtab = {
+	's',
+	"srv",
+
+	devreset,
+	srvinit,	
+	devshutdown,
+	srvattach,
+	srvwalk,
+	srvstat,
+	srvopen,
+	srvcreate,
+	srvclose,
+	srvread,
+	devbread,
+	srvwrite,
+	devbwrite,
+	srvremove,
+	srvwstat,
+};
+
+void
+srvrenameuser(char *old, char *new)
+{
+	Board *b;
+	Srv *sp;
+
+	wlock(&srvlk);
+	b = &srvroot;
+	do {
+		if(strcmp(b->ln.owner, old) == 0)
+			kstrdup(&b->ln.owner, new);
+		for(sp = b->srv; sp != nil; sp = sp->ln.link)
+			if(strcmp(sp->ln.owner, old) == 0)
+				kstrdup(&sp->ln.owner, new);
+		b = b->next;
+	} while(b != &srvroot);
+	wunlock(&srvlk);
+}
\ No newline at end of file
--- a/kern/devtab.c
+++ b/kern/devtab.c
@@ -6,6 +6,7 @@
 
 extern Dev consdevtab;
 extern Dev rootdevtab;
+extern Dev dupdevtab;
 extern Dev pipedevtab;
 extern Dev ssldevtab;
 extern Dev tlsdevtab;
@@ -17,11 +18,13 @@
 extern Dev cmddevtab;
 extern Dev envdevtab;
 extern Dev procdevtab;
+extern Dev srvdevtab;
 extern Dev capdevtab;
 
 Dev *devtab[] = {
 	&rootdevtab,
 	&consdevtab,
+	&dupdevtab,
 	&pipedevtab,
 	&ssldevtab,
 	&tlsdevtab,
@@ -33,6 +36,7 @@
 	&cmddevtab,
 	&envdevtab,
 	&procdevtab,
+	&srvdevtab,
 	&capdevtab,
 	0
 };
--- a/kern/fns.h
+++ b/kern/fns.h
@@ -56,7 +56,6 @@
 Walkqid*	devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*);
 int	    	devwstat(Chan*, uchar*, int);
 Dir*		dirchanstat(Chan*);
-void		drawcmap(void);
 void        donote(char *, ulong);
 void        dump(void);
 Fgrp*		dupfgrp(Fgrp*);
@@ -81,8 +80,8 @@
 void        freesegs(void);
 uintptr		getmalloctag(void*);
 uintptr		getrealloctag(void*);
-void		gotolabel(Label*);
 char*		getconfenv(void);
+void		gotolabel(Label*);
 long		hostdomainwrite(char*, int);
 long		hostownerwrite(char*, int);
 Block*		iallocb(int);
@@ -157,7 +156,7 @@
 #define		poperror()		up->nerrlab--
 int		    postnote(Proc*, int, char*, int);
 int	        pprint(char*, ...);
-int		    procfdprint(Chan*, int, int, char*, int);
+int		    procfdprint(Chan*, int, char*, int);
 void		procinit0(void);
 void        procrun(void*);
 Proc*		proctab(int);
@@ -256,5 +255,5 @@
 void	    procwakeup(Proc*);
 void	    osinit(void);
 void	    screeninit(void);
-extern	void	terminit(void);
+
 extern	void	setterm(int);
--- a/kern/screen.h
+++ b/kern/screen.h
@@ -33,9 +33,6 @@
 extern	Cursorinfo cursor;
 extern	Cursorinfo arrow;
 
-void	screeninit(void);
-void	screenload(Rectangle, int, uchar *, Point, int);
-
 void	getcolor(ulong, ulong*, ulong*, ulong*);
 void	setcolor(ulong, ulong, ulong, ulong);
 
@@ -42,6 +39,7 @@
 void	setcursor(void);
 void	mouseset(Point);
 void	flushmemscreen(Rectangle);
+void	screenload(Rectangle, int, uchar *, Point, int);
 Memdata*attachscreen(Rectangle*, ulong*, int*, int*, int*);
 void	deletescreenimage(void);
 void	resetscreenimage(void);
@@ -49,7 +47,6 @@
 extern	QLock drawlock;
 #define	ishwimage(i)	0
 
-void	terminit(void);
 void	screenresize(Rectangle);
 void	screensize(Rectangle, ulong);
 
@@ -56,5 +53,4 @@
 void	mouseresize(void);
 void	mousetrack(int, int, int, ulong);
 void	absmousetrack(int, int, int, ulong);
-void	cpubody(void);
-void	guimain(void);
+
--- a/kern/sysproc.c
+++ b/kern/sysproc.c
@@ -147,6 +147,17 @@
 	wunlock(&fd->rw);
 }
 
+int
+procfdprint(Chan *c, int fd, char *s, int ns)
+{
+	return snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %lud %.2ux) %5ld %8lld %s\n",
+		fd,
+		&"r w rw"[(c->mode&3)<<1],
+		devtab[c->type]->dc, c->dev,
+		c->qid.path, c->qid.vers, c->qid.type,
+		8102, c->offset, c->path->s);
+}
+
 void
 fdclear(Fd *fd)
 {
--- a/main.c
+++ b/main.c
@@ -4,12 +4,13 @@
 #include "kern/fns.h"
 #include "user.h"
 #include "drawcpu.h"
+#include "auth.h"
 #include "args.h"
 #include "proc.h"
 
 char *argv0;
-int debug;
-char *ninepath;
+char cons[] = "/dev/cons";
+int  debug;
 
 void
 sizebug(void)
@@ -29,30 +30,28 @@
 	assert(sizeof(uvlong)==8);
 }
 
-// TODO: remove libgui, or at least revamp as cpubody goes away
-void cpubody(void) {}
-
-char*
-estrdup(char *s)
-{
-	s = strdup(s);
-	if(s == nil)
-		sysfatal("out of memory");
-    return s;
-}
-
-
 static void
 usage(void)
 {
-	fprintf(stderr, "usage: drawcpu [-p <path> -d]\n");
+	fprintf(stderr, "usage: drawcpu [-d]\n");
 	exit(1);
 }
 
 void
+postsrv(int fd, char *name)
+{
+	int sfd;
+
+	sfd = create(smprint("/srv/%s", name), OWRITE, 0666);
+	fprint(sfd, "%d", fd);
+	close(sfd);
+}
+
+void
 notehandler(void *d, char *note)
 {
 	USED(d);
+print("note: %s\n", note);
 	if(strncmp(note, "sys:", 4) == 0)
 		return;
 	
@@ -63,74 +62,40 @@
 	return;
 }
 
-static void
-envinit(char *nvram)
-{
-	int fd, nvrlen;
-
-	/* We want to set up our env based on some details here 
-	 * nvram, nvroff, nvrlen, cputype 
-	 */
-	if((fd = create("/env/nvram", ORDWR, 0666)) < 0)
-		panic("open env/nvram: %r");
-	fprint(fd, "%s", nvram);
-	close(fd);
-
-	// We need to set our actual nvlen
-	if((fd = open(nvram, OREAD)) < 0)
-		panic("open %d: %r", nvram);
-
-	nvrlen = seek(fd, 0, SEEK_END);
-	close(fd);
-
-	if((fd = create("/env/nvroff", ORDWR, 0666)) < 0)
-		panic("open env/nvroff: %r");
-	fprint(fd, "0");
-	close(fd);
-
-	if((fd = create("/env/nvrlen", ORDWR, 0666)) < 0)
-		panic("open env/nvrlen: %r");
-	fprint(fd, "%d", nvrlen);
-	close(fd);
-
-	if((fd = create("/env/cputype", ORDWR, 0666)) < 0)
-		panic("open env/cputype: %r");
-	fprint(fd, "arm");
-	close(fd);
-}
-
 int
 main(int argc, char **argv)
 {
 	extern ulong kerndate;
-	char *file, *nvram;
+	char *fs, *sysname;
+	int sfd, fd, tls = 0;
 
-	debug = 0;
-	kerndate = seconds();
-	eve = getuser();
-	nvram = "/tmp/nvram";
+	debug 		= 0;
+	kerndate 	= seconds();
+	eve 		= getuser();
 
 	ARGBEGIN {
-	case 'p':
-		ninepath = EARGF(usage());
-		break;
 	case 'd':
 		debug++;
 		break;
-	case 'n':
-		nvram = EARGF(usage());
+	case 'f':
+		fs = EARGF(usage());
 		break;
 	case 'u':
 		eve = EARGF(usage());
 		break;
+	case 's':
+		sysname = EARGF(usage());
+		break;
+	case 't':
+		tls++;
+		break;
 	default:
 		usage();
 	} ARGEND;
+		
+	/* We don't use argv for the root loadtext */
+	argv[0] = "";
 
-
-	if(!ninepath)
-		ninepath = getwd(ninepath, 256);
-
 	sizebug();
 	osinit();
 	procinit0();
@@ -139,56 +104,69 @@
 	chandevreset();
 	chandevinit();
 	quotefmtinstall();
+	notify(notehandler);
 
-	if(bind("#c", "/dev", MBEFORE) < 0)
-		panic("bind #c: %r");
-	if(bind("#e", "/env", MREPL|MCREATE) < 0)
-		panic("bind #e: %r");
-	if(bind("#L", "/fd", MREPL|MCREATE) < 0)
-		panic("bind #L");
-	if(bind("#I", "/net", MBEFORE) < 0)
-		panic("bind #I: %r");
-	if(bind("#U", "/root", MREPL|MCREATE) < 0)
-		panic("bind #U: %r");
-	if(bind("#p", "/proc", MBEFORE) < 0)
-		panic("bind #p: %r");
+	/* This ordering is based on /lib/namespace 
+	 * - Our host fs connection lives in /srv/boot
+	 * - Everything else should eventually get a /srv
+	 */
+	bind("#c", "/dev", MREPL);
+	bind("#d", "/fd", MREPL);
+	bind("#e", "/env", MREPL|MCREATE);
+	bind("#p", "/proc", MREPL);
+	bind("#s", "/srv", MREPL|MCREATE);
+	//bind -q #σ /shr MREPL
+	bind("#¤", "/dev", MAFTER);
 
-	if(bind(smprint("/root/%s/arm", ninepath), "/arm", MREPL|MCREATE) < 0)
-		panic("bind arm: %r");
-	if(bind(smprint("/root/%s/rc", ninepath), "/rc", MREPL|MCREATE) < 0)
-		panic("bind rc: %r");
+	open(cons, OREAD);
+	open(cons, OWRITE);
+	open(cons, OWRITE);
 
-	bind("#A", "/dev", MAFTER);
-	bind("#N", "/dev", MAFTER);
-	bind("#¤", "/dev", MAFTER);
-	bind("#C", "/", MAFTER);
+	//bind("#l", "/net", MAFTER);
+	bind("#I", "/net", MAFTER);
+	//bind("#a", "/net", MAFTER);
 
-	if(bind("/root", "/", MAFTER) < 0)
-		panic("bind /root: %r");
+	// TODO: This might be incorrect port
+	fd = dial(netmkaddr(fs, tls ? "tls" : "tcp", "9fs"), nil, nil, nil);
+	if(fd < 0)
+		panic("dial fs: %r");
+	postsrv(fd, "boot");
+	close(fd);
 
-	/* This should work, but it doesn't */
+	/* Set up our root */
+	sfd = open("/srv/boot", ORDWR);
+	mount(sfd, -1, "/root", MREPL|MCREATE, "");
+	close(sfd);
+
+	// TODO: mntgen -s slashmnt /mnt
+	//postsrv(fd, "slashmnt");
+	// TODO: mntget -s slashn /n
+	//postsrv(fd, "slashn");
+	// TODO: mntgen -s slashexport /mnt/exportfs
+	//postsrv(fd, "slashexport");
+
+	/* Used for `os` */
+	bind("#C", "/mnt/term/", MAFTER);
+	bind("#U", "/mnt/cpu", MAFTER);
+	bind("/mnt/cpu/tmp", "/tmp", MCREATE|MAFTER);
+	bind("/root", "/", MCREATE|MAFTER);
+
+	/* Build our /bin directory */
 	if(bind("/arm/bin", "/bin", MCREATE|MREPL) < 0 || bind("/rc/bin", "/bin", MAFTER) < 0)
 		panic("bind bin: %r");
+	chdir(smprint("/usr/%s", eve));
 
-	if(**argv == '/' || **argv == '.' || **argv == '#') {
-		if(loadtext(*argv, argc, argv) < 0)
-			panic("loadtext: %r");
-	} else {
-		file = smprint("/bin/%s", *argv);
-		if(loadtext(file, argc, argv) < 0)
-			panic("loadtext: %r");
-		free(file);
-	}
+	loadtext("/bin/rc", 1, argv);
+	ksetenv("cputype", "arm", 0); // cputype being anything but arm should fail for now
+	ksetenv("objtype", "arm", 0);
+	ksetenv("rootdir", "/root", 0);
+	ksetenv("user", eve, 0);
+	ksetenv("service", "cpu", 0);
+	ksetenv("sysname", sysname, 0);
+	ksetenv("prompt", "unix\% ", 0);
+	ksetenv("nvram", "/tmp/nvram", 0); /* Set up in the host /tmp */
 
-	envinit(nvram);
-	if(open("/dev/cons", OREAD) != 0)
-			panic("open0: %r");
-	if(open("/dev/cons", OWRITE) != 1)
-			panic("open1: %r");
-	if(open("/dev/cons", OWRITE) != 2)
-			panic("open2: %r");
-
-	notify(notehandler);
+	/* Run machine */
 	procrun(0);
 
 	exits(0);
--- a/rc/lib/rcmain
+++ /dev/null
@@ -1,40 +1,0 @@
-# rcmain: Plan 9 version
-
-if(~ $#home 0) home=/
-if(~ $#ifs 0) ifs=' 	
-'
-switch($#prompt){
-case 0
-	prompt=('unix% ' '	')
-case 1
-	prompt=($prompt '	')
-}
-if(~ $rcname ?.out) prompt=('broken! ' '	')
-if(flag p) path=/bin
-if not{
-	finit
-	if(~ $#path 0) path=(/bin .)
-}
-fn sigexit
-if(! ~ $#cflag 0){
-	if(flag l){
-		if(/bin/test -r /rc/lib/rcmain.local) . /rc/lib/rcmain.local
-		if(/bin/test -r $home/lib/profile) . $home/lib/profile
-	}
-	status=''
-	eval $cflag
-}
-if not if(flag i){
-	if(flag l){
-		if(/bin/test -r /rc/lib/rcmain.local) . /rc/lib/rcmain.local
-		if(/bin/test -r $home/lib/profile) . $home/lib/profile
-	}
-	status=''
-	if(! ~ $#* 0) . $*
-	. -i /fd/0
-}
-if not if(~ $#* 0) . /fd/0
-if not{
-	status=''
-	. $*
-}
\ No newline at end of file
--