mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-11-04 05:29:42 +00:00 
			
		
		
		
	We need to clear `grub_errno` after handling a memory allocation failure, otherwise we mistakenly report "out of memory" shortly afterwards.
		
			
				
	
	
		
			359 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			359 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From e760841d961fc46c5f7a82830d2e0eb6d4b53e8d Mon Sep 17 00:00:00 2001
 | 
						|
From: Colin Watson <cjwatson@ubuntu.com>
 | 
						|
Date: Mon, 13 Jan 2014 12:13:28 +0000
 | 
						|
Subject: Add configure option to bypass boot menu if possible
 | 
						|
 | 
						|
If other operating systems are installed, then automatically unhide the
 | 
						|
menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus if
 | 
						|
available to check whether Shift is pressed.  If it is, show the menu,
 | 
						|
otherwise boot immediately.  If keystatus is not available, then fall
 | 
						|
back to a short delay interruptible with Escape.
 | 
						|
 | 
						|
This may or may not remain Ubuntu-specific, although it's not obviously
 | 
						|
wanted upstream.  It implements a requirement of
 | 
						|
https://wiki.ubuntu.com/DesktopExperienceTeam/KarmicBootExperienceDesignSpec#Bootloader.
 | 
						|
 | 
						|
If the previous boot failed (defined as failing to get to the end of one
 | 
						|
of the normal runlevels), then show the boot menu regardless.
 | 
						|
 | 
						|
Author: Richard Laager <rlaager@wiktel.com>
 | 
						|
Author: Robie Basak <robie.basak@ubuntu.com>
 | 
						|
Forwarded: no
 | 
						|
Last-Update: 2015-09-04
 | 
						|
 | 
						|
Patch-Name: quick-boot.patch
 | 
						|
---
 | 
						|
 configure.ac                | 11 ++++++
 | 
						|
 docs/grub.texi              | 14 +++++++
 | 
						|
 grub-core/normal/menu.c     | 24 ++++++++++++
 | 
						|
 util/grub-mkconfig.in       |  3 +-
 | 
						|
 util/grub.d/00_header.in    | 77 +++++++++++++++++++++++++++++++------
 | 
						|
 util/grub.d/10_linux.in     |  4 ++
 | 
						|
 util/grub.d/30_os-prober.in | 21 ++++++++++
 | 
						|
 7 files changed, 141 insertions(+), 13 deletions(-)
 | 
						|
 | 
						|
diff --git a/configure.ac b/configure.ac
 | 
						|
index 256fc44ef..c42e4c784 100644
 | 
						|
--- a/configure.ac
 | 
						|
+++ b/configure.ac
 | 
						|
@@ -1926,6 +1926,17 @@ else
 | 
						|
 fi
 | 
						|
 AC_SUBST([QUIET_BOOT])
 | 
						|
 
 | 
						|
+AC_ARG_ENABLE([quick-boot],
 | 
						|
+              [AS_HELP_STRING([--enable-quick-boot],
 | 
						|
+                              [bypass boot menu if possible (default=no)])],
 | 
						|
+              [], [enable_quick_boot=no])
 | 
						|
+if test x"$enable_quick_boot" = xyes ; then
 | 
						|
+  QUICK_BOOT=1
 | 
						|
+else
 | 
						|
+  QUICK_BOOT=0
 | 
						|
+fi
 | 
						|
+AC_SUBST([QUICK_BOOT])
 | 
						|
+
 | 
						|
 LIBS=""
 | 
						|
 
 | 
						|
 AC_SUBST([FONT_SOURCE])
 | 
						|
diff --git a/docs/grub.texi b/docs/grub.texi
 | 
						|
index f8b4b3b21..0b58dafb2 100644
 | 
						|
--- a/docs/grub.texi
 | 
						|
+++ b/docs/grub.texi
 | 
						|
@@ -1563,6 +1563,20 @@ This option may be set to a list of GRUB module names separated by spaces.
 | 
						|
 Each module will be loaded as early as possible, at the start of
 | 
						|
 @file{grub.cfg}.
 | 
						|
 
 | 
						|
+@item GRUB_RECORDFAIL_TIMEOUT
 | 
						|
+If this option is set, it overrides the default recordfail setting.  A
 | 
						|
+setting of -1 causes GRUB to wait for user input indefinitely.  However, a
 | 
						|
+false positive in the recordfail mechanism may occur if power is lost during
 | 
						|
+boot before boot success is recorded in userspace.  The default setting is
 | 
						|
+30, which causes GRUB to wait for user input for thirty seconds before
 | 
						|
+continuing.  This default allows interactive users the opportunity to switch
 | 
						|
+to a different, working kernel, while avoiding a false positive causing the
 | 
						|
