]> git.proxmox.com Git - grub2.git/blame - grub-core/normal/main.c
Lift 255x255 erminal sie restriction to 65535x65535. Also change from
[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
684aef11 68 if (pos + 1 >= 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);
03f7c8c3 130 grub_free (entry);
ce5bf700 131 entry = next_entry;
132 }
133
4b13b216 134 grub_free (menu);
2fbcbbc3 135 grub_env_unset_menu ();
ce5bf700 136}
137
09fd6d82
CW
138/* Helper for read_config_file. */
139static grub_err_t
140read_config_file_getline (char **line, int cont __attribute__ ((unused)),
141 void *data)
ce5bf700 142{
09fd6d82 143 grub_file_t file = data;
b39f9d20 144
09fd6d82 145 while (1)
77c4a393 146 {
09fd6d82 147 char *buf;
d558e6b5 148
09fd6d82
CW
149 *line = buf = grub_file_getline (file);
150 if (! buf)
151 return grub_errno;
d558e6b5 152
09fd6d82
CW
153 if (buf[0] == '#')
154 grub_free (*line);
155 else
156 break;
77c4a393 157 }
158
09fd6d82
CW
159 return GRUB_ERR_NONE;
160}
161
162static grub_menu_t
163read_config_file (const char *config)
164{
165 grub_file_t file;
14af86e4 166 char *old_file = 0, *old_dir = 0;
09fd6d82 167 char *config_dir, *ptr = 0;
14af86e4 168 const char *ctmp;
09fd6d82 169
77c4a393 170 grub_menu_t newmenu;
171
2fbcbbc3 172 newmenu = grub_env_get_menu ();
d558e6b5 173 if (! newmenu)
a8aa5762 174 {
eab58da2 175 newmenu = grub_zalloc (sizeof (*newmenu));
a8aa5762 176 if (! newmenu)
177 return 0;
d558e6b5 178
2fbcbbc3 179 grub_env_set_menu (newmenu);
a8aa5762 180 }
77c4a393 181
ce5bf700 182 /* Try to open the config file. */
4b13b216 183 file = grub_file_open (config);
ce5bf700 184 if (! file)
185 return 0;
186
14af86e4
VS
187 ctmp = grub_env_get ("config_file");
188 if (ctmp)
189 old_file = grub_strdup (ctmp);
190 ctmp = grub_env_get ("config_directory");
191 if (ctmp)
192 old_dir = grub_strdup (ctmp);
40e80b94
VS
193 grub_env_set ("config_file", config);
194 config_dir = grub_strdup (config);
195 if (config_dir)
196 ptr = grub_strrchr (config_dir, '/');
197 if (ptr)
198 *ptr = 0;
199 grub_env_set ("config_directory", config_dir);
03f7c8c3 200 grub_free (config_dir);
40e80b94
VS
201
202 grub_env_export ("config_file");
203 grub_env_export ("config_directory");
204
f4c623e1
VS
205 while (1)
206 {
207 char *line;
208
209 /* Print an error, if any. */
210 grub_print_error ();
211 grub_errno = GRUB_ERR_NONE;
212
09fd6d82 213 if ((read_config_file_getline (&line, 0, file)) || (! line))
f4c623e1
VS
214 break;
215
09fd6d82 216 grub_normal_parse_line (line, read_config_file_getline, file);
f4c623e1
VS
217 grub_free (line);
218 }
219
40e80b94
VS
220 if (old_file)
221 grub_env_set ("config_file", old_file);
222 else
223 grub_env_unset ("config_file");
224 if (old_dir)
225 grub_env_set ("config_directory", old_dir);
226 else
227 grub_env_unset ("config_directory");
14af86e4
VS
228 grub_free (old_file);
229 grub_free (old_dir);
40e80b94 230
77c4a393 231 grub_file_close (file);
6de2ee99 232
65f201ad 233 return newmenu;
ce5bf700 234}
235
ce5bf700 236/* Initialize the screen. */
237void
cdce14fa
VS
238grub_normal_init_page (struct grub_term_output *term,
239 int y)
ce5bf700 240{
8b282ad2 241 grub_ssize_t msg_len;
b99518d1 242 int posx;
243 const char *msg = _("GNU GRUB version %s");
8b442f3f 244 char *msg_formatted;
b99518d1 245 grub_uint32_t *unicode_msg;
246 grub_uint32_t *last_position;
a2c1332b 247
fa533ebb 248 grub_term_cls (term);
8b442f3f 249
61eb45ee 250 msg_formatted = grub_xasprintf (msg, PACKAGE_VERSION);
8b442f3f
VS
251 if (!msg_formatted)
252 return;
253
a2c1332b 254 msg_len = grub_utf8_to_ucs4_alloc (msg_formatted,
b99518d1 255 &unicode_msg, &last_position);
4a8a763c 256 grub_free (msg_formatted);
a2c1332b 257
b99518d1 258 if (msg_len < 0)
259 {
260 return;
261 }
b362c9e9 262
2e713831 263 posx = grub_getstringwidth (unicode_msg, last_position, term);
cdce14fa
VS
264 posx = ((int) grub_term_width (term) - posx) / 2;
265 if (posx < 0)
266 posx = 0;
e89c2d48 267 grub_term_gotoxy (term, (struct grub_term_coordinate) { posx, y });
b362c9e9 268
f588f1c8 269 grub_print_ucs4 (unicode_msg, last_position, 0, 0, term);
701f1df9
VS
270 grub_putcode ('\n', term);
271 grub_putcode ('\n', term);
b99518d1 272 grub_free (unicode_msg);
ce5bf700 273}
274
027de555
VS
275static void
276read_lists (const char *val)
277{
a6393224 278 if (! grub_no_modules)
72539694
BC
279 {
280 read_command_list (val);
281 read_fs_list (val);
282 read_crypto_list (val);
283 read_terminal_list (val);
284 }
17f38c0f 285 grub_gettext_reread_prefix (val);
027de555
VS
286}
287
e880248e 288static char *
027de555
VS
289read_lists_hook (struct grub_env_var *var __attribute__ ((unused)),
290 const char *val)
e880248e 291{
027de555 292 read_lists (val);
e880248e
RM
293 return val ? grub_strdup (val) : NULL;
294}
39c9d41d 295
4241d2b1 296/* Read the config file CONFIG and execute the menu interface or
297 the command line interface if BATCH is false. */
ce5bf700 298void
f04f02e4 299grub_normal_execute (const char *config, int nested, int batch)
ce5bf700 300{
4b13b216 301 grub_menu_t menu = 0;
3fa06487 302 const char *prefix;
ce5bf700 303
3fa06487
CW
304 if (! nested)
305 {
306 prefix = grub_env_get ("prefix");
307 read_lists (prefix);
308 grub_register_variable_hook ("prefix", NULL, read_lists_hook);
3fa06487 309 }
d558e6b5 310
e744219b
VS
311 grub_boot_time ("Executing config file");
312
ce5bf700 313 if (config)
314 {
d558e6b5 315 menu = read_config_file (config);
ce5bf700 316
317 /* Ignore any error. */
4b13b216 318 grub_errno = GRUB_ERR_NONE;
ce5bf700 319 }
320
e744219b
VS
321 grub_boot_time ("Executed config file");
322
f04f02e4 323 if (! batch)
93f3a1d8 324 {
f04f02e4 325 if (menu && menu->size)
d558e6b5 326 {
e744219b
VS
327
328 grub_boot_time ("Entering menu");
dcb883b1 329 grub_show_menu (menu, nested, 0);
d558e6b5 330 if (nested)
fc55cc4c 331 grub_normal_free_menu (menu);
d558e6b5 332 }
93f3a1d8 333 }
ce5bf700 334}
335
d558e6b5 336/* This starts the normal mode. */
337void
338grub_enter_normal_mode (const char *config)
b1b797cb 339{
e744219b 340 grub_boot_time ("Entering normal mode");
6066889c 341 nested_level++;
d558e6b5 342 grub_normal_execute (config, 0, 0);
e744219b 343 grub_boot_time ("Entering shell");
6066889c
VS
344 grub_cmdline_run (0);
345 nested_level--;
346 if (grub_normal_exit_level)
347 grub_normal_exit_level--;
e744219b 348 grub_boot_time ("Exiting normal mode");
b1b797cb 349}
350
ce5bf700 351/* Enter normal mode from rescue mode. */
b1b797cb 352static grub_err_t
2e713831 353grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
b1b797cb 354 int argc, char *argv[])
ce5bf700 355{
356 if (argc == 0)
357 {
5f3607e0 358 /* Guess the config filename. It is necessary to make CONFIG static,
359 so that it won't get broken by longjmp. */
2e713831 360 char *config;
ce5bf700 361 const char *prefix;
b39f9d20 362
4b13b216 363 prefix = grub_env_get ("prefix");
ce5bf700 364 if (prefix)
365 {
61eb45ee 366 config = grub_xasprintf ("%s/grub.cfg", prefix);
ce5bf700 367 if (! config)
b1b797cb 368 goto quit;
ce5bf700 369
4b13b216 370 grub_enter_normal_mode (config);
371 grub_free (config);
ce5bf700 372 }
373 else
4b13b216 374 grub_enter_normal_mode (0);
ce5bf700 375 }
376 else
4b13b216 377 grub_enter_normal_mode (argv[0]);
b1b797cb 378
379quit:
b1b797cb 380 return 0;
ce5bf700 381}
382
6066889c 383/* Exit from normal mode to rescue mode. */
d558e6b5 384static grub_err_t
6066889c
VS
385grub_cmd_normal_exit (struct grub_command *cmd __attribute__ ((unused)),
386 int argc __attribute__ ((unused)),
387 char *argv[] __attribute__ ((unused)))
d558e6b5 388{
6066889c
VS
389 if (nested_level <= grub_normal_exit_level)
390 return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in normal environment");
391 grub_normal_exit_level++;
392 return GRUB_ERR_NONE;
d558e6b5 393}
394
395static grub_err_t
6066889c 396grub_normal_reader_init (int nested)
d558e6b5 397{
f4c623e1 398 struct grub_term_output *term;
7f39d92f 399 const char *msg = _("Minimal BASH-like line editing is supported. For "
400 "the first word, TAB lists possible command completions. Anywhere "
401 "else TAB lists possible device or file completions. %s");
7f39d92f 402 const char *msg_esc = _("ESC at any time exits.");
8b442f3f 403 char *msg_formatted;
7f39d92f 404
61eb45ee 405 msg_formatted = grub_xasprintf (msg, nested ? msg_esc : "");
8b442f3f
VS
406 if (!msg_formatted)
407 return grub_errno;
7f39d92f 408
3be7f8de
VS
409 FOR_ACTIVE_TERM_OUTPUTS(term)
410 {
cdce14fa 411 grub_normal_init_page (term, 1);
3be7f8de 412 grub_term_setcursor (term, 1);
701f1df9 413
cdce14fa
VS
414 if (grub_term_width (term) > 3 + STANDARD_MARGIN + 20)
415 grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term);
416 else
417 grub_print_message_indented (msg_formatted, 0, 0, term);
418 grub_putcode ('\n', term);
701f1df9
VS
419 grub_putcode ('\n', term);
420 grub_putcode ('\n', term);
3be7f8de 421 }
7f39d92f 422 grub_free (msg_formatted);
a2c1332b 423
d558e6b5 424 return 0;
425}
426
d558e6b5 427static grub_err_t
6066889c 428grub_normal_read_line_real (char **line, int cont, int nested)
d558e6b5 429{
d56a6ac7 430 const char *prompt;
d558e6b5 431
6066889c 432 if (cont)
a9e9dc7c
VS
433 /* TRANSLATORS: it's command line prompt. */
434 prompt = _(">");
6066889c 435 else
a9e9dc7c
VS
436 /* TRANSLATORS: it's command line prompt. */
437 prompt = _("grub>");
d558e6b5 438
b09a4a8d
VS
439 if (!prompt)
440 return grub_errno;
d558e6b5 441
442 while (1)
443 {
2e713831
VS
444 *line = grub_cmdline_get (prompt);
445 if (*line)
a9e9dc7c 446 return 0;
d558e6b5 447
6066889c 448 if (cont || nested)
d558e6b5 449 {
2e713831 450 grub_free (*line);
d558e6b5 451 *line = 0;
452 return grub_errno;
453 }
454 }
a9e9dc7c 455
d558e6b5 456}
457
6066889c 458static grub_err_t
09fd6d82
CW
459grub_normal_read_line (char **line, int cont,
460 void *data __attribute__ ((unused)))
6066889c
VS
461{
462 return grub_normal_read_line_real (line, cont, 0);
463}
464
f4c623e1
VS
465void
466grub_cmdline_run (int nested)
467{
468 grub_err_t err = GRUB_ERR_NONE;
469
470 err = grub_auth_check_authentication (NULL);
471
472 if (err)
473 {
474 grub_print_error ();
475 grub_errno = GRUB_ERR_NONE;
476 return;
477 }
478
6066889c 479 grub_normal_reader_init (nested);
f4c623e1
VS
480
481 while (1)
482 {
483 char *line;
484
6066889c
VS
485 if (grub_normal_exit_level)
486 break;
487
f4c623e1
VS
488 /* Print an error, if any. */
489 grub_print_error ();
490 grub_errno = GRUB_ERR_NONE;
491
6066889c 492 grub_normal_read_line_real (&line, 0, nested);
f4c623e1 493 if (! line)
2e713831 494 break;
f4c623e1 495
09fd6d82 496 grub_normal_parse_line (line, grub_normal_read_line, NULL);
f4c623e1
VS
497 grub_free (line);
498 }
499}
d558e6b5 500
501static char *
502grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
503 const char *val)
504{
505 grub_set_more ((*val == '1'));
506 return grub_strdup (val);
507}
508
919e37b0
VS
509/* clear */
510static grub_err_t
511grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)),
512 int argc __attribute__ ((unused)),
513 char *argv[] __attribute__ ((unused)))
514{
515 grub_cls ();
516 return 0;
517}
518
519static grub_command_t cmd_clear;
520
0a239a82 521static void (*grub_xputs_saved) (const char *str);
5bfb6e71 522static const char *features[] = {
274416e8 523 "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint",
d9bef9bc 524 "feature_default_font_path", "feature_all_video_module",
7cd0df84
VS
525 "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
526 "feature_nativedisk_cmd"
5bfb6e71 527};
0a239a82 528
6d099807 529GRUB_MOD_INIT(normal)
ce5bf700 530{
5bfb6e71
VS
531 unsigned i;
532
e744219b
VS
533 grub_boot_time ("Preparing normal module");
534
fc2ef117
VS
535 /* Previously many modules depended on gzio. Be nice to user and load it. */
536 grub_dl_load ("gzio");
377c98cb 537 grub_errno = 0;
fc2ef117 538
df895792 539 grub_normal_auth_init ();
2fbcbbc3 540 grub_context_init ();
20ebf732 541 grub_script_init ();
9284756e 542 grub_menu_init ();
2fbcbbc3 543
0a239a82
VS
544 grub_xputs_saved = grub_xputs;
545 grub_xputs = grub_xputs_normal;
546
ce5bf700 547 /* Normal mode shouldn't be unloaded. */
6d099807 548 if (mod)
549 grub_dl_ref (mod);
ce5bf700 550
919e37b0
VS
551 cmd_clear =
552 grub_register_command ("clear", grub_mini_cmd_clear,
553 0, N_("Clear the screen."));
554
4b13b216 555 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
5aded270 556
d558e6b5 557 grub_register_variable_hook ("pager", 0, grub_env_write_pager);
537dc9be 558 grub_env_export ("pager");
d558e6b5 559
ce5bf700 560 /* Register a command "normal" for the rescue mode. */
2e713831 561 grub_register_command ("normal", grub_cmd_normal,
d8b5cd40 562 0, N_("Enter normal mode."));
6066889c 563 grub_register_command ("normal_exit", grub_cmd_normal_exit,
d8b5cd40 564 0, N_("Exit from normal mode."));
ce5bf700 565
0ece25b1 566 /* Reload terminal colors when these variables are written to. */
567 grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
568 grub_register_variable_hook ("color_highlight", NULL, grub_env_write_color_highlight);
569
570 /* Preserve hooks after context changes. */
571 grub_env_export ("color_normal");
572 grub_env_export ("color_highlight");
681440aa
BC
573
574 /* Set default color names. */
575 grub_env_set ("color_normal", "white/black");
576 grub_env_set ("color_highlight", "black/white");
b38a4983 577
5bfb6e71
VS
578 for (i = 0; i < ARRAY_SIZE (features); i++)
579 {
580 grub_env_set (features[i], "y");
581 grub_env_export (features[i]);
582 }
92cd0f6e
VS
583 grub_env_set ("grub_cpu", GRUB_TARGET_CPU);
584 grub_env_export ("grub_cpu");
585 grub_env_set ("grub_platform", GRUB_PLATFORM);
586 grub_env_export ("grub_platform");
e744219b
VS
587
588 grub_boot_time ("Normal module prepared");
ce5bf700 589}
590
6d099807 591GRUB_MOD_FINI(normal)
ce5bf700 592{
2fbcbbc3 593 grub_context_fini ();
20ebf732 594 grub_script_fini ();
9284756e 595 grub_menu_fini ();
df895792 596 grub_normal_auth_fini ();
2fbcbbc3 597
0a239a82
VS
598 grub_xputs = grub_xputs_saved;
599
4b13b216 600 grub_set_history (0);
d558e6b5 601 grub_register_variable_hook ("pager", 0, 0);
602 grub_fs_autoload_hook = 0;
919e37b0 603 grub_unregister_command (cmd_clear);
ce5bf700 604}