Allow the entire backup run to be halted by an action (Closes: #455836)
[matthijs/upstream/backupninja.git] / src / backupninja.in
index 3bf0ad161e4ab7896d2ad6f504d7c48bd7787c42..75b892af5f4a7b19d2ec23a3cb859d449f4433f4 100755 (executable)
@@ -29,17 +29,18 @@ function setupcolors () {
        RED="\033[31;01m"
        OFF="\033[0m"
        CYAN="\033[36;01m"
-       COLORS=($BLUE $GREEN $YELLOW $RED $PURPLE)
+       COLORS=($BLUE $GREEN $YELLOW $RED $PURPLE $CYAN)
 }
 
 function colorize () {
        if [ "$usecolors" == "yes" ]; then
-               local typestr=`echo "$@" | sed 's/\(^[^:]*\).*$/\1/'`
+               local typestr=`echo "$@" | @SED@ 's/\(^[^:]*\).*$/\1/'`
                [ "$typestr" == "Debug" ] && type=0
                [ "$typestr" == "Info" ] && type=1
                [ "$typestr" == "Warning" ] && type=2
                [ "$typestr" == "Error" ] && type=3
                [ "$typestr" == "Fatal" ] && type=4
+               [ "$typestr" == "Halt" ] && type=5
                color=${COLORS[$type]}
                endcolor=$OFF
                echo -e "$color$@$endcolor"
@@ -54,6 +55,7 @@ function colorize () {
 # 2 - warnings - yellow
 # 3 - errors - red
 # 4 - fatal - purple
+# 5 - halt - cyan
 # First variable passed is the error level, all others are printed
 
 # if 1, echo out all warnings, errors, or fatal
@@ -68,15 +70,16 @@ function printmsg() {
        type=$1
        shift
        if [ $type == 100 ]; then
-               typestr=`echo "$@" | sed 's/\(^[^:]*\).*$/\1/'`
+               typestr=`echo "$@" | @SED@ 's/\(^[^:]*\).*$/\1/'`
                [ "$typestr" == "Debug" ] && type=0
                [ "$typestr" == "Info" ] && type=1
                [ "$typestr" == "Warning" ] && type=2
                [ "$typestr" == "Error" ] && type=3
                [ "$typestr" == "Fatal" ] && type=4
+               [ "$typestr" == "Halt" ] && type=5
                typestr=""
        else
-               types=(Debug Info Warning Error Fatal)
+               types=(Debug Info Warning Error Fatal Halt)
                typestr="${types[$type]}: "
        fi
        
@@ -118,6 +121,10 @@ function fatal() {
        printmsg 4 "$@"
        exit 2
 }
+function halt() {
+       printmsg 5 "$@"
+       exit 2
+}
 
 msgcount=0
 function msg {
@@ -131,32 +138,40 @@ function msg {
 
 function check_perms() {
    local file=$1
+   debug "check_perms $file"
    local perms
-   perms=($(stat -L --format='%a %g %G %u %U' $file))
-   local gperm=${perms[0]:1:1}
-   local wperm=${perms[0]:2:1}
-   local gid=${perms[1]}
-   local group=${perms[2]}
-   local owner=${perms[3]}
+   local owners
+
+   perms=($(stat -L --format='%A' $file))
+   debug "perms: $perms"
+   local gperm=${perms:4:3}
+   debug "gperm: $gperm"
+   local wperm=${perms:7:3}
+   debug "wperm: $wperm"
+
+   owners=($(stat -L --format='%g %G %u %U' $file))
+   local gid=${owners[0]}
+   local group=${owners[1]}
+   local owner=${owners[2]}
 
    if [ "$owner" != 0 ]; then
       echo "Configuration files must be owned by root! Dying on file $file"
       fatal "Configuration files must be owned by root! Dying on file $file"
    fi
    
-   if [ $wperm -gt 0 ]; then
+   if [ "$wperm" != '---' ]; then
       echo "Configuration files must not be world writable/readable! Dying on file $file"
       fatal "Configuration files must not be world writable/readable! Dying on file $file"
    fi
 
-   if [ $gperm -gt 0 ]; then
+   if [ "$gperm" != '---' ]; then
       case "$admingroup" in
          $gid|$group) :;;
 
          *)
            if [ "$gid" != 0 ]; then
-              echo "Configuration files must writable/readable by group ${perms[2]}! Dying on file $file"
-              fatal "Configuration files must writable/readable by group ${perms[2]}! Dying on file $file"
+              echo "Configuration files must not be writable/readable by group $group! Use the admingroup option in backupninja.conf. Dying on file $file"
+              fatal "Configuration files must not be writable/readable by group $group! Use the admingroup option in backupninja.conf. Dying on file $file"
            fi
          ;;
          esac
@@ -170,7 +185,7 @@ function tolower() {
 
 # simple to integer function
 function toint() {
-       echo "$1" | tr -d [:alpha:] 
+       echo "$1" | tr -d '[:alpha:]'
 }
 
 #
@@ -196,7 +211,7 @@ function isnow() {
        whendayofweek=$1; at=$2; whentime=$3;
        whenday=`toint "$whendayofweek"`
        whendayofweek=`tolower "$whendayofweek"`
-       whentime=`echo "$whentime" | sed 's/:[0-9][0-9]$//' | sed -r 's/^([0-9])$/0\1/'`
+       whentime=`echo "$whentime" | @SED@ 's/:[0-9][0-9]$//' | @SED@ -r 's/^([0-9])$/0\1/'`
 
        if [ "$whendayofweek" == "everyday" -o "$whendayofweek" == "daily" ]; then
                whendayofweek=$nowdayofweek
@@ -244,19 +259,20 @@ The following options are available:
                      
 When in debug mode, output to the console will be colored:
 EOF
-       debug=1
-       debug   "Debugging info (when run with -d)"
-       info    "Informational messages (verbosity level 4)"
-       warning "Warnings (verbosity level 3 and up)"
-       error   "Errors (verbosity level 2 and up)"
-       fatal   "Fatal, halting errors (always shown)"
+       usecolors=yes
+       colorize "Debug: Debugging info (when run with -d)"
+       colorize "Info: Informational messages (verbosity level 4)"
+       colorize "Warning: Warnings (verbosity level 3 and up)"
+       colorize "Error: Errors (verbosity level 2 and up)"
+       colorize "Fatal: Errors which halt a given backup action (always shown)"
+       colorize "Halt: Errors which halt the whole backupninja run (always shown)"
 }
 
 ##
 ## this function handles the running of a backup action
 ##
 ## these globals are modified:
-## fatals, errors, warnings, actions_run, errormsg
+## halts, fatals, errors, warnings, actions_run, errormsg
 ##
 
 function process_action() {
@@ -314,10 +330,15 @@ function process_action() {
        _warnings=`cat $bufferfile | grep "^Warning: " | wc -l`
        _errors=`cat $bufferfile | grep "^Error: " | wc -l`
        _fatals=`cat $bufferfile | grep "^Fatal: " | wc -l`
+       _halts=`cat $bufferfile | grep "^Halt: " | wc -l`
        
-       ret=`grep "\(^Warning: \|^Error: \|^Fatal: \)" $bufferfile`
+       ret=`grep "\(^Warning: \|^Error: \|^Fatal: \|Halt: \)" $bufferfile`
        rm $bufferfile
-       if [ $_fatals != 0 ]; then
+       if [ $_halts != 0 ]; then
+               msg "*halt* -- $file"
+               errormsg="$errormsg\n== halt request from $file==\n\n$ret\n"
+               passthru "Halt: <<<< finished action $file: FAILED"
+       elif [ $_fatals != 0 ]; then
                msg "*failed* -- $file"
                errormsg="$errormsg\n== fatal errors from $file ==\n\n$ret\n"
                passthru "Fatal: <<<< finished action $file: FAILED"
@@ -334,6 +355,7 @@ function process_action() {
                info "<<<< finished action $file: SUCCESS"
        fi
 
+       let "halts += _halts"
        let "fatals += _fatals"
        let "errors += _errors"
        let "warnings += _warnings"     
@@ -371,8 +393,8 @@ while [ $# -ge 1 ]; do
                                singlerun=$2
                                processnow=1
                        else
-                               echo "--run option must be fallowed by a backupninja action file"
-                               fatal "--run option must be fallowed by a backupninja action file"
+                               echo "--run option must be followed by a backupninja action file"
+                               fatal "--run option must be followed by a backupninja action file"
                                usage
                        fi
                        shift
@@ -401,7 +423,7 @@ if [ ! -r "$conffile" ]; then
 fi
 
 # find $libdirectory
-libdirectory=`grep '^libdirectory' $conffile | awk '{print $3}'`
+libdirectory=`grep '^libdirectory' $conffile | @AWK@ '{print $3}'`
 if [ -z "$libdirectory" ]; then
         if [ -d "@libdir@" ]; then
           libdirectory="@libdir@"
@@ -425,9 +447,12 @@ setfile $conffile
 # get global config options (second param is the default)
 getconf configdirectory @CFGDIR@/backup.d
 getconf scriptdirectory @datadir@
+getconf reportdirectory
 getconf reportemail
+getconf reporthost
 getconf reportspace
 getconf reportsuccess yes
+getconf reportuser
 getconf reportwarning yes
 getconf loglevel 3
 getconf when "Everyday at 01:00"
@@ -437,11 +462,14 @@ getconf usecolors "yes"
 getconf SLAPCAT /usr/sbin/slapcat
 getconf LDAPSEARCH /usr/bin/ldapsearch
 getconf RDIFFBACKUP /usr/bin/rdiff-backup
+getconf CSTREAM /usr/bin/cstream
+getconf MYSQLADMIN /usr/bin/mysqladmin
 getconf MYSQL /usr/bin/mysql
 getconf MYSQLHOTCOPY /usr/bin/mysqlhotcopy
 getconf MYSQLDUMP /usr/bin/mysqldump
 getconf PGSQLDUMP /usr/bin/pg_dump
 getconf PGSQLDUMPALL /usr/bin/pg_dumpall
+getconf PGSQLUSER postgres
 getconf GZIP /bin/gzip
 getconf RSYNC /usr/bin/rsync
 getconf admingroup root
@@ -468,6 +496,7 @@ fi
 umask 077
 
 # these globals are set by process_action()
+halts=0
 fatals=0
 errors=0
 warnings=0
@@ -486,6 +515,7 @@ fi
 
 for file in $files; do
        [ -f "$file" ] || continue
+       [ "$halts" = "0" ] || continue
 
         check_perms ${file%/*} # check containing dir
        check_perms $file
@@ -530,12 +560,11 @@ if [ $doit == 1 ]; then
                if [ "$reportspace" == "yes" ]; then
                        previous=""
                        for i in $(ls "$configdirectory"); do
-                       backuploc=$(grep ^directory "$configdirectory"/"$i" | awk '{print $3}')
+                       backuploc=$(grep ^directory "$configdirectory"/"$i" | @AWK@ '{print $3}')
                        if [ "$backuploc" != "$previous" ]; then
-                               mountdev=$(mount | grep "$backuploc" | awk '{print $1}')
-                               df -h "$mountdev"
+                               df -h "$backuploc"
                                previous="$backuploc"
-                               fi
+                       fi
                        done
                fi
        } | mail -s "backupninja: $hostname $subject" $reportemail
@@ -543,4 +572,12 @@ fi
 
 if [ $actions_run != 0 ]; then
        info "FINISHED: $actions_run actions run. $fatals fatal. $errors error. $warnings warning."
+       if [ "$halts" != "0" ]; then
+               info "Backup was halted prematurely.  Some actions may not have run."
+       fi
+fi
+
+if [ -n "$reporthost" ]; then
+       debug "send $logfile to $reportuser@$reporthost:$reportdirectory"
+       rsync -qt $logfile $reportuser@$reporthost:$reportdirectory
 fi