#!/bin/bash
# Copyright (c) 2012 Peter Varkoly Nürnberg, Germany.  All rights reserved.
# oss-backup
# 
# $Id: oss-backup,v 1.10 2007/07/18 16:43:22 pv Exp $
#

LOGFILE=/var/log/oss-backup.log
DATE=`date +%Y-%m-%d-%H-%M`
#TODO Make all variables configurable.
MYSQLDUMP_OPTIONS="--lock-tables --add-drop-database --add-locks --quote-names --opt --create-options"
MAILADDR="admin"
FORCE="no"
VERBOSE="yes"
CONFIG=/etc/sysconfig/schoolserver
RSYNCPARS=" -aA --delete --size-only "
LIMIT=80
DAY_OF_WEEK=$( date +%u )

if [ -e /var/adm/oss/BackupRunning ]
then
	BPID=$( cat /var/adm/oss/BackupRunning )
	if [ -d /proc/$BPID ]; then
		echo "An other backup process is running with PID: $BPID"
		exit 1;
	fi
fi

echo $$ > /var/adm/oss/BackupRunning

function TheEnd(){
	rm /var/adm/oss/BackupRunning
	echo $DATE > /var/adm/backup/LAST_BACKUP
	if [ "$2" ]; then
		LOG "$2 $1";
	fi
	exit $1
}

function usage (){
	echo 
	echo "Usage: `basename $0` [OPTION] "
	echo "       -h|--help     : help (this message)"
	echo "       -f            : force backup (even if it's disabled in config)"
	echo "       -v            : be verbose"
	echo 
	echo "       Use this script to immediately create a backup of your OSS."
	echo "       You can find the configuration in $CONFIG."
	echo "       Feel free to read the administration handbook for further details."
	echo
	TheEnd $1
}

function check_discspace() {
	if [ "$SCHOOL_BACKUP_WARNING_LIMIT" ]; then
		LIMIT=$SCHOOL_BACKUP_WARNING_LIMIT
	fi

	USED=`df $1 | tail -n1 | awk '{ print $(NF-1) }' | sed s/%//`
	if [ $USED -gt $LIMIT ]; then
	{
		AVAIL=`df -h $1 | tail -n1 | awk '{ print $(NF-2) }'`
		echo "WARNING: only $AVAIL space available on $1." | tee -a $LOGFILE
	} | mail -s "BACKUP WARNING from $0" $MAILADDR
	fi
}

function LOG() {
	LOG_DATE=`date "+%b %d %H:%M:%S"`
	HOST=`hostname`
	echo "$LOG_DATE $HOST oss-backup: $1" >> $LOGFILE
	if [ "$VERBOSE" = "yes" ]; then
		echo "$1"
	fi
}

while getopts 'fhv --long help --' OPTION ; do
        case $OPTION in
		        h|H|help)    usage 0
                ;;
				f) FORCE="yes"
				;;
				v) VERBOSE="yes"
				;;
		esac
done

shift $(( OPTIND - 1 ))

if [ ! -f $CONFIG ]; then
	echo -e "\033[0;31;1mThis script is for Open School Server only!\033[\0m"
	echo -e "\033[0;31;1m*********         exiting         *********\033[\0m"
	TheEnd 1
fi

# Read the configuration
. $CONFIG
if [ -z "$SCHOOL_BACKUP_DAYS" ]; then
        SCHOOL_BACKUP_DAYS="1234567"
fi
if [ "$SCHOOL_BACKUP_CAN_NOT_SAVE_ACL" = "yes" ]; then
	RSYNCPARS=" -a --delete "
fi

if [ "$SCHOOL_BACKUP_CAN_NOT_SAVE_OWNER" = "yes" ]; then
	RSYNCPARS=" -r --delete "
fi

if [ "${SCHOOL_BACKUP_DAYS/$DAY_OF_WEEK/}" = $SCHOOL_BACKUP_DAYS -a "$FORCE" != "yes" ]; then
        LOG "********** No backup needed today **********"
        exit 0;
fi

MAILADDR="admin@$SCHOOL_DOMAIN"

if [ "$SCHOOL_BACKUP" = "yes" ] || [ "$FORCE" = "yes" ] ; then
	LOG "********** Starting Backup **********"

    if [ "$SCHOOL_BACKUP_START_CMD" ]; then
	eval $SCHOOL_BACKUP_START_CMD
    fi
    if [ -e /var/adm/backup/LAST_BACKUP ]; then
        LAST_BACKUP=`cat /var/adm/backup/LAST_BACKUP`
    else    
        LAST_BACKUP=$DATE
    fi
	# check needed configs
	if [ -z $SCHOOL_BACKUP_FULL_DIR ]; then
		VERBOSE="yes"
		LOG "No SCHOOL_BACKUP_FULL_DIR defined - exiting" 
		TheEnd 1
	fi
	check_discspace $SCHOOL_BACKUP_FULL_DIR
	if [ -z $SCHOOL_BACKUP_INC_DIR ]; then
		VERBOSE="yes"
		LOG "No SCHOOL_BACKUP_INC_DIR defined - using $SCHOOL_BACKUP_FULL_DIR instead" 
		SCHOOL_BACKUP_INC_DIR=$SCHOOL_BACKUP_FULL_DIR
	else
		check_discspace $SCHOOL_BACKUP_INC_DIR
	fi

    #create the backup direcktory
    BACKUP_DIR="$SCHOOL_BACKUP_INC_DIR/$LAST_BACKUP"
    mkdir -p $BACKUP_DIR
    if [ $? != 0 ]; then
	TheEnd 6 "CAN_NOT_MAKE_BACKUP"
    fi  
    touch $SCHOOL_BACKUP_FULL_DIR/DO_BACKUP
    if [ $? != 0 ]; then
	TheEnd 6 "CAN_NOT_MAKE_BACKUP"
    fi  

    export BACKUP_DIR
    export SCHOOL_BACKUP_FULL_DIR
    if [ "$SCHOOL_BACKUP_CHECK_MOUNT" = "yes" ]; then
        mount | grep -q "$SCHOOL_BACKUP_FULL_DIR" || {
            LOG "Unable to mount $SCHOOL_BACKUP_FULL_DIR" 
            TheEnd 5
        }
        mount | grep -q "$SCHOOL_BACKUP_INC_DIR" || {
            LOG "Unable to mount $SCHOOL_BACKUP_INC_DIR" 
            TheEnd 5
        }
    fi

    # copy sysconfig file schoolconf to the base for simple recovery
    cp /etc/sysconfig/schoolserver $SCHOOL_BACKUP_FULL_DIR/
    if [ $? != 0 ]; then
	TheEnd 6 "CAN_NOT_MAKE_BACKUP"
    fi  

    # save custom squidGuard database
    LOG "Syncing custom squidGuard database" 
    mkdir -p $SCHOOL_BACKUP_FULL_DIR/var/lib/squidGuard/db/custom/
    mkdir -p $BACKUP_DIR/var/lib/squidGuard/db/custom/
    rsync $RSYNCPARS -b --backup-dir=$BACKUP_DIR/var/lib/squidGuard/db/custom/ \
		/var/lib/squidGuard/db/custom/ \
		$SCHOOL_BACKUP_FULL_DIR/var/lib/squidGuard/db/custom/
    if [ $? != 0 ]; then
	TheEnd 6 "CAN_NOT_MAKE_BACKUP"
    fi  

    LOG "Syncing samba"
    if [ "$SCHOOL_BACKUP_CAN_NOT_SAVE_ACL" = "yes" ]; then
       test -e $SCHOOL_BACKUP_FULL_DIR/samba_facls.gz && mv $SCHOOL_BACKUP_FULL_DIR/samba_facls.gz $BACKUP_DIR
       getfacl --absolute-names -R /var/lib/samba/ | gzip > $SCHOOL_BACKUP_FULL_DIR/samba_facls.gz
    fi
    mkdir -p $BACKUP_DIR/var/lib/samba/
    rsync $RSYNCPARS -b --backup-dir=$BACKUP_DIR/var/lib/samba/ /var/lib/samba/ $SCHOOL_BACKUP_FULL_DIR/var/lib/samba/
    if [ $? != 0 ]; then
        TheEnd 6 "CAN_NOT_MAKE_BACKUP"
    fi

    # save /etc - must run after samba-backup otherwise secrets.tdb.bak is not saved
    if [ "$SCHOOL_BACKUP_CAN_NOT_SAVE_ACL" = "yes" ]; then
	LOG "Saving acls on /etc/"
	if [ -e $SCHOOL_BACKUP_FULL_DIR/etc_facls.gz ]; then
		mv $SCHOOL_BACKUP_FULL_DIR/etc_facls.gz $BACKUP_DIR/etc_facls.gz
	fi
	getfacl --skip-base --absolute-names -R /etc/ | gzip > $SCHOOL_BACKUP_FULL_DIR/etc_facls.gz
    fi
    LOG "Syncing /etc/"
    mkdir -p $BACKUP_DIR/etc/
    rsync $RSYNCPARS -b --backup-dir=$BACKUP_DIR/etc/ /etc/ $SCHOOL_BACKUP_FULL_DIR/etc/
    if [ $? != 0 ]; then
	TheEnd 6 "CAN_NOT_MAKE_BACKUP"
    fi  

    # save /root (needed already for ssh-key files)
    LOG "Syncing /root/"
    mkdir -p $BACKUP_DIR/root/
    rsync $RSYNCPARS -b --backup-dir=$BACKUP_DIR/root/ /root/ $SCHOOL_BACKUP_FULL_DIR/root/

    if [ "$SCHOOL_BACKUP_HOME" = "yes" ]; then
        if [ "$SCHOOL_BACKUP_CAN_NOT_SAVE_ACL" = "yes" ]; then
		LOG "Saving acls on /home/" 
		if [ -e $SCHOOL_BACKUP_FULL_DIR/home_facls.gz ]; then
		    mv $SCHOOL_BACKUP_FULL_DIR/home_facls.gz $BACKUP_DIR/home_facls.gz
		fi
		getfacl --skip-base --absolute-names -R /home/ | gzip > $SCHOOL_BACKUP_FULL_DIR/home_facls.gz
	fi
	LOG "Syncing /home/" 
	test -e /usr/share/oss/templates/exclude-from-home-backup || touch /usr/share/oss/templates/exclude-from-home-backup
	# If $SCHOOL_BACKUP_FULL_DIR equal $SCHOOL_BACKUP_INC_DIR we make hartlinks
	if [ $SCHOOL_BACKUP_FULL_DIR = $SCHOOL_BACKUP_INC_DIR -a "$SCHOOL_BACKUP_WITH_HARDLINK" = "yes" ]; then
	    if [ -d $SCHOOL_BACKUP_FULL_DIR/home/ ]; then
	    	mv $SCHOOL_BACKUP_FULL_DIR/home/ $BACKUP_DIR/home/
	    else
	    	mkdir -p $BACKUP_DIR/home/
	    fi
	    rsync $RSYNCPARS --exclude-from=/usr/share/oss/templates/exclude-from-home-backup --link-dest=$BACKUP_DIR/home/ /home/ $SCHOOL_BACKUP_FULL_DIR/home/
	    if [ $? != 0 ]; then
		TheEnd 6 "CAN_NOT_MAKE_BACKUP"
	    fi  
	else
	    mkdir -p $BACKUP_DIR/home/
	    rsync $RSYNCPARS --exclude-from=/usr/share/oss/templates/exclude-from-home-backup -b --backup-dir=$BACKUP_DIR/home/ /home/ $SCHOOL_BACKUP_FULL_DIR/home/
	    if [ $? != 0 ]; then
		TheEnd 6 "CAN_NOT_MAKE_BACKUP"
	    fi  
	fi
    fi

    if [ "$SCHOOL_BACKUP_CTOOL" = "yes" ]; then
    	LOG "Syncing itool"  
    	mkdir -p $SCHOOL_BACKUP_FULL_DIR/srv/itool
    	mkdir -p $BACKUP_DIR/srv/itool
    	rsync $RSYNCPARS -b --backup-dir=$BACKUP_DIR/srv/itool/ /srv/itool/ $SCHOOL_BACKUP_FULL_DIR/srv/itool/
        if [ $? != 0 ]; then
            TheEnd 6 "CAN_NOT_MAKE_BACKUP"
        fi  
    fi
    
    if [ "$SCHOOL_BACKUP_DB" = "yes" ]; then
	LOG "Syncing OSS Database"
        mysqldump $MYSQLDUMP_OPTIONS --all-databases | gzip > $BACKUP_DIR/MYSQL.sql.gz
	if [ $? != 0 ]; then
		LOG " CAN_NOT_MAKE_BACKUP"
	fi  
    fi

    if [ "$SCHOOL_BACKUP_MAIL" = "yes" ]; then
	LOG "Syncing Mail Data"
        for i in var/spool/imap/ var/lib/imap/; do
            mkdir -p $SCHOOL_BACKUP_FULL_DIR/$i
            mkdir -p $BACKUP_DIR/$i
            rsync $RSYNCPARS -b --backup-dir=$BACKUP_DIR/$i /$i $SCHOOL_BACKUP_FULL_DIR/$i
	    if [ $? != 0 ]; then
		LOG " CAN_NOT_MAKE_BACKUP"
	    fi  
        done    
    fi

    # Now we make recovery easy
    if [ -f /usr/share/oss/tools/oss_recover.sh ]; then
      cp -f /usr/share/oss/tools/oss_recover.sh $SCHOOL_BACKUP_FULL_DIR/
      chmod 750 $SCHOOL_BACKUP_FULL_DIR/oss_recover.sh 
      chown root:root $SCHOOL_BACKUP_FULL_DIR/oss_recover.sh
    fi
    if [ -f /usr/share/doc/packages/openschool-base/oss_recover.readme ]; then
      cp -f /usr/share/doc/packages/openschool-base/oss_recover.readme $SCHOOL_BACKUP_FULL_DIR/	
    fi

    # Execute custom scripts
    if [ "$SCHOOL_BACKUP_CUSTOM_SCRIPTS" ]; then
        for i in $SCHOOL_BACKUP_CUSTOM_SCRIPTS
        do
                LOG "Starting $i"
                $i $BACKUP_DIR $SCHOOL_BACKUP_FULL_DIR
        done
    fi

    # create mark for last backup
    DATE=`date +%Y-%m-%d-%H-%M`
    LOG "********** Backup finished **********"
    echo $DATE > /var/adm/backup/LAST_BACKUP
    if [ "$SCHOOL_BACKUP_STOP_CMD" ]; then
	eval $SCHOOL_BACKUP_STOP_CMD
    fi
   
fi
TheEnd
