]> git.proxmox.com Git - grub2.git/blame - normal/main.c
2004-04-04 Yoshinori K. Okuji <okuji@enbug.org>
[grub2.git] / normal / main.c
CommitLineData
ce5bf700 1/* main.c - the normal mode main routine */
2/*
4b13b216 3 * GRUB -- GRand Unified Bootloader
8367695c 4 * Copyright (C) 2000,2001,2002,2003 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
4b13b216 33#define GRUB_DEFAULT_HISTORY_SIZE 50
5aded270 34
ce5bf700 35/* Read a line from the file FILE. */
36static int
4b13b216 37get_line (grub_file_t file, char cmdline[], int max_len)
ce5bf700 38{
39 char c;
40 int pos = 0;
41 int literal = 0;
42 int comment = 0;
43
44 while (1)
45 {
4b13b216 46 if (grub_file_read (file, &c, 1) != 1)
ce5bf700 47 break;
48
49 /* Skip all carriage returns. */
50 if (c == '\r')
51 continue;
52
53 /* Replace tabs with spaces. */
54 if (c == '\t')
55 c = ' ';
56
57 /* The previous is a backslash, then... */
58 if (literal)
59 {
60 /* If it is a newline, replace it with a space and continue. */
61 if (c == '\n')
62 {
63 c = ' ';
64
65 /* Go back to overwrite the backslash. */
66 if (pos > 0)
67 pos--;
68 }
69
70 literal = 0;
71 }
72
73 if (c == '\\')
74 literal = 1;
75
76 if (comment)
77 {
78 if (c == '\n')
79 comment = 0;
80 }
81 else if (pos == 0)
82 {
83 if (c == '#')
84 comment = 1;
4b13b216 85 else if (! grub_isspace (c))
ce5bf700 86 cmdline[pos++] = c;
87 }
88 else
89 {
90 if (c == '\n')
91 break;
92
93 if (pos < max_len)
94 cmdline[pos++] = c;
95 }
96 }
97
98 cmdline[pos] = '\0';
99
100 return pos;
101}
102
103static void
4b13b216 104free_menu (grub_menu_t menu)
ce5bf700 105{
4b13b216 106 grub_menu_entry_t entry = menu->entry_list;
ce5bf700 107
108 while (entry)
109 {
4b13b216 110 grub_menu_entry_t next_entry = entry->next;
111 grub_command_list_t cmd = entry->command_list;
ce5bf700 112
113 while (cmd)
114 {
4b13b216 115 grub_command_list_t next_cmd = cmd->next;
ce5bf700 116
4b13b216 117 grub_free ((void *) cmd->command);
ce5bf700 118 cmd = next_cmd;
119 }
120
4b13b216 121 grub_free ((void *) entry->title);
ce5bf700 122 entry = next_entry;
123 }
124
4b13b216 125 grub_free (menu);
ce5bf700 126}
127
128/* Read the config file CONFIG and return a menu. If no entry is present,
129 return NULL. */
4b13b216 130static grub_menu_t
ce5bf700 131read_config_file (const char *config)
132{
4b13b216 133 grub_file_t file;
134 static char cmdline[GRUB_MAX_CMDLINE];
135 grub_menu_t menu;
136 grub_menu_entry_t *next_entry, cur_entry = 0;
137 grub_command_list_t *next_cmd, cur_cmd;
ce5bf700 138
139 /* Try to open the config file. */
4b13b216 140 file = grub_file_open (config);
ce5bf700 141 if (! file)
142 return 0;
143
144 /* Initialize the menu. */
4b13b216 145 menu = (grub_menu_t) grub_malloc (sizeof (*menu));
ce5bf700 146 if (! menu)
147 {
4b13b216 148 grub_file_close (file);
ce5bf700 149 return 0;
150 }
151 menu->default_entry = 0;
152 menu->fallback_entry = -1;
153 menu->timeout = -1;
154 menu->size = 0;
155 menu->entry_list = 0;
156
157 next_entry = &(menu->entry_list);
158 next_cmd = 0;
159
160 /* Read each line. */
161 while (get_line (file, cmdline, sizeof (cmdline)))
162 {
4b13b216 163 grub_command_t cmd;
ce5bf700 164
4b13b216 165 cmd = grub_command_find (cmdline);
166 grub_errno = GRUB_ERR_NONE;
ce5bf700 167 if (! cmd)
168 {
4b13b216 169 grub_printf ("Unknown command `%s' is ignored.\n", cmdline);
ce5bf700 170 continue;
171 }
172
4b13b216 173 if (cmd->flags & GRUB_COMMAND_FLAG_TITLE)
ce5bf700 174 {
175 char *p;
176
4b13b216 177 cur_entry = (grub_menu_entry_t) grub_malloc (sizeof (*cur_entry));
ce5bf700 178 if (! cur_entry)
179 goto fail;
180
4b13b216 181 p = grub_strchr (cmdline, ' ');
ce5bf700 182 if (p)
4b13b216 183 cur_entry->title = grub_strdup (p);
ce5bf700 184 else
4b13b216 185 cur_entry->title = grub_strdup ("");
ce5bf700 186
187 if (! cur_entry->title)
188 {
4b13b216 189 grub_free (cur_entry);
ce5bf700 190 goto fail;
191 }
192
193 cur_entry->num = 0;
194 cur_entry->command_list = 0;
195 cur_entry->next = 0;
196
197 *next_entry = cur_entry;
198 next_entry = &(cur_entry->next);
199
200 next_cmd = &(cur_entry->command_list);
201
202 menu->size++;
203 }
204 else if (! cur_entry)
205 {
206 /* Run the command if possible. */
4b13b216 207 if (cmd->flags & GRUB_COMMAND_FLAG_MENU)
ce5bf700 208 {
4b13b216 209 grub_command_execute (cmdline);
210 grub_print_error ();
211 grub_errno = GRUB_ERR_NONE;
ce5bf700 212 }
213 else
214 {
4b13b216 215 grub_printf ("Invalid command `%s' is ignored.\n", cmdline);
ce5bf700 216 continue;
217 }
218 }
219 else
220 {
4b13b216 221 cur_cmd = (grub_command_list_t) grub_malloc (sizeof (*cur_cmd));
ce5bf700 222 if (! cur_cmd)
223 goto fail;
224
4b13b216 225 cur_cmd->command = grub_strdup (cmdline);
ce5bf700 226 if (! cur_cmd->command)
227 {
4b13b216 228 grub_free (cur_cmd);
ce5bf700 229 goto fail;
230 }
231
232 cur_cmd->next = 0;
233
234 *next_cmd = cur_cmd;
235 next_cmd = &(cur_cmd->next);
236
237 cur_entry->num++;
238 }
239 }
240
241 fail:
242
4b13b216 243 grub_file_close (file);
ce5bf700 244
245 /* If no entry was found or any error occurred, return NULL. */
4b13b216 246 if (menu->size == 0 || grub_errno != GRUB_ERR_NONE)
ce5bf700 247 {
248 free_menu (menu);
249 return 0;
250 }
251
252 /* Check values of the default entry and the fallback one. */
253 if (menu->fallback_entry >= menu->size)
254 menu->fallback_entry = -1;
255
256 if (menu->default_entry < 0 || menu->default_entry >= menu->size)
257 {
258 if (menu->fallback_entry < 0)
259 menu->default_entry = 0;
260 else
261 {
262 menu->default_entry = menu->fallback_entry;
263 menu->fallback_entry = -1;
264 }
265 }
266
267 return menu;
268}
269
270/* This starts the normal mode. */
271void
4b13b216 272grub_enter_normal_mode (const char *config)
ce5bf700 273{
4b13b216 274 if (grub_setjmp (grub_exit_env) == 0)
275 grub_normal_execute (config, 0);
ce5bf700 276}
277
278/* Initialize the screen. */
279void
4b13b216 280grub_normal_init_page (void)
ce5bf700 281{
4b13b216 282 grub_cls ();
283 grub_printf ("\n\
284 GRUB version %s\n\n",
ce5bf700 285 PACKAGE_VERSION);
286}
287
288/* Read the config file CONFIG and execute the menu interface or
289 the command-line interface. */
290void
4b13b216 291grub_normal_execute (const char *config, int nested)
ce5bf700 292{
4b13b216 293 grub_menu_t menu = 0;
ce5bf700 294
295 if (config)
296 {
297 menu = read_config_file (config);
298
299 /* Ignore any error. */
4b13b216 300 grub_errno = GRUB_ERR_NONE;
ce5bf700 301 }
302
303 if (menu)
4b13b216 304 grub_menu_run (menu, nested);
ce5bf700 305 else
4b13b216 306 grub_cmdline_run (nested);
ce5bf700 307}
308
309/* Enter normal mode from rescue mode. */
310static void
4b13b216 311grub_rescue_cmd_normal (int argc, char *argv[])
ce5bf700 312{
313 if (argc == 0)
314 {
315 /* Guess the config filename. */
316 char *config;
317 const char *prefix;
318
4b13b216 319 prefix = grub_env_get ("prefix");
ce5bf700 320 if (prefix)
321 {
4b13b216 322 config = grub_malloc (grub_strlen (prefix) + sizeof ("/grub.cfg"));
ce5bf700 323 if (! config)
324 return;
325
4b13b216 326 grub_sprintf (config, "%s/grub.cfg", prefix);
327 grub_enter_normal_mode (config);
328 grub_free (config);
ce5bf700 329 }
330 else
4b13b216 331 grub_enter_normal_mode (0);
ce5bf700 332 }
333 else
4b13b216 334 grub_enter_normal_mode (argv[0]);
ce5bf700 335}
336
4b13b216 337#ifdef GRUB_UTIL
1f7315a3 338void
4b13b216 339grub_normal_init (void)
1f7315a3 340{
4b13b216 341 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
5aded270 342
1f7315a3 343 /* Register a command "normal" for the rescue mode. */
4b13b216 344 grub_rescue_register_command ("normal", grub_rescue_cmd_normal,
1f7315a3 345 "enter normal mode");
346
347 /* This registers some built-in commands. */
4b13b216 348 grub_command_init ();
1f7315a3 349
350}
351
352void
4b13b216 353grub_normal_fini (void)
1f7315a3 354{
4b13b216 355 grub_set_history (0);
356 grub_rescue_unregister_command ("normal");
1f7315a3 357
358}
4b13b216 359#else /* ! GRUB_UTIL */
360GRUB_MOD_INIT
ce5bf700 361{
362 /* Normal mode shouldn't be unloaded. */
4b13b216 363 grub_dl_ref (mod);
ce5bf700 364
4b13b216 365 grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
5aded270 366
ce5bf700 367 /* Register a command "normal" for the rescue mode. */
4b13b216 368 grub_rescue_register_command ("normal", grub_rescue_cmd_normal,
ce5bf700 369 "enter normal mode");
370
371 /* This registers some built-in commands. */
4b13b216 372 grub_command_init ();
ce5bf700 373}
374
4b13b216 375GRUB_MOD_FINI
ce5bf700 376{
4b13b216 377 grub_set_history (0);
378 grub_rescue_unregister_command ("normal");
ce5bf700 379}
4b13b216 380#endif /* ! GRUB_UTIL */