#!/bin/bash set -e USAGE="Usage: $0 {backup /dir [user@host:]/dest | restore file.tar.gz}" dnf install -y tar pigz pv openssh-clients &>/dev/null || exit 1 case "${1:?$USAGE}" in backup) SRC="${2:?$USAGE}" DEST="${3:?$USAGE}" NAME="$(basename "$SRC").tar.gz" [ ! -d "$SRC" ] && echo "Error: not a directory: $SRC" && exit 1 du -sh "$SRC"; SIZE=$(du -sb "$SRC" | awk '{print $1}'); LHASH=$(mktemp); trap "rm -f $LHASH" EXIT # tar+pigz stream over ssh, hash both sides in one connection, abort on mismatch # ssh-agent bash -c 'ssh-add ~/keyfile && tar cf - /backup_dir | pv | pigz -1 | ssh root@host "tee /dest/backup_dir.tar.gz | sha256sum"' if [[ "$DEST" == *:* ]]; then H="${DEST%%:*}" D="${DEST#*:}"; echo "→ ${H}:${D}/${NAME}" RHASH=$(tar cf - "$SRC" | pv -s "$SIZE" | pigz -1 | tee >(sha256sum | awk '{print $1}' > "$LHASH") | ssh "$H" "h=\$(tee ${D}/${NAME} | sha256sum | awk '{print \$1}'); echo \$h > ${D}/${NAME}.sha256; echo \$h") L=$(cat "$LHASH"); echo "Local: $L"; echo "Remote: $RHASH" [ "$L" = "$RHASH" ] && echo "Checksum OK" || { echo "CHECKSUM MISMATCH!"; exit 1; } echo "Verify: ssh $H \"sha256sum ${D}/${NAME}\"" # tar+pigz to local file, write .sha256 sidecar next to it # tar cf - /backup_dir | pv | pigz -1 > /tmp/backup_dir.tar.gz && sha256sum /tmp/backup_dir.tar.gz else echo "→ $DEST/$NAME" tar cf - "$SRC" | pv -s "$SIZE" | pigz -1 > "$DEST/$NAME" sha256sum "$DEST/$NAME" | awk '{print $1}' > "$DEST/$NAME.sha256" echo "Checksum: $(cat "$DEST/$NAME.sha256")" echo "Verify: sha256sum $DEST/$NAME" fi ;; restore) FILE="${2:?$USAGE}" [[ "$FILE" == *.tar.gz ]] && [ -f "$FILE" ] || { echo "Error: not a .tar.gz file: $FILE"; exit 1; } echo "$FILE ($(numfmt --to=iec $(stat -c%s "$FILE"))) → $(pwd)" # verify .sha256 sidecar matches archive, then decompress+extract to current dir # sha256sum -c backup_dir.tar.gz.sha256 && pv backup_dir.tar.gz | pigz -d | tar xf - if [ -f "$FILE.sha256" ]; then echo "Verifying..."; EXP=$(cat "$FILE.sha256"); ACT=$(sha256sum "$FILE" | awk '{print $1}') [ "$EXP" = "$ACT" ] && echo "Checksum OK" || { echo "CHECKSUM MISMATCH!"; exit 1; } else echo "Warning: no .sha256 file, skipping verification"; fi pv "$FILE" | pigz -d | tar xf - ;; *) echo "$USAGE"; exit 1 ;; esac echo "Done"