Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 25 additions & 15 deletions usr/share/rear/conf/default.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3476,25 +3476,35 @@ readonly BACKUP_RESTORE_MOVE_AWAY_DIRECTORY="$VAR_DIR/moved_away_after_backup_re
# (because such stuff is considered as outdated leftover e.g. from a previous recovery)
# but already existing stuff in the BACKUP_RESTORE_MOVE_AWAY_DIRECTORY that is not
# in the current BACKUP_RESTORE_MOVE_AWAY_FILES list is kept.
# Example:
# Probably stuff in the /var/tmp directory is not needed after a system recovery
# and /etc/udev/rules.d/70-persistent-net.rules is created and maintained
#
# Examples:
#
# Probably stuff in the /var/tmp directory is not needed after a system recovery:
# BACKUP_RESTORE_MOVE_AWAY_FILES+=( /var/tmp )
#
# /etc/udev/rules.d/70-persistent-net.rules is created and maintained
# by systemd/udev (see https://github.com/rear/rear/issues/770):
# BACKUP_RESTORE_MOVE_AWAY_FILES=( /var/tmp /etc/udev/rules.d/70-persistent-net.rules )
# BACKUP_RESTORE_MOVE_AWAY_FILES+=( /etc/udev/rules.d/70-persistent-net.rules )
#
# Move away outdated information from previous boot via GRUB2
# to avoid a possible GRUB2 "error: invalid environment block."
# cf. https://github.com/rear/rear/issues/1828
# Move away outdated information from a previous boot via GRUB2:
# BACKUP_RESTORE_MOVE_AWAY_FILES+=( /boot/grub/grubenv /boot/grub2/grubenv )
# This avoids a possible GRUB2 message "error: invalid environment block."
# which should be harmless because the system should boot nevertheless
# (cf. https://github.com/rear/rear/issues/1828#issuecomment-398717889).
# GRUB2 can use /boot/grub/grubenv or /boot/grub2/grubenv
# to remember a small amount of information from one boot to the next.
# But on a by "rear recover" recreated system there is no such thing
# as a meaningful previous boot (because "rear recover" recreates a system
# by reinstalling it completely from scratch) so that there is no meaningful
# use-case to remember any information from a possible previous boot,
# cf. https://github.com/rear/rear/issues/1828#issuecomment-399050741
# Nevertheless that information from the last boot on the original system
# could be still of interest for the user so that it is not deleted:
BACKUP_RESTORE_MOVE_AWAY_FILES=( /boot/grub/grubenv /boot/grub2/grubenv )
# Because "rear recover" recreates the system by reinstalling it from scratch
# it could cause booting issues when possibly outdated information from a
# previous boot of the original system is still used in the recreated system
# (cf. https://github.com/rear/rear/issues/1828#issuecomment-399050741).
# On the other hand GRUB2 relies on grubenv for certain special stuff.
# For example grubenv may contain essential information,
# such as saved_entry, default or kernelopts.
# So grubenv can be considered as part of the GRUB2 configuration.
# Therefore grubenv should not be moved away by default
# (for details see https://github.com/rear/rear/issues/3578).
#
BACKUP_RESTORE_MOVE_AWAY_FILES=()
####

####
Expand Down
55 changes: 55 additions & 0 deletions usr/share/rear/finalize/Linux-i386/665_set_grubenv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Set up grubenv (GRUB environment block)

function set_grubenv() {
local grubenv_file="$VAR_DIR/recovery/grubenv"

# A non-existing grubenv_file is considered OK because it exists only
# if env_block was set.
if [ ! -f "$grubenv_file" ]; then
return 0
fi

local grub_editenv
if ! grub_editenv=$(get_grub_editenv); then
LogPrintError "Failed to set grubenv: neither grub-editenv nor grub2-editenv was found"
return 1
fi

# Remove grubenv from the restored filesystem before setting variables
local restored_grubenv
for restored_grubenv in /boot/grub2/grubenv /boot/grub/grubenv; do
restored_grubenv="${TARGET_FS_ROOT}${restored_grubenv}"
if [ -f "$restored_grubenv" ]; then
rm "$restored_grubenv"
Log "'$restored_grubenv' was removed"
fi
done
Comment thread
svlv marked this conversation as resolved.

# It is essential to set up the environment block in the reserved btrfs sector
# See https://en.opensuse.org/GRUB#GRUB2_on_btrfs_/boot for more details
chroot "$TARGET_FS_ROOT" /bin/bash -c "\"$grub_editenv\" - unset dummy"

local exit_code=0
local var_value
while IFS= read -r var_value; do
local var="${var_value%=*}"
# env_block is read-only after initialization
if [ "$var" = "env_block" ] ; then
continue
fi
if ! chroot "$TARGET_FS_ROOT" /bin/bash -c "\"$grub_editenv\" - set \"$var_value\""; then
LogPrintError "Failed to set '$var_value' to grubenv"
Comment thread
svlv marked this conversation as resolved.
exit_code=1
fi
done < "$grubenv_file"

if [ $exit_code -eq 0 ]; then
Log "grubenv was set successfully"
fi

return $exit_code
}

if is_grub2_used; then
set_grubenv
fi
40 changes: 40 additions & 0 deletions usr/share/rear/layout/save/default/700_save_grubenv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Save grubenv (GRUB environment block) to $VAR_DIR/recovery/grubenv.
# See https://www.gnu.org/software/grub/manual/grub/html_node/Environment-block.html
# for more details about grubenv.

function list_grubenv() {
local grub_editenv
if ! grub_editenv=$(get_grub_editenv); then
LogPrintError "Failed to list grubenv: neither grub-editenv nor grub2-editenv was found"
return 1
fi

"$grub_editenv" - list
}

# env_block sets the external raw block where GRUB can store environment block.
# See https://www.gnu.org/software/grub/manual/grub/html_node/env_005fblock.html
# for more details about env_block.
function is_fs_envblock_used() {
list_grubenv | grep -q "^env_block="
}

function save_grubenv() {
local grubenv_file="$VAR_DIR/recovery/grubenv"

if ! list_grubenv > "$grubenv_file"; then
LogPrintError "Failed to save grubenv to '$grubenv_file'"
return 1
fi

Log "grubenv was successfully saved to '$grubenv_file'"
return 0
}

# Save grubenv only if Btrfs envblock is used, because the envblock
# located in the Btrfs header is not accessible during recovery. In other cases,
# the envblock is located at /boot/grub/envblock or /boot/grub2/envblock,
# which is backed up and restored as a regular file.
if is_grub2_used && is_fs_envblock_used; then
save_grubenv
fi
44 changes: 44 additions & 0 deletions usr/share/rear/lib/bootloader-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1018,4 +1018,48 @@ function get_sysconfig_bootloader() {
echo "$sysconfig_bootloader"
}

: "${GRUB_EDITENV_PATH:=""}"

function get_grub_editenv() {
# Check cached path first
if [ -n "$GRUB_EDITENV_PATH" ]; then
echo "$GRUB_EDITENV_PATH"
return 0
fi

local grub_editenv_path="type -P grub-editenv || type -P grub2-editenv"

if test "$RECOVERY_MODE"; then
GRUB_EDITENV_PATH="$(chroot "$TARGET_FS_ROOT" /bin/bash -c "$grub_editenv_path")"
else
GRUB_EDITENV_PATH="$($grub_editenv_path)"
fi

if [ -z "$GRUB_EDITENV_PATH" ]; then
return 1
fi

echo "$GRUB_EDITENV_PATH"
}

function is_grub2_used() {
local bootloader_path="$VAR_DIR/recovery/bootloader"

if [ ! -f "$bootloader_path" ]; then
return 1
fi

local used_bootloader
used_bootloader="$( cat "$bootloader_path" )"

case $used_bootloader in
(GRUB2|GRUB2-EFI)
return 0
;;
(*)
return 1
;;
esac
}

# vim: set et ts=4 sw=4