# 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=
CONFIG_PATH=/etc/bacap/hosts
# Name of the local host (so no ssh would be used with this host)
-LOCALHOST=localhost
+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="-aAXHx --numeric-ids --delete"
+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 -c arcfour -o Compression=no -x"
+RSYNC_RSH="ssh"
#_INCLUDE_END_
# 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
}
-load_config
-export RSYNC_RSH
-
-run=
-[ $DRY_RUN -eq 1 ] &&
- run=echo
-[ $VERBOSE -eq 1 ] &&
- RSYNC_FLAGS="$RSYNC_FLAGS $RSYNC_VERBOSE_FLAGS"
-[ $DEBUG -eq 1 ] &&
- V=-v
-[ -n "$LOG_FILE" ] &&
- exec 3>&2 &&
- exec 1>>"$LOG_FILE" &&
- exec 2>>"$LOG_FILE"
-
-pout() {
+error() {
echo "$@" >&3
}
-plog() {
+log() {
[ $VERBOSE -eq 1 ] &&
echo "$@"
}
-perror() {
+logerr() {
echo "$@" >&2
}
-host_up() {
+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"`
-plog
-plog
-plog "========================================================================="
-plog "Starting backup for $date at `date '+%Y-%m-%d %H:%M:%S'`"
-plog "========================================================================="
+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
- source "$host_path/bacaprc" 2>/dev/null
+ 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" ] &&
include="$host_path/includes"
current_link="$host_backup_path/current"
current_dir="$host_backup_path/`readlink \"$current_link\"`"
- exclude_flags=
- include_flags=
- plog "-----------------------------------------------------------------"
- plog "Backup for host $host"
- plog "-----------------------------------------------------------------"
- plog "Source: "$src
- plog "Destination: $dst"
- plog "Last: $current_dir"
- plog
- [ -d "$dst" ] &&
- perror "$dst already exists, skipping..." &&
+ 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
- ! host_up $host &&
- perror "$host is down, skipping..." &&
+ [ "$PING_CHECK" -eq 1 ] && ! ping_host $host &&
+ logerr "$host is down, skipping..." &&
continue
[ -r "$exclude" ] &&
- extra_flags="--exclude-from=$exclude --delete-excluded"
+ extra_flags="--exclude-from=$exclude"
[ -r "$include" ] &&
extra_flags="$extra_flags --include-from=$include"
- plog "Rotating backup..."
- $run cp -al $V "$current_dir" "$dst" ||
- ret=$(($ret+1))
- plog "Running rsync..."
- $run rsync $RSYNC_FLAGS $extra_flags $src "$dst/" ||
- ret=$(($ret+1))
- plog "Moving current..."
- $run rm $V "$current_link" ||
+ 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" ||
+ $run ln -s $V "$date" "$current_link" ||
ret=$(($ret+1))
+ else
+ ERROR_HOSTS="$ERROR_HOSTS $host"
+ fi
done
-plog "========================================================================="
-plog "Backup for $date finished at `date '+%Y-%m-%d %H:%M:%S'`"
-plog "========================================================================="
+log "========================================================================="
+log "Backup for $date finished at `date '+%Y-%m-%d %H:%M:%S'`"
+log "========================================================================="
if [ $ret -ne 0 ]
then
- pout 'There were some errors when running the backup.'
- pout
- pout "Please take a look at the log: $LOG_FILE"
- pout
+ 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