From 439de947262b0d8d4a02ca5afb1ef4f15853962c Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Fri, 9 Dec 2016 15:40:29 -0500 Subject: [PATCH 2/9] Add BLS support to grub-mkconfig GRUB now has BootLoaderSpec support, the user can choose to use this by setting GRUB_ENABLE_BLSCFG to true in /etc/default/grub. On this setup, the boot menu entries are not added to the grub.cfg, instead BLS config files are parsed by blscfg command and the entries created dynamically. A 10_linux_bls grub.d snippet to generate menu entries from BLS files is also added that can be used on platforms where the bootloader doesn't have BLS support and only can parse a normal grub configuration file. Portions of the 10_linux_bls were taken from the ostree-grub-generator script that's included in the OSTree project. Fixes to support multi-devices and generate a BLS section even if no kernels are found in the boot directory were proposed by Yclept Nemo and Tom Gundersen respectively. Signed-off-by: Peter Jones [javierm: remove outdated URL for BLS document] Signed-off-by: Javier Martinez Canillas [iwienand@redhat.com: skip machine ID check when updating entries] Signed-off-by: Ian Wienand [rharwood: commit message composits, drop man pages] Signed-off-by: Robbie Harwood --- util/grub-mkconfig.in | 9 +- util/grub-mkconfig_lib.in | 22 +++- util/grub.d/10_linux.in | 244 +++++++++++++++++++++++++++++++++++++- 3 files changed, 269 insertions(+), 6 deletions(-) diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in index cf5b79342..7af15df94 100644 --- a/util/grub-mkconfig.in +++ b/util/grub-mkconfig.in @@ -49,6 +49,8 @@ grub_script_check="${bindir}/@grub_script_check@" export TEXTDOMAIN=@PACKAGE@ export TEXTDOMAINDIR="@localedir@" +export GRUB_GRUBENV_UPDATE="yes" + . "${pkgdatadir}/grub-mkconfig_lib" # Usage: usage @@ -58,6 +60,7 @@ usage () { gettext "Generate a grub config file"; echo echo print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")" + print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")" print_option_help "-h, --help" "$(gettext "print this message and exit")" print_option_help "-V, --version" "$(gettext "print the version information and exit")" echo @@ -93,6 +96,9 @@ do --output=*) grub_cfg=`echo "$option" | sed 's/--output=//'` ;; + --no-grubenv-update) + GRUB_GRUBENV_UPDATE="no" + ;; -*) gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 usage @@ -300,7 +306,8 @@ export GRUB_DEFAULT \ GRUB_DISABLE_SUBMENU \ SUSE_BTRFS_SNAPSHOT_BOOTING \ SUSE_CMDLINE_XENEFI \ - SUSE_REMOVE_LINUX_ROOT_PARAM + SUSE_REMOVE_LINUX_ROOT_PARAM \ + GRUB_ENABLE_BLSCFG if test "x${grub_cfg}" != "x"; then rm -f "${grub_cfg}.new" diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in index 22fb7668f..5db4337c6 100644 --- a/util/grub-mkconfig_lib.in +++ b/util/grub-mkconfig_lib.in @@ -30,6 +30,9 @@ fi if test "x$grub_file" = x; then grub_file="${bindir}/@grub_file@" fi +if test "x$grub_editenv" = x; then + grub_editenv="${bindir}/@grub_editenv@" +fi if test "x$grub_mkrelpath" = x; then grub_mkrelpath="${bindir}/@grub_mkrelpath@" fi @@ -123,8 +126,19 @@ EOF fi } +prepare_grub_to_access_device_with_variable () +{ + device_variable="$1" + shift + prepare_grub_to_access_device "$@" + unset "device_variable" +} + prepare_grub_to_access_device () { + if [ -z "$device_variable" ]; then + device_variable="root" + fi old_ifs="$IFS" IFS=' ' @@ -159,18 +173,18 @@ prepare_grub_to_access_device () # otherwise set root as per value in device.map. fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`" if [ "x$fs_hint" != x ]; then - echo "set root='$fs_hint'" + echo "set ${device_variable}='$fs_hint'" fi if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints= if [ "x$hints" != x ]; then echo "if [ x\$feature_platform_search_hint = xy ]; then" - echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}" + echo " search --no-floppy --fs-uuid --set=${device_variable} ${hints} ${fs_uuid}" echo "else" - echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}" + echo " search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" echo "fi" else - echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}" + echo "search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" fi fi IFS="$old_ifs" diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index 5531239eb..49eccbeaf 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -91,6 +91,244 @@ if [ "x$SUSE_REMOVE_LINUX_ROOT_PARAM" = "xtrue" ]; then LINUX_ROOT_DEVICE="" fi +populate_header_warn() +{ +if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then + bls_parser="10_linux script" +else + bls_parser="blscfg command" +fi +cat </dev/null | tac)) || : + + echo "${files[@]}" +} + +update_bls_cmdline() +{ + local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + local -a files=($(get_sorted_bls)) + + for bls in "${files[@]}"; do + local options="${cmdline}" + if [ -z "${bls##*debug*}" ]; then + options="${options} ${GRUB_CMDLINE_LINUX_DEBUG}" + fi + options="$(echo "${options}" | sed -e 's/\//\\\//g')" + sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf" + done +} + +populate_menu() +{ + local -a files=($(get_sorted_bls)) + + gettext_printf "Generating boot entries from BLS files...\n" >&2 + + for bls in "${files[@]}"; do + read_config "${blsdir}/${bls}.conf" + + menu="${menu}menuentry '${title}' ${grub_arg} --id=${bls} {\n" + menu="${menu}\t linux ${linux} ${options}\n" + if [ -n "${initrd}" ] ; then + menu="${menu}\t initrd ${boot_prefix}${initrd}\n" + fi + menu="${menu}}\n\n" + done + # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation + printf "$menu" +} + +# Make BLS the default if GRUB_ENABLE_BLSCFG was not set and grubby is not installed. +if [ -z "${GRUB_ENABLE_BLSCFG}" ] && ! command -v new-kernel-pkg >/dev/null; then + GRUB_ENABLE_BLSCFG="true" +fi + +if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then + if [ x$dirname = x/ ]; then + if [ -z "${prepare_root_cache}" ]; then + prepare_grub_to_access_device ${GRUB_DEVICE} + fi + else + if [ -z "${prepare_boot_cache}" ]; then + prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} + fi + fi + + if [ -d /sys/firmware/efi ]; then + bootefi_device="`${grub_probe} --target=device /boot/efi/`" + prepare_grub_to_access_device_with_variable boot ${bootefi_device} + else + boot_device="`${grub_probe} --target=device /boot/`" + prepare_grub_to_access_device_with_variable boot ${boot_device} + fi + + arch="$(uname -m)" + if [ "x${arch}" = "xppc64le" ] && [ -d /sys/firmware/opal ]; then + + BLS_POPULATE_MENU="true" + petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot" + + if test -e ${petitboot_path}; then + read -r -d '' petitboot_version < ${petitboot_path} + petitboot_version="$(echo ${petitboot_version//v})" + + if test -n ${petitboot_version}; then + major_version="$(echo ${petitboot_version} | cut -d . -f1)" + minor_version="$(echo ${petitboot_version} | cut -d . -f2)" + + re='^[0-9]+$' + if [[ $major_version =~ $re ]] && [[ $minor_version =~ $re ]] && + ([[ ${major_version} -gt 1 ]] || + [[ ${major_version} -eq 1 && + ${minor_version} -ge 8 ]]); then + BLS_POPULATE_MENU="false" + fi + fi + fi + fi + + populate_header_warn + + cat << EOF +# The kernelopts variable should be defined in the grubenv file. But to ensure that menu +# entries populated from BootLoaderSpec files that use this variable work correctly even +# without a grubenv file, define a fallback kernelopts variable if this has not been set. +# +# The kernelopts variable in the grubenv file can be modified using the grubby tool or by +# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX +# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both +# the kernelopts variable in the grubenv file and the fallback kernelopts variable. +if [ -z "\${kernelopts}" ]; then + set kernelopts="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" +fi +EOF + + update_bls_cmdline + + if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then + populate_menu + else + cat << EOF + +insmod blscfg +blscfg +EOF + fi + + if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then + blsdir="/boot/loader/entries" + [ -d "${blsdir}" ] && GRUB_BLS_FS="$(${grub_probe} --target=fs ${blsdir})" + if [ "x${GRUB_BLS_FS}" = "xbtrfs" ] || [ "x${GRUB_BLS_FS}" = "xzfs" ]; then + blsdir=$(make_system_path_relative_to_its_root "${blsdir}") + if [ "x${blsdir}" != "x/loader/entries" ] && [ "x${blsdir}" != "x/boot/loader/entries" ]; then + ${grub_editenv} - set blsdir="${blsdir}" + fi + fi + + if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then + ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}" + fi + + if [ -n "${GRUB_DEFAULT_DTB}" ]; then + ${grub_editenv} - set devicetree="${GRUB_DEFAULT_DTB}" + fi + + if [ -n "${GRUB_SAVEDEFAULT}" ]; then + ${grub_editenv} - set save_default="${GRUB_SAVEDEFAULT}" + fi + fi + + exit 0 +fi + +mktitle () +{ + local title_type + local version + local OS_NAME + local OS_VERS + + title_type=$1 && shift + version=$1 && shift + + OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})" + OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})" + + case $title_type in + recovery) + title=$(printf '%s (%s) %s (recovery mode)' \ + "${OS_NAME}" "${version}" "${OS_VERS}") + ;; + *) + title=$(printf '%s (%s) %s' \ + "${OS_NAME}" "${version}" "${OS_VERS}") + ;; + esac + echo -n ${title} +} + title_correction_code= hotkey=1 @@ -124,6 +362,7 @@ linux_entry () if [ -z "$boot_device_id" ]; then boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" fi + if [ x$type != xsimple ] ; then case $type in recovery) @@ -298,6 +537,7 @@ fi is_top_level=true for linux in ${reverse_sorted_list}; do gettext_printf "Found linux image: %s\n" "$linux" >&2 + basename=`basename $linux` dirname=`dirname $linux` rel_dirname=`make_system_path_relative_to_its_root $dirname` @@ -348,7 +588,9 @@ for linux in ${reverse_sorted_list}; do for i in ${initrd}; do initrd_display="${initrd_display} ${dirname}/${i}" done - gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 + if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then + gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 + fi fi config= -- 2.44.0