2 * Copyright (c) 2010 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include "bootstrap.h"
40 static void menu_display(void);
41 static int menu_execute(int);
44 * This is called from common and must reference files to bring
45 * library modules into common during linking.
48 dloader_init_cmds(void)
53 * This intercepts lines of the form 'a=b'
55 COMMAND_SET(local, "local", "List local variables", command_local);
56 COMMAND_SET(lunset, "lunset", "Unset local variable", command_lunset);
57 COMMAND_SET(lunsetif, "lunsetif", "Unset local if envvar set to 1 or YES", command_lunsetif);
58 COMMAND_SET(loadall, "loadall", "Load kernel + modules", command_loadall);
59 COMMAND_SET(menuclear, "menuclear", "Clear all menus", command_menuclear);
60 COMMAND_SET(menuitem, "menuitem", "Add menu bullet", command_menuitem);
61 COMMAND_SET(menuadd, "menuadd", "Add script line for bullet", command_menuadd);
62 COMMAND_SET(menu, "menu", "Run menu system", command_menu);
67 static char *kenv_vars[] = {
89 * List or set local variable. Sniff assignment of kenv_vars[] and
90 * loader tunables (recognized by '.' in name).
97 command_local(int ac, char **av)
106 * local command executed directly.
108 if (strcmp(av[0], "local") == 0) {
110 for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
111 for (j = 1; j < ac; ++j) {
112 if (!strncmp(dvar->name, av[j], strlen(av[j])))
115 if (ac > 1 && j == ac)
118 pager_output(dvar->name);
120 for (i = 0; i < dvar->count; ++i) {
124 pager_output(dvar->data[i]);
134 * local command intercept for 'var=val'
137 data = strchr(name, '=');
139 sprintf(command_errbuf, "Bad variable syntax");
145 dvar_set(name, &data, 1);
150 * Take care of loader tunables and several other variables,
151 * all of which have to mirror to kenv because libstand or
152 * other consumers may have hooks into them.
154 if (strchr(name, '.')) {
155 setenv(name, data, 1);
157 for (i = 0; kenv_vars[i] != NULL; i++) {
158 if (strcmp(name, kenv_vars[i]) == 0) {
159 setenv(name, data, 1);
168 * Unset local variables
171 command_lunset(int ac, char **av)
175 for (i = 1; i < ac; ++i)
181 command_lunsetif(int ac, char **av)
186 sprintf(command_errbuf,
187 "syntax error use lunsetif lname envname");
190 envdata = getenv(av[2]);
191 if (strcmp(envdata, "yes") == 0 ||
192 strcmp(envdata, "YES") == 0 ||
193 strtol(envdata, NULL, 0)) {
200 * Load the kernel + all modules specified with MODULE_load="YES"
203 command_loadall(int ac, char **av)
217 (void)perform(1, argv);
223 argv[1] = getenv("kernelname");
224 argv[2] = getenv("kernel_options");
226 argv[1] = strdup("kernel");
227 res = perform((argv[2] == NULL)?2:3, argv);
233 printf("Unable to load %s%s\n", DirBase, argv[1]);
240 for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
241 len = strlen(dvar->name);
242 if (len <= 5 || strcmp(dvar->name + len - 5, "_load"))
244 if (strcmp(dvar->data[0], "yes") != 0 &&
245 strcmp(dvar->data[0], "YES") != 0) {
249 mod_name = strdup(dvar->name);
250 mod_name[len - 5] = 0;
254 /* Check if there's a matching foo_type */
255 for (dvar2 = dvar_first();
256 dvar2 && (mod_type == NULL);
257 dvar2 = dvar_next(dvar2)) {
258 len = strlen(dvar2->name);
259 if (len <= 5 || strcmp(dvar2->name + len - 5, "_type"))
261 tmp_str = strdup(dvar2->name);
262 tmp_str[len - 5] = 0;
263 if (strcmp(tmp_str, mod_name) == 0)
264 mod_type = dvar2->data[0];
269 /* Check if there's a matching foo_name */
270 for (dvar2 = dvar_first();
271 dvar2 && (mod_fname == NULL);
272 dvar2 = dvar_next(dvar2)) {
273 len = strlen(dvar2->name);
274 if (len <= 5 || strcmp(dvar2->name + len - 5, "_name"))
276 tmp_str = strdup(dvar2->name);
277 tmp_str[len - 5] = 0;
278 if (strcmp(tmp_str, mod_name) == 0) {
279 mod_fname = dvar2->data[0];
281 mod_name = strdup(mod_fname);
297 tmp = perform(argc, argv);
299 time_t t = time(NULL);
300 printf("Unable to load %s%s\n", DirBase, mod_name);
301 while (time(NULL) == t)
303 /* don't kill the boot sequence */
315 command_menuclear(int ac, char **av)
317 dvar_unset("menu_*");
318 dvar_unset("item_*");
328 command_menuitem(int ac, char **av)
334 sprintf(command_errbuf, "Bad menuitem syntax");
337 curitem = (unsigned char)av[1][0];
339 sprintf(command_errbuf, "Bad menuitem syntax");
342 snprintf(namebuf, sizeof(namebuf), "menu_%c", curitem);
343 dvar_set(namebuf, &av[2], 1);
353 command_menuadd(int ac, char **av)
361 sprintf(command_errbuf, "Missing menuitem for menuadd");
364 snprintf(namebuf, sizeof(namebuf), "item_%c_%d", curitem, curadd);
365 dvar_set(namebuf, &av[1], ac - 1);
371 * Execute menu system
374 command_menu(int ac, char **av)
387 if ((cp = getenv("autoboot_delay")) != NULL)
388 timeout = strtol(cp, NULL, 0);
391 if (timeout > 24 * 60 * 60)
392 timeout = 24 * 60 * 60;
394 time_target = time(NULL) + timeout;
400 if (c == '\r' || c == '\n') {
406 printf("\rCountdown halted by "
413 setenv("autoboot_delay", "NO", 1);
416 (void)perform(2, argv);
419 res = menu_execute(c);
421 setenv("autoboot_delay", "NO", 1);
424 /* else ignore char */
431 printf("\rBooting in %d second%s... ",
432 (int)(time_target - t),
433 ((time_target - t) == 1 ? "" : "s"));
434 if ((int)(time_target - t) <= 0) {
440 res = menu_execute(c);
442 setenv("autoboot_delay", "NO", 1);
446 #define LOGO_LINES 16
449 static char *logo_blank_line = " ";
450 static char *menu_header_left = "============================ DragonFly BSD ====================================\n";
451 static char *menu_header_right = "==================================== DragonFly BSD ============================\n";
452 static char *menu_footer = "===============================================================================\n";
454 static char *logo_color[LOGO_LINES] = {
455 "
\e[37m ,--,
\e[31m|
\e[37m,--,
\e[0m",
456 "
\e[37m | `-,
\e[31m,^,
\e[37m,-' |
\e[0m",
457 "
\e[37m `, `-,
\e[32m(
\e[31m/ \\
\e[32m)
\e[37m,-' ,'
\e[0m",
458 "
\e[37m `-, `-,
\e[31m/ \\
\e[37m,-' ,-'
\e[0m",
459 "
\e[37m `------
\e[31m( )
\e[37m------'
\e[0m",
460 "
\e[37m ,----------
\e[31m( )
\e[37m----------,
\e[0m",
461 "
\e[37m | _,-
\e[31m( )
\e[37m-,_ |
\e[0m",
462 "
\e[37m `-,__,-'
\e[31m\\ /
\e[37m`-,__,-'
\e[0m",
463 "
\e[37m
\e[31m| |
\e[0m",
464 "
\e[37m
\e[31m| |
\e[0m",
465 "
\e[37m
\e[31m| |
\e[0m",
466 "
\e[37m
\e[31m| |
\e[0m",
467 "
\e[37m
\e[31m| |
\e[0m",
468 "
\e[37m
\e[31m| |
\e[0m",
469 "
\e[37m
\e[31m`|'
\e[0m",
472 static char *logo_mono[LOGO_LINES] = {
475 " `, `-, (/ \\) ,-' ,' ",
476 " `-, `-,/ \\,-' ,-' ",
477 " `------( )------' ",
478 " ,----------( )----------, ",
480 " `-,__,-' \\ / `-,__,-' ",
490 static char *logo_blank[LOGO_LINES] = {
509 logo_display(char **logo, int line, int orientation)
513 if (orientation == FRED_LEFT)
519 if (line < LOGO_LINES)
520 printf(fmt, logo[line]);
522 printf(fmt, logo_blank_line);
531 int logo_left = 0; /* default to fred on right */
532 char **logo = logo_mono;
535 if (dvar_istrue(dvar_get("loader_color")))
538 if (dvar_istrue(dvar_get("fred_disable")))
541 if (dvar_istrue(dvar_get("fred_on_left")))
548 printf(logo_left ? menu_header_left : menu_header_right);
549 printf(logo_left ? "%35s|%43s\n" : "%43s|%35s\n", " ", " ");
552 while (dvar || i < LOGO_LINES) {
554 logo_display(logo, i, FRED_LEFT);
557 if (strncmp(dvar->name, "menu_", 5) == 0) {
558 printf(" %c. %-38.38s",
559 dvar->name[5], dvar->data[0]);
560 dvar = dvar_next(dvar);
563 dvar = dvar_next(dvar);
566 * Pad when the number of menu entries is less than
570 printf(" %38.38s", " ");
573 logo_display(logo, i, FRED_RIGHT);
591 snprintf(namebuf, sizeof(namebuf), "item_%c_0", c);
594 * Does this menu option exist?
596 if (dvar_get(namebuf) == NULL)
599 snprintf(namebuf, sizeof(namebuf), "item_%c", c);
601 for (dvar = dvar_first(); dvar; dvar = dvar_next(dvar)) {
602 if (strncmp(dvar->name, namebuf, 6) == 0) {
603 res = perform(dvar->count, dvar->data);
606 dvar->data[0], command_errmsg);
607 setenv("autoboot_delay", "NO", 1);