xref: /netbsd-src/sys/arch/zaurus/stand/zboot/bootmenu.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: bootmenu.c,v 1.3 2014/06/28 09:16:18 rtr Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/reboot.h>
31 #include <sys/bootblock.h>
32 
33 #include "boot.h"
34 #include "unixdev.h"
35 #include "bootmenu.h"
36 #include "pathnames.h"
37 
38 #define isnum(c) ((c) >= '0' && (c) <= '9')
39 
40 #define MENUFORMAT_AUTO	  0
41 #define MENUFORMAT_NUMBER 1
42 #define MENUFORMAT_LETTER 2
43 
44 int
45 atoi(const char *in)
46 {
47 	char *c;
48 	int ret;
49 
50 	ret = 0;
51 	c = (char *)in;
52 	if (*c == '-')
53 		c++;
54 	for (; isnum(*c); c++)
55 		ret = (ret * 10) + (*c - '0');
56 
57 	return (*in == '-') ? -ret : ret;
58 }
59 
60 void
61 parsebootconf(const char *conf)
62 {
63 	perform_bootcfg(conf, &bootcfg_do_noop, 0);
64 }
65 
66 /*
67  * doboottypemenu will render the menu and parse any user input
68  */
69 static int
70 getchoicefrominput(char *input, int def)
71 {
72 	int choice = -1;
73 
74 	if (*input == '\0' || *input == '\r' || *input == '\n')
75 		choice = def;
76 	else if (*input >= 'A' && *input < bootcfg_info.nummenu + 'A')
77 		choice = (*input) - 'A';
78 	else if (*input >= 'a' && *input < bootcfg_info.nummenu + 'a')
79 		choice = (*input) - 'a';
80 	else if (isnum(*input)) {
81 		choice = atoi(input) - 1;
82 		if (choice < 0 || choice >= bootcfg_info.nummenu)
83 			choice = -1;
84 	}
85 	return choice;
86 }
87 
88 void
89 doboottypemenu(void)
90 {
91 	char input[80], *ic, *oc;
92 	int choice;
93 
94 	printf("\n");
95 	/* Display menu */
96 	if (bootcfg_info.menuformat == MENUFORMAT_LETTER) {
97 		for (choice = 0; choice < bootcfg_info.nummenu; choice++)
98 			printf("    %c. %s\n", choice + 'A',
99 			    bootcfg_info.desc[choice]);
100 	} else {
101 		/* Can't use %2d format string with libsa */
102 		for (choice = 0; choice < bootcfg_info.nummenu; choice++)
103 			printf("    %s%d. %s\n",
104 			    (choice < 9) ?  " " : "",
105 			    choice + 1,
106 			    bootcfg_info.desc[choice]);
107 	}
108 	choice = -1;
109 	for (;;) {
110 		input[0] = '\0';
111 
112 		if (bootcfg_info.timeout < 0) {
113 			if (bootcfg_info.menuformat == MENUFORMAT_LETTER)
114 				printf("\nOption: [%c]:",
115 				    bootcfg_info.def + 'A');
116 			else
117 				printf("\nOption: [%d]:",
118 				    bootcfg_info.def + 1);
119 
120 			gets(input);
121 			choice = getchoicefrominput(input, bootcfg_info.def);
122 		} else if (bootcfg_info.timeout == 0)
123 			choice = bootcfg_info.def;
124 		else  {
125 			printf("\nChoose an option; RETURN for default; "
126 			       "SPACE to stop countdown.\n");
127 			if (bootcfg_info.menuformat == MENUFORMAT_LETTER)
128 				printf("Option %c will be chosen in ",
129 				    bootcfg_info.def + 'A');
130 			else
131 				printf("Option %d will be chosen in ",
132 				    bootcfg_info.def + 1);
133 			input[0] = awaitkey(bootcfg_info.timeout, 1);
134 			input[1] = '\0';
135 			choice = getchoicefrominput(input, bootcfg_info.def);
136 			/* If invalid key pressed, drop to menu */
137 			if (choice == -1)
138 				bootcfg_info.timeout = -1;
139 		}
140 		if (choice < 0)
141 			continue;
142 		if (!strcmp(bootcfg_info.command[choice], "prompt")) {
143 			printf("type \"?\" or \"help\" for help.\n");
144 			bootmenu(); /* does not return */
145 		} else {
146 			ic = bootcfg_info.command[choice];
147 			/* Split command string at ; into separate commands */
148 			do {
149 				oc = input;
150 				/* Look for ; separator */
151 				for (; *ic && *ic != COMMAND_SEPARATOR; ic++)
152 					*oc++ = *ic;
153 				if (*input == '\0')
154 					continue;
155 				/* Strip out any trailing spaces */
156 				oc--;
157 				for (; *oc == ' ' && oc > input; oc--);
158 				*++oc = '\0';
159 				if (*ic == COMMAND_SEPARATOR)
160 					ic++;
161 				/* Stop silly command strings like ;;; */
162 				if (*input != '\0')
163 					docommand(input);
164 				/* Skip leading spaces */
165 				for (; *ic == ' '; ic++);
166 			} while (*ic);
167 		}
168 	}
169 }
170