diff options
Diffstat (limited to 'backupninja')
-rwxr-xr-x | backupninja | 549 |
1 files changed, 0 insertions, 549 deletions
diff --git a/backupninja b/backupninja deleted file mode 100755 index d653144..0000000 --- a/backupninja +++ /dev/null @@ -1,549 +0,0 @@ -#!/bin/bash -# |\_ -# B A C K U P N I N J A /()/ -# `\| -# -# Copyright (C) 2004-05 riseup.net -- property is theft. -# -# 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 -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# - -##################################################### -## FUNCTIONS - -function setupcolors() { - BLUE="\033[34;01m" - GREEN="\033[32;01m" - YELLOW="\033[33;01m" - PURPLE="\033[35;01m" - RED="\033[31;01m" - OFF="\033[0m" - CYAN="\033[36;01m" - COLORS=($BLUE $GREEN $YELLOW $RED $PURPLE) -} - -function colorize() { - if [ "$usecolors" == "yes" ]; then - 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" - else - echo -e "$@" - fi -} - -# We have the following message levels: -# 0 - debug - blue -# 1 - normal messages - green -# 2 - warnings - yellow -# 3 - errors - orange -# 4 - fatal - red -# First variable passed is the error level, all others are printed - -# if 1, echo out all warnings, errors, or fatal -# used to capture output from handlers -echo_debug_msg=0 - -usecolors=yes - -function printmsg() { - [ ${#@} -gt 1 ] || return - - type=$1 - shift - if [ $type == 100 ]; then - 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="" - else - types=(Debug Info Warning Error Fatal) - typestr="${types[$type]}: " - fi - - print=$[4-type] - - if [ $echo_debug_msg == 1 ]; then - echo -e "$typestr$@" >&2 - elif [ $debug ]; then - colorize "$typestr$@" >&2 - fi - - if [ $print -lt $loglevel ]; then - logmsg "$typestr$@" - fi -} - -function logmsg() { - if [ -w "$logfile" ]; then - echo -e `date "+%h %d %H:%M:%S"` "$@" >> $logfile - fi -} - -function passthru() { - printmsg 100 "$@" -} -function debug() { - printmsg 0 "$@" -} -function info() { - printmsg 1 "$@" -} -function warning() { - printmsg 2 "$@" -} -function error() { - printmsg 3 "$@" -} -function fatal() { - printmsg 4 "$@" - exit 2 -} - -msgcount=0 -function msg { - messages[$msgcount]=$1 - 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 -} - -# simple lowercase function -function tolower() { - echo "$1" | tr [:upper:] [:lower:] -} - -# simple to integer function -function toint() { - echo "$1" | tr [:alpha:] -d -} - -# -# function isnow(): returns 1 if the time/day passed as $1 matches -# the current time/day. -# -# format is <day> at <time>: -# sunday at 16 -# 8th at 01 -# everyday at 22 -# - -# we grab the current time once, since processing -# all the configs might take more than an hour. -nowtime=`date +%H` -nowday=`date +%d` -nowdayofweek=`date +%A` -nowdayofweek=`tolower "$nowdayofweek"` - -function isnow() { - local when="$1" - set -- $when - 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/'` - - if [ "$whendayofweek" == "everyday" -o "$whendayofweek" == "daily" ]; then - whendayofweek=$nowdayofweek - fi - - if [ "$whenday" == "" ]; then - if [ "$whendayofweek" != "$nowdayofweek" ]; then - whendayofweek=${whendayofweek%s} - if [ "$whendayofweek" != "$nowdayofweek" ]; then - return 0 - fi - fi - elif [ "$whenday" != "$nowday" ]; then - return 0 - fi - - [ "$at" == "at" ] || return 0 - [ "$whentime" == "$nowtime" ] || return 0 - - return 1 -} - -function usage() { - cat << EOF -$0 usage: -This script allows you to coordinate system backup by dropping a few -simple configuration files into /etc/backup.d/. Typically, this -script is run hourly from cron. - -The following options are available: --h, --help This usage message --d, --debug Run in debug mode, where all log messages are - output to the current shell. --f, --conffile FILE Use FILE for the main configuration instead - of /etc/backupninja.conf --t, --test Test run mode. This will test if the backup - could run, without actually preforming any - backups. For example, it will attempt to authenticate - or test that ssh keys are set correctly. --n, --now Perform actions now, instead of when they might - be scheduled. No output will be created unless also - run with -d. - --run FILE Execute the specified action file and then exit. - Also puts backupninja in debug mode. - -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)" -} - -## -## this function handles the running of a backup action -## -## these globals are modified: -## fatals, errors, warnings, actions_run, errormsg -## - -function process_action() { - local file="$1" - local suffix="$2" - local run="no" - setfile $file - - # skip over this config if "when" option - # is not set to the current time. - getconf when "$defaultwhen" - if [ "$processnow" == 1 ]; then - info ">>>> starting action $file (because of --now)" - run="yes" - elif [ "$when" == "hourly" ]; then - info ">>>> starting action $file (because 'when = hourly')" - run="yes" - else - IFS=$'\t\n' - for w in $when; do - IFS=$' \t\n' - isnow "$w" - ret=$? - IFS=$'\t\n' - if [ $ret == 0 ]; then - debug "skipping $file because it is not $w" - else - info ">>>> starting action $file (because it is $w)" - run="yes" - fi - done - IFS=$' \t\n' - fi - debug $run - [ "$run" == "no" ] && return - - let "actions_run += 1" - - # call the handler: - local bufferfile=`maketemp backupninja.buffer` - echo "" > $bufferfile - echo_debug_msg=1 - ( - . $scriptdir/$suffix $file - ) 2>&1 | ( - while read a; do - echo $a >> $bufferfile - [ $debug ] && colorize "$a" - done - ) - retcode=$? - # ^^^^^^^^ we have a problem! we can't grab the return code "$?". grrr. - echo_debug_msg=0 - - _warnings=`cat $bufferfile | grep "^Warning: " | wc -l` - _errors=`cat $bufferfile | grep "^Error: " | wc -l` - _fatals=`cat $bufferfile | grep "^Fatal: " | wc -l` - - ret=`grep "\(^Warning: \|^Error: \|^Fatal: \)" $bufferfile` - rm $bufferfile - if [ $_fatals != 0 ]; then - msg "*failed* -- $file" - errormsg="$errormsg\n== fatal errors from $file ==\n\n$ret\n" - passthru "Fatal: <<<< finished action $file: FAILED" - elif [ $_errors != 0 ]; then - msg "*error* -- $file" - errormsg="$errormsg\n== errors from $file ==\n\n$ret\n" - error "<<<< finished action $file: ERROR" - elif [ $_warnings != 0 ]; then - msg "*warning* -- $file" - errormsg="$errormsg\n== warnings from $file ==\n\n$ret\n" - warning "<<<< finished action $file: WARNING" - else - msg "success -- $file" - info "<<<< finished action $file: SUCCESS" - fi - - let "fatals += _fatals" - let "errors += _errors" - let "warnings += _warnings" -} - -##################################################### -## MAIN - -setupcolors -conffile="/etc/backupninja.conf" -loglevel=3 - -## process command line options - -while [ $# -ge 1 ]; do - case $1 in - -h|--help) usage;; - -d|--debug) debug=1;; - -t|--test) test=1;debug=1;; - -n|--now) processnow=1;; - -f|--conffile) - if [ -f $2 ]; then - conffile=$2 - else - echo "-f|--conffile option must be followed by an existing filename" - fatal "-f|--conffile option must be followed by an existing filename" - usage - fi - # we shift here to avoid processing the file path - shift - ;; - --run) - debug=1 - if [ -f $2 ]; then - 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" - usage - fi - shift - ;; - *) - debug=1 - echo "Unknown option $1" - fatal "Unknown option $1" - usage - exit - ;; - esac - shift -done - -#if [ $debug ]; then -# usercolors=yes -#fi - -## Load and confirm basic configuration values - -# bootstrap -if [ ! -r "$conffile" ]; then - echo "Configuration file $conffile not found." - 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" -fi - -if [ ! -d "$scriptdir" ]; then - echo "Script directory $scriptdir not found." - fatal "Script directory $scriptdir not found." -fi - -setfile $conffile - -# get global config options (second param is the default) -getconf configdirectory /etc/backup.d -getconf reportemail -getconf reportsuccess yes -getconf reportwarning yes -getconf loglevel 3 -getconf when "Everyday at 01:00" -defaultwhen=$when -getconf logfile /var/log/backupninja.log -getconf usecolors "yes" -getconf SLAPCAT /usr/sbin/slapcat -getconf LDAPSEARCH /usr/bin/ldapsearch -getconf RDIFFBACKUP /usr/bin/rdiff-backup -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 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` - -if [ ! -d "$configdirectory" ]; then - echo "Configuration directory '$configdirectory' not found." - fatal "Configuration directory '$configdirectory' not found." -fi - -[ -f "$logfile" ] || touch $logfile - -if [ "$UID" != "0" ]; then - echo "$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. -umask 077 - -# these globals are set by process_action() -fatals=0 -errors=0 -warnings=0 -actions_run=0 -errormsg="" - -if [ "$singlerun" ]; then - files=$singlerun -else - files=`find $configdirectory -mindepth 1 ! -name '.*.swp' | sort -n` -fi - -for file in $files; do - [ -f "$file" ] || continue - - check_perms $file - suffix="${file##*.}" - base=`basename $file` - if [ "${base:0:1}" == "0" -o "$suffix" == "disabled" ]; then - info "Skipping $file" - continue - fi - - if [ -e "$scriptdir/$suffix" ]; then - process_action $file $suffix - else - error "Can't process file '$file': no handler script for suffix '$suffix'" - msg "*missing handler* -- $file" - fi -done - -## mail the messages to the report address - -if [ $actions_run == 0 ]; then doit=0 -elif [ "$reportemail" == "" ]; then doit=0 -elif [ $fatals != 0 ]; then doit=1 -elif [ $errors != 0 ]; then doit=1 -elif [ "$reportsuccess" == "yes" ]; then doit=1 -elif [ "$reportwarning" == "yes" -a $warnings != 0 ]; then doit=1 -else doit=0 -fi - -if [ $doit == 1 ]; then - debug "send report to $reportemail" - hostname=`hostname` - [ $warnings == 0 ] || subject="WARNING" - [ $errors == 0 ] || subject="ERROR" - [ $fatals == 0 ] || subject="FAILED" - - { - for ((i=0; i < ${#messages[@]} ; i++)); do - echo ${messages[$i]} - done - echo -e "$errormsg" - } | mail $reportemail -s "backupninja: $hostname $subject" -fi - -if [ $actions_run != 0 ]; then - info "FINISHED: $actions_run actions run. $fatals fatal. $errors error. $warnings warning." -fi |