--- usr/share/rear/build/GNU/Linux/400_copy_modules.sh	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/build/GNU/Linux/400_copy_modules.sh	2021-01-27 10:05:09.332386569 +0100
@@ -11,136 +11,165 @@
 # Test the first MODULES array element because other scripts
 # in particular rescue/GNU/Linux/240_kernel_modules.sh
 # already appended other modules to the MODULES array:
 if test "no_modules" = "$MODULES" ; then
     LogPrint "Omit copying kernel modules (MODULES contains 'no_modules')"
     return
 fi
 
 # As general condition the /lib/modules/$KERNEL_VERSION directory must exist:
 test "$KERNEL_VERSION" || KERNEL_VERSION="$( uname -r )"
 if ! test -d "/lib/modules/$KERNEL_VERSION" ; then
     Error "Cannot copy kernel modules because /lib/modules/$KERNEL_VERSION does not exist"
 fi
 
 # Local functions that are 'unset' at the end of this script:
 function modinfo_filename () {
     local module_name=$1
     local module_filename=""
-    local alias_module_name=$(modprobe -n -R $module_name 2>/dev/null)
     # If the installed modprobe command supports resolving module aliases (-R), use that capability.
+    # 'modprobe -n -R' prints all module names matching an alias so we have its output in an array
+    # and use only its first element to consider only the first printed module name:
+    local alias_module_name=( $( modprobe -n -R $module_name 2>/dev/null ) )
     test $alias_module_name && module_name=$alias_module_name
     # Older modinfo (e.g. the one in SLES10) does not support '-k'
     # but that old modinfo returns a zero exit code when called as 'modinfo -k ...'
     # and shows a 'modinfo: invalid option -- k ...' message on stderr and nothing on stdout
-    # so that we need to check if we got a non-empty module filename:
-    module_filename=$( modinfo -k $KERNEL_VERSION -F filename $module_name )
+    # so that we need to check if we got a non-empty module filename.
+    # Older modinfo (in particular modinfo before kmod-27 since SLES15-SP3)
+    # outputs nothing on stdout for builtin kernel "modules" and exits with exit code 1 like
+    #   # modinfo -F filename unix
+    #   modinfo: ERROR: Module unix not found.
+    # Newer modinfo (in particular modinfo in kmod-27 since SLES15-SP3)
+    # outputs on stdout for builtin kernel "modules" and exits with zero exit code like
+    #   # modinfo -F filename unix
+    #   name:           unix
+    #   (builtin)
+    # For real kernel modules the modinfo stdout is one word that is the kernel module filename like
+    #   # modinfo -F filename sg
+    #   /lib/modules/5.3.18-43-default/kernel/drivers/scsi/sg.ko.xz
+    module_filename="$( modinfo -k $KERNEL_VERSION -F filename $module_name )"
     # If 'modinfo -k ...' stdout is empty we retry without '-k' regardless why stdout is empty
     # but then we do not discard stderr so that error messages appear in the log file.
     # In this case we must additionally ensure that KERNEL_VERSION matches 'uname -r'
     # otherwise a module file for a wrong kernel version would be found:
-    if ! test $module_filename ; then
+    if ! test "$module_filename" ; then
         test "$KERNEL_VERSION" = "$( uname -r )" || Error "modinfo_filename failed because KERNEL_VERSION does not match 'uname -r'"
-        module_filename=$( modinfo -F filename $module_name )
+        module_filename="$( modinfo -F filename $module_name )"
     fi
-    test $module_filename && echo $module_filename
+    # grep for '(builtin)' in the modinfo stdout to get the builtin kernel "module" case and otherwise
+    # 'readlink -e something' shows the filename when something is one or more files and exits with zero exit code
+    # 'readlink -e something' shows the symlink target when something is a symlink and exits with zero exit code
+    # 'readlink -e something' shows nothing when something is no file or a broken symlink and exits with exit code 1
+    # 'readlink -e something' shows nothing on stdout but an error on stderr when something is empty and exits with exit code 1
+    grep -q '(builtin)' <<<"$module_filename" && echo '' || readlink -e $module_filename
 }
 
 # Artificial 'for' clause that is run only once
 # to be able to 'continue' with the code after it
 # when the kernel modules have been copied into the rescue/recovery system
 # (the 'for' loop is run only once so that 'continue' is the same as 'break')
 # which avoids dowdy looking code with deeply nested 'if...else' conditions:
 for dummy in "once" ; do
 
     # The special user setting MODULES=( 'all_modules' ) enforces that
     # all files in the /lib/modules/$KERNEL_VERSION directory
     # get included in the rescue/recovery system.
     # Test all MODULES array members to make the 'all_modules' functionality work for
     # MODULES array contents like MODULES=( 'moduleX' 'all_modules' 'moduleY' ):
     if IsInArray "all_modules" "${MODULES[@]}" ; then
         LogPrint "Copying all kernel modules in /lib/modules/$KERNEL_VERSION (MODULES contains 'all_modules')"
         # The '--parents' is needed to get the '/lib/modules/' directory in the copy:
         if ! cp $verbose -t $ROOTFS_DIR -a --parents /lib/modules/$KERNEL_VERSION 1>&2 ; then
             Error "Failed to copy all kernel modules in /lib/modules/$KERNEL_VERSION"
         fi
         # After successful copying do the the code after the artificial 'for' clause:
         continue
     fi
 
     # The special user setting MODULES=( 'loaded_modules' ) enforces that
     # only those kernel modules that are currently loaded
     # get included in the rescue/recovery system.
     # Test all MODULES array members to make the 'loaded_modules' functionality work for
     # MODULES array contents like MODULES=( 'moduleX' 'loaded_modules' 'moduleY' ):
     if IsInArray "loaded_modules" "${MODULES[@]}" ; then
