Fix hang/crash when requesting ZPOOL with incorrect backing device
[grub2/phcoder.git] / normal / menu.c
blob59ad83fa701577833599732f14c7314dd31ec774
1 /* menu.c - General supporting functionality for menus. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2003,2004,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/normal.h>
21 #include <grub/misc.h>
22 #include <grub/loader.h>
23 #include <grub/mm.h>
24 #include <grub/time.h>
25 #include <grub/env.h>
26 #include <grub/menu_viewer.h>
27 #include <grub/command.h>
28 #include <grub/parser.h>
30 /* Get a menu entry by its index in the entry list. */
31 grub_menu_entry_t
32 grub_menu_get_entry (grub_menu_t menu, int no)
34 grub_menu_entry_t e;
36 for (e = menu->entry_list; e && no > 0; e = e->next, no--)
39 return e;
42 /* Return the current timeout. If the variable "timeout" is not set or
43 invalid, return -1. */
44 int
45 grub_menu_get_timeout (void)
47 char *val;
48 int timeout;
50 val = grub_env_get ("timeout");
51 if (! val)
52 return -1;
54 grub_error_push ();
56 timeout = (int) grub_strtoul (val, 0, 0);
58 /* If the value is invalid, unset the variable. */
59 if (grub_errno != GRUB_ERR_NONE)
61 grub_env_unset ("timeout");
62 grub_errno = GRUB_ERR_NONE;
63 timeout = -1;
66 grub_error_pop ();
68 return timeout;
71 /* Set current timeout in the variable "timeout". */
72 void
73 grub_menu_set_timeout (int timeout)
75 /* Ignore TIMEOUT if it is zero, because it will be unset really soon. */
76 if (timeout > 0)
78 char buf[16];
80 grub_sprintf (buf, "%d", timeout);
81 grub_env_set ("timeout", buf);
85 /* Get the first entry number from the value of the environment variable NAME,
86 which is a space-separated list of non-negative integers. The entry number
87 which is returned is stripped from the value of NAME. If no entry number
88 can be found, -1 is returned. */
89 static int
90 get_and_remove_first_entry_number (const char *name)
92 char *val;
93 char *tail;
94 int entry;
96 val = grub_env_get (name);
97 if (! val)
98 return -1;
100 grub_error_push ();
102 entry = (int) grub_strtoul (val, &tail, 0);
104 if (grub_errno == GRUB_ERR_NONE)
106 /* Skip whitespace to find the next digit. */
107 while (*tail && grub_isspace (*tail))
108 tail++;
109 grub_env_set (name, tail);
111 else
113 grub_env_unset (name);
114 grub_errno = GRUB_ERR_NONE;
115 entry = -1;
118 grub_error_pop ();
120 return entry;
123 /* Run a menu entry. */
124 void
125 grub_menu_execute_entry(grub_menu_entry_t entry)
127 grub_parser_execute ((char *) entry->sourcecode);
129 if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
130 /* Implicit execution of boot, only if something is loaded. */
131 grub_command_execute ("boot", 0, 0);
134 /* Execute ENTRY from the menu MENU, falling back to entries specified
135 in the environment variable "fallback" if it fails. CALLBACK is a
136 pointer to a struct of function pointers which are used to allow the
137 caller provide feedback to the user. */
138 void
139 grub_menu_execute_with_fallback (grub_menu_t menu,
140 grub_menu_entry_t entry,
141 grub_menu_execute_callback_t callback,
142 void *callback_data)
144 int fallback_entry;
146 callback->notify_booting (entry, callback_data);
148 grub_menu_execute_entry (entry);
150 /* Deal with fallback entries. */
151 while ((fallback_entry = get_and_remove_first_entry_number ("fallback"))
152 >= 0)
154 grub_print_error ();
155 grub_errno = GRUB_ERR_NONE;
157 entry = grub_menu_get_entry (menu, fallback_entry);
158 callback->notify_fallback (entry, callback_data);
159 grub_menu_execute_entry (entry);
160 /* If the function call to execute the entry returns at all, then this is
161 taken to indicate a boot failure. For menu entries that do something
162 other than actually boot an operating system, this could assume
163 incorrectly that something failed. */
166 callback->notify_failure (callback_data);