diff --git a/usr/share/rear/lib/uefi-functions.sh b/usr/share/rear/lib/uefi-functions.sh index 95e6292d..c583e044 100644 --- a/usr/share/rear/lib/uefi-functions.sh +++ b/usr/share/rear/lib/uefi-functions.sh @@ -37,20 +37,76 @@ function trim { } function build_bootx86_efi { - local gmkimage - if has_binary grub-mkimage; then - gmkimage=grub-mkimage - elif has_binary grub2-mkimage; then - gmkimage=grub2-mkimage + local outfile="$1" + local embedded_config="" + local gmkstandalone="" + local gprobe="" + local dirs=() + # modules is the list of modules to load + local modules=() + + # Configuration file is optional for image creation. + shift + if [[ -n "$1" ]] ; then + # graft point syntax. $1 will appear as /boot/grub/grub.cfg in the image + embedded_config="/boot/grub/grub.cfg=$1" + shift + # directories that should be accessible by GRUB2 (e.g. because they contain the kernel) + dirs=( ${@:+"$@"} ) + fi + + if has_binary grub-mkstandalone ; then + gmkstandalone=grub-mkstandalone + elif has_binary grub2-mkstandalone ; then + # At least SUSE systems use 'grub2' prefixed names for GRUB2 programs: + gmkstandalone=grub2-mkstandalone else - Log "Did not find grub-mkimage (cannot build bootx86.efi)" - return + # This build_bootx86_efi function is only called in output/ISO/Linux-i386/250_populate_efibootimg.sh + # which runs only if UEFI is used so that we simply error out here if we cannot make a bootable EFI image of GRUB2 + # (normally a function should not exit out but return to its caller with a non-zero return code): + Error "Cannot make bootable EFI image of GRUB2 (neither grub-mkstandalone nor grub2-mkstandalone found)" + fi + + # Determine what modules need to be loaded in order to access given directories + # (if the list of modules is not overriden by GRUB2_MODULES_LOAD) + if (( ${#dirs[@]} )) && ! (( ${#modules[@]} )) ; then + if has_binary grub-probe ; then + gprobe=grub-probe + elif has_binary grub2-probe ; then + # At least SUSE systems use 'grub2' prefixed names for GRUB2 programs: + gprobe=grub2-probe + else + LogWarn "Neither grub-probe nor grub2-probe found" + if test /usr/lib/grub*/x86_64-efi/partmap.lst ; then + LogWarn "including all partition modules" + modules=( $(cat /usr/lib/grub*/x86_64-efi/partmap.lst) ) + else + Error "Can not determine partition modules, ${dirs[*]} would be likely inaccessible in GRUB2" + fi + fi + + if [ -n "$gprobe" ]; then + # this is unfortunately only a crude approximation of the Grub internal probe_mods() function + modules=( $( for p in "${dirs[@]}" ; do + $gprobe --target=fs "$p" + $gprobe --target=partmap "$p" | sed -e 's/^/part_/' + $gprobe --target=abstraction "$p" + done | sort -u ) ) + fi + fi + + # grub-mkimage needs /usr/lib/grub/x86_64-efi/moddep.lst (cf. https://github.com/rear/rear/issues/1193) + # and at least on SUSE systems grub2-mkimage needs /usr/lib/grub2/x86_64-efi/moddep.lst (in 'grub2' directory) + # so that we error out if grub-mkimage or grub2-mkimage would fail when its moddep.lst is missing. + # Careful: usr/sbin/rear sets nullglob so that /usr/lib/grub*/x86_64-efi/moddep.lst gets empty if nothing matches + # and 'test -f' succeeds with empty argument so that we cannot use 'test -f /usr/lib/grub*/x86_64-efi/moddep.lst' + # also 'test -n' succeeds with empty argument but (fortunately/intentionally?) plain 'test' fails with empty argument: + test /usr/lib/grub*/x86_64-efi/moddep.lst || Error "$gmkstandalone would not make bootable EFI image of GRUB2 (no /usr/lib/grub*/x86_64-efi/moddep.lst file)" + + (( ${#modules[@]} )) && LogPrint "GRUB2 modules to load: ${modules[*]}" + + if ! $gmkstandalone $v ${modules:+"--modules=${modules[*]}"} -O x86_64-efi -o $outfile $embedded_config ; then + Error "Failed to make bootable EFI image of GRUB2 (error during $gmkstandalone of $outfile)" fi - # as not all Linux distro's have the same grub modules present we verify what we have (see also https://github.com/rear/rear/pull/2001) - grub_modules="" - for grub_module in part_gpt part_msdos fat ext2 normal chain boot configfile linux linuxefi multiboot jfs iso9660 usb usbms usb_keyboard video udf ntfs all_video gzio efi_gop reboot search test echo btrfs ; do - test "$( find /boot -type f -name "$grub_module.mod" 2>/dev/null )" && grub_modules="$grub_modules $grub_module" - done - $gmkimage $v -O x86_64-efi -c $TMP_DIR/mnt/EFI/BOOT/embedded_grub.cfg -o $TMP_DIR/mnt/EFI/BOOT/BOOTX64.efi -p "/EFI/BOOT" $grub_modules - StopIfError "Error occurred during $gmkimage of BOOTX64.efi" } + diff --git a/usr/share/rear/output/ISO/Linux-i386/250_populate_efibootimg.sh b/usr/share/rear/output/ISO/Linux-i386/250_populate_efibootimg.sh index fdf66039..e9325012 100644 --- a/usr/share/rear/output/ISO/Linux-i386/250_populate_efibootimg.sh +++ b/usr/share/rear/output/ISO/Linux-i386/250_populate_efibootimg.sh @@ -2,6 +2,9 @@ is_true $USING_UEFI_BOOTLOADER || return 0 # empty or 0 means NO UEFI +local boot_dir="/boot" +local efi_boot_tmp_dir="$TMP_DIR/mnt/EFI/BOOT" + mkdir $v -p $TMP_DIR/mnt/EFI/BOOT >&2 StopIfError "Could not create $TMP_DIR/mnt/EFI/BOOT" @@ -56,14 +59,8 @@ title Relax-and-Recover (no Secure Boot) EOF else -# create small embedded grub.cfg file for grub-mkimage -cat > $TMP_DIR/mnt/EFI/BOOT/embedded_grub.cfg < $TMP_DIR/mnt/EFI/BOOT/grub.cfg + # create a grub.cfg + create_grub2_cfg > $efi_boot_tmp_dir/grub.cfg fi # Create BOOTX86.efi but only if we are NOT secure booting. @@ -72,15 +69,15 @@ fi # See issue #1374 # build_bootx86_efi () can be safely used for other scenarios. if ! test -f "$SECURE_BOOT_BOOTLOADER" ; then - build_bootx86_efi + build_bootx86_efi $TMP_DIR/mnt/EFI/BOOT/BOOTX64.efi $efi_boot_tmp_dir/grub.cfg "$boot_dir" "$UEFI_BOOTLOADER" fi # We will be using grub-efi or grub2 (with efi capabilities) to boot from ISO. # Because usr/sbin/rear sets 'shopt -s nullglob' the 'echo -n' command # outputs nothing if nothing matches the bash globbing pattern '/boot/grub*' -local grubdir="$( echo -n /boot/grub* )" +local grubdir="$( echo -n ${boot_dir}/grub* )" # Use '/boot/grub' as fallback if nothing matches '/boot/grub*' -test -d "$grubdir" || grubdir='/boot/grub' +test -d "$grubdir" || grubdir="${boot_dir}/grub" if [ -d $(dirname ${UEFI_BOOTLOADER})/fonts ]; then cp $v $(dirname ${UEFI_BOOTLOADER})/fonts/* $TMP_DIR/mnt/EFI/BOOT/fonts/ >&2 diff --git a/usr/share/rear/output/default/940_grub2_rescue.sh b/usr/share/rear/output/default/940_grub2_rescue.sh index a94957de..fbbd7074 100644 --- a/usr/share/rear/output/default/940_grub2_rescue.sh +++ b/usr/share/rear/output/default/940_grub2_rescue.sh @@ -144,13 +144,18 @@ if is_true $USING_UEFI_BOOTLOADER ; then # probably a bug, as I was able to boot with value set to root=anything root_uuid=$(mount | grep -w 'on /' | awk '{print $1}' | xargs blkid -s UUID -o value) - # Grub2 modules that will be used for booting "Relax-and-Recover" - # It might be useful to make this variable global in the future - grub2_modules="linux echo all_video part_gpt ext2 btrfs search configfile" - # Create configuration file for "Relax-and-Recover" UEFI boot entry. # This file will not interact with existing Grub2 configuration in any way. - ( echo "menuentry '$grub_rear_menu_entry_name' --class os {" + ( echo "set btrfs_relative_path=y" + echo "insmod efi_gop" + echo "insmod efi_uga" + echo "insmod video_bochs" + echo "insmod video_cirrus" + echo "insmod all_video" + echo "" + echo "set gfxpayload=keep" + echo "" + echo "menuentry '$grub_rear_menu_entry_name' --class os {" echo " search --no-floppy --fs-uuid --set=root $grub_boot_uuid" echo " echo 'Loading kernel $boot_kernel_file ...'" echo " linux $grub_boot_dir/$boot_kernel_name root=UUID=$root_uuid $KERNEL_CMDLINE" @@ -159,19 +164,8 @@ if is_true $USING_UEFI_BOOTLOADER ; then echo "}" ) > $grub_config_dir/rear.cfg - # Tell rear.efi which configuration file to load - ( echo "search --no-floppy --fs-uuid --set=root $grub_boot_uuid" - echo "" - echo "set btrfs_relative_path=y" - echo "set prefix=(\$root)${grub_boot_dir}/grub${grub_num}" - echo "" - echo "configfile (\$root)${grub_boot_dir}/grub${grub_num}/rear.cfg" - ) > $grub_config_dir/rear_embed.cfg - # Create rear.efi at UEFI default boot directory location. - if ! grub${grub_num}-mkimage -o $boot_dir/efi/EFI/BOOT/rear.efi -O x86_64-efi -c $grub_config_dir/rear_embed.cfg -p /EFI/BOOT $grub2_modules ; then - Error "Could not create UEFI boot image" - fi + build_bootx86_efi $boot_dir/efi/EFI/BOOT/rear.efi $grub_config_dir/rear.cfg "$boot_dir" "$UEFI_BOOTLOADER" # If UEFI boot entry for "Relax-and-Recover" does not exist, create it. # This will also add "Relax-and-Recover" to boot order because if UEFI entry is not listed in BootOrder,