Hi! I've developed a patch which implement few related features: - ability to define which linux kernels and in which order will be listed in top menu instead of single auto-detected latest kernel - ability to show kernel version in top menu items, to distinguish between different kernels added by previous feature - ability to use custom kernel command line parameters for depending on kernel version instead of GRUB_CMDLINE_LINUX_DEFAULT for all kernels
Here is my real use-case explaining needs in these features. I'm experimenting with switching between proprietary nvidia driver and nouveau. My main kernel is 3.10.1-hardened-r1 (for proprietary nvidia driver), and I've also compiled experimental kernel with "_nouveau" local version: 3.10.1-hardened-r1_nouveau. First issue - auto-detect of latest kernel choose 3.10.1-hardened-r1_nouveau, which is wrong for me, and only way to change this is add some fake local version for main kernel just to make sure it will be sorted before "_nouveau" string. Second issue - main kernel need "vga=" parameter, while nouveau kernel need "video=" parameter, but there is no way to configure this. Third issue - I'd like to have both normal and nouveau kernels in main menu, in manually defined order. All these features configured in /etc/default/grub using new variables: GRUB_SIMPLE_VERSION, GRUB_MENU_LINUX, GRUB_CMDLINE_LINUX_CUSTOM. Example: ---cut--- # Show kernel version in top menu entries GRUB_SIMPLE_VERSION=true # Manually define list of top menu entries instead of auto-detecting # latest kernel. GRUB_MENU_LINUX=' /boot/vmlinuz-3.10.1-hardened-r1 /boot/vmlinuz-3.10.1-hardened-r1_nouveau ' # Append parameters to the linux kernel command line for non-recovery entries # for some kernels (instead of GRUB_CMDLINE_LINUX_DEFAULT) # Should contain any amount of pairs: shell pattern for kernel version and # kernel command line for it (must be quoted if contain spaces). # First matched pattern will be used. Example: # GRUB_CMDLINE_LINUX_CUSTOM=' # *_nouveau video=800x600 # 3.10.* "vga=0x315 it87.force_id=0x8721" # 3.9.9-hardened "init=/bin/sh" # ' GRUB_CMDLINE_LINUX_CUSTOM=' *_nouveau "video=800x600" ' ---cut--- Attached patch is for grub-2.00_p5107. Patch tested with dash and bash. -- WBR, Alex.
diff -uNr grub-2.00.orig/util/grub.d/10_linux.in grub-2.00/util/grub.d/10_linux.in --- grub-2.00.orig/util/grub.d/10_linux.in 2013-08-04 22:24:58.000000000 +0300 +++ grub-2.00/util/grub.d/10_linux.in 2013-10-20 00:30:13.305280525 +0300 @@ -98,7 +98,12 @@ fi echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" else - echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + if [ "x$GRUB_SIMPLE_VERSION" = xtrue ]; then + title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" + else + title="${os}" + fi + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" fi if [ x$type != xrecovery ] ; then save_default_entry | grub_add_tab @@ -150,6 +155,25 @@ EOF } +make__get_cmdline_linux () { + local func IFS + IFS=' +' + set -- `echo "$GRUB_CMDLINE_LINUX_CUSTOM" | xargs -n 1 echo` "*" "$GRUB_CMDLINE_LINUX_DEFAULT" + if [ $(( $# % 2 )) -ne 0 ]; then + echo GRUB_CMDLINE_LINUX_CUSTOM must contain even elements >&2 + exit 1 + fi + func='get_cmdline_linux () { case $1 in '; + while [ $# -gt 0 ]; do + func="$func $1) echo '$2' ;;" + shift 2 + done + func="$func esac; }" + eval $func +} +make__get_cmdline_linux + machine=`uname -m` case "x$machine" in xi?86 | xx86_64) @@ -161,6 +185,9 @@ if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi done` ;; esac +list_simple=`for i in ${GRUB_MENU_LINUX} ; do + if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi + done` case "$machine" in i?86) GENKERNEL_ARCH="x86" ;; @@ -179,9 +206,15 @@ # yet, so it's empty. In a submenu it will be equal to '\t' (one tab). submenu_indentation="" +submenu_tmpfile=/tmp/grub.10_linux.submenu.$$ +exec 3>$submenu_tmpfile + is_first_entry=true while [ "x$list" != "x" ] ; do linux=`version_find_latest $list` + if [ "x$list_simple" != "x" ]; then + linux=${list_simple%% *} + fi gettext_printf "Found linux image: %s\n" "$linux" >&2 basename=`basename $linux` dirname=`dirname $linux` @@ -189,6 +222,7 @@ version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` alt_version=`echo $version | sed -e "s,\.old$,,g"` linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" + cmdline_linux=`get_cmdline_linux ${version}` initrd= for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \ @@ -226,24 +260,28 @@ linux_root_device_thisversion=${GRUB_DEVICE} fi + submenu_indentation="" if [ "x$is_first_entry" = xtrue ]; then linux_entry "${OS}" "${version}" simple \ - "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + "${GRUB_CMDLINE_LINUX} ${cmdline_linux}" - submenu_indentation="$grub_tab" - if [ -z "$boot_device_id" ]; then boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" fi # TRANSLATORS: %s is replaced with an OS name - echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {" + echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {" >&3 + elif [ "x$list_simple" != "x" ]; then + linux_entry "${OS}" "${version}" simple \ + "${GRUB_CMDLINE_LINUX} ${cmdline_linux}" fi + list_simple=${list_simple#* } - linux_entry "${OS}" "${version}" advanced \ - "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + submenu_indentation="$grub_tab" + linux_entry "${OS}" "${version}" advanced \ + "${GRUB_CMDLINE_LINUX} ${cmdline_linux}" >&3 if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then linux_entry "${OS}" "${version}" recovery \ - "single ${GRUB_CMDLINE_LINUX}" + "single ${GRUB_CMDLINE_LINUX}" >&3 fi list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '` @@ -253,7 +291,10 @@ # If at least one kernel was found, then we need to # add a closing '}' for the submenu command. if [ x"$is_first_entry" != xtrue ]; then - echo '}' + echo '}' >&3 + exec 3>&- + cat $submenu_tmpfile + rm $submenu_tmpfile fi echo "$title_correction_code" diff -uNr grub-2.00.orig/util/grub-mkconfig.in grub-2.00/util/grub-mkconfig.in --- grub-2.00.orig/util/grub-mkconfig.in 2013-08-15 20:09:04.000000000 +0300 +++ grub-2.00/util/grub-mkconfig.in 2013-10-20 00:13:27.799357848 +0300 @@ -192,8 +192,11 @@ GRUB_BUTTON_CMOS_ADDRESS \ GRUB_BUTTON_CMOS_CLEAN \ GRUB_DISTRIBUTOR \ + GRUB_SIMPLE_VERSION \ + GRUB_MENU_LINUX \ GRUB_CMDLINE_LINUX \ GRUB_CMDLINE_LINUX_DEFAULT \ + GRUB_CMDLINE_LINUX_CUSTOM \ GRUB_CMDLINE_XEN \ GRUB_CMDLINE_XEN_DEFAULT \ GRUB_CMDLINE_LINUX_XEN_REPLACE \
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel