From: Colin D Bennett <colin@gibibit.com>
To: grub-devel@gnu.org
Subject: [PATCH] 1/5 Multiple fallback entries
Date: Sat, 31 Jan 2009 11:57:43 -0800 [thread overview]
Message-ID: <20090131115743.34bb6762@gibibit.com> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 218 bytes --]
This patch adds support for multiple fallback entries in grub.cfg.
I'll prepare the ChangeLog entry when the patch is approved to be
committed.
The patch is against GRUB trunk revision 1964.
Regards,
Colin
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 01_multiple-fallback.patch --]
[-- Type: text/x-patch, Size: 7332 bytes --]
=== modified file 'include/grub/normal.h'
--- include/grub/normal.h 2009-01-31 09:15:43 +0000
+++ include/grub/normal.h 2009-01-31 17:47:55 +0000
@@ -98,10 +98,24 @@
extern struct grub_menu_viewer grub_normal_terminal_menu_viewer;
+typedef struct grub_menu_execute_callback
+{
+ void (*notify_booting) (void *userdata, grub_menu_entry_t entry);
+ void (*notify_fallback) (void *userdata, grub_menu_entry_t entry);
+ void (*notify_failure) (void *userdata);
+}
+*grub_menu_execute_callback_t;
+
void grub_enter_normal_mode (const char *config);
void grub_normal_execute (const char *config, int nested);
+void grub_menu_execute_with_fallback (grub_menu_t menu,
+ grub_menu_entry_t entry,
+ grub_menu_execute_callback_t callback,
+ void *callback_data);
void grub_menu_entry_run (grub_menu_entry_t entry);
void grub_menu_execute_entry(grub_menu_entry_t entry);
+int grub_menu_get_timeout (void);
+void grub_menu_set_timeout (int timeout);
void grub_cmdline_run (int nested);
int grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
int echo_char, int readline);
=== modified file 'normal/menu.c'
--- normal/menu.c 2009-01-31 09:15:43 +0000
+++ normal/menu.c 2009-01-31 17:47:55 +0000
@@ -244,8 +244,8 @@
/* Return the current timeout. If the variable "timeout" is not set or
invalid, return -1. */
-static int
-get_timeout (void)
+int
+grub_menu_get_timeout (void)
{
char *val;
int timeout;
@@ -272,8 +272,8 @@
}
/* Set current timeout in the variable "timeout". */
-static void
-set_timeout (int timeout)
+void
+grub_menu_set_timeout (int timeout)
{
/* Ignore TIMEOUT if it is zero, because it will be unset really soon. */
if (timeout > 0)
@@ -311,6 +311,44 @@
return entry;
}
+/* Get the first entry number from the variable NAME, which is a
+ space-separated list of nonnegative integers. The entry number which
+ is returned is stripped from the value of NAME. If no entry number can
+ be found, returns -1. */
+static int
+get_and_remove_first_entry_number (const char *name)
+{
+ char *val;
+ char *tail;
+ int entry;
+
+ val = grub_env_get (name);
+ if (! val)
+ return -1;
+
+ grub_error_push ();
+
+ entry = (int) grub_strtoul (val, &tail, 0);
+
+ if (grub_errno == GRUB_ERR_NONE)
+ {
+ /* Skip whitespace to find the next digit. */
+ while (*tail && grub_isspace (*tail))
+ tail++;
+ grub_env_set (name, tail);
+ }
+ else
+ {
+ grub_env_unset (name);
+ grub_errno = GRUB_ERR_NONE;
+ entry = -1;
+ }
+
+ grub_error_pop ();
+
+ return entry;
+}
+
static void
print_timeout (int timeout, int offset, int second_stage)
{
@@ -343,7 +381,7 @@
default_entry = 0;
/* If timeout is 0, drawing is pointless (and ugly). */
- if (get_timeout () == 0)
+ if (grub_menu_get_timeout () == 0)
return default_entry;
offset = default_entry;
@@ -362,7 +400,7 @@
print_entries (menu, first, offset);
grub_refresh ();
- timeout = get_timeout ();
+ timeout = grub_menu_get_timeout ();
if (timeout > 0)
print_timeout (timeout, offset, 0);
@@ -370,7 +408,7 @@
while (1)
{
int c;
- timeout = get_timeout ();
+ timeout = grub_menu_get_timeout ();
if (timeout > 0)
{
@@ -380,7 +418,7 @@
if (current_time - saved_time >= 1000)
{
timeout--;
- set_timeout (timeout);
+ grub_menu_set_timeout (timeout);
saved_time = current_time;
print_timeout (timeout, offset, 1);
}
@@ -498,12 +536,12 @@
offset += GRUB_TERM_NUM_ENTRIES;
if (offset > menu->size - 1 ||
- offset > GRUB_TERM_NUM_ENTRIES - 1)
+ offset > GRUB_TERM_NUM_ENTRIES - 1)
{
offset = menu->size - first - 1;
}
if (offset > GRUB_TERM_NUM_ENTRIES)
- {
+ {
first += offset - GRUB_TERM_NUM_ENTRIES + 1;
offset = GRUB_TERM_NUM_ENTRIES - 1;
}
@@ -561,6 +599,74 @@
grub_command_execute ("boot", 0);
}
+/* Execute ENTRY from the menu MENU, falling back to entries specified
+ in the environment variable "fallback" if it fails. CALLBACK is a
+ pointer to a struct of function pointers which are used to allow the
+ caller provide feedback to the user. */
+void
+grub_menu_execute_with_fallback (grub_menu_t menu,
+ grub_menu_entry_t entry,
+ grub_menu_execute_callback_t callback,
+ void *callback_data)
+{
+ int fallback_entry;
+
+ callback->notify_booting (callback_data, entry);
+
+ grub_menu_execute_entry (entry);
+
+ /* Deal with fallback entries. */
+ while ((fallback_entry = get_and_remove_first_entry_number ("fallback"))
+ >= 0)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+
+ entry = get_entry (menu, fallback_entry);
+ callback->notify_fallback (callback_data, entry);
+ grub_menu_execute_entry (entry);
+ }
+
+ if (grub_errno != GRUB_ERR_NONE)
+ callback->notify_failure (callback_data);
+}
+
+/* Callbacks for grub_menu_execute_with_fallback() for the text menu. */
+
+static void
+notify_booting (void *userdata __attribute__((unused)),
+ grub_menu_entry_t entry)
+{
+ grub_printf (" Booting \'%s\'\n\n", entry->title);
+}
+
+static void
+notify_fallback (void *userdata __attribute__((unused)),
+ grub_menu_entry_t entry)
+{
+ grub_printf ("\n Falling back to \'%s\'\n\n", entry->title);
+ grub_millisleep (2000);
+}
+
+static void
+notify_execution_failure (void *userdata __attribute__((unused)))
+{
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+
+ grub_wait_after_message ();
+ }
+}
+
+static struct grub_menu_execute_callback execution_callback =
+{
+ .notify_booting = notify_booting,
+ .notify_fallback = notify_fallback,
+ .notify_failure = notify_execution_failure
+};
+
static grub_err_t
show_text_menu (grub_menu_t menu, int nested)
{
@@ -568,7 +674,6 @@
{
int boot_entry;
grub_menu_entry_t e;
- int fallback_entry;
boot_entry = run_menu (menu, nested);
if (boot_entry < 0)
@@ -581,31 +686,7 @@
grub_cls ();
grub_setcursor (1);
- grub_printf (" Booting \'%s\'\n\n", e->title);
-
- grub_menu_execute_entry (e);
-
- /* Deal with a fallback entry. */
- /* FIXME: Multiple fallback entries like GRUB Legacy. */
- fallback_entry = get_entry_number ("fallback");
- if (fallback_entry >= 0)
- {
- grub_print_error ();
- grub_errno = GRUB_ERR_NONE;
-
- e = get_entry (menu, fallback_entry);
- grub_env_unset ("fallback");
- grub_printf ("\n Falling back to \'%s\'\n\n", e->title);
- grub_menu_execute_entry (e);
- }
-
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_print_error ();
- grub_errno = GRUB_ERR_NONE;
-
- grub_wait_after_message ();
- }
+ grub_menu_execute_with_fallback (menu, e, &execution_callback, 0);
}
return GRUB_ERR_NONE;
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
next reply other threads:[~2009-01-31 19:57 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-01-31 19:57 Colin D Bennett [this message]
2009-01-31 21:08 ` [PATCH] 1/5 Multiple fallback entries Vesa Jääskeläinen
2009-02-05 17:40 ` Colin D Bennett
2009-02-13 20:08 ` Colin D Bennett
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090131115743.34bb6762@gibibit.com \
--to=colin@gibibit.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.