Moved currently useless parts inside #if 0
[grub2/phcoder.git] / normal / main.c
blob7f6336eebdeb8a19e8c2acee7588c34960dfcb6a
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>
32 #define GRUB_DEFAULT_HISTORY_SIZE 50
34 /* Read a line from the file FILE. */
35 char *
36 grub_file_getline (grub_file_t file)
38 char c;
39 int pos = 0;
40 int literal = 0;
41 char *cmdline;
42 int max_len = 64;
44 /* Initially locate some space. */
45 cmdline = grub_malloc (max_len);
46 if (! cmdline)
47 return 0;
49 while (1)
51 if (grub_file_read (file, &c, 1) != 1)
52 break;
54 /* Skip all carriage returns. */
55 if (c == '\r')
56 continue;
58 /* Replace tabs with spaces. */
59 if (c == '\t')
60 c = ' ';
62 /* The previous is a backslash, then... */
63 if (literal)
65 /* If it is a newline, replace it with a space and continue. */
66 if (c == '\n')
68 c = ' ';
70 /* Go back to overwrite the backslash. */
71 if (pos > 0)
72 pos--;
75 literal = 0;
78 if (c == '\\')
79 literal = 1;
81 if (pos == 0)
83 if (! grub_isspace (c))
84 cmdline[pos++] = c;
86 else
88 if (pos >= max_len)
90 char *old_cmdline = cmdline;
91 max_len = max_len * 2;
92 cmdline = grub_realloc (cmdline, max_len);
93 if (! cmdline)
95 grub_free (old_cmdline);
96 return 0;
100 if (c == '\n')
101 break;
103 cmdline[pos++] = c;
107 cmdline[pos] = '\0';
109 /* If the buffer is empty, don't return anything at all. */
110 if (pos == 0)
112 grub_free (cmdline);
113 cmdline = 0;
116 return cmdline;
119 static void
120 free_menu (grub_menu_t menu)
122 grub_menu_entry_t entry = menu->entry_list;
124 while (entry)
126 grub_menu_entry_t next_entry = entry->next;
128 grub_free ((void *) entry->title);
129 grub_free ((void *) entry->sourcecode);
130 entry = next_entry;
133 grub_free (menu);
134 grub_env_unset_data_slot ("menu");
137 static void
138 free_menu_entry_classes (struct grub_menu_entry_class *head)
140 /* Free all the classes. */
141 while (head)
143 struct grub_menu_entry_class *next;
145 grub_free (head->name);
146 next = head->next;
147 grub_free (head);
148 head = next;
152 /* Add a menu entry to the current menu context (as given by the environment
153 variable data slot `menu'). As the configuration file is read, the script
154 parser calls this when a menu entry is to be created. */
155 grub_err_t
156 grub_normal_add_menu_entry (int argc, const char **args,
157 const char *sourcecode)
159 const char *menutitle = 0;
160 const char *menusourcecode;
161 grub_menu_t menu;
162 grub_menu_entry_t *last;
163 int failed = 0;
164 int i;
165 struct grub_menu_entry_class *classes_head; /* Dummy head node for list. */
166 struct grub_menu_entry_class *classes_tail;
168 /* Allocate dummy head node for class list. */
169 classes_head = grub_malloc (sizeof (struct grub_menu_entry_class));
170 if (! classes_head)
171 return grub_errno;
172 classes_head->name = 0;
173 classes_head->next = 0;
174 classes_tail = classes_head;
176 menu = grub_env_get_data_slot ("menu");
177 if (! menu)
178 return grub_error (GRUB_ERR_MENU, "no menu context");
180 last = &menu->entry_list;
182 menusourcecode = grub_strdup (sourcecode);
183 if (! menusourcecode)
184 return grub_errno;
186 /* Parse menu arguments. */
187 for (i = 0; i < argc; i++)
189 /* Capture arguments. */
190 if (grub_strncmp ("--", args[i], 2) == 0)
192 const char *arg = &args[i][2];
194 /* Handle menu class. */
195 if (grub_strcmp(arg, "class") == 0)
197 char *class_name;
198 struct grub_menu_entry_class *new_class;
200 i++;
201 class_name = grub_strdup (args[i]);
202 if (! class_name)
204 failed = 1;
205 break;
208 /* Create a new class and add it at the tail of the list. */
209 new_class = grub_malloc (sizeof (struct grub_menu_entry_class));
210 if (! new_class)
212 grub_free (class_name);
213 failed = 1;
214 break;
216 /* Fill in the new class node. */
217 new_class->name = class_name;
218 new_class->next = 0;
219 /* Link the tail to it, and make it the new tail. */
220 classes_tail->next = new_class;
221 classes_tail = new_class;
222 continue;
224 else
226 /* Handle invalid argument. */
227 failed = 1;
228 grub_error (GRUB_ERR_MENU,
229 "invalid argument for menuentry: %s", args[i]);
230 break;
234 /* Capture title. */
235 if (! menutitle)
237 menutitle = grub_strdup (args[i]);
239 else
241 failed = 1;
242 grub_error (GRUB_ERR_MENU,
243 "too many titles for menuentry: %s", args[i]);
244 break;
248 /* Validate arguments. */
249 if ((! failed) && (! menutitle))
251 grub_error (GRUB_ERR_MENU, "menuentry is missing title");
252 failed = 1;
255 /* If argument parsing failed, free any allocated resources. */
256 if (failed)
258 free_menu_entry_classes (classes_head);
259 grub_free ((void *) menutitle);
260 grub_free ((void *) menusourcecode);
262 /* Here we assume that grub_error has been used to specify failure details. */
263 return grub_errno;
266 /* Add the menu entry at the end of the list. */
267 while (*last)
268 last = &(*last)->next;
270 *last = grub_malloc (sizeof (**last));
271 if (! *last)
273 free_menu_entry_classes (classes_head);
274 grub_free ((void *) menutitle);
275 grub_free ((void *) menusourcecode);
276 return grub_errno;
279 (*last)->title = menutitle;
280 (*last)->classes = classes_head;
281 (*last)->next = 0;
282 (*last)->sourcecode = menusourcecode;
284 menu->size++;
286 return GRUB_ERR_NONE;
289 static grub_menu_t
290 read_config_file (const char *config)
292 grub_file_t file;
293 grub_parser_t old_parser = 0;
295 auto grub_err_t getline (char **line, int cont);
296 grub_err_t getline (char **line, int cont __attribute__ ((unused)))
298 while (1)
300 char *buf;
302 *line = buf = grub_file_getline (file);
303 if (! buf)
304 return grub_errno;
306 if (buf[0] == '#')
308 if (buf[1] == '!')
310 grub_parser_t parser;
311 grub_named_list_t list;
313 buf += 2;
314 while (grub_isspace (*buf))
315 buf++;
317 if (! old_parser)
318 old_parser = grub_parser_get_current ();
320 list = GRUB_AS_NAMED_LIST (grub_parser_class.handler_list);
321 parser = grub_named_list_find (list, buf);
322 if (parser)
323 grub_parser_set_current (parser);
324 else
326 char cmd_name[8 + grub_strlen (buf)];
328 /* Perhaps it's not loaded yet, try the autoload
329 command. */
330 grub_strcpy (cmd_name, "parser.");
331 grub_strcat (cmd_name, buf);
332 grub_command_execute (cmd_name, 0, 0);
335 grub_free (*line);
337 else
338 break;
341 return GRUB_ERR_NONE;
344 grub_menu_t newmenu;
346 newmenu = grub_env_get_data_slot ("menu");
347 if (! newmenu)
349 newmenu = grub_malloc (sizeof (*newmenu));
350 if (! newmenu)
351 return 0;
352 newmenu->size = 0;
353 newmenu->entry_list = 0;
355 grub_env_set_data_slot ("menu", newmenu);
358 /* Try to open the config file. */
359 file = grub_file_open (config);
360 if (! file)
361 return 0;
363 grub_reader_loop (getline);
364 grub_file_close (file);
366 if (old_parser)
367 grub_parser_set_current (old_parser);
369 return newmenu;
372 /* Initialize the screen. */
373 void
374 grub_normal_init_page (void)
376 grub_uint8_t width, margin;
378 #define TITLE ("GNU GRUB version " PACKAGE_VERSION)
380 width = grub_getwh () >> 8;
381 margin = (width - (sizeof(TITLE) + 7)) / 2;
383 grub_cls ();
384 grub_putchar ('\n');
386 while (margin--)
387 grub_putchar (' ');
389 grub_printf ("%s\n\n", TITLE);
391 #undef TITLE
394 static int reader_nested;
396 /* Read the config file CONFIG and execute the menu interface or
397 the command line interface if BATCH is false. */
398 void
399 grub_normal_execute (const char *config, int nested, int batch)
401 grub_menu_t menu = 0;
403 read_command_list ();
404 read_fs_list ();
405 read_handler_list ();
406 grub_command_execute ("parser.sh", 0, 0);
408 reader_nested = nested;
410 if (config)
412 menu = read_config_file (config);
414 /* Ignore any error. */
415 grub_errno = GRUB_ERR_NONE;
418 if (! batch)
420 if (menu && menu->size)
422 grub_menu_viewer_show_menu (menu, nested);
423 if (nested)
424 free_menu (menu);
429 /* This starts the normal mode. */
430 void
431 grub_enter_normal_mode (const char *config)
433 grub_normal_execute (config, 0, 0);
436 /* Enter normal mode from rescue mode. */
437 static grub_err_t
438 grub_cmd_normal (struct grub_command *cmd,
439 int argc, char *argv[])
441 grub_unregister_command (cmd);
443 if (argc == 0)
445 /* Guess the config filename. It is necessary to make CONFIG static,
446 so that it won't get broken by longjmp. */
447 static char *config;
448 const char *prefix;
450 prefix = grub_env_get ("prefix");
451 if (prefix)
453 config = grub_malloc (grub_strlen (prefix) + sizeof ("/grub.cfg"));
454 if (! config)
455 goto quit;
457 grub_sprintf (config, "%s/grub.cfg", prefix);
458 grub_enter_normal_mode (config);
459 grub_free (config);
461 else
462 grub_enter_normal_mode (0);
464 else
465 grub_enter_normal_mode (argv[0]);
467 quit:
468 return 0;
471 void
472 grub_cmdline_run (int nested)
474 grub_reader_t reader = grub_reader_get_current ();
476 reader_nested = nested;
477 if (reader->init)
478 reader->init ();
479 grub_reader_loop (0);
482 static grub_err_t
483 grub_normal_reader_init (void)
485 grub_normal_init_page ();
486 grub_setcursor (1);
488 grub_printf ("\
489 [ Minimal BASH-like line editing is supported. For the first word, TAB\n\
490 lists possible command completions. Anywhere else TAB lists possible\n\
491 device/file completions.%s ]\n\n",
492 reader_nested ? " ESC at any time exits." : "");
494 return 0;
497 static char cmdline[GRUB_MAX_CMDLINE];
499 static grub_err_t
500 grub_normal_read_line (char **line, int cont)
502 grub_parser_t parser = grub_parser_get_current ();
503 char prompt[8 + grub_strlen (parser->name)];
505 grub_sprintf (prompt, "%s:%s> ", parser->name, (cont) ? "" : "grub");
507 while (1)
509 cmdline[0] = 0;
510 if (grub_cmdline_get (prompt, cmdline, sizeof (cmdline), 0, 1))
511 break;
513 if ((reader_nested) || (cont))
515 *line = 0;
516 return grub_errno;
520 *line = grub_strdup (cmdline);
521 return 0;
524 static struct grub_reader grub_normal_reader =
526 .name = "normal",
527 .init = grub_normal_reader_init,
528 .read_line = grub_normal_read_line
531 static char *
532 grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
533 const char *val)
535 grub_set_more ((*val == '1'));
536 return grub_strdup (val);
539 GRUB_MOD_INIT(normal)
541 /* Normal mode shouldn't be unloaded. */
542 if (mod)
543 grub_dl_ref (mod);
545 grub_menu_viewer_register (&grub_normal_text_menu_viewer);
547 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
549 grub_reader_register ("normal", &grub_normal_reader);
550 grub_reader_set_current (&grub_normal_reader);
551 grub_register_variable_hook ("pager", 0, grub_env_write_pager);
553 /* Register a command "normal" for the rescue mode. */
554 grub_register_command_prio ("normal", grub_cmd_normal,
555 0, "Enter normal mode", 0);
557 /* Reload terminal colors when these variables are written to. */
558 grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
559 grub_register_variable_hook ("color_highlight", NULL, grub_env_write_color_highlight);
561 /* Preserve hooks after context changes. */
562 grub_env_export ("color_normal");
563 grub_env_export ("color_highlight");
566 GRUB_MOD_FINI(normal)
568 grub_set_history (0);
569 grub_reader_unregister (&grub_normal_reader);
570 grub_register_variable_hook ("pager", 0, 0);
571 grub_fs_autoload_hook = 0;
572 free_handler_list ();