Scalix Backup

Aus Neobiker's Wiki
Version vom 20. August 2009, 07:21 Uhr von Neobiker (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Scalix Backup

Skript zum sichern der Scalix Mailboxen und Scalix Installation.

#!/bin/sh
###############################################################################
# sxbackup:
#   a backup script for scalix mail servers
#
#   This script is used to backup Scalix mail servers; it exports each
#   user to a bzip2 compressed file using the 'sxmboxexp' command, then
#   duplicates the scalix data directory using rsync.
#
#   Before using this program you should set the values of the variables
#   below to match your server/preferences.
#
#   For detailed descriptions of the available command line switches,
#   execute the program with the -h flag.
#
#
#   Copyright (C) 2006 Jon Allie <jon@jonallie.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
#
#
#
# ------------------------------ Modifications ----------------------------
#
# Ianaré Sévi <ianare@gmail.com> last modified on 2006-10-13:
#
#   Combined various incarnations and patches of the original script
#   found here:  http://www.scalix.com/community/viewtopic.php?t=1922
#   into a fully working script. Huge thanks to all the original
#   contributors - I am but a shadow in their footsteps.
#
#   Added -r option and associated programming to allow rotation of backups
#   based on the day of the week (7 working backups)
#
#   Added -c option and associated programming to allow backing up of system
#   configuration files in case of complete hardware failure for example.
#
#   Added various error checking.
#
###############################################################################



### Main variables:
#   You MUST modify these for the script to work!
#
MAILNODE=$(omshowmn | grep '**' | tr -d \t | cut -f 3)
backuproot=/var/opt/scalix/backup
ROOT_BACKUP_DIR=/var/opt/scalix/backup
SCALIX_DIR=/var/opt/scalix/${MAILNODE:0:1}${MAILNODE: -1:1}
SCALIX_BIN=/opt/scalix/bin
LOGFILE=/var/log/sxbackup.log
USERFILE=/tmp/userfile.$$
DATE=`date +"%Y-%m-%d"`
PROCESS_BLOCK_SIZE=5
ROTATE_BACKUP=Y
BACKUP_CONFIGURATION=Y

### Configuration file locations:
#   Modify these if backing up configuration files.
#   The entire directory contents will be recursively tar'ed.
#   Use a blank value to skip.
#
CONF_MAIL=/etc/mail
CONF_SYSCONFIG=
CONF_HTTPD=/etc/apache2
CONF_AV=/etc/clamav
CONF_STUNNEL=
CONF_RULESET=
CONF_OTHER=


### function declarations

function usage
{
printf $"
Usage: sxbackup [-h] [-b backup dir] [-d scalix data dir] [-s scalix bin dir]
                [-l logfile] [-u user file] [-m mailnode] [-r rotate backups (Y|N)]
                [-c backup configuration files (Y|N)]

  sxbackup comes with ABSOLUTELY NO WARRANTY.  This is free software, and you
  are welcome to redistribute it under certain conditions.  See the GNU
  General Public Licence for details.

sxbackup is a shell script to perform both user level and system level backups
of a Scalix mail server. User mailboxes are backed up via the 'sxmboxexp' utility
and are stored in a configurable backup directory in a subdirectory named the
same as the mailnode being backed up. Systems level backups are performed by
copying the whole Scalix data dir (usually /var/opt/scalix) to a backup directory
using rysnc.

Most options can be configured by setting the values of the variables in the script
or can be passed to the script at runtime

Options:
    -h                  : print this message and exit

    -m <mailnode>       : mailnode to dump users from

    -b <backup dir>     : backup directory. This directory will store both the user and
                        system level backups. User backups are stored in a subdirectory
                        under this directory users/<mailnode>/<userfile>.

    -d <scalix dir>     : scalix data dir. Defaults to /var/opt/scalix

    -s <bin dir>        : scalix bin dir. Contains scalix utility binaries. Defaults to
                        /opt/scalix/bin

    -l <logfile>        : path to a logfile for logging backup actions.

    -u <userfile>       : userfile. This file is created during the user mailbox
                        backup. Defaults to /tmp/userfile.[pid]

    -r <Y|N>            : whether or not to rotate backups on 7 day schedule.

    -c <Y|N>            : whether or not to backup configuration files.


Copyright (C) 2006 by Jon Allie <jon@jonallie.com>

With contributions from Scalix.com forum members.\n\n"

exit ${1:-0}
}

function badInput
{
    echo "Use -h for more information."
    echo
    exit 1
}

function log_it
{
    echo "[ `date` ]: $*" >>$LOGFILE
}

function echo_and_log
{
    echo $*
    log_it $*
}

function clean_up
{
    echo_and_log "Cleaning up temporary files"
    [ -f $USERFILE ] && rm -f $USERFILE
}

function restart_on_error
{
    echo_and_log "Error: $*"
    start_scalix
    clean_up
    exit 1
}

function exit_with_error
{
    echo_and_log "Error: $*"
    clean_up
    exit 1
}

function start_scalix
{
    log_it "Starting Scalix services"
    /etc/init.d/scalix start
    [ "$?" != "0" ] && exit_with_error "Error restarting scalix services"
}

function pre_check
{
    # look for scalix directories
    for dir in $SCALIX_BIN $SCALIX_DIR
    do
        [ -d $dir ] || exit_with_error "A required Scalix directory $dir doesn't exist."
    done

    # make sure that the $BACKUP_DIR structure exists, try to create it if not.
    for dir in $BACKUP_DIR $CONFIG_DIR $BACKUP_DIR/users $BACKUP_DIR/users/$MAILNODE
    do
        if [ ! -d $dir ]
        then
            log_it "$dir doesn't exist: creating it"
            mkdir -p $dir || exit_with_error "Unable to create required directory $dir"
        fi
    done

    # clear out user backup files
    rm -rf $BACKUP_DIR/users/$MAILNODE/*

    # clear out timestamp
    rm -f $BACKUP_DIR/created:*

    # make new timestamp
    touch $BACKUP_DIR/created:\ $DATE
}

function dump_users
{
    # index for processing block
    let i=1
    let index=1

    # Build userfile
    $SCALIX_BIN/omshowu -m $MAILNODE|cut -f1 -d'/' >$USERFILE
    [ "$?" != "0" ] && exit_with_error "Unable to build userfile $USERFILE from mailnode $MAILNODE"

    # Loop over userfile and create backups. Use 'while read' instead of 'for' because of spaces in names
    while read sc_username
    do
        # Create a version of the username without spaces and other crappy characters
        nospaces=`echo $sc_username|sed -e "s/[ \.;=*'?_!]//g"`

        BACKUP_FILE="$BACKUP_DIR/users/$MAILNODE/${nospaces}-mbox.bz2"
        BACKUP_LIST="$BACKUP_DIR/users/$MAILNODE/${nospaces}-list"

        if [ $i -le $PROCESS_BLOCK_SIZE ]
        then
            echo "Adding Process: Number $index of $PROCESS_BLOCK_SIZE -- User: $sc_username"
            ## BACKGROUND PROCESS
            #$SCALIX_BIN/omcpoutu -n "$sc_username/$MAILNODE" -f - -F | bzip2 | cat > $BACKUP_FILE || echo_and_log "Error: Unable to complete backup operation for $sc_username" &
            $SCALIX_BIN/sxmboxexp --force -u "$sc_username" -l $BACKUP_LIST -a - | bzip2 | cat > $BACKUP_FILE || echo_and_log "Error: Unable to complete backup operation for $sc_username" &
            PIDs[$index]=$!
            let i+=1
            let index=$i
        else
            echo "Process block is full."
            echo "Waiting for first complete process..."
            while [ $i -gt $PROCESS_BLOCK_SIZE ]
            do
                for p in `seq 1 $PROCESS_BLOCK_SIZE`
                do
                        ps ${PIDs[$p]} > /dev/null
                        if [ "$?" != "0" ]
                        then
                                echo_and_log "Process number $p of $PROCESS_BLOCK_SIZE has completed. -- User: $sc_username"
                                unset PIDs[$p]
                                let index=$p
                                #echo "Adding Process: Number $index of $PROCESS_BLOCK_SIZE -- User: $sc_username"
                                ## BACKGROUND PROCESS
                                #$SCALIX_BIN/omcpoutu -n "$sc_username/$MAILNODE" -f - -F | bzip2 | cat > $BACKUP_FILE || echo_and_log "Error: Unable to complete backup operation for $sc_username" &
                                $SCALIX_BIN/sxmboxexp -u "$sc_username" -l $BACKUP_LIST -a - | bzip2 | cat > $BACKUP_FILE || echo_and_log "Error: Unable to complete backup operation for $sc_username" &
                                PIDs[$index]=$!
                                break 2
                        fi
                done
            done
        fi
    done < $USERFILE
    echo "All processes have been added."
    echo "Waiting for those still running..."
    wait
    echo_and_log "All users done!"
}

function sync_files
{
    echo_and_log "Beginning rsync of $SCALIX_DIR to $BACKUP_DIR"
    rsync -a -q --delete --link-dest=${LINK_DIR}/ $SCALIX_DIR $BACKUP_DIR/ >>$LOGFILE

    if [ "$?" != "0" ]
    then
        restart_on_error "Rsync operation of $SCALIX_DIR to $BACKUP_DIR did not complete successfully"
    else
        echo_and_log "Completed rsync of $SCALIX_DIR to $BACKUP_DIR"
    fi
}

# Mount and Dismount commands for all reasons are in the following functions
# you can also mount windows-shares via smbclient e.g.
# here: mount for writing during backup, and mount readonly afterwards

mounting ()
{
    precom=0
    mount -o remount,rw ${backuproot} || mountfail
}

umounting ()
{
    postcom=0
    mount -o remount,ro ${backuproot} || umountfail
}

mountfail ()
{
  echo >&2 "I can't mount filesystem ${backuproot}"
  exit 1
}

umountfail ()
{
  echo >&2 "I can't unmount filesystem ${backuproot}"
  exit 1
}

# process command line arguments
# -h            : show help
# -b <dir>      : backup directory
# -l <file>     : log file
# -u <userfile> : userfile
# -m <mailnode> : main mailnode
# -d <dir>      : location of the scalix data dir
# -s <dir>      : location of the scalix bin dir
# -r <Y|N>      : rotate backups or not
# -c <Y|N>      : backup config files or not

while getopts hb:l:u:m:s:r:c: opt
do
    case "$opt" in
        h) usage ;;
        b) BACKUP_DIR=$OPTARG ;;
        l) LOGFILE=$OPTARG ;;
        u) USERFILE=$OPTARG ;;
        m) MAILNODE=$OPTARG ;;
        d) SCALIX_DIR=$OPTARG ;;
        s) SCALIX_BIN=$OPTARG ;;
        r) ROTATE_BACKUP=$OPTARG ;;
        c) BACKUP_CONFIGURATION=$OPTARG ;;
        \?) badInput ;;
    esac
done

# validate that all required options are set
for x in "$LOGFILE" "$ROOT_BACKUP_DIR" "$MAILNODE" "$SCALIX_DIR" "$SCALIX_BIN" "$USERFILE" "$ROTATE_BACKUP" "$BACKUP_CONFIGURATION"
do
    if [ -z "$x" ]
    then
        echo "A required parameter is missing, please check your command arguments."
        badInput
    fi
done

# mounting $backuproot write enable
mounting

# rotate backups or not
if [ "$ROTATE_BACKUP" = "Y" ]
    then
        DAYWEEK=`date +%A`
        DAYLINK=`date +%A -d '1 day ago'`
        BACKUP_DIR=$ROOT_BACKUP_DIR/$DAYWEEK
        LINK_DIR=$ROOT_BACKUP_DIR/$DAYLINK
    else
        BACKUP_DIR=$ROOT_BACKUP_DIR
fi

if [ "$BACKUP_CONFIGURATION" = "Y" ]
    then
        CONFIG_DIR=$BACKUP_DIR/configs
    else
        CONFIG_DIR=$BACKUP_DIR
fi

# initialize the logfile
>$LOGFILE

# call pre_check function to verify backup directory structure
pre_check

# backup configuration directories or not
if [ "$BACKUP_CONFIGURATION" = "Y" ]
    then
        # clear out old file first
        rm -f $CONFIG_DIR/* || echo "No backup config file to delete."

        for dir in $CONF_MAIL $CONF_SYSCONFIG $CONF_HTTPD $CONF_AV $CONF_STUNNEL $CONF_RULESET $CONF_OTHER
        do
            # don't process if no value given
            if [ ! -z "$dir" ]
            then
                # directory must exist
                if [ ! -d $dir ]
                then
                    echo_and_log "Config dir $dir doesn't exist: aborting!"
                else
                    # tar 'em up!
                    end=`expr match "$dir" '/.*/'`
                    tar -cf $CONFIG_DIR/${dir:$end}.tar $dir 2>&1| grep -v "^tar: Removing leading "

                    echo_and_log "tared $dir to $CONFIG_DIR/${dir:$end}.tar"
                fi
            fi
        done
fi

# call dump_users function to make backups of user mailboxes
dump_users

# stop scalix before doing the rsync
echo_and_log "Stopping scalix services"
/etc/init.d/scalix stop
[ "$?" != "0" ] && exit_with_error "Unable to halt scalix services"

# call sync_files function to make a backup of the $SCALIX_DIR
sync_files

# restart scalix services
start_scalix

# explicily call the clean_up function to erase leftover files
clean_up

# mounting $backuproot readonly
umounting

# exit successfully
echo_and_log "All operations complete"
exit 0