Add support for user-level 9P servers/clients and various bug fixes to go with them.
diff --git a/src/cmd/plumb/fsys.c b/src/cmd/plumb/fsys.c
index 6f95a23..912e5ca 100644
--- a/src/cmd/plumb/fsys.c
+++ b/src/cmd/plumb/fsys.c
@@ -3,14 +3,13 @@
 #include <bio.h>
 #include <regexp.h>
 #include <thread.h>
-#include <auth.h>
 #include <fcall.h>
 #include <plumb.h>
 #include "plumber.h"
 
 enum
 {
-	Stack = 8*1024
+	Stack = 32*1024
 };
 
 typedef struct Dirtab Dirtab;
@@ -73,13 +72,12 @@
 
 struct	/* needed because incref() doesn't return value */
 {
-	Lock;
-	int			ref;
+	Lock	lk;
+	int	ref;
 } rulesref;
 
 enum
 {
-	DEBUG	= 0,
 	NDIR	= 50,
 	Nhash	= 16,
 
@@ -99,13 +97,10 @@
 static int	ndir = NQID;
 
 static int		srvfd;
-static int		srvclosefd;			/* rock for end of pipe to close */
-static int		clockfd;
 static int		clock;
 static Fid		*fids[Nhash];
 static QLock	readlock;
 static QLock	queue;
-static char	srvfile[128];
 static int		messagesize = 8192+IOHDRSZ;	/* good start */
 
 static void	fsysproc(void*);
@@ -183,54 +178,35 @@
 static ulong
 getclock(void)
 {
-	char buf[32];
-
-	seek(clockfd, 0, 0);
-	read(clockfd, buf, sizeof buf);
-	return atoi(buf);
+	return time(0);
 }
 
 void
 startfsys(void)
 {
-	int p[2], fd;
+	int p[2];
 
 	fmtinstall('F', fcallfmt);
-	clockfd = open("/dev/time", OREAD|OCEXEC);
 	clock = getclock();
 	if(pipe(p) < 0)
 		error("can't create pipe: %r");
 	/* 0 will be server end, 1 will be client end */
 	srvfd = p[0];
-	srvclosefd = p[1];
-	sprint(srvfile, "/srv/plumb.%s.%d", user, getpid());
-	if(putenv("plumbsrv", srvfile) < 0)
-		error("can't write $plumbsrv: %r");
-	fd = create(srvfile, OWRITE|OCEXEC|ORCLOSE, 0600);
-	if(fd < 0)
-		error("can't create /srv file: %r");
-	if(fprint(fd, "%d", p[1]) <= 0)
-		error("can't write /srv/file: %r");
-	/* leave fd open; ORCLOSE will take care of it */
-
-	procrfork(fsysproc, nil, Stack, RFFDG);
-
-	close(p[0]);
-	if(mount(p[1], -1, "/mnt/plumb", MREPL, "") < 0)
-		error("can't mount /mnt/plumb: %r");
+	if(post9pservice(p[1], "plumb") < 0)
+		sysfatal("post9pservice plumb: %r");
 	close(p[1]);
+	proccreate(fsysproc, nil, Stack);
 }
 
 static void
-fsysproc(void*)
+fsysproc(void *v)
 {
 	int n;
 	Fcall *t;
 	Fid *f;
 	uchar *buf;
 
-	close(srvclosefd);
-	srvclosefd = -1;
+	USED(v);
 	t = nil;
 	for(;;){
 		buf = malloc(messagesize);	/* avoid memset of emalloc */
@@ -250,7 +226,7 @@
 			t = emalloc(sizeof(Fcall));
 		if(convM2S(buf, n, t) != n)
 			error("convert error in convM2S");
-		if(DEBUG)
+		if(debug)
 			fprint(2, "<= %F\n", t);
 		if(fcall[t->type] == nil)
 			fsysrespond(t, buf, Ebadfcall);
@@ -281,7 +257,7 @@
 		error("convert error in convS2M");
 	if(write(srvfd, buf, n) != n)
 		error("write error in respond");
-	if(DEBUG)
+	if(debug)
 		fprint(2, "=> %F\n", t);
 	free(buf);
 }
@@ -555,8 +531,10 @@
 }
 
 static Fcall*
-fsysversion(Fcall *t, uchar *buf, Fid*)
+fsysversion(Fcall *t, uchar *buf, Fid *fid)
 {
+	USED(fid);
+
 	if(t->msize < 256){
 		fsysrespond(t, buf, "version: message size too small");
 		return t;
@@ -574,8 +552,9 @@
 }
 
 static Fcall*
-fsysauth(Fcall *t, uchar *buf, Fid*)
+fsysauth(Fcall *t, uchar *buf, Fid *fid)
 {
+	USED(fid);
 	fsysrespond(t, buf, "plumber: authentication not required");
 	return t;
 }
@@ -605,10 +584,11 @@
 }
 
 static Fcall*
-fsysflush(Fcall *t, uchar *buf, Fid*)
+fsysflush(Fcall *t, uchar *buf, Fid *fid)
 {
 	int i;
 
+	USED(fid);
 	qlock(&queue);
 	for(i=NQID; i<ndir; i++)
 		flushqueue(&dir[i], t->oldtag);
@@ -729,14 +709,14 @@
 	if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
 		goto Deny;
 	if(f->qid.path==Qrules && (mode==OWRITE || mode==ORDWR)){
-		lock(&rulesref);
+		lock(&rulesref.lk);
 		if(rulesref.ref++ != 0){
 			rulesref.ref--;
-			unlock(&rulesref);
+			unlock(&rulesref.lk);
 			fsysrespond(t, buf, Einuse);
 			return t;
 		}
-		unlock(&rulesref);
+		unlock(&rulesref.lk);
 	}
 	if(clearrules){
 		writerules(nil, 0);
@@ -761,8 +741,9 @@
 }
 
 static Fcall*
-fsyscreate(Fcall *t, uchar *buf, Fid*)
+fsyscreate(Fcall *t, uchar *buf, Fid *fid)
 {
+	USED(fid);
 	fsysrespond(t, buf, Eperm);
 	return t;
 }
@@ -916,15 +897,17 @@
 }
 
 static Fcall*
-fsyswstat(Fcall *t, uchar *buf, Fid*)
+fsyswstat(Fcall *t, uchar *buf, Fid *fid)
 {
+	USED(fid);
 	fsysrespond(t, buf, Eperm);
 	return t;
 }
 
 static Fcall*
-fsysremove(Fcall *t, uchar *buf, Fid*)
+fsysremove(Fcall *t, uchar *buf, Fid *fid)
 {
+	USED(fid);
 	fsysrespond(t, buf, Eperm);
 	return t;
 }
@@ -945,9 +928,9 @@
 			 * unless last write ended with a blank line
 			 */
 			writerules(nil, 0);
-			lock(&rulesref);
+			lock(&rulesref.lk);
 			rulesref.ref--;
-			unlock(&rulesref);
+			unlock(&rulesref.lk);
 		}
 		prev = nil;
 		for(p=d->fopen; p; p=p->nextopen){
diff --git a/src/cmd/plumb/match.c b/src/cmd/plumb/match.c
index 42a9232..dc1abbb 100644
--- a/src/cmd/plumb/match.c
+++ b/src/cmd/plumb/match.c
@@ -6,6 +6,7 @@
 #include <plumb.h>
 #include "plumber.h"
 
+/*
 static char*
 nonnil(char *s)
 {
@@ -13,6 +14,7 @@
 		return "";
 	return s;
 }
+*/
 
 int
 verbis(int obj, Plumbmsg *m, Rule *r)
@@ -44,10 +46,10 @@
 		free(match[i]);
 		match[i] = nil;
 	}
-	for(i=0; i<10 && rs[i].sp!=nil; i++){
-		n = rs[i].ep-rs[i].sp;
+	for(i=0; i<10 && rs[i].s.sp!=nil; i++){
+		n = rs[i].e.ep-rs[i].s.sp;
 		match[i] = emalloc(n+1);
-		memmove(match[i], rs[i].sp, n);
+		memmove(match[i], rs[i].s.sp, n);
 		match[i][n] = '\0';
 	}
 }
@@ -66,7 +68,7 @@
 	for(i=0; i<=click; i++){
 		memset(rs, 0, 10*sizeof(Resub));
 		if(regexec(re, text+i, rs, 10))
-			if(rs[0].sp<=clickp && clickp<=rs[0].ep)
+			if(rs[0].s.sp<=clickp && clickp<=rs[0].e.ep)
 				return 1;
 	}
 	return 0;
@@ -94,8 +96,8 @@
 		}
 		if(!clickmatch(r->regex, m->data, rs, atoi(clickval)))
 			break;
-		p0 = rs[0].sp - m->data;
-		p1 = rs[0].ep - m->data;
+		p0 = rs[0].s.sp - m->data;
+		p1 = rs[0].e.ep - m->data;
 		if(e->p0 >=0 && !(p0==e->p0 && p1==e->p1))
 			break;
 		e->clearclick = 1;
@@ -120,7 +122,7 @@
 		/* must match full text */
 		if(ntext < 0)
 			ntext = strlen(alltext);
-		if(!regexec(r->regex, alltext, rs, 10) || rs[0].sp!=alltext || rs[0].ep!=alltext+ntext)
+		if(!regexec(r->regex, alltext, rs, 10) || rs[0].s.sp!=alltext || rs[0].e.ep!=alltext+ntext)
 			break;
 		setvar(rs, e->match);
 		return 1;
@@ -389,7 +391,7 @@
 {
 	NARGS		= 100,
 	NARGCHAR	= 8*1024,
-	EXECSTACK 	= 4096+(NARGS+1)*sizeof(char*)+NARGCHAR
+	EXECSTACK 	= 32*1024+(NARGS+1)*sizeof(char*)+NARGCHAR
 };
 
 /* copy argv to stack and free the incoming strings, so we don't leak argument vectors */
@@ -419,19 +421,17 @@
 void
 execproc(void *v)
 {
+	int fd[3];
 	char **av;
-	char buf[1024], *args[NARGS+1], argc[NARGCHAR];
+	char *args[NARGS+1], argc[NARGCHAR];
 
-	rfork(RFFDG);
-	close(0);
-	open("/dev/null", OREAD);
+	fd[0] = open("/dev/null", OREAD);
+	fd[1] = dup(1, -1);
+	fd[2] = dup(2, -1);
 	av = v;
 	stackargv(av, args, argc);
 	free(av);
-	procexec(nil, args[0], args);
-	if(args[0][0]!='/' && strncmp(args[0], "./", 2)!=0 && strncmp(args[0], "../", 3)!=0)
-		snprint(buf, sizeof buf, "/bin/%s", args[0]);
-	procexec(nil, buf, args);
+	procexec(nil, fd, args[0], args);
 	threadexits("can't exec");
 }
 
diff --git a/src/cmd/plumb/mkfile b/src/cmd/plumb/mkfile
index d6a1465..6550387 100644
--- a/src/cmd/plumb/mkfile
+++ b/src/cmd/plumb/mkfile
@@ -1,10 +1,9 @@
-</$objtype/mkfile
+PLAN9=../../..
+<$PLAN9/src/mkhdr
 
 TARG=plumber plumb
 
-
-BIN=/$objtype/bin
-</sys/src/cmd/mkmany
+<$PLAN9/src/mkmany
 
 PLUMBER=plumber.$O fsys.$O match.$O rules.$O
 PLUMB=plumb.$O
@@ -15,6 +14,4 @@
 $O.plumb:	$PLUMB
 $O.plumber:	$PLUMBER
 
-syms:V:
-	8c -a plumber.c	>syms
-	8c -aa fsys.c match.c rules.c >>syms
+LDFLAGS=$LDFLAGS -lplumb -lfs -lmux -lthread -lregexp9 -l9 -lbio -lfmt -lutf
diff --git a/src/cmd/plumb/plumber.c b/src/cmd/plumb/plumber.c
index d0bd9c1..424469f 100644
--- a/src/cmd/plumb/plumber.c
+++ b/src/cmd/plumb/plumber.c
@@ -3,10 +3,10 @@
 #include <regexp.h>
 #include <thread.h>
 #include <plumb.h>
-#include <auth.h>
 #include <fcall.h>
 #include "plumber.h"
 
+int debug;
 char	*plumbfile;
 char *user;
 char *home;
@@ -47,13 +47,18 @@
 	progname = "plumber";
 
 	ARGBEGIN{
+	case 'd':
+		debug = 1;
+		break;
 	case 'p':
 		plumbfile = ARGF();
 		break;
 	}ARGEND
 
-	user = getenv("user");
+	user = getuser();
 	home = getenv("home");
+	if(home == nil)
+		home = getenv("HOME");
 	if(user==nil || home==nil)
 		error("can't initialize $user or $home: %r");
 	if(plumbfile == nil){
diff --git a/src/cmd/plumb/plumber.h b/src/cmd/plumb/plumber.h
index 0d1205f..4b9267a 100644
--- a/src/cmd/plumb/plumber.h
+++ b/src/cmd/plumb/plumber.h
@@ -91,3 +91,4 @@
 char		*lasterror;
 char		**ports;
 int		nports;
+int		debug;
diff --git a/src/cmd/plumb/rules.c b/src/cmd/plumb/rules.c
index 262f6d6..b51bb61 100644
--- a/src/cmd/plumb/rules.c
+++ b/src/cmd/plumb/rules.c
@@ -143,7 +143,7 @@
 getline(void)
 {
 	static int n = 0;
-	static char *s, *incl;
+	static char *s /*, *incl*/;
 	int c, i;
 
 	i = 0;
@@ -414,7 +414,7 @@
 	t = args[1];
 	fd = open(t, OREAD);
 	if(fd<0 && t[0]!='/' && strncmp(t, "./", 2)!=0 && strncmp(t, "../", 3)!=0){
-		snprint(buf, sizeof buf, "/sys/lib/plumb/%s", t);
+		snprint(buf, sizeof buf, "#9/plumb/%s", t);
 		t = buf;
 		fd = open(t, OREAD);
 	}