* [PATCH] Use submenus for 10_linux
@ 2010-11-24 17:21 Colin Watson
2010-11-25 2:54 ` Jordan Uggla
0 siblings, 1 reply; 5+ messages in thread
From: Colin Watson @ 2010-11-24 17:21 UTC (permalink / raw)
To: grub-devel
What do people think of this? It's a remarkably small change now that
Vladimir's implemented submenus, and I've had a number of requests for
it.
I wonder if it would be worth having some visual indication that a menu
entry is a submenu; but that probably ought to be done centrally.
I don't know whether this is 1.99 material or not, and would appreciate
comments.
2010-11-24 Colin Watson <cjwatson@ubuntu.com>
* util/grub.d/10_linux.in: Put second and subsequent menu entries in
a submenu.
=== modified file 'util/grub.d/10_linux.in'
--- util/grub.d/10_linux.in 2010-11-01 11:49:40 +0000
+++ util/grub.d/10_linux.in 2010-11-24 17:15:27 +0000
@@ -114,6 +114,7 @@ list=`for i in /boot/vmlinuz-* /boot/vml
done`
prepare_boot_cache=
+in_submenu=false
while [ "x$list" != "x" ] ; do
linux=`version_find_latest $list`
echo "Found linux image: $linux" >&2
@@ -159,4 +160,13 @@ while [ "x$list" != "x" ] ; do
fi
list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
+
+ if [ "$list" ] && ! $in_submenu; then
+ echo "submenu \"Previous Linux versions\" {"
+ in_submenu=:
+ fi
done
+
+if $in_submenu; then
+ echo "}"
+fi
--
Colin Watson [cjwatson@ubuntu.com]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Use submenus for 10_linux
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
0 siblings, 1 reply; 5+ messages in thread
From: Jordan Uggla @ 2010-11-25 2:54 UTC (permalink / raw)
To: The development of GNU GRUB
[-- Attachment #1: Type: text/plain, Size: 988 bytes --]
On 11/24/2010 09:21 AM, Colin Watson wrote:
> What do people think of this? It's a remarkably small change now that
> Vladimir's implemented submenus, and I've had a number of requests for
> it.
<snip>
> * util/grub.d/10_linux.in: Put second and subsequent menu entries in
> a submenu.
<snip>
> + echo "submenu \"Previous Linux versions\" {"
Since most users don't need to know what kernel version is being used by
default, I think we should simplify the title of the default menu entry
(by removing the "with Linux ...") and have a submenu labeled "Advanced
options for $OS". This submenu would include all kernel entries,
including the first entry (which would also be booted if you just
selected the main entry instead of going to the submenu). So the submenu
would look exactly like the main menu currently does, except only
listing kernel entries for one OS.
I've attached a proof of concept patch which does this.
--
Jordan Uggla (Jordan_U on irc.freenode.net)
[-- Attachment #2: submenu.patch --]
[-- Type: text/x-patch, Size: 2014 bytes --]
=== modified file 'util/grub.d/10_linux.in'
--- util/grub.d/10_linux.in 2010-11-01 11:49:40 +0000
+++ util/grub.d/10_linux.in 2010-11-25 01:03:00 +0000
@@ -55,15 +55,25 @@
{
os="$1"
version="$2"
- recovery="$3"
+ type="$3"
args="$4"
- if ${recovery} ; then
- title="$(gettext_quoted "%s, with Linux %s (recovery mode)")"
+
+ case $type in
+ simple)
+ title="$(gettext_quoted "%s")" ;;
+ recovery)
+ title="$(gettext_quoted "%s, with Linux %s (recovery mode)")" ;;
+ *)
+ title="$(gettext_quoted "%s, with Linux %s")" ;;
+ esac
+
+ if [ x$type = xsimple ]; then
+ printf "menuentry '${title}' ${CLASS} {\n" "${os}"
else
- title="$(gettext_quoted "%s, with Linux %s")"
+ printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}"
fi
- printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}"
- if ! ${recovery} ; then
+
+ if [ x$type != xrecovery ] ; then
save_default_entry | sed -e "s/^/\t/"
fi
@@ -114,6 +124,8 @@
done`
prepare_boot_cache=
+is_first_entry=true
+
while [ "x$list" != "x" ] ; do
linux=`version_find_latest $list`
echo "Found linux image: $linux" >&2
@@ -151,12 +163,26 @@
linux_root_device_thisversion=${GRUB_DEVICE}
fi
- linux_entry "${OS}" "${version}" false \
+ if [ x$is_first_entry = xtrue ]; then
+ linux_entry "${OS}" "${version}" simple \
+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+
+ cat << EOF
+submenu '$(gettext_quoted "Advanced options for ${OS}")' {
+EOF
+ fi
+
+ linux_entry "${OS}" "${version}" advanced \
"${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
- linux_entry "${OS}" "${version}" true \
+ linux_entry "${OS}" "${version}" recovery \
"single ${GRUB_CMDLINE_LINUX}"
fi
list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
+ is_first_entry=false
done
+
+if [ x$is_first_entry != xtrue ]; then #At least 1 kernel found, submenu started
+ echo '}'
+fi
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Use submenus for 10_linux
2010-11-25 2:54 ` Jordan Uggla
@ 2010-11-30 13:36 ` Žika
2010-12-05 0:54 ` Colin Watson
0 siblings, 1 reply; 5+ messages in thread
From: Žika @ 2010-11-30 13:36 UTC (permalink / raw)
To: grub-devel
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...
Regards...
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Use submenus for 10_linux
2010-11-30 13:36 ` Žika
@ 2010-12-05 0:54 ` Colin Watson
2010-12-05 8:11 ` Jordan Uggla
0 siblings, 1 reply; 5+ messages in thread
From: Colin Watson @ 2010-12-05 0:54 UTC (permalink / raw)
To: grub-devel
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]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Use submenus for 10_linux
2010-12-05 0:54 ` Colin Watson
@ 2010-12-05 8:11 ` Jordan Uggla
0 siblings, 0 replies; 5+ messages in thread
From: Jordan Uggla @ 2010-12-05 8:11 UTC (permalink / raw)
To: The development of GNU GRUB
On Sat, Dec 4, 2010 at 4:54 PM, Colin Watson <cjwatson@ubuntu.com> wrote:
> + /* 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. *
In addition to the performance impact with static submenus, this will
be completely unworkable with dynamically generated submenus. (Yes, I
can think of use cases for a saved default with a dynamically
generated submenu)
I would prefer something like:
GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 2.6.36.1"
Where '>' (or some other character) designates the what follows,
"Ubuntu, with Linux 2.6.36.1", is an entry within the submenu created
by selecting what precedes it, "Advanced options for Ubuntu".
Separately this also highlights an advantage of using a simplified
primary menu title (without a kernel version), as in this case if a
user wanted the default selection to be Ubuntu with the latest
installed kernel they would simply specify:
GRUB_DEFAULT="Ubuntu"
--
Jordan Uggla (Jordan_U on irc.freenode.net)
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-12-05 8:12 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
2010-12-05 8:11 ` Jordan Uggla
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.