2013-07-16 23:10:27 +02:00
#!/bin/bash
###### Remote (or local) backup script for files & databases
###### (L) 2013 by Orsiris "Ozy" de Jong (www.netpower.fr)
2014-09-22 22:45:18 +02:00
AUTHOR = "(L) 2013-2014 by Orsiris \"Ozy\" de Jong"
CONTACT = "http://www.netpower.fr/osync - ozy@netpower.fr"
PROGRAM_VERSION = 1.84preRC4
2014-11-27 15:35:56 +01:00
PROGRAM_BUILD = 2711201404
2014-09-22 22:45:18 +02:00
## type doesn't work on platforms other than linux (bash). If if doesn't work, always assume output is not a zero exitcode
if ! type -p " $BASH " > /dev/null
then
echo "Please run this script only with bash shell. Tested on bash >= 3.2"
exit 127
fi
## allow debugging from command line with preceding ocsync with DEBUG=yes
if [ ! " $DEBUG " = = "yes" ]
then
DEBUG = no
SLEEP_TIME = 1
else
SLEEP_TIME = 10
fi
2013-07-16 23:10:27 +02:00
SCRIPT_PID = $$
LOCAL_USER = $( whoami)
LOCAL_HOST = $( hostname)
## Default log file until config file is loaded
2013-11-02 18:55:17 +01:00
if [ -w /var/log ]
2013-09-22 12:04:09 +02:00
then
LOG_FILE = /var/log/obackup.log
else
LOG_FILE = ./obackup.log
fi
## Default directory where to store run files
2013-11-02 18:55:17 +01:00
if [ -w /dev/shm ]
2013-09-22 12:04:09 +02:00
then
RUN_DIR = /dev/shm
2013-11-02 18:55:17 +01:00
elif [ -w /tmp ]
2013-09-22 12:04:09 +02:00
then
RUN_DIR = /tmp
2013-11-02 18:55:17 +01:00
elif [ -w /var/tmp ]
2013-09-22 12:04:09 +02:00
then
RUN_DIR = /var/tmp
else
RUN_DIR = .
fi
2013-07-16 23:10:27 +02:00
2014-11-27 14:40:30 +01:00
## Working directory for partial downloads
PARTIAL_DIR = ".obackup_workdir_partial"
2013-07-16 23:10:27 +02:00
## Log a state message every $KEEP_LOGGING seconds. Should generally not be equal to soft or hard execution time so your log won't be unnecessary big.
KEEP_LOGGING = 1801
2014-09-22 22:45:18 +02:00
## Correct output of all system commands (language agnostic)
export LC_ALL = C
2013-07-16 23:10:27 +02:00
## Global variables and forked command results
DATABASES_TO_BACKUP = "" # Processed list of DBs that will be backed up
DATABASES_EXCLUDED_LIST = "" # Processed list of DBs that won't be backed up
TOTAL_DATABASES_SIZE = 0 # Total DB size of $DATABASES_TO_BACKUP
DIRECTORIES_RECURSE_TO_BACKUP = "" # Processed list of recursive directories that will be backed up
DIRECTORIES_EXCLUDED_LIST = "" # Processed list of recursive directorires that won't be backed up
DIRECTORIES_TO_BACKUP = "" # Processed list of all directories to backup
TOTAL_FILES_SIZE = 0 # Total file size of $DIRECTORIES_TO_BACKUP
2013-11-02 18:55:17 +01:00
# $RUN_DIR/obackup_remote_os_$SCRIPT_PID Result of remote OS detection
2013-09-22 12:04:09 +02:00
# $RUN_DIR/obackup_dblist_$SCRIPT_PID Databases list and sizes
# $RUN_DIR/obackup_dirs_recurse_list_$SCRIPT_PID Recursive directories list
# $RUN_DIR/obackup_local_sql_storage_$SCRIPT_PID Local free space for sql backup
# $RUN_DIR/obackup_local_file_storage_$SCRIPT_PID Local free space for file backup
# $RUN_DIR/obackup_fsize_$SCRIPT_PID Size of $DIRECTORIES_TO_BACKUP
# $RUN_DIR/obackup_rsync_output_$SCRIPT_PID Output of Rsync command
# $RUN_DIR/obackup_config_$SCRIPT_PID Parsed configuration file
# $RUN_DIR/obackup_run_local_$SCRIPT_PID Output of command to be run localy
# $RUN_DIR/obackup_run_remote_$SCRIPT_PID Output of command to be run remotely
2013-07-16 23:10:27 +02:00
2014-09-22 22:45:18 +02:00
ALERT_LOG_FILE = $RUN_DIR /obackup_lastlog # This is the path where to store a temporary log file to send by mail
2014-03-23 21:59:13 +01:00
2013-07-16 23:10:27 +02:00
function Log
{
2013-11-02 18:55:17 +01:00
echo -e " TIME: $SECONDS - $1 " >> " $LOG_FILE "
2013-07-16 23:10:27 +02:00
if [ $silent -eq 0 ]
then
2013-09-03 21:31:41 +02:00
echo -e " TIME: $SECONDS - $1 "
2013-07-16 23:10:27 +02:00
fi
}
function LogError
{
Log " $1 "
error_alert = 1
}
2014-09-22 22:45:18 +02:00
function LogDebug
{
if [ " $DEBUG " = = "yes" ]
then
Log " $1 "
fi
}
2013-07-16 23:10:27 +02:00
function TrapError
{
local JOB = " $0 "
local LINE = " $1 "
local CODE = " ${ 2 :- 1 } "
if [ $silent -eq 0 ]
then
echo " /!\ Error in ${ JOB } : Near line ${ LINE } , exit code ${ CODE } "
fi
}
function TrapStop
{
LogError " /!\ WARNING: Manual exit of backup script. Backups may be in inconsistent state."
2013-07-17 11:31:21 +02:00
exit 1
}
function TrapQuit
{
2013-09-03 21:31:41 +02:00
# Kill all child processes
2013-09-22 12:04:09 +02:00
if type -p pkill > /dev/null 2>& 1
then
pkill -TERM -P $$
2013-11-02 18:55:17 +01:00
elif [ " $LOCAL_OS " = = "msys" ] || [ " $OSTYPE " = = "msys" ]
2013-09-22 12:04:09 +02:00
then
## This is not really a clean way to get child process pids, especially the tail -n +2 which resolves a strange char apparition in msys bash
for pid in $( ps -a | awk '{$1=$1}$1' | awk '{print $1" "$2}' | grep " $$ $" | awk '{print $1}' | tail -n +2)
do
kill -9 $pid > /dev/null 2>& 1
done
else
for pid in $( ps -a --Group $$ )
do
kill -9 $pid
done
fi
2013-09-03 21:31:41 +02:00
2013-07-18 13:31:17 +02:00
if [ $error_alert -ne 0 ]
then
SendAlert
2013-08-18 11:58:55 +02:00
CleanUp
2013-07-18 13:31:17 +02:00
LogError "Backup script finished with errors."
exit 1
else
2013-08-18 11:58:55 +02:00
CleanUp
2013-07-18 13:31:17 +02:00
Log "Backup script finshed."
exit 0
fi
2013-07-16 23:10:27 +02:00
}
function Spinner
{
if [ $silent -eq 1 ]
then
return 1
fi
case $toggle
in
1)
echo -n $1 " \ "
echo -ne "\r"
toggle = "2"
; ;
2)
echo -n $1 " | "
echo -ne "\r"
toggle = "3"
; ;
3)
echo -n $1 " / "
echo -ne "\r"
toggle = "4"
; ;
*)
echo -n $1 " - "
echo -ne "\r"
toggle = "1"
; ;
esac
}
function Dummy
{
exit 1;
}
function StripQuotes
{
echo $( echo $1 | sed "s/^\([\"']\)\(.*\)\1\$/\2/g" )
}
function EscapeSpaces
{
echo $( echo $1 | sed 's/ /\\ /g' )
}
function CleanUp
{
2013-07-17 11:31:21 +02:00
if [ " $DEBUG " != "yes" ]
then
2013-10-12 19:12:15 +02:00
rm -f " $RUN_DIR /obackup_remote_os_ $SCRIPT_PID "
2013-09-22 12:04:09 +02:00
rm -f " $RUN_DIR /obackup_dblist_ $SCRIPT_PID "
rm -f " $RUN_DIR /obackup_local_sql_storage_ $SCRIPT_PID "
rm -f " $RUN_DIR /obackup_local_file_storage_ $SCRIPT_PID "
rm -f " $RUN_DIR /obackup_dirs_recurse_list_ $SCRIPT_PID "
rm -f " $RUN_DIR /obackup_fsize_ $SCRIPT_PID "
rm -f " $RUN_DIR /obackup_rsync_output_ $SCRIPT_PID "
rm -f " $RUN_DIR /obackup_config_ $SCRIPT_PID "
rm -f " $RUN_DIR /obackup_run_local_ $SCRIPT_PID "
rm -f " $RUN_DIR /obackup_run_remote_ $SCRIPT_PID "
2013-07-17 11:31:21 +02:00
fi
2013-07-16 23:10:27 +02:00
}
function SendAlert
{
2014-11-27 14:40:30 +01:00
eval " cat \" $LOG_FILE \" $COMPRESSION_PROGRAM > $ALERT_LOG_FILE "
2014-09-22 22:45:18 +02:00
MAIL_ALERT_MSG = $MAIL_ALERT_MSG $'\n\n' $( tail -n 25 " $LOG_FILE " )
2013-07-16 23:10:27 +02:00
if type -p mutt > /dev/null 2>& 1
then
2014-09-22 22:45:18 +02:00
echo $MAIL_ALERT_MSG | $( type -p mutt) -x -s " Backup alert for $BACKUP_ID " $DESTINATION_MAILS -a " $ALERT_LOG_FILE "
2013-09-22 12:04:09 +02:00
if [ $? != 0 ]
then
Log " WARNING: Cannot send alert email via $( type -p mutt) !!! "
else
Log "Sent alert mail using mutt."
fi
2013-07-16 23:10:27 +02:00
elif type -p mail > /dev/null 2>& 1
2013-09-22 12:04:09 +02:00
then
2014-09-22 22:45:18 +02:00
echo $MAIL_ALERT_MSG | $( type -p mail) -a " $ALERT_LOG_FILE " -s " Backup alert for $BACKUP_ID " $DESTINATION_MAILS
2013-09-22 12:04:09 +02:00
if [ $? != 0 ]
then
Log " WARNING: Cannot send alert email via $( type -p mail) with attachments !!! "
echo $MAIL_ALERT_MSG | $( type -p mail) -s " Backup alert for $BACKUP_ID " $DESTINATION_MAILS
if [ $? != 0 ]
then
Log " WARNING: Cannot send alert email via $( type -p mail) without attachments !!! "
else
Log "Sent alert mail using mail command without attachment."
fi
else
Log "Sent alert mail using mail command."
fi
elif type -p sendemail > /dev/null 2>& 1
then
$( type -p sendemail) -f $SENDER_MAIL -t $DESTINATION_MAILS -u " Backup alert for $BACKUP_ID " -m " $MAIL_ALERT_MSG " -s $SMTP_SERVER -o username $SMTP_USER -p password $SMTP_PASSWORD > /dev/null 2>& 1
2013-07-16 23:10:27 +02:00
if [ $? != 0 ]
then
2013-09-22 12:04:09 +02:00
Log " WARNING: Cannot send alert email via $( type -p sendemail) !!! "
2013-07-16 23:10:27 +02:00
else
Log "Sent alert mail using mail command without attachment."
2013-09-22 12:04:09 +02:00
fi
2013-07-16 23:10:27 +02:00
else
Log "WARNING: Cannot send alert email (no mutt / mail present) !!!"
2014-03-23 17:46:08 +01:00
fi
2014-09-22 22:45:18 +02:00
if [ -f " $ALERT_LOG_FILE " ]
2014-03-23 17:46:08 +01:00
then
2014-09-22 22:45:18 +02:00
rm " $ALERT_LOG_FILE "
2013-07-16 23:10:27 +02:00
fi
}
function LoadConfigFile
{
if [ ! -f " $1 " ]
then
LogError " Cannot load backup configuration file [ $1 ]. Backup cannot start. "
return 1
2013-08-04 16:16:27 +02:00
elif [ [ " $1 " != *".conf" ] ]
2013-07-16 23:10:27 +02:00
then
LogError " Wrong configuration file supplied [ $1 ]. Backup cannot start. "
2013-08-04 16:16:27 +02:00
return 1
2014-09-22 22:45:18 +02:00
else
2013-09-22 12:04:09 +02:00
egrep '^#|^[^ ]*=[^;&]*' " $1 " > " $RUN_DIR /obackup_config_ $SCRIPT_PID "
source " $RUN_DIR /obackup_config_ $SCRIPT_PID "
2013-07-16 23:10:27 +02:00
fi
2014-09-22 22:45:18 +02:00
}
2013-07-16 23:10:27 +02:00
function CheckEnvironment
{
sed --version > /dev/null 2>& 1
if [ $? != 0 ]
then
LogError "GNU coreutils not found (tested for sed --version). Backup cannot start."
return 1
fi
2014-09-22 22:45:18 +02:00
2013-07-16 23:10:27 +02:00
if [ " $REMOTE_BACKUP " = = "yes" ]
then
if ! type -p ssh > /dev/null 2>& 1
then
LogError "ssh not present. Cannot start backup."
return 1
fi
if [ " $BACKUP_SQL " != "no" ]
then
if ! type -p mysqldump > /dev/null 2>& 1
then
LogError "mysqldump not present. Cannot start backup."
return 1
fi
fi
fi
if [ " $BACKUP_FILES " != "no" ]
then
if ! type -p rsync > /dev/null 2>& 1
then
LogError "rsync not present. Backup cannot start."
return 1
fi
fi
}
2014-09-22 22:45:18 +02:00
function GetLocalOS
2013-10-12 19:12:15 +02:00
{
2014-09-22 22:45:18 +02:00
LOCAL_OS_VAR = $( uname -spio 2>& 1)
2013-11-16 12:44:21 +01:00
if [ $? != 0 ]
then
LOCAL_OS_VAR = $( uname -v 2>& 1)
2014-09-22 22:45:18 +02:00
if [ $? != 0 ]
2013-11-16 12:44:21 +01:00
then
LOCAL_OS_VAR = ( $uname )
fi
fi
2013-11-02 18:55:17 +01:00
2014-09-22 22:45:18 +02:00
case $LOCAL_OS_VAR in
*"Linux" *)
LOCAL_OS = "Linux"
; ;
*"BSD" *)
LOCAL_OS = "BSD"
; ;
*"MINGW32" *)
LOCAL_OS = "msys"
; ;
*"Darwin" *)
LOCAL_OS = "MacOSX"
; ;
*)
LogError " Running on >> $LOCAL_OS_VAR << not supported. Please report to the author. "
exit 1
; ;
esac
LogDebug " Local OS: [ $LOCAL_OS_VAR ]. "
}
function GetRemoteOS
{
if [ " $REMOTE_SYNC " = = "yes" ]
2013-10-12 19:12:15 +02:00
then
2014-09-22 22:45:18 +02:00
CheckConnectivity3rdPartyHosts
CheckConnectivityRemoteHost
eval " $SSH_CMD \"uname -spio\" > $RUN_DIR /osync_remote_os_ $SCRIPT_PID 2>&1 "
2013-11-16 12:44:21 +01:00
child_pid = $!
WaitForTaskCompletion $child_pid 120 240
retval = $?
if [ $retval != 0 ]
then
2014-09-22 22:45:18 +02:00
eval " $SSH_CMD \"uname -v\" > $RUN_DIR /osync_remote_os_ $SCRIPT_PID 2>&1 "
2013-11-16 12:44:21 +01:00
child_pid = $!
WaitForTaskCompletion $child_pid 120 240
retval = $?
if [ $retval != 0 ]
then
2014-09-22 22:45:18 +02:00
eval " $SSH_CMD \"uname\" > $RUN_DIR /osync_remote_os_ $SCRIPT_PID 2>&1 "
2013-11-16 12:44:21 +01:00
child_pid = $!
WaitForTaskCompletion $child_pid 120 240
retval = $?
if [ $retval != 0 ]
then
LogError "Cannot Get remote OS type."
fi
fi
fi
2013-10-12 19:12:15 +02:00
2014-09-22 22:45:18 +02:00
REMOTE_OS_VAR = $( cat $RUN_DIR /osync_remote_os_$SCRIPT_PID )
case $REMOTE_OS_VAR in
*"Linux" *)
REMOTE_OS = "Linux"
; ;
*"BSD" *)
REMOTE_OS = "BSD"
; ;
*"MINGW32" *)
REMOTE_OS = "msys"
; ;
*"Darwin" *)
REMOTE_OS = "MacOSX"
; ;
*"ssh" *| *"SSH" *)
LogError "Cannot connect to remote system."
exit 1
; ;
*)
LogError "Running on remote OS failed. Please report to the author if the OS is not supported."
LogError " Remote OS said:\n $REMOTE_OS_VAR "
exit 1
esac
2013-10-12 19:12:15 +02:00
2014-09-22 22:45:18 +02:00
LogDebug " Remote OS: [ $REMOTE_OS_VAR ]. "
2013-11-19 16:38:10 +01:00
fi
2013-10-12 19:12:15 +02:00
}
2014-09-22 22:45:18 +02:00
# Waits for pid $1 to complete. Will log an alert if $2 seconds passed since current task execution unless $2 equals 0.
# Will stop task and log alert if $3 seconds passed since current task execution unless $3 equals 0.
2013-07-18 13:31:17 +02:00
function WaitForTaskCompletion
2013-07-16 23:10:27 +02:00
{
soft_alert = 0
SECONDS_BEGIN = $SECONDS
2014-11-24 19:30:20 +01:00
while eval " $PROCESS_TEST_CMD " > /dev/null
2013-07-16 23:10:27 +02:00
do
Spinner
EXEC_TIME = $(( $SECONDS - $SECONDS_BEGIN ))
2014-09-22 22:45:18 +02:00
if [ $(( ( $EXEC_TIME + 1 ) % $KEEP_LOGGING )) -eq 0 ]
2013-07-16 23:10:27 +02:00
then
Log "Current task still running."
fi
if [ $EXEC_TIME -gt $2 ]
then
if [ $soft_alert -eq 0 ] && [ $2 != 0 ]
then
LogError "Max soft execution time exceeded for task."
soft_alert = 1
fi
if [ $EXEC_TIME -gt $3 ] && [ $3 != 0 ]
then
LogError "Max hard execution time exceeded for task. Stopping task execution."
2014-09-22 22:45:18 +02:00
kill -s SIGTERM $1
2013-07-18 13:31:17 +02:00
if [ $? = = 0 ]
then
LogError "Task stopped succesfully"
else
2014-09-22 22:45:18 +02:00
LogError "Sending SIGTERM to proces failed. Trying the hard way."
kill -9 $1
if [ $? != 0 ]
then
LogError "Could not stop task."
fi
2013-07-18 13:31:17 +02:00
fi
2013-07-16 23:10:27 +02:00
return 1
fi
fi
2014-09-22 22:45:18 +02:00
sleep $SLEEP_TIME
2013-07-16 23:10:27 +02:00
done
2014-09-22 22:45:18 +02:00
wait $child_pid
return $?
2013-07-16 23:10:27 +02:00
}
## Runs local command $1 and waits for completition in $2 seconds
function RunLocalCommand
{
2013-09-03 21:31:41 +02:00
if [ $dryrun -ne 0 ]
then
Log " Dryrun: Local command [ $1 ] not run. "
return 1
fi
2013-11-02 18:55:17 +01:00
Log " Running command [ $1 ] on local host. "
2013-11-02 19:41:05 +01:00
eval " $1 " > $RUN_DIR /obackup_run_local_$SCRIPT_PID 2>& 1 &
2013-07-16 23:10:27 +02:00
child_pid = $!
2013-07-18 13:31:17 +02:00
WaitForTaskCompletion $child_pid 0 $2
2013-07-16 23:10:27 +02:00
retval = $?
if [ $retval -eq 0 ]
then
2013-11-02 18:55:17 +01:00
Log "Command succeded."
2013-07-16 23:10:27 +02:00
else
2013-11-02 18:55:17 +01:00
LogError "Command failed."
2013-07-16 23:10:27 +02:00
fi
2014-09-22 22:45:18 +02:00
2013-11-16 12:44:21 +01:00
if [ $verbose -eq 1 ] || [ $retval -ne 0 ]
2013-07-20 14:48:06 +02:00
then
2013-09-22 12:04:09 +02:00
Log " Command output:\n $( cat $RUN_DIR /obackup_run_local_$SCRIPT_PID ) "
2013-07-20 14:48:06 +02:00
fi
2014-09-22 22:45:18 +02:00
2013-11-02 18:55:17 +01:00
if [ " $STOP_ON_CMD_ERROR " = = "yes" ] && [ $retval -ne 0 ]
2013-09-11 16:18:32 +02:00
then
exit 1
fi
2013-07-16 23:10:27 +02:00
}
## Runs remote command $1 and waits for completition in $2 seconds
function RunRemoteCommand
{
CheckConnectivity3rdPartyHosts
2013-08-24 19:41:18 +02:00
CheckConnectivityRemoteHost
2013-09-03 21:31:41 +02:00
if [ $dryrun -ne 0 ]
then
Log " Dryrun: Remote command [ $1 ] not run. "
return 1
fi
2013-11-02 18:55:17 +01:00
Log " Running command [ $1 ] on remote host. "
2013-09-22 12:04:09 +02:00
eval " $SSH_CMD \" $1 \" > $RUN_DIR /obackup_run_remote_ $SCRIPT_PID 2>&1 & "
2013-08-24 19:41:18 +02:00
child_pid = $!
WaitForTaskCompletion $child_pid 0 $2
retval = $?
if [ $retval -eq 0 ]
then
2013-11-02 18:55:17 +01:00
Log "Command succeded."
2013-08-24 19:41:18 +02:00
else
2013-11-02 18:55:17 +01:00
LogError "Command failed."
2013-08-24 19:41:18 +02:00
fi
2014-09-22 22:45:18 +02:00
2013-11-16 12:44:21 +01:00
if [ -f $RUN_DIR /obackup_run_remote_$SCRIPT_PID ] && ( [ $verbose -eq 1 ] || $retval -ne 0 ] )
2013-08-24 19:41:18 +02:00
then
2013-09-22 12:04:09 +02:00
Log " Command output:\n $( cat $RUN_DIR /obackup_run_remote_$SCRIPT_PID ) "
2013-07-16 23:10:27 +02:00
fi
2013-09-11 16:18:32 +02:00
2013-11-02 18:55:17 +01:00
if [ " $STOP_ON_CMD_ERROR " = = "yes" ] && [ $retval -ne 0 ]
2013-09-11 16:18:32 +02:00
then
2013-11-02 18:55:17 +01:00
exit 1
2013-09-11 16:18:32 +02:00
fi
2013-07-16 23:10:27 +02:00
}
function RunBeforeHook
{
if [ " $LOCAL_RUN_BEFORE_CMD " != "" ]
then
RunLocalCommand " $LOCAL_RUN_BEFORE_CMD " $MAX_EXEC_TIME_PER_CMD_BEFORE
fi
if [ " $REMOTE_RUN_BEFORE_CMD " != "" ]
then
RunRemoteCommand " $REMOTE_RUN_BEFORE_CMD " $MAX_EXEC_TIME_PER_CMD_BEFORE
2014-09-22 22:45:18 +02:00
fi
2013-07-16 23:10:27 +02:00
}
function RunAfterHook
{
if [ " $LOCAL_RUN_AFTER_CMD " != "" ]
then
RunLocalCommand " $LOCAL_RUN_AFTER_CMD " $MAX_EXEC_TIME_PER_CMD_AFTER
fi
if [ " $REMOTE_RUN_AFTER_CMD " != "" ]
then
RunRemoteCommand " $REMOTE_RUN_AFTER_CMD " $MAX_EXEC_TIME_PER_CMD_AFTER
fi
}
function CreateLocalStorageDirectories
{
if [ ! -d $LOCAL_SQL_STORAGE ] && [ " $BACKUP_SQL " != "no" ]
then
mkdir -p $LOCAL_SQL_STORAGE
fi
if [ ! -d $LOCAL_FILE_STORAGE ] && [ " $BACKUP_FILES " != "no" ]
then
mkdir -p $LOCAL_FILE_STORAGE
fi
}
function CheckSpaceRequirements
{
if [ " $BACKUP_SQL " != "no" ]
then
2013-11-02 18:55:17 +01:00
if [ -w $LOCAL_SQL_STORAGE ]
2013-07-16 23:10:27 +02:00
then
# Not elegant solution to make df silent on errors
2013-09-22 12:04:09 +02:00
df -P $LOCAL_SQL_STORAGE > $RUN_DIR /obackup_local_sql_storage_$SCRIPT_PID 2>& 1
2013-07-16 23:10:27 +02:00
if [ $? != 0 ]
then
LOCAL_SQL_SPACE = 0
else
2013-09-22 12:04:09 +02:00
LOCAL_SQL_SPACE = $( cat $RUN_DIR /obackup_local_sql_storage_$SCRIPT_PID | tail -1 | awk '{print $4}' )
LOCAL_SQL_DRIVE = $( cat $RUN_DIR /obackup_local_sql_storage_$SCRIPT_PID | tail -1 | awk '{print $1}' )
2013-07-16 23:10:27 +02:00
fi
if [ $LOCAL_SQL_SPACE -eq 0 ]
then
LogError "Local sql storage space reported to be 0Ko."
elif [ $LOCAL_SQL_SPACE -lt $TOTAL_DATABASES_SIZE ]
then
LogError "Local disk space may be insufficient to backup files (available space is lower than non compressed databases)."
fi
else
LOCAL_SQL_SPACE = 0
2013-11-02 18:55:17 +01:00
LogError " SQL storage path [ $LOCAL_SQL_STORAGE ] doesn't exist or cannot write to it. "
2013-07-16 23:10:27 +02:00
fi
2013-09-13 13:36:08 +02:00
else
LOCAL_SQL_SPACE = 0
2013-07-16 23:10:27 +02:00
fi
if [ " $BACKUP_FILES " != "no" ]
then
2013-11-02 18:55:17 +01:00
if [ -w $LOCAL_FILE_STORAGE ]
2013-07-16 23:10:27 +02:00
then
2013-09-22 12:04:09 +02:00
df -P $LOCAL_FILE_STORAGE > $RUN_DIR /obackup_local_file_storage_$SCRIPT_PID 2>& 1
2013-07-16 23:10:27 +02:00
if [ $? != 0 ]
then
LOCAL_FILE_SPACE = 0
else
2013-09-22 12:04:09 +02:00
LOCAL_FILE_SPACE = $( cat $RUN_DIR /obackup_local_file_storage_$SCRIPT_PID | tail -1 | awk '{print $4}' )
LOCAL_FILE_DRIVE = $( cat $RUN_DIR /obackup_local_file_storage_$SCRIPT_PID | tail -1 | awk '{print $1}' )
2013-07-16 23:10:27 +02:00
fi
if [ $LOCAL_FILE_SPACE -eq 0 ]
then
LogError "Local file storage space reported to be 0Ko."
elif [ $LOCAL_FILE_SPACE -lt $TOTAL_FILES_SIZE ]
then
LogError "Local disk space may be insufficient to backup files (available space is lower than full backup)."
fi
else
LOCAL_FILE_SPACE = 0
2013-11-02 18:55:17 +01:00
LogError " File storage path [ $LOCAL_FILE_STORAGE ] doesn't exist or cannot write to it. "
2013-07-16 23:10:27 +02:00
fi
2013-09-13 13:36:08 +02:00
else
LOCAL_FILE_SPACE = 0
2013-07-16 23:10:27 +02:00
fi
if [ " $LOCAL_SQL_DRIVE " = = " $LOCAL_FILE_DRIVE " ]
then
LOCAL_SPACE = $LOCAL_FILE_SPACE
else
LOCAL_SPACE = $(( $LOCAL_SQL_SPACE + $LOCAL_FILE_SPACE ))
fi
if [ $BACKUP_SIZE_MINIMUM -gt $(( $TOTAL_DATABASES_SIZE + $TOTAL_FILES_SIZE )) ]
then
LogError "Backup size is smaller then expected."
elif [ $LOCAL_STORAGE_WARN_MIN_SPACE -gt $LOCAL_SPACE ]
then
LogError " Local disk space is lower than warning value [ $LOCAL_STORAGE_WARN_MIN_SPACE Ko]. "
fi
Log " Local Space: $LOCAL_SPACE Ko - Databases size: $TOTAL_DATABASES_SIZE Ko - Files size: $TOTAL_FILES_SIZE Ko "
}
2014-09-22 22:45:18 +02:00
2013-07-16 23:10:27 +02:00
function CheckTotalExecutionTime
{
2013-08-24 19:41:18 +02:00
#### Check if max execution time of whole script as been reached
2013-07-16 23:10:27 +02:00
if [ $SECONDS -gt $SOFT_MAX_EXEC_TIME_TOTAL ]
then
if [ $soft_alert_total -eq 0 ]
then
LogError " Max soft execution time of the whole backup exceeded while backing up $BACKUP_TASK . "
soft_alert_total = 1
fi
if [ $SECONDS -gt $HARD_MAX_EXEC_TIME_TOTAL ]
then
LogError " Max hard execution time of the whole backup exceeded while backing up $BACKUP_TASK , stopping backup process. "
exit 1
fi
fi
}
function CheckConnectivityRemoteHost
{
2014-09-22 22:45:18 +02:00
if [ " $REMOTE_HOST_PING " != "no" ] && [ " $REMOTE_SYNC " != "no" ]
then
eval " $PING_CMD $REMOTE_HOST > /dev/null 2>&1 "
if [ $? != 0 ]
then
LogError " Cannot ping $REMOTE_HOST "
exit 1
fi
fi
2013-07-16 23:10:27 +02:00
}
2014-09-22 22:45:18 +02:00
2013-07-16 23:10:27 +02:00
function CheckConnectivity3rdPartyHosts
{
2014-09-22 22:45:18 +02:00
if [ " $REMOTE_3RD_PARTY_HOSTS " != "" ]
then
remote_3rd_party_success = 0
OLD_IFS = $IFS
2013-09-13 13:28:45 +02:00
IFS = $' \t\n'
2014-09-22 22:45:18 +02:00
for i in $REMOTE_3RD_PARTY_HOSTS
do
eval " $PING_CMD $i > /dev/null 2>&1 "
if [ $? != 0 ]
then
Log " Cannot ping 3rd party host $i "
else
remote_3rd_party_success = 1
fi
done
IFS = $OLD_IFS
if [ $remote_3rd_party_success -ne 1 ]
then
LogError "No remote 3rd party host responded to ping. No internet ?"
exit 1
fi
fi
2013-07-16 23:10:27 +02:00
}
2014-09-22 22:45:18 +02:00
2013-07-16 23:10:27 +02:00
function ListDatabases
{
SECONDS_BEGIN = $SECONDS
Log "Listing databases."
CheckConnectivity3rdPartyHosts
2013-08-24 19:41:18 +02:00
CheckConnectivityRemoteHost
if [ " $REMOTE_BACKUP " != "no" ]
2013-07-16 23:10:27 +02:00
then
2013-09-22 12:04:09 +02:00
eval " $SSH_CMD \"mysql -u $SQL_USER -Bse 'SELECT table_schema, round(sum( data_length + index_length ) / 1024) FROM information_schema.TABLES GROUP by table_schema;'\" > $RUN_DIR /obackup_dblist_ $SCRIPT_PID & "
2013-07-16 23:10:27 +02:00
else
2013-09-22 12:04:09 +02:00
mysql -u $SQL_USER -Bse 'SELECT table_schema, round(sum( data_length + index_length ) / 1024) FROM information_schema.TABLES GROUP by table_schema;' > $RUN_DIR /obackup_dblist_$SCRIPT_PID &
2013-07-16 23:10:27 +02:00
fi
child_pid = $!
2013-07-18 13:31:17 +02:00
WaitForTaskCompletion $child_pid $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK
2013-07-16 23:10:27 +02:00
retval = $?
if [ $retval -eq 0 ]
then
Log "Listing databases succeeded."
else
LogError "Listing databases failed."
2013-09-22 12:04:09 +02:00
if [ -f $RUN_DIR /obackup_dblist_$SCRIPT_PID ]
2013-07-16 23:10:27 +02:00
then
2013-09-22 12:04:09 +02:00
LogError " Command output:\n $( cat $RUN_DIR /obackup_dblist_$SCRIPT_PID ) "
2013-07-16 23:10:27 +02:00
fi
return $retval
fi
2013-09-22 12:04:09 +02:00
OLD_IFS = $IFS
IFS = $' \n'
2014-09-22 22:45:18 +02:00
for line in $( cat $RUN_DIR /obackup_dblist_$SCRIPT_PID )
2013-07-16 23:10:27 +02:00
do
2013-09-22 12:04:09 +02:00
db_name = $( echo $line | cut -f1)
db_size = $( echo $line | cut -f2)
2013-07-16 23:10:27 +02:00
if [ " $DATABASES_ALL " = = "yes" ]
then
db_backup = 1
for j in $DATABASES_ALL_EXCLUDE_LIST
do
if [ " $db_name " = = " $j " ]
then
db_backup = 0
fi
done
else
db_backup = 0
for j in $DATABASES_LIST
do
if [ " $db_name " = = " $j " ]
then
db_backup = 1
fi
done
fi
if [ $db_backup -eq 1 ]
then
if [ " $DATABASES_TO_BACKUP " != "" ]
then
DATABASES_TO_BACKUP = " $DATABASES_TO_BACKUP $db_name "
else
DATABASES_TO_BACKUP = $db_name
fi
TOTAL_DATABASES_SIZE = $(( TOTAL_DATABASES_SIZE+$db_size ))
else
DATABASES_EXCLUDED_LIST = " $DATABASES_EXCLUDED_LIST $db_name "
fi
2013-09-22 12:04:09 +02:00
done
IFS = $OLD_IFS
2013-11-02 18:55:17 +01:00
if [ $verbose -eq 1 ]
then
Log " Database backup list: $DATABASES_TO_BACKUP "
Log " Database exclude list: $DATABASES_EXCLUDED_LIST "
fi
2013-07-16 23:10:27 +02:00
}
function BackupDatabase
{
CheckConnectivity3rdPartyHosts
if [ " $REMOTE_BACKUP " = = "yes" ] && [ " $COMPRESSION_REMOTE " = = "no" ]
then
CheckConnectivityRemoteHost
if [ $? != 0 ]
then
LogError "Connectivity test failed. Stopping current task."
exit 1
fi
2014-11-27 14:40:30 +01:00
dry_sql_cmd = " $SSH_CMD mysqldump -u $SQL_USER --skip-lock-tables --single-transaction --database $1 > /dev/null 2>&1 "
2014-09-22 22:45:18 +02:00
sql_cmd = " $SSH_CMD mysqldump -u $SQL_USER --skip-lock-tables --single-transaction --database $1 $COMPRESSION_PROGRAM $COMPRESSION_OPTIONS > $LOCAL_SQL_STORAGE / $1 .sql $COMPRESSION_EXTENSION "
2013-07-16 23:10:27 +02:00
elif [ " $REMOTE_BACKUP " = = "yes" ] && [ " $COMPRESSION_REMOTE " = = "yes" ]
then
CheckConnectivityRemoteHost
if [ $? != 0 ]
then
LogError "Connectivity test failed. Stopping current task."
exit 1
fi
2014-11-27 14:40:30 +01:00
dry_sql_cmd = " $SSH_CMD \"mysqldump -u $SQL_USER --skip-lock-tables --single-transaction --database $1 $COMPRESSION_PROGRAM $COMPRESSION_OPTIONS \" > /dev/null 2>&1 "
2014-09-22 22:45:18 +02:00
sql_cmd = " $SSH_CMD \"mysqldump -u $SQL_USER --skip-lock-tables --single-transaction --database $1 $COMPRESSION_PROGRAM $COMPRESSION_OPTIONS \" > $LOCAL_SQL_STORAGE / $1 .sql $COMPRESSION_EXTENSION "
2013-07-16 23:10:27 +02:00
else
2014-11-27 14:40:30 +01:00
dry_sql_cmd = " mysqldump -u $SQL_USER --skip-lock-tables --single-transaction --database $1 $COMPRESSION_PROGRAM $COMPRESSION_OPTIONS > /dev/null 2>&1 "
2014-09-22 22:45:18 +02:00
sql_cmd = " mysqldump -u $SQL_USER --skip-lock-tables --single-transaction --database $1 $COMPRESSION_PROGRAM $COMPRESSION_OPTIONS > $LOCAL_SQL_STORAGE / $1 .sql $COMPRESSION_EXTENSION "
2013-07-16 23:10:27 +02:00
fi
2013-11-02 18:55:17 +01:00
if [ $verbose -eq 1 ]
then
Log " SQL_CMD: $sql_cmd "
fi
2014-11-27 14:40:30 +01:00
if [ $dryrun -ne 1 ]
then
eval " $sql_cmd 2>&1 "
else
eval " $dry_sql_cmd "
fi
2013-07-16 23:10:27 +02:00
exit $?
}
function BackupDatabases
{
2013-09-17 11:51:05 +02:00
OLD_IFS = $IFS
IFS = $' \t\n'
2013-07-16 23:10:27 +02:00
for BACKUP_TASK in $DATABASES_TO_BACKUP
do
Log " Backing up database $BACKUP_TASK "
SECONDS_BEGIN = $SECONDS
BackupDatabase $BACKUP_TASK &
child_pid = $!
2013-07-18 13:31:17 +02:00
WaitForTaskCompletion $child_pid $SOFT_MAX_EXEC_TIME_DB_TASK $HARD_MAX_EXEC_TIME_DB_TASK
2013-07-16 23:10:27 +02:00
retval = $?
if [ $retval -ne 0 ]
then
LogError "Backup failed."
else
Log "Backup succeeded."
fi
2014-09-22 22:45:18 +02:00
2013-07-16 23:10:27 +02:00
CheckTotalExecutionTime
done
2013-09-17 11:51:05 +02:00
IFS = $OLD_IFS
2013-07-16 23:10:27 +02:00
}
# Fetches single quoted directory listing including recursive ones separated by commas (eg '/dir1';'/dir2';'/dir3')
function ListDirectories
{
SECONDS_BEGIN = $SECONDS
Log "Listing directories to backup."
OLD_IFS = $IFS
IFS = $PATH_SEPARATOR_CHAR
2013-08-24 19:41:18 +02:00
for dir in $DIRECTORIES_RECURSE_LIST
2013-07-16 23:10:27 +02:00
do
CheckConnectivity3rdPartyHosts
if [ " $REMOTE_BACKUP " = = "yes" ]
then
CheckConnectivityRemoteHost
if [ $? != 0 ]
then
LogError "Connectivity test failed. Stopping current task."
Dummy &
else
2014-11-27 15:35:56 +01:00
eval " $SSH_CMD \" $COMMAND_SUDO $FIND_CMD -L $dir / -mindepth 1 -maxdepth 1 -type d\" > $RUN_DIR /obackup_dirs_recurse_list_ $SCRIPT_PID & "
2013-07-16 23:10:27 +02:00
fi
else
2014-11-27 15:35:56 +01:00
eval " $COMMAND_SUDO $FIND_CMD -L $dir / -mindepth 1 -maxdepth 1 -type d > $RUN_DIR /obackup_dirs_recurse_list_ $SCRIPT_PID & "
2013-07-16 23:10:27 +02:00
fi
child_pid = $!
2013-07-18 13:31:17 +02:00
WaitForTaskCompletion $child_pid $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK
2013-07-16 23:10:27 +02:00
retval = $?
if [ $retval != 0 ]
then
2013-08-24 19:41:18 +02:00
LogError " Could not enumerate recursive directories in $dir . "
2013-09-22 12:04:09 +02:00
if [ -f $RUN_DIR /obackup_dirs_recurse_list_$SCRIPT_PID ]
2013-07-16 23:10:27 +02:00
then
2013-09-22 12:04:09 +02:00
LogError " Command output:\n $( cat $RUN_DIR /obackup_dirs_recurse_list_$SCRIPT_PID ) "
2013-07-16 23:10:27 +02:00
fi
return 1
fi
2013-09-22 12:04:09 +02:00
OLD_IFS = $IFS
IFS = $' \n'
for line in $( cat $RUN_DIR /obackup_dirs_recurse_list_$SCRIPT_PID )
2013-07-16 23:10:27 +02:00
do
file_exclude = 0
2013-11-19 16:38:10 +01:00
IFS = $PATH_SEPARATOR_CHAR
2013-07-16 23:10:27 +02:00
for k in $DIRECTORIES_RECURSE_EXCLUDE_LIST
do
if [ " $k " = = " $line " ]
then
file_exclude = 1
fi
done
2013-11-19 16:38:10 +01:00
IFS = $' \n'
2014-09-22 22:45:18 +02:00
2013-07-16 23:10:27 +02:00
if [ $file_exclude -eq 0 ]
then
if [ " $DIRECTORIES_TO_BACKUP " = = "" ]
then
DIRECTORIES_TO_BACKUP = " ' $line ' "
else
DIRECTORIES_TO_BACKUP = " $DIRECTORIES_TO_BACKUP $PATH_SEPARATOR_CHAR ' $line ' "
fi
else
DIRECTORIES_EXCLUDED_LIST = " $DIRECTORIES_EXCLUDED_LIST $PATH_SEPARATOR_CHAR ' $line ' "
fi
2013-09-22 12:04:09 +02:00
done
2013-11-02 18:55:17 +01:00
Log " Listing of recursive directories succeeded for $dir "
if [ $verbose -eq 1 ]
then
Log " \n $( cat $RUN_DIR /obackup_dirs_recurse_list_$SCRIPT_PID ) "
fi
2013-09-22 12:04:09 +02:00
IFS = $OLD_IFS
2013-07-16 23:10:27 +02:00
done
DIRECTORIES_TO_BACKUP_RECURSE = $DIRECTORIES_TO_BACKUP
2014-09-22 22:45:18 +02:00
2013-08-24 19:41:18 +02:00
for dir in $DIRECTORIES_SIMPLE_LIST
2013-07-16 23:10:27 +02:00
do
if [ " $DIRECTORIES_TO_BACKUP " = = "" ]
then
2013-08-24 19:41:18 +02:00
DIRECTORIES_TO_BACKUP = " ' $dir ' "
2013-07-16 23:10:27 +02:00
else
2013-08-24 19:41:18 +02:00
DIRECTORIES_TO_BACKUP = " $DIRECTORIES_TO_BACKUP $PATH_SEPARATOR_CHAR ' $dir ' "
2013-07-16 23:10:27 +02:00
fi
done
IFS = $OLD_IFS
}
function GetDirectoriesSize
2014-09-22 22:45:18 +02:00
{
2013-07-16 23:10:27 +02:00
# remove the path separator char from the dir list with sed 's/;/ /g'
dir_list = $( echo $DIRECTORIES_TO_BACKUP | sed 's/' " $PATH_SEPARATOR_CHAR " '/ /g' )
Log "Getting files size"
CheckConnectivity3rdPartyHosts
if [ " $REMOTE_BACKUP " = = "yes" ]
then
CheckConnectivityRemoteHost
if [ $? != 0 ]
then
LogError "Connectivity test failed. Stopping current task."
Dummy &
else
2013-09-22 12:04:09 +02:00
eval " $SSH_CMD \"echo $dir_list | xargs $COMMAND_SUDO du -cs | tail -n1 | cut -f1\" > $RUN_DIR /obackup_fsize_ $SCRIPT_PID & "
2013-07-16 23:10:27 +02:00
fi
else
2013-09-22 12:04:09 +02:00
echo $dir_list | xargs $COMMAND_SUDO du -cs | tail -n1 | cut -f1 > $RUN_DIR /obackup_fsize_$SCRIPT_PID &
2013-07-16 23:10:27 +02:00
fi
child_pid = $!
2013-07-18 13:31:17 +02:00
WaitForTaskCompletion $child_pid $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK
2013-07-16 23:10:27 +02:00
retval = $?
if [ $retval != 0 ]
then
LogError "Could not get files size."
2013-09-22 12:04:09 +02:00
if [ -f $RUN_DIR /obackup_fsize_$SCRIPT_PID ]
2013-07-16 23:10:27 +02:00
then
2013-09-22 12:04:09 +02:00
LogError " Command output:\n $( cat $RUN_DIR /obackup_fsize_$SCRIPT_PID ) "
2013-07-16 23:10:27 +02:00
fi
return 1
else
Log "File size fetched successfully."
2013-09-22 12:04:09 +02:00
TOTAL_FILES_SIZE = $( cat $RUN_DIR /obackup_fsize_$SCRIPT_PID )
2013-07-16 23:10:27 +02:00
fi
}
function RsyncExcludePattern
{
OLD_IFS = $IFS
IFS = $PATH_SEPARATOR_CHAR
for excludedir in $RSYNC_EXCLUDE_PATTERN
do
if [ " $RSYNC_EXCLUDE " = = "" ]
then
RSYNC_EXCLUDE = " --exclude= $( EscapeSpaces $excludedir ) "
else
RSYNC_EXCLUDE = " $RSYNC_EXCLUDE --exclude= $( EscapeSpaces $excludedir ) "
fi
done
IFS = $OLD_IFS
}
2014-11-24 10:28:23 +01:00
function RsyncExcludeFrom
{
if [ ! $RSYNC_EXCLUDE_FROM = = "" ]
then
## Check if the exclude list has a full path, and if not, add the config file path if there is one
if [ " $( basename $RSYNC_EXCLUDE_FROM ) " = = " $RSYNC_EXCLUDE_FROM " ]
then
RSYNC_EXCLUDE_FROM = $( dirname $ConfigFile ) /$RSYNC_EXCLUDE_FROM
fi
if [ -e $RSYNC_EXCLUDE_FROM ]
then
RSYNC_EXCLUDE = " $RSYNC_EXCLUDE --exclude-from=\" $RSYNC_EXCLUDE_FROM \" "
fi
fi
}
2013-07-16 23:10:27 +02:00
function Rsync
{
i = " $( StripQuotes $1 ) "
if [ " $LOCAL_STORAGE_KEEP_ABSOLUTE_PATHS " = = "yes" ]
then
local_file_storage_path = " $( dirname $LOCAL_FILE_STORAGE $i ) "
else
2013-11-02 18:55:17 +01:00
local_file_storage_path = $LOCAL_FILE_STORAGE
2013-07-16 23:10:27 +02:00
fi
2013-11-02 18:55:17 +01:00
## Manage to backup recursive directories lists files only (not recursing into subdirectories)
if [ " $2 " = = "no-recurse" ]
then
RSYNC_EXCLUDE = $RSYNC_EXCLUDE " --exclude=*/*/"
2014-11-19 17:20:49 +01:00
# Fixes symlinks to directories in target cannot be deleted when backing up root directory without recursion
RSYNC_NO_RECURSE_ARGS = " -k"
else
RSYNC_NO_RECURSE_ARGS = ""
2013-11-02 18:55:17 +01:00
fi
2014-11-27 14:40:30 +01:00
# Directories should not be created here
#if [ ! -d $local_file_storage_path ]
#then
# mkdir -p "$local_file_storage_path"
#fi
2013-07-16 23:10:27 +02:00
CheckConnectivity3rdPartyHosts
if [ " $REMOTE_BACKUP " = = "yes" ]
then
CheckConnectivityRemoteHost
if [ $? != 0 ]
then
LogError "Connectivity test failed. Stopping current task."
exit 1
fi
2014-11-19 17:20:49 +01:00
rsync_cmd = " $( type -p $RSYNC_EXECUTABLE ) $RSYNC_ARGS $RSYNC_NO_RECURSE_ARGS --stats $RSYNC_DELETE $RSYNC_EXCLUDE --rsync-path=\" $RSYNC_PATH \" -e \" $RSYNC_SSH_CMD \" \" $REMOTE_USER @ $REMOTE_HOST : $1 \" \" $local_file_storage_path \" > $RUN_DIR /obackup_rsync_output_ $SCRIPT_PID 2>&1 "
2013-07-16 23:10:27 +02:00
else
2014-11-19 17:20:49 +01:00
rsync_cmd = " $( type -p $RSYNC_EXECUTABLE ) $RSYNC_ARGS $RSYNC_NO_RECURSE_ARGS --stats $RSYNC_DELETE $RSYNC_EXCLUDE --rsync-path=\" $RSYNC_PATH \" \" $1 \" \" $local_file_storage_path \" > $RUN_DIR /obackup_rsync_output_ $SCRIPT_PID 2>&1 "
2013-07-16 23:10:27 +02:00
fi
#### Eval is used so the full command is processed without bash adding single quotes round variables
2013-08-18 11:58:55 +02:00
if [ $verbose -eq 1 ]
2013-07-16 23:10:27 +02:00
then
2013-08-18 11:58:55 +02:00
Log " RSYNC_CMD: $rsync_cmd "
2013-07-16 23:10:27 +02:00
fi
eval $rsync_cmd
exit $?
}
#### First backup simple list then recursive list
function FilesBackup
{
OLD_IFS = $IFS
IFS = $PATH_SEPARATOR_CHAR
for BACKUP_TASK in $DIRECTORIES_SIMPLE_LIST
do
BACKUP_TASK = $( StripQuotes $BACKUP_TASK )
2013-11-02 18:55:17 +01:00
Log " Beginning recursive file backup on $BACKUP_TASK "
2013-07-16 23:10:27 +02:00
SECONDS_BEGIN = $SECONDS
Rsync $BACKUP_TASK &
child_pid = $!
2013-07-18 13:31:17 +02:00
WaitForTaskCompletion $child_pid $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK
2013-07-16 23:10:27 +02:00
retval = $?
2013-09-22 12:04:09 +02:00
if [ $verbose -eq 1 ] && [ -f $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ]
2013-08-18 11:58:55 +02:00
then
2013-09-22 12:04:09 +02:00
Log " List:\n $( cat $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ) "
2013-08-18 11:58:55 +02:00
fi
2013-07-16 23:10:27 +02:00
if [ $retval -ne 0 ]
then
LogError "Backup failed on remote files."
2013-09-22 12:04:09 +02:00
if [ $verbose -eq 0 ] && [ -f $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ]
2013-08-25 12:39:13 +02:00
then
2013-09-22 12:04:09 +02:00
LogError " $( cat $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ) "
2013-08-25 12:39:13 +02:00
fi
2013-07-16 23:10:27 +02:00
else
Log "Backup succeeded."
fi
CheckTotalExecutionTime
done
2013-11-02 18:55:17 +01:00
## Also backup files at root of DIRECTORIES_RECURSE_LIST directories
for BACKUP_TASK in $DIRECTORIES_RECURSE_LIST
do
BACKUP_TASK = " $( StripQuotes $BACKUP_TASK ) "
Log " Beginning non recursive file backup on $BACKUP_TASK "
SECONDS_BEGIN = $SECONDS
Rsync $BACKUP_TASK "no-recurse" &
child_pid = $!
WaitForTaskCompletion $child_pid $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK
retval = $?
if [ $verbose -eq 1 ] && [ -f $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ]
then
Log " List:\n $( cat $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ) "
fi
if [ $retval -ne 0 ]
then
LogError "Backup failed on remote files."
if [ $verbose -eq 0 ] && [ -f $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ]
then
LogError " $( cat $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ) "
fi
else
Log "Backup succeeded."
fi
CheckTotalExecutionTime
done
2013-07-16 23:10:27 +02:00
for BACKUP_TASK in $DIRECTORIES_TO_BACKUP_RECURSE
do
BACKUP_TASK = $( StripQuotes $BACKUP_TASK )
2013-11-02 18:55:17 +01:00
Log " Beginning recursive file backup on $BACKUP_TASK "
2013-07-16 23:10:27 +02:00
SECONDS_BEGIN = $SECONDS
Rsync $BACKUP_TASK "recurse" &
child_pid = $!
2013-07-18 13:31:17 +02:00
WaitForTaskCompletion $child_pid $SOFT_MAX_EXEC_TIME_FILE_TASK $HARD_MAX_EXEC_TIME_FILE_TASK
2013-07-16 23:10:27 +02:00
retval = $?
2013-09-22 12:04:09 +02:00
if [ $verbose -eq 1 ] && [ -f $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ]
2013-08-25 12:39:13 +02:00
then
2013-09-22 12:04:09 +02:00
Log " List:\n $( cat $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ) "
2013-08-25 12:39:13 +02:00
fi
2013-07-16 23:10:27 +02:00
if [ $retval -ne 0 ]
then
LogError "Backup failed on remote files."
2013-09-22 12:04:09 +02:00
if [ $verbose -eq 0 ] && [ -f $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ]
2013-07-16 23:10:27 +02:00
then
2013-09-22 12:04:09 +02:00
LogError " $( cat $RUN_DIR /obackup_rsync_output_$SCRIPT_PID ) "
2013-07-16 23:10:27 +02:00
fi
else
Log "Backup succeeded."
fi
CheckTotalExecutionTime
done
2014-09-22 22:45:18 +02:00
2013-07-16 23:10:27 +02:00
IFS = $OLD_IFS
}
# Will rotate everything in $1
function RotateBackups
{
2013-09-17 11:51:05 +02:00
OLD_IFS = $IFS
IFS = $' \t\n'
2013-07-16 23:10:27 +02:00
for backup in $( ls -I "*.obackup.*" $1 )
do
copy = $ROTATE_COPIES
while [ $copy -gt 1 ]
do
if [ $copy -eq $ROTATE_COPIES ]
then
2014-09-22 22:45:18 +02:00
rm -rf " $1 / $backup .obackup. $copy " &
child_pid = $!
WaitForTaskCompletion $child_pid 0 0
2013-07-16 23:10:27 +02:00
fi
path = " $1 / $backup .obackup. $(( $copy - 1 )) "
if [ [ -f $path || -d $path ] ]
then
2014-09-22 22:45:18 +02:00
mv $path " $1 / $backup .obackup. $copy " &
child_pid = $!
WaitForTaskCompletion $child_pid 0 0
2013-07-16 23:10:27 +02:00
fi
copy = $(( $copy - 1 ))
done
# Latest file backup will not be moved if script configured for remote backup so next rsync execution will only do delta copy instead of full one
if [ [ $backup = = *.sql.* ] ]
then
2014-09-22 22:45:18 +02:00
mv " $1 / $backup " " $1 / $backup .obackup.1 " &
child_pid = $!
WaitForTaskCompletion $child_pid 0 0
2013-07-16 23:10:27 +02:00
elif [ " $REMOTE_BACKUP " = = "yes" ]
then
2014-09-22 22:45:18 +02:00
cp -R " $1 / $backup " " $1 / $backup .obackup.1 " &
child_pid = $!
WaitForTaskCompletion $child_pid 0 0
2013-07-16 23:10:27 +02:00
else
2014-09-22 22:45:18 +02:00
mv " $1 / $backup " " $1 / $backup .obackup.1 " &
child_pid = $!
WaitForTaskCompletion $child_pid 0 0
2013-07-16 23:10:27 +02:00
fi
done
2013-09-17 11:51:05 +02:00
IFS = $OLD_IFS
2013-07-16 23:10:27 +02:00
}
function Init
{
# Set error exit code if a piped command fails
set -o pipefail
set -o errtrace
2013-07-17 11:31:21 +02:00
trap TrapStop SIGINT SIGQUIT SIGKILL SIGTERM SIGHUP
trap TrapQuit EXIT
2013-07-16 23:10:27 +02:00
if [ " $DEBUG " = = "yes" ]
then
trap 'TrapError ${LINENO} $?' ERR
fi
2013-08-18 11:58:55 +02:00
if [ " $LOGFILE " = = "" ]
then
2013-11-02 18:55:17 +01:00
if [ -w /var/log ]
2013-09-22 12:04:09 +02:00
then
2014-09-22 22:45:18 +02:00
LOG_FILE = /var/log/obackup_$BACKUP_ID .log
2013-09-22 12:04:09 +02:00
else
2014-09-22 22:45:18 +02:00
LOG_FILE = ./obackup_$BACKUP_ID .log
2013-09-22 12:04:09 +02:00
fi
2013-08-18 11:58:55 +02:00
else
LOG_FILE = " $LOGFILE "
fi
2014-09-22 22:45:18 +02:00
MAIL_ALERT_MSG = " Warning: Execution of obackup instance $BACKUP_ID (pid $SCRIPT_PID ) as $LOCAL_USER @ $LOCAL_HOST produced errors on $( date) . "
2013-09-22 12:04:09 +02:00
2013-07-20 14:48:06 +02:00
## Set SSH command
if [ " $SSH_COMPRESSION " = = "yes" ]
then
SSH_COMP = -C
else
SSH_COMP =
fi
2013-09-22 12:04:09 +02:00
SSH_CMD = " $( type -p ssh) $SSH_COMP -i $SSH_RSA_PRIVATE_KEY $REMOTE_USER @ $REMOTE_HOST -p $REMOTE_PORT "
RSYNC_SSH_CMD = " $( type -p ssh) $SSH_COMP -i $SSH_RSA_PRIVATE_KEY -p $REMOTE_PORT "
2013-07-20 14:48:06 +02:00
## Support for older config files without RSYNC_EXECUTABLE option
if [ " $RSYNC_EXECUTABLE " = = "" ]
then
RSYNC_EXECUTABLE = rsync
fi
## Sudo execution option
if [ " $SUDO_EXEC " = = "yes" ]
then
2013-09-22 12:04:09 +02:00
if [ " $RSYNC_REMOTE_PATH " != "" ]
then
2014-03-23 17:46:08 +01:00
RSYNC_PATH = " sudo $RSYNC_REMOTE_PATH / $RSYNC_EXECUTABLE "
2013-09-22 12:04:09 +02:00
else
2013-10-10 20:39:17 +02:00
RSYNC_PATH = " sudo $RSYNC_EXECUTABLE "
2013-09-22 12:04:09 +02:00
fi
COMMAND_SUDO = "sudo"
2013-07-20 14:48:06 +02:00
else
2013-09-22 12:04:09 +02:00
if [ " $RSYNC_REMOTE_PATH " != "" ]
then
2014-03-23 17:46:08 +01:00
RSYNC_PATH = " $RSYNC_REMOTE_PATH / $RSYNC_EXECUTABLE "
2013-09-22 12:04:09 +02:00
else
2013-10-10 20:39:17 +02:00
RSYNC_PATH = " $RSYNC_EXECUTABLE "
2013-09-22 12:04:09 +02:00
fi
2013-07-20 14:48:06 +02:00
COMMAND_SUDO = ""
fi
2013-08-18 11:58:55 +02:00
## Set Rsync arguments
2014-11-19 09:36:30 +01:00
RSYNC_ARGS = -rlptgoD
2013-09-10 11:58:45 +02:00
if [ " $PRESERVE_ACL " = = "yes" ]
2013-08-18 11:58:55 +02:00
then
RSYNC_ARGS = $RSYNC_ARGS "A"
fi
if [ " $PRESERVE_XATTR " = = "yes" ]
then
RSYNC_ARGS = $RSYNC_ARGS "X"
fi
if [ " $RSYNC_COMPRESS " = = "yes" ]
then
RSYNC_ARGS = $RSYNC_ARGS "z"
fi
2014-11-27 15:35:56 +01:00
if [ " $COPY_SYMLINKS " != "no" ]
then
RSYNC_ARGS = $RSYNC_ARGS " -L"
fi
if [ " $KEEP_DIRLINKS " != "no" ]
then
RSYNC_ARGS = $RSYNC_ARGS " -K"
fi
if [ " $PRESERVE_HARDLINKS " = = "yes" ]
then
RSYNC_ARGS = $RSYNC_ARGS " -H"
fi
2013-08-18 11:58:55 +02:00
if [ $verbose -eq 1 ]
then
RSYNC_ARGS = $RSYNC_ARGS "i"
fi
if [ $dryrun -eq 1 ]
then
RSYNC_ARGS = $RSYNC_ARGS "n"
DRY_WARNING = "/!\ DRY RUN"
fi
2013-11-02 18:55:17 +01:00
if [ " $BANDWIDTH " != "" ] && [ " $BANDWIDTH " != "0" ]
2013-08-18 11:58:55 +02:00
then
RSYNC_ARGS = $RSYNC_ARGS " --bwlimit= $BANDWIDTH "
fi
2014-11-27 14:40:30 +01:00
if [ " $PARTIAL " = = "yes" ]
then
SYNC_OPTS = $SYNC_OPTS " --partial --partial-dir=\" $PARTIAL_DIR \" "
RSYNC_EXCLUDE = " $RSYNC_EXCLUDE --exclude=\" $PARTIAL_DIR \" "
fi
if [ $stats -eq 1 ]
then
SYNC_OPTS = $SYNC_OPTS " --stats"
fi
2014-11-18 14:43:04 +01:00
## Fix for symlink to directories on target can't get updated
RSYNC_ARGS = $RSYNC_ARGS " --force"
2014-09-22 22:45:18 +02:00
## Set compression executable and extension
COMPRESSION_LEVEL = 9
if type -p xz > /dev/null 2>& 1
2013-07-20 14:48:06 +02:00
then
2014-09-22 22:45:18 +02:00
COMPRESSION_PROGRAM = " | xz - $COMPRESSION_LEVEL "
2013-07-20 14:48:06 +02:00
COMPRESSION_EXTENSION = .xz
2014-09-22 22:45:18 +02:00
elif type -p lzma > /dev/null 2>& 1
2013-07-20 14:48:06 +02:00
then
2014-09-22 22:45:18 +02:00
COMPRESSION_PROGRAM = " | lzma - $COMPRESSION_LEVEL "
2013-07-20 14:48:06 +02:00
COMPRESSION_EXTENSION = .lzma
2014-09-22 22:45:18 +02:00
elif type -p pigz > /dev/null 2>& 1
2013-07-20 14:48:06 +02:00
then
2014-09-22 22:45:18 +02:00
COMPRESSION_PROGRAM = " | pigz - $COMPRESSION_LEVEL "
COMPRESSION_EXTENSION = .gz
COMPRESSION_OPTIONS = --rsyncable
elif type -p gzip > /dev/null 2>& 1
then
COMPRESSION_PROGRAM = " | gzip - $COMPRESSION_LEVEL "
2013-07-20 14:48:06 +02:00
COMPRESSION_EXTENSION = .gz
COMPRESSION_OPTIONS = --rsyncable
else
2014-09-22 22:45:18 +02:00
COMPRESSION_PROGRAM =
2013-07-20 14:48:06 +02:00
COMPRESSION_EXTENSION =
fi
2014-09-22 22:45:18 +02:00
ALERT_LOG_FILE = " $ALERT_LOG_FILE $COMPRESSION_EXTENSION "
}
function InitLocalOSSettings
{
2014-11-24 10:28:23 +01:00
## If running under Msys, some commands don't run the same way
## Using mingw version of find instead of windows one
## Getting running processes is quite different
## Ping command isn't the same
2014-09-22 22:45:18 +02:00
if [ " $LOCAL_OS " = = "msys" ]
then
FIND_CMD = $( dirname $BASH ) /find
2014-11-24 19:30:20 +01:00
## TODO: The following command needs to be checked on msys. Does the $1 variable substitution work ?
PROCESS_TEST_CMD = 'ps -a | awk "{\$1=\$1}\$1" | awk "{print \$1}" | grep $1'
2014-11-24 10:28:23 +01:00
PING_CMD = "ping -n 2"
2014-09-22 22:45:18 +02:00
else
FIND_CMD = find
2014-11-24 19:30:20 +01:00
PROCESS_TEST_CMD = 'ps -p$1'
2014-11-24 10:28:23 +01:00
PING_CMD = "ping -c 2 -i .2"
2014-09-22 22:45:18 +02:00
fi
## Stat command has different syntax on Linux and FreeBSD/MacOSX
if [ " $LOCAL_OS " = = "MacOSX" ] || [ " $LOCAL_OS " = = "BSD" ]
then
STAT_CMD = "stat -f \"%Sm\""
else
STAT_CMD = "stat --format %y"
fi
}
function InitRemoteOSSettings
{
## MacOSX does not use the -E parameter like Linux or BSD does (-E is mapped to extended attrs instead of preserve executability
if [ " $LOCAL_OS " != "MacOSX" ] && [ " $REMOTE_OS " != "MacOSX" ]
then
RSYNC_ARGS = $RSYNC_ARGS " -E"
fi
if [ " $REMOTE_OS " = = "msys" ]
then
REMOTE_FIND_CMD = $( dirname $BASH ) /find
else
REMOTE_FIND_CMD = find
fi
2013-07-16 23:10:27 +02:00
}
function Main
{
if [ " $BACKUP_SQL " != "no" ]
then
ListDatabases
fi
if [ " $BACKUP_FILES " != "no" ]
then
ListDirectories
GetDirectoriesSize
fi
2013-08-18 11:58:55 +02:00
if [ $dryrun -ne 1 ]
then
CreateLocalStorageDirectories
fi
2013-08-24 19:41:18 +02:00
2013-07-16 23:10:27 +02:00
CheckSpaceRequirements
2013-08-18 11:58:55 +02:00
# Actual backup process
2013-07-16 23:10:27 +02:00
if [ " $BACKUP_SQL " != "no" ]
then
2013-08-18 11:58:55 +02:00
if [ $dryrun -ne 1 ]
2013-07-16 23:10:27 +02:00
then
2013-08-18 11:58:55 +02:00
if [ " $ROTATE_BACKUPS " = = "yes" ]
then
RotateBackups $LOCAL_SQL_STORAGE
fi
2013-07-16 23:10:27 +02:00
fi
2014-11-27 14:40:30 +01:00
BackupDatabases
2013-07-16 23:10:27 +02:00
fi
2013-08-18 11:58:55 +02:00
2013-07-16 23:10:27 +02:00
if [ " $BACKUP_FILES " != "no" ]
then
2013-08-18 11:58:55 +02:00
if [ $dryrun -ne 1 ]
2013-07-16 23:10:27 +02:00
then
2013-08-18 11:58:55 +02:00
if [ " $ROTATE_BACKUPS " = = "yes" ]
then
RotateBackups $LOCAL_FILE_STORAGE
fi
2013-07-16 23:10:27 +02:00
fi
2014-11-24 10:28:23 +01:00
## Add Rsync exclude patterns
RsyncExcludePattern
## Add Rsync exclude from file
RsyncExcludeFrom
2013-07-16 23:10:27 +02:00
FilesBackup
fi
# Be a happy sysadmin (and drink a coffee ? Nahh... it's past midnight.)
}
function Usage
{
2014-09-22 22:45:18 +02:00
echo " $PROGRAM $PROGRAM_VERSION $PROGRAM_BUILD "
echo " $AUTHOR "
echo " $CONTACT "
2013-07-16 23:10:27 +02:00
echo ""
2013-09-03 21:31:41 +02:00
echo "usage: obackup /path/to/backup.conf [--dry] [--silent] [--verbose] [--no-maxtime]"
2013-07-16 23:10:27 +02:00
echo ""
echo "--dry: will run obackup without actually doing anything, just testing"
echo "--silent: will run obackup without any output to stdout, usefull for cron backups"
2013-07-21 21:42:00 +02:00
echo "--verbose: adds command outputs"
2014-11-27 14:40:30 +01:00
echo "--stats Adds rsync transfer statistics to verbose output"
echo "--partial Allows rsync to keep partial downloads that can be resumed later (experimental)"
2013-08-18 11:58:55 +02:00
echo "--no-maxtime: disables any soft and hard execution time checks"
2013-07-16 23:10:27 +02:00
exit 128
}
# Command line argument flags
dryrun = 0
silent = 0
2013-08-18 11:58:55 +02:00
no_maxtime = 0
if [ " $DEBUG " = = "yes" ]
then
verbose = 1
else
verbose = 0
fi
2014-11-27 14:40:30 +01:00
stats = 0
PARTIAL = 0
2013-07-16 23:10:27 +02:00
# Alert flags
soft_alert_total = 0
error_alert = 0
if [ $# -eq 0 ]
then
Usage
fi
for i in " $@ "
do
case $i in
--dry)
dryrun = 1
; ;
--silent)
silent = 1
; ;
2013-07-20 14:48:06 +02:00
--verbose)
verbose = 1
; ;
2014-11-27 14:40:30 +01:00
--stats)
stats = 1
; ;
--partial)
PARTIAL = "yes"
; ;
2013-08-18 11:58:55 +02:00
--no-maxtime)
no_maxtime = 1
; ;
2013-07-20 14:48:06 +02:00
--help| -h| --version| -v)
2013-07-16 23:10:27 +02:00
Usage
; ;
esac
done
2014-09-22 22:45:18 +02:00
GetLocalOS
InitLocalOSSettings
2013-07-16 23:10:27 +02:00
CheckEnvironment
if [ $? = = 0 ]
then
2014-09-22 22:45:18 +02:00
if [ " $1 " != "" ]
2013-07-16 23:10:27 +02:00
then
LoadConfigFile $1
if [ $? = = 0 ]
then
Init
2014-09-22 22:45:18 +02:00
GetRemoteOS
InitRemoteOSSettings
2013-07-16 23:10:27 +02:00
DATE = $( date)
Log "--------------------------------------------------------------------"
2014-09-22 22:45:18 +02:00
Log " $DRY_WARNING $DATE - $PROGRAM v $PROGRAM_VERSION script begin. "
2013-07-16 23:10:27 +02:00
Log "--------------------------------------------------------------------"
2013-08-18 11:58:55 +02:00
Log " Backup task [ $BACKUP_ID ] launched as $LOCAL_USER @ $LOCAL_HOST (PID $SCRIPT_PID ) "
2014-09-22 22:45:18 +02:00
2013-08-18 11:58:55 +02:00
if [ $no_maxtime -eq 1 ]
then
SOFT_MAX_EXEC_TIME = 0
HARD_MAX_EXEC_TIME = 0
fi
OLD_IFS = $IFS
RunBeforeHook
Main
IFS = $OLD_IFS
RunAfterHook
2013-07-16 23:10:27 +02:00
CleanUp
else
LogError "Configuration file could not be loaded."
exit 1
fi
else
LogError "No configuration file provided."
exit 1
fi
else
LogError "Environment not suitable to run obackup."
2013-10-10 19:17:45 +02:00
exit 1
2013-07-16 23:10:27 +02:00
fi