Blame SOURCES/0074-Add-BLS-support-to-grub-mkconfig.patch

5593c8
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
5593c8
From: Peter Jones <pjones@redhat.com>
5593c8
Date: Fri, 9 Dec 2016 15:40:29 -0500
5593c8
Subject: [PATCH] Add BLS support to grub-mkconfig
5593c8
5593c8
GRUB now has BootLoaderSpec support, the user can choose to use this by
5593c8
setting GRUB_ENABLE_BLSCFG to true in /etc/default/grub. On this setup,
5593c8
the boot menu entries are not added to the grub.cfg, instead BLS config
5593c8
files are parsed by blscfg command and the entries created dynamically.
5593c8
5593c8
A 10_linux_bls grub.d snippet to generate menu entries from BLS files
5593c8
is also added that can be used on platforms where the bootloader doesn't
5593c8
have BLS support and only can parse a normal grub configuration file.
5593c8
5593c8
Portions of the 10_linux_bls were taken from the ostree-grub-generator
5593c8
script that's included in the OSTree project.
5593c8
5593c8
Fixes to support multi-devices and generate a BLS section even if no
5593c8
kernels are found in the boot directory were proposed by Yclept Nemo
5593c8
and Tom Gundersen respectively.
5593c8
5593c8
Signed-off-by: Peter Jones <pjones@redhat.com>
5593c8
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
5593c8
---
5593c8
 util/grub-mkconfig.8      |   4 +
5593c8
 util/grub-mkconfig.in     |   9 +-
5593c8
 util/grub-mkconfig_lib.in |  22 ++++-
5593c8
 util/grub.d/10_linux.in   | 223 +++++++++++++++++++++++++++++++++++++++++++++-
5593c8
 4 files changed, 252 insertions(+), 6 deletions(-)
5593c8
5593c8
diff --git a/util/grub-mkconfig.8 b/util/grub-mkconfig.8
d3c3ab
index a2d1f577b9b..434fa4deda4 100644
5593c8
--- a/util/grub-mkconfig.8
5593c8
+++ b/util/grub-mkconfig.8
5593c8
@@ -13,5 +13,9 @@
5593c8
 \fB--output\fR=\fIFILE\fR
5593c8
 Write generated output to \fIFILE\fR.
5593c8
 
5593c8
+.TP
5593c8
+\fB--no-grubenv-update\fR
5593c8
+Do not update variables in the grubenv file.
5593c8
+
5593c8
 .SH SEE ALSO
5593c8
 .BR "info grub"
5593c8
diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
d3c3ab
index 535c0f02499..f55339a3f64 100644
5593c8
--- a/util/grub-mkconfig.in
5593c8
+++ b/util/grub-mkconfig.in
5593c8
@@ -50,6 +50,8 @@ grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
5593c8
 export TEXTDOMAIN=@PACKAGE@
5593c8
 export TEXTDOMAINDIR="@localedir@"
5593c8
 
5593c8
+export GRUB_GRUBENV_UPDATE="yes"
5593c8
+
5593c8
 . "${pkgdatadir}/grub-mkconfig_lib"
5593c8
 
5593c8
 # Usage: usage
5593c8
@@ -59,6 +61,7 @@ usage () {
5593c8
     gettext "Generate a grub config file"; echo
5593c8
     echo
5593c8
     print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")"
5593c8
+    print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")"
5593c8
     print_option_help "-h, --help" "$(gettext "print this message and exit")"
5593c8
     print_option_help "-V, --version" "$(gettext "print the version information and exit")"
5593c8
     echo
5593c8
@@ -94,6 +97,9 @@ do
5593c8
     --output=*)
5593c8
 	grub_cfg=`echo "$option" | sed 's/--output=//'`
5593c8
 	;;
5593c8
+    --no-grubenv-update)
5593c8
+	GRUB_GRUBENV_UPDATE="no"
5593c8
+	;;
5593c8
     -*)
5593c8
 	gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
5593c8
 	usage
5593c8
@@ -253,7 +259,8 @@ export GRUB_DEFAULT \
5593c8
   GRUB_OS_PROBER_SKIP_LIST \
5593c8
   GRUB_DISABLE_SUBMENU \
5593c8
   GRUB_DEFAULT_DTB \
5593c8
-  SUSE_BTRFS_SNAPSHOT_BOOTING
5593c8
+  SUSE_BTRFS_SNAPSHOT_BOOTING \
5593c8
+  GRUB_ENABLE_BLSCFG
5593c8
 
5593c8
 if test "x${grub_cfg}" != "x"; then
5593c8
   rm -f "${grub_cfg}.new"
