Add a few new files.
[grub2/phcoder/solaris.git] / normal / main.c
blob2e6df90ead0ae9f2945d7fdf71cf2ae0f3b8b0fb
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 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/rescue.h>
24 #include <grub/misc.h>
25 #include <grub/file.h>
26 #include <grub/mm.h>
27 #include <grub/term.h>
28 #include <grub/env.h>
29 #include <grub/parser.h>
30 #include <grub/script.h>
32 grub_jmp_buf grub_exit_env;
34 static grub_fs_module_list_t fs_module_list = 0;
36 #define GRUB_DEFAULT_HISTORY_SIZE 50
38 /* Read a line from the file FILE. */
39 static char *
40 get_line (grub_file_t file)
42 char c;
43 int pos = 0;
44 int literal = 0;
45 int comment = 0;
46 char *cmdline;
47 int max_len = 64;
49 /* Initially locate some space. */
50 cmdline = grub_malloc (max_len);
51 if (! cmdline)
52 return 0;
54 while (1)
56 if (grub_file_read (file, &c, 1) != 1)
57 break;
59 /* Skip all carriage returns. */
60 if (c == '\r')
61 continue;
63 /* Replace tabs with spaces. */
64 if (c == '\t')
65 c = ' ';
67 /* The previous is a backslash, then... */
68 if (literal)
70 /* If it is a newline, replace it with a space and continue. */
71 if (c == '\n')
73 c = ' ';
75 /* Go back to overwrite the backslash. */
76 if (pos > 0)
77 pos--;
80 literal = 0;
83 if (c == '\\')
84 literal = 1;
86 if (comment)
88 if (c == '\n')
89 comment = 0;
91 else if (pos == 0)
93 if (c == '#')
94 comment = 1;
95 else if (! grub_isspace (c))
96 cmdline[pos++] = c;
98 else
100 if (pos >= max_len)
102 char *old_cmdline = cmdline;
103 max_len = max_len * 2;
104 cmdline = grub_realloc (cmdline, max_len);
105 if (! cmdline)
107 grub_free (old_cmdline);
108 return 0;
112 if (c == '\n')
113 break;
115 cmdline[pos++] = c;
119 cmdline[pos] = '\0';
121 /* If the buffer is empty, don't return anything at all. */
122 if (pos == 0)
124 grub_free (cmdline);
125 cmdline = 0;
128 return cmdline;
131 static void
132 free_menu (grub_menu_t menu)
134 grub_menu_entry_t entry = menu->entry_list;
136 while (entry)
138 grub_menu_entry_t next_entry = entry->next;
140 grub_script_free (entry->commands);
141 grub_free ((void *) entry->title);
142 grub_free ((void *) entry->sourcecode);
143 entry = next_entry;
146 grub_free (menu);
147 grub_env_unset_data_slot ("menu");
150 grub_err_t
151 grub_normal_menu_addentry (const char *title, struct grub_script *script,
152 const char *sourcecode)
154 const char *menutitle;
155 const char *menusourcecode;
156 grub_menu_t menu;
157 grub_menu_entry_t *last;
159 menu = grub_env_get_data_slot("menu");
160 if (! menu)
161 return grub_error (GRUB_ERR_MENU, "no menu context");
163 last = &menu->entry_list;
165 menusourcecode = grub_strdup (sourcecode);
166 if (! menusourcecode)
167 return grub_errno;
169 menutitle = grub_strdup (title);
170 if (! menutitle)
172 grub_free ((void *) menusourcecode);
173 return grub_errno;
176 /* Add the menu entry at the end of the list. */
177 while (*last)
178 last = &(*last)->next;
180 *last = grub_malloc (sizeof (**last));
181 if (! *last)
183 grub_free ((void *) menutitle);
184 grub_free ((void *) menusourcecode);
185 return grub_errno;
188 (*last)->commands = script;
189 (*last)->title = menutitle;
190 (*last)->next = 0;
191 (*last)->sourcecode = menusourcecode;
193 menu->size++;
195 return GRUB_ERR_NONE;
198 static grub_menu_t
199 read_config_file (const char *config, int nested)
201 grub_file_t file;
202 auto grub_err_t getline (char **line);
203 int currline = 0;
204 int errors = 0;
206 grub_err_t getline (char **line)
208 currline++;
210 *line = get_line (file);
211 if (! *line)
212 return grub_errno;
214 return GRUB_ERR_NONE;
217 grub_menu_t newmenu;
219 newmenu = grub_env_get_data_slot ("menu");
221 if (nested || ! newmenu)
223 newmenu = grub_malloc (sizeof (*newmenu));
224 if (! newmenu)
225 return 0;
226 newmenu->size = 0;
227 newmenu->entry_list = 0;
230 /* Try to open the config file. */
231 file = grub_file_open (config);
232 if (! file)
233 return 0;
235 grub_env_set_data_slot ("menu", newmenu);
237 while (1)
239 struct grub_script *parsed_script;
240 int startline;
241 char *cmdline;
243 cmdline = get_line (file);
244 if (!cmdline)
245 break;
247 startline = ++currline;
249 /* Execute the script, line for line. */
250 parsed_script = grub_script_parse (cmdline, getline);
252 grub_free (cmdline);
254 if (! parsed_script)
256 grub_printf ("(line %d-%d)\n", startline, currline);
257 errors++;
258 continue;
261 /* Execute the command(s). */
262 grub_script_execute (parsed_script);
264 /* Ignore errors. */
265 grub_errno = GRUB_ERR_NONE;
267 /* The parsed script was executed, throw it away. */
268 grub_script_free (parsed_script);
271 grub_file_close (file);
273 if (errors > 0)
274 grub_wait_after_message ();
276 return newmenu;
279 /* This starts the normal mode. */
280 void
281 grub_enter_normal_mode (const char *config)
283 if (grub_setjmp (grub_exit_env) == 0)
284 grub_normal_execute (config, 0);
287 /* Initialize the screen. */
288 void
289 grub_normal_init_page (void)
291 grub_cls ();
292 grub_printf ("\n\
293 GNU GRUB version %s\n\n",
294 PACKAGE_VERSION);
297 /* Read the file command.lst for auto-loading. */
298 static void
299 read_command_list (void)
301 const char *prefix;
303 prefix = grub_env_get ("prefix");
304 if (prefix)
306 char *filename;
308 filename = grub_malloc (grub_strlen (prefix) + sizeof ("/command.lst"));
309 if (filename)
311 grub_file_t file;
313 grub_sprintf (filename, "%s/command.lst", prefix);
314 file = grub_file_open (filename);
315 if (file)
317 while (1)
319 char *p;
320 grub_command_t cmd;
321 char *buf = get_line (file);
323 if (! buf)
324 break;
326 if (! grub_isgraph (buf[0]))
327 continue;
329 p = grub_strchr (buf, ':');
330 if (! p)
331 continue;
333 *p = '\0';
334 while (*++p == ' ')
337 if (! grub_isgraph (*p))
338 continue;
340 cmd = grub_register_command (buf, 0,
341 GRUB_COMMAND_FLAG_NOT_LOADED,
342 0, 0, 0);
343 if (! cmd)
345 grub_free (buf);
346 continue;
349 cmd->module_name = grub_strdup (p);
350 if (! cmd->module_name)
351 grub_unregister_command (buf);
352 grub_free (buf);
355 grub_file_close (file);
358 grub_free (filename);
362 /* Ignore errors. */
363 grub_errno = GRUB_ERR_NONE;
366 /* The auto-loading hook for filesystems. */
367 static int
368 autoload_fs_module (void)
370 grub_fs_module_list_t p;
372 while ((p = fs_module_list) != 0)
374 if (! grub_dl_get (p->name) && grub_dl_load (p->name))
375 return 1;
377 fs_module_list = p->next;
378 grub_free (p->name);
379 grub_free (p);
382 return 0;
385 /* Read the file fs.lst for auto-loading. */
386 static void
387 read_fs_list (void)
389 const char *prefix;
391 prefix = grub_env_get ("prefix");
392 if (prefix)
394 char *filename;
396 filename = grub_malloc (grub_strlen (prefix) + sizeof ("/fs.lst"));
397 if (filename)
399 grub_file_t file;
401 grub_sprintf (filename, "%s/fs.lst", prefix);
402 file = grub_file_open (filename);
403 if (file)
405 while (1)
407 char *buf;
408 char *p;
409 char *q;
410 grub_fs_module_list_t fs_mod;
412 buf = get_line (file);
413 if (! buf)
414 break;
416 p = buf;
417 q = buf + grub_strlen (buf) - 1;
419 /* Ignore space. */
420 while (grub_isspace (*p))
421 p++;
423 while (p < q && grub_isspace (*q))
424 *q-- = '\0';
426 /* If the line is empty, skip it. */
427 if (p >= q)
428 continue;
430 fs_mod = grub_malloc (sizeof (*fs_mod));
431 if (! fs_mod)
432 continue;
434 fs_mod->name = grub_strdup (p);
435 if (! fs_mod->name)
437 grub_free (fs_mod);
438 continue;
441 fs_mod->next = fs_module_list;
442 fs_module_list = fs_mod;
445 grub_file_close (file);
448 grub_free (filename);
452 /* Ignore errors. */
453 grub_errno = GRUB_ERR_NONE;
455 /* Set the hook. */
456 grub_fs_autoload_hook = autoload_fs_module;
459 /* Read the config file CONFIG and execute the menu interface or
460 the command-line interface. */
461 void
462 grub_normal_execute (const char *config, int nested)
464 grub_menu_t menu = 0;
466 read_command_list ();
467 read_fs_list ();
469 if (config)
471 menu = read_config_file (config, nested);
473 /* Ignore any error. */
474 grub_errno = GRUB_ERR_NONE;
477 if (menu && menu->size)
479 grub_menu_run (menu, nested);
480 if (nested)
481 free_menu (menu);
483 else
484 grub_cmdline_run (nested);
487 /* Enter normal mode from rescue mode. */
488 static void
489 grub_rescue_cmd_normal (int argc, char *argv[])
491 if (argc == 0)
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;
496 const char *prefix;
498 prefix = grub_env_get ("prefix");
499 if (prefix)
501 config = grub_malloc (grub_strlen (prefix) + sizeof ("/grub.cfg"));
502 if (! config)
503 return;
505 grub_sprintf (config, "%s/grub.cfg", prefix);
506 grub_enter_normal_mode (config);
507 grub_free (config);
509 else
510 grub_enter_normal_mode (0);
512 else
513 grub_enter_normal_mode (argv[0]);
516 GRUB_MOD_INIT(normal)
518 /* Normal mode shouldn't be unloaded. */
519 if (mod)
520 grub_dl_ref (mod);
522 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
524 /* Register a command "normal" for the rescue mode. */
525 grub_rescue_register_command ("normal", grub_rescue_cmd_normal,
526 "enter normal mode");
528 /* Reload terminal colors when these variables are written to. */
529 grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
530 grub_register_variable_hook ("color_highlight", NULL, grub_env_write_color_highlight);
532 /* Preserve hooks after context changes. */
533 grub_env_export ("color_normal");
534 grub_env_export ("color_highlight");
536 /* This registers some built-in commands. */
537 grub_command_init ();
540 GRUB_MOD_FINI(normal)
542 grub_set_history (0);
543 grub_rescue_unregister_command ("normal");