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 * "local" intercepts assignments: 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 variable if kenv variable is true", 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
[] = {
101 * List or set local variable. Sniff assignment of kenv_vars[] and
102 * loader tunables (recognized by '.' in name).
109 command_local(int ac
, char **av
)
118 * local command executed directly.
120 if (strcmp(av
[0], "local") == 0) {
122 for (dvar
= dvar_first(); dvar
; dvar
= dvar_next(dvar
)) {
123 for (j
= 1; j
< ac
; ++j
) {
124 if (!strncmp(dvar
->name
, av
[j
], strlen(av
[j
])))
127 if (ac
> 1 && j
== ac
)
130 pager_output(dvar
->name
);
132 for (i
= 0; i
< dvar
->count
; ++i
) {
136 pager_output(dvar
->data
[i
]);
146 * local command intercept for 'var=val'
149 data
= strchr(name
, '=');
151 sprintf(command_errbuf
, "Bad variable syntax");
157 dvar_set(name
, &data
, 1);
162 * Take care of loader tunables and several other variables,
163 * all of which have to mirror to kenv because libstand or
164 * other consumers may have hooks into them.
166 if (strchr(name
, '.')) {
167 setenv(name
, data
, 1);
169 for (i
= 0; kenv_vars
[i
] != NULL
; i
++) {
170 if (strcmp(name
, kenv_vars
[i
]) == 0) {
171 setenv(name
, data
, 1);
180 * Unset local variables
183 command_lunset(int ac
, char **av
)
187 for (i
= 1; i
< ac
; ++i
)
193 command_lunsetif(int ac
, char **av
)
198 sprintf(command_errbuf
,
199 "syntax error use lunsetif lname envname");
202 envdata
= getenv(av
[2]);
203 if (strcmp(envdata
, "yes") == 0 ||
204 strcmp(envdata
, "YES") == 0 ||
205 strtol(envdata
, NULL
, 0)) {
212 * Load the kernel + all modules specified with MODULE_load="YES"
215 command_loadall(int ac
, char **av
)
229 (void)perform(1, argv
);
235 argv
[1] = getenv("kernelname");
236 argv
[2] = getenv("kernel_options");
238 argv
[1] = strdup("kernel");
239 res
= perform((argv
[2] == NULL
)?2:3, argv
);
245 printf("Unable to load %s%s\n", DirBase
, argv
[1]);
252 for (dvar
= dvar_first(); dvar
; dvar
= dvar_next(dvar
)) {
253 len
= strlen(dvar
->name
);
254 if (len
<= 5 || strcmp(dvar
->name
+ len
- 5, "_load"))
256 if (strcmp(dvar
->data
[0], "yes") != 0 &&
257 strcmp(dvar
->data
[0], "YES") != 0) {
261 mod_name
= strdup(dvar
->name
);
262 mod_name
[len
- 5] = 0;
266 /* Check if there's a matching foo_type */
267 for (dvar2
= dvar_first();
268 dvar2
&& (mod_type
== NULL
);
269 dvar2
= dvar_next(dvar2
)) {
270 len
= strlen(dvar2
->name
);
271 if (len
<= 5 || strcmp(dvar2
->name
+ len
- 5, "_type"))
273 tmp_str
= strdup(dvar2
->name
);
274 tmp_str
[len
- 5] = 0;
275 if (strcmp(tmp_str
, mod_name
) == 0)
276 mod_type
= dvar2
->data
[0];
281 /* Check if there's a matching foo_name */
282 for (dvar2
= dvar_first();
283 dvar2
&& (mod_fname
== NULL
);
284 dvar2
= dvar_next(dvar2
)) {
285 len
= strlen(dvar2
->name
);
286 if (len
<= 5 || strcmp(dvar2
->name
+ len
- 5, "_name"))
288 tmp_str
= strdup(dvar2
->name
);
289 tmp_str
[len
- 5] = 0;
290 if (strcmp(tmp_str
, mod_name
) == 0) {
291 mod_fname
= dvar2
->data
[0];
293 mod_name
= strdup(mod_fname
);
309 tmp
= perform(argc
, argv
);
311 time_t t
= time(NULL
);
312 printf("Unable to load %s%s\n", DirBase
, mod_name
);
313 while (time(NULL
) == t
)
315 /* don't kill the boot sequence */
327 command_menuclear(int ac
, char **av
)
329 dvar_unset("menu_*");
330 dvar_unset("item_*");
340 command_menuitem(int ac
, char **av
)
345 sprintf(command_errbuf
, "Bad menuitem syntax");
348 curitem
= (unsigned char)av
[1][0];
350 sprintf(command_errbuf
, "Bad menuitem syntax");
353 snprintf(namebuf
, sizeof(namebuf
), "menu_%c", curitem
);
354 dvar_set(namebuf
, &av
[2], 1);
364 command_menuadd(int ac
, char **av
)
371 sprintf(command_errbuf
, "Missing menuitem for menuadd");
374 snprintf(namebuf
, sizeof(namebuf
), "item_%c_%d", curitem
, curadd
);
375 dvar_set(namebuf
, &av
[1], ac
- 1);
381 * Execute menu system
384 command_menu(int ac
, char **av
)
396 if ((cp
= getenv("autoboot_delay")) != NULL
)
397 timeout
= strtol(cp
, NULL
, 0);
400 if (timeout
> 24 * 60 * 60)
401 timeout
= 24 * 60 * 60;
403 time_target
= time(NULL
) + timeout
;
409 if (c
== '\r' || c
== '\n') {
415 printf("\rCountdown halted by "
422 setenv("autoboot_delay", "NO", 1);
425 res
= menu_execute(c
);
427 setenv("autoboot_delay", "NO", 1);
430 /* else ignore char */
437 printf("\rBooting in %d second%s... ",
438 (int)(time_target
- t
),
439 ((time_target
- t
) == 1 ? "" : "s"));
440 if ((int)(time_target
- t
) <= 0) {
446 res
= menu_execute(c
);
448 setenv("autoboot_delay", "NO", 1);
452 #define LOGO_LINES 16
455 static char *logo_blank_line
= " ";
457 static char *logo_color
[LOGO_LINES
] = {
458 "\e[31;1m ,--, ,--, \e[0m",
459 "\e[31;1m | `-, \e[33;1m_\e[31m:\e[33;1m_\e[31;1m ,-' | \e[0m",
460 "\e[31;1m `, `-, \e[33;1m(\e[31m/ \\\e[33;1m)\e[31;1m ,-' ,' \e[0m",
461 "\e[31;1m `-, `-,\e[31m/ \\\e[31;1m,-' ,-' \e[0m",
462 "\e[31;1m `------\e[31m{ }\e[31;1m------' \e[0m",
463 "\e[31;1m ,----------\e[31m{ }\e[31;1m----------, \e[0m",
464 "\e[31;1m | _,-\e[31m{ }\e[31;1m-,_ | \e[0m",
465 "\e[31;1m `-,__,-' \e[31m\\ /\e[31;1m `-,__,-' \e[0m",
475 static char *logo_indigo
[LOGO_LINES
] = {
476 "\e[36m ,--, ,--\e[36;1m, \e[0m",
477 "\e[36m | `-, \e[34;1m_\e[34m:\e[34;1m_\e[36m ,-' \e[36;1m| \e[0m",
478 "\e[36m `, `-, \e[34;1m(\e[34m/ \\\e[34;1m)\e[36m ,-' \e[36;1m,' \e[0m",
479 "\e[36m `-, `-,\e[34m/ \\\e[36m,-' \e[36;1m,-' \e[0m",
480 "\e[36m `------\e[34m{ }\e[36m------\e[36;1m' \e[0m",
481 "\e[36m ,----------\e[34m{ }\e[36m----------\e[36;1m, \e[0m",
482 "\e[36m | \e[36;1m_,-\e[34m{ }\e[36m-,_ \e[36;1m| \e[0m",
483 "\e[36m `-,__\e[36;1m,-' \e[34m\\ /\e[36m `-,__\e[36;1m,-' \e[0m",
493 static char *logo_mono
[LOGO_LINES
] = {
496 " `, `-, (/ \\) ,-' ,' ",
497 " `-, `-,/ \\,-' ,-' ",
498 " `------{ }------' ",
499 " ,----------{ }----------, ",
501 " `-,__,-' \\ / `-,__,-' ",
512 logo_display(char **logo
, int line
, int orientation
, int barrier
)
516 if (orientation
== FRED_LEFT
)
517 fmt
= barrier
? "%s | " : " %s ";
519 fmt
= barrier
? " | %s" : " %s ";
522 if (line
< LOGO_LINES
)
523 printf(fmt
, logo
[line
]);
525 printf(fmt
, logo_blank_line
);
534 int logo_left
= 0; /* default to fred on right */
535 int separated
= 0; /* default blue fred without line */
536 char **logo
= logo_indigo
;
537 char *console_val
= getenv("console");
539 if (dvar_istrue(dvar_get("fred_is_red")))
542 if (dvar_istrue(dvar_get("loader_plain")))
545 if (strcmp(console_val
, "comconsole") == 0)
548 if (dvar_istrue(dvar_get("fred_disable")))
551 if (dvar_istrue(dvar_get("fred_on_left")))
554 if (dvar_istrue(dvar_get("fred_separated")))
562 printf(separated
? "%35s|%43s\n" : "%35s %43s\n",
565 printf(separated
? "%43s|%35s\n" : "%43s %35s\n",
569 while (dvar
|| i
< LOGO_LINES
) {
571 logo_display(logo
, i
, FRED_LEFT
, separated
);
574 if (strncmp(dvar
->name
, "menu_", 5) == 0) {
575 printf(" %c. %-38.38s",
576 dvar
->name
[5], dvar
->data
[0]);
577 dvar
= dvar_next(dvar
);
580 dvar
= dvar_next(dvar
);
583 * Pad when the number of menu entries is less than
587 printf(" %38.38s", " ");
590 logo_display(logo
, i
, FRED_RIGHT
, separated
);
600 dvar_t dvar_exec
= NULL
;
601 dvar_t
*dvar_execp
= &dvar_exec
;
605 snprintf(namebuf
, sizeof(namebuf
), "item_%c_0", c
);
608 * Does this menu option exist?
610 if (dvar_get(namebuf
) == NULL
)
613 snprintf(namebuf
, sizeof(namebuf
), "item_%c", c
);
618 * Copy the items to execute (the act of execution may modify our
619 * local variables so we need to copy).
621 for (dvar
= dvar_first(); dvar
; dvar
= dvar_next(dvar
)) {
622 if (strncmp(dvar
->name
, namebuf
, 6) == 0) {
623 *dvar_execp
= dvar_copy(dvar
);
624 dvar_execp
= &(*dvar_execp
)->next
;
631 for (dvar
= dvar_exec
; dvar
; dvar
= dvar
->next
) {
632 res
= perform(dvar
->count
, dvar
->data
);
635 dvar
->data
[0], command_errmsg
);
636 setenv("autoboot_delay", "NO", 1);
645 dvar_free(&dvar_exec
);