-        LogPrint "Copying only currently loaded kernel modules (MODULES contains 'loaded_modules')"
+        LogPrint "Copying only currently loaded kernel modules (MODULES contains 'loaded_modules') and those in MODULES_LOAD"
         # The rescue/recovery system cannot work when its kernel modules
         # do not match the kernel that gets included in the rescue/recovery system
         # so that "rear mkrescue/mkbackup" errors out to be on the safe side
         # cf. https://github.com/rear/rear/wiki/Coding-Style
         # and https://github.com/rear/rear/wiki/Developers-Guide
         currently_running_kernel_version="$( uname -r )"
         if ! test "$KERNEL_VERSION" = "$currently_running_kernel_version" ; then
             Error "KERNEL_VERSION='$KERNEL_VERSION' does not match currently running kernel version ('uname -r' shows '$currently_running_kernel_version')"
         fi
-        loaded_modules="$( lsmod | tail -n +2 | cut -d ' ' -f 1 )"
-        # It can happen that a module is loaded but 'modinfo -F filename' cannot show its filename
-        # when it is loaded under a module alias name but the above modinfo_filename function
-        # could not resolve aliases (when the modprobe command does not support -R):
-        loaded_modules_files="$( for loaded_module in $loaded_modules ; do modinfo_filename $loaded_module || Error "$loaded_module loaded but no module file?" ; done )"
-        # $loaded_modules_files cannot be empty because modinfo_filename fails when it cannot show a module filename:
+        # Kernel modules that should be loaded during recovery system startup must be always copied into the recovery system:
+        loaded_modules="${MODULES_LOAD[@]}"
+        # The leading blank before $(...) is mandatory (otherwise the last in MODULES_LOAD is concatenated with the first of lsmod):
+        loaded_modules+=" $( lsmod | tail -n +2 | cut -d ' ' -f 1 )"
+        # It can happen that a module is loaded or should be loaded but 'modinfo -F filename' cannot show its filename
+        # when it is loaded or should be loaded under a module alias name but the above modinfo_filename function
+        # could not resolve aliases (when the modprobe command does not support -R).
+        # The 'sort -u' removes duplicates only to avoid useless stderr warnings from the subsequent 'cp'
+        # like "cp: warning: source file '/lib/modules/.../foo.ko' specified more than once"
+        # regardless that nothing goes wrong when 'cp' gets duplicate source files
+        # cf. http://blog.schlomo.schapiro.org/2015/04/warning-is-waste-of-my-time.html
+        loaded_modules_files="$( for loaded_module in $loaded_modules ; do modinfo_filename $loaded_module || Error "$loaded_module loaded or to be loaded but no module file?" ; done | sort -u )"
+        # $loaded_modules_files could be empty as extreme case because modinfo_filename outputs nothing in the builtin kernel "module" case:
+        test "$loaded_modules_files" || continue
         if ! cp $verbose -t $ROOTFS_DIR -L --preserve=all --parents $loaded_modules_files 1>&2 ; then
             Error "Failed to copy '$loaded_modules_files'"
         fi
         # After successful copying do the the code after the artificial 'for' clause:
         continue
     fi
 
     # Finally the default case:
     LogPrint "Copying kernel modules"
