From f4c6bee7ca4ff9931ad8e028f400b9b3884dacec Mon Sep 17 00:00:00 2001
From: root <root@pontos02.fi.muni.cz>
Date: Fri, 17 Apr 2020 10:17:15 +0200
Subject: [PATCH] backup: Per-source backup

---
 backup-tar/backup.sh | 99 ++++++++++++++++++++++++++------------------
 1 file changed, 59 insertions(+), 40 deletions(-)

diff --git a/backup-tar/backup.sh b/backup-tar/backup.sh
index f1dcb72..d7715db 100755
--- a/backup-tar/backup.sh
+++ b/backup-tar/backup.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-set -e
+set -ex
 
 SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
 
@@ -13,58 +13,77 @@ fail() {
     exit 1
 }
 
-TYPE=$1
-[[ "$TYPE" ]] || {
-	if ! ls *.snar >&/dev/null; then
-		TYPE=full
+TARGET=backup-$HOSTNAME@antea
+SOURCES_FILE=$SCRIPT_DIR/sources_$HOSTNAME
+. $SOURCES_FILE
+[[ $SOURCES ]] || fail "SOURCES expected to be set in $SOURCES_FILE"
+TIMESTAMP=$(date +"%Y-%m-%d")
+
+mkdir lock || fail "ERROR: backup already in progress (lock dir exists)"
+trap "rmdir lock" EXIT
+
+get_snars() { find $1/ -type f -name '*.snar' -printf '%f\n' | sort; }
+get_type() {
+    mkdir -p "$1"
+
+	if ! ls $1/*.snar >&/dev/null; then
+		echo full
 	else
-		LAST_FULL=$(date --date=$(ls *.snar | sort | grep full | tail -n1 | sed 's/[.].*$//') +%s)
-		LAST_BIG=$(date --date=$(ls *.snar | sort | grep '\(full\|weekly\)' | tail -n1 | sed 's/[.].*$//') +%s)
+		LAST_FULL=$(date --date=$(get_snars $1 | grep full | tail -n1 | sed 's/[.].*$//') +%s)
+		LAST_BIG=$(date --date=$(get_snars $1 | grep '\(full\|weekly\)' | tail -n1 | sed 's/[.].*$//') +%s)
 		NOW=$(date +%s)
 		# do a full backup every 8 weeks
 		if [[ $(($NOW - $LAST_FULL)) -ge $((3600 * 24 * 7 * 8)) ]]; then
-			TYPE=full
+			echo full
 		elif [[ $(($NOW - $LAST_BIG)) -ge $((3600 * 24 * 7)) ]]; then
-			TYPE=weekly
+			echo weekly
 		else
-			TYPE=daily
+			echo daily
 		fi
 	fi
-	echo "Performing $TYPE backup (autodetected)" >&2
 }
-[[ "$TYPE" = "full" ]] || [[ "$TYPE" = "weekly" ]] || [[ "$TYPE" = "daily" ]] || \
-    fail "usage: $0 [full|weekly|daily]"
 
-TARGET=backup-$HOSTNAME@antea
-LOCAL_HOME_ID=$(stat -c %d /home)
-SOURCES_FILE=$SCRIPT_DIR/sources_$HOSTNAME
-. $SOURCES_FILE
-[[ $SOURCES ]] || fail "SOURCES expected to be set in $SOURCES_FILE"
-TIMESTAMP=$(date +"%Y-%m-%d")
+for SRC in $SOURCES; do
+    SRC_ID=$(echo $SRC | sed 's|^/||')
+    mkdir -p $SRC_ID
 
-BACKUP_FILE=${TIMESTAMP}.${TYPE}.tar.xz
-INCFILE_TGT=stamps/${TIMESTAMP}.${TYPE}.snar.xz
-INCFILE=${TIMESTAMP}.${TYPE}.snar
-INCFILE_TMP=${INCFILE}.tmp
+    TYPE=$(get_type $SRC_ID)
+    [[ "$TYPE" = "full" ]] || [[ "$TYPE" = "weekly" ]] || [[ "$TYPE" = "daily" ]] || \
+        fail "invalid backup type for $SRC: $TYPE"
 
-INC_FILTER="."
-if [[ "$TYPE" = "weekly" ]]; then
-    INC_FILTER='\(full\|weekly\)'
-fi
+    BACKUP_FILE=${SRC_ID}/${TIMESTAMP}.${TYPE}.tar.xz
+    INCFILE_TGT=stamps/${SRC_ID}/${TIMESTAMP}.${TYPE}.snar.xz
+    INCFILE=${SRC_ID}/${TIMESTAMP}.${TYPE}.snar
+    INCFILE_TMP=${INCFILE}.tmp
 
-mkdir lock || fail "ERROR: backup already in progress (lock dir exists)"
-trap "rmdir lock" EXIT
+    [[ -f $INCFILE_TMP ]] && fail "ERROR: backup already in progress (incremental backup file exists)"
 
-[[ -f $INCFILE_TMP ]] && fail "ERROR: backup already in progress (incremental backup file exists)"
-if [[ "$TYPE" != "full" ]]; then
-    LAST=$(ls *.snar | sort | grep $INC_FILTER | tail -n1)
-    if [[ -f "$LAST" ]]; then
-        cp --reflink=auto $LAST $INCFILE_TMP
+    INC_FILTER="."
+    if [[ "$TYPE" = "weekly" ]]; then
+        INC_FILTER='\(full\|weekly\)'
     fi
-fi
 
-ssh $TARGET "mkdir -p stamps"
-tar --create --xattrs --acls --listed-incremental=$INCFILE_TMP $SOURCES | \
-    xz -T$COMPRESS_THRS -3 | ssh $TARGET "cat > $BACKUP_FILE"
-xz -T$COMPRESS_THRS --keep --stdout $INCFILE_TMP | ssh $TARGET "cat > $INCFILE_TGT"
-mv $INCFILE_TMP $INCFILE
+    if [[ "$TYPE" != "full" ]]; then
+        LAST=${SRC_ID}/$(get_snars $SRC_ID | grep $INC_FILTER | tail -n1)
+        if [[ -f "$LAST" ]]; then
+            cp --reflink=auto $LAST $INCFILE_TMP
+        fi
+    fi
+
+    ssh $TARGET "mkdir -p stamps/${SRC_ID} ${SRC_ID}"
+    echo "Backup $SRC ($TYPE)…"
+    tar --create --xattrs --acls --listed-incremental=$INCFILE_TMP $SRC | \
+        xz -T$COMPRESS_THRS -3 | ssh $TARGET "umask 0027; cat > $BACKUP_FILE"
+    xz -T$COMPRESS_THRS --keep --stdout $INCFILE_TMP | ssh $TARGET "umask 0027; cat > $INCFILE_TGT"
+    if echo $SRC | grep -q '^/home'; then
+        USR=$(echo $SRC | sed 's|^/home/\([^/]*\).*$|\1|')
+        ssh $TARGET "setfacl -m 'u:$USR:r' $BACKUP_FILE"
+        DIR=$(dirname $BACKUP_FILE)
+        while true; do
+            ssh $TARGET "setfacl -m 'u:$USR:rx' $DIR"
+            [[ "$DIR" = "." ]] && break
+            DIR=$(dirname $DIR)
+        done
+    fi
+    mv $INCFILE_TMP $INCFILE
+done
-- 
GitLab