1 /* cmdline.c - the device-independent GRUB text command line */ 2 /* 3 * GRUB -- GRand Unified Bootloader 4 * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21 #include <shared.h> 22 #include <term.h> 23 24 extern struct term_entry *current_term; 25 26 #ifdef SUPPORT_DISKLESS 27 # include <grub.h> 28 #endif 29 30 grub_jmp_buf restart_cmdline_env; 31 32 /* Find the next word from CMDLINE and return the pointer. If 33 AFTER_EQUAL is non-zero, assume that the character `=' is treated as 34 a space. Caution: this assumption is for backward compatibility. */ 35 char * 36 skip_to (int after_equal, char *cmdline) 37 { 38 /* Skip until we hit whitespace, or maybe an equal sign. */ 39 while (*cmdline && *cmdline != ' ' && *cmdline != '\t' && 40 ! (after_equal && *cmdline == '=')) 41 cmdline ++; 42 43 /* Skip whitespace, and maybe equal signs. */ 44 while (*cmdline == ' ' || *cmdline == '\t' || 45 (after_equal && *cmdline == '=')) 46 cmdline ++; 47 48 return cmdline; 49 } 50 51 /* Print a helpful message for the command-line interface. */ 52 void 53 print_cmdline_message (int forever) 54 { 55 printf (" [ Minimal BASH-like line editing is supported. For the first word, TAB\n" 56 " lists possible command completions. Anywhere else TAB lists the possible\n" 57 " completions of a device/filename.%s ]\n", 58 (forever ? "" : " ESC at any time exits.")); 59 } 60 61 /* Find the builtin whose command name is COMMAND and return the 62 pointer. If not found, return 0. */ 63 struct builtin * 64 find_command (char *command) 65 { 66 char *ptr; 67 char c; 68 struct builtin **builtin; 69 70 /* Find the first space and terminate the command name. */ 71 ptr = command; 72 while (*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '=') 73 ptr ++; 74 75 c = *ptr; 76 *ptr = 0; 77 78 /* Seek out the builtin whose command name is COMMAND. */ 79 for (builtin = builtin_table; *builtin != 0; builtin++) 80 { 81 int ret = grub_strcmp (command, (*builtin)->name); 82 83 if (ret == 0) 84 { 85 /* Find the builtin for COMMAND. */ 86 *ptr = c; 87 return *builtin; 88 } 89 else if (ret < 0) 90 break; 91 } 92 93 /* Cannot find COMMAND. */ 94 errnum = ERR_UNRECOGNIZED; 95 *ptr = c; 96 return 0; 97 } 98 99 /* Initialize the data for the command-line. */ 100 static void 101 init_cmdline (void) 102 { 103 /* Initialization. */ 104 saved_drive = boot_drive; 105 saved_partition = install_partition; 106 current_drive = GRUB_INVALID_DRIVE; 107 errnum = 0; 108 count_lines = -1; 109 110 /* Restore memory probe state. */ 111 mbi.mem_upper = saved_mem_upper; 112 if (mbi.mmap_length) 113 mbi.flags |= MB_INFO_MEM_MAP; 114 115 /* Initialize the data for the builtin commands. */ 116 init_builtins (); 117 } 118 119 /* Enter the command-line interface. HEAP is used for the command-line 120 buffer. Return only if FOREVER is nonzero and get_cmdline returns 121 nonzero (ESC is pushed). */ 122 void 123 enter_cmdline (char *heap, int forever) 124 { 125 /* Initialize the data and print a message. */ 126 init_cmdline (); 127 grub_setjmp (restart_cmdline_env); 128 init_page (); 129 #ifdef SUPPORT_DISKLESS 130 print_network_configuration (); 131 grub_putchar ('\n'); 132 #endif 133 print_cmdline_message (forever); 134 135 while (1) 136 { 137 struct builtin *builtin; 138 char *arg; 139 140 *heap = 0; 141 print_error (); 142 errnum = ERR_NONE; 143 144 /* Get the command-line with the minimal BASH-like interface. */ 145 if (get_cmdline (PACKAGE "> ", heap, 2048, 0, 1)) 146 return; 147 148 /* If there was no command, grab a new one. */ 149 if (! heap[0]) 150 continue; 151 152 /* Find a builtin. */ 153 builtin = find_command (heap); 154 if (! builtin) 155 continue; 156 157 /* If BUILTIN cannot be run in the command-line, skip it. */ 158 if (! (builtin->flags & BUILTIN_CMDLINE)) 159 { 160 errnum = ERR_UNRECOGNIZED; 161 continue; 162 } 163 164 /* Invalidate the cache, because the user may exchange removable 165 disks. */ 166 buf_drive = -1; 167 168 /* Start to count lines, only if the internal pager is in use. */ 169 if (use_pager) 170 count_lines = 0; 171 172 /* Run BUILTIN->FUNC. */ 173 arg = skip_to (1, heap); 174 (builtin->func) (arg, BUILTIN_CMDLINE); 175 176 /* Finish the line count. */ 177 count_lines = -1; 178 } 179 } 180 181 /* Run an entry from the script SCRIPT. HEAP is used for the 182 command-line buffer. If an error occurs, return non-zero, otherwise 183 return zero. */ 184 int 185 run_script (char *script, char *heap) 186 { 187 char *old_entry; 188 char *cur_entry = script; 189 190 /* Initialize the data. */ 191 init_cmdline (); 192 193 while (1) 194 { 195 struct builtin *builtin; 196 char *arg; 197 198 print_error (); 199 200 if (errnum) 201 { 202 errnum = ERR_NONE; 203 204 /* 205 * At this point something must have gone wrong, so dump the 206 * buffer and flip output back on. 207 */ 208 builtin = find_command("verbose"); 209 (builtin->func) ("on", BUILTIN_SCRIPT); 210 211 /* If a fallback entry is defined, don't prompt a user's 212 intervention. */ 213 if (fallback_entryno < 0) 214 { 215 grub_printf ("\nPress any key to continue..."); 216 (void) getkey (); 217 } 218 219 return 1; 220 } 221 222 /* Copy the first string in CUR_ENTRY to HEAP. */ 223 old_entry = cur_entry; 224 while (*cur_entry++) 225 ; 226 227 grub_memmove (heap, old_entry, (int) cur_entry - (int) old_entry); 228 if (! *heap) 229 { 230 /* If there is no more command in SCRIPT... */ 231 232 /* If any kernel is not loaded, just exit successfully. */ 233 if (kernel_type == KERNEL_TYPE_NONE) 234 return 0; 235 236 if (reset_term) 237 if (current_term->shutdown) { 238 (*current_term->shutdown)(); 239 current_term = term_table; /* assumption: console is first */ 240 } 241 242 243 /* Otherwise, the command boot is run implicitly. */ 244 grub_memmove (heap, "boot", 5); 245 } 246 247 /* Find a builtin. */ 248 builtin = find_command (heap); 249 if (! builtin) 250 { 251 grub_printf ("%s\n", old_entry); 252 continue; 253 } 254 255 if (! (builtin->flags & BUILTIN_NO_ECHO)) 256 grub_printf ("%s\n", old_entry); 257 258 /* If BUILTIN cannot be run in the command-line, skip it. */ 259 if (! (builtin->flags & BUILTIN_CMDLINE)) 260 { 261 errnum = ERR_UNRECOGNIZED; 262 continue; 263 } 264 265 /* Invalidate the cache, because the user may exchange removable 266 disks. */ 267 buf_drive = -1; 268 269 /* Run BUILTIN->FUNC. */ 270 arg = skip_to (1, heap); 271 (builtin->func) (arg, BUILTIN_SCRIPT); 272 } 273 } 274