#!/bin/bash #_INCLUDE_START_ # Default config values # Be verbose VERBOSE=1 # Be extra verbose DEBUG=0 # Don't actually do anything, just print the commands DRY_RUN=0 # Force synchronization, even when the target already exist FORCE_SYNC=0 # Log file (if empty, print to stdout/err) LOG_FILE= # Where to find the configuration of the hosts to backup CONFIG_PATH=/etc/bacap/hosts # Name of the local host (so no ssh would be used with this host) LOCALHOST=$HOSTNAME # Where to put the backups BACKUP_PATH=/backup # Date format used for backed up directories (passed to the date command) DATE_FMT="%Y-%m-%d" # Ping remote hosts to check if they are up (set to 0 if your hosts don't # reply to ICMP pings). PING_CHECK=1 # rsync flags to use RSYNC_FLAGS="-aAHSXx --numeric-ids" # rsync flags to use when in verbose mode RSYNC_VERBOSE_FLAGS="-v --stats" # rsync remote shell to use RSYNC_RSH="ssh" #_INCLUDE_END_ SCRIPT_DIR=$(dirname `readlink -f $0`) BACAPRC=$1 # Load configuration files load_config() { extra_config=$1 source "/etc/bacaprc" 2> /dev/null source "/etc/bacap/bacaprc" 2> /dev/null source "$SCRIPT_DIR/bacaprc" 2> /dev/null test -n "$BACAPRC" && source "$BACAPRC" test -n "$extra_config" && source "$1" 2> /dev/null run= [ $DRY_RUN -eq 1 ] && run=echo [ $VERBOSE -eq 1 ] && RSYNC_FLAGS="$RSYNC_FLAGS $RSYNC_VERBOSE_FLAGS" [ $DEBUG -eq 1 ] && V=-v exec 3>&2 [ -n "$LOG_FILE" ] && exec 1>>"$LOG_FILE" && exec 2>>"$LOG_FILE" export RSYNC_RSH } error() { echo "$@" >&3 } log() { [ $VERBOSE -eq 1 ] && echo "$@" } logerr() { echo "$@" >&2 } ping_host() { ping -c1 "$1" > /dev/null 2>&1 } load_config if ! test -d "$BACKUP_PATH" then error "BACKUP_PATH=$BACKUP_PATH doesn't exist!" exit 1 fi date=`date "+$DATE_FMT"` log log log "=========================================================================" log "Starting backup for $date at `date '+%Y-%m-%d %H:%M:%S'`" log "=========================================================================" ret=0 for host_path in "$CONFIG_PATH"/* do saved_ret=$ret # Load default config and override config if correspond load_config "$host_path/bacaprc" host=`basename "$host_path"` host_backup_path="$BACKUP_PATH/$host" mkdir -p $host_backup_path dst="$BACKUP_PATH/$host/$date" src=`cat "$host_path/paths"` [ "$host" != "$LOCALHOST" ] && src=`awk "{print \"$host:\"\\$1}" "$host_path/paths"` exclude="$host_path/excludes" include="$host_path/includes" current_link="$host_backup_path/current" current_dir="$host_backup_path/`readlink \"$current_link\"`" extra_flags= log "-----------------------------------------------------------------" log "Backup for host $host started at `date '+%Y-%m-%d %H:%M:%S'`" log "-----------------------------------------------------------------" log "Source: $src" log "Destination: $dst" log "Last: $current_dir" log [ -d "$dst" ] && [ "$FORCE_SYNC" -ne 1 ] && logerr "$dst already exists, skipping..." && continue [ "$PING_CHECK" -eq 1 ] && ! ping_host $host && logerr "$host is down, skipping..." && continue [ -r "$exclude" ] && extra_flags="--exclude-from=$exclude" [ -r "$include" ] && extra_flags="$extra_flags --include-from=$include" log "Running rsync..." $run rsync $RSYNC_FLAGS $extra_flags \ --link-dest="$current_dir" $src "$dst/" rsync_ret=$? case $rsync_ret in 0) # Normal return ;; 24) # Ignore error 24 from rsync ("Partial transfer due to # vanished source files") which is somewhat expected # since we don't do a snapshot ;; *) # Any other error is important enough ret=$(($ret+1)) ;; esac if [ $ret -eq $saved_ret ] then # Only move current if rsync did not fail, to avoid dangling # symlinks log "Moving current..." $run rm -f $V "$current_link" || ret=$(($ret+1)) $run ln -s $V "$date" "$current_link" || ret=$(($ret+1)) else ERROR_HOSTS="$ERROR_HOSTS $host" fi done log "=========================================================================" log "Backup for $date finished at `date '+%Y-%m-%d %H:%M:%S'`" log "=========================================================================" if [ $ret -ne 0 ] then error error "There were some errors when running the backup on: $ERROR_HOSTS" error if [ -n "$LOG_FILE" ] then error "Please take a look at the log: $LOG_FILE" error fi fi exit $ret