Charles.Forsyth20060303644188019 years agoHistory
628 lines · 12.1 KB · Brainfuck
RawDownload
## Generalized boot Inferno# implement Init; include "sys.m";	sys:	Sys; include "draw.m"; include "keyring.m";	kr: Keyring; include "security.m";	auth: Auth;	random: Random; include "tftp.m"; Bootpreadlen: con 128; Init: module{	init:	fn();}; ip: string;mask: string;fsip: string;bootprotocol: string;bootserver: string;bootfile: string; debug: con 0; init(){	ipavailable: int;	sys = load Sys Sys->PATH; 	kexecfd := sys->open("#B/kexec", Sys->OWRITE);	if (kexecfd == nil)		fatal(sys->sprint("opening #B/kexec: %r")); 	ipavailable = 0;	if (dobind("#l", "/net", sys->MREPL) && dobind("#I", "/net", sys->MAFTER))		ipavailable = 1; 	dobind("#c", "/dev", sys->MAFTER); 	# console device 	if (!ipavailable)		fatal("no IP stack available");	cfd := sys->open("/net/ipifc/clone", sys->ORDWR);	if(cfd == nil)		fatal(sys->sprint("open /net/ipifc/clone: %r")); 	if (sys->fprint(cfd, "bind ether ether0") < 0)		fatal(sys->sprint("binding ether0: %r")); 	fsready := 0; 	fsip = ipconfig(cfd); 	bootstring := getenvdefault("bootpath", "tftp"); 	(bootprotocol, bootserver, bootfile) = parsebootstring(bootstring); 	if (bootprotocol == nil)		fatal(bootstring + ": unrecognised syntax"); 	# Run dhcp if necessary	if (bootprotocol == "tftp" && (bootserver == nil || bootfile == nil))		dhcp(); 	# determine server	if (bootprotocol == "net" && bootserver == nil)		bootserver = fsip; 	if (bootserver == nil)		fatal("couldn't determine boot server"); 	if (bootfile == nil)		fatal("couldn't determine boot file"); 	if (bootprotocol == nil)		fatal("couldn't determine boot protocol"); 	sys->print("loading %s!%s!%s\n", bootprotocol, bootserver, bootfile); 	if (bootprotocol == "net") {		sys->print("Attempting remote mount\n");		if (netfs(bootserver) == 0)			sys->print("Remote mount successful\n");		else			fatal(sys->sprint("Remote mount failed: %r"));		fd := sys->open("/n/remote" + bootfile, Sys->OREAD);		if (fd == nil)			fatal(sys->sprint("%s:/n/remote%s: %r", bootserver, bootfile));		if (sys->stream(fd, kexecfd, 4096) < 0)			fatal(sys->sprint("copying %s: %r", bootfile));	}	else if (bootprotocol == "tftp") {		tftp := load Tftp Tftp->PATH;		if (tftp == nil)			fatal("can't load tftp module");		tftp->init(1);		errstr := tftp->receive(bootserver, bootfile, kexecfd);		if (errstr != nil)			fatal("tftp: " + errstr);	}	else		fatal("protocol " + bootprotocol + " not supported");	sys->print("Launching new kernel\n");	kexecfd = nil;} parsebootstring(s: string): (string, string, string){	proto, server, file: string;	(n, l) := sys->tokenize(s, "!");	if (n > 3)		return (nil, nil, nil);	proto = hd l;	l = tl l;	if (l != nil) {		server = hd l;		l = tl l;	}	if (l != nil)		file = hd l;	case proto {	"tftp" =>		;	"net" =>		# can't have a default file, so n must be 3		if (n != 3)			return (nil, nil, nil);	* =>		return (nil, nil, nil);	}	return (proto, server, file);} dobind(f, t: string, flags: int): int{	if(sys->bind(f, t, flags) < 0) {		err(sys->sprint("can't bind %s on %s: %r", f, t));		return 0;	}	return 1;} err(s: string){	sys->fprint(sys->fildes(2), "bootinit: %s\n", s);} hang(){	<-(chan of int);} fatal(s: string){	err(s);	hang();} envlist: list of string; getenv(name: string): string{	if (envlist == nil) {		fd := sys->open("/dev/sysenv", Sys->OREAD);		if (fd != nil) {			ntok: int;			buf := array[1024] of byte;			nr := sys->read(fd, buf, len buf);			if(nr > 0)				(ntok, envlist) = sys->tokenize(string buf, "\n");		}	}	ls := envlist;	while(ls != nil) {		(ntok2, ls2) := sys->tokenize(hd ls, "=");		if(hd ls2 == name)			return hd tl ls2;		ls = tl ls;	}	return nil;} getenvdefault(name: string, default: string): string{	rv := getenv(name);	if (rv == nil)		return default;	return rv;} ipconfig(cfd: ref sys->FD): string{	ip = getenv("wireip");	if (ip == nil)		ip = getenv("ip");	mask = getenv("ipmask");	fsip = getenv("fsip");	if (ip != nil && mask != nil) {		sys->print("ip %s %s\n", ip, mask);		sys->fprint(cfd, "add %s %s", ip, mask);		gwip := getenv("gwip");		if (gwip != nil) {			sys->print("gwip %s\n", gwip);			rfd := sys->open("/net/iproute", Sys->ORDWR);			if (rfd == nil || sys->fprint(rfd, "add 0.0.0.0 0.0.0.0 %s", gwip) < 0)				err(sys->sprint("failed to add default route: %r"));		}	}	if (ip == nil || mask == nil)		return bootp(cfd);	return fsip;} bootpdone: int; bootp(cfd: ref sys->FD): string{	if (bootpdone == 1)		return fsip; 	bootpdone = 1; 	sys->print("bootp ..."); 	if (sys->fprint(cfd, "bootp") < 0) {		sys->print("init: bootp: %r");		return nil;	} 	fd := sys->open("/net/bootp", sys->OREAD);	if(fd == nil) {		err(sys->sprint("open /net/bootp: %r"));		return nil;	} 	buf := array[Bootpreadlen] of byte;	nr := sys->read(fd, buf, len buf);	fd = nil;	if(nr <= 0) {		err(sys->sprint("read /net/bootp: %r"));		return nil;	}	(ntok, ls) := sys->tokenize(string buf, " \t\n");	while(ls != nil) {		name := hd ls;		ls = tl ls;		if (ls == nil)			break;		value := hd ls;		ls = tl ls;		if (name == "fsip")			fsip = value;		else if (name == "ipaddr")			ip = value;		else if (name == "ipmask")			mask = value;	}	return fsip;} netfs(server: string): int{	auth = load Auth  Auth->PATH;	if (auth != nil)		auth->init(); 	kr = load Keyring Keyring->PATH;	sys->print("dial...");	(ok, c) := sys->dial("tcp!" + server + "!6666", nil);	if(ok < 0)		return -1;		if(kr != nil && auth != nil){		err: string;		sys->print("Authenticate ...");		ai := kr->readauthinfo("/nvfs/default");		if(ai == nil){			sys->print("readauthinfo /nvfs/default failed: %r\n");			sys->print("trying mount as `nobody'\n");		}		(c.dfd, err) = auth->client("none", ai, c.dfd);		if(c.dfd == nil){			sys->print("authentication failed: %s\n", err);			return -1;		}	}		sys->print("mount ...");		c.cfd = nil;	n := sys->mount(c.dfd, nil, "/n/remote", sys->MREPL, "");	if(n > 0)		return 0;	return -1;} ### DHCP## Dhcp: adt {	op: int;	htype: int;	hops: int;	xid: int;	secs: int;	flags: int;	ciaddr: int;	yiaddr: int;	siaddr: int;	giaddr: int;	chaddr: array of byte;	sname: string;	file: string;}; nboputl(buf: array of byte, val: int){	buf[0] = byte (val >> 24);	buf[1] = byte (val >> 16);	buf[2] = byte (val >> 8);	buf[3] = byte val;} nboputs(buf: array of byte, val: int){	buf[0] = byte (val >> 8);	buf[1] = byte val;} nbogets(buf: array of byte): int{	return (int buf[0] << 8) | int buf[1];} nbogetl(buf: array of byte): int{	return (int buf[0] << 24) | (int buf[1] << 16) | (int buf[2] << 8) | int buf[3];} stringget(buf: array of byte): string{	for (x := 0; x < len buf; x++)		if (buf[x] == byte 0)			break;	if (x == 0)		return nil;	return string buf[0 : x];} memcmp(b1: array of byte, b2: array of byte): int{	l := len b1;	if (l < len b2)		return int -b2[l];	if (l > len b2)		return int b1[l];	for (i := 0; i < l; i++) {		d := int b1[i] - int b2[i];		if (d != 0)			return d;	}	return 0;} memncpy(out: array of byte, in: array of byte){	if (in == nil)		return;	l := len in;	if (l > len out)		l = len out;	out[0 :] = in[0 : l];} memset(out: array of byte, val: byte){	for (l := 0; l < len out; l++)		out[l] = val;} dhcpsend(dfd: ref Sys->FD, dhcp: ref Dhcp){	buf := array[576] of byte;	buf[0] = byte dhcp.op;	buf[1] = byte dhcp.htype;	buf[2] = byte len dhcp.chaddr;	buf[3] = byte dhcp.hops;	nboputl(buf[4 : 8], dhcp.xid);	nboputs(buf[8 : 10], dhcp.secs);	nboputs(buf[10 : 12], dhcp.flags);	nboputl(buf[12 : 16], dhcp.ciaddr);	nboputl(buf[16 : 20], dhcp.yiaddr);	nboputl(buf[20 : 24], dhcp.siaddr);	nboputl(buf[24 : 28], dhcp.giaddr);	memset(buf[28 :], byte 0);	memncpy(buf[28 : 44], dhcp.chaddr);	memncpy(buf[44 : 108], array of byte dhcp.sname);	memncpy(buf[108 : 236], array of byte dhcp.file);	sys->write(dfd, buf, len buf);} kill(pid: int){	fd := sys->open("#p/" + string pid + "/ctl", sys->OWRITE);	if (fd == nil)		return; 	msg := array of byte "kill";        sys->write(fd, msg, len msg);} ipfmt(ipaddr: int): string{	return sys->sprint("%ud.%ud.%ud.%ud",		(ipaddr >> 24) & 16rff,		(ipaddr >> 16) & 16rff,		(ipaddr >> 8) & 16rff,		ipaddr & 16rff);} dumpdhcp(dhcp: ref Dhcp){	sys->print("op %d htype %d hops %d xid %ud\n", dhcp.op, dhcp.htype, dhcp.hops, dhcp.xid);	sys->print("secs %d flags 0x%.4ux\n", dhcp.secs, dhcp.flags);	sys->print("ciaddr %s\n", ipfmt(dhcp.ciaddr));	sys->print("yiaddr %s\n", ipfmt(dhcp.yiaddr));	sys->print("siaddr %s\n", ipfmt(dhcp.siaddr));	sys->print("giaddr %s\n", ipfmt(dhcp.giaddr));	sys->print("chaddr ");	for (x := 0; x < len dhcp.chaddr; x++)		sys->print("%.2ux", int dhcp.chaddr[x]);	sys->print("\n");	if (dhcp.sname != nil)		sys->print("sname %s\n", dhcp.sname);	if (dhcp.file != nil)		sys->print("file %s\n", dhcp.file);} dhcplisten(pidc: chan of int, fd: ref Sys->FD, dc: chan of ref Dhcp){	pid := sys->pctl(0, nil);	pidc <-= pid;	buf := array [576] of byte;	while (1) {		n := sys->read(fd, buf, len buf);		dhcp := ref Dhcp;		dhcp.op = int buf[0];		dhcp.htype = int buf[1];		hlen := int buf[2];		dhcp.hops = int buf[3];		dhcp.xid = nbogetl(buf[4 : 8]);		dhcp.secs = nbogets(buf[8 : 10]);		dhcp.flags = nbogets(buf[10 : 12]);		dhcp.ciaddr = nbogetl(buf[12 : 16]);		dhcp.yiaddr = nbogetl(buf[16 : 20]);		dhcp.siaddr = nbogetl(buf[20 : 24]);		dhcp.giaddr = nbogetl(buf[24: 28]);		dhcp.chaddr = buf[28 : 28 + hlen];		dhcp.sname = stringget(buf[44 : 108]);		dhcp.file = stringget(buf[108 : 236]);		dc <-= dhcp;	}}	timeoutproc(pid: chan of int, howlong: int, c: chan of string){	pid <-= sys->pctl(0, nil); 	sys->sleep(howlong); 	# send timeout	c <-= "timed out";} tpid := -1;tc: chan of string; timeoutcancel(){	if (tpid >= 0) {		kill(tpid);		tpid = -1;	}} timeoutstart(howlong: int): (chan of string)

Lines 1–500 of 628.