xref: /dflybsd-src/stand/boot/dloader/cmds.c (revision 479ab7f0492f2a51b48e8537e4f1dc686fc6014b)
1*479ab7f0SSascha Wildner /*
2*479ab7f0SSascha Wildner  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
3*479ab7f0SSascha Wildner  *
4*479ab7f0SSascha Wildner  * This code is derived from software contributed to The DragonFly Project
5*479ab7f0SSascha Wildner  * by Matthew Dillon <dillon@backplane.com>
6*479ab7f0SSascha Wildner  *
7*479ab7f0SSascha Wildner  * Redistribution and use in source and binary forms, with or without
8*479ab7f0SSascha Wildner  * modification, are permitted provided that the following conditions
9*479ab7f0SSascha Wildner  * are met:
10*479ab7f0SSascha Wildner  *
11*479ab7f0SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
12*479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
13*479ab7f0SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
14*479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer in
15*479ab7f0SSascha Wildner  *    the documentation and/or other materials provided with the
16*479ab7f0SSascha Wildner  *    distribution.
17*479ab7f0SSascha Wildner  * 3. Neither the name of The DragonFly Project nor the names of its
18*479ab7f0SSascha Wildner  *    contributors may be used to endorse or promote products derived
19*479ab7f0SSascha Wildner  *    from this software without specific, prior written permission.
20*479ab7f0SSascha Wildner  *
21*479ab7f0SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*479ab7f0SSascha Wildner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*479ab7f0SSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*479ab7f0SSascha Wildner  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25*479ab7f0SSascha Wildner  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*479ab7f0SSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*479ab7f0SSascha Wildner  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*479ab7f0SSascha Wildner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29*479ab7f0SSascha Wildner  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30*479ab7f0SSascha Wildner  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31*479ab7f0SSascha Wildner  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*479ab7f0SSascha Wildner  * SUCH DAMAGE.
33*479ab7f0SSascha Wildner  */
34*479ab7f0SSascha Wildner 
35*479ab7f0SSascha Wildner #include <stand.h>
36*479ab7f0SSascha Wildner #include <string.h>
37*479ab7f0SSascha Wildner #include "bootstrap.h"
38*479ab7f0SSascha Wildner #include "dloader.h"
39*479ab7f0SSascha Wildner 
40*479ab7f0SSascha Wildner static void menu_display(void);
41*479ab7f0SSascha Wildner static int menu_execute(int);
42*479ab7f0SSascha Wildner 
43*479ab7f0SSascha Wildner /*
44*479ab7f0SSascha Wildner  * This is called from common and must reference files to bring
45*479ab7f0SSascha Wildner  * library modules into common during linking.
46*479ab7f0SSascha Wildner  */
47*479ab7f0SSascha Wildner void
dloader_init_cmds(void)48*479ab7f0SSascha Wildner dloader_init_cmds(void)
49*479ab7f0SSascha Wildner {
50*479ab7f0SSascha Wildner }
51*479ab7f0SSascha Wildner 
52*479ab7f0SSascha Wildner /*
53*479ab7f0SSascha Wildner  * "local" intercepts assignments: lines of the form 'a=b'
54*479ab7f0SSascha Wildner  */
55*479ab7f0SSascha Wildner COMMAND_SET(local, "local", "List local variables", command_local);
56*479ab7f0SSascha Wildner COMMAND_SET(lunset, "lunset", "Unset local variable", command_lunset);
57*479ab7f0SSascha Wildner COMMAND_SET(lunsetif, "lunsetif", "Unset local variable if kenv variable is true", command_lunsetif);
58*479ab7f0SSascha Wildner COMMAND_SET(loadall, "loadall", "Load kernel + modules", command_loadall);
59*479ab7f0SSascha Wildner COMMAND_SET(menuclear, "menuclear", "Clear all menus", command_menuclear);
60*479ab7f0SSascha Wildner COMMAND_SET(menuitem, "menuitem", "Add menu bullet", command_menuitem);
61*479ab7f0SSascha Wildner COMMAND_SET(menuadd, "menuadd", "Add script line for bullet", command_menuadd);
62*479ab7f0SSascha Wildner COMMAND_SET(menu, "menu", "Run menu system", command_menu);
63*479ab7f0SSascha Wildner 
64*479ab7f0SSascha Wildner static int curitem;
65*479ab7f0SSascha Wildner static int curadd;
66*479ab7f0SSascha Wildner 
67*479ab7f0SSascha Wildner static char *kenv_vars[] = {
68*479ab7f0SSascha Wildner 	"LINES",
69*479ab7f0SSascha Wildner 	"acpi_load",
70*479ab7f0SSascha Wildner 	"autoboot_delay",
71*479ab7f0SSascha Wildner 	"boot_askname",
72*479ab7f0SSascha Wildner 	"boot_cdrom",
73*479ab7f0SSascha Wildner 	"boot_ddb",
74*479ab7f0SSascha Wildner 	"boot_gdb",
75*479ab7f0SSascha Wildner 	"boot_serial",
76*479ab7f0SSascha Wildner 	"boot_single",
77*479ab7f0SSascha Wildner 	"boot_verbose",
78*479ab7f0SSascha Wildner 	"boot_vidcons",
79*479ab7f0SSascha Wildner 	"bootfile",
80*479ab7f0SSascha Wildner 	"console",
81*479ab7f0SSascha Wildner 	"currdev",
82*479ab7f0SSascha Wildner 	"default_kernel",
83*479ab7f0SSascha Wildner 	"dumpdev",
84*479ab7f0SSascha Wildner 	"ehci_load",
85*479ab7f0SSascha Wildner 	"interpret",
86*479ab7f0SSascha Wildner 	"init_chroot",
87*479ab7f0SSascha Wildner 	"init_path",
88*479ab7f0SSascha Wildner 	"kernel_options",
89*479ab7f0SSascha Wildner 	"kernelname",
90*479ab7f0SSascha Wildner 	"loaddev",
91*479ab7f0SSascha Wildner 	"local_modules",
92*479ab7f0SSascha Wildner 	"module_path",
93*479ab7f0SSascha Wildner 	"num_ide_disks",
94*479ab7f0SSascha Wildner 	"prompt",
95*479ab7f0SSascha Wildner 	"rootdev",
96*479ab7f0SSascha Wildner 	"root_disk_unit",
97*479ab7f0SSascha Wildner 	"xhci_load",
98*479ab7f0SSascha Wildner 	NULL
99*479ab7f0SSascha Wildner };
100*479ab7f0SSascha Wildner 
101*479ab7f0SSascha Wildner /*
102*479ab7f0SSascha Wildner  * List or set local variable.  Sniff assignment of kenv_vars[] and
103*479ab7f0SSascha Wildner  * loader tunables (recognized by '.' in name).
104*479ab7f0SSascha Wildner  *
105*479ab7f0SSascha Wildner  * format for av[0]:
106*479ab7f0SSascha Wildner  *  - List: local
107*479ab7f0SSascha Wildner  *  - Set:  var=val
108*479ab7f0SSascha Wildner  */
109*479ab7f0SSascha Wildner static int
command_local(int ac,char ** av)110*479ab7f0SSascha Wildner command_local(int ac, char **av)
111*479ab7f0SSascha Wildner {
112*479ab7f0SSascha Wildner 	char *name;
113*479ab7f0SSascha Wildner 	char *data;
114*479ab7f0SSascha Wildner 	dvar_t dvar;
115*479ab7f0SSascha Wildner 	int i;
116*479ab7f0SSascha Wildner 	int j;
117*479ab7f0SSascha Wildner 
118*479ab7f0SSascha Wildner 	/*
119*479ab7f0SSascha Wildner 	 * local command executed directly.
120*479ab7f0SSascha Wildner 	 */
121*479ab7f0SSascha Wildner 	if (strcmp(av[0], "local") == 0) {
122*479ab7f0SSascha Wildner 		pager_open();
123*479ab7f0SSascha Wildner 		for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
124*479ab7f0SSascha Wildner 			for (j = 1; j < ac; ++j) {
125*479ab7f0SSascha Wildner 				if (!strncmp(dvar->name, av[j], strlen(av[j])))
126*479ab7f0SSascha Wildner 					break;
127*479ab7f0SSascha Wildner 			}
128*479ab7f0SSascha Wildner 			if (ac > 1 && j == ac)
129*479ab7f0SSascha Wildner 				continue;
130*479ab7f0SSascha Wildner 
131*479ab7f0SSascha Wildner 			pager_output(dvar->name);
132*479ab7f0SSascha Wildner 			pager_output("=");
133*479ab7f0SSascha Wildner 			for (i = 0; i < dvar->count; ++i) {
134*479ab7f0SSascha Wildner 				if (i)
135*479ab7f0SSascha Wildner 					pager_output(",");
136*479ab7f0SSascha Wildner 				pager_output("\"");
137*479ab7f0SSascha Wildner 				pager_output(dvar->data[i]);
138*479ab7f0SSascha Wildner 				pager_output("\"");
139*479ab7f0SSascha Wildner 			}
140*479ab7f0SSascha Wildner 			pager_output("\n");
141*479ab7f0SSascha Wildner 		}
142*479ab7f0SSascha Wildner 		pager_close();
143*479ab7f0SSascha Wildner 		return(CMD_OK);
144*479ab7f0SSascha Wildner 	}
145*479ab7f0SSascha Wildner 
146*479ab7f0SSascha Wildner 	/*
147*479ab7f0SSascha Wildner 	 * local command intercept for 'var=val'
148*479ab7f0SSascha Wildner 	 */
149*479ab7f0SSascha Wildner 	name = av[0];
150*479ab7f0SSascha Wildner 	data = strchr(name, '=');
151*479ab7f0SSascha Wildner 	if (data == NULL) {
152*479ab7f0SSascha Wildner 		sprintf(command_errbuf, "Bad variable syntax");
153*479ab7f0SSascha Wildner 		return (CMD_ERROR);
154*479ab7f0SSascha Wildner 	}
155*479ab7f0SSascha Wildner 	*data++ = 0;
156*479ab7f0SSascha Wildner 
157*479ab7f0SSascha Wildner 	if (*data)
158*479ab7f0SSascha Wildner 		dvar_set(name, &data, 1);
159*479ab7f0SSascha Wildner 	else
160*479ab7f0SSascha Wildner 		dvar_unset(name);
161*479ab7f0SSascha Wildner 
162*479ab7f0SSascha Wildner 	/*
163*479ab7f0SSascha Wildner 	 * Take care of loader tunables and several other variables,
164*479ab7f0SSascha Wildner 	 * all of which have to mirror to kenv because libstand or
165*479ab7f0SSascha Wildner 	 * other consumers may have hooks into them.
166*479ab7f0SSascha Wildner 	 */
167*479ab7f0SSascha Wildner 	if (strchr(name, '.')) {
168*479ab7f0SSascha Wildner 		setenv(name, data, 1);
169*479ab7f0SSascha Wildner 	} else {
170*479ab7f0SSascha Wildner 		for (i = 0; kenv_vars[i] != NULL; i++) {
171*479ab7f0SSascha Wildner 			if (strcmp(name, kenv_vars[i]) == 0) {
172*479ab7f0SSascha Wildner 				setenv(name, data, 1);
173*479ab7f0SSascha Wildner 				return(CMD_OK);
174*479ab7f0SSascha Wildner 			}
175*479ab7f0SSascha Wildner 		}
176*479ab7f0SSascha Wildner 	}
177*479ab7f0SSascha Wildner 	return(CMD_OK);
178*479ab7f0SSascha Wildner }
179*479ab7f0SSascha Wildner 
180*479ab7f0SSascha Wildner /*
181*479ab7f0SSascha Wildner  * Unset local variables
182*479ab7f0SSascha Wildner  */
183*479ab7f0SSascha Wildner static int
command_lunset(int ac,char ** av)184*479ab7f0SSascha Wildner command_lunset(int ac, char **av)
185*479ab7f0SSascha Wildner {
186*479ab7f0SSascha Wildner 	int i;
187*479ab7f0SSascha Wildner 
188*479ab7f0SSascha Wildner 	for (i = 1; i < ac; ++i)
189*479ab7f0SSascha Wildner 		dvar_unset(av[i]);
190*479ab7f0SSascha Wildner 	return(0);
191*479ab7f0SSascha Wildner }
192*479ab7f0SSascha Wildner 
193*479ab7f0SSascha Wildner static int
command_lunsetif(int ac,char ** av)194*479ab7f0SSascha Wildner command_lunsetif(int ac, char **av)
195*479ab7f0SSascha Wildner {
196*479ab7f0SSascha Wildner 	char *envdata;
197*479ab7f0SSascha Wildner 
198*479ab7f0SSascha Wildner 	if (ac != 3) {
199*479ab7f0SSascha Wildner 		sprintf(command_errbuf,
200*479ab7f0SSascha Wildner 			"syntax error use lunsetif lname envname");
201*479ab7f0SSascha Wildner 		return(CMD_ERROR);
202*479ab7f0SSascha Wildner 	}
203*479ab7f0SSascha Wildner 	envdata = getenv(av[2]);
204*479ab7f0SSascha Wildner 	if (strcmp(envdata, "yes") == 0 ||
205*479ab7f0SSascha Wildner 	    strcmp(envdata, "YES") == 0 ||
206*479ab7f0SSascha Wildner 	    strtol(envdata, NULL, 0)) {
207*479ab7f0SSascha Wildner 		dvar_unset(av[1]);
208*479ab7f0SSascha Wildner 	}
209*479ab7f0SSascha Wildner 	return (CMD_OK);
210*479ab7f0SSascha Wildner }
211*479ab7f0SSascha Wildner 
212*479ab7f0SSascha Wildner /*
213*479ab7f0SSascha Wildner  * Load the kernel + all modules specified with MODULE_load="YES"
214*479ab7f0SSascha Wildner  */
215*479ab7f0SSascha Wildner static int
command_loadall(int ac,char ** av)216*479ab7f0SSascha Wildner command_loadall(int ac, char **av)
217*479ab7f0SSascha Wildner {
218*479ab7f0SSascha Wildner 	char *argv[4];
219*479ab7f0SSascha Wildner 	char *mod_name;
220*479ab7f0SSascha Wildner 	char *mod_fname;
221*479ab7f0SSascha Wildner 	char *mod_type;
222*479ab7f0SSascha Wildner 	char *tmp_str;
223*479ab7f0SSascha Wildner 	dvar_t dvar, dvar2;
224*479ab7f0SSascha Wildner 	int len;
225*479ab7f0SSascha Wildner 	int argc;
226*479ab7f0SSascha Wildner 	int res;
227*479ab7f0SSascha Wildner 	int tmp;
228*479ab7f0SSascha Wildner 
229*479ab7f0SSascha Wildner 	argv[0] = "unload";
230*479ab7f0SSascha Wildner 	(void)perform(1, argv);
231*479ab7f0SSascha Wildner 
232*479ab7f0SSascha Wildner 	/*
233*479ab7f0SSascha Wildner 	 * Load kernel
234*479ab7f0SSascha Wildner 	 */
235*479ab7f0SSascha Wildner 	argv[0] = "load";
236*479ab7f0SSascha Wildner 	argv[1] = getenv("kernelname");
237*479ab7f0SSascha Wildner 	argv[2] = getenv("kernel_options");
238*479ab7f0SSascha Wildner 	if (argv[1] == NULL)
239*479ab7f0SSascha Wildner 		argv[1] = strdup("kernel");
240*479ab7f0SSascha Wildner 	res = perform((argv[2] == NULL)?2:3, argv);
241*479ab7f0SSascha Wildner 	free(argv[1]);
242*479ab7f0SSascha Wildner 	if (argv[2])
243*479ab7f0SSascha Wildner 		free(argv[2]);
244*479ab7f0SSascha Wildner 
245*479ab7f0SSascha Wildner 	if (res != CMD_OK) {
246*479ab7f0SSascha Wildner 		printf("Unable to load %s%s\n", DirBase, argv[1]);
247*479ab7f0SSascha Wildner 		return(res);
248*479ab7f0SSascha Wildner 	}
249*479ab7f0SSascha Wildner 
250*479ab7f0SSascha Wildner 	/*
251*479ab7f0SSascha Wildner 	 * Load modules
252*479ab7f0SSascha Wildner 	 */
253*479ab7f0SSascha Wildner 	for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
254*479ab7f0SSascha Wildner 		len = strlen(dvar->name);
255*479ab7f0SSascha Wildner 		if (len <= 5 || strcmp(dvar->name + len - 5, "_load"))
256*479ab7f0SSascha Wildner 			continue;
257*479ab7f0SSascha Wildner 		if (strcmp(dvar->data[0], "yes") != 0 &&
258*479ab7f0SSascha Wildner 		    strcmp(dvar->data[0], "YES") != 0) {
259*479ab7f0SSascha Wildner 			continue;
260*479ab7f0SSascha Wildner 		}
261*479ab7f0SSascha Wildner 
262*479ab7f0SSascha Wildner 		mod_name = strdup(dvar->name);
263*479ab7f0SSascha Wildner 		mod_name[len - 5] = 0;
264*479ab7f0SSascha Wildner 		mod_type = NULL;
265*479ab7f0SSascha Wildner 		mod_fname = NULL;
266*479ab7f0SSascha Wildner 
267*479ab7f0SSascha Wildner 		/* Check if there's a matching foo_type */
268*479ab7f0SSascha Wildner 		for (dvar2 = dvar_first();
269*479ab7f0SSascha Wildner 		     dvar2 && (mod_type == NULL);
270*479ab7f0SSascha Wildner 		     dvar2 = dvar_next(dvar2)) {
271*479ab7f0SSascha Wildner 			len = strlen(dvar2->name);
272*479ab7f0SSascha Wildner 			if (len <= 5 || strcmp(dvar2->name + len - 5, "_type"))
273*479ab7f0SSascha Wildner 				continue;
274*479ab7f0SSascha Wildner 			tmp_str = strdup(dvar2->name);
275*479ab7f0SSascha Wildner 			tmp_str[len - 5] = 0;
276*479ab7f0SSascha Wildner 			if (strcmp(tmp_str, mod_name) == 0)
277*479ab7f0SSascha Wildner 				mod_type = dvar2->data[0];
278*479ab7f0SSascha Wildner 
279*479ab7f0SSascha Wildner 			free(tmp_str);
280*479ab7f0SSascha Wildner 		}
281*479ab7f0SSascha Wildner 
282*479ab7f0SSascha Wildner 		/* Check if there's a matching foo_name */
283*479ab7f0SSascha Wildner 		for (dvar2 = dvar_first();
284*479ab7f0SSascha Wildner 		     dvar2 && (mod_fname == NULL);
285*479ab7f0SSascha Wildner 		     dvar2 = dvar_next(dvar2)) {
286*479ab7f0SSascha Wildner 			len = strlen(dvar2->name);
287*479ab7f0SSascha Wildner 			if (len <= 5 || strcmp(dvar2->name + len - 5, "_name"))
288*479ab7f0SSascha Wildner 				continue;
289*479ab7f0SSascha Wildner 			tmp_str = strdup(dvar2->name);
290*479ab7f0SSascha Wildner 			tmp_str[len - 5] = 0;
291*479ab7f0SSascha Wildner 			if (strcmp(tmp_str, mod_name) == 0) {
292*479ab7f0SSascha Wildner 				mod_fname = dvar2->data[0];
293*479ab7f0SSascha Wildner 				free(mod_name);
294*479ab7f0SSascha Wildner 				mod_name = strdup(mod_fname);
295*479ab7f0SSascha Wildner 			}
296*479ab7f0SSascha Wildner 
297*479ab7f0SSascha Wildner 			free(tmp_str);
298*479ab7f0SSascha Wildner 		}
299*479ab7f0SSascha Wildner 
300*479ab7f0SSascha Wildner 		argv[0] = "load";
301*479ab7f0SSascha Wildner 		if (mod_type) {
302*479ab7f0SSascha Wildner 			argc = 4;
303*479ab7f0SSascha Wildner 			argv[1] = "-t";
304*479ab7f0SSascha Wildner 			argv[2] = mod_type;
305*479ab7f0SSascha Wildner 			argv[3] = mod_name;
306*479ab7f0SSascha Wildner 		} else {
307*479ab7f0SSascha Wildner 			argc = 2;
308*479ab7f0SSascha Wildner 			argv[1] = mod_name;
309*479ab7f0SSascha Wildner 		}
310*479ab7f0SSascha Wildner 		tmp = perform(argc, argv);
311*479ab7f0SSascha Wildner 		if (tmp != CMD_OK) {
312*479ab7f0SSascha Wildner 			time_t t = time(NULL);
313*479ab7f0SSascha Wildner 			printf("Unable to load %s%s\n", DirBase, mod_name);
314*479ab7f0SSascha Wildner 			while (time(NULL) == t)
315*479ab7f0SSascha Wildner 				;
316*479ab7f0SSascha Wildner 			/* don't kill the boot sequence */
317*479ab7f0SSascha Wildner 			/* res = tmp; */
318*479ab7f0SSascha Wildner 		}
319*479ab7f0SSascha Wildner 		free(mod_name);
320*479ab7f0SSascha Wildner 	}
321*479ab7f0SSascha Wildner 	return(res);
322*479ab7f0SSascha Wildner }
323*479ab7f0SSascha Wildner 
324*479ab7f0SSascha Wildner /*
325*479ab7f0SSascha Wildner  * Clear all menus
326*479ab7f0SSascha Wildner  */
327*479ab7f0SSascha Wildner static int
command_menuclear(int ac,char ** av)328*479ab7f0SSascha Wildner command_menuclear(int ac, char **av)
329*479ab7f0SSascha Wildner {
330*479ab7f0SSascha Wildner 	dvar_unset("menu_*");
331*479ab7f0SSascha Wildner 	dvar_unset("item_*");
332*479ab7f0SSascha Wildner 	curitem = 0;
333*479ab7f0SSascha Wildner 	curadd = 0;
334*479ab7f0SSascha Wildner 	return(0);
335*479ab7f0SSascha Wildner }
336*479ab7f0SSascha Wildner 
337*479ab7f0SSascha Wildner /*
338*479ab7f0SSascha Wildner  * Add menu bullet
339*479ab7f0SSascha Wildner  */
340*479ab7f0SSascha Wildner static int
command_menuitem(int ac,char ** av)341*479ab7f0SSascha Wildner command_menuitem(int ac, char **av)
342*479ab7f0SSascha Wildner {
343*479ab7f0SSascha Wildner 	char namebuf[32];
344*479ab7f0SSascha Wildner 
345*479ab7f0SSascha Wildner 	if (ac != 3) {
346*479ab7f0SSascha Wildner 		sprintf(command_errbuf, "Bad menuitem syntax");
347*479ab7f0SSascha Wildner 		return (CMD_ERROR);
348*479ab7f0SSascha Wildner 	}
349*479ab7f0SSascha Wildner 	curitem = (unsigned char)av[1][0];
350*479ab7f0SSascha Wildner 	if (curitem == 0) {
351*479ab7f0SSascha Wildner 		sprintf(command_errbuf, "Bad menuitem syntax");
352*479ab7f0SSascha Wildner 		return (CMD_ERROR);
353*479ab7f0SSascha Wildner 	}
354*479ab7f0SSascha Wildner 	snprintf(namebuf, sizeof(namebuf), "menu_%c", curitem);
355*479ab7f0SSascha Wildner 	dvar_set(namebuf, &av[2], 1);
356*479ab7f0SSascha Wildner 	curadd = 0;
357*479ab7f0SSascha Wildner 
358*479ab7f0SSascha Wildner 	return(CMD_OK);
359*479ab7f0SSascha Wildner }
360*479ab7f0SSascha Wildner 
361*479ab7f0SSascha Wildner /*
362*479ab7f0SSascha Wildner  * Add execution item
363*479ab7f0SSascha Wildner  */
364*479ab7f0SSascha Wildner static int
command_menuadd(int ac,char ** av)365*479ab7f0SSascha Wildner command_menuadd(int ac, char **av)
366*479ab7f0SSascha Wildner {
367*479ab7f0SSascha Wildner 	char namebuf[32];
368*479ab7f0SSascha Wildner 
369*479ab7f0SSascha Wildner 	if (ac == 1)
370*479ab7f0SSascha Wildner 		return(CMD_OK);
371*479ab7f0SSascha Wildner 	if (curitem == 0) {
372*479ab7f0SSascha Wildner 		sprintf(command_errbuf, "Missing menuitem for menuadd");
373*479ab7f0SSascha Wildner 		return(CMD_ERROR);
374*479ab7f0SSascha Wildner 	}
375*479ab7f0SSascha Wildner 	snprintf(namebuf, sizeof(namebuf), "item_%c_%d", curitem, curadd);
376*479ab7f0SSascha Wildner 	dvar_set(namebuf, &av[1], ac - 1);
377*479ab7f0SSascha Wildner 	++curadd;
378*479ab7f0SSascha Wildner 	return (CMD_OK);
379*479ab7f0SSascha Wildner }
380*479ab7f0SSascha Wildner 
381*479ab7f0SSascha Wildner /*
382*479ab7f0SSascha Wildner  * Execute menu system
383*479ab7f0SSascha Wildner  */
384*479ab7f0SSascha Wildner static int
command_menu(int ac,char ** av)385*479ab7f0SSascha Wildner command_menu(int ac, char **av)
386*479ab7f0SSascha Wildner {
387*479ab7f0SSascha Wildner 	int timeout = -1;
388*479ab7f0SSascha Wildner 	time_t time_target;
389*479ab7f0SSascha Wildner 	time_t time_last;
390*479ab7f0SSascha Wildner 	time_t t;
391*479ab7f0SSascha Wildner 	char *cp;
392*479ab7f0SSascha Wildner 	int c;
393*479ab7f0SSascha Wildner 	int res;
394*479ab7f0SSascha Wildner 	int counting = 1;
395*479ab7f0SSascha Wildner 
396*479ab7f0SSascha Wildner 	menu_display();
397*479ab7f0SSascha Wildner 	if ((cp = getenv("autoboot_delay")) != NULL)
398*479ab7f0SSascha Wildner 		timeout = strtol(cp, NULL, 0);
399*479ab7f0SSascha Wildner 	if (timeout <= 0)
400*479ab7f0SSascha Wildner 		timeout = 10;
401*479ab7f0SSascha Wildner 	if (timeout > 24 * 60 * 60)
402*479ab7f0SSascha Wildner 		timeout = 24 * 60 * 60;
403*479ab7f0SSascha Wildner 
404*479ab7f0SSascha Wildner 	time_target = time(NULL) + timeout;
405*479ab7f0SSascha Wildner 	time_last = 0;
406*479ab7f0SSascha Wildner 	c = '1';
407*479ab7f0SSascha Wildner 	for (;;) {
408*479ab7f0SSascha Wildner 		if (ischar()) {
409*479ab7f0SSascha Wildner 			c = getchar();
410*479ab7f0SSascha Wildner 			if (c == '\r' || c == '\n') {
411*479ab7f0SSascha Wildner 				c = '1';
412*479ab7f0SSascha Wildner 				break;
413*479ab7f0SSascha Wildner 			}
414*479ab7f0SSascha Wildner 			if (c == ' ') {
415*479ab7f0SSascha Wildner 				if (counting) {
416*479ab7f0SSascha Wildner 					printf("\rCountdown halted by "
417*479ab7f0SSascha Wildner 					       "space   ");
418*479ab7f0SSascha Wildner 				}
419*479ab7f0SSascha Wildner 				counting = 0;
420*479ab7f0SSascha Wildner 				continue;
421*479ab7f0SSascha Wildner 			}
422*479ab7f0SSascha Wildner 			if (c == 0x1b) {
423*479ab7f0SSascha Wildner 				setenv("autoboot_delay", "NO", 1);
424*479ab7f0SSascha Wildner 				return(CMD_OK);
425*479ab7f0SSascha Wildner 			}
426*479ab7f0SSascha Wildner 			res = menu_execute(c);
427*479ab7f0SSascha Wildner 			if (res >= 0) {
428*479ab7f0SSascha Wildner 				setenv("autoboot_delay", "NO", 1);
429*479ab7f0SSascha Wildner 				return(CMD_OK);
430*479ab7f0SSascha Wildner 			}
431*479ab7f0SSascha Wildner 			/* else ignore char */
432*479ab7f0SSascha Wildner 		}
433*479ab7f0SSascha Wildner 		if (counting) {
434*479ab7f0SSascha Wildner 			t = time(NULL);
435*479ab7f0SSascha Wildner 			if (time_last == t)
436*479ab7f0SSascha Wildner 				continue;
437*479ab7f0SSascha Wildner 			time_last = t;
438*479ab7f0SSascha Wildner 			printf("\rBooting in %d second%s... ",
439*479ab7f0SSascha Wildner 				(int)(time_target - t),
440*479ab7f0SSascha Wildner 				((time_target - t) == 1 ? "" : "s"));
441*479ab7f0SSascha Wildner 			if ((int)(time_target - t) <= 0) {
442*479ab7f0SSascha Wildner 				c = '1';
443*479ab7f0SSascha Wildner 				break;
444*479ab7f0SSascha Wildner 			}
445*479ab7f0SSascha Wildner 		}
446*479ab7f0SSascha Wildner 	}
447*479ab7f0SSascha Wildner 	res = menu_execute(c);
448*479ab7f0SSascha Wildner 	if (res != CMD_OK)
449*479ab7f0SSascha Wildner 		setenv("autoboot_delay", "NO", 1);
450*479ab7f0SSascha Wildner 	return (res);
451*479ab7f0SSascha Wildner }
452*479ab7f0SSascha Wildner 
453*479ab7f0SSascha Wildner #define LOGO_LINES 16
454*479ab7f0SSascha Wildner #define FRED_LEFT 0
455*479ab7f0SSascha Wildner #define FRED_RIGHT 1
456*479ab7f0SSascha Wildner static char *logo_blank_line = "                                 ";
457*479ab7f0SSascha Wildner 
458*479ab7f0SSascha Wildner static char *logo_color[LOGO_LINES] = {
459*479ab7f0SSascha Wildner 	" ,--,                       ,--, ",
460*479ab7f0SSascha Wildner 	" |   `-,       _:_       ,-'   | ",
461*479ab7f0SSascha Wildner 	"  `,    `-,   (/ \\)   ,-'    ,'  ",
462*479ab7f0SSascha Wildner 	"    `-,    `-,/   \\,-'    ,-'    ",
463*479ab7f0SSascha Wildner 	"       `------{   }------'       ",
464*479ab7f0SSascha Wildner 	"   ,----------{   }----------,   ",
465*479ab7f0SSascha Wildner 	"  |        _,-{   }-,_        |  ",
466*479ab7f0SSascha Wildner 	"   `-,__,-'   \\   /   `-,__,-'   ",
467*479ab7f0SSascha Wildner 	"               | |               ",
468*479ab7f0SSascha Wildner 	"               | |               ",
469*479ab7f0SSascha Wildner 	"               | |               ",
470*479ab7f0SSascha Wildner 	"               | |               ",
471*479ab7f0SSascha Wildner 	"               | |               ",
472*479ab7f0SSascha Wildner 	"               | |               ",
473*479ab7f0SSascha Wildner 	"               `,'               ",
474*479ab7f0SSascha Wildner 	"                                 " };
475*479ab7f0SSascha Wildner 
476*479ab7f0SSascha Wildner static char *logo_indigo[LOGO_LINES] = {
477*479ab7f0SSascha Wildner 	" ,--,                       ,--, ",
478*479ab7f0SSascha Wildner 	" |   `-,       _:_       ,-'   | ",
479*479ab7f0SSascha Wildner 	"  `,    `-,   (/ \\)   ,-'    ,'  ",
480*479ab7f0SSascha Wildner 	"    `-,    `-,/   \\,-'    ,-'    ",
481*479ab7f0SSascha Wildner 	"       `------{   }------'       ",
482*479ab7f0SSascha Wildner 	"   ,----------{   }----------,   ",
483*479ab7f0SSascha Wildner 	"  |        _,-{   }-,_        |  ",
484*479ab7f0SSascha Wildner 	"   `-,__,-'   \\   /   `-,__,-'   ",
485*479ab7f0SSascha Wildner 	"               | |               ",
486*479ab7f0SSascha Wildner 	"               | |               ",
487*479ab7f0SSascha Wildner 	"               | |               ",
488*479ab7f0SSascha Wildner 	"               | |               ",
489*479ab7f0SSascha Wildner 	"               | |               ",
490*479ab7f0SSascha Wildner 	"               | |               ",
491*479ab7f0SSascha Wildner 	"               `,'               ",
492*479ab7f0SSascha Wildner 	"                                 " };
493*479ab7f0SSascha Wildner 
494*479ab7f0SSascha Wildner static char *logo_mono[LOGO_LINES] =  {
495*479ab7f0SSascha Wildner 	" ,--,                       ,--, ",
496*479ab7f0SSascha Wildner 	" |   `-,       _:_       ,-'   | ",
497*479ab7f0SSascha Wildner 	"  `,    `-,   (/ \\)   ,-'    ,'  ",
498*479ab7f0SSascha Wildner 	"    `-,    `-,/   \\,-'    ,-'    ",
499*479ab7f0SSascha Wildner 	"       `------{   }------'       ",
500*479ab7f0SSascha Wildner 	"   ,----------{   }----------,   ",
501*479ab7f0SSascha Wildner 	"  |        _,-{   }-,_        |  ",
502*479ab7f0SSascha Wildner 	"   `-,__,-'   \\   /   `-,__,-'   ",
503*479ab7f0SSascha Wildner 	"               | |               ",
504*479ab7f0SSascha Wildner 	"               | |               ",
505*479ab7f0SSascha Wildner 	"               | |               ",
506*479ab7f0SSascha Wildner 	"               | |               ",
507*479ab7f0SSascha Wildner 	"               | |               ",
508*479ab7f0SSascha Wildner 	"               | |               ",
509*479ab7f0SSascha Wildner 	"               `,'               ",
510*479ab7f0SSascha Wildner 	"                                 " };
511*479ab7f0SSascha Wildner 
512*479ab7f0SSascha Wildner static void
logo_display(char ** logo,int line,int orientation,int barrier)513*479ab7f0SSascha Wildner logo_display(char **logo, int line, int orientation, int barrier)
514*479ab7f0SSascha Wildner {
515*479ab7f0SSascha Wildner 	const char *fmt;
516*479ab7f0SSascha Wildner 
517*479ab7f0SSascha Wildner 	if (orientation == FRED_LEFT)
518*479ab7f0SSascha Wildner 		fmt = barrier ? "%s  | " : "  %s  ";
519*479ab7f0SSascha Wildner 	else
520*479ab7f0SSascha Wildner 		fmt = barrier ? " |  %s" : "  %s  ";
521*479ab7f0SSascha Wildner 
522*479ab7f0SSascha Wildner 	if (logo != NULL) {
523*479ab7f0SSascha Wildner 		if (line < LOGO_LINES)
524*479ab7f0SSascha Wildner 			printf(fmt, logo[line]);
525*479ab7f0SSascha Wildner 		else
526*479ab7f0SSascha Wildner 			printf(fmt, logo_blank_line);
527*479ab7f0SSascha Wildner 	}
528*479ab7f0SSascha Wildner }
529*479ab7f0SSascha Wildner 
530*479ab7f0SSascha Wildner static void
menu_display(void)531*479ab7f0SSascha Wildner menu_display(void)
532*479ab7f0SSascha Wildner {
533*479ab7f0SSascha Wildner 	dvar_t dvar;
534*479ab7f0SSascha Wildner 	int i;
535*479ab7f0SSascha Wildner 	int logo_left = 0;		/* default to fred on right */
536*479ab7f0SSascha Wildner 	int separated = 0;		/* default blue fred without line */
537*479ab7f0SSascha Wildner 	char **logo = logo_indigo;
538*479ab7f0SSascha Wildner 	char *console_val = getenv("console");
539*479ab7f0SSascha Wildner 
540*479ab7f0SSascha Wildner 	if (dvar_istrue(dvar_get("fred_is_red")))
541*479ab7f0SSascha Wildner 		logo = logo_color;
542*479ab7f0SSascha Wildner 
543*479ab7f0SSascha Wildner 	if (dvar_istrue(dvar_get("loader_plain")))
544*479ab7f0SSascha Wildner 		logo = logo_mono;
545*479ab7f0SSascha Wildner 
546*479ab7f0SSascha Wildner 	if (strcmp(console_val, "comconsole") == 0)
547*479ab7f0SSascha Wildner 		logo = logo_mono;
548*479ab7f0SSascha Wildner 
549*479ab7f0SSascha Wildner 	if (dvar_istrue(dvar_get("fred_disable")))
550*479ab7f0SSascha Wildner 		logo = NULL;
551*479ab7f0SSascha Wildner 
552*479ab7f0SSascha Wildner 	if (dvar_istrue(dvar_get("fred_on_left")))
553*479ab7f0SSascha Wildner 		logo_left = 1;
554*479ab7f0SSascha Wildner 
555*479ab7f0SSascha Wildner 	if (dvar_istrue(dvar_get("fred_separated")))
556*479ab7f0SSascha Wildner 		separated = 1;
557*479ab7f0SSascha Wildner 
558*479ab7f0SSascha Wildner 	dvar = dvar_first();
559*479ab7f0SSascha Wildner 	i = 0;
560*479ab7f0SSascha Wildner 
561*479ab7f0SSascha Wildner 	if (logo != NULL) {
562*479ab7f0SSascha Wildner 		if (logo_left)
563*479ab7f0SSascha Wildner 			printf(separated ? "%35s|%43s\n" : "%35s %43s\n",
564*479ab7f0SSascha Wildner 				" ", " ");
565*479ab7f0SSascha Wildner 		else
566*479ab7f0SSascha Wildner 			printf(separated ? "%43s|%35s\n" : "%43s %35s\n",
567*479ab7f0SSascha Wildner 				" ", " ");
568*479ab7f0SSascha Wildner 	}
569*479ab7f0SSascha Wildner 
570*479ab7f0SSascha Wildner 	while (dvar || i < LOGO_LINES) {
571*479ab7f0SSascha Wildner 		if (logo_left)
572*479ab7f0SSascha Wildner 			logo_display(logo, i, FRED_LEFT, separated);
573*479ab7f0SSascha Wildner 
574*479ab7f0SSascha Wildner 		while (dvar) {
575*479ab7f0SSascha Wildner 			if (strncmp(dvar->name, "menu_", 5) == 0) {
576*479ab7f0SSascha Wildner 				printf(" %c. %-38.38s",
577*479ab7f0SSascha Wildner 				    dvar->name[5], dvar->data[0]);
578*479ab7f0SSascha Wildner 				dvar = dvar_next(dvar);
579*479ab7f0SSascha Wildner 				break;
580*479ab7f0SSascha Wildner 			}
581*479ab7f0SSascha Wildner 			dvar = dvar_next(dvar);
582*479ab7f0SSascha Wildner 		}
583*479ab7f0SSascha Wildner 		/*
584*479ab7f0SSascha Wildner 		 * Pad when the number of menu entries is less than
585*479ab7f0SSascha Wildner 		 * LOGO_LINES.
586*479ab7f0SSascha Wildner 		 */
587*479ab7f0SSascha Wildner 		if (dvar == NULL)
588*479ab7f0SSascha Wildner 			printf("    %38.38s", " ");
589*479ab7f0SSascha Wildner 
590*479ab7f0SSascha Wildner 		if (!logo_left)
591*479ab7f0SSascha Wildner 			logo_display(logo, i, FRED_RIGHT, separated);
592*479ab7f0SSascha Wildner 		printf("\n");
593*479ab7f0SSascha Wildner 		i++;
594*479ab7f0SSascha Wildner 	}
595*479ab7f0SSascha Wildner }
596*479ab7f0SSascha Wildner 
597*479ab7f0SSascha Wildner static int
menu_execute(int c)598*479ab7f0SSascha Wildner menu_execute(int c)
599*479ab7f0SSascha Wildner {
600*479ab7f0SSascha Wildner 	dvar_t dvar;
601*479ab7f0SSascha Wildner 	dvar_t dvar_exec = NULL;
602*479ab7f0SSascha Wildner 	dvar_t *dvar_execp = &dvar_exec;
603*479ab7f0SSascha Wildner 	char namebuf[32];
604*479ab7f0SSascha Wildner 	int res;
605*479ab7f0SSascha Wildner 
606*479ab7f0SSascha Wildner 	snprintf(namebuf, sizeof(namebuf), "item_%c_0", c);
607*479ab7f0SSascha Wildner 
608*479ab7f0SSascha Wildner 	/*
609*479ab7f0SSascha Wildner 	 * Does this menu option exist?
610*479ab7f0SSascha Wildner 	 */
611*479ab7f0SSascha Wildner 	if (dvar_get(namebuf) == NULL)
612*479ab7f0SSascha Wildner 		return(-1);
613*479ab7f0SSascha Wildner 
614*479ab7f0SSascha Wildner 	snprintf(namebuf, sizeof(namebuf), "item_%c", c);
615*479ab7f0SSascha Wildner 	res = CMD_OK;
616*479ab7f0SSascha Wildner 	printf("\n");
617*479ab7f0SSascha Wildner 
618*479ab7f0SSascha Wildner 	/*
619*479ab7f0SSascha Wildner 	 * Copy the items to execute (the act of execution may modify our
620*479ab7f0SSascha Wildner 	 * local variables so we need to copy).
621*479ab7f0SSascha Wildner 	 */
622*479ab7f0SSascha Wildner 	for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
623*479ab7f0SSascha Wildner 		if (strncmp(dvar->name, namebuf, 6) == 0) {
624*479ab7f0SSascha Wildner 			*dvar_execp = dvar_copy(dvar);
625*479ab7f0SSascha Wildner 			dvar_execp = &(*dvar_execp)->next;
626*479ab7f0SSascha Wildner 		}
627*479ab7f0SSascha Wildner 	}
628*479ab7f0SSascha Wildner 
629*479ab7f0SSascha Wildner 	/*
630*479ab7f0SSascha Wildner 	 * Execute items
631*479ab7f0SSascha Wildner 	 */
632*479ab7f0SSascha Wildner 	for (dvar = dvar_exec; dvar; dvar = dvar->next) {
633*479ab7f0SSascha Wildner 		res = perform(dvar->count, dvar->data);
634*479ab7f0SSascha Wildner 		if (res != CMD_OK) {
635*479ab7f0SSascha Wildner 			printf("%s: %s\n",
636*479ab7f0SSascha Wildner 				dvar->data[0], command_errmsg);
637*479ab7f0SSascha Wildner 			setenv("autoboot_delay", "NO", 1);
638*479ab7f0SSascha Wildner 			break;
639*479ab7f0SSascha Wildner 		}
640*479ab7f0SSascha Wildner 	}
641*479ab7f0SSascha Wildner 
642*479ab7f0SSascha Wildner 	/*
643*479ab7f0SSascha Wildner 	 * Free items
644*479ab7f0SSascha Wildner 	 */
645*479ab7f0SSascha Wildner 	while (dvar_exec)
646*479ab7f0SSascha Wildner 		dvar_free(&dvar_exec);
647*479ab7f0SSascha Wildner 
648*479ab7f0SSascha Wildner 	return(res);
649*479ab7f0SSascha Wildner }
650