~kris/9p

9hist

451641fb0e3398218aa6829ac993d0521da8389d — David du Colombier 25 years ago ad718a2
Plan 9 from Bell Labs 2001-08-19
M boot/boot.c => boot/boot.c +16 -12
@@ 34,7 34,7 @@ rconv(va_list *arg, Fconv *fp)
void
boot(int argc, char *argv[])
{
	int fd;
	int fd, afd;
	Method *mp;
	char cmd[64];
	char rootbuf[64];


@@ 43,9 43,11 @@ boot(int argc, char *argv[])
	char *rp;
	int n;
	char buf[32];
	AuthInfo *ai;

	sleep(1000);


	fmtinstall('r', rconv);

	open("#c/cons", OREAD);


@@ 53,6 55,7 @@ boot(int argc, char *argv[])
	open("#c/cons", OWRITE);
	bind("#c", "/dev", MAFTER);
	bind("#e", "/env", MREPL|MCREATE);
	bind("#s", "/srv", MREPL|MCREATE);

#ifdef DEBUG
	print("argc=%d\n", argc);


@@ 62,9 65,6 @@ boot(int argc, char *argv[])
#endif DEBUG

	ARGBEGIN{
	case 'u':
		strcpy(username, ARGF());
		break;
	case 'k':
		kflag = 1;
		break;


@@ 87,9 87,9 @@ boot(int argc, char *argv[])
	ishybrid = strcmp(mp->name, "hybrid") == 0;

	/*
	 *  get/set key or password
 	 *  authentication agent
	 */
	(*pword)(islocal, mp);
	authentication(cpuflag);

	/*
	 *  connect to the root file system


@@ 108,7 108,6 @@ boot(int argc, char *argv[])
	if(!islocal && !ishybrid){
		if(cfs)
			fd = (*cfs)(fd);
		doauthenticate(fd, mp);
	}
	srvcreate("boot", fd);



@@ 120,10 119,15 @@ boot(int argc, char *argv[])
	rp = getenv("rootspec");
	if(rp == nil)
		rp = "";
print("boot about to mount\n");
	if(mount(fd, "/root", MREPL|MCREATE, rp) < 0)
	
	afd = fauth(fd, rp);
	if(afd >= 0){
		ai = auth_proxy(afd, "p9any", 0, auth_getkey);
		if(ai == nil)
			print("authentication failed (%r), trying mount anyways\n");
	}
	if(mount(fd, afd, "/root", MREPL|MCREATE, rp) < 0)
		fatal("mount /");
print("mount is done\n");
	rp = getenv("rootdir");
	if(rp == nil)
		rp = rootdir;


@@ 160,13 164,13 @@ print("mount is done\n");
			fd = (*mp->connect)();
			if(fd < 0)
				break;
			mount(fd, "/n/kfs", MAFTER|MCREATE, "") ;
			mount(fd, -1, "/n/kfs", MAFTER|MCREATE, "") ;
			close(fd);
			break;
		}
	}

	settime(islocal);
	settime(islocal, afd);
	swapproc();

	sprint(cmd, "/%s/ninit", cputype);

M boot/boot.h => boot/boot.h +5 -2
@@ 3,11 3,11 @@ struct Method
{
	char	*name;
	void	(*config)(Method*);
	int	(*auth)(void);
	int	(*connect)(void);
	char	*arg;
};

extern void	authentication(int);
extern char*	bootdisk;
extern char*	rootdir;
extern int	(*cfs)(int);


@@ 40,7 40,7 @@ extern int	readfile(char*, char*, int);
extern long	readn(int, void*, long);
extern int	sendmsg(int, char*);
extern void	setenv(char*, char*);
extern void	settime(int);
extern void	settime(int, int);
extern void	srvcreate(char*, int);
extern void	setusername(int, Method*);
extern void	warning(char*);


@@ 63,3 63,6 @@ extern int	connectlocal(void);
extern void	configsac(Method*);
extern int	authsac(void);
extern int	connectsac(void);

/* hack for passing authentication address */
extern char	*authaddr;

A boot/bootauth.c => boot/bootauth.c +74 -0
@@ 0,0 1,74 @@
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include "../boot/boot.h"

char	*authaddr;

void
authentication(int cpuflag)
{
	char *argv[16], **av;
	int ac;
	int factotumpid, pid;

	/* start agent */
	ac = 0;
	av = argv;
	av[ac++] = "factotum";
//av[ac++] = "-dt";
	if(cpuflag)
		av[ac++] = "-s";
	else
		av[ac++] = "-u";
	if(authaddr != nil){
		av[ac++] = "-a";
		av[ac++] = authaddr;
	}
	av[ac] = 0;
	switch(fork()){
	case -1:
		fatal("starting factotum: %r");
	case 0:
		exec("/factotum", av);
		fatal("execing /factotum");
	default:
		break;
	}

	/* wait for agent to really be there */
	while(access("/mnt/factotum", 0) < 0)
		sleep(250);

	if(cpuflag)
		return;
	/* ask for password */
#ifdef quux
	/* start agent */
	ac = 0;
	av = argv;
	av[ac++] = "factotum";
	av[ac++] = "-gd";
	av[ac++] = "p9sk1";
	av[ac++] = "cs.bell-labs.com";
	av[ac] = 0;
	switch((factotumpid = fork())){
	case -1:
		fatal("starting factotum: %r");
	case 0:
		exec("/factotum", av);
		fatal("execing /factotum");
	default:
		break;
	}

	for(;;){
		pid = waitpid();
		if(pid == factotumpid)
			break;
		if(pid == -1)
			fatal("waiting for factotum");
	}
#endif quux
}

M boot/bootcache.c => boot/bootcache.c +1 -1
@@ 65,7 65,7 @@ cache(int fd)
		if(fflag)
			execl("/cfs", "bootcfs", "-rs", "-f", partition, 0);
		else
			execl("/cfs", "bootcfs", "-s", "-f", partition, 0);
			execl("/cfs", "bootcfs", "-ds", "-f", partition, 0);
		break;
	default:
		close(p[0]);

M boot/bootip.c => boot/bootip.c +23 -25
@@ 4,9 4,9 @@

#include "boot.h"

static uchar	fsip[IPaddrlen];
static uchar	auip[IPaddrlen];
static char	mpoint[32];
static	uchar	fsip[IPaddrlen];
	uchar	auip[IPaddrlen];
static	char	mpoint[32];

static int isvalidip(uchar*);
static void netndb(char*, uchar*);


@@ 15,9 15,9 @@ static void netenv(char*, uchar*);
void
configip(void)
{
	int argc, pid, wpid;
	int argc, pid;
	char **argv, *p;
	Waitmsg w;
	Waitmsg *w;
	char **arg;
	char buf[32];
	


@@ 66,13 66,15 @@ configip(void)

	/* wait for ipconfig to finish */
	for(;;){
		wpid = wait(&w);
		if(wpid == pid){
			if(w.msg[0] != 0)
				fatal(w.msg);
		w = wait();
		if(w != nil && w->pid == pid){
			if(w->msg[0] != 0)
				fatal(w->msg);
			free(w);
			break;
		} else if(wpid < 0)
		} else if(w == nil)
			fatal("configuring ip");
		free(w);
	}

	/* if we didn't get a file and auth server, query user */


@@ 95,6 97,15 @@ configip(void)
	}
}

static void
setauthaddr(char *proto, int port)
{
	char buf[128];

	snprint(buf, sizeof buf, "%s!%I!%d", proto, auip, port);
	authaddr = strdup(buf);
}

void
configtcp(Method*)
{


@@ 105,12 116,7 @@ configtcp(Method*)
	sleep(100);
	print(".");
	sleep(100);
}

int
authtcp(void)
{
	return -1;
	setauthaddr("tcp", 567);
}

int


@@ 126,15 132,7 @@ void
configil(Method*)
{
	configip();
}

int
authil(void)
{
	char buf[64];

	snprint(buf, sizeof buf, "il!%I!566", auip);
	return dial(buf, 0, 0, 0);
	setauthaddr("il", 566);
}

int

M boot/dosboot.c => boot/dosboot.c +4 -4
@@ 30,13 30,13 @@ dosboot(void)
	 */
	if(bind("/", "/", MREPL) < 0)
		fatal("bind /");
	if(mount(fd, "/", MAFTER|MCREATE, "#f/fd0disk") < 0)
		if(mount(fd, "/", MAFTER|MCREATE, "#f/fd1disk") < 0)
			if(mount(fd, "/", MAFTER|MCREATE, "#S/sdC0/dos") < 0)
	if(mount(fd, -1, "/", MAFTER|MCREATE, "#f/fd0disk") < 0)
		if(mount(fd, -1, "/", MAFTER|MCREATE, "#f/fd1disk") < 0)
			if(mount(fd, -1, "/", MAFTER|MCREATE, "#S/sdC0/dos") < 0)
				fatal("mount /");
	close(fd);

	settime(1);
	settime(1, -1);
	swapproc();

	execl("/386/init", "init", "-mt", 0);

M boot/settime.c => boot/settime.c +4 -4
@@ 12,7 12,7 @@ static long lusertime(char*);
char *timeserver = "#s/boot";

void
settime(int islocal)
settime(int islocal, int afd)
{
	int n, f;
	int timeset;


@@ 44,17 44,17 @@ settime(int islocal)
		f = open(timeserver, ORDWR);
		if(f < 0)
			return;
		if(mount(f, "/mnt", MREPL, "") < 0){
		if(mount(f, afd, "/tmp", MREPL, "") < 0){
			warning("settime mount");
			close(f);
			return;
		}
		close(f);
		if(stat("/mnt", statbuf, sizeof statbuf) < 0)
		if(stat("/tmp", statbuf, sizeof statbuf) < 0)
			fatal("stat");
		convM2D(statbuf, sizeof statbuf, &dir[0], (char*)&dir[1]);
		sprint(timebuf, "%ld", dir[0].atime);
		unmount(0, "/mnt");
		unmount(0, "/tmp");
	}

	f = open("#c/time", OWRITE);

M pc/dat.h => pc/dat.h +1 -1
@@ 17,7 17,7 @@ typedef struct Segdesc	Segdesc;
typedef struct Ureg	Ureg;
typedef struct Vctl	Vctl;

#define MAXSYSARG	5	/* for mount(fd, mpt, flag, arg, srv) */
#define MAXSYSARG	5	/* for mount(fd, afd, mpt, flag, arg) */

/*
 *  parameters for sysproc.c

M port/auth.c => port/auth.c +32 -137
@@ 23,19 23,16 @@ iseve(void)
long
sysfversion(ulong *arg)
{
	Fcall f;	/* two Fcalls should be big enough for reply */
	uchar *msg;
	char *vers;
	uint arglen, n, m, msize;
	uint arglen, m, msize;
	Chan *c;
	uvlong oo;

	msize = arg[1];
	vers = (char*)arg[2];
	arglen = arg[3];
	validaddr(arg[2], arglen, 1);
	/* check there's a NUL in the version string */
	if(memchr(vers, 0, arglen) == 0)
	if(arglen==0 || memchr(vers, 0, arglen)==0)
		error(Ebadarg);
	c = fdtochan(arg[0], ORDWR, 0, 1);
	if(waserror()){


@@ 43,68 40,7 @@ sysfversion(ulong *arg)
		nexterror();
	}

	if((c->flag&CMSG) && c->version!=nil) /* BUG: insufficient; should check compatibility */
		goto Return;

	f.type = Tversion;
	f.tag = NOTAG;
	if(msize == 0)
		msize = IOHDRSZ+8192;	/* reasonable default */
	f.msize = msize;
	if(vers[0] == '\0')
		vers = VERSION9P;
	f.version = vers;
	msg = smalloc(8192+IOHDRSZ);
	if(waserror()){
		free(msg);
		nexterror();
	}
	n = convS2M(&f, msg, 8192+IOHDRSZ);
	if(n == 0)
		error("bad fversion conversion on send");

	lock(c);
	oo = c->offset;
	c->offset += n;
	unlock(c);

	m = devtab[c->type]->write(c, msg, n, oo);

	if(m < n){
		lock(c);
		c->offset -= n - m;
		unlock(c);
		error("short write in fversion");
	}

	/* message sent; receive and decode reply */
	m = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
	if(m <= 0)
		error("EOF receiving fversion reply");

	lock(c);
	c->offset += m;
	unlock(c);

	n = convM2S(msg, m, &f);
	if(n != m)
		error("bad fversion conversion on reply");
	if(f.type != Rversion)
		error("unexpected reply type in fversion");
	if(f.msize > msize)
		error("server tries to increase msize in fversion");
	if(f.msize<256 || f.msize>1024*1024)
		error("nonsense value of msize in fversion");
	kstrdup(&c->version, f.version);
	c->iounit = f.msize;
	free(msg);
	poperror();

Return:
	m = strlen(c->version);
	if(m > arglen)
		m = arglen;
	memmove((char*)arg[2], c->version, m);
	m = mntversion(c, vers, msize, arglen);

	cclose(c);
	poperror();


@@ 112,90 48,49 @@ Return:
}

long
sysfsession(ulong *arg)
sys_fsession(ulong *arg)
{
	Fcall f;
	uchar *msg;
	uint authlen, n, m;
	Chan *c;
	uvlong oo;
	/* deprecated; backwards compatibility only */

	if(arg[2] == 0)
		error(Ebadarg);
	validaddr(arg[1], arg[2], 1);
	((uchar*)arg[1])[0] = '\0';
	return 0;
}

long
sysfauth(ulong *arg)
{
	Chan *c, *ac;
	char *aname;
	int fd;

//BUG print("warning: stub fsession being used\n");
	authlen = arg[2];
	validaddr(arg[1], authlen, 1);
	validaddr(arg[1], 1, 0);
	aname = (char*)arg[1];
	validname(aname, 0);
	c = fdtochan(arg[0], ORDWR, 0, 1);
	if(waserror()){
		cclose(c);
		nexterror();
	}

	if(c->flag & CMSG){
//BUG what to do?
		((uchar*)arg[1])[0] = 0;
		poperror();
		cclose(c);
		return 0;
	}

	f.type = Tsession;
	f.tag = NOTAG;
	f.nchal = 0;
	f.chal = (uchar*)"";
	msg = smalloc(8192+IOHDRSZ);
	ac = mntauth(c, aname);
	if(waserror()){
		free(msg);
		cclose(ac);
		nexterror();
	}
	n = convS2M(&f, msg, 8192+IOHDRSZ);
	if(n == 0)
		error("bad fsession conversion on send");

	lock(c);
	oo = c->offset;
	c->offset += n;
	unlock(c);

	m = devtab[c->type]->write(c, msg, n, oo);

	if(m < n){
		lock(c);
		c->offset -= n - m;
		unlock(c);
		error("short write in fsession");
	}

	/* message sent; receive and decode reply */
	m = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
	if(m <= 0)
		error("EOF receiving fsession reply");
	fd = newfd(ac);
	if(fd < 0)
		error(Enofd);
	poperror();	/* ac */
	poperror();	/* c */

	lock(c);
	c->offset += m;
	unlock(c);
	/* always mark it close on exec */
	ac->flag |= CCEXEC;

	n = convM2S(msg, m, &f);
	if(n != m)
		error("bad fsession conversion on reply");
	if(f.type != Rsession)
		error("unexpected reply type in fsession");
	m = f.nchal;
	if(m > authlen)
		error(Eshort);
//BUG print("auth stuff ignored; noauth by default\n");
	((uchar*)arg[1])[0] = 0;

	free(msg);
	poperror();
	poperror();
	cclose(c);
	return m;
}

long
sysfauth(ulong *)
{
	error("sysfauth unimplemented");
	return -1;
	return fd;
}

/*

M port/chan.c => port/chan.c +16 -73
@@ 174,19 174,6 @@ kstrdup(char **p, char *s)
	static Lock l;

	n = strlen(s)+1;
//	if(n == 1){
//		ulong pc;
//		int i;
//		static ulong pcs[128];
//		pc = getcallerpc(&p);
//		for(i=0; i<nelem(pcs) && pcs[i]; i++)
//			if(pc == pcs[i])
//				break;
//		if(up!=nil && i<nelem(pcs) && pcs[i]==0){
//			pcs[i] = pc;
//			print("kstrdup(null string) called from 0x%lux\n", pc);
//		}
//	}
	/* if it's a user, we can wait for memory; if not, something's very wrong */
	if(up){
		t = smalloc(n);


@@ 253,9 240,9 @@ newchan(void)
	c->aux = 0;
	c->mchan = 0;
	c->mcp = 0;
	c->mux = 0;
	memset(&c->mqid, 0, sizeof(c->mqid));
	c->name = 0;
	c->version = 0;
	return c;
}



@@ 330,10 317,6 @@ chanfree(Chan *c)
{
	c->flag = CFREE;

	if(c->version){
		free(c->version);
		c->version = 0;
	}
	if(c->umh != nil){
		putmhead(c->umh);
		c->umh = nil;


@@ 342,6 325,14 @@ chanfree(Chan *c)
		cclose(c->umc);
		c->umc = nil;
	}
	if(c->mux != nil){
		muxclose(c->mux);
		c->mux = nil;
	}
	if(c->mchan != nil){
		cclose(c->mchan);
		c->mchan = nil;
	}

	cnameclose(c->name);



@@ 356,6 347,7 @@ cclose(Chan *c)
{
	if(c->flag&CFREE)
		panic("cclose %lux", getcallerpc(&c));

	if(decref(c))
		return;



@@ 690,9 682,6 @@ undomount(Chan *c, Cname *name)
		for(f = *h; f; f = f->hash) {
			if(strcmp(f->from->name->s, name->s) != 0)
				continue;
if(chandebug)
print("[%lud]\tundomount found head %s; need chan (path %.8llux dev %C %lud)\n",
	up->pid, name->s, c->qid.path, devtab[c->type]->dc, c->dev);
			for(t = f->mount; t; t = t->next) {
				if(eqchan(c, t->to, 1)) {
					/*


@@ 707,8 696,6 @@ print("[%lud]\tundomount found head %s; need chan (path %.8llux dev %C %lud)\n",
					incref(nc);
					cclose(c);
					c = nc;
if(chandebug)
print("[%lud]\tundomount found %s\n", up->pid, c2name(c));
					break;
				}
			}


@@ 732,23 719,12 @@ walk(Chan **cp, char **names, int nnames, int nomount)
	Mhead *mh, *nmh;
	Walkqid *wq;

//BUG: waserror?

	c = *cp;
	incref(c);
	cname = c->name;
	incref(cname);
	mh = nil;

if(chandebug){
qlock(&chanprint);
print("[%lud] walk %s to ", up->pid, c2name(c));
for(i=0; i<nnames; i++)
	print("%s%s", i?"/":"", names[i]);
print("\n");
qunlock(&chanprint);
}

	/*
	 * While we haven't gotten all the way down the path:
	 *    1. step through a mount point, if any


@@ 775,15 751,6 @@ qunlock(&chanprint);
			}
		}

if(chandebug){
qlock(&chanprint);
print("[%lud]\twalk from %s (path %.8llux dev %C %lud) to ", 
	up->pid, c2name(c), c->qid.path, devtab[c->type]->dc, c->dev);
for(i=0; i<ntry; i++)
	print("%s%s", i?"/":"", names[i]);
print("\n");
qunlock(&chanprint);
}
		if(!dotdot && !nomount)
			domount(&c, &mh);



@@ 791,11 758,9 @@ qunlock(&chanprint);
		dev = c->dev;

		if((wq = devtab[type]->walk(c, nil, names, ntry)) == nil){
if(chandebug) print("[%lud]\twalk failed.\n", up->pid);
			/* try a union mount, if any */
			if(mh == nil || nomount){
			Giveup:
if(chandebug) print("[%lud]\tgive up\n", up->pid);
				cclose(c);
				cnameclose(cname);
				return -1;


@@ 807,13 772,8 @@ if(chandebug) print("[%lud]\tgive up\n", up->pid);
				nexterror();
			}
			for(f = mh->mount; f; f = f->next)
{
if(chandebug)
 print("[%lud]\twalk from %s (path %.8llux dev %C %lud)\n", 
  up->pid, c2name(c), c->qid.path, devtab[c->type]->dc, c->dev);
				if((wq = devtab[f->to->type]->walk(f->to, nil, names, ntry)) != nil)
					break;
}
			poperror();
			runlock(&mh->lock);



@@ 830,11 790,7 @@ if(chandebug)
			assert(wq->clone != nil);

			cname = addelem(cname, "..");
if(chandebug)
print("[%lud]\tundo wq->clone %s cname %s\n", up->pid, c2name(wq->clone), cname?cname->s:"<nil name>");
			nc = undomount(wq->clone, cname);
if(chandebug)
print("[%lud]\tundo returned %s\n", up->pid, c2name(nc));
			n = 1;
		} else {
			nc = nil;


@@ 843,8 799,6 @@ print("[%lud]\tundo returned %s\n", up->pid, c2name(nc));
					if(findmount(&nc, &nmh, type, dev, wq->qid[i]))
						break;
			if(nc == nil){	/* no mount points along path */
if(chandebug)
print("[%lud]\tno mount points along path\n", up->pid);
				if(wq->clone == nil){
					cclose(c);
					cnameclose(cname);


@@ 854,15 808,6 @@ print("[%lud]\tno mount points along path\n", up->pid);
				n = wq->nqid;
				nc = wq->clone;
			}else{		/* stopped early, at a mount point */
if(chandebug){int j;
qlock(&chanprint);
print("[%lud]\tfound mount point: ", up->pid);
for(j=0; j<=i; j++)
	print("%s%s", j?"/":"", names[j]);
print(" becomes ");
print("%s\n", c2name(nc));
qunlock(&chanprint);
}
				if(wq->clone != nil){
					cclose(wq->clone);
					wq->clone = nil;


@@ 872,7 817,6 @@ qunlock(&chanprint);
			for(i=0; i<n; i++)
				cname = addelem(cname, names[i]);
		}

		cclose(c);
		c = nc;
		putmhead(mh);


@@ 886,19 830,18 @@ qunlock(&chanprint);
	putmhead(mh);

	c = cunique(c);
if(c->umh != nil){
	print("walk umh\n");
	putmhead(c->umh);
	c->umh = nil;
}

	if(c->umh != nil){	//BUG
		print("walk umh\n");
		putmhead(c->umh);
		c->umh = nil;
	}

	cnameclose(c->name);
	c->name = cname;

	cclose(*cp);
	*cp = c;
if(chandebug)
print("[%lud]\twalk succeeds; name %s chan (path %.8llux dev %C %lud)\n", up->pid, c2name(c), c->qid.path, devtab[c->type]->dc, c->dev);
	return 0;
}


M port/dev.c => port/dev.c +0 -7
@@ 115,7 115,6 @@ devclone(Chan *c)
	nc->umh = nil;
	nc->mountid = c->mountid;
	nc->aux = c->aux;
	nc->mchan = c->mchan;
	nc->mqid = c->mqid;
	nc->mcp = c->mcp;
	return nc;


@@ 132,12 131,6 @@ devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen
	if(nname > 0)
		isdir(c);

//	print("devwalk (%d:%c:%p) ", nname, devtab[c->type]->dc, nc);
//	for(i=0; i<nname; i++)
//		print("%s/", name[i]);
//	print("\n");
//delay(500);

	alloc = 0;
	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
	if(waserror()){

M port/devcons.c => port/devcons.c +1 -1
@@ 241,7 241,7 @@ panic(char *fmt, ...)
	spllo();
	prflush();
	putstrn(buf, n+1);
	dumpstack();
//	dumpstack();

	exit(1);
}

M port/devdup.c => port/devdup.c +3 -1
@@ 63,7 63,7 @@ dupopen(Chan *c, int omode)
	Chan *f;
	int fd, twicefd;

	if(c->qid.type == QTDIR){
	if(c->qid.type & QTDIR){
		if(omode != 0)
			error(Eisdir);
		c->mode = 0;


@@ 71,6 71,8 @@ dupopen(Chan *c, int omode)
		c->offset = 0;
		return c;
	}
	if(c->qid.type & QTAUTH)
		error(Eperm);
	twicefd = c->qid.path - 1;
	fd = twicefd/2;
	if((twicefd & 1)){

M port/devmnt.c => port/devmnt.c +255 -72
@@ 5,6 5,17 @@
#include	"fns.h"
#include	"../port/error.h"

/*
 * References are managed as follows:
 * The channel to the server - a network connection or pipe - has one
 * reference for every Chan open on the server.  The server channel has
 * c->mux set to the Mnt used for muxing control to that server.  Mnts
 * have no reference count; they go away when c goes away.
 * Each channel derived from the mount point has mchan set to c,
 * and increfs/decrefs mchan to manage references on the server
 * connection.
 */

#define MAXRPC (IOHDRSZ+8192)

struct Mntrpc


@@ 16,6 27,7 @@ struct Mntrpc
	Mnt*	m;		/* Mount device during rpc */
	Rendez	r;		/* Place to hang out */
	uchar*	rpc;		/* I/O Data buffer */
	uint		rpclen;	/* len of buffer */
	Block	*b;		/* reply blocks */
	char	done;		/* Rpc completed */
	uvlong	stime;		/* start time for mnt statistics */


@@ 37,7 49,6 @@ struct Mntalloc
}mntalloc;

void	mattach(Mnt*, Chan*, char*);
void	mntauth(Mnt*, Mntrpc*, char*, ushort);
Mnt*	mntchk(Chan*);
void	mntdirfix(uchar*, Chan*);
Mntrpc*	mntflushalloc(Mntrpc*, ulong);


@@ 53,10 64,10 @@ void	mountio(Mnt*, Mntrpc*);
void	mountmux(Mnt*, Mntrpc*);
void	mountrpc(Mnt*, Mntrpc*);
int	rpcattn(void*);
void	mclose(Mnt*, Chan*);
Chan*	mntchan(void);

char	Esbadstat[] = "invalid directory entry received from server";
char Enoversion[] = "version not established for mount channel";

void (*mntstats)(int, Chan*, uvlong, ulong);



@@ 77,43 88,114 @@ mntreset(void)
	cinit();
}

static Chan*
mntattach(char *muxattach)
/*
 * Version is not multiplexed: message sent only once per connection.
 */
long
mntversion(Chan *c, char *version, int msize, int returnlen)
{
	Fcall f;
	uchar *msg;
	Mnt *m;
	Chan *c;
	struct bogus{
		Chan	*chan;
		char	*spec;
		int	flags;
	}bogus;
	char *v;
	long k, l;
	uvlong oo;
	char buf[128];

	bogus = *((struct bogus *)muxattach);
	c = bogus.chan;
	qlock(&c->umqlock);	/* make sure no one else does this until we've established ourselves */
	if(waserror()){
		qunlock(&c->umqlock);
		nexterror();
	}

	lock(&mntalloc);
	for(m = mntalloc.list; m; m = m->list) {
		if(m->c == c && m->id) {
			lock(m);
			if(m->id && m->ref > 0 && m->c == c) {
				m->ref++;
				unlock(m);
				unlock(&mntalloc);
				c = mntchan();
				if(waserror()) {
					chanfree(c);
					nexterror();
				}
				mattach(m, c, bogus.spec);
				poperror();
				if(bogus.flags&MCACHE)
					c->flag |= CCACHE;
				return c;
			}
			unlock(m);
	/* defaults */
	if(msize == 0)
		msize = MAXRPC-IOHDRSZ;
	v = version;
	if(v == nil || v[0] == '\0')
		v = VERSION9P;

	/* validity */
	if(msize < 0)
		error("bad iounit in version call");
	if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
		error("bad 9P version specification");

	m = c->mux;

	if(m != nil){
		qunlock(&c->umqlock);
		poperror();

		strecpy(buf, buf+sizeof buf, m->version);
		k = strlen(buf);
		if(strncmp(buf, v, k) != 0){
			snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
			error(buf);
		}
		if(returnlen > 0){
			if(returnlen < k)
				error(Eshort);
			memmove(version, buf, k);
		}
		return k;
	}

	f.type = Tversion;
	f.tag = NOTAG;
	f.msize = msize;
	f.version = v;
	msg = malloc(8192+IOHDRSZ);
	if(msg == nil)
		exhausted("version memory");
	if(waserror()){
		free(msg);
		nexterror();
	}
	k = convS2M(&f, msg, 8192+IOHDRSZ);
	if(k == 0)
		error("bad fversion conversion on send");

	lock(c);
	oo = c->offset;
	c->offset += k;
	unlock(c);

	l = devtab[c->type]->write(c, msg, k, oo);

	if(l < k){
		lock(c);
		c->offset -= k - l;
		unlock(c);
		error("short write in fversion");
	}

	/* message sent; receive and decode reply */
	k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
	if(k <= 0)
		error("EOF receiving fversion reply");

	lock(c);
	c->offset += k;
	unlock(c);

	l = convM2S(msg, k, &f);
	if(l != k)
		error("bad fversion conversion on reply");
	if(f.type != Rversion)
		error("unexpected reply type in fversion");
	if(f.msize > msize)
		error("server tries to increase msize in fversion");
	if(f.msize<256 || f.msize>1024*1024)
		error("nonsense value of msize in fversion");
	if(strncmp(f.version, v, strlen(f.version)) != 0)
		error("bad 9P version returned from server");
	c->iounit = f.msize;
	if(c->iounit == 0)
		c->iounit = MAXRPC;

	/* now build Mnt associated with this connection */
	lock(&mntalloc);
	m = mntalloc.mntfree;
	if(m != 0)
		mntalloc.mntfree = m->list;


@@ 126,27 208,53 @@ mntattach(char *muxattach)
	}
	m->list = mntalloc.list;
	mntalloc.list = m;
	kstrdup(&m->version, f.version);
	m->id = mntalloc.id++;
	m->q = qopen(10*MAXRPC, 0, nil, nil);
	unlock(&mntalloc);

	poperror();	/* msg */
	free(msg);

	lock(m);
	m->ref = 1;
	m->queue = 0;
	m->rip = 0;

	c->flag |= CMSG;
	c->mux = m;
	m->c = c;
	m->c->flag |= CMSG;
	if(m->c->iounit == 0)
		m->c->iounit = MAXRPC;
	m->flags = bogus.flags & ~MCACHE;
	unlock(m);

	incref(m->c);
	poperror();	/* c */
	qunlock(&c->umqlock);

	unlock(m);
	k = strlen(f.version);
	if(returnlen > 0){
		if(returnlen < k)
			error(Eshort);
		memmove(version, f.version, k);
	}

	return k;
}

Chan*
mntauth(Chan *c, char *spec)
{
	Mnt *m;
	Mntrpc *r;

	m = c->mux;

	if(m == nil){
		mntversion(c, VERSION9P, MAXRPC, 0);
		m = c->mux;
		if(m == nil)
			error(Enoversion);
	}

	c = mntchan();
	if(waserror()) {
		mclose(m, c);
		/* Close must not be called since it will
		 * call mnt recursively
		 */


@@ 154,35 262,69 @@ mntattach(char *muxattach)
		nexterror();
	}

	mattach(m, c, bogus.spec);
	poperror();
	r = mntralloc(0, m->c->iounit);

	if(bogus.flags & MCACHE)
		c->flag |= CCACHE;
	if(waserror()) {
		mntfree(r);
		nexterror();
	}

	return c;
}
	r->request.type = Tauth;
	r->request.afid = c->fid;
	r->request.uname = up->user;
	r->request.aname = spec;
	mountrpc(m, r);

Chan*
mntchan(void)
{
	Chan *c;
	c->qid = r->reply.aqid;
	c->mchan = m->c;
	incref(m->c);
	c->mqid = c->qid;
	c->mode = ORDWR;

	c = devattach('M', 0);
	lock(&mntalloc);
	c->dev = mntalloc.id++;
	unlock(&mntalloc);
	poperror();	/* r */
	mntfree(r);

	poperror();	/* c */

	return c;

}

void
mattach(Mnt *m, Chan *c, char *spec)
static Chan*
mntattach(char *muxattach)
{
	Mnt *m;
	Chan *c;
	Mntrpc *r;
	struct bogus{
		Chan	*chan;
		Chan	*authchan;
		char	*spec;
		int	flags;
	}bogus;

	bogus = *((struct bogus *)muxattach);
	c = bogus.chan;

	m = c->mux;

	if(m == nil){
		mntversion(c, nil, 0, 0);
		m = c->mux;
		if(m == nil)
			error(Enoversion);
	}

	c = mntchan();
	if(waserror()) {
		/* Close must not be called since it will
		 * call mnt recursively
		 */
		chanfree(c);
		nexterror();
	}

	r = mntralloc(0, m->c->iounit);
	c->mntptr = m;

	if(waserror()) {
		mntfree(r);


@@ 191,18 333,42 @@ mattach(Mnt *m, Chan *c, char *spec)

	r->request.type = Tattach;
	r->request.fid = c->fid;
	if(bogus.authchan == nil)
		r->request.afid = NOFID;
	else
		r->request.afid = bogus.authchan->fid;
	r->request.uname = up->user;
	r->request.aname = spec;
	r->request.nauth = 0;
	r->request.auth = (uchar*)"";
	r->request.aname = bogus.spec;
	mountrpc(m, r);

	c->qid = r->reply.qid;
	c->mchan = m->c;
	incref(m->c);
	c->mqid = c->qid;

	poperror();
	poperror();	/* r */
	mntfree(r);

	poperror();	/* c */

	if(bogus.flags&MCACHE)
		c->flag |= CCACHE;
	return c;
}

Chan*
mntchan(void)
{
	Chan *c;

	c = devattach('M', 0);
	lock(&mntalloc);
	c->dev = mntalloc.id++;
	unlock(&mntalloc);

	if(c->mchan)
		panic("mntchan non-zero %p", c->mchan);
	return c;
}

static Walkqid*


@@ 213,6 379,8 @@ mntwalk(Chan *c, Chan *nc, char **name, int nname)
	Mntrpc *r;
	Walkqid *wq;

	if(nc != nil)
		print("mntwalk: nc != nil\n");
	if(nname > MAXWELEM)
		error("devmnt: too many name elements");
	alloc = 0;


@@ 268,7 436,8 @@ mntwalk(Chan *c, Chan *nc, char **name, int nname)
	if(wq->clone != nil){
		if(wq->clone != c){
			wq->clone->type = c->type;
			incref(m);
			wq->clone->mchan = c->mchan;
			incref(c->mchan);
		}
		if(r->reply.nwqid > 0)
			wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];


@@ 377,7 546,6 @@ mntclunk(Chan *c, int t)
	r = mntralloc(c, m->c->iounit);
	if(waserror()){
		mntfree(r);
		mclose(m, c);
		nexterror();
	}



@@ 385,24 553,19 @@ mntclunk(Chan *c, int t)
	r->request.fid = c->fid;
	mountrpc(m, r);
	mntfree(r);
	mclose(m, c);
	poperror();
}

void
mclose(Mnt *m, Chan*)
muxclose(Mnt *m)
{
	Mntrpc *q, *r;

	if(decref(m) != 0)
		return;

	for(q = m->queue; q; q = r) {
		r = q->list;
		mntfree(q);
	}
	m->id = 0;
	cclose(m->c);
	mntpntfree(m);
}



@@ 853,11 1016,23 @@ mntralloc(Chan *c, ulong iounit)
			unlock(&mntalloc);
			exhausted("mount rpc buffer");
		}
		new->rpclen = iounit;
		new->request.tag = mntalloc.rpctag++;
	}
	else {
		mntalloc.rpcfree = new->list;
		mntalloc.nrpcfree--;
		if(new->rpclen < iounit){
			free(new->rpc);
			new->rpc = mallocz(iounit, 0);
			if(new->rpc == nil){
				free(new);
				mntalloc.nrpcused--;
				unlock(&mntalloc);
				exhausted("mount rpc buffer");
			}
			new->rpclen = iounit;
		}
	}
	mntalloc.nrpcused++;
	unlock(&mntalloc);


@@ 911,13 1086,21 @@ mntchk(Chan *c)
{
	Mnt *m;

	m = c->mntptr;
	/* This routine is mostly vestiges of prior lives; now it's just sanity checking */

	if(c->mchan == nil)
		panic("mntchk 1: nil mchan c %s\n", c2name(c));

	m = c->mchan->mux;

	if(m == nil)
		print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan));

	/*
	 * Was it closed and reused
	 * Was it closed and reused (was error(Eshutdown); now, it can't happen)
	 */
	if(m->id == 0 || m->id >= c->dev)
		error(Eshutdown);
		panic("mntchk 3: can't happen");

	return m;
}

M port/devproc.c => port/devproc.c +6 -6
@@ 133,7 133,7 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
	len = tab->length;
	switch(QID(c->qid)) {
	case Qwait:
		len = p->nwait * sizeof(Waitmsg);
		len = p->nwait;	/* incorrect size, but >0 means there's something to read */
		break;
	case Qprofile:
		q = p->seg[TSEG];


@@ 653,9 653,6 @@ procread(Chan *c, void *va, long n, vlong off)
		return n;

	case Qwait:
		if(n < sizeof(Waitmsg))
			error(Etoosmall);

		if(!canqlock(&p->qwaitr))
			error(Einuse);



@@ 684,9 681,12 @@ procread(Chan *c, void *va, long n, vlong off)

		qunlock(&p->qwaitr);
		poperror();
		memmove(a, &wq->w, sizeof(Waitmsg));
		n = snprint(a, n, "%d %lud %lud %lud %q",
			wq->w.pid,
			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
			wq->w.msg);
		free(wq);
		return sizeof(Waitmsg);
		return n;

	case Qns:
		qlock(&p->debug);

M port/devroot.c => port/devroot.c +1 -0
@@ 69,6 69,7 @@ rootreset(void)
	addrootdir("dev");
	addrootdir("env");
	addrootdir("fd");
	addrootdir("mnt");
	addrootdir("net");
	addrootdir("net.alt");
	addrootdir("proc");

M port/devsrv.c => port/devsrv.c +2 -0
@@ 294,6 294,8 @@ srvwrite(Chan *c, void *va, long n, vlong)
	}
	if(c1->flag & (CCEXEC|CRCLOSE))
		error("posted fd has remove-on-close or close-on-exec");
	if(c1->qid.type & QTAUTH)
		error("can't post auth file in srv");
	sp = srvlookup(nil, c->qid.path);
	if(sp == 0)
		error(Enonexist);

M port/error.h => port/error.h +1 -1
@@ 3,7 3,7 @@ extern char Emount[];		/* inconsistent mount */
extern char Eunmount[];		/* not mounted */
extern char Eunion[];		/* not in union */
extern char Emountrpc[];	/* mount rpc error */
extern char Eshutdown[];	/* mounted device shut down */
extern char Eshutdown[];	/* device shut down */
extern char Enocreate[];	/* mounted directory forbids creation */
extern char Enonexist[];	/* file does not exist */
extern char Eexist[];		/* file already exists */

M port/fault.c => port/fault.c +12 -6
@@ 38,8 38,14 @@ fault(ulong addr, int read)
}

static void
faulterror(char *s, int freemem)
faulterror(char *s, Chan *c, int freemem)
{
	char buf[ERRMAX];

	if(c && c->name){
		snprint(buf, sizeof buf, "%s accessing %s: %s", s, c->name->s, up->error);
		s = buf;
	}
	if(up->nerrlab) {
		postnote(up, 1, s, NDebug);
		error(s);


@@ 125,7 131,7 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
			if(swapfull()){
				qunlock(&s->lk);
				pprint("swap space full\n");
				faulterror(Enoswap, 1);
				faulterror(Enoswap, nil, 1);
			}

			new = newpage(0, &s, addr);


@@ 217,7 223,7 @@ retry:
				continue;
			kunmap(k);
			putpage(new);
			faulterror("sys: demand load I/O error", 0);
			faulterror("sys: demand load I/O error", c, 0);
		}

		ask = s->flen-soff;


@@ 226,7 232,7 @@ retry:

		n = devtab[c->type]->read(c, kaddr, ask, daddr);
		if(n != ask)
			faulterror(Eioload, 0);
			faulterror(Eioload, c, 0);
		if(ask < BY2PG)
			memset(kaddr+ask, 0, BY2PG-ask);



@@ 253,12 259,12 @@ retry:
			putpage(new);
			qlock(&s->lk);
			qunlock(&s->lk);
			faulterror("sys: page in I/O error", 0);
			faulterror("sys: page in I/O error", c, 0);
		}

		n = devtab[c->type]->read(c, kaddr, BY2PG, daddr);
		if(n != BY2PG)
			faulterror(Eioload, 0);
			faulterror(Eioload, c, 0);

		poperror();
		kunmap(k);

M port/lib.h => port/lib.h +10 -1
@@ 112,6 112,7 @@ extern	int	tokenize(char*, char**, int);

typedef struct Qid	Qid;
typedef struct Dir	Dir;
typedef struct OWaitmsg	OWaitmsg;
typedef struct Waitmsg	Waitmsg;

#define	ERRMAX			128	/* max length of error string */


@@ 122,6 123,7 @@ typedef struct Waitmsg	Waitmsg;
#define QTAPPEND	0x40		/* type bit for append only files */
#define QTEXCL		0x20		/* type bit for exclusive use files */
#define QTMOUNT		0x10		/* type bit for mounted channel */
#define QTAUTH		0x08		/* type bit for authentication file */
#define QTFILE		0x00		/* plain file */

/* bits in Dir.mode */


@@ 156,9 158,16 @@ struct Dir {
	char	*muid;	/* last modifier name */
};

struct Waitmsg
struct OWaitmsg
{
	char	pid[12];	/* of loved one */
	char	time[3*12];	/* of loved one and descendants */
	char	msg[64];	/* compatibility BUG */
};

struct Waitmsg
{
	int	pid;	/* of loved one */
	ulong	time[3];	/* of loved one and descendants */
	char	msg[ERRMAX];	/* actually variable-size in user mode */
};

M port/portdat.h => port/portdat.h +4 -3
@@ 157,16 157,15 @@ struct Chan
	int	uri;			/* union read index */
	ulong	mountid;
	Mntcache *mcp;			/* Mount cache pointer */
	Mnt		*mux;		/* Mnt for clients using me for messages */
	union {
		void*	aux;
		Qid	pgrpid;		/* for #p/notepg */
		Mnt*	mntptr;		/* for devmnt */
		ulong	mid;		/* for ns in devproc */
	};
	Chan*	mchan;			/* channel to mounted server */
	Qid	mqid;			/* qid of root of mount point */
	Session*session;
	char	*version;			/* 9P version */
	Cname	*name;
};



@@ 254,13 253,15 @@ struct Mhead

struct Mnt
{
	Ref;			/* Count of attached channels */
	Lock;
	/* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */
	Chan	*c;		/* Channel to file service */
	Proc	*rip;		/* Reader in progress */
	Mntrpc	*queue;		/* Queue of pending requests on this channel */
	ulong	id;		/* Multiplexer id for channel check */
	Mnt	*list;		/* Free list */
	int	flags;		/* cache */
	char	*version;			/* 9P version */
	Queue	*q;		/* input queue */
};


M port/portfns.h => port/portfns.h +5 -0
@@ 16,6 16,7 @@ int		blocklen(Block*);
void		cachedel(Image*, ulong);
void		cachepage(Page*, Image*);
void		callwithureg(void(*)(Ureg*));
char*	c2name(Chan*);
int		cangetc(void*);
int		canlock(Lock*);
int		canpage(Proc*);


@@ 163,12 164,16 @@ void		microdelay(int);
void		mkqid(Qid*, vlong, ulong, int);
void		mmurelease(Proc*);
void		mmuswitch(Proc*);
Chan*		mntauth(Chan*, char*);
void		mntdump(void);
long		mntversion(Chan*, char*, int, int);
void		mountfree(Mount*);
ulong		msize(void*);
void		muxclose(Mnt*);
Chan*		namec(char*, int, int, ulong);
#define		nelem(x)	(sizeof(x)/sizeof(x[0]))
Chan*		newchan(void);
int		newfd(Chan*);
Mount*		newmount(Mhead*, Chan*, int, char*);
Page*		newpage(int, Segment **, ulong);
Pgrp*		newpgrp(void);

M port/print.c => port/print.c +4 -0
@@ 665,6 665,8 @@ needsquotes(char *s, int *quotelenp)
	int nextra, ok, w;
	Rune r;

	if(*s == '\0')
		return 1;
	nextra = 0;
	ok = 1;
	for(t=s; *t; t+=w){


@@ 692,6 694,8 @@ runeneedsquotes(Rune *s, int *quotelenp)
	int nextra, ok;
	Rune r;

	if(*s == L'\0')
		return 1;
	nextra = 0;
	ok = 1;
	for(t=s; *t; t++){

M port/proc.c => port/proc.c +7 -16
@@ 717,7 717,6 @@ freebroken(void)
void
pexit(char *exitstr, int freemem)
{
	int n;
	Proc *p;
	Segment **s, **es;
	long utime, stime;


@@ 773,20 772,12 @@ pexit(char *exitstr, int freemem)
		wq = smalloc(sizeof(Waitq));
		poperror();

		readnum(0, wq->w.pid, NUMSIZE, up->pid, NUMSIZE);
		utime = up->time[TUser] + up->time[TCUser];
		stime = up->time[TSys] + up->time[TCSys];
		readnum(0, &wq->w.time[TUser*12], NUMSIZE,
			TK2MS(utime), NUMSIZE);
		readnum(0, &wq->w.time[TSys*12], NUMSIZE,
			TK2MS(stime), NUMSIZE);
		readnum(0, &wq->w.time[TReal*12], NUMSIZE,
			TK2MS(MACHP(0)->ticks - up->time[TReal]), NUMSIZE);
		if(exitstr && exitstr[0]){
			n = sprint(wq->w.msg, "%s %lud:", up->text, up->pid);
			strncpy(wq->w.msg+n, exitstr, sizeof wq->w.msg-n);
			wq->w.msg[sizeof wq->w.msg-1] = 0;
		}
		wq->w.pid = up->pid;
		wq->w.time[TUser] = utime = up->time[TUser] + up->time[TCUser];
		wq->w.time[TSys] = stime = up->time[TSys] + up->time[TCSys];
		wq->w.time[TReal] = TK2MS(MACHP(0)->ticks - up->time[TReal]);
		if(exitstr && exitstr[0])
			snprint(wq->w.msg, sizeof(wq->w.msg), "%s %lud: %s", up->text, up->pid, exitstr);
		else
			wq->w.msg[0] = '\0';



@@ 900,7 891,7 @@ pwait(Waitmsg *w)

	if(w)
		memmove(w, &wq->w, sizeof(Waitmsg));
	cpid = atoi(wq->w.pid);
	cpid = wq->w.pid;
	free(wq);
	return cpid;
}

M port/sysfile.c => port/sysfile.c +31 -16
@@ 271,6 271,7 @@ sysopen(ulong *arg)
	if(fd < 0)
		error(Enofd);
	poperror();
if(strstr(up->text, "syscall")!=0) pprint("open %s ref count %d\n", c2name(c), c->ref); // BUG
	return fd;
}



@@ 668,19 669,17 @@ syschdir(ulong *arg)
}

long
bindmount(ulong *arg, int ismount)
bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec)
{
	ulong flag;
	int fd, ret;
	Chan *c0, *c1, *bc;
	int ret;
	Chan *c0, *c1, *ac, *bc;
	struct{
		Chan	*chan;
		Chan	*authchan;
		char	*spec;
		int	flags;
	}bogus;

	flag = arg[2];
	fd = arg[0];
	if(flag>MMASK || (flag&MORDER)==(MBEFORE|MAFTER))
		error(Ebadarg);



@@ 690,32 689,41 @@ bindmount(ulong *arg, int ismount)
		if(up->pgrp->noattach)
			error(Enoattach);

		ac = nil;
		bc = fdtochan(fd, ORDWR, 0, 1);
		if(waserror()) {
			if(ac)
				cclose(ac);
			cclose(bc);
			nexterror();
		}

		if(afd >= 0)
			ac = fdtochan(afd, ORDWR, 0, 1);

		bogus.chan = bc;
		bogus.authchan = ac;

		validaddr(arg[3], 1, 0);
		validname((char*)arg[3], 1);
		validaddr((ulong)spec, 1, 0);
		validname(spec, 1);

		bogus.spec = (char*)arg[3];
		bogus.spec = spec;
		if(waserror())
			error(Ebadspec);
		validname(bogus.spec, 1);
		poperror();

		ret = devno('M', 0);
		c0 = devtab[ret]->attach((char*)&bogus);

		poperror();
		if(ac)
			cclose(ac);
		cclose(bc);
	}
	else {
		bogus.spec = 0;
		validaddr(arg[0], 1, 0);
		c0 = namec((char*)arg[0], Amount, 0, 0);
		validaddr((ulong)arg0, 1, 0);
		c0 = namec(arg0, Amount, 0, 0);
	}

	if(waserror()){


@@ 723,8 731,8 @@ bindmount(ulong *arg, int ismount)
		nexterror();
	}

	validaddr(arg[1], 1, 0);
	c1 = namec((char*)arg[1], Amount, 0, 0);
	validaddr((ulong)arg1, 1, 0);
	c1 = namec(arg1, Amount, 0, 0);
	if(waserror()){
		cclose(c1);
		nexterror();


@@ 738,19 746,26 @@ bindmount(ulong *arg, int ismount)
	cclose(c0);
	if(ismount)
		fdclose(fd, 0);

	return ret;
}

long
sysbind(ulong *arg)
{
	return bindmount(arg, 0);
	return bindmount(0, -1, -1, (char*)arg[0], (char*)arg[1], arg[2], nil);
}

long
sysmount(ulong *arg)
{
	return bindmount(arg, 1);
	return bindmount(1, arg[0], arg[1], nil, (char*)arg[2], arg[3], (char*)arg[4]);
}

long
sys_mount(ulong *arg)
{
	return bindmount(1, arg[0], -1, nil, (char*)arg[1], arg[2], (char*)arg[3]);
}

long

M port/sysproc.c => port/sysproc.c +46 -10
@@ 12,13 12,13 @@ int	shargs(char*, int, char**);
long
sysr1(ulong *arg)
{
extern int chandebug;
extern void dumpmount(void);
	extern int chandebug;
	extern void dumpmount(void);

	print("[%s %s %lud] r1 = %lud\n", up->user, up->text, up->pid, arg[0]);
chandebug=!chandebug;
if(chandebug)
	dumpmount();
	chandebug=!chandebug;
	if(chandebug)
		dumpmount();

	return 0;
}


@@ 567,13 567,49 @@ sysexits(ulong *arg)
}

