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

Reply via email to