Compare commits

...

3 Commits

Author SHA1 Message Date
f3294984ca Import from AlmaLinux stable repository 2024-05-31 18:05:50 +00:00
a3fe46d75a Sync with stable 2024-04-10 08:28:45 +03:00
CentOS Sources
f8754e78fc import rear-2.6-9.el8 2023-05-16 07:12:26 +00:00
16 changed files with 2066 additions and 2 deletions

View File

@ -1 +0,0 @@
13c23ad59254438ffcd0cde6400fd991cbfe194e SOURCES/rear-2.6.tar.gz

View File

@ -0,0 +1,32 @@
From 89b61793d80bc2cb2abe47a7d0549466fb087d16 Mon Sep 17 00:00:00 2001
From: Johannes Meixner <jsmeix@suse.com>
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

View File

@ -0,0 +1,46 @@
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 d3c9ae86..f21845df 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
@@ -70,14 +70,20 @@ local lvs_exit_code
# Get physical_device configuration.
# Format: lvmdev <volume_group> <device> [<uuid>] [<size(bytes)>]
header_printed="no"
- # Example output of "lvm pvdisplay -c":
- # /dev/sda1:system:41940992:-1:8:8:-1:4096:5119:2:5117:7wwpcO-KmNN-qsTE-7sp7-JBJS-vBdC-Zyt1W7
+ # Set pvdisplay separator to '|' to prevent issues with a colon in the path under /dev/disk/by-path
+ # that contains a ':' in the SCSI slot name.
+ # Example output of "lvm pvdisplay -C --separator '|' --noheadings --nosuffix --units=b -o pv_name,vg_name,pv_size,pv_uuid"
+ # on a system where LVM is configured to show the /dev/disk/by-path device names instead of the usual
+ # /dev/sda etc. (by using a setting like
+ # filter = [ "r|/dev/disk/by-path/.*-usb-|", "a|/dev/disk/by-path/pci-.*-nvme-|", "a|/dev/disk/by-path/pci-.*-scsi-|", "a|/dev/disk/by-path/pci-.*-ata-|", "a|/dev/disk/by-path/pci-.*-sas-|", "a|loop|", "r|.*|" ]
+ # in /etc/lvm/lvm.conf):
+ # /dev/disk/by-path/pci-0000:03:00.0-scsi-0:0:1:0-part1|system|107340627968|7wwpcO-KmNN-qsTE-7sp7-JBJS-vBdC-Zyt1W7
# There are two leading blanks in the output (at least on SLES12-SP4 with LVM 2.02.180).
- lvm pvdisplay -c | while read line ; do
+ lvm pvdisplay -C --separator '|' --noheadings --nosuffix --units=b -o pv_name,vg_name,pv_size,pv_uuid | while read line ; do
- # With the above example pdev=/dev/sda1
+ # With the above example pdev=/dev/disk/by-path/pci-0000:03:00.0-scsi-0:0:1:0-part1
# (the "echo $line" makes the leading blanks disappear)
- pdev=$( echo $line | cut -d ":" -f "1" )
+ pdev=$( echo $line | cut -d "|" -f "1" )
# Skip lines that are not describing physical devices
# i.e. lines where pdev does not start with a leading / character:
@@ -91,11 +97,11 @@ local lvs_exit_code
fi
# With the above example vgrp=system
- vgrp=$( echo $line | cut -d ":" -f "2" )
- # With the above example size=41940992
- size=$( echo $line | cut -d ":" -f "3" )
+ vgrp=$( echo $line | cut -d "|" -f "2" )
+ # With the above example size=107340627968
+ size=$( echo $line | cut -d "|" -f "3" )
# With the above example uuid=7wwpcO-KmNN-qsTE-7sp7-JBJS-vBdC-Zyt1W7
- uuid=$( echo $line | cut -d ":" -f "12" )
+ uuid=$( echo $line | cut -d "|" -f "4" )
# Translate pdev through diskbyid_mappings file:
pdev=$( get_device_mapping $pdev )

View File

@ -0,0 +1,20 @@
diff --git a/usr/share/rear/finalize/Fedora/i386/550_rebuild_initramfs.sh b/usr/share/rear/finalize/Fedora/550_rebuild_initramfs.sh
similarity index 100%
rename from usr/share/rear/finalize/Fedora/i386/550_rebuild_initramfs.sh
rename to usr/share/rear/finalize/Fedora/550_rebuild_initramfs.sh
diff --git a/usr/share/rear/finalize/Fedora/ppc64/550_rebuild_initramfs.sh b/usr/share/rear/finalize/Fedora/ppc64/550_rebuild_initramfs.sh
deleted file mode 120000
index 22eede59..00000000
--- a/usr/share/rear/finalize/Fedora/ppc64/550_rebuild_initramfs.sh
+++ /dev/null
@@ -1 +0,0 @@
-../i386/550_rebuild_initramfs.sh
\ No newline at end of file
diff --git a/usr/share/rear/finalize/Fedora/ppc64le/550_rebuild_initramfs.sh b/usr/share/rear/finalize/Fedora/ppc64le/550_rebuild_initramfs.sh
deleted file mode 120000
index 22eede59..00000000
--- a/usr/share/rear/finalize/Fedora/ppc64le/550_rebuild_initramfs.sh
+++ /dev/null
@@ -1 +0,0 @@
-../i386/550_rebuild_initramfs.sh
\ No newline at end of file

View File

@ -0,0 +1,129 @@
diff --git a/usr/share/rear/layout/prepare/GNU/Linux/131_include_filesystem_code.sh b/usr/share/rear/layout/prepare/GNU/Linux/131_include_filesystem_code.sh
index 172ac032..9cff63a0 100644
--- a/usr/share/rear/layout/prepare/GNU/Linux/131_include_filesystem_code.sh
+++ b/usr/share/rear/layout/prepare/GNU/Linux/131_include_filesystem_code.sh
@@ -143,9 +143,9 @@ function create_fs () {
# unless the user has explicitly specified XFS filesystem options:
local xfs_opts
local xfs_device_basename="$( basename $device )"
- local xfs_info_filename="$LAYOUT_XFS_OPT_DIR/$xfs_device_basename.xfs"
+ local xfs_info_filename="$LAYOUT_XFS_OPT_DIR_RESTORE/$xfs_device_basename.xfs"
# Only uppercase letters and digits are used to ensure mkfs_xfs_options_variable_name is a valid bash variable name
- # even in case of complicated device nodes e.g. things like /dev/mapper/SIBM_2810XIV_78033E7012F-part3
+ # even in case of complicated device nodes e.g. things like /dev/mapper/SIBM_2810XIV_78033E7012F-part3
# cf. current_orig_device_basename_alnum_uppercase in layout/prepare/default/300_map_disks.sh
local xfs_device_basename_alnum_uppercase="$( echo $xfs_device_basename | tr -d -c '[:alnum:]' | tr '[:lower:]' '[:upper:]' )"
# cf. predefined_input_variable_name in the function UserInput in lib/_input-output-functions.sh
diff --git a/usr/share/rear/layout/prepare/default/010_prepare_files.sh b/usr/share/rear/layout/prepare/default/010_prepare_files.sh
index 85964712..7a980e63 100644
--- a/usr/share/rear/layout/prepare/default/010_prepare_files.sh
+++ b/usr/share/rear/layout/prepare/default/010_prepare_files.sh
@@ -5,6 +5,7 @@ LAYOUT_DEPS="$VAR_DIR/layout/diskdeps.conf"
LAYOUT_TODO="$VAR_DIR/layout/disktodo.conf"
LAYOUT_CODE="$VAR_DIR/layout/diskrestore.sh"
LAYOUT_XFS_OPT_DIR="$VAR_DIR/layout/xfs"
+LAYOUT_XFS_OPT_DIR_RESTORE="$LAYOUT_XFS_OPT_DIR/restore"
FS_UUID_MAP="$VAR_DIR/layout/fs_uuid_mapping"
LUN_WWID_MAP="$VAR_DIR/layout/lun_wwid_mapping"
diff --git a/usr/share/rear/layout/prepare/default/319_rename_xfs_configs.sh b/usr/share/rear/layout/prepare/default/319_rename_xfs_configs.sh
new file mode 100644
index 00000000..406afa61
--- /dev/null
+++ b/usr/share/rear/layout/prepare/default/319_rename_xfs_configs.sh
@@ -0,0 +1,83 @@
+# Cleanup directory which hold XFS configuration file for `rear recover'.
+# This will avoid possible mess in LAYOUT_XFS_OPT_DIR_RESTORE if `rear recover'
+# would be launched multiple times, where user will choose different disk
+# mapping each time.
+# Removing and creating LAYOUT_XFS_OPT_DIR_RESTORE will ensure that ReaR will
+# have only current files available during current session.
+rm -rf "$LAYOUT_XFS_OPT_DIR_RESTORE"
+mkdir -p "$LAYOUT_XFS_OPT_DIR_RESTORE"
+
+local excluded_configs=()
+
+# Read $MAPPING_FILE (disk_mappings) to discover final disk mapping.
+# Once mapping is known, configuration files can be renamed.
+# (e.g. sds2.xfs to sdb2.xfs, ...)
+while read source target junk ; do
+ # Disks in MAPPING_FILE are listed with full device path. Since XFS config
+ # files are created in format e.g. sda2.xfs strip prefixed path to have
+ # only short device name available.
+ base_source=$(basename "$source")
+ base_target=$(basename "$target")
+
+ # Check if XFS configuration file for whole device (unpartitioned)
+ # is available (sda, sdb, ...). If so, rename and copy it to
+ # LAYOUT_XFS_OPT_DIR_RESTORE.
+ if [ -e "$LAYOUT_XFS_OPT_DIR/$base_source.xfs" ]; then
+ Log "Migrating XFS configuration file $base_source.xfs to $base_target.xfs"
+ cp "$v" "$LAYOUT_XFS_OPT_DIR/$base_source.xfs" \
+ "$LAYOUT_XFS_OPT_DIR_RESTORE/$base_target.xfs"
+
+ # Replace old device name in meta-data= option in XFS
+ # configuration file as well.
+ sed -i s#"meta-data=${source}\(\s\)"#"meta-data=${target}\1"# \
+ "$LAYOUT_XFS_OPT_DIR_RESTORE/$base_target.xfs"
+
+ # Mark XFS config file as processed to avoid copying it again later.
+ # More details on why are configs excluded can be found near the
+ # end of this script (near `tar' command).
+ excluded_configs+=("--exclude=$base_source.xfs")
+ fi
+
+ # Find corresponding partitions to source disk in LAYOUT_FILE
+ # and migrate/rename them too if necessary.
+ while read _ layout_device _ _ _ _ layout_partition; do
+ if [[ "$source" = "$layout_device" ]]; then
+ base_src_layout_partition=$(basename "$layout_partition")
+ base_dst_layout_partition=${base_src_layout_partition//$base_source/$base_target}
+ dst_layout_partition=${layout_partition//$base_source/$base_target}
+
+ if [ -e "$LAYOUT_XFS_OPT_DIR/$base_src_layout_partition.xfs" ]; then
+ Log "Migrating XFS configuration $base_src_layout_partition.xfs to $base_dst_layout_partition.xfs"
+ cp "$v" "$LAYOUT_XFS_OPT_DIR/$base_src_layout_partition.xfs" \
+ "$LAYOUT_XFS_OPT_DIR_RESTORE/$base_dst_layout_partition.xfs"
+
+ # Replace old device name in meta-data= option in XFS
+ # configuration file as well.
+ sed -i s#"meta-data=${layout_partition}\(\s\)"#"meta-data=${dst_layout_partition}\1"# \
+ "$LAYOUT_XFS_OPT_DIR_RESTORE/$base_dst_layout_partition.xfs"
+
+ # Mark XFS config file as processed to avoid copying it again later.
+ # More details on why are configs excluded can be found near the
+ # end of this script (near `tar' command).
+ excluded_configs+=("--exclude=$base_src_layout_partition.xfs")
+ fi
+ fi
+ done < <( grep -E "^part " "$LAYOUT_FILE" )
+done < <( grep -v '^#' "$MAPPING_FILE" )
+
+pushd "$LAYOUT_XFS_OPT_DIR" >/dev/null
+# Copy remaining files
+# We need to copy remaining files into LAYOUT_XFS_OPT_DIR_RESTORE which will
+# serve as base dictionary where ReaR will look for XFS config files.
+# It is necessary to copy only files that were not previously processed,
+# because in LAYOUT_XFS_OPT_DIR they are still listed with
+# original name and copy to LAYOUT_XFS_OPT_DIR_RESTORE could overwrite
+# XFS configs already migrated.
+# e.g. with following disk mapping situation:
+# /dev/sda2 => /dev/sdb2
+# /dev/sdb2 => /dev/sda2
+# Files in LAYOUT_XFS_OPT_DIR_RESTORE would be overwritten by XFS configs with
+# wrong names.
+# tar is used to take advantage of its exclude feature.
+tar cf - --exclude=restore "${excluded_configs[@]}" . | tar xfp - -C "$LAYOUT_XFS_OPT_DIR_RESTORE"
+popd >/dev/null
diff --git a/usr/share/rear/layout/save/GNU/Linux/100_create_layout_file.sh b/usr/share/rear/layout/save/GNU/Linux/100_create_layout_file.sh
index 7895e4ee..fc0fa8fc 100644
--- a/usr/share/rear/layout/save/GNU/Linux/100_create_layout_file.sh
+++ b/usr/share/rear/layout/save/GNU/Linux/100_create_layout_file.sh
@@ -10,6 +10,7 @@ mkdir -p $v $VAR_DIR/layout/config
# We need directory for XFS options only if XFS is in use:
if test "$( mount -t xfs )" ; then
LAYOUT_XFS_OPT_DIR="$VAR_DIR/layout/xfs"
+ rm -rf $LAYOUT_XFS_OPT_DIR
mkdir -p $v $LAYOUT_XFS_OPT_DIR
fi

View File

@ -0,0 +1,32 @@
commit 4f03a10d4866efc9b6920a3878e6397d170742f9
Author: Johannes Meixner <jsmeix@suse.com>
Date: Thu Jul 20 15:11:52 2023 +0200
Merge pull request #3027 from rmetrich/shrinking_file
In build/GNU/Linux/100_copy_as_is.sh
ensure to really get all COPY_AS_IS files copied by using
'tar ... -i' when extracting to avoid a false regular exit of 'tar'
in particular when padding zeroes get added when a file being read shrinks
because for 'tar' (without '-i') two consecutive 512-blocks of zeroes mean EOF,
cf. https://github.com/rear/rear/pull/3027
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 ec55f331..0e402b01 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
@@ -92,9 +92,13 @@ done >$copy_as_is_exclude_file
# COPY_AS_IS+=( /path/to/directory/* )
# which are used in our scripts and by users in their etc/rear/local.conf
# cf. https://github.com/rear/rear/pull/2405#issuecomment-633512932
+# Using '-i' when extracting is necessary to avoid a false regular exit of 'tar'
+# in particular when padding zeroes get added when a file being read shrinks
+# because for 'tar' (without '-i') two consecutive 512-blocks of zeroes mean EOF,
+# cf. https://github.com/rear/rear/pull/3027
# FIXME: The following code fails if file names contain characters from IFS (e.g. blanks),
# cf. https://github.com/rear/rear/issues/1372
-if ! tar -v -X $copy_as_is_exclude_file -P -C / -c ${COPY_AS_IS[*]} 2>$copy_as_is_filelist_file | tar $v -C $ROOTFS_DIR/ -x 1>/dev/null ; then
+if ! tar -v -X $copy_as_is_exclude_file -P -C / -c ${COPY_AS_IS[*]} 2>$copy_as_is_filelist_file | tar $v -C $ROOTFS_DIR/ -x -i 1>/dev/null ; then
Error "Failed to copy files and directories in COPY_AS_IS minus COPY_AS_IS_EXCLUDE"
fi
Log "Finished copying files and directories in COPY_AS_IS minus COPY_AS_IS_EXCLUDE"

View File

@ -0,0 +1,25 @@
commit 2aa7b47354bdf5863071c8b479d29c99aad05ecb
Author: Johannes Meixner <jsmeix@suse.com>
Date: Fri Jul 24 13:02:45 2020 +0200
Update 240_reassign_luks_keyfiles.sh
Use ReaR specific TMP_DIR (not TMPDIR or hardcoded /tmp)
diff --git a/usr/share/rear/finalize/GNU/Linux/240_reassign_luks_keyfiles.sh b/usr/share/rear/finalize/GNU/Linux/240_reassign_luks_keyfiles.sh
index d989c3fb..358f3950 100644
--- a/usr/share/rear/finalize/GNU/Linux/240_reassign_luks_keyfiles.sh
+++ b/usr/share/rear/finalize/GNU/Linux/240_reassign_luks_keyfiles.sh
@@ -24,9 +24,9 @@ awk '
while read target_name source_device original_keyfile; do
Log "Re-assigning keyfile $original_keyfile to LUKS device $target_name ($source_device)"
- # The scheme for generating a temporary keyfile path must be the same here and in the 'layout/prepare' stage.
- temp_keyfile="${TMPDIR:-/tmp}/LUKS-keyfile-$target_name"
- [ -f "$temp_keyfile" ] || BugError "temporary keyfile $temp_keyfile not found"
+ # The scheme for generating a temporary keyfile path must be the same here and in the 'layout/prepare' stage:
+ temp_keyfile="$TMP_DIR/LUKS-keyfile-$target_name"
+ test -f "$temp_keyfile" || BugError "temporary LUKS keyfile $temp_keyfile not found"
target_keyfile="$TARGET_FS_ROOT/$original_keyfile"

View File

@ -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
-

View File

@ -0,0 +1,102 @@
From e7b84271536782fbc8673ef4573e155e1dfa850e Mon Sep 17 00:00:00 2001
From: pcahyna <pcahyna@users.noreply.github.com>
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='<missing_VG>'
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 <volume_group> <extentsize> [<size(extents)>] [<size(bytes)>]
@@ -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

View File

@ -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

View File

@ -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/%,/}"
+}

View File

@ -0,0 +1,82 @@
commit 4af486794d45adbda7567361d8dcc658599dcd2c
Author: Johannes Meixner <jsmeix@suse.com>
Date: Tue Aug 8 14:44:16 2023 +0200
Merge pull request #3031 from rear/jsmeix-USB-Secure-Boot
Secure Boot support for OUTPUT=USB:
In output/USB/Linux-i386/100_create_efiboot.sh
added SECURE_BOOT_BOOTLOADER related code that is based
on the code in output/ISO/Linux-i386/250_populate_efibootimg.sh
with some adaptions to make it work within the existing USB code.
The basic idea for Secure Boot booting of the ReaR recovery system
is to "just copy" the (signed) EFI binaries of the Linux distribution
(shim*.efi and grub*.efi as first and second stage UEFI bootloaders)
instead of let ReaR make its own EFI binary via build_bootx86_efi()
see https://github.com/rear/rear/pull/3031
diff --git a/usr/share/rear/output/USB/Linux-i386/100_create_efiboot.sh b/usr/share/rear/output/USB/Linux-i386/100_create_efiboot.sh
index f4659306..fd631c44 100644
--- a/usr/share/rear/output/USB/Linux-i386/100_create_efiboot.sh
+++ b/usr/share/rear/output/USB/Linux-i386/100_create_efiboot.sh
@@ -29,6 +29,44 @@ mount $EFI_PART $EFI_MPT || Error "Failed to mount EFI partition '$EFI_PART' at
mkdir -p $EFI_DST || Error "Failed to create directory '$EFI_DST'"
# Copy boot loader
+# The SECURE_BOOT_BOOTLOADER related code below is based on the code in output/ISO/Linux-i386/250_populate_efibootimg.sh
+# because I <jsmeix@suse.de> noticed that Secure Boot works with ISO at least for me, cf.
+# https://github.com/rear/rear/pull/3025#issuecomment-1635876186
+# but not with USB, cf.
+# https://github.com/rear/rear/pull/3025#issuecomment-1643774477
+# so I tried to re-use the ISO Secure Boot code for USB
+# which made Secure Boot "just work" for me with USB
+# but I had to do some (minor) adaptions to make it work
+# within the existing USB code, cf.
+# https://github.com/rear/rear/pull/3031#issuecomment-1653443454
+# Copy UEFI bootloader:
+if test -f "$SECURE_BOOT_BOOTLOADER" ; then
+ # For a technical description of Shim see https://mjg59.dreamwidth.org/19448.html
+ # Shim is a signed EFI binary that is a first stage bootloader
+ # that loads and executes another (signed) EFI binary
+ # which normally is a second stage bootloader
+ # which normally is a GRUB EFI binary
+ # which normally is available as a file named grub*.efi
+ # so when SECURE_BOOT_BOOTLOADER is used as UEFI_BOOTLOADER
+ # (cf. rescue/default/850_save_sysfs_uefi_vars.sh)
+ # then Shim (usually shim.efi) must be copied as EFI/BOOT/BOOTX64.efi
+ # and Shim's second stage bootloader must be also copied where Shim already is.
+ DebugPrint "Using '$SECURE_BOOT_BOOTLOADER' as first stage Secure Boot bootloader BOOTX64.efi"
+ cp -L $v "$SECURE_BOOT_BOOTLOADER" "$EFI_DST/BOOTX64.efi" || Error "Failed to copy SECURE_BOOT_BOOTLOADER '$SECURE_BOOT_BOOTLOADER' to $EFI_DST/BOOTX64.efi"
+ # When Shim is used, its second stage bootloader can be actually anything
+ # named grub*.efi (second stage bootloader is Shim compile time option), see
+ # http://www.rodsbooks.com/efi-bootloaders/secureboot.html#initial_shim
+ local uefi_bootloader_dirname="$( dirname $SECURE_BOOT_BOOTLOADER )"
+ local second_stage_UEFI_bootloader_files="$( echo $uefi_bootloader_dirname/grub*.efi )"
+ # Avoid 'nullglob' pitfall when nothing matches .../grub*.efi which would result
+ # an invalid "cp -v /var/tmp/.../EFI/BOOT/" command that fails
+ # cf. https://github.com/rear/rear/issues/1921
+ test "$second_stage_UEFI_bootloader_files" || Error "Could not find second stage Secure Boot bootloader $uefi_bootloader_dirname/grub*.efi"
+ DebugPrint "Using second stage Secure Boot bootloader files: $second_stage_UEFI_bootloader_files"
+ cp -L $v $second_stage_UEFI_bootloader_files $EFI_DST/ || Error "Failed to copy second stage Secure Boot bootloader files"
+else
+ cp -L $v "$UEFI_BOOTLOADER" "$EFI_DST/BOOTX64.efi" || Error "Failed to copy UEFI_BOOTLOADER '$UEFI_BOOTLOADER' to $EFI_DST/BOOTX64.efi"
+fi
cp $v $UEFI_BOOTLOADER "$EFI_DST/BOOTX64.efi" || Error "Failed to copy UEFI_BOOTLOADER '$UEFI_BOOTLOADER' to $EFI_DST/BOOTX64.efi"
# Copy kernel
@@ -93,7 +131,14 @@ EOF
create_grub2_cfg ${EFI_DIR}/kernel ${EFI_DIR}/$REAR_INITRD_FILENAME > ${EFI_DST}/grub.cfg
# Create bootloader, this overwrite BOOTX64.efi copied in previous step ...
- build_bootx86_efi ${EFI_DST}/BOOTX64.efi ${EFI_DST}/grub.cfg "/boot" "$UEFI_BOOTLOADER"
+ # Create BOOTX86.efi but only if we are NOT secure booting.
+ # We are not able to create signed boot loader
+ # so we need to reuse existing one.
+ # See issue #1374
+ # build_bootx86_efi () can be safely used for other scenarios.
+ if ! test -f "$SECURE_BOOT_BOOTLOADER" ; then
+ build_bootx86_efi ${EFI_DST}/BOOTX64.efi ${EFI_DST}/grub.cfg "/boot" "$UEFI_BOOTLOADER"
+ fi
;;
*)
BugError "Neither grub 0.97 nor 2.0"

