From 6320df788730c2b541d11375aece64b204c8bc8b Mon Sep 17 00:00:00 2001 From: eabdullin Date: Thu, 28 Mar 2024 11:38:59 +0000 Subject: [PATCH] import CS rear-2.6-24.el9 --- SOURCES/rear-CVE-2024-23301.patch | 32 + SOURCES/rear-nbu-RHEL-17390-RHEL-17393.patch | 117 ++++ ...or-symlinks-in-COPY_AS_IS-RHEL-15108.patch | 21 + ...restore-hybrid-bootloader-RHEL-16864.patch | 569 ++++++++++++++++++ ...-save-lvm-poolmetadatasize-RHEL-6984.patch | 102 ++++ .../rear-skip-invalid-drives-RHEL-22863.patch | 60 ++ ...useless-xfs-mount-options-RHEL-10478.patch | 85 +++ SOURCES/rear-support-export-TMPDIR.patch | 63 ++ SPECS/rear.spec | 57 +- 9 files changed, 1105 insertions(+), 1 deletion(-) create mode 100644 SOURCES/rear-CVE-2024-23301.patch create mode 100644 SOURCES/rear-nbu-RHEL-17390-RHEL-17393.patch create mode 100644 SOURCES/rear-resolve-libraries-for-symlinks-in-COPY_AS_IS-RHEL-15108.patch create mode 100644 SOURCES/rear-restore-hybrid-bootloader-RHEL-16864.patch create mode 100644 SOURCES/rear-save-lvm-poolmetadatasize-RHEL-6984.patch create mode 100644 SOURCES/rear-skip-invalid-drives-RHEL-22863.patch create mode 100644 SOURCES/rear-skip-useless-xfs-mount-options-RHEL-10478.patch create mode 100644 SOURCES/rear-support-export-TMPDIR.patch diff --git a/SOURCES/rear-CVE-2024-23301.patch b/SOURCES/rear-CVE-2024-23301.patch new file mode 100644 index 0000000..1361f52 --- /dev/null +++ b/SOURCES/rear-CVE-2024-23301.patch @@ -0,0 +1,32 @@ +From 89b61793d80bc2cb2abe47a7d0549466fb087d16 Mon Sep 17 00:00:00 2001 +From: Johannes Meixner +Date: Fri, 12 Jan 2024 08:04:40 +0100 +Subject: [PATCH] Make initrd accessible only by root (#3123) + +In pack/GNU/Linux/900_create_initramfs.sh call +chmod 0600 "$TMP_DIR/$REAR_INITRD_FILENAME" +to let only 'root' access the ReaR initrd because +the ReaR recovery system in the initrd can contain secrets +(not by default but when certain things are explicitly +configured by the user like SSH keys without passphrase) +see https://github.com/rear/rear/issues/3122 +and https://bugzilla.opensuse.org/show_bug.cgi?id=1218728 +--- + usr/share/rear/pack/GNU/Linux/900_create_initramfs.sh | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/usr/share/rear/pack/GNU/Linux/900_create_initramfs.sh b/usr/share/rear/pack/GNU/Linux/900_create_initramfs.sh +index 1e0c11039..12be718ed 100644 +--- a/usr/share/rear/pack/GNU/Linux/900_create_initramfs.sh ++++ b/usr/share/rear/pack/GNU/Linux/900_create_initramfs.sh +@@ -125,4 +125,10 @@ case "$REAR_INITRD_COMPRESSION" in + fi + ;; + esac ++ ++# Only root should be allowed to access the initrd ++# because the ReaR recovery system can contain secrets ++# cf. https://github.com/rear/rear/issues/3122 ++test -s "$TMP_DIR/$REAR_INITRD_FILENAME" && chmod 0600 "$TMP_DIR/$REAR_INITRD_FILENAME" ++ + popd >/dev/null diff --git a/SOURCES/rear-nbu-RHEL-17390-RHEL-17393.patch b/SOURCES/rear-nbu-RHEL-17390-RHEL-17393.patch new file mode 100644 index 0000000..f482a3b --- /dev/null +++ b/SOURCES/rear-nbu-RHEL-17390-RHEL-17393.patch @@ -0,0 +1,117 @@ +diff --git a/usr/share/rear/conf/default.conf b/usr/share/rear/conf/default.conf +index 17a764cba..a944114b3 100644 +--- a/usr/share/rear/conf/default.conf ++++ b/usr/share/rear/conf/default.conf +@@ -1866,7 +1866,7 @@ OBDR_BLOCKSIZE=2048 + # BACKUP=NBU stuff (Symantec/Veritas NetBackup) + ## + # +-COPY_AS_IS_NBU=( /usr/openv/bin/vnetd /usr/openv/bin/vopied /usr/openv/lib /usr/openv/netbackup /usr/openv/var/auth/[mn]*.txt /usr/openv/var/vxss /usr/openv/var/webtruststore /usr/openv/resources/nbpxyhelper /opt/VRTSpbx /etc/vx/VxICS /etc/vx/vrtslog.conf /var/log/VRTSpbx ) ++COPY_AS_IS_NBU=( /usr/openv/bin/vnetd /usr/openv/bin/vopied /usr/openv/lib /usr/openv/netbackup /usr/openv/var /usr/openv/resources/nbpxyhelper /opt/VRTSpbx /etc/vx/VxICS /etc/vx/vrtslog.conf /var/log/VRTSpbx ) + COPY_AS_IS_EXCLUDE_NBU=( "/usr/openv/netbackup/logs/*" "/usr/openv/netbackup/bin/bpjava*" /usr/openv/netbackup/bin/xbp /usr/openv/netbackup/bin/private /usr/openv/lib/java "/usr/openv/lib/*-plugins" /usr/openv/lib/shared/vddk /usr/openv/netbackup/baremetal "/var/log/VRTSpbx/*" ) + # See https://github.com/rear/rear/issues/2105 why /usr/openv/netbackup/sec/at/lib/ is needed: + NBU_LD_LIBRARY_PATH="/usr/openv/lib:/usr/openv/netbackup/sec/at/lib/:/usr/openv/lib/boost" +diff --git a/usr/share/rear/finalize/NBU/default/990_copy_bplogrestorelog.sh b/usr/share/rear/finalize/NBU/default/990_copy_bplogrestorelog.sh +index 60d9a222c..e326db612 100644 +--- a/usr/share/rear/finalize/NBU/default/990_copy_bplogrestorelog.sh ++++ b/usr/share/rear/finalize/NBU/default/990_copy_bplogrestorelog.sh +@@ -1,5 +1,51 @@ + # 990_copy_bprestorelog.sh +-# copy the logfile to the recovered system, at least the part that has been written till now. ++# copy the logfiles to the recovered system, at least the part that has been written till now. + +-mkdir -p $TARGET_FS_ROOT/$ROOT_HOME_DIR +-cp -f $TMP_DIR/bplog.restore* $TARGET_FS_ROOT/$ROOT_HOME_DIR/ ++# $VAR_DIR/restore will be copied to $recovery_system_recover_log_dir in wrapup/default/990_copy_logfile.sh ++mkdir -p "$VAR_DIR/restore/netbackup" ++cp -pr /usr/openv/netbackup/logs/* "$VAR_DIR/restore/netbackup" ++ ++# take care of $VAR_DIR/restore/bplog.restore* files (that used to be in /root before) ++function symlink_bprestore_logs () ++{ ++ # adapted from wrapup/default/990_copy_logfile.sh ++ local final_logfile_name_full ++ local final_logfile_name ++ local log_file_symlink_target ++ local log_file_symlink ++ local recover_log_dir=$LOG_DIR/recover ++ local recovery_system_recover_log_dir=$TARGET_FS_ROOT/$recover_log_dir ++ # Create the directories with mode 0700 (rwx------) so that only root can access files and subdirectories therein ++ # because in particular logfiles could contain security relevant information. ++ ++ # To be backward compatible with where to the logfile was copied before ++ # have it as a symbolic link that points to where the logfile actually is: ++ # ( "roots" in recovery_system_roots_home_dir means root's but ' in a variable name is not so good ;-) ++ local recovery_system_roots_home_dir=$TARGET_FS_ROOT/$ROOT_HOME_DIR ++ test -d $recovery_system_roots_home_dir || mkdir $verbose -m 0700 $recovery_system_roots_home_dir ++ ++ # Remove existing and now outdated symlinks that would falsely point to the same target ++ # The symlink name bplog.restore-$( date -Iseconds ).log is for example bplog.restore-2019-12-17T09:40:36+01:00.log or rear-2006-08-14T02:34:56-06:00.log ++ # so a matching globbing pattern is bplog.restore-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]*.log ('*' for the UTC offset): ++ for log_file_symlink in $recovery_system_roots_home_dir/bplog.restore*-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]*.log ; do ++ # Skip if a file that matches the globbing pattern is not a symlink (it could be even a directory full of user's sacrocanct files): ++ test -L $log_file_symlink || continue ++ # Remove also outdated dangling symlinks where their target does not exist by using 'readlink -m': ++ test "$log_file_symlink_target" = "$( readlink -m $log_file_symlink )" || continue ++ rm $verbose $log_file_symlink ++ done ++ ++ # At the moment this function runs, $VAR_DIR/restore will have been already copied ++ # to $recovery_system_recover_log_dir in wrapup/default/990_copy_logfile.sh ++ # (exit tasks run in reverse order, so this task will run after the tasks defined in ++ # wrapup/default/990_copy_logfile.sh ) ++ for final_logfile_name_full in $recovery_system_recover_log_dir/restore/bplog.restore* ; do ++ final_logfile_name="$( basename "$final_logfile_name_full" )" ++ log_file_symlink_target="$recover_log_dir/restore/$final_logfile_name" ++ # Create symlink with current timestamp that points to where the logfile actually is: ++ log_file_symlink=$recovery_system_roots_home_dir/$( basename "$final_logfile_name" .log )-$( date -Iseconds ).log ++ ln $verbose -s $log_file_symlink_target $log_file_symlink || true ++ done ++} ++ ++AddExitTask "symlink_bprestore_logs" +diff --git a/usr/share/rear/restore/NBU/default/400_restore_with_nbu.sh b/usr/share/rear/restore/NBU/default/400_restore_with_nbu.sh +index 71f7359a1..4280cb021 100644 +--- a/usr/share/rear/restore/NBU/default/400_restore_with_nbu.sh ++++ b/usr/share/rear/restore/NBU/default/400_restore_with_nbu.sh +@@ -2,6 +2,23 @@ + # 400_restore_with_nbu.sh + # restore files with NBU + ++# Unique log file name: adapted from restore/NETFS/default/400_restore_backup.sh ++# and restore/TSM/default/400_restore_with_tsm.sh ++local backup_restore_log_dir="$VAR_DIR/restore" ++mkdir -p $backup_restore_log_dir ++local backup_restore_log_file="" ++local backup_restore_log_prefix="bplog.restore" ++local backup_restore_log_suffix="log" ++# E.g. when "rear -C 'general.conf /path/to/special.conf' recover" was called CONFIG_APPEND_FILES is "general.conf /path/to/special.conf" ++# so that in particular '/' characters must be replaced in the backup restore log file (by a colon) and then ++# the backup restore log file name will be like .../restore/bplog.restore.generalconf_:path:to:specialconf.1234.log ++# It does not work with $( tr -d -c '[:alnum:]/[:space:]' <<<"$CONFIG_APPEND_FILES" | tr -s '/[:space:]' ':_' ) ++# because the <<<"$CONFIG_APPEND_FILES" results a trailing newline that becomes a trailing '_' character so that ++# echo -n $CONFIG_APPEND_FILES (without double quotes) is used to avoid leading and trailing spaces and newlines: ++test "$CONFIG_APPEND_FILES" && backup_restore_log_prefix=$backup_restore_log_prefix.$( echo -n $CONFIG_APPEND_FILES | tr -d -c '[:alnum:]/[:space:]' | tr -s '/[:space:]' ':_' ) ++ ++backup_restore_log_file=$backup_restore_log_dir/$backup_restore_log_prefix.$MASTER_PID.$backup_restore_log_suffix ++ + LogPrint "NetBackup: restoring / into $TARGET_FS_ROOT" + + echo "change / to $TARGET_FS_ROOT" > $TMP_DIR/nbu_change_file +@@ -10,13 +27,13 @@ echo "change / to $TARGET_FS_ROOT" > $TMP_DIR/nbu_change_file + # $TMP_DIR/restore_fs_list was made by 300_create_nbu_restore_fs_list.sh + if [ ${#NBU_ENDTIME[@]} -gt 0 ] ; then + edate="${NBU_ENDTIME[@]}" +- bprestore_args="-B -H -L $TMP_DIR/bplog.restore -8 -R $TMP_DIR/nbu_change_file -t 0 -w 0 -e ${edate} -C ${NBU_CLIENT_SOURCE} -D ${NBU_CLIENT_NAME} -f $TMP_DIR/restore_fs_list" ++ bprestore_args="-B -H -L $backup_restore_log_file -8 -R $TMP_DIR/nbu_change_file -t 0 -w 0 -e ${edate} -C ${NBU_CLIENT_SOURCE} -D ${NBU_CLIENT_NAME} -f $TMP_DIR/restore_fs_list" + else +- bprestore_args="-B -H -L $TMP_DIR/bplog.restore -8 -R $TMP_DIR/nbu_change_file -t 0 -w 0 -C ${NBU_CLIENT_SOURCE} -D ${NBU_CLIENT_NAME} -f $TMP_DIR/restore_fs_list" ++ bprestore_args="-B -H -L $backup_restore_log_file -8 -R $TMP_DIR/nbu_change_file -t 0 -w 0 -C ${NBU_CLIENT_SOURCE} -D ${NBU_CLIENT_NAME} -f $TMP_DIR/restore_fs_list" + fi + + LogPrint "RUN: /usr/openv/netbackup/bin/bprestore $bprestore_args" +-LogPrint "Restore progress: see $TMP_DIR/bplog.restore" ++LogPrint "Restore progress: see $backup_restore_log_file" + LANG=C /usr/openv/netbackup/bin/bprestore $bprestore_args + rc=$? + if (( $rc > 1 )) ; then diff --git a/SOURCES/rear-resolve-libraries-for-symlinks-in-COPY_AS_IS-RHEL-15108.patch b/SOURCES/rear-resolve-libraries-for-symlinks-in-COPY_AS_IS-RHEL-15108.patch new file mode 100644 index 0000000..1e76b68 --- /dev/null +++ b/SOURCES/rear-resolve-libraries-for-symlinks-in-COPY_AS_IS-RHEL-15108.patch @@ -0,0 +1,21 @@ +diff --git a/usr/share/rear/build/GNU/Linux/100_copy_as_is.sh b/usr/share/rear/build/GNU/Linux/100_copy_as_is.sh +index 0e402b017..9e1810c9a 100644 +--- a/usr/share/rear/build/GNU/Linux/100_copy_as_is.sh ++++ b/usr/share/rear/build/GNU/Linux/100_copy_as_is.sh +@@ -117,10 +117,13 @@ local copy_as_is_file="" + # cf. https://github.com/rear/rear/pull/2378 + # It is crucial to append to /dev/$DISPENSABLE_OUTPUT_DEV (cf. 'Print' in lib/_input-output-functions.sh): + while read -r copy_as_is_file ; do +- # Skip non-regular files like directories, device files, and 'tar' error messages (e.g. in case of non-existent files, see above): ++ # Skip non-regular files like directories, device files, and 'tar' error messages (e.g. in case of non-existent files, see above) ++ # but do not skip symbolic links. Their targets will be copied later by build/default/490_fix_broken_links.sh. ++ # We thus need library dependencies for symlinked executables just like for normal executables ++ # and build/default/490_fix_broken_links.sh does not perform library dependency scan. ++ # See GitHub PR https://github.com/rear/rear/pull/3073 ++ # and issue https://github.com/rear/rear/issues/3064 for details. + test -f "$copy_as_is_file" || continue +- # Skip symbolic links (only care about symbolic link targets): +- test -L "$copy_as_is_file" && continue + # Remember actual regular files that are executable: + test -x "$copy_as_is_file" && copy_as_is_executables+=( "$copy_as_is_file" ) + done < <( sort -u $copy_as_is_filelist_file ) 2>>/dev/$DISPENSABLE_OUTPUT_DEV diff --git a/SOURCES/rear-restore-hybrid-bootloader-RHEL-16864.patch b/SOURCES/rear-restore-hybrid-bootloader-RHEL-16864.patch new file mode 100644 index 0000000..8a31d1d --- /dev/null +++ b/SOURCES/rear-restore-hybrid-bootloader-RHEL-16864.patch @@ -0,0 +1,569 @@ +diff --git a/usr/share/rear/finalize/Linux-i386/630_install_grub.sh b/usr/share/rear/finalize/Linux-i386/630_install_grub.sh +index f3d9a8204..a0e87e1db 100644 +--- a/usr/share/rear/finalize/Linux-i386/630_install_grub.sh ++++ b/usr/share/rear/finalize/Linux-i386/630_install_grub.sh +@@ -1,22 +1,18 @@ + # This script is an improvement over the default grub-install '(hd0)' + # +-# However the following issues still exist: ++# However the following issue still exists: + # + # * We don't know what the first disk will be, so we cannot be sure the MBR +-# is written to the correct disk(s). That's why we make all disks bootable. +-# +-# * There is no guarantee that GRUB was the boot loader used originally. +-# One possible attempt would be to save and restore the MBR for each disk, +-# but this does not guarantee a correct boot order, +-# or even a working boot loader config +-# (eg. GRUB stage2 might not be at the exact same location). ++# is written to the correct disk(s). That's why we make all suitable disks bootable. + + # Skip if another boot loader is already installed + # (then $NOBOOTLOADER is not a true value cf. finalize/default/010_prepare_checks.sh): + is_true $NOBOOTLOADER || return 0 + +-# For UEFI systems with grub legacy with should use efibootmgr instead: +-is_true $USING_UEFI_BOOTLOADER && return ++# For UEFI systems with grub legacy with should use efibootmgr instead, ++# but if BOOTLOADER is explicitly set to GRUB, we are on a hybrid (BIOS/UEFI) ++# boot system and we need to install GRUB to MBR as well. ++# Therefore, we don't test $USING_UEFI_BOOTLOADER. + + # If the BOOTLOADER variable (read by finalize/default/010_prepare_checks.sh) + # is not "GRUB" (which means GRUB Legacy) skip this script (which is only for GRUB Legacy) +@@ -25,31 +21,27 @@ is_true $USING_UEFI_BOOTLOADER && return + test "GRUB" = "$BOOTLOADER" || return 0 + + # If the BOOTLOADER variable is "GRUB" (which means GRUB Legacy) +-# do not unconditionally trust that because https://github.com/rear/rear/pull/589 +-# reads (excerpt): +-# Problems found: +-# The ..._install_grub.sh checked for GRUB2 which is not part +-# of the first 2048 bytes of a disk - only GRUB was present - +-# thus the check for grub-probe/grub2-probe +-# and https://github.com/rear/rear/commit/079de45b3ad8edcf0e3df54ded53fe955abded3b +-# reads (excerpt): +-# replace grub-install by grub-probe +-# as grub-install also exist in legacy grub +-# so that it seems there are cases where actually GRUB 2 is used +-# but wrongly detected as "GRUB" so that another test is needed +-# to detected if actually GRUB 2 is used and that test is to +-# check if grub-probe or grub2-probe is installed because +-# grub-probe or grub2-probe is only installed in case of GRUB 2 +-# and when GRUB 2 is installed we assume GRUB 2 is used as boot loader +-# so that then we skip this script (which is only for GRUB Legacy) +-# because finalize/Linux-i386/660_install_grub2.sh is for installing GRUB 2: +-if type -p grub-probe >&2 || type -p grub2-probe >&2 ; then +- LogPrint "Skip installing GRUB Legacy boot loader because GRUB 2 is installed (grub-probe or grub2-probe exist)." ++# we could in principle trust that and continue because ++# layout/save/default/445_guess_bootloader.sh (where the value has been set) ++# is now able to distinguish between GRUB Legacy and GRUB 2. ++# But, as this code used to support the value "GRUB" for GRUB 2, ++# the user can have BOOTLOADER=GRUB set explicitly in the configuration file ++# and then it overrides the autodetection in layout/save/default/445_guess_bootloader.sh . ++# The user expects this setting to work with GRUB 2, thus for backward compatibility ++# we need to take into accout the possibility that GRUB actually means GRUB 2. ++if is_grub2_installed ; then ++ LogPrint "Skip installing GRUB Legacy boot loader because GRUB 2 is installed." ++ # We have the ErrorIfDeprecated function, but it aborts ReaR by default, ++ # which is not a good thing to do during recovery. ++ # Therefore it better to log a warning and continue. ++ LogPrintError "WARNING: setting BOOTLOADER=GRUB for GRUB 2 is deprecated, set BOOTLOADER=GRUB2 if setting BOOTLOADER explicitly" + return + fi + + # The actual work: + LogPrint "Installing GRUB Legacy boot loader:" ++# See above for the reasoning why not to use ErrorIfDeprecated ++LogPrintError "WARNING: support for GRUB Legacy is deprecated" + + # Installing GRUB Legacy boot loader requires an executable "grub": + type -p grub >&2 || Error "Cannot install GRUB Legacy boot loader because there is no 'grub' program." +@@ -79,8 +71,10 @@ if [[ -r "$LAYOUT_FILE" && -r "$LAYOUT_DEPS" ]] ; then + + for disk in $disks ; do + # Installing grub on an LVM PV will wipe the metadata so we skip those +- # function is_disk_a_pv returns with 1 if disk is a PV +- is_disk_a_pv "$disk" || continue ++ # function is_disk_a_pv returns true if disk is a PV ++ is_disk_a_pv "$disk" && continue ++ # Is the disk suitable for GRUB installation at all? ++ is_disk_grub_candidate "$disk" || continue + # Use first boot partition by default + part=$( echo $bootparts | cut -d' ' -f1 ) + +diff --git a/usr/share/rear/finalize/Linux-i386/660_install_grub2.sh b/usr/share/rear/finalize/Linux-i386/660_install_grub2.sh +index 58163d622..f42b5bfbe 100644 +--- a/usr/share/rear/finalize/Linux-i386/660_install_grub2.sh ++++ b/usr/share/rear/finalize/Linux-i386/660_install_grub2.sh +@@ -38,6 +38,37 @@ + # so that after "rear recover" finished he can manually install the bootloader + # as appropriate for his particular system. + ++local grub_name ++local grub2_install_failed grub2_install_device ++local source_disk target_disk junk ++local grub2_installed_disks ++local part bootparts ++local disk disks bootdisk ++ ++function bios_grub_install () ++{ ++ local grub2_install_device="$1" ++ ++ if is_true $USING_UEFI_BOOTLOADER ; then ++ # If running under UEFI, we need to specify the target explicitly, otherwise grub-install thinks ++ # that we are installing the EFI bootloader. ++ if ! chroot $TARGET_FS_ROOT /bin/bash --login -c "$grub_name-install --target=i386-pc $grub2_install_device" ; then ++ LogPrintError "Failed to install GRUB2 for BIOS boot (target i386-pc) on $bootdisk" ++ # purely informational test that may help to explain the reason for the error ++ if ! test -d "$TARGET_FS_ROOT/boot/$grub_name/i386-pc" ; then ++ LogPrintError "GRUB2 module dir for BIOS boot (boot/$grub_name/i386-pc in $TARGET_FS_ROOT) does not exist, is GRUB2 for BIOS (target i386-pc) installed?" ++ fi ++ return 1 ++ fi ++ else ++ if ! chroot $TARGET_FS_ROOT /bin/bash --login -c "$grub_name-install $grub2_install_device" ; then ++ LogPrintError "Failed to install GRUB2 on $grub2_install_device" ++ return 1 ++ fi ++ fi ++ return 0 ++} ++ + # Skip if another bootloader was already installed: + # In this case NOBOOTLOADER is not true, + # cf. finalize/default/050_prepare_checks.sh +@@ -45,12 +76,16 @@ is_true $NOBOOTLOADER || return 0 + + # For UEFI systems with grub2 we should use efibootmgr instead, + # cf. finalize/Linux-i386/670_run_efibootmgr.sh +-is_true $USING_UEFI_BOOTLOADER && return ++# but if BOOTLOADER is explicitly set to GRUB2, we are on a hybrid (BIOS/UEFI) ++# boot system and we need to install GRUB to MBR as well ++if is_true $USING_UEFI_BOOTLOADER && [ "GRUB2" != "$BOOTLOADER" ] ; then ++ return 0 ++fi + + # Only for GRUB2 - GRUB Legacy will be handled by its own script. + # GRUB2 is detected by testing for grub-probe or grub2-probe which does not exist in GRUB Legacy. + # If neither grub-probe nor grub2-probe is there assume GRUB2 is not there: +-type -p grub-probe || type -p grub2-probe || return 0 ++is_grub2_installed || return 0 + + LogPrint "Installing GRUB2 boot loader..." + +@@ -94,7 +129,7 @@ if test "$GRUB2_INSTALL_DEVICES" ; then + 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_device" ; then ++ if ! bios_grub_install "$grub2_install_device" ; then + LogPrintError "Failed to install GRUB2 on $grub2_install_device" + grub2_install_failed="yes" + fi +@@ -138,8 +173,8 @@ fi + grub2_installed_disks=() + for disk in $disks ; do + # Installing GRUB2 on an LVM PV will wipe the metadata so we skip those: +- # function is_disk_a_pv returns with 1 if disk is a PV +- is_disk_a_pv "$disk" || continue ++ # function is_disk_a_pv returns true if disk is a PV ++ is_disk_a_pv "$disk" && continue + + # Use first boot partition by default: + part=$( echo $bootparts | cut -d' ' -f1 ) +@@ -158,6 +193,8 @@ for disk in $disks ; do + + # Install GRUB2 on the boot disk if one was found: + if test "$bootdisk" ; then ++ # Is the disk suitable for GRUB installation at all? ++ is_disk_grub_candidate "$bootdisk" || continue + # Continue with the next possible boot disk when GRUB2 was already installed on the current one. + # When there are more disks like /dev/sda and /dev/sdb it can happen that + # for /dev/sda bootdisk=/dev/sda and GRUB2 gets installed on /dev/sda and +@@ -165,7 +202,7 @@ for disk in $disks ; do + # so we avoid that GRUB2 gets needlessly installed two times on the same device: + IsInArray "$bootdisk" "${grub2_installed_disks[@]}" && continue + LogPrint "Found possible boot disk $bootdisk - installing GRUB2 there" +- if chroot $TARGET_FS_ROOT /bin/bash --login -c "$grub_name-install $bootdisk" ; then ++ if bios_grub_install "$bootdisk" ; then + grub2_installed_disks+=( "$bootdisk" ) + # In contrast to the above behaviour when GRUB2_INSTALL_DEVICES is specified + # consider it here as a successful bootloader installation when GRUB2 +@@ -174,11 +211,14 @@ for disk in $disks ; do + # Continue with the next possible boot disk: + continue + fi +- LogPrintError "Failed to install GRUB2 on possible boot disk $bootdisk" + fi + done + + is_true $NOBOOTLOADER || return 0 +-LogPrintError "Failed to install GRUB2 - you may have to manually install it" ++if is_true $USING_UEFI_BOOTLOADER ; then ++ LogPrintError "Failed to install GRUB2 for BIOS boot - you may have to manually install it to preserve the hybrid BIOS/UEFI boot support, otherwise only UEFI boot will work" ++else ++ LogPrintError "Failed to install GRUB2 - you may have to manually install it" ++fi + return 1 + +diff --git a/usr/share/rear/finalize/default/050_prepare_checks.sh b/usr/share/rear/finalize/default/050_prepare_checks.sh +index 1679c9a41..57b44bca4 100644 +--- a/usr/share/rear/finalize/default/050_prepare_checks.sh ++++ b/usr/share/rear/finalize/default/050_prepare_checks.sh +@@ -10,10 +10,18 @@ + NOBOOTLOADER=1 + + # Try to read the BOOTLOADER value if /var/lib/rear/recovery/bootloader is not empty. +-# Currently (June 2016) the used BOOTLOADER values (grep for '$BOOTLOADER') are: ++# Currently (February 2024) the used BOOTLOADER values (grep for '$BOOTLOADER') are: + # GRUB for GRUB Legacy + # GRUB2 for GRUB 2 + # ELILO for elilo ++# LILO for lilo ++# GRUB2-EFI for GRUB 2, EFI version ++# EFI for any EFI bootloader, dummy value ++# ARM for ARM devices, dummy value ++# ARM-ALLWINNER for Allwinner devices ++# ZIPL for zIPL, on IBM Z (s390x) ++# PPC for any bootloader in the PReP boot partition (can be LILO, YABOOT, GRUB2) ++ + local bootloader_file="$VAR_DIR/recovery/bootloader" + # The output is stored in an artificial bash array so that $BOOTLOADER is the first word: + test -s $bootloader_file && BOOTLOADER=( $( grep -v '^[[:space:]]*#' $bootloader_file ) ) +diff --git a/usr/share/rear/layout/save/default/445_guess_bootloader.sh b/usr/share/rear/layout/save/default/445_guess_bootloader.sh +index fd5267dcf..b9e636a02 100644 +--- a/usr/share/rear/layout/save/default/445_guess_bootloader.sh ++++ b/usr/share/rear/layout/save/default/445_guess_bootloader.sh +@@ -1,7 +1,15 @@ + + # Determine or guess the used bootloader if not specified by the user + # and save this information into /var/lib/rear/recovery/bootloader +-bootloader_file="$VAR_DIR/recovery/bootloader" ++local bootloader_file="$VAR_DIR/recovery/bootloader" ++ ++local sysconfig_bootloader ++local block_device ++local blockd ++local disk_device ++local bootloader_area_strings_file ++local block_size ++local known_bootloader + + # When BOOTLOADER is specified use that: + if test "$BOOTLOADER" ; then +@@ -57,39 +65,31 @@ for block_device in /sys/block/* ; do + # Continue guessing the used bootloader by inspecting the first bytes on the next disk: + continue + fi +- # 'Hah!IdontNeedEFI' is the ASCII representation of the official GUID number +- # for a GPT BIOS boot partition which is 21686148-6449-6E6F-744E-656564454649 +- # see https://en.wikipedia.org/wiki/BIOS_boot_partition (issue #1752). +- # Use single quotes for 'Hah!IdontNeedEFI' to be on the safe side +- # because with double quotes the ! would cause history expansion if that is enabled +- # (non-interactive shells do not perform history expansion by default but better safe than sorry): +- if grep -q 'Hah!IdontNeedEFI' $bootloader_area_strings_file ; then +- # Because 'Hah!IdontNeedEFI' contains the known bootloader 'EFI' +- # the default code below would falsely guess that 'EFI' is used +- # but actually another non-EFI bootloader is used here +- # cf. https://github.com/rear/rear/issues/1752#issue-303856221 +- # so that in the 'Hah!IdontNeedEFI' case only non-EFI bootloaders are tested. +- # IBM Z (s390) uses zipl boot loader for RHEL and Ubuntu +- # cf. https://github.com/rear/rear/issues/2137 +- for known_bootloader in GRUB2 GRUB ELILO LILO ZIPL ; do +- if grep -q -i "$known_bootloader" $bootloader_area_strings_file ; then +- LogPrint "Using guessed bootloader '$known_bootloader' (found in first bytes on $disk_device with GPT BIOS boot partition)" +- echo "$known_bootloader" >$bootloader_file +- return +- fi +- done +- # When in the 'Hah!IdontNeedEFI' case no known non-EFI bootloader is found +- # continue guessing the used bootloader by inspecting the first bytes on the next disk +- # because otherwise the default code below would falsely guess that 'EFI' is used +- # cf. https://github.com/rear/rear/pull/1754#issuecomment-383531597 +- continue +- fi + # Check the default cases of known bootloaders. + # IBM Z (s390) uses zipl boot loader for RHEL and Ubuntu + # cf. https://github.com/rear/rear/issues/2137 +- for known_bootloader in GRUB2-EFI EFI GRUB2 GRUB ELILO LILO ZIPL ; do ++ for known_bootloader in GRUB2 GRUB LILO ZIPL ; do + if grep -q -i "$known_bootloader" $bootloader_area_strings_file ; then ++ # If we find "GRUB" (which means GRUB Legacy) ++ # do not unconditionally trust that because https://github.com/rear/rear/pull/589 ++ # reads (excerpt): ++ # Problems found: ++ # The ..._install_grub.sh checked for GRUB2 which is not part ++ # of the first 2048 bytes of a disk - only GRUB was present - ++ # thus the check for grub-probe/grub2-probe ++ # and https://github.com/rear/rear/commit/079de45b3ad8edcf0e3df54ded53fe955abded3b ++ # reads (excerpt): ++ # replace grub-install by grub-probe ++ # as grub-install also exist in legacy grub ++ # so that if actually GRUB 2 is used, the string in the bootloader area ++ # is "GRUB" so that another test is needed to detect if actually GRUB 2 is used. ++ # When GRUB 2 is installed we assume GRUB 2 is used as boot loader. ++ if [ "$known_bootloader" = "GRUB" ] && is_grub2_installed ; then ++ known_bootloader=GRUB2 ++ LogPrint "GRUB found in first bytes on $disk_device and GRUB 2 is installed, using GRUB2 as a guessed bootloader for 'rear recover'" ++ else + LogPrint "Using guessed bootloader '$known_bootloader' (found in first bytes on $disk_device)" ++ fi + echo "$known_bootloader" >$bootloader_file + return + fi +@@ -103,6 +103,26 @@ for block_device in /sys/block/* ; do + Log "End of strings in the first bytes on $disk_device" + done + ++# No bootloader detected, but we are using UEFI - there is probably an EFI bootloader ++if is_true $USING_UEFI_BOOTLOADER ; then ++ if is_grub2_installed ; then ++ echo "GRUB2-EFI" >$bootloader_file ++ elif test -f /sbin/elilo ; then ++ echo "ELILO" >$bootloader_file ++ else ++ # There is an EFI bootloader, we don't know which one exactly. ++ # The value "EFI" is a bit redundant with USING_UEFI_BOOTLOADER=1, ++ # which already indicates that there is an EFI bootloader. We use it as a placeholder ++ # to not leave $bootloader_file empty. ++ # Note that it is legal to have USING_UEFI_BOOTLOADER=1 and e.g. known_bootloader=GRUB2 ++ # (i.e. a non=EFI bootloader). This will happen in BIOS/UEFI hybrid boot scenarios. ++ # known_bootloader=GRUB2 indicates that there is a BIOS bootloader and USING_UEFI_BOOTLOADER=1 ++ # indicates that there is also an EFI bootloader. Only the EFI one is being used at this ++ # time, but both will need to be restored. ++ echo "EFI" >$bootloader_file ++ fi ++ return 0 ++fi + + # Error out when no bootloader was specified or could be autodetected: + Error "Cannot autodetect what is used as bootloader, see default.conf about 'BOOTLOADER'" +diff --git a/usr/share/rear/lib/bootloader-functions.sh b/usr/share/rear/lib/bootloader-functions.sh +index 5402f1da0..7aa40a589 100644 +--- a/usr/share/rear/lib/bootloader-functions.sh ++++ b/usr/share/rear/lib/bootloader-functions.sh +@@ -491,6 +491,53 @@ function get_root_disk_UUID { + echo $(mount | grep ' on / ' | awk '{print $1}' | xargs blkid -s UUID -o value) + } + ++# Detect whether actually GRUB 2 is installed and that test is to ++# check if grub-probe or grub2-probe is installed because ++# grub-probe or grub2-probe is only installed in case of GRUB 2. ++# Needed because one can't tell the GRUB version by looking at the MBR ++# (both GRUB 2 and GRUB Legacy have the string "GRUB" in their MBR). ++function is_grub2_installed () { ++ if type -p grub-probe >&2 || type -p grub2-probe >&2 ; then ++ Log "GRUB 2 is installed (grub-probe or grub2-probe exist)." ++ return 0 ++ else ++ return 1 ++ fi ++} ++ ++# Determine whether a disk is worth detecting or installing GRUB on ++function is_disk_grub_candidate () { ++ local disk="$1" ++ local disk_partitions part ++ local label flags ++ ++ # ToDo : validate $disk (does it even exist? Isn't it write-protected?) ++ ++ # Installing grub on an LVM PV will wipe the metadata so we skip those ++ is_disk_a_pv "$disk" && return 1 ++ ++ label="$( get_disklabel_type "$disk" )" || return 1 ++ # We don't care about the SUSE-specific 'gpt_sync_mbr' partition scheme ++ # anymore: https://github.com/rear/rear/pull/3145#discussion_r1481388431 ++ if [ "$label" == gpt ] ; then ++ # GPT needs a special BIOS boot partition to store GRUB (BIOS version). ++ # Let's try to find it. It can be recognized as having the bios_grub flag. ++ disk_partitions=( $( get_child_components "$disk" "part" ) ) ++ for part in "${disk_partitions[@]}" ; do ++ flags=( $( get_partition_flags "$part" ) ) ++ IsInArray bios_grub "${flags[@]}" && return 0 # found! ++ done ++ # If a given GPT-partitioned disk does not contain a BIOS boot partition, ++ # GRUB for BIOS booting can not be installed into its MBR (grub-install errors out). ++ return 1 ++ else ++ # Other disklabel types don't need anything special to install GRUB. ++ # The test for the PReP boot partition (finalize/Linux-ppc64le/660_install_grub2.sh) ++ # is a bit similar, but operates on the partition itself, not on the uderlying disk. ++ return 0 ++ fi ++} ++ + # Create configuration grub + function create_grub2_cfg { + root_uuid=$(get_root_disk_UUID) +diff --git a/usr/share/rear/lib/checklayout-workflow.sh b/usr/share/rear/lib/checklayout-workflow.sh +index 94b70fc06..744ca0be1 100644 +--- a/usr/share/rear/lib/checklayout-workflow.sh ++++ b/usr/share/rear/lib/checklayout-workflow.sh +@@ -15,6 +15,10 @@ function WORKFLOW_checklayout () { + + SourceStage "layout/precompare" + ++ # layout code needs to know whether we are using UEFI (USING_UEFI_BOOTLOADER) ++ # as it also detects the bootloader in use ( layout/save/default/445_guess_bootloader.sh ) ++ Source $SHARE_DIR/prep/default/320_include_uefi_env.sh ++ + # In case of e.g. BACKUP_URL=file:///mybackup/ automatically exclude the matching component 'fs:/mybackup' + # otherwise 'rear checklayout' would always detect a changed layout with BACKUP_URL=file:///... + # because during 'rear mkrescue/mkbackup' such a component was automatically excluded this way +diff --git a/usr/share/rear/lib/layout-functions.sh b/usr/share/rear/lib/layout-functions.sh +index 4f5b8f6f8..f5fc7538e 100644 +--- a/usr/share/rear/lib/layout-functions.sh ++++ b/usr/share/rear/lib/layout-functions.sh +@@ -520,6 +520,33 @@ get_component_type() { + grep -E "^[^ ]+ $1 " $LAYOUT_TODO | cut -d " " -f 3 + } + ++# Get the disklabel (partition table) type of the disk $1 from the layout file ++# (NOT from the actual disk, so layout file must exist before calling this, ++# and it is useful during recovery even before the disk layout has been recreated) ++function get_disklabel_type () { ++ # from create_disk() in layout/prepare/GNU/Linux/100_include_partition_code.sh ++ local component disk size label junk ++ ++ disk='' ++ ++ read component disk size label junk < <(grep "^disk $1 " "$LAYOUT_FILE") ++ test $disk || return 1 ++ ++ echo $label ++} ++ ++# Get partition flags from layout (space-separated) of partition given as $1 ++function get_partition_flags () { ++ local part disk size pstart name flags partition junk ++ ++ while read part disk size pstart name flags partition junk; do ++ if [ "$partition" == "$1" ] ; then ++ echo "$flags" | tr ',' ' ' ++ return 0 ++ fi ++ done < <(grep "^part " $LAYOUT_FILE) ++} ++ + # Function returns 0 when v1 is greater or equal than v2 + version_newer() { + local v1list=( ${1//[-.]/ } ) +@@ -794,17 +821,17 @@ blkid_label_of_device() { + echo "$label" + } + +-# Returns 1 if the device is an LVM physical volume +-# Returns 0 otherwise or if the device doesn't exists ++# Returns true if the device is an LVM physical volume ++# Returns false otherwise or if the device doesn't exists + is_disk_a_pv() { + disk=$1 + + # Using awk, select the 'lvmdev' line for which $disk is the device (column 3), + # cf. https://github.com/rear/rear/pull/1897 + # If exit == 1, then there is such line (so $disk is a PV), +- # otherwise exit with default value '0', which falls through to 'return 0' below. +- awk "\$1 == \"lvmdev\" && \$3 == \"${disk}\" { exit 1 }" "$LAYOUT_FILE" >/dev/null || return 1 +- return 0 ++ # otherwise exit with default value '0', which falls through to 'return 1' below. ++ awk "\$1 == \"lvmdev\" && \$3 == \"${disk}\" { exit 1 }" "$LAYOUT_FILE" >/dev/null || return 0 ++ return 1 + } + + function is_multipath_path { +diff --git a/usr/share/rear/lib/savelayout-workflow.sh b/usr/share/rear/lib/savelayout-workflow.sh +index 69cda58e9..27bb0a1ad 100644 +--- a/usr/share/rear/lib/savelayout-workflow.sh ++++ b/usr/share/rear/lib/savelayout-workflow.sh +@@ -10,6 +10,10 @@ if [[ "$VERBOSE" ]]; then + fi + WORKFLOWS+=( savelayout ) + WORKFLOW_savelayout () { ++ # layout code needs to know whether we are using UEFI (USING_UEFI_BOOTLOADER) ++ # as it also detects the bootloader in use ( layout/save/default/445_guess_bootloader.sh ) ++ Source $SHARE_DIR/prep/default/320_include_uefi_env.sh ++ + #DISKLAYOUT_FILE=$VAR_DIR/layout/disklayout.conf # defined in default.conf now (issue #678) + SourceStage "layout/save" + } +diff --git a/usr/share/rear/prep/GNU/Linux/300_include_grub_tools.sh b/usr/share/rear/prep/GNU/Linux/300_include_grub_tools.sh +index fcf0a5ff6..7d494281a 100644 +--- a/usr/share/rear/prep/GNU/Linux/300_include_grub_tools.sh ++++ b/usr/share/rear/prep/GNU/Linux/300_include_grub_tools.sh +@@ -1,8 +1,6 @@ + # + # GRUB2 has much more commands than the legacy grub command, including modules + +-test -d $VAR_DIR/recovery || mkdir -p $VAR_DIR/recovery +- + # cf. https://github.com/rear/rear/issues/2137 + # s390 zlinux does not use grub + # ********************************************************************************* +@@ -11,19 +9,8 @@ test -d $VAR_DIR/recovery || mkdir -p $VAR_DIR/recovery + # ********************************************************************************* + [ "$ARCH" == "Linux-s390" ] && return 0 + +-# 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* )" +-# Use '/boot/grub' as fallback if nothing matches '/boot/grub*' +-test -d "$grubdir" || grubdir='/boot/grub' +- +-# Check if we're using grub or grub2 before doing something. +-if has_binary grub-probe ; then +- grub-probe -t device $grubdir >$VAR_DIR/recovery/bootdisk 2>/dev/null || return 0 +-elif has_binary grub2-probe ; then +- grub2-probe -t device $grubdir >$VAR_DIR/recovery/bootdisk 2>/dev/null || return 0 +-fi +- ++# It is safe to assume that we are using GRUB and try to add these files to the rescue image ++# even if the assumption is wrong. + # Missing programs in the PROGS array are ignored: + PROGS+=( grub-bios-setup grub2-bios-setup + grub-install grub2-install +diff --git a/usr/share/rear/prep/Linux-s390/305_include_s390_tools.sh b/usr/share/rear/prep/Linux-s390/305_include_s390_tools.sh +index 084ea3104..4451f53d0 100644 +--- a/usr/share/rear/prep/Linux-s390/305_include_s390_tools.sh ++++ b/usr/share/rear/prep/Linux-s390/305_include_s390_tools.sh +@@ -1,10 +1,13 @@ + # + # s390 zIPL boot loader and grubby for configuring boot loader` + +-test -d $VAR_DIR/recovery || mkdir -p $VAR_DIR/recovery +- +-local bootdir="$( echo -n /boot/ )" +-test -d "$bootdir" || $bootdir='/boot/' ++# See the code in prep/GNU/Linux/300_include_grub_tools.sh ++# that sets grubdir via ++# local grubdir="$( echo -n /boot/grub* )" ++# where 'shopt -s nullglob' results nothing when nothing matches ++# but that is not needed here to set a fixed bootdir="/boot" ++# cf. https://github.com/rear/rear/issues/1040#issuecomment-1034890880 ++local bootdir="/boot/" + + # cf. https://github.com/rear/rear/issues/2137 + # findmnt is used the same as grub-probe to find the device where /boot is mounted +@@ -16,7 +19,7 @@ test -d "$bootdir" || $bootdir='/boot/' + # findmnt returns --> /dev/dasda3[/@/.snapshots/1/snapshot] + # use 300_include_grub_tools.sh instead of this file (grub2-probe) + if has_binary findmnt ; then +- findmnt -no SOURCE --target $bootdir >$VAR_DIR/recovery/bootdisk || return 0 ++ findmnt -no SOURCE --target $bootdir > /dev/null || return 0 + fi + + # Missing programs in the PROGS array are ignored: +diff --git a/usr/share/rear/prep/default/320_include_uefi_env.sh b/usr/share/rear/prep/default/320_include_uefi_env.sh +index ea86af4ca..93e59eae5 100644 +--- a/usr/share/rear/prep/default/320_include_uefi_env.sh ++++ b/usr/share/rear/prep/default/320_include_uefi_env.sh +@@ -87,7 +87,3 @@ fi + DebugPrint "Found EFI system partition ${esp_proc_mounts_line[0]} on ${esp_proc_mounts_line[1]} type ${esp_proc_mounts_line[2]}" + USING_UEFI_BOOTLOADER=1 + LogPrint "Using UEFI Boot Loader for Linux (USING_UEFI_BOOTLOADER=1)" +- +-# Remember the ESP device node in VAR_DIR/recovery/bootdisk: +-echo "${esp_proc_mounts_line[0]}" >$VAR_DIR/recovery/bootdisk +- diff --git a/SOURCES/rear-save-lvm-poolmetadatasize-RHEL-6984.patch b/SOURCES/rear-save-lvm-poolmetadatasize-RHEL-6984.patch new file mode 100644 index 0000000..8754e6d --- /dev/null +++ b/SOURCES/rear-save-lvm-poolmetadatasize-RHEL-6984.patch @@ -0,0 +1,102 @@ +From e7b84271536782fbc8673ef4573e155e1dfa850e Mon Sep 17 00:00:00 2001 +From: pcahyna +Date: Wed, 1 Nov 2023 12:53:33 +0100 +Subject: [PATCH] Merge pull request #3061 from + pcahyna/save-lvm-poolmetadatasize + +Save LVM pool metadata volume size in disk layout +--- + .../layout/save/GNU/Linux/220_lvm_layout.sh | 39 ++++++++++++------- + 1 file changed, 24 insertions(+), 15 deletions(-) + +diff --git a/usr/share/rear/layout/save/GNU/Linux/220_lvm_layout.sh b/usr/share/rear/layout/save/GNU/Linux/220_lvm_layout.sh +index f21845df9..42f0e4126 100644 +--- a/usr/share/rear/layout/save/GNU/Linux/220_lvm_layout.sh ++++ b/usr/share/rear/layout/save/GNU/Linux/220_lvm_layout.sh +@@ -18,7 +18,7 @@ local already_processed_lvs=() + local lv_layout_supported lvs_fields + local origin lv vg + local layout modules +-local thinpool chunksize stripes stripesize segmentsize ++local thinpool chunksize stripes stripesize segmentsize poolmetadatasize + local kval infokval + local lvs_exit_code + +@@ -130,7 +130,7 @@ local lvs_exit_code + echo "# Skipping PV $pdev that is not part of a valid VG (VG '$vgrp' empty or more than one word):" + contains_visible_char "$vgrp" || vgrp='' + echo "# lvmdev /dev/$vgrp $pdev $uuid $size" +- # Continue with the next line in the output of "lvm pvdisplay -c" ++ # Continue with the next line in the output of "lvm pvdisplay -C" + continue + fi + # With the above example the output is: +@@ -138,10 +138,10 @@ local lvs_exit_code + echo "lvmdev /dev/$vgrp $pdev $uuid $size" + + done +- # Check the exit code of "lvm pvdisplay -c" +- # in the "lvm pvdisplay -c | while read line ; do ... done" pipe: ++ # Check the exit code of "lvm pvdisplay -C" ++ # in the "lvm pvdisplay -C ... | while read line ; do ... done" pipe: + pvdisplay_exit_code=${PIPESTATUS[0]} +- test $pvdisplay_exit_code -eq 0 || Error "LVM command 'lvm pvdisplay -c' failed with exit code $pvdisplay_exit_code" ++ test $pvdisplay_exit_code -eq 0 || Error "LVM command 'lvm pvdisplay -C ... -o pv_name,vg_name,pv_size,pv_uuid' failed with exit code $pvdisplay_exit_code" + + # Get the volume group configuration: + # Format: lvmgrp [] [] +@@ -200,17 +200,17 @@ local lvs_exit_code + + # Specify the fields for the lvs command depending on whether or not the 'lv_layout' field is supported: + if is_true $lv_layout_supported ; then +- lvs_fields="origin,lv_name,vg_name,lv_size,lv_layout,pool_lv,chunk_size,stripes,stripe_size,seg_size" ++ lvs_fields="origin,lv_name,vg_name,lv_size,lv_layout,pool_lv,chunk_size,stripes,stripe_size,seg_size,lv_metadata_size" + else + # Use the 'modules' field as fallback replacement when the 'lv_layout' field is not supported: +- lvs_fields="origin,lv_name,vg_name,lv_size,modules,pool_lv,chunk_size,stripes,stripe_size,seg_size" ++ lvs_fields="origin,lv_name,vg_name,lv_size,modules,pool_lv,chunk_size,stripes,stripe_size,seg_size,lv_metadata_size" + fi + + # Example output of "lvs --separator=':' --noheadings --units b --nosuffix -o $lvs_fields" +- # with lvs_fields="origin,lv_name,vg_name,lv_size,lv_layout,pool_lv,chunk_size,stripes,stripe_size,seg_size" ++ # with lvs_fields="origin,lv_name,vg_name,lv_size,lv_layout,pool_lv,chunk_size,stripes,stripe_size,seg_size,lv_metadata_size" + # i.e. when the 'lv_layout' field is supported: +- # :root:system:19927138304:linear::0:1:0:19927138304 +- # :swap:system:1535115264:linear::0:1:0:1535115264 ++ # :root:system:19927138304:linear::0:1:0:19927138304: ++ # :swap:system:1535115264:linear::0:1:0:1535115264: + # There are two leading blanks in the output (at least on SLES12-SP4 with LVM 2.02.180). + lvm lvs --separator=':' --noheadings --units b --nosuffix -o $lvs_fields | while read line ; do + +@@ -261,14 +261,23 @@ local lvs_exit_code + # With the above example segmentsize=19927138304 and segmentsize=1535115264 + segmentsize="$( echo "$line" | awk -F ':' '{ print $10 }' )" + +- # TODO: Explain what that code is meant to do. +- # In particular a more explanatory variable name than 'kval' might help. +- # In 110_include_lvm_code.sh there is a comment what 'kval' means there +- # # kval: "key:value" pairs, separated by spaces +- # so probably 'kval' means the same here, but what is 'infokval'? ++ # With the above example poolmetadatasize="" ++ poolmetadatasize="$( echo "$line" | awk -F ':' '{ print $11 }' )" ++ ++ # kval is a string of space-separated key:value pairs. Key names are chosen to represent ++ # long options to lvcreate, and value will be the parameter for each long option. ++ # e.g. "chunksize:${chunksize}b" will eventually become a --chunksize=${chunksize}b ++ # argument to lvcreate. ++ # This way 110_include_lvm_code.sh which constructs the arguments to lvcreate ++ # can be kept generic and does not need to be updated every time an argument is added, ++ # as long as the argument can follow this generic scheme. ++ # infokval are key:value pairs that are not used when restoring the layout ++ # and are kept in disklayout.conf only as comments for information ++ # (because the setting is not easy or desirable to preserve). + kval="" + infokval="" + [ -z "$thinpool" ] || kval="${kval:+$kval }thinpool:$thinpool" ++ [ -z "$poolmetadatasize" ] || kval="${kval:+$kval }poolmetadatasize:${poolmetadatasize}b" + [ $chunksize -eq 0 ] || kval="${kval:+$kval }chunksize:${chunksize}b" + [ $stripesize -eq 0 ] || kval="${kval:+$kval }stripesize:${stripesize}b" + [ $segmentsize -eq $size ] || infokval="${infokval:+$infokval }segmentsize:${segmentsize}b" +-- +2.43.0 + diff --git a/SOURCES/rear-skip-invalid-drives-RHEL-22863.patch b/SOURCES/rear-skip-invalid-drives-RHEL-22863.patch new file mode 100644 index 0000000..557e03a --- /dev/null +++ b/SOURCES/rear-skip-invalid-drives-RHEL-22863.patch @@ -0,0 +1,60 @@ +diff --git a/usr/share/rear/layout/save/GNU/Linux/200_partition_layout.sh b/usr/share/rear/layout/save/GNU/Linux/200_partition_layout.sh +index da6ce64c4..ab14ec83f 100644 +--- a/usr/share/rear/layout/save/GNU/Linux/200_partition_layout.sh ++++ b/usr/share/rear/layout/save/GNU/Linux/200_partition_layout.sh +@@ -395,6 +395,10 @@ Log "Saving disk partitions." + elif [[ ! ($blockd = *rpmb || $blockd = *[0-9]boot[0-9]) ]]; then # Silently skip Replay Protected Memory Blocks and others + devname=$(get_device_name $disk) + devsize=$(get_disk_size ${disk#/sys/block/}) ++ if ! validation_error=$(is_disk_valid $devname) ; then ++ LogPrintError "Ignoring $blockd: $validation_error" ++ continue ++ fi + disktype=$(parted -s $devname print | grep -E "Partition Table|Disk label" | cut -d ":" -f "2" | tr -d " ") + if [ "$disktype" != "dasd" ]; then + echo "# Disk $devname" +diff --git a/usr/share/rear/lib/layout-functions.sh b/usr/share/rear/lib/layout-functions.sh +index f5fc7538e..90b16cb20 100644 +--- a/usr/share/rear/lib/layout-functions.sh ++++ b/usr/share/rear/lib/layout-functions.sh +@@ -834,6 +834,40 @@ is_disk_a_pv() { + return 1 + } + ++# Check whether disk is suitable for being added to layout ++# Can be used to skip obviously unsuitable/broken devices ++# (missing device node, zero size, device can't be opened). ++# Should not be used to skip potential mapping targets before layout restoration ++# - an invalid disk may become valid later, for example if it is a DASD that needs ++# low-level formatting (see 090_include_dasd_code.sh and 360_generate_dasd_format_code.sh), ++# unformatted DASDs show zero size. ++# Returns 0 if the device is ok ++# Returns nonzero code if it should be skipped, and a text describing the error ++# (without the device name) on stdout ++# usage example: ++# local err ++# if ! err=$(is_disk_valid /dev/sda); then ++ ++function is_disk_valid { ++ local disk="$1" ++ local size ++ ++ if ! test -b "$disk" ; then ++ echo "$disk is not a block device" ++ return 1 ++ fi ++ # capture stdout in a variable and redirect stderr to stdout - the error message ++ # will be our output ++ if { size=$(blockdev --getsize64 "$disk") ; } 2>&1 ; then ++ if ! test "$size" -gt 0 2>/dev/null ; then ++ echo "$disk has invalid size $size" ++ return 1 ++ fi ++ else ++ return 1 ++ fi ++} ++ + function is_multipath_path { + # Return 'false' if there is no device as argument: + test "$1" || return 1 diff --git a/SOURCES/rear-skip-useless-xfs-mount-options-RHEL-10478.patch b/SOURCES/rear-skip-useless-xfs-mount-options-RHEL-10478.patch new file mode 100644 index 0000000..2863131 --- /dev/null +++ b/SOURCES/rear-skip-useless-xfs-mount-options-RHEL-10478.patch @@ -0,0 +1,85 @@ +diff --git a/usr/share/rear/layout/prepare/GNU/Linux/133_include_mount_filesystem_code.sh b/usr/share/rear/layout/prepare/GNU/Linux/133_include_mount_filesystem_code.sh +index d57077791..87ab5d691 100644 +--- a/usr/share/rear/layout/prepare/GNU/Linux/133_include_mount_filesystem_code.sh ++++ b/usr/share/rear/layout/prepare/GNU/Linux/133_include_mount_filesystem_code.sh +@@ -29,6 +29,7 @@ mount_fs() { + case $name in + (options) + # Do not mount nodev, as chrooting later on would fail: ++ # FIXME: naive approach, will replace any "nodev" inside longer options/values + value=${value//nodev/dev} + # btrfs mount options like subvolid=259 or subvol=/@/.snapshots/1/snapshot + # from the old system cannot work here for recovery because btrfs subvolumes +@@ -147,6 +148,27 @@ mount_fs() { + echo "mount $mountopts,remount,user_xattr $device $TARGET_FS_ROOT$mountpoint" + ) >> "$LAYOUT_CODE" + ;; ++ (xfs) ++ # remove logbsize=... mount option. It is a purely performance/memory usage optimization option, ++ # which can lead to mount failures, because it must be an integer multiple of the log stripe unit ++ # and the log stripe unit can be different in the recreated filesystem from the original filesystem ++ # (for example when using MKFS_XFS_OPTIONS, or in some exotic situations involving an old filesystem, ++ # see GitHub issue #2777 ). ++ # If logbsize is not an integer multiple of the log stripe unit, mount fails with the warning ++ # "XFS (...): logbuf size must be greater than or equal to log stripe size" ++ # in the kernel log ++ # (and a confusing error message ++ # "mount: ...: wrong fs type, bad option, bad superblock on ..., missing codepage or helper program, or other error." ++ # from the mount command), causing the layout restoration in the recovery process to fail. ++ # Wrong sunit/swidth can cause mount to fail as well, with this in the kernel log: ++ # "kernel: XFS (...): alignment check failed: sunit/swidth vs. agsize", ++ # so remove the sunit=.../swidth=... mount options as well. ++ mountopts="$( remove_mount_options_values "$mountopts" logbsize sunit swidth )" ++ ( ++ echo "mkdir -p $TARGET_FS_ROOT$mountpoint" ++ echo "mount $mountopts $device $TARGET_FS_ROOT$mountpoint" ++ ) >> "$LAYOUT_CODE" ++ ;; + (*) + ( + echo "mkdir -p $TARGET_FS_ROOT$mountpoint" +diff --git a/usr/share/rear/lib/filesystems-functions.sh b/usr/share/rear/lib/filesystems-functions.sh +index afdd3f24c..658d757f4 100644 +--- a/usr/share/rear/lib/filesystems-functions.sh ++++ b/usr/share/rear/lib/filesystems-functions.sh +@@ -239,3 +239,40 @@ function xfs_parse + # Output xfs options for further use + echo "$xfs_opts" + } ++ ++ ++# $1 is a mount command argument (string containing comma-separated ++# mount options). The remaining arguments to the function ($2 ... ) ++# specify the mount options to remove from $1, together with a trailing "=" ++# and any value that follows each option. ++# For example, the call ++# "remove_mount_options_values nodev,uid=1,rw,gid=1 uid gid" ++# returns "nodev,rw". ++# There is no support for removing a mount option without a value and "=", ++# so "remove_mount_options_values nodev,uid=1,rw,gid=1 rw" will not work. ++# The function will return the modified string on stdout. ++ ++function remove_mount_options_values () { ++ local str="$1" ++ ++ shift ++ # First add a comma at the end so that it is easier to remove a mount option at the end: ++ str="${str/%/,}" ++ for i in "$@" ; do ++ # FIXME this also removes trailing strings at the end of longer words ++ # For example if one wants to remove any id=... option, ++ # the function will also replace "uid=1" by "u" by removing ++ # the trailing "id=1", which is not intended. ++ # Not easy to fix because $str can contain prefixes which are not ++ # mount options but arguments to the mount command itself ++ # (in particluar, "-o "). ++ # FIXME this simple approach would fail in case of mount options ++ # containing commas, for example the "context" option values, ++ # see mount(8) ++ ++ # the extglob shell option is enabled in rear ++ str="${str//$i=*([^,]),/}" ++ done ++ # Remove all commas at the end: ++ echo "${str/%,/}" ++} diff --git a/SOURCES/rear-support-export-TMPDIR.patch b/SOURCES/rear-support-export-TMPDIR.patch new file mode 100644 index 0000000..6571c0a --- /dev/null +++ b/SOURCES/rear-support-export-TMPDIR.patch @@ -0,0 +1,63 @@ +diff --git a/usr/sbin/rear b/usr/sbin/rear +index d2cb6c070..ea66f0a98 100755 +--- a/usr/sbin/rear ++++ b/usr/sbin/rear +@@ -376,6 +376,10 @@ fi + # and fd6 to get input from the user regardless where to STDIN is redirected: + source $SHARE_DIR/lib/_input-output-functions.sh + ++# Used to determine whether TMPDIR has been changed in user config. ++# Save the current value to detect changes. ++saved_tmpdir="${TMPDIR-}" ++ + # Keep old log file: + test -r "$RUNTIME_LOGFILE" && mv -f "$RUNTIME_LOGFILE" "$RUNTIME_LOGFILE".old 2>/dev/null + +@@ -446,6 +450,14 @@ for config in site local rescue ; do + test "$( tr -d -c '\r' < $CONFIG_DIR/$config.conf )" && Error "Carriage return character in $CONFIG_DIR/$config.conf (perhaps DOS or Mac format)" + Source "$CONFIG_DIR/$config.conf" || true + fi ++ if [ "$config" == local ] ; then ++ # changing TMPDIR in rescue.conf is expected for now, see ++ # rescue/GNU/Linux/600_unset_TMPDIR_in_rescue_conf.sh, ++ # so perform the check after reading local.conf but before rescue.conf ++ if [ "$saved_tmpdir" != "${TMPDIR-}" ] ; then ++ LogPrintError "Warning: Setting TMPDIR in a configuration file is deprecated. To specify a working area directory prefix, export TMPDIR before executing '$PROGRAM'" ++ fi ++ fi + done + # Finally source additional configuration files if specified on the command line: + if test "$CONFIG_APPEND_FILES" ; then +diff --git a/usr/share/rear/conf/default.conf b/usr/share/rear/conf/default.conf +index d5fe6dcc4..4e67e38c9 100644 +--- a/usr/share/rear/conf/default.conf ++++ b/usr/share/rear/conf/default.conf +@@ -50,12 +50,9 @@ + # which usually results /tmp/rear.XXXXXXXXXXXXXXX or $TMPDIR/rear.XXXXXXXXXXXXXXX + # the latter when the canonical Linux/Unix environment variable TMPDIR + # is set in the environment where /usr/sbin/rear is called. +-# To have a specific working area directory prefix for Relax-and-Recover +-# specify in /etc/rear/local.conf something like +-# ++# To have a specific working area directory prefix for Relax-and-Recover call + # export TMPDIR="/prefix/for/rear/working/directory" +-# +-# where /prefix/for/rear/working/directory must already exist. ++# before calling 'rear' (/prefix/for/rear/working/directory must already exist). + # This is useful for example when there is not sufficient free space + # in /var/tmp or $TMPDIR for the ISO image or even the backup archive. + # TMPDIR cannot be set to a default value here unconditionally but only +diff --git a/usr/share/rear/rescue/GNU/Linux/600_unset_TMPDIR_in_rescue_conf.sh b/usr/share/rear/rescue/GNU/Linux/600_unset_TMPDIR_in_rescue_conf.sh +new file mode 100644 +index 000000000..84d0cabb2 +--- /dev/null ++++ b/usr/share/rear/rescue/GNU/Linux/600_unset_TMPDIR_in_rescue_conf.sh +@@ -0,0 +1,8 @@ ++cat - <> "$ROOTFS_DIR/etc/rear/rescue.conf" ++# TMPDIR variable may be defined in local.conf file as prefix dir for mktemp command ++# e.g. by defining TMPDIR=/var we would get our BUILD_DIR=/var/tmp/rear.XXXXXXXXXXXX ++# However, in rescue we want our BUILD_DIR=/tmp/rear.XXXXXXX as we are not sure that ++# the user defined TMPDIR would exist in our rescue image ++# by 'unset TMPDIR' we achieve above goal (as rescue.conf is read after local.conf)! ++unset TMPDIR ++EOF diff --git a/SPECS/rear.spec b/SPECS/rear.spec index 9855485..2b3794e 100644 --- a/SPECS/rear.spec +++ b/SPECS/rear.spec @@ -3,7 +3,7 @@ Name: rear Version: 2.6 -Release: 19%{?dist} +Release: 24%{?dist} Summary: Relax-and-Recover is a Linux disaster recovery and system migration tool URL: http://relax-and-recover.org/ License: GPLv3 @@ -51,6 +51,34 @@ Patch60: rear-luks-key-bz2228779.patch Patch61: rear-uefi-usb-secureboot-bz2196445.patch Patch62: rear-vg-command-not-found-bz2121476.patch Patch63: rear-remove-lvmdevices-bz2145014.patch +Patch64: rear-save-lvm-poolmetadatasize-RHEL-6984.patch +Patch65: rear-skip-useless-xfs-mount-options-RHEL-10478.patch + +# make initrd accessible only by root +# https://github.com/rear/rear/commit/89b61793d80bc2cb2abe47a7d0549466fb087d16 +Patch111: rear-CVE-2024-23301.patch + +# Support saving and restoring hybrid BIOS/UEFI bootloader setup and clean up bootloader detection +# https://github.com/rear/rear/pull/3145 +Patch113: rear-restore-hybrid-bootloader-RHEL-16864.patch + +# Resolve libs for executable links in COPY_AS_IS +# https://github.com/rear/rear/commit/9f859c13f5ba285cd1d5983c9b595975c21888d3 +Patch114: rear-resolve-libraries-for-symlinks-in-COPY_AS_IS-RHEL-15108.patch + +# Skip invalid disk drives (zero sized, no media) when saving layout +# https://github.com/rear/rear/commit/808b15a677191aac62faadd1bc71885484091316 +Patch115: rear-skip-invalid-drives-RHEL-22863.patch + +###################### +# downstream patches # +###################### + +# additional fixes for NBU support +Patch206: rear-nbu-RHEL-17390-RHEL-17393.patch + +# support "export TMPDIR" again, temporarily, with a warning. +Patch207: rear-support-export-TMPDIR.patch # rear contains only bash scripts plus documentation so that on first glance it could be "BuildArch: noarch" # but actually it is not "noarch" because it only works on those architectures that are explicitly supported. @@ -176,6 +204,33 @@ install -m 0644 %{SOURCE3} %{buildroot}%{_docdir}/%{name}/ #-- CHANGELOG -----------------------------------------------------------------# %changelog +* Sat Feb 24 2024 Pavel Cahyna - 2.6-24 +- Support "export TMPDIR" in user configuration again, print a warning + when this is used - revert commit f464eae2, adapt PR 3163, add commit + b422845f. + Will be supported only until the update to 2.7 + +* Fri Feb 9 2024 Pavel Cahyna - 2.6-23 +- Resolve libs for executable links in COPY_AS_IS, PR 3073 +- Skip invalid disk drives when saving layout PR 3047 + +* Thu Feb 8 2024 Pavel Cahyna - 2.6-22 +- Do not delete NetBackup logs in case of errors and save + /usr/openv/netbackup/logs to the restored system after a successful recovery +- Add /usr/openv/var to COPY_AS_IS_NBU, fixes an issue seen + with NetBackup 10.2.0.1 + +* Thu Feb 8 2024 Pavel Cahyna - 2.6-21 +- Support saving and restoring hybrid BIOS/UEFI bootloader, PRs 3145 3136 +- make initrd accessible only by root (CVE-2024-23301), PR 3123 + +* Fri Dec 1 2023 Pavel Cahyna - 2.6-20 +- Backport PR 3061 to save LVM pool metadata volume size in disk layout + and restore it +- Backport PR 3058 to skip useless xfs mount options when mounting + during recovery, prevents mount errors like "logbuf size must be greater + than or equal to log stripe size" + * Fri Aug 25 2023 Pavel Cahyna - 2.6-19 - Add patch to force removal of lvmdevices, prevents LVM problems after restoring to different disks/cloning. Upstream PR 3043