fix cstream definition
[matthijs/upstream/backupninja.git] / src / backupninja.in
index 31b8d1b10545c3147bafbf74f66f8de545fd0b3f..7fa6fb11e0b180a95ede816c1178075afa71d1e3 100755 (executable)
@@ -1,4 +1,6 @@
 #!@BASH@
+# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
+#
 #                          |\_
 # B A C K U P N I N J A   /()/
 #                         `\|
@@ -19,7 +21,7 @@
 #####################################################
 ## FUNCTIONS
 
-setupcolors () {
+function setupcolors () {
        BLUE="\033[34;01m"
        GREEN="\033[32;01m"
        YELLOW="\033[33;01m"
@@ -27,18 +29,20 @@ setupcolors () {
        RED="\033[31;01m"
        OFF="\033[0m"
        CYAN="\033[36;01m"
+       COLORS=($BLUE $GREEN $YELLOW $RED $PURPLE)
 }
 
-colorize () {
+function colorize () {
        if [ "$usecolors" == "yes" ]; then
-               local typestr=`echo "$@" | sed 's/\(^[^:]*\).*$/\1/'`
-               [ "$typestr" == "Debug" ] && COLOR=$BLUE
-               [ "$typestr" == "Info" ] && COLOR=$GREEN
-               [ "$typestr" == "Warning" ] && COLOR=$YELLOW
-               [ "$typestr" == "Error" ] && COLOR=$RED
-               [ "$typestr" == "Fatal" ] && COLOR=$PURPLE
+               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
+               color=${COLORS[$type]}
                endcolor=$OFF
-               echo -e "$COLOR$@$endcolor"
+               echo -e "$color$@$endcolor"
        else
                echo -e "$@"
        fi
@@ -64,7 +68,7 @@ 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
@@ -121,70 +125,50 @@ function msg {
        let "msgcount += 1"
 }
 
-function setfile() {
-       CURRENT_CONF_FILE=$1
-}
-
-function setsection() {
-       CURRENT_SECTION=$1
-}
-
-
-#
-# create a temporary file in a secure way.
-#
-function maketemp() {
-       if [ -x /bin/mktemp ]
-       then
-               local tempfile=`mktemp /tmp/$1.XXXXXXXX`
-       else
-               DATE=`date`
-               sectmp=`echo $DATE | /usr/bin/md5sum | cut -d- -f1`
-               local tempfile=/tmp/$1.$sectmp
-       fi
-       echo $tempfile
-}
-
-
-#
-# sets a global var with name equal to $1
-# to the value of the configuration parameter $1
-# $2 is the default.
-# 
-
-function getconf() {
-       CURRENT_PARAM=$1
-       ret=`awk -f $scriptdir/parseini S=$CURRENT_SECTION P=$CURRENT_PARAM $CURRENT_CONF_FILE`
-       # if nothing is returned, set the default
-       if [ "$ret" == "" -a "$2" != "" ]; then
-               ret="$2"
-       fi
-
-       # replace * with %, so that it is not globbed.
-       ret="${ret//\\*/__star__}"
-
-       # this is weird, but single quotes are needed to 
-       # allow for returned values with spaces. $ret is still expanded
-       # because it is in an 'eval' statement.
-       eval $1='$ret'
-}
-
 #
 # enforces very strict permissions on configuration file $file.
 #
 
 function check_perms() {
-       local file=$1
-       local perms=`ls -ld $file`
-       perms=${perms:4:6}
-       if [ "$perms" != "------" ]; then
-               echo "Configuration files must not be group or world writable/readable! Dying on file $file"
-               fatal "Configuration files must not be group or world writable/readable! Dying on file $file"
-       fi
-       if [ `ls -ld $file | awk '{print $3}'` != "root" ]; 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
+   local file=$1
+   debug "check_perms $file"
+   local perms
+   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" != '---' ]; 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" != '---' ]; then
+      case "$admingroup" in
+         $gid|$group) :;;
+
+         *)
+           if [ "$gid" != 0 ]; then
+              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
+   fi
 }
 
 # simple lowercase function
@@ -194,7 +178,7 @@ function tolower() {
 
 # simple to integer function
 function toint() {
-       echo "$1" | tr [:alpha:] -d 
+       echo "$1" | tr -d '[:alpha:]'
 }
 
 #
@@ -220,7 +204,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
@@ -324,7 +308,7 @@ function process_action() {
        echo "" > $bufferfile
        echo_debug_msg=1
        (
-               . $scriptdir/$suffix $file
+               . $scriptdirectory/$suffix $file
        ) 2>&1 | (
                while read a; do
                        echo $a >> $bufferfile
@@ -424,23 +408,37 @@ if [ ! -r "$conffile" ]; then
        fatal "Configuration file $conffile not found."
 fi
 
-scriptdir=`grep scriptdirectory $conffile | awk '{print $3}'`
-if [ ! -n "$scriptdir" ]; then
-       echo "Cound not find entry 'scriptdirectory' in $conffile" 
-       fatal "Cound not find entry 'scriptdirectory' in $conffile"
+# find $libdirectory
+libdirectory=`grep '^libdirectory' $conffile | @AWK@ '{print $3}'`
+if [ -z "$libdirectory" ]; then
+        if [ -d "@libdir@" ]; then
+          libdirectory="@libdir@"
+       else
+          echo "Could not find entry 'libdirectory' in $conffile." 
+          fatal "Could not find entry 'libdirectory' in $conffile." 
+       fi
+else
+        if [ ! -d "$libdirectory" ]; then
+          echo "Lib directory $libdirectory not found." 
+          fatal "Lib directory $libdirectory not found." 
+       fi
 fi
 
-if [ ! -d "$scriptdir" ]; then
-       echo "Script directory $scriptdir not found." 
-       fatal "Script directory $scriptdir not found."
-fi
+# include shared functions
+. $libdirectory/tools
+. $libdirectory/vserver
 
 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"
@@ -450,17 +448,21 @@ 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 vservers no
-getconf VSERVERINFO /usr/sbin/vserver-info
-getconf VSERVER /usr/sbin/vserver
-getconf VROOTDIR `if [ -f "$VSERVERINFO" ]; then $VSERVERINFO info SYSINFO |grep vserver-Rootdir | awk '{print $2}'; fi`
+getconf admingroup root
+
+# initialize vservers support
+# (get config variables and check real vservers availability)
+init_vservers nodialog
 
 if [ ! -d "$configdirectory" ]; then
        echo "Configuration directory '$configdirectory' not found."
@@ -470,15 +472,10 @@ fi
 [ -f "$logfile" ] || touch $logfile
 
 if [ "$UID" != "0" ]; then
-       echo "$0 can only be run as root"
+       echo "`basename $0` can only be run as root"
        exit 1
 fi
 
-if [ "$vservers" == "yes" -a ! -d "$VROOTDIR" ]; then
-       echo "vservers option set in config, but $VROOTDIR is not a directory!"
-       fatal "vservers option set in config, but $VROOTDIR is not a directory!"
-fi
-
 ## Process each configuration file
 
 # by default, don't make files which are world or group readable.
@@ -494,12 +491,17 @@ errormsg=""
 if [ "$singlerun" ]; then
        files=$singlerun
 else
-       files=`find $configdirectory -mindepth 1 ! -name '.*.swp' | sort -n`
+       files=`find $configdirectory -follow -mindepth 1 -maxdepth 1 -type f ! -name '.*.swp' | sort -n`
+
+       if [ -z "$files" ]; then
+               fatal "No backup actions configured in '$configdirectory', run ninjahelper!"
+       fi
 fi
 
 for file in $files; do
        [ -f "$file" ] || continue
 
+        check_perms ${file%/*} # check containing dir
        check_perms $file
        suffix="${file##*.}"
        base=`basename $file`
@@ -508,7 +510,7 @@ for file in $files; do
                continue
        fi
 
-       if [ -e "$scriptdir/$suffix" ]; then
+       if [ -e "$scriptdirectory/$suffix" ]; then
                process_action $file $suffix
        else
                error "Can't process file '$file': no handler script for suffix '$suffix'"
@@ -539,9 +541,24 @@ if [ $doit == 1 ]; then
                        echo ${messages[$i]}
                done
                echo -e "$errormsg"
-       } | mail $reportemail -s "backupninja: $hostname $subject"
+               if [ "$reportspace" == "yes" ]; then
+                       previous=""
+                       for i in $(ls "$configdirectory"); do
+                       backuploc=$(grep ^directory "$configdirectory"/"$i" | @AWK@ '{print $3}')
+                       if [ "$backuploc" != "$previous" ]; then
+                               df -h "$backuploc"
+                               previous="$backuploc"
+                       fi
+                       done
+               fi
+       } | mail -s "backupninja: $hostname $subject" $reportemail
 fi
 
 if [ $actions_run != 0 ]; then
        info "FINISHED: $actions_run actions run. $fatals fatal. $errors error. $warnings warning."
 fi
+
+if [ -n "$reporthost" ]; then
+       debug "send $logfile to $reportuser@$reporthost:$reportdirectory"
+       rsync -qt $logfile $reportuser@$reporthost:$reportdirectory
+fi