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