]> git.proxmox.com Git - grub2.git/blame - grub-core/normal/main.c
* grub-core/loader/i386/linux.c (grub_linux_boot): Use right version.
[grub2.git] / grub-core / normal / main.c
CommitLineData
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
e745cf0c
VS
36GRUB_MOD_LICENSE ("GPLv3+");
37
4b13b216 38#define GRUB_DEFAULT_HISTORY_SIZE 50
5aded270 39
6066889c
VS
40static int nested_level = 0;
41int grub_normal_exit_level = 0;
42
ce5bf700 43/* Read a line from the file FILE. */
d05f0df3 44char *
45grub_file_getline (grub_file_t file)
ce5bf700 46{
47 char c;
9fdb2d7b 48 grub_size_t pos = 0;
2cff3677 49 char *cmdline;
9fdb2d7b
VS
50 int have_newline = 0;
51 grub_size_t max_len = 64;
2cff3677 52
53 /* Initially locate some space. */
54 cmdline = grub_malloc (max_len);
55 if (! cmdline)
56 return 0;
ce5bf700 57
58 while (1)
59 {
4b13b216 60 if (grub_file_read (file, &c, 1) != 1)
ce5bf700 61 break;
62
63 /* Skip all carriage returns. */
64 if (c == '\r')
65 continue;
66
ce5bf700 67
9fdb2d7b 68 if (pos >= max_len)
ce5bf700 69 {
9fdb2d7b
VS
70 char *old_cmdline = cmdline;
71 max_len = max_len * 2;
72 cmdline = grub_realloc (cmdline, max_len);
73 if (! cmdline)
ce5bf700 74 {
9fdb2d7b
VS
75 grub_free (old_cmdline);
76 return 0;
ce5bf700 77 }
ce5bf700 78 }
79
9fdb2d7b 80 if (c == '\n')
ce5bf700 81 {
9fdb2d7b
VS
82 have_newline = 1;
83 break;
ce5bf700 84 }
2cff3677 85
9fdb2d7b 86 cmdline[pos++] = c;
ce5bf700 87 }
88
89 cmdline[pos] = '\0';
2cff3677 90
91 /* If the buffer is empty, don't return anything at all. */
9fdb2d7b 92 if (pos == 0 && !have_newline)
2cff3677 93 {
94 grub_free (cmdline);
95 cmdline = 0;
96 }
b39f9d20 97
2cff3677 98 return cmdline;
ce5bf700 99}
100
fc55cc4c
VS
101void
102grub_normal_free_menu (grub_menu_t menu)
ce5bf700 103{
4b13b216 104 grub_menu_entry_t entry = menu->entry_list;
a8aa5762 105
ce5bf700 106 while (entry)
107 {
4b13b216 108 grub_menu_entry_t next_entry = entry->next;
5ad1be82 109 grub_size_t i;
ce5bf700 110
5ad1be82
AV
111 if (entry->classes)
112 {
113 struct grub_menu_entry_class *class;
114 for (class = entry->classes; class; class = class->next)
115 grub_free (class->name);
116 grub_free (entry->classes);
117 }
118
119 if (entry->args)
120 {
121 for (i = 0; entry->args[i]; i++)
122 grub_free (entry->args[i]);
123 grub_free (entry->args);
124 }
125
126 grub_free ((void *) entry->id);
127 grub_free ((void *) entry->users);
4b13b216 128 grub_free ((void *) entry->title);
77c4a393 129 grub_free ((void *) entry->sourcecode);
ce5bf700 130 entry = next_entry;
131 }
132
4b13b216 133 grub_free (menu);
2fbcbbc3 134 grub_env_unset_menu ();
ce5bf700 135}
136
4b13b216 137static grub_menu_t
d558e6b5 138read_config_file (const char *config)
ce5bf700 139{
4b13b216 140 grub_file_t file;
40e80b94
VS
141 const char *old_file, *old_dir;
142 char *config_dir, *ptr = 0;
b39f9d20 143
d558e6b5 144 auto grub_err_t getline (char **line, int cont);
145 grub_err_t getline (char **line, int cont __attribute__ ((unused)))
77c4a393 146 {
d558e6b5 147 while (1)
148 {
149 char *buf;
150
151 *line = buf = grub_file_getline (file);
152 if (! buf)
153 return grub_errno;
154
155 if (buf[0] == '#')
d56a6ac7 156 grub_free (*line);
d558e6b5 157 else
158 break;
159 }
77c4a393 160
161 return GRUB_ERR_NONE;
162 }
163
77c4a393 164 grub_menu_t newmenu;
165
2fbcbbc3 166 newmenu = grub_env_get_menu ();
d558e6b5 167 if (! newmenu)
a8aa5762 168 {
eab58da2 169 newmenu = grub_zalloc (sizeof (*newmenu));
a8aa5762 170 if (! newmenu)
171 return 0;
d558e6b5 172
2fbcbbc3 173 grub_env_set_menu (newmenu);
a8aa5762 174 }
77c4a393 175
ce5bf700 176 /* Try to open the config file. */
4b13b216 177 file = grub_file_open (config);
ce5bf700 178 if (! file)
179 return 0;
180
40e80b94
VS
181 old_file = grub_env_get ("config_file");
182 old_dir = grub_env_get ("config_directory");
183 grub_env_set ("config_file", config);
184 config_dir = grub_strdup (config);
185 if (config_dir)
186 ptr = grub_strrchr (config_dir, '/');
187 if (ptr)
188 *ptr = 0;
189 grub_env_set ("config_directory", config_dir);
190
191 grub_env_export ("config_file");
192 grub_env_export ("config_directory");
193
f4c623e1
VS
194 while (1)
195 {
196 char *line;
197
198 /* Print an error, if any. */
199 grub_print_error ();
200 grub_errno = GRUB_ERR_NONE;
201
202 if ((getline (&line, 0)) || (! line))
203 break;
204
d56a6ac7 205 grub_normal_parse_line (line, getline);
f4c623e1
VS
206 grub_free (line);
207 }
208
40e80b94
VS
209 if (old_file)
210 grub_env_set ("config_file", old_file);
211 else
212 grub_env_unset ("config_file");
213 if (old_dir)
214 grub_env_set ("config_directory", old_dir);
215 else
216 grub_env_unset ("config_directory");
217
77c4a393 218 grub_file_close (file);
6de2ee99 219
65f201ad 220 return newmenu;
ce5bf700 221}
222
ce5bf700 223/* Initialize the screen. */
224void
f4c623e1 225grub_normal_init_page (struct grub_term_output *term)
ce5bf700 226{
8b282ad2 227 grub_ssize_t msg_len;
b99518d1 228 int posx;
229 const char *msg = _("GNU GRUB version %s");
8b442f3f 230 char *msg_formatted;
b99518d1 231 grub_uint32_t *unicode_msg;
232 grub_uint32_t *last_position;
a2c1332b 233
fa533ebb 234 grub_term_cls (term);
8b442f3f 235
61eb45ee 236 msg_formatted = grub_xasprintf (msg, PACKAGE_VERSION);
8b442f3f
VS
237 if (!msg_formatted)
238 return;
239
a2c1332b 240 msg_len = grub_utf8_to_ucs4_alloc (msg_formatted,
b99518d1 241 &unicode_msg, &last_position);
4a8a763c 242 grub_free (msg_formatted);
a2c1332b 243
b99518d1 244 if (msg_len < 0)
245 {
246 return;
247 }
b362c9e9 248
2e713831 249 posx = grub_getstringwidth (unicode_msg, last_position, term);
f4c623e1 250 posx = (grub_term_width (term) - posx) / 2;
2e713831 251 grub_term_gotoxy (term, posx, 1);
b362c9e9 252
f588f1c8 253 grub_print_ucs4 (unicode_msg, last_position, 0, 0, term);
701f1df9
VS
254 grub_putcode ('\n', term);
255 grub_putcode ('\n', term);
b99518d1 256 grub_free (unicode_msg);
ce5bf700 257}
258
027de555
VS
259static void
260read_lists (const char *val)
261{
72539694
BC
262 if (! grub_no_autoload)
263 {
264 read_command_list (val);
265 read_fs_list (val);
266 read_crypto_list (val);
267 read_terminal_list (val);
268 }
17f38c0f 269 grub_gettext_reread_prefix (val);
027de555
VS
270}
271
e880248e 272static char *
027de555
VS
273read_lists_hook (struct grub_env_var *var __attribute__ ((unused)),
274 const char *val)
e880248e 275{
027de555 276 read_lists (val);
e880248e
RM
277 return val ? grub_strdup (val) : NULL;
278}
39c9d41d 279
4241d2b1 280/* Read the config file CONFIG and execute the menu interface or
281 the command line interface if BATCH is false. */
ce5bf700 282void
f04f02e4 283grub_normal_execute (const char *config, int nested, int batch)
ce5bf700 284{
4b13b216 285 grub_menu_t menu = 0;
3fa06487 286 const char *prefix;
ce5bf700 287
3fa06487
CW
288 if (! nested)
289 {
290 prefix = grub_env_get ("prefix");
291 read_lists (prefix);
292 grub_register_variable_hook ("prefix", NULL, read_lists_hook);
3fa06487 293 }
d558e6b5 294
ce5bf700 295 if (config)
296 {
d558e6b5 297 menu = read_config_file (config);
ce5bf700 298
299 /* Ignore any error. */
4b13b216 300 grub_errno = GRUB_ERR_NONE;
ce5bf700 301 }
302
f04f02e4 303 if (! batch)
93f3a1d8 304 {
f04f02e4 305 if (menu && menu->size)
d558e6b5 306 {
dcb883b1 307 grub_show_menu (menu, nested, 0);
d558e6b5 308 if (nested)
fc55cc4c 309 grub_normal_free_menu (menu);
d558e6b5 310 }
93f3a1d8 311 }
ce5bf700 312}
313
d558e6b5 314/* This starts the normal mode. */
315void
316grub_enter_normal_mode (const char *config)
b1b797cb 317{
6066889c 318 nested_level++;
d558e6b5 319 grub_normal_execute (config, 0, 0);
6066889c
VS
320 grub_cmdline_run (0);
321 nested_level--;
322 if (grub_normal_exit_level)
323 grub_normal_exit_level--;
b1b797cb 324}
325
ce5bf700 326/* Enter normal mode from rescue mode. */
b1b797cb 327static grub_err_t
2e713831 328grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
b1b797cb 329 int argc, char *argv[])
ce5bf700 330{
331 if (argc == 0)
332 {
5f3607e0 333 /* Guess the config filename. It is necessary to make CONFIG static,
334 so that it won't get broken by longjmp. */
2e713831 335 char *config;
ce5bf700 336 const char *prefix;
b39f9d20 337
4b13b216 338 prefix = grub_env_get ("prefix");
ce5bf700 339 if (prefix)
340 {
61eb45ee 341 config = grub_xasprintf ("%s/grub.cfg", prefix);
ce5bf700 342 if (! config)
b1b797cb 343 goto quit;
ce5bf700 344
4b13b216 345 grub_enter_normal_mode (config);
346 grub_free (config);
ce5bf700 347 }
348 else
4b13b216 349 grub_enter_normal_mode (0);
ce5bf700 350 }
351 else
4b13b216 352 grub_enter_normal_mode (argv[0]);
b1b797cb 353
354quit:
b1b797cb 355 return 0;
ce5bf700 356}
357
6066889c 358/* Exit from normal mode to rescue mode. */
d558e6b5 359static grub_err_t
6066889c
VS
360grub_cmd_normal_exit (struct grub_command *cmd __attribute__ ((unused)),
361 int argc __attribute__ ((unused)),
362 char *argv[] __attribute__ ((unused)))
d558e6b5 363{
6066889c
VS
364 if (nested_level <= grub_normal_exit_level)
365 return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in normal environment");
366 grub_normal_exit_level++;
367 return GRUB_ERR_NONE;
d558e6b5 368}
369
370static grub_err_t
6066889c 371grub_normal_reader_init (int nested)
d558e6b5 372{
f4c623e1 373 struct grub_term_output *term;
7f39d92f 374 const char *msg = _("Minimal BASH-like line editing is supported. For "
375 "the first word, TAB lists possible command completions. Anywhere "
376 "else TAB lists possible device or file completions. %s");
7f39d92f 377 const char *msg_esc = _("ESC at any time exits.");
8b442f3f 378 char *msg_formatted;
7f39d92f 379
61eb45ee 380 msg_formatted = grub_xasprintf (msg, nested ? msg_esc : "");
8b442f3f
VS
381 if (!msg_formatted)
382 return grub_errno;
7f39d92f 383
3be7f8de
VS
384 FOR_ACTIVE_TERM_OUTPUTS(term)
385 {
386 grub_normal_init_page (term);
387 grub_term_setcursor (term, 1);
701f1df9 388
3be7f8de 389 grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term);
701f1df9
VS
390 grub_putcode ('\n', term);
391 grub_putcode ('\n', term);
3be7f8de 392 }
7f39d92f 393 grub_free (msg_formatted);
a2c1332b 394
d558e6b5 395 return 0;
396}
397
d558e6b5 398static grub_err_t
6066889c 399grub_normal_read_line_real (char **line, int cont, int nested)
d558e6b5 400{
d56a6ac7 401 const char *prompt;
d558e6b5 402
6066889c 403 if (cont)
a9e9dc7c
VS
404 /* TRANSLATORS: it's command line prompt. */
405 prompt = _(">");
6066889c 406 else
a9e9dc7c
VS
407 /* TRANSLATORS: it's command line prompt. */
408 prompt = _("grub>");
d558e6b5 409
b09a4a8d
VS
410 if (!prompt)
411 return grub_errno;
d558e6b5 412
413 while (1)
414 {
2e713831
VS
415 *line = grub_cmdline_get (prompt);
416 if (*line)
a9e9dc7c 417 return 0;
d558e6b5 418
6066889c 419 if (cont || nested)
d558e6b5 420 {
2e713831 421 grub_free (*line);
d558e6b5 422 *line = 0;
423 return grub_errno;
424 }
425 }
a9e9dc7c 426
d558e6b5 427}
428
6066889c
VS
429static grub_err_t
430grub_normal_read_line (char **line, int cont)
431{
432 return grub_normal_read_line_real (line, cont, 0);
433}
434
f4c623e1
VS
435void
436grub_cmdline_run (int nested)
437{
438 grub_err_t err = GRUB_ERR_NONE;
439
440 err = grub_auth_check_authentication (NULL);
441
442 if (err)
443 {
444 grub_print_error ();
445 grub_errno = GRUB_ERR_NONE;
446 return;
447 }
448
6066889c 449 grub_normal_reader_init (nested);
f4c623e1
VS
450
451 while (1)
452 {
453 char *line;
454
6066889c
VS
455 if (grub_normal_exit_level)
456 break;
457
f4c623e1
VS
458 /* Print an error, if any. */
459 grub_print_error ();
460 grub_errno = GRUB_ERR_NONE;
461
6066889c 462 grub_normal_read_line_real (&line, 0, nested);
f4c623e1 463 if (! line)
2e713831 464 break;
f4c623e1 465
d56a6ac7 466 grub_normal_parse_line (line, grub_normal_read_line);
f4c623e1
VS
467 grub_free (line);
468 }
469}
d558e6b5 470
471static char *
472grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
473 const char *val)
474{
475 grub_set_more ((*val == '1'));
476 return grub_strdup (val);
477}
478
919e37b0
VS
479/* clear */
480static grub_err_t
481grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)),
482 int argc __attribute__ ((unused)),
483 char *argv[] __attribute__ ((unused)))
484{
485 grub_cls ();
486 return 0;
487}
488
489static grub_command_t cmd_clear;
490
0a239a82 491static void (*grub_xputs_saved) (const char *str);
5bfb6e71 492static const char *features[] = {
274416e8 493 "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint",
d9bef9bc
VS
494 "feature_default_font_path", "feature_all_video_module",
495 "feature_menuentry_id", "feature_menuentry_options"
5bfb6e71 496};
0a239a82 497
6d099807 498GRUB_MOD_INIT(normal)
ce5bf700 499{
5bfb6e71
VS
500 unsigned i;
501
fc2ef117
VS
502 /* Previously many modules depended on gzio. Be nice to user and load it. */
503 grub_dl_load ("gzio");
504
df895792 505 grub_normal_auth_init ();
2fbcbbc3 506 grub_context_init ();
20ebf732 507 grub_script_init ();
9284756e 508 grub_menu_init ();
2fbcbbc3 509
0a239a82
VS
510 grub_xputs_saved = grub_xputs;
511 grub_xputs = grub_xputs_normal;
512
ce5bf700 513 /* Normal mode shouldn't be unloaded. */
6d099807 514 if (mod)
515 grub_dl_ref (mod);
ce5bf700 516
919e37b0
VS
517 cmd_clear =
518 grub_register_command ("clear", grub_mini_cmd_clear,
519 0, N_("Clear the screen."));
520
4b13b216 521 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
5aded270 522
d558e6b5 523 grub_register_variable_hook ("pager", 0, grub_env_write_pager);
537dc9be 524 grub_env_export ("pager");
d558e6b5 525
ce5bf700 526 /* Register a command "normal" for the rescue mode. */
2e713831 527 grub_register_command ("normal", grub_cmd_normal,
d8b5cd40 528 0, N_("Enter normal mode."));
6066889c 529 grub_register_command ("normal_exit", grub_cmd_normal_exit,
d8b5cd40 530 0, N_("Exit from normal mode."));
ce5bf700 531
0ece25b1 532 /* Reload terminal colors when these variables are written to. */
533 grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
534 grub_register_variable_hook ("color_highlight", NULL, grub_env_write_color_highlight);
535
536 /* Preserve hooks after context changes. */
537 grub_env_export ("color_normal");
538 grub_env_export ("color_highlight");
681440aa
BC
539
540 /* Set default color names. */
541 grub_env_set ("color_normal", "white/black");
542 grub_env_set ("color_highlight", "black/white");
b38a4983 543
5bfb6e71
VS
544 for (i = 0; i < ARRAY_SIZE (features); i++)
545 {
546 grub_env_set (features[i], "y");
547 grub_env_export (features[i]);
548 }
92cd0f6e
VS
549 grub_env_set ("grub_cpu", GRUB_TARGET_CPU);
550 grub_env_export ("grub_cpu");
551 grub_env_set ("grub_platform", GRUB_PLATFORM);
552 grub_env_export ("grub_platform");
ce5bf700 553}
554
6d099807 555GRUB_MOD_FINI(normal)
ce5bf700 556{
2fbcbbc3 557 grub_context_fini ();
20ebf732 558 grub_script_fini ();
9284756e 559 grub_menu_fini ();
df895792 560 grub_normal_auth_fini ();
2fbcbbc3 561
0a239a82
VS
562 grub_xputs = grub_xputs_saved;
563
4b13b216 564 grub_set_history (0);
d558e6b5 565 grub_register_variable_hook ("pager", 0, 0);
566 grub_fs_autoload_hook = 0;
919e37b0 567 grub_unregister_command (cmd_clear);
ce5bf700 568}