5593c8
diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
d3c3ab
index fafeac95061..d8bb4069360 100644
5593c8
--- a/util/grub-mkconfig_lib.in
5593c8
+++ b/util/grub-mkconfig_lib.in
5593c8
@@ -30,6 +30,9 @@ fi
5593c8
 if test "x$grub_file" = x; then
5593c8
   grub_file="${bindir}/@grub_file@"
5593c8
 fi
5593c8
+if test "x$grub_editenv" = x; then
5593c8
+  grub_editenv="${bindir}/@grub_editenv@"
5593c8
+fi
5593c8
 if test "x$grub_mkrelpath" = x; then
5593c8
   grub_mkrelpath="${bindir}/@grub_mkrelpath@"
5593c8
 fi
5593c8
@@ -125,8 +128,19 @@ EOF
5593c8
   fi
5593c8
 }
5593c8
 
5593c8
+prepare_grub_to_access_device_with_variable ()
5593c8
+{
5593c8
+  device_variable="$1"
5593c8
+  shift
5593c8
+  prepare_grub_to_access_device "$@"
5593c8
+  unset "device_variable"
5593c8
+}
5593c8
+
5593c8
 prepare_grub_to_access_device ()
5593c8
 {
5593c8
+  if [ -z "$device_variable" ]; then
5593c8
+    device_variable="root"
5593c8
+  fi
5593c8
   old_ifs="$IFS"
5593c8
   IFS='
5593c8
 '
5593c8
@@ -161,18 +175,18 @@ prepare_grub_to_access_device ()
5593c8
   # otherwise set root as per value in device.map.
5593c8
   fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`"
5593c8
   if [ "x$fs_hint" != x ]; then
5593c8
-    echo "set root='$fs_hint'"
5593c8
+    echo "set ${device_variable}='$fs_hint'"
5593c8
   fi
5593c8
   if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then
5593c8
     hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints=
5593c8
     if [ "x$hints" != x ]; then
5593c8
       echo "if [ x\$feature_platform_search_hint = xy ]; then"
5593c8
-      echo "  search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}"
5593c8
+      echo "  search --no-floppy --fs-uuid --set=${device_variable} ${hints} ${fs_uuid}"
5593c8
       echo "else"
5593c8
-      echo "  search --no-floppy --fs-uuid --set=root ${fs_uuid}"
5593c8
+      echo "  search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}"
5593c8
       echo "fi"
5593c8
     else
5593c8
-      echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}"
5593c8
+      echo "search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}"
5593c8
     fi
5593c8
   fi
5593c8
   IFS="$old_ifs"
5593c8
diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
d3c3ab
index cbfaca34cc7..68adb55d893 100644
5593c8
--- a/util/grub.d/10_linux.in
5593c8
+++ b/util/grub.d/10_linux.in
5593c8
@@ -82,6 +82,223 @@ case x"$GRUB_FS" in
5593c8
 	;;
5593c8
 esac
5593c8
 
5593c8
+populate_header_warn()
5593c8
+{
5593c8
+if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then
5593c8
+  bls_parser="10_linux script"
5593c8
+else
5593c8
+  bls_parser="blscfg command"
5593c8
+fi
5593c8
+cat <
5593c8
+
5593c8
+# This section was generated by a script. Do not modify the generated file - all changes
5593c8
+# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files.
5593c8
+#
5593c8
+# The $bls_parser parses the BootLoaderSpec files stored in /boot/loader/entries and
5593c8
+# populates the boot menu. Please refer to the Boot Loader Specification documentation
5593c8
+# for the files format: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/.
5593c8
+
5593c8
+EOF
5593c8
+}
5593c8
+
5593c8
+read_config()
5593c8
+{
5593c8
+    config_file=${1}
5593c8
+    title=""
5593c8
+    initrd=""
5593c8
+    options=""
5593c8
+    linux=""
5593c8
+    grub_arg=""
5593c8
+
5593c8
+    while read -r line
5593c8
+    do
5593c8
+        record=$(echo ${line} | cut -f 1 -d ' ')
5593c8
+        value=$(echo ${line} | cut -s -f2- -d ' ')
5593c8
+        case "${record}" in
5593c8
+            "title")
5593c8
+                title=${value}
5593c8
+                ;;
5593c8
+            "initrd")
5593c8
+                initrd=${value}
5593c8
+                ;;
5593c8
+            "linux")
5593c8
+                linux=${value}
5593c8
+                ;;
5593c8
+            "options")
5593c8
+                options=${value}
5593c8
+                ;;
5593c8
+            "grub_arg")
5593c8
+                grub_arg=${value}
5593c8
+                ;;
5593c8
+        esac
5593c8
+    done < ${config_file}
5593c8
+}
5593c8
+
5593c8
+blsdir="/boot/loader/entries"
5593c8
+
5593c8
+get_sorted_bls()
5593c8
+{
5593c8
+    if ! [ -d "${blsdir}" ] || ! [ -e /etc/machine-id ]; then
5593c8
+        return
5593c8
+    fi
5593c8
+
5593c8
+    read machine_id < /etc/machine-id
5593c8
+    if [ -z "${machine_id}" ]; then
5593c8
+        return
5593c8
+    fi
5593c8
+
5593c8
+    local IFS=$'\n'
5593c8
+
5593c8
+    files=($(for bls in ${blsdir}/${machine_id}-*.conf; do
5593c8
+        if ! [[ -e "${bls}" ]] ; then
5593c8
+            continue
5593c8
+        fi
5593c8
+        bls="${bls%.conf}"
5593c8
+        bls="${bls##*/}"
5593c8
+        echo "${bls}"
5593c8
+    done | ${kernel_sort} 2>/dev/null | tac)) || :
5593c8
+
5593c8
+    echo "${files[@]}"
5593c8
+}
5593c8
+
5593c8
+update_bls_cmdline()
5593c8
+{
5593c8
+    local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
5593c8
+    local -a files=($(get_sorted_bls))
5593c8
+
5593c8
+    for bls in "${files[@]}"; do
5593c8
+        local options="${cmdline}"
5593c8
+        if [ -z "${bls##*debug*}" ]; then
5593c8
+            options="${options} ${GRUB_CMDLINE_LINUX_DEBUG}"
5593c8
+        fi
5593c8
+        options="$(echo "${options}" | sed -e 's/\//\\\//g')"
5593c8
+        sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf"
5593c8
+    done
5593c8
+}
5593c8
+
5593c8
+populate_menu()
5593c8
+{
5593c8
+    local -a files=($(get_sorted_bls))
5593c8
+
5593c8
+    gettext_printf "Generating boot entries from BLS files...\n" >&2
5593c8
+
5593c8
+    for bls in "${files[@]}"; do
5593c8
+        read_config "${blsdir}/${bls}.conf"
5593c8
+
5593c8
+        menu="${menu}menuentry '${title}' ${grub_arg} --id=${bls} {\n"
5593c8
+        menu="${menu}\t linux ${linux} ${options}\n"
5593c8
+        if [ -n "${initrd}" ] ; then
5593c8
+            menu="${menu}\t initrd ${boot_prefix}${initrd}\n"
5593c8
+        fi
5593c8
+        menu="${menu}}\n\n"
5593c8
+    done
5593c8
+    # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation
5593c8
+    printf "$menu"
5593c8
+}
5593c8
+
5593c8
+# Make BLS the default if GRUB_ENABLE_BLSCFG was not set and grubby is not installed.
5593c8
+if [ -z "${GRUB_ENABLE_BLSCFG}" ] && [ -z "$(which new-kernel-pkg 2> /dev/null)" ]; then
5593c8
+	  GRUB_ENABLE_BLSCFG="true"
5593c8
+fi
5593c8
+
5593c8
+if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then
5593c8
+  if [ x$dirname = x/ ]; then
5593c8
+    if [ -z "${prepare_root_cache}" ]; then
5593c8
+      prepare_grub_to_access_device ${GRUB_DEVICE}
5593c8
+    fi
5593c8
+  else
5593c8
+    if [ -z "${prepare_boot_cache}" ]; then
5593c8
+      prepare_grub_to_access_device ${GRUB_DEVICE_BOOT}
5593c8
+    fi
5593c8
+  fi
5593c8
+
5593c8
+  if [ -d /sys/firmware/efi ]; then
5593c8
+      bootefi_device="`${grub_probe} --target=device /boot/efi/`"
5593c8
+      prepare_grub_to_access_device_with_variable boot ${bootefi_device}
5593c8
+  else
5593c8
+      boot_device="`${grub_probe} --target=device /boot/`"
5593c8
+      prepare_grub_to_access_device_with_variable boot ${boot_device}
5593c8
+  fi
5593c8
+
5593c8
+  arch="$(uname -m)"
5593c8
+  if [ "x${arch}" = "xppc64le" ] && [ -d /sys/firmware/opal ]; then
5593c8
+
5593c8
+      BLS_POPULATE_MENU="true"
5593c8
+      petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot"
5593c8
+
5593c8
+      if test -e ${petitboot_path}; then
5593c8
+          read -r -d '' petitboot_version < ${petitboot_path}
5593c8
+          petitboot_version="$(echo ${petitboot_version//v})"
5593c8
+
5593c8
+	  if test -n ${petitboot_version}; then
5593c8
+              major_version="$(echo ${petitboot_version} | cut -d . -f1)"
5593c8
+              minor_version="$(echo ${petitboot_version} | cut -d . -f2)"
5593c8
+
5593c8
+              re='^[0-9]+$'
5593c8
+              if [[ $major_version =~ $re ]] && [[ $minor_version =~ $re ]] &&
5593c8
+                 ([[ ${major_version} -gt 1 ]] ||
5593c8
+                  [[ ${major_version} -eq 1 &&
5593c8
+                     ${minor_version} -ge 8  ]]); then
5593c8
+                  BLS_POPULATE_MENU="false"
5593c8
+              fi
5593c8
+          fi
5593c8
+      fi
5593c8
+  fi
5593c8
+
5593c8
+  populate_header_warn
5593c8
+
5593c8
+  cat << EOF
5593c8
+# The kernelopts variable should be defined in the grubenv file. But to ensure that menu
5593c8
+# entries populated from BootLoaderSpec files that use this variable work correctly even
5593c8
+# without a grubenv file, define a fallback kernelopts variable if this has not been set.
5593c8
+#
5593c8
+# The kernelopts variable in the grubenv file can be modified using the grubby tool or by
5593c8
+# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX
5593c8
+# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both
5593c8
+# the kernelopts variable in the grubenv file and the fallback kernelopts variable.
5593c8
+if [ -z "\${kernelopts}" ]; then
5593c8
+  set kernelopts="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
5593c8
+fi
5593c8
+EOF
5593c8
+
5593c8
+  update_bls_cmdline
5593c8
+
5593c8
+  if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then
5593c8
+      populate_menu
5593c8
+  else
5593c8
+      cat << EOF
5593c8
+
5593c8
+insmod blscfg
5593c8
+blscfg
5593c8
+EOF
5593c8
+  fi
5593c8
+
5593c8
+  if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then
5593c8
+      blsdir="/boot/loader/entries"
5593c8
+      [ -d "${blsdir}" ] && GRUB_BLS_FS="$(${grub_probe} --target=fs ${blsdir})"
5593c8
+      if [ "x${GRUB_BLS_FS}" = "xbtrfs" ] || [ "x${GRUB_BLS_FS}" = "xzfs" ]; then
5593c8
+          blsdir=$(make_system_path_relative_to_its_root "${blsdir}")
5593c8
+          if [ "x${blsdir}" != "x/loader/entries" ] && [ "x${blsdir}" != "x/boot/loader/entries" ]; then
5593c8
+              ${grub_editenv} - set blsdir="${blsdir}"
5593c8
+          fi
5593c8
+      fi
5593c8
+
5593c8
+      if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then
5593c8
+          ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}"
5593c8
+      fi
5593c8
+
5593c8
+      if [ -n "${GRUB_DEFAULT_DTB}" ]; then
5593c8
+          ${grub_editenv} - set devicetree="${GRUB_DEFAULT_DTB}"
5593c8
+      fi
5593c8
+
5593c8
+      if [ -n "${GRUB_SAVEDEFAULT}" ]; then
5593c8
+           ${grub_editenv} - set save_default="${GRUB_SAVEDEFAULT}"
5593c8
+      fi
5593c8
+  fi
5593c8
+
5593c8
+  exit 0
5593c8
+fi
5593c8
+
5593c8
 mktitle ()
5593c8
 {
5593c8
   local title_type
5593c8
@@ -121,6 +338,7 @@ linux_entry ()
5593c8
   if [ -z "$boot_device_id" ]; then
5593c8
       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
5593c8
   fi
5593c8
+
5593c8
   if [ x$type != xsimple ] ; then
5593c8
       title=$(mktitle "$type" "$version")
5593c8
       if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
5593c8
@@ -224,6 +442,7 @@ is_top_level=true
5593c8
 while [ "x$list" != "x" ] ; do
5593c8
   linux=`version_find_latest $list`
5593c8
   gettext_printf "Found linux image: %s\n" "$linux" >&2
5593c8
+
5593c8
   basename=`basename $linux`
5593c8
   dirname=`dirname $linux`
5593c8
   rel_dirname=`make_system_path_relative_to_its_root $dirname`
5593c8
@@ -262,7 +481,9 @@ while [ "x$list" != "x" ] ; do
5593c8
     for i in ${initrd}; do
5593c8
       initrd_display="${initrd_display} ${dirname}/${i}"
5593c8
     done
5593c8
-    gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
5593c8
+    if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then
5593c8
+      gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
5593c8
+    fi
5593c8
   fi
5593c8
 
5593c8
   fdt=