From cafbf43222e5f16679c751977fd33be99b73994b Mon Sep 17 00:00:00 2001 From: deajan Date: Fri, 18 Nov 2016 09:05:06 +0100 Subject: [PATCH] Rebuilt targets --- dev/debug_osync.sh | 343 ++++++++++++++++++++++++++++----------------- install.sh | 2 +- osync.sh | 323 ++++++++++++++++++++++++++---------------- 3 files changed, 415 insertions(+), 253 deletions(-) diff --git a/dev/debug_osync.sh b/dev/debug_osync.sh index f8efd66..9fd6af3 100755 --- a/dev/debug_osync.sh +++ b/dev/debug_osync.sh @@ -3,8 +3,8 @@ 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.2-beta2 -PROGRAM_BUILD=2016111502 +PROGRAM_VERSION=1.2-beta3 +PROGRAM_BUILD=2016111704 IS_STABLE=no # Execution order #__WITH_PARANOIA_DEBUG @@ -45,17 +45,22 @@ IS_STABLE=no #### MINIMAL-FUNCTION-SET BEGIN #### -## FUNC_BUILD=2016111503 +## FUNC_BUILD=2016111705 ## BEGIN Generic bash functions written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr ## To use in a program, define the following variables: ## PROGRAM=program-name ## INSTANCE_ID=program-instance-name ## _DEBUG=yes/no -## _LOGGER_STDERR=true/false +## _LOGGER_LOGGER_SILENT=true/false +## _LOGGER_LOGGER_VERBOSE=true/false ## _LOGGER_ERR_ONLY=true/false ## _LOGGER_PREFIX="date"/"time"/"" +## Logger sets {ERROR|WARN}_ALERT variable when called with critical / error / warn loglevel +## When called from subprocesses, variable of main process can't be set. Status needs to be get via $RUN_DIR/$PROGRAM.Logger.{error|warn}.$SCRIPT_PID + +#TODO: Rewrite Logger so we can decide what to send to stdout, stderr and logfile #TODO: Windows checks, check sendmail & mailsend if ! type "$BASH" > /dev/null; then @@ -71,10 +76,10 @@ MAIL_ALERT_MSG="Execution of $PROGRAM instance $INSTANCE_ID on $(date) has warni # Environment variables that can be overriden by programs _DRYRUN=false -_SILENT=false -_VERBOSE=false +_LOGGER_SILENT=false +_LOGGER_VERBOSE=false +_LOGGER_ERR_ONLY=false _LOGGER_PREFIX="date" -_LOGGER_STDERR=false if [ "$KEEP_LOGGING" == "" ]; then KEEP_LOGGING=1801 fi @@ -83,9 +88,6 @@ fi ERROR_ALERT=false WARN_ALERT=false -# Log from current run -CURRENT_LOG="" - ## allow function call checks #__WITH_PARANOIA_DEBUG if [ "$_PARANOIA_DEBUG" == "yes" ];then #__WITH_PARANOIA_DEBUG _DEBUG=yes #__WITH_PARANOIA_DEBUG @@ -95,13 +97,13 @@ fi #__WITH_PARANOIA_DEBUG if [ ! "$_DEBUG" == "yes" ]; then _DEBUG=no SLEEP_TIME=.05 # Tested under linux and FreeBSD bash, #TODO tests on cygwin / msys - _VERBOSE=false + _LOGGER_VERBOSE=false else - if [ "$SLEEP_TIME" == "" ]; then - SLEEP_TIME=1 + if [ "$SLEEP_TIME" == "" ]; then # Set SLEEP_TIME as environment variable when runinng with bash -x in order to avoid spamming console + SLEEP_TIME=.05 fi trap 'TrapError ${LINENO} $?' ERR - _VERBOSE=true + _LOGGER_VERBOSE=true fi SCRIPT_PID=$$ @@ -148,28 +150,43 @@ function Dummy { # Sub function of Logger function _Logger { - local svalue="${1}" # What to log to stdout - local lvalue="${2:-$svalue}" # What to log to logfile, defaults to screen value - local evalue="${3}" # What to log to stderr + local logValue="${1}" # Log to file + local stdValue="${2}" # Log to screeen + local toStderr="${3:-false}" # Log to stderr instead of stdout + + echo -e "$logValue" >> "$LOG_FILE" + # Current log file + echo -e "$logValue" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" - echo -e "$lvalue" >> "$LOG_FILE" - CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue" + if [ "$stdValue" != "" ] && [ "$_LOGGER_SILENT" != true ]; then + if [ $toStderr == true ]; then + # Force stderr color in subshell + (>&2 echo -e "$stdValue") - if [ $_LOGGER_STDERR == true ] && [ "$evalue" != "" ]; then - cat <<< "$evalue" 1>&2 - elif [ "$_SILENT" == false ]; then - echo -e "$svalue" + else + echo -e "$stdValue" + fi fi } # General log function with log levels: -# CRITICAL, ERROR, WARN are colored in stdout, prefixed in stderr -# NOTICE is standard level -# VERBOSE is only sent to stdout / stderr if _VERBOSE=true -# DEBUG & PARANOIA_DEBUG are only sent if _DEBUG=yes + +# Environment variables +# _LOGGER_SILENT: Disables any output to stdout & stderr +# _LOGGER_STD_ERR: Disables any output to stdout except for ALWAYS loglevel +# _LOGGER_VERBOSE: Allows VERBOSE loglevel messages to be sent to stdout + +# Loglevels +# Except for VERBOSE, all loglevels are ALWAYS sent to log file + +# CRITICAL, ERROR, WARN sent to stderr, color depending on level, level also logged +# NOTICE sent to stdout +# VERBOSE sent to stdout if _LOGGER_VERBOSE = true +# ALWAYS is sent to stdout unless _LOGGER_SILENT = true +# DEBUG & PARANOIA_DEBUG are only sent to stdout if _DEBUG=yes function Logger { local value="${1}" # Sentence to log (in double quotes) - local level="${2}" # Log level: PARANOIA_DEBUG, DEBUG, VERBOSE, NOTICE, WARN, ERROR, CRITIAL + local level="${2}" # Log level if [ "$_LOGGER_PREFIX" == "time" ]; then prefix="TIME: $SECONDS - " @@ -180,42 +197,44 @@ function Logger { fi if [ "$level" == "CRITICAL" ]; then - _Logger "$prefix\e[41m$value\e[0m" "$prefix$level:$value" "$level:$value" + _Logger "$prefix($level):$value" "$prefix\e[41m$value\e[0m" true ERROR_ALERT=true + # ERROR_ALERT / WARN_ALERT isn't set in main when Logger is called from a subprocess. Need to keep this flag. + echo "1" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" return elif [ "$level" == "ERROR" ]; then - _Logger "$prefix\e[91m$value\e[0m" "$prefix$level:$value" "$level:$value" + _Logger "$prefix($level):$value" "$prefix\e[91m$value\e[0m" true ERROR_ALERT=true + echo "1" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" return elif [ "$level" == "WARN" ]; then - _Logger "$prefix\e[33m$value\e[0m" "$prefix$level:$value" "$level:$value" + _Logger "$prefix($level):$value" "$prefix\e[33m$value\e[0m" true WARN_ALERT=true + echo "1" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.warn.$SCRIPT_PID" return elif [ "$level" == "NOTICE" ]; then if [ "$_LOGGER_ERR_ONLY" != true ]; then - _Logger "$prefix$value" + _Logger "$prefix$value" "$prefix$value" fi return elif [ "$level" == "VERBOSE" ]; then - if [ $_VERBOSE == true ]; then - _Logger "$prefix$value" + if [ $_LOGGER_VERBOSE == true ]; then + _Logger "$prefix:$value" "$prefix$value" fi return elif [ "$level" == "ALWAYS" ]; then - if [ $_SILENT != true ]; then - _Logger "$prefix$value" "$prefix$level:$value" "$level:$value" - fi + _Logger "$prefix$value" "$prefix$value" return elif [ "$level" == "DEBUG" ]; then if [ "$_DEBUG" == "yes" ]; then - _Logger "$prefix$value" + _Logger "$prefix$value" "$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 + elif [ "$level" == "PARANOIA_DEBUG" ]; then #__WITH_PARANOIA_DEBUG + if [ "$_PARANOIA_DEBUG" == "yes" ]; then #__WITH_PARANOIA_DEBUG + _Logger "$prefix$value" "$prefix$value" #__WITH_PARANOIA_DEBUG + return #__WITH_PARANOIA_DEBUG + fi #__WITH_PARANOIA_DEBUG else _Logger "\e[41mLogger function called without proper loglevel [$level].\e[0m" _Logger "Value was: $prefix$value" @@ -242,7 +261,7 @@ function QuickLogger { __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG - if [ $_SILENT == true ]; then + if [ $_LOGGER_SILENT == true ]; then _QuickLogger "$value" "log" else _QuickLogger "$value" "stdout" @@ -305,10 +324,10 @@ function SendAlert { __CheckArguments 0-1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG - local attachment= - local attachmentFile= - local subject= - local body= + local attachment + local attachmentFile + local subject + local body if [ "$DESTINATION_MAILS" == "" ]; then return 0 @@ -333,7 +352,9 @@ function SendAlert { else attachment=true fi - body="$MAIL_ALERT_MSG"$'\n\n'"$CURRENT_LOG" + if [ -e "$RUN_DIR/$PROGRAM._Logger.$SCRIPT_PID" ]; then + body="$MAIL_ALERT_MSG"$'\n\n'"$(cat $RUN_DIR/$PROGRAM._Logger.$SCRIPT_PID)" + fi if [ $ERROR_ALERT == true ]; then subject="Error alert for $INSTANCE_ID" @@ -521,7 +542,7 @@ function TrapError { local line="$1" local code="${2:-1}" - if [ $_SILENT == false ]; then + if [ $_LOGGER_SILENT == false ]; then echo -e "\e[45m/!\ ERROR in ${job}: Near line ${line}, exit code ${code}\e[0m" fi } @@ -548,7 +569,7 @@ function LoadConfigFile { } function Spinner { - if [ $_SILENT == true ] || [ "$_LOGGER_ERR_ONLY" == true ]; then + if [ $_LOGGER_SILENT == true ] || [ "$_LOGGER_ERR_ONLY" == true ]; then return 0 fi @@ -1091,7 +1112,7 @@ function RunLocalCommand { Logger "Command failed." "ERROR" fi - if [ $_VERBOSE == true ] || [ $retval -ne 0 ]; then + if [ $_LOGGER_VERBOSE == true ] || [ $retval -ne 0 ]; then Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE" fi @@ -1126,7 +1147,7 @@ function RunRemoteCommand { Logger "Command failed." "ERROR" fi - if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_VERBOSE == true ] || [ $retval -ne 0 ]) + if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_LOGGER_VERBOSE == true ] || [ $retval -ne 0 ]) then Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE" fi @@ -1622,12 +1643,19 @@ function TrapStop { function TrapQuit { local exitcode + # Get ERROR / WARN alert flags from subprocesses that call Logger + if [ -f "$RUN_DIR/$PROGRAM.Logger.warn.$SCRIPT_PID" ]; then + WARN_ALERT=true + fi + if [ -f "$RUN_DIR/$PROGRAM.Logger.error.$SCRIPT_PID" ]; then + ERROR_ALERT=true + fi + if [ $ERROR_ALERT == true ]; then UnlockReplicas if [ "$RUN_AFTER_CMD_ON_ERROR" == "yes" ]; then RunAfterHook fi - CleanUp Logger "$PROGRAM finished with errors." "ERROR" if [ "$_DEBUG" != "yes" ] then @@ -1641,7 +1669,6 @@ function TrapQuit { if [ "$RUN_AFTER_CMD_ON_ERROR" == "yes" ]; then RunAfterHook fi - CleanUp Logger "$PROGRAM finished with warnings." "WARN" if [ "$_DEBUG" != "yes" ] then @@ -1653,11 +1680,11 @@ function TrapQuit { else UnlockReplicas RunAfterHook - CleanUp Logger "$PROGRAM finished." "NOTICE" exitcode=0 fi + CleanUp KillChilds $$ > /dev/null 2>&1 exit $exitcode @@ -1705,6 +1732,8 @@ function CheckCurrentConfig { function CheckCurrentConfigAll { __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG + local tmp + if [ "$INSTANCE_ID" == "" ]; then Logger "No INSTANCE_ID defined in config file." "CRITICAL" exit 1 @@ -1726,9 +1755,13 @@ function CheckCurrentConfigAll { exit 1 fi - if [ "$SKIP_DELETION" != "" ] && [ $(arrayContains "${INITIATOR[$__type]}" "${SKIP_DELETION[@]}") -eq 0 ] && [ $(arrayContains "${TARGET[$__type]}" "${SKIP_DELETION[@]}") -eq 0 ]; then - Logger "Bogus skip deletion parameter." "CRITICAL" - exit 1 + if [ "$SKIP_DELETION" != "" ]; then + tmp="$SKIP_DELETION" + IFS=',' read -r -a SKIP_DELETION <<< "$tmp" + if [ $(arrayContains "${INITIATOR[$__type]}" "${SKIP_DELETION[@]}") -eq 0 ] && [ $(arrayContains "${TARGET[$__type]}" "${SKIP_DELETION[@]}") -eq 0 ]; then + Logger "Bogus skip deletion parameter [$SKIP_DELETION]." "CRITICAL" + exit 1 + fi fi } @@ -1950,27 +1983,41 @@ function CreateStateDirs { function _CheckLocksLocal { local lockfile="${1}" - __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG + local replicaType="${2}" - local lockfile_content - local lock_pid - local lock_instance_id + __CheckArguments 2 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG - 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#*@} - kill -9 $lock_pid > /dev/null 2>&1 + local lockfileContent + local lockPid + local lockInstanceID + + if [ -s "$lockfile" ]; then + lockfileContent=$(cat $lockfile) + Logger "Master lock pid present: $lockfileContent" "DEBUG" + lockPid=${lockfileContent%@*} + if [ $(IsInteger $lockPid) -ne 1 ]; then + Logger "Invalid pid [$lockPid] in local replica." "CRITICAL" + exit 1 + fi + lockInstanceID=${lockfileContent#*@} + if [ "$lockInstanceID" == "" ]; then + Logger "Invalid instance id [$lockInstanceID] in local replica." "CRITICAL" + exit 1 + + Logger "Local $replicaType lock is: [$lockPid@$lockInstanceID]." "DEBUG" + + fi + kill -0 $lockPid > /dev/null 2>&1 if [ $? != 0 ]; then - Logger "There is a dead osync lock in [$lockfile]. Instance [$lock_pid] no longer running. Resuming." "NOTICE" - #rm "$lockfile" - #if [ $? != 0 ]; then - # Logger "Cannot remove lock in [$lockfile]." "CRITICAL" - # exit 1 - #fi + Logger "There is a local dead osync lock [$lockPid@$lockInstanceID] that is no longer running. Resuming." "NOTICE" + if [ "$replicaType" == "${INITIATOR[$__type]}" ]; then + # REPLICA_OVERWRITE_LOCK disables noclobber option in WriteLock functions + INITIATOR_OVERWRITE_LOCK=true + elif [ "$replicaType" == "${TARGET[$__type]}" ]; then + TARGET_OVERWRITE_LOCK=true + fi else - Logger "There is already a local instance of osync running [$lock_pid] for this replica. Cannot start." "CRITICAL" + Logger "There is already a local instance [$lockPid@$lockInstanceID] of osync running for this replica. Cannot start." "CRITICAL" exit 1 fi fi @@ -1981,9 +2028,9 @@ function _CheckLocksRemote { __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd - local lock_pid - local lock_instance_id - local lockfile_content + local lockPid + local lockInstanceID + local lockfileContent CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost @@ -1992,34 +2039,42 @@ function _CheckLocksRemote { Logger "cmd: $cmd" "DEBUG" eval "$cmd" 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 + Logger "Cannot check remote replica lock." "CRITICAL" + exit 1 fi - lock_pid=${lockfile_content%@*} - lock_instance_id=${lockfile_content#*@} + if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then + lockfileContent="$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" + + lockPid=${lockfileContent%@*} + if [ $(IsInteger $lockPid) -ne 1 ]; then + Logger "Invalid pid [$lockPid] in remote replica lock." "CRITICAL" + exit 1 + fi + lockInstanceID=${lockfileContent#*@} + if [ "$lockInstanceID" == "" ]; then + Logger "Invalid instance id [$lockInstanceID] in remote replica." "CRITICAL" + exit 1 + fi - if [ "$lock_pid" != "" ] && [ "$lock_instance_id" != "" ]; then - Logger "Remote lock is: $lock_pid@$lock_instance_id" "DEBUG" + Logger "Remote lock is: [$lockPid@$lockInstanceID]" "DEBUG" - kill -0 $lock_pid > /dev/null 2>&1 + kill -0 $lockPid > /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" + if [ "$lockInstanceID" == "$INSTANCE_ID" ]; then + Logger "There is a remote dead osync lock [$lockPid@lockInstanceID] on target replica that corresponds to this initiator INSTANCE_ID. Pid [$lockPid] no longer running. Resuming." "NOTICE" + TARGET_OVERWRITE_LOCK=true 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" + Logger "There is a remote (maybe dead) osync lock [$lockPid@$lockInstanceID] on target replica that does not correspond to this initiator INSTANCE_ID. Forcing resume." "WARN" + TARGET_OVERWRITE_LOCK=true 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" + Logger "There is a remote (maybe dead) osync lock [$lockPid@$lockInstanceID] on target replica that does not correspond to this initiator 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" + Logger "There is already a local instance of osync that locks target replica [$lockPid@$lockInstanceID]. Cannot start." "CRITICAL" exit 1 fi fi @@ -2041,10 +2096,10 @@ function CheckLocks { exit 1 fi else - _CheckLocksLocal "${INITIATOR[$__lockFile]}" & + _CheckLocksLocal "${INITIATOR[$__lockFile]}" "${INITIATOR[$__type]}" & pids="$!" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckLocksLocal "${TARGET[$__lockFile]}" & + _CheckLocksLocal "${TARGET[$__lockFile]}" "${INITIATOR[$__type]}" & pids="$pids;$!" else _CheckLocksRemote "${TARGET[$__lockFile]}" & @@ -2062,10 +2117,14 @@ function CheckLocks { function _WriteLockFilesLocal { local lockfile="${1}" local replicaType="${2}" - __CheckArguments 2 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG + local overwrite="${3:-false}" + + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG ( - set -o noclobber + if [ $overwrite == true ]; then + set -o noclobber + fi $COMMAND_SUDO echo "$SCRIPT_PID@$INSTANCE_ID" > "$lockfile" 2> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-$replicaType.$SCRIPT_PID" ) if [ $? != 0 ]; then @@ -2080,19 +2139,23 @@ function _WriteLockFilesLocal { function _WriteLockFilesRemote { local lockfile="${1}" local replicaType="${2}" - __CheckArguments 2 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG + local overwrite="${3-false}" + + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "( set -o noclobber; echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\")" > /dev/null 2> $RUN_DIR/$PROGRAM._WriteLockFilesRemote.$replicaType.$SCRIPT_PID' + cmd=$SSH_CMD' "( if [ $overwrite == true ]; then set -o noclobber; fi; echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\")" > /dev/null 2> $RUN_DIR/$PROGRAM._WriteLockFilesRemote.$replicaType.$SCRIPT_PID' + #WIP + #cmd=$SSH_CMD' "( set -o noclobber; echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\")" > /dev/null 2> $RUN_DIR/$PROGRAM._WriteLockFilesRemote.$replicaType.$SCRIPT_PID' Logger "cmd: $cmd" "DEBUG" eval "$cmd" if [ $? != 0 ]; then Logger "Could not create lock file on remote $replicaType in [$lockfile]." "CRITICAL" - Loggxer "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID)" "NOTICE" + Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID)" "NOTICE" return 1 else Logger "Locked remote $replicaType replica in [$lockfile]." "DEBUG" @@ -2107,14 +2170,14 @@ function WriteLockFiles { local pidArray local pid - _WriteLockFilesLocal "${INITIATOR[$__lockFile]}" "${INITIATOR[$__type]}"& + _WriteLockFilesLocal "${INITIATOR[$__lockFile]}" "${INITIATOR[$__type]}" $INITIATOR_LOCK_OVERWRITE & initiatorPid="$!" if [ "$REMOTE_OPERATION" != "yes" ]; then - _WriteLockFilesLocal "${TARGET[$__lockFile]}" "${TARGET[$__type]}" & + _WriteLockFilesLocal "${TARGET[$__lockFile]}" "${TARGET[$__type]}" $TARGET_LOCK_OVERWRITE & targetPid="$!" else - _WriteLockFilesRemote "${TARGET[$__lockFile]}" "${TARGET[$__type]}" & + _WriteLockFilesRemote "${TARGET[$__lockFile]}" "${TARGET[$__type]}" $TARGET_LOCK_OVERWRITE & targetPid="$!" fi @@ -2212,11 +2275,11 @@ function treeList { local replicaType="${2}" # replica type: initiator, target local treeFilename="${3}" # filename to output tree (will be prefixed with $replicaType) + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG + local escapedReplicaPath local rsyncCmd - __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG - escapedReplicaPath=$(EscapeSpaces "$replicaPath") Logger "Creating $replicaType replica file list [$replicaPath]." "NOTICE" @@ -2255,6 +2318,17 @@ function deleteList { local cmd + local failedDeletionListFromReplica + + if [ "$replicaType" == "${INITIATOR[$__type]}" ]; then + failedDeletionListFromReplica="${TARGET[$__type]}" + elif [ "$replicaType" == "${TARGET[$__type]}" ]; then + failedDeletionListFromReplica="${INITIATOR[$__type]}" + else + Logger "Bogus replicaType in [${FUNCNAME[0]}]." "CRITICAL" + exit 1 + fi + Logger "Creating $replicaType replica deleted file list." "NOTICE" if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeAfterFileNoSuffix]}" ]; then ## Same functionnality, comm is much faster than grep but is not available on every platform @@ -2270,10 +2344,10 @@ function deleteList { retval=$? # Add delete failed file list to current delete list and then empty it - if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" ]; then - cat "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}" + if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$failedDeletionListFromReplica${INITIATOR[$__failedDeletedListFile]}" ]; then + cat "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$failedDeletionListFromReplica${INITIATOR[$__failedDeletedListFile]}" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}" if [ $? == 0 ]; then - rm -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" + rm -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$failedDeletionListFromReplica${INITIATOR[$__failedDeletedListFile]}" else Logger "Cannot add failed deleted list to current deleted list for replica [$replicaType]." "ERROR" fi @@ -2635,7 +2709,7 @@ function _deleteRemote { exit 1 fi -$SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$deletionListFromReplica${INITIATOR[$__deletedListFile]}")" REPLICA_DIR="$(EscapeSpaces "$replicaDir")" SOFT_DELETE=$SOFT_DELETE DELETION_DIR="$(EscapeSpaces "$deletionDir")" FAILED_DELETE_LIST="$failedDeleteList" SUCCESS_DELETE_LIST="$successDeleteList" 'bash -s' << 'ENDSSH' >> "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 +$SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _LOGGER_VERBOSE=$_LOGGER_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$deletionListFromReplica${INITIATOR[$__deletedListFile]}")" REPLICA_DIR="$(EscapeSpaces "$replicaDir")" SOFT_DELETE=$SOFT_DELETE DELETION_DIR="$(EscapeSpaces "$deletionDir")" FAILED_DELETE_LIST="$failedDeleteList" SUCCESS_DELETE_LIST="$successDeleteList" 'bash -s' << 'ENDSSH' >> "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 ## The following lines are executed remotely function _logger { @@ -2662,7 +2736,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ _logger "$prefix$value" return elif [ "$level" == "VERBOSE" ]; then - if [ $_VERBOSE == true ]; then + if [ $_LOGGER_VERBOSE == true ]; then _logger "$prefix$value" fi return @@ -2706,12 +2780,12 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ # In order to keep full path on soft deletion, create parent directories before move parentdir="$(dirname "$files")" if [ "$parentdir" != "." ]; then + Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETION_DIR/$parentdir]." "VERBOSE" $COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETION_DIR/$parentdir" $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETION_DIR/$parentdir" - Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETION_DIR/$parentdir]." "VERBOSE" else - $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETION_DIR" Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETION_DIR]." "VERBOSE" + $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETION_DIR" fi if [ $? != 0 ]; then Logger "Cannot move [$REPLICA_DIR$files] to deletion directory." "ERROR" @@ -2725,10 +2799,9 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ else if [ $_DRYRUN == false ]; then if [ -e "$REPLICA_DIR$files" ]; then - $COMMAND_SUDO rm -rf "$REPLICA_DIR$files" - $result=$? Logger "Deleting [$REPLICA_DIR$files]." "VERBOSE" - if [ $result != 0 ]; then + $COMMAND_SUDO rm -rf "$REPLICA_DIR$files" + if [ $? != 0 ]; then Logger "Cannot delete [$REPLICA_DIR$files]." "ERROR" echo "$files" >> "$FAILED_DELETE_LIST" else @@ -2977,8 +3050,7 @@ function Sync { ## Step 2 if [ "$resumeInitiator" == "${SYNC_ACTION[2]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[2]}" ]; then - #TODO(high) only -X and -A (xattr & acl) should trigger this - if [ "$RSYNC_ATTR_ARGS" != "" ]; then + if [[ "$RSYNC_ATTR_ARGS" == *"-X"* ]] || [[ "$RSYNC_ATTR_ARGS" == *"-A"* ]]; then syncAttrs "${INITIATOR[$__replicaDir]}" "$TARGET_SYNC_DIR" WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING if [ $? != 0 ]; then @@ -3152,7 +3224,7 @@ function _SoftDeleteLocal { Logger "Removing files older than $changeTime days on $replicaType replica for $deletionType deletion." "NOTICE" fi - if [ $_VERBOSE == true ]; then + if [ $_LOGGER_VERBOSE == true ]; then # Cannot launch log function from xargs, ugly hack $COMMAND_SUDO $FIND_CMD "$replicaDeletionPath/" -type f -ctime +$changeTime -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)" "VERBOSE" @@ -3203,7 +3275,7 @@ function _SoftDeleteRemote { Logger "Removing files older than $changeTime days on $replicaType replica for $deletionType deletion." "NOTICE" fi - if [ $_VERBOSE == true ]; then + if [ $_LOGGER_VERBOSE == true ]; then # Cannot launch log function from xargs, ugly hack cmd=$SSH_CMD' "if [ -d \"'$replicaDeletionPath'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replicaDeletionPath'/\" -type f -ctime +'$changeTime' -print0 | xargs -0 -I {} echo Will delete file {} && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replicaDeletionPath'/\" -type d -empty -ctime '$changeTime' -print0 | xargs -0 -I {} echo Will delete directory {}; else echo \"The $replicaType replica dir [$replicaDeletionPath] does not exist. Skipping cleaning of old files.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" @@ -3269,7 +3341,7 @@ function _SummaryFromFile { local summaryFile="${2}" local direction="${3}" - __CheckArguments 2 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG if [ -f "$summaryFile" ]; then while read -r file; do @@ -3454,7 +3526,7 @@ function Init { ## Set sync only function arguments for rsync SYNC_OPTS="-u" - if [ $_VERBOSE == true ] || [ $_SUMMARY == true ]; then + if [ $_LOGGER_VERBOSE == true ] || [ $_SUMMARY == true ]; then SYNC_OPTS=$SYNC_OPTS" -i" fi @@ -3467,8 +3539,8 @@ function Init { ## Conflict options if [ "$CONFLICT_BACKUP" != "no" ]; then - INITIATOR_BACKUP="--backup --backup-dir=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__backupDir]}\"" - TARGET_BACKUP="--backup --backup-dir=\"${TARGET[$__replicaDir]}${TARGET[$__backupDir]}\"" + INITIATOR_BACKUP="--backup --backup-dir=\"${INITIATOR[$__backupDir]}\"" + TARGET_BACKUP="--backup --backup-dir=\"${TARGET[$__backupDir]}\"" 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)" @@ -3619,11 +3691,11 @@ for i in "$@"; do opts=$opts" --dry" ;; --silent) - _SILENT=true + _LOGGER_SILENT=true opts=$opts" --silent" ;; --verbose) - _VERBOSE=true + _LOGGER_VERBOSE=true opts=$opts" --verbose" ;; --stats) @@ -3671,20 +3743,17 @@ for i in "$@"; do ;; --skip-deletion=*) opts=$opts" --skip-deletion=\"${i##*=}\"" - IFS=',' read -r -a SKIP_DELETION <<< ${i##*=} + SKIP_DELETION=${##*=} ;; --on-changes) sync_on_changes=true _NOLOCKS=true _LOGGER_PREFIX="date" - _LOGGER_STDERR=true ;; --no-locks) _NOLOCKS=true ;; --errors-only) - #TODO: let err_only only output to stderr - #_LOGGER_STDERR=true _LOGGER_ERR_ONLY=true ;; --summary) @@ -3739,6 +3808,18 @@ opts="${opts# *}" HARD_MAX_EXEC_TIME=0 fi + if [ "$PRESERVE_ACL" == "" ]; then + PRESERVE_ACL="yes" + fi + + if [ "$PRESERVE_XATTR" == "" ]; then + PRESERVE_XATTR="yes" + fi + + if [ "$PATH_SEPARATOR_CHAR" == "" ]; then + PATH_SEPARATOR_CHAR=";" + fi + MIN_WAIT=30 else ConfigFile="${1}" diff --git a/install.sh b/install.sh index d6ce718..2558c05 100755 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash PROGRAM=osync -PROGRAM_VERSION=1.2-beta2 +PROGRAM_VERSION=1.2-beta3 PROGRAM_BINARY=$PROGRAM".sh" PROGRAM_BATCH=$PROGRAM"-batch.sh" SCRIPT_BUILD=2016111201 diff --git a/osync.sh b/osync.sh index 804406f..4af3ba3 100755 --- a/osync.sh +++ b/osync.sh @@ -3,25 +3,30 @@ 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.2-beta2 -PROGRAM_BUILD=2016111502 +PROGRAM_VERSION=1.2-beta3 +PROGRAM_BUILD=2016111704 IS_STABLE=no #### MINIMAL-FUNCTION-SET BEGIN #### -## FUNC_BUILD=2016111503 +## FUNC_BUILD=2016111705 ## BEGIN Generic bash functions written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr ## To use in a program, define the following variables: ## PROGRAM=program-name ## INSTANCE_ID=program-instance-name ## _DEBUG=yes/no -## _LOGGER_STDERR=true/false +## _LOGGER_LOGGER_SILENT=true/false +## _LOGGER_LOGGER_VERBOSE=true/false ## _LOGGER_ERR_ONLY=true/false ## _LOGGER_PREFIX="date"/"time"/"" +## Logger sets {ERROR|WARN}_ALERT variable when called with critical / error / warn loglevel +## When called from subprocesses, variable of main process can't be set. Status needs to be get via $RUN_DIR/$PROGRAM.Logger.{error|warn}.$SCRIPT_PID + +#TODO: Rewrite Logger so we can decide what to send to stdout, stderr and logfile #TODO: Windows checks, check sendmail & mailsend if ! type "$BASH" > /dev/null; then @@ -37,10 +42,10 @@ MAIL_ALERT_MSG="Execution of $PROGRAM instance $INSTANCE_ID on $(date) has warni # Environment variables that can be overriden by programs _DRYRUN=false -_SILENT=false -_VERBOSE=false +_LOGGER_SILENT=false +_LOGGER_VERBOSE=false +_LOGGER_ERR_ONLY=false _LOGGER_PREFIX="date" -_LOGGER_STDERR=false if [ "$KEEP_LOGGING" == "" ]; then KEEP_LOGGING=1801 fi @@ -49,21 +54,18 @@ fi ERROR_ALERT=false WARN_ALERT=false -# Log from current run -CURRENT_LOG="" - ## allow debugging from command line with _DEBUG=yes if [ ! "$_DEBUG" == "yes" ]; then _DEBUG=no SLEEP_TIME=.05 # Tested under linux and FreeBSD bash, #TODO tests on cygwin / msys - _VERBOSE=false + _LOGGER_VERBOSE=false else - if [ "$SLEEP_TIME" == "" ]; then - SLEEP_TIME=1 + if [ "$SLEEP_TIME" == "" ]; then # Set SLEEP_TIME as environment variable when runinng with bash -x in order to avoid spamming console + SLEEP_TIME=.05 fi trap 'TrapError ${LINENO} $?' ERR - _VERBOSE=true + _LOGGER_VERBOSE=true fi SCRIPT_PID=$$ @@ -109,28 +111,43 @@ function Dummy { # Sub function of Logger function _Logger { - local svalue="${1}" # What to log to stdout - local lvalue="${2:-$svalue}" # What to log to logfile, defaults to screen value - local evalue="${3}" # What to log to stderr + local logValue="${1}" # Log to file + local stdValue="${2}" # Log to screeen + local toStderr="${3:-false}" # Log to stderr instead of stdout + + echo -e "$logValue" >> "$LOG_FILE" + # Current log file + echo -e "$logValue" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" - echo -e "$lvalue" >> "$LOG_FILE" - CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue" + if [ "$stdValue" != "" ] && [ "$_LOGGER_SILENT" != true ]; then + if [ $toStderr == true ]; then + # Force stderr color in subshell + (>&2 echo -e "$stdValue") - if [ $_LOGGER_STDERR == true ] && [ "$evalue" != "" ]; then - cat <<< "$evalue" 1>&2 - elif [ "$_SILENT" == false ]; then - echo -e "$svalue" + else + echo -e "$stdValue" + fi fi } # General log function with log levels: -# CRITICAL, ERROR, WARN are colored in stdout, prefixed in stderr -# NOTICE is standard level -# VERBOSE is only sent to stdout / stderr if _VERBOSE=true -# DEBUG & PARANOIA_DEBUG are only sent if _DEBUG=yes + +# Environment variables +# _LOGGER_SILENT: Disables any output to stdout & stderr +# _LOGGER_STD_ERR: Disables any output to stdout except for ALWAYS loglevel +# _LOGGER_VERBOSE: Allows VERBOSE loglevel messages to be sent to stdout + +# Loglevels +# Except for VERBOSE, all loglevels are ALWAYS sent to log file + +# CRITICAL, ERROR, WARN sent to stderr, color depending on level, level also logged +# NOTICE sent to stdout +# VERBOSE sent to stdout if _LOGGER_VERBOSE = true +# ALWAYS is sent to stdout unless _LOGGER_SILENT = true +# DEBUG & PARANOIA_DEBUG are only sent to stdout if _DEBUG=yes function Logger { local value="${1}" # Sentence to log (in double quotes) - local level="${2}" # Log level: PARANOIA_DEBUG, DEBUG, VERBOSE, NOTICE, WARN, ERROR, CRITIAL + local level="${2}" # Log level if [ "$_LOGGER_PREFIX" == "time" ]; then prefix="TIME: $SECONDS - " @@ -141,35 +158,37 @@ function Logger { fi if [ "$level" == "CRITICAL" ]; then - _Logger "$prefix\e[41m$value\e[0m" "$prefix$level:$value" "$level:$value" + _Logger "$prefix($level):$value" "$prefix\e[41m$value\e[0m" true ERROR_ALERT=true + # ERROR_ALERT / WARN_ALERT isn't set in main when Logger is called from a subprocess. Need to keep this flag. + echo "1" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" return elif [ "$level" == "ERROR" ]; then - _Logger "$prefix\e[91m$value\e[0m" "$prefix$level:$value" "$level:$value" + _Logger "$prefix($level):$value" "$prefix\e[91m$value\e[0m" true ERROR_ALERT=true + echo "1" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.error.$SCRIPT_PID" return elif [ "$level" == "WARN" ]; then - _Logger "$prefix\e[33m$value\e[0m" "$prefix$level:$value" "$level:$value" + _Logger "$prefix($level):$value" "$prefix\e[33m$value\e[0m" true WARN_ALERT=true + echo "1" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.warn.$SCRIPT_PID" return elif [ "$level" == "NOTICE" ]; then if [ "$_LOGGER_ERR_ONLY" != true ]; then - _Logger "$prefix$value" + _Logger "$prefix$value" "$prefix$value" fi return elif [ "$level" == "VERBOSE" ]; then - if [ $_VERBOSE == true ]; then - _Logger "$prefix$value" + if [ $_LOGGER_VERBOSE == true ]; then + _Logger "$prefix:$value" "$prefix$value" fi return elif [ "$level" == "ALWAYS" ]; then - if [ $_SILENT != true ]; then - _Logger "$prefix$value" "$prefix$level:$value" "$level:$value" - fi + _Logger "$prefix$value" "$prefix$value" return elif [ "$level" == "DEBUG" ]; then if [ "$_DEBUG" == "yes" ]; then - _Logger "$prefix$value" + _Logger "$prefix$value" "$prefix$value" return fi else @@ -196,7 +215,7 @@ function QuickLogger { local value="${1}" - if [ $_SILENT == true ]; then + if [ $_LOGGER_SILENT == true ]; then _QuickLogger "$value" "log" else _QuickLogger "$value" "stdout" @@ -256,10 +275,10 @@ function SendAlert { local runAlert="${1:-false}" # Specifies if current message is sent while running or at the end of a run - local attachment= - local attachmentFile= - local subject= - local body= + local attachment + local attachmentFile + local subject + local body if [ "$DESTINATION_MAILS" == "" ]; then return 0 @@ -284,7 +303,9 @@ function SendAlert { else attachment=true fi - body="$MAIL_ALERT_MSG"$'\n\n'"$CURRENT_LOG" + if [ -e "$RUN_DIR/$PROGRAM._Logger.$SCRIPT_PID" ]; then + body="$MAIL_ALERT_MSG"$'\n\n'"$(cat $RUN_DIR/$PROGRAM._Logger.$SCRIPT_PID)" + fi if [ $ERROR_ALERT == true ]; then subject="Error alert for $INSTANCE_ID" @@ -471,7 +492,7 @@ function TrapError { local line="$1" local code="${2:-1}" - if [ $_SILENT == false ]; then + if [ $_LOGGER_SILENT == false ]; then echo -e "\e[45m/!\ ERROR in ${job}: Near line ${line}, exit code ${code}\e[0m" fi } @@ -497,7 +518,7 @@ function LoadConfigFile { } function Spinner { - if [ $_SILENT == true ] || [ "$_LOGGER_ERR_ONLY" == true ]; then + if [ $_LOGGER_SILENT == true ] || [ "$_LOGGER_ERR_ONLY" == true ]; then return 0 fi @@ -1022,7 +1043,7 @@ function RunLocalCommand { Logger "Command failed." "ERROR" fi - if [ $_VERBOSE == true ] || [ $retval -ne 0 ]; then + if [ $_LOGGER_VERBOSE == true ] || [ $retval -ne 0 ]; then Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE" fi @@ -1056,7 +1077,7 @@ function RunRemoteCommand { Logger "Command failed." "ERROR" fi - if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_VERBOSE == true ] || [ $retval -ne 0 ]) + if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ] && ([ $_LOGGER_VERBOSE == true ] || [ $retval -ne 0 ]) then Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE" fi @@ -1492,12 +1513,19 @@ function TrapStop { function TrapQuit { local exitcode + # Get ERROR / WARN alert flags from subprocesses that call Logger + if [ -f "$RUN_DIR/$PROGRAM.Logger.warn.$SCRIPT_PID" ]; then + WARN_ALERT=true + fi + if [ -f "$RUN_DIR/$PROGRAM.Logger.error.$SCRIPT_PID" ]; then + ERROR_ALERT=true + fi + if [ $ERROR_ALERT == true ]; then UnlockReplicas if [ "$RUN_AFTER_CMD_ON_ERROR" == "yes" ]; then RunAfterHook fi - CleanUp Logger "$PROGRAM finished with errors." "ERROR" if [ "$_DEBUG" != "yes" ] then @@ -1511,7 +1539,6 @@ function TrapQuit { if [ "$RUN_AFTER_CMD_ON_ERROR" == "yes" ]; then RunAfterHook fi - CleanUp Logger "$PROGRAM finished with warnings." "WARN" if [ "$_DEBUG" != "yes" ] then @@ -1523,11 +1550,11 @@ function TrapQuit { else UnlockReplicas RunAfterHook - CleanUp Logger "$PROGRAM finished." "NOTICE" exitcode=0 fi + CleanUp KillChilds $$ > /dev/null 2>&1 exit $exitcode @@ -1572,6 +1599,8 @@ function CheckCurrentConfig { function CheckCurrentConfigAll { + local tmp + if [ "$INSTANCE_ID" == "" ]; then Logger "No INSTANCE_ID defined in config file." "CRITICAL" exit 1 @@ -1593,9 +1622,13 @@ function CheckCurrentConfigAll { exit 1 fi - if [ "$SKIP_DELETION" != "" ] && [ $(arrayContains "${INITIATOR[$__type]}" "${SKIP_DELETION[@]}") -eq 0 ] && [ $(arrayContains "${TARGET[$__type]}" "${SKIP_DELETION[@]}") -eq 0 ]; then - Logger "Bogus skip deletion parameter." "CRITICAL" - exit 1 + if [ "$SKIP_DELETION" != "" ]; then + tmp="$SKIP_DELETION" + IFS=',' read -r -a SKIP_DELETION <<< "$tmp" + if [ $(arrayContains "${INITIATOR[$__type]}" "${SKIP_DELETION[@]}") -eq 0 ] && [ $(arrayContains "${TARGET[$__type]}" "${SKIP_DELETION[@]}") -eq 0 ]; then + Logger "Bogus skip deletion parameter [$SKIP_DELETION]." "CRITICAL" + exit 1 + fi fi } @@ -1808,26 +1841,40 @@ function CreateStateDirs { function _CheckLocksLocal { local lockfile="${1}" + local replicaType="${2}" - 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#*@} - kill -9 $lock_pid > /dev/null 2>&1 + local lockfileContent + local lockPid + local lockInstanceID + + if [ -s "$lockfile" ]; then + lockfileContent=$(cat $lockfile) + Logger "Master lock pid present: $lockfileContent" "DEBUG" + lockPid=${lockfileContent%@*} + if [ $(IsInteger $lockPid) -ne 1 ]; then + Logger "Invalid pid [$lockPid] in local replica." "CRITICAL" + exit 1 + fi + lockInstanceID=${lockfileContent#*@} + if [ "$lockInstanceID" == "" ]; then + Logger "Invalid instance id [$lockInstanceID] in local replica." "CRITICAL" + exit 1 + + Logger "Local $replicaType lock is: [$lockPid@$lockInstanceID]." "DEBUG" + + fi + kill -0 $lockPid > /dev/null 2>&1 if [ $? != 0 ]; then - Logger "There is a dead osync lock in [$lockfile]. Instance [$lock_pid] no longer running. Resuming." "NOTICE" - #rm "$lockfile" - #if [ $? != 0 ]; then - # Logger "Cannot remove lock in [$lockfile]." "CRITICAL" - # exit 1 - #fi + Logger "There is a local dead osync lock [$lockPid@$lockInstanceID] that is no longer running. Resuming." "NOTICE" + if [ "$replicaType" == "${INITIATOR[$__type]}" ]; then + # REPLICA_OVERWRITE_LOCK disables noclobber option in WriteLock functions + INITIATOR_OVERWRITE_LOCK=true + elif [ "$replicaType" == "${TARGET[$__type]}" ]; then + TARGET_OVERWRITE_LOCK=true + fi else - Logger "There is already a local instance of osync running [$lock_pid] for this replica. Cannot start." "CRITICAL" + Logger "There is already a local instance [$lockPid@$lockInstanceID] of osync running for this replica. Cannot start." "CRITICAL" exit 1 fi fi @@ -1837,9 +1884,9 @@ function _CheckLocksRemote { local lockfile="${1}" local cmd - local lock_pid - local lock_instance_id - local lockfile_content + local lockPid + local lockInstanceID + local lockfileContent CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost @@ -1848,34 +1895,42 @@ function _CheckLocksRemote { Logger "cmd: $cmd" "DEBUG" eval "$cmd" 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 + Logger "Cannot check remote replica lock." "CRITICAL" + exit 1 fi - lock_pid=${lockfile_content%@*} - lock_instance_id=${lockfile_content#*@} + if [ -s "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then + lockfileContent="$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" - if [ "$lock_pid" != "" ] && [ "$lock_instance_id" != "" ]; then - Logger "Remote lock is: $lock_pid@$lock_instance_id" "DEBUG" + lockPid=${lockfileContent%@*} + if [ $(IsInteger $lockPid) -ne 1 ]; then + Logger "Invalid pid [$lockPid] in remote replica lock." "CRITICAL" + exit 1 + fi + lockInstanceID=${lockfileContent#*@} + if [ "$lockInstanceID" == "" ]; then + Logger "Invalid instance id [$lockInstanceID] in remote replica." "CRITICAL" + exit 1 + fi - kill -0 $lock_pid > /dev/null 2>&1 + Logger "Remote lock is: [$lockPid@$lockInstanceID]" "DEBUG" + + kill -0 $lockPid > /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" + if [ "$lockInstanceID" == "$INSTANCE_ID" ]; then + Logger "There is a remote dead osync lock [$lockPid@lockInstanceID] on target replica that corresponds to this initiator INSTANCE_ID. Pid [$lockPid] no longer running. Resuming." "NOTICE" + TARGET_OVERWRITE_LOCK=true 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" + Logger "There is a remote (maybe dead) osync lock [$lockPid@$lockInstanceID] on target replica that does not correspond to this initiator INSTANCE_ID. Forcing resume." "WARN" + TARGET_OVERWRITE_LOCK=true 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" + Logger "There is a remote (maybe dead) osync lock [$lockPid@$lockInstanceID] on target replica that does not correspond to this initiator 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" + Logger "There is already a local instance of osync that locks target replica [$lockPid@$lockInstanceID]. Cannot start." "CRITICAL" exit 1 fi fi @@ -1896,10 +1951,10 @@ function CheckLocks { exit 1 fi else - _CheckLocksLocal "${INITIATOR[$__lockFile]}" & + _CheckLocksLocal "${INITIATOR[$__lockFile]}" "${INITIATOR[$__type]}" & pids="$!" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckLocksLocal "${TARGET[$__lockFile]}" & + _CheckLocksLocal "${TARGET[$__lockFile]}" "${INITIATOR[$__type]}" & pids="$pids;$!" else _CheckLocksRemote "${TARGET[$__lockFile]}" & @@ -1917,9 +1972,13 @@ function CheckLocks { function _WriteLockFilesLocal { local lockfile="${1}" local replicaType="${2}" + local overwrite="${3:-false}" + ( - set -o noclobber + if [ $overwrite == true ]; then + set -o noclobber + fi $COMMAND_SUDO echo "$SCRIPT_PID@$INSTANCE_ID" > "$lockfile" 2> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-$replicaType.$SCRIPT_PID" ) if [ $? != 0 ]; then @@ -1934,18 +1993,22 @@ function _WriteLockFilesLocal { function _WriteLockFilesRemote { local lockfile="${1}" local replicaType="${2}" + local overwrite="${3-false}" + local cmd CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "( set -o noclobber; echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\")" > /dev/null 2> $RUN_DIR/$PROGRAM._WriteLockFilesRemote.$replicaType.$SCRIPT_PID' + cmd=$SSH_CMD' "( if [ $overwrite == true ]; then set -o noclobber; fi; echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\")" > /dev/null 2> $RUN_DIR/$PROGRAM._WriteLockFilesRemote.$replicaType.$SCRIPT_PID' + #WIP + #cmd=$SSH_CMD' "( set -o noclobber; echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\")" > /dev/null 2> $RUN_DIR/$PROGRAM._WriteLockFilesRemote.$replicaType.$SCRIPT_PID' Logger "cmd: $cmd" "DEBUG" eval "$cmd" if [ $? != 0 ]; then Logger "Could not create lock file on remote $replicaType in [$lockfile]." "CRITICAL" - Loggxer "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID)" "NOTICE" + Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID)" "NOTICE" return 1 else Logger "Locked remote $replicaType replica in [$lockfile]." "DEBUG" @@ -1959,14 +2022,14 @@ function WriteLockFiles { local pidArray local pid - _WriteLockFilesLocal "${INITIATOR[$__lockFile]}" "${INITIATOR[$__type]}"& + _WriteLockFilesLocal "${INITIATOR[$__lockFile]}" "${INITIATOR[$__type]}" $INITIATOR_LOCK_OVERWRITE & initiatorPid="$!" if [ "$REMOTE_OPERATION" != "yes" ]; then - _WriteLockFilesLocal "${TARGET[$__lockFile]}" "${TARGET[$__type]}" & + _WriteLockFilesLocal "${TARGET[$__lockFile]}" "${TARGET[$__type]}" $TARGET_LOCK_OVERWRITE & targetPid="$!" else - _WriteLockFilesRemote "${TARGET[$__lockFile]}" "${TARGET[$__type]}" & + _WriteLockFilesRemote "${TARGET[$__lockFile]}" "${TARGET[$__type]}" $TARGET_LOCK_OVERWRITE & targetPid="$!" fi @@ -2061,10 +2124,10 @@ function treeList { local replicaType="${2}" # replica type: initiator, target local treeFilename="${3}" # filename to output tree (will be prefixed with $replicaType) + local escapedReplicaPath local rsyncCmd - escapedReplicaPath=$(EscapeSpaces "$replicaPath") Logger "Creating $replicaType replica file list [$replicaPath]." "NOTICE" @@ -2102,6 +2165,17 @@ function deleteList { local cmd + local failedDeletionListFromReplica + + if [ "$replicaType" == "${INITIATOR[$__type]}" ]; then + failedDeletionListFromReplica="${TARGET[$__type]}" + elif [ "$replicaType" == "${TARGET[$__type]}" ]; then + failedDeletionListFromReplica="${INITIATOR[$__type]}" + else + Logger "Bogus replicaType in [${FUNCNAME[0]}]." "CRITICAL" + exit 1 + fi + Logger "Creating $replicaType replica deleted file list." "NOTICE" if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeAfterFileNoSuffix]}" ]; then ## Same functionnality, comm is much faster than grep but is not available on every platform @@ -2117,10 +2191,10 @@ function deleteList { retval=$? # Add delete failed file list to current delete list and then empty it - if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" ]; then - cat "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}" + if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$failedDeletionListFromReplica${INITIATOR[$__failedDeletedListFile]}" ]; then + cat "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$failedDeletionListFromReplica${INITIATOR[$__failedDeletedListFile]}" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}" if [ $? == 0 ]; then - rm -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" + rm -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$failedDeletionListFromReplica${INITIATOR[$__failedDeletedListFile]}" else Logger "Cannot add failed deleted list to current deleted list for replica [$replicaType]." "ERROR" fi @@ -2476,7 +2550,7 @@ function _deleteRemote { exit 1 fi -$SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$deletionListFromReplica${INITIATOR[$__deletedListFile]}")" REPLICA_DIR="$(EscapeSpaces "$replicaDir")" SOFT_DELETE=$SOFT_DELETE DELETION_DIR="$(EscapeSpaces "$deletionDir")" FAILED_DELETE_LIST="$failedDeleteList" SUCCESS_DELETE_LIST="$successDeleteList" 'bash -s' << 'ENDSSH' >> "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 +$SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _LOGGER_VERBOSE=$_LOGGER_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$deletionListFromReplica${INITIATOR[$__deletedListFile]}")" REPLICA_DIR="$(EscapeSpaces "$replicaDir")" SOFT_DELETE=$SOFT_DELETE DELETION_DIR="$(EscapeSpaces "$deletionDir")" FAILED_DELETE_LIST="$failedDeleteList" SUCCESS_DELETE_LIST="$successDeleteList" 'bash -s' << 'ENDSSH' >> "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 ## The following lines are executed remotely function _logger { @@ -2503,7 +2577,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ _logger "$prefix$value" return elif [ "$level" == "VERBOSE" ]; then - if [ $_VERBOSE == true ]; then + if [ $_LOGGER_VERBOSE == true ]; then _logger "$prefix$value" fi return @@ -2547,12 +2621,12 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ # In order to keep full path on soft deletion, create parent directories before move parentdir="$(dirname "$files")" if [ "$parentdir" != "." ]; then + Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETION_DIR/$parentdir]." "VERBOSE" $COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETION_DIR/$parentdir" $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETION_DIR/$parentdir" - Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETION_DIR/$parentdir]." "VERBOSE" else - $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETION_DIR" Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETION_DIR]." "VERBOSE" + $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETION_DIR" fi if [ $? != 0 ]; then Logger "Cannot move [$REPLICA_DIR$files] to deletion directory." "ERROR" @@ -2566,10 +2640,9 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ else if [ $_DRYRUN == false ]; then if [ -e "$REPLICA_DIR$files" ]; then - $COMMAND_SUDO rm -rf "$REPLICA_DIR$files" - $result=$? Logger "Deleting [$REPLICA_DIR$files]." "VERBOSE" - if [ $result != 0 ]; then + $COMMAND_SUDO rm -rf "$REPLICA_DIR$files" + if [ $? != 0 ]; then Logger "Cannot delete [$REPLICA_DIR$files]." "ERROR" echo "$files" >> "$FAILED_DELETE_LIST" else @@ -2816,8 +2889,7 @@ function Sync { ## Step 2 if [ "$resumeInitiator" == "${SYNC_ACTION[2]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[2]}" ]; then - #TODO(high) only -X and -A (xattr & acl) should trigger this - if [ "$RSYNC_ATTR_ARGS" != "" ]; then + if [[ "$RSYNC_ATTR_ARGS" == *"-X"* ]] || [[ "$RSYNC_ATTR_ARGS" == *"-A"* ]]; then syncAttrs "${INITIATOR[$__replicaDir]}" "$TARGET_SYNC_DIR" WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING if [ $? != 0 ]; then @@ -2990,7 +3062,7 @@ function _SoftDeleteLocal { Logger "Removing files older than $changeTime days on $replicaType replica for $deletionType deletion." "NOTICE" fi - if [ $_VERBOSE == true ]; then + if [ $_LOGGER_VERBOSE == true ]; then # Cannot launch log function from xargs, ugly hack $COMMAND_SUDO $FIND_CMD "$replicaDeletionPath/" -type f -ctime +$changeTime -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)" "VERBOSE" @@ -3040,7 +3112,7 @@ function _SoftDeleteRemote { Logger "Removing files older than $changeTime days on $replicaType replica for $deletionType deletion." "NOTICE" fi - if [ $_VERBOSE == true ]; then + if [ $_LOGGER_VERBOSE == true ]; then # Cannot launch log function from xargs, ugly hack cmd=$SSH_CMD' "if [ -d \"'$replicaDeletionPath'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replicaDeletionPath'/\" -type f -ctime +'$changeTime' -print0 | xargs -0 -I {} echo Will delete file {} && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replicaDeletionPath'/\" -type d -empty -ctime '$changeTime' -print0 | xargs -0 -I {} echo Will delete directory {}; else echo \"The $replicaType replica dir [$replicaDeletionPath] does not exist. Skipping cleaning of old files.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" @@ -3287,7 +3359,7 @@ function Init { ## Set sync only function arguments for rsync SYNC_OPTS="-u" - if [ $_VERBOSE == true ] || [ $_SUMMARY == true ]; then + if [ $_LOGGER_VERBOSE == true ] || [ $_SUMMARY == true ]; then SYNC_OPTS=$SYNC_OPTS" -i" fi @@ -3300,8 +3372,8 @@ function Init { ## Conflict options if [ "$CONFLICT_BACKUP" != "no" ]; then - INITIATOR_BACKUP="--backup --backup-dir=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__backupDir]}\"" - TARGET_BACKUP="--backup --backup-dir=\"${TARGET[$__replicaDir]}${TARGET[$__backupDir]}\"" + INITIATOR_BACKUP="--backup --backup-dir=\"${INITIATOR[$__backupDir]}\"" + TARGET_BACKUP="--backup --backup-dir=\"${TARGET[$__backupDir]}\"" 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)" @@ -3449,11 +3521,11 @@ for i in "$@"; do opts=$opts" --dry" ;; --silent) - _SILENT=true + _LOGGER_SILENT=true opts=$opts" --silent" ;; --verbose) - _VERBOSE=true + _LOGGER_VERBOSE=true opts=$opts" --verbose" ;; --stats) @@ -3501,20 +3573,17 @@ for i in "$@"; do ;; --skip-deletion=*) opts=$opts" --skip-deletion=\"${i##*=}\"" - IFS=',' read -r -a SKIP_DELETION <<< ${i##*=} + SKIP_DELETION=${##*=} ;; --on-changes) sync_on_changes=true _NOLOCKS=true _LOGGER_PREFIX="date" - _LOGGER_STDERR=true ;; --no-locks) _NOLOCKS=true ;; --errors-only) - #TODO: let err_only only output to stderr - #_LOGGER_STDERR=true _LOGGER_ERR_ONLY=true ;; --summary) @@ -3569,6 +3638,18 @@ opts="${opts# *}" HARD_MAX_EXEC_TIME=0 fi + if [ "$PRESERVE_ACL" == "" ]; then + PRESERVE_ACL="yes" + fi + + if [ "$PRESERVE_XATTR" == "" ]; then + PRESERVE_XATTR="yes" + fi + + if [ "$PATH_SEPARATOR_CHAR" == "" ]; then + PATH_SEPARATOR_CHAR=";" + fi + MIN_WAIT=30 else ConfigFile="${1}"