xref: /plan9-contrib/sys/src/9/pcboot/conf.c (revision 426f2a32150b219ea919a1d76cbd0c50d6d55686)
125210b06SDavid du Colombier /*
225210b06SDavid du Colombier  * parse plan.ini or /cfg/pxe/%E file into low memory
325210b06SDavid du Colombier  */
425210b06SDavid du Colombier #include	"u.h"
525210b06SDavid du Colombier #include	"../port/lib.h"
625210b06SDavid du Colombier #include	"mem.h"
725210b06SDavid du Colombier #include	"dat.h"
825210b06SDavid du Colombier #include	"fns.h"
925210b06SDavid du Colombier #include	"io.h"
1025210b06SDavid du Colombier #include	"ureg.h"
1125210b06SDavid du Colombier #include	"pool.h"
1225210b06SDavid du Colombier #include	"../port/netif.h"
1325210b06SDavid du Colombier #include	"../ip/ip.h"
1425210b06SDavid du Colombier #include	"pxe.h"
1525210b06SDavid du Colombier 
1625210b06SDavid du Colombier typedef struct {
1725210b06SDavid du Colombier 	char*	name;
1825210b06SDavid du Colombier 	int	start;
1925210b06SDavid du Colombier 	int	end;
2025210b06SDavid du Colombier } Mblock;
2125210b06SDavid du Colombier 
2225210b06SDavid du Colombier typedef struct {
2325210b06SDavid du Colombier 	char*	tag;
2425210b06SDavid du Colombier 	Mblock*	mb;
2525210b06SDavid du Colombier } Mitem;
2625210b06SDavid du Colombier 
27c1e5ebd3SDavid du Colombier Chan *conschan;
28c1e5ebd3SDavid du Colombier 
2925210b06SDavid du Colombier static Mblock mblock[MAXCONF];
3025210b06SDavid du Colombier static int nmblock;
3125210b06SDavid du Colombier static Mitem mitem[MAXCONF];
3225210b06SDavid du Colombier static int nmitem;
3325210b06SDavid du Colombier static char* mdefault;
3425210b06SDavid du Colombier static char mdefaultbuf[10];
3525210b06SDavid du Colombier static int mtimeout;
3625210b06SDavid du Colombier 
3725210b06SDavid du Colombier static char*
comma(char * line,char ** residue)3825210b06SDavid du Colombier comma(char* line, char** residue)
3925210b06SDavid du Colombier {
4025210b06SDavid du Colombier 	char *q, *r;
4125210b06SDavid du Colombier 
4225210b06SDavid du Colombier 	if((q = strchr(line, ',')) != nil){
4325210b06SDavid du Colombier 		*q++ = 0;
4425210b06SDavid du Colombier 		if(*q == ' ')
4525210b06SDavid du Colombier 			q++;
4625210b06SDavid du Colombier 	}
4725210b06SDavid du Colombier 	*residue = q;
4825210b06SDavid du Colombier 
4925210b06SDavid du Colombier 	if((r = strchr(line, ' ')) != nil)
5025210b06SDavid du Colombier 		*r = 0;
5125210b06SDavid du Colombier 
5225210b06SDavid du Colombier 	if(*line == ' ')
5325210b06SDavid du Colombier 		line++;
5425210b06SDavid du Colombier 	return line;
5525210b06SDavid du Colombier }
5625210b06SDavid du Colombier 
5725210b06SDavid du Colombier static Mblock*
findblock(char * name,char ** residue)5825210b06SDavid du Colombier findblock(char* name, char** residue)
5925210b06SDavid du Colombier {
6025210b06SDavid du Colombier 	int i;
6125210b06SDavid du Colombier 	char *p;
6225210b06SDavid du Colombier 
6325210b06SDavid du Colombier 	p = comma(name, residue);
6425210b06SDavid du Colombier 	for(i = 0; i < nmblock; i++){
6525210b06SDavid du Colombier 		if(strcmp(p, mblock[i].name) == 0)
6625210b06SDavid du Colombier 			return &mblock[i];
6725210b06SDavid du Colombier 	}
6825210b06SDavid du Colombier 	return nil;
6925210b06SDavid du Colombier }
7025210b06SDavid du Colombier 
7125210b06SDavid du Colombier static Mitem*
finditem(char * name,char ** residue)7225210b06SDavid du Colombier finditem(char* name, char** residue)
7325210b06SDavid du Colombier {
7425210b06SDavid du Colombier 	int i;
7525210b06SDavid du Colombier 	char *p;
7625210b06SDavid du Colombier 
7725210b06SDavid du Colombier 	p = comma(name, residue);
7825210b06SDavid du Colombier 	for(i = 0; i < nmitem; i++){
7925210b06SDavid du Colombier 		if(strcmp(p, mitem[i].mb->name) == 0)
8025210b06SDavid du Colombier 			return &mitem[i];
8125210b06SDavid du Colombier 	}
8225210b06SDavid du Colombier 	return nil;
8325210b06SDavid du Colombier }
8425210b06SDavid du Colombier 
8525210b06SDavid du Colombier /* timeout is in seconds */
8625210b06SDavid du Colombier int
getstr(char * prompt,char * buf,int size,char * def,int timeout)8725210b06SDavid du Colombier getstr(char *prompt, char *buf, int size, char *def, int timeout)
8825210b06SDavid du Colombier {
8925210b06SDavid du Colombier 	int len, isdefault;
9025210b06SDavid du Colombier 	static char pbuf[PRINTSIZE];
9125210b06SDavid du Colombier 
9225210b06SDavid du Colombier 	if(conschan == nil)
93c1e5ebd3SDavid du Colombier 		panic("getstr: #c/cons not open");
9425210b06SDavid du Colombier 	buf[0] = 0;
9525210b06SDavid du Colombier 	isdefault = (def && *def);
9625210b06SDavid du Colombier 	if(isdefault == 0){
9725210b06SDavid du Colombier 		timeout = 0;
9825210b06SDavid du Colombier 		snprint(pbuf, sizeof pbuf, "%s: ", prompt);
9925210b06SDavid du Colombier 	}
10025210b06SDavid du Colombier 	else if(timeout)
10125210b06SDavid du Colombier 		snprint(pbuf, sizeof pbuf, "%s[default==%s (%ds timeout)]: ",
10225210b06SDavid du Colombier 			prompt, def, timeout);
10325210b06SDavid du Colombier 	else
10425210b06SDavid du Colombier 		snprint(pbuf, sizeof pbuf, "%s[default==%s]: ", prompt, def);
10525210b06SDavid du Colombier 	for (;;) {
10625210b06SDavid du Colombier 		print("%s", pbuf);
10725210b06SDavid du Colombier 		if (timeout > 0) {
10825210b06SDavid du Colombier 			for(timeout *= 1000; timeout > 0; timeout -= 100) {
10925210b06SDavid du Colombier 				if (qlen(kbdq) > 0)	/* if input queued */
11025210b06SDavid du Colombier 					break;
111c1e5ebd3SDavid du Colombier 				tsleep(&up->sleep, return0, 0, 100);
11225210b06SDavid du Colombier 			}
11325210b06SDavid du Colombier 			if (timeout <= 0) {		/* use default */
11425210b06SDavid du Colombier 				print("\n");
11525210b06SDavid du Colombier 				len = 0;
11625210b06SDavid du Colombier 				break;
11725210b06SDavid du Colombier 			}
11825210b06SDavid du Colombier 		}
11925210b06SDavid du Colombier 		buf[0] = '\0';
12025210b06SDavid du Colombier 		len = devtab[conschan->type]->read(conschan, buf, size - 1,
12125210b06SDavid du Colombier 			conschan->offset);
12225210b06SDavid du Colombier 		if(len >= 0)
12325210b06SDavid du Colombier 			buf[len] = '\0';
12425210b06SDavid du Colombier 		switch(len){
12525210b06SDavid du Colombier 		case 0:				/* eof */
12625210b06SDavid du Colombier 		case 1:				/* newline */
12725210b06SDavid du Colombier 			len = 0;
12825210b06SDavid du Colombier 			buf[len] = '\0';
12925210b06SDavid du Colombier 			if(!isdefault)
13025210b06SDavid du Colombier 				continue;
13125210b06SDavid du Colombier 			break;
13225210b06SDavid du Colombier 		}
13325210b06SDavid du Colombier 		if(len < size - 1)
13425210b06SDavid du Colombier 			break;
13525210b06SDavid du Colombier 		print("line too long\n");
13625210b06SDavid du Colombier 	}
13725210b06SDavid du Colombier 	if(len == 0 && isdefault)
13825210b06SDavid du Colombier 		strncpy(buf, def, size);
13925210b06SDavid du Colombier 	return 0;
14025210b06SDavid du Colombier }
14125210b06SDavid du Colombier 
142e4575fb1SDavid du Colombier void
askbootfile(char * buf,int len,char ** bootfp,int secs,char * def)143e4575fb1SDavid du Colombier askbootfile(char *buf, int len, char **bootfp, int secs, char *def)
144e4575fb1SDavid du Colombier {
145e4575fb1SDavid du Colombier 	getstr("\nBoot from", buf, len, def, secs);
146e4575fb1SDavid du Colombier 	trimnl(buf);
147e4575fb1SDavid du Colombier 	if (bootfp)
148e4575fb1SDavid du Colombier 		kstrdup(bootfp, buf);
149e4575fb1SDavid du Colombier }
150e4575fb1SDavid du Colombier 
15125210b06SDavid du Colombier int
isconf(char * name)15225210b06SDavid du Colombier isconf(char *name)
15325210b06SDavid du Colombier {
15425210b06SDavid du Colombier 	int i;
15525210b06SDavid du Colombier 
15625210b06SDavid du Colombier 	for(i = 0; i < nconf; i++)
15725210b06SDavid du Colombier 		if(cistrcmp(confname[i], name) == 0)
15825210b06SDavid du Colombier 			return 1;
15925210b06SDavid du Colombier 	return 0;
16025210b06SDavid du Colombier }
16125210b06SDavid du Colombier 
162e4575fb1SDavid du Colombier /* result is not malloced, unlike user-mode getenv() */
16325210b06SDavid du Colombier char*
getconf(char * name)16425210b06SDavid du Colombier getconf(char *name)
16525210b06SDavid du Colombier {
16625210b06SDavid du Colombier 	int i, n, nmatch;
16725210b06SDavid du Colombier 	char buf[120];
16825210b06SDavid du Colombier 
16925210b06SDavid du Colombier 	nmatch = 0;
17025210b06SDavid du Colombier 	for(i = 0; i < nconf; i++)
17125210b06SDavid du Colombier 		if(cistrcmp(confname[i], name) == 0)
17225210b06SDavid du Colombier 			nmatch++;
17325210b06SDavid du Colombier 
17425210b06SDavid du Colombier 	switch(nmatch) {
17525210b06SDavid du Colombier 	default:
17625210b06SDavid du Colombier 		print("\n");
17725210b06SDavid du Colombier 		nmatch = 0;
17825210b06SDavid du Colombier 		for(i = 0; i < nconf; i++)
17925210b06SDavid du Colombier 			if(cistrcmp(confname[i], name) == 0)
18025210b06SDavid du Colombier 				print("%d. %s\n", ++nmatch, confval[i]);
18125210b06SDavid du Colombier 		print("%d. none of the above\n", ++nmatch);
18225210b06SDavid du Colombier 		do {
18325210b06SDavid du Colombier 			getstr(name, buf, sizeof(buf), nil, 0);
18425210b06SDavid du Colombier 			n = atoi(buf);
18525210b06SDavid du Colombier 		} while(n < 1 || n > nmatch);
18625210b06SDavid du Colombier 
18725210b06SDavid du Colombier 		for(i = 0; i < nconf; i++)
18825210b06SDavid du Colombier 			if(cistrcmp(confname[i], name) == 0)
18925210b06SDavid du Colombier 				if(--n == 0)
19025210b06SDavid du Colombier 					return confval[i];
19125210b06SDavid du Colombier 		break;
19225210b06SDavid du Colombier 
19325210b06SDavid du Colombier 	case 1:
19425210b06SDavid du Colombier 		for(i = 0; i < nconf; i++)
19525210b06SDavid du Colombier 			if(cistrcmp(confname[i], name) == 0)
19625210b06SDavid du Colombier 				return confval[i];
19725210b06SDavid du Colombier 		break;
19825210b06SDavid du Colombier 
19925210b06SDavid du Colombier 	case 0:
20025210b06SDavid du Colombier 		break;
20125210b06SDavid du Colombier 	}
20225210b06SDavid du Colombier 	return nil;
20325210b06SDavid du Colombier }
20425210b06SDavid du Colombier 
20525210b06SDavid du Colombier static void
parsemenu(char * str,char * scratch,int len)20625210b06SDavid du Colombier parsemenu(char* str, char* scratch, int len)
20725210b06SDavid du Colombier {
20825210b06SDavid du Colombier 	Mitem *mi;
20925210b06SDavid du Colombier 	Mblock *mb, *menu;
21025210b06SDavid du Colombier 	char buf[20], *p, *q, *line[MAXCONF];
21125210b06SDavid du Colombier 	int i, inblock, n, show;
21225210b06SDavid du Colombier 
21325210b06SDavid du Colombier 	inblock = 0;
21425210b06SDavid du Colombier 	menu = nil;
21525210b06SDavid du Colombier 	memmove(scratch, str, len);
21625210b06SDavid du Colombier 	n = getfields(scratch, line, MAXCONF, 0, "\n");
21725210b06SDavid du Colombier 	if(n >= MAXCONF)
21825210b06SDavid du Colombier 		print("warning: possibly too many lines in plan9.ini\n");
21925210b06SDavid du Colombier 	for(i = 0; i < n; i++){
22025210b06SDavid du Colombier 		p = line[i];
22125210b06SDavid du Colombier 		if(inblock && *p == '['){
22225210b06SDavid du Colombier 			mblock[nmblock].end = i;
22325210b06SDavid du Colombier 			if(strcmp(mblock[nmblock].name, "menu") == 0)
22425210b06SDavid du Colombier 				menu = &mblock[nmblock];
22525210b06SDavid du Colombier 			nmblock++;
22625210b06SDavid du Colombier 			inblock = 0;
22725210b06SDavid du Colombier 		}
22825210b06SDavid du Colombier 		if(*p == '['){
22925210b06SDavid du Colombier 			if(nmblock == 0 && i != 0){
23025210b06SDavid du Colombier 				mblock[nmblock].name = "common";
23125210b06SDavid du Colombier 				mblock[nmblock].start = 0;
23225210b06SDavid du Colombier 				mblock[nmblock].end = i;
23325210b06SDavid du Colombier 				nmblock++;
23425210b06SDavid du Colombier 			}
23525210b06SDavid du Colombier 			q = strchr(p+1, ']');
23625210b06SDavid du Colombier 			if(q == nil || *(q+1) != 0){
23725210b06SDavid du Colombier 				print("malformed menu block header - %s\n", p);
23825210b06SDavid du Colombier 				return;
23925210b06SDavid du Colombier 			}
24025210b06SDavid du Colombier 			*q = 0;
24125210b06SDavid du Colombier 			mblock[nmblock].name = p+1;
24225210b06SDavid du Colombier 			mblock[nmblock].start = i+1;
24325210b06SDavid du Colombier 			inblock = 1;
24425210b06SDavid du Colombier 		}
24525210b06SDavid du Colombier 	}
24625210b06SDavid du Colombier 
24725210b06SDavid du Colombier 	if(inblock){
24825210b06SDavid du Colombier 		mblock[nmblock].end = i;
24925210b06SDavid du Colombier 		nmblock++;
25025210b06SDavid du Colombier 	}
25125210b06SDavid du Colombier 	if(menu == nil)
25225210b06SDavid du Colombier 		return;
25325210b06SDavid du Colombier 	if(nmblock < 2){
25425210b06SDavid du Colombier 		print("incomplete menu specification\n");
25525210b06SDavid du Colombier 		return;
25625210b06SDavid du Colombier 	}
25725210b06SDavid du Colombier 
25825210b06SDavid du Colombier 	for(i = menu->start; i < menu->end; i++){
25925210b06SDavid du Colombier 		p = line[i];
26025210b06SDavid du Colombier 		if(cistrncmp(p, "menuitem=", 9) == 0){
26125210b06SDavid du Colombier 			p += 9;
26225210b06SDavid du Colombier 			if((mb = findblock(p, &q)) == nil){
26325210b06SDavid du Colombier 				print("no block for menuitem %s\n", p);
26425210b06SDavid du Colombier 				return;
26525210b06SDavid du Colombier 			}
26625210b06SDavid du Colombier 			if(q != nil)
26725210b06SDavid du Colombier 				mitem[nmitem].tag = q;
26825210b06SDavid du Colombier 			else
26925210b06SDavid du Colombier 				mitem[nmitem].tag = mb->name;
27025210b06SDavid du Colombier 			mitem[nmitem].mb = mb;
27125210b06SDavid du Colombier 			nmitem++;
27225210b06SDavid du Colombier 		}
27325210b06SDavid du Colombier 		else if(cistrncmp(p, "menudefault=", 12) == 0){
27425210b06SDavid du Colombier 			p += 12;
27525210b06SDavid du Colombier 			if((mi = finditem(p, &q)) == nil){
27625210b06SDavid du Colombier 				print("no item for menudefault %s\n", p);
27725210b06SDavid du Colombier 				return;
27825210b06SDavid du Colombier 			}
27925210b06SDavid du Colombier 			if(q != nil)
28025210b06SDavid du Colombier 				mtimeout = strtol(q, 0, 0);
28125210b06SDavid du Colombier 			snprint(mdefaultbuf, sizeof mdefaultbuf, "%ld",
28225210b06SDavid du Colombier 				mi-mitem+1);
28325210b06SDavid du Colombier 			mdefault = mdefaultbuf;
28425210b06SDavid du Colombier 		}
28525210b06SDavid du Colombier 		else if(cistrncmp(p, "menuconsole=", 12) == 0){
28625210b06SDavid du Colombier 			p += 12;
28725210b06SDavid du Colombier 			p = comma(p, &q);
28825210b06SDavid du Colombier 			i8250config(p);
28925210b06SDavid du Colombier 		}
29025210b06SDavid du Colombier 		else{
29125210b06SDavid du Colombier 			print("invalid line in [menu] block - %s\n", p);
29225210b06SDavid du Colombier 			return;
29325210b06SDavid du Colombier 		}
29425210b06SDavid du Colombier 	}
29525210b06SDavid du Colombier 
29625210b06SDavid du Colombier again:
29725210b06SDavid du Colombier 	print("\nPlan 9 Startup Menu:\n====================\n");
29825210b06SDavid du Colombier 	for(i = 0; i < nmitem; i++)
29925210b06SDavid du Colombier 		print("    %d. %s\n", i+1, mitem[i].tag);
30025210b06SDavid du Colombier 	for(;;){
30125210b06SDavid du Colombier 		getstr("Selection", buf, sizeof(buf), mdefault, mtimeout);
30225210b06SDavid du Colombier 		mtimeout = 0;
30325210b06SDavid du Colombier 		i = strtol(buf, &p, 0)-1;
30425210b06SDavid du Colombier 		if(i < 0 || i >= nmitem)
30525210b06SDavid du Colombier 			goto again;
30625210b06SDavid du Colombier 		switch(*p){
30725210b06SDavid du Colombier 		case 'p':
30825210b06SDavid du Colombier 		case 'P':
30925210b06SDavid du Colombier 			show = 1;
31025210b06SDavid du Colombier 			print("\n");
31125210b06SDavid du Colombier 			break;
31225210b06SDavid du Colombier 		case 0:
31325210b06SDavid du Colombier 		case '\n':
31425210b06SDavid du Colombier 			show = 0;
31525210b06SDavid du Colombier 			break;
31625210b06SDavid du Colombier 		default:
31725210b06SDavid du Colombier 			continue;
31825210b06SDavid du Colombier 
31925210b06SDavid du Colombier 		}
32025210b06SDavid du Colombier 		mi = &mitem[i];
32125210b06SDavid du Colombier 
32225210b06SDavid du Colombier 		p = str;
323*426f2a32SDavid du Colombier 		p += snprint(p, len, "menuitem=%s\n", mi->mb->name);
32425210b06SDavid du Colombier 		for(i = 0; i < nmblock; i++){
32525210b06SDavid du Colombier 			mb = &mblock[i];
32625210b06SDavid du Colombier 			if(mi->mb != mb && cistrcmp(mb->name, "common") != 0)
32725210b06SDavid du Colombier 				continue;
32825210b06SDavid du Colombier 			for(n = mb->start; n < mb->end; n++)
329*426f2a32SDavid du Colombier 				p += snprint(p, &str[len] - p, "%s\n", line[n]);
33025210b06SDavid du Colombier 		}
33125210b06SDavid du Colombier 
33225210b06SDavid du Colombier 		if(show){
33325210b06SDavid du Colombier 			for(q = str; q < p; q += i){
33425210b06SDavid du Colombier 				if((i = print(q)) <= 0)
33525210b06SDavid du Colombier 					break;
33625210b06SDavid du Colombier 			}
33725210b06SDavid du Colombier 			goto again;
33825210b06SDavid du Colombier 		}
33925210b06SDavid du Colombier 		break;
34025210b06SDavid du Colombier 	}
34125210b06SDavid du Colombier 	print("\n");
34225210b06SDavid du Colombier }
34325210b06SDavid du Colombier 
34425210b06SDavid du Colombier /* dig out tables created by l16r.s in real mode */
34525210b06SDavid du Colombier void
readlsconf(void)34625210b06SDavid du Colombier readlsconf(void)
34725210b06SDavid du Colombier {
34825210b06SDavid du Colombier 	int i, n;
34925210b06SDavid du Colombier 	uchar *p;
35025210b06SDavid du Colombier 	MMap *map;
35125210b06SDavid du Colombier 	u64int addr, len;
35225210b06SDavid du Colombier 
35325210b06SDavid du Colombier 	/*
35425210b06SDavid du Colombier 	 * we could be running above 1MB, so put bios tables in low memory,
35525210b06SDavid du Colombier 	 * not after end.
35625210b06SDavid du Colombier 	 */
35725210b06SDavid du Colombier 	p = (uchar*)KADDR(BIOSTABLES);
35825210b06SDavid du Colombier 	for(n = 0; n < nelem(mmap); n++){
35925210b06SDavid du Colombier 		if(*p == 0)
36025210b06SDavid du Colombier 			break;
36125210b06SDavid du Colombier 		if(memcmp(p, "APM\0", 4) == 0){
36225210b06SDavid du Colombier 			p += 20;
36325210b06SDavid du Colombier 			continue;
36425210b06SDavid du Colombier 		}
36525210b06SDavid du Colombier 		else if(memcmp(p, "MAP\0", 4) == 0){
36625210b06SDavid du Colombier 			map = (MMap*)p;
36725210b06SDavid du Colombier 
36825210b06SDavid du Colombier 			switch(map->type){
36925210b06SDavid du Colombier 			default:
37025210b06SDavid du Colombier 				if(v_flag)
37125210b06SDavid du Colombier 					print("type %ud", map->type);
37225210b06SDavid du Colombier 				break;
37325210b06SDavid du Colombier 			case 1:
37425210b06SDavid du Colombier 				if(v_flag)
37525210b06SDavid du Colombier 					print("Memory");
37625210b06SDavid du Colombier 				break;
37725210b06SDavid du Colombier 			case 2:
37825210b06SDavid du Colombier 				if(v_flag)
37925210b06SDavid du Colombier 					print("reserved");
38025210b06SDavid du Colombier 				break;
38125210b06SDavid du Colombier 			case 3:
38225210b06SDavid du Colombier 				if(v_flag)
38325210b06SDavid du Colombier 					print("ACPI Reclaim Memory");
38425210b06SDavid du Colombier 				break;
38525210b06SDavid du Colombier 			case 4:
38625210b06SDavid du Colombier 				if(v_flag)
38725210b06SDavid du Colombier 					print("ACPI NVS Memory");
38825210b06SDavid du Colombier 				break;
38925210b06SDavid du Colombier 			}
39025210b06SDavid du Colombier 			addr = (((u64int)map->base[1])<<32)|map->base[0];
39125210b06SDavid du Colombier 			len = (((u64int)map->length[1])<<32)|map->length[0];
39225210b06SDavid du Colombier 			if(v_flag)
39325210b06SDavid du Colombier 				print("\t%#16.16lluX %#16.16lluX (%llud)\n",
39425210b06SDavid du Colombier 					addr, addr+len, len);
39525210b06SDavid du Colombier 
39625210b06SDavid du Colombier 			if(nmmap < nelem(mmap)){
39725210b06SDavid du Colombier 				memmove(&mmap[nmmap], map, sizeof(MMap));
39825210b06SDavid du Colombier 				mmap[nmmap].size = 20;
39925210b06SDavid du Colombier 				nmmap++;
40025210b06SDavid du Colombier 			}
40125210b06SDavid du Colombier 			p += 24;
40225210b06SDavid du Colombier 			continue;
40325210b06SDavid du Colombier 		}
40425210b06SDavid du Colombier 		else{
40525210b06SDavid du Colombier 			 /* ideally we shouldn't print here */
40625210b06SDavid du Colombier 			print("\nweird low-memory map at %#p:\n", p);
40725210b06SDavid du Colombier 			for(i = 0; i < 24; i++)
40825210b06SDavid du Colombier 				print(" %2.2uX", *(p+i));
40925210b06SDavid du Colombier 			print("\n");
41025210b06SDavid du Colombier 			delay(5000);
41125210b06SDavid du Colombier 		}
41225210b06SDavid du Colombier 		break;
41325210b06SDavid du Colombier 	}
41425210b06SDavid du Colombier }
41525210b06SDavid du Colombier 
41625210b06SDavid du Colombier void
addconf(char * fmt,...)41725210b06SDavid du Colombier addconf(char *fmt, ...)
41825210b06SDavid du Colombier {
41925210b06SDavid du Colombier 	va_list arg;
42025210b06SDavid du Colombier 
42125210b06SDavid du Colombier 	va_start(arg, fmt);
42225210b06SDavid du Colombier 	vseprint(BOOTARGS+strlen(BOOTARGS), BOOTARGS+BOOTARGSLEN, fmt, arg);
42325210b06SDavid du Colombier 	va_end(arg);
42425210b06SDavid du Colombier }
42525210b06SDavid du Colombier 
42625210b06SDavid du Colombier void
dumpbootargs(void)42725210b06SDavid du Colombier dumpbootargs(void)
42825210b06SDavid du Colombier {
42925210b06SDavid du Colombier 	char *p, *nl;
43025210b06SDavid du Colombier 
43125210b06SDavid du Colombier 	/* in the boot, we can only print PRINTSIZE (256) bytes at a time. */
43225210b06SDavid du Colombier 	print("boot args: ");
43325210b06SDavid du Colombier 	for (p = (char *)BOOTARGS; *p != '\0'; p = nl) {
43425210b06SDavid du Colombier 		nl = strchr(p, '\n');
43525210b06SDavid du Colombier 		if (nl != nil) {
43625210b06SDavid du Colombier 			++nl;
43725210b06SDavid du Colombier 			print("%.*s", (int)(nl - p), p);
43825210b06SDavid du Colombier 		}
43925210b06SDavid du Colombier 	}
44025210b06SDavid du Colombier }
44125210b06SDavid du Colombier 
44225210b06SDavid du Colombier void
changeconf(char * fmt,...)44325210b06SDavid du Colombier changeconf(char *fmt, ...)
44425210b06SDavid du Colombier {
44525210b06SDavid du Colombier 	va_list arg;
44625210b06SDavid du Colombier 	char *p, *q, pref[20], buf[128];
44725210b06SDavid du Colombier 
44825210b06SDavid du Colombier 	va_start(arg, fmt);
44925210b06SDavid du Colombier 	vseprint(buf, buf+sizeof buf, fmt, arg);
45025210b06SDavid du Colombier 	va_end(arg);
45125210b06SDavid du Colombier 
45225210b06SDavid du Colombier 	pref[0] = '\n';
45325210b06SDavid du Colombier 	strncpy(pref+1, buf, 19);
45425210b06SDavid du Colombier 	pref[19] = '\0';
45525210b06SDavid du Colombier 	if(p = strchr(pref, '='))
45625210b06SDavid du Colombier 		*(p+1) = '\0';
45725210b06SDavid du Colombier 	else
45825210b06SDavid du Colombier 		print("warning: did not change %s in plan9.ini\n", buf);
45925210b06SDavid du Colombier 
46025210b06SDavid du Colombier 	/* find old line by looking for \nwhat= */
46125210b06SDavid du Colombier 	if(strncmp(BOOTARGS, pref+1, strlen(pref+1)) == 0)
46225210b06SDavid du Colombier 		p = BOOTARGS;
46325210b06SDavid du Colombier 	else if(p = strstr(BOOTARGS, pref))
46425210b06SDavid du Colombier 		p++;
46525210b06SDavid du Colombier 	else
46625210b06SDavid du Colombier 		p = nil;
46725210b06SDavid du Colombier 
46825210b06SDavid du Colombier 	/* move rest of args up, deleting what= line. */
46925210b06SDavid du Colombier 	if(p != nil && (q = strchr(p, '\n')) != nil)
47025210b06SDavid du Colombier 		memmove(p, q+1, strlen(q+1)+1);
47125210b06SDavid du Colombier 
47225210b06SDavid du Colombier 	/* add replacement to end */
47325210b06SDavid du Colombier 	addconf("%s", buf);
47425210b06SDavid du Colombier }
47525210b06SDavid du Colombier 
47625210b06SDavid du Colombier /*
47725210b06SDavid du Colombier  *  read configuration file
47825210b06SDavid du Colombier  */
47925210b06SDavid du Colombier static char id[8] = "ZORT 0\r\n";
48025210b06SDavid du Colombier 
48125210b06SDavid du Colombier int
dotini(char * inibuf)48225210b06SDavid du Colombier dotini(char *inibuf)
48325210b06SDavid du Colombier {
48425210b06SDavid du Colombier 	int blankline, i, incomment, inspace, n;
48525210b06SDavid du Colombier 	char *cp, *p, *q, *line[MAXCONF];
48625210b06SDavid du Colombier 
48725210b06SDavid du Colombier 	cp = inibuf;
48825210b06SDavid du Colombier 
48925210b06SDavid du Colombier 	/*
49025210b06SDavid du Colombier 	 * Strip out '\r', change '\t' -> ' '.
49125210b06SDavid du Colombier 	 * Change runs of spaces into single spaces.
49225210b06SDavid du Colombier 	 * Strip out trailing spaces, blank lines.
49325210b06SDavid du Colombier 	 *
49425210b06SDavid du Colombier 	 * We do this before we make the copy so that if we
49525210b06SDavid du Colombier 	 * need to change the copy, it is already fairly clean.
49625210b06SDavid du Colombier 	 * The main need is in the case when plan9.ini has been
49725210b06SDavid du Colombier 	 * padded with lots of trailing spaces, as is the case
49825210b06SDavid du Colombier 	 * for those created during a distribution install.
49925210b06SDavid du Colombier 	 */
50025210b06SDavid du Colombier 	p = cp;
50125210b06SDavid du Colombier 	blankline = 1;
50225210b06SDavid du Colombier 	incomment = inspace = 0;
50325210b06SDavid du Colombier 	for(q = cp; *q; q++){
50425210b06SDavid du Colombier 		if(*q == '\r')
50525210b06SDavid du Colombier 			continue;
50625210b06SDavid du Colombier 		if(*q == '\t')
50725210b06SDavid du Colombier 			*q = ' ';
50825210b06SDavid du Colombier 		if(*q == ' '){
50925210b06SDavid du Colombier 			inspace = 1;
51025210b06SDavid du Colombier 			continue;
51125210b06SDavid du Colombier 		}
51225210b06SDavid du Colombier 		if(*q == '\n'){
51325210b06SDavid du Colombier 			if(!blankline){
51425210b06SDavid du Colombier 				if(!incomment)
51525210b06SDavid du Colombier 					*p++ = '\n';
51625210b06SDavid du Colombier 				blankline = 1;
51725210b06SDavid du Colombier 			}
51825210b06SDavid du Colombier 			incomment = inspace = 0;
51925210b06SDavid du Colombier 			continue;
52025210b06SDavid du Colombier 		}
52125210b06SDavid du Colombier 		if(inspace){
52225210b06SDavid du Colombier 			if(!blankline && !incomment)
52325210b06SDavid du Colombier 				*p++ = ' ';
52425210b06SDavid du Colombier 			inspace = 0;
52525210b06SDavid du Colombier 		}
52625210b06SDavid du Colombier 		if(blankline && *q == '#')
52725210b06SDavid du Colombier 			incomment = 1;
52825210b06SDavid du Colombier 		blankline = 0;
52925210b06SDavid du Colombier 		if(!incomment)
53025210b06SDavid du Colombier 			*p++ = *q;
53125210b06SDavid du Colombier 	}
53225210b06SDavid du Colombier 	if(p > cp && p[-1] != '\n')
53325210b06SDavid du Colombier 		*p++ = '\n';
53425210b06SDavid du Colombier 	*p++ = 0;
53525210b06SDavid du Colombier 	n = p-cp;
53625210b06SDavid du Colombier 
53725210b06SDavid du Colombier 	parsemenu(cp, BOOTARGS, n);
53825210b06SDavid du Colombier 
53925210b06SDavid du Colombier 	/*
54025210b06SDavid du Colombier 	 * Keep a copy.
54125210b06SDavid du Colombier 	 * We could change this to pass the parsed strings
54225210b06SDavid du Colombier 	 * to the booted programme instead of the raw
54325210b06SDavid du Colombier 	 * string, then it only gets done once.
54425210b06SDavid du Colombier 	 */
54525210b06SDavid du Colombier 	if(strncmp(cp, id, sizeof(id))){
54625210b06SDavid du Colombier 		memmove(BOOTARGS, id, sizeof(id));
54725210b06SDavid du Colombier 		if(n+1+sizeof(id) >= BOOTARGSLEN)
54825210b06SDavid du Colombier 			n -= sizeof(id);
54925210b06SDavid du Colombier 		memmove(BOOTARGS+sizeof(id), cp, n+1);
55025210b06SDavid du Colombier 	}
55125210b06SDavid du Colombier 	else
55225210b06SDavid du Colombier 		memmove(BOOTARGS, cp, n+1);
55325210b06SDavid du Colombier 
55425210b06SDavid du Colombier 	n = getfields(cp, line, MAXCONF, 0, "\n");
55525210b06SDavid du Colombier 	for(i = 0; i < n; i++){
55625210b06SDavid du Colombier 		cp = strchr(line[i], '=');
55725210b06SDavid du Colombier 		if(cp == 0)
55825210b06SDavid du Colombier 			continue;
55925210b06SDavid du Colombier 		*cp++ = 0;
56025210b06SDavid du Colombier 		if(cp - line[i] >= NAMELEN+1)
56125210b06SDavid du Colombier 			*(line[i]+NAMELEN-1) = 0;
56225210b06SDavid du Colombier 		confname[nconf] = line[i];
56325210b06SDavid du Colombier 		confval[nconf] = cp;
56425210b06SDavid du Colombier 		nconf++;
56525210b06SDavid du Colombier 	}
56625210b06SDavid du Colombier 	return 0;
56725210b06SDavid du Colombier }
568