|
|
| @@ -8,14 +8,16 @@ backup) |
| 8 | SRC="${2:?$USAGE}" DEST="${3:?$USAGE}" NAME="$(basename "$SRC").tar.gz" |
8 | SRC="${2:?$USAGE}" DEST="${3:?$USAGE}" NAME="$(basename "$SRC").tar.gz" |
| 9 | [ ! -d "$SRC" ] && echo "Error: not a directory: $SRC" && exit 1 |
9 | [ ! -d "$SRC" ] && echo "Error: not a directory: $SRC" && exit 1 |
| 10 | du -sh "$SRC"; SIZE=$(du -sb "$SRC" | awk '{print $1}'); LHASH=$(mktemp); trap "rm -f $LHASH" EXIT |
10 | du -sh "$SRC"; SIZE=$(du -sb "$SRC" | awk '{print $1}'); LHASH=$(mktemp); trap "rm -f $LHASH" EXIT |
| 11 | # remote: tar+pigz stream over ssh, tee hash both sides |
11 | # tar+pigz stream over ssh, hash both sides in one connection, abort on mismatch |
| |
12 | # ssh-agent bash -c 'ssh-add ~/keyfile && tar cf - /backup_dir | pv | pigz -1 | ssh root@host "tee /dest/backup_dir.tar.gz | sha256sum"' |
| 12 | if [[ "$DEST" == *:* ]]; then |
13 | if [[ "$DEST" == *:* ]]; then |
| 13 | H="${DEST%%:*}" D="${DEST#*:}"; echo "→ ${H}:${D}/${NAME}" |
14 | H="${DEST%%:*}" D="${DEST#*:}"; echo "→ ${H}:${D}/${NAME}" |
| 14 | 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") |
15 | 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") |
| 15 | L=$(cat "$LHASH"); echo "Local: $L"; echo "Remote: $RHASH" |
16 | L=$(cat "$LHASH"); echo "Local: $L"; echo "Remote: $RHASH" |
| 16 | [ "$L" = "$RHASH" ] && echo "Checksum OK" || { echo "CHECKSUM MISMATCH!"; exit 1; } |
17 | [ "$L" = "$RHASH" ] && echo "Checksum OK" || { echo "CHECKSUM MISMATCH!"; exit 1; } |
| 17 | echo "Verify: ssh $H \"sha256sum ${D}/${NAME}\"" |
18 | echo "Verify: ssh $H \"sha256sum ${D}/${NAME}\"" |
| 18 | # local: tar+pigz to file, write .sha256 sidecar |
19 | # tar+pigz to local file, write .sha256 sidecar next to it |
| |
20 | # tar cf - /backup_dir | pv | pigz -1 > /tmp/backup_dir.tar.gz && sha256sum /tmp/backup_dir.tar.gz |
| 19 | else |
21 | else |
| 20 | echo "→ $DEST/$NAME" |
22 | echo "→ $DEST/$NAME" |
| 21 | tar cf - "$SRC" | pv -s "$SIZE" | pigz -1 > "$DEST/$NAME" |
23 | tar cf - "$SRC" | pv -s "$SIZE" | pigz -1 > "$DEST/$NAME" |
| @@ -27,7 +29,8 @@ restore) |
| 27 | FILE="${2:?$USAGE}" |
29 | FILE="${2:?$USAGE}" |
| 28 | [[ "$FILE" == *.tar.gz ]] && [ -f "$FILE" ] || { echo "Error: not a .tar.gz file: $FILE"; exit 1; } |
30 | [[ "$FILE" == *.tar.gz ]] && [ -f "$FILE" ] || { echo "Error: not a .tar.gz file: $FILE"; exit 1; } |
| 29 | echo "$FILE ($(numfmt --to=iec $(stat -c%s "$FILE"))) → $(pwd)" |
31 | echo "$FILE ($(numfmt --to=iec $(stat -c%s "$FILE"))) → $(pwd)" |
| 30 | # verify checksum before extracting |
32 | # verify .sha256 sidecar matches archive, then decompress+extract to current dir |
| |
33 | # sha256sum -c backup_dir.tar.gz.sha256 && pv backup_dir.tar.gz | pigz -d | tar xf - |
| 31 | if [ -f "$FILE.sha256" ]; then |
34 | if [ -f "$FILE.sha256" ]; then |
| 32 | echo "Verifying..."; EXP=$(cat "$FILE.sha256"); ACT=$(sha256sum "$FILE" | awk '{print $1}') |
35 | echo "Verifying..."; EXP=$(cat "$FILE.sha256"); ACT=$(sha256sum "$FILE" | awk '{print $1}') |
| 33 | [ "$EXP" = "$ACT" ] && echo "Checksum OK" || { echo "CHECKSUM MISMATCH!"; exit 1; } |
36 | [ "$EXP" = "$ACT" ] && echo "Checksum OK" || { echo "CHECKSUM MISMATCH!"; exit 1; } |
|