#!/bin/sh

# 'backup2net.sh'
#
# A script to perform backups to a network drive.
#
# -----------------------------------------------------------------
# This program is free software; you can redistribute it and/or
# modify it under the terms of the version 2 of the GNU General
# Public License as published by the Free Software Foundation.
#
# 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.
# -----------------------------------------------------------------
# Copyright (c) 2010 Joerg Hau <joerg.hau(at)sunrise.ch>.
#
# Largely based on my back2tape.sh script, rsync idea is from
# http://blog.interlinked.org/tutorials/rsync_time_machine.html
# -----------------------------------------------------------------
# - All variables below can be specified in an external file
#   which is read on the cmd line. In other words: put all 'your'
#   stuff in that external file - no need to modify this script.
# -----------------------------------------------------------------
# History:
#   2010-09-01, JHa (first "draft").
#   2010-12-23, JHa (more params, now using config file) 
#   2011-01-01, JHa (more comments & cleanup)
#   2011-01-04, JHa (more checks for non-root use)
# -----------------------------------------------------------------
# set some default options
# -----------------------------------------------------------------

VERBOSE=""      # verbose mode or not (empty string = no)
ERRCNT=0        # error counter

MAILTO="root"      # Backup operator

# Backup source directory
SRC="/home/jha"

# Backup destination and log directory. 
# NOTE: Non-root users need write permission here!
DEST="/mnt/linkstation/backup/"	
LOGDIR="/var/log/backup/linkstation"    

PREFIX="backup-jha"
EXCLUDE="--exclude-from=$HOME/.rsync/exclude"

# my own exclude file contains these lines (uncommented, of course ;-):
# *[cC]ache*
# *[tT]trash*
# *[tT]humbnails*
# *~
# .googleearth/*
# .local/share/akonadi/*
# .local/share/marble/*
# .kde/share/apps/okular/*

#
# --- "No user adjustable parts below this line" :-) ---
#

# -----------------------------------------------------------------
# subroutine to check for some required executables
# argument: (list of) programs to test for
# will exit with rc=1 if any program was not found
# ! Not every version of 'which' behaves the same !
# -----------------------------------------------------------------
function checkfor()
{
for i in $*; do
    PROG=`which $i`
    if [ -x "$PROG" ] ; then
        shift
    else
        echo "'$i' command not found, exiting."
        exit 1
    fi
done
}

# ------------------------------------------------------------
# subroutine to log stuff to file with date/time stamp
# argument: text to log
# ------------------------------------------------------------
function logging()
{
# get date/time stamp
DATETIME=`date --iso-8601=sec`

# append text ($1) to file
echo "${DATETIME}. $1" >> $LOGFILE

# if verbose mode is set, echo also to screen
if [ $VERBOSE ] ; then
    echo "${DATETIME}. $1"
fi
}

# ------------------------------------------------------------
# subroutine to check error status of last command
# argument: error message
# will exit with rc=1 if errorlevel was not 0
# ------------------------------------------------------------
function errcheck()
{
if [ $? != 0 ]; then
    logging "Abort: $1, status: $?"
    echo `date --iso-8601=sec`. $1 >> $STDERR
    mail -s "$NAME-Backup ABORT!" $MAILTO < $STDERR
    exit 1
fi
}


# ------------------------------------------------------------
# verify if a directory is existing and accessible
# - if it does not exist, create ist.
# - arguments: $1 = path/to/directory
# ------------------------------------------------------------
function checkdir()
{
if [ ! -d $1 ] ; then
    mkdir -p $1 || errcheck "Error during creation of '$1'"
fi
if [ ! -r $1 ] ; then
    errcheck "'$1' exists but is not readable"
fi
}


# ------------------------------------------------------------
# subroutine to read (source) an external config file
# requires global variable $CONFIG_FILE
# ------------------------------------------------------------
function read_config_file()
if [ $CONFIG_FILE ]; then
    echo -n "Reading configuration from $CONFIG_FILE ... "
    if [ -e "$CONFIG_FILE" ]; then
        source $CONFIG_FILE && echo "done."
    else
        logging "Configuration file $CONFIG_FILE not found!"
        exit 1
    fi
fi


# ------------------------------------------------------------
# subroutine to print usage mode
# ------------------------------------------------------------
function usage()
{
cat << eof

${0##*/} -  Backup script

A script to back up files and directories over the network.

Copyright (c) 2010 Joerg Hau <joerg.hau(at)sunrise.ch>.

This program is free software; you can redistribute it and/or
modify it under the terms of version 2 of the GNU General Public
License as published by the Free Software Foundation.

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.

Usage: ${0##*/} [-c | --config config_file] [-v | --verbose]

    -c config_file    Specify a configuration file.
                      Default is to use the built-in values:
                      SRC=$SRC
                      DEST=$DEST
                      PREFIX=$PREFIX
                      LOGDIR=$LOGDIR
    -v, --verbose     Verbose mode.
    -? | -h | --help  This help.

eof
}

#
# === main script starts here ===
#

# ------------------------------------------------------------
# see if you have the right to access all this stuff
# ------------------------------------------------------------
# if [ `whoami` != 'root' ]; then
#     echo "You must be root to run this script."
#     exit 2
# fi


# ------------------------------------------------------------
# handle Ctrl-C and other stuff
# ------------------------------------------------------------
trap 'errcheck "${0##*/} killed!" ; \
      exit 1' \
      9 15

# ------------------------------------------------------------
# see if everything is accessible
# ------------------------------------------------------------
checkfor mkdir rsync gzip mail cp echo cat  # uuencode 

# ------------------------------------------------------------
# handle command line parameters (flags)
# ------------------------------------------------------------
while [ "$1" != "" ]; do
    case $1 in
        -v | --verbose )        VERBOSE="blablah"
                                ;;
        -c | --config )         shift
                                CONFIG_FILE="$1"
                                read_config_file
                                ;;
        -h | -? | --help )      usage
                                exit 2
                                ;;
        * )                     usage
                                exit 1
    esac
    shift
done

# ------------------------------------------------------------
# set some variables
# ------------------------------------------------------------

# Get the system name (without domain suffix)
#
NAME=${HOSTNAME%%.*}

# One "general" log file
# to keep track of date/time & success/failure
# (one line per event)
#
LOGFILE=${LOGDIR}/${NAME}.${PREFIX}.bkup2net

# "individual" log files, a pair for each backup process
# The filenames contain hostname & date/time, so they do not
# get overwritten when multiple backups are done the same day
#
LOGNAME=${LOGFILE}.`date +%Y%m%dT%H%M`
STDOUT=${LOGNAME}.ok
STDERR=${LOGNAME}.err
DIFF=${LOGNAME}.diff


# ------------------------------------------------------------
# Check if log directory exists, exit if problem
# FIXME: we cannot use 'errcheck' here since it uses $LOGDIR ;-)
# ------------------------------------------------------------
checkdir $LOGDIR 
logging "Logfile is $LOGFILE."


# ------------------------------------------------------------
# Check if target directory exists, exit if problem
# ------------------------------------------------------------
checkdir $DEST


# ------------------------------------------------------------
# Ah, finally ... here we go - !
# ------------------------------------------------------------

DATE=`date "+%Y%m%dT%H%M%S"`
DO_IT="rsync -azP $EXCLUDE --delete --delete-excluded --modify-window=1 --link-dest=${DEST}/${PREFIX}-current $SRC ${DEST}/${PREFIX}-${DATE}"

logging "Executing: '${DO_IT}'"
$DO_IT > $STDOUT 2> $STDERR
ERRCNT=$?
logging "rysnc done, status: $ERRCNT"

rm -f ${DEST}/${PREFIX}-current || errcheck "Problem during 'rm -f ${DEST}/${PREFIX}-current' !"
ln -sf ${DEST}/${PREFIX}-${DATE} ${DEST}/${PREFIX}-current || errcheck "Problem during 'ln -sf ${DEST}/${PREFIX}-${DATE} ${DEST}/${PREFIX}-current' !"
logging "Linking done, status: $ERRCNT"


# ------------------------------------------------------------
# Error => mail to backup-admin
# ------------------------------------------------------------
if [ $ERRCNT -gt 0 ] ; then
    mail -s "$NAME-Backup ERROR!" $MAILTO < $STDERR
else
    #cat $STDOUT | gzip | uuencode backup-ok-`date --iso-8601=min`.gz | \
    #mail -s "$NAME-Backup OK!" $MAILTO
   # remove empty error listings
   [ ! -s $STDERR ] && rm $STDERR
fi

# compress logfile
gzip $STDOUT    

if [ $VERBOSE ] ; then echo `date --iso-8601=sec`", Backup script ended." ; fi

exit 0

