| Current Path : /usr/share/rear/backup/NETFS/default/ |
| Current File : //usr/share/rear/backup/NETFS/default/500_make_backup.sh |
# 500_make_backup.sh
#
function set_tar_features {
# Default tar options
TAR_OPTIONS=
# Test for features in tar
# true if at supports the --warning option (v1.23+)
FEATURE_TAR_WARNINGS=
local tar_version=$(get_version tar --version)
if version_newer "$tar_version" 1.23; then
FEATURE_TAR_WARNINGS="y"
TAR_OPTIONS="$TAR_OPTIONS --warning=no-xdev"
fi
FEATURE_TAR_IS_SET=1
}
Log "Include list:"
while read -r ; do
Log " $REPLY"
done < $TMP_DIR/backup-include.txt
Log "Exclude list:"
while read -r ; do
Log " $REPLY"
done < $TMP_DIR/backup-exclude.txt
local scheme=$(url_scheme $BACKUP_URL)
local path=$(url_path $BACKUP_URL)
local opath=$(backup_path $scheme $path)
if [[ "$opath" ]]; then
mkdir -p $v "${opath}" >&2
fi
# Disable BACKUP_PROG_CRYPT_OPTIONS by replacing the default with 'cat' when encryption is disabled
# (by default encryption is disabled but the default BACKUP_PROG_CRYPT_OPTIONS is not 'cat'):
if is_true "$BACKUP_PROG_CRYPT_ENABLED" ; then
# Backup archive encryption is only supported with 'tar':
test "tar" = "$BACKUP_PROG" || Error "Backup archive encryption is only supported with BACKUP_PROG=tar"
LogPrint "Encrypting backup archive with key defined in variable \$BACKUP_PROG_CRYPT_KEY"
else
Log "Encrypting backup archive is disabled"
BACKUP_PROG_CRYPT_OPTIONS="cat"
BACKUP_PROG_CRYPT_KEY=""
fi
# Check if the backup needs to be splitted or not (on multiple ISOs)
if [[ -n "$ISO_MAX_SIZE" ]]; then
# Computation of the real backup maximum size by excluding bootable files size on the first ISO (EFI, kernel, ramdisk)
# Don't use that on max size less than 200MB which would result in too many backups
if [[ $ISO_MAX_SIZE -gt 200 ]]; then
INITRD_SIZE=$(stat -c '%s' $TMP_DIR/$REAR_INITRD_FILENAME)
KERNEL_SIZE=$(stat -c '%s' $KERNEL_FILE)
# We add 15MB which is the average size of all isolinux binaries
BASE_ISO_SIZE=$(((${INITRD_SIZE}+${KERNEL_SIZE})/1024/1024+15))
# If we are EFI, add 30MB (+ previous 15MB), UEFI files can't exceed this size
is_true $USING_UEFI_BOOTLOADER && BASE_ISO_SIZE=$((${BASE_ISO_SIZE}+30))
ISO_MAX_SIZE=$((${ISO_MAX_SIZE}-${BASE_ISO_SIZE}))
fi
SPLIT_COMMAND="split -d -b ${ISO_MAX_SIZE}m - ${backuparchive}."
else
SPLIT_COMMAND="dd of=$backuparchive"
fi
# Used by "tar" method to record which pipe command failed
FAILING_BACKUP_PROG_FILE="$TMP_DIR/failing_backup_prog"
FAILING_BACKUP_PROG_RC_FILE="$TMP_DIR/failing_backup_prog_rc"
LogPrint "Creating $BACKUP_PROG archive '$backuparchive'"
ProgressStart "Preparing archive operation"
(
case "$(basename ${BACKUP_PROG})" in
# tar compatible programs here
(tar)
set_tar_features
Log $BACKUP_PROG $TAR_OPTIONS --sparse --block-number --totals --verbose \
--no-wildcards-match-slash --one-file-system \
--ignore-failed-read "${BACKUP_PROG_OPTIONS[@]}" \
$BACKUP_PROG_CREATE_NEWER_OPTIONS \
${BACKUP_PROG_BLOCKS:+-b $BACKUP_PROG_BLOCKS} "${BACKUP_PROG_COMPRESS_OPTIONS[@]}" \
-X $TMP_DIR/backup-exclude.txt -C / -c -f - \
$(cat $TMP_DIR/backup-include.txt) $RUNTIME_LOGFILE \| $BACKUP_PROG_CRYPT_OPTIONS BACKUP_PROG_CRYPT_KEY \| $SPLIT_COMMAND
# Variable used to record the short name of piped commands in case of
# error, e.g. ( "tar" "cat" "dd" ) in case of unencrypted and unsplit backup.
backup_prog_shortnames=(
"$(basename $(echo "$BACKUP_PROG" | awk '{ print $1 }'))"
"$(basename $(echo "$BACKUP_PROG_CRYPT_OPTIONS" | awk '{ print $1 }'))"
"$(basename $(echo "$SPLIT_COMMAND" | awk '{ print $1 }'))"
)
for index in ${!backup_prog_shortnames[@]} ; do
[ -n "${backup_prog_shortnames[$index]}" ] || BugError "No computed shortname for pipe component $index"
done
$BACKUP_PROG $TAR_OPTIONS --sparse --block-number --totals --verbose \
--no-wildcards-match-slash --one-file-system \
--ignore-failed-read "${BACKUP_PROG_OPTIONS[@]}" \
$BACKUP_PROG_CREATE_NEWER_OPTIONS \
${BACKUP_PROG_BLOCKS:+-b $BACKUP_PROG_BLOCKS} \
"${BACKUP_PROG_COMPRESS_OPTIONS[@]}" \
-X $TMP_DIR/backup-exclude.txt -C / -c -f - \
$(cat $TMP_DIR/backup-include.txt) $RUNTIME_LOGFILE | \
\
$BACKUP_PROG_CRYPT_OPTIONS $BACKUP_PROG_CRYPT_KEY | \
\
$SPLIT_COMMAND
pipes_rc=( ${PIPESTATUS[@]} )
# Exit code logic:
# - never return rc=1 (this is reserved for "tar" warning about modified files)
# - process exit code in pipe's reverse order
# - if last command failed (e.g. "dd"), return an error
# - otherwise if previous command failed (e.g. "encrypt"), return an error
# ...
# - otherwise return "tar" exit code
#
# When an error occurs, record the program name in $FAILING_BACKUP_PROG_FILE
# and real exit code in $FAILING_BACKUP_PROG_RC_FILE.
let index=${#pipes_rc[@]}-1
while [ $index -ge 0 ] ; do
rc=${pipes_rc[$index]}
if [ $rc -ne 0 ] ; then
echo "${backup_prog_shortnames[$index]}" > $FAILING_BACKUP_PROG_FILE
echo "$rc" > $FAILING_BACKUP_PROG_RC_FILE
if [ $rc -eq 1 ] && [ "${backup_prog_shortnames[$index]}" != "tar" ] ; then
rc=2
fi
exit $rc
fi
# This pipe command succeeded, check the previous one
let index--
done
# This was a success
exit 0
;;
(rsync)
# make sure that the target is a directory
mkdir -p $v "$backuparchive" >&2
Log $BACKUP_PROG --verbose "${BACKUP_RSYNC_OPTIONS[@]}" --one-file-system --delete \
--exclude-from=$TMP_DIR/backup-exclude.txt --delete-excluded \
$(cat $TMP_DIR/backup-include.txt) "$backuparchive"
$BACKUP_PROG --verbose "${BACKUP_RSYNC_OPTIONS[@]}" --one-file-system --delete \
--exclude-from=$TMP_DIR/backup-exclude.txt --delete-excluded \
$(cat $TMP_DIR/backup-include.txt) "$backuparchive" >&2
;;
(*)
Log "Using unsupported backup program '$BACKUP_PROG'"
Log $BACKUP_PROG "${BACKUP_PROG_COMPRESS_OPTIONS[@]}" \
$BACKUP_PROG_OPTIONS_CREATE_ARCHIVE $TMP_DIR/backup-exclude.txt \
"${BACKUP_PROG_OPTIONS[@]}" $backuparchive \
$(cat $TMP_DIR/backup-include.txt) $RUNTIME_LOGFILE > $backuparchive
$BACKUP_PROG "${BACKUP_PROG_COMPRESS_OPTIONS[@]}" \
$BACKUP_PROG_OPTIONS_CREATE_ARCHIVE $TMP_DIR/backup-exclude.txt \
"${BACKUP_PROG_OPTIONS[@]}" $backuparchive \
$(cat $TMP_DIR/backup-include.txt) $RUNTIME_LOGFILE > $backuparchive
;;
esac 2> "${TMP_DIR}/${BACKUP_PROG_ARCHIVE}.log"
# important trick: the backup prog is the last in each case entry and the case .. esac is the last command
# in the (..) subshell. As a result the return code of the subshell is the return code of the backup prog!
) &
BackupPID=$!
starttime=$SECONDS
sleep 1 # Give the backup software a good chance to start working
# return disk usage in bytes
function get_disk_used() {
let "$(stat -f -c 'used=(%b-%f)*%S' $1)"
echo $used
}
# While the backup runs in a sub-process, display some progress information to the user.
# ProgressInfo texts have a space at the end to get the 'OK' from ProgressStop shown separated.
test "$PROGRESS_WAIT_SECONDS" || PROGRESS_WAIT_SECONDS=1
case "$( basename $BACKUP_PROG )" in
(tar)
while sleep $PROGRESS_WAIT_SECONDS ; kill -0 $BackupPID 2>/dev/null; do
#blocks="$(stat -c %b ${backuparchive})"
#size="$((blocks*512))"
size="$(stat -c %s ${backuparchive}* | awk '{s+=$1} END {print s}')"
ProgressInfo "Archived $((size/1024/1024)) MiB [avg $((size/1024/(SECONDS-starttime))) KiB/sec] "
done
;;
(rsync)
# since we do not want to do a $(du -s) run every second we count disk usage instead
# this obviously leads to wrong results in case something else is writing to the same
# disk at the same time as is very likely with a networked file system. For local disks
# this should be good enough and in any case this is only some eye candy.
# TODO: Find a fast way to count the actual transfer data, preferrable getting the info from rsync.
let old_disk_used="$(get_disk_used "$backuparchive")"
while sleep $PROGRESS_WAIT_SECONDS ; kill -0 $BackupPID 2>/dev/null; do
let disk_used="$(get_disk_used "$backuparchive")" size=disk_used-old_disk_used
ProgressInfo "Archived $((size/1024/1024)) MiB [avg $((size/1024/(SECONDS-starttime))) KiB/sec] "
done
;;
(*)
while sleep $PROGRESS_WAIT_SECONDS ; kill -0 $BackupPID 2>/dev/null; do
size="$(stat -c "%s" "$backuparchive")" || {
kill -9 $BackupPID
ProgressError
Error "$(basename $BACKUP_PROG) failed to create the archive file"
}
ProgressInfo "Archived $((size/1024/1024)) MiB [avg $((size/1024/(SECONDS-starttime))) KiB/sec] "
done
;;
esac
ProgressStop
transfertime="$((SECONDS-starttime))"
# harvest return code from background job. The kill -0 $BackupPID loop above should
# have made sure that this wait won't do any real "waiting" :-)
wait $BackupPID
backup_prog_rc=$?
if [[ $BACKUP_INTEGRITY_CHECK =~ ^[yY1] && "$(basename ${BACKUP_PROG})" = "tar" ]] ; then
(cd $(dirname $backuparchive) && md5sum $(basename $backuparchive) > ${backuparchive}.md5 || md5sum $(basename $backuparchive).?? > ${backuparchive}.md5)
fi
sleep 1
# everyone should see this warning, even if not verbose
case "$(basename $BACKUP_PROG)" in
(tar)
if (( $backup_prog_rc != 0 )); then
prog="$(cat $FAILING_BACKUP_PROG_FILE)"
if (( $backup_prog_rc == 1 )); then
LogUserOutput "WARNING: $prog ended with return code 1 and below output:
---snip---
$(grep '^tar: ' "${TMP_DIR}/${BACKUP_PROG_ARCHIVE}.log" | sed -e 's/^/ /' | tail -n3)
----------
This means that files have been modified during the archiving
process. As a result the backup may not be completely consistent
or may not be a perfect copy of the system. Relax-and-Recover
will continue, however it is highly advisable to verify the
backup in order to be sure to safely recover this system.
"
else
rc=$(cat $FAILING_BACKUP_PROG_RC_FILE)
Error "$prog failed with return code $rc and below output:
---snip---
$(grep "^$prog: " "${TMP_DIR}/${BACKUP_PROG_ARCHIVE}.log" | sed -e 's/^/ /' | tail -n3)
----------
This means that the archiving process ended prematurely, or did
not even start. As a result it is unlikely you can recover this
system properly. Relax-and-Recover is therefore aborting execution.
"
fi
fi
;;
(*)
if (( $backup_prog_rc > 0 )) ; then
Error "$(basename $BACKUP_PROG) failed with return code $backup_prog_rc
This means that the archiving process ended prematurely, or did
not even start. As a result it is unlikely you can recover this
system properly. Relax-and-Recover is therefore aborting execution.
"
fi
;;
esac
tar_message="$(tac $RUNTIME_LOGFILE | grep -m1 '^Total bytes written: ')"
if [ $backup_prog_rc -eq 0 -a "$tar_message" ] ; then
LogPrint "$tar_message in $transfertime seconds."
elif [ "$size" ]; then
LogPrint "Archived $((size/1024/1024)) MiB in $((transfertime)) seconds [avg $((size/1024/transfertime)) KiB/sec]"
fi
### Copy progress log to backup media
cp $v "${TMP_DIR}/${BACKUP_PROG_ARCHIVE}.log" "${opath}/${BACKUP_PROG_ARCHIVE}.log" >&2
# vim: set et ts=4 sw=4: