diff --git a/dev/de b/dev/de
deleted file mode 100755
index 5ac2adf..0000000
--- a/dev/de
+++ /dev/null
@@ -1,2750 +0,0 @@
-#!/usr/bin/env bash
-
-#TODO: test if trapquit works on kill (sigterm)
-
-PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
-AUTHOR="(C) 2013-2016 by Orsiris de Jong"
-CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
-PROGRAM_VERSION=1.1-dev
-PROGRAM_BUILD=2016021804
-IS_STABLE=no
-
-## FUNC_BUILD=2016021802
-## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
-
-## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
-if ! type "$BASH" > /dev/null; then
- echo "Please run this script only with bash shell. Tested on bash >= 3.2"
- exit 127
-fi
-
-# Environment variables
-_DRYRUN=0
-_SILENT=0
-
-# Initial error status, logging 'WARN', 'ERROR' or 'CRITICAL' will enable alerts flags
-ERROR_ALERT=0
-WARN_ALERT=0
-
-## allow function call checks #__WITH_PARANOIA_DEBUG
-if [ "$_PARANOIA_DEBUG" == "yes" ];then #__WITH_PARANOIA_DEBUG
- _DEBUG=yes #__WITH_PARANOIA_DEBUG
-fi #__WITH_PARANOIA_DEBUG
-
-## allow debugging from command line with _DEBUG=yes
-if [ ! "$_DEBUG" == "yes" ]; then
- _DEBUG=no
- SLEEP_TIME=.1
- _VERBOSE=0
-else
- SLEEP_TIME=1
- trap 'TrapError ${LINENO} $?' ERR
- _VERBOSE=1
-fi
-
-SCRIPT_PID=$$
-
-LOCAL_USER=$(whoami)
-LOCAL_HOST=$(hostname)
-
-## Default log file until config file is loaded
-if [ -w /var/log ]; then
- LOG_FILE="/var/log/$PROGRAM.log"
-else
- LOG_FILE="./$PROGRAM.log"
-fi
-
-## Default directory where to store temporary run files
-if [ -w /tmp ]; then
- RUN_DIR=/tmp
-elif [ -w /var/tmp ]; then
- RUN_DIR=/var/tmp
-else
- RUN_DIR=.
-fi
-
-## Log a state message every $KEEP_LOGGING seconds. Should not be equal to soft or hard execution time so your log will not be unnecessary big.
-KEEP_LOGGING=1801
-
-## Correct output of sort command (language agnostic sorting)
-export LC_ALL=C
-
-# Standard alert mail body
-MAIL_ALERT_MSG="Execution of $PROGRAM instance $INSTANCE_ID on $(date) has warnings/errors."
-
-# Default alert attachment filename
-ALERT_LOG_FILE="$RUN_DIR/$PROGRAM.last.log"
-
-# Set error exit code if a piped command fails
- set -o pipefail
- set -o errtrace
-
-
-function Dummy {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
- sleep .1
-}
-
-function _Logger {
- local svalue="${1}" # What to log to screen
- local lvalue="${2:-$svalue}" # What to log to logfile, defaults to screen value
- echo -e "$lvalue" >> "$LOG_FILE"
-
- if [ $_SILENT -eq 0 ]; then
- echo -e "$svalue"
- fi
-}
-
-function Logger {
- local value="${1}" # Sentence to log (in double quotes)
- local level="${2}" # Log level: PARANOIA_DEBUG, DEBUG, NOTICE, WARN, ERROR, CRITIAL
-
- # Special case in daemon mode we should timestamp instead of counting seconds
- if [ "$sync_on_changes" == "1" ]; then
- prefix="$(date) - "
- else
- prefix="TIME: $SECONDS - "
- fi
- #
-
- if [ "$level" == "CRITICAL" ]; then
- _Logger "$prefix\e[41m$value\e[0m" "$prefix$value"
- ERROR_ALERT=1
- return
- elif [ "$level" == "ERROR" ]; then
- _Logger "$prefix\e[91m$value\e[0m" "$prefix$value"
- ERROR_ALERT=1
- return
- elif [ "$level" == "WARN" ]; then
- _Logger "$prefix\e[93m$value\e[0m" "$prefix$value"
- WARN_ALERT=1
- return
- elif [ "$level" == "NOTICE" ]; then
- _Logger "$prefix$value"
- return
- elif [ "$level" == "DEBUG" ]; then
- if [ "$_DEBUG" == "yes" ]; then
- _Logger "$prefix$value"
- return
- fi
- elif [ "$level" == "PARANOIA_DEBUG" ]; then #__WITH_PARANOIA_DEBUG
- if [ "$_PARANOIA_DEBUG" == "yes" ]; then #__WITH_PARANOIA_DEBUG
- _Logger "$prefix$value" #__WITH_PARANOIA_DEBUG
- return #__WITH_PARANOIA_DEBUG
- fi #__WITH_PARANOIA_DEBUG
- else
- _Logger "\e[41mLogger function called without proper loglevel.\e[0m"
- _Logger "$prefix$value"
- fi
-}
-
-# Portable child (and grandchild) kill function tester under Linux, BSD and MacOS X
-function KillChilds {
- local pid="${1}"
- local self="${2:-false}"
-
- if children="$(pgrep -P "$pid")"; then
- for child in $children; do
- KillChilds "$child" true
- done
- fi
-
- # Try to kill nicely, if not, wait 30 seconds to let Trap actions happen before killing
- if [ "$self" == true ]; then
- kill -s SIGTERM "$pid" || (sleep 30 && kill -9 "$pid" &)
- fi
-}
-
-function TrapError {
- local job="$0"
- local line="$1"
- local code="${2:-1}"
- if [ $_SILENT -eq 0 ]; then
- echo -e " /!\ ERROR in ${job}: Near line ${line}, exit code ${code}"
- fi
-}
-
-function Spinner {
- if [ $_SILENT -eq 1 ]; then
- return 0
- fi
-
- case $toggle
- in
- 1)
- echo -n " \ "
- echo -ne "\r"
- toggle="2"
- ;;
-
- 2)
- echo -n " | "
- echo -ne "\r"
- toggle="3"
- ;;
-
- 3)
- echo -n " / "
- echo -ne "\r"
- toggle="4"
- ;;
-
- *)
- echo -n " - "
- echo -ne "\r"
- toggle="1"
- ;;
- esac
-}
-
-function SedStripQuotes {
- echo $(echo $1 | sed "s/^\([\"']\)\(.*\)\1\$/\2/g")
-}
-
-function StripSingleQuotes {
- local string="${1}"
- string="${string/#\'/}" # Remove singlequote if it begins string
- string="${string/%\'/}" # Remove singlequote if it ends string
- echo "$string"
-}
-
-function StripDoubleQuotes {
- local string="${1}"
- string="${string/#\"/}"
- string="${string/%\"/}"
- echo "$string"
-}
-
-function StripQuotes {
- local string="${1}"
- echo "$(StripSingleQuotes $(StripDoubleQuotes $string))"
-}
-
-function EscapeSpaces {
- local string="${1}" # String on which spaces will be escaped
- echo "${string// /\ }"
-}
-
-function IsNumeric {
- eval "local value=\"${1}\"" # Needed so variable variables can be processed
-
- local re="^-?[0-9]+([.][0-9]+)?$"
- if [[ $value =~ $re ]]; then
- echo 1
- else
- echo 0
- fi
-}
-
-function CleanUp {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ "$_DEBUG" != "yes" ]; then
- rm -f "$RUN_DIR/$PROGRAM."*".$SCRIPT_PID"
- fi
-}
-
-function SendAlert {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local mail_no_attachment=
- local attachment_command=
-
- if [ "$_DEBUG" == "yes" ]; then
- Logger "Debug mode, no warning email will be sent." "NOTICE"
- return 0
- fi
-
- #
- if [ "$_QUICK_SYNC" == "2" ]; then
- Logger "Current task is a quicksync task. Will not send any alert." "NOTICE"
- return 0
- fi
- #
-
- eval "cat \"$LOG_FILE\" $COMPRESSION_PROGRAM > $ALERT_LOG_FILE"
- if [ $? != 0 ]; then
- Logger "Cannot create [$ALERT_LOG_FILE]" "WARN"
- mail_no_attachment=1
- else
- mail_no_attachment=0
- fi
- MAIL_ALERT_MSG="$MAIL_ALERT_MSG"$'\n\n'$(tail -n 50 "$LOG_FILE")
- if [ $ERROR_ALERT -eq 1 ]; then
- subject="Error alert for $INSTANCE_ID"
- elif [ $WARN_ALERT -eq 1 ]; then
- subject="Warning alert for $INSTANCE_ID"
- else
- subject="Alert for $INSTANCE_ID"
- fi
-
- if [ "$mail_no_attachment" -eq 0 ]; then
- attachment_command="-a $ALERT_LOG_FILE"
- fi
- if type mutt > /dev/null 2>&1 ; then
- echo "$MAIL_ALERT_MSG" | $(type -p mutt) -x -s "$subject" $DESTINATION_MAILS $attachment_command
- if [ $? != 0 ]; then
- Logger "WARNING: Cannot send alert email via $(type -p mutt) !!!" "WARN"
- else
- Logger "Sent alert mail using mutt." "NOTICE"
- return 0
- fi
- fi
-
- if type mail > /dev/null 2>&1 ; then
- if [ "$mail_no_attachment" -eq 0 ] && $(type -p mail) -V | grep "GNU" > /dev/null; then
- attachment_command="-A $ALERT_LOG_FILE"
- elif [ "$mail_no_attachment" -eq 0 ] && $(type -p mail) -V > /dev/null; then
- attachment_command="-a $ALERT_LOG_FILE"
- else
- attachment_command=""
- fi
- echo "$MAIL_ALERT_MSG" | $(type -p mail) $attachment_command -s "$subject" $DESTINATION_MAILS
- if [ $? != 0 ]; then
- Logger "WARNING: Cannot send alert email via $(type -p mail) with attachments !!!" "WARN"
- echo "$MAIL_ALERT_MSG" | $(type -p mail) -s "$subject" $DESTINATION_MAILS
- if [ $? != 0 ]; then
- Logger "WARNING: Cannot send alert email via $(type -p mail) without attachments !!!" "WARN"
- else
- Logger "Sent alert mail using mail command without attachment." "NOTICE"
- return 0
- fi
- else
- Logger "Sent alert mail using mail command." "NOTICE"
- return 0
- fi
- fi
-
- if type sendmail > /dev/null 2>&1 ; then
- echo -e "Subject:$subject\r\n$MAIL_ALERT_MSG" | $(type -p sendmail) $DESTINATION_MAILS
- if [ $? != 0 ]; then
- Logger "WARNING: Cannot send alert email via $(type -p sendmail) !!!" "WARN"
- else
- Logger "Sent alert mail using sendmail command without attachment." "NOTICE"
- return 0
- fi
- fi
-
- if type sendemail > /dev/null 2>&1 ; then
- if [ "$SMTP_USER" != "" ] && [ "$SMTP_PASSWORD" != "" ]; then
- SMTP_OPTIONS="-xu $SMTP_USER -xp $SMTP_PASSWORD"
- else
- SMTP_OPTIONS=""
- fi
- $(type -p sendemail) -f $SENDER_MAIL -t $DESTINATION_MAILS -u "$subject" -m "$MAIL_ALERT_MSG" -s $SMTP_SERVER $SMTP_OPTIONS > /dev/null 2>&1
- if [ $? != 0 ]; then
- Logger "WARNING: Cannot send alert email via $(type -p sendemail) !!!" "WARN"
- else
- Logger "Sent alert mail using sendemail command without attachment." "NOTICE"
- return 0
- fi
- fi
-
- # If function has not returned 0 yet, assume it's critical that no alert can be sent
- Logger "/!\ CRITICAL: Cannot send alert (neither mutt, mail, sendmail nor sendemail found)." "ERROR" # Is not marked critical because execution must continue
-
- # Delete tmp log file
- if [ -f "$ALERT_LOG_FILE" ]; then
- rm "$ALERT_LOG_FILE"
- fi
-}
-
-function LoadConfigFile {
- local config_file="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
-
- if [ ! -f "$config_file" ]; then
- Logger "Cannot load configuration file [$config_file]. Cannot start." "CRITICAL"
- exit 1
- elif [[ "$1" != *".conf" ]]; then
- Logger "Wrong configuration file supplied [$config_file]. Cannot start." "CRITICAL"
- exit 1
- else
- grep '^[^ ]*=[^;&]*' "$config_file" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" # WITHOUT COMMENTS
- # Shellcheck source=./sync.conf
- source "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID"
- fi
-
- CONFIG_FILE="$config_file"
-}
-
-function GetLocalOS {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local local_os_var=
-
- local_os_var="$(uname -spio 2>&1)"
- if [ $? != 0 ]; then
- local_os_var="$(uname -v 2>&1)"
- if [ $? != 0 ]; then
- local_os_var="$(uname)"
- fi
- fi
-
- case $local_os_var in
- *"Linux"*)
- LOCAL_OS="Linux"
- ;;
- *"BSD"*)
- LOCAL_OS="BSD"
- ;;
- *"MINGW32"*)
- LOCAL_OS="msys"
- ;;
- *"Darwin"*)
- LOCAL_OS="MacOSX"
- ;;
- *)
- Logger "Running on >> $local_os_var << not supported. Please report to the author." "ERROR"
- exit 1
- ;;
- esac
- Logger "Local OS: [$local_os_var]." "DEBUG"
-}
-
-function GetRemoteOS {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local cmd=
- local remote_os_var=
-
-
- if [ "$REMOTE_OPERATION" == "yes" ]; then
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
- cmd=$SSH_CMD' "uname -spio" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 120 240 ${FUNCNAME[0]}"-1"
- retval=$?
- if [ $retval != 0 ]; then
- cmd=$SSH_CMD' "uname -v" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 120 240 ${FUNCNAME[0]}"-2"
- retval=$?
- if [ $retval != 0 ]; then
- cmd=$SSH_CMD' "uname" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 120 240 ${FUNCNAME[0]}"-3"
- retval=$?
- if [ $retval != 0 ]; then
- Logger "Cannot Get remote OS type." "ERROR"
- fi
- fi
- fi
-
- remote_os_var=$(cat "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$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"*)
- Logger "Cannot connect to remote system." "CRITICAL"
- exit 1
- ;;
- *)
- Logger "Running on remote OS failed. Please report to the author if the OS is not supported." "CRITICAL"
- Logger "Remote OS said:\n$remote_os_var" "CRITICAL"
- exit 1
- esac
-
- Logger "Remote OS: [$remote_os_var]." "DEBUG"
- fi
-}
-
-function WaitForTaskCompletion {
- local pid="${1}" # pid to wait for
- local soft_max_time="${2}" # If program with pid $pid takes longer than $soft_max_time seconds, will log a warning, unless $soft_max_time equals 0.
- local hard_max_time="${3}" # If program with pid $pid takes longer than $hard_max_time seconds, will stop execution, unless $hard_max_time equals 0.
- local caller_name="${4}" # Who called this function
- Logger "${FUNCNAME[0]} called by [$caller_name]." "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG
- __CheckArguments 4 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once
- local log_ttime=0 # local time instance for comparaison
-
- local seconds_begin=$SECONDS # Seconds since the beginning of the script
- local exec_time=0 # Seconds since the beginning of this function
-
- while eval "$PROCESS_TEST_CMD" > /dev/null
- do
- Spinner
- exec_time=$(($SECONDS - $seconds_begin))
- if [ $((($exec_time + 1) % $KEEP_LOGGING)) -eq 0 ]; then
- if [ $log_ttime -ne $exec_time ]; then
- log_ttime=$exec_time
- Logger "Current task still running." "NOTICE"
- fi
- fi
- if [ $exec_time -gt $soft_max_time ]; then
- if [ $soft_alert -eq 0 ] && [ $soft_max_time -ne 0 ]; then
- Logger "Max soft execution time exceeded for task." "WARN"
- soft_alert=1
- SendAlert
-
- fi
- if [ $exec_time -gt $hard_max_time ] && [ $hard_max_time -ne 0 ]; then
- Logger "Max hard execution time exceeded for task. Stopping task execution." "ERROR"
- kill -s SIGTERM $pid
- if [ $? == 0 ]; then
- Logger "Task stopped succesfully" "NOTICE"
- else
- Logger "Sending SIGTERM to proces failed. Trying the hard way." "ERROR"
- sleep 5 && kill -9 $pid
- if [ $? != 0 ]; then
- Logger "Could not stop task." "ERROR"
- fi
- fi
- return 1
- fi
- fi
- sleep $SLEEP_TIME
- done
- wait $pid
- local retval=$?
- Logger "${FUNCNAME[0]} ended for [$caller_name] with status $retval." "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG
- return $retval
-}
-
-function WaitForCompletion {
- local pid="${1}" # pid to wait for
- local soft_max_time="${2}" # If program with pid $pid takes longer than $soft_max_time seconds, will log a warning, unless $soft_max_time equals 0.
- local hard_max_time="${3}" # If program with pid $pid takes longer than $hard_max_time seconds, will stop execution, unless $hard_max_time equals 0.
- local caller_name="${4}" # Who called this function
- Logger "${FUNCNAME[0]} called by [$caller_name]" "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG
- __CheckArguments 4 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local soft_alert=0 # Does a soft alert need to be triggered, if yes, send an alert once
- local log_ttime=0 # local time instance for comparaison
-
- local seconds_begin=$SECONDS # Seconds since the beginning of the script
- local exec_time=0 # Seconds since the beginning of this function
-
- while eval "$PROCESS_TEST_CMD" > /dev/null
- do
- Spinner
- if [ $((($SECONDS + 1) % $KEEP_LOGGING)) -eq 0 ]; then
- if [ $log_time -ne $SECONDS ]; then
- log_time=$SECONDS
- Logger "Current task still running." "NOTICE"
- fi
- fi
- if [ $SECONDS -gt $soft_max_time ]; then
- if [ $soft_alert -eq 0 ] && [ $soft_max_time != 0 ]; then
- Logger "Max soft execution time exceeded for script." "WARN"
- soft_alert=1
- SendAlert
- fi
- if [ $SECONDS -gt $hard_max_time ] && [ $hard_max_time != 0 ]; then
- Logger "Max hard execution time exceeded for script. Stopping current task execution." "ERROR"
- kill -s SIGTERM $pid
- if [ $? == 0 ]; then
- Logger "Task stopped succesfully" "NOTICE"
- else
- Logger "Sending SIGTERM to proces failed. Trying the hard way." "ERROR"
- kill -9 $pid
- if [ $? != 0 ]; then
- Logger "Could not stop task." "ERROR"
- fi
- fi
- return 1
- fi
- fi
- sleep $SLEEP_TIME
- done
- wait $pid
- retval=$?
- Logger "${FUNCNAME[0]} ended for [$caller_name] with status $retval." "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG
- return $retval
-}
-
-function RunLocalCommand {
- local command="${1}" # Command to run
- local hard_max_time="${2}" # Max time to wait for command to compleet
- __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ $_DRYRUN -ne 0 ]; then
- Logger "Dryrun: Local command [$command] not run." "NOTICE"
- return 0
- fi
-
- Logger "Running command [$command] on local host." "NOTICE"
- eval "$command" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1 &
- WaitForTaskCompletion $! 0 $hard_max_time ${FUNCNAME[0]}
- retval=$?
- if [ $retval -eq 0 ]; then
- Logger "Command succeded." "NOTICE"
- else
- Logger "Command failed." "ERROR"
- fi
-
- if [ $_VERBOSE -eq 1 ] || [ $retval -ne 0 ]; then
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- fi
-
- if [ "$STOP_ON_CMD_ERROR" == "yes" ] && [ $retval -ne 0 ]; then
- Logger "Stopping on command execution error." "CRITICAL"
- exit 1
- fi
-}
-
-## Runs remote command $1 and waits for completition in $2 seconds
-function RunRemoteCommand {
- local command="${1}" # Command to run
- local hard_max_time="${2}" # Max time to wait for command to compleet
- __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
- if [ $_DRYRUN -ne 0 ]; then
- Logger "Dryrun: Local command [$command] not run." "NOTICE"
- return 0
- fi
-
- Logger "Running command [$command] on remote host." "NOTICE"
- cmd=$SSH_CMD' "$command" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 0 $hard_max_time ${FUNCNAME[0]}
- retval=$?
- if [ $retval -eq 0 ]; then
- Logger "Command succeded." "NOTICE"
- else
- Logger "Command failed." "ERROR"
- fi
-
- if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_VERBOSE -eq 1 ] || [ $retval -ne 0 ])
- then
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- fi
-
- if [ "$STOP_ON_CMD_ERROR" == "yes" ] && [ $retval -ne 0 ]; then
- Logger "Stopping on command execution error." "CRITICAL"
- exit 1
- fi
-}
-
-function RunBeforeHook {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- 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
- fi
-}
-
-function RunAfterHook {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- 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 CheckConnectivityRemoteHost {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ "$_PARANOIA_DEBUG" != "yes" ]; then # Do not loose time in paranoia debug
-
- if [ "$REMOTE_HOST_PING" != "no" ] && [ "$REMOTE_OPERATION" != "no" ]; then
- eval "$PING_CMD $REMOTE_HOST > /dev/null 2>&1" &
- WaitForTaskCompletion $! 180 180 ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- Logger "Cannot ping $REMOTE_HOST" "CRITICAL"
- return 1
- fi
- fi
- fi
-}
-
-function CheckConnectivity3rdPartyHosts {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ "$_PARANOIA_DEBUG" != "yes" ]; then # Do not loose time in paranoia debug
-
- if [ "$REMOTE_3RD_PARTY_HOSTS" != "" ]; then
- remote_3rd_party_success=0
- OLD_IFS=$IFS
- IFS=$' \t\n'
- for i in $REMOTE_3RD_PARTY_HOSTS
- do
- eval "$PING_CMD $i > /dev/null 2>&1" &
- WaitForTaskCompletion $! 360 360 ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- Logger "Cannot ping 3rd party host $i" "WARN"
- else
- remote_3rd_party_success=1
- fi
- done
- IFS=$OLD_IFS
- if [ $remote_3rd_party_success -ne 1 ]; then
- Logger "No remote 3rd party host responded to ping. No internet ?" "CRITICAL"
- return 1
- fi
- fi
- fi
-}
-
-#__BEGIN_WITH_PARANOIA_DEBUG
-function __CheckArguments {
- # Checks the number of arguments of a function and raises an error if some are missing
-
- if [ "$_DEBUG" == "yes" ]; then
- local number_of_arguments="${1}" # Number of arguments the tested function should have
- local number_of_given_arguments="${2}" # Number of arguments that have been passed
- local function_name="${3}" # Function name that called __CheckArguments
-
- if [ "$_PARANOIA_DEBUG" == "yes" ]; then
- Logger "Entering function [$function_name]." "DEBUG"
- fi
-
- # All arguments of the function to check are passed as array in ${4} (the function call waits for $@)
- # If any of the arguments contains spaces, bash things there are two aguments
- # In order to avoid this, we need to iterate over ${4} and count
-
- local iterate=4
- local fetch_arguments=1
- local arg_list=""
- while [ $fetch_arguments -eq 1 ]; do
- cmd='argument=${'$iterate'}'
- eval $cmd
- if [ "$argument" = "" ]; then
- fetch_arguments=0
- else
- arg_list="$arg_list [Argument $(($iterate-3)): $argument]"
- iterate=$(($iterate+1))
- fi
- done
- local counted_arguments=$((iterate-4))
-
- if [ $counted_arguments -ne $number_of_arguments ]; then
- Logger "Function $function_name may have inconsistent number of arguments. Expected: $number_of_arguments, count: $counted_arguments, see log file." "ERROR"
- Logger "Arguments passed: $arg_list" "ERROR"
- fi
- fi
-}
-
-
-function old__CheckArguments {
- # Checks the number of arguments and raises an error if some are missing
- if [ "$_DEBUG" == "yes" ]; then
-
- local number_of_arguments="${1}" # Number of arguments a function should have
- local number_of_given_arguments="${2}" # Number of arguments that have been passed
- local function_name="${3}" # Function name that called __CheckArguments
- local arguments="${4}" # All other arguments
-
- if [ "$_PARANOIA_DEBUG" == "yes" ]; then
- Logger "Entering function [$function_name]." "DEBUG"
-
- # Paranoia check... Can help finding empty arguments. __CheckArguments should be grepped out in production builds.
- local count=-3 # Number of arguments minus the function calls for __CheckArguments
- for i in $@; do
- count=$((count + 1))
- done
- if [ $count -ne $1 ]; then
- Logger "Function $function_name may have inconsistent number of arguments. Expected: $number_of_arguments, count: $count, see log file." "WARN"
- echo "Argument list (including checks): $*" >> "$LOG_FILE"
- fi
- fi
-
- if [ $number_of_arguments -ne $number_of_given_arguments ]; then
- Logger "Inconsistnent number of arguments in $function_name. Should have $number_of_arguments arguments, has $number_of_given_arguments arguments, see log file." "CRITICAL"
- # Cannot user Logger here because $@ is a list of arguments
- echo "Argumnt list: $4" >> "$LOG_FILE"
- fi
-
- fi
-}
-#__END_WITH_PARANOIA_DEBUG
-
-function PreInit {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- ## SSH compression
- if [ "$SSH_COMPRESSION" != "no" ]; then
- SSH_COMP=-C
- else
- SSH_COMP=
- fi
-
- ## 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
- if [ "$RSYNC_REMOTE_PATH" != "" ]; then
- RSYNC_PATH="sudo $RSYNC_REMOTE_PATH/$RSYNC_EXECUTABLE"
- else
- RSYNC_PATH="sudo $RSYNC_EXECUTABLE"
- fi
- COMMAND_SUDO="sudo"
- else
- if [ "$RSYNC_REMOTE_PATH" != "" ]; then
- RSYNC_PATH="$RSYNC_REMOTE_PATH/$RSYNC_EXECUTABLE"
- else
- RSYNC_PATH="$RSYNC_EXECUTABLE"
- fi
- COMMAND_SUDO=""
- fi
-
- ## Set rsync default arguments
- RSYNC_ARGS="-rltD"
- RSYNC_ATTR_ARGS="-pgo"
-
- if [ "$PRESERVE_ACL" == "yes" ]; then
- RSYNC_ATTR_ARGS=$RSYNC_ATTR_ARGS" -A"
- fi
- if [ "$PRESERVE_XATTR" == "yes" ]; then
- RSYNC_ATTR_ARGS=$RSYNC_ATTR_ARGS" -X"
- fi
- if [ "$RSYNC_COMPRESS" == "yes" ]; then
- RSYNC_ARGS=$RSYNC_ARGS" -z"
- fi
- if [ "$COPY_SYMLINKS" == "yes" ]; then
- RSYNC_ARGS=$RSYNC_ARGS" -L"
- fi
- if [ "$KEEP_DIRLINKS" == "yes" ]; then
- RSYNC_ARGS=$RSYNC_ARGS" -K"
- fi
- if [ "$PRESERVE_HARDLINKS" == "yes" ]; then
- RSYNC_ARGS=$RSYNC_ARGS" -H"
- fi
- if [ "$CHECKSUM" == "yes" ]; then
- RSYNC_TYPE_ARGS=$RSYNC_TYPE_ARGS" --checksum"
- fi
- if [ $_DRYRUN -eq 1 ]; then
- RSYNC_ARGS=$RSYNC_ARGS" -n"
- DRY_WARNING="/!\ DRY RUN"
- fi
- if [ "$BANDWIDTH" != "" ] && [ "$BANDWIDTH" != "0" ]; then
- RSYNC_ARGS=$RSYNC_ARGS" --bwlimit=$BANDWIDTH"
- fi
-
- if [ "$PARTIAL" == "yes" ]; then
- RSYNC_ARGS=$RSYNC_ARGS" --partial --partial-dir=\"$PARTIAL_DIR\""
- RSYNC_PARTIAL_EXCLUDE="--exclude=\"$PARTIAL_DIR\""
- fi
-
- if [ "$DELTA_COPIES" != "no" ]; then
- RSYNC_ARGS=$RSYNC_ARGS" --no-whole-file"
- else
- RSYNC_ARGS=$RSYNC_ARGS" --whole-file"
- fi
-
- ## Set compression executable and extension
- COMPRESSION_LEVEL=3
- if type xz > /dev/null 2>&1
- then
- COMPRESSION_PROGRAM="| xz -$COMPRESSION_LEVEL"
- COMPRESSION_EXTENSION=.xz
- elif type lzma > /dev/null 2>&1
- then
- COMPRESSION_PROGRAM="| lzma -$COMPRESSION_LEVEL"
- COMPRESSION_EXTENSION=.lzma
- elif type pigz > /dev/null 2>&1
- then
- COMPRESSION_PROGRAM="| pigz -$COMPRESSION_LEVEL"
- COMPRESSION_EXTENSION=.gz
- # obackup specific
- COMPRESSION_OPTIONS=--rsyncable
- elif type gzip > /dev/null 2>&1
- then
- COMPRESSION_PROGRAM="| gzip -$COMPRESSION_LEVEL"
- COMPRESSION_EXTENSION=.gz
- # obackup specific
- COMPRESSION_OPTIONS=--rsyncable
- else
- COMPRESSION_PROGRAM=
- COMPRESSION_EXTENSION=
- fi
- ALERT_LOG_FILE="$ALERT_LOG_FILE$COMPRESSION_EXTENSION"
-}
-
-function PostInit {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- # Define remote commands
- SSH_CMD="$(type -p ssh) $SSH_COMP -i $SSH_RSA_PRIVATE_KEY $REMOTE_USER@$REMOTE_HOST -p $REMOTE_PORT"
- SCP_CMD="$(type -p scp) $SSH_COMP -i $SSH_RSA_PRIVATE_KEY -P $REMOTE_PORT"
- RSYNC_SSH_CMD="$(type -p ssh) $SSH_COMP -i $SSH_RSA_PRIVATE_KEY -p $REMOTE_PORT"
-}
-
-function InitLocalOSSettings {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- ## If running under Msys, some commands do not run the same way
- ## Using mingw version of find instead of windows one
- ## Getting running processes is quite different
- ## Ping command is not the same
- if [ "$LOCAL_OS" == "msys" ]; then
- FIND_CMD=$(dirname $BASH)/find
- #TODO: The following command needs to be checked on msys. Does the $1 variable substitution work ?
- # PROCESS_TEST_CMD assumes there is a variable $pid
- PROCESS_TEST_CMD='ps -a | awk "{\$1=\$1}\$1" | awk "{print \$1}" | grep $pid'
- PING_CMD="ping -n 2"
- else
- FIND_CMD=find
- # PROCESS_TEST_CMD assumes there is a variable $pid
- PROCESS_TEST_CMD='ps -p$pid'
- PING_CMD="ping -c 2 -i .2"
- 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 {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- ## 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_ATTR_ARGS=$RSYNC_ATTR_ARGS" -E"
- fi
-
- if [ "$REMOTE_OS" == "msys" ]; then
- REMOTE_FIND_CMD=$(dirname $BASH)/find
- else
- REMOTE_FIND_CMD=find
- fi
-}
-
-## END Generic functions
-
-## Working directory. This directory exists in any replica and contains state files, backups, soft deleted files etc
-OSYNC_DIR=".osync_workdir"
-
-function TrapStop {
- if [ $soft_stop -eq 0 ]; then
- Logger " /!\ WARNING: Manual exit of osync is really not recommended. Sync will be in inconsistent state." "WARN"
- Logger " /!\ WARNING: If you are sure, please hit CTRL+C another time to quit." "WARN"
- soft_stop=1
- return 1
- fi
-
- if [ $soft_stop -eq 1 ]; then
- Logger " /!\ WARNING: CTRL+C hit twice. Exiting osync. Please wait while replicas get unlocked..." "WARN"
- soft_stop=2
- exit 1
- fi
-}
-
-function TrapQuit {
- if [ $ERROR_ALERT -ne 0 ]; then
- UnlockReplicas
- if [ "$_DEBUG" != "yes" ]
- then
- SendAlert
- else
- Logger "Debug mode, no alert mail will be sent." "NOTICE"
- fi
- CleanUp
- Logger "$PROGRAM finished with errors." "ERROR"
- exitcode=1
- elif [ $WARN_ALERT -ne 0 ]; then
- UnlockReplicas
- if [ "$_DEBUG" != "yes" ]
- then
- SendAlert
- else
- Logger "Debug mode, no alert mail will be sent." "NOTICE"
- fi
- CleanUp
- Logger "$PROGRAM finished with warnings." "WARN"
- exitcode=2
- else
- UnlockReplicas
- CleanUp
- Logger "$PROGRAM finished." "NOTICE"
- exitcode=0
- fi
-
-#TODO: Check new KillChilds function for service mode
-
-# if ps -p $OSYNC_SUB_PID > /dev/null 2>&1
-# then
-# kill -s SIGTERM $OSYNC_SUB_PID
-# if [ $? == 0 ]; then
-# Logger "Stopped sub process [$OSYNC_SUB_PID]." "DEBUG"
-# else
-# Logger "Could not terminate sub process [$OSYNC_SUB_PID]. Trying the hard way." "DEBUG"
-# kill -9 $OSYNC_SUB_PID
-# if [ $? != 0 ]; then
-# Logger "Could not kill sub process [$OSYNC_SUB_PID]." "ERROR"
-# fi
-# fi
-# fi
-
- KillChilds $$ > /dev/null 2>&1
-
- exit $exitcode
-}
-
-function CheckEnvironment {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ "$REMOTE_OPERATION" == "yes" ]; then
- if ! type ssh > /dev/null 2>&1 ; then
- Logger "ssh not present. Cannot start sync." "CRITICAL"
- exit 1
- fi
- fi
-
- if ! type rsync > /dev/null 2>&1 ; then
- Logger "rsync not present. Sync cannot start." "CRITICAL"
- exit 1
- fi
-}
-
-function CheckCurrentConfig {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ "$INSTANCE_ID" == "" ]; then
- Logger "No INSTANCE_ID defined in config file." "CRITICAL"
- exit 1
- fi
-
- if [ "$INITIATOR_SYNC_DIR" == "" ]; then
- Logger "No INITIATOR_SYNC_DIR set in config file." "CRITICAL"
- exit 1
- fi
-
- if [ "$TARGET_SYNC_DIR" == "" ]; then
- Logger "Not TARGET_SYNC_DIR set in config file." "CRITICAL"
- exit 1
- fi
-
- # Check all variables that should contain "yes" or "no"
- declare -a yes_no_vars=(CREATE_DIRS SUDO_EXEC SSH_COMPRESSION REMOTE_HOST_PING PRESERVE_ACL PRESERVE_XATTR COPY_SYMLINKS KEEP_DIRLINKS PRESERVE_HARDLINKS CHECKSUM RSYNC_COMPRESS CONFLICT_BACKUP CONFLICT_BACKUP_MULTIPLE SOFT_DELETE RESUME_SYNC FORCE_STRANGER_LOCK_RESUME PARTIAL DELTA_COPIES STOP_ON_CMD_ERROR)
- for i in "${yes_no_vars[@]}"; do
- test="if [ \"\$$i\" != \"yes\" ] && [ \"\$$i\" != \"no\" ]; then Logger \"Bogus $i value defined in config file.\" \"CRITICAL\"; exit 1; fi"
- eval "$test"
- done
-
- # Check all variables that should contain a numerical value >= 0
- declare -a num_vars=(MINIMUM_SPACE BANDWIDTH SOFT_MAX_EXEC_TIME HARD_MAX_EXEC_TIME MIN_WAIT MAX_WAIT CONFLICT_BACKUP_DAYS SOFT_DELETE_DAYS RESUME_TRY)
- for i in "${num_vars[@]}"; do
- test="if [ $(IsNumeric \"\$$i\") -eq 0 ]; then Logger \"Bogus $i value defined in config file.\" \"CRITICAL\"; exit 1; fi"
- eval "$test"
- done
-
- #TODO-v2.1: Add runtime variable tests (RSYNC_ARGS etc)
-}
-
-###### Osync specific functions (non shared)
-
-function _CreateStateDirsLocal {
- local replica_state_dir="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if ! [ -d "$replica_state_dir" ]; then
- $COMMAND_SUDO mkdir -p "$replica_state_dir" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1
- if [ $? != 0 ]; then
- Logger "Cannot create state dir [$replica_state_dir]." "CRITICAL"
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "ERROR"
- exit 1
- fi
- fi
-}
-
-function _CreateStateDirsRemote {
- local replica_state_dir="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local cmd=
-
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
-
- cmd=$SSH_CMD' "if ! [ -d \"'$replica_state_dir'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_state_dir'\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- Logger "Cannot create remote state dir [$replica_state_dir]." "CRITICAL"
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "ERROR"
- exit 1
- fi
-}
-
-function CreateStateDirs {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- _CreateStateDirsLocal "${INITIATOR[1]}${INITIATOR[3]}"
- if [ "$REMOTE_OPERATION" != "yes" ]; then
- _CreateStateDirsLocal "${TARGET[1]}${TARGET[3]}"
- else
- _CreateStateDirsRemote "${TARGET[1]}${TARGET[3]}"
- fi
-}
-
-function _CheckReplicaPathsLocal {
- local replica_path="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ ! -d "$replica_path" ]; then
- if [ "$CREATE_DIRS" == "yes" ]; then
- $COMMAND_SUDO mkdir -p "$replica_path" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1
- if [ $? != 0 ]; then
- Logger "Cannot create local replica path [$replica_path]." "CRITICAL"
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)"
- exit 1
- else
- Logger "Created local replica path [$replica_path]." "NOTICE"
- fi
- else
- Logger "Local replica path [$replica_path] does not exist." "CRITICAL"
- exit 1
- fi
- fi
-
- if [ ! -w "$replica_path" ]; then
- Logger "Local replica path [$replica_path] is not writable." "CRITICAL"
- exit 1
- fi
-}
-
-function _CheckReplicaPathsRemote {
- local replica_path="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local cmd=
-
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
- cmd=$SSH_CMD' "if ! [ -d \"'$replica_path'\" ]; then if [ \"'$CREATE_DIRS'\" == \"yes\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_path'\"; fi; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- Logger "Cannot create remote replica path [$replica_path]." "CRITICAL"
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "ERROR"
- exit 1
- fi
-
- cmd=$SSH_CMD' "if [ ! -w \"'$replica_path'\" ];then exit 1; fi" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- Logger "Remote replica path [$replica_path] is not writable." "CRITICAL"
- exit 1
- fi
-}
-
-function CheckReplicaPaths {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- #INITIATOR_SYNC_DIR_CANN=$(realpath "$INITIATOR_SYNC_DIR") #TODO: investigate realpath & readlink issues on MSYS and busybox here
- #TARGET_SYNC_DIR_CANN=$(realpath "$TARGET_SYNC_DIR") #TODO2: replace all variables with INITIATOR object
-
- #if [ "$REMOTE_OPERATION" != "yes" ]; then
- # if [ "$INITIATOR_SYNC_DIR_CANN" == "$TARGET_SYNC_DIR_CANN" ]; then
- # Logger "Master directory [$INITIATOR_SYNC_DIR] cannot be the same as target directory." "CRITICAL"
- # exit 1
- # fi
- #fi
-
- _CheckReplicaPathsLocal "${INITIATOR[1]}"
- if [ "$REMOTE_OPERATION" != "yes" ]; then
- _CheckReplicaPathsLocal "${TARGET[1]}"
- else
- _CheckReplicaPathsRemote "${TARGET[1]}"
- fi
-}
-
-function _CheckDiskSpaceLocal {
- local replica_path="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local disk_space=
-
- Logger "Checking minimum disk space in [$replica_path]." "NOTICE"
-
- disk_space=$(df -P "$replica_path" | tail -1 | awk '{print $4}')
- if [ $disk_space -lt $MINIMUM_SPACE ]; then
- Logger "There is not enough free space on replica [$replica_path] ($disk_space KB)." "WARN"
- fi
-}
-
-function _CheckDiskSpaceRemote {
- local replica_path="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- Logger "Checking minimum disk space on target [$replica_path]." "NOTICE"
-
- local cmd=
- local disk_space=
-
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
-
- cmd=$SSH_CMD' "'$COMMAND_SUDO' df -P \"'$replica_path'\"" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- Logger "Cannot get free space on target [$replica_path]." "ERROR"
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- else
- disk_space=$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID | tail -1 | awk '{print $4}')
- if [ $disk_space -lt $MINIMUM_SPACE ]; then
- Logger "There is not enough free space on replica [$replica_path] ($disk_space KB)." "WARN"
- fi
- fi
-}
-
-function CheckDiskSpace {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- _CheckDiskSpaceLocal "${INITIATOR[1]}"
- if [ "$REMOTE_OPERATION" != "yes" ]; then
- _CheckDiskSpaceLocal "${TARGET[1]}"
- else
- _CheckDiskSpaceRemote "${TARGET[1]}"
- fi
-}
-
-function RsyncPatternsAdd {
- local pattern="${1}"
- local pattern_type="${2}" # exclude or include
- __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local rest=
-
- # Disable globbing so wildcards from exclusions do not get expanded
- set -f
- rest="$pattern"
- while [ -n "$rest" ]
- do
- # Take the string until first occurence until $PATH_SEPARATOR_CHAR
- str=${rest%%;*}
- # Handle the last case
- if [ "$rest" = "${rest/$PATH_SEPARATOR_CHAR/}" ]; then
- rest=
- else
- # Cut everything before the first occurence of $PATH_SEPARATOR_CHAR
- rest=${rest#*$PATH_SEPARATOR_CHAR}
- fi
- if [ "$RSYNC_PATTERNS" == "" ]; then
- RSYNC_PATTERNS="--"$pattern_type"=\"$str\""
- else
- RSYNC_PATTERNS="$RSYNC_PATTERNS --"$pattern_type"=\"$str\""
- fi
- done
- set +f
-}
-
-function RsyncPatternsFromAdd {
- local pattern_from="${1}"
- local pattern_type="${2}"
- __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local pattern_from=
-
- ## Check if the exclude list has a full path, and if not, add the config file path if there is one
- if [ "$(basename $pattern_from)" == "$pattern_from" ]; then
- pattern_from="$(dirname $CONFIG_FILE)/$pattern_from"
- fi
-
- if [ -e "$pattern_from" ]; then
- RSYNC_PATTERNS="$RSYNC_PATTERNS --"$pattern_type"-from=\"$pattern_from\""
- fi
-}
-
-function RsyncPatterns {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ "$RSYNC_PATTERN_FIRST" == "exclude" ]; then
- RsyncPatternsAdd "$RSYNC_EXCLUDE_PATTERN" "exclude"
- if [ "$RSYNC_EXCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_EXCLUDE_FROM" "exclude"
- fi
- RsyncPatternsAdd "$RSYNC_INCLUDE_PATTERN" "include"
- if [ "$RSYNC_INCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_INCLUDE_FROM" "include"
- fi
- elif [ "$RSYNC_PATTERN_FIRST" == "include" ]; then
- RsyncPatternsAdd "$RSYNC_INCLUDE_PATTERN" "include"
- if [ "$RSYNC_INCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_INCLUDE_FROM" "include"
- fi
- RsyncPatternsAdd "$RSYNC_EXCLUDE_PATTERN" "exclude"
- if [ "$RSYNC_EXCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_EXCLUDE_FROM" "exclude"
- fi
- else
- Logger "Bogus RSYNC_PATTERN_FIRST value in config file. Will not use rsync patterns." "WARN"
- fi
-}
-
-function _WriteLockFilesLocal {
- local lockfile="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- $COMMAND_SUDO echo "$SCRIPT_PID@$INSTANCE_ID" > "$lockfile" #TODO: Determine best format for lockfile for v2
- if [ $? != 0 ]; then
- Logger "Could not create lock file [$lockfile]." "CRITICAL"
- exit 1
- else
- Logger "Locked replica on [$lockfile]." "DEBUG"
- fi
-}
-
-function _WriteLockFilesRemote {
- local lockfile="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local cmd=
-
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
-
- cmd=$SSH_CMD' "echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\"" > /dev/null 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- Logger "Could not set lock on remote target replica." "CRITICAL"
- exit 1
- else
- Logger "Locked remote target replica." "DEBUG"
- fi
-}
-
-function WriteLockFiles {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- _WriteLockFilesLocal "${INITIATOR[2]}"
- if [ "$REMOTE_OPERATION" != "yes" ]; then
- _WriteLockFilesLocal "${TARGET[2]}"
- else
- _WriteLockFilesRemote "${TARGET[2]}"
- fi
-}
-
-function _CheckLocksLocal {
- local lockfile="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local lockfile_content=
- local lock_pid=
- local lock_instance_id=
-
- if [ -f "$lockfile" ]; then
- lockfile_content=$(cat $lockfile)
- Logger "Master lock pid present: $lockfile_content" "DEBUG"
- lock_pid=${lockfile_content%@*}
- lock_instance_id=${lockfile_content#*@}
- ps -p$lock_pid > /dev/null 2>&1
- if [ $? != 0 ]; then
- Logger "There is a dead osync lock in [$lockfile]. Instance [$lock_pid] no longer running. Resuming." "NOTICE"
- else
- Logger "There is already a local instance of osync running [$lock_pid]. Cannot start." "CRITICAL"
- exit 1
- fi
- fi
-}
-
-function _CheckLocksRemote { #TODO: Rewrite this a bit more beautiful
- local lockfile="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local cmd=
- local lock_pid=
- local lock_instance_id=
- local lockfile_content=
-
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
-
- cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then cat \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'"'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
- lockfile_content=$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)
- else
- Logger "Cannot get remote lockfile." "CRITICAL"
- exit 1
- fi
- fi
-
- lock_pid=${lockfile_content%@*}
- lock_instance_id=${lockfile_content#*@}
-
- if [ "$lock_pid" != "" ] && [ "$lock_instance_id" != "" ]; then
- Logger "Remote lock is: $lock_pid@$lock_instance_id" "DEBUG"
-
- ps -p$lock_pid > /dev/null 2>&1
- if [ $? != 0 ]; then
- if [ "$lock_instance_id" == "$INSTANCE_ID" ]; then
- Logger "There is a dead osync lock on target replica that corresponds to this initiator sync id [$lock_instance_id]. Instance [$lock_pid] no longer running. Resuming." "NOTICE"
- else
- if [ "$FORCE_STRANGER_LOCK_RESUME" == "yes" ]; then
- Logger "WARNING: There is a dead osync lock on target replica that does not correspond to this initiator sync-id [$lock_instance_id]. Forcing resume." "WARN"
- else
- Logger "There is a dead osync lock on target replica that does not correspond to this initiator sync-id [$lock_instance_id]. Will not resume." "CRITICAL"
- exit 1
- fi
- fi
- else
- Logger "There is already a local instance of osync that locks target replica [$lock_pid@$lock_instance_id]. Cannot start." "CRITICAL"
- exit 1
- fi
- fi
-}
-
-function CheckLocks {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ $_NOLOCKS -eq 1 ]; then
- return 0
- fi
-
- # Do not bother checking for locks when FORCE_UNLOCK is set
- if [ $FORCE_UNLOCK -eq 1 ]; then
- WriteLockFiles
- if [ $? != 0 ]; then
- exit 1
- fi
- fi
- _CheckLocksLocal "${INITIATOR[2]}"
- if [ "$REMOTE_OPERATION" != "yes" ]; then
- _CheckLocksLocal "${TARGET[2]}"
- else
- _CheckLocksRemote "${TARGET{2]}"
- fi
-
- WriteLockFiles
-}
-
-function _UnlockReplicasLocal {
- local lockfile="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ -f "$lockfile" ]; then
- $COMMAND_SUDO rm "$lockfile"
- if [ $? != 0 ]; then
- Logger "Could not unlock local replica." "ERROR"
- else
- Logger "Removed local replica lock." "DEBUG"
- fi
- fi
-}
-
-function _UnlockReplicasRemote {
- local lockfile="${1}"
- __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local cmd=
-
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
-
- cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then '$COMMAND_SUDO' rm -f \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForTaskCompletion $! 720 1800 ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- Logger "Could not unlock remote replica." "ERROR"
- Logger "Command Output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- else
- Logger "Removed remote replica lock." "DEBUG"
- fi
-}
-
-function UnlockReplicas {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ $_NOLOCKS -eq 1 ]; then
- return 0
- fi
-
- _UnlockReplicasLocal "${INITIATOR[2]}"
- if [ "$REMOTE_OPERATION" != "yes" ]; then
- _UnlockReplicasLocal "${TARGET[2]}"
- else
- _UnlockReplicasRemote "${TARGET[2]}"
- fi
-}
-
-###### Sync core functions
-
- ## Rsync does not like spaces in directory names, considering it as two different directories. Handling this schema by escaping space.
- ## It seems this only happens when trying to execute an rsync command through weval $rsync_cmd on a remote host.
- ## So I am using unescaped $INITIATOR_SYNC_DIR for local rsync calls and escaped $ESC_INITIATOR_SYNC_DIR for remote rsync calls like user@host:$ESC_INITIATOR_SYNC_DIR
- ## The same applies for target sync dir..............................................T.H.I.S..I.S..A..P.R.O.G.R.A.M.M.I.N.G..N.I.G.H.T.M.A.R.E
-
-function tree_list {
- local replica_path="${1}" # path to the replica for which a tree needs to be constructed
- local replica_type="${2}" # replica type: initiator, target
- local tree_filename="${3}" # filename to output tree (will be prefixed with $replica_type)
-
- local escaped_replica_path=
- local rsync_cmd=
-
- __CheckArguments 3 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- escaped_replica_path=$(EscapeSpaces "$replica_path")
-
- Logger "Creating $replica_type replica file list [$replica_path]." "NOTICE"
- if [ "$REMOTE_OPERATION" == "yes" ] && [ "$replica_type" == "target" ]; then
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" --list-only $REMOTE_USER@$REMOTE_HOST:\"$escaped_replica_path/\" | grep \"^-\|^d\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID\" &"
- else
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --list-only \"$replica_path/\" | grep \"^-\|^d\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID\" &"
- fi
- Logger "RSYNC_CMD: $rsync_cmd" "DEBUG"
- ## Redirect commands stderr here to get rsync stderr output in logfile
- eval "$rsync_cmd" 2>> "$LOG_FILE"
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- retval=$?
- ## Retval 24 = some files vanished while creating list
- if ([ $retval == 0 ] || [ $retval == 24 ]) && [ -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" ]; then
- mv -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_filename"
- return $?
- else
- Logger "Cannot create replica file list." "CRITICAL"
- exit $retval
- fi
-}
-
-# delete_list(replica, tree-file-after, tree-file-current, deleted-list-file, deleted-failed-list-file): Creates a list of files vanished from last run on replica $1 (initiator/target)
-function delete_list {
- local replica_type="${1}" # replica type: initiator, target
- local tree_file_after="${2}" # tree-file-after, will be prefixed with replica type #TODO: use this
- local tree_file_current="${3}" # tree-file-current, will be prefixed with replica type
- local deleted_list_file="${4}" # file containing deleted file list, will be prefixed with replica type
- local deleted_failed_list_file="${5}" # file containing files that could not be deleted on last run, will be prefixed with replica type
- __CheckArguments 5 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local cmd=
-
- # TODO: Check why external filenames are used (see _DRYRUN option because of NOSUFFIX)
-
- Logger "Creating $replica_type replica deleted file list." "NOTICE"
- if [ -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX" ]; then
- ## Same functionnality, comm is much faster than grep but is not available on every platform
- if type comm > /dev/null 2>&1 ; then
- cmd="comm -23 \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_file_current\" > \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file\""
- else
- ## The || : forces the command to have a good result
- cmd="(grep -F -x -v -f \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_file_current\" \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" || :) > \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file\""
- fi
-
- Logger "CMD: $cmd" "DEBUG"
- eval "$cmd" 2>> "$LOG_FILE"
- retval=$?
-
- # Add delete failed file list to current delete list and then empty it
- if [ -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" ]; then
- cat "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" >> "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file"
- rm -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file"
- fi
-
- return $retval
- else
- touch "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file"
- return $retval
- fi
-}
-
-function _get_file_ctime_mtime_local {
- local replica_path="${1}" # Contains replica path
- local replica_type="${2}" # Initiator / Target
- local file_list="${3}" # Contains list of files to get time attrs
- __CheckArguments 3 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- cat "$file_list" | xargs -I {} stat -c '%n|%Z|%Y' "$replica_path{}" | sort > "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID"
-}
-
-function _get_file_ctime_mtime_remote {
- local replica_path="${1}" # Contains replica path
- local replica_type="${2}"
- local file_list="${3}"
- __CheckArguments 3 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local cmd=
-
- cmd='cat "'$file_list'" | '$SSH_CMD' xargs -I "'$replica_path'"{} stat -c "%n|%Z|%Y" "{}" | sort > "'$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID'"'
- Logger "CMD: $cmd" "DEBUG"
- eval "$cmd"
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- if [ $? != 0 ]; then
- Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL"
- if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" ]; then
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID)" "NOTICE"
- fi
- exit 1
- fi
-}
-
-# rsync does sync with mtime, but file attribute modifications only change ctime.
-# Hence, detect newer ctime on the replica that gets updated first with CONFLICT_PREVALANCE and update all newer file attributes on this replica before real update
-function sync_attrs {
- local initiator_replica="${1}"
- local target_replica="${2}"
- __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local rsync_cmd=
- local retval=
-
- Logger "Getting file attributes." "NOTICE"
-
- if [ "$REMOTE_OPERATION" == "yes" ]; then
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiator_replica\" $REMOTE_USER@$REMOTE_HOST:\"$target_replica\" > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1 &"
- else
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiator_replica\" \"$target_replica\" > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1 &"
- fi
- Logger "RSYNC_CMD: $rsync_cmd" "DEBUG"
- eval "$rsync_cmd"
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- retval=$?
- if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
- Logger "List:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- fi
-
- if [ $retval != 0 ] && [ $retval != 24 ]; then
- Logger "Getting file list for attribute sync failed [$retval]. Stopping execution." "CRITICAL"
- if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then
- Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- fi
- exit $retval
- else
- cat "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" | ( grep -Ev "^[^ ]*(c|s|t)[^ ]* " || :) | ( grep -E "^[^ ]*(p|o|g|a)[^ ]* " || :) | sed -e 's/^[^ ]* //' > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID"
- if [ $? != 0 ]; then
- Logger "Cannot prepare file list for attribute sync." "CRITICAL"
- exit 1
- fi
- fi
-
- _get_file_ctime_mtime_local "${INITIATOR[1]}" "${INITIATOR[0]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID"
- if [ "$REMOTE_OPERATION" != "yes" ]; then
- _get_file_ctime_mtime_local "${TARGET[1]}" "${TARGET[0]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID"
- else
- _get_file_ctime_mtime_remote "${TARGET[1]}" "${TARGET[0]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID"
- fi
-
-
- # If target gets updated first, then sync_attr must update initiator's attrs first
- # Also, change replica paths of the two file lists so rsync will know what to sync
- if [ "$CONFLICT_PREVALANCE" == "${INITIATOR[0]}" ]; then
- local source_dir="${TARGET[1]}"
- local dest_dir="${INITIATOR[1]}"
- local dest_replica="${INITIATOR[0]}"
- sed -i "s;^${INITIATOR[1]};${TARGET[1]};g" "$RUN_DIR/$PROGRAM.ctime_mtime.${INITIATOR[0]}.$SCRIPT_PID"
- join -j 1 -t ';' -o 1.1,1.2,2.2 "$RUN_DIR/$PROGRAM.ctime_mtime.${TARGET[0]}.$SCRIPT_PID" "$RUN_DIR/$PROGRAM.ctime_mtime.${INITIATOR[0]}.$SCRIPT_PID" | awk -F';' '{if ($2 < $3) print $1}' > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID"
-
- else
-
- local source_dir="${INITIATOR[1]}"
- local dest_dir="${TARGET[1]}"
- local dest_replica="${TARGET[0]}"
- sed -i "s;^${TARGET[1]};${INITIATOR[1]};g" "$RUN_DIR/$PROGRAM.ctime_mtime.${TARGET[0]}.$SCRIPT_PID"
- join -j 1 -t ';' -o 1.1,1.2,2.2 "$RUN_DIR/$PROGRAM.ctime_mtime.${INITIATOR[0]}.$SCRIPT_PID" "$RUN_DIR/$PROGRAM.ctime_mtime.${TARGET[0]}.$SCRIPT_PID" | awk -F';' '{if ($2 < $3) print $1}' > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID"
- fi
-
- if [ "$REMOTE_OPERATION" == "yes" ]; then
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
-
- if [ "$dest" == "${INITIATOR[0]}" ]; then
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/${INITIATOR[0]$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/${TARGET[0]}$delete_list_filename\" $REMOTE_USER@REMOTE_HOST:\"$esc_source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID 2>&1 &"
- else
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/${INITIATOR[0]$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/${TARGET[0]}$delete_list_filename\" \"$source_dir\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir\" > $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID 2>&1 &"
- fi
- else
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ATTR_ARGS $SYNC_OPTS --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/{$INITIATOR[0]}$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/${TARGET[0]}$delete_list_filename\" \"$source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID 2>&1 &"
-
- fi
-
- Logger "RSYNC_CMD: $rsync_cmd" "DEBUG"
- eval "$rsync_cmd"
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- retval=$?
- if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-attrfiles.$SCRIPT_PID" ]; then
- Logger "List:\n$(cat $RUN_DIR/$PROGRAM.$FUNCNAM-attrfiles.$SCRIPT_PID)" "NOTICE"
- fi
-
- if [ $retval != 0 ] && [ $retval != 24 ]; then
- Logger "Updating file attributes on $source [$retval]. Stopping execution." "CRITICAL"
- if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-attrfiles.$SCRIPT_PID" ]; then
- Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}-attrfiles.$SCRIPT_PID)" "NOTICE"
- fi
- exit $retval
- else
- Logger "Successfully updated file attributes on $dest replica." "NOTICE"
- fi
-}
-
-# sync_update(source replica, destination replica, delete_list_filename)
-function sync_update {
- local source_replica="${1}" # Contains replica type of source: initiator, target
- local destination_replica="${2}" # Contains replica type of destination: initiator, target
- local delete_list_filename="${3}" # Contains deleted list filename, will be prefixed with replica type
- __CheckArguments 3 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local rsync_cmd=
- local retval=
-
- Logger "Updating $destination_replica replica." "NOTICE"
- if [ "$source_replica" == "${INITIATOR[0]}" ]; then
- local source_dir="${INITIATOR[1]}"
- local esc_source_dir=$(EscapeSpaces "${INITIATOR[1]}")
- local dest_dir="${TARGET[1]}"
- local esc_dest_dir=$(EscapeSpaces "${TARGET[1]}")
- local backup_args="$TARGET_BACKUP_ARGS"
- else
- local source_dir="${TARGET[1]}"
- local esc_source_dir=$(EscapeSpaces "${TARGET[1]}")
- local dest_dir="${INITIATOR[1]}"
- local esc_dest_dir=$(EscapeSpaces "${INITIATOR[1]}")
- local backup_args="$INITIATOR_BACKUP"
- fi
-
- if [ "$REMOTE_OPERATION" == "yes" ]; then
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
- if [ "$source_replica" == "${INITIATOR[0]}" ]; then
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" \"$source_dir\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &"
- else
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &"
- fi
- else
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" \"$source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &"
- fi
- Logger "RSYNC_CMD: $rsync_cmd" "DEBUG"
- eval "$rsync_cmd"
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- retval=$?
- if [ $_VERBOSE -eq 1 ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
- Logger "List:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE"
- fi
-
- if [ $retval != 0 ] && [ $retval != 24 ]; then
- Logger "Updating $destination_replica replica failed. Stopping execution." "CRITICAL"
- if [ $_VERBOSE -eq 0 ] && [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then
- Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE"
- fi
- exit $retval
- else
- Logger "Updating $destination_replica replica succeded." "NOTICE"
- return 0
- fi
-}
-
-# delete_local(replica dir, delete file list, delete dir, delete failed file)
-function _delete_local {
- local replica_dir="${1}" # Full path to replica
- local deleted_list_file="${2}" # file containing deleted file list, will be prefixed with replica type
- local deletion_dir="${3}" # deletion dir in format .[workdir]/deleted
- local deleted_failed_list_file="${4}" # file containing files that could not be deleted on last run, will be prefixed with replica type
- __CheckArguments 4 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local parentdir=
-
- ## On every run, check wheter the next item is already deleted because it is included in a directory already deleted
- local previous_file=""
- OLD_IFS=$IFS
- IFS=$'\r\n'
- for files in $(cat "${INITIATOR[1]}${INITIATOR[3]}/$deleted_list_file")
- do
- if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then
- if [ "$SOFT_DELETE" != "no" ]; then
- if [ ! -d "$replica_dir$deletion_dir" ]; then
- mkdir -p "$replica_dir$deletion_dir"
- if [ $? != 0 ]; then
- Logger "Cannot create replica deletion directory." "ERROR"
- fi
- fi
-
- if [ $_VERBOSE -eq 1 ]; then
- Logger "Soft deleting $replica_dir$files" "NOTICE"
- fi
-
- if [ $_DRYRUN -ne 1 ]; then
- if [ -e "$replica_dir$deletion_dir/$files" ]; then
- rm -rf "${replica_dir:?}$deletion_dir/$files" #TODO: WTF :?
- fi
- # In order to keep full path on soft deletion, create parent directories before move
- parentdir="$(dirname "$files")"
- if [ "$parentdir" != "." ]; then
- mkdir --parents "$replica_dir$deletion_dir/$parentdir"
- mv -f "$replica_dir$files" "$replica_dir$deletion_dir/$parentdir"
- else
- mv -f "$replica_dir$files" "$replica_dir$deletion_dir"
- fi
- if [ $? != 0 ]; then
- Logger "Cannot move $replica_dir$files to deletion directory." "ERROR"
- echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file"
- fi
- fi
- else
- if [ $_VERBOSE -eq 1 ]; then
- Logger "Deleting $replica_dir$files" "NOTICE"
- fi
-
- if [ $_DRYRUN -ne 1 ]; then
- rm -rf "$replica_dir$files"
- if [ $? != 0 ]; then
- Logger "Cannot delete $replica_dir$files" "ERROR"
- echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file"
- fi
- fi
- fi
- previous_file="$files"
- fi
- done
- IFS=$OLD_IFS
-}
-
-function _delete_remote {
- local replica_dir="${1}" # Full path to replica
- local deleted_list_file="${2}" # file containing deleted file list, will be prefixed with replica type
- local deletion_dir="${3}" # deletion dir in format .[workdir]/deleted
- local deleted_failed_list_file="${4}" # file containing files that could not be deleted on last run, will be prefixed with replica type
- __CheckArguments 4 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local esc_dest_dir=
- local rsync_cmd=
-
- ## This is a special coded function. Need to redelcare local functions on remote host, passing all needed variables as escaped arguments to ssh command.
- ## Anything beetween << ENDSSH and ENDSSH will be executed remotely
-
- # Additionnaly, we need to copy the deletetion list to the remote state folder
- esc_dest_dir="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}")"
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" \"${INITIATOR[1]}$INITIATOR[3]}/$2\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir/\" > $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.precopy.$SCRIPT_PID 2>&1"
- Logger "RSYNC_CMD: $rsync_cmd" "DEBUG"
- eval "$rsync_cmd" 2>> "$LOG_FILE"
- if [ $? != 0 ]; then
- Logger "Cannot copy the deletion list to remote replica." "ERROR"
- if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.precopy.$SCRIPT_PID" ]; then
- Logger "$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.precopy.$SCRIPT_PID)" "ERROR"
- fi
- exit 1
- fi
-
-$SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_list_file")" REPLICA_DIR="$(EscapeSpaces "$replica_dir")" DELETE_DIR="$(EscapeSpaces "$deletion_dir")" FAILED_DELETE_LIST="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}/$deleted_failed_list_file")" 'bash -s' << 'ENDSSH' > "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 &
-
- ## The following lines are executed remotely
- function _logger {
- local value="${1}" # What to log
- echo -e "$value" >> "$LOG_FILE"
-
- if [ $_SILENT -eq 0 ]; then
- echo -e "$value"
- fi
- }
-
- function Logger {
- local value="${1}" # What to log
- local level="${2}" # Log level: DEBUG, NOTICE, WARN, ERROR, CRITIAL
-
- local prefix="RTIME: $SECONDS - "
-
- if [ "$level" == "CRITICAL" ]; then
- _logger "$prefix\e[41m$value\e[0m"
- ERROR_ALERT=1
- elif [ "$level" == "ERROR" ]; then
- _logger "$prefix\e[91m$value\e[0m"
- ERROR_ALERT=1
- elif [ "$level" == "WARN" ]; then
- _logger "$prefix\e[93m$value\e[0m"
- elif [ "$level" == "NOTICE" ]; then
- _logger "$prefix$value"
- elif [ "$level" == "DEBUG" ]; then
- if [ "$_DEBUG" == "yes" ]; then
- _logger "$prefix$value"
- fi
- else
- _logger "\e[41mLogger function called without proper loglevel.\e[0m"
- _logger "$prefix$value"
- fi
- }
-
- ## Empty earlier failed delete list
- > "$FAILED_DELETE_LIST"
-
- local parentdir=
-
- ## On every run, check wheter the next item is already deleted because it is included in a directory already deleted
- local previous_file=""
- OLD_IFS=$IFS
- IFS=$'\r\n'
- for files in $(cat "$FILE_LIST")
- do
- if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then
- if [ ! -d "$REPLICA_DIR$DELETE_DIR" ]; then
- $COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR"
- if [ $? != 0 ]; then
- Logger "Cannot create replica deletion directory." "ERROR"
- fi
- fi
-
- if [ "$SOFT_DELETE" != "no" ]; then
- if [ $_VERBOSE -eq 1 ]; then
- Logger "Soft deleting $REPLICA_DIR$files" "NOTICE"
- fi
-
- if [ $_DRYRUN -ne 1 ]; then
- if [ -e "$REPLICA_DIR$DELETE_DIR/$files" ]; then
- $COMMAND_SUDO rm -rf "$REPLICA_DIR$DELETE_DIR/$files"
- fi
- # In order to keep full path on soft deletion, create parent directories before move
- parentdir="$(dirname "$files")"
- if [ "$parentdir" != "." ]; then
- $COMMAND_SUDO mkdir --parents "$REPLICA_DIR$DELETE_DIR/$parentdir"
- $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR/$parentdir"
- else
- $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR"1
- fi
- if [ $? != 0 ]; then
- Logger "Cannot move $REPLICA_DIR$files to deletion directory." "ERROR"
- echo "$files" >> "$FAILED_DELETE_LIST"
- fi
- fi
- else
- if [ $_VERBOSE -eq 1 ]; then
- Logger "Deleting $REPLICA_DIR$files" "NOTICE"
- fi
-
- if [ $_DRYRUN -ne 1 ]; then
- $COMMAND_SUDO rm -rf "$REPLICA_DIR$files"
- if [ $? != 0 ]; then
- Logger "Cannot delete $REPLICA_DIR$files" "ERROR"
- echo "$files" >> "$TARGET_STATE_DIR/$FAILED_DELETE_LIST"
- fi
- fi
- fi
- previous_file="$files"
- fi
- done
- IFS=$OLD_IFS
-ENDSSH
-
- ## Need to add a trivial sleep time to give ssh time to log to local file
- sleep 5
-
- ## Copy back the deleted failed file list
- esc_source_file="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}/$deleted_failed_list_file")"
- #TODO: Need to check if file exists prior to copy (or add a filemask and copy all state files)
- rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_file\" \"${INITIATOR[1]}${INITIATOR[3]}\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\""
- Logger "RSYNC_CMD: $rsync_cmd" "DEBUG"
- eval "$rsync_cmd" 2>> "$LOG_FILE"
- if [ $? != 0 ]; then
- Logger "Cannot copy back the failed deletion list to initiator replica." "CRITICAL"
- if [ -f "$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID" ]; then
- Logger "Comand output: $(cat $RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID)" "NOTICE"
- fi
- exit 1
- fi
-
-
-
- exit $?
-}
-
-# delete_propagation(replica name, deleted_list_filename, deleted_failed_file_list)
-function deletion_propagation {
- local replica_type="${1}" # Contains replica type: initiator, target
- local deleted_list_file="${2}" # file containing deleted file list, will be prefixed with replica type
- local deleted_failed_list_file="${3}" # file containing files that could not be deleted on last run, will be prefixed with replica type
- __CheckArguments 3 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local replica_dir=
- local delete_dir=
-
- Logger "Propagating deletions to $replica_type replica." "NOTICE"
-
- if [ "$replica_type" == "{$INITIATOR[0]}" ]; then
- replica_dir="${INITIATOR[1]}${INITIATOR[3]}/"
- delete_dir="${INITIATOR[5]}"
-
- _delete_local "$replica_dir" "${TARGET[0]}$deleted_list_file" "$delete_dir" "${TARGET[0]}$deleted_failed_list_file" &
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- retval=$?
- if [ $retval != 0 ]; then
- Logger "Deletion on replica $replica_type failed." "CRITICAL"
- exit 1
- fi
- else
- replica_dir="${TARGET[1]}${TARGET[3]}/"
- delete_dir="${TARGET[5]}"
-
- if [ "$REMOTE_OPERATION" == "yes" ]; then
- _delete_remote "$replica_dir" "${INITIATOR[0]}$deleted_list_file" "$delete_dir" "${INITIATOR[0]}$deleted_failed_list_file" &
- else
- _delete_local "$replica_dir" "${INITIATOR[0]}$deleted_list_file" "$delete_dir" "${INITIATOR[0]}$deleted_failed_list_file" &
- fi
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- retval=$?
- if [ $retval == 0 ]; then
- if [ -f "$RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID" ] && [ $_VERBOSE -eq 1 ]; then
- Logger "Remote:\n$(cat $RUN_DIR/$PROGRAM._delete_remote.$SCRIPT_PID)" "DEBUG"
- fi
- return $retval
- else
- Logger "Deletion on remote system failed." "CRITICAL"
- if [ -f "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" ]; then
- Logger "Remote:\n$(cat $RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID)" "CRITICAL"
- fi
- exit 1
- fi
- fi
-}
-
-###### Sync function in 6 steps (functions above)
-######
-###### Step 1: Create current tree list for initiator and target replicas (Steps 1M and 1S)
-###### Step 2: Create deleted file list for initiator and target replicas (Steps 2M and 2S)
-###### Step 3a: Update initiator and target file attributes only
-###### Step 3b: Update initiator and target replicas (Steps 3M and 3S, order depending on conflict prevalence)
-###### Step 4: Deleted file propagation to initiator and target replicas (Steps 4M and 4S)
-###### Step 5: Create after run tree list for initiator and target replicas (Steps 5M and 5S)
-
-function Sync {
- local resume_count=
- local resume_sync=
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- Logger "Starting synchronization task." "NOTICE"
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
-
- if [ -f "${INITIATOR[7]}" ] && [ "$RESUME_SYNC" != "no" ]; then
- resume_sync=$(cat "${INITIATOR[7]}")
- if [ -f "${INITIATOR[8]}" ]; then
- resume_count=$(cat "${INITIATOR[8]}")
- else
- resume_count=0
- fi
-
- if [ $resume_count -lt $RESUME_TRY ]; then
- if [ "$resume_sync" != "sync.success" ]; then
- Logger "WARNING: Trying to resume aborted osync execution on $($STAT_CMD "${INITIATOR[7]}") at task [$resume_sync]. [$resume_count] previous tries." "WARN"
- echo $(($resume_count+1)) > "${INITIATOR[8]}"
- else
- resume_sync=none
- fi
- else
- Logger "Will not resume aborted osync execution. Too many resume tries [$resume_count]." "WARN"
- echo "noresume" > "${INITIATOR[7]}"
- echo "0" > "${INITIATOR[8]}"
- resume_sync=none
- fi
- else
- resume_sync=none
- fi
-
-
- ################################################################################################################################################# Actual sync begins here
-
- ## This replaces the case statement because ;& operator is not supported in bash 3.2... Code is more messy than case :(
- if [ "$resume_sync" == "none" ] || [ "$resume_sync" == "noresume" ] || [ "$resume_sync" == "${SYNC_ACTION[0]}.fail" ]; then
- #initiator_tree_current
- tree_list "${INITIATOR[1]}${INITIATOR[3]}" initiator "$TREE_CURRENT_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[0]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[0]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[0]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[1]}.fail" ]; then
- #target_tree_current
- tree_list "${TARGET[1]}${TARGET[3]}" target "$TREE_CURRENT_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[1]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[1]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[1]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[2]}.fail" ]; then
- delete_list initiator "$TREE_AFTER_FILENAME" "$TREE_CURRENT_FILENAME" "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[2]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[2]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[2]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[3]}.fail" ]; then
- delete_list target "$TREE_AFTER_FILENAME" "$TREE_CURRENT_FILENAME" "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[3]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[3]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[3]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.fail" ]; then
- sync_attrs "$INITIATOR_SYNC_DIR" "$TARGET_SYNC_DIR"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[4]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[4]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ]; then
- if [ "$CONFLICT_PREVALANCE" != "${INITIATOR[0]}" ]; then
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ]; then
- sync_update ${TARGET[0]} ${INITIATOR[0]} "$DELETED_LIST_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[5]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[5]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ]; then
- sync_update ${INITIATOR[0]} ${TARGET[0]} "$DELETED_LIST_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[6]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[6]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- else
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ]; then
- sync_update ${INITIATOR[0]} ${TARGET[0]} "$DELETED_LIST_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[6]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[6]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ]; then
- sync_update ${TARGET[0]} ${INITIATOR[0]} "$DELETED_LIST_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[5]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[5]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- fi
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[7]}.fail" ]; then
- deletion_propagation target "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[7]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[7]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[7]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[8]}.fail" ]; then
- deletion_propagation initiator "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[8]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[8]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[8]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[9]}.fail" ]; then
- #initiator_tree_after
- tree_list "${INITIATOR[1]}${INITIATOR[3]}" ${INITIATOR[0]} "$TREE_AFTER_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[9]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[9]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
- if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[9]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[10]}.fail" ]; then
- #target_tree_after
- tree_list "${TARGET[1]}${TARGET[3]}" ${TARGET[0]} "$TREE_AFTER_FILENAME"
- if [ $? == 0 ]; then
- echo "${SYNC_ACTION[10]}.success" > "${INITIATOR[7]}"
- else
- echo "${SYNC_ACTION[10]}.fail" > "${INITIATOR[7]}"
- fi
- resume_sync="resumed"
- fi
-
- Logger "Finished synchronization task." "NOTICE"
- echo "${SYNC_ACTION[11]}" > "${INITIATOR[7]}"
-
- echo "0" > "${INITIATOR[8]}"
-}
-
-function _SoftDeleteLocal {
- local replica_type="${1}" # replica type (initiator, target)
- local replica_deletion_path="${2}" # Contains the full path to softdelete / backup directory without ending slash
- local change_time="${3}"
- __CheckArguments 3 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local retval=
-
- if [ -d "$replica_deletion_path" ]; then
- if [ $_DRYRUN -eq 1 ]; then
- Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE"
- else
- Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE"
- fi
- if [ $_VERBOSE -eq 1 ]; then
- # Cannot launch log function from xargs, ugly hack
- $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} echo "Will delete file {}" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID"
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- $FIND_CMD "$replica_deletion_path/" -type d -empty -ctime +$change_time -print0 | xargs -0 -I {} echo "Will delete directory {}" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID"
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- fi
- if [ $_DRYRUN -ne 1 ]; then
- $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} rm -f "{}" && $FIND_CMD "$replica_deletion_path/" -type d -empty -ctime +$change_time -print0 | xargs -0 -I {} rm -rf "{}" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1 &
- else
- Dummy &
- fi
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- retval=$?
- if [ $retval -ne 0 ]; then
- Logger "Error while executing cleanup on $replica_type replica." "ERROR"
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- else
- Logger "Cleanup complete on $replica_type replica." "NOTICE"
- fi
- elif [ -d "$replica_deletion_path" ] && ! [ -w "$replica_deletion_path" ]; then
- Logger "Warning: $replica_type replica dir [$replica_deletion_path] is not writable. Cannot clean old files." "ERROR"
- fi
-}
-
-function _SoftDeleteRemote {
- local replica_type="${1}"
- local replica_deletion_path="${2}" # Contains the full path to softdelete / backup directory without ending slash
- local change_time="${3}"
- __CheckArguments 3 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local retval=
-
- CheckConnectivity3rdPartyHosts
- CheckConnectivityRemoteHost
-
- if [ $_DRYRUN -eq 1 ]; then
- Logger "Listing files older than $change_time days on target replica. Does not remove anything." "NOTICE"
- else
- Logger "Removing files older than $change_time days on target replica." "NOTICE"
- fi
-
- if [ $_VERBOSE -eq 1 ]; then
- # Cannot launch log function from xargs, ugly hack
- cmd=$SSH_CMD' "if [ -d \"'$replica_deletion_path'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type f -ctime +'$change_time' -print0 | xargs -0 -I {} echo Will delete file {} && '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} echo Will delete directory {}; else echo \"No remote backup/deletion directory.\"; exit 1; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- fi
-
- if [ $_DRYRUN -ne 1 ]; then
- cmd=$SSH_CMD' "if [ -d \"'$replica_deletion_path'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type f -ctime +'$change_time' -print0 | xargs -0 -I {} rm -f \"{}\" && '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} rm -rf \"{}\"; else echo \"No remote backup/deletion directory.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1'
-
- Logger "cmd: $cmd" "DEBUG"
- eval "$cmd" &
- else
- Dummy &
- fi
- WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]}
- retval=$?
- if [ $retval -ne 0 ]; then
- Logger "Error while executing cleanup on remote target replica." "ERROR"
- Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE"
- else
- Logger "Cleanup complete on target replica." "NOTICE"
- fi
-}
-
-function SoftDelete {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ "$CONFLICT_BACKUP" != "no" ] && [ $CONFLICT_BACKUP_DAYS -ne 0 ]; then
- Logger "Running conflict backup cleanup." "NOTICE"
-
- _SoftDeleteLocal "${INITIATOR[0]}" "${INITIATOR[1]}${INITIATOR[4]}" $CONFLICT_BACKUP_DAYS
- if [ "$REMOTE_OPERATION" != "yes" ]; then
- _SoftDeleteLocal "${TARGET[0]}" "${TARGET[1]}${TARGET[4]}" $CONFLICT_BACKUP_DAYS
- else
- _SoftDeleteRemote "${TARGET[0]}" "${TARGET[1]}${TARGET[4]}" $CONFLICT_BACKUP_DAYS
- fi
- fi
-
- if [ "$SOFT_DELETE" != "no" ] && [ $SOFT_DELETE_DAYS -ne 0 ]; then
- Logger "Running soft deletion cleanup." "NOTICE"
-
- _SoftDeleteLocal "${INITIATOR[0]}" "${INITIATOR[1]}${INITIATOR[5]}" $SOFT_DELETE_DAYS
- if [ "$REMOTE_OPERATION" != "yes" ]; then
- _SoftDeleteLocal "${TARGET[0]}" "${TARGET[1]}${TARGET[5]}" $SOFT_DELETE_DAYS
- else
- _SoftDeleteRemote "${TARGET[0]}" "${TARGET[1]}${TARGET[5]}" $SOFT_DELETE_DAYS
- fi
- fi
-}
-
-function Init {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- # Set error exit code if a piped command fails
- set -o pipefail
- set -o errtrace
-
- # Do not use exit and quit traps if osync runs in monitor mode
- if [ $sync_on_changes -eq 0 ]; then
- trap TrapStop SIGINT SIGHUP SIGTERM SIGQUIT
- trap TrapQuit EXIT
- else
- trap TrapQuit SIGTERM EXIT SIGHUP SIGQUIT
- fi
-
- local uri
- local hosturiandpath
- local hosturi
-
-
- ## Test if target dir is a ssh uri, and if yes, break it down it its values
- if [ "${TARGET_SYNC_DIR:0:6}" == "ssh://" ]; then
- REMOTE_OPERATION="yes"
-
- # remove leadng 'ssh://'
- uri=${TARGET_SYNC_DIR#ssh://*}
- if [[ "$uri" == *"@"* ]]; then
- # remove everything after '@'
- REMOTE_USER=${uri%@*}
- else
- REMOTE_USER=$LOCAL_USER
- fi
-
- if [ "$SSH_RSA_PRIVATE_KEY" == "" ]; then
- SSH_RSA_PRIVATE_KEY=~/.ssh/id_rsa
- fi
-
- # remove everything before '@'
- hosturiandpath=${uri#*@}
- # remove everything after first '/'
- hosturi=${hosturiandpath%%/*}
- if [[ "$hosturi" == *":"* ]]; then
- REMOTE_PORT=${hosturi##*:}
- else
- REMOTE_PORT=22
- fi
- REMOTE_HOST=${hosturi%%:*}
-
- # remove everything before first '/'
- TARGET_SYNC_DIR=${hosturiandpath#*/}
- fi
-
- ## Make sure there is only one trailing slash on path
- INITIATOR_SYNC_DIR="${INITIATOR_SYNC_DIR%/}/"
- TARGET_SYNC_DIR="${TARGET_SYNC_DIR%/}/"
-
- if [ $_DRYRUN -eq 1 ]; then
- dry_suffix="-dry"
- fi
-
- ## Replica format
- ## Why the f*** does bash not have simple objects ?
-
- #${REPLICA[0]} contains replica type (initiator / target)
- #${REPLICA[1]} contains full replica path (can be absolute or relative) with ending slash
- #${REPLICA[2]} contains full lock file path
- #${REPLICA[3]} contains state dir path, relative to replica path
- #${REPLICA[4]} contains backup dir path, relative to replica path
- #${REPLICA[5]} contains deletion dir path, relative to replica path
- #${REPLICA[6]} contains partial dir path, relative to replica path
- #${REPLICA[7]} contains full last action file path
- #${REPLICA[8]} contains full resume count file path
-
- # Local variables used for state filenames
- local lock_filename="lock"
- local state_dir="state"
- local backup_dir="backup"
- local delete_dir="deleted"
- local partial_dir="_partial"
- local last_action="last-action"
- local resume_count="resume-count"
- local dry_suffix="dry"
-
- #TODO: replace all other instances by the following
- INITIATOR=(
- 'initiator'
- "$INITIATOR_SYNC_DIR"
- "$INITIATOR_SYNC_DIR$OSYNC_DIR/$lock_filename"
- "$OSYNC_DIR/$state_dir"
- "$OSYNC_DIR/$backup_dir"
- "$OSYNC_DIR/$delete_dir"
- "$OSYNC_DIR/$partial_dir"
- "$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$last_action-$INSTANCE_ID$dry_suffix"
- "$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix"
- )
-
- TARGET=(
- 'target'
- "$TARGET_SYNC_DIR"
- "$TARGET_SYNC_DIR$OSYNC_DIR/$lock_filename"
- "$OSYNC_DIR/$state_dir"
- "$OSYNC_DIR/$backup_dir"
- "$OSYNC_DIR/$delete_dir"
- "$OSYNC_DIR/$partial_dir"
- "$TARGET_SYNC_DIR$OSYNC_DIR/$state_dir/$last_action-$INSTANCE_ID$dry_suffix"
- "$TARGET_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix"
- )
-
- PARTIAL_DIR=$OSYNC_DIR"_partial"
-
- ## Set sync only function arguments for rsync
- SYNC_OPTS="-u"
-
- if [ $_VERBOSE -eq 1 ]; then
- SYNC_OPTS=$SYNC_OPTS"i"
- fi
-
- if [ $STATS -eq 1 ]; then
- SYNC_OPTS=$SYNC_OPTS" --stats"
- fi
-
- ## Add Rsync include / exclude patterns
- if [ $_QUICK_SYNC -lt 2 ]; then
- RsyncPatterns
- fi
-
- ## Conflict options
- if [ "$CONFLICT_BACKUP" != "no" ]; then
- INITIATOR_BACKUP="--backup --backup-dir=\"${INITIATOR[1]}${INITIATOR[4]}\""
- TARGET_BACKUP="--backup --backup-dir=\"${TARGET[1]}${TARGET[4]}\""
- if [ "$CONFLICT_BACKUP_MULTIPLE" == "yes" ]; then
- INITIATOR_BACKUP="$INITIATOR_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)"
- TARGET_BACKUP="$TARGET_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)"
- fi
- else
- INITIATOR_BACKUP="
- TARGET_BACKUP="
- fi
-
- TREE_CURRENT_FILENAME="-tree-current-$INSTANCE_ID$dry_suffix"
- TREE_AFTER_FILENAME="-tree-after-$INSTANCE_ID$dry_suffix"
- TREE_AFTER_FILENAME_NO_SUFFIX="-tree-after-$INSTANCE_ID"
- DELETED_LIST_FILENAME="-deleted-list-$INSTANCE_ID$dry_suffix"
- FAILED_DELETE_LIST_FILENAME="-failed-delete-$INSTANCE_ID$dry_suffix"
-
- ## Sync function actions (0-10)
- SYNC_ACTION=(
- 'initiator-replica-tree'
- 'target-replica-tree'
- 'initiator-deleted-list'
- 'target-deleted-list'
- 'sync-attrs'
- 'update-initiator-replica'
- 'update-target-replica'
- 'delete-propagation-target'
- 'delete-propagation-initiator'
- 'initiator-replica-tree-after'
- 'target-replica-tree-after'
- 'sync.success'
- )
-}
-
-function Main {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- CreateStateDirs
- CheckLocks
- sleep 900
- Sync
-}
-
-function Usage {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- if [ "$IS_STABLE" != "yes" ]; then
- echo -e "\e[93mThis is an unstable dev build. Please use with caution.\e[0m"
- fi
-
- echo "$PROGRAM $PROGRAM_VERSION $PROGRAM_BUILD"
- echo $AUTHOR
- echo $CONTACT
- echo ""
- echo "You may use osync with a full blown configuration file, or use its default options for quick command line sync."
- echo "Usage: osync.sh /path/to/config/file [OPTIONS]"
- echo "or osync.sh --initiator=/path/to/initiator/replica --target=/path/to/target/replica [OPTIONS] [QUICKSYNC OPTIONS]"
- echo "or osync.sh --initiator=/path/to/initiator/replica --target=ssh://[backupuser]@remotehost.com[:portnumber]//path/to/target/replica [OPTIONS] [QUICKSYNC OPTIONS]"
- echo ""
- echo "[OPTIONS]"
- echo "--dry Will run osync without actually doing anything; just testing"
- echo "--silent Will run osync without any output to stdout, used for cron jobs"
- echo "--verbose Increases output"
- echo "--stats Adds rsync transfer statistics to verbose output"
- echo "--partial Allows rsync to keep partial downloads that can be resumed later (experimental)"
- echo "--no-maxtime Disables any soft and hard execution time checks"
- echo "--force-unlock Will override any existing active or dead locks on initiator and target replica"
- echo "--on-changes Will launch a sync task after a short wait period if there is some file activity on initiator replica. You should try daemon mode instead"
- echo ""
- echo "[QUICKSYNC OPTIONS]"
- echo "--initiator=\"\" Master replica path. Will contain state and backup directory (is mandatory)"
- echo "--target=\"\" Local or remote target replica path. Can be a ssh uri like ssh://user@host.com:22//path/to/target/replica (is mandatory)"
- echo "--rsakey=\"\" Alternative path to rsa private key for ssh connection to target replica"
- echo "--instance-id=\"\" Optional sync task name to identify this synchronization task when using multiple targets"
- echo ""
- echo "Additionaly, you may set most osync options at runtime. eg:"
- echo "SOFT_DELETE_DAYS=365 osync.sh --initiator=/path --target=/other/path"
- echo ""
- exit 128
-}
-
-function SyncOnChanges {
- __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
-
- local cmd=
- local retval=
-
- if ! type inotifywait > /dev/null 2>&1 ; then
- Logger "No inotifywait command found. Cannot monitor changes." "CRITICAL"
- exit 1
- fi
-
- Logger "#### Running osync in file monitor mode." "NOTICE"
-
- while true
- do
- if [ "$ConfigFile" != "" ]; then
- cmd='bash '$osync_cmd' "'$ConfigFile'" '$opts
- else
- cmd='bash '$osync_cmd' '$opts
- fi
- Logger "daemon cmd: $cmd" "DEBUG"
- eval "$cmd"
- retval=$?
- if [ $retval != 0 ]; then
- Logger "osync child exited with error." "CRITICAL"
- exit $retval
- fi
-
- Logger "#### Monitoring now." "NOTICE"
- inotifywait --exclude $OSYNC_DIR $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE -qq -r -e create -e modify -e delete -e move -e attrib --timeout "$MAX_WAIT" "$INITIATOR_SYNC_DIR" &
- #OSYNC_SUB_PID=$! Not used anymore with killchilds func
- wait $!
- retval=$?
- if [ $retval == 0 ]; then
- Logger "#### Changes detected, waiting $MIN_WAIT seconds before running next sync." "NOTICE"
- sleep $MIN_WAIT
- elif [ $retval == 2 ]; then
- Logger "#### $MAX_WAIT timeout reached, running sync." "NOTICE"
- else
- Logger "#### inotify error detected, waiting $MIN_WAIT seconds before running next sync." "ERROR"
- sleep $MIN_WAIT
- fi
- done
-
-}
-
-STATS=0
-PARTIAL=0
-FORCE_UNLOCK=0
-no_maxtime=0
-# Alert flags
-opts=""
-ERROR_ALERT=0
-soft_stop=0
-_QUICK_SYNC=0
-sync_on_changes=0
-_NOLOCKS=0
-osync_cmd=$0
-
-if [ $# -eq 0 ]
-then
- Usage
-fi
-
-first=1
-for i in "$@"
-do
- case $i in
- --dry)
- _DRYRUN=1
- opts=$opts" --dry"
- ;;
- --silent)
- _SILENT=1
- opts=$opts" --silent"
- ;;
- --verbose)
- _VERBOSE=1
- opts=$opts" --verbose"
- ;;
- --stats)
- STATS=1
- opts=$opts" --stats"
- ;;
- --partial)
- PARTIAL="yes"
- opts=$opts" --partial"
- ;;
- --force-unlock)
- FORCE_UNLOCK=1
- opts=$opts" --force-unlock"
- ;;
- --no-maxtime)
- no_maxtime=1
- opts=$opts" --no-maxtime"
- ;;
- --help|-h|--version|-v)
- Usage
- ;;
- --initiator=*)
- _QUICK_SYNC=$(($_QUICK_SYNC + 1))
- no_maxtime=1
- INITIATOR_SYNC_DIR=${i##*=}
- opts=$opts" --initiator=\"$INITIATOR_SYNC_DIR\""
- ;;
- --target=*)
- _QUICK_SYNC=$(($_QUICK_SYNC + 1))
- TARGET_SYNC_DIR=${i##*=}
- opts=$opts" --target=\"$TARGET_SYNC_DIR\""
- no_maxtime=1
- ;;
- --rsakey=*)
- SSH_RSA_PRIVATE_KEY=${i##*=}
- opts=$opts" --rsakey=\"$SSH_RSA_PRIVATE_KEY\""
- ;;
- --instance-id=*)
- INSTANCE_ID=${i##*=}
- opts=$opts" --instance-id=\"$INSTANCE_ID\""
- ;;
- --on-changes)
- sync_on_changes=1
- _NOLOCKS=1
- ;;
- --no-locks)
- _NOLOCKS=1
- ;;
- *)
- if [ $first == "0" ]; then
- Logger "Unknown option '$i'" "CRITICAL"
- Usage
- fi
- ;;
- esac
- first=0
-done
-
-# Remove leading space if there is one
-opts="${opts# *}"
-
- ## Here we set default options for quicksync tasks when no configuration file is provided.
-
- if [ $_QUICK_SYNC -eq 2 ]; then
- if [ "$INSTANCE_ID" == "" ]; then
- INSTANCE_ID="quicksync_task"
- fi
-
- # Let the possibility to initialize those values directly via command line like SOFT_DELETE_DAYS=60 ./osync.sh
-
- if [ "$MINIMUM_SPACE" == "" ]; then
- MINIMUM_SPACE=1024
- fi
-
- if [ "$CONFLICT_BACKUP_DAYS" == "" ]; then
- CONFLICT_BACKUP_DAYS=30
- fi
-
- if [ "$SOFT_DELETE_DAYS" == "" ]; then
- SOFT_DELETE_DAYS=30
- fi
-
- if [ "$RESUME_TRY" == "" ]; then
- RESUME_TRY=1
- fi
-
- if [ "$SOFT_MAX_EXEC_TIME" == "" ]; then
- SOFT_MAX_EXEC_TIME=0
- fi
-
- if [ "$HARD_MAX_EXEC_TIME" == "" ]; then
- HARD_MAX_EXEC_TIME=0
- fi
-
- MIN_WAIT=30
- REMOTE_OPERATION=no
- else
- ConfigFile="${1}"
- LoadConfigFile "$ConfigFile"
- fi
-
- if [ "$LOGFILE" == "" ]; then
- if [ -w /var/log ]; then
- LOG_FILE=/var/log/$PROGRAM.$INSTANCE_ID.log
- else
- LOG_FILE=./$PROGRAM.$INSTANCE_ID.log
- fi
- else
- LOG_FILE="$LOGFILE"
- fi
-
- if [ "$IS_STABLE" != "yes" ]; then
- Logger "This is an unstable dev build. Please use with caution." "WARN"
- fi
-
- GetLocalOS
- InitLocalOSSettings
- CheckEnvironment
- PreInit
- Init
- PostInit
- if [ $_QUICK_SYNC -lt 2 ]; then
- CheckCurrentConfig
- fi
- GetRemoteOS
- InitRemoteOSSettings
-
- if [ $sync_on_changes -eq 1 ]; then
- SyncOnChanges
- else
- DATE=$(date)
- Logger "-------------------------------------------------------------" "NOTICE"
- Logger "$DRY_WARNING $DATE - $PROGRAM $PROGRAM_VERSION script begin." "NOTICE"
- Logger "-------------------------------------------------------------" "NOTICE"
- Logger "Sync task [$INSTANCE_ID] launched as $LOCAL_USER@$LOCAL_HOST (PID $SCRIPT_PID)" "NOTICE"
- if [ $no_maxtime -eq 1 ]; then
- SOFT_MAX_EXEC_TIME=0
- HARD_MAX_EXEC_TIME=0
- fi
- CheckReplicaPaths
- CheckDiskSpace
- RunBeforeHook
- Main
- if [ $? == 0 ]; then
- SoftDelete
- fi
- RunAfterHook
- fi
diff --git a/dev/debug_osync.sh b/dev/debug_osync.sh
index e296052..f0e4aa7 100755
--- a/dev/debug_osync.sh
+++ b/dev/debug_osync.sh
@@ -4,14 +4,10 @@ PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
PROGRAM_VERSION=1.1-dev
-<<<<<<< HEAD
PROGRAM_BUILD=2016040101
-=======
-PROGRAM_BUILD=2016033101
->>>>>>> master
IS_STABLE=yes
-## FUNC_BUILD=2016033105
+## FUNC_BUILD=2016040102
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
@@ -801,7 +797,7 @@ function __CheckArguments {
local counted_arguments=$((iterate-4))
if [ $counted_arguments -ne $number_of_arguments ]; then
- Logger "Function $function_name may have inconsistent number of arguments. Expected: $number_of_arguments, count: $counted_arguments, see log file." "ERROR"
+ Logger "Function $function_name may have inconsistent number of arguments. Expected: $number_of_arguments, count: $counted_arguments, bash seen: $number_of_given_arguments. see log file." "ERROR"
Logger "Arguments passed: $arg_list" "ERROR"
fi
fi
@@ -810,8 +806,8 @@ function __CheckArguments {
#__END_WITH_PARANOIA_DEBUG
function RsyncPatternsAdd {
- local pattern="${1}"
- local pattern_type="${2}" # exclude or include
+ local pattern_type="${1}" # exclude or include
+ local pattern="${2}"
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
local rest=
@@ -840,8 +836,8 @@ function RsyncPatternsAdd {
}
function RsyncPatternsFromAdd {
- local pattern_from="${1}"
- local pattern_type="${2}"
+ local pattern_type="${1}"
+ local pattern_from="${2}"
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
local pattern_from=
@@ -860,22 +856,22 @@ function RsyncPatterns {
__CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
if [ "$RSYNC_PATTERN_FIRST" == "exclude" ]; then
- RsyncPatternsAdd "$RSYNC_EXCLUDE_PATTERN" "exclude"
+ RsyncPatternsAdd "exclude" "$RSYNC_EXCLUDE_PATTERN"
if [ "$RSYNC_EXCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_EXCLUDE_FROM" "exclude"
+ RsyncPatternsFromAdd "exclude" "$RSYNC_EXCLUDE_FROM"
fi
RsyncPatternsAdd "$RSYNC_INCLUDE_PATTERN" "include"
if [ "$RSYNC_INCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_INCLUDE_FROM" "include"
+ RsyncPatternsFromAdd "include" "$RSYNC_INCLUDE_FROM"
fi
elif [ "$RSYNC_PATTERN_FIRST" == "include" ]; then
- RsyncPatternsAdd "$RSYNC_INCLUDE_PATTERN" "include"
+ RsyncPatternsAdd "include" "$RSYNC_INCLUDE_PATTERN"
if [ "$RSYNC_INCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_INCLUDE_FROM" "include"
+ RsyncPatternsFromAdd "include" "$RSYNC_INCLUDE_FROM"
fi
- RsyncPatternsAdd "$RSYNC_EXCLUDE_PATTERN" "exclude"
+ RsyncPatternsAdd "exclude" "$RSYNC_EXCLUDE_PATTERN"
if [ "$RSYNC_EXCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_EXCLUDE_FROM" "exclude"
+ RsyncPatternsFromAdd "exclude" "$RSYNC_EXCLUDE_FROM"
fi
else
Logger "Bogus RSYNC_PATTERN_FIRST value in config file. Will not use rsync patterns." "WARN"
diff --git a/dev/n_osync.sh b/dev/n_osync.sh
index 0997f20..59daf82 100755
--- a/dev/n_osync.sh
+++ b/dev/n_osync.sh
@@ -4,11 +4,7 @@ PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
PROGRAM_VERSION=1.1-dev
-<<<<<<< HEAD
PROGRAM_BUILD=2016040101
-=======
-PROGRAM_BUILD=2016033101
->>>>>>> master
IS_STABLE=yes
source "./ofunctions.sh"
diff --git a/dev/ofunctions.sh b/dev/ofunctions.sh
index ab8f181..03fa60d 100644
--- a/dev/ofunctions.sh
+++ b/dev/ofunctions.sh
@@ -1,4 +1,4 @@
-## FUNC_BUILD=2016033105
+## FUNC_BUILD=2016040102
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
@@ -788,7 +788,7 @@ function __CheckArguments {
local counted_arguments=$((iterate-4))
if [ $counted_arguments -ne $number_of_arguments ]; then
- Logger "Function $function_name may have inconsistent number of arguments. Expected: $number_of_arguments, count: $counted_arguments, see log file." "ERROR"
+ Logger "Function $function_name may have inconsistent number of arguments. Expected: $number_of_arguments, count: $counted_arguments, bash seen: $number_of_given_arguments. see log file." "ERROR"
Logger "Arguments passed: $arg_list" "ERROR"
fi
fi
@@ -797,8 +797,8 @@ function __CheckArguments {
#__END_WITH_PARANOIA_DEBUG
function RsyncPatternsAdd {
- local pattern="${1}"
- local pattern_type="${2}" # exclude or include
+ local pattern_type="${1}" # exclude or include
+ local pattern="${2}"
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
local rest=
@@ -827,8 +827,8 @@ function RsyncPatternsAdd {
}
function RsyncPatternsFromAdd {
- local pattern_from="${1}"
- local pattern_type="${2}"
+ local pattern_type="${1}"
+ local pattern_from="${2}"
__CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
local pattern_from=
@@ -847,22 +847,22 @@ function RsyncPatterns {
__CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG
if [ "$RSYNC_PATTERN_FIRST" == "exclude" ]; then
- RsyncPatternsAdd "$RSYNC_EXCLUDE_PATTERN" "exclude"
+ RsyncPatternsAdd "exclude" "$RSYNC_EXCLUDE_PATTERN"
if [ "$RSYNC_EXCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_EXCLUDE_FROM" "exclude"
+ RsyncPatternsFromAdd "exclude" "$RSYNC_EXCLUDE_FROM"
fi
RsyncPatternsAdd "$RSYNC_INCLUDE_PATTERN" "include"
if [ "$RSYNC_INCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_INCLUDE_FROM" "include"
+ RsyncPatternsFromAdd "include" "$RSYNC_INCLUDE_FROM"
fi
elif [ "$RSYNC_PATTERN_FIRST" == "include" ]; then
- RsyncPatternsAdd "$RSYNC_INCLUDE_PATTERN" "include"
+ RsyncPatternsAdd "include" "$RSYNC_INCLUDE_PATTERN"
if [ "$RSYNC_INCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_INCLUDE_FROM" "include"
+ RsyncPatternsFromAdd "include" "$RSYNC_INCLUDE_FROM"
fi
- RsyncPatternsAdd "$RSYNC_EXCLUDE_PATTERN" "exclude"
+ RsyncPatternsAdd "exclude" "$RSYNC_EXCLUDE_PATTERN"
if [ "$RSYNC_EXCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_EXCLUDE_FROM" "exclude"
+ RsyncPatternsFromAdd "exclude" "$RSYNC_EXCLUDE_FROM"
fi
else
Logger "Bogus RSYNC_PATTERN_FIRST value in config file. Will not use rsync patterns." "WARN"
diff --git a/osync.sh b/osync.sh
index 1ec3724..3c3736b 100755
--- a/osync.sh
+++ b/osync.sh
@@ -4,14 +4,10 @@ PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
AUTHOR="(C) 2013-2016 by Orsiris de Jong"
CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
PROGRAM_VERSION=1.1-dev
-<<<<<<< HEAD
PROGRAM_BUILD=2016040101
-=======
-PROGRAM_BUILD=2016033101
->>>>>>> master
IS_STABLE=yes
-## FUNC_BUILD=2016033105
+## FUNC_BUILD=2016040102
## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
@@ -745,8 +741,8 @@ function CheckConnectivity3rdPartyHosts {
#__END_WITH_PARANOIA_DEBUG
function RsyncPatternsAdd {
- local pattern="${1}"
- local pattern_type="${2}" # exclude or include
+ local pattern_type="${1}" # exclude or include
+ local pattern="${2}"
local rest=
@@ -774,8 +770,8 @@ function RsyncPatternsAdd {
}
function RsyncPatternsFromAdd {
- local pattern_from="${1}"
- local pattern_type="${2}"
+ local pattern_type="${1}"
+ local pattern_from="${2}"
local pattern_from=
@@ -792,22 +788,22 @@ function RsyncPatternsFromAdd {
function RsyncPatterns {
if [ "$RSYNC_PATTERN_FIRST" == "exclude" ]; then
- RsyncPatternsAdd "$RSYNC_EXCLUDE_PATTERN" "exclude"
+ RsyncPatternsAdd "exclude" "$RSYNC_EXCLUDE_PATTERN"
if [ "$RSYNC_EXCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_EXCLUDE_FROM" "exclude"
+ RsyncPatternsFromAdd "exclude" "$RSYNC_EXCLUDE_FROM"
fi
RsyncPatternsAdd "$RSYNC_INCLUDE_PATTERN" "include"
if [ "$RSYNC_INCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_INCLUDE_FROM" "include"
+ RsyncPatternsFromAdd "include" "$RSYNC_INCLUDE_FROM"
fi
elif [ "$RSYNC_PATTERN_FIRST" == "include" ]; then
- RsyncPatternsAdd "$RSYNC_INCLUDE_PATTERN" "include"
+ RsyncPatternsAdd "include" "$RSYNC_INCLUDE_PATTERN"
if [ "$RSYNC_INCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_INCLUDE_FROM" "include"
+ RsyncPatternsFromAdd "include" "$RSYNC_INCLUDE_FROM"
fi
- RsyncPatternsAdd "$RSYNC_EXCLUDE_PATTERN" "exclude"
+ RsyncPatternsAdd "exclude" "$RSYNC_EXCLUDE_PATTERN"
if [ "$RSYNC_EXCLUDE_FROM" != "" ]; then
- RsyncPatternsFromAdd "$RSYNC_EXCLUDE_FROM" "exclude"
+ RsyncPatternsFromAdd "exclude" "$RSYNC_EXCLUDE_FROM"
fi
else
Logger "Bogus RSYNC_PATTERN_FIRST value in config file. Will not use rsync patterns." "WARN"