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