1 /* main.c - the normal mode main routine */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
6 * GRUB 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 3 of the License, or
9 * (at your option) any later version.
11 * GRUB 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.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/kernel.h>
21 #include <grub/normal.h>
23 #include <grub/misc.h>
24 #include <grub/file.h>
26 #include <grub/term.h>
28 #include <grub/parser.h>
29 #include <grub/reader.h>
30 #include <grub/menu_viewer.h>
31 #include <grub/auth.h>
32 #include <grub/i18n.h>
33 #include <grub/charset.h>
34 #include <grub/script_sh.h>
36 GRUB_MOD_LICENSE ("GPLv3+");
38 #define GRUB_DEFAULT_HISTORY_SIZE 50
40 static int nested_level
= 0;
41 int grub_normal_exit_level
= 0;
43 /* Read a line from the file FILE. */
45 grub_file_getline (grub_file_t file
)
53 /* Initially locate some space. */
54 cmdline
= grub_malloc (max_len
);
60 if (grub_file_read (file
, &c
, 1) != 1)
63 /* Skip all carriage returns. */
67 /* Replace tabs with spaces. */
71 /* The previous is a backslash, then... */
74 /* If it is a newline, replace it with a space and continue. */
79 /* Go back to overwrite the backslash. */
92 if (! grub_isspace (c
))
99 char *old_cmdline
= cmdline
;
100 max_len
= max_len
* 2;
101 cmdline
= grub_realloc (cmdline
, max_len
);
104 grub_free (old_cmdline
);
118 /* If the buffer is empty, don't return anything at all. */
129 grub_normal_free_menu (grub_menu_t menu
)
131 grub_menu_entry_t entry
= menu
->entry_list
;
135 grub_menu_entry_t next_entry
= entry
->next
;
137 grub_free ((void *) entry
->title
);
138 grub_free ((void *) entry
->sourcecode
);
143 grub_env_unset_menu ();
147 read_config_file (const char *config
)
151 auto grub_err_t
getline (char **line
, int cont
);
152 grub_err_t
getline (char **line
, int cont
__attribute__ ((unused
)))
158 *line
= buf
= grub_file_getline (file
);
168 return GRUB_ERR_NONE
;
173 newmenu
= grub_env_get_menu ();
176 newmenu
= grub_zalloc (sizeof (*newmenu
));
180 grub_env_set_menu (newmenu
);
183 /* Try to open the config file. */
184 file
= grub_file_open (config
);
192 /* Print an error, if any. */
194 grub_errno
= GRUB_ERR_NONE
;
196 if ((getline (&line
, 0)) || (! line
))
199 grub_normal_parse_line (line
, getline
);
203 grub_file_close (file
);
208 /* Initialize the screen. */
210 grub_normal_init_page (struct grub_term_output
*term
)
214 const char *msg
= _("GNU GRUB version %s");
216 grub_uint32_t
*unicode_msg
;
217 grub_uint32_t
*last_position
;
219 grub_term_cls (term
);
221 msg_formatted
= grub_xasprintf (msg
, PACKAGE_VERSION
);
225 msg_len
= grub_utf8_to_ucs4_alloc (msg_formatted
,
226 &unicode_msg
, &last_position
);
227 grub_free (msg_formatted
);
234 posx
= grub_getstringwidth (unicode_msg
, last_position
, term
);
235 posx
= (grub_term_width (term
) - posx
) / 2;
236 grub_term_gotoxy (term
, posx
, 1);
238 grub_print_ucs4 (unicode_msg
, last_position
, 0, 0, term
);
239 grub_putcode ('\n', term
);
240 grub_putcode ('\n', term
);
241 grub_free (unicode_msg
);
245 read_lists (const char *val
)
247 if (! grub_no_autoload
)
249 read_command_list (val
);
251 read_crypto_list (val
);
252 read_terminal_list (val
);
257 read_lists_hook (struct grub_env_var
*var
__attribute__ ((unused
)),
261 return val
? grub_strdup (val
) : NULL
;
264 /* Read the config file CONFIG and execute the menu interface or
265 the command line interface if BATCH is false. */
267 grub_normal_execute (const char *config
, int nested
, int batch
)
269 grub_menu_t menu
= 0;
274 prefix
= grub_env_get ("prefix");
276 grub_register_variable_hook ("prefix", NULL
, read_lists_hook
);
281 menu
= read_config_file (config
);
283 /* Ignore any error. */
284 grub_errno
= GRUB_ERR_NONE
;
289 if (menu
&& menu
->size
)
291 grub_show_menu (menu
, nested
, 0);
293 grub_normal_free_menu (menu
);
298 /* This starts the normal mode. */
300 grub_enter_normal_mode (const char *config
)
303 grub_normal_execute (config
, 0, 0);
304 grub_cmdline_run (0);
306 if (grub_normal_exit_level
)
307 grub_normal_exit_level
--;
310 /* Enter normal mode from rescue mode. */
312 grub_cmd_normal (struct grub_command
*cmd
__attribute__ ((unused
)),
313 int argc
, char *argv
[])
317 /* Guess the config filename. It is necessary to make CONFIG static,
318 so that it won't get broken by longjmp. */
322 prefix
= grub_env_get ("prefix");
325 config
= grub_xasprintf ("%s/grub.cfg", prefix
);
329 grub_enter_normal_mode (config
);
333 grub_enter_normal_mode (0);
336 grub_enter_normal_mode (argv
[0]);
342 /* Exit from normal mode to rescue mode. */
344 grub_cmd_normal_exit (struct grub_command
*cmd
__attribute__ ((unused
)),
345 int argc
__attribute__ ((unused
)),
346 char *argv
[] __attribute__ ((unused
)))
348 if (nested_level
<= grub_normal_exit_level
)
349 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "not in normal environment");
350 grub_normal_exit_level
++;
351 return GRUB_ERR_NONE
;
355 grub_normal_reader_init (int nested
)
357 struct grub_term_output
*term
;
358 const char *msg
= _("Minimal BASH-like line editing is supported. For "
359 "the first word, TAB lists possible command completions. Anywhere "
360 "else TAB lists possible device or file completions. %s");
361 const char *msg_esc
= _("ESC at any time exits.");
364 msg_formatted
= grub_xasprintf (msg
, nested
? msg_esc
: "");
368 FOR_ACTIVE_TERM_OUTPUTS(term
)
370 grub_normal_init_page (term
);
371 grub_term_setcursor (term
, 1);
373 grub_print_message_indented (msg_formatted
, 3, STANDARD_MARGIN
, term
);
374 grub_putcode ('\n', term
);
375 grub_putcode ('\n', term
);
377 grub_free (msg_formatted
);
383 grub_normal_read_line_real (char **line
, int cont
, int nested
)
388 /* TRANSLATORS: it's command line prompt. */
391 /* TRANSLATORS: it's command line prompt. */
399 *line
= grub_cmdline_get (prompt
);
414 grub_normal_read_line (char **line
, int cont
)
416 return grub_normal_read_line_real (line
, cont
, 0);
420 grub_cmdline_run (int nested
)
422 grub_err_t err
= GRUB_ERR_NONE
;
424 err
= grub_auth_check_authentication (NULL
);
429 grub_errno
= GRUB_ERR_NONE
;
433 grub_normal_reader_init (nested
);
439 if (grub_normal_exit_level
)
442 /* Print an error, if any. */
444 grub_errno
= GRUB_ERR_NONE
;
446 grub_normal_read_line_real (&line
, 0, nested
);
450 grub_normal_parse_line (line
, grub_normal_read_line
);
456 grub_env_write_pager (struct grub_env_var
*var
__attribute__ ((unused
)),
459 grub_set_more ((*val
== '1'));
460 return grub_strdup (val
);
465 grub_mini_cmd_clear (struct grub_command
*cmd
__attribute__ ((unused
)),
466 int argc
__attribute__ ((unused
)),
467 char *argv
[] __attribute__ ((unused
)))
473 static grub_command_t cmd_clear
;
475 static void (*grub_xputs_saved
) (const char *str
);
476 static const char *features
[] = {
477 "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint"
480 GRUB_MOD_INIT(normal
)
484 /* Previously many modules depended on gzio. Be nice to user and load it. */
485 grub_dl_load ("gzio");
487 grub_normal_auth_init ();
488 grub_context_init ();
492 grub_xputs_saved
= grub_xputs
;
493 grub_xputs
= grub_xputs_normal
;
495 /* Normal mode shouldn't be unloaded. */
500 grub_register_command ("clear", grub_mini_cmd_clear
,
501 0, N_("Clear the screen."));
503 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE
);
505 grub_register_variable_hook ("pager", 0, grub_env_write_pager
);
506 grub_env_export ("pager");
508 /* Register a command "normal" for the rescue mode. */
509 grub_register_command ("normal", grub_cmd_normal
,
510 0, N_("Enter normal mode."));
511 grub_register_command ("normal_exit", grub_cmd_normal_exit
,
512 0, N_("Exit from normal mode."));
514 /* Reload terminal colors when these variables are written to. */
515 grub_register_variable_hook ("color_normal", NULL
, grub_env_write_color_normal
);
516 grub_register_variable_hook ("color_highlight", NULL
, grub_env_write_color_highlight
);
518 /* Preserve hooks after context changes. */
519 grub_env_export ("color_normal");
520 grub_env_export ("color_highlight");
522 /* Set default color names. */
523 grub_env_set ("color_normal", "white/black");
524 grub_env_set ("color_highlight", "black/white");
526 for (i
= 0; i
< ARRAY_SIZE (features
); i
++)
528 grub_env_set (features
[i
], "y");
529 grub_env_export (features
[i
]);
531 grub_env_set ("grub_cpu", GRUB_TARGET_CPU
);
532 grub_env_export ("grub_cpu");
533 grub_env_set ("grub_platform", GRUB_PLATFORM
);
534 grub_env_export ("grub_platform");
537 GRUB_MOD_FINI(normal
)
539 grub_context_fini ();
542 grub_normal_auth_fini ();
544 grub_xputs
= grub_xputs_saved
;
546 grub_set_history (0);
547 grub_register_variable_hook ("pager", 0, 0);
548 grub_fs_autoload_hook
= 0;
549 grub_unregister_command (cmd_clear
);