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 23 #ifdef SUPPORT_DISKLESS 24 # define GRUB 1 25 # include <etherboot.h> 26 #endif 27 28 grub_jmp_buf restart_cmdline_env; 29 30 /* Find the next word from CMDLINE and return the pointer. If 31 AFTER_EQUAL is non-zero, assume that the character `=' is treated as 32 a space. Caution: this assumption is for backward compatibility. */ 33 char * 34 skip_to (int after_equal, char *cmdline) 35 { 36 /* Skip until we hit whitespace, or maybe an equal sign. */ 37 while (*cmdline && *cmdline != ' ' && *cmdline != '\t' && 38 ! (after_equal && *cmdline == '=')) 39 cmdline ++; 40 41 /* Skip whitespace, and maybe equal signs. */ 42 while (*cmdline == ' ' || *cmdline == '\t' || 43 (after_equal && *cmdline == '=')) 44 cmdline ++; 45 46 return cmdline; 47 } 48 49 /* Print a helpful message for the command-line interface. */ 50 void 51 print_cmdline_message (int forever) 52 { 53 printf (" [ Minimal BASH-like line editing is supported. For the first word, TAB\n" 54 " lists possible command completions. Anywhere else TAB lists the possible\n" 55 " completions of a device/filename.%s ]\n", 56 (forever ? "" : " ESC at any time exits.")); 57 } 58 59 /* Find the builtin whose command name is COMMAND and return the 60 pointer. If not found, return 0. */ 61 struct builtin * 62 find_command (char *command) 63 { 64 char *ptr; 65 char c; 66 struct builtin **builtin; 67 68 /* Find the first space and terminate the command name. */ 69 ptr = command; 70 while (*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '=') 71 ptr ++; 72 73 c = *ptr; 74 *ptr = 0; 75 76 /* Seek out the builtin whose command name is COMMAND. */ 77 for (builtin = builtin_table; *builtin != 0; builtin++) 78 { 79 int ret = grub_strcmp (command, (*builtin)->name); 80 81 if (ret == 0) 82 { 83 /* Find the builtin for COMMAND. */ 84 *ptr = c; 85 return *builtin; 86 } 87 else if (ret < 0) 88 break; 89 } 90 91 /* Cannot find COMMAND. */ 92 errnum = ERR_UNRECOGNIZED; 93 *ptr = c; 94 return 0; 95 } 96 97 /* Initialize the data for the command-line. */ 98 static void 99 init_cmdline (void) 100 { 101 /* Initialization. */ 102 saved_drive = boot_drive; 103 saved_partition = install_partition; 104 current_drive = GRUB_INVALID_DRIVE; 105 errnum = 0; 106 count_lines = -1; 107 108 /* Restore memory probe state. */ 109 mbi.mem_upper = saved_mem_upper; 110 if (mbi.mmap_length) 111 mbi.flags |= MB_INFO_MEM_MAP; 112 113 /* Initialize the data for the builtin commands. */ 114 init_builtins (); 115 } 116 117 /* Enter the command-line interface. HEAP is used for the command-line 118 buffer. Return only if FOREVER is nonzero and get_cmdline returns 119 nonzero (ESC is pushed). */ 120 void 121 enter_cmdline (char *heap, int forever) 122 { 123 /* Initialize the data and print a message. */ 124 init_cmdline (); 125 grub_setjmp (restart_cmdline_env); 126 init_page (); 127 #ifdef SUPPORT_DISKLESS 128 print_network_configuration (); 129 grub_putchar ('\n'); 130 #endif 131 print_cmdline_message (forever); 132 133 while (1) 134 { 135 struct builtin *builtin; 136 char *arg; 137 138 *heap = 0; 139 print_error (); 140 errnum = ERR_NONE; 141 142 /* Get the command-line with the minimal BASH-like interface. */ 143 if (get_cmdline (PACKAGE "> ", heap, 2048, 0, 1)) 144 return; 145 146 /* If there was no command, grab a new one. */ 147 if (! heap[0]) 148 continue; 149 150 /* Find a builtin. */ 151 builtin = find_command (heap); 152 if (! builtin) 153 continue; 154 155 /* If BUILTIN cannot be run in the command-line, skip it. */ 156 if (! (builtin->flags & BUILTIN_CMDLINE)) 157 { 158 errnum = ERR_UNRECOGNIZED; 159 continue; 160 } 161 162 /* Invalidate the cache, because the user may exchange removable 163 disks. */ 164 buf_drive = -1; 165 166 /* Start to count lines, only if the internal pager is in use. */ 167 if (use_pager) 168 count_lines = 0; 169 170 /* Run BUILTIN->FUNC. */ 171 arg = skip_to (1, heap); 172 (builtin->func) (arg, BUILTIN_CMDLINE); 173 174 /* Finish the line count. */ 175 count_lines = -1; 176 } 177 } 178 179 /* Run an entry from the script SCRIPT. HEAP is used for the 180 command-line buffer. If an error occurs, return non-zero, otherwise 181 return zero. */ 182 int 183 run_script (char *script, char *heap) 184 { 185 char *old_entry; 186 char *cur_entry = script; 187 188 /* Initialize the data. */ 189 init_cmdline (); 190 191 while (1) 192 { 193 struct builtin *builtin; 194 char *arg; 195 196 print_error (); 197 198 if (errnum) 199 { 200 errnum = ERR_NONE; 201 202 /* If a fallback entry is defined, don't prompt a user's 203 intervention. */ 204 if (fallback_entryno < 0) 205 { 206 grub_printf ("\nPress any key to continue..."); 207 (void) getkey (); 208 } 209 210 return 1; 211 } 212 213 /* Copy the first string in CUR_ENTRY to HEAP. */ 214 old_entry = cur_entry; 215 while (*cur_entry++) 216 ; 217 218 grub_memmove (heap, old_entry, (int) cur_entry - (int) old_entry); 219 if (! *heap) 220 { 221 /* If there is no more command in SCRIPT... */ 222 223 /* If any kernel is not loaded, just exit successfully. */ 224 if (kernel_type == KERNEL_TYPE_NONE) 225 return 0; 226 227 /* Otherwise, the command boot is run implicitly. */ 228 grub_memmove (heap, "boot", 5); 229 } 230 231 /* Find a builtin. */ 232 builtin = find_command (heap); 233 if (! builtin) 234 { 235 grub_printf ("%s\n", old_entry); 236 continue; 237 } 238 239 if (! (builtin->flags & BUILTIN_NO_ECHO)) 240 grub_printf ("%s\n", old_entry); 241 242 /* If BUILTIN cannot be run in the command-line, skip it. */ 243 if (! (builtin->flags & BUILTIN_CMDLINE)) 244 { 245 errnum = ERR_UNRECOGNIZED; 246 continue; 247 } 248 249 /* Invalidate the cache, because the user may exchange removable 250 disks. */ 251 buf_drive = -1; 252 253 /* Run BUILTIN->FUNC. */ 254 arg = skip_to (1, heap); 255 (builtin->func) (arg, BUILTIN_SCRIPT); 256 } 257 } 258