=== modified file 'grub-core/commands/legacycfg.c' --- grub-core/commands/legacycfg.c 2012-02-26 16:28:05 +0000 +++ grub-core/commands/legacycfg.c 2012-03-03 12:11:30 +0000 @@ -123,7 +123,7 @@ 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; @@ -174,7 +174,8 @@ 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); } === modified file 'grub-core/commands/menuentry.c' --- grub-core/commands/menuentry.c 2012-02-26 16:28:05 +0000 +++ grub-core/commands/menuentry.c 2012-03-03 12:11:30 +0000 @@ -36,6 +36,8 @@ 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} }; @@ -67,7 +69,8 @@ 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) @@ -77,6 +80,7 @@ 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; @@ -139,6 +143,10 @@ 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) @@ -164,6 +172,7 @@ goto fail; (*last)->title = menu_title; + (*last)->id = menu_id; (*last)->hotkey = menu_hotkey; (*last)->classes = menu_classes; if (menu_users) @@ -196,6 +205,7 @@ grub_free (menu_users); grub_free (menu_title); + grub_free (menu_id); return grub_errno; } @@ -257,7 +267,9 @@ 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'); @@ -274,7 +286,8 @@ 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'); @@ -291,10 +304,12 @@ { 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); === modified file 'grub-core/normal/main.c' --- grub-core/normal/main.c 2012-02-26 17:09:07 +0000 +++ grub-core/normal/main.c 2012-03-03 12:11:30 +0000 @@ -475,7 +475,8 @@ 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) === modified file 'grub-core/normal/menu.c' --- grub-core/normal/menu.c 2012-03-03 12:05:08 +0000 +++ grub-core/normal/menu.c 2012-03-03 12:11:30 +0000 @@ -188,7 +188,7 @@ grub_env_set ("timeout", "0"); } - for (ptr = entry->title; *ptr; ptr++) + for (ptr = entry->id; *ptr; ptr++) sz += (*ptr == '>') ? 2 : 1; if (chosen) { @@ -217,7 +217,7 @@ optr = grub_stpcpy (optr, chosen); *optr++ = '>'; } - for (ptr = entry->title; *ptr; ptr++) + for (ptr = entry->id; *ptr; ptr++) { if (*ptr == '>') *optr++ = '>'; @@ -411,10 +411,10 @@ } 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) { @@ -459,7 +459,8 @@ 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; === modified file 'include/grub/menu.h' --- include/grub/menu.h 2011-01-10 22:27:58 +0000 +++ include/grub/menu.h 2012-03-03 12:11:30 +0000 @@ -32,6 +32,9 @@ /* The title name. */ const char *title; + /* The identifier. */ + const char *id; + /* If set means not everybody is allowed to boot this entry. */ int restricted; === modified file 'include/grub/normal.h' --- include/grub/normal.h 2012-02-09 13:38:34 +0000 +++ include/grub/normal.h 2012-03-03 12:11:30 +0000 @@ -120,6 +120,7 @@ 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); === modified file 'util/grub-mkconfig_lib.in' --- util/grub-mkconfig_lib.in 2012-02-27 10:04:50 +0000 +++ util/grub-mkconfig_lib.in 2012-03-03 12:11:30 +0000 @@ -162,6 +162,16 @@ 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 === modified file 'util/grub.d/00_header.in' --- util/grub.d/00_header.in 2012-02-29 23:40:02 +0000 +++ util/grub.d/00_header.in 2012-03-03 12:11:30 +0000 @@ -63,6 +63,13 @@ EOF fi cat <&2 cat << EOF -menuentry "$OS" { +menuentry "$OS" \$menuentry_id_option '$osid-$(grub_get_device_id "${dev}")' { EOF save_default_entry | sed -e 's,^,\t,' === modified file 'util/grub.d/20_linux_xen.in' --- util/grub.d/20_linux_xen.in 2012-02-27 18:07:09 +0000 +++ util/grub.d/20_linux_xen.in 2012-03-03 12:11:30 +0000 @@ -87,7 +87,10 @@ 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 @@ -139,6 +142,7 @@ 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}" @@ -147,7 +151,10 @@ 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 === modified file 'util/grub.d/30_os-prober.in' --- util/grub.d/30_os-prober.in 2012-03-02 14:09:10 +0000 +++ util/grub.d/30_os-prober.in 2012-03-03 12:11:30 +0000 @@ -52,7 +52,7 @@ # 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/" @@ -104,6 +104,8 @@ 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 '^' ' '`" @@ -121,7 +123,7 @@ 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/" @@ -144,6 +146,7 @@ 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`" @@ -163,8 +166,17 @@ 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 @@ -192,7 +204,7 @@ 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/"