+boot to block indefinitely on headless and appliance systems where access to
 | 
						|
+a console is restricted or limited.
 | 
						|
+
 | 
						|
+This option is only effective when GRUB was configured with the
 | 
						|
+@option{--enable-quick-boot} option.
 | 
						|
+
 | 
						|
 @end table
 | 
						|
 
 | 
						|
 The following options are still accepted for compatibility with existing
 | 
						|
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
 | 
						|
index e9d8444b5..0440340b8 100644
 | 
						|
--- a/grub-core/normal/menu.c
 | 
						|
+++ b/grub-core/normal/menu.c
 | 
						|
@@ -603,6 +603,30 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
 | 
						|
       static struct grub_term_coordinate *pos;
 | 
						|
       int entry = -1;
 | 
						|
 
 | 
						|
+      if (timeout == 0)
 | 
						|
+	{
 | 
						|
+	  /* If modifier key statuses can't be detected without a delay,
 | 
						|
+	     then a hidden timeout of zero cannot be interrupted in any way,
 | 
						|
+	     which is not very helpful.  Bump it to three seconds in this
 | 
						|
+	     case to give the user a fighting chance.  */
 | 
						|
+	  grub_term_input_t term;
 | 
						|
+	  int nterms = 0;
 | 
						|
+	  int mods_detectable = 1;
 | 
						|
+
 | 
						|
+	  FOR_ACTIVE_TERM_INPUTS(term)
 | 
						|
+	  {
 | 
						|
+	    if (!term->getkeystatus)
 | 
						|
+	      {
 | 
						|
+		mods_detectable = 0;
 | 
						|
+		break;
 | 
						|
+	      }
 | 
						|
+	    else
 | 
						|
+	      nterms++;
 | 
						|
+	  }
 | 
						|
+	  if (!mods_detectable || !nterms)
 | 
						|
+	    timeout = 3;
 | 
						|
+	}
 | 
						|
+
 | 
						|
       if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout)
 | 
						|
 	{
 | 
						|
 	  pos = grub_term_save_pos ();
 | 
						|
diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
 | 
						|
index 0265a5a66..fa9c53a92 100644
 | 
						|
--- a/util/grub-mkconfig.in
 | 
						|
+++ b/util/grub-mkconfig.in
 | 
						|
@@ -256,7 +256,8 @@ export GRUB_DEFAULT \
 | 
						|
   GRUB_ENABLE_CRYPTODISK \
 | 
						|
   GRUB_BADRAM \
 | 
						|
   GRUB_OS_PROBER_SKIP_LIST \
 | 
						|
-  GRUB_DISABLE_SUBMENU
 | 
						|
+  GRUB_DISABLE_SUBMENU \
 | 
						|
+  GRUB_RECORDFAIL_TIMEOUT
 | 
						|
 
 | 
						|
 if test "x${grub_cfg}" != "x"; then
 | 
						|
   rm -f "${grub_cfg}.new"
 | 
						|
diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
 | 
						|
index 93a90233e..674a76140 100644
 | 
						|
--- a/util/grub.d/00_header.in
 | 
						|
+++ b/util/grub.d/00_header.in
 | 
						|
@@ -21,6 +21,8 @@ prefix="@prefix@"
 | 
						|
 exec_prefix="@exec_prefix@"
 | 
						|
 datarootdir="@datarootdir@"
 | 
						|
 grub_lang=`echo $LANG | cut -d . -f 1`
 | 
						|
+grubdir="`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`"
 | 
						|
+quick_boot="@QUICK_BOOT@"
 | 
						|
 
 | 
						|
 export TEXTDOMAIN=@PACKAGE@
 | 
						|
 export TEXTDOMAINDIR="@localedir@"
 | 
						|
@@ -44,6 +46,7 @@ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT
 | 
						|
 
 | 
						|
 cat << EOF
 | 
						|
 if [ -s \$prefix/grubenv ]; then
 | 
						|
+  set have_grubenv=true
 | 
						|
   load_env
 | 
						|
 fi
 | 
						|
 EOF
 | 
						|
@@ -96,7 +99,50 @@ function savedefault {
 | 
						|
     save_env saved_entry
 | 
						|
   fi
 | 
						|
 }
 | 
						|
+EOF
 | 
						|
+
 | 
						|
+if [ "$quick_boot" = 1 ]; then
 | 
						|
+    cat <<EOF
 | 
						|
+function recordfail {
 | 
						|
+  set recordfail=1
 | 
						|
+EOF
 | 
						|
+
 | 
						|
+  check_writable () {
 | 
						|
+    abstractions="$(grub-probe --target=abstraction "${grubdir}")"
 | 
						|
+    for abstraction in $abstractions; do
 | 
						|
+      case "$abstraction" in
 | 
						|
+        diskfilter | lvm)
 | 
						|
+          cat <<EOF
 | 
						|
+  # GRUB lacks write support for $abstraction, so recordfail support is disabled.
 | 
						|
+EOF
 | 
						|
+          return
 | 
						|
+          ;;
 | 
						|
+      esac
 | 
						|
+    done
 | 
						|
+
 | 
						|
+    FS="$(grub-probe --target=fs "${grubdir}")"
 | 
						|
+    case "$FS" in
 | 
						|
+      btrfs | cpiofs | newc | odc | romfs | squash4 | tarfs | zfs)
 | 
						|
+	cat <<EOF
 | 
						|
+  # GRUB lacks write support for $FS, so recordfail support is disabled.
 | 
						|
+EOF
 | 
						|
+	return
 | 
						|
+	;;
 | 
						|
+    esac
 | 
						|
+
 | 
						|
+    cat <<EOF
 | 
						|
+  if [ -n "\${have_grubenv}" ]; then if [ -z "\${boot_once}" ]; then save_env recordfail; fi; fi
 | 
						|
+EOF
 | 
						|
+  }
 | 
						|
+
 | 
						|
+  check_writable
 | 
						|
 
 | 
						|
+  cat <<EOF
 | 
						|
+}
 | 
						|
+EOF
 | 
						|
+fi
 | 
						|
+
 | 
						|
+cat <<EOF
 | 
						|
 function load_video {
 | 
						|
 EOF
 | 
						|
 if [ -n "${GRUB_VIDEO_BACKEND}" ]; then
 | 
						|
@@ -282,10 +328,16 @@ fi
 | 
						|
 
 | 
						|
 make_timeout ()
 | 
						|
 {
 | 
						|
+    cat << EOF
 | 
						|
+if [ "\${recordfail}" = 1 ] ; then
 | 
						|
+  set timeout=${GRUB_RECORDFAIL_TIMEOUT:-30}
 | 
						|
+else
 | 
						|
+EOF
 | 
						|
     if [ "x${3}" != "x" ] ; then
 | 
						|
 	timeout="${2}"
 | 
						|
 	style="${3}"
 | 
						|
-    elif [ "x${1}" != "x" ] && [ "x${1}" != "x0" ] ; then
 | 
						|
+    elif [ "x${1}" != "x" ] && \
 | 
						|
+	 ([ "$quick_boot" = 1 ] || [ "x${1}" != "x0" ]) ; then
 | 
						|
 	# Handle the deprecated GRUB_HIDDEN_TIMEOUT scheme.
 | 
						|
 	timeout="${1}"
 | 
						|
 	if [ "x${2}" != "x0" ] ; then
 | 
						|
@@ -304,26 +356,27 @@ make_timeout ()
 | 
						|
 	style="menu"
 | 
						|
     fi
 | 
						|
     cat << EOF
 | 
						|
-if [ x\$feature_timeout_style = xy ] ; then
 | 
						|
-  set timeout_style=${style}
 | 
						|
-  set timeout=${timeout}
 | 
						|
+  if [ x\$feature_timeout_style = xy ] ; then
 | 
						|
+    set timeout_style=${style}
 | 
						|
+    set timeout=${timeout}
 | 
						|
 EOF
 | 
						|
     if [ "x${style}" = "xmenu" ] ; then
 | 
						|
 	cat << EOF
 | 
						|
-# Fallback normal timeout code in case the timeout_style feature is
 | 
						|
-# unavailable.
 | 
						|
-else
 | 
						|
-  set timeout=${timeout}
 | 
						|
+  # Fallback normal timeout code in case the timeout_style feature is
 | 
						|
+  # unavailable.
 | 
						|
+  else
 | 
						|
+    set timeout=${timeout}
 | 
						|
 EOF
 | 
						|
     else
 | 
						|
 	cat << EOF
 | 
						|
-# Fallback hidden-timeout code in case the timeout_style feature is
 | 
						|
-# unavailable.
 | 
						|
-elif sleep${verbose} --interruptible ${timeout} ; then
 | 
						|
-  set timeout=0
 | 
						|
+  # Fallback hidden-timeout code in case the timeout_style feature is
 | 
						|
+  # unavailable.
 | 
						|
+  elif sleep${verbose} --interruptible ${timeout} ; then
 | 
						|
+    set timeout=0
 | 
						|
 EOF
 | 
						|
     fi
 | 
						|
     cat << EOF
 | 
						|
+  fi
 | 
						|
 fi
 | 
						|
 EOF
 | 
						|
 }
 | 
						|
diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
 | 
						|
index 869a7eec5..80315a31b 100644
 | 
						|
--- a/util/grub.d/10_linux.in
 | 
						|
+++ b/util/grub.d/10_linux.in
 | 
						|
@@ -22,6 +22,7 @@ exec_prefix="@exec_prefix@"
 | 
						|
 datarootdir="@datarootdir@"
 | 
						|
 ubuntu_recovery="@UBUNTU_RECOVERY@"
 | 
						|
 quiet_boot="@QUIET_BOOT@"
 | 
						|
+quick_boot="@QUICK_BOOT@"
 | 
						|
 
 | 
						|
 . "$pkgdatadir/grub-mkconfig_lib"
 | 
						|
 
 | 
						|
@@ -129,6 +130,9 @@ linux_entry ()
 | 
						|
   else
 | 
						|
       echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
 | 
						|
   fi      
 | 
						|
+  if [ "$quick_boot" = 1 ]; then
 | 
						|
+      echo "	recordfail" | sed "s/^/$submenu_indentation/"
 | 
						|
+  fi
 | 
						|
   if [ x$type != xrecovery ] ; then
 | 
						|
       save_default_entry | grub_add_tab
 | 
						|
   fi
 | 
						|
diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
 | 
						|
index 98aee403e..225a3baf7 100644
 | 
						|
--- a/util/grub.d/30_os-prober.in
 | 
						|
+++ b/util/grub.d/30_os-prober.in
 | 
						|
@@ -20,12 +20,26 @@ set -e
 | 
						|
 prefix="@prefix@"
 | 
						|
 exec_prefix="@exec_prefix@"
 | 
						|
 datarootdir="@datarootdir@"
 | 
						|
+quick_boot="@QUICK_BOOT@"
 | 
						|
 
 | 
						|
 export TEXTDOMAIN=@PACKAGE@
 | 
						|
 export TEXTDOMAINDIR="@localedir@"
 | 
						|
 
 | 
						|
 . "$pkgdatadir/grub-mkconfig_lib"
 | 
						|
 
 | 
						|
+found_other_os=
 | 
						|
+
 | 
						|
+adjust_timeout () {
 | 
						|
+  if [ "$quick_boot" = 1 ] && [ "x${found_other_os}" != "x" ]; then
 | 
						|
+    cat << EOF
 | 
						|
+set timeout_style=menu
 | 
						|
+if [ "\${timeout}" = 0 ]; then
 | 
						|
+  set timeout=10
 | 
						|
+fi
 | 
						|
+EOF
 | 
						|
+  fi
 | 
						|
+}
 | 
						|
+
 | 
						|
 if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then
 | 
						|
   grub_warn "$(gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.")"
 | 
						|
   exit 0
 | 
						|
@@ -45,6 +59,7 @@ if [ -z "${OSPROBED}" ] ; then
 | 
						|
 fi
 | 
						|
 
 | 
						|
 osx_entry() {
 | 
						|
+    found_other_os=1
 | 
						|
     if [ x$2 = x32 ]; then
 | 
						|
         # TRANSLATORS: it refers to kernel architecture (32-bit)
 | 
						|
 	bitstr="$(gettext "(32-bit)")"
 | 
						|
@@ -168,6 +183,7 @@ for OS in ${OSPROBED} ; do
 | 
						|
 	  ;;
 | 
						|
       esac
 | 
						|
 
 | 
						|
+      found_other_os=1
 | 
						|
 	  onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
 | 
						|
       cat << EOF
 | 
						|
 menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' $CLASS --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' {
 | 
						|
@@ -198,6 +214,7 @@ EOF
 | 
						|
     ;;
 | 
						|
     efi)
 | 
						|
 
 | 
						|
+	found_other_os=1
 | 
						|
 	EFIPATH=${DEVICE#*@}
 | 
						|
 	DEVICE=${DEVICE%@*}
 | 
						|
 	onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
 | 
						|
@@ -246,6 +263,7 @@ EOF
 | 
						|
 	  [ "${prepare_boot_cache}" ] || continue
 | 
						|
 	fi
 | 
						|
 
 | 
						|
+	found_other_os=1
 | 
						|
 	onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
 | 
						|
 	recovery_params="$(echo "${LPARAMS}" | grep 'single\|recovery')" || true
 | 
						|
 	counter=1
 | 
						|
@@ -322,6 +340,7 @@ EOF
 | 
						|
       fi
 | 
						|
     ;;
 | 
						|
     hurd)
 | 
						|
+      found_other_os=1
 | 
						|
       onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
 | 
						|
       cat << EOF
 | 
						|
 menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' {
 | 
						|
@@ -364,3 +383,5 @@ EOF
 | 
						|
     ;;
 | 
						|
   esac
 | 
						|
 done
 | 
						|
+
 | 
						|
+adjust_timeout
 |