Skip to content
Snippets Groups Projects
Commit 22e4f224 authored by root's avatar root
Browse files

backup-tar: Hardening, avoid leaving files from failed backups

parent 345158ab
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -Eeuo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
...@@ -13,7 +13,7 @@ fail() { ...@@ -13,7 +13,7 @@ fail() {
exit 1 exit 1
} }
if [[ $1 ]]; then if [[ ${1:-} ]]; then
. $1 . $1
[[ $WORK_DIR ]] && mkdir -p $WORK_DIR && cd $WORK_DIR [[ $WORK_DIR ]] && mkdir -p $WORK_DIR && cd $WORK_DIR
else else
...@@ -22,12 +22,13 @@ else ...@@ -22,12 +22,13 @@ else
SOURCES_FILE=$SCRIPT_DIR/sources_$SHORT_HOST SOURCES_FILE=$SCRIPT_DIR/sources_$SHORT_HOST
. $SOURCES_FILE . $SOURCES_FILE
fi fi
[[ $TARGET ]] || fail "TARGET expected to be set in config" [[ ${TARGET:-} ]] || fail "TARGET expected to be set in config"
[[ $SOURCES ]] || fail "SOURCES expected to be set in $SOURCES_FILE or config" [[ ${SOURCES:-} ]] || fail "SOURCES expected to be set in $SOURCES_FILE or config"
TIMESTAMP=$(date +"%Y-%m-%d") TIMESTAMP=$(date +"%Y-%m-%d")
mkdir lock || fail "ERROR: backup already in progress (lock dir exists)" mkdir lock || fail "ERROR: backup already in progress (lock dir exists)"
trap "rmdir lock" EXIT function trap_global { rmdir lock; }
trap trap_global EXIT
get_snars() { find $1/ -type f -name '*.snar' -printf '%f\n' | sort; } get_snars() { find $1/ -type f -name '*.snar' -printf '%f\n' | sort; }
get_type() { get_type() {
...@@ -91,20 +92,28 @@ for SRC in $SOURCES; do ...@@ -91,20 +92,28 @@ for SRC in $SOURCES; do
fi fi
ssh $TARGET "mkdir -p stamps/${SRC_ID} ${SRC_ID}" ssh $TARGET "mkdir -p stamps/${SRC_ID} ${SRC_ID}"
[[ "$TYPE" != "daily" ]] && echo "Backup $SRC ($TYPE)…"
function trap_local {
ssh $TARGET "rm -f $BACKUP_FILE.tmp $INCFILE.tmp"
rm -f $INCFILE_TMP
trap_global
}
trap trap_local EXIT;
echo "Backup $SRC ($TYPE)…"
{ {
{ {
tar --create --xattrs --acls --listed-incremental=$INCFILE_TMP $SRC | \ tar --create --xattrs --acls --listed-incremental=$INCFILE_TMP $SRC | \
xz -T$COMPRESS_THRS -3 | \ xz -T$COMPRESS_THRS -3 | \
ssh $TARGET "umask 0027; cat > $BACKUP_FILE" ssh $TARGET "umask 0027; cat > $BACKUP_FILE.tmp"
} 3>&1 1>&2 2>&3 | \ } 3>&1 1>&2 2>&3 | \
{ grep -v "Removing leading \`/'" || true; } | \ { grep -v "Removing leading \`/'" || true; } | \
{ grep -v "socket ignored" || true; } { grep -v "socket ignored" || true; }
} 3>&1 1>&2 2>&3 } 3>&1 1>&2 2>&3
xz -T$COMPRESS_THRS --keep --stdout $INCFILE_TMP | ssh $TARGET "umask 0027; cat > $INCFILE_TGT" xz -T$COMPRESS_THRS --keep --stdout $INCFILE_TMP | ssh $TARGET "umask 0027; cat > $INCFILE_TGT.tmp"
if echo $SRC | grep -q '^/home'; then if echo $SRC | grep -q '^/home'; then
USR=$(echo $SRC | sed 's|^/home/\([^/]*\).*$|\1|') USR=$(echo $SRC | sed 's|^/home/\([^/]*\).*$|\1|')
ssh $TARGET "setfacl -m 'u:$USR:r' $BACKUP_FILE" ssh $TARGET "setfacl -m 'u:$USR:r' $BACKUP_FILE.tmp"
DIR=$(dirname $BACKUP_FILE) DIR=$(dirname $BACKUP_FILE)
while true; do while true; do
ssh $TARGET "setfacl -m 'u:$USR:rx' $DIR" ssh $TARGET "setfacl -m 'u:$USR:rx' $DIR"
...@@ -112,5 +121,7 @@ for SRC in $SOURCES; do ...@@ -112,5 +121,7 @@ for SRC in $SOURCES; do
DIR=$(dirname $DIR) DIR=$(dirname $DIR)
done done
fi fi
ssh $TARGET "mv $BACKUP_FILE{.tmp,}; mv $INCFILE_TGT{.tmp,}"
trap trap_global EXIT
mv $INCFILE_TMP $INCFILE mv $INCFILE_TMP $INCFILE
done done
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment