]> arthur.barton.de Git - backup-script.git/blobdiff - bin/backup-script
Introduce internal "sys_root" variable
[backup-script.git] / bin / backup-script
index f19992ef8eef656c57979586bda712bd44b29bdb..df719d3fe314731408efdc142c10967d4a0069d5 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 #
 # backup-script system for cloning systems using rsync
-# Copyright (c)2008-2013 Alexander Barton, alex@barton.de
+# Copyright (c)2008-2015 Alexander Barton <alex@barton.de>
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -11,7 +11,6 @@
 #
 
 NAME=`basename $0`
-CONF_D="/etc/backup-script.d"
 PIDFILE="/var/run/$NAME.pid"
 
 DRYRUN=0
@@ -27,6 +26,7 @@ declare -i count_ok_vanished=0
 destinations=""
 
 # Default settings, can be overwritten in backup-script.conf:
+conf_d="/etc/backup-script.d"
 pre_exec=""
 post_exec=""
 default_target=""
@@ -38,12 +38,14 @@ default_compress=1
 default_ping=1
 default_local=0
 default_generations=0
+default_job_pre_exec=""
+default_job_post_exec=""
 
 Usage() {
        echo "Usage: $NAME [<options>] [<system> [<system> [...]]]"
        echo
        echo "  -p, --progress    Show progress, see rsync(1)."
-       echo "  -d, --dry-run     Test run only, don't copy any data."
+       echo "  -n, --dry-run     Test run only, don't copy any data."
        echo
        echo "When no <system> is given, all defined systems are used."
        echo
@@ -72,6 +74,27 @@ GotSignal() {
        exit 9
 }
 
+ExecJob() {
+       what="$1"
+       cmd="$2"
+
+       echo "Running job ${what}-exec command ..."
+       [ "$local" -eq 0 ] \
+               && cmd="$ssh_cmd ${user}@${system} $cmd"
+       echo -n "Start date (${what}-exec): "; date
+       echo "$cmd"
+       if [ "$DRYRUN" -eq 0 ]; then
+               $SHELL -c "$cmd"; ret=$?
+       else
+               echo " *** Trial run, not executing ${what}-exec command!"
+               ret=0
+       fi
+       [ $ret -eq 0 ] \
+               && echo "The ${what}-exec command completed with status 0, OK." \
+               || echo "The ${what}-exec command completed with ERRORS, code $ret!"
+       return $ret
+}
+
 while [ $# -gt 0 ]; do
        case "$1" in
          "-n"|"--dry-run")
@@ -88,25 +111,30 @@ while [ $# -gt 0 ]; do
        esac
 done
 
+trap GotSignal SIGINT
+
+echo -n "Started: "; date
+
+for conf in "/etc/backup-script.conf" "${conf_d}/backup-script.conf"; do
+       if [ -r "$conf" ]; then
+               echo "Reading configuration: \"$conf\" ..."
+               source "$conf"
+       fi
+done
+echo
+
 if [ $# -ge 1 ]; then
        for s in $@; do
-               if [ ! -r "${CONF_D}/$s" ]; then
-                       echo "$NAME: Can' read \"${CONF_D}/$s\"!"
+               if [ ! -r "${conf_d}/$s" ]; then
+                       echo "$NAME: Can' read \"${conf_d}/$s\"!"
                        exit 1
                fi
-               sys="$sys ${CONF_D}/$s"
+               sys="$sys ${conf_d}/$s"
        done
 else
-       sys=${CONF_D}/*
+       sys=${conf_d}/*
 fi
 
-trap GotSignal SIGINT
-
-echo -n "Started: "; date
-echo
-
-[ -r "${CONF_D}/backup-script.conf" ] && source "${CONF_D}/backup-script.conf"
-
 # check and create PID file
 if [ -e "$PIDFILE" ]; then
        echo "Lockfile \"$PIDFILE\" already exists."
@@ -158,6 +186,8 @@ for f in $sys; do
        ping="$default_ping"
        local="$default_local"
        generations="$default_generations"
+       job_pre_exec="$default_job_pre_exec"
+       job_post_exec="$default_job_post_exec"
 
        # Read in system configuration file
        source "$f"
@@ -170,7 +200,7 @@ for f in $sys; do
                || systxt="\"$fname\" [\"$system\"]"
        [ "$local" -eq 0 ] \
                && echo "Working on $systxt ..." \
-               || echo "Working on $sytxts (local system) ..."
+               || echo "Working on $systxt (local system) ..."
 
        count_all=$count_all+1
 
@@ -184,12 +214,13 @@ for f in $sys; do
                echo; continue
        fi
 
-       sys_target="$target/$system"
+       sys_target="$target/$fname"
+       sys_root="$sys_target"
        if [ "$DRYRUN" -eq 0 ]; then
                mkdir -p "$sys_target" >/dev/null 2>&1
                if [ $? -ne 0 ]; then
                        echo "Can't create \"$sys_target\"!? \"$system\" skipped!"
-                       echo continue
+                       echo; continue
                fi
        fi
 
@@ -264,6 +295,17 @@ for f in $sys; do
        ssh_cmd="ssh"
        [ -n "$ssh_args_add" ] && ssh_cmd="$ssh_cmd $ssh_args_add"
 
+       # execute job "pre-exec" command, if any
+       if [ -n "$job_pre_exec" ]; then
+               ExecJob pre "$job_pre_exec" ; ret=$?
+               if [ $ret -ne 0 ]; then
+                       [ $ret -ne 99 ] && count_started=$count_started+1
+                       echo "Pre-exec command failed, \"$system\" skipped!"
+                       echo; continue
+               fi
+       fi
+
+       # prepare (remote) command ...
        cmd="rsync --archive"
        [ "$compress" -ne 0 ] && cmd="$cmd --compress"
        cmd="$cmd --rsh=\"$ssh_cmd\" --delete --delete-excluded --sparse"
@@ -283,6 +325,7 @@ for f in $sys; do
        echo -n "Start date: "; date
        echo "$cmd"
        count_started=$count_started+1
+       ok=0
        
        if [ "$DRYRUN" -eq 0 ]; then
                rm -f "$sys_target/.stamp"
@@ -305,10 +348,47 @@ for f in $sys; do
 
                echo "System \"$system\" completed with status $ret, OK."
                [ "$DRYRUN" -gt 0 ] || count_ok=$count_ok+1
+               ok=1
        else
                echo "System \"$system\" completed with ERRORS, code $ret!"
        fi
 
+       # execute job "post-exec" command, if any
+       if [ -n "$job_post_exec" ]; then
+               ExecJob post "$job_post_exec"
+       fi
+
+       if [ $generations -gt 0 ]; then
+               # Clean up old generations
+               to_delete=`ls -1t "$sys_root" 2>/dev/null | tail -n+$generations | sort`
+               if [ -n "$to_delete" -a $ok -eq 1 ]; then
+                       [ "$DRYRUN" -eq 0 ] \
+                               && echo "Deleting old backup generations:" \
+                               || echo " *** Trial run, not deleting old generations:"
+                       for delete in $to_delete; do
+                               dir="$sys_root/$delete"
+                               if [ ! -e "$dir/.stamp" ]; then
+                                       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`
+                               echo "Removing backup from" $last "..."
+                               if [ "$DRYRUN" -eq 0 ]; then
+                                       btrfs subvolume delete \
+                                        "$dir" >/dev/null 2>&1
+                                       [ $? -eq 0 ] || \
+                                        echo "Failed to delete \"$dir\"!"
+                               fi
+                       done
+                       echo -n "Clean up finished: "; date
+               elif [ -n "$to_delete" ]; then
+                       echo "There have been errors, not cleaning up old generations!"
+               else
+                       echo "Nothing to clean up."
+               fi
+       fi
+
        destinations="$destinations $target"
        echo
 done