]> git.proxmox.com Git - grub2.git/blame - normal/main.c
Added forgotten include/grub/i386/pc/vbe.h to DISTLIST.
[grub2.git] / normal / main.c
CommitLineData
ce5bf700 1/* main.c - the normal mode main routine */
2/*
4b13b216 3 * GRUB -- GRand Unified Bootloader
93f3a1d8 4 * Copyright (C) 2000,2001,2002,2003,2005 Free Software Foundation, Inc.
ce5bf700 5 *
6 * This program 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
4b13b216 21#include <grub/kernel.h>
22#include <grub/normal.h>
23#include <grub/dl.h>
24#include <grub/rescue.h>
25#include <grub/misc.h>
26#include <grub/file.h>
27#include <grub/mm.h>
28#include <grub/term.h>
29#include <grub/env.h>
ce5bf700 30
4b13b216 31grub_jmp_buf grub_exit_env;
ce5bf700 32
39c9d41d 33static grub_fs_module_list_t fs_module_list = 0;
34
4b13b216 35#define GRUB_DEFAULT_HISTORY_SIZE 50
5aded270 36
ce5bf700 37/* Read a line from the file FILE. */
38static int
4b13b216 39get_line (grub_file_t file, char cmdline[], int max_len)
ce5bf700 40{
41 char c;
42 int pos = 0;
43 int literal = 0;
44 int comment = 0;
45
46 while (1)
47 {
4b13b216 48 if (grub_file_read (file, &c, 1) != 1)
ce5bf700 49 break;
50
51 /* Skip all carriage returns. */
52 if (c == '\r')
53 continue;
54
55 /* Replace tabs with spaces. */
56 if (c == '\t')
57 c = ' ';
58
59 /* The previous is a backslash, then... */
60 if (literal)
61 {
62 /* If it is a newline, replace it with a space and continue. */
63 if (c == '\n')
64 {
65 c = ' ';
66
67 /* Go back to overwrite the backslash. */
68 if (pos > 0)
69 pos--;
70 }
71
72 literal = 0;
73 }
74
75 if (c == '\\')
76 literal = 1;
77
78 if (comment)
79 {
80 if (c == '\n')
81 comment = 0;
82 }
83 else if (pos == 0)
84 {
85 if (c == '#')
86 comment = 1;
4b13b216 87 else if (! grub_isspace (c))
ce5bf700 88 cmdline[pos++] = c;
89 }
90 else
91 {
92 if (c == '\n')
93 break;
94
95 if (pos < max_len)
96 cmdline[pos++] = c;
97 }
98 }
99
100 cmdline[pos] = '\0';
101
102 return pos;
103}
104
105static void
4b13b216 106free_menu (grub_menu_t menu)
ce5bf700 107{
4b13b216 108 grub_menu_entry_t entry = menu->entry_list;
ce5bf700 109
110 while (entry)
111 {
4b13b216 112 grub_menu_entry_t next_entry = entry->next;
113 grub_command_list_t cmd = entry->command_list;
ce5bf700 114
115 while (cmd)
116 {
4b13b216 117 grub_command_list_t next_cmd = cmd->next;
ce5bf700 118
4b13b216 119 grub_free ((void *) cmd->command);
ce5bf700 120 cmd = next_cmd;
121 }
122
4b13b216 123 grub_free ((void *) entry->title);
ce5bf700 124 entry = next_entry;
125 }
126
4b13b216 127 grub_free (menu);
ce5bf700 128}
129
130/* Read the config file CONFIG and return a menu. If no entry is present,
131 return NULL. */
4b13b216 132static grub_menu_t
ce5bf700 133read_config_file (const char *config)
134{
4b13b216 135 grub_file_t file;
136 static char cmdline[GRUB_MAX_CMDLINE];
137 grub_menu_t menu;
138 grub_menu_entry_t *next_entry, cur_entry = 0;
139 grub_command_list_t *next_cmd, cur_cmd;
ce5bf700 140
141 /* Try to open the config file. */
4b13b216 142 file = grub_file_open (config);
ce5bf700 143 if (! file)
144 return 0;
145
146 /* Initialize the menu. */
4b13b216 147 menu = (grub_menu_t) grub_malloc (sizeof (*menu));
ce5bf700 148 if (! menu)
149 {
4b13b216 150 grub_file_close (file);
ce5bf700 151 return 0;
152 }
153 menu->default_entry = 0;
154 menu->fallback_entry = -1;
155 menu->timeout = -1;
156 menu->size = 0;
157 menu->entry_list = 0;
158
93f3a1d8 159 if (! grub_context_push_menu (menu))
160 {
161 grub_print_error ();
162 grub_errno = GRUB_ERR_NONE;
163
164 free_menu (menu);
165 grub_file_close (file);
166
167 /* Wait until the user pushes any key so that the user
168 can see what happened. */
169 grub_printf ("\nPress any key to continue...");
170 (void) grub_getkey ();
171 return 0;
172 }
173
ce5bf700 174 next_entry = &(menu->entry_list);
175 next_cmd = 0;
176
177 /* Read each line. */
178 while (get_line (file, cmdline, sizeof (cmdline)))
179 {
4b13b216 180 grub_command_t cmd;
ce5bf700 181
4b13b216 182 cmd = grub_command_find (cmdline);
183 grub_errno = GRUB_ERR_NONE;
ce5bf700 184 if (! cmd)
185 {
4b13b216 186 grub_printf ("Unknown command `%s' is ignored.\n", cmdline);
ce5bf700 187 continue;
188 }
189
4b13b216 190 if (cmd->flags & GRUB_COMMAND_FLAG_TITLE)
ce5bf700 191 {
192 char *p;
193
4b13b216 194 cur_entry = (grub_menu_entry_t) grub_malloc (sizeof (*cur_entry));
ce5bf700 195 if (! cur_entry)
196 goto fail;
197
4b13b216 198 p = grub_strchr (cmdline, ' ');
ce5bf700 199 if (p)
4b13b216 200 cur_entry->title = grub_strdup (p);
ce5bf700 201 else
4b13b216 202 cur_entry->title = grub_strdup ("");
ce5bf700 203
204 if (! cur_entry->title)
205 {
4b13b216 206 grub_free (cur_entry);
ce5bf700 207 goto fail;
208 }
209
210 cur_entry->num = 0;
211 cur_entry->command_list = 0;
212 cur_entry->next = 0;
213
214 *next_entry = cur_entry;
215 next_entry = &(cur_entry->next);
216
217 next_cmd = &(cur_entry->command_list);
218
219 menu->size++;
220 }
221 else if (! cur_entry)
222 {
223 /* Run the command if possible. */
4b13b216 224 if (cmd->flags & GRUB_COMMAND_FLAG_MENU)
ce5bf700 225 {
4b13b216 226 grub_command_execute (cmdline);
93f3a1d8 227 if (grub_errno != GRUB_ERR_NONE)
228 {
229 grub_print_error ();
230 grub_errno = GRUB_ERR_NONE;
231 }
ce5bf700 232 }
233 else
234 {
4b13b216 235 grub_printf ("Invalid command `%s' is ignored.\n", cmdline);
ce5bf700 236 continue;
237 }
238 }
239 else
240 {
4b13b216 241 cur_cmd = (grub_command_list_t) grub_malloc (sizeof (*cur_cmd));
ce5bf700 242 if (! cur_cmd)
243 goto fail;
244
4b13b216 245 cur_cmd->command = grub_strdup (cmdline);
ce5bf700 246 if (! cur_cmd->command)
247 {
4b13b216 248 grub_free (cur_cmd);
ce5bf700 249 goto fail;
250 }
251
252 cur_cmd->next = 0;
253
254 *next_cmd = cur_cmd;
255 next_cmd = &(cur_cmd->next);
256
257 cur_entry->num++;
258 }
259 }
260
261 fail:
262
4b13b216 263 grub_file_close (file);
ce5bf700 264
265 /* If no entry was found or any error occurred, return NULL. */
4b13b216 266 if (menu->size == 0 || grub_errno != GRUB_ERR_NONE)
ce5bf700 267 {
93f3a1d8 268 grub_context_pop_menu ();
ce5bf700 269 free_menu (menu);
270 return 0;
271 }
272
273 /* Check values of the default entry and the fallback one. */
274 if (menu->fallback_entry >= menu->size)
275 menu->fallback_entry = -1;
276
277 if (menu->default_entry < 0 || menu->default_entry >= menu->size)
278 {
279 if (menu->fallback_entry < 0)
280 menu->default_entry = 0;
281 else
282 {
283 menu->default_entry = menu->fallback_entry;
284 menu->fallback_entry = -1;
285 }
286 }
287
288 return menu;
289}
290
291/* This starts the normal mode. */
292void
4b13b216 293grub_enter_normal_mode (const char *config)
ce5bf700 294{
4b13b216 295 if (grub_setjmp (grub_exit_env) == 0)
296 grub_normal_execute (config, 0);
ce5bf700 297}
298
299/* Initialize the screen. */
300void
4b13b216 301grub_normal_init_page (void)
ce5bf700 302{
4b13b216 303 grub_cls ();
304 grub_printf ("\n\
97543f08 305 GNU GRUB version %s\n\n",
ce5bf700 306 PACKAGE_VERSION);
307}
308
5822ff87 309/* Read the file command.lst for auto-loading. */
310static void
311read_command_list (void)
312{
313 const char *prefix;
314
315 prefix = grub_env_get ("prefix");
316 if (prefix)
317 {
318 char *filename;
319
320 filename = grub_malloc (grub_strlen (prefix) + sizeof ("/command.lst"));
321 if (filename)
322 {
323 grub_file_t file;
324
325 grub_sprintf (filename, "%s/command.lst", prefix);
326 file = grub_file_open (filename);
327 if (file)
328 {
329 char buf[80]; /* XXX arbitrary */
330
331 while (get_line (file, buf, sizeof (buf)))
332 {
333 char *p;
334 grub_command_t cmd;
335
336 if (! grub_isgraph (buf[0]))
337 continue;
338
339 p = grub_strchr (buf, ':');
340 if (! p)
341 continue;
342
343 *p = '\0';
344 while (*++p == ' ')
345 ;
346
347 if (! grub_isgraph (*p))
348 continue;
349
350 cmd = grub_register_command (buf, 0,
351 GRUB_COMMAND_FLAG_NOT_LOADED,
352 0, 0, 0);
353 if (! cmd)
354 continue;
355
356 cmd->module_name = grub_strdup (p);
357 if (! cmd->module_name)
358 grub_unregister_command (buf);
359 }
360
361 grub_file_close (file);
362 }
363
364 grub_free (filename);
365 }
366 }
367
368 /* Ignore errors. */
369 grub_errno = GRUB_ERR_NONE;
370}
371
39c9d41d 372/* The auto-loading hook for filesystems. */
373static int
374autoload_fs_module (void)
375{
376 grub_fs_module_list_t p;
377
378 while ((p = fs_module_list) != 0)
379 {
380 if (! grub_dl_get (p->name) && grub_dl_load (p->name))
381 return 1;
382
383 fs_module_list = p->next;
384 grub_free (p->name);
385 grub_free (p);
386 }
387
388 return 0;
389}
390
391/* Read the file fs.lst for auto-loading. */
392static void
393read_fs_list (void)
394{
395 const char *prefix;
396
397 prefix = grub_env_get ("prefix");
398 if (prefix)
399 {
400 char *filename;
401
402 filename = grub_malloc (grub_strlen (prefix) + sizeof ("/fs.lst"));
403 if (filename)
404 {
405 grub_file_t file;
406
407 grub_sprintf (filename, "%s/fs.lst", prefix);
408 file = grub_file_open (filename);
409 if (file)
410 {
411 char buf[80]; /* XXX arbitrary */
412
413 while (get_line (file, buf, sizeof (buf)))
414 {
415 char *p = buf;
416 char *q = buf + grub_strlen (buf) - 1;
417 grub_fs_module_list_t fs_mod;
418
419 /* Ignore space. */
420 while (grub_isspace (*p))
421 p++;
422
423 while (p < q && grub_isspace (*q))
424 *q-- = '\0';
425
426 /* If the line is empty, skip it. */
427 if (p >= q)
428 continue;
429
430 fs_mod = grub_malloc (sizeof (*fs_mod));
431 if (! fs_mod)
432 continue;
433
434 fs_mod->name = grub_strdup (p);
435 if (! fs_mod->name)
436 {
437 grub_free (fs_mod);
438 continue;
439 }
440
441 fs_mod->next = fs_module_list;
442 fs_module_list = fs_mod;
443 }
444
445 grub_file_close (file);
446 }
447
448 grub_free (filename);
449 }
450 }
451
452 /* Ignore errors. */
453 grub_errno = GRUB_ERR_NONE;
454
455 /* Set the hook. */
456 grub_fs_autoload_hook = autoload_fs_module;
457}
458
ce5bf700 459/* Read the config file CONFIG and execute the menu interface or
460 the command-line interface. */
461void
4b13b216 462grub_normal_execute (const char *config, int nested)
ce5bf700 463{
4b13b216 464 grub_menu_t menu = 0;
ce5bf700 465
466 if (config)
467 {
468 menu = read_config_file (config);
469
470 /* Ignore any error. */
4b13b216 471 grub_errno = GRUB_ERR_NONE;
ce5bf700 472 }
473
5822ff87 474 read_command_list ();
39c9d41d 475 read_fs_list ();
5822ff87 476
ce5bf700 477 if (menu)
93f3a1d8 478 {
479 grub_menu_run (menu, nested);
480 grub_context_pop_menu ();
481 free_menu (menu);
482 }
ce5bf700 483 else
4b13b216 484 grub_cmdline_run (nested);
ce5bf700 485}
486
487/* Enter normal mode from rescue mode. */
488static void
4b13b216 489grub_rescue_cmd_normal (int argc, char *argv[])
ce5bf700 490{
491 if (argc == 0)
492 {
5f3607e0 493 /* Guess the config filename. It is necessary to make CONFIG static,
494 so that it won't get broken by longjmp. */
495 static char *config;
ce5bf700 496 const char *prefix;
497
4b13b216 498 prefix = grub_env_get ("prefix");
ce5bf700 499 if (prefix)
500 {
4b13b216 501 config = grub_malloc (grub_strlen (prefix) + sizeof ("/grub.cfg"));
ce5bf700 502 if (! config)
503 return;
504
4b13b216 505 grub_sprintf (config, "%s/grub.cfg", prefix);
506 grub_enter_normal_mode (config);
507 grub_free (config);
ce5bf700 508 }
509 else
4b13b216 510 grub_enter_normal_mode (0);
ce5bf700 511 }
512 else
4b13b216 513 grub_enter_normal_mode (argv[0]);
ce5bf700 514}
515
4b13b216 516#ifdef GRUB_UTIL
1f7315a3 517void
4b13b216 518grub_normal_init (void)
1f7315a3 519{
4b13b216 520 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
5aded270 521
1f7315a3 522 /* Register a command "normal" for the rescue mode. */
4b13b216 523 grub_rescue_register_command ("normal", grub_rescue_cmd_normal,
1f7315a3 524 "enter normal mode");
525
526 /* This registers some built-in commands. */
4b13b216 527 grub_command_init ();
1f7315a3 528
529}
530
531void
4b13b216 532grub_normal_fini (void)
1f7315a3 533{
4b13b216 534 grub_set_history (0);
535 grub_rescue_unregister_command ("normal");
1f7315a3 536
537}
4b13b216 538#else /* ! GRUB_UTIL */
539GRUB_MOD_INIT
ce5bf700 540{
541 /* Normal mode shouldn't be unloaded. */
4b13b216 542 grub_dl_ref (mod);
ce5bf700 543
4b13b216 544 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
5aded270 545
ce5bf700 546 /* Register a command "normal" for the rescue mode. */
4b13b216 547 grub_rescue_register_command ("normal", grub_rescue_cmd_normal,
ce5bf700 548 "enter normal mode");
549
550 /* This registers some built-in commands. */
4b13b216 551 grub_command_init ();
ce5bf700 552}
553
4b13b216 554GRUB_MOD_FINI
ce5bf700 555{
4b13b216 556 grub_set_history (0);
557 grub_rescue_unregister_command ("normal");
ce5bf700 558}
4b13b216 559#endif /* ! GRUB_UTIL */