shithub: riscv

Download patch

ref: 478d1024433f8713927729f02285682af0e0cf9b
parent: 4d4fc2ca3453a4deb79b26eb62449eab94b86827
author: iru <devnull@localhost>
date: Sat Apr 16 13:42:16 EDT 2011

Initial import of the new boot(8). Change pccd and pcf to use it.

--- a/sys/src/9/boot/aux.c
+++ b/sys/src/9/boot/aux.c
@@ -2,68 +2,7 @@
 #include <libc.h>
 #include <../boot/boot.h>
 
-/*
-int
-plumb(char *dir, char *dest, int *efd, char *here)
-{
-	char buf[128];
-	char name[128];
-	int n;
-
-	sprint(name, "%s/clone", dir);
-	efd[0] = open(name, ORDWR);
-	if(efd[0] < 0)
-		return -1;
-	n = read(efd[0], buf, sizeof(buf)-1);
-	if(n < 0){
-		close(efd[0]);
-		return -1;
-	}
-	buf[n] = 0;
-	sprint(name, "%s/%s/data", dir, buf);
-	if(here){
-		sprint(buf, "announce %s", here);
-		if(sendmsg(efd[0], buf) < 0){
-			close(efd[0]);
-			return -1;
-		}
-	}
-	sprint(buf, "connect %s", dest);
-	if(sendmsg(efd[0], buf) < 0){
-		close(efd[0]);
-		return -1;
-	}
-	efd[1] = open(name, ORDWR);
-	if(efd[1] < 0){
-		close(efd[0]);
-		return -1;
-	}
-	return efd[1];
-}
- */
-
-int
-sendmsg(int fd, char *msg)
-{
-	int n;
-
-	n = strlen(msg);
-	if(write(fd, msg, n) != n)
-		return -1;
-	return 0;
-}
-
 void
-warning(char *s)
-{
-	char buf[ERRMAX];
-
-	buf[0] = '\0';
-	errstr(buf, sizeof buf);
-	fprint(2, "boot: %s: %s\n", s, buf);
-}
-
-void
 fatal(char *s)
 {
 	char buf[ERRMAX];
@@ -90,6 +29,33 @@
 	return 0;
 }
 
+void
+run(char *file, ...)
+{
+	char buf[64];
+	Waitmsg *w;
+	int pid;
+
+	switch(pid = fork()){
+	case -1:
+		fatal("fork");
+	case 0:
+		exec(file, &file);
+		snprint(buf, sizeof buf, "can't exec %s", file);
+		fatal(buf);
+	default:
+		while((w = wait()) != nil)
+			if(w->pid == pid)
+				break;
+		if(w == nil){
+			snprint(buf, sizeof buf, "wait returned nil running %s", file);
+			free(w);
+			fatal(buf);
+		}
+		free(w);
+	}
+}
+
 int
 writefile(char *name, char *buf, int len)
 {
@@ -104,12 +70,12 @@
 }
 
 void