View File

@ -0,0 +1,41 @@
commit 1cd41052f7a7cd42ea14ea53b7280c73624aba3f
Author: Johannes Meixner <jsmeix@suse.com>
Date: Mon Mar 21 12:14:21 2022 +0100
Merge pull request #2774 from rear/jsmeix-1024-USB_UEFI_PART_SIZE
In default.conf increase USB_UEFI_PART_SIZE to 1024 MiB,
cf. https://github.com/rear/rear/pull/1205
in particular to also make things work by default when additional
third-party kernel modules and firmware (e.g. from Nvidia) are used,
cf. https://github.com/rear/rear/issues/2770#issuecomment-1068935688
diff --git a/usr/share/rear/conf/default.conf b/usr/share/rear/conf/default.conf
index 8faa56aa..17a764cb 100644
--- a/usr/share/rear/conf/default.conf
+++ b/usr/share/rear/conf/default.conf
@@ -872,13 +872,20 @@ USB_PARTITION_ALIGN_BLOCK_SIZE="8"
# in MiB when formatting a medium by the format workflow.
# If USB_UEFI_PART_SIZE is empty or invalid (i.e. not an unsigned integer larger than 0)
# the user must interactively enter a valid value while running the format workflow.
-# The default value of 400 MiB should be sufficiently big and it is in compliance
-# with the 8 MiB partition alignment default value ( 400 = 8 * 50 )
-# and even with a 16 MiB partition alignment value ( 400 = 16 * 25 )
+# The default value of 1024 MiB should be sufficiently big
# cf. https://github.com/rear/rear/pull/1205
+# in particular when third-party kernel modules and firmware (e.g. from Nvidia) are used
+# cf. https://github.com/rear/rear/issues/2770#issuecomment-1068935688
+# and 1024 MiB is in compliance with the 8 MiB partition alignment value ( 1024 = 8 * 128 )
+# and also with higher 2^n MiB partition alignment values.
+# Furthermore the default value of 1024 MiB results that the FAT filesystem of the ESP
+# will be in compliance with that the ESP should officially use a FAT32 filesystem
+# because mkfs.vfat automatically makes a FAT32 filesystem starting at 512 MiB
+# (a FAT16 ESP works in most cases but causes issues with certain UEFI firmware)
+# cf. https://github.com/rear/rear/issues/2575
# The value of USB_UEFI_PART_SIZE will be rounded to the nearest
# USB_PARTITION_ALIGN_BLOCK_SIZE chunk:
-USB_UEFI_PART_SIZE="400"
+USB_UEFI_PART_SIZE="1024"
#
# Default boot option (i.e. what gets booted automatically after some timeout)
# when EXTLINUX boots the USB stick or USB disk or other disk device on BIOS systems.

