Commit 82480176 authored by Colin Watson's avatar Colin Watson Committed by Colin Watson

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
parent f3a7735a
...@@ -1841,6 +1841,17 @@ else ...@@ -1841,6 +1841,17 @@ else
fi fi
AC_SUBST([QUIET_BOOT]) 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="" LIBS=""
AC_SUBST([FONT_SOURCE]) AC_SUBST([FONT_SOURCE])
......
...@@ -1490,6 +1490,20 @@ This option may be set to a list of GRUB module names separated by spaces. ...@@ -1490,6 +1490,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 Each module will be loaded as early as possible, at the start of
@file{grub.cfg}. @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 @end table
The following options are still accepted for compatibility with existing The following options are still accepted for compatibility with existing
......
...@@ -604,6 +604,30 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) ...@@ -604,6 +604,30 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
static struct grub_term_coordinate *pos; static struct grub_term_coordinate *pos;
int entry = -1; 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) if (timeout_style == TIMEOUT_STYLE_COUNTDOWN && timeout)
{ {
pos = grub_term_save_pos (); pos = grub_term_save_pos ();
......
...@@ -239,7 +239,8 @@ export GRUB_DEFAULT \ ...@@ -239,7 +239,8 @@ export GRUB_DEFAULT \
GRUB_ENABLE_CRYPTODISK \ GRUB_ENABLE_CRYPTODISK \
GRUB_BADRAM \ GRUB_BADRAM \
GRUB_OS_PROBER_SKIP_LIST \ GRUB_OS_PROBER_SKIP_LIST \
GRUB_DISABLE_SUBMENU GRUB_DISABLE_SUBMENU \
GRUB_RECORDFAIL_TIMEOUT
if test "x${grub_cfg}" != "x"; then if test "x${grub_cfg}" != "x"; then
rm -f "${grub_cfg}.new" rm -f "${grub_cfg}.new"
......
...@@ -21,6 +21,8 @@ prefix="@prefix@" ...@@ -21,6 +21,8 @@ prefix="@prefix@"
exec_prefix="@exec_prefix@" exec_prefix="@exec_prefix@"
datarootdir="@datarootdir@" datarootdir="@datarootdir@"
grub_lang=`echo $LANG | cut -d . -f 1` grub_lang=`echo $LANG | cut -d . -f 1`
grubdir="`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`"
quick_boot="@QUICK_BOOT@"
export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAIN=@PACKAGE@
export TEXTDOMAINDIR="@localedir@" export TEXTDOMAINDIR="@localedir@"
...@@ -44,6 +46,7 @@ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT ...@@ -44,6 +46,7 @@ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT
cat << EOF cat << EOF
if [ -s \$prefix/grubenv ]; then if [ -s \$prefix/grubenv ]; then
set have_grubenv=true
load_env load_env
fi fi
EOF EOF
...@@ -96,7 +99,50 @@ function savedefault { ...@@ -96,7 +99,50 @@ function savedefault {
save_env saved_entry save_env saved_entry
fi 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 { function load_video {
EOF EOF
if [ -n "${GRUB_VIDEO_BACKEND}" ]; then if [ -n "${GRUB_VIDEO_BACKEND}" ]; then
...@@ -282,10 +328,16 @@ fi ...@@ -282,10 +328,16 @@ fi
make_timeout () make_timeout ()
{ {
cat << EOF
if [ "\${recordfail}" = 1 ] ; then
set timeout=${GRUB_RECORDFAIL_TIMEOUT:-30}
else
EOF
if [ "x${3}" != "x" ] ; then if [ "x${3}" != "x" ] ; then
timeout="${2}" timeout="${2}"
style="${3}" 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. # Handle the deprecated GRUB_HIDDEN_TIMEOUT scheme.
timeout="${1}" timeout="${1}"
if [ "x${2}" != "x0" ] ; then if [ "x${2}" != "x0" ] ; then
...@@ -304,26 +356,27 @@ make_timeout () ...@@ -304,26 +356,27 @@ make_timeout ()
style="menu" style="menu"
fi fi
cat << EOF cat << EOF
if [ x\$feature_timeout_style = xy ] ; then if [ x\$feature_timeout_style = xy ] ; then
set timeout_style=${style} set timeout_style=${style}
set timeout=${timeout} set timeout=${timeout}
EOF EOF
if [ "x${style}" = "xmenu" ] ; then if [ "x${style}" = "xmenu" ] ; then
cat << EOF cat << EOF
# Fallback normal timeout code in case the timeout_style feature is # Fallback normal timeout code in case the timeout_style feature is
# unavailable. # unavailable.
else else
set timeout=${timeout} set timeout=${timeout}
EOF EOF
else else
cat << EOF cat << EOF
# Fallback hidden-timeout code in case the timeout_style feature is # Fallback hidden-timeout code in case the timeout_style feature is
# unavailable. # unavailable.
elif sleep${verbose} --interruptible ${timeout} ; then elif sleep${verbose} --interruptible ${timeout} ; then
set timeout=0 set timeout=0
EOF EOF
fi fi
cat << EOF cat << EOF
fi
fi fi
EOF EOF
} }
......
...@@ -22,6 +22,7 @@ exec_prefix="@exec_prefix@" ...@@ -22,6 +22,7 @@ exec_prefix="@exec_prefix@"
datarootdir="@datarootdir@" datarootdir="@datarootdir@"
ubuntu_recovery="@UBUNTU_RECOVERY@" ubuntu_recovery="@UBUNTU_RECOVERY@"
quiet_boot="@QUIET_BOOT@" quiet_boot="@QUIET_BOOT@"
quick_boot="@QUICK_BOOT@"
. "$pkgdatadir/grub-mkconfig_lib" . "$pkgdatadir/grub-mkconfig_lib"
...@@ -119,6 +120,9 @@ linux_entry () ...@@ -119,6 +120,9 @@ linux_entry ()
else else
echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
fi fi
if [ "$quick_boot" = 1 ]; then
echo " recordfail" | sed "s/^/$submenu_indentation/"
fi
if [ x$type != xrecovery ] ; then if [ x$type != xrecovery ] ; then
save_default_entry | grub_add_tab save_default_entry | grub_add_tab
fi fi
......
...@@ -20,12 +20,26 @@ set -e ...@@ -20,12 +20,26 @@ set -e
prefix="@prefix@" prefix="@prefix@"
exec_prefix="@exec_prefix@" exec_prefix="@exec_prefix@"
datarootdir="@datarootdir@" datarootdir="@datarootdir@"
quick_boot="@QUICK_BOOT@"
export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAIN=@PACKAGE@
export TEXTDOMAINDIR="@localedir@" export TEXTDOMAINDIR="@localedir@"
. "$pkgdatadir/grub-mkconfig_lib" . "$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 if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then
exit 0 exit 0
fi fi
...@@ -42,6 +56,7 @@ if [ -z "${OSPROBED}" ] ; then ...@@ -42,6 +56,7 @@ if [ -z "${OSPROBED}" ] ; then
fi fi
osx_entry() { osx_entry() {
found_other_os=1
if [ x$2 = x32 ]; then if [ x$2 = x32 ]; then
# TRANSLATORS: it refers to kernel architecture (32-bit) # TRANSLATORS: it refers to kernel architecture (32-bit)
bitstr="$(gettext "(32-bit)")" bitstr="$(gettext "(32-bit)")"
...@@ -165,6 +180,7 @@ for OS in ${OSPROBED} ; do ...@@ -165,6 +180,7 @@ for OS in ${OSPROBED} ; do
;; ;;
esac esac
found_other_os=1
onstr="$(gettext_printf "(on %s)" "${DEVICE}")" onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
cat << EOF cat << EOF
menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' $CLASS --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' { menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' $CLASS --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' {
...@@ -195,6 +211,7 @@ EOF ...@@ -195,6 +211,7 @@ EOF
;; ;;
efi) efi)
found_other_os=1
EFIPATH=${DEVICE#*@} EFIPATH=${DEVICE#*@}
DEVICE=${DEVICE%@*} DEVICE=${DEVICE%@*}
onstr="$(gettext_printf "(on %s)" "${DEVICE}")" onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
...@@ -243,6 +260,7 @@ EOF ...@@ -243,6 +260,7 @@ EOF
[ "${prepare_boot_cache}" ] || continue [ "${prepare_boot_cache}" ] || continue
fi fi
found_other_os=1
onstr="$(gettext_printf "(on %s)" "${DEVICE}")" onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
recovery_params="$(echo "${LPARAMS}" | grep 'single\|recovery')" || true recovery_params="$(echo "${LPARAMS}" | grep 'single\|recovery')" || true
counter=1 counter=1
...@@ -311,6 +329,7 @@ EOF ...@@ -311,6 +329,7 @@ EOF
fi fi
;; ;;
hurd) hurd)
found_other_os=1
onstr="$(gettext_printf "(on %s)" "${DEVICE}")" onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
cat << EOF 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}")' { 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}")' {
...@@ -353,3 +372,5 @@ EOF ...@@ -353,3 +372,5 @@ EOF
;; ;;
esac esac
done done
adjust_timeout
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment