Fix cross compilation (e.g. on Darwin). Following changes to make.tmpl,
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / normal / main.c
blob623b93ba624a9ab2a0a4f43bba4253819b41c31f
1 /* main.c - the normal mode main routine */
2 /*
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>
22 #include <grub/dl.h>
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>
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;
44 void
45 grub_normal_free_menu (grub_menu_t menu)
47 grub_menu_entry_t entry = menu->entry_list;
49 while (entry)
51 grub_menu_entry_t next_entry = entry->next;
52 grub_size_t i;
54 if (entry->classes)
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);
62 if (entry->args)
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);
73 grub_free (entry);
74 entry = next_entry;
77 grub_free (menu);
78 grub_env_unset_menu ();
81 /* Helper for read_config_file. */
82 static grub_err_t
83 read_config_file_getline (char **line, int cont __attribute__ ((unused)),
84 void *data)
86 grub_file_t file = data;
88 while (1)
90 char *buf;
92 *line = buf = grub_file_getline (file);
93 if (! buf)
94 return grub_errno;
96 if (buf[0] == '#')
97 grub_free (*line);
98 else
99 break;
102 return GRUB_ERR_NONE;
105 static grub_menu_t
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;
111 const char *ctmp;
113 grub_menu_t newmenu;
115 newmenu = grub_env_get_menu ();
116 if (! newmenu)
118 newmenu = grub_zalloc (sizeof (*newmenu));
119 if (! newmenu)
120 return 0;
122 grub_env_set_menu (newmenu);
125 /* Try to open the config file. */
126 rawfile = grub_file_open (config);
127 if (! rawfile)
128 return 0;
130 file = grub_bufio_open (rawfile, 0);
131 if (! file)
133 grub_file_close (rawfile);
134 return 0;
137 ctmp = grub_env_get ("config_file");
138 if (ctmp)
139 old_file = grub_strdup (ctmp);
140 ctmp = grub_env_get ("config_directory");
141 if (ctmp)
142 old_dir = grub_strdup (ctmp);
143 if (*config == '(')
145 grub_env_set ("config_file", config);
146 config_dir = grub_strdup (config);
148 else
150 /* $root is guranteed to be defined, otherwise open above would fail */
151 config_dir = grub_xasprintf ("(%s)%s", grub_env_get ("root"), config);
152 if (config_dir)
153 grub_env_set ("config_file", config_dir);
155 if (config_dir)
157 ptr = grub_strrchr (config_dir, '/');
158 if (ptr)
159 *ptr = 0;
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");
167 while (1)
169 char *line;
171 /* Print an error, if any. */
172 grub_print_error ();
173 grub_errno = GRUB_ERR_NONE;
175 if ((read_config_file_getline (&line, 0, file)) || (! line))
176 break;
178 grub_normal_parse_line (line, read_config_file_getline, file);
179 grub_free (line);
182 if (old_file)
183 grub_env_set ("config_file", old_file);
184 else
185 grub_env_unset ("config_file");
186 if (old_dir)
187 grub_env_set ("config_directory", old_dir);
188 else
189 grub_env_unset ("config_directory");
190 grub_free (old_file);
191 grub_free (old_dir);
193 grub_file_close (file);
195 return newmenu;
198 /* Initialize the screen. */
199 void
200 grub_normal_init_page (struct grub_term_output *term,
201 int y)
203 grub_ssize_t msg_len;
204 int posx;
205 char *msg_formatted;
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);
212 if (!msg_formatted)
213 return;
215 msg_len = grub_utf8_to_ucs4_alloc (msg_formatted,
216 &unicode_msg, &last_position);
217 grub_free (msg_formatted);
219 if (msg_len < 0)
221 return;
224 posx = grub_getstringwidth (unicode_msg, last_position, term);
225 posx = ((int) grub_term_width (term) - posx) / 2;
226 if (posx < 0)
227 posx = 0;
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);
236 static void
237 read_lists (const char *val)
239 if (! grub_no_modules)
241 read_command_list (val);
242 read_fs_list (val);
243 read_crypto_list (val);
244 read_terminal_list (val);
246 grub_gettext_reread_prefix (val);
249 static char *
250 read_lists_hook (struct grub_env_var *var __attribute__ ((unused)),
251 const char *val)
253 read_lists (val);
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. */
259 void
260 grub_normal_execute (const char *config, int nested, int batch)
262 grub_menu_t menu = 0;
263 const char *prefix;
265 if (! nested)
267 prefix = grub_env_get ("prefix");
268 read_lists (prefix);
269 grub_register_variable_hook ("prefix", NULL, read_lists_hook);
272 grub_boot_time ("Executing config file");
274 if (config)
276 menu = read_config_file (config);
278 /* Ignore any error. */
279 grub_errno = GRUB_ERR_NONE;
282 grub_boot_time ("Executed config file");
284 if (! batch)
286 if (menu && menu->size)
289 grub_boot_time ("Entering menu");
290 grub_show_menu (menu, nested, 0);
291 if (nested)
292 grub_normal_free_menu (menu);
297 /* This starts the normal mode. */
298 void
299 grub_enter_normal_mode (const char *config)
301 grub_boot_time ("Entering normal mode");
302 nested_level++;
303 grub_normal_execute (config, 0, 0);
304 grub_boot_time ("Entering shell");
305 grub_cmdline_run (0, 1);
306 nested_level--;
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. */
313 static grub_err_t
314 grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
315 int argc, char *argv[])
317 if (argc == 0)
319 /* Guess the config filename. It is necessary to make CONFIG static,
320 so that it won't get broken by longjmp. */
321 char *config;
322 const char *prefix;
324 prefix = grub_env_get ("prefix");
325 if (prefix)
327 config = grub_xasprintf ("%s/grub.cfg", prefix);
328 if (! config)
329 goto quit;
331 grub_enter_normal_mode (config);
332 grub_free (config);
334 else
335 grub_enter_normal_mode (0);
337 else
338 grub_enter_normal_mode (argv[0]);
340 quit:
341 return 0;
344 /* Exit from normal mode to rescue mode. */
345 static grub_err_t
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;
356 static grub_err_t
357 grub_normal_reader_init (int nested)
359 struct grub_term_output *term;
360 const char *msg_esc = _("ESC at any time exits.");
361 char *msg_formatted;
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 : "");
367 if (!msg_formatted)
368 return grub_errno;
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);
377 else
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);
385 return 0;
388 static grub_err_t
389 grub_normal_read_line_real (char **line, int cont, int nested)
391 const char *prompt;
393 if (cont)
394 /* TRANSLATORS: it's command line prompt. */
395 prompt = _(">");
396 else
397 /* TRANSLATORS: it's command line prompt. */
398 prompt = _("grub>");
400 if (!prompt)
401 return grub_errno;
403 while (1)
405 *line = grub_cmdline_get (prompt);
406 if (*line)
407 return 0;
409 if (cont || nested)
411 grub_free (*line);
412 *line = 0;
413 return grub_errno;
419 static grub_err_t
420 grub_normal_read_line (char **line, int cont,
421 void *data __attribute__ ((unused)))
423 return grub_normal_read_line_real (line, cont, 0);
426 void
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);
437 if (err)
439 grub_print_error ();
440 grub_errno = GRUB_ERR_NONE;
441 return;
444 grub_normal_reader_init (nested);
446 while (1)
448 char *line;
450 if (grub_normal_exit_level)
451 break;
453 /* Print an error, if any. */
454 grub_print_error ();
455 grub_errno = GRUB_ERR_NONE;
457 grub_normal_read_line_real (&line, 0, nested);
458 if (! line)
459 break;
461 grub_normal_parse_line (line, grub_normal_read_line, NULL);
462 grub_free (line);
466 static char *
467 grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
468 const char *val)
470 grub_set_more ((*val == '1'));
471 return grub_strdup (val);
474 /* clear */
475 static grub_err_t
476 grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)),
477 int argc __attribute__ ((unused)),
478 char *argv[] __attribute__ ((unused)))
480 grub_cls ();
481 return 0;
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)
496 unsigned i;
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");
502 grub_errno = 0;
504 grub_normal_auth_init ();
505 grub_context_init ();
506 grub_script_init ();
507 grub_menu_init ();
509 grub_xputs_saved = grub_xputs;
510 grub_xputs = grub_xputs_normal;
512 /* Normal mode shouldn't be unloaded. */
513 if (mod)
514 grub_dl_ref (mod);
516 cmd_clear =
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 ();
559 grub_script_fini ();
560 grub_menu_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);