Blob Blame History Raw
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 <<EOF
-set prefix=(cd0)/EFI/BOOT
-configfile /EFI/BOOT/grub.cfg
-EOF
-
-# create a grub.cfg
-    create_grub2_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,