* grub-core/commands/menuentry.c (options): New option --id.
(grub_normal_add_menu_entry): New argument id. All users updated.
(grub_cmd_menuentry): Handle --id.
(grub_menu_init): Accept unknown arguments.
* grub-core/normal/main.c (features): Add feature_menuentry_id and
feature_menuentry_options.
* grub-core/normal/menu.c (grub_menu_execute_entry): Use id for
saved_entry.
(get_entry_number): Match with id as well.
* include/grub/menu.h (grub_menu_entry): New member id.
* util/grub-mkconfig_lib.in (grub_get_device_id): New function.
* util/grub.d/00_header.in: Define menuentry_id_option.
* util/grub.d/10_hurd.in: Define id.
* util/grub.d/10_illumos.in: Likewise.
* util/grub.d/10_kfreebsd.in: Likewise.
* util/grub.d/10_linux.in: Likewise.
* util/grub.d/10_netbsd.in: Likewise.
* util/grub.d/10_windows.in: Likewise.
* util/grub.d/20_linux_xen.in: Likewise.
* util/grub.d/30_os-prober.in: Likewise.
-2012-03-03 Vladimir Serbinenko <phcoder@gmail.com>
+2012-03-04 Vladimir Serbinenko <phcoder@gmail.com>
+
+ Fix menu title instability bug.
+
+ * grub-core/commands/menuentry.c (options): New option --id.
+ (grub_normal_add_menu_entry): New argument id. All users updated.
+ (grub_cmd_menuentry): Handle --id.
+ (grub_menu_init): Accept unknown arguments.
+ * grub-core/normal/main.c (features): Add feature_menuentry_id and
+ feature_menuentry_options.
+ * grub-core/normal/menu.c (grub_menu_execute_entry): Use id for
+ saved_entry.
+ (get_entry_number): Match with id as well.
+ * include/grub/menu.h (grub_menu_entry): New member id.
+ * util/grub-mkconfig_lib.in (grub_get_device_id): New function.
+ * util/grub.d/00_header.in: Define menuentry_id_option.
+ * util/grub.d/10_hurd.in: Define id.
+ * util/grub.d/10_illumos.in: Likewise.
+ * util/grub.d/10_kfreebsd.in: Likewise.
+ * util/grub.d/10_linux.in: Likewise.
+ * util/grub.d/10_netbsd.in: Likewise.
+ * util/grub.d/10_windows.in: Likewise.
+ * util/grub.d/20_linux_xen.in: Likewise.
+ * util/grub.d/30_os-prober.in: Likewise.
+
+2012-03-04 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/script/execute.c (grub_script_return): Replace ambiguous
"scope" with "body".
return grub_errno;
}
args[0] = oldname;
- grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL,
+ grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL, NULL,
entrysrc, 0);
grub_free (args);
entrysrc[0] = 0;
return grub_errno;
}
args[0] = entryname;
- grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, NULL, entrysrc, 0);
+ grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
+ NULL, NULL, entrysrc, 0);
grub_free (args);
}
N_("Keyboard key to quickly boot this entry."), N_("KEYBOARD_KEY"), ARG_TYPE_STRING},
{"source", 4, 0,
N_("Use STRING as menu entry body."), N_("STRING"), ARG_TYPE_STRING},
+ {"id", 1, GRUB_ARG_OPTION_REPEATABLE,
+ N_("Menu entry identifier."), N_("STRING"), ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
variable data slot `menu'). As the configuration file is read, the script
parser calls this when a menu entry is to be created. */
grub_err_t
-grub_normal_add_menu_entry (int argc, const char **args, char **classes,
+grub_normal_add_menu_entry (int argc, const char **args,
+ char **classes, const char *id,
const char *users, const char *hotkey,
const char *prefix, const char *sourcecode,
int submenu)
char *menu_users = NULL;
char *menu_title = NULL;
char *menu_sourcecode = NULL;
+ char *menu_id = NULL;
struct grub_menu_entry_class *menu_classes = NULL;
grub_menu_t menu;
if (! menu_title)
goto fail;
+ menu_id = grub_strdup (id ? : menu_title);
+ if (! menu_id)
+ goto fail;
+
/* Save argc, args to pass as parameters to block arg later. */
menu_args = grub_malloc (sizeof (char*) * (argc + 1));
if (! menu_args)
goto fail;
(*last)->title = menu_title;
+ (*last)->id = menu_id;
(*last)->hotkey = menu_hotkey;
(*last)->classes = menu_classes;
if (menu_users)
grub_free (menu_users);
grub_free (menu_title);
+ grub_free (menu_id);
return grub_errno;
}
if (! ctxt->script)
return grub_normal_add_menu_entry (argc, (const char **) args,
(ctxt->state[0].set ? ctxt->state[0].args
- : NULL), ctxt->state[1].arg,
+ : NULL),
+ ctxt->state[4].arg,
+ ctxt->state[1].arg,
ctxt->state[2].arg, 0,
ctxt->state[3].arg,
ctxt->extcmd->cmd->name[0] == 's');
return grub_errno;
r = grub_normal_add_menu_entry (argc - 1, (const char **) args,
- ctxt->state[0].args, ctxt->state[1].arg,
+ ctxt->state[0].args, ctxt->state[4].arg,
+ ctxt->state[1].arg,
ctxt->state[2].arg, prefix, src + 1,
ctxt->extcmd->cmd->name[0] == 's');
{
cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
GRUB_COMMAND_FLAG_BLOCKS
+ | GRUB_COMMAND_ACCEPT_DASH
| GRUB_COMMAND_FLAG_EXTRACTOR,
N_("BLOCK"), N_("Define a menu entry."), options);
cmd_sub = grub_register_extcmd ("submenu", grub_cmd_menuentry,
GRUB_COMMAND_FLAG_BLOCKS
+ | GRUB_COMMAND_ACCEPT_DASH
| GRUB_COMMAND_FLAG_EXTRACTOR,
N_("BLOCK"), N_("Define a submenu."),
options);
static void (*grub_xputs_saved) (const char *str);
static const char *features[] = {
"feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint",
- "feature_default_font_path", "feature_all_video_module"
+ "feature_default_font_path", "feature_all_video_module",
+ "feature_menuentry_id", "feature_menuentry_options"
};
GRUB_MOD_INIT(normal)
grub_env_set ("timeout", "0");
}
- for (ptr = entry->title; *ptr; ptr++)
+ for (ptr = entry->id; *ptr; ptr++)
sz += (*ptr == '>') ? 2 : 1;
if (chosen)
{
optr = grub_stpcpy (optr, chosen);
*optr++ = '>';
}
- for (ptr = entry->title; *ptr; ptr++)
+ for (ptr = entry->id; *ptr; ptr++)
{
if (*ptr == '>')
*optr++ = '>';
}
static int
-menuentry_eq (const char *title, const char *spec)
+menuentry_eq (const char *id, const char *spec)
{
const char *ptr1, *ptr2;
- ptr1 = title;
+ ptr1 = id;
ptr2 = spec;
while (1)
{
for (i = 0; e; i++)
{
- if (menuentry_eq (e->title, val))
+ if (menuentry_eq (e->title, val)
+ || menuentry_eq (e->id, val))
{
entry = i;
break;
/* The title name. */
const char *title;
+ /* The identifier. */
+ const char *id;
+
/* If set means not everybody is allowed to boot this entry. */
int restricted;
grub_err_t
grub_normal_add_menu_entry (int argc, const char **args, char **classes,
+ const char *id,
const char *users, const char *hotkey,
const char *prefix, const char *sourcecode,
int submenu);
fi
}
+grub_get_device_id ()
+{
+ device="$1"
+ if fs_uuid="`"${grub_probe}" --device "${device}" --target=fs_uuid 2> /dev/null`" ; then
+ echo "$fs_uuid";
+ else
+ echo "$device"
+ fi
+}
+
grub_file_is_not_garbage ()
{
if test -f "$1" ; then
EOF
fi
cat <<EOF
+
+if [ x"\${feature_menuentry_id}" = xy ]; then
+ menuentry_id_option="--id"
+else
+ menuentry_id_option=""
+fi
+
+export menuentry_id_option
+
if [ "\${prev_saved_entry}" ]; then
set saved_entry="\${prev_saved_entry}"
save_env saved_entry
KERNEL="using ${kernel_base}"
cat << EOF
-menuentry "${OS} ${KERNEL}" ${CLASS} {
+menuentry "${OS} ${KERNEL}" ${CLASS} \$menuentry_id_option 'gnuhurd-$kernel-false-$(grub_get_device_id "${GRUB_DEVICE_BOOT}")' {
EOF
- prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/"
+ prepare_grub_to_access_device "${GRUB_DEVICE_BOOT}" | sed -e "s/^/\t/"
message="$(gettext_printf "Loading GNU Mach ...")"
cat << EOF
echo '$message'
;;
esac
-echo "menuentry '${OS}' ${CLASS} {"
+echo "menuentry '${OS}' ${CLASS} \$menuentry_id_option 'illumos-$(grub_get_device_id "${GRUB_DEVICE_BOOT}")' {"
save_default_entry | sed -e "s/^/\t/"
-prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/"
+prepare_grub_to_access_device "${GRUB_DEVICE_BOOT}" | sed -e "s/^/\t/"
message="$(gettext_printf "Loading kernel of Illumos ...")"
cat << EOF
insmod gzio
else
title="$(gettext_quoted "%s, with kFreeBSD %s")"
fi
- printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}"
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+ fi
+ printf "menuentry '${title}' ${CLASS} \$menuentry_id_option 'kfreebsd-$version-$recovery-$boot_device_id' {\n" "${os}" "${version}"
if ! ${recovery} ; then
save_default_entry | sed -e "s/^/\t/"
fi
if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
done`
prepare_boot_cache=
+boot_device_id=
while [ "x$list" != "x" ] ; do
kfreebsd=`version_find_latest $list`
else
title="$(gettext_quoted "%s, with Linux %s")"
fi
- printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${version}"
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+ fi
+ printf "menuentry '${title}' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$recovery-$boot_device_id' {\n" "${os}" "${version}"
if ! ${recovery} ; then
save_default_entry | sed -e "s/^/\t/"
fi
prepare_boot_cache=
prepare_root_cache=
+boot_device_id=
while [ "x$list" != "x" ] ; do
linux=`version_find_latest $list`
title="$(gettext_quoted "%s, with kernel %s (via %s)")"
fi
- printf "menuentry \"${title}\" {\n" \
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+ fi
+ printf "menuentry \"${title}\" \$menuentry_id_option 'netbsd-$kernel-$recovery-$boot_device_id' {\n" \
"${OS}" "$(echo ${kernel} | sed -e 's,^.*/,,')" "${loader}"
printf "%s\n" "${prepare_boot_cache}"
case "${loader}" in
}
prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e 's,^, ,')"
+boot_device_id=
# We look for NetBSD kernels in / but not in subdirectories. We simply
# pick all statically linked ELF executable files (or links) in / with a
test -n "$dir" || continue
needmap=
+ osid=
# Check for Vista bootmgr.
if [ -f "$dir"/bootmgr -a -f "$dir"/boot/bcd ] ; then
OS="$(gettext_quoted "Windows Vista/7 (loader)")"
-
+ osid=bootmgr
# Check for NTLDR.
elif [ -f "$dir"/ntldr -a -f "$dir"/ntdetect.com -a -f "$dir"/boot.ini ] ; then
OS=`get_os_name_from_boot_ini "$dir"/boot.ini` || OS="$(gettext_quoted "Windows NT/2000/XP (loader)")"
+ osid=ntldr
needmap=t
else
gettext_printf "Found %s on %s (%s)\n" "$OS" "$drv" "$dev" >&2
cat << EOF
-menuentry "$OS" {
+menuentry "$OS" \$menuentry_id_option '$osid-$(grub_get_device_id "${dev}")' {
EOF
save_default_entry | sed -e 's,^,\t,'
else
title="$(gettext_quoted "%s, with Xen %s and Linux %s")"
fi
- printf "menuentry '${title}' ${CLASS} {\n" "${os}" "${xen_version}" "${version}"
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+ fi
+ printf "menuentry '${title}' ${CLASS} \$menuentry_id_option 'xen-gnulinux-$version-$recovery-$boot_device_id' {\n" "${os}" "${xen_version}" "${version}"
if ! ${recovery} ; then
save_default_entry | sed -e "s/^/\t/"
fi
if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
done`
prepare_boot_cache=
+boot_device_id=
while [ "x${xen_list}" != "x" ] ; do
list="${linux_list}"
xen_dirname=`dirname ${current_xen}`
rel_xen_dirname=`make_system_path_relative_to_its_root $xen_dirname`
xen_version=`echo $xen_basename | sed -e "s,.gz$,,g;s,^xen-,,g"`
- echo "submenu \"Xen ${xen_version}\" {"
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+ fi
+ echo "submenu \"Xen ${xen_version}\" \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {"
while [ "x$list" != "x" ] ; do
linux=`version_find_latest $list`
gettext_printf "Found linux image: %s\n" "$linux" >&2
# TRANSLATORS: it refers on the OS residing on device %s
onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
cat << EOF
-menuentry "${LONGNAME} $bitstr $onstr" --class osx --class darwin --class os {
+menuentry "${LONGNAME} $bitstr $onstr" --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' {
EOF
save_default_entry | sed -e "s/^/\t/"
prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"
EOF
}
+used_osprober_linux_ids=
+
for OS in ${OSPROBED} ; do
DEVICE="`echo ${OS} | cut -d ':' -f 1`"
LONGNAME="`echo ${OS} | cut -d ':' -f 2 | tr '^' ' '`"
onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
cat << EOF
-menuentry "${LONGNAME} $onstr" --class windows --class os {
+menuentry "${LONGNAME} $onstr" --class windows --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' {
EOF
save_default_entry | sed -e "s/^/\t/"
prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"
linux)
LINUXPROBED="`linux-boot-prober ${DEVICE} 2> /dev/null | tr ' ' '^' | paste -s -d ' '`"
prepare_boot_cache=
+ boot_device_id=
for LINUX in ${LINUXPROBED} ; do
LROOT="`echo ${LINUX} | cut -d ':' -f 1`"
fi
onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+ recovery_params="$(echo "${LPARAMS}" | grep single)"
+ counter=1
+ while echo "$used_osprober_linux_ids" | grep 'osprober-gnulinux-$LKERNEL-${recovery_params}-$counter-$boot_device_id' > /dev/null; do
+ counter=$((counter+1));
+ done
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${DEVICE}")"
+ fi
+ used_osprober_linux_ids="$used_osprober_linux_ids 'osprober-gnulinux-$LKERNEL-${recovery_params}-$counter-$boot_device_id'"
cat << EOF
-menuentry "${LLABEL} $onstr" --class gnu-linux --class gnu --class os {
+menuentry "${LLABEL} $onstr" --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-$LKERNEL-${recovery_params}-$boot_device_id' {
EOF
save_default_entry | sed -e "s/^/\t/"
if [ -z "${prepare_boot_cache}" ]; then
hurd)
onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
cat << EOF
-menuentry "${LONGNAME} $onstr" --class hurd --class gnu --class os {
+menuentry "${LONGNAME} $onstr" --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' {
EOF
save_default_entry | sed -e "s/^/\t/"
prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"