-setenv(char *name, char *val)
+setenv(char *name, char *val, int ec)
 {
 	int f;
 	char ename[64];
 
-	snprint(ename, sizeof ename, "#e/%s", name);
+	snprint(ename, sizeof ename, "#e%s/%s", ec ? "c" : "", name);
 	f = create(ename, 1, 0666);
 	if(f < 0){
 		fprint(2, "create %s: %r\n", ename);
@@ -142,41 +108,3 @@
 	close(f);
 }
 
-void
-catchint(void *a, char *note)
-{
-	USED(a);
-	if(strcmp(note, "alarm") == 0)
-		noted(NCONT);
-	noted(NDFLT);
-}
-
-int
-outin(char *prompt, char *def, int len)
-{
-	int n;
-	char buf[256];
-
-	if(len >= sizeof buf)
-		len = sizeof(buf)-1;
-
-	if(cpuflag){
-		notify(catchint);
-		alarm(15*1000);
-	}
-	print("%s[%s]: ", prompt, *def ? def : "no default");
-	memset(buf, 0, sizeof buf);
-	n = read(0, buf, len);
-	if(cpuflag){
-		alarm(0);
-		notify(0);
-	}
-
-	if(n < 0)
-		return 1;
-	if(n > 1){
-		buf[n-1] = 0;
-		strcpy(def, buf);
-	}
-	return n;
-}
--- a/sys/src/9/boot/boot.c
+++ b/sys/src/9/boot/boot.c
@@ -5,7 +5,6 @@
 #include "../boot/boot.h"
 
 char	cputype[64];
-char	sys[2*64];
 char 	reply[256];
 int	printcol;
 int	mflag;
@@ -12,36 +11,14 @@
 int	fflag;
 int	kflag;
 
-char	*bargv[Nbarg];
-int	bargc;
-
-static void	swapproc(void);
-static Method	*rootserver(char*);
-static void	usbinit(void);
-static void	kbmap(void);
-
 void
 boot(int argc, char *argv[])
 {
-	int fd, afd;
-	Method *mp;
-	char *cmd, cmdbuf[64], *iargv[16];
-	char rootbuf[64];
-	int islocal, ishybrid;
-	char *rp, *rsp;
-	int iargc, n;
-	char buf[32];
-	AuthInfo *ai;
+	Waitmsg *w;
+	int pid, i;
 
 	fmtinstall('r', errfmt);
 
-	/*
-	 * we should inherit the standard fds all referring to /dev/cons,
-	 * but we're being paranoid.
-	 */
-	close(0);
-	close(1);
-	close(2);
 	bind("#c", "/dev", MBEFORE);
 	open("/dev/cons", OREAD);
 	open("/dev/cons", OWRITE);
@@ -53,13 +30,14 @@
 	bind("#ec", "/env", MREPL);
 	bind("#e", "/env", MBEFORE|MCREATE);
 	bind("#s", "/srv", MREPL|MCREATE);
-#ifdef DEBUG
-	print("argc=%d\n", argc);
-	for(fd = 0; fd < argc; fd++)
-		print("%#p %s ", argv[fd], argv[fd]);
-	print("\n");
-#endif DEBUG
 
+	if(Debug){
+		print("argc=%d\n", argc);
+		for(i = 0; i < argc; i++)
+			print("%lux %s ", (ulong)argv[i], argv[i]);
+		print("\n");
+	}
+
 	ARGBEGIN{
 	case 'k':
 		kflag = 1;
@@ -73,281 +51,35 @@
 	}ARGEND
 
 	readfile("#e/cputype", cputype, sizeof(cputype));
-
-	/*
-	 *  set up usb keyboard, mouse and disk, if any.
-	 */
-	usbinit();
-
-	/*
-	 *  pick a method and initialize it
-	 */
-	if(method[0].name == nil)
-		fatal("no boot methods");
-	mp = rootserver(argc ? *argv : 0);
-	(*mp->config)(mp);
-	islocal = strcmp(mp->name, "local") == 0;
-	ishybrid = strcmp(mp->name, "hybrid") == 0;
-
-	/*
-	 *  load keymap if it's there.
-	 */
-	kbmap();
-
-	/*
- 	 *  authentication agent
-	 */
-	authentication(cpuflag);
-
-	/*
-	 *  connect to the root file system
-	 */
-	fd = (*mp->connect)();
-	if(fd < 0)
-		fatal("can't connect to file server");
-	if(getenv("srvold9p"))
-		fd = old9p(fd);
-	if(!islocal && !ishybrid){
-		if(cfs)
-			fd = (*cfs)(fd);
-	}
-	print("version...");
-	buf[0] = '\0';
-	n = fversion(fd, 0, buf, sizeof buf);
-	if(n < 0)
-		fatal("can't init 9P");
-	srvcreate("boot", fd);
-
-	/*
-	 *  create the name space, mount the root fs
-	 */
-	if(bind("/", "/", MREPL) < 0)
-		fatal("bind /");
-	rp = getenv("rootspec");
-	if(rp == nil)
-		rp = "";
+	setenv("bootdisk", bootdisk, 0);
 	
-	afd = fauth(fd, rp);
-	if(afd >= 0){
-		ai = auth_proxy(afd, auth_getkey, "proto=p9any role=client");
-		if(ai == nil)
-			print("authentication failed (%r), trying mount anyways\n");
-	}
-	if(mount(fd, afd, "/root", MREPL|MCREATE, rp) < 0)
-		fatal("mount /");
-	rsp = rp;
-	rp = getenv("rootdir");
-	if(rp == nil)
-		rp = rootdir;
-	if(bind(rp, "/", MAFTER|MCREATE) < 0){
-		if(strncmp(rp, "/root", 5) == 0){
-			fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
-			fatal("second bind /");
-		}
-		snprint(rootbuf, sizeof rootbuf, "/root/%s", rp);
-		rp = rootbuf;
-		if(bind(rp, "/", MAFTER|MCREATE) < 0){
-			fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
-			if(strcmp(rootbuf, "/root//plan9") == 0){
-				fprint(2, "**** warning: remove rootdir=/plan9 entry from plan9.ini\n");
-				rp = "/root";
-				if(bind(rp, "/", MAFTER|MCREATE) < 0)
-					fatal("second bind /");
-			}else
-				fatal("second bind /");
-		}
-	}
-	close(fd);
-	setenv("rootdir", rp);
+	/* setup the boot namespace */
+	run("/boot/mntgen", "-s", "slash", "/mnt", nil);
+	run("/boot/bzfs", "-f", "/boot/rootfs.bz2", "-m", "/mnt/broot", nil);
+	bind("/mnt/broot", "/", MAFTER);
+	bind("/386/bin", "/bin", MAFTER);
+	bind("/rc/bin", "/bin", MAFTER);
+	bind("/boot", "/bin", MAFTER);
 
-	settime(islocal, afd, rsp);
-	if(afd > 0)
-		close(afd);
-	swapproc();
-
-	cmd = getenv("init");
-	if(cmd == nil){
-		sprint(cmdbuf, "/%s/init -%s%s", cputype,
-			cpuflag ? "c" : "t", mflag ? "m" : "");
-		cmd = cmdbuf;
-	}
-	iargc = tokenize(cmd, iargv, nelem(iargv)-1);
-	cmd = iargv[0];
-
-	/* make iargv[0] basename(iargv[0]) */
-	if(iargv[0] = strrchr(iargv[0], '/'))
-		iargv[0]++;
-	else
-		iargv[0] = cmd;
-
-	iargv[iargc] = nil;
-
-	exec(cmd, iargv);
-	fatal(cmd);
-}
-
-static Method*
-findmethod(char *a)
-{
-	Method *mp;
-	int i, j;
-	char *cp;
-
-	if((i = strlen(a)) == 0)
-		return nil;
-	cp = strchr(a, '!');
-	if(cp)
-		i = cp - a;
-	for(mp = method; mp->name; mp++){
-		j = strlen(mp->name);
-		if(j > i)
-			j = i;
-		if(strncmp(a, mp->name, j) == 0)
-			break;
-	}
-	if(mp->name)
-		return mp;
-	return nil;
-}
-
-/*
- *  ask user from whence cometh the root file system
- */
-static Method*
-rootserver(char *arg)
-{
-	char prompt[256];
-	Method *mp;
-	char *cp;
-	int n;
-
-	/* look for required reply */
-	readfile("#e/nobootprompt", reply, sizeof(reply));
-	if(reply[0]){
-		mp = findmethod(reply);
-		if(mp)
-			goto HaveMethod;
-		print("boot method %s not found\n", reply);
-		reply[0] = 0;
-	}
-
-	/* make list of methods */
-	mp = method;
-	n = sprint(prompt, "root is from (%s", mp->name);
-	for(mp++; mp->name; mp++)
-		n += sprint(prompt+n, ", %s", mp->name);
-	sprint(prompt+n, ")");
-
-	/* create default reply */
-	readfile("#e/bootargs", reply, sizeof(reply));
-	if(reply[0] == 0 && arg != 0)
-		strcpy(reply, arg);
-	if(reply[0]){
-		mp = findmethod(reply);
-		if(mp == 0)
-			reply[0] = 0;
-	}
-	if(reply[0] == 0)
-		strcpy(reply, method->name);
-
-	/* parse replies */
-	do{
-		outin(prompt, reply, sizeof(reply));
-		mp = findmethod(reply);
-	}while(mp == nil);
-
-HaveMethod:
-	bargc = tokenize(reply, bargv, Nbarg-2);
-	bargv[bargc] = nil;
-	cp = strchr(reply, '!');
-	if(cp)
-		strcpy(sys, cp+1);
-	return mp;
-}
-
-static void
-swapproc(void)
-{
-	int fd;
-
-	fd = open("#c/swap", OWRITE);
-	if(fd < 0){
-		warning("opening #c/swap");
-		return;
-	}
-	if(write(fd, "start", 5) <= 0)
-		warning("starting swap kproc");
-	close(fd);
-}
-
-int
-old9p(int fd)
-{
-	int p[2];
-
-	if(pipe(p) < 0)
-		fatal("pipe");
-
-	print("srvold9p...");
-	switch(fork()) {
+	switch(pid = rfork(RFFDG|RFREND|RFPROC)){
 	case -1:
-		fatal("rfork srvold9p");
+		fatal("fork error");
 	case 0:
-		dup(fd, 1);
-		close(fd);
-		dup(p[0], 0);
-		close(p[0]);
-		close(p[1]);
-		execl("/srvold9p", "srvold9p", "-s", 0);
-		fatal("exec srvold9p");
+		setenv("cpuflag", cpuflag ? "1" : "0", 0);
+		run("/bin/rc", "/rc/bin/bootrc", nil);
+		break;
 	default:
-		close(fd);
-		close(p[0]);
+		while((w = wait()) != nil)
+			if(w->pid == pid)
+				break;
+		if(w == nil){
+			free(w);
+			fatal("wait error");
+		}
+		free(w);
+		break;
 	}
-	return p[1];
-}
 
-static void
-usbinit(void)
-{
-	static char usbd[] = "/boot/usbd";
-
-	if(access("#u/usb/ctl", 0) >= 0 && bind("#u", "/dev", MAFTER) >= 0 &&
-	    access(usbd, AEXIST) >= 0)
-		run(usbd, nil);
-}
-
-static void
-kbmap(void)
-{
-	char *f;
-	int n, in, out;
-	char buf[1024];
-
-	f = getenv("kbmap");
-	if(f == nil)
-		return;
-	if(bind("#κ", "/dev", MAFTER) < 0){
-		warning("can't bind #κ");
-		return;
-	}
-
-	in = open(f, OREAD);
-	if(in < 0){
-		warning("can't open kbd map: %r");
-		return;
-	}
-	out = open("/dev/kbmap", OWRITE);
-	if(out < 0) {
-		warning("can't open /dev/kbmap: %r");
-		close(in);
-		return;
-	}
-	while((n = read(in, buf, sizeof(buf))) > 0)
-		if(write(out, buf, n) != n){
-			warning("write to /dev/kbmap failed");
-			break;
-		}
-	close(in);
-	close(out);
+	for(;;)
+		;
 }
--- a/sys/src/9/boot/boot.h
+++ b/sys/src/9/boot/boot.h
@@ -1,73 +1,18 @@
-typedef struct Method	Method;
-struct Method
-{
-	char	*name;
-	void	(*config)(Method*);
-	int	(*connect)(void);
-	char	*arg;
+enum {
+	Debug = 0,
 };
-enum
-{
-	Statsz=	256,
-	Nbarg=	16,
-};
 
-extern void	authentication(int);
 extern char*	bootdisk;
 extern char*	rootdir;
-extern int	(*cfs)(int);
-extern int	cpuflag;
-extern char	cputype[];
-extern int	fflag;
-extern int	kflag;
-extern Method	method[];
-extern void	(*pword)(int, Method*);
-extern char	sys[];
-extern uchar	hostkey[];
-extern uchar	statbuf[Statsz];
-extern int	bargc;
-extern char	*bargv[Nbarg];
-extern int	pcload;
+extern int		(*cfs)(int);
+extern int		cpuflag;
+extern char		cputype[];
+extern int		fflag;
+extern int		kflag;
 
-/* libc equivalent */
-extern int	cache(int);
-extern char*	checkkey(Method*, char*, char*);
-extern void	fatal(char*);
-extern void	getpasswd(char*, int);
-extern void	key(int, Method*);
-extern int	outin(char*, char*, int);
-extern int	plumb(char*, char*, int*, char*);
+extern void fatal(char*);
 extern int	readfile(char*, char*, int);
-extern long	readn(int, void*, long);
-extern void	run(char *file, ...);
-extern int	sendmsg(int, char*);
-extern void	setenv(char*, char*);
-extern void	settime(int, int, char*);
-extern void	srvcreate(char*, int);
-extern void	warning(char*);
+extern void run(char*, ...);
+extern void	setenv(char*, char*, int);
 extern int	writefile(char*, char*, int);
 extern void	boot(int, char **);
-extern void	doauthenticate(int, Method*);
-extern int		old9p(int);
-extern int	parsefields(char*, char**, int, char*);
-
-/* methods */
-extern void	configtcp(Method*);
-extern int	connecttcp(void);
-
-extern void	configlocal(Method*);
-extern int	connectlocal(void);
-
-extern void	configsac(Method*);
-extern int	connectsac(void);
-
-extern void	configpaq(Method*);
-extern int	connectpaq(void);
-
-extern void	configembed(Method*);
-extern int	connectembed(void);
-
-extern void	configip(int, char**, int);
-
-/* hack for passing authentication address */
-extern char	*authaddr;
--- a/sys/src/9/boot/bootauth.c
+++ /dev/null
@@ -1,72 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include <fcall.h>
-#include "../boot/boot.h"
-
-char	*authaddr;
-static void glenda(void);
-
-void
-authentication(int cpuflag)
-{
-	char *s;
-	char *argv[16], **av;
-	int ac;
-
-	if(access("/boot/factotum", AEXEC) < 0){
-		glenda();
-		return;
-	}
-
-	/* start agent */
-	ac = 0;
-	av = argv;
-	av[ac++] = "factotum";
-	if(getenv("debugfactotum"))
-		av[ac++] = "-p";
-	s = getenv("factotumopts");
-	if(s != nil && *s != '\0')
-		av[ac++] = s;
-//	av[ac++] = "-d";		/* debug traces */
-//	av[ac++] = "-D";		/* 9p messages */
-	if(cpuflag)
-		av[ac++] = "-S";
-	else
-		av[ac++] = "-u";
-	av[ac++] = "-sfactotum";
-	if(authaddr != nil){
-		av[ac++] = "-a";
-		av[ac++] = authaddr;
-	}
-	av[ac] = 0;
-	switch(fork()){
-	case -1:
-		fatal("starting factotum: %r");
-	case 0:
-		exec("/boot/factotum", av);
-		fatal("execing /boot/factotum");
-	}
-
-	/* wait for agent to really be there */
-	while(access("/mnt/factotum", 0) < 0)
-		sleep(250);
-}
-
-static void
-glenda(void)
-{
-	int fd;
-	char *s;
-
-	s = getenv("user");
-	if(s == nil)
-		s = "glenda";
-
-	fd = open("#c/hostowner", OWRITE);
-	if(fd >= 0){
-		if(write(fd, s, strlen(s)) != strlen(s))
-			fprint(2, "setting #c/hostowner to %s: %r\n", s);
-		close(fd);
-	}
-}
--- a/sys/src/9/boot/bootcache.c
+++ /dev/null
@@ -1,80 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <../boot/boot.h>
-
-uchar statbuf[Statsz];
-
-int
-cache(int fd)
-{
-	int argc, i, p[2];
-	char *argv[5], bd[32], buf[256], partition[64], *pp;
-
-	if(stat("/boot/cfs", statbuf, sizeof statbuf) < 0)
-		return fd;
-
-	*partition = 0;
-
-	bind("#S", "/dev", MAFTER);
-	readfile("#e/cfs", buf, sizeof(buf));
-	if(*buf){
-		argc = tokenize(buf, argv, 4);
-		for(i = 0; i < argc; i++){
-			if(strcmp(argv[i], "off") == 0)
-				return fd;
-			else if(stat(argv[i], statbuf, sizeof statbuf) >= 0){
-				strncpy(partition, argv[i], sizeof(partition)-1);
-				partition[sizeof(partition)-1] = 0;
-			}
-		}
-	}
-
-	if(*partition == 0){
-		readfile("#e/bootdisk", bd, sizeof(bd));
-		if(*bd){
-			if(pp = strchr(bd, ':'))
-				*pp = 0;
-			/* damned artificial intelligence */
-			i = strlen(bd);
-			if(strcmp("disk", &bd[i-4]) == 0)
-				bd[i-4] = 0;
-			else if(strcmp("fs", &bd[i-2]) == 0)
-				bd[i-2] = 0;
-			else if(strcmp("fossil", &bd[i-6]) == 0)
-				bd[i-6] = 0;
-			sprint(partition, "%scache", bd);
-			if(stat(partition, statbuf, sizeof statbuf) < 0)
-				*bd = 0;
-		}
-		if(*bd == 0){
-			sprint(partition, "%scache", bootdisk);
-			if(stat(partition, statbuf, sizeof statbuf) < 0)
-				return fd;
-		}
-	}
-
-	print("cfs...");
-	if(pipe(p)<0)
-		fatal("pipe");
-	switch(fork()){
-	case -1:
-		fatal("fork");
-	case 0:
-		close(p[1]);
-		dup(fd, 0);
-		close(fd);
-		dup(p[0], 1);
-		close(p[0]);
-		if(fflag)
-			execl("/boot/cfs", "bootcfs", "-rs", "-f", partition, 0);
-		else
-			execl("/boot/cfs", "bootcfs", "-s", "-f", partition, 0);
-		break;
-	default:
-		close(p[0]);
-		close(fd);
-		fd = p[1];
-		break;
-	}
-	return fd;
-}
--- a/sys/src/9/boot/bootip.c
+++ /dev/null
@@ -1,203 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <ip.h>
-
-#include "boot.h"
-
-static	uchar	fsip[IPaddrlen];
-	uchar	auip[IPaddrlen];
-static	char	mpoint[32];
-
-static int isvalidip(uchar*);
-static void netndb(char*, uchar*);
-static void netenv(char*, uchar*);
-
-
-void
-configip(int bargc, char **bargv, int needfs)
-{
-	Waitmsg *w;
-	int argc, pid;
-	char **arg, **argv, buf[32], *p;
-
-	fmtinstall('I', eipfmt);
-	fmtinstall('M', eipfmt);
-	fmtinstall('E', eipfmt);
-
-	arg = malloc((bargc+1) * sizeof(char*));
-	if(arg == nil)
-		fatal("%r");
-	memmove(arg, bargv, bargc * sizeof(char*));
-	arg[bargc] = 0;
-
-	argc = bargc;
-	argv = arg;
-	strcpy(mpoint, "/net");
-	ARGBEGIN {
-	case 'x':
-		p = ARGF();
-		if(p != nil)
-			snprint(mpoint, sizeof(mpoint), "/net%s", p);
-		break;
-	case 'g':
-	case 'b':
-	case 'h':
-	case 'm':
-		p = ARGF();
-		USED(p);
-		break;
-	} ARGEND;
-
-	/* bind in an ip interface */
-	if(bind("#I", mpoint, MAFTER) < 0)
-		fatal("bind #I: %r\n");
-	if(access("#l0", 0) == 0 && bind("#l0", mpoint, MAFTER) < 0)
-		print("bind #l0: %r\n");
-	if(access("#l1", 0) == 0 && bind("#l1", mpoint, MAFTER) < 0)
-		print("bind #l1: %r\n");
-	if(access("#l2", 0) == 0 && bind("#l2", mpoint, MAFTER) < 0)
-		print("bind #l2: %r\n");
-	if(access("#l3", 0) == 0 && bind("#l3", mpoint, MAFTER) < 0)
-		print("bind #l3: %r\n");
-	werrstr("");
-
-	/* let ipconfig configure the ip interface */
-	switch(pid = fork()){
-	case -1:
-		fatal("configuring ip: %r");
-	case 0:
-		exec("/boot/ipconfig", arg);
-		fatal("execing /ipconfig");
-	default:
-		break;
-	}
-
-	/* wait for ipconfig to finish */
-	for(;;){
-		w = wait();
-		if(w != nil && w->pid == pid){
-			if(w->msg[0] != 0)
-				fatal(w->msg);
-			free(w);
-			break;
-		} else if(w == nil)
-			fatal("configuring ip");
-		free(w);
-	}
-
-	if(!needfs)
-		return;
-
-	/* if we didn't get a file and auth server, query user */
-	netndb("fs", fsip);
-	if(!isvalidip(fsip))
-		netenv("fs", fsip);
-	while(!isvalidip(fsip)){
-		buf[0] = 0;
-		outin("filesystem IP address", buf, sizeof(buf));
-		if (parseip(fsip, buf) == -1)
-			fprint(2, "configip: can't parse fs ip %s\n", buf);
-	}
-
-	netndb("auth", auip);
-	if(!isvalidip(auip))
-		netenv("auth", auip);
-	while(!isvalidip(auip)){
-		buf[0] = 0;
-		outin("authentication server IP address", buf, sizeof(buf));
-		if (parseip(auip, buf) == -1)
-			fprint(2, "configip: can't parse auth ip %s\n", buf);
-	}
-}
-
-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*)
-{
-	configip(bargc, bargv, 1);
-	setauthaddr("tcp", 567);
-}
-
-int
-connecttcp(void)
-{
-	int fd;
-	char buf[64];
-
-	snprint(buf, sizeof buf, "tcp!%I!564", fsip);
-	fd = dial(buf, 0, 0, 0);
-	if (fd < 0)
-		werrstr("dial %s: %r", buf);
-	return fd;
-}
-
-static int
-isvalidip(uchar *ip)
-{
-	if(ipcmp(ip, IPnoaddr) == 0)
-		return 0;
-	if(ipcmp(ip, v4prefix) == 0)
-		return 0;
-	return 1;
-}
-
-static void
-netenv(char *attr, uchar *ip)
-{
-	int fd, n;
-	char buf[128];
-
-	ipmove(ip, IPnoaddr);
-	snprint(buf, sizeof(buf), "#e/%s", attr);
-	fd = open(buf, OREAD);
-	if(fd < 0)
-		return;
-
-	n = read(fd, buf, sizeof(buf)-1);
-	if(n <= 0)
-		return;
-	buf[n] = 0;
-	if (parseip(ip, buf) == -1)
-		fprint(2, "netenv: can't parse ip %s\n", buf);
-}
-
-static void
-netndb(char *attr, uchar *ip)
-{
-	int fd, n, c;
-	char buf[1024];
-	char *p;
-
-	ipmove(ip, IPnoaddr);
-	snprint(buf, sizeof(buf), "%s/ndb", mpoint);
-	fd = open(buf, OREAD);
-	if(fd < 0)
-		return;
-	n = read(fd, buf, sizeof(buf)-1);
-	close(fd);
-	if(n <= 0)
-		return;
-	buf[n] = 0;
-	n = strlen(attr);
-	for(p = buf; ; p++){
-		p = strstr(p, attr);
-		if(p == nil)
-			break;
-		c = *(p-1);
-		if(*(p + n) == '=' && (p == buf || c == '\n' || c == ' ' || c == '\t')){
-			p += n+1;
-			if (parseip(ip, p) == -1)
-				fprint(2, "netndb: can't parse ip %s\n", p);
-			return;
-		}
-	}
-	return;
-}
--- a/sys/src/9/boot/bootmkfile
+++ b/sys/src/9/boot/bootmkfile
@@ -2,17 +2,8 @@
 BOOTLIB=$BOOTDIR/libboot.a$O
 
 BOOTFILES=\
-	bootauth.$O\
 	aux.$O\
 	boot.$O\
-	bootcache.$O\
-	bootip.$O\
-	local.$O\
-	embed.$O\
-	settime.$O\
-	sac.$O\
-	paq.$O\
-	printstub.$O\
 
 $BOOTLIB(%.$O):N:	%.$O
 
--- /dev/null
+++ b/sys/src/9/boot/bootrc
@@ -1,0 +1,183 @@
+# TODO
+# settime
+# handle rootspec
+# handle rootdir
+# clean rc environment before running init(8)
+# kfs
+# caching
+
+rfork e
+# boot methods
+mlocal = (configlocal connectlocal)
+mtcp = (configtcp connecttcp)
+mtab = (mlocal mtcp)
+config=1
+connect=2
+bootargs=()
+
+. /rc/lib/conf.rc
+. /rc/lib/menu.rc
+. /rc/lib/local.rc
+. /rc/lib/tcp.rc
+
+cputype=`{cat '#e'/cputype}
+
+fn fatal {
+	echo $*
+	exit $"*
+}
+
+fn must {
+	$* || fatal $"*^': '^$status
+}
+
+
+fn usbinit{
+	if(test -f '#u'){
+		bind -a '#u' /dev
+		# TODO: check access to /dev/usb
+		must usbd
+	}
+}
+
+fn kbmap{
+	if(! ~ $#kbmap 0){
+		bind -a '#κ' /dev
+		cat $kbmap > /dev/kbmap
+	}
+}
+
+fn readmethod{
+	resp=()
+	timeo=5
+	found=0
+
+	echo
+	echo Storage devices
+	for(i in /dev/sd??){
+		echo -n local!^$i'	'
+		echo `{sed 's/inquiry[ ]+//g; q' $i/ctl}\
+			partitions: `{cat $i/ctl | grep part | awk '{print $2}'}
+	}
+
+	while(~ $found 0){
+		if(~ $#pcload 0)
+			echo -n 'root is from: '
+		if not
+			echo -n 'kernel is at: '
+
+		while(~ $#resp 0){
+			resp=`{tread $timeo}
+			if(! ~ $status ''){
+				bootconf	# set configuration from file
+				if(! ~ $#nobootprompt 0)
+					bootargs=$nobootprompt
+				resp=$bootargs
+			}
+			if(~ $resp !rc)
+				rc
+			timeo=0
+		}
+
+		method=`{echo $resp | awk -F! '{print $1}'}
+		NF=`{echo $resp | awk -F! '{print NF}'}
+
+		for(i in `{seq 1 $#mtab}){
+			if(~ $mtab($i) m^$method)
+				found = $i 
+		}
+
+	 	if(~ $found 0){
+			echo method $method not found
+			resp=()
+		}
+	}
+
+	methodarg = `{echo $resp | sed 's/^[A-Za-z]+!(.*)$/\1/'}
+	mp = $$mtab($found)
+}
+
+fn authentication{
+	# in pcload we only need to read the kernel
+	if(~ $pcload 1)
+		user=none
+
+	if(! test -x /boot/factotum){
+		if(~ $#user 0)
+			user=glenda
+		echo -n $user > '#c'/hostowner
+	}
+	
+	if not{
+		x=(/boot/factotum -u -sfactotum)
+		if(~ $cpuflag 1)
+			x=($x -S)
+		if(! ~ $#authaddr 0)
+			x=($x -a $authaddr)
+		if(! ~ $#debugfactotum 0)
+			x=($x -p)
+
+		must $x
+	}
+}
+
+fn swapproc{
+	if(test -x '#c'/swap)
+		echo -n start > '#c'/swap
+}
+
+usbinit		# set up usb keyboard, mouse, and disk, if any
+kbmap
+
+configlocal	# add partitions and binds
+
+readmethod
+$mp($config)
+
+switch($method){
+case local
+	islocal=1
+case hybrid
+	ishybrid=1
+}
+
+# authentication agent
+authentication
+
+# connect to the root file system
+$mp($connect)
+
+swapproc
+
+mount -c '#s/boot' /root
+
+# remove part of our temporary root
+unmount /$cputype/bin /bin
+/mnt/broot/$cputype/bin/unmount /rc/bin /bin
+/mnt/broot/$cputype/bin/unmount /boot /bin
+/mnt/broot/$cputype/bin/unmount /
+
+if(~ $pcload 1)
+	/boot/echo reboot /root/$kern >/dev/reboot
+
+# create the name space, mount the root fs
+/mnt/broot/$cputype/bin/bind / /
+/mnt/broot/$cputype/bin/mount -ac '#s/boot' /
+
+# remove the remaining temporary root
+/mnt/broot/$cputype/bin/unmount /mnt/broot
+
+rootdir=/root
+
+if(~ $#init 0){
+	init=/$cputype/init
+	if(~ $cpuflag 1)
+		init=($init -c)
+	if not
+		init=($init -t)
+	# TODO handle mflag
+}
+
+$init
+
+
--- /dev/null
+++ b/sys/src/9/boot/conf.rc
@@ -1,0 +1,50 @@
+#!/bin/rc
+
+mounted=0
+found=0
+
+fn confmount{
+	part=`{echo $1 | sed 's!^.*/!!g; s!''$!!g'}
+
+	switch($part){
+	case dos
+		mprog=dossrv
+	case 9fat
+		mprog=dossrv
+	case fd?disk
+		mprog=dossrv
+	case data
+		mprog=9660srv
+	case *
+		mprog=0
+		mounted=0
+	}
+
+	if(! ~ $mprog 0){
+		$mprog -f $1 conf >/dev/null >[2=1]
+		mount /srv/conf /mnt/conf
+		mounted=1
+	}
+}
+
+fn findconf{
+	# search cd/dvd drives first
+	for(d in $cddevs /dev/sd* /dev/fd*disk)
+	for(p in `{ls $d}){
+		if(~ $found 0){
+			confmount $p
+			if(test -e /mnt/conf/plan9.ini)
+				found=1
+			if(test $mounted -eq 1 -a $found -eq 0){
+				unmount /mnt/conf
+				rm /srv/conf
+			}
+		}
+	}
+}
+
+fn bootconf{
+	findconf
+	if(~ $found 1)
+		parseconf
+}
--- a/sys/src/9/boot/doauthenticate.c
+++ /dev/null
@@ -1,126 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include "../boot/boot.h"
-
-static char *pbmsg = "AS protocol botch";
-static char *ccmsg = "can't connect to AS";
-
-long
-readn(int fd, void *buf, long len)
-{
-	int m, n;
-	char *p;
-
-	p = buf;
-	for(n = 0; n < len; n += m){
-		m = read(fd, p+n, len-n);
-		if(m <= 0)
-			return -1;
-	}
-	return n;
-}
-
-static char*
-fromauth(Method *mp, char *trbuf, char *tbuf)
-{
-	int afd;
-	char t;
-	char *msg;
-	static char error[2*ERRMAX];
-
-	if(mp->auth == 0)
-		fatal("no method for accessing auth server");
-	afd = (*mp->auth)();
-	if(afd < 0) {
-		sprint(error, "%s: %r", ccmsg);
-		return error;
-	}
-
-	if(write(afd, trbuf, TICKREQLEN) < 0 || read(afd, &t, 1) != 1){
-		close(afd);
-		sprint(error, "%s: %r", pbmsg);
-		return error;
-	}
-	switch(t){
-	case AuthOK:
-		msg = 0;
-		if(readn(afd, tbuf, 2*TICKETLEN) < 0) {
-			sprint(error, "%s: %r", pbmsg);
-			msg = error;
-		}
-		break;
-	case AuthErr:
-		if(readn(afd, error, ERRMAX) < 0) {
-			sprint(error, "%s: %r", pbmsg);
-			msg = error;
-		}
-		else {
-			error[ERRMAX-1] = 0;
-			msg = error;
-		}
-		break;
-	default:
-		msg = pbmsg;
-		break;
-	}
-
-	close(afd);
-	return msg;
-}
-
-void
-doauthenticate(int fd, Method *mp)
-{
-	char *msg;
-	char trbuf[TICKREQLEN];
-	char tbuf[2*TICKETLEN];
-
-	print("session...");
-	if(fsession(fd, trbuf, sizeof trbuf) < 0)
-		fatal("session command failed");
-
-	/* no authentication required? */
-	memset(tbuf, 0, 2*TICKETLEN);
-	if(trbuf[0] == 0)
-		return;
-
-	/* try getting to an auth server */
-	print("getting ticket...");
-	msg = fromauth(mp, trbuf, tbuf);
-	print("authenticating...");
-	if(msg == 0)
-		if(fauth(fd, tbuf) >= 0)
-			return;
-
-	/* didn't work, go for the security hole */
-	fprint(2, "no authentication server (%s), using your key as server key\n", msg);
-}
-
-char*
-checkkey(Method *mp, char *name, char *key)
-{
-	char *msg;
-	Ticketreq tr;
-	Ticket t;
-	char trbuf[TICKREQLEN];
-	char tbuf[TICKETLEN];
-
-	memset(&tr, 0, sizeof tr);
-	tr.type = AuthTreq;
-	strcpy(tr.authid, name);
-	strcpy(tr.hostid, name);
-	strcpy(tr.uid, name);
-	convTR2M(&tr, trbuf);
-	msg = fromauth(mp, trbuf, tbuf);
-	if(msg == ccmsg){
-		fprint(2, "boot: can't contact auth server, passwd unchecked\n");
-		return 0;
-	}
-	if(msg)
-		return msg;
-	convM2T(tbuf, &t, key);
-	if(t.num == AuthTc && strcmp(name, t.cuid)==0)
-		return 0;
-	return "no match";
-}
--- a/sys/src/9/boot/embed.c
+++ /dev/null
@@ -1,74 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <../boot/boot.h>
-
-static char *paqfile;
-
-void
-configembed(Method *m)
-{
-	if(*sys == '/' || *sys == '#'){
-		/*
-		 *  if the user specifies the disk in the boot cmd or
-		 * 'root is from' prompt, use it
-		 */
-		paqfile = sys;
-	} else if(m->arg){
-		/*
-		 *  a default is supplied when the kernel is made
-		 */
-		paqfile = m->arg;
-	}
-}
-
-int
-connectembed(void)
-{
-	int i, p[2];
-	Dir *dir;
-	char **arg, **argp;
-
-	dir = dirstat("/boot/paqfs");
-	if(dir == nil)
-		return -1;
-	free(dir);
-
-	dir = dirstat(paqfile);
-	if(dir == nil || dir->mode & DMDIR)
-		return -1;
-	free(dir);
-
-	print("paqfs...");
-	if(bind("#c", "/dev", MREPL) < 0)
-		fatal("bind #c");
-	if(bind("#p", "/proc", MREPL) < 0)
-		fatal("bind #p");
-	if(pipe(p)<0)
-		fatal("pipe");
-	switch(fork()){
-	case -1:
-		fatal("fork");
-	case 0:
-		arg = malloc((bargc+5)*sizeof(char*));
-		argp = arg;
-		*argp++ = "/boot/paqfs";
-		*argp++ = "-iv";
-		*argp++ = paqfile;
-		for(i=1; i<bargc; i++)
-			*argp++ = bargv[i];
-		*argp = 0;
-
-		dup(p[0], 0);
-		dup(p[1], 1);
-		close(p[0]);
-		close(p[1]);
-		exec("/boot/paqfs", arg);
-		fatal("can't exec paqfs");
-	default:
-		break;
-	}
-	waitpid();
-
-	close(p[1]);
-	return p[0];
-}
--- a/sys/src/9/boot/getpasswd.c
+++ /dev/null
@@ -1,43 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <../boot/boot.h>
-
-void
-getpasswd(char *p, int len)
-{
-	char c;
-	int i, n, fd;
-
-	fd = open("#c/consctl", OWRITE);
-	if(fd < 0)
-		fatal("can't open consctl; please reboot");
-	write(fd, "rawon", 5);
- Prompt:		
-	print("password: ");
-	n = 0;
-	for(;;){
-		do{
-			i = read(0, &c, 1);
-			if(i < 0)
-				fatal("can't read cons; please reboot");
-		}while(i == 0);
-		switch(c){
-		case '\n':
-			p[n] = '\0';
-			close(fd);
-			print("\n");
-			return;
-		case '\b':
-			if(n > 0)
-				n--;
-			break;
-		case 'u' - 'a' + 1:		/* cntrl-u */
-			print("\n");
-			goto Prompt;
-		default:
-			if(n < len - 1)
-				p[n++] = c;
-			break;
-		}
-	}
-}
--- a/sys/src/9/boot/local.c
+++ /dev/null
@@ -1,275 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <../boot/boot.h>
-
-static char diskname[64];
-static char *disk;
-static char **args;
-
-void
-configlocal(Method *mp)
-{
-	char *p;
-	int n;
-
-	if(*sys == '/' || *sys == '#'){
-		/*
-		 *  if the user specifies the disk in the boot cmd or
-		 * 'root is from' prompt, use it
-		 */
-		disk = sys;
-	} else if(strncmp(argv0, "dksc(0,", 7) == 0){
-		/*
-		 *  on many mips arg0 of the boot command specifies the
-		 *  scsi logical unit number
-		 */
-		p = strchr(argv0, ',');
-		n = strtoul(p+1, 0, 10);
-		sprint(diskname, "#w%d/sd%dfs", n, n);
-		disk = diskname;
-	} else if(mp->arg){
-		/*
-		 *  a default is supplied when the kernel is made
-		 */
-		disk = mp->arg;
-	} else if(*bootdisk){
-		/*
-		 *  an environment variable from a pc's plan9.ini or
-		 *  from the mips nvram or generated by the kernel
-		 *  is the last resort.
-		 */
-		disk = bootdisk;
-	}
-
-	/* if we've decided on one, pass it on to all programs */
-	if(disk)
-		setenv("bootdisk", disk);
-
-	USED(mp);
-}
-
-int
-connectlocalkfs(void)
-{
-	int i, pid, fd, p[2];
-	char partition[64];
-	char *dev;
-	char **arg, **argp;
-	Dir *d;
-
-	if(stat("/boot/kfs", statbuf, sizeof statbuf) < 0)
-		return -1;
-
-	dev = disk ? disk : bootdisk;
-	snprint(partition, sizeof partition, "%sfs", dev);
-	fd = open(partition, OREAD);
-	if(fd < 0){
-		strcpy(partition, dev);
-		fd = open(partition, OREAD);
-		if(fd < 0)
-			return -1;
-	}
-	/*
-	 * can't do this check -- might be some other server posing as kfs.
-	 *
-	memset(buf, 0, sizeof buf);
-	pread(fd, buf, 512, 0);
-	close(fd);
-	if(memcmp(buf+256, "kfs wren device\n", 16) != 0){
-		if(strstr(partition, "/fs"))
-			print("no kfs file system found on %s\n", partition);
-		return -1;
-	}
-	 *
-	 */
-	d = dirfstat(fd);
-	close(fd);
-	if(d == nil)
-		return -1;
-	if(d->mode&DMDIR){
-		free(d);
-		return -1;
-	}
-	free(d);
-
-	print("kfs...");
-	if(pipe(p)<0)
-		fatal("pipe");
-	switch(pid = fork()){
-	case -1:
-		fatal("fork");
-	case 0:
-		arg = malloc((bargc+5)*sizeof(char*));
-		argp = arg;
-		*argp++ = "kfs";
-		*argp++ = "-f";
-		*argp++ = partition;
-		*argp++ = "-s";
-		for(i=1; i<bargc; i++)
-			*argp++ = bargv[i];
-		*argp = 0;
-
-		dup(p[0], 0);
-		dup(p[1], 1);
-		close(p[0]);
-		close(p[1]);
-		exec("/boot/kfs", arg);
-		fatal("can't exec kfs");
-	default:
-		break;
-	}
-	for(;;){
-		if((i = waitpid()) == -1)
-			fatal("waitpid for kfs failed");
-		if(i == pid)
-			break;
-	}
-
-	close(p[1]);
-	return p[0];
-}
-
-void
-run(char *file, ...)
-{
-	int i, pid;
-
-	switch(pid = fork()){
-	case -1:
-		fatal("fork");
-	case 0:
-		exec(file, &file);
-		fatal(smprint("can't exec %s: %r", file));
-	default:
-		while ((i = waitpid()) != pid && i != -1)
-			;
-		if(i == -1)
-			fatal(smprint("wait failed running %s", file));
-	}
-}
-
-static int
-print1(int fd, char *s)
-{
-	return write(fd, s, strlen(s));
-}
-
-void
-configloopback(void)
-{
-	int fd;
-
-	if((fd = open("/net/ipifc/clone", ORDWR)) < 0){
-		bind("#I", "/net", MAFTER);
-		if((fd = open("/net/ipifc/clone", ORDWR)) < 0)
-			fatal("open /net/ipifc/clone for loopback");
-	}
-	if(print1(fd, "bind loopback /dev/null") < 0
-	|| print1(fd, "add 127.0.0.1 255.255.255.255") < 0)
-		fatal("write /net/ipifc/clone for loopback");
-}
-
-int
-connectlocalfossil(void)
-{
-	int fd;
-	char *venti, *f[32], *p;
-	int nf;
-	char partition[128], buf[512];
-	char *dev;
-
-	if(stat("/boot/fossil", statbuf, sizeof statbuf) < 0)
-		return -1;
-
-	/* look for fossil partition */
-	dev = disk ? disk : bootdisk;
-	snprint(partition, sizeof partition, "%sfossil", dev);
-	fd = open(partition, OREAD);
-	if(fd < 0){
-		strcpy(partition, dev);
-		fd = open(partition, OREAD);
-		if(fd < 0)
-			return -1;
-	}
-	memset(buf, 0, sizeof buf);
-	pread(fd, buf, 512, 127*1024);
-	close(fd);
-	if(memcmp(buf, "fossil config\n", 14) != 0){
-		if(strstr(partition, "/fossil"))
-			print("no fossil config found on %s\n", partition);
-		return -1;
-	}
-
-	settime(1, -1, nil);
-
-	/* make venti available */
-	if((venti = getenv("venti")) && (nf = tokenize(venti, f, nelem(f)))){
-		if((fd = open(f[0], OREAD)) >= 0){
-			print("venti...");
-			memset(buf, 0, sizeof buf);
-			pread(fd, buf, 512, 248*1024);
-			close(fd);
-			if(memcmp(buf, "venti config\n", 13) != 0){
-				print("no venti config found on %s\n", f[0]);
-				return -1;
-			}
-			if(stat("/boot/venti", statbuf, sizeof statbuf) < 0){
-				print("/boot/venti does not exist\n");
-				return -1;
-			}
-			switch(nf){
-			case 1:
-				f[1] = "tcp!127.1!17034";
-			case 2:
-				f[2] = "tcp!127.1!8000";
-			}
-			configloopback();
-			run("/boot/venti", "-c", f[0], "-a", f[1], "-h", f[2], 0);
-			/*
-			 * If the announce address is tcp!*!foo, then set
-			 * $venti to tcp!127.1!foo instead, which is actually dialable.
-			 */
-			if((p = strstr(f[1], "!*!")) != 0){
-				*p = 0;
-				snprint(buf, sizeof buf, "%s!127.1!%s", f[1], p+3);
-				f[1] = buf;
-			}
-			setenv("venti", f[1]);
-		}else{
-			/* set up the network so we can talk to the venti server */
-			/* this is such a crock. */
-			configip(nf, f, 0);
-			setenv("venti", f[0]);
-		}
-	}
-
-	/* start fossil */
-	print("fossil(%s)...", partition);
-	run("/boot/fossil", "-f", partition, "-c", "srv -A fboot", "-c", "srv -p fscons", 0);
-	fd = open("#s/fboot", ORDWR);
-	if(fd < 0){
-		print("open #s/fboot: %r\n");
-		return -1;
-	}
-	remove("#s/fboot");	/* we'll repost as #s/boot */
-	return fd;
-}
-
-int
-connectlocal(void)
-{
-	int fd;
-
-	if(bind("#c", "/dev", MREPL) < 0)
-		fatal("bind #c");
-	if(bind("#p", "/proc", MREPL) < 0)
-		fatal("bind #p");
-	bind("#S", "/dev", MAFTER);
-	bind("#k", "/dev", MAFTER);
-	bind("#æ", "/dev", MAFTER);
-
-	if((fd = connectlocalfossil()) < 0)
-	if((fd = connectlocalkfs()) < 0)
-		return -1;
-	return fd;
-}
--- /dev/null
+++ b/sys/src/9/boot/local.rc
@@ -1,0 +1,72 @@
+#!/bin/rc
+
+cddevs=()
+
+# fill cddevs with cd or dvd devices
+fn findcds{
+	for(dev in /dev/sd*){
+		x=`{sed '/([Cc][Dd]|[Dd][Vv][Dd])/!d' $dev/ctl >[2]/dev/null}
+		if(! ~ $#x 0)
+			cddevs=($cddevs $dev)
+	}
+}
+
+fn configlocal{
+	disk=`{echo $methodarg | sed 's,(.*)!.*,\1,g'}
+	fstype=`{echo $disk | sed 's,.*/(.*)$,\1,g'}
+	disk=`{echo $disk | sed 's,(.*)/.*$,\1,'}
+
+	if(~ $pcload 1){
+		kern=`{echo $methodarg | sed 's,.*!(.*)$,\1,g'}
+
+		# for now we only allow kernels in the same dev/part of $methodargs
+		if(~ $#kern 0 || ! ~ $#bootfile 0)
+			kern=`{echo $bootfile | sed 's,.*!(.*)$,\1,g'}
+	}
+
+	bind -a '#c' /dev >/dev/null >[2=1] 
+	bind '#p' /proc >[2=1] >/dev/null >[2=1]  
+	bind -a '#S' /dev >/dev/null >[2=1] 
+	bind -a '#f' /dev >/dev/null >[2=1] 
+	bind -a '#k' /dev >/dev/null >[2=1] 
+	bind -a '#æ' /dev >/dev/null >[2=1] 
+
+	diskparts
+	findcds
+}
+
+fn connectlocal{
+	switch($fstype){
+	case fossil
+		connectlocalfossil
+	case fs
+		connectlocalkfs
+	case data
+		# test for cd/dvd
+		x=`{sed '/([Cc][Dd]|[Dd][Vv][Dd])/!d' $disk^/ctl}
+		if(! ~ $#x 0)
+			must 9660srv -f $disk^/$fstype boot >/dev/null >[2=1]
+	case *
+		fatal unknown partition $fstype
+	}
+}
+
+fn connectlocalfossil{
+	if(! test -x /bin/fossil/fossil){
+		echo no fossil
+		exit nofossil
+	}
+
+	partition=$disk^/$fstype
+
+	# settime(1, -1, nil)
+
+	# make venti available
+
+	# start fossil
+	echo 'fossil('$partition')...'
+	must fossil/fossil -f $partition -c 'srv -A boot' -c 'srv -p fscons'
+}
+
+
+
--- /dev/null
+++ b/sys/src/9/boot/menu.rc
@@ -1,0 +1,134 @@
+#!/bin/rc
+
+conffile=/mnt/conf/plan9.ini
+items=()
+
+fn menuitems{
+oifs=$ifs
+ifs='
+'
+	# get menu items and save them in the form 'item\tstring'
+	x=(`{awk -F'\n' '
+			$0 ~ /\[menu\]/ {
+				FS="[= ]"
+				for(nitem=1;;nitem++){
+					getline
+					if(match($0, /\[/))	# if we entered a block, we are done
+						break
+					sub(/\,/, "")		# remove comma
+					if(match($0, /^#/)) # comments
+						continue
+					if(match($0, /^$/)) # empty line
+						continue
+					printf("%s\t\"    %d. ", $2, nitem)
+					for(i=3; i <= NF; i++)
+						printf("%s ", $i)
+					printf("\"\t\n")
+				}
+			}
+	' $conffile})
+
+	ifs='	'
+	for(itemline in $x){
+		# separate item from string
+		item=`{echo $itemline(1)}
+
+		# $menuitemtext holds the string for the item
+		$item(1)^text=$item(2)
+		items=($items $item(1))
+	}
+	if(! ~ $#items 0){
+		echo 'Plan 9 Startup Menu:'
+		echo '--------------------'
+	}
+	ifs=$oifs
+}
+
+# load block definitions
+fn menublock{
+	for(i in `{
+		awk -F'\n' -v item'='`{echo '['$1']' | sed 's/ //g'} '
+		{
+				# find menuitem block
+				if(index($0, item)){
+					for(;;){
+						if(getline <= 0)
+							break
+						if(match($0, /\[/))	# entered a block, we are done
+							break
+						if(match($0, /^$/))
+							continue
+			
+						# skip comments, quote kernel devices
+						if(index($0, "#") == 1)
+							continue
+						else
+							gsub("#", "''#''")
+						printf("%s\n", $1)
+					}
+				}
+		}' $conffile}){
+			name=`{echo $i | awk -F'=' '{print $1}'}
+			val=`{echo $i | awk -F'=' '{print $2}'}
+
+			# a name beginning with * denotes
+			# a kernel variable, save to #ec
+			v0=`{echo $i | sed 's/(\*).*/\1/'}
+			if(~ $v0 '*'){
+				bind -bc '#ec' /env
+				eval $name'='$val
+				unmount '#ec' /env
+			}
+			if not 
+				eval $name'='$val
+		}
+}
+
+fn freevars{
+	for(i in `{
+		awk -F'\n' '{
+			if(match($0, /\[/))	# entered a block, we are done
+				exit
+			if(match($0, /^$/))
+				exit
+			# skip comments, quote kernel devices
+			if(index($0, "#") == 1)
+				exit
+			else
+				gsub("#", "''#''")
+			printf("%s\n", $1)
+		}' $conffile}){
+		# a name beginning with * denotes
+		# a kernel variable, save to #ec
+		val=`{echo $i | sed 's/(\*).*/\1/'}
+		if(~ $val '*'){
+			bind -bc '#ec' /env
+			eval $i
+			unmount '#ec' /env
+		}
+		if not eval $i
+	}
+}
+
+fn parseconf{
+	opt=0
+	if(test -f $conffile){
+		freevars	
+		menuitems
+		menublock 'common'
+
+		if(! ~ $#items 0){
+			while(test $opt -lt 1 || test $opt -gt $#items){
+				for(item in $items)
+					echo -n $`{echo $item^text} | sed 's/"//g'
+
+				echo -n '    Selection: '
+				opt=`{read}
+
+				if(test $opt -ge 1 && test $opt -le $#items)
+					menublock $items($opt)
+			}
+		}
+	}
+}
+
--- a/sys/src/9/boot/mkboot
+++ b/sys/src/9/boot/mkboot
@@ -12,53 +12,6 @@
 #include <libc.h>
 #include "../boot/boot.h"
 
-Method	method[]={
----
-
-#
-#  configure all remote methods, i.e. all methods in the 'boot' section
-#
-#  EXAMPLE
-#	boot
-#		incon
-#		9600
-#		19200
-#
-../port/mkextract boot 0 $* | awk '{
-	printf "	{ \""  "" $1 "\", "\
-	"config" $1 ", "\
-	"connect" $1 ", "
-	print fieldn(2) " },"
-	}
-
-	func fieldn(n,	s,i)
-	{
-		s = $0
-		while (n > 1) {
-			sub(/^[ \t]*/, "", s)
-			if (substr(s, 1, 1) == "\"") {
-				sub(/^"[^\"]*"/, "", s)
-			} else {
-				sub(/^[^ \t]*/, "", s)
-			}
-			n--
-		}
-		sub(/^[ \t]*/, "", s)
-		if (substr(s, 1, 1) == "\"") {
-			i = index(substr(s, 2), "\"")
-			if (i > 0)
-				return substr(s, 1, i+1)
-			else
-				return s
-		} else {
-			sub(/[ \t].*/, "", s)
-			return s
-		}
-	}'
-
-cat <<'---'
-	{ 0 },
-};
 ---
 
 awk '
--- a/sys/src/9/boot/nopsession.c
+++ /dev/null
@@ -1,52 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include <fcall.h>
-#include "../boot/boot.h"
-
-static Fcall	hdr;
-
-static void
-rpc(int fd, int type)
-{
-	int n, l;
-	char buf[128], *p;
-
-	hdr.type = type;
-	hdr.tag = NOTAG;
-	n = convS2M(&hdr, buf);
-	if(write(fd, buf, n) != n)
-		fatal("write rpc");
-
-	print("...");
-	p = buf;
-	l = 0;
-	while(l < 3) {
-		n = read(fd, p, 3);
-		if(n <= 0)
-			fatal("read rpc");
-		if(n == 2 && l == 0 && buf[0] == 'O' && buf[1] == 'K')
-			continue;
-		p += n;
-		l += n;
-	}
-	if(convM2S(buf, &hdr, n) == 0){
-		print("%ux %ux %ux\n", buf[0], buf[1], buf[2]);
-		fatal("rpc format");
-	}
-	if(hdr.tag != NOTAG)
-		fatal("rpc tag not NOTAG");
-	if(hdr.type == Rerror){
-		print("error %s;", hdr.ename);
-		fatal("remote error");
-	}
-	if(hdr.type != type+1)
-		fatal("not reply");
-}
-
-void
-nop(int fd)
-{
-	print("nop");
-	rpc(fd, Tnop);
-}
--- a/sys/src/9/boot/paq.c
+++ /dev/null
@@ -1,67 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <../boot/boot.h>
-
-char *fparts[] =
-{
-	"add bootldr	0x0000000 0x0040000",
-	"add params	0x0040000 0x0080000",
-	"add kernel	0x0080000 0x0140000",
-	"add user	0x0140000 0x0200000",
-	"add ramdisk	0x0200000 0x0600000",
-};
-
-void
-configpaq(Method*)
-{
-	int fd;
-	int i;
-
-	if(bind("#F", "/dev", MAFTER) < 0)
-		fatal("bind #c");
-	if(bind("#p", "/proc", MREPL) < 0)
-		fatal("bind #p");
-	fd = open("/dev/flash/flashctl", OWRITE);
-	if(fd < 0)
-		fatal("opening flashctl");
-	for(i = 0; i < nelem(fparts); i++)
-		if(fprint(fd, fparts[i]) < 0)
-			fatal(fparts[i]);
-	close(fd);
-}
-
-int
-connectpaq(void)
-{
-	int  p[2];
-	char **arg, **argp;
-
-	print("paq...");
-	if(pipe(p)<0)
-		fatal("pipe");
-	switch(fork()){
-	case -1:
-		fatal("fork");
-	case 0:
-		arg = malloc(10*sizeof(char*));
-		argp = arg;
-		*argp++ = "paqfs";
-		*argp++ = "-v";
-		*argp++ = "-i";
-		*argp++ = "/dev/flash/ramdisk";
-		*argp = 0;
-
-		dup(p[0], 0);
-		dup(p[1], 1);
-		close(p[0]);
-		close(p[1]);
-		exec("/boot/paqfs", arg);
-		fatal("can't exec paqfs");
-	default:
-		break;
-	}
-	waitpid();
-
-	close(p[1]);
-	return p[0];
-}
--- a/sys/src/9/boot/sac.c
+++ /dev/null
@@ -1,50 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <../boot/boot.h>
-
-/*
- * HACK - take over from boot since file system is not
- * available on a pipe
- */
-
-void
-configsac(Method *mp)
-{
-	int fd;
-	char cmd[64];
-
-	USED(mp);
-
-	/*
-	 *  create the name space, mount the root fs
-	 */
-	if(bind("/", "/", MREPL) < 0)
-		fatal("bind /");
-	if(bind("#C", "/", MAFTER) < 0)
-		fatal("bind /");
-
-	/* fixed sysname - enables correct namespace file */
-	fd = open("#c/sysname", OWRITE);
-	if(fd < 0)
-		fatal("open sysname");
-	write(fd, "brick", 5);
-	close(fd);
-
-	fd = open("#c/hostowner", OWRITE);
-	if(fd < 0)
-		fatal("open sysname");
-	write(fd, "brick", 5);
-	close(fd);
-
-	sprint(cmd, "/%s/init", cputype);
-	print("starting %s\n", cmd);
-	execl(cmd, "init", "-c", 0);
-	fatal(cmd);
-}
-
-int
-connectsac(void)
-{
-	/* does not get here */
-	return -1;
-}
--- a/sys/src/9/boot/settime.c
+++ /dev/null
@@ -1,149 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include <fcall.h>
-#include "../boot/boot.h"
-
-static long lusertime(char*);
-
-char *timeserver = "#s/boot";
-
-void
-settime(int islocal, int afd, char *rp)
-{
-	int n, f;
-	int timeset;
-	Dir dir[2];
-	char timebuf[64];
-
-	print("time...");
-	timeset = 0;
-	if(islocal){
-		/*
-		 *  set the time from the real time clock
-		 */
-		f = open("#r/rtc", ORDWR);
-		if(f >= 0){
-			if((n = read(f, timebuf, sizeof(timebuf)-1)) > 0){
-				timebuf[n] = '\0';
-				timeset = 1;
-			}
-			close(f);
-		}else do{
-			strcpy(timebuf, "yymmddhhmm[ss]");
-			outin("\ndate/time ", timebuf, sizeof(timebuf));
-		}while((timeset=lusertime(timebuf)) <= 0);
-	}
-	if(timeset == 0){
-		/*
-		 *  set the time from the access time of the root
-		 */
-		f = open(timeserver, ORDWR);
-		if(f < 0)
-			return;
-		if(mount(f, afd, "/tmp", MREPL, rp) < 0){
-			warning("settime mount");
-			close(f);
-			return;
-		}
-		close(f);
-		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, "/tmp");
-	}
-
-	f = open("#c/time", OWRITE);
-	if(write(f, timebuf, strlen(timebuf)) < 0)
-		warning("can't set #c/time");
-	close(f);
-	print("\n");
-}
-
-#define SEC2MIN 60L
-#define SEC2HOUR (60L*SEC2MIN)
-#define SEC2DAY (24L*SEC2HOUR)
-
-int
-g2(char **pp)
-{
-	int v;
-
-	v = 10*((*pp)[0]-'0') + (*pp)[1]-'0';
-	*pp += 2;
-	return v;
-}
-
-/*
- *  days per month plus days/year
- */
-static	int	dmsize[] =
-{
-	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-static	int	ldmsize[] =
-{
-	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-/*
- *  return the days/month for the given year
- */
-static int *
-yrsize(int y)
-{
-
-	if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
-		return ldmsize;
-	else
-		return dmsize;
-}
-
-/*
- *  compute seconds since Jan 1 1970
- */
-static long
-lusertime(char *argbuf)
-{
-	char *buf;
-	ulong secs;
-	int i, y, m;
-	int *d2m;
-
-	buf = argbuf;
-	i = strlen(buf);
-	if(i != 10 && i != 12)
-		return -1;
-	secs = 0;
-	y = g2(&buf);
-	m = g2(&buf);
-	if(y < 70)
-		y += 2000;
-	else
-		y += 1900;
-
-	/*
-	 *  seconds per year
-	 */
-	for(i = 1970; i < y; i++){
-		d2m = yrsize(i);
-		secs += d2m[0] * SEC2DAY;
-	}
-
-	/*
-	 *  seconds per month
-	 */
-	d2m = yrsize(y);
-	for(i = 1; i < m; i++)
-		secs += d2m[i] * SEC2DAY;
-
-	secs += (g2(&buf)-1) * SEC2DAY;
-	secs += g2(&buf) * SEC2HOUR;
-	secs += g2(&buf) * SEC2MIN;
-	if(*buf)
-		secs += g2(&buf);
-
-	sprint(argbuf, "%ld", secs);
-	return secs;
-}
--- /dev/null
+++ b/sys/src/9/boot/tcp.rc
@@ -1,0 +1,61 @@
+#!/bin/rc
+
+fn isvalidip{
+	# TODO: more precise test
+	if(! ~ $#1 0 && ! test `{echo $1 | sed '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/d'})
+		echo -n
+}
+
+fn configtcp{
+	# TODO: 
+	# should we accept a different mount point?
+	# should we add more interfaces?
+
+	# bind in an ip interface
+	for(i in I l`{seq 0 3})
+		bind -a '#'$i /net >/dev/null >[2=1]
+
+	if(! test -x /bin/ip/ipconfig){
+		echo no ipconfig
+		exit noipconfig
+	}
+
+	ip/ipconfig	# TODO: should receive args passed to boot(8)
+	
+	# XXX: should configuration from file override the values from ipconfig(8)?
+	if(~ $#fs 0){
+		_fsip=`{grep fs /net/ndb | awk -F'=' '{print $2}' >/dev/null >[2=1]}
+		if(! ~ $#_fsip 0 && `{isvalidip $_fsip})
+			fsip=$_fsip
+	}
+
+	# if we didn't get a file and auth server from either 
+	# the configuration file or ipconfig(8), ask the user
+	if(~ $#fsip 0){
+		while(! isvalidip $fsip){
+			echo -n 'filesystem IP address: '
+			fsip=`{read}
+		}
+	}
+	
+	if(~ $#auth 0){
+		_authip=`{grep auth /net/ndb | awk -F'=' '{print $2}' >/dev/null >[2=1]}
+		if(! ~ $#_authip 0 && `{isvalidip $_authip})
+			authip=_authip
+	}
+	
+	if(~ $#authip 0){
+		while(! isvalidip $authip){
+			echo -n 'authentication server IP address: '
+			authip=`{read}
+		}
+	}
+
+	authaddr=tcp!$authip!567	# leave this for factotum(4)
+
+	rm -f /env/_authip /env/_fsip
+}
+
+fn connecttcp{
+	srv -q tcp!$fsip!564 boot 
+}
--- a/sys/src/9/boot/testboot.c
+++ /dev/null
@@ -1,37 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-
-void
-usage(void)
-{
-	fprint(2, "usage: testboot cmd args...\n");
-	exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
-	int p[2];
-
-	if(argc == 1)
-		usage();
-
-	pipe(p);
-	switch(rfork(RFPROC|RFFDG|RFNAMEG)){
-	case -1:
-		sysfatal("fork: %r");
-
-	case 0:
-		dup(p[0], 0);
-		dup(p[1], 1);
-		exec(argv[1], argv+1);
-		sysfatal("exec: %r");
-
-	default:
-		if(amount(p[0], "/n/kremvax", MREPL, "") < 0)
-			sysfatal("amount: %r");
-		break;
-	}
-	exits(nil);
-}
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -79,6 +79,9 @@
 	$LD -o $target -T$KTZERO -l $OBJ $CONF.$O $LIB
 	size $target
 
+rootfs.bz2:
+	rc ../port/mkbootfs
+
 # don't strip the gzipped kernels -- too frustrating when that's all you have!
 $p%.gz:D:	$p%
 	gzip -9 <$p$stem >$p$stem.gz
--- a/sys/src/9/pc/pccd
+++ b/sys/src/9/pc/pccd
@@ -125,6 +125,8 @@
 
 bootdir
 	bootpccd.out boot
-	/386/bin/ip/ipconfig ipconfig
-	/386/bin/9660srv kfs
-	/386/bin/usb/usbd
+	/386/bin/auth/factotum
+	/386/bin/bzfs
+	/386/bin/echo
+	/386/bin/mntgen
+	rootfs.bz2
--- a/sys/src/9/pc/pcf
+++ b/sys/src/9/pc/pcf
@@ -130,8 +130,8 @@
 
 bootdir
 	bootpcf.out boot
-	/386/bin/ip/ipconfig
 	/386/bin/auth/factotum
-	/386/bin/fossil/fossil
-	/386/bin/venti/venti
-	/386/bin/usb/usbd
+	/386/bin/bzfs
+	/386/bin/echo
+	/386/bin/mntgen
+	rootfs.bz2
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -30,7 +30,7 @@
 		mk 'CONF='$i
 
 clean:V:
-	rm -f *.[$OS] *.root.s *.rootc.c cfs.h fs.h init.h conf.h *.out *.m errstr.h
+	rm -f *.[$OS] *.root.s *.rootc.c cfs.h fs.h init.h conf.h *.out *.m errstr.h rootfs.bz2
 	for(i in $CONFLIST $CRAPLIST)
 		mk $i.clean