From: Colin Watson <cjwatson@ubuntu.com>
To: grub-devel@gnu.org
Subject: Re: [PATCH] Use submenus for 10_linux
Date: Sun, 5 Dec 2010 00:54:49 +0000 [thread overview]
Message-ID: <20101205005447.GD21862@riva.ucam.org> (raw)
In-Reply-To: <loom.20101130T143425-83@post.gmane.org>
On Tue, Nov 30, 2010 at 01:36:15PM +0000, Žika wrote:
> I like the idea. But how are we to set default kernel, other than
> first, to boot automatically, now...? Old-school method doesn't
> work...
The following patch should fix handling of default='title' for entries
within submenus. I haven't bothered defining a way to select submenu
entries by number.
Review welcome! I'd particularly like confirmation from Vladimir that I'm
using the new extractor interface correctly, as I don't see any other
significant use of it in trunk at the moment beyond the extract_* commands
which nothing seems to be using yet.
2010-12-05 Colin Watson <cjwatson@ubuntu.com>
Fix defaults within submenus.
* grub-core/normal/main.c (new_menu): New function. Handles
propagating `default', `fallback', and `timeout' variables to
submenu contexts.
(grub_normal_new_menu_context): Likewise.
(grub_normal_new_menu_extractor): Likewise.
* include/grub/normal.h (grub_normal_new_menu_context): Add
prototype.
(grub_normal_new_menu_extractor): Likewise.
* grub-core/normal/menu.c (grub_menu_execute_entry): Use
grub_normal_new_menu_context. Unset `default', `fallback', and
`timeout' if we fall off the end of the menu, to allow escape from a
failed boot.
(get_entry_number): Recursively scan submenus.
(run_menu): Automatically traverse into a submenu if it contains the
default entry.
(show_menu): Initialise auto_boot to 0.
* grub-core/script/execute.c (grub_script_execute_cmdline): Silence
error messages for commands not valid when extracting menu entries
(otherwise, if nothing else, we always get errors about setparams).
=== modified file 'grub-core/normal/main.c'
--- grub-core/normal/main.c 2010-09-20 22:47:49 +0000
+++ grub-core/normal/main.c 2010-12-05 00:36:28 +0000
@@ -123,6 +123,62 @@ grub_file_getline (grub_file_t file)
return cmdline;
}
+/* Open a new nested menu, propagating environment variables to the new
+ context as necessary. */
+static grub_menu_t
+new_menu (int extractor)
+{
+ const char *default_val, *fallback_val, *timeout_val;
+ grub_menu_t menu;
+
+ default_val = grub_env_get ("default");
+ fallback_val = grub_env_get ("fallback");
+ timeout_val = grub_env_get ("timeout");
+
+ if (extractor)
+ grub_env_extractor_open (0);
+ else
+ grub_env_context_open ();
+
+ menu = grub_zalloc (sizeof (*menu));
+ if (!menu)
+ {
+ if (extractor)
+ grub_env_extractor_close (0);
+ else
+ grub_env_context_close ();
+ return NULL;
+ }
+ grub_env_set_menu (menu);
+
+ if (default_val)
+ {
+ /* Only propagate string defaults. */
+ (void) grub_strtoul (default_val, 0, 0);
+ if (grub_errno == GRUB_ERR_BAD_NUMBER)
+ grub_env_set ("default", default_val);
+ grub_errno = GRUB_ERR_NONE;
+ }
+ if (fallback_val)
+ grub_env_set ("fallback", fallback_val);
+ if (timeout_val)
+ grub_env_set ("timeout", timeout_val);
+
+ return menu;
+}
+
+grub_menu_t
+grub_normal_new_menu_context (void)
+{
+ return new_menu (0);
+}
+
+grub_menu_t
+grub_normal_new_menu_extractor (void)
+{
+ return new_menu (1);
+}
+
void
grub_normal_free_menu (grub_menu_t menu)
{
=== modified file 'grub-core/normal/menu.c'
--- grub-core/normal/menu.c 2010-09-20 22:47:49 +0000
+++ grub-core/normal/menu.c 2010-12-05 00:43:40 +0000
@@ -175,11 +175,9 @@ grub_menu_execute_entry(grub_menu_entry_
if (entry->submenu)
{
- grub_env_context_open ();
- menu = grub_zalloc (sizeof (*menu));
+ menu = grub_normal_new_menu_context ();
if (! menu)
return;
- grub_env_set_menu (menu);
}
grub_env_set ("chosen", entry->title);
@@ -201,6 +199,11 @@ grub_menu_execute_entry(grub_menu_entry_
}
grub_env_context_close ();
}
+
+ /* If we reach here, previous first-time defaults no longer make sense. */
+ grub_env_unset ("default");
+ grub_env_unset ("fallback");
+ grub_env_unset ("timeout");
}
/* Execute ENTRY from the menu MENU, falling back to entries specified
@@ -311,7 +314,7 @@ grub_menu_register_viewer (struct grub_m
/* Get the entry number from the variable NAME. */
static int
-get_entry_number (grub_menu_t menu, const char *name)
+get_entry_number (grub_menu_t menu, const char *name, int *in_submenu)
{
char *val;
int entry;
@@ -323,6 +326,7 @@ get_entry_number (grub_menu_t menu, cons
grub_error_push ();
entry = (int) grub_strtoul (val, 0, 0);
+ *in_submenu = 0;
if (grub_errno == GRUB_ERR_BAD_NUMBER)
{
@@ -330,20 +334,43 @@ get_entry_number (grub_menu_t menu, cons
grub_menu_entry_t e = menu->entry_list;
int i;
+ entry = -1;
grub_errno = GRUB_ERR_NONE;
- for (i = 0; e; i++)
+ for (i = 0; e && entry == -1; i++)
{
if (grub_strcmp (e->title, val) == 0)
+ entry = i;
+ else if (e->submenu)
{
- entry = i;
- break;
+ /* To make this work with submenus, we need to extract entries
+ from the submenu, then return the entry number of the
+ submenu itself if one of its entries (recursively) matches;
+ when the submenu is executed for real, it will then have to
+ call this function again one level down. This is not going
+ to be very efficient with a deep menu stack, but it seems
+ unlikely that many people will bother with more than a
+ couple of levels. */
+ grub_menu_t submenu;
+
+ submenu = grub_normal_new_menu_extractor ();
+ if (submenu)
+ {
+ grub_script_execute_sourcecode (e->sourcecode,
+ e->argc, e->args);
+ if (get_entry_number (submenu, name, in_submenu) != -1)
+ {
+ entry = i;
+ *in_submenu = 1;
+ }
+
+ grub_normal_free_menu (submenu);
+ grub_env_extractor_close (0);
+ }
}
+
e = e->next;
}
-
- if (! e)
- entry = -1;
}
if (grub_errno != GRUB_ERR_NONE)
@@ -369,16 +396,21 @@ static int
run_menu (grub_menu_t menu, int nested, int *auto_boot)
{
grub_uint64_t saved_time;
- int default_entry, current_entry;
+ int default_entry = -1, current_entry;
+ int in_submenu = 0;
int timeout;
- default_entry = get_entry_number (menu, "default");
+ default_entry = get_entry_number (menu, "default", &in_submenu);
/* If DEFAULT_ENTRY is not within the menu entries, fall back to
the first entry. */
if (default_entry < 0 || default_entry >= menu->size)
default_entry = 0;
+ /* If a submenu was automatically selected, traverse into it. */
+ if (in_submenu)
+ return default_entry;
+
/* If timeout is 0, drawing is pointless (and ugly). */
if (grub_menu_get_timeout () == 0)
{
@@ -596,7 +628,7 @@ show_menu (grub_menu_t menu, int nested)
{
int boot_entry;
grub_menu_entry_t e;
- int auto_boot;
+ int auto_boot = 0;
boot_entry = run_menu (menu, nested, &auto_boot);
if (boot_entry < 0)
=== modified file 'grub-core/script/execute.c'
--- grub-core/script/execute.c 2010-11-07 10:43:14 +0000
+++ grub-core/script/execute.c 2010-12-04 23:58:02 +0000
@@ -628,7 +628,7 @@ grub_script_execute_cmdline (struct grub
if (invert)
{
- if (ret == GRUB_ERR_TEST_FAILURE)
+ if (ret == GRUB_ERR_TEST_FAILURE || ret == GRUB_ERR_EXTRACTOR)
grub_errno = ret = GRUB_ERR_NONE;
else if (ret == GRUB_ERR_NONE)
ret = grub_error (GRUB_ERR_TEST_FAILURE, "false");
@@ -642,7 +642,7 @@ grub_script_execute_cmdline (struct grub
/* Free arguments. */
grub_script_argv_free (&argv);
- if (grub_errno == GRUB_ERR_TEST_FAILURE)
+ if (grub_errno == GRUB_ERR_TEST_FAILURE || grub_errno == GRUB_ERR_EXTRACTOR)
grub_errno = GRUB_ERR_NONE;
grub_print_error ();
=== modified file 'include/grub/normal.h'
--- include/grub/normal.h 2010-09-20 22:47:49 +0000
+++ include/grub/normal.h 2010-12-05 00:36:26 +0000
@@ -125,6 +125,8 @@ grub_normal_add_menu_entry (int argc, co
grub_err_t
grub_normal_set_password (const char *user, const char *password);
+grub_menu_t grub_normal_new_menu_context (void);
+grub_menu_t grub_normal_new_menu_extractor (void);
void grub_normal_free_menu (grub_menu_t menu);
void grub_normal_auth_init (void);
--
Colin Watson [cjwatson@ubuntu.com]
next prev parent reply other threads:[~2010-12-05 0:55 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-24 17:21 [PATCH] Use submenus for 10_linux Colin Watson
2010-11-25 2:54 ` Jordan Uggla
2010-11-30 13:36 ` Žika
2010-12-05 0:54 ` Colin Watson [this message]
2010-12-05 8:11 ` Jordan Uggla
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=20101205005447.GD21862@riva.ucam.org \
--to=cjwatson@ubuntu.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.