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 *
skip_to(int after_equal,char * cmdline)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
print_cmdline_message(int forever)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 *
find_command(char * command)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
init_cmdline(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
enter_cmdline(char * heap,int forever)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
run_script(char * script,char * heap)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