xref: /minix3/sys/arch/i386/stand/lib/bootmenu.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: bootmenu.c,v 1.11 2013/07/28 08:50:09 he Exp $	*/
258a2b000SEvgeniy Ivanov 
358a2b000SEvgeniy Ivanov /*-
458a2b000SEvgeniy Ivanov  * Copyright (c) 2008 The NetBSD Foundation, Inc.
558a2b000SEvgeniy Ivanov  * All rights reserved.
658a2b000SEvgeniy Ivanov  *
758a2b000SEvgeniy Ivanov  * Redistribution and use in source and binary forms, with or without
858a2b000SEvgeniy Ivanov  * modification, are permitted provided that the following conditions
958a2b000SEvgeniy Ivanov  * are met:
1058a2b000SEvgeniy Ivanov  * 1. Redistributions of source code must retain the above copyright
1158a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer.
1258a2b000SEvgeniy Ivanov  * 2. Redistributions in binary form must reproduce the above copyright
1358a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer in the
1458a2b000SEvgeniy Ivanov  *    documentation and/or other materials provided with the distribution.
1558a2b000SEvgeniy Ivanov  *
1658a2b000SEvgeniy Ivanov  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1758a2b000SEvgeniy Ivanov  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1858a2b000SEvgeniy Ivanov  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1958a2b000SEvgeniy Ivanov  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2058a2b000SEvgeniy Ivanov  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2158a2b000SEvgeniy Ivanov  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2258a2b000SEvgeniy Ivanov  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2358a2b000SEvgeniy Ivanov  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2458a2b000SEvgeniy Ivanov  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2558a2b000SEvgeniy Ivanov  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2658a2b000SEvgeniy Ivanov  * POSSIBILITY OF SUCH DAMAGE.
2758a2b000SEvgeniy Ivanov  */
2858a2b000SEvgeniy Ivanov 
2958a2b000SEvgeniy Ivanov #ifndef SMALL
3058a2b000SEvgeniy Ivanov 
3158a2b000SEvgeniy Ivanov #include <sys/types.h>
3258a2b000SEvgeniy Ivanov #include <sys/reboot.h>
3358a2b000SEvgeniy Ivanov #include <sys/bootblock.h>
3458a2b000SEvgeniy Ivanov 
3558a2b000SEvgeniy Ivanov #include <lib/libsa/stand.h>
3658a2b000SEvgeniy Ivanov #include <lib/libsa/ufs.h>
3758a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
3858a2b000SEvgeniy Ivanov 
3958a2b000SEvgeniy Ivanov #include <libi386.h>
4058a2b000SEvgeniy Ivanov #include <bootmenu.h>
4158a2b000SEvgeniy Ivanov 
4258a2b000SEvgeniy Ivanov #define isnum(c) ((c) >= '0' && (c) <= '9')
4358a2b000SEvgeniy Ivanov 
44*84d9c625SLionel Sambuc static void docommandchoice(int);
45*84d9c625SLionel Sambuc 
4658a2b000SEvgeniy Ivanov extern struct x86_boot_params boot_params;
4758a2b000SEvgeniy Ivanov extern	const char bootprog_name[], bootprog_rev[], bootprog_kernrev[];
4858a2b000SEvgeniy Ivanov 
4958a2b000SEvgeniy Ivanov #define MENUFORMAT_AUTO	  0
5058a2b000SEvgeniy Ivanov #define MENUFORMAT_NUMBER 1
5158a2b000SEvgeniy Ivanov #define MENUFORMAT_LETTER 2
5258a2b000SEvgeniy Ivanov 
5358a2b000SEvgeniy Ivanov struct bootconf_def bootconf;
5458a2b000SEvgeniy Ivanov 
5558a2b000SEvgeniy Ivanov int
5658a2b000SEvgeniy Ivanov atoi(const char *in)
5758a2b000SEvgeniy Ivanov {
5858a2b000SEvgeniy Ivanov 	char *c;
5958a2b000SEvgeniy Ivanov 	int ret;
6058a2b000SEvgeniy Ivanov 
6158a2b000SEvgeniy Ivanov 	ret = 0;
6258a2b000SEvgeniy Ivanov 	c = (char *)in;
6358a2b000SEvgeniy Ivanov 	if (*c == '-')
6458a2b000SEvgeniy Ivanov 		c++;
6558a2b000SEvgeniy Ivanov 	for (; isnum(*c); c++)
6658a2b000SEvgeniy Ivanov 		ret = (ret * 10) + (*c - '0');
6758a2b000SEvgeniy Ivanov 
6858a2b000SEvgeniy Ivanov 	return (*in == '-') ? -ret : ret;
6958a2b000SEvgeniy Ivanov }
7058a2b000SEvgeniy Ivanov 
7158a2b000SEvgeniy Ivanov /*
7258a2b000SEvgeniy Ivanov  * This function parses a boot.cfg file in the root of the filesystem
7358a2b000SEvgeniy Ivanov  * (if present) and populates the global boot configuration.
7458a2b000SEvgeniy Ivanov  *
7558a2b000SEvgeniy Ivanov  * The file consists of a number of lines each terminated by \n
7658a2b000SEvgeniy Ivanov  * The lines are in the format keyword=value. There should not be spaces
7758a2b000SEvgeniy Ivanov  * around the = sign.
7858a2b000SEvgeniy Ivanov  *
7958a2b000SEvgeniy Ivanov  * The recognised keywords are:
8058a2b000SEvgeniy Ivanov  * banner: text displayed instead of the normal welcome text
8158a2b000SEvgeniy Ivanov  * menu: Descriptive text:command to use
8258a2b000SEvgeniy Ivanov  * timeout: Timeout in seconds (overrides that set by installboot)
8358a2b000SEvgeniy Ivanov  * default: the default menu option to use if Return is pressed
8458a2b000SEvgeniy Ivanov  * consdev: the console device to use
8558a2b000SEvgeniy Ivanov  * format: how menu choices are displayed: (a)utomatic, (n)umbers or (l)etters
8658a2b000SEvgeniy Ivanov  * clear: whether to clear the screen or not
8758a2b000SEvgeniy Ivanov  *
8858a2b000SEvgeniy Ivanov  * Example boot.cfg file:
8958a2b000SEvgeniy Ivanov  * banner=Welcome to NetBSD
9058a2b000SEvgeniy Ivanov  * banner=Please choose the boot type from the following menu
9158a2b000SEvgeniy Ivanov  * menu=Boot NetBSD:boot netbsd
9258a2b000SEvgeniy Ivanov  * menu=Boot into single user mode:boot netbsd -s
9358a2b000SEvgeniy Ivanov  * menu=:boot hd1a:netbsd -cs
9458a2b000SEvgeniy Ivanov  * menu=Goto boot comand line:prompt
9558a2b000SEvgeniy Ivanov  * timeout=10
9658a2b000SEvgeniy Ivanov  * consdev=com0
9758a2b000SEvgeniy Ivanov  * default=1
9858a2b000SEvgeniy Ivanov */
9958a2b000SEvgeniy Ivanov void
10058a2b000SEvgeniy Ivanov parsebootconf(const char *conf)
10158a2b000SEvgeniy Ivanov {
10258a2b000SEvgeniy Ivanov 	char *bc, *c;
10358a2b000SEvgeniy Ivanov 	int cmenu, cbanner, len;
10458a2b000SEvgeniy Ivanov 	int fd, err, off;
10558a2b000SEvgeniy Ivanov 	struct stat st;
10658a2b000SEvgeniy Ivanov 	char *next, *key, *value, *v2;
10758a2b000SEvgeniy Ivanov 
10858a2b000SEvgeniy Ivanov 	/* Clear bootconf structure */
10958a2b000SEvgeniy Ivanov 	memset((void *)&bootconf, 0, sizeof(bootconf));
11058a2b000SEvgeniy Ivanov 
11158a2b000SEvgeniy Ivanov 	/* Set timeout to configured */
11258a2b000SEvgeniy Ivanov 	bootconf.timeout = boot_params.bp_timeout;
11358a2b000SEvgeniy Ivanov 
11458a2b000SEvgeniy Ivanov 	/* automatically switch between letter and numbers on menu */
11558a2b000SEvgeniy Ivanov 	bootconf.menuformat = MENUFORMAT_AUTO;
11658a2b000SEvgeniy Ivanov 
11758a2b000SEvgeniy Ivanov 	fd = open(BOOTCONF, 0);
11858a2b000SEvgeniy Ivanov 	if (fd < 0)
11958a2b000SEvgeniy Ivanov 		return;
12058a2b000SEvgeniy Ivanov 
12158a2b000SEvgeniy Ivanov 	err = fstat(fd, &st);
12258a2b000SEvgeniy Ivanov 	if (err == -1) {
12358a2b000SEvgeniy Ivanov 		close(fd);
12458a2b000SEvgeniy Ivanov 		return;
12558a2b000SEvgeniy Ivanov 	}
12658a2b000SEvgeniy Ivanov 
12758a2b000SEvgeniy Ivanov 	/*
12858a2b000SEvgeniy Ivanov 	 * Check the size. A bootconf file is normally only a few
12958a2b000SEvgeniy Ivanov 	 * hundred bytes long. If it is much bigger than expected,
13058a2b000SEvgeniy Ivanov 	 * don't try to load it. We can't load something big into
13158a2b000SEvgeniy Ivanov 	 * an 8086 real mode segment anyway, and in pxeboot this is
13258a2b000SEvgeniy Ivanov 	 * probably a case of the loader getting a filename for the
13358a2b000SEvgeniy Ivanov 	 * kernel and thinking it is boot.cfg by accident. (The 32k
13458a2b000SEvgeniy Ivanov 	 * number is arbitrary but 8086 real mode data segments max
13558a2b000SEvgeniy Ivanov 	 * out at 64k.)
13658a2b000SEvgeniy Ivanov 	 */
13758a2b000SEvgeniy Ivanov 	if (st.st_size > 32768) {
13858a2b000SEvgeniy Ivanov 		close(fd);
13958a2b000SEvgeniy Ivanov 		return;
14058a2b000SEvgeniy Ivanov 	}
14158a2b000SEvgeniy Ivanov 
14258a2b000SEvgeniy Ivanov 	bc = alloc(st.st_size + 1);
14358a2b000SEvgeniy Ivanov 	if (bc == NULL) {
14458a2b000SEvgeniy Ivanov 		printf("Could not allocate memory for boot configuration\n");
14558a2b000SEvgeniy Ivanov 		return;
14658a2b000SEvgeniy Ivanov 	}
14758a2b000SEvgeniy Ivanov 
14858a2b000SEvgeniy Ivanov 	off = 0;
14958a2b000SEvgeniy Ivanov 	do {
15058a2b000SEvgeniy Ivanov 		len = read(fd, bc + off, 1024);
15158a2b000SEvgeniy Ivanov 		if (len <= 0)
15258a2b000SEvgeniy Ivanov 			break;
15358a2b000SEvgeniy Ivanov 		off += len;
15458a2b000SEvgeniy Ivanov 	} while (len > 0);
15558a2b000SEvgeniy Ivanov 	bc[off] = '\0';
15658a2b000SEvgeniy Ivanov 
15758a2b000SEvgeniy Ivanov 	close(fd);
15858a2b000SEvgeniy Ivanov 	/* bc now contains the whole boot.cfg file */
15958a2b000SEvgeniy Ivanov 
16058a2b000SEvgeniy Ivanov 	cmenu = 0;
16158a2b000SEvgeniy Ivanov 	cbanner = 0;
16258a2b000SEvgeniy Ivanov 	for (c = bc; *c; c = next) {
16358a2b000SEvgeniy Ivanov 		key = c;
16458a2b000SEvgeniy Ivanov 		/* find end of line */
16558a2b000SEvgeniy Ivanov 		for (; *c && *c != '\n'; c++)
16658a2b000SEvgeniy Ivanov 			/* zero terminate line on start of comment */
16758a2b000SEvgeniy Ivanov 			if (*c == '#')
16858a2b000SEvgeniy Ivanov 				*c = 0;
16958a2b000SEvgeniy Ivanov 		/* zero terminate line */
17058a2b000SEvgeniy Ivanov 		if (*(next = c))
17158a2b000SEvgeniy Ivanov 			*next++ = 0;
17258a2b000SEvgeniy Ivanov 		/* Look for = separator between key and value */
17358a2b000SEvgeniy Ivanov 		for (c = key; *c && *c != '='; c++)
17458a2b000SEvgeniy Ivanov 			continue;
17558a2b000SEvgeniy Ivanov 		/* Ignore lines with no key=value pair */
17658a2b000SEvgeniy Ivanov 		if (*c == '\0')
17758a2b000SEvgeniy Ivanov 			continue;
17858a2b000SEvgeniy Ivanov 
17958a2b000SEvgeniy Ivanov 		/* zero terminate key which points to keyword */
18058a2b000SEvgeniy Ivanov 		*c++ = 0;
18158a2b000SEvgeniy Ivanov 		value = c;
18258a2b000SEvgeniy Ivanov 		/* Look for end of line (or file) and zero terminate value */
18358a2b000SEvgeniy Ivanov 		for (; *c && *c != '\n'; c++)
18458a2b000SEvgeniy Ivanov 			continue;
18558a2b000SEvgeniy Ivanov 		*c = 0;
18658a2b000SEvgeniy Ivanov 
18758a2b000SEvgeniy Ivanov 		if (!strncmp(key, "menu", 4)) {
18858a2b000SEvgeniy Ivanov 			/*
18958a2b000SEvgeniy Ivanov 			 * Parse "menu=<description>:<command>".  If the
19058a2b000SEvgeniy Ivanov 			 * description is empty ("menu=:<command>)",
19158a2b000SEvgeniy Ivanov 			 * then re-use the command as the description.
19258a2b000SEvgeniy Ivanov 			 * Note that the command may contain embedded
19358a2b000SEvgeniy Ivanov 			 * colons.
19458a2b000SEvgeniy Ivanov 			 */
19558a2b000SEvgeniy Ivanov 			if (cmenu >= MAXMENU)
19658a2b000SEvgeniy Ivanov 				continue;
19758a2b000SEvgeniy Ivanov 			bootconf.desc[cmenu] = value;
19858a2b000SEvgeniy Ivanov 			for (v2 = value; *v2 && *v2 != ':'; v2++)
19958a2b000SEvgeniy Ivanov 				continue;
20058a2b000SEvgeniy Ivanov 			if (*v2) {
20158a2b000SEvgeniy Ivanov 				*v2++ = 0;
20258a2b000SEvgeniy Ivanov 				bootconf.command[cmenu] = v2;
20358a2b000SEvgeniy Ivanov 				if (! *value)
20458a2b000SEvgeniy Ivanov 					bootconf.desc[cmenu] = v2;
20558a2b000SEvgeniy Ivanov 				cmenu++;
20658a2b000SEvgeniy Ivanov 			} else {
20758a2b000SEvgeniy Ivanov 				/* No delimiter means invalid line */
20858a2b000SEvgeniy Ivanov 				bootconf.desc[cmenu] = NULL;
20958a2b000SEvgeniy Ivanov 			}
21058a2b000SEvgeniy Ivanov 		} else if (!strncmp(key, "banner", 6)) {
21158a2b000SEvgeniy Ivanov 			if (cbanner < MAXBANNER)
21258a2b000SEvgeniy Ivanov 				bootconf.banner[cbanner++] = value;
21358a2b000SEvgeniy Ivanov 		} else if (!strncmp(key, "timeout", 7)) {
21458a2b000SEvgeniy Ivanov 			if (!isnum(*value))
21558a2b000SEvgeniy Ivanov 				bootconf.timeout = -1;
21658a2b000SEvgeniy Ivanov 			else
21758a2b000SEvgeniy Ivanov 				bootconf.timeout = atoi(value);
21858a2b000SEvgeniy Ivanov 		} else if (!strncmp(key, "default", 7)) {
21958a2b000SEvgeniy Ivanov 			bootconf.def = atoi(value) - 1;
22058a2b000SEvgeniy Ivanov 		} else if (!strncmp(key, "consdev", 7)) {
22158a2b000SEvgeniy Ivanov 			bootconf.consdev = value;
22258a2b000SEvgeniy Ivanov 		} else if (!strncmp(key, "load", 4)) {
22358a2b000SEvgeniy Ivanov 			module_add(value);
22458a2b000SEvgeniy Ivanov 		} else if (!strncmp(key, "format", 6)) {
22558a2b000SEvgeniy Ivanov 			printf("value:%c\n", *value);
22658a2b000SEvgeniy Ivanov 			switch (*value) {
22758a2b000SEvgeniy Ivanov 			case 'a':
22858a2b000SEvgeniy Ivanov 			case 'A':
22958a2b000SEvgeniy Ivanov 				bootconf.menuformat = MENUFORMAT_AUTO;
23058a2b000SEvgeniy Ivanov 				break;
23158a2b000SEvgeniy Ivanov 
23258a2b000SEvgeniy Ivanov 			case 'n':
23358a2b000SEvgeniy Ivanov 			case 'N':
23458a2b000SEvgeniy Ivanov 			case 'd':
23558a2b000SEvgeniy Ivanov 			case 'D':
23658a2b000SEvgeniy Ivanov 				bootconf.menuformat = MENUFORMAT_NUMBER;
23758a2b000SEvgeniy Ivanov 				break;
23858a2b000SEvgeniy Ivanov 
23958a2b000SEvgeniy Ivanov 			case 'l':
24058a2b000SEvgeniy Ivanov 			case 'L':
24158a2b000SEvgeniy Ivanov 				bootconf.menuformat = MENUFORMAT_LETTER;
24258a2b000SEvgeniy Ivanov 				break;
24358a2b000SEvgeniy Ivanov 			}
24458a2b000SEvgeniy Ivanov 		} else if (!strncmp(key, "clear", 5)) {
24558a2b000SEvgeniy Ivanov 			bootconf.clear = !!atoi(value);
24658a2b000SEvgeniy Ivanov 		} else if (!strncmp(key, "userconf", 8)) {
24758a2b000SEvgeniy Ivanov 			userconf_add(value);
24858a2b000SEvgeniy Ivanov 		}
24958a2b000SEvgeniy Ivanov 	}
25058a2b000SEvgeniy Ivanov 	switch (bootconf.menuformat) {
25158a2b000SEvgeniy Ivanov 	case MENUFORMAT_AUTO:
25258a2b000SEvgeniy Ivanov 		if (cmenu > 9 && bootconf.timeout > 0)
25358a2b000SEvgeniy Ivanov 			bootconf.menuformat = MENUFORMAT_LETTER;
25458a2b000SEvgeniy Ivanov 		else
25558a2b000SEvgeniy Ivanov 			bootconf.menuformat = MENUFORMAT_NUMBER;
25658a2b000SEvgeniy Ivanov 		break;
25758a2b000SEvgeniy Ivanov 
25858a2b000SEvgeniy Ivanov 	case MENUFORMAT_NUMBER:
25958a2b000SEvgeniy Ivanov 		if (cmenu > 9 && bootconf.timeout > 0)
26058a2b000SEvgeniy Ivanov 			cmenu = 9;
26158a2b000SEvgeniy Ivanov 		break;
26258a2b000SEvgeniy Ivanov 	}
26358a2b000SEvgeniy Ivanov 
26458a2b000SEvgeniy Ivanov 	bootconf.nummenu = cmenu;
26558a2b000SEvgeniy Ivanov 	if (bootconf.def < 0)
26658a2b000SEvgeniy Ivanov 		bootconf.def = 0;
26758a2b000SEvgeniy Ivanov 	if (bootconf.def >= cmenu)
26858a2b000SEvgeniy Ivanov 		bootconf.def = cmenu - 1;
26958a2b000SEvgeniy Ivanov }
27058a2b000SEvgeniy Ivanov 
27158a2b000SEvgeniy Ivanov /*
27258a2b000SEvgeniy Ivanov  * doboottypemenu will render the menu and parse any user input
27358a2b000SEvgeniy Ivanov  */
27458a2b000SEvgeniy Ivanov static int
27558a2b000SEvgeniy Ivanov getchoicefrominput(char *input, int def)
27658a2b000SEvgeniy Ivanov {
27758a2b000SEvgeniy Ivanov 	int choice, usedef;
27858a2b000SEvgeniy Ivanov 
27958a2b000SEvgeniy Ivanov 	choice = -1;
28058a2b000SEvgeniy Ivanov 	usedef = 0;
28158a2b000SEvgeniy Ivanov 
28258a2b000SEvgeniy Ivanov 	if (*input == '\0' || *input == '\r' || *input == '\n') {
28358a2b000SEvgeniy Ivanov 		choice = def;
28458a2b000SEvgeniy Ivanov 		usedef = 1;
28558a2b000SEvgeniy Ivanov 	} else if (*input >= 'A' && *input < bootconf.nummenu + 'A')
28658a2b000SEvgeniy Ivanov 		choice = (*input) - 'A';
28758a2b000SEvgeniy Ivanov 	else if (*input >= 'a' && *input < bootconf.nummenu + 'a')
28858a2b000SEvgeniy Ivanov 		choice = (*input) - 'a';
28958a2b000SEvgeniy Ivanov 	else if (isnum(*input)) {
29058a2b000SEvgeniy Ivanov 		choice = atoi(input) - 1;
29158a2b000SEvgeniy Ivanov 		if (choice < 0 || choice >= bootconf.nummenu)
29258a2b000SEvgeniy Ivanov 			choice = -1;
29358a2b000SEvgeniy Ivanov 	}
29458a2b000SEvgeniy Ivanov 
29558a2b000SEvgeniy Ivanov 	if (bootconf.menuformat != MENUFORMAT_LETTER &&
29658a2b000SEvgeniy Ivanov 	    !isnum(*input) && !usedef)
29758a2b000SEvgeniy Ivanov 		choice = -1;
29858a2b000SEvgeniy Ivanov 
29958a2b000SEvgeniy Ivanov 	return choice;
30058a2b000SEvgeniy Ivanov }
30158a2b000SEvgeniy Ivanov 
3029733fcdbSDavid van Moolenbroek static void
303*84d9c625SLionel Sambuc docommandchoice(int choice)
304*84d9c625SLionel Sambuc {
305*84d9c625SLionel Sambuc 	char input[80], *ic, *oc;
306*84d9c625SLionel Sambuc 
307*84d9c625SLionel Sambuc 	ic = bootconf.command[choice];
308*84d9c625SLionel Sambuc 	/* Split command string at ; into separate commands */
309*84d9c625SLionel Sambuc 	do {
310*84d9c625SLionel Sambuc 		oc = input;
311*84d9c625SLionel Sambuc 		/* Look for ; separator */
312*84d9c625SLionel Sambuc 		for (; *ic && *ic != COMMAND_SEPARATOR; ic++)
313*84d9c625SLionel Sambuc 			*oc++ = *ic;
314*84d9c625SLionel Sambuc 		if (*input == '\0')
315*84d9c625SLionel Sambuc 			continue;
316*84d9c625SLionel Sambuc 		/* Strip out any trailing spaces */
317*84d9c625SLionel Sambuc 		oc--;
318*84d9c625SLionel Sambuc 		for (; *oc == ' ' && oc > input; oc--);
319*84d9c625SLionel Sambuc 		*++oc = '\0';
320*84d9c625SLionel Sambuc 		if (*ic == COMMAND_SEPARATOR)
321*84d9c625SLionel Sambuc 			ic++;
322*84d9c625SLionel Sambuc 		/* Stop silly command strings like ;;; */
323*84d9c625SLionel Sambuc 		if (*input != '\0')
324*84d9c625SLionel Sambuc 			docommand(input);
325*84d9c625SLionel Sambuc 		/* Skip leading spaces */
326*84d9c625SLionel Sambuc 		for (; *ic == ' '; ic++);
327*84d9c625SLionel Sambuc 	} while (*ic);
328*84d9c625SLionel Sambuc }
329*84d9c625SLionel Sambuc 
330*84d9c625SLionel Sambuc void
331*84d9c625SLionel Sambuc bootdefault(void)
332*84d9c625SLionel Sambuc {
333*84d9c625SLionel Sambuc 	int choice;
334*84d9c625SLionel Sambuc 	static int entered;
335*84d9c625SLionel Sambuc 
336*84d9c625SLionel Sambuc 	if (bootconf.nummenu > 0) {
337*84d9c625SLionel Sambuc 		if (entered) {
338*84d9c625SLionel Sambuc 			printf("default boot twice, skipping...\n");
339*84d9c625SLionel Sambuc 			return;
340*84d9c625SLionel Sambuc 		}
341*84d9c625SLionel Sambuc 		entered = 1;
342*84d9c625SLionel Sambuc 		choice = bootconf.def;
343*84d9c625SLionel Sambuc 		printf("command(s): %s\n", bootconf.command[choice]);
344*84d9c625SLionel Sambuc 		docommandchoice(choice);
345*84d9c625SLionel Sambuc 	}
346*84d9c625SLionel Sambuc }
347*84d9c625SLionel Sambuc 
348*84d9c625SLionel Sambuc #if defined(__minix)
349*84d9c625SLionel Sambuc static void
3509733fcdbSDavid van Moolenbroek showmenu(void)
35158a2b000SEvgeniy Ivanov {
35258a2b000SEvgeniy Ivanov 	int choice;
35358a2b000SEvgeniy Ivanov 
35458a2b000SEvgeniy Ivanov 	printf("\n");
35558a2b000SEvgeniy Ivanov 	/* Display menu */
35658a2b000SEvgeniy Ivanov 	if (bootconf.menuformat == MENUFORMAT_LETTER) {
35758a2b000SEvgeniy Ivanov 		for (choice = 0; choice < bootconf.nummenu; choice++)
35858a2b000SEvgeniy Ivanov 			printf("    %c. %s\n", choice + 'A',
35958a2b000SEvgeniy Ivanov 			    bootconf.desc[choice]);
36058a2b000SEvgeniy Ivanov 	} else {
36158a2b000SEvgeniy Ivanov 		/* Can't use %2d format string with libsa */
36258a2b000SEvgeniy Ivanov 		for (choice = 0; choice < bootconf.nummenu; choice++)
36358a2b000SEvgeniy Ivanov 			printf("    %s%d. %s\n",
36458a2b000SEvgeniy Ivanov 			    (choice < 9) ?  " " : "",
36558a2b000SEvgeniy Ivanov 			    choice + 1,
36658a2b000SEvgeniy Ivanov 			    bootconf.desc[choice]);
36758a2b000SEvgeniy Ivanov 	}
3689733fcdbSDavid van Moolenbroek }
369*84d9c625SLionel Sambuc #endif /* defined(__minix) */
3709733fcdbSDavid van Moolenbroek 
3719733fcdbSDavid van Moolenbroek void
3729733fcdbSDavid van Moolenbroek doboottypemenu(void)
3739733fcdbSDavid van Moolenbroek {
374*84d9c625SLionel Sambuc #if !defined(__minix)
375*84d9c625SLionel Sambuc 	int choice;
376*84d9c625SLionel Sambuc 	char input[80];
377*84d9c625SLionel Sambuc 
378*84d9c625SLionel Sambuc 	printf("\n");
379*84d9c625SLionel Sambuc 	/* Display menu */
380*84d9c625SLionel Sambuc 	if (bootconf.menuformat == MENUFORMAT_LETTER) {
381*84d9c625SLionel Sambuc 		for (choice = 0; choice < bootconf.nummenu; choice++)
382*84d9c625SLionel Sambuc 			printf("    %c. %s\n", choice + 'A',
383*84d9c625SLionel Sambuc 			    bootconf.desc[choice]);
384*84d9c625SLionel Sambuc 	} else {
385*84d9c625SLionel Sambuc 		/* Can't use %2d format string with libsa */
386*84d9c625SLionel Sambuc 		for (choice = 0; choice < bootconf.nummenu; choice++)
387*84d9c625SLionel Sambuc 			printf("    %s%d. %s\n",
388*84d9c625SLionel Sambuc 			    (choice < 9) ?  " " : "",
389*84d9c625SLionel Sambuc 			    choice + 1,
390*84d9c625SLionel Sambuc 			    bootconf.desc[choice]);
391*84d9c625SLionel Sambuc 	}
392*84d9c625SLionel Sambuc #else
3939733fcdbSDavid van Moolenbroek 	int choice, editing;
3949733fcdbSDavid van Moolenbroek 	char input[256], *ic, *oc;
395*84d9c625SLionel Sambuc #endif /* !defined(__minix) */
396*84d9c625SLionel Sambuc #if defined(__minix)
3979733fcdbSDavid van Moolenbroek 	showmenu();
398*84d9c625SLionel Sambuc #endif /* defined(__minix) */
39958a2b000SEvgeniy Ivanov 	choice = -1;
400*84d9c625SLionel Sambuc #if defined(__minix)
4019733fcdbSDavid van Moolenbroek 	editing = 0;
402*84d9c625SLionel Sambuc #endif /* defined(__minix) */
40358a2b000SEvgeniy Ivanov 	for (;;) {
40458a2b000SEvgeniy Ivanov 		input[0] = '\0';
40558a2b000SEvgeniy Ivanov 
40658a2b000SEvgeniy Ivanov 		if (bootconf.timeout < 0) {
40758a2b000SEvgeniy Ivanov 			if (bootconf.menuformat == MENUFORMAT_LETTER)
408*84d9c625SLionel Sambuc #if !defined(__minix)
409*84d9c625SLionel Sambuc 				printf("\nOption: [%c]:",
410*84d9c625SLionel Sambuc #else
4119733fcdbSDavid van Moolenbroek 				printf("\nOption%s: [%c]:",
4129733fcdbSDavid van Moolenbroek 				    editing ? " (edit)" : "",
413*84d9c625SLionel Sambuc #endif /* !defined(__minix) */
41458a2b000SEvgeniy Ivanov 				    bootconf.def + 'A');
41558a2b000SEvgeniy Ivanov 			else
416*84d9c625SLionel Sambuc #if !defined(__minix)
417*84d9c625SLionel Sambuc 				printf("\nOption: [%d]:",
418*84d9c625SLionel Sambuc #else
4199733fcdbSDavid van Moolenbroek 				printf("\nOption%s: [%d]:",
4209733fcdbSDavid van Moolenbroek 				    editing ? " (edit)" : "",
421*84d9c625SLionel Sambuc #endif /* !defined(__minix) */
42258a2b000SEvgeniy Ivanov 				    bootconf.def + 1);
42358a2b000SEvgeniy Ivanov 
424*84d9c625SLionel Sambuc #if !defined(__minix)
425*84d9c625SLionel Sambuc 			gets(input);
426*84d9c625SLionel Sambuc #else
4279733fcdbSDavid van Moolenbroek 			editline(input, sizeof(input), NULL);
428*84d9c625SLionel Sambuc #endif /* !defined(__minix) */
42958a2b000SEvgeniy Ivanov 			choice = getchoicefrominput(input, bootconf.def);
43058a2b000SEvgeniy Ivanov 		} else if (bootconf.timeout == 0)
43158a2b000SEvgeniy Ivanov 			choice = bootconf.def;
43258a2b000SEvgeniy Ivanov 		else  {
43358a2b000SEvgeniy Ivanov 			printf("\nChoose an option; RETURN for default; "
43458a2b000SEvgeniy Ivanov 			       "SPACE to stop countdown.\n");
43558a2b000SEvgeniy Ivanov 			if (bootconf.menuformat == MENUFORMAT_LETTER)
43658a2b000SEvgeniy Ivanov 				printf("Option %c will be chosen in ",
43758a2b000SEvgeniy Ivanov 				    bootconf.def + 'A');
43858a2b000SEvgeniy Ivanov 			else
43958a2b000SEvgeniy Ivanov 				printf("Option %d will be chosen in ",
44058a2b000SEvgeniy Ivanov 				    bootconf.def + 1);
44158a2b000SEvgeniy Ivanov 			input[0] = awaitkey(bootconf.timeout, 1);
44258a2b000SEvgeniy Ivanov 			input[1] = '\0';
44358a2b000SEvgeniy Ivanov 			choice = getchoicefrominput(input, bootconf.def);
44458a2b000SEvgeniy Ivanov 			/* If invalid key pressed, drop to menu */
44558a2b000SEvgeniy Ivanov 			if (choice == -1)
44658a2b000SEvgeniy Ivanov 				bootconf.timeout = -1;
44758a2b000SEvgeniy Ivanov 		}
44858a2b000SEvgeniy Ivanov 		if (choice < 0)
44958a2b000SEvgeniy Ivanov 			continue;
450*84d9c625SLionel Sambuc #if !defined(__minix)
451*84d9c625SLionel Sambuc 		if (!strcmp(bootconf.command[choice], "prompt") &&
452*84d9c625SLionel Sambuc 		    ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 ||
453*84d9c625SLionel Sambuc 		    check_password((char *)boot_params.bp_password))) {
454*84d9c625SLionel Sambuc 			printf("type \"?\" or \"help\" for help.\n");
455*84d9c625SLionel Sambuc 			bootmenu(); /* does not return */
456*84d9c625SLionel Sambuc 		} else {
457*84d9c625SLionel Sambuc 			docommandchoice(choice);
458*84d9c625SLionel Sambuc 		}
459*84d9c625SLionel Sambuc #else
4609733fcdbSDavid van Moolenbroek 		ic = bootconf.command[choice];
4619733fcdbSDavid van Moolenbroek 		if (editing) {
4629733fcdbSDavid van Moolenbroek 			printf("> ");
4639733fcdbSDavid van Moolenbroek 			editline(input, sizeof(input), ic);
4649733fcdbSDavid van Moolenbroek 			ic = input;
4659733fcdbSDavid van Moolenbroek 		}
4669733fcdbSDavid van Moolenbroek 		if (!strcmp(ic, "edit") &&
46758a2b000SEvgeniy Ivanov 		    ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 ||
46858a2b000SEvgeniy Ivanov 		    check_password((char *)boot_params.bp_password))) {
4699733fcdbSDavid van Moolenbroek 			editing = 1;
4709733fcdbSDavid van Moolenbroek 			bootconf.timeout = -1;
4719733fcdbSDavid van Moolenbroek 		} else if (!strcmp(ic, "prompt") &&
4729733fcdbSDavid van Moolenbroek 		    ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 ||
4739733fcdbSDavid van Moolenbroek 		    check_password((char *)boot_params.bp_password))) {
4749733fcdbSDavid van Moolenbroek 			printf("type \"?\" or \"help\" for help, "
4759733fcdbSDavid van Moolenbroek 			    "or \"menu\" to return to the menu.\n");
4769733fcdbSDavid van Moolenbroek 			prompt(1);
4779733fcdbSDavid van Moolenbroek 			showmenu();
4789733fcdbSDavid van Moolenbroek 			editing = 0;
4799733fcdbSDavid van Moolenbroek 			bootconf.timeout = -1;
48058a2b000SEvgeniy Ivanov 		} else {
48158a2b000SEvgeniy Ivanov 			/* Split command string at ; into separate commands */
48258a2b000SEvgeniy Ivanov 			do {
4839733fcdbSDavid van Moolenbroek 				/*
4849733fcdbSDavid van Moolenbroek 				 * This must support inline editing, since ic
4859733fcdbSDavid van Moolenbroek 				 * may also point to input.
4869733fcdbSDavid van Moolenbroek 				 */
48758a2b000SEvgeniy Ivanov 				oc = input;
48858a2b000SEvgeniy Ivanov 				/* Look for ; separator */
48958a2b000SEvgeniy Ivanov 				for (; *ic && *ic != COMMAND_SEPARATOR; ic++)
49058a2b000SEvgeniy Ivanov 					*oc++ = *ic;
4919733fcdbSDavid van Moolenbroek 				if (*ic == COMMAND_SEPARATOR)
4929733fcdbSDavid van Moolenbroek 					ic++;
4939733fcdbSDavid van Moolenbroek 				if (oc == input)
49458a2b000SEvgeniy Ivanov 					continue;
49558a2b000SEvgeniy Ivanov 				/* Strip out any trailing spaces */
49658a2b000SEvgeniy Ivanov 				oc--;
49758a2b000SEvgeniy Ivanov 				for (; *oc == ' ' && oc > input; oc--);
49858a2b000SEvgeniy Ivanov 				*++oc = '\0';
49958a2b000SEvgeniy Ivanov 				/* Stop silly command strings like ;;; */
50058a2b000SEvgeniy Ivanov 				if (*input != '\0')
50158a2b000SEvgeniy Ivanov 					docommand(input);
50258a2b000SEvgeniy Ivanov 				/* Skip leading spaces */
50358a2b000SEvgeniy Ivanov 				for (; *ic == ' '; ic++);
50458a2b000SEvgeniy Ivanov 			} while (*ic);
50558a2b000SEvgeniy Ivanov 		}
506*84d9c625SLionel Sambuc #endif /* !defined(__minix) */
50758a2b000SEvgeniy Ivanov 
50858a2b000SEvgeniy Ivanov 	}
50958a2b000SEvgeniy Ivanov }
51058a2b000SEvgeniy Ivanov 
51158a2b000SEvgeniy Ivanov #endif	/* !SMALL */
512