#!/bin/bash
#
# Univention Remote Backup
#  client and server for remote backup
#
# Copyright 2003-2014 Univention GmbH
#
# http://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <http://www.gnu.org/licenses/>.

errors=0
skippings=0
BWLIMITKBPS=0
echo

# source the config file and test variable presence
. /etc/remote-backup.conf 2>/dev/null
if [ -e /etc/remote-backup.servers -a -e /etc/remote-backup.clients -a -d "$BACKUPROOT" -a "$MAXHISTORY" -ge 0 ] 2>/dev/null; then
	true
else
	echo "configuration not found"
	echo
	exit 255
fi

# cmdline parm test
case $* in
	--servers)
		CONFFILE=/etc/remote-backup.servers
		TYPE=server
		;;
	--clients)
		CONFFILE=/etc/remote-backup.clients
		TYPE=client
		;;
	*)
		echo "Syntax error!"
		echo "Use either"
		echo "`basename $0` --servers     or"
		echo "`basename $0` --clients"
		echo
		exit 255
		;;
esac

# rotate backup dirs
if [ $MAXHISTORY = 0 ]; then
	if ! mkdir -p $BACKUPROOT/0 2>/dev/null; then
		echo "FATAL ERROR"
		echo
		exit 255
	fi
else
	c=$MAXHISTORY
	if [ "`date +%j`" = "`cat /var/lib/remote-backup/status`" ]; then
		echo  "Backups have already been rotated today. Not rotating."
	else
		if [ -d $BACKUPROOT/$c ]; then
			echo -n "Removing oldest backup... "
			if rm -rf $BACKUPROOT/$c 2>/dev/null; then
				echo "OK"
			else
				echo "FATAL ERROR"
				echo
				exit 255
			fi
		fi
		echo -n "Rotating backups... "
		while [ $c -gt 0 ]; do
			c=$(($c-1))
			if [ -d $BACKUPROOT/$c ]; then
				if ! mv $BACKUPROOT/$c $BACKUPROOT/$(($c+1)) 2>/dev/null; then
					echo "FATAL ERROR"
					echo
					exit 255
				fi
			fi
		done
		if [ -e $BACKUPROOT/1 ]; then
			if ! cp -a $BACKUPROOT/1 $BACKUPROOT/0 2>/dev/null; then
				echo "FATAL ERROR"
				echo
				exit 255
			fi
		else
			if ! mkdir $BACKUPROOT/0 2>/dev/null; then
				echo "FATAL ERROR"
				echo
				exit 255
			fi
		fi
		date +%j >/var/lib/remote-backup/status
		echo "OK"
	fi
fi


# rsync remote dirs
for line in `egrep -v "^ *#|^ *$" $CONFFILE`; do
	host=`echo "$line" | cut -f1 -d":" | cut -f2 -d"@"`
	remuser=`echo "$line" | cut -f1 -d":" | grep "^[a-zA-Z0-9.-]\+@" | cut -f1 -d"@"`
	dirs=`echo "$line" | cut -f2 -d":" | sed "s/,/ /g"`

	echo "Syncing from $TYPE $host:"
	if ! ping -c1 $host >/dev/null 2>&1; then
		echo -e "\tSKIP: does not respond"
		if [ $TYPE = client ]; then
			skippings=$(($skippings+1))
		else
			errors=$(($errors+1))
		fi
		continue
	fi
	if [ ! -d "$BACKUPROOT/0/$host" ]; then
		echo -n -e "\tcreating backup directory... "
		if mkdir -p -m 700 "$BACKUPROOT/0/$host" >/dev/null; then
			echo "OK"
		else
			echo "ERROR: cannot create dir!"
			errors=$(($errors+1))
			continue
		fi
	fi
	for dir in $dirs; do
		echo -n -e "\t$dir... "
		if [ -z "$remuser" ]; then
			remuser=root
		fi
		mountpoint="`echo "$dir" | sed 's|/|_=_|g'`"
		mkdir -p "$BACKUPROOT/0/$host/$mountpoint"
		if rsync -e 'ssh -o BatchMode=yes' -ar -x -z --safe-links --delete --bwlimit=$BWLIMITKBPS "$remuser@$host:$dir" "$BACKUPROOT/0/$host/$mountpoint" </dev/null >/dev/null; then
			echo "OK"
		else
			echo "ERROR: rsync error!"
			errors=$(($errors+1))
		fi
	done
	echo -n "Removing orphaned dirs... "
	for checkdir in `find "$BACKUPROOT/0/$host" -maxdepth 1 -type d | grep -v "^$BACKUPROOT/0/$host$" | sed "s|^$BACKUPROOT/0/$host/||g"`; do
		if ! echo "$dirs" | sed 's|/|_=_|g' | egrep "^$checkdir| $checkdir|$checkdir |$checkdir$" >/dev/null; then
			rm -rf "$BACKUPROOT/0/$host/$checkdir"
		fi
	done
	echo "OK"
done
echo

case $skippings in
	0) true;;
	1) echo "1 client skipped.";;
	*) echo "$skippings clients skipped.";;
esac
case $errors in
	0) true;;
	1) echo "1 error occured.";;
	*) echo "$errors errors occured.";;
esac
echo
exit $errors