-    for module in "${MODULES[@]}" ; do
+    # Kernel modules that should be loaded during recovery system startup must be always copied into the recovery system:
+    for module in "${MODULES_LOAD[@]}" "${MODULES[@]}" ; do
         # Strip trailing ".o" if there:
         module=${module#.o}
         # Strip trailing ".ko" if there:
         module=${module#.ko}
         # Continue with the next module if the current one does not exist:
         modinfo $module 1>/dev/null || continue
         # Resolve module dependencies:
         # Get the module file plus the module files of other needed modules.
         # This is currently only a "best effort" attempt because
         # in general 'modprobe --show-depends' is insufficient to get all needed modules
         # see https://github.com/rear/rear/issues/1355
         # The --ignore-install is helpful because it converts currently unsupported '^install' output lines
         # into supported '^insmod' output lines for the particular module but that is also insufficient
         # see also https://github.com/rear/rear/issues/1355
         # The 'sort -u' removes duplicates only to avoid useless stderr warnings from the subsequent 'cp'
         # like "cp: warning: source file '/lib/modules/.../foo.ko' specified more than once"
         # regardless that nothing goes wrong when 'cp' gets duplicate source files
         # cf. http://blog.schlomo.schapiro.org/2015/04/warning-is-waste-of-my-time.html
         module_files=$( modprobe --ignore-install --set-version $KERNEL_VERSION --show-depends $module | awk '/^insmod / { print $2 }' | sort -u )
         if ! test "$module_files" ; then
             # Fallback is the plain module file without other needed modules (cf. the MODULES=( 'loaded_modules' ) case above):
             # It can happen that 'modinfo -F filename' cannot show the module filename
             # when it is specified under a module alias name but the above modinfo_filename function
             # could not resolve aliases (when the modprobe command does not support -R):
             module_files="$( modinfo_filename $module || Error "$module exists but no module file?" )"
         fi
-        # $module_files cannot be empty because modinfo_filename fails when it cannot show a module filename:
+        # $module_files can be empty because modinfo_filename outputs nothing in the builtin kernel "module" case:
+	test "$module_files" || continue
         if ! cp $verbose -t $ROOTFS_DIR -L --preserve=all --parents $module_files 1>&2 ; then
             Error "Failed to copy '$module_files'"
         fi
     done
 
 # End of artificial 'for' clause:
 done
 
 # Remove those modules that are specified in the EXCLUDE_MODULES array:
 for exclude_module in "${EXCLUDE_MODULES[@]}" ; do
     # Continue with the next module if the current one does not exist:
     modinfo $exclude_module 1>/dev/null || continue
     # In this case it is ignored when a module exists but 'modinfo -F filename' cannot show its filename
     # because then it is assumed that also no module file had been copied above:
     exclude_module_file="$( modinfo_filename $exclude_module )"
     test -e "$ROOTFS_DIR$exclude_module_file" && rm $verbose $ROOTFS_DIR$exclude_module_file 1>&2
 done
 
--- usr/share/rear/finalize/Linux-ppc64le/620_install_grub2.sh	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/finalize/Linux-ppc64le/620_install_grub2.sh	2021-01-27 11:23:37.052386569 +0100
@@ -89,100 +89,130 @@
 # cf. https://github.com/rear/rear/issues/1828#issuecomment-398717889
 # and do not umount them when leaving this script because
 # it is better when also after "rear recover" things still
 # work in the "chroot TARGET_FS_ROOT" environment so that
 # the user could more easily adapt things after "rear recover":
 for mount_device in proc sys dev ; do
     umount $TARGET_FS_ROOT/$mount_device && sleep 1
     mount --bind /$mount_device $TARGET_FS_ROOT/$mount_device
 done
 
 # Generate GRUB configuration file anew to be on the safe side (this could be even mandatory in MIGRATION_MODE):
 if ! chroot $TARGET_FS_ROOT /bin/bash --login -c "$grub_name-mkconfig -o /boot/$grub_name/grub.cfg" ; then
     LogPrintError "Failed to generate boot/$grub_name/grub.cfg in $TARGET_FS_ROOT - trying to install GRUB2 nevertheless"
 fi
 
 # Do not update nvram when system is running in PowerNV mode (BareMetal).
 # grub2-install will fail if not run with the --no-nvram option on a PowerNV system,
 # see https://github.com/rear/rear/pull/1742
-grub2_install_option=""
+grub2_no_nvram_option=""
 if [[ $(awk '/platform/ {print $NF}' < /proc/cpuinfo) == PowerNV ]] ; then
-    grub2_install_option="--no-nvram"
+    grub2_no_nvram_option="--no-nvram"
+fi
+# Also do not update nvram when no character device node /dev/nvram exists.
+# On POWER architecture the nvram kernel driver could be also built as a kernel module
+# that gets loaded via etc/scripts/system-setup.d/41-load-special-modules.sh
+# but whether or not the nvram kernel driver will then create /dev/nvram
+# depends on whether or not the hardware platform supports nvram.
+# I <jsmeix@suse.de> asked on a SUSE internal mailing list
+# and got the following reply (excerpts):
+# ----------------------------------------------------------------
+# > I would like to know when /dev/nvram exists and when not.
+# > I assume /dev/nvram gets created as other device nodes
+# > by the kernel (probably together with udev).
+# > I would like to know under what conditions /dev/nvram
+# > gets created and when it is not created.
+# > It seems on PPC /dev/nvram usually exist but sometimes not.
+# In case of powerpc, it gets created by nvram driver
+# (nvram_module_init) whenever the powerpc platform driver
+# has ppc_md.nvram_size greater than zero in it's machine
+# description structure.
+# How exactly ppc_md.nvram_size gets gets populated by platform
+# code depends on the platform, e.g. on most modern systems
+# it gets populated from 'nvram' device tree node
+# (and only if such node has #bytes > 0).
+# ----------------------------------------------------------------
+# So /dev/nvram may not exist regardless that the nvram kernel driver is there
+# and then grub2-install must be called with the '--no-nvram' option
+# because otherwise installing the bootloader fails
+# cf. https://github.com/rear/rear/issues/2554
+if ! test -c /dev/nvram ; then
+    grub2_no_nvram_option="--no-nvram"
 fi
 
 # When GRUB2_INSTALL_DEVICES is specified by the user
 # install GRUB2 only there and nowhere else:
 if test "$GRUB2_INSTALL_DEVICES" ; then
     grub2_install_failed="no"
     for grub2_install_device in $GRUB2_INSTALL_DEVICES ; do
         # In MIGRATION_MODE disk mappings (in var/lib/rear/layout/disk_mappings)
         # are applied when devices in GRUB2_INSTALL_DEVICES match
         # cf. https://github.com/rear/rear/issues/1437
         # MAPPING_FILE (var/lib/rear/layout/disk_mappings)
         # is set in layout/prepare/default/300_map_disks.sh
         # only if MIGRATION_MODE is true:
         if test -s "$MAPPING_FILE" ; then
             # Cf. the function apply_layout_mappings() in lib/layout-functions.sh
             while read source_disk target_disk junk ; do
                 # Skip lines that have wrong syntax:
                 test "$source_disk" -a "$target_disk" || continue
                 if test "$grub2_install_device" = "$source_disk" ; then
                     LogPrint "Installing GRUB2 on $target_disk ($source_disk in GRUB2_INSTALL_DEVICES is mapped to $target_disk in $MAPPING_FILE)"
                     grub2_install_device="$target_disk"
                     break
                 fi
             done < <( grep -v '^#' "$MAPPING_FILE" )
         else
             LogPrint "Installing GRUB2 on $grub2_install_device (specified in GRUB2_INSTALL_DEVICES)"
         fi
-        if ! chroot $TARGET_FS_ROOT /bin/bash --login -c "$grub_name-install $grub2_install_option $grub2_install_device" ; then
+        if ! chroot $TARGET_FS_ROOT /bin/bash --login -c "$grub_name-install $grub2_no_nvram_option $grub2_install_device" ; then
             LogPrintError "Failed to install GRUB2 on $grub2_install_device"
             grub2_install_failed="yes"
         fi
     done
     is_false $grub2_install_failed && NOBOOTLOADER=''
     # return even if it failed to install GRUB2 on one of the specified GRUB2_INSTALL_DEVICES
     # because then the user gets an explicit WARNING via finalize/default/890_finish_checks.sh
     is_true $NOBOOTLOADER && return 1 || return 0
 fi
 
 # If GRUB2_INSTALL_DEVICES is not specified try to automatically determine where to install GRUB2:
 if ! test -r "$LAYOUT_FILE" ; then
     LogPrintError "Cannot determine where to install GRUB2"
     return 1
 fi
 LogPrint "Determining where to install GRUB2 (no GRUB2_INSTALL_DEVICES specified)"
 
 # Find PPC PReP Boot partitions:
 part_list=$( awk -F ' ' '/^part / {if ($6 ~ /prep/) {print $7}}' $LAYOUT_FILE )
 if ! test "$part_list" ; then
     LogPrintError "Cannot install GRUB2 (unable to find a PPC PReP boot partition)"
     return 1
 fi
 
 # We do not know what the first boot device will be, so we cannot be sure
 # GRUB2 is installed on the correct boot device.
 # If software RAID1 is used, several boot devices will be found and
 # then GRUB2 needs to be installed on each of them.
 # This is the reason why we make all possible boot disks bootable here:
 for part in $part_list ; do
     # Install GRUB2 on the PPC PReP boot partition if one was found:
     if test "$part" ; then
         LogPrint "Found PPC PReP boot partition $part - installing GRUB2 there"
         # Erase the first 512 bytes of the PPC PReP boot partition:
         dd if=/dev/zero of=$part
-        if chroot $TARGET_FS_ROOT /bin/bash --login -c "$grub_name-install $grub2_install_option $part" ; then
+        if chroot $TARGET_FS_ROOT /bin/bash --login -c "$grub_name-install $grub2_no_nvram_option $part" ; then
             # In contrast to the above behaviour when GRUB2_INSTALL_DEVICES is specified
             # consider it here as a successful bootloader installation when GRUB2
             # got installed on at least one PPC PReP boot partition:
             NOBOOTLOADER=''
             # Continue with the next PPC PReP boot partition:
             continue
         fi
         LogPrintError "Failed to install GRUB2 on PPC PReP boot partition $part"
     fi
 done
 
 is_true $NOBOOTLOADER || return 0
 LogPrintError "Failed to install GRUB2 - you may have to manually install it"
 return 1
 
--- usr/share/rear/lib/layout-functions.sh	2018-09-26 14:05:57.000000000 +0200
+++ usr/share/rear/lib/layout-functions.sh	2021-01-20 14:51:05.010510411 +0100
@@ -630,37 +630,52 @@
         label=$( echo "$LINE" | grep "^LABEL=" | cut -d= -f2 | sed -e 's/"//g' | sed -e 's/ /\\\\b/g')  # replace all " " with "\\b"
         [[ ! -z "$label" ]] && break
     done
     echo "$label"
 }
 
 # Returns 1 if the device is an LVM physical volume
 # Returns 0 otherwise or if the device doesn't exists
 is_disk_a_pv() {
     disk=$1
     if grep -q "^lvmdev .* ${disk} " $LAYOUT_FILE ; then
         return 0
     else
         return 1
     fi
 }
 
 function is_multipath_path {
-    [ "$1" ] && type multipath &>/dev/null && multipath -c /dev/$1 &>/dev/null
+    # Return 'false' if there is no device as argument:
+    test "$1" || return 1
+    # Return 'false' if there is no multipath command:
+    type multipath &>/dev/null || return 1
+    # Return 'false' if multipath is not used,
+    # see https://github.com/rear/rear/issues/2298
+    # Because "multipath -l" always returns zero exit code
+    # we check if it has real output via grep -q '[[:alnum:]]'
+    # so that no "multipath -l" output could clutter the log
+    # (the "multipath -l" output is irrelevant here)
+    # in contrast to e.g. test "$( multipath -l )"
+    # that would falsely succeed with blank output and the
+    # output would appear in the log in 'set -x' debugscript mode:
+    multipath -l | grep -q '[[:alnum:]]' || return 1
+    # Check if a block device should be a path in a multipath device:
+    multipath -c /dev/$1 &>/dev/null
 }
 
 # retry_command () is binded with REAR_SLEEP_DELAY and REAR_MAX_RETRIES.
 # This function will do maximum of REAR_MAX_RETRIES command execution
 # and will sleep REAR_SLEEP_DELAY after each unsuccessful command execution.
 # It outputs command stdout if succeeded or returns 1 on failure.
 retry_command ()
 {
     local retry=0
 
     until command_stdout=$(eval "$@"); do
         sleep $REAR_SLEEP_DELAY
 
         let retry++
 
         if (( retry >= REAR_MAX_RETRIES )) ; then
             Log "retry_command '$*' failed"
             return 1
--- usr/share/rear/skel/default/etc/scripts/system-setup.d/41-load-special-modules.sh	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/skel/default/etc/scripts/system-setup.d/41-load-special-modules.sh	2021-01-27 11:24:13.228386569 +0100
@@ -1,6 +1,26 @@
-# some things are special
 
-# XEN PV does not autoload some modules
-if [ -d /proc/xen ] ; then
-	modprobe xenblk
+# Special cases of kernel module loading.
+
+# XEN PV does not autoload some modules:
+test -d /proc/xen && modprobe xenblk
+
+# On POWER architecture the nvram kernel driver may be no longer built into the kernel
+# but nowadays it could be also built as a kernel module that needs to be loaded
+# cf. https://github.com/rear/rear/issues/2554#issuecomment-764720180
+# because normally grub2-install gets called without the '--no-nvram' option
+# e.g. see finalize/Linux-ppc64le/620_install_grub2.sh
+# which is how grub2-install should be called when the hardware supports nvram.
+# Nothing to do when the character device node /dev/nvram exists
+# because then the nvram kernel driver is already there:
+if ! test -c /dev/nvram ; then
+    # Nothing can be done when there is no nvram kernel module.
+    # Suppress the possible 'modprobe -n nvram' error message like
+    # "modprobe: FATAL: Module nvram not found in directory /lib/modules/..."
+    # to avoid a possible "FATAL" false alarm message that would appear
+    # on the user's terminal during recovery system startup
+    # cf. https://github.com/rear/rear/pull/2537#issuecomment-741825046
+    # but when there is a nvram kernel module show possible 'modprobe nvram'
+    # (error) messages on the user's terminal during recovery system startup:
+    modprobe -n nvram 2>/dev/null && modprobe nvram
 fi
+
--- usr/share/rear/conf/GNU/Linux.conf.orig	2021-02-01 10:47:36.773795306 +0100
+++ usr/share/rear/conf/GNU/Linux.conf	2021-02-01 10:51:53.517795306 +0100
@@ -228,8 +228,10 @@
 /usr/lib*/libnssdbm3.so*
 )
 
+# nvram could be a module on POWER architecture, cf. https://github.com/rear/rear/issues/2554#issuecomment-764720180
 MODULES=(
 ${MODULES[@]:-}
+nvram
 vfat
 nls_iso8859_1
 nls_utf8
--- usr/share/rear/output/ISO/Linux-i386/810_prepare_multiple_iso.sh.orig	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/output/ISO/Linux-i386/810_prepare_multiple_iso.sh	2021-02-01 11:23:30.629795306 +0100
@@ -66,6 +66,9 @@
     mkdir -p $TEMP_BACKUP_DIR
     mv $BACKUP_NAME $TEMP_BACKUP_DIR
     pushd $TEMP_ISO_DIR 1>/dev/null
+    # Error out when files greater or equal ISO_FILE_SIZE_LIMIT should be included in the ISO (cf. default.conf).
+    # Consider all regular files and follow symbolic links to also get regular files where symlinks point to:
+    assert_ISO_FILE_SIZE_LIMIT $( find -L . -type f )
     if ! $ISO_MKISOFS_BIN $v -o "$ISO_OUTPUT_PATH" -R -J -volid "${ISO_VOLID}_$iso_number" -v -iso-level 3 . 1>/dev/null ; then
         Error "Failed to create ISO image $ISO_NAME (with $ISO_MKISOFS_BIN)"
     fi
--- usr/share/rear/output/ISO/Linux-i386/820_create_iso_image.sh.orig	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/output/ISO/Linux-i386/820_create_iso_image.sh	2021-02-01 11:24:55.037795306 +0100
@@ -16,6 +16,11 @@
 fi
 
 pushd $TMP_DIR/isofs >/dev/null
+
+# Error out when files greater or equal ISO_FILE_SIZE_LIMIT should be included in the ISO (cf. default.conf).
+# Consider all regular files and follow symbolic links to also get regular files where symlinks point to:
+assert_ISO_FILE_SIZE_LIMIT $( find -L . -type f )
+
 # ebiso uses different command line options and parameters:
 if test "ebiso" = $( basename $ISO_MKISOFS_BIN ) ; then
     # ebiso currently works only with UEFI:
--- usr/share/rear/output/ISO/Linux-ia64/800_create_isofs.sh.orig	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/output/ISO/Linux-ia64/800_create_isofs.sh	2021-02-01 11:29:04.565795306 +0100
@@ -24,6 +24,10 @@
 # Careful in case of 'return' after 'pushd' (must call the matching 'popd' before 'return'):
 pushd $TMP_DIR/isofs >&2 # so that relative paths will work
 
+# Error out when files greater or equal ISO_FILE_SIZE_LIMIT should be included in the ISO (cf. default.conf).
+# Consider all regular files and follow symbolic links to also get regular files where symlinks point to:
+assert_ISO_FILE_SIZE_LIMIT $( find -L . -type f )
+
 $ISO_MKISOFS_BIN $v -o "$ISO_DIR/$ISO_PREFIX.iso" -b boot/boot.img -c boot/boot.catalog \
 	-no-emul-boot -R -T -J -volid "$ISO_VOLID" -v . >/dev/null
 StopIfError "Could not create ISO image"
--- usr/share/rear/output/ISO/Linux-ppc64le/820_create_iso_image.sh.orig	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/output/ISO/Linux-ppc64le/820_create_iso_image.sh	2021-02-01 11:37:06.337795306 +0100
@@ -17,6 +17,10 @@
     chrp_boot_option="-chrp-boot"
 fi
 
+# Error out when files greater or equal ISO_FILE_SIZE_LIMIT should be included in the ISO (cf. default.conf).
+# Consider all regular files and follow symbolic links to also get regular files where symlinks point to:
+assert_ISO_FILE_SIZE_LIMIT "${ISO_FILES[@]}"
+
 $ISO_MKISOFS_BIN $v -o "$ISO_DIR/$ISO_PREFIX.iso" -U $chrp_boot_option -R -J -volid "$ISO_VOLID" -v -graft-points "${ISO_FILES[@]}" >&2
 
 StopIfError "Could not create ISO image (with $ISO_MKISOFS_BIN)"
--- usr/share/rear/conf/default.conf.orig	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/conf/default.conf	2021-02-01 11:20:42.677795306 +0100
@@ -573,7 +573,38 @@
 # Accordingly when ISO_MAX_SIZE is set the mkrescue workflow is forbidden
 # to be on the safe side to not possibly destroy an existing backup.
 ISO_MAX_SIZE=
-
+#
+# Error out when files greater or equal ISO_FILE_SIZE_LIMIT should be included in the ISO.
+# There is a limit of the ISO 9660 file system that is 2GiB or 4GiB according to
+# https://en.wikipedia.org/wiki/ISO_9660#The_2/4_GiB_file_size_limit
+# Usually 'mkisofs' is called with '-iso-level 3'
+# cf. usr/share/rear/prep/ISO/GNU/Linux/320_verify_mkisofs.sh
+# but there are cases where ISO 9660 level 1 or 2 is used that has a 2GiB file size limit.
+# For example when 'ebiso' is used there is a 2GiB file size limit
+# cf. https://github.com/gozora/ebiso/issues/12
+# but also other tools that are specified by ISO_MKISOFS_BIN could have that limit.
+# Accordingly to be by default on the safe side we use by default a 2GiB limit
+# cf. https://github.com/rear/rear/pull/2525
+# Under normal circumstances files greater or equal 2GiB should not appear in the ISO.
+# An exception is when the backup is included in the ISO with BACKUP_URL=iso://
+# where the backup archive file (e.g. backup.tar.gz) could be greater or equal 2GiB.
+# The user might adapt ISO_FILE_SIZE_LIMIT provided he verified that "rear recover"
+# actually works in his particular environment even when there are files in his ISO
+# (in particular backup.tar.gz) that are actually greater than the default 2GiB limit.
+# When there is a 2GiB file size limit a backup.tar.gz that is greater than 2GiB
+# will get corrupted in the ISO so backup restore via "rear recover" would fail
+# which is a dead end because the backup in the ISO got corrupted which is a severe error.
+# Also the ReaR recovery system initrd could become greater or equal 2GiB
+# (e.g. because of accidentally too much in COPY_AS_IS) which is likely an error
+# that could let booting or running the recovery system fail because
+# a recovery system in a 2GiB or bigger compressed initrd will need
+# more memory space when uncompressed and running in the ramdisk.
+# By default we error out when files greater or equal ISO_FILE_SIZE_LIMIT should be
+# included in the ISO but if really needed this ISO_FILE_SIZE_LIMIT test
+# can be skipped with ISO_FILE_SIZE_LIMIT=0 in etc/rear/local.conf
+# (2 GiB =  2 * 1024 * 1024 * 1024 bytes = 2147483648 bytes):
+ISO_FILE_SIZE_LIMIT=2147483648
+#
 # How to find mkisofs:
 # Guess the common names mkisofs or genisoimage
 # script in prep stage will verify this and complain if not found
--- usr/share/rear/lib/output-functions.sh.orig	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/lib/output-functions.sh	2021-02-01 11:06:18.633795306 +0100
@@ -25,3 +25,32 @@
 
 	done
 }
+
+# Error out when files greater or equal ISO_FILE_SIZE_LIMIT should be included in the ISO (cf. default.conf)
+# for files passed as arguments e.g: assert_ISO_FILE_SIZE_LIMIT file1 relative/path/file2 /absolute/path/file3 ...
+# Normally there should be no error exit inside a function but a function should return non-zero exit code
+# and leave it to its caller what to do depending on the callers environment. But this function is an exception.
+# It is meant like the "assert" macro in C that outputs a message on stderr and then exits with abort().
+# Furthermore it is less duplicated code to implement the error exit inside this function
+# than to let this function return non-zero exit code and implement the error exit in each caller
+# when the meaning of this function is to always exit for files greater or equal ISO_FILE_SIZE_LIMIT
+# (for the reasoning why "always exit" for such files see default.conf).
+# It errors out for the first file that is greater or equal ISO_FILE_SIZE_LIMIT and shows only this one to the user
+# so if there are also other files greater or equal ISO_FILE_SIZE_LIMIT they are not shown. At least for now
+# this should be sufficient because more than one file greater or equal ISO_FILE_SIZE_LIMIT is not expected
+# and the "assert" meaning is that this error exit is there only as safeguard for exceptional cases.
+function assert_ISO_FILE_SIZE_LIMIT () {
+    # Skip when there is no usable ISO_FILE_SIZE_LIMIT set (in particular for ISO_FILE_SIZE_LIMIT=0):
+    is_positive_integer $ISO_FILE_SIZE_LIMIT || return 0
+    local file_for_iso file_for_iso_size
+    for file_for_iso in $@ ; do
+        file_for_iso_size=$( stat -L -c '%s' $file_for_iso )
+        # Continue "bona fide" with testing the next one if size could not be determined (assume the current one is OK):
+        is_positive_integer $file_for_iso_size || continue
+        # Continue testing the next one when this one is below the file size limit:
+        test $file_for_iso_size -lt $ISO_FILE_SIZE_LIMIT && continue
+        # Show only basename to avoid the meaningless ReaR-internal path where files for the ISO are (temporarily) located:
+        Error "File for ISO $( basename $file_for_iso ) size $file_for_iso_size greater or equal ISO_FILE_SIZE_LIMIT=$ISO_FILE_SIZE_LIMIT"
+    done
+}
+
--- usr/share/rear/prep/ISO/GNU/Linux/320_verify_mkisofs.sh.orig	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/prep/ISO/GNU/Linux/320_verify_mkisofs.sh	2021-02-01 11:58:44.209795306 +0100
@@ -1,8 +1,37 @@
-# verify that we have a working mkisofs
+
+# Verify that we have a working program to make ISO9660 filesystem.
 #
-# default for ISO_MKISOFS_BIN is to check for mkisofs and genisoimage in the path
+# In default.conf ISO_MKISOFS_BIN is to check what there is in the path with
+# xorrisofs used as the preferred method for generating the iso image
+# and mkisofs and genisoimage as second and third option
+# but for UEFI bootable systems 'ISO_MKISOFS_BIN=/usr/bin/ebiso' is used.
+test -x "$ISO_MKISOFS_BIN" || Error "Could not find program to make ISO9660 filesystem. Install 'mkisofs', 'genisoimage' or 'ebiso' or specify ISO_MKISOFS_BIN (currently '$ISO_MKISOFS_BIN')"
+DebugPrint "Using '$ISO_MKISOFS_BIN' to create ISO filesystem images"
+
+# Include 'udf' module which is required if backup archive is >= 4GiB and mkisofs/genisoimage is used:
+IsInArray "all_modules" "${MODULES[@]}" || MODULES+=( udf )
+# Enforce 2GiB ISO_FILE_SIZE_LIMIT when the MODULES array contains 'loaded_modules'
+# because in this case MODULES+=( udf ) has no effect (unless it is loaded which normally isn't)
+# except the user has specified to skip the ISO_FILE_SIZE_LIMIT test with ISO_FILE_SIZE_LIMIT=0
+# but keep what the user has specified if ISO_FILE_SIZE_LIMIT is specified less than 2GiB.
+# Do nothing when the MODULES array contains 'no_modules' because that is meant for experts usually
+# when they have all needed modules (they have to know what they need) compiled into their kernel
+# (in default.conf a 2GiB ISO_FILE_SIZE_LIMIT is set so by default things should behave safe):
+if IsInArray "loaded_modules" "${MODULES[@]}" ; then
+    if is_positive_integer $ISO_FILE_SIZE_LIMIT && test $ISO_FILE_SIZE_LIMIT -gt 2147483648 ; then
+        DebugPrint "Enforcing 2GiB ISO_FILE_SIZE_LIMIT (MODULES contains 'loaded_modules')"
+        ISO_FILE_SIZE_LIMIT=2147483648
+    fi
+fi
 
-[ -x "$ISO_MKISOFS_BIN" ]
-StopIfError "Could not find 'mkisofs' compatible program. Please install 'mkisofs', 'genisoimage' or 'ebiso' into your path or manually set ISO_MKISOFS_BIN [$ISO_MKISOFS_BIN]"
+# ebiso has a 2GiB file size limit cf. https://github.com/gozora/ebiso/issues/12
+# so an actual ISO_FILE_SIZE_LIMIT value must be set that is not greater than 2GiB:
+if test "ebiso" = "$( basename $ISO_MKISOFS_BIN )" ; then
+    # For ebiso the ISO_FILE_SIZE_LIMIT test must not be skipped with ISO_FILE_SIZE_LIMIT=0
+    # because it would be disastrous when e.g. a backup.tar.gz in the ISO becomes bigger than 2GiB
+    # that gets corrupted in the ISO so the backup is lost and restore via "rear recover" cannot work:
+    is_positive_integer $ISO_FILE_SIZE_LIMIT || Error "ebiso has a 2GiB file size limit but ISO_FILE_SIZE_LIMIT is not set accordingly"
+    # 2 GiB =  2 * 1024 * 1024 * 1024 bytes = 2147483648 bytes:
+    test $ISO_FILE_SIZE_LIMIT -le 2147483648 || Error "ebiso has a 2GiB file size limit but ISO_FILE_SIZE_LIMIT is greater than 2GiB"
+fi
 
-Log "Using '$ISO_MKISOFS_BIN' to create ISO images"
--- usr/share/rear/build/default/980_verify_rootfs.sh.orig	2018-08-10 12:36:00.000000000 +0200
+++ usr/share/rear/build/default/980_verify_rootfs.sh	2021-02-01 13:35:10.249795306 +0100
@@ -54,6 +54,17 @@
 # Actually test all binaries for 'not found' libraries.
 # Find all binaries and libraries also e.g. those that are copied via COPY_AS_IS into other paths:
 for binary in $( find $ROOTFS_DIR -type f -executable -printf '/%P\n' ); do
+    # Skip the ldd test for kernel modules because in general running ldd on kernel modules does not make sense
+    # and sometimes running ldd on kernel modules causes needless errors because sometimes that segfaults
+    # which results false alarm "ldd: exited with unknown exit code (139)" messages ( 139 - 128 = 11 = SIGSEGV )
+    # cf. https://github.com/rear/rear/issues/2177 which also shows that sometimes kernel modules could be
+    # not only in the usual directory /lib/modules/ but also e.g. in /usr/lib/modules/
+    # so we 'grep' for '/lib/modules/' anywhere in the full path of the binary.
+    # Skip the ldd test for firmware files where it also does not make sense.
+    # Skip the ldd test for ReaR files (mainly bash scripts) where it does not make sense
+    # (programs in the recovery system get all copied into /bin/ so it is /bin/rear)
+    # cf. https://github.com/rear/rear/issues/2519#issuecomment-731196820
+    egrep -q "/lib/modules/|/lib.*/firmware/|$SHARE_DIR|/bin/rear$" <<<"$binary" && continue
     # In order to handle relative paths, we 'cd' to the directory containing $binary before running ldd.
     # In particular third-party backup tools may have shared object dependencies with relative paths.
     # For an example see https://github.com/rear/rear/pull/1560#issuecomment-343504359 that reads (excerpt):
--- usr/share/rear/lib/layout-functions.sh	2018-09-26 14:05:57.000000000 +0200
+++ usr/share/rear/lib/layout-functions.sh	2020-12-10 13:32:16.884965400 +0100
@@ -474,62 +543,57 @@
 ### Translate a sysfs name or device name to the name preferred in
 ### Relax-and-Recover.
 ### The device does not necessarily exist.
 ###     cciss!c0d0 -> /dev/cciss/c0d0
 ###     /dev/dm-3 -> /dev/mapper/system-tmp
 ###     /dev/dm-4 -> /dev/mapper/oralun
 ###     /dev/dm-5 -> /dev/mapper/oralunp1
+###     /dev/sda -> /dev/sda
+###
+### Returns 0 on success, 1 if device is not existing
 get_device_name() {
     ### strip common prefixes
     local name=${1#/dev/}
     name=${name#/sys/block/}
 
     contains_visible_char "$name" || BugError "Empty string passed to get_device_name"
 
-    ### Translate dm-8 -> mapper/test
-    local device dev_number mapper_number
-    if [[ -d /sys/block/$name ]] ; then
+    if [[ "$name" =~ ^mapper/ ]]; then
+        echo "/dev/$name"
+        return 0
+    fi
+
+    if [[ -L "/dev/$name" ]] ; then
+        # Map vg/lv into dm-X, which will then be resolved later
+        name="$( basename $(readlink -f /dev/$name) )"
+    fi
+
+    if [[ "$name" =~ ^dm- ]] ; then
+        local device
         if [[ -r /sys/block/$name/dm/name ]] ; then
             ### recent kernels have a dm subfolder
-            echo "/dev/mapper/$( < /sys/block/$name/dm/name)";
-            return 0
+            device="$( < /sys/block/$name/dm/name )"
         else
-            ### loop over all block devices
-            dev_number=$( < /sys/block/$name/dev)
-            for device in /dev/mapper/* ; do
-                mapper_number=$(dmsetup info -c --noheadings -o major,minor ${device#/dev/mapper/} 2>/dev/null )
-                if [ "$dev_number" = "$mapper_number" ] ; then
-                    echo "$device"
-                    return 0
-                fi
-            done
+            local dev_number=$( < /sys/block/$name/dev)
+            if [[ ! -r "$TMP_DIR/dmsetup_info.txt" ]] ; then
+                dmsetup info --noheadings -c -o name,major,minor > "$TMP_DIR/dmsetup_info.txt"
+            fi
+            device="$( awk -F ':' "/$dev_number\$/ { print \$1 }" < "$TMP_DIR/dmsetup_info.txt" )"
+            [[ -n "$device" ]] || BugError "No device returned for major/minor $dev_number"
         fi
-    fi
-
-    ### Translate device name to mapper name. ex: vg/lv -> mapper/vg-lv
-    if [[ "$name" =~ ^mapper/ ]]; then
-        echo "/dev/$name"
+        echo "/dev/mapper/$device"
         return 0
     fi
-    if my_dm=`readlink /dev/$name`; then
-       for mapper_dev in /dev/mapper/*; do
-           if mapper_dm=`readlink $mapper_dev`; then
-              if [ "$my_dm" = "$mapper_dm" ]; then
-                 echo $mapper_dev
-                 return 0
-              fi
-           fi
-       done
-    fi
 
     ### handle cciss sysfs naming
     name=${name//!//}
 
     ### just return the possibly nonexisting name
     echo "/dev/$name"
+    [[ -r "/dev/$name" ]] && return 0
     return 1
 }
 
 # check $VAR_LIB/recovery/diskbyid_mappings file to see whether we find
 # a disk/by-id mapping to dm style (the by-id dev is not translated
 # properly by get_device_name function - dm dev are better)
 # 220_lvm_layout.sh uses get_device_mapping to translate lvmdev better
--- usr/share/rear/rescue/GNU/Linux/270_fc_transport_info.sh	2021-02-08 12:17:23.301678202 +0100
+++ usr/share/rear/rescue/GNU/Linux/270_fc_transport_info.sh	2021-02-08 12:16:36.333049709 +0100
@@ -1,5 +1,9 @@
 # collect output from production SAN disks
 
+# don't collect this anymore, this can be very slow
+# cf. https://github.com/rear/rear/pull/2034
+return 0
+
 find /sys/class/fc_transport -follow -maxdepth 6 \( -name model -o -name vendor -o -name rev -name state -o -name model_name -o -name size -o -name node_name \) 2>/dev/null| egrep -v 'driver|rport|power|drivers|devices' | xargs grep '.' > $VAR_DIR/recovery/fc_transport.info  >&2
 
 if [[ -s $VAR_DIR/recovery/fc_transport.info ]]; then
