]> arthur.barton.de Git - backup-script.git/blobdiff - bin/backup-script
Use correct counter when checking which generations to delete
[backup-script.git] / bin / backup-script
index fb7f7accab90c95f8964a036760d77a7dd1513fd..478e505f9795f9bff02d47990abb8f522bca2449 100755 (executable)
@@ -10,7 +10,7 @@
 # Please read the file COPYING, README and AUTHORS for more information.
 #
 
-NAME=`basename $0`
+NAME=$(basename "$0")
 PIDFILE="/var/run/$NAME.pid"
 
 DRYRUN=0
@@ -29,6 +29,7 @@ destinations=""
 conf_d="/etc/backup-script.d"
 pre_exec=""
 post_exec=""
+default_source_root="/"
 default_target=""
 default_user="root"
 default_ssh_args_add=""
@@ -75,8 +76,8 @@ GotSignal() {
 }
 
 ExecJob() {
-       what="$1"
-       cmd="$2"
+       local what="$1"
+       local cmd="$2"
 
        echo "Running job ${what}-exec command ..."
        [ "$local" -eq 0 ] \
@@ -84,7 +85,7 @@ ExecJob() {
        echo -n "Start date (${what}-exec): "; date
        echo "$cmd"
        if [ "$DRYRUN" -eq 0 ]; then
-               $SHELL -c "$cmd"; ret=$?
+               $SHELL -c "$cmd"; local ret=$?
        else
                echo " *** Trial run, not executing ${what}-exec command!"
                ret=0
@@ -95,6 +96,91 @@ ExecJob() {
        return $ret
 }
 
+GetFS() {
+       local dir="$1"
+
+       while [ -n "$dir" ]; do
+               findmnt -fn -o FSTYPE --raw "$dir" 2>/dev/null; local r=$?
+               if [ $r -eq 0 ]; then
+                       return 0
+               elif [ $r -eq 127 ]; then
+                       echo "UNKNOWN"
+                       return 1
+               fi
+               dir=$(dirname "$dir") || return 1
+       done
+}
+
+CreateSubvolume() {
+       local volume="$1"
+       local fs
+       local dir
+
+       dir=$(dirname "$volume")
+       fs=$(GetFS "$dir")
+       case "$fs" in
+         "btrfs")
+               btrfs subvolume create "$volume"  >/dev/null || return 1
+               ;;
+         *)
+               echo "CreateSubvolume: Incompatible FS type \"$fs\" on \"$dir\"!"
+               return 9
+       esac
+       return 0
+}
+
+CloneSubvolume() {
+       local source="$1"
+       local volume="$2"
+       local dir
+       local fs
+
+       dir=$(dirname "source")
+       fs=$(GetFS "$source")
+       case "$fs" in
+         "btrfs")
+               btrfs subvolume snapshot "$source" "$volume"  >/dev/null || return 1
+               ;;
+         *)
+               echo "CloneSubvolume: Incompatible FS type \"$fs\" on \"$source\"!"
+               return 9
+       esac
+       return 0
+}
+
+RenameSubvolume() {
+       local source="$1"
+       local target="$2"
+       local fs
+
+       fs=$(GetFS "$source")
+       case "$fs" in
+         "btrfs")
+               mv "$source" "$target" || return 1
+               ;;
+         *)
+               echo "RenameSubvolume: Incompatible FS type \"$fs\" on \"$source\"!"
+               return 9
+       esac
+       return 0
+}
+
+DeleteSubvolume() {
+       local volume="$1"
+       local fs
+
+       fs=$(GetFS "$source")
+       case "$fs" in
+         "btrfs")
+               btrfs subvolume delete "$volume" >/dev/null || return 1
+               ;;
+         *)
+               echo "DeleteSubvolume: Incompatible FS type \"$fs\" on \"$volume\"!"
+               return 9
+       esac
+       return 0
+}
+
 while [ $# -gt 0 ]; do
        case "$1" in
          "-n"|"--dry-run")