long
syswait(ulong *arg)
sys_wait(ulong *arg)
{
	if(arg[0]){
		validaddr(arg[0], sizeof(Waitmsg), 1);
		evenaddr(arg[0]);
	int pid;
	Waitmsg w;
	OWaitmsg *ow;

	if(arg[0] == 0)
		return pwait(nil);

	validaddr(arg[0], sizeof(OWaitmsg), 1);
	evenaddr(arg[0]);
	pid = pwait(&w);
	if(pid >= 0){
		ow = (OWaitmsg*)arg[0];
		readnum(0, ow->pid, NUMSIZE, w.pid, NUMSIZE);
		readnum(0, ow->time+TUser*NUMSIZE, NUMSIZE, w.time[TUser], NUMSIZE);
		readnum(0, ow->time+TSys*NUMSIZE, NUMSIZE, w.time[TSys], NUMSIZE);
		readnum(0, ow->time+TReal*NUMSIZE, NUMSIZE, w.time[TReal], NUMSIZE);
		strncpy(ow->msg, w.msg, sizeof(ow->msg));
		ow->msg[sizeof(ow->msg)-1] = '\0';
	}
	return pwait((Waitmsg*)arg[0]);
	return pid;
}

long
sysawait(ulong *arg)
{
	int i;
	int pid;
	Waitmsg w;
	ulong n;

	n = arg[1];
	validaddr(arg[0], n, 1);
	pid = pwait(&w);
	if(pid < 0)
		return -1;
	i = snprint((char*)arg[0], n, "%d %lud %lud %lud %q",
		w.pid,
		w.time[TUser], w.time[TSys], w.time[TReal],
		w.msg);

	return i;
}

long

M port/systab.h => port/systab.h +15 -9
@@ 11,11 11,11 @@ Syscall sysdup;
Syscall sysalarm;
Syscall sysexec;
Syscall sysexits;
Syscall sysfsession;
Syscall sys_fsession;
Syscall sysfauth;
Syscall sys_fstat;
Syscall syssegbrk;
Syscall sysmount;
Syscall sys_mount;
Syscall sysopen;
Syscall sys_read;
Syscall sysoseek;


@@ 38,7 38,7 @@ Syscall syssegfree;
Syscall syssegflush;
Syscall sysrendezvous;
Syscall sysunmount;
Syscall syswait;
Syscall sys_wait;
Syscall sysseek;
Syscall sysfversion;
Syscall syserrstr;


@@ 46,6 46,8 @@ Syscall sysstat;
Syscall sysfstat;
Syscall syswstat;
Syscall sysfwstat;
Syscall sysmount;
Syscall sysawait;
Syscall syspread;
Syscall syspwrite;
Syscall	sysdeath;


@@ 60,11 62,11 @@ Syscall *systab[]={
	[ALARM]		sysalarm,
	[EXEC]		sysexec,
	[EXITS]		sysexits,
	[FSESSION]	sysfsession,
	[_FSESSION]	sys_fsession,
	[FAUTH]		sysfauth,
	[_FSTAT]	sys_fstat,
	[SEGBRK]	syssegbrk,
	[MOUNT]		sysmount,
	[_MOUNT]	sys_mount,
	[OPEN]		sysopen,
	[_READ]		sys_read,
	[OSEEK]		sysoseek,


@@ 87,7 89,7 @@ Syscall *systab[]={
	[SEGFLUSH]	syssegflush,
	[RENDEZVOUS]	sysrendezvous,
	[UNMOUNT]	sysunmount,
	[WAIT]		syswait,
	[_WAIT]		sys_wait,
	[SEEK]		sysseek,
	[FVERSION]	sysfversion,
	[ERRSTR]	syserrstr,


@@ 95,6 97,8 @@ Syscall *systab[]={
	[FSTAT]		sysfstat,
	[WSTAT]		syswstat,
	[FWSTAT]	sysfwstat,
	[MOUNT]		sysmount,
	[AWAIT]		sysawait,
	[PREAD]		syspread,
	[PWRITE]	syspwrite,
};


@@ 109,11 113,11 @@ char *sysctab[]={
	[ALARM]		"Alarm",
	[EXEC]		"Exec",
	[EXITS]		"Exits",
	[FSESSION]	"Fsession",
	[_FSESSION]	"_fsession",
	[FAUTH]		"Fauth",
	[_FSTAT]	"_fstat",
	[SEGBRK]	"Segbrk",
	[MOUNT]		"Mount",
	[_MOUNT]	"_mount",
	[OPEN]		"Open",
	[_READ]		"_read",
	[OSEEK]		"Oseek",


@@ 136,7 140,7 @@ char *sysctab[]={
	[SEGFLUSH]	"Segflush",
	[RENDEZVOUS]	"Rendez",
	[UNMOUNT]	"Unmount",
	[WAIT]		"Wait",
	[_WAIT]		"_wait",
	[SEEK]		"Seek",
	[FVERSION]	"Fversion",
	[ERRSTR]	"Errstr",


@@ 144,6 148,8 @@ char *sysctab[]={
	[FSTAT]		"Fstat",
	[WSTAT]		"Wstat",
	[FWSTAT]	"Fwstat",
	[MOUNT]		"Mount",
	[AWAIT]		"Await",
	[PREAD]		"Pread",
	[PWRITE]	"Pwrite",
};