View File

@ -0,0 +1,21 @@
commit ead05a460d3b219372f47be888ba6011c7fd3318
Author: Pavel Cahyna <pcahyna@redhat.com>
Date: Tue Aug 22 12:32:04 2023 +0200
Fix downstream only bug
\$IsInArray -> IsInArray - it is a shell function, not a variable.
diff --git a/usr/share/rear/layout/prepare/GNU/Linux/110_include_lvm_code.sh b/usr/share/rear/layout/prepare/GNU/Linux/110_include_lvm_code.sh
index d34ab335..a65a9c8e 100644
--- a/usr/share/rear/layout/prepare/GNU/Linux/110_include_lvm_code.sh
+++ b/usr/share/rear/layout/prepare/GNU/Linux/110_include_lvm_code.sh
@@ -246,7 +246,7 @@ create_lvmvol() {
local warnraidline
if [ $is_thin -eq 0 ] ; then
- ifline="if IsInArray $vg \"\${create_logical_volumes[@]}\" && ! \$IsInArray $vg \"\${create_thin_volumes_only[@]}\" ; then"
+ ifline="if IsInArray $vg \"\${create_logical_volumes[@]}\" && ! IsInArray $vg \"\${create_thin_volumes_only[@]}\" ; then"
else
ifline="if IsInArray $vg \"\${create_logical_volumes[@]}\" ; then"
fi

View File

@ -0,0 +1,751 @@
diff --git a/usr/share/rear/conf/default.conf b/usr/share/rear/conf/default.conf
index 23a83b71..0d13b487 100644
--- a/usr/share/rear/conf/default.conf
+++ b/usr/share/rear/conf/default.conf
@@ -416,6 +416,18 @@ test "$RECOVERY_UPDATE_URL" || RECOVERY_UPDATE_URL=""
# export MIGRATION_MODE='true'
# directly before he calls "rear recover":
test "$MIGRATION_MODE" || MIGRATION_MODE=''
+####
+
+####
+# Formatting DASDs (S/390 specific)
+# DASD (Direct Access Storage Device) denotes a disk drive on the S/390 architecture.
+# DASDs need to be formatted before use (even before creating a partition table on them).
+# By default ReaR will format the DASDs that are going to be used to recreate the system
+# (are referenced in disklayout.conf) before recreating the disk layout.
+# This can be suppressed by setting FORMAT_DASDS="false". It can be useful when one intends
+# to use already formatted DASDs as recovery target.
+FORMAT_DASDS=""
+####
##
# Resizing partitions in MIGRATION_MODE during "rear recover"
diff --git a/usr/share/rear/layout/prep-for-mount/Linux-s390/205_s390_enable_disk.sh b/usr/share/rear/layout/prep-for-mount/Linux-s390/205_s390_enable_disk.sh
new file mode 120000
index 00000000..5f7a2ac0
--- /dev/null
+++ b/usr/share/rear/layout/prep-for-mount/Linux-s390/205_s390_enable_disk.sh
@@ -0,0 +1 @@
+../../prepare/Linux-s390/205_s390_enable_disk.sh
\ No newline at end of file
diff --git a/usr/share/rear/layout/prepare/GNU/Linux/100_include_partition_code.sh b/usr/share/rear/layout/prepare/GNU/Linux/100_include_partition_code.sh
index 13c69ce8..2a2bc33f 100644
--- a/usr/share/rear/layout/prepare/GNU/Linux/100_include_partition_code.sh
+++ b/usr/share/rear/layout/prepare/GNU/Linux/100_include_partition_code.sh
@@ -24,6 +24,7 @@ fi
### Prepare a disk for partitioning/general usage.
create_disk() {
local component disk size label junk
+ local blocksize layout dasdtype dasdcyls junk2
read component disk size label junk < <(grep "^disk $1 " "$LAYOUT_FILE")
### Disks should be block devices.
@@ -67,7 +68,8 @@ sync
EOF
- create_partitions "$disk" "$label"
+ # $junk can contain useful DASD-specific fields
+ create_partitions "$disk" "$label" "$junk"
cat >> "$LAYOUT_CODE" <<EOF
# Make sure device nodes are visible (eg. in RHEL4)
@@ -93,6 +95,11 @@ create_partitions() {
### List partition types/names to detect disk label type.
local -a names=()
local part disk size pstart name junk
+ local orig_block_size layout dasdtype dasdcyls junk2
+ if [ "$label" == dasd ]; then
+ # dasd has more fields - junk is not junk anymore
+ read orig_block_size layout dasdtype dasdcyls junk2 <<<$3
+ fi
while read part disk size pstart name junk ; do
names+=( $name )
case $name in
@@ -227,10 +234,12 @@ EOF
if [[ "$end" ]] ; then
end=$( mathlib_calculate "$end - 1" )
fi
- if [[ "$ARCH" == "Linux-s390" ]] ; then
- # if dasd disk is LDL formated, then do not partition it, because it is partitioned and can take only partition
- if [[ ! "${listDasdLdl[@]}" =~ "$device" ]] ; then
- echo "not LDL dasd formated disk, create a partition"
+ if [[ "$ARCH" == "Linux-s390" && "$label" == dasd ]] ; then
+ # LDL formatted disks are already partitioned and should not be partitioned with parted or fdasd , it will fail
+ if [ "$layout" == LDL ]; then
+ Debug "$device: LDL formatted DASD, do not create a partition"
+ else
+ Debug "$device: ${layout} formatted DASD, create a partition"
cat >> "$LAYOUT_CODE" <<EOF
create_disk_partition "$device" "$name" $number $start $end
EOF
diff --git a/usr/share/rear/layout/prepare/Linux-s390/090_include_dasd_code.sh b/usr/share/rear/layout/prepare/Linux-s390/090_include_dasd_code.sh
new file mode 100644
index 00000000..fc5be463
--- /dev/null
+++ b/usr/share/rear/layout/prepare/Linux-s390/090_include_dasd_code.sh
@@ -0,0 +1,17 @@
+# Generate code for low-level formatting of a DASD
+
+dasd_format_code() {
+ local device size blocksize layout dasdtype dasdcyls
+
+ device="$1"
+ size="$2"
+ blocksize="$3"
+ layout="$4"
+ dasdtype="$5"
+ dasdcyls="$6"
+
+ has_binary dasdfmt || Error "Cannot find 'dasdfmt' command"
+
+ LogPrint 'dasdfmt:' $device ', blocksize:' $blocksize ', layout:' $layout
+ echo "dasdfmt -b $blocksize -d $layout -y $device"
+}
diff --git a/usr/share/rear/layout/prepare/Linux-s390/205_s390_enable_disk.sh b/usr/share/rear/layout/prepare/Linux-s390/205_s390_enable_disk.sh
index c4037e02..0f6946a9 100644
--- a/usr/share/rear/layout/prepare/Linux-s390/205_s390_enable_disk.sh
+++ b/usr/share/rear/layout/prepare/Linux-s390/205_s390_enable_disk.sh
@@ -2,45 +2,36 @@
# Before we can compare or map DASD devices we must enable them.
# This operation is only needed during "rear recover".
-format_s390_disk() {
- LogPrint "run dasdfmt"
- while read line ; do
- LogPrint 'dasdfmt:' "$line"
- # example format command: dasdfmt -b 4096 -d cdl -y /dev/dasda
- # where
- # b is the block size
- # d is the layout:
- # cdl - compatible disk layout (can be shared with zos and zvm apps)
- # ldl - linux disk layout
- # y - answer yes
- device=$( echo $line | awk '{ print $7 }' )
- blocksize=$( echo $line | awk '{ print $3 }' )
- layout=$( echo $line | awk '{ print tolower($5) }' )
- if [[ "$layout" == "ldl" ]] ; then
- # listDasdLdl contains devices such as /dev/dasdb that are formatted as LDL
- # LDL formatted disks are already partitioned and should not be partitioned with parted or fdasd , it will fail
- # this var, listDasdLdl, is used by 100_include_partition_code.sh to exclude writing partition code to diskrestore.sh for LDL disks
- listDasdLdl+=( $device )
- LogPrint "LDL disk added to listDasdLdl:" ${listDasdLdl[@]}
- fi
- LogPrint 'dasdfmt:' $device ', blocksize:' $blocksize ', layout:' $layout
- # dasd format
- dasdfmt -b $blocksize -d $layout -y $device
- done < <( grep "^dasdfmt " "$LAYOUT_FILE" )
-}
-
+DISK_MAPPING_HINTS=()
enable_s390_disk() {
+ local keyword device bus len newname
+
LogPrint "run chccwdev"
- while read line ; do
- LogPrint 'dasd channel:' "$line"
- device=$( echo $line | awk '{ print $4 }' )
- bus=$( echo $line | awk '{ print $2 }' )
- channel=$( echo $line | awk '{ print $5 }' )
- LogPrint 'chccwdev:' $device ', bus:' $bus ', channel:' $channel
- # dasd channel enable
- chccwdev -e $bus
- done < <( grep "^dasd_channel " "$LAYOUT_FILE" )
+ while read len device bus ; do
+ # this while loop must be outside the pipeline so that variables propagate outside
+ # (pipelines run in subshells)
+ LogPrint "Enabling DASD $device with virtual device number $bus"
+ if chccwdev -e $bus ; then
+ newname=$(lsdasd $bus | awk "/$bus/ { print \$3}" )
+ if ! test $newname ; then
+ LogPrintError "New device with virtual device number $bus not found among online DASDs"
+ continue
+ fi
+ if [ "$newname" != "$device" ]; then
+ LogPrint "original DASD '$device' changed name to '$newname'"
+ test "$MIGRATION_MODE" || MIGRATION_MODE='true'
+ fi
+ DISK_MAPPING_HINTS+=( "/dev/$device /dev/$newname" )
+ else
+ LogPrintError "Failed to enable $bus"
+ fi
+ done < <( grep "^dasd_channel " "$LAYOUT_FILE" | while read keyword bus device; do
+ # add device name length, so that "dasdb" sorts properly before "dasdaa"
+ # we need to create devices in the same order as the kernel orders them (by minor number)
+ # - this increases the chance that they will get identical names
+ echo ${#device} $device $bus
+ done | sort -k1n -k2 )
}
# May need to look at $OS_VENDOR also as DASD disk layout is distro specific:
@@ -49,7 +40,6 @@ case $OS_MASTER_VENDOR in
# "Fedora" also handles Red Hat
# "Debian" also handles Ubuntu
enable_s390_disk
- format_s390_disk
;;
(*)
LogPrintError "No code for DASD disk device enablement on $OS_MASTER_VENDOR"
diff --git a/usr/share/rear/layout/prepare/Linux-s390/360_generate_dasd_format_code.sh b/usr/share/rear/layout/prepare/Linux-s390/360_generate_dasd_format_code.sh
new file mode 100644
index 00000000..14bb942d
--- /dev/null
+++ b/usr/share/rear/layout/prepare/Linux-s390/360_generate_dasd_format_code.sh
@@ -0,0 +1,51 @@
+# DASD_FORMAT_CODE is the script to recreate the dasd formatting (dasdformat.sh).
+
+local component disk size label junk
+local blocksize layout dasdtype dasdcyls junk2
+
+
+save_original_file "$DASD_FORMAT_CODE"
+
+# Initialize
+
+echo '#!/bin/bash' >"$DASD_FORMAT_CODE"
+
+# Show the current output of lsdasd, it can be useful for identifying disks
+# (in particular it shows the Linux device name <-> virtual device number mapping,
+# formatted / unformatted status and the number/size of blocks when formatted )
+echo "# Current output of 'lsdasd':" >>"$DASD_FORMAT_CODE"
+lsdasd | sed -e 's/^/# /' >>"$DASD_FORMAT_CODE"
+
+cat <<EOF >>"$DASD_FORMAT_CODE"
+
+LogPrint "Start DASD format restoration."
+
+set -e
+set -x
+
+EOF
+
+while read component disk size label junk; do
+ if [ "$label" == dasd ]; then
+ # Ignore excluded components.
+ # Normally they are removed in 520_exclude_components.sh,
+ # but we run before it, so we must skip them here as well.
+ if IsInArray "$disk" "${EXCLUDE_RECREATE[@]}" ; then
+ Log "Excluding $disk from DASD reformatting."
+ continue
+ fi
+ # dasd has more fields - junk is not junk anymore
+ read blocksize layout dasdtype dasdcyls junk2 <<<$junk
+ dasd_format_code "$disk" "$size" "$blocksize" "$layout" "$dasdtype" "$dasdcyls" >> "$DASD_FORMAT_CODE" || \
+ LogPrintError "Error producing DASD format code for $disk"
+ fi
+done < <(grep "^disk " "$LAYOUT_FILE")
+
+cat <<EOF >>"$DASD_FORMAT_CODE"
+
+set +x
+set +e
+
+LogPrint "DASD(s) formatted."
+
+EOF
diff --git a/usr/share/rear/layout/prepare/Linux-s390/370_confirm_dasd_format_code.sh b/usr/share/rear/layout/prepare/Linux-s390/370_confirm_dasd_format_code.sh
new file mode 100644
index 00000000..5ba4edd5
--- /dev/null
+++ b/usr/share/rear/layout/prepare/Linux-s390/370_confirm_dasd_format_code.sh
@@ -0,0 +1,69 @@
+# adapted from 100_confirm_layout_code.sh
+#
+# Let the user confirm the
+# DASD format code (dasdformat.sh) script.
+#
+
+is_false "$FORMAT_DASDS" && return 0
+
+# Show the user confirmation dialog in any case but when not in migration mode
+# automatically proceed with less timeout USER_INPUT_INTERRUPT_TIMEOUT (by default 10 seconds)
+# to avoid longer delays (USER_INPUT_TIMEOUT is by default 300 seconds) in case of unattended recovery:
+# (taken from 120_confirm_wipedisk_disks.sh)
+local timeout="$USER_INPUT_TIMEOUT"
+is_true "$MIGRATION_MODE" || timeout="$USER_INPUT_INTERRUPT_TIMEOUT"
+
+rear_workflow="rear $WORKFLOW"
+original_disk_space_usage_file="$VAR_DIR/layout/config/df.txt"
+rear_shell_history="$( echo -e "cd $VAR_DIR/layout/\nvi $DASD_FORMAT_CODE\nless $DASD_FORMAT_CODE" )"
+unset choices
+choices[0]="Confirm DASD format script and continue '$rear_workflow'"
+choices[1]="Edit DASD format script ($DASD_FORMAT_CODE)"
+choices[2]="View DASD format script ($DASD_FORMAT_CODE)"
+choices[3]="View original disk space usage ($original_disk_space_usage_file)"
+choices[4]="Confirm what is currently on the DASDs, skip formatting them and continue '$rear_workflow'"
+choices[5]="Use Relax-and-Recover shell and return back to here"
+choices[6]="Abort '$rear_workflow'"
+prompt="Confirm or edit the DASD format script"
+choice=""
+wilful_input=""
+# When USER_INPUT_DASD_FORMAT_CODE_CONFIRMATION has any 'true' value be liberal in what you accept and
+# assume choices[0] 'Confirm DASD format' was actually meant:
+is_true "$USER_INPUT_DASD_FORMAT_CODE_CONFIRMATION" && USER_INPUT_DASD_FORMAT_CODE_CONFIRMATION="${choices[0]}"
+while true ; do
+ choice="$( UserInput -I DASD_FORMAT_CODE_CONFIRMATION -t "$timeout" -p "$prompt" -D "${choices[0]}" "${choices[@]}" )" && wilful_input="yes" || wilful_input="no"
+ case "$choice" in
+ (${choices[0]})
+ # Confirm DASD format file and continue:
+ is_true "$wilful_input" && LogPrint "User confirmed DASD format script" || LogPrint "Continuing '$rear_workflow' by default"
+ break
+ ;;
+ (${choices[1]})
+ # Run 'vi' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
+ vi $DASD_FORMAT_CODE 0<&6 1>&7 2>&8
+ ;;
+ (${choices[2]})
+ # Run 'less' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
+ less $DASD_FORMAT_CODE 0<&6 1>&7 2>&8
+ ;;
+ (${choices[3]})
+ # Run 'less' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
+ less $original_disk_space_usage_file 0<&6 1>&7 2>&8
+ ;;
+ (${choices[4]})
+ # Confirm what is on the disks and continue without formatting
+ FORMAT_DASDS="false"
+ ;;
+ (${choices[5]})
+ # rear_shell runs 'bash' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
+ rear_shell "" "$rear_shell_history"
+ ;;
+ (${choices[6]})
+ abort_dasd_format
+ Error "User chose to abort '$rear_workflow' in ${BASH_SOURCE[0]}"
+ ;;
+ esac
+done
+
+chmod +x $DASD_FORMAT_CODE
+
diff --git a/usr/share/rear/layout/prepare/Linux-s390/400_run_dasd_format_code.sh b/usr/share/rear/layout/prepare/Linux-s390/400_run_dasd_format_code.sh
new file mode 100644
index 00000000..16451af6
--- /dev/null
+++ b/usr/share/rear/layout/prepare/Linux-s390/400_run_dasd_format_code.sh
@@ -0,0 +1,185 @@
+# adapted from 200_run_layout_code.sh
+#
+# Run the DASD format code (dasdformat.sh)
+# again and again until it succeeds or the user aborts.
+#
+
+# Skip DASD formatting when the user has explicitly specified to not format them
+# or when the user selected "Confirm what is currently on the DASDs, skip formatting them"
+# in 370_confirm_dasd_format_code.sh
+
+is_false "$FORMAT_DASDS" && return 0
+
+function lsdasd_output () {
+ lsdasd 1>> >( tee -a "$RUNTIME_LOGFILE" 1>&7 )
+}
+
+rear_workflow="rear $WORKFLOW"
+original_disk_space_usage_file="$VAR_DIR/layout/config/df.txt"
+rear_shell_history="$( echo -e "cd $VAR_DIR/layout/\nvi $DASD_FORMAT_CODE\nless $RUNTIME_LOGFILE" )"
+wilful_input=""
+
+unset choices
+choices[0]="Rerun DASD format script ($DASD_FORMAT_CODE)"
+choices[1]="View '$rear_workflow' log file ($RUNTIME_LOGFILE)"
+choices[2]="Edit DASD format script ($DASD_FORMAT_CODE)"
+choices[3]="Show what is currently on the disks ('lsdasd' device list)"
+choices[4]="View original disk space usage ($original_disk_space_usage_file)"
+choices[5]="Use Relax-and-Recover shell and return back to here"
+choices[6]="Confirm what is currently on the disks and continue '$rear_workflow'"
+choices[7]="Abort '$rear_workflow'"
+prompt="DASD format choices"
+
+choice=""
+# When USER_INPUT_DASD_FORMAT_CODE_RUN has any 'true' value be liberal in what you accept and
+# assume choices[0] 'Rerun DASD format script' was actually meant
+# regardless that this likely lets 'rear recover' run an endless loop
+# of failed DASD format attempts but ReaR must obey what the user specified
+# (perhaps it is intended to let 'rear recover' loop here until an admin intervenes):
+is_true "$USER_INPUT_DASD_FORMAT_CODE_RUN" && USER_INPUT_DASD_FORMAT_CODE_RUN="${choices[0]}"
+
+unset confirm_choices
+confirm_choices[0]="Confirm recreated DASD format and continue '$rear_workflow'"
+confirm_choices[1]="Go back one step to redo DASD format"
+confirm_choices[2]="Use Relax-and-Recover shell and return back to here"
+confirm_choices[3]="Abort '$rear_workflow'"
+confirm_prompt="Confirm the recreated DASD format or go back one step"
+confirm_choice=""
+# When USER_INPUT_DASD_FORMAT_MIGRATED_CONFIRMATION has any 'true' value be liberal in what you accept and
+# assume confirm_choices[0] 'Confirm recreated DASD format and continue' was actually meant:
+is_true "$USER_INPUT_DASD_FORMAT_MIGRATED_CONFIRMATION" && USER_INPUT_DASD_FORMAT_MIGRATED_CONFIRMATION="${confirm_choices[0]}"
+
+# Run the DASD format code (dasdformat.sh)
+# again and again until it succeeds or the user aborts
+# or the user confirms to continue with what is currently on the disks
+# (the user may have setup manually what he needs via the Relax-and-Recover shell):
+while true ; do
+ prompt="The DASD format had failed"
+ # After switching to recreating with DASD format script
+ # change choices[0] from "Run ..." to "Rerun ...":
+ choices[0]="Rerun DASD format script ($DASD_FORMAT_CODE)"
+ # Run DASD_FORMAT_CODE in a sub-shell because it sets 'set -e'
+ # so that it exits the running shell in case of an error
+ # but that exit must not exit this running bash here:
+ ( source $DASD_FORMAT_CODE )
+ # One must explicitly test whether or not $? is zero in a separated bash command
+ # because with bash 3.x and bash 4.x code like
+ # # ( set -e ; cat qqq ; echo "hello" ) && echo ok || echo failed
+ # cat: qqq: No such file or directory
+ # hello
+ # ok
+ # does not work as one may expect (cf. what "man bash" describes for 'set -e').
+ # There is a subtle behavioural difference between bash 3.x and bash 4.x
+ # when a script that has 'set -e' set gets sourced:
+ # With bash 3.x the 'set -e' inside the sourced script is effective:
+ # # echo 'set -e ; cat qqq ; echo hello' >script.sh
+ # # ( source script.sh ) && echo ok || echo failed
+ # cat: qqq: No such file or directory
+ # failed
+ # With bash 4.x the 'set -e' inside the sourced script gets noneffective:
+ # # echo 'set -e ; cat qqq ; echo hello' >script.sh
+ # # ( source script.sh ) && echo ok || echo failed
+ # cat: qqq: No such file or directory
+ # hello
+ # ok
+ # With bash 3.x and bash 4.x testing $? in a separated bash command
+ # keeps the 'set -e' inside the sourced script effective:
+ # # echo 'set -e ; cat qqq ; echo hello' >script.sh
+ # # ( source script.sh ) ; (( $? == 0 )) && echo ok || echo failed
+ # cat: qqq: No such file or directory
+ # failed
+ # See also https://github.com/rear/rear/pull/1573#issuecomment-344303590
+ if (( $? == 0 )) ; then
+ prompt="DASD format had been successful"
+ # When DASD_FORMAT_CODE succeeded and when not in migration mode
+ # break the outer while loop and continue the "rear recover" workflow
+ # which means continue with restoring the backup:
+ is_true "$MIGRATION_MODE" || break
+ # When DASD_FORMAT_CODE succeeded in migration mode
+ # let the user explicitly confirm the recreated (and usually migrated) format
+ # before continuing the "rear recover" workflow with restoring the backup.
+ # Show the recreated DASD format to the user on his terminal (and also in the log file):
+ LogPrint "Recreated DASD format:"
+ lsdasd_output
+ # Run an inner while loop with a user dialog so that the user can inspect the recreated DASD format
+ # and perhaps even manually fix the recreated DASD format if it is not what the user wants
+ # (e.g. by using the Relax-and-Recover shell and returning back to this user dialog):
+ while true ; do
+ confirm_choice="$( UserInput -I DASD_FORMAT_MIGRATED_CONFIRMATION -p "$confirm_prompt" -D "${confirm_choices[0]}" "${confirm_choices[@]}" )" && wilful_input="yes" || wilful_input="no"
+ case "$confirm_choice" in
+ (${confirm_choices[0]})
+ # Confirm recreated DASD format and continue:
+ is_true "$wilful_input" && LogPrint "User confirmed recreated DASD format" || LogPrint "Continuing with recreated DASD format by default"
+ # Break the outer while loop and continue with restoring the backup:
+ break 2
+ ;;
+ (${confirm_choices[1]})
+ # Go back one step to redo DASD format:
+ # Only break the inner while loop (i.e. this user dialog loop)
+ # and continue with the next user dialog below:
+ break
+ ;;
+ (${confirm_choices[2]})
+ # rear_shell runs 'bash' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
+ rear_shell "" "$rear_shell_history"
+ ;;
+ (${confirm_choices[3]})
+ abort_dasd_format
+ Error "User did not confirm the recreated DASD format but aborted '$rear_workflow' in ${BASH_SOURCE[0]}"
+ ;;
+ esac
+ done
+ fi
+ # Run an inner while loop with a user dialog so that the user can fix things
+ # when DASD_FORMAT_CODE failed.
+ # Such a fix does not necessarily mean the user must change
+ # the dasdformat.sh script when DASD_FORMAT_CODE failed.
+ # The user might also fix things by only using the Relax-and-Recover shell and
+ # then confirm what is on the disks and continue with restoring the backup
+ # or abort this "rear recover" run to re-try from scratch.
+ while true ; do
+ choice="$( UserInput -I DASD_FORMAT_CODE_RUN -p "$prompt" -D "${choices[0]}" "${choices[@]}" )" && wilful_input="yes" || wilful_input="no"
+ case "$choice" in
+ (${choices[0]})
+ # Rerun or run (after switching to recreating with DASD format script) DASD format script:
+ is_true "$wilful_input" && LogPrint "User runs DASD format script" || LogPrint "Running DASD format script by default"
+ # Only break the inner while loop (i.e. the user dialog loop):
+ break
+ ;;
+ (${choices[1]})
+ # Run 'less' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
+ less $RUNTIME_LOGFILE 0<&6 1>&7 2>&8
+ ;;
+ (${choices[2]})
+ # Run 'vi' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
+ vi $DASD_FORMAT_CODE 0<&6 1>&7 2>&8
+ ;;
+ (${choices[3]})
+ LogPrint "This is the current list of DASDs:"
+ lsdasd_output
+ ;;
+ (${choices[4]})
+ # Run 'less' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
+ less $original_disk_space_usage_file 0<&6 1>&7 2>&8
+ ;;
+ (${choices[5]})
+ # rear_shell runs 'bash' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user:
+ rear_shell "" "$rear_shell_history"
+ ;;
+ (${choices[6]})
+ # Confirm what is on the disks and continue:
+ # Break the outer while loop and continue with restoring the backup:
+ break 2
+ ;;
+ (${choices[7]})
+ abort_dasd_format
+ Error "User chose to abort '$rear_workflow' in ${BASH_SOURCE[0]}"
+ ;;
+ esac
+ done
+# End of the outer while loop:
+done
+
+# Local functions must be 'unset' because bash does not support 'local function ...'
+# cf. https://unix.stackexchange.com/questions/104755/how-can-i-create-a-local-function-in-my-bashrc
+unset -f lsdasd_output
diff --git a/usr/share/rear/layout/prepare/default/010_prepare_files.sh b/usr/share/rear/layout/prepare/default/010_prepare_files.sh
index 7a980e63..4191be33 100644
--- a/usr/share/rear/layout/prepare/default/010_prepare_files.sh
+++ b/usr/share/rear/layout/prepare/default/010_prepare_files.sh
@@ -7,6 +7,8 @@ LAYOUT_CODE="$VAR_DIR/layout/diskrestore.sh"
LAYOUT_XFS_OPT_DIR="$VAR_DIR/layout/xfs"
LAYOUT_XFS_OPT_DIR_RESTORE="$LAYOUT_XFS_OPT_DIR/restore"
+DASD_FORMAT_CODE="$VAR_DIR/layout/dasdformat.sh"
+
FS_UUID_MAP="$VAR_DIR/layout/fs_uuid_mapping"
LUN_WWID_MAP="$VAR_DIR/layout/lun_wwid_mapping"
diff --git a/usr/share/rear/layout/prepare/default/250_compare_disks.sh b/usr/share/rear/layout/prepare/default/250_compare_disks.sh
index c459b928..751433ba 100644
--- a/usr/share/rear/layout/prepare/default/250_compare_disks.sh
+++ b/usr/share/rear/layout/prepare/default/250_compare_disks.sh
@@ -54,7 +54,9 @@ local more_than_one_same_orig_size=''
# Cf. the "Compare disks one by one" code below:
while read disk dev size junk ; do
if IsInArray "$size" "${original_system_used_disk_sizes[@]}" ; then
- more_than_one_same_orig_size='true'
+ if ! has_mapping_hint "$dev" ; then
+ more_than_one_same_orig_size='true'
+ fi
else
original_system_used_disk_sizes+=( "$size" )
fi
@@ -109,14 +111,17 @@ fi
# No further disk comparisons are needed when MIGRATION_MODE is already set true above:
if ! is_true "$MIGRATION_MODE" ; then
# Compare original disks and their possible target disk one by one:
- while read disk dev size junk ; do
- dev=$( get_sysfs_name $dev )
+ while read disk devnode size junk ; do
+ dev=$( get_sysfs_name $devnode )
Log "Comparing $dev"
if test -e "/sys/block/$dev" ; then
Log "Device /sys/block/$dev exists"
newsize=$( get_disk_size $dev )
if test "$newsize" -eq "$size" ; then
LogPrint "Device $dev has expected (same) size $size bytes (will be used for '$WORKFLOW')"
+ elif test "$( get_mapping_hint $devnode )" == "$devnode" ; then
+ Debug "Found identical mapping hint ${devnode} -> ${devnode}"
+ LogPrint "Device $dev found according to mapping hints (will be used for '$WORKFLOW')"
else
LogPrint "Device $dev has size $newsize bytes but $size bytes is expected (needs manual configuration)"
MIGRATION_MODE='true'
diff --git a/usr/share/rear/layout/prepare/default/300_map_disks.sh b/usr/share/rear/layout/prepare/default/300_map_disks.sh
index 2e90768c..468aa35c 100644
--- a/usr/share/rear/layout/prepare/default/300_map_disks.sh
+++ b/usr/share/rear/layout/prepare/default/300_map_disks.sh
@@ -112,7 +112,14 @@ while read keyword orig_device orig_size junk ; do
# Continue with next original device when it is already used as source in the mapping file:
is_mapping_source "$orig_device" && continue
# First, try to find if there is a current disk with same name and same size as the original:
- sysfs_device_name="$( get_sysfs_name "$orig_device" )"
+ # (possibly influenced by mapping hints if known)
+ if has_mapping_hint "$orig_device" ; then
+ candidate_target_device_name="$( get_mapping_hint "$orig_device" )"
+ Debug "Using mapping hint ${candidate_target_device_name} as candidate for $orig_device mapping"
+ else
+ candidate_target_device_name="$orig_device"
+ fi
+ sysfs_device_name="$( get_sysfs_name "$candidate_target_device_name" )"
current_device="/sys/block/$sysfs_device_name"
if test -e $current_device ; then
current_size=$( get_disk_size $sysfs_device_name )
@@ -122,11 +129,16 @@ while read keyword orig_device orig_size junk ; do
# Continue with next one if the current one is already used as target in the mapping file:
is_mapping_target "$preferred_target_device_name" && continue
# Use the current one if it is of same size as the old one:
- if test "$orig_size" -eq "$current_size" ; then
+ if has_mapping_hint "$orig_device" || test "$orig_size" -eq "$current_size" ; then
# Ensure the determined target device is really a block device:
if test -b "$preferred_target_device_name" ; then
+ if has_mapping_hint "$orig_device" ; then
+ mapping_reason="determined by mapping hint"
+ else
+ mapping_reason="same name and same size $current_size"
+ fi
add_mapping "$orig_device" "$preferred_target_device_name"
- LogPrint "Using $preferred_target_device_name (same name and same size) for recreating $orig_device"
+ LogPrint "Using $preferred_target_device_name ($mapping_reason) for recreating $orig_device"
# Continue with next original device in the LAYOUT_FILE:
continue
fi
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 3ab7357d..da6ce64c 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
@@ -362,18 +362,27 @@ Log "Saving disk partitions."
if [[ $blockd == dasd* && "$ARCH" == "Linux-s390" ]] ; then
devname=$(get_device_name $disk)
+ dasdnum=$( lsdasd | awk "\$3 == \"$blockd\" { print \$1}" )
+ dasdstatus=$( lsdasd | awk "\$3 == \"$blockd\" { print \$2}" )
+ # ECKD or FBA
+ dasdtype=$( lsdasd | awk "\$3 == \"$blockd\" { print \$5}" )
+ if [ "$dasdtype" != ECKD ] && [ "$dasdtype" != FBA ]; then
+ LogPrint "Type $dasdtype of DASD $blockd unexpected: neither ECKD nor FBA"
+ fi
- echo "# active dasd bus and channel"
- echo "# bus-id <name device> type"
- echo "dasd_channel $( lsdasd|grep $blockd|awk '{ print $1 " " $2 " " $3 " " $4}' )"
-
- echo "# dasdfmt - disk layout is either cdl for the compatible disk layout (default) or ldl"
- echo "# example usage: dasdfmt -b 4096 -d cdl -y /dev/dasda"
- layout=$(dasdview -x /dev/$blockd|grep "^format"|awk '{print $7}')
- blocksize=$( dasdview -i /dev/$blockd|grep blocksize|awk '{print $6}' )
- echo "# dasdfmt $devname"
- echo "# dasdfmt -b <blocksize> -d <layout> -y <devname>"
- echo "dasdfmt -b $blocksize -d $layout -y $devname"
+ echo "# every DASD bus and channel"
+ echo "# Format: dasd_channel <bus-id> <device name>"
+ echo "dasd_channel $dasdnum $blockd"
+
+ # We need to print the dasd_channel line even for ignored devices,
+ # otherwise we could have naming gaps and naming would change when
+ # recreating layout.
+ # E.g. if dasda is ignored, and dasdb is not, we would create only dasdb
+ # during recreation, but it would be named dasda.
+ if [ "$dasdstatus" != active ]; then
+ Log "Ignoring $blockd: it is not active (Status is $dasdstatus)"
+ continue
+ fi
fi
#FIXME: exclude *rpmb (Replay Protected Memory Block) for nvme*, mmcblk* and uas
@@ -387,11 +396,38 @@ Log "Saving disk partitions."
devname=$(get_device_name $disk)
devsize=$(get_disk_size ${disk#/sys/block/})
disktype=$(parted -s $devname print | grep -E "Partition Table|Disk label" | cut -d ":" -f "2" | tr -d " ")
-
- echo "# Disk $devname"
- echo "# Format: disk <devname> <size(bytes)> <partition label type>"
- echo "disk $devname $devsize $disktype"
-
+ if [ "$disktype" != "dasd" ]; then
+ echo "# Disk $devname"
+ echo "# Format: disk <devname> <size(bytes)> <partition label type>"
+ echo "disk $devname $devsize $disktype"
+ elif [[ $blockd == dasd* && "$ARCH" == "Linux-s390" ]] ; then
+ layout=$(dasdview -x $devname |grep "^format"|awk '{print $7}')
+ case "$layout" in
+ (NOT)
+ # NOT -> dasdview has printed "NOT formatted"
+ LogPrintError "Ignoring $blockd: it is not formatted"
+ continue
+ ;;
+ (LDL|CDL)
+ ;;
+ (*)
+ BugError "Invalid 'disk $devname' entry (unknown DASD layout $layout)"
+ ;;
+ esac
+ test $disktype || Error "No partition label type for DASD entry 'disk $devname'"
+ blocksize=$( get_block_size "$blockd" )
+ if ! test $blocksize ; then
+ # fallback - ugly method
+ blocksize=$( dasdview -i $devname |grep blocksize|awk '{print $6}' )
+ test $blocksize || Error "Unknown block size of DASD $devname"
+ fi
+ dasdcyls=$( get_dasd_cylinders "$blockd" )
+ echo "# Disk $devname"
+ echo "# Format: disk <devname> <size(bytes)> <partition label type> <logical block size> <DASD layout> <DASD type> <size(cylinders)>"
+ echo "disk $devname $devsize $disktype $blocksize $layout $dasdtype $dasdcyls"
+ else
+ Error "Invalid 'disk $devname' entry (DASD partition label on non-s390 arch $ARCH)"
+ fi
echo "# Partitions on $devname"
echo "# Format: part <device> <partition size(bytes)> <partition start(bytes)> <partition type|name> <flags> /dev/<partition>"
extract_partitions "$devname"
diff --git a/usr/share/rear/lib/layout-functions.sh b/usr/share/rear/lib/layout-functions.sh
index 91c5ff73..4f5b8f6f 100644
--- a/usr/share/rear/lib/layout-functions.sh
+++ b/usr/share/rear/lib/layout-functions.sh
@@ -93,6 +93,12 @@ abort_recreate() {
restore_original_file "$LAYOUT_FILE"
}
+abort_dasd_format() {
+ Log "Error detected during DASD formatting."
+ Log "Restoring saved original $DASD_FORMAT_FILE"
+ restore_original_file "$DASD_FORMAT_FILE"
+}
+
# Test and log if a component $1 (type $2) needs to be recreated.
create_component() {
local device="$1"
@@ -722,6 +728,46 @@ get_block_size() {
fi
}
+# Get the number of cylinders of a DASD.
+# The number of cylinders has the advantage of being fixed - size depends on formatting
+# and number of cylinders is valid even for unformatted DASDs, size is not.
+get_dasd_cylinders() {
+ local disk_name="${1##*/}" # /some/path/dasda -> dasda
+ local dasd_cyls
+
+ dasd_cyls=$(dasdview -i /dev/$disk_name | grep cylinders | cut -d ':' -f2 | awk '{print $4}')
+ ### Make sure we always return a number
+ echo $(( dasd_cyls ))
+}
+
+# Sometimes we know what the new device for the original device should be in a more reliable way
+# than by looking at disk sizes. THis information is called "mapping hints". Let's pass them
+# to the mapping code using the DISK_MAPPING_HINTS array. Each element of the array has the form
+# "/dev/source /dev/target" (space-separated).
+
+# Output the mapping hint for the original device.
+function get_mapping_hint () {
+ local device="$1"
+ local hint mapping_hint_source mapping_hint_target
+
+ for hint in "${DISK_MAPPING_HINTS[@]}"; do
+ mapping_hint_source=${hint%% *}
+ mapping_hint_target=${hint##* }
+ if [ "${device}" == "${mapping_hint_source}" ] ; then
+ echo "$mapping_hint_target"
+ return 0
+ fi
+ done
+ return 1
+}
+
+# Determine if there is a mapping hint for the original device.
+function has_mapping_hint () {
+ local device="$1"
+
+ get_mapping_hint "$device" > /dev/null
+}
+
# Get the UUID of a device.
# Device is something like /dev/sda1.
blkid_uuid_of_device() {

View File

@ -3,7 +3,7 @@
Summary: Relax-and-Recover is a Linux disaster recovery and system migration tool
Name: rear
Version: 2.6
Release: 7%{?dist}
Release: 12%{?dist}
License: GPLv3
Group: Applications/File
URL: http://relax-and-recover.org/
@ -30,6 +30,29 @@ Patch48: rear-bz2111059.patch
Patch49: pxe-rsync-output.patch
Patch50: rear-bz2119501.patch
Patch51: rear-bz2120736.patch
Patch52: rear-bz2091163.patch
Patch53: rear-bz2130945.patch
Patch54: rear-bz2131946.patch
Patch56: s390-no-clobber-disks.patch
Patch58: rear-device-shrinking-bz2223895.patch
Patch59: rear-usb-uefi-part-size-bz2228402.patch
Patch60: rear-luks-key-bz2228779.patch
Patch61: rear-uefi-usb-secureboot-bz2196445.patch
Patch62: rear-vg-command-not-found-bz2121476.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
# 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
### Dependencies on all distributions
BuildRequires: asciidoc
@ -79,6 +102,11 @@ Requires: /usr/sbin/ofpathname
# Needed to make PowerVM LPARs bootable
Requires: /usr/sbin/bootlist
%endif
%ifarch s390x
# Contain many utilities for working with DASDs
Requires: s390utils-base
Requires: s390utils-core
%endif
Requires: crontabs
Requires: iproute
@ -148,6 +176,20 @@ fi
%patch49 -p1
%patch50 -p1
%patch51 -p1
%patch52 -p1
%patch53 -p1
%patch54 -p1
%patch56 -p1
%patch58 -p1
%patch59 -p1
%patch60 -p1
%patch61 -p1
%patch62 -p1
%patch64 -p1
%patch65 -p1
%patch111 -p1
%patch113 -p1
%patch115 -p1
echo "30 1 * * * root test -f /var/lib/rear/layout/disklayout.conf && /usr/sbin/rear checklayout || /usr/sbin/rear mkrescue" >rear.cron
@ -181,6 +223,34 @@ TZ=UTC %{__make} -C doc
%{_sbindir}/rear
%changelog
* Wed Feb 21 2024 Pavel Cahyna <pcahyna@redhat.com> - 2.6-12
- Skip invalid disk drives when saving layout PR 3047
- Support saving and restoring hybrid BIOS/UEFI bootloader, PRs 3145 3136
- make initrd accessible only by root (CVE-2024-23301), PR 3123
- 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"
* Tue Aug 22 2023 Pavel Cahyna <pcahyna@redhat.com> - 2.6-10
- Apply PR 3027 to ensure correct creation of the rescue environment
when a file is shrinking while being read
- Backport PR 2774 to increase USB_UEFI_PART_SIZE to 1024 MiB
- Apply upstream patch for temp dir usage with LUKS to ensure
that during recovery an encrypted disk can be unlocked using a keyfile
- Backport upstream PR 3031: Secure Boot support for OUTPUT=USB
- Correct a mistake done when backporting PR 2691
* Wed Feb 22 2023 Pavel Cahyna <pcahyna@redhat.com> - 2.6-9
- Backport PR2943 to fix s390x dasd formatting
- Require s390utils-{core,base} on s390x
* Sun Jan 15 2023 Pavel Cahyna <pcahyna@redhat.com> - 2.6-8
- Apply PR2903 to protect against colons in pvdisplay output
- Apply PR2873 to fix initrd regeneration on s390x
- Apply PR2431 to migrate XFS configuration files
* Wed Aug 24 2022 Pavel Cahyna <pcahyna@redhat.com> - 2.6-7
- Avoid stderr message about irrelevant broken links
- Changes for NetBackup (NBU) 9.x support