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>
35 #include <grub/bufio.h>
37 GRUB_MOD_LICENSE ("GPLv3+");
39 #define GRUB_DEFAULT_HISTORY_SIZE 50
41 static int nested_level
= 0;
42 int grub_normal_exit_level
= 0;
45 grub_normal_free_menu (grub_menu_t menu
)
47 grub_menu_entry_t entry
= menu
->entry_list
;
51 grub_menu_entry_t next_entry
= entry
->next
;
56 struct grub_menu_entry_class
*class;
57 for (class = entry
->classes
; class; class = class->next
)
58 grub_free (class->name
);
59 grub_free (entry
->classes
);
64 for (i
= 0; entry
->args
[i
]; i
++)
65 grub_free (entry
->args
[i
]);
66 grub_free (entry
->args
);
69 grub_free ((void *) entry
->id
);
70 grub_free ((void *) entry
->users
);
71 grub_free ((void *) entry
->title
);
72 grub_free ((void *) entry
->sourcecode
);
78 grub_env_unset_menu ();
81 /* Helper for read_config_file. */
83 read_config_file_getline (char **line
, int cont
__attribute__ ((unused
)),
86 grub_file_t file
= data
;
92 *line
= buf
= grub_file_getline (file
);
102 return GRUB_ERR_NONE
;
106 read_config_file (const char *config
)
108 grub_file_t rawfile
, file
;
109 char *old_file
= 0, *old_dir
= 0;
110 char *config_dir
, *ptr
= 0;
115 newmenu
= grub_env_get_menu ();
118 newmenu
= grub_zalloc (sizeof (*newmenu
));
122 grub_env_set_menu (newmenu
);
125 /* Try to open the config file. */
126 rawfile
= grub_file_open (config
);
130 file
= grub_bufio_open (rawfile
, 0);
133 grub_file_close (rawfile
);
137 ctmp
= grub_env_get ("config_file");
139 old_file
= grub_strdup (ctmp
);
140 ctmp
= grub_env_get ("config_directory");
142 old_dir
= grub_strdup (ctmp
);
145 grub_env_set ("config_file", config
);
146 config_dir
= grub_strdup (config
);
150 /* $root is guranteed to be defined, otherwise open above would fail */
151 config_dir
= grub_xasprintf ("(%s)%s", grub_env_get ("root"), config
);
153 grub_env_set ("config_file", config_dir
);
157 ptr
= grub_strrchr (config_dir
, '/');
160 grub_env_set ("config_directory", config_dir
);
161 grub_free (config_dir
);
164 grub_env_export ("config_file");
165 grub_env_export ("config_directory");
171 /* Print an error, if any. */
173 grub_errno
= GRUB_ERR_NONE
;
175 if ((read_config_file_getline (&line
, 0, file
)) || (! line
))
178 grub_normal_parse_line (line
, read_config_file_getline
, file
);
183 grub_env_set ("config_file", old_file
);
185 grub_env_unset ("config_file");
187 grub_env_set ("config_directory", old_dir
);
189 grub_env_unset ("config_directory");
190 grub_free (old_file
);
193 grub_file_close (file
);
198 /* Initialize the screen. */
200 grub_normal_init_page (struct grub_term_output
*term
,
203 grub_ssize_t msg_len
;
206 grub_uint32_t
*unicode_msg
;
207 grub_uint32_t
*last_position
;
209 grub_term_cls (term
);
211 msg_formatted
= grub_xasprintf (_("GNU GRUB version %s"), PACKAGE_VERSION
);
215 msg_len
= grub_utf8_to_ucs4_alloc (msg_formatted
,
216 &unicode_msg
, &last_position
);
217 grub_free (msg_formatted
);
224 posx
= grub_getstringwidth (unicode_msg
, last_position
, term
);
225 posx
= ((int) grub_term_width (term
) - posx
) / 2;
228 grub_term_gotoxy (term
, (struct grub_term_coordinate
) { posx
, y
});
230 grub_print_ucs4 (unicode_msg
, last_position
, 0, 0, term
);
231 grub_putcode ('\n', term
);
232 grub_putcode ('\n', term
);
233 grub_free (unicode_msg
);
237 read_lists (const char *val
)
239 if (! grub_no_modules
)
241 read_command_list (val
);
243 read_crypto_list (val
);
244 read_terminal_list (val
);
246 grub_gettext_reread_prefix (val
);
250 read_lists_hook (struct grub_env_var
*var
__attribute__ ((unused
)),
254 return val
? grub_strdup (val
) : NULL
;
257 /* Read the config file CONFIG and execute the menu interface or
258 the command line interface if BATCH is false. */
260 grub_normal_execute (const char *config
, int nested
, int batch
)
262 grub_menu_t menu
= 0;
267 prefix
= grub_env_get ("prefix");
269 grub_register_variable_hook ("prefix", NULL
, read_lists_hook
);
272 grub_boot_time ("Executing config file");
276 menu
= read_config_file (config
);
278 /* Ignore any error. */
279 grub_errno
= GRUB_ERR_NONE
;
282 grub_boot_time ("Executed config file");
286 if (menu
&& menu
->size
)
289 grub_boot_time ("Entering menu");
290 grub_show_menu (menu
, nested
, 0);
292 grub_normal_free_menu (menu
);
297 /* This starts the normal mode. */
299 grub_enter_normal_mode (const char *config
)
301 grub_boot_time ("Entering normal mode");
303 grub_normal_execute (config
, 0, 0);
304 grub_boot_time ("Entering shell");
305 grub_cmdline_run (0, 1);
307 if (grub_normal_exit_level
)
308 grub_normal_exit_level
--;
309 grub_boot_time ("Exiting normal mode");
312 /* Enter normal mode from rescue mode. */
314 grub_cmd_normal (struct grub_command
*cmd
__attribute__ ((unused
)),
315 int argc
, char *argv
[])
319 /* Guess the config filename. It is necessary to make CONFIG static,
320 so that it won't get broken by longjmp. */
324 prefix
= grub_env_get ("prefix");
327 config
= grub_xasprintf ("%s/grub.cfg", prefix
);
331 grub_enter_normal_mode (config
);
335 grub_enter_normal_mode (0);
338 grub_enter_normal_mode (argv
[0]);
344 /* Exit from normal mode to rescue mode. */
346 grub_cmd_normal_exit (struct grub_command
*cmd
__attribute__ ((unused
)),
347 int argc
__attribute__ ((unused
)),
348 char *argv
[] __attribute__ ((unused
)))
350 if (nested_level
<= grub_normal_exit_level
)
351 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "not in normal environment");
352 grub_normal_exit_level
++;
353 return GRUB_ERR_NONE
;
357 grub_normal_reader_init (int nested
)
359 struct grub_term_output
*term
;
360 const char *msg_esc
= _("ESC at any time exits.");
363 msg_formatted
= grub_xasprintf (_("Minimal BASH-like line editing is supported. For "
364 "the first word, TAB lists possible command completions. Anywhere "
365 "else TAB lists possible device or file completions. %s"),
366 nested
? msg_esc
: "");
370 FOR_ACTIVE_TERM_OUTPUTS(term
)
372 grub_normal_init_page (term
, 1);
373 grub_term_setcursor (term
, 1);
375 if (grub_term_width (term
) > 3 + STANDARD_MARGIN
+ 20)
376 grub_print_message_indented (msg_formatted
, 3, STANDARD_MARGIN
, term
);
378 grub_print_message_indented (msg_formatted
, 0, 0, term
);
379 grub_putcode ('\n', term
);
380 grub_putcode ('\n', term
);
381 grub_putcode ('\n', term
);
383 grub_free (msg_formatted
);
389 grub_normal_read_line_real (char **line
, int cont
, int nested
)
394 /* TRANSLATORS: it's command line prompt. */
397 /* TRANSLATORS: it's command line prompt. */
405 *line
= grub_cmdline_get (prompt
);
420 grub_normal_read_line (char **line
, int cont
,
421 void *data
__attribute__ ((unused
)))
423 return grub_normal_read_line_real (line
, cont
, 0);
427 grub_cmdline_run (int nested
, int force_auth
)
429 grub_err_t err
= GRUB_ERR_NONE
;
433 err
= grub_auth_check_authentication (NULL
);
435 while (err
&& force_auth
);
440 grub_errno
= GRUB_ERR_NONE
;
444 grub_normal_reader_init (nested
);
450 if (grub_normal_exit_level
)
453 /* Print an error, if any. */
455 grub_errno
= GRUB_ERR_NONE
;
457 grub_normal_read_line_real (&line
, 0, nested
);
461 grub_normal_parse_line (line
, grub_normal_read_line
, NULL
);
467 grub_env_write_pager (struct grub_env_var
*var
__attribute__ ((unused
)),
470 grub_set_more ((*val
== '1'));
471 return grub_strdup (val
);
476 grub_mini_cmd_clear (struct grub_command
*cmd
__attribute__ ((unused
)),
477 int argc
__attribute__ ((unused
)),
478 char *argv
[] __attribute__ ((unused
)))
484 static grub_command_t cmd_clear
;
486 static void (*grub_xputs_saved
) (const char *str
);
487 static const char *features
[] = {
488 "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint",
489 "feature_default_font_path", "feature_all_video_module",
490 "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
491 "feature_nativedisk_cmd", "feature_timeout_style"
494 GRUB_MOD_INIT(normal
)
498 grub_boot_time ("Preparing normal module");
500 /* Previously many modules depended on gzio. Be nice to user and load it. */
501 grub_dl_load ("gzio");
504 grub_normal_auth_init ();
505 grub_context_init ();
509 grub_xputs_saved
= grub_xputs
;
510 grub_xputs
= grub_xputs_normal
;
512 /* Normal mode shouldn't be unloaded. */
517 grub_register_command ("clear", grub_mini_cmd_clear
,
518 0, N_("Clear the screen."));
520 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE
);
522 grub_register_variable_hook ("pager", 0, grub_env_write_pager
);
523 grub_env_export ("pager");
525 /* Register a command "normal" for the rescue mode. */
526 grub_register_command ("normal", grub_cmd_normal
,
527 0, N_("Enter normal mode."));
528 grub_register_command ("normal_exit", grub_cmd_normal_exit
,
529 0, N_("Exit from normal mode."));
531 /* Reload terminal colors when these variables are written to. */
532 grub_register_variable_hook ("color_normal", NULL
, grub_env_write_color_normal
);
533 grub_register_variable_hook ("color_highlight", NULL
, grub_env_write_color_highlight
);
535 /* Preserve hooks after context changes. */
536 grub_env_export ("color_normal");
537 grub_env_export ("color_highlight");
539 /* Set default color names. */
540 grub_env_set ("color_normal", "light-gray/black");
541 grub_env_set ("color_highlight", "black/light-gray");
543 for (i
= 0; i
< ARRAY_SIZE (features
); i
++)
545 grub_env_set (features
[i
], "y");
546 grub_env_export (features
[i
]);
548 grub_env_set ("grub_cpu", GRUB_TARGET_CPU
);
549 grub_env_export ("grub_cpu");
550 grub_env_set ("grub_platform", GRUB_PLATFORM
);
551 grub_env_export ("grub_platform");
553 grub_boot_time ("Normal module prepared");
556 GRUB_MOD_FINI(normal
)
558 grub_context_fini ();
561 grub_normal_auth_fini ();
563 grub_xputs
= grub_xputs_saved
;
565 grub_set_history (0);
566 grub_register_variable_hook ("pager", 0, 0);
567 grub_fs_autoload_hook
= 0;
568 grub_unregister_command (cmd_clear
);