]> git.proxmox.com Git - grub2.git/commitdiff
Add configure option to bypass boot menu if possible
authorColin Watson <cjwatson@ubuntu.com>
Mon, 13 Jan 2014 12:13:28 +0000 (12:13 +0000)
committerColin Watson <cjwatson@debian.org>
Fri, 24 Sep 2021 23:37:38 +0000 (00:37 +0100)
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
docs/grub.texi
grub-core/normal/menu.c
util/grub-mkconfig.in
util/grub.d/00_header.in
util/grub.d/10_linux.in
util/grub.d/30_os-prober.in

index 256fc44ef1990dc45664e2794b051c5d5c00fc46..c42e4c784db7ed57f0b8f6f549fe5adbb5f31d67 100644 (file)
@@ -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])
index f8b4b3b21a7fa6e1ac3d55afe0238709d60110b4..0b58dafb2d2acd97ee62ec583f9eaf8850034d34 100644 (file)
@@ -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
index e9d8444b552e72fa2d1f019c02c40dc9c6413d8b..0440340b8e42ac5a0080142faba88baac38a9bb4 100644 (file)
@@ -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 ();
index 0265a5a66e8cb15318895c2c639f630a6468f1fb..fa9c53a927fc8b4c3eff852120f23ddcae2849df 100644 (file)
@@ -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"
index 93a90233ead40bfbb9d0994ae41098aa884a36d7..674a76140202f21033ddd95f31fafc47171a79c7 100644 (file)
@@ -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
 }
index 869a7eec5b39671b3bf726df19de0f306ca270a2..80315a31b9972f7298e8fa23e9386f7ad3ac8c06 100644 (file)
@@ -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
index 98aee403eed0913340ffa7e3167c5a5360c06fc1..225a3baf7c12c2eaabb99da32f5a221aa696baab 100644 (file)
@@ -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