@@ -124,7 +210,7 @@ done
 echo
 
 if [ $# -ge 1 ]; then
-       for s in $@; do
+       for s in "$@"; do
                if [ ! -r "${conf_d}/$s" ]; then
                        echo "$NAME: Can' read \"${conf_d}/$s\"!"
                        exit 1
@@ -132,7 +218,7 @@ if [ $# -ge 1 ]; then
                sys="$sys ${conf_d}/$s"
        done
 else
-       sys=${conf_d}/*
+       sys="${conf_d}/"*
 fi
 
 # check and create PID file
@@ -168,7 +254,7 @@ fi
 for f in $sys; do
        [ -r "$f" -a -f "$f" ] || continue
 
-       fname=`basename $f`
+       fname=$(basename "$f")
        case "$fname" in
                "backup-script.conf"|*.sh)
                        continue
@@ -178,6 +264,7 @@ for f in $sys; do
        # Set global defaults
        system="$fname"
        user="$default_user"
+       source_root="$default_source_root"
        target="$default_target"
        ssh_args_add="$default_ssh_args_add"
        rsync_args_add="$default_rsync_args_add"
@@ -244,20 +331,19 @@ for f in $sys; do
                fi
 
                # Search directory of last generation, if any
-               last="`ls -1 "$sys_target" 2>/dev/null | sort -r | head -n1`"
+               last=$(ls -1d "$sys_target"/[0-9]* 2>/dev/null | sort -r | head -n1)
                if [ -n "$last" ]; then
-                       last="$sys_target/$last"
                        if [ ! -d "$last" ]; then
                                echo "Last snapshot \"$last\" seems not to be a directory!? \"$system\" skipped!"
                                echo; continue
                        fi
                fi
-               sys_target="$sys_target/`date +%Y%m%d-%H%M%S`"
+               sys_target="$sys_target/$(date +%Y%m%d-%H%M%S)"
 
                if [ -n "$last" -a ! -e "$last/.stamp" ]; then
                        # Old backup directory without "stamp file", continue
                        echo "Found incomplete snapshot in \"$last\", reusing and renaming it ..."
-                       mv "$last" "$sys_target" >/dev/null 2>&1
+                       RenameSubvolume "$last" "$sys_target"
                        if [ $? -ne 0 ]; then
                                echo "Failed to rename last snapshot \"$last\" to \"$sys_target\"!? \"$system\" skipped!"
                                echo; continue
@@ -266,10 +352,9 @@ for f in $sys; do
                        # Old backup directory found, create new snapshot
                        echo "Found last snapshot in \"$last\"."
                        if [ "$DRYRUN" -eq 0 ]; then
-                               btrfs subvolume snapshot \
-                                 "$last" "$sys_target" >/dev/null 2>&1; r=$?
+                               CloneSubvolume "$last" "$sys_target"; r=$?
                                if [ $r -ne 0 ]; then
-                                       echo "Can't create btrfs snapshot \"$sys_target\" of \"$last\", code $r!? \"$system\" skipped!"
+                                       echo "Can't create snapshot \"$sys_target\" of \"$last\", code $r!? \"$system\" skipped!"
                                        echo; continue
                                fi
                                echo "Created new snapshot in \"$sys_target\"."
@@ -279,10 +364,9 @@ for f in $sys; do
                else
                        # No old backup found, create new subvolume
                        if [ "$DRYRUN" -eq 0 ]; then
-                               btrfs subvolume create \
-                                 "$sys_target" >/dev/null 2>&1; r=$?
+                               CreateSubvolume "$sys_target"; r=$?
                                if [ $r -ne 0 ]; then
-                                       echo "Can't create btrfs subvolume \"$sys_target\", code $r!? \"$system\" skipped!"
+                                       echo "Can't create subvolume \"$sys_target\", code $r!? \"$system\" skipped!"
                                        echo; continue
                                fi
                                echo "Created new subvolume in \"$sys_target\"."
@@ -308,25 +392,28 @@ for f in $sys; do
        # prepare (remote) command ...
        cmd="rsync --archive"
        [ "$compress" -ne 0 ] && cmd="$cmd --compress"
-       cmd="$cmd --rsh=\"$ssh_cmd\" --delete --delete-excluded --sparse"
+       [ "$local" -eq 0 ] && cmd="$cmd --rsh=\"$ssh_cmd\""
+       cmd="$cmd --delete --delete-excluded --sparse"
        [ "$VERBOSE" -gt 0 ] && cmd="$cmd --progress"
-       cmd="$cmd --exclude=/dev --exclude=/proc --exclude=/sys"
-       cmd="$cmd --exclude=/run --exclude=/tmp --exclude=/var/tmp"
-       cmd="$cmd --exclude=/media --exclude=/mnt --exclude=/net"
-       cmd="$cmd --exclude=/var/cache/apt --exclude=/var/log"
+       if [ "$source_root" = "$default_source_root" ]; then
+               cmd="$cmd --exclude=/dev --exclude=/proc --exclude=/sys"
+               cmd="$cmd --exclude=/run --exclude=/tmp --exclude=/var/tmp"
+               cmd="$cmd --exclude=/media --exclude=/mnt --exclude=/net"
+               cmd="$cmd --exclude=/var/cache/apt --exclude=/var/log"
+       fi
        [ -n "$exclude_args_add" ] && cmd="$cmd $exclude_args_add"
        [ -n "$rsync_args_add" ] && cmd="$cmd $rsync_args_add"
 
        [ "$local" -eq 0 ] \
-               && cmd="$cmd ${user}@${system}:/ $sys_target/" \
-               || cmd="$cmd / $sys_target/"
+               && cmd="$cmd ${user}@${system}:$source_root $sys_target/" \
+               || cmd="$cmd $source_root $sys_target/"
 
        echo "Backing up to \"$sys_target\" ..."
        echo -n "Start date: "; date
        echo "$cmd"
        count_started=$count_started+1
        ok=0
-       
+
        if [ "$DRYRUN" -eq 0 ]; then
                rm -f "$sys_target/.stamp"
                $SHELL -c "$cmd"; ret=$?
@@ -365,10 +452,11 @@ for f in $sys; do
                        ln -s "$sys_target" "$sys_root/latest"
                fi
                # Clean up old generations
-               to_delete=`ls -1t "$sys_root" 2>/dev/null | tail -n+$generations | sort`
+               declare -i gen_count=$generations+2
+               to_delete=$(ls -1t "$sys_root" 2>/dev/null | tail -n+$gen_count | sort)
                if [ -n "$to_delete" -a $ok -eq 1 ]; then
                        [ "$DRYRUN" -eq 0 ] \
-                               && echo "Deleting old backup generations:" \
+                               && echo "Deleting old backup generations (keep $generations) ..." \
                                || echo " *** Trial run, not deleting old generations:"
                        for delete in $to_delete; do
                                dir="$sys_root/$delete"
@@ -376,14 +464,13 @@ for f in $sys; do
                                        echo "Not deleting \"$dir\", not a backup directory!?"
                                        continue
                                fi
-                               last=`stat "$dir/.stamp" 2>/dev/null | grep "^Modify: " \
-                                | cut -d':' -f2- | cut -d. -f1`
+                               last=$(stat "$dir/.stamp" 2>/dev/null | grep "^Modify: " \
+                                | cut -d':' -f2- | cut -d. -f1)
                                echo "Removing backup from" $last "..."
                                if [ "$DRYRUN" -eq 0 ]; then
-                                       btrfs subvolume delete \
-                                        "$dir" >/dev/null 2>&1
+                                       DeleteSubvolume "$dir"
                                        [ $? -eq 0 ] || \
-                                        echo "Failed to delete \"$dir\"!"
+                                         echo "Failed to delete \"$dir\"!"
                                fi
                        done
                        echo -n "Clean up finished: "; date