]>
Commit | Line | Data |
---|---|---|
ce5bf700 | 1 | /* main.c - the normal mode main routine */ |
2 | /* | |
4b13b216 | 3 | * GRUB -- GRand Unified Bootloader |
6fa42fa6 | 4 | * Copyright (C) 2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. |
ce5bf700 | 5 | * |
5a79f472 | 6 | * GRUB is free software: you can redistribute it and/or modify |
ce5bf700 | 7 | * it under the terms of the GNU General Public License as published by |
5a79f472 | 8 | * the Free Software Foundation, either version 3 of the License, or |
ce5bf700 | 9 | * (at your option) any later version. |
10 | * | |
5a79f472 | 11 | * GRUB is distributed in the hope that it will be useful, |
ce5bf700 | 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 | |
5a79f472 | 17 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
ce5bf700 | 18 | */ |
19 | ||
4b13b216 | 20 | #include <grub/kernel.h> |
21 | #include <grub/normal.h> | |
22 | #include <grub/dl.h> | |
4b13b216 | 23 | #include <grub/misc.h> |
24 | #include <grub/file.h> | |
25 | #include <grub/mm.h> | |
26 | #include <grub/term.h> | |
27 | #include <grub/env.h> | |
77c4a393 | 28 | #include <grub/parser.h> |
d558e6b5 | 29 | #include <grub/reader.h> |
6fa42fa6 | 30 | #include <grub/menu_viewer.h> |
e7e1f93f | 31 | #include <grub/auth.h> |
e2c37719 | 32 | #include <grub/i18n.h> |
2e713831 | 33 | #include <grub/charset.h> |
d56a6ac7 | 34 | #include <grub/script_sh.h> |
ce5bf700 | 35 | |
4b13b216 | 36 | #define GRUB_DEFAULT_HISTORY_SIZE 50 |
5aded270 | 37 | |
6066889c VS |
38 | static int nested_level = 0; |
39 | int grub_normal_exit_level = 0; | |
40 | ||
ce5bf700 | 41 | /* Read a line from the file FILE. */ |
d05f0df3 | 42 | char * |
43 | grub_file_getline (grub_file_t file) | |
ce5bf700 | 44 | { |
45 | char c; | |
46 | int pos = 0; | |
47 | int literal = 0; | |
2cff3677 | 48 | char *cmdline; |
49 | int max_len = 64; | |
50 | ||
51 | /* Initially locate some space. */ | |
52 | cmdline = grub_malloc (max_len); | |
53 | if (! cmdline) | |
54 | return 0; | |
ce5bf700 | 55 | |
56 | while (1) | |
57 | { | |
4b13b216 | 58 | if (grub_file_read (file, &c, 1) != 1) |
ce5bf700 | 59 | break; |
60 | ||
61 | /* Skip all carriage returns. */ | |
62 | if (c == '\r') | |
63 | continue; | |
64 | ||
65 | /* Replace tabs with spaces. */ | |
66 | if (c == '\t') | |
67 | c = ' '; | |
68 | ||
69 | /* The previous is a backslash, then... */ | |
70 | if (literal) | |
71 | { | |
72 | /* If it is a newline, replace it with a space and continue. */ | |
73 | if (c == '\n') | |
74 | { | |
75 | c = ' '; | |
76 | ||
77 | /* Go back to overwrite the backslash. */ | |
78 | if (pos > 0) | |
79 | pos--; | |
80 | } | |
81 | ||
82 | literal = 0; | |
83 | } | |
84 | ||
85 | if (c == '\\') | |
86 | literal = 1; | |
87 | ||
d558e6b5 | 88 | if (pos == 0) |
ce5bf700 | 89 | { |
d558e6b5 | 90 | if (! grub_isspace (c)) |
ce5bf700 | 91 | cmdline[pos++] = c; |
92 | } | |
93 | else | |
94 | { | |
2cff3677 | 95 | if (pos >= max_len) |
96 | { | |
97 | char *old_cmdline = cmdline; | |
98 | max_len = max_len * 2; | |
99 | cmdline = grub_realloc (cmdline, max_len); | |
100 | if (! cmdline) | |
101 | { | |
102 | grub_free (old_cmdline); | |
103 | return 0; | |
104 | } | |
105 | } | |
106 | ||
e93e4679 | 107 | if (c == '\n') |
108 | break; | |
109 | ||
2cff3677 | 110 | cmdline[pos++] = c; |
ce5bf700 | 111 | } |
112 | } | |
113 | ||
114 | cmdline[pos] = '\0'; | |
2cff3677 | 115 | |
116 | /* If the buffer is empty, don't return anything at all. */ | |
117 | if (pos == 0) | |
118 | { | |
119 | grub_free (cmdline); | |
120 | cmdline = 0; | |
121 | } | |
b39f9d20 | 122 | |
2cff3677 | 123 | return cmdline; |
ce5bf700 | 124 | } |
125 | ||
126 | static void | |
4b13b216 | 127 | free_menu (grub_menu_t menu) |
ce5bf700 | 128 | { |
4b13b216 | 129 | grub_menu_entry_t entry = menu->entry_list; |
a8aa5762 | 130 | |
ce5bf700 | 131 | while (entry) |
132 | { | |
4b13b216 | 133 | grub_menu_entry_t next_entry = entry->next; |
ce5bf700 | 134 | |
4b13b216 | 135 | grub_free ((void *) entry->title); |
77c4a393 | 136 | grub_free ((void *) entry->sourcecode); |
ce5bf700 | 137 | entry = next_entry; |
138 | } | |
139 | ||
4b13b216 | 140 | grub_free (menu); |
2fbcbbc3 | 141 | grub_env_unset_menu (); |
ce5bf700 | 142 | } |
143 | ||
6fa42fa6 | 144 | static void |
145 | free_menu_entry_classes (struct grub_menu_entry_class *head) | |
146 | { | |
147 | /* Free all the classes. */ | |
148 | while (head) | |
149 | { | |
150 | struct grub_menu_entry_class *next; | |
151 | ||
152 | grub_free (head->name); | |
153 | next = head->next; | |
154 | grub_free (head); | |
155 | head = next; | |
156 | } | |
157 | } | |
158 | ||
16c8e9fd VS |
159 | static struct |
160 | { | |
161 | char *name; | |
162 | int key; | |
163 | } hotkey_aliases[] = | |
164 | { | |
165 | {"backspace", '\b'}, | |
166 | {"tab", '\t'}, | |
167 | {"delete", GRUB_TERM_DC} | |
168 | }; | |
169 | ||
230c0ad6 | 170 | /* Add a menu entry to the current menu context (as given by the environment |
171 | variable data slot `menu'). As the configuration file is read, the script | |
172 | parser calls this when a menu entry is to be created. */ | |
77c4a393 | 173 | grub_err_t |
230c0ad6 | 174 | grub_normal_add_menu_entry (int argc, const char **args, |
175 | const char *sourcecode) | |
77c4a393 | 176 | { |
6fa42fa6 | 177 | const char *menutitle = 0; |
a8aa5762 | 178 | const char *menusourcecode; |
179 | grub_menu_t menu; | |
180 | grub_menu_entry_t *last; | |
6fa42fa6 | 181 | int failed = 0; |
182 | int i; | |
183 | struct grub_menu_entry_class *classes_head; /* Dummy head node for list. */ | |
184 | struct grub_menu_entry_class *classes_tail; | |
e7e1f93f | 185 | char *users = NULL; |
16c8e9fd | 186 | int hotkey = 0; |
6fa42fa6 | 187 | |
188 | /* Allocate dummy head node for class list. */ | |
eab58da2 | 189 | classes_head = grub_zalloc (sizeof (struct grub_menu_entry_class)); |
6fa42fa6 | 190 | if (! classes_head) |
191 | return grub_errno; | |
6fa42fa6 | 192 | classes_tail = classes_head; |
a8aa5762 | 193 | |
2fbcbbc3 | 194 | menu = grub_env_get_menu (); |
a8aa5762 | 195 | if (! menu) |
196 | return grub_error (GRUB_ERR_MENU, "no menu context"); | |
197 | ||
198 | last = &menu->entry_list; | |
199 | ||
200 | menusourcecode = grub_strdup (sourcecode); | |
201 | if (! menusourcecode) | |
202 | return grub_errno; | |
77c4a393 | 203 | |
6fa42fa6 | 204 | /* Parse menu arguments. */ |
205 | for (i = 0; i < argc; i++) | |
206 | { | |
207 | /* Capture arguments. */ | |
c2ffc8e9 | 208 | if (grub_strncmp ("--", args[i], 2) == 0 && i + 1 < argc) |
6fa42fa6 | 209 | { |
210 | const char *arg = &args[i][2]; | |
211 | ||
212 | /* Handle menu class. */ | |
213 | if (grub_strcmp(arg, "class") == 0) | |
214 | { | |
215 | char *class_name; | |
216 | struct grub_menu_entry_class *new_class; | |
217 | ||
218 | i++; | |
219 | class_name = grub_strdup (args[i]); | |
220 | if (! class_name) | |
221 | { | |
222 | failed = 1; | |
223 | break; | |
224 | } | |
225 | ||
226 | /* Create a new class and add it at the tail of the list. */ | |
eab58da2 | 227 | new_class = grub_zalloc (sizeof (struct grub_menu_entry_class)); |
6fa42fa6 | 228 | if (! new_class) |
229 | { | |
230 | grub_free (class_name); | |
231 | failed = 1; | |
232 | break; | |
233 | } | |
234 | /* Fill in the new class node. */ | |
235 | new_class->name = class_name; | |
6fa42fa6 | 236 | /* Link the tail to it, and make it the new tail. */ |
237 | classes_tail->next = new_class; | |
238 | classes_tail = new_class; | |
239 | continue; | |
240 | } | |
e7e1f93f | 241 | else if (grub_strcmp(arg, "users") == 0) |
242 | { | |
243 | i++; | |
244 | users = grub_strdup (args[i]); | |
245 | if (! users) | |
246 | { | |
247 | failed = 1; | |
248 | break; | |
249 | } | |
250 | ||
251 | continue; | |
252 | } | |
16c8e9fd VS |
253 | else if (grub_strcmp(arg, "hotkey") == 0) |
254 | { | |
255 | unsigned j; | |
256 | ||
257 | i++; | |
258 | if (args[i][1] == 0) | |
259 | { | |
260 | hotkey = args[i][0]; | |
261 | continue; | |
262 | } | |
263 | ||
264 | for (j = 0; j < ARRAY_SIZE (hotkey_aliases); j++) | |
265 | if (grub_strcmp (args[i], hotkey_aliases[j].name) == 0) | |
266 | { | |
267 | hotkey = hotkey_aliases[j].key; | |
268 | break; | |
269 | } | |
270 | ||
271 | if (j < ARRAY_SIZE (hotkey_aliases)) | |
272 | continue; | |
273 | ||
274 | failed = 1; | |
275 | grub_error (GRUB_ERR_MENU, | |
276 | "Invalid hotkey: '%s'.", args[i]); | |
277 | break; | |
278 | } | |
6fa42fa6 | 279 | else |
280 | { | |
281 | /* Handle invalid argument. */ | |
282 | failed = 1; | |
f04f02e4 | 283 | grub_error (GRUB_ERR_MENU, |
d558e6b5 | 284 | "invalid argument for menuentry: %s", args[i]); |
6fa42fa6 | 285 | break; |
286 | } | |
287 | } | |
288 | ||
289 | /* Capture title. */ | |
290 | if (! menutitle) | |
291 | { | |
292 | menutitle = grub_strdup (args[i]); | |
293 | } | |
294 | else | |
295 | { | |
296 | failed = 1; | |
f04f02e4 | 297 | grub_error (GRUB_ERR_MENU, |
d558e6b5 | 298 | "too many titles for menuentry: %s", args[i]); |
6fa42fa6 | 299 | break; |
300 | } | |
301 | } | |
302 | ||
303 | /* Validate arguments. */ | |
304 | if ((! failed) && (! menutitle)) | |
a8aa5762 | 305 | { |
6fa42fa6 | 306 | grub_error (GRUB_ERR_MENU, "menuentry is missing title"); |
307 | failed = 1; | |
308 | } | |
309 | ||
310 | /* If argument parsing failed, free any allocated resources. */ | |
311 | if (failed) | |
312 | { | |
313 | free_menu_entry_classes (classes_head); | |
314 | grub_free ((void *) menutitle); | |
a8aa5762 | 315 | grub_free ((void *) menusourcecode); |
6fa42fa6 | 316 | |
317 | /* Here we assume that grub_error has been used to specify failure details. */ | |
a8aa5762 | 318 | return grub_errno; |
319 | } | |
77c4a393 | 320 | |
321 | /* Add the menu entry at the end of the list. */ | |
322 | while (*last) | |
323 | last = &(*last)->next; | |
324 | ||
eab58da2 | 325 | *last = grub_zalloc (sizeof (**last)); |
77c4a393 | 326 | if (! *last) |
327 | { | |
6fa42fa6 | 328 | free_menu_entry_classes (classes_head); |
77c4a393 | 329 | grub_free ((void *) menutitle); |
a8aa5762 | 330 | grub_free ((void *) menusourcecode); |
77c4a393 | 331 | return grub_errno; |
332 | } | |
333 | ||
77c4a393 | 334 | (*last)->title = menutitle; |
16c8e9fd | 335 | (*last)->hotkey = hotkey; |
6fa42fa6 | 336 | (*last)->classes = classes_head; |
e7e1f93f | 337 | if (users) |
338 | (*last)->restricted = 1; | |
339 | (*last)->users = users; | |
a8aa5762 | 340 | (*last)->sourcecode = menusourcecode; |
77c4a393 | 341 | |
a8aa5762 | 342 | menu->size++; |
65f201ad | 343 | |
77c4a393 | 344 | return GRUB_ERR_NONE; |
345 | } | |
346 | ||
4b13b216 | 347 | static grub_menu_t |
d558e6b5 | 348 | read_config_file (const char *config) |
ce5bf700 | 349 | { |
4b13b216 | 350 | grub_file_t file; |
b39f9d20 | 351 | |
d558e6b5 | 352 | auto grub_err_t getline (char **line, int cont); |
353 | grub_err_t getline (char **line, int cont __attribute__ ((unused))) | |
77c4a393 | 354 | { |
d558e6b5 | 355 | while (1) |
356 | { | |
357 | char *buf; | |
358 | ||
359 | *line = buf = grub_file_getline (file); | |
360 | if (! buf) | |
361 | return grub_errno; | |
362 | ||
363 | if (buf[0] == '#') | |
d56a6ac7 | 364 | grub_free (*line); |
d558e6b5 | 365 | else |
366 | break; | |
367 | } | |
77c4a393 | 368 | |
369 | return GRUB_ERR_NONE; | |
370 | } | |
371 | ||
77c4a393 | 372 | grub_menu_t newmenu; |
373 | ||
2fbcbbc3 | 374 | newmenu = grub_env_get_menu (); |
d558e6b5 | 375 | if (! newmenu) |
a8aa5762 | 376 | { |
eab58da2 | 377 | newmenu = grub_zalloc (sizeof (*newmenu)); |
a8aa5762 | 378 | if (! newmenu) |
379 | return 0; | |
d558e6b5 | 380 | |
2fbcbbc3 | 381 | grub_env_set_menu (newmenu); |
a8aa5762 | 382 | } |
77c4a393 | 383 | |
ce5bf700 | 384 | /* Try to open the config file. */ |
4b13b216 | 385 | file = grub_file_open (config); |
ce5bf700 | 386 | if (! file) |
387 | return 0; | |
388 | ||
f4c623e1 VS |
389 | while (1) |
390 | { | |
391 | char *line; | |
392 | ||
393 | /* Print an error, if any. */ | |
394 | grub_print_error (); | |
395 | grub_errno = GRUB_ERR_NONE; | |
396 | ||
397 | if ((getline (&line, 0)) || (! line)) | |
398 | break; | |
399 | ||
d56a6ac7 | 400 | grub_normal_parse_line (line, getline); |
f4c623e1 VS |
401 | grub_free (line); |
402 | } | |
403 | ||
77c4a393 | 404 | grub_file_close (file); |
6de2ee99 | 405 | |
65f201ad | 406 | return newmenu; |
ce5bf700 | 407 | } |
408 | ||
ce5bf700 | 409 | /* Initialize the screen. */ |
410 | void | |
f4c623e1 | 411 | grub_normal_init_page (struct grub_term_output *term) |
ce5bf700 | 412 | { |
b99518d1 | 413 | int msg_len; |
414 | int posx; | |
415 | const char *msg = _("GNU GRUB version %s"); | |
8b442f3f | 416 | char *msg_formatted; |
b99518d1 | 417 | grub_uint32_t *unicode_msg; |
418 | grub_uint32_t *last_position; | |
a2c1332b | 419 | |
fa533ebb | 420 | grub_term_cls (term); |
8b442f3f | 421 | |
61eb45ee | 422 | msg_formatted = grub_xasprintf (msg, PACKAGE_VERSION); |
8b442f3f VS |
423 | if (!msg_formatted) |
424 | return; | |
425 | ||
a2c1332b | 426 | msg_len = grub_utf8_to_ucs4_alloc (msg_formatted, |
b99518d1 | 427 | &unicode_msg, &last_position); |
4a8a763c | 428 | grub_free (msg_formatted); |
a2c1332b | 429 | |
b99518d1 | 430 | if (msg_len < 0) |
431 | { | |
432 | return; | |
433 | } | |
b362c9e9 | 434 | |
2e713831 | 435 | posx = grub_getstringwidth (unicode_msg, last_position, term); |
f4c623e1 | 436 | posx = (grub_term_width (term) - posx) / 2; |
2e713831 | 437 | grub_term_gotoxy (term, posx, 1); |
b362c9e9 | 438 | |
2e713831 | 439 | grub_print_ucs4 (unicode_msg, last_position, term); |
b99518d1 | 440 | grub_printf("\n\n"); |
441 | grub_free (unicode_msg); | |
ce5bf700 | 442 | } |
443 | ||
027de555 VS |
444 | static void |
445 | read_lists (const char *val) | |
446 | { | |
447 | read_command_list (val); | |
448 | read_fs_list (val); | |
449 | read_crypto_list (val); | |
450 | read_terminal_list (val); | |
451 | } | |
452 | ||
e880248e | 453 | static char * |
027de555 VS |
454 | read_lists_hook (struct grub_env_var *var __attribute__ ((unused)), |
455 | const char *val) | |
e880248e | 456 | { |
027de555 | 457 | read_lists (val); |
e880248e RM |
458 | return val ? grub_strdup (val) : NULL; |
459 | } | |
39c9d41d | 460 | |
4241d2b1 | 461 | /* Read the config file CONFIG and execute the menu interface or |
462 | the command line interface if BATCH is false. */ | |
ce5bf700 | 463 | void |
f04f02e4 | 464 | grub_normal_execute (const char *config, int nested, int batch) |
ce5bf700 | 465 | { |
4b13b216 | 466 | grub_menu_t menu = 0; |
027de555 | 467 | const char *prefix = grub_env_get ("prefix"); |
ce5bf700 | 468 | |
027de555 | 469 | read_lists (prefix); |
027de555 | 470 | grub_register_variable_hook ("prefix", NULL, read_lists_hook); |
13b33fba | 471 | grub_command_execute ("parser.grub", 0, 0); |
d558e6b5 | 472 | |
ce5bf700 | 473 | if (config) |
474 | { | |
d558e6b5 | 475 | menu = read_config_file (config); |
ce5bf700 | 476 | |
477 | /* Ignore any error. */ | |
4b13b216 | 478 | grub_errno = GRUB_ERR_NONE; |
ce5bf700 | 479 | } |
480 | ||
f04f02e4 | 481 | if (! batch) |
93f3a1d8 | 482 | { |
f04f02e4 | 483 | if (menu && menu->size) |
d558e6b5 | 484 | { |
2e713831 | 485 | grub_show_menu (menu, nested); |
d558e6b5 | 486 | if (nested) |
487 | free_menu (menu); | |
488 | } | |
93f3a1d8 | 489 | } |
ce5bf700 | 490 | } |
491 | ||
d558e6b5 | 492 | /* This starts the normal mode. */ |
493 | void | |
494 | grub_enter_normal_mode (const char *config) | |
b1b797cb | 495 | { |
6066889c | 496 | nested_level++; |
d558e6b5 | 497 | grub_normal_execute (config, 0, 0); |
6066889c VS |
498 | grub_cmdline_run (0); |
499 | nested_level--; | |
500 | if (grub_normal_exit_level) | |
501 | grub_normal_exit_level--; | |
b1b797cb | 502 | } |
503 | ||
ce5bf700 | 504 | /* Enter normal mode from rescue mode. */ |
b1b797cb | 505 | static grub_err_t |
2e713831 | 506 | grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), |
b1b797cb | 507 | int argc, char *argv[]) |
ce5bf700 | 508 | { |
509 | if (argc == 0) | |
510 | { | |
5f3607e0 | 511 | /* Guess the config filename. It is necessary to make CONFIG static, |
512 | so that it won't get broken by longjmp. */ | |
2e713831 | 513 | char *config; |
ce5bf700 | 514 | const char *prefix; |
b39f9d20 | 515 | |
4b13b216 | 516 | prefix = grub_env_get ("prefix"); |
ce5bf700 | 517 | if (prefix) |
518 | { | |
61eb45ee | 519 | config = grub_xasprintf ("%s/grub.cfg", prefix); |
ce5bf700 | 520 | if (! config) |
b1b797cb | 521 | goto quit; |
ce5bf700 | 522 | |
4b13b216 | 523 | grub_enter_normal_mode (config); |
524 | grub_free (config); | |
ce5bf700 | 525 | } |
526 | else | |
4b13b216 | 527 | grub_enter_normal_mode (0); |
ce5bf700 | 528 | } |
529 | else | |
4b13b216 | 530 | grub_enter_normal_mode (argv[0]); |
b1b797cb | 531 | |
532 | quit: | |
b1b797cb | 533 | return 0; |
ce5bf700 | 534 | } |
535 | ||
6066889c | 536 | /* Exit from normal mode to rescue mode. */ |
d558e6b5 | 537 | static grub_err_t |
6066889c VS |
538 | grub_cmd_normal_exit (struct grub_command *cmd __attribute__ ((unused)), |
539 | int argc __attribute__ ((unused)), | |
540 | char *argv[] __attribute__ ((unused))) | |
d558e6b5 | 541 | { |
6066889c VS |
542 | if (nested_level <= grub_normal_exit_level) |
543 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in normal environment"); | |
544 | grub_normal_exit_level++; | |
545 | return GRUB_ERR_NONE; | |
d558e6b5 | 546 | } |
547 | ||
548 | static grub_err_t | |
6066889c | 549 | grub_normal_reader_init (int nested) |
d558e6b5 | 550 | { |
f4c623e1 | 551 | struct grub_term_output *term; |
7f39d92f | 552 | const char *msg = _("Minimal BASH-like line editing is supported. For " |
553 | "the first word, TAB lists possible command completions. Anywhere " | |
554 | "else TAB lists possible device or file completions. %s"); | |
7f39d92f | 555 | const char *msg_esc = _("ESC at any time exits."); |
8b442f3f | 556 | char *msg_formatted; |
7f39d92f | 557 | |
61eb45ee | 558 | msg_formatted = grub_xasprintf (msg, nested ? msg_esc : ""); |
8b442f3f VS |
559 | if (!msg_formatted) |
560 | return grub_errno; | |
7f39d92f | 561 | |
3be7f8de VS |
562 | FOR_ACTIVE_TERM_OUTPUTS(term) |
563 | { | |
564 | grub_normal_init_page (term); | |
565 | grub_term_setcursor (term, 1); | |
566 | ||
567 | grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term); | |
568 | grub_puts ("\n"); | |
569 | } | |
7f39d92f | 570 | grub_free (msg_formatted); |
a2c1332b | 571 | |
d558e6b5 | 572 | return 0; |
573 | } | |
574 | ||
d558e6b5 | 575 | static grub_err_t |
6066889c | 576 | grub_normal_read_line_real (char **line, int cont, int nested) |
d558e6b5 | 577 | { |
d56a6ac7 | 578 | const char *prompt; |
d558e6b5 | 579 | |
6066889c | 580 | if (cont) |
d56a6ac7 | 581 | prompt = ">"; |
6066889c | 582 | else |
d56a6ac7 | 583 | prompt = "grub>"; |
d558e6b5 | 584 | |
b09a4a8d VS |
585 | if (!prompt) |
586 | return grub_errno; | |
d558e6b5 | 587 | |
588 | while (1) | |
589 | { | |
2e713831 VS |
590 | *line = grub_cmdline_get (prompt); |
591 | if (*line) | |
d558e6b5 | 592 | break; |
593 | ||
6066889c | 594 | if (cont || nested) |
d558e6b5 | 595 | { |
2e713831 | 596 | grub_free (*line); |
d558e6b5 | 597 | *line = 0; |
598 | return grub_errno; | |
599 | } | |
600 | } | |
4a8a763c | 601 | |
d558e6b5 | 602 | return 0; |
603 | } | |
604 | ||
6066889c VS |
605 | static grub_err_t |
606 | grub_normal_read_line (char **line, int cont) | |
607 | { | |
608 | return grub_normal_read_line_real (line, cont, 0); | |
609 | } | |
610 | ||
f4c623e1 VS |
611 | void |
612 | grub_cmdline_run (int nested) | |
613 | { | |
614 | grub_err_t err = GRUB_ERR_NONE; | |
615 | ||
616 | err = grub_auth_check_authentication (NULL); | |
617 | ||
618 | if (err) | |
619 | { | |
620 | grub_print_error (); | |
621 | grub_errno = GRUB_ERR_NONE; | |
622 | return; | |
623 | } | |
624 | ||
6066889c | 625 | grub_normal_reader_init (nested); |
f4c623e1 VS |
626 | |
627 | while (1) | |
628 | { | |
629 | char *line; | |
630 | ||
6066889c VS |
631 | if (grub_normal_exit_level) |
632 | break; | |
633 | ||
f4c623e1 VS |
634 | /* Print an error, if any. */ |
635 | grub_print_error (); | |
636 | grub_errno = GRUB_ERR_NONE; | |
637 | ||
6066889c | 638 | grub_normal_read_line_real (&line, 0, nested); |
f4c623e1 | 639 | if (! line) |
2e713831 | 640 | break; |
f4c623e1 | 641 | |
d56a6ac7 | 642 | grub_normal_parse_line (line, grub_normal_read_line); |
f4c623e1 VS |
643 | grub_free (line); |
644 | } | |
645 | } | |
d558e6b5 | 646 | |
647 | static char * | |
648 | grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)), | |
649 | const char *val) | |
650 | { | |
651 | grub_set_more ((*val == '1')); | |
652 | return grub_strdup (val); | |
653 | } | |
654 | ||
6d099807 | 655 | GRUB_MOD_INIT(normal) |
ce5bf700 | 656 | { |
2fbcbbc3 VS |
657 | grub_context_init (); |
658 | ||
ce5bf700 | 659 | /* Normal mode shouldn't be unloaded. */ |
6d099807 | 660 | if (mod) |
661 | grub_dl_ref (mod); | |
ce5bf700 | 662 | |
4b13b216 | 663 | grub_set_history (GRUB_DEFAULT_HISTORY_SIZE); |
5aded270 | 664 | |
c6f2fe52 | 665 | grub_install_newline_hook (); |
d558e6b5 | 666 | grub_register_variable_hook ("pager", 0, grub_env_write_pager); |
667 | ||
ce5bf700 | 668 | /* Register a command "normal" for the rescue mode. */ |
2e713831 | 669 | grub_register_command ("normal", grub_cmd_normal, |
d8b5cd40 | 670 | 0, N_("Enter normal mode.")); |
6066889c | 671 | grub_register_command ("normal_exit", grub_cmd_normal_exit, |
d8b5cd40 | 672 | 0, N_("Exit from normal mode.")); |
ce5bf700 | 673 | |
0ece25b1 | 674 | /* Reload terminal colors when these variables are written to. */ |
675 | grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal); | |
676 | grub_register_variable_hook ("color_highlight", NULL, grub_env_write_color_highlight); | |
677 | ||
678 | /* Preserve hooks after context changes. */ | |
679 | grub_env_export ("color_normal"); | |
680 | grub_env_export ("color_highlight"); | |
ce5bf700 | 681 | } |
682 | ||
6d099807 | 683 | GRUB_MOD_FINI(normal) |
ce5bf700 | 684 | { |
2fbcbbc3 VS |
685 | grub_context_fini (); |
686 | ||
4b13b216 | 687 | grub_set_history (0); |
d558e6b5 | 688 | grub_register_variable_hook ("pager", 0, 0); |
689 | grub_fs_autoload_hook = 0; | |
ce5bf700 | 690 | } |