1 /* $NetBSD: bootmenu.c,v 1.13 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 #ifndef SMALL 30 31 #include <sys/types.h> 32 #include <sys/reboot.h> 33 #include <sys/bootblock.h> 34 35 #include <lib/libsa/stand.h> 36 #include <lib/libsa/bootcfg.h> 37 #include <lib/libsa/ufs.h> 38 #include <lib/libkern/libkern.h> 39 40 #include <libi386.h> 41 #include <bootmenu.h> 42 43 #define isnum(c) ((c) >= '0' && (c) <= '9') 44 45 static void docommandchoice(int); 46 47 extern struct x86_boot_params boot_params; 48 extern const char bootprog_name[], bootprog_rev[], bootprog_kernrev[]; 49 50 #define MENUFORMAT_AUTO 0 51 #define MENUFORMAT_NUMBER 1 52 #define MENUFORMAT_LETTER 2 53 54 int 55 atoi(const char *in) 56 { 57 char *c; 58 int ret; 59 60 ret = 0; 61 c = (char *)in; 62 if (*c == '-') 63 c++; 64 for (; isnum(*c); c++) 65 ret = (ret * 10) + (*c - '0'); 66 67 return (*in == '-') ? -ret : ret; 68 } 69 70 /* 71 * XXX 72 * if module_add, userconf_add are strictly mi they can be folded back 73 * into sys/lib/libsa/bootcfg.c:perform_bootcfg(). 74 */ 75 static void 76 do_bootcfg_command(const char *cmd, char *arg) 77 { 78 if (strcmp(cmd, BOOTCFG_CMD_LOAD) == 0) 79 module_add(arg); 80 else if (strcmp(cmd, BOOTCFG_CMD_USERCONF) == 0) 81 userconf_add(arg); 82 } 83 84 void 85 parsebootconf(const char *conf) 86 { 87 perform_bootcfg(conf, &do_bootcfg_command, 32768); 88 } 89 90 /* 91 * doboottypemenu will render the menu and parse any user input 92 */ 93 static int 94 getchoicefrominput(char *input, int def) 95 { 96 int choice, usedef; 97 98 choice = -1; 99 usedef = 0; 100 101 if (*input == '\0' || *input == '\r' || *input == '\n') { 102 choice = def; 103 usedef = 1; 104 } else if (*input >= 'A' && *input < bootcfg_info.nummenu + 'A') 105 choice = (*input) - 'A'; 106 else if (*input >= 'a' && *input < bootcfg_info.nummenu + 'a') 107 choice = (*input) - 'a'; 108 else if (isnum(*input)) { 109 choice = atoi(input) - 1; 110 if (choice < 0 || choice >= bootcfg_info.nummenu) 111 choice = -1; 112 } 113 114 if (bootcfg_info.menuformat != MENUFORMAT_LETTER && 115 !isnum(*input) && !usedef) 116 choice = -1; 117 118 return choice; 119 } 120 121 static void 122 docommandchoice(int choice) 123 { 124 char input[80], *ic, *oc; 125 126 ic = bootcfg_info.command[choice]; 127 /* Split command string at ; into separate commands */ 128 do { 129 oc = input; 130 /* Look for ; separator */ 131 for (; *ic && *ic != COMMAND_SEPARATOR; ic++) 132 *oc++ = *ic; 133 if (*input == '\0') 134 continue; 135 /* Strip out any trailing spaces */ 136 oc--; 137 for (; *oc == ' ' && oc > input; oc--); 138 *++oc = '\0'; 139 if (*ic == COMMAND_SEPARATOR) 140 ic++; 141 /* Stop silly command strings like ;;; */ 142 if (*input != '\0') 143 docommand(input); 144 /* Skip leading spaces */ 145 for (; *ic == ' '; ic++); 146 } while (*ic); 147 } 148 149 void 150 bootdefault(void) 151 { 152 int choice; 153 static int entered; 154 155 if (bootcfg_info.nummenu > 0) { 156 if (entered) { 157 printf("default boot twice, skipping...\n"); 158 return; 159 } 160 entered = 1; 161 choice = bootcfg_info.def; 162 printf("command(s): %s\n", bootcfg_info.command[choice]); 163 docommandchoice(choice); 164 } 165 } 166 167 __dead void 168 doboottypemenu(void) 169 { 170 int choice; 171 char input[80]; 172 173 printf("\n"); 174 /* Display menu */ 175 if (bootcfg_info.menuformat == MENUFORMAT_LETTER) { 176 for (choice = 0; choice < bootcfg_info.nummenu; choice++) 177 printf(" %c. %s\n", choice + 'A', 178 bootcfg_info.desc[choice]); 179 } else { 180 /* Can't use %2d format string with libsa */ 181 for (choice = 0; choice < bootcfg_info.nummenu; choice++) 182 printf(" %s%d. %s\n", 183 (choice < 9) ? " " : "", 184 choice + 1, 185 bootcfg_info.desc[choice]); 186 } 187 choice = -1; 188 for (;;) { 189 input[0] = '\0'; 190 191 if (bootcfg_info.timeout < 0) { 192 if (bootcfg_info.menuformat == MENUFORMAT_LETTER) 193 printf("\nOption: [%c]:", 194 bootcfg_info.def + 'A'); 195 else 196 printf("\nOption: [%d]:", 197 bootcfg_info.def + 1); 198 199 gets(input); 200 choice = getchoicefrominput(input, bootcfg_info.def); 201 } else if (bootcfg_info.timeout == 0) 202 choice = bootcfg_info.def; 203 else { 204 printf("\nChoose an option; RETURN for default; " 205 "SPACE to stop countdown.\n"); 206 if (bootcfg_info.menuformat == MENUFORMAT_LETTER) 207 printf("Option %c will be chosen in ", 208 bootcfg_info.def + 'A'); 209 else 210 printf("Option %d will be chosen in ", 211 bootcfg_info.def + 1); 212 input[0] = awaitkey(bootcfg_info.timeout, 1); 213 input[1] = '\0'; 214 choice = getchoicefrominput(input, bootcfg_info.def); 215 /* If invalid key pressed, drop to menu */ 216 if (choice == -1) 217 bootcfg_info.timeout = -1; 218 } 219 if (choice < 0) 220 continue; 221 if (!strcmp(bootcfg_info.command[choice], "prompt") && 222 ((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 || 223 check_password((char *)boot_params.bp_password))) { 224 printf("type \"?\" or \"help\" for help.\n"); 225 bootmenu(); /* does not return */ 226 } else { 227 docommandchoice(choice); 228 } 229 230 } 231 } 232 233 #endif /* !SMALL */ 234