From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 6 Jun 2018 08:44:11 +0200 Subject: [PATCH] Add auto-hide menu support On single-os systems we do not want to show the menu, unless something went wrong with the previous boot, in which case the user may need the menu to debug/fix the problem. This commit adds a new grub.d/00_menu_auto_hide file which emits a config snippet implementing this. I've chosen to do this in a separate grub.d file because chances of this going upstream are small and this way it will be easier to rebase. Since auto-hiding the menu requires detecting the previous boot was ok, we get fastboot support (where we don't check for a key at all) for free so this commit also adds support for this. The new config-file code uses the following variables: menu_auto_hide Set this to "1" to activate the new auto-hide feature Set this to "2" to auto-hide the menu even when multiple operating systems are installed. Note the menu will still auto show after booting an other os as that won't set boot_success. menu_show_once Set this to "1" to force showing the menu once. boot_success The OS sets this to "1" to indicate a successful boot. boot_indeterminate The OS increments this integer when rebooting after e.g. installing updates or a selinux relabel. fastboot If set to "1" and the conditions for auto-hiding the menu are met, the menu is not shown and all checks for keypresses are skipped, booting the default immediately. 30_os-prober.in changes somewhat inspired by: https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/patches/quick_boot.patch Signed-off-by: Hans de Goede --- Makefile.util.def | 6 +++++ util/grub.d/01_menu_auto_hide.in | 48 ++++++++++++++++++++++++++++++++++++++++ util/grub.d/30_os-prober.in | 18 +++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 util/grub.d/01_menu_auto_hide.in diff --git a/Makefile.util.def b/Makefile.util.def index 48512bc63..314e6f2ac 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -458,6 +458,12 @@ script = { installdir = grubconf; }; +script = { + name = '01_menu_auto_hide'; + common = util/grub.d/01_menu_auto_hide.in; + installdir = grubconf; +}; + script = { name = '01_users'; common = util/grub.d/01_users.in; diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/01_menu_auto_hide.in new file mode 100644 index 000000000..ad175870a --- /dev/null +++ b/util/grub.d/01_menu_auto_hide.in @@ -0,0 +1,48 @@ +#! /bin/sh + +# Disable / skip generating menu-auto-hide config parts on serial terminals +for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do + case "$x" in + serial*) + exit 0 + ;; + esac +done + +cat << EOF +if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then + set last_boot_ok=1 +else + set last_boot_ok=0 +fi + +# Reset boot_indeterminate after a successful boot +if [ "\${boot_success}" = "1" ] ; then + set boot_indeterminate=0 +# Avoid boot_indeterminate causing the menu to be hidden more then once +elif [ "\${boot_indeterminate}" = "1" ]; then + set boot_indeterminate=2 +fi +set boot_success=0 +save_env boot_success boot_indeterminate + +if [ x\$feature_timeout_style = xy ] ; then + if [ "\${menu_show_once}" ]; then + unset menu_show_once + save_env menu_show_once + set timeout_style=menu + set timeout=60 + elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then + set orig_timeout_style=\${timeout_style} + set orig_timeout=\${timeout} + if [ "\${fastboot}" = "1" ]; then + # timeout_style=menu + timeout=0 avoids the countdown code keypress check + set timeout_style=menu + set timeout=0 + else + set timeout_style=hidden + set timeout=1 + fi + fi +fi +EOF diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index 4b27bd201..3c9431cfc 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -42,6 +42,7 @@ if [ -z "${OSPROBED}" ] ; then fi osx_entry() { + found_other_os=1 # TRANSLATORS: it refers on the OS residing on device %s onstr="$(gettext_printf "(on %s)" "${DEVICE}")" hints="" @@ -102,6 +103,7 @@ for OS in ${OSPROBED} ; do case ${BOOT} in chain) + found_other_os=1 onstr="$(gettext_printf "(on %s)" "${DEVICE}")" cat << EOF @@ -132,6 +134,7 @@ EOF EOF ;; efi) + found_other_os=1 EFIPATH=${DEVICE#*@} DEVICE=${DEVICE%@*} @@ -176,6 +179,7 @@ EOF LINITRD="${LINITRD#/boot}" fi + found_other_os=1 onstr="$(gettext_printf "(on %s)" "${DEVICE}")" recovery_params="$(echo "${LPARAMS}" | grep single)" || true counter=1 @@ -257,6 +261,7 @@ EOF done ;; 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}")' { @@ -283,6 +288,7 @@ EOF EOF ;; minix) + found_other_os=1 cat << EOF menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" { EOF @@ -299,3 +305,15 @@ EOF ;; esac done + +# We override the results of the menu_auto_hide code here, this is a bit ugly, +# but grub-mkconfig writes out the file linearly, so this is the only way +if [ "${found_other_os}" = "1" ]; then + cat << EOF +# Other OS found, undo autohiding of menu unless menu_auto_hide=2 +if [ "\${orig_timeout_style}" -a "\${menu_auto_hide}" != "2" ]; then + set timeout_style=\${orig_timeout_style} + set timeout=\${orig_timeout} +fi +EOF +fi