380 lines
9.6 KiB
Bash
Executable file
380 lines
9.6 KiB
Bash
Executable file
#!/bin/bash
|
|
#
|
|
# script to do drive mirroring of another machine
|
|
# Copyright 2002-5, David Lane for Egressive Limited, www.egressive.com
|
|
#
|
|
#
|
|
VERSION=0.2
|
|
#
|
|
# default log file
|
|
EGRS_NAME=`basename $0`
|
|
#echo $EGRS_NAME
|
|
EGRS_DIR=/etc/egscripts/egrsync
|
|
EGRS_CMD=$EGRS_DIR/egrsync
|
|
EGRS_CONF_DIR=$EGRS_DIR
|
|
SITE_CONF=$EGRS_DIR/site.conf
|
|
#
|
|
# this provides values for DST_NAME and EMAIL
|
|
. $SITE_CONF
|
|
#
|
|
LOGS=/var/log
|
|
LOG=$LOGS/egrsync.log
|
|
RUNDIR=$LOGS/egrsync
|
|
# required programs
|
|
MAIL=`which mail`
|
|
GREP=`which grep`
|
|
LS=`which ls`
|
|
ID=`which id`
|
|
DATE=`which date`
|
|
DF=`which df`
|
|
GZIP=`which gzip`
|
|
RM=`which rm`
|
|
LN=`which ln`
|
|
CUT=`which cut`
|
|
RSYNC=`which rsync`
|
|
SSH=`which ssh`
|
|
# determine today's date
|
|
TODAY=`$DATE '+%Y-%m-%d-%a'`
|
|
# determine today's date
|
|
NOW=`$DATE '+%H-%M-%S'`
|
|
# a timestamp for logging purposes
|
|
TIMESTAMP=`$DATE '+%Y-%m-%d %H:%M.%S'`
|
|
# temporary holding point for email
|
|
TMP_DIR=/tmp
|
|
TMP_EMAIL=$TMP_DIR/$EGRS_NAME"_tmp_email_"$TODAY.$TIME
|
|
#
|
|
#==========================================
|
|
# The Functions - these have to be defined
|
|
# before they're called! Note, refer
|
|
# to them without the "()" and provide
|
|
# up to one argument, referred to as "$@"
|
|
# in the function...
|
|
#==========================================
|
|
#
|
|
# function to direct a message...
|
|
message() {
|
|
#
|
|
# a timestamp for logging purposes
|
|
timestamp
|
|
if test -w $LOG ; then
|
|
echo "$EGRS_NAME: $TIMESTAMP $@" >> $LOG
|
|
fi
|
|
if test -w $TMP_EMAIL ; then
|
|
echo "$EGRS_NAME: $TIMESTAMP $@" >> $TMP_EMAIL
|
|
fi
|
|
verbose "$TIMESTAMP $@"
|
|
}
|
|
#
|
|
# function to direct a message...
|
|
verbose() {
|
|
if test $VERBOSE ; then
|
|
echo "$@"
|
|
fi
|
|
}
|
|
#
|
|
# insert a blank line into the log and on the console
|
|
insert_blank() {
|
|
echo "" >> $TMP_EMAIL
|
|
verbose ""
|
|
}
|
|
#
|
|
# update date and time info..
|
|
today() {
|
|
# determine today's date
|
|
TODAY=`$DATE '+%Y-%m-%d-%a'`
|
|
}
|
|
now() {
|
|
# determine today's date
|
|
NOW=`$DATE '+%H-%M-%S'`
|
|
}
|
|
timestamp() {
|
|
# a timestamp for logging purposes
|
|
TIMESTAMP=`date '+%Y-%m-%d %H:%M.%S'`
|
|
}
|
|
#
|
|
# create the temporary email file
|
|
create_tmp_email() {
|
|
if test -d $TMP_DIR ; then
|
|
if test -w $TMP_DIR ; then
|
|
touch $TMP_EMAIL 2>&1
|
|
else
|
|
error "Email tmp directory $TMP_DIR is not writable"
|
|
fi
|
|
else
|
|
error "Email tmp directory $TMP_DIR does not exist"
|
|
fi
|
|
|
|
if test -w $TMP_EMAIL ; then
|
|
message "created temporary email $TMP_EMAIL"
|
|
else
|
|
error "Failed to create temporary email $TMP_EMAIL"
|
|
fi
|
|
}
|
|
#
|
|
# send the contents of the temporary file to the
|
|
# designated report recipient
|
|
send_email_report() {
|
|
if test -f $TMP_EMAIL ; then
|
|
message "sending email report to $EMAIL_TO"
|
|
if test $ERROR_STATUS == 1 ; then
|
|
EMAIL_SUBJ="[ERROR] $SRC -> $DST Rsync"
|
|
else
|
|
EMAIL_SUBJ="[SUCCESS] $SRC -> $DST Rsync Report"
|
|
fi
|
|
# check space again to see how close things are to full
|
|
|
|
message "Printing disk space for reference purposes:"
|
|
DISK_SPACE=`$DF`
|
|
message "$DISK_SPACE"
|
|
RES=`$MAIL -s "$EMAIL_SUBJ" $EMAIL_TO < $TMP_EMAIL`
|
|
if test -z $RES ; then
|
|
if test $ERROR_STATUS == 1 ; then
|
|
message "Error email report successfully sent"
|
|
else
|
|
message "Email report successfully sent"
|
|
fi
|
|
else
|
|
if ! test $ERROR_STATUS == 1 ; then
|
|
error "Email report send failed with this message: $RES"
|
|
fi
|
|
fi
|
|
if test -w $TMP_EMAIL ; then
|
|
$RM $TMP_EMAIL 2>&1
|
|
else
|
|
if ! test $ERROR_STATUS == 1 ; then
|
|
error "Failed to remove email message file, $TMP_EMAIL: permission denied."
|
|
fi
|
|
fi
|
|
if test -f $TMP_EMAIL ; then
|
|
error "Failed to remove email message file $TMP_EMAIL for an unknown reason"
|
|
else
|
|
message "successfully removed temporary email $TMP_EMAIL"
|
|
fi
|
|
else
|
|
if ! test $ERROR_STATUS == 1 ; then
|
|
error "Email message file, $TMP_EMAIL, does not exist."
|
|
fi
|
|
fi
|
|
}
|
|
#
|
|
# function to direct an error...
|
|
error() {
|
|
#
|
|
# recognise that the system experienced
|
|
# an error and send out a special email, and halt
|
|
# the program!
|
|
timestamp
|
|
ERROR_STATUS=1
|
|
#
|
|
# get current user details
|
|
USER_DETAILS=`$ID`
|
|
if test -w $LOG ; then
|
|
echo "$EGRS_NAME: **ERROR** $TIMESTAMP $@" >> $LOG
|
|
echo "$EGRS_NAME: user details - $USER_DETAILS" >> $LOG
|
|
fi
|
|
if test -w $TMP_EMAIL ; then
|
|
echo "$EGRS_NAME: **ERROR** $TIMESTAMP $@" >> $TMP_EMAIL
|
|
echo " user details: $USER_DETAILS" >> $LOG
|
|
fi
|
|
verbose "$TIMESTAMP **ERROR** $@"
|
|
verbose " user details: $USER_DETAILS"
|
|
}
|
|
|
|
#
|
|
# build excludes list
|
|
build_excludes() {
|
|
message "building excludes"
|
|
for PAT in $EXCLUDE
|
|
do
|
|
EXCLUDES="$EXCLUDES --exclude $PAT"
|
|
done
|
|
if test -z $NO_BACKUP_DIR ; then
|
|
EXCLUDES="$EXCLUDES --exclude $NO_BACKUP_DIR"
|
|
fi
|
|
#echo "Excludes = $EXCLUDES"
|
|
}
|
|
#
|
|
# if the server could be at more than one address,
|
|
# we can identify a series of IPs... and here we pick the
|
|
# right one on the occasion
|
|
pick_server() {
|
|
message "searching for the right IP from $TEST_IPS"
|
|
for TEST_IP in $TEST_IPS
|
|
do
|
|
message "checking $TEST_IP..."
|
|
# ask the machine to tell us its hostname...
|
|
# if we don't have access via ssh, it'll time out.
|
|
# If we do, it'll probably return the hostname of
|
|
# the server, and voila, we have our host.
|
|
RES=`$SSH $USER@$TEST_IP hostname`
|
|
message "response: $RES"
|
|
#
|
|
TEST=`echo $RES | grep -c $SERVER`
|
|
if test $TEST == 1 ; then
|
|
IP=$TEST_IP
|
|
message "Picking $IP"
|
|
fi
|
|
done
|
|
}
|
|
#
|
|
# function to perform the rsyncing
|
|
do_rsync() {
|
|
build_excludes
|
|
if ! test $TEST_IPS == 0 ; then
|
|
pick_server
|
|
if test $IP == 0 ; then
|
|
error "didn't find a valid server - perhaps TEST_IPS is set unnecessarily?"
|
|
else
|
|
SERVER=$IP
|
|
fi
|
|
fi
|
|
if test -d $BASEDIR ; then
|
|
if test -w $BASEDIR ; then
|
|
message "performing rsync of $SERVER..."
|
|
touch $RUNDIR/$SERVER-start
|
|
for DIR in $DIRS ;
|
|
do
|
|
TEST=`$SSH $USER@$SERVER $LS -d $DIR`
|
|
if test $TEST == $DIR ; then
|
|
message "starting $DIR on $SERVER (as $USER) into $BASEDIR..."
|
|
#message " with a nice value of $NICE"
|
|
CMD="$RSYNC $FLAGS $EXCLUDES $USER@$SERVER:$DIR $BASEDIR"
|
|
if test $DRY_RUN == 1 ; then
|
|
message "dry run - not running $CMD"
|
|
else
|
|
message "running command $CMD"
|
|
# run the actual command
|
|
RES=`$CMD >> $LOG`
|
|
message "rsync output: $RES"
|
|
if ! test "$?" == "0" ; then
|
|
error "-------rsync ended with error, error: $? ----------"
|
|
error "RSYNC EXIT CODE: $?"
|
|
else
|
|
message "+++++++rsync of $DIR successfully finished++++++++"
|
|
fi
|
|
fi
|
|
message "done with $DIR."
|
|
else
|
|
message "WARNING: $DIR does not exist"
|
|
fi
|
|
done
|
|
touch $RUNDIR/$SERVER-stop
|
|
else
|
|
error "local directory $BASEDIR is not writable!"
|
|
fi
|
|
else
|
|
error "local directory $BASEDIR does not exist!"
|
|
fi
|
|
}
|
|
#========================================
|
|
# The Error Checking
|
|
#========================================
|
|
insert_blank
|
|
message "Starting $EGRS_NAME..."
|
|
#
|
|
# first, check that all the necessary files and stuff are there and usable
|
|
#
|
|
# if the log doesn't exist, create it
|
|
if ! test -f $LOG ; then
|
|
message "creating non-existent log file $LOG"
|
|
RET=`touch $LOG 2>&1 /dev/null`
|
|
TEST=`echo $RET | $GREP -c "Permission denied" -`
|
|
if test $TEST == 1 ; then
|
|
error "Failed to create log file $LOG, user cannot write to that directory"
|
|
fi
|
|
fi
|
|
# checking whether it's there an is writable
|
|
if ! test -w $LOG ; then
|
|
error "Log file $LOG not writable"
|
|
fi
|
|
|
|
#========================================
|
|
# The Functional Part of the Script
|
|
#========================================
|
|
# set variable defaults
|
|
ERROR_STATUS=0 # initially assume no errors
|
|
#
|
|
#
|
|
# control loop, using external arguments
|
|
#
|
|
# process command line arguments
|
|
#
|
|
# set some default values, so that we can test if they've
|
|
# been set in the configuration file...
|
|
VERBOSE=0
|
|
CONF=0
|
|
DRY_RUN=0
|
|
IP=0
|
|
TEST_IPS=0
|
|
NICE=-1
|
|
#
|
|
# set the default mode in case somebody figures out how to get
|
|
# past the options below...
|
|
MODE=help
|
|
#
|
|
# cycle through the commandline options
|
|
while test $# -ne 0 ; do # while there are arguments
|
|
case $1 in
|
|
--verbose|-v)
|
|
VERBOSE=1
|
|
verbose "setting verbosity to true"
|
|
;;
|
|
--dryrun)
|
|
verbose "setting dryrun to ON"
|
|
DRY_RUN=1
|
|
;;
|
|
#
|
|
# these are the primary (and mutually exclusive) modes
|
|
# of operation for this system...
|
|
--help|-?|?|-h)
|
|
MODE=help
|
|
verbose "setting mode to $MODE"
|
|
;;
|
|
*)
|
|
TEST=`echo $1 | $GREP -c '^-'`
|
|
if ! test $TEST == 1 ; then
|
|
CONF=$1
|
|
verbose "using configuration file $CONF"
|
|
MODE=do_rsync
|
|
fi
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
#
|
|
# read in config info, from the config
|
|
# file provided, or, if none is provided
|
|
# from the default file...
|
|
if test -r $CONF ; then
|
|
. $CONF
|
|
message "reading config file: $CONF"
|
|
else
|
|
error "config file $CONF does not exist!"
|
|
fi
|
|
#
|
|
# Now actually try to do the job we've been asked to do...
|
|
#
|
|
case $MODE in
|
|
do_rsync)
|
|
create_tmp_email
|
|
do_rsync
|
|
insert_blank
|
|
send_email_report
|
|
;;
|
|
help)
|
|
echo ""
|
|
echo "$EGRS_NAME, version $VERSION, copyright 2002-2005 Egressive Ltd, www.egressive.com"
|
|
echo "==================="
|
|
echo "usage: $EGRS_NAME [--dryrun] [-v|--verbose] confpath"
|
|
echo ""
|
|
echo "Uses rsync to mirror a series of paths (excluding some files if desired)"
|
|
echo ""
|
|
echo "confpath is the full path to a valid $EGRS_NAME configuration file"
|
|
echo "-v or --verbose - give extra feedback on progress to stdout"
|
|
echo "--dryrun - do everything *but* don't actually initiate rsync"
|
|
echo "-? or --help - display this help information"
|
|
echo ""
|
|
exit 1
|
|
;;
|
|
esac
|
|
exit 0
|