From a6ab8b686e21103a159819878d164ec8e820a0d4 Mon Sep 17 00:00:00 2001 From: deajan Date: Mon, 17 Oct 2016 17:40:37 +0200 Subject: [PATCH] Improved upgrade script --- dev/debug_osync.sh | 692 +++++++++++++++++++++-------------------- install.sh | 2 +- osync.sh | 592 ++++++++++++++++++----------------- upgrade-v1.0x-v1.2x.sh | 229 ++++++++++---- 4 files changed, 838 insertions(+), 677 deletions(-) diff --git a/dev/debug_osync.sh b/dev/debug_osync.sh index 7011cf5..63eb423 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-beta -PROGRAM_BUILD=2016083004 +PROGRAM_VERSION=1.2-beta2 +PROGRAM_BUILD=2016101701 IS_STABLE=no # Execution order #__WITH_PARANOIA_DEBUG @@ -26,18 +26,18 @@ IS_STABLE=no # CheckLocks yes #__WITH_PARANOIA_DEBUG # WriteLockFiles yes #__WITH_PARANOIA_DEBUG # Sync no #__WITH_PARANOIA_DEBUG -# tree_list yes #__WITH_PARANOIA_DEBUG -# tree_list yes #__WITH_PARANOIA_DEBUG -# delete_list yes #__WITH_PARANOIA_DEBUG -# delete_list yes #__WITH_PARANOIA_DEBUG -# sync_attrs no #__WITH_PARANOIA_DEBUG -# _get_file_ctime_mtime yes #__WITH_PARANOIA_DEBUG -# sync_update no #__WITH_PARANOIA_DEBUG -# sync_update no #__WITH_PARANOIA_DEBUG -# deletion_propagation yes #__WITH_PARANOIA_DEBUG -# deletion_propagation yes #__WITH_PARANOIA_DEBUG -# tree_list yes #__WITH_PARANOIA_DEBUG -# tree_list yes #__WITH_PARANOIA_DEBUG +# treeList yes #__WITH_PARANOIA_DEBUG +# treeList yes #__WITH_PARANOIA_DEBUG +# deleteList yes #__WITH_PARANOIA_DEBUG +# deleteList yes #__WITH_PARANOIA_DEBUG +# syncAttrs no #__WITH_PARANOIA_DEBUG +# _getFileCtimeMtime yes #__WITH_PARANOIA_DEBUG +# syncUpdate no #__WITH_PARANOIA_DEBUG +# syncUpdate no #__WITH_PARANOIA_DEBUG +# deletionPropagation yes #__WITH_PARANOIA_DEBUG +# deletionPropagation yes #__WITH_PARANOIA_DEBUG +# treeList yes #__WITH_PARANOIA_DEBUG +# treeList yes #__WITH_PARANOIA_DEBUG # SoftDelete yes #__WITH_PARANOIA_DEBUG # RunAfterHook yes #__WITH_PARANOIA_DEBUG # UnlockReplicas yes #__WITH_PARANOIA_DEBUG @@ -45,7 +45,7 @@ IS_STABLE=no #### MINIMAL-FUNCTION-SET BEGIN #### -## FUNC_BUILD=2016090701 +## FUNC_BUILD=2016091601 ## 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: @@ -148,9 +148,9 @@ function _Logger { local evalue="${3}" # What to log to stderr echo -e "$lvalue" >> "$LOG_FILE" - CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue" + CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue" #WIP - if [ $_LOGGER_STDERR == true ]; then + if [ $_LOGGER_STDERR == true ] && [ "$evalue" != "" ]; then cat <<< "$evalue" 1>&2 elif [ "$_SILENT" == false ]; then echo -e "$svalue" @@ -312,7 +312,7 @@ function SendAlert { fi # - if [ "$_QUICK_SYNC" == "2" ]; then + if [ "$_QUICK_SYNC" -eq 2 ]; then Logger "Current task is a quicksync task. Will not send any alert." "NOTICE" return 0 fi @@ -868,8 +868,6 @@ function CleanUp { fi } -#### MINIMAL-FUNCTION-SET END #### - # obsolete, use StripQuotes function SedStripQuotes { echo $(echo $1 | sed "s/^\([\"']\)\(.*\)\1\$/\2/g") @@ -995,6 +993,8 @@ function GetLocalOS { Logger "Local OS: [$local_os_var]." "DEBUG" } +#### MINIMAL-FUNCTION-SET END #### + function GetRemoteOS { __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG @@ -1177,7 +1177,7 @@ function CheckConnectivityRemoteHost { WaitForTaskCompletion $! 60 180 ${FUNCNAME[0]} true $KEEP_LOGGING retval=$? if [ $retval != 0 ]; then - Logger "Cannot ping [$REMOTE_HOST]. Return code [$retval]." "ERROR" + Logger "Cannot ping [$REMOTE_HOST]. Return code [$retval]." "WARN" return $retval fi fi @@ -1207,7 +1207,7 @@ function CheckConnectivity3rdPartyHosts { done if [ $remote_3rd_party_success == false ]; then - Logger "No remote 3rd party host responded to ping. No internet ?" "ERROR" + Logger "No remote 3rd party host responded to ping. No internet ?" "WARN" return 1 else return 0 @@ -1329,7 +1329,8 @@ function RsyncPatterns { if [ "$RSYNC_INCLUDE_FROM" != "" ]; then RsyncPatternsFromAdd "include" "$RSYNC_INCLUDE_FROM" fi - elif [ "$RSYNC_PATTERN_FIRST" == "include" ]; then + # Use default include first for quicksync runs + elif [ "$RSYNC_PATTERN_FIRST" == "include" ] || [ $_QUICK_SYNC -eq 2 ]; then if [ "$RSYNC_INCLUDE_PATTERN" != "" ]; then RsyncPatternsAdd "include" "$RSYNC_INCLUDE_PATTERN" fi @@ -1534,6 +1535,19 @@ function PrintIFS { printf "IFS is: %q" "$IFS" } +# Process debugging +# Recursive function to get all parents from a pid +function ParentPid { + local pid="${1}" # Pid to analyse + local parent + + parent=$(ps -p $pid -o ppid=) + echo "$pid is a child of $parent" + if [ $parent -gt 0 ]; then + ParentPid $parent + fi +} + ## END Generic functions _LOGGER_PREFIX="time" @@ -1600,7 +1614,7 @@ function TrapQuit { } function CheckEnvironment { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG if [ "$REMOTE_OPERATION" == "yes" ]; then if ! type ssh > /dev/null 2>&1 ; then @@ -1616,7 +1630,7 @@ function CheckEnvironment { } function CheckCurrentConfig { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG # Check all variables that should contain "yes" or "no" declare -a yes_no_vars=(CREATE_DIRS SUDO_EXEC SSH_COMPRESSION SSH_IGNORE_KNOWN_HOSTS REMOTE_HOST_PING PRESERVE_PERMISSIONS PRESERVE_OWNER PRESERVE_GROUP PRESERVE_EXECUTABILITY 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 RUN_AFTER_CMD_ON_ERROR) @@ -1634,7 +1648,7 @@ function CheckCurrentConfig { } function CheckCurrentConfigAll { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG if [ "$INSTANCE_ID" == "" ]; then Logger "No INSTANCE_ID defined in config file." "CRITICAL" @@ -1662,7 +1676,7 @@ function CheckCurrentConfigAll { function _CheckReplicaPathsLocal { local replica_path="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG if [ ! -w "$replica_path" ]; then Logger "Local replica path [$replica_path] is not writable." "CRITICAL" @@ -1688,7 +1702,7 @@ function _CheckReplicaPathsLocal { function _CheckReplicaPathsRemote { local replica_path="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd @@ -1714,13 +1728,13 @@ function _CheckReplicaPathsRemote { } function CheckReplicaPaths { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local pids # Use direct comparaison before having a portable realpath implementation #INITIATOR_SYNC_DIR_CANN=$(realpath "${INITIATOR[$__replicaDir]}") #TODO(verylow): investigate realpath & readlink issues on MSYS and busybox here - #TARGET_SYNC_DIR_CANN=$(realpath "${TARGET[$__replicaDir]}) + #TARGET_SYNC_DIR_CANN=$(realpath "${TARGET[$__replicaDir]}") if [ "$REMOTE_OPERATION" != "yes" ]; then if [ "${INITIATOR[$__replicaDir]}" == "${TARGET[$__replicaDir]}" ]; then @@ -1747,7 +1761,7 @@ function CheckReplicaPaths { function _CheckDiskSpaceLocal { local replica_path="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local disk_space @@ -1761,9 +1775,9 @@ function _CheckDiskSpaceLocal { function _CheckDiskSpaceRemote { local replica_path="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG - Logger "Checking minimum disk space on target [$replica_path]." "NOTICE" + Logger "Checking remote minimum disk space in [$replica_path]." "NOTICE" local cmd local disk_space @@ -1786,7 +1800,7 @@ function _CheckDiskSpaceRemote { } function CheckDiskSpace { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local pids @@ -1810,7 +1824,7 @@ function CheckDiskSpace { function _CreateStateDirsLocal { local replica_state_dir="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __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 @@ -1824,7 +1838,7 @@ function _CreateStateDirsLocal { function _CreateStateDirsRemote { local replica_state_dir="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd @@ -1842,7 +1856,7 @@ function _CreateStateDirsRemote { } function CreateStateDirs { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local pids @@ -1864,7 +1878,7 @@ function CreateStateDirs { function _CheckLocksLocal { local lockfile="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local lockfile_content local lock_pid @@ -1887,7 +1901,7 @@ function _CheckLocksLocal { function _CheckLocksRemote { local lockfile="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd local lock_pid @@ -1935,7 +1949,7 @@ function _CheckLocksRemote { } function CheckLocks { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local pids @@ -1970,22 +1984,22 @@ function CheckLocks { function _WriteLockFilesLocal { local lockfile="${1}" - local replica_type="${2}" - __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + local replicaType="${2}" + __CheckArguments 2 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG $COMMAND_SUDO echo "$SCRIPT_PID@$INSTANCE_ID" > "$lockfile" if [ $? != 0 ]; then - Logger "Could not create lock file on local $replica_type in [$lockfile]." "CRITICAL" + Logger "Could not create lock file on local $replicaType in [$lockfile]." "CRITICAL" exit 1 else - Logger "Locked local $replica_type replica in [$lockfile]." "DEBUG" + Logger "Locked local $replicaType replica in [$lockfile]." "DEBUG" fi } function _WriteLockFilesRemote { local lockfile="${1}" - local replica_type="${2}" - __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + local replicaType="${2}" + __CheckArguments 2 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd @@ -1996,15 +2010,15 @@ function _WriteLockFilesRemote { Logger "cmd: $cmd" "DEBUG" eval "$cmd" if [ $? != 0 ]; then - Logger "Could not create lock file on remote $replica_type in [$lockfile]." "CRITICAL" + Logger "Could not create lock file on remote $replicaType in [$lockfile]." "CRITICAL" exit 1 else - Logger "Locked remote $replica_type replica in [$lockfile]." "DEBUG" + Logger "Locked remote $replicaType replica in [$lockfile]." "DEBUG" fi } function WriteLockFiles { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local initiatorPid local targetPid @@ -2043,7 +2057,7 @@ function WriteLockFiles { function _UnlockReplicasLocal { local lockfile="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG if [ -f "$lockfile" ]; then $COMMAND_SUDO rm "$lockfile" @@ -2057,7 +2071,7 @@ function _UnlockReplicasLocal { function _UnlockReplicasRemote { local lockfile="${1}" - __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd= @@ -2076,7 +2090,7 @@ function _UnlockReplicasRemote { } function UnlockReplicas { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local pids @@ -2107,64 +2121,69 @@ function UnlockReplicas { ###### 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. + ## It seems this only happens when trying to execute an rsync command through weval $rsyncCmd 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) +function treeList { + local replicaPath="${1}" # path to the replica for which a tree needs to be constructed + local replicaType="${2}" # replica type: initiator, target + local treeFilename="${3}" # filename to output tree (will be prefixed with $replicaType) - local escaped_replica_path - local rsync_cmd + local escapedReplicaPath + local rsyncCmd - __CheckArguments 3 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG - escaped_replica_path=$(EscapeSpaces "$replica_path") + escapedReplicaPath=$(EscapeSpaces "$replicaPath") - Logger "Creating $replica_type replica file list [$replica_path]." "NOTICE" - if [ "$REMOTE_OPERATION" == "yes" ] && [ "$replica_type" == "${TARGET[$__type]}" ]; then + Logger "Creating $replicaType replica file list [$replicaPath]." "NOTICE" + if [ "$REMOTE_OPERATION" == "yes" ] && [ "$replicaType" == "${TARGET[$__type]}" ]; 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\"" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS -L $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:\"$escapedReplicaPath\" 2> \"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.error.$SCRIPT_PID\" | grep \"^-\|^d\|^l\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$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\"" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS -L $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --list-only \"$replicaPath\" 2> \"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.error.$SCRIPT_PID\" | grep \"^-\|^d\|^l\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID\"" fi - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - ## Redirect commands stderr here to get rsync stderr output in logfile with eval "$rsync_cmd" 2>> "$LOG_FILE" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + #TODO: check the following statement + ## Redirect commands stderr here to get rsync stderr output in logfile with eval "$rsyncCmd" 2>> "$LOG_FILE" ## When log writing fails, $! is empty and WaitForTaskCompletion fails. Removing the 2>> log - eval "$rsync_cmd" + eval "$rsyncCmd" retval=$? + + if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID" ]; then + mv -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID" "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType$treeFilename" + fi + ## 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[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$tree_filename" + if ([ $retval == 0 ] || [ $retval == 24 ]) then return $? + elif [ $retval == 23 ]; then + Logger "Some files could not be listed in [$replicaPath]. Check for failing symlinks." "ERROR" + Logger "Command output\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.error.$SCRIPT_PID)" "NOTICE" + return 0 else - Logger "Cannot create replica file list in [$replica_path]." "CRITICAL" + Logger "Cannot create replica file list in [$replicaPath]." "CRITICAL" return $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 - 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 +# deleteList(replicaType): Creates a list of files vanished from last run on replica $1 (initiator/target) +function deleteList { + local replicaType="${1}" # replica type: initiator, target + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd - Logger "Creating $replica_type replica deleted file list." "NOTICE" - if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type${INITIATOR[$__treeAfterFile]}_NO_SUFFIX" ]; then + 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 if type comm > /dev/null 2>&1 ; then - cmd="comm -23 \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type${INITIATOR[$__treeAfterFileNoSuffix]}\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$tree_file_current\" > \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_list_file\"" + cmd="comm -23 \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeAfterFileNoSuffix]}\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeCurrentFile]}\" > \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}\"" else ## The || : forces the command to have a good result - cmd="(grep -F -x -v -f \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$tree_file_current\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type${INITIATOR[$__treeAfterFileNoSuffix]}\" || :) > \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_list_file\"" + cmd="(grep -F -x -v -f \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeCurrentFile]}\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeAfterFileNoSuffix]}\" || :) > \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}\"" fi Logger "CMD: $cmd" "DEBUG" @@ -2172,51 +2191,54 @@ function delete_list { retval=$? # Add delete failed file list to current delete list and then empty it - if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_failed_list_file" ]; then - cat "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_failed_list_file" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_list_file" - rm -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_failed_list_file" + 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 [ $? == 0 ]; then + rm -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" + else + Logger "Cannot add failed deleted list to current deleted list for replica [$replicaType]." "ERROR" + fi fi - return $retval else - touch "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_list_file" + touch "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}" 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 +function _getFileCtimeMtimeLocal { + local replicaPath="${1}" # Contains replica path + local replicaType="${2}" # Initiator / Target + local fileList="${3}" # Contains list of files to get time attrs + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG - echo -n "" > "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" - while read -r file; do $STAT_CTIME_MTIME_CMD "$replica_path$file" | sort >> "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID"; done < "$file_list" + echo -n "" > "$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID" + while read -r file; do $STAT_CTIME_MTIME_CMD "$replicaPath$file" | sort >> "$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID"; done < "$fileList" if [ $? != 0 ]; then - Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL" - if [ -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)" "VERBOSE" + Logger "Getting file attributes failed [$retval] on $replicaType. Stopping execution." "CRITICAL" + if [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID" ]; then + Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID)" "VERBOSE" fi exit 1 fi } -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 +function _getFileCtimeMtimeRemote { + local replicapath="${1}" # Contains replica path + local replicaType="${2}" + local fileList="${3}" + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd - cmd='cat "'$file_list'" | '$SSH_CMD' "while read -r file; do '$REMOTE_STAT_CTIME_MTIME_CMD' \"'$replica_path'\$file\"; done | sort" > "'$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID'"' + cmd='cat "'$fileList'" | '$SSH_CMD' "while read -r file; do '$REMOTE_STAT_CTIME_MTIME_CMD' \"'$replicaPath'\$file\"; done | sort" > "'$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID'"' Logger "CMD: $cmd" "DEBUG" eval "$cmd" if [ $? != 0 ]; then - Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL" - if [ -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)" "VERBOSE" + Logger "Getting file attributes failed [$retval] on $replicaType. Stopping execution." "CRITICAL" + if [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID" ]; then + Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID)" "VERBOSE" fi exit 1 fi @@ -2224,29 +2246,31 @@ function _get_file_ctime_mtime_remote { # 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}" - local delete_list_filename="${INITIATOR[$__deletedListFile]}" # Contains deleted list filename, will be prefixed with replica type - __CheckArguments 2 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG +function syncAttrs { + local initiatorReplica="${1}" + local targetReplica="${2}" + __CheckArguments 2 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG - local rsync_cmd + local rsyncCmd local retval - local esc_source_dir - local esc_dest_dir + local sourceDir + local destDir + local escSourceDir + local escDestDir + local destReplica Logger "Getting list of files that need updates." "NOTICE" if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i -n -8 $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 &" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i -n -8 $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiatorReplica\" $REMOTE_USER@$REMOTE_HOST:\"$targetReplica\" >> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i -n -8 $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 &" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i -n -8 $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiatorReplica\" \"$targetReplica\" >> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1 &" fi - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - eval "$rsync_cmd" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING retval=$? @@ -2260,6 +2284,7 @@ function sync_attrs { if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then Logger "List:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "VERBOSE" fi + #TODO: Apply SC2002: unnecessary cat 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" @@ -2268,225 +2293,227 @@ function sync_attrs { fi Logger "Getting ctimes for pending files on initiator." "NOTICE" - _get_file_ctime_mtime_local "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & + _getFileCtimeMtimeLocal "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & pids="$!" Logger "Getting ctimes for pending files on target." "NOTICE" if [ "$REMOTE_OPERATION" != "yes" ]; then - _get_file_ctime_mtime_local "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & + _getFileCtimeMtimeLocal "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & pids="$pids;$!" else - _get_file_ctime_mtime_remote "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & + _getFileCtimeMtimeRemote "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & pids="$pids;$!" fi WaitForTaskCompletion $pids 1800 0 ${FUNCNAME[0]} true $KEEP_LOGGING - # If target gets updated first, then sync_attr must update initiator's attrs first + # If target gets updated first, then sync_attr must update initiators attrs first # For join, remove leading replica paths sed -i'.tmp' "s;^${INITIATOR[$__replicaDir]};;g" "$RUN_DIR/$PROGRAM.ctime_mtime.${INITIATOR[$__type]}.$SCRIPT_PID" sed -i'.tmp' "s;^${TARGET[$__replicaDir]};;g" "$RUN_DIR/$PROGRAM.ctime_mtime.${TARGET[$__type]}.$SCRIPT_PID" if [ "$CONFLICT_PREVALANCE" == "${TARGET[$__type]}" ]; then - local source_dir="${INITIATOR[$__replicaDir]}" - esc_source_dir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") - local dest_dir="${TARGET[$__replicaDir]}" - esc_dest_dir=$(EscapeSpaces "${TARGET[$__replicaDir]}") - local dest_replica="${TARGET[$__type]}" + sourceDir="${INITIATOR[$__replicaDir]}" + escSourceDir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") + destDir="${TARGET[$__replicaDir]}" + escDestDir=$(EscapeSpaces "${TARGET[$__replicaDir]}") + destReplica="${TARGET[$__type]}" join -j 1 -t ';' -o 1.1,1.2,2.2 "$RUN_DIR/$PROGRAM.ctime_mtime.${INITIATOR[$__type]}.$SCRIPT_PID" "$RUN_DIR/$PROGRAM.ctime_mtime.${TARGET[$__type]}.$SCRIPT_PID" | awk -F';' '{if ($2 > $3) print $1}' > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID" else - local source_dir="${TARGET[$__replicaDir]}" - esc_source_dir=$(EscapeSpaces "${TARGET[$__replicaDir]}") - local dest_dir="${INITIATOR[$__replicaDir]}" - esc_dest_dir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") - local dest_replica="${INITIATOR[$__type]}" + sourceDir="${TARGET[$__replicaDir]}" + escSourceDir=$(EscapeSpaces "${TARGET[$__replicaDir]}") + destDir="${INITIATOR[$__replicaDir]}" + escDestDir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") + destReplica="${INITIATOR[$__type]}" join -j 1 -t ';' -o 1.1,1.2,2.2 "$RUN_DIR/$PROGRAM.ctime_mtime.${TARGET[$__type]}.$SCRIPT_PID" "$RUN_DIR/$PROGRAM.ctime_mtime.${INITIATOR[$__type]}.$SCRIPT_PID" | awk -F';' '{if ($2 > $3) print $1}' > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID" fi if [ $(wc -l < "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID") -eq 0 ]; then - Logger "Updating file attributes on $dest_replica not required" "NOTICE" + Logger "Updating file attributes on $destReplica not required" "NOTICE" return 0 fi - Logger "Updating file attributes on $dest_replica." "NOTICE" + Logger "Updating file attributes on $destReplica." "NOTICE" if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost # No rsync args (hence no -r) because files are selected with --from-file - if [ "$dest_replica" == "${INITIATOR[$__type]}" ]; then - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}$delete_list_filename\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_dir\" \"$dest_dir\" >> $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID 2>&1 &" + if [ "$destReplica" == "${INITIATOR[$__type]}" ]; then + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}${INITIATOR[$__deletedListFile]}\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" $REMOTE_USER@$REMOTE_HOST:\"$escSourceDir\" \"$destDir\" >> $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}$delete_list_filename\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" \"$source_dir\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir\" >> $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID 2>&1 &" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}${INITIATOR[$__deletedListFile]}\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" \"$sourceDir\" $REMOTE_USER@$REMOTE_HOST:\"$escDestDir\" >> $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID 2>&1 &" fi else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}$delete_list_filename\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" \"$source_dir\" \"$dest_dir\" >> $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID 2>&1 &" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}${INITIATOR[$__deletedListFile]}\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" \"$sourceDir\" \"$destDir\" >> $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID 2>&1 &" fi - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - eval "$rsync_cmd" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING retval=$? if [ $retval != 0 ] && [ $retval != 24 ]; then - Logger "Updating file attributes on $dest_replica [$retval]. Stopping execution." "CRITICAL" - if [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then - Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "NOTICE" + Logger "Updating file attributes on $destReplica [$retval]. Stopping execution." "CRITICAL" + if [ -f "$RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID" ]; then + Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID)" "NOTICE" fi exit 1 else - if [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then - Logger "List:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "VERBOSE" + if [ -f "$RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID" ]; then + Logger "List:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID)" "VERBOSE" fi - Logger "Successfully updated file attributes on $dest_replica replica." "NOTICE" + Logger "Successfully updated file attributes on $destReplica 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 +# syncUpdate(source replica, destination replica, delete_list_filename) +function syncUpdate { + local sourceReplica="${1}" # Contains replica type of source: initiator, target + local destinationReplica="${2}" # Contains replica type of destination: initiator, target + __CheckArguments 2 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG - local rsync_cmd + local rsyncCmd local retval - local esc_source_dir - local esc_dest_dir + local sourceDir + local escSourceDir + local destDir + local escDestDir + + local backupArgs - Logger "Updating $destination_replica replica." "NOTICE" - if [ "$source_replica" == "${INITIATOR[$__type]}" ]; then - local source_dir="${INITIATOR[$__replicaDir]}" - local dest_dir="${TARGET[$__replicaDir]}" - local backup_args="$TARGET_BACKUP" + Logger "Updating $destinationReplica replica." "NOTICE" + if [ "$sourceReplica" == "${INITIATOR[$__type]}" ]; then + sourceDir="${INITIATOR[$__replicaDir]}" + destDir="${TARGET[$__replicaDir]}" + backupArgs="$TARGET_BACKUP" - esc_source_dir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") - esc_dest_dir=$(EscapeSpaces "${TARGET[$__replicaDir]}") + escSourceDir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") + escDestDir=$(EscapeSpaces "${TARGET[$__replicaDir]}") else - local source_dir="${TARGET[$__replicaDir]}" - local dest_dir="${INITIATOR[$__replicaDir]}" - local backup_args="$INITIATOR_BACKUP" + sourceDir="${TARGET[$__replicaDir]}" + destDir="${INITIATOR[$__replicaDir]}" + backupArgs="$INITIATOR_BACKUP" - esc_source_dir=$(EscapeSpaces "${TARGET[$__replicaDir]}") - esc_dest_dir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") + escSourceDir=$(EscapeSpaces "${TARGET[$__replicaDir]}") + escDestDir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") fi if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - if [ "$source_replica" == "${INITIATOR[$__type]}" ]; then - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $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[$__replicaDir]}${INITIATOR[$__stateDir]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destination_replica$delete_list_filename\" \"$source_dir\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir\" >> $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1" + if [ "$sourceReplica" == "${INITIATOR[$__type]}" ]; then + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backupArgs --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$sourceReplica${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destinationReplica${INITIATOR[$__deletedListFile]}\" \"$sourceDir\" $REMOTE_USER@$REMOTE_HOST:\"$escDestDir\" >> $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID 2>&1" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $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[$__replicaDir]}${INITIATOR[$__stateDir]}/$destination_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$source_replica$delete_list_filename\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_dir\" \"$dest_dir\" >> $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backupArgs --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destinationReplica${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$sourceReplica${INITIATOR[$__deletedListFile]}\" $REMOTE_USER@$REMOTE_HOST:\"$escSourceDir\" \"$destDir\" >> $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID 2>&1" fi else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destination_replica$delete_list_filename\" \"$source_dir\" \"$dest_dir\" >> $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS $backupArgs --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$sourceReplica${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destinationReplica${INITIATOR[$__deletedListFile]}\" \"$sourceDir\" \"$destDir\" >> $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID 2>&1" fi - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - eval "$rsync_cmd" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" retval=$? if [ $retval != 0 ] && [ $retval != 24 ]; then - Logger "Updating $destination_replica replica failed. Stopping execution." "CRITICAL" - if [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then - Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE" + Logger "Updating $destinationReplica replica failed. Stopping execution." "CRITICAL" + if [ -f "$RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID" ]; then + Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID)" "NOTICE" fi exit 1 else - if [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then - Logger "List:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "VERBOSE" + if [ -f "$RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID" ]; then + Logger "List:\n$(cat $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID)" "VERBOSE" fi - Logger "Updating $destination_replica replica succeded." "NOTICE" + Logger "Updating $destinationReplica 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 +function _deleteLocal { + local replicaType="${1}" # Replica type + local replicaDir="${2}" # Full path to replica + local deletionDir="${3}" # deletion dir in format .[workdir]/deleted + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local parentdir - local previous_file="" + local previousFile="" local result - if [ ! -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN == false ]; then - $COMMAND_SUDO mkdir -p "$replica_dir$deletion_dir" + if [ ! -d "$replicaDir$deletionDir" ] && [ $_DRYRUN == false ]; then + $COMMAND_SUDO mkdir -p "$replicaDir$deletionDir" if [ $? != 0 ]; then - Logger "Cannot create local replica deletion directory in [$replica_dir$deletion_dir]." "ERROR" + Logger "Cannot create local replica deletion directory in [$replicaDir$deletionDir]." "ERROR" exit 1 fi fi while read -r files; do ## On every run, check wheter the next item is already deleted because it is included in a directory already deleted - if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then + if [[ "$files" != "$previousFile/"* ]] && [ "$files" != "" ]; then if [ "$SOFT_DELETE" != "no" ]; then if [ $_DRYRUN == false ]; then - if [ -e "$replica_dir$deletion_dir/$files" ]; then - rm -rf "${replica_dir:?}$deletion_dir/$files" + if [ -e "$replicaDir$deletionDir/$files" ]; then + rm -rf "${replicaDir:?}$deletionDir/$files" fi - if [ -e "$replica_dir$files" ]; then + if [ -e "$replicaDir$files" ]; then # In order to keep full path on soft deletion, create parent directories before move parentdir="$(dirname "$files")" if [ "$parentdir" != "." ]; then - mkdir -p "$replica_dir$deletion_dir/$parentdir" - Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir/$parentdir]." "VERBOSE" - mv -f "$replica_dir$files" "$replica_dir$deletion_dir/$parentdir" + mkdir -p "$replicaDir$deletionDir/$parentdir" + Logger "Moving deleted file [$replicaDir$files] to [$replicaDir$deletionDir/$parentdir]." "VERBOSE" + mv -f "$replicaDir$files" "$replicaDir$deletionDir/$parentdir" else - Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir]." "VERBOSE" - mv -f "$replica_dir$files" "$replica_dir$deletion_dir" + Logger "Moving deleted file [$replicaDir$files] to [$replicaDir$deletionDir]." "VERBOSE" + mv -f "$replicaDir$files" "$replicaDir$deletionDir" fi if [ $? != 0 ]; then - Logger "Cannot move [$replica_dir$files] to deletion directory." "ERROR" - echo "$files" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$deleted_failed_list_file" + Logger "Cannot move [$replicaDir$files] to deletion directory." "ERROR" + echo "$files" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" fi fi fi else if [ $_DRYRUN == false ]; then - if [ -e "$replica_dir$files" ]; then - rm -rf "$replica_dir$files" + if [ -e "$replicaDir$files" ]; then + rm -rf "$replicaDir$files" result=$? - Logger "Deleting [$replica_dir$files]." "VERBOSE" + Logger "Deleting [$replicaDir$files]." "VERBOSE" if [ $result != 0 ]; then - Logger "Cannot delete [$replica_dir$files]." "ERROR" - echo "$files" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$deleted_failed_list_file" + Logger "Cannot delete [$replicaDir$files]." "ERROR" + echo "$files" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" fi fi fi fi - previous_file="$files" + previousFile="$files" fi - done < "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$deleted_list_file" + done < "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}" } -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 +function _deleteRemote { + local replicaType="${1}" # Replica type + local replicaDir="${2}" # Full path to replica + local deletionDir="${3}" # deletion dir in format .[workdir]/deleted + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG + + local escDestDir + local rsyncCmd - local esc_dest_dir - local rsync_cmd + local escSourceFile ## 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[$__replicaDir]}${TARGET[$__stateDir]}")" - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -e \"$RSYNC_SSH_CMD\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$deleted_list_file\" $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" + escDestDir="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}")" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -e \"$RSYNC_SSH_CMD\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}\" $REMOTE_USER@$REMOTE_HOST:\"$escDestDir/\" >> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.precopy.$SCRIPT_PID 2>&1" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" 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 @@ -2495,7 +2522,7 @@ function _delete_remote { 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]}/$deleted_list_file")" REPLICA_DIR="$(EscapeSpaces "$replica_dir")" SOFT_DELETE=$SOFT_DELETE DELETE_DIR="$(EscapeSpaces "$deletion_dir")" FAILED_DELETE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$deleted_failed_list_file")" '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 _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}")" REPLICA_DIR="$(EscapeSpaces "$replicaDir")" SOFT_DELETE=$SOFT_DELETE DELETION_DIR="$(EscapeSpaces "$deletionDir")" FAILED_DELETE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/${INITIATOR[$__failedDeletedListFile]}")" 'bash -s' << 'ENDSSH' >> "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 ## The following lines are executed remotely function _logger { @@ -2541,36 +2568,36 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ > "$FAILED_DELETE_LIST" parentdir= - previous_file="" + previousFile="" - if [ ! -d "$REPLICA_DIR$DELETE_DIR" ] && [ $_DRYRUN == false ]; then - $COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR" + if [ ! -d "$REPLICA_DIR$DELETION_DIR" ] && [ $_DRYRUN == false ]; then + $COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETION_DIR" if [ $? != 0 ]; then - Logger "Cannot create remote replica deletion directory in [$REPLICA_DIR$DELETE_DIR]." "ERROR" + Logger "Cannot create remote replica deletion directory in [$REPLICA_DIR$DELETION_DIR]." "ERROR" exit 1 fi fi while read -r files; do ## On every run, check wheter the next item is already deleted because it is included in a directory already deleted - if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then + if [[ "$files" != "$previousFile/"* ]] && [ "$files" != "" ]; then if [ "$SOFT_DELETE" != "no" ]; then if [ $_DRYRUN == false ]; then - if [ -e "$REPLICA_DIR$DELETE_DIR/$files" ]; then - $COMMAND_SUDO rm -rf "$REPLICA_DIR$DELETE_DIR/$files" + if [ -e "$REPLICA_DIR$DELETION_DIR/$files" ]; then + $COMMAND_SUDO rm -rf "$REPLICA_DIR$DELETION_DIR/$files" fi if [ -e "$REPLICA_DIR$files" ]; then # In order to keep full path on soft deletion, create parent directories before move parentdir="$(dirname "$files")" if [ "$parentdir" != "." ]; then - $COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR/$parentdir" - $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR/$parentdir" - Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_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$DELETE_DIR" - Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_DIR]." "VERBOSE" + $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETION_DIR" + Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETION_DIR]." "VERBOSE" fi if [ $? != 0 ]; then Logger "Cannot move [$REPLICA_DIR$files] to deletion directory." "ERROR" @@ -2591,7 +2618,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ fi fi fi - previous_file="$files" + previousFile="$files" fi done < "$FILE_LIST" ENDSSH @@ -2602,10 +2629,10 @@ ENDSSH fi ## Copy back the deleted failed file list - esc_source_file="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$deleted_failed_list_file")" - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_file\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - eval "$rsync_cmd" 2>> "$LOG_FILE" + escSourceFile="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/${INITIATOR[$__failedDeletedListFile]}")" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$escSourceFile\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" 2>> "$LOG_FILE" result=$? if [ $result != 0 ]; then Logger "Cannot copy back the failed deletion list to initiator replica." "CRITICAL" @@ -2617,36 +2644,36 @@ ENDSSH return 0 } -# 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 +# delete_Propagation(replica type) +function deletionPropagation { + local replicaType="${1}" # Contains replica type: initiator, target + __CheckArguments 1 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG + + local replicaDir + local deleteDir - local replica_dir - local delete_dir + Logger "Propagating deletions to $replicaType replica." "NOTICE" - Logger "Propagating deletions to $replica_type replica." "NOTICE" + #TODO: deletionPropagation replicaType = source replica whereas _deleteXxxxxx replicaType = dest replica - if [ "$replica_type" == "${INITIATOR[$__type]}" ]; then - replica_dir="${INITIATOR[$__replicaDir]}" - delete_dir="${INITIATOR[$__deleteDir]}" + if [ "$replicaType" == "${INITIATOR[$__type]}" ]; then + replicaDir="${INITIATOR[$__replicaDir]}" + deleteDir="${INITIATOR[$__deleteDir]}" - _delete_local "$replica_dir" "${TARGET[$__type]}$deleted_list_file" "$delete_dir" "${TARGET[$__type]}$deleted_failed_list_file" + _deleteLocal "${TARGET[$__type]}" "$replicaDir" "$deleteDir" retval=$? if [ $retval != 0 ]; then - Logger "Deletion on replica $replica_type failed." "CRITICAL" + Logger "Deletion on $replicaType replica failed." "CRITICAL" exit 1 fi else - replica_dir="${TARGET[$__replicaDir]}" - delete_dir="${TARGET[$__deleteDir]}" + replicaDir="${TARGET[$__replicaDir]}" + deleteDir="${TARGET[$__deleteDir]}" if [ "$REMOTE_OPERATION" == "yes" ]; then - _delete_remote "$replica_dir" "${INITIATOR[$__type]}$deleted_list_file" "$delete_dir" "${INITIATOR[$__type]}$deleted_failed_list_file" + _deleteRemote "${INITIATOR[$__type]}" "$replicaDir" "$deleteDir" else - _delete_local "$replica_dir" "${INITIATOR[$__type]}$deleted_list_file" "$delete_dir" "${INITIATOR[$__type]}$deleted_failed_list_file" + _deleteLocal "${INITIATOR[$__type]}" "$replicaDir" "$deleteDir" fi retval=$? if [ $retval == 0 ]; then @@ -2655,7 +2682,7 @@ function deletion_propagation { fi return $retval else - Logger "Deletion on remote system failed." "CRITICAL" + Logger "Deletion on $replicaType 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 @@ -2674,7 +2701,7 @@ function deletion_propagation { ###### Step 5a & 5b: Create after run file list of replicas function Sync { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local resumeCount local resumeInitiator @@ -2740,12 +2767,12 @@ function Sync { ## Step 0a & 0b if [ "$resumeInitiator" == "none" ] || [ "$resumeTarget" == "none" ] || [ "$resumeInitiator" == "${SYNC_ACTION[0]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[0]}" ]; then if [ "$resumeInitiator" == "none" ] || [ "$resumeInitiator" == "${SYNC_ACTION[0]}" ]; then - tree_list "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "${INITIATOR[$__treeCurrentFile]}" & + treeList "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "${INITIATOR[$__treeCurrentFile]}" & initiatorPid="$!" fi if [ "$resumeTarget" == "none" ] || [ "$resumeTarget" == "${SYNC_ACTION[0]}" ]; then - tree_list "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "${INITIATOR[$__treeCurrentFile]}" & + treeList "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "${INITIATOR[$__treeCurrentFile]}" & targetPid="$!" fi @@ -2785,12 +2812,12 @@ function Sync { ## Step 1a & 1b if [ "$resumeInitiator" == "${SYNC_ACTION[1]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[1]}" ]; then if [ "$resumeInitiator" == "${SYNC_ACTION[1]}" ]; then - delete_list "${INITIATOR[$__type]}" "${INITIATOR[$__treeAfterFile]}" "${INITIATOR[$__treeCurrentFile]}" "${INITIATOR[$__deletedListFile]}" "${INITIATOR[$__failedDeletedListFile]}" & + deleteList "${INITIATOR[$__type]}" & initiatorPid="$!" fi if [ "$resumeTarget" == "${SYNC_ACTION[1]}" ]; then - delete_list "${TARGET[$__type]}" "${INITIATOR[$__treeAfterFile]}" "${INITIATOR[$__treeCurrentFile]}" "${INITIATOR[$__deletedListFile]}" "${INITIATOR[$__failedDeletedListFile]}" & + deleteList "${TARGET[$__type]}" & targetPid="$!" fi @@ -2830,7 +2857,7 @@ function Sync { ## Step 2 if [ "$resumeInitiator" == "${SYNC_ACTION[2]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[2]}" ]; then if [ "$RSYNC_ATTR_ARGS" != "" ]; then - sync_attrs "${INITIATOR[$__replicaDir]}" "$TARGET_SYNC_DIR" + syncAttrs "${INITIATOR[$__replicaDir]}" "$TARGET_SYNC_DIR" WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING if [ $? != 0 ]; then echo "${SYNC_ACTION[2]}" > "${INITIATOR[$__initiatorLastActionFile]}" @@ -2855,14 +2882,14 @@ function Sync { if [ "$resumeInitiator" == "${SYNC_ACTION[3]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[3]}" ]; then if [ "$CONFLICT_PREVALANCE" == "${TARGET[$__type]}" ]; then if [ "$resumeTarget" == "${SYNC_ACTION[3]}" ]; then - sync_update "${TARGET[$__type]}" "${INITIATOR[$__type]}" "${INITIATOR[$__deletedListFile]}" + syncUpdate "${TARGET[$__type]}" "${INITIATOR[$__type]}" if [ $? == 0 ]; then echo "${SYNC_ACTION[4]}" > "${INITIATOR[$__targetLastActionFile]}" resumeTarget="${SYNC_ACTION[4]}" fi fi if [ "$resumeInitiator" == "${SYNC_ACTION[3]}" ]; then - sync_update "${INITIATOR[$__type]}" "${TARGET[$__type]}" "${INITIATOR[$__deletedListFile]}" + syncUpdate "${INITIATOR[$__type]}" "${TARGET[$__type]}" if [ $? == 0 ]; then echo "${SYNC_ACTION[4]}" > "${INITIATOR[$__initiatorLastActionFile]}" resumeInitiator="${SYNC_ACTION[4]}" @@ -2870,14 +2897,14 @@ function Sync { fi else if [ "$resumeInitiator" == "${SYNC_ACTION[3]}" ]; then - sync_update "${INITIATOR[$__type]}" "${TARGET[$__type]}" "${INITIATOR[$__deletedListFile]}" + syncUpdate "${INITIATOR[$__type]}" "${TARGET[$__type]}" if [ $? == 0 ]; then echo "${SYNC_ACTION[4]}" > "${INITIATOR[$__initiatorLastActionFile]}" resumeInitiator="${SYNC_ACTION[4]}" fi fi if [ "$resumeTarget" == "${SYNC_ACTION[3]}" ]; then - sync_update "${TARGET[$__type]}" "${INITIATOR[$__type]}" "${INITIATOR[$__deletedListFile]}" + syncUpdate "${TARGET[$__type]}" "${INITIATOR[$__type]}" if [ $? == 0 ]; then echo "${SYNC_ACTION[4]}" > "${INITIATOR[$__targetLastActionFile]}" resumeTarget="${SYNC_ACTION[4]}" @@ -2889,12 +2916,12 @@ function Sync { ## Step 4a & 4b if [ "$resumeInitiator" == "${SYNC_ACTION[4]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[4]}" ]; then if [ "$resumeInitiator" == "${SYNC_ACTION[4]}" ]; then - deletion_propagation "${TARGET[$__type]}" "${INITIATOR[$__deletedListFile]}" "${INITIATOR[$__failedDeletedListFile]}" & + deletionPropagation "${TARGET[$__type]}" & initiatorPid="$!" fi if [ "$resumeTarget" == "${SYNC_ACTION[4]}" ]; then - deletion_propagation "${INITIATOR[$__type]}" "${INITIATOR[$__deletedListFile]}" "${INITIATOR[$__failedDeletedListFile]}" & + deletionPropagation "${INITIATOR[$__type]}" & targetPid="$!" fi @@ -2935,12 +2962,12 @@ function Sync { ## Step 5a & 5b if [ "$resumeInitiator" == "${SYNC_ACTION[5]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[5]}" ]; then if [ "$resumeInitiator" == "${SYNC_ACTION[5]}" ]; then - tree_list "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "${INITIATOR[$__treeAfterFile]}" & + treeList "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "${INITIATOR[$__treeAfterFile]}" & initiatorPid="$!" fi if [ "$resumeTarget" == "${SYNC_ACTION[5]}" ]; then - tree_list "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "${INITIATOR[$__treeAfterFile]}" & + treeList "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "${INITIATOR[$__treeAfterFile]}" & targetPid="$!" fi @@ -2982,52 +3009,53 @@ function Sync { } 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 replicaType="${1}" # replica type (initiator, target) + local replicaDeletionPath="${2}" # Contains the full path to softdelete / backup directory without ending slash + local changeTime="${3}" + + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local retval - if [ -d "$replica_deletion_path" ]; then + if [ -d "$replicaDeletionPath" ]; then if [ $_DRYRUN == true ]; then - Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE" + Logger "Listing files older than $changeTime days on $replicaType replica. Does not remove anything." "NOTICE" else - Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE" + Logger "Removing files older than $changeTime days on $replicaType replica." "NOTICE" fi if [ $_VERBOSE == true ]; then # Cannot launch log function from xargs, ugly hack - $COMMAND_SUDO $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" + $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" - $COMMAND_SUDO $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" + $COMMAND_SUDO $FIND_CMD "$replicaDeletionPath/" -type d -empty -ctime +$changeTime -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)" "VERBOSE" fi if [ $_DRYRUN == false ]; then - $COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -f "{}" && $COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type d -empty -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -rf "{}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1 + $COMMAND_SUDO $FIND_CMD "$replicaDeletionPath/" -type f -ctime +$changeTime -print0 | xargs -0 -I {} $COMMAND_SUDO rm -f "{}" && $COMMAND_SUDO $FIND_CMD "$replicaDeletionPath/" -type d -empty -ctime +$changeTime -print0 | xargs -0 -I {} $COMMAND_SUDO rm -rf "{}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1 else Dummy fi retval=$? if [ $retval -ne 0 ]; then - Logger "Error while executing cleanup on $replica_type replica." "ERROR" + Logger "Error while executing cleanup on $replicaType replica." "ERROR" Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE" else - Logger "Cleanup complete on $replica_type replica." "NOTICE" + Logger "Cleanup complete on $replicaType replica." "NOTICE" fi - elif [ -d "$replica_deletion_path" ] && ! [ -w "$replica_deletion_path" ]; then - Logger "The $replica_type replica dir [$replica_deletion_path] is not writable. Cannot clean old files." "ERROR" + elif [ -d "$replicaDeletionPath" ] && ! [ -w "$replicaDeletionPath" ]; then + Logger "The $replicaType replica dir [$replicaDeletionPath] is not writable. Cannot clean old files." "ERROR" else - Logger "The $replica_type replica dir [$replica_deletion_path] does not exist. Skipping cleaning of old files." "VERBOSE" + Logger "The $replicaType replica dir [$replicaDeletionPath] does not exist. Skipping cleaning of old files." "VERBOSE" 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 replicaType="${1}" + local replicaDeletionPath="${2}" # Contains the full path to softdelete / backup directory without ending slash + local changeTime="${3}" + __CheckArguments 3 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local retval @@ -3035,21 +3063,21 @@ function _SoftDeleteRemote { CheckConnectivityRemoteHost if [ $_DRYRUN == true ]; then - Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE" + Logger "Listing files older than $changeTime days on $replicaType replica. Does not remove anything." "NOTICE" else - Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE" + Logger "Removing files older than $changeTime days on $replicaType replica." "NOTICE" fi if [ $_VERBOSE == true ]; 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 {} && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} echo Will delete directory {}; else echo \"The $replica_type replica dir [$replica_deletion_path] does not exist. Skipping cleaning of old files.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' + 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" eval "$cmd" Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "VERBOSE" fi if [ $_DRYRUN == false ]; 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 {} '$COMMAND_SUDO' rm -f \"{}\" && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -rf \"{}\"; else echo \"The $replica_type replica_dir [$replica_deletion_path] does not exist. Skipping cleaning of old files.\"; fi" >> "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' + cmd=$SSH_CMD' "if [ -d \"'$replicaDeletionPath'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replicaDeletionPath'/\" -type f -ctime +'$changeTime' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -f \"{}\" && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replicaDeletionPath'/\" -type d -empty -ctime '$changeTime' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -rf \"{}\"; else echo \"The $replicaType replicaDir [$replicaDeletionPath] does not exist. Skipping cleaning of old files.\"; fi" >> "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" @@ -3058,15 +3086,15 @@ function _SoftDeleteRemote { fi retval=$? if [ $retval -ne 0 ]; then - Logger "Error while executing cleanup on remote $replica_type replica." "ERROR" + Logger "Error while executing cleanup on remote $replicaType replica." "ERROR" Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE" else - Logger "Cleanup complete on $replica_type replica." "NOTICE" + Logger "Cleanup complete on $replicaType replica." "NOTICE" fi } function SoftDelete { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local pids @@ -3102,7 +3130,7 @@ function SoftDelete { } function Init { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG # Set error exit code if a piped command fails set -o pipefail @@ -3171,17 +3199,17 @@ function Init { ## Replica format ## Why the f*** does bash not have simple objects ? # 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 lockFilename="lock" + local stateDir="state" + local backupDir="backup" + local deleteDir="deleted" + local partialDir="_partial" + local lastAction="last-action" + local resumeCount="resume-count" if [ "$_DRYRUN" == true ]; then - local dry_suffix="-dry" + local drySuffix="-dry" else - local dry_suffix= + local drySuffix= fi # The following associative like array definitions are used for bash ver < 4 compat @@ -3198,33 +3226,33 @@ function Init { readonly __treeCurrentFile=10 readonly __treeAfterFile=11 readonly __treeAfterFileNoSuffix=12 - readonly __deletedListfile=13 + readonly __deletedListFile=13 readonly __failedDeletedListFile=14 INITIATOR=() INITIATOR[$__type]='initiator' INITIATOR[$__replicaDir]="$INITIATOR_SYNC_DIR" - INITIATOR[$__lockFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$lock_filename" - INITIATOR[$__stateDir]="$OSYNC_DIR/$state_dir" - INITIATOR[$__backupDir]="$OSYNC_DIR/$backup_dir" - INITIATOR[$__deleteDir]="$OSYNC_DIR/$delete_dir" - INITIATOR[$__partialDir]="$OSYNC_DIR/$partial_dir" - INITIATOR[$__initiatorLastActionFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/initiator-$last_action-$INSTANCE_ID$dry_suffix" - INITIATOR[$__targetLastActionFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/target-$last_action-$INSTANCE_ID$dry_suffix" - INITIATOR[$__resumeCount]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix" - INITIATOR[$__treeCurrentFile]="-tree-current-$INSTANCE_ID$dry_suffix" - INITIATOR[$__treeAfterFile]="-tree-after-$INSTANCE_ID$dry_suffix" + INITIATOR[$__lockFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$lockFilename" + INITIATOR[$__stateDir]="$OSYNC_DIR/$stateDir" + INITIATOR[$__backupDir]="$OSYNC_DIR/$backupDir" + INITIATOR[$__deleteDir]="$OSYNC_DIR/$deleteDir" + INITIATOR[$__partialDir]="$OSYNC_DIR/$partialDir" + INITIATOR[$__initiatorLastActionFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$stateDir/initiator-$lastAction-$INSTANCE_ID$drySuffix" + INITIATOR[$__targetLastActionFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$stateDir/target-$lastAction-$INSTANCE_ID$drySuffix" + INITIATOR[$__resumeCount]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$stateDir/$resumeCount-$INSTANCE_ID$drySuffix" + INITIATOR[$__treeCurrentFile]="-tree-current-$INSTANCE_ID$drySuffix" + INITIATOR[$__treeAfterFile]="-tree-after-$INSTANCE_ID$drySuffix" INITIATOR[$__treeAfterFileNoSuffix]="-tree-after-$INSTANCE_ID" - INITIATOR[$__deletedListFile]="-deleted-list-$INSTANCE_ID$dry_suffix" - INITIATOR[$__failedDeletedListFile]="-failed-delete-$INSTANCE_ID$dry_suffix" + INITIATOR[$__deletedListFile]="-deleted-list-$INSTANCE_ID$drySuffix" + INITIATOR[$__failedDeletedListFile]="-failed-delete-$INSTANCE_ID$drySuffix" TARGET=() TARGET[$__type]='target' TARGET[$__replicaDir]="$TARGET_SYNC_DIR" - TARGET[$__lockFile]="$TARGET_SYNC_DIR$OSYNC_DIR/$lock_filename" - TARGET[$__stateDir]="$OSYNC_DIR/$state_dir" - TARGET[$__backupDir]="$OSYNC_DIR/$backup_dir" - TARGET[$__deleteDir]="$OSYNC_DIR/$delete_dir" + TARGET[$__lockFile]="$TARGET_SYNC_DIR$OSYNC_DIR/$lockFilename" + TARGET[$__stateDir]="$OSYNC_DIR/$stateDir" + TARGET[$__backupDir]="$OSYNC_DIR/$backupDir" + TARGET[$__deleteDir]="$OSYNC_DIR/$deleteDir" PARTIAL_DIR="${INITIATOR[$__partialDir]}" @@ -3240,9 +3268,7 @@ function Init { fi ## Add Rsync include / exclude patterns - if [ $_QUICK_SYNC -lt 2 ]; then - RsyncPatterns - fi + RsyncPatterns ## Conflict options if [ "$CONFLICT_BACKUP" != "no" ]; then @@ -3269,7 +3295,7 @@ function Init { } function Main { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG CreateStateDirs CheckLocks @@ -3277,15 +3303,15 @@ function Main { } function Usage { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __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 "$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]" @@ -3315,7 +3341,7 @@ function Usage { } function SyncOnChanges { - __CheckArguments 0 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG + __CheckArguments 0 $# "${FUNCNAME[0]}" "$@" #__WITH_PARANOIA_DEBUG local cmd local retval diff --git a/install.sh b/install.sh index 7a45430..902ffa5 100755 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash PROGRAM=osync -PROGRAM_VERSION=1.2-beta +PROGRAM_VERSION=1.2-beta2 PROGRAM_BINARY=$PROGRAM".sh" PROGRAM_BATCH=$PROGRAM"-batch.sh" SCRIPT_BUILD=2016090605 diff --git a/osync.sh b/osync.sh index ae58b3d..44f2ae0 100755 --- a/osync.sh +++ b/osync.sh @@ -3,15 +3,15 @@ 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-beta -PROGRAM_BUILD=2016083004 +PROGRAM_VERSION=1.2-beta2 +PROGRAM_BUILD=2016101701 IS_STABLE=no #### MINIMAL-FUNCTION-SET BEGIN #### -## FUNC_BUILD=2016090701 +## FUNC_BUILD=2016091601 ## 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: @@ -109,9 +109,9 @@ function _Logger { local evalue="${3}" # What to log to stderr echo -e "$lvalue" >> "$LOG_FILE" - CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue" + CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue" #WIP - if [ $_LOGGER_STDERR == true ]; then + if [ $_LOGGER_STDERR == true ] && [ "$evalue" != "" ]; then cat <<< "$evalue" 1>&2 elif [ "$_SILENT" == false ]; then echo -e "$svalue" @@ -263,7 +263,7 @@ function SendAlert { fi # - if [ "$_QUICK_SYNC" == "2" ]; then + if [ "$_QUICK_SYNC" -eq 2 ]; then Logger "Current task is a quicksync task. Will not send any alert." "NOTICE" return 0 fi @@ -802,8 +802,6 @@ function CleanUp { fi } -#### MINIMAL-FUNCTION-SET END #### - # obsolete, use StripQuotes function SedStripQuotes { echo $(echo $1 | sed "s/^\([\"']\)\(.*\)\1\$/\2/g") @@ -928,6 +926,8 @@ function GetLocalOS { Logger "Local OS: [$local_os_var]." "DEBUG" } +#### MINIMAL-FUNCTION-SET END #### + function GetRemoteOS { local cmd= @@ -1104,7 +1104,7 @@ function CheckConnectivityRemoteHost { WaitForTaskCompletion $! 60 180 ${FUNCNAME[0]} true $KEEP_LOGGING retval=$? if [ $retval != 0 ]; then - Logger "Cannot ping [$REMOTE_HOST]. Return code [$retval]." "ERROR" + Logger "Cannot ping [$REMOTE_HOST]. Return code [$retval]." "WARN" return $retval fi fi @@ -1133,7 +1133,7 @@ function CheckConnectivity3rdPartyHosts { done if [ $remote_3rd_party_success == false ]; then - Logger "No remote 3rd party host responded to ping. No internet ?" "ERROR" + Logger "No remote 3rd party host responded to ping. No internet ?" "WARN" return 1 else return 0 @@ -1203,7 +1203,8 @@ function RsyncPatterns { if [ "$RSYNC_INCLUDE_FROM" != "" ]; then RsyncPatternsFromAdd "include" "$RSYNC_INCLUDE_FROM" fi - elif [ "$RSYNC_PATTERN_FIRST" == "include" ]; then + # Use default include first for quicksync runs + elif [ "$RSYNC_PATTERN_FIRST" == "include" ] || [ $_QUICK_SYNC -eq 2 ]; then if [ "$RSYNC_INCLUDE_PATTERN" != "" ]; then RsyncPatternsAdd "include" "$RSYNC_INCLUDE_PATTERN" fi @@ -1404,6 +1405,19 @@ function PrintIFS { printf "IFS is: %q" "$IFS" } +# Process debugging +# Recursive function to get all parents from a pid +function ParentPid { + local pid="${1}" # Pid to analyse + local parent + + parent=$(ps -p $pid -o ppid=) + echo "$pid is a child of $parent" + if [ $parent -gt 0 ]; then + ParentPid $parent + fi +} + ## END Generic functions _LOGGER_PREFIX="time" @@ -1584,7 +1598,7 @@ function CheckReplicaPaths { # Use direct comparaison before having a portable realpath implementation #INITIATOR_SYNC_DIR_CANN=$(realpath "${INITIATOR[$__replicaDir]}") #TODO(verylow): investigate realpath & readlink issues on MSYS and busybox here - #TARGET_SYNC_DIR_CANN=$(realpath "${TARGET[$__replicaDir]}) + #TARGET_SYNC_DIR_CANN=$(realpath "${TARGET[$__replicaDir]}") if [ "$REMOTE_OPERATION" != "yes" ]; then if [ "${INITIATOR[$__replicaDir]}" == "${TARGET[$__replicaDir]}" ]; then @@ -1625,7 +1639,7 @@ function _CheckDiskSpaceLocal { function _CheckDiskSpaceRemote { local replica_path="${1}" - Logger "Checking minimum disk space on target [$replica_path]." "NOTICE" + Logger "Checking remote minimum disk space in [$replica_path]." "NOTICE" local cmd local disk_space @@ -1825,20 +1839,20 @@ function CheckLocks { function _WriteLockFilesLocal { local lockfile="${1}" - local replica_type="${2}" + local replicaType="${2}" $COMMAND_SUDO echo "$SCRIPT_PID@$INSTANCE_ID" > "$lockfile" if [ $? != 0 ]; then - Logger "Could not create lock file on local $replica_type in [$lockfile]." "CRITICAL" + Logger "Could not create lock file on local $replicaType in [$lockfile]." "CRITICAL" exit 1 else - Logger "Locked local $replica_type replica in [$lockfile]." "DEBUG" + Logger "Locked local $replicaType replica in [$lockfile]." "DEBUG" fi } function _WriteLockFilesRemote { local lockfile="${1}" - local replica_type="${2}" + local replicaType="${2}" local cmd @@ -1849,10 +1863,10 @@ function _WriteLockFilesRemote { Logger "cmd: $cmd" "DEBUG" eval "$cmd" if [ $? != 0 ]; then - Logger "Could not create lock file on remote $replica_type in [$lockfile]." "CRITICAL" + Logger "Could not create lock file on remote $replicaType in [$lockfile]." "CRITICAL" exit 1 else - Logger "Locked remote $replica_type replica in [$lockfile]." "DEBUG" + Logger "Locked remote $replicaType replica in [$lockfile]." "DEBUG" fi } @@ -1956,62 +1970,67 @@ function UnlockReplicas { ###### 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. + ## It seems this only happens when trying to execute an rsync command through weval $rsyncCmd 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) +function treeList { + local replicaPath="${1}" # path to the replica for which a tree needs to be constructed + local replicaType="${2}" # replica type: initiator, target + local treeFilename="${3}" # filename to output tree (will be prefixed with $replicaType) - local escaped_replica_path - local rsync_cmd + local escapedReplicaPath + local rsyncCmd - escaped_replica_path=$(EscapeSpaces "$replica_path") + escapedReplicaPath=$(EscapeSpaces "$replicaPath") - Logger "Creating $replica_type replica file list [$replica_path]." "NOTICE" - if [ "$REMOTE_OPERATION" == "yes" ] && [ "$replica_type" == "${TARGET[$__type]}" ]; then + Logger "Creating $replicaType replica file list [$replicaPath]." "NOTICE" + if [ "$REMOTE_OPERATION" == "yes" ] && [ "$replicaType" == "${TARGET[$__type]}" ]; 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\"" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS -L $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:\"$escapedReplicaPath\" 2> \"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.error.$SCRIPT_PID\" | grep \"^-\|^d\|^l\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$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\"" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS -L $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --list-only \"$replicaPath\" 2> \"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.error.$SCRIPT_PID\" | grep \"^-\|^d\|^l\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID\"" fi - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - ## Redirect commands stderr here to get rsync stderr output in logfile with eval "$rsync_cmd" 2>> "$LOG_FILE" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + #TODO: check the following statement + ## Redirect commands stderr here to get rsync stderr output in logfile with eval "$rsyncCmd" 2>> "$LOG_FILE" ## When log writing fails, $! is empty and WaitForTaskCompletion fails. Removing the 2>> log - eval "$rsync_cmd" + eval "$rsyncCmd" retval=$? + + if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID" ]; then + mv -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.$SCRIPT_PID" "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType$treeFilename" + fi + ## 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[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$tree_filename" + if ([ $retval == 0 ] || [ $retval == 24 ]) then return $? + elif [ $retval == 23 ]; then + Logger "Some files could not be listed in [$replicaPath]. Check for failing symlinks." "ERROR" + Logger "Command output\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$replicaType.error.$SCRIPT_PID)" "NOTICE" + return 0 else - Logger "Cannot create replica file list in [$replica_path]." "CRITICAL" + Logger "Cannot create replica file list in [$replicaPath]." "CRITICAL" return $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 - 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 +# deleteList(replicaType): Creates a list of files vanished from last run on replica $1 (initiator/target) +function deleteList { + local replicaType="${1}" # replica type: initiator, target local cmd - Logger "Creating $replica_type replica deleted file list." "NOTICE" - if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type${INITIATOR[$__treeAfterFile]}_NO_SUFFIX" ]; then + 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 if type comm > /dev/null 2>&1 ; then - cmd="comm -23 \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type${INITIATOR[$__treeAfterFileNoSuffix]}\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$tree_file_current\" > \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_list_file\"" + cmd="comm -23 \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeAfterFileNoSuffix]}\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeCurrentFile]}\" > \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}\"" else ## The || : forces the command to have a good result - cmd="(grep -F -x -v -f \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$tree_file_current\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type${INITIATOR[$__treeAfterFileNoSuffix]}\" || :) > \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_list_file\"" + cmd="(grep -F -x -v -f \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeCurrentFile]}\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__treeAfterFileNoSuffix]}\" || :) > \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}\"" fi Logger "CMD: $cmd" "DEBUG" @@ -2019,49 +2038,52 @@ function delete_list { retval=$? # Add delete failed file list to current delete list and then empty it - if [ -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_failed_list_file" ]; then - cat "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_failed_list_file" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_list_file" - rm -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_failed_list_file" + 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 [ $? == 0 ]; then + rm -f "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" + else + Logger "Cannot add failed deleted list to current deleted list for replica [$replicaType]." "ERROR" + fi fi - return $retval else - touch "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replica_type$deleted_list_file" + touch "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}" 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 +function _getFileCtimeMtimeLocal { + local replicaPath="${1}" # Contains replica path + local replicaType="${2}" # Initiator / Target + local fileList="${3}" # Contains list of files to get time attrs - echo -n "" > "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID" - while read -r file; do $STAT_CTIME_MTIME_CMD "$replica_path$file" | sort >> "$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID"; done < "$file_list" + echo -n "" > "$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID" + while read -r file; do $STAT_CTIME_MTIME_CMD "$replicaPath$file" | sort >> "$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID"; done < "$fileList" if [ $? != 0 ]; then - Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL" - if [ -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)" "VERBOSE" + Logger "Getting file attributes failed [$retval] on $replicaType. Stopping execution." "CRITICAL" + if [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID" ]; then + Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID)" "VERBOSE" fi exit 1 fi } -function _get_file_ctime_mtime_remote { - local replica_path="${1}" # Contains replica path - local replica_type="${2}" - local file_list="${3}" +function _getFileCtimeMtimeRemote { + local replicapath="${1}" # Contains replica path + local replicaType="${2}" + local fileList="${3}" local cmd - cmd='cat "'$file_list'" | '$SSH_CMD' "while read -r file; do '$REMOTE_STAT_CTIME_MTIME_CMD' \"'$replica_path'\$file\"; done | sort" > "'$RUN_DIR/$PROGRAM.ctime_mtime.$replica_type.$SCRIPT_PID'"' + cmd='cat "'$fileList'" | '$SSH_CMD' "while read -r file; do '$REMOTE_STAT_CTIME_MTIME_CMD' \"'$replicaPath'\$file\"; done | sort" > "'$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID'"' Logger "CMD: $cmd" "DEBUG" eval "$cmd" if [ $? != 0 ]; then - Logger "Getting file attributes failed [$retval] on $replica_type. Stopping execution." "CRITICAL" - if [ -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)" "VERBOSE" + Logger "Getting file attributes failed [$retval] on $replicaType. Stopping execution." "CRITICAL" + if [ -f "$RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID" ]; then + Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.ctime_mtime.$replicaType.$SCRIPT_PID)" "VERBOSE" fi exit 1 fi @@ -2069,28 +2091,30 @@ function _get_file_ctime_mtime_remote { # 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}" - local delete_list_filename="${INITIATOR[$__deletedListFile]}" # Contains deleted list filename, will be prefixed with replica type +function syncAttrs { + local initiatorReplica="${1}" + local targetReplica="${2}" - local rsync_cmd + local rsyncCmd local retval - local esc_source_dir - local esc_dest_dir + local sourceDir + local destDir + local escSourceDir + local escDestDir + local destReplica Logger "Getting list of files that need updates." "NOTICE" if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i -n -8 $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 &" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i -n -8 $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiatorReplica\" $REMOTE_USER@$REMOTE_HOST:\"$targetReplica\" >> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i -n -8 $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 &" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i -n -8 $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiatorReplica\" \"$targetReplica\" >> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID 2>&1 &" fi - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - eval "$rsync_cmd" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING retval=$? @@ -2104,6 +2128,7 @@ function sync_attrs { if [ -f "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" ]; then Logger "List:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "VERBOSE" fi + #TODO: Apply SC2002: unnecessary cat 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" @@ -2112,222 +2137,224 @@ function sync_attrs { fi Logger "Getting ctimes for pending files on initiator." "NOTICE" - _get_file_ctime_mtime_local "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & + _getFileCtimeMtimeLocal "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & pids="$!" Logger "Getting ctimes for pending files on target." "NOTICE" if [ "$REMOTE_OPERATION" != "yes" ]; then - _get_file_ctime_mtime_local "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & + _getFileCtimeMtimeLocal "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & pids="$pids;$!" else - _get_file_ctime_mtime_remote "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & + _getFileCtimeMtimeRemote "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-cleaned.$SCRIPT_PID" & pids="$pids;$!" fi WaitForTaskCompletion $pids 1800 0 ${FUNCNAME[0]} true $KEEP_LOGGING - # If target gets updated first, then sync_attr must update initiator's attrs first + # If target gets updated first, then sync_attr must update initiators attrs first # For join, remove leading replica paths sed -i'.tmp' "s;^${INITIATOR[$__replicaDir]};;g" "$RUN_DIR/$PROGRAM.ctime_mtime.${INITIATOR[$__type]}.$SCRIPT_PID" sed -i'.tmp' "s;^${TARGET[$__replicaDir]};;g" "$RUN_DIR/$PROGRAM.ctime_mtime.${TARGET[$__type]}.$SCRIPT_PID" if [ "$CONFLICT_PREVALANCE" == "${TARGET[$__type]}" ]; then - local source_dir="${INITIATOR[$__replicaDir]}" - esc_source_dir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") - local dest_dir="${TARGET[$__replicaDir]}" - esc_dest_dir=$(EscapeSpaces "${TARGET[$__replicaDir]}") - local dest_replica="${TARGET[$__type]}" + sourceDir="${INITIATOR[$__replicaDir]}" + escSourceDir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") + destDir="${TARGET[$__replicaDir]}" + escDestDir=$(EscapeSpaces "${TARGET[$__replicaDir]}") + destReplica="${TARGET[$__type]}" join -j 1 -t ';' -o 1.1,1.2,2.2 "$RUN_DIR/$PROGRAM.ctime_mtime.${INITIATOR[$__type]}.$SCRIPT_PID" "$RUN_DIR/$PROGRAM.ctime_mtime.${TARGET[$__type]}.$SCRIPT_PID" | awk -F';' '{if ($2 > $3) print $1}' > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID" else - local source_dir="${TARGET[$__replicaDir]}" - esc_source_dir=$(EscapeSpaces "${TARGET[$__replicaDir]}") - local dest_dir="${INITIATOR[$__replicaDir]}" - esc_dest_dir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") - local dest_replica="${INITIATOR[$__type]}" + sourceDir="${TARGET[$__replicaDir]}" + escSourceDir=$(EscapeSpaces "${TARGET[$__replicaDir]}") + destDir="${INITIATOR[$__replicaDir]}" + escDestDir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") + destReplica="${INITIATOR[$__type]}" join -j 1 -t ';' -o 1.1,1.2,2.2 "$RUN_DIR/$PROGRAM.ctime_mtime.${TARGET[$__type]}.$SCRIPT_PID" "$RUN_DIR/$PROGRAM.ctime_mtime.${INITIATOR[$__type]}.$SCRIPT_PID" | awk -F';' '{if ($2 > $3) print $1}' > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID" fi if [ $(wc -l < "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID") -eq 0 ]; then - Logger "Updating file attributes on $dest_replica not required" "NOTICE" + Logger "Updating file attributes on $destReplica not required" "NOTICE" return 0 fi - Logger "Updating file attributes on $dest_replica." "NOTICE" + Logger "Updating file attributes on $destReplica." "NOTICE" if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost # No rsync args (hence no -r) because files are selected with --from-file - if [ "$dest_replica" == "${INITIATOR[$__type]}" ]; then - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}$delete_list_filename\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_dir\" \"$dest_dir\" >> $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID 2>&1 &" + if [ "$destReplica" == "${INITIATOR[$__type]}" ]; then + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}${INITIATOR[$__deletedListFile]}\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" $REMOTE_USER@$REMOTE_HOST:\"$escSourceDir\" \"$destDir\" >> $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}$delete_list_filename\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" \"$source_dir\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir\" >> $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID 2>&1 &" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}${INITIATOR[$__deletedListFile]}\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" \"$sourceDir\" $REMOTE_USER@$REMOTE_HOST:\"$escDestDir\" >> $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID 2>&1 &" fi else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}$delete_list_filename\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" \"$source_dir\" \"$dest_dir\" >> $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID 2>&1 &" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $SYNC_OPTS --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${INITIATOR[$__type]}${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/${TARGET[$__type]}${INITIATOR[$__deletedListFile]}\" --files-from=\"$RUN_DIR/$PROGRAM.${FUNCNAME[0]}-ctime_files.$SCRIPT_PID\" \"$sourceDir\" \"$destDir\" >> $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID 2>&1 &" fi - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - eval "$rsync_cmd" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING retval=$? if [ $retval != 0 ] && [ $retval != 24 ]; then - Logger "Updating file attributes on $dest_replica [$retval]. Stopping execution." "CRITICAL" - if [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then - Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "NOTICE" + Logger "Updating file attributes on $destReplica [$retval]. Stopping execution." "CRITICAL" + if [ -f "$RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID" ]; then + Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID)" "NOTICE" fi exit 1 else - if [ -f "$RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID" ]; then - Logger "List:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$dest_replica.$SCRIPT_PID)" "VERBOSE" + if [ -f "$RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID" ]; then + Logger "List:\n$(cat $RUN_DIR/$PROGRAM.attr-update.$destReplica.$SCRIPT_PID)" "VERBOSE" fi - Logger "Successfully updated file attributes on $dest_replica replica." "NOTICE" + Logger "Successfully updated file attributes on $destReplica 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 +# syncUpdate(source replica, destination replica, delete_list_filename) +function syncUpdate { + local sourceReplica="${1}" # Contains replica type of source: initiator, target + local destinationReplica="${2}" # Contains replica type of destination: initiator, target - local rsync_cmd + local rsyncCmd local retval - local esc_source_dir - local esc_dest_dir + local sourceDir + local escSourceDir + local destDir + local escDestDir + + local backupArgs - Logger "Updating $destination_replica replica." "NOTICE" - if [ "$source_replica" == "${INITIATOR[$__type]}" ]; then - local source_dir="${INITIATOR[$__replicaDir]}" - local dest_dir="${TARGET[$__replicaDir]}" - local backup_args="$TARGET_BACKUP" + Logger "Updating $destinationReplica replica." "NOTICE" + if [ "$sourceReplica" == "${INITIATOR[$__type]}" ]; then + sourceDir="${INITIATOR[$__replicaDir]}" + destDir="${TARGET[$__replicaDir]}" + backupArgs="$TARGET_BACKUP" - esc_source_dir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") - esc_dest_dir=$(EscapeSpaces "${TARGET[$__replicaDir]}") + escSourceDir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") + escDestDir=$(EscapeSpaces "${TARGET[$__replicaDir]}") else - local source_dir="${TARGET[$__replicaDir]}" - local dest_dir="${INITIATOR[$__replicaDir]}" - local backup_args="$INITIATOR_BACKUP" + sourceDir="${TARGET[$__replicaDir]}" + destDir="${INITIATOR[$__replicaDir]}" + backupArgs="$INITIATOR_BACKUP" - esc_source_dir=$(EscapeSpaces "${TARGET[$__replicaDir]}") - esc_dest_dir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") + escSourceDir=$(EscapeSpaces "${TARGET[$__replicaDir]}") + escDestDir=$(EscapeSpaces "${INITIATOR[$__replicaDir]}") fi if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - if [ "$source_replica" == "${INITIATOR[$__type]}" ]; then - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $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[$__replicaDir]}${INITIATOR[$__stateDir]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destination_replica$delete_list_filename\" \"$source_dir\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir\" >> $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1" + if [ "$sourceReplica" == "${INITIATOR[$__type]}" ]; then + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backupArgs --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$sourceReplica${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destinationReplica${INITIATOR[$__deletedListFile]}\" \"$sourceDir\" $REMOTE_USER@$REMOTE_HOST:\"$escDestDir\" >> $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID 2>&1" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $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[$__replicaDir]}${INITIATOR[$__stateDir]}/$destination_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$source_replica$delete_list_filename\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_dir\" \"$dest_dir\" >> $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backupArgs --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destinationReplica${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$sourceReplica${INITIATOR[$__deletedListFile]}\" $REMOTE_USER@$REMOTE_HOST:\"$escSourceDir\" \"$destDir\" >> $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID 2>&1" fi else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destination_replica$delete_list_filename\" \"$source_dir\" \"$dest_dir\" >> $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_DRY_ARG $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS $backupArgs --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$sourceReplica${INITIATOR[$__deletedListFile]}\" --exclude-from=\"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$destinationReplica${INITIATOR[$__deletedListFile]}\" \"$sourceDir\" \"$destDir\" >> $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID 2>&1" fi - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - eval "$rsync_cmd" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" retval=$? if [ $retval != 0 ] && [ $retval != 24 ]; then - Logger "Updating $destination_replica replica failed. Stopping execution." "CRITICAL" - if [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then - Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "NOTICE" + Logger "Updating $destinationReplica replica failed. Stopping execution." "CRITICAL" + if [ -f "$RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID" ]; then + Logger "Rsync output:\n$(cat $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID)" "NOTICE" fi exit 1 else - if [ -f "$RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID" ]; then - Logger "List:\n$(cat $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID)" "VERBOSE" + if [ -f "$RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID" ]; then + Logger "List:\n$(cat $RUN_DIR/$PROGRAM.update.$destinationReplica.$SCRIPT_PID)" "VERBOSE" fi - Logger "Updating $destination_replica replica succeded." "NOTICE" + Logger "Updating $destinationReplica 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 +function _deleteLocal { + local replicaType="${1}" # Replica type + local replicaDir="${2}" # Full path to replica + local deletionDir="${3}" # deletion dir in format .[workdir]/deleted local parentdir - local previous_file="" + local previousFile="" local result - if [ ! -d "$replica_dir$deletion_dir" ] && [ $_DRYRUN == false ]; then - $COMMAND_SUDO mkdir -p "$replica_dir$deletion_dir" + if [ ! -d "$replicaDir$deletionDir" ] && [ $_DRYRUN == false ]; then + $COMMAND_SUDO mkdir -p "$replicaDir$deletionDir" if [ $? != 0 ]; then - Logger "Cannot create local replica deletion directory in [$replica_dir$deletion_dir]." "ERROR" + Logger "Cannot create local replica deletion directory in [$replicaDir$deletionDir]." "ERROR" exit 1 fi fi while read -r files; do ## On every run, check wheter the next item is already deleted because it is included in a directory already deleted - if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then + if [[ "$files" != "$previousFile/"* ]] && [ "$files" != "" ]; then if [ "$SOFT_DELETE" != "no" ]; then if [ $_DRYRUN == false ]; then - if [ -e "$replica_dir$deletion_dir/$files" ]; then - rm -rf "${replica_dir:?}$deletion_dir/$files" + if [ -e "$replicaDir$deletionDir/$files" ]; then + rm -rf "${replicaDir:?}$deletionDir/$files" fi - if [ -e "$replica_dir$files" ]; then + if [ -e "$replicaDir$files" ]; then # In order to keep full path on soft deletion, create parent directories before move parentdir="$(dirname "$files")" if [ "$parentdir" != "." ]; then - mkdir -p "$replica_dir$deletion_dir/$parentdir" - Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir/$parentdir]." "VERBOSE" - mv -f "$replica_dir$files" "$replica_dir$deletion_dir/$parentdir" + mkdir -p "$replicaDir$deletionDir/$parentdir" + Logger "Moving deleted file [$replicaDir$files] to [$replicaDir$deletionDir/$parentdir]." "VERBOSE" + mv -f "$replicaDir$files" "$replicaDir$deletionDir/$parentdir" else - Logger "Moving deleted file [$replica_dir$files] to [$replica_dir$deletion_dir]." "VERBOSE" - mv -f "$replica_dir$files" "$replica_dir$deletion_dir" + Logger "Moving deleted file [$replicaDir$files] to [$replicaDir$deletionDir]." "VERBOSE" + mv -f "$replicaDir$files" "$replicaDir$deletionDir" fi if [ $? != 0 ]; then - Logger "Cannot move [$replica_dir$files] to deletion directory." "ERROR" - echo "$files" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$deleted_failed_list_file" + Logger "Cannot move [$replicaDir$files] to deletion directory." "ERROR" + echo "$files" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" fi fi fi else if [ $_DRYRUN == false ]; then - if [ -e "$replica_dir$files" ]; then - rm -rf "$replica_dir$files" + if [ -e "$replicaDir$files" ]; then + rm -rf "$replicaDir$files" result=$? - Logger "Deleting [$replica_dir$files]." "VERBOSE" + Logger "Deleting [$replicaDir$files]." "VERBOSE" if [ $result != 0 ]; then - Logger "Cannot delete [$replica_dir$files]." "ERROR" - echo "$files" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$deleted_failed_list_file" + Logger "Cannot delete [$replicaDir$files]." "ERROR" + echo "$files" >> "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__failedDeletedListFile]}" fi fi fi fi - previous_file="$files" + previousFile="$files" fi - done < "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$deleted_list_file" + done < "${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}" } -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 +function _deleteRemote { + local replicaType="${1}" # Replica type + local replicaDir="${2}" # Full path to replica + local deletionDir="${3}" # deletion dir in format .[workdir]/deleted - local esc_dest_dir - local rsync_cmd + local escDestDir + local rsyncCmd + + local escSourceFile ## 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[$__replicaDir]}${TARGET[$__stateDir]}")" - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -e \"$RSYNC_SSH_CMD\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$deleted_list_file\" $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" + escDestDir="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}")" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -e \"$RSYNC_SSH_CMD\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}\" $REMOTE_USER@$REMOTE_HOST:\"$escDestDir/\" >> $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.precopy.$SCRIPT_PID 2>&1" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" 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 @@ -2336,7 +2363,7 @@ function _delete_remote { 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]}/$deleted_list_file")" REPLICA_DIR="$(EscapeSpaces "$replica_dir")" SOFT_DELETE=$SOFT_DELETE DELETE_DIR="$(EscapeSpaces "$deletion_dir")" FAILED_DELETE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$deleted_failed_list_file")" '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 _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$replicaType${INITIATOR[$__deletedListFile]}")" REPLICA_DIR="$(EscapeSpaces "$replicaDir")" SOFT_DELETE=$SOFT_DELETE DELETION_DIR="$(EscapeSpaces "$deletionDir")" FAILED_DELETE_LIST="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/${INITIATOR[$__failedDeletedListFile]}")" 'bash -s' << 'ENDSSH' >> "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 ## The following lines are executed remotely function _logger { @@ -2382,36 +2409,36 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ > "$FAILED_DELETE_LIST" parentdir= - previous_file="" + previousFile="" - if [ ! -d "$REPLICA_DIR$DELETE_DIR" ] && [ $_DRYRUN == false ]; then - $COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR" + if [ ! -d "$REPLICA_DIR$DELETION_DIR" ] && [ $_DRYRUN == false ]; then + $COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETION_DIR" if [ $? != 0 ]; then - Logger "Cannot create remote replica deletion directory in [$REPLICA_DIR$DELETE_DIR]." "ERROR" + Logger "Cannot create remote replica deletion directory in [$REPLICA_DIR$DELETION_DIR]." "ERROR" exit 1 fi fi while read -r files; do ## On every run, check wheter the next item is already deleted because it is included in a directory already deleted - if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then + if [[ "$files" != "$previousFile/"* ]] && [ "$files" != "" ]; then if [ "$SOFT_DELETE" != "no" ]; then if [ $_DRYRUN == false ]; then - if [ -e "$REPLICA_DIR$DELETE_DIR/$files" ]; then - $COMMAND_SUDO rm -rf "$REPLICA_DIR$DELETE_DIR/$files" + if [ -e "$REPLICA_DIR$DELETION_DIR/$files" ]; then + $COMMAND_SUDO rm -rf "$REPLICA_DIR$DELETION_DIR/$files" fi if [ -e "$REPLICA_DIR$files" ]; then # In order to keep full path on soft deletion, create parent directories before move parentdir="$(dirname "$files")" if [ "$parentdir" != "." ]; then - $COMMAND_SUDO mkdir -p "$REPLICA_DIR$DELETE_DIR/$parentdir" - $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETE_DIR/$parentdir" - Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_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$DELETE_DIR" - Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETE_DIR]." "VERBOSE" + $COMMAND_SUDO mv -f "$REPLICA_DIR$files" "$REPLICA_DIR$DELETION_DIR" + Logger "Moving deleted file [$REPLICA_DIR$files] to [$REPLICA_DIR$DELETION_DIR]." "VERBOSE" fi if [ $? != 0 ]; then Logger "Cannot move [$REPLICA_DIR$files] to deletion directory." "ERROR" @@ -2432,7 +2459,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _DEBUG=$_DEBUG _DRYRUN=$ fi fi fi - previous_file="$files" + previousFile="$files" fi done < "$FILE_LIST" ENDSSH @@ -2443,10 +2470,10 @@ ENDSSH fi ## Copy back the deleted failed file list - esc_source_file="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/$deleted_failed_list_file")" - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_file\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" - Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" - eval "$rsync_cmd" 2>> "$LOG_FILE" + escSourceFile="$(EscapeSpaces "${TARGET[$__replicaDir]}${TARGET[$__stateDir]}/${INITIATOR[$__failedDeletedListFile]}")" + rsyncCmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$escSourceFile\" \"${INITIATOR[$__replicaDir]}${INITIATOR[$__stateDir]}\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" + Logger "RSYNC_CMD: $rsyncCmd" "DEBUG" + eval "$rsyncCmd" 2>> "$LOG_FILE" result=$? if [ $result != 0 ]; then Logger "Cannot copy back the failed deletion list to initiator replica." "CRITICAL" @@ -2458,35 +2485,35 @@ ENDSSH return 0 } -# 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 +# delete_Propagation(replica type) +function deletionPropagation { + local replicaType="${1}" # Contains replica type: initiator, target + + local replicaDir + local deleteDir - local replica_dir - local delete_dir + Logger "Propagating deletions to $replicaType replica." "NOTICE" - Logger "Propagating deletions to $replica_type replica." "NOTICE" + #TODO: deletionPropagation replicaType = source replica whereas _deleteXxxxxx replicaType = dest replica - if [ "$replica_type" == "${INITIATOR[$__type]}" ]; then - replica_dir="${INITIATOR[$__replicaDir]}" - delete_dir="${INITIATOR[$__deleteDir]}" + if [ "$replicaType" == "${INITIATOR[$__type]}" ]; then + replicaDir="${INITIATOR[$__replicaDir]}" + deleteDir="${INITIATOR[$__deleteDir]}" - _delete_local "$replica_dir" "${TARGET[$__type]}$deleted_list_file" "$delete_dir" "${TARGET[$__type]}$deleted_failed_list_file" + _deleteLocal "${TARGET[$__type]}" "$replicaDir" "$deleteDir" retval=$? if [ $retval != 0 ]; then - Logger "Deletion on replica $replica_type failed." "CRITICAL" + Logger "Deletion on $replicaType replica failed." "CRITICAL" exit 1 fi else - replica_dir="${TARGET[$__replicaDir]}" - delete_dir="${TARGET[$__deleteDir]}" + replicaDir="${TARGET[$__replicaDir]}" + deleteDir="${TARGET[$__deleteDir]}" if [ "$REMOTE_OPERATION" == "yes" ]; then - _delete_remote "$replica_dir" "${INITIATOR[$__type]}$deleted_list_file" "$delete_dir" "${INITIATOR[$__type]}$deleted_failed_list_file" + _deleteRemote "${INITIATOR[$__type]}" "$replicaDir" "$deleteDir" else - _delete_local "$replica_dir" "${INITIATOR[$__type]}$deleted_list_file" "$delete_dir" "${INITIATOR[$__type]}$deleted_failed_list_file" + _deleteLocal "${INITIATOR[$__type]}" "$replicaDir" "$deleteDir" fi retval=$? if [ $retval == 0 ]; then @@ -2495,7 +2522,7 @@ function deletion_propagation { fi return $retval else - Logger "Deletion on remote system failed." "CRITICAL" + Logger "Deletion on $replicaType 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 @@ -2579,12 +2606,12 @@ function Sync { ## Step 0a & 0b if [ "$resumeInitiator" == "none" ] || [ "$resumeTarget" == "none" ] || [ "$resumeInitiator" == "${SYNC_ACTION[0]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[0]}" ]; then if [ "$resumeInitiator" == "none" ] || [ "$resumeInitiator" == "${SYNC_ACTION[0]}" ]; then - tree_list "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "${INITIATOR[$__treeCurrentFile]}" & + treeList "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "${INITIATOR[$__treeCurrentFile]}" & initiatorPid="$!" fi if [ "$resumeTarget" == "none" ] || [ "$resumeTarget" == "${SYNC_ACTION[0]}" ]; then - tree_list "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "${INITIATOR[$__treeCurrentFile]}" & + treeList "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "${INITIATOR[$__treeCurrentFile]}" & targetPid="$!" fi @@ -2624,12 +2651,12 @@ function Sync { ## Step 1a & 1b if [ "$resumeInitiator" == "${SYNC_ACTION[1]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[1]}" ]; then if [ "$resumeInitiator" == "${SYNC_ACTION[1]}" ]; then - delete_list "${INITIATOR[$__type]}" "${INITIATOR[$__treeAfterFile]}" "${INITIATOR[$__treeCurrentFile]}" "${INITIATOR[$__deletedListFile]}" "${INITIATOR[$__failedDeletedListFile]}" & + deleteList "${INITIATOR[$__type]}" & initiatorPid="$!" fi if [ "$resumeTarget" == "${SYNC_ACTION[1]}" ]; then - delete_list "${TARGET[$__type]}" "${INITIATOR[$__treeAfterFile]}" "${INITIATOR[$__treeCurrentFile]}" "${INITIATOR[$__deletedListFile]}" "${INITIATOR[$__failedDeletedListFile]}" & + deleteList "${TARGET[$__type]}" & targetPid="$!" fi @@ -2669,7 +2696,7 @@ function Sync { ## Step 2 if [ "$resumeInitiator" == "${SYNC_ACTION[2]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[2]}" ]; then if [ "$RSYNC_ATTR_ARGS" != "" ]; then - sync_attrs "${INITIATOR[$__replicaDir]}" "$TARGET_SYNC_DIR" + syncAttrs "${INITIATOR[$__replicaDir]}" "$TARGET_SYNC_DIR" WaitForTaskCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME ${FUNCNAME[0]} false $KEEP_LOGGING if [ $? != 0 ]; then echo "${SYNC_ACTION[2]}" > "${INITIATOR[$__initiatorLastActionFile]}" @@ -2694,14 +2721,14 @@ function Sync { if [ "$resumeInitiator" == "${SYNC_ACTION[3]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[3]}" ]; then if [ "$CONFLICT_PREVALANCE" == "${TARGET[$__type]}" ]; then if [ "$resumeTarget" == "${SYNC_ACTION[3]}" ]; then - sync_update "${TARGET[$__type]}" "${INITIATOR[$__type]}" "${INITIATOR[$__deletedListFile]}" + syncUpdate "${TARGET[$__type]}" "${INITIATOR[$__type]}" if [ $? == 0 ]; then echo "${SYNC_ACTION[4]}" > "${INITIATOR[$__targetLastActionFile]}" resumeTarget="${SYNC_ACTION[4]}" fi fi if [ "$resumeInitiator" == "${SYNC_ACTION[3]}" ]; then - sync_update "${INITIATOR[$__type]}" "${TARGET[$__type]}" "${INITIATOR[$__deletedListFile]}" + syncUpdate "${INITIATOR[$__type]}" "${TARGET[$__type]}" if [ $? == 0 ]; then echo "${SYNC_ACTION[4]}" > "${INITIATOR[$__initiatorLastActionFile]}" resumeInitiator="${SYNC_ACTION[4]}" @@ -2709,14 +2736,14 @@ function Sync { fi else if [ "$resumeInitiator" == "${SYNC_ACTION[3]}" ]; then - sync_update "${INITIATOR[$__type]}" "${TARGET[$__type]}" "${INITIATOR[$__deletedListFile]}" + syncUpdate "${INITIATOR[$__type]}" "${TARGET[$__type]}" if [ $? == 0 ]; then echo "${SYNC_ACTION[4]}" > "${INITIATOR[$__initiatorLastActionFile]}" resumeInitiator="${SYNC_ACTION[4]}" fi fi if [ "$resumeTarget" == "${SYNC_ACTION[3]}" ]; then - sync_update "${TARGET[$__type]}" "${INITIATOR[$__type]}" "${INITIATOR[$__deletedListFile]}" + syncUpdate "${TARGET[$__type]}" "${INITIATOR[$__type]}" if [ $? == 0 ]; then echo "${SYNC_ACTION[4]}" > "${INITIATOR[$__targetLastActionFile]}" resumeTarget="${SYNC_ACTION[4]}" @@ -2728,12 +2755,12 @@ function Sync { ## Step 4a & 4b if [ "$resumeInitiator" == "${SYNC_ACTION[4]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[4]}" ]; then if [ "$resumeInitiator" == "${SYNC_ACTION[4]}" ]; then - deletion_propagation "${TARGET[$__type]}" "${INITIATOR[$__deletedListFile]}" "${INITIATOR[$__failedDeletedListFile]}" & + deletionPropagation "${TARGET[$__type]}" & initiatorPid="$!" fi if [ "$resumeTarget" == "${SYNC_ACTION[4]}" ]; then - deletion_propagation "${INITIATOR[$__type]}" "${INITIATOR[$__deletedListFile]}" "${INITIATOR[$__failedDeletedListFile]}" & + deletionPropagation "${INITIATOR[$__type]}" & targetPid="$!" fi @@ -2774,12 +2801,12 @@ function Sync { ## Step 5a & 5b if [ "$resumeInitiator" == "${SYNC_ACTION[5]}" ] || [ "$resumeTarget" == "${SYNC_ACTION[5]}" ]; then if [ "$resumeInitiator" == "${SYNC_ACTION[5]}" ]; then - tree_list "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "${INITIATOR[$__treeAfterFile]}" & + treeList "${INITIATOR[$__replicaDir]}" "${INITIATOR[$__type]}" "${INITIATOR[$__treeAfterFile]}" & initiatorPid="$!" fi if [ "$resumeTarget" == "${SYNC_ACTION[5]}" ]; then - tree_list "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "${INITIATOR[$__treeAfterFile]}" & + treeList "${TARGET[$__replicaDir]}" "${TARGET[$__type]}" "${INITIATOR[$__treeAfterFile]}" & targetPid="$!" fi @@ -2821,50 +2848,51 @@ function Sync { } 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}" + local replicaType="${1}" # replica type (initiator, target) + local replicaDeletionPath="${2}" # Contains the full path to softdelete / backup directory without ending slash + local changeTime="${3}" + local retval - if [ -d "$replica_deletion_path" ]; then + if [ -d "$replicaDeletionPath" ]; then if [ $_DRYRUN == true ]; then - Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE" + Logger "Listing files older than $changeTime days on $replicaType replica. Does not remove anything." "NOTICE" else - Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE" + Logger "Removing files older than $changeTime days on $replicaType replica." "NOTICE" fi if [ $_VERBOSE == true ]; then # Cannot launch log function from xargs, ugly hack - $COMMAND_SUDO $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" + $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" - $COMMAND_SUDO $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" + $COMMAND_SUDO $FIND_CMD "$replicaDeletionPath/" -type d -empty -ctime +$changeTime -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)" "VERBOSE" fi if [ $_DRYRUN == false ]; then - $COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type f -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -f "{}" && $COMMAND_SUDO $FIND_CMD "$replica_deletion_path/" -type d -empty -ctime +$change_time -print0 | xargs -0 -I {} $COMMAND_SUDO rm -rf "{}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1 + $COMMAND_SUDO $FIND_CMD "$replicaDeletionPath/" -type f -ctime +$changeTime -print0 | xargs -0 -I {} $COMMAND_SUDO rm -f "{}" && $COMMAND_SUDO $FIND_CMD "$replicaDeletionPath/" -type d -empty -ctime +$changeTime -print0 | xargs -0 -I {} $COMMAND_SUDO rm -rf "{}" >> "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1 else Dummy fi retval=$? if [ $retval -ne 0 ]; then - Logger "Error while executing cleanup on $replica_type replica." "ERROR" + Logger "Error while executing cleanup on $replicaType replica." "ERROR" Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE" else - Logger "Cleanup complete on $replica_type replica." "NOTICE" + Logger "Cleanup complete on $replicaType replica." "NOTICE" fi - elif [ -d "$replica_deletion_path" ] && ! [ -w "$replica_deletion_path" ]; then - Logger "The $replica_type replica dir [$replica_deletion_path] is not writable. Cannot clean old files." "ERROR" + elif [ -d "$replicaDeletionPath" ] && ! [ -w "$replicaDeletionPath" ]; then + Logger "The $replicaType replica dir [$replicaDeletionPath] is not writable. Cannot clean old files." "ERROR" else - Logger "The $replica_type replica dir [$replica_deletion_path] does not exist. Skipping cleaning of old files." "VERBOSE" + Logger "The $replicaType replica dir [$replicaDeletionPath] does not exist. Skipping cleaning of old files." "VERBOSE" 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}" + local replicaType="${1}" + local replicaDeletionPath="${2}" # Contains the full path to softdelete / backup directory without ending slash + local changeTime="${3}" local retval @@ -2872,21 +2900,21 @@ function _SoftDeleteRemote { CheckConnectivityRemoteHost if [ $_DRYRUN == true ]; then - Logger "Listing files older than $change_time days on $replica_type replica. Does not remove anything." "NOTICE" + Logger "Listing files older than $changeTime days on $replicaType replica. Does not remove anything." "NOTICE" else - Logger "Removing files older than $change_time days on $replica_type replica." "NOTICE" + Logger "Removing files older than $changeTime days on $replicaType replica." "NOTICE" fi if [ $_VERBOSE == true ]; 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 {} && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} echo Will delete directory {}; else echo \"The $replica_type replica dir [$replica_deletion_path] does not exist. Skipping cleaning of old files.\"; fi" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' + 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" eval "$cmd" Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "VERBOSE" fi if [ $_DRYRUN == false ]; 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 {} '$COMMAND_SUDO' rm -f \"{}\" && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replica_deletion_path'/\" -type d -empty -ctime '$change_time' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -rf \"{}\"; else echo \"The $replica_type replica_dir [$replica_deletion_path] does not exist. Skipping cleaning of old files.\"; fi" >> "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' + cmd=$SSH_CMD' "if [ -d \"'$replicaDeletionPath'\" ]; then '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replicaDeletionPath'/\" -type f -ctime +'$changeTime' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -f \"{}\" && '$COMMAND_SUDO' '$REMOTE_FIND_CMD' \"'$replicaDeletionPath'/\" -type d -empty -ctime '$changeTime' -print0 | xargs -0 -I {} '$COMMAND_SUDO' rm -rf \"{}\"; else echo \"The $replicaType replicaDir [$replicaDeletionPath] does not exist. Skipping cleaning of old files.\"; fi" >> "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" @@ -2895,10 +2923,10 @@ function _SoftDeleteRemote { fi retval=$? if [ $retval -ne 0 ]; then - Logger "Error while executing cleanup on remote $replica_type replica." "ERROR" + Logger "Error while executing cleanup on remote $replicaType replica." "ERROR" Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID)" "NOTICE" else - Logger "Cleanup complete on $replica_type replica." "NOTICE" + Logger "Cleanup complete on $replicaType replica." "NOTICE" fi } @@ -3006,17 +3034,17 @@ function Init { ## Replica format ## Why the f*** does bash not have simple objects ? # 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 lockFilename="lock" + local stateDir="state" + local backupDir="backup" + local deleteDir="deleted" + local partialDir="_partial" + local lastAction="last-action" + local resumeCount="resume-count" if [ "$_DRYRUN" == true ]; then - local dry_suffix="-dry" + local drySuffix="-dry" else - local dry_suffix= + local drySuffix= fi # The following associative like array definitions are used for bash ver < 4 compat @@ -3033,33 +3061,33 @@ function Init { readonly __treeCurrentFile=10 readonly __treeAfterFile=11 readonly __treeAfterFileNoSuffix=12 - readonly __deletedListfile=13 + readonly __deletedListFile=13 readonly __failedDeletedListFile=14 INITIATOR=() INITIATOR[$__type]='initiator' INITIATOR[$__replicaDir]="$INITIATOR_SYNC_DIR" - INITIATOR[$__lockFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$lock_filename" - INITIATOR[$__stateDir]="$OSYNC_DIR/$state_dir" - INITIATOR[$__backupDir]="$OSYNC_DIR/$backup_dir" - INITIATOR[$__deleteDir]="$OSYNC_DIR/$delete_dir" - INITIATOR[$__partialDir]="$OSYNC_DIR/$partial_dir" - INITIATOR[$__initiatorLastActionFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/initiator-$last_action-$INSTANCE_ID$dry_suffix" - INITIATOR[$__targetLastActionFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/target-$last_action-$INSTANCE_ID$dry_suffix" - INITIATOR[$__resumeCount]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix" - INITIATOR[$__treeCurrentFile]="-tree-current-$INSTANCE_ID$dry_suffix" - INITIATOR[$__treeAfterFile]="-tree-after-$INSTANCE_ID$dry_suffix" + INITIATOR[$__lockFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$lockFilename" + INITIATOR[$__stateDir]="$OSYNC_DIR/$stateDir" + INITIATOR[$__backupDir]="$OSYNC_DIR/$backupDir" + INITIATOR[$__deleteDir]="$OSYNC_DIR/$deleteDir" + INITIATOR[$__partialDir]="$OSYNC_DIR/$partialDir" + INITIATOR[$__initiatorLastActionFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$stateDir/initiator-$lastAction-$INSTANCE_ID$drySuffix" + INITIATOR[$__targetLastActionFile]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$stateDir/target-$lastAction-$INSTANCE_ID$drySuffix" + INITIATOR[$__resumeCount]="$INITIATOR_SYNC_DIR$OSYNC_DIR/$stateDir/$resumeCount-$INSTANCE_ID$drySuffix" + INITIATOR[$__treeCurrentFile]="-tree-current-$INSTANCE_ID$drySuffix" + INITIATOR[$__treeAfterFile]="-tree-after-$INSTANCE_ID$drySuffix" INITIATOR[$__treeAfterFileNoSuffix]="-tree-after-$INSTANCE_ID" - INITIATOR[$__deletedListFile]="-deleted-list-$INSTANCE_ID$dry_suffix" - INITIATOR[$__failedDeletedListFile]="-failed-delete-$INSTANCE_ID$dry_suffix" + INITIATOR[$__deletedListFile]="-deleted-list-$INSTANCE_ID$drySuffix" + INITIATOR[$__failedDeletedListFile]="-failed-delete-$INSTANCE_ID$drySuffix" TARGET=() TARGET[$__type]='target' TARGET[$__replicaDir]="$TARGET_SYNC_DIR" - TARGET[$__lockFile]="$TARGET_SYNC_DIR$OSYNC_DIR/$lock_filename" - TARGET[$__stateDir]="$OSYNC_DIR/$state_dir" - TARGET[$__backupDir]="$OSYNC_DIR/$backup_dir" - TARGET[$__deleteDir]="$OSYNC_DIR/$delete_dir" + TARGET[$__lockFile]="$TARGET_SYNC_DIR$OSYNC_DIR/$lockFilename" + TARGET[$__stateDir]="$OSYNC_DIR/$stateDir" + TARGET[$__backupDir]="$OSYNC_DIR/$backupDir" + TARGET[$__deleteDir]="$OSYNC_DIR/$deleteDir" PARTIAL_DIR="${INITIATOR[$__partialDir]}" @@ -3075,9 +3103,7 @@ function Init { fi ## Add Rsync include / exclude patterns - if [ $_QUICK_SYNC -lt 2 ]; then - RsyncPatterns - fi + RsyncPatterns ## Conflict options if [ "$CONFLICT_BACKUP" != "no" ]; then @@ -3117,8 +3143,8 @@ function Usage { fi echo "$PROGRAM $PROGRAM_VERSION $PROGRAM_BUILD" - echo $AUTHOR - echo $CONTACT + 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]" diff --git a/upgrade-v1.0x-v1.2x.sh b/upgrade-v1.0x-v1.2x.sh index c659026..50a24d7 100755 --- a/upgrade-v1.0x-v1.2x.sh +++ b/upgrade-v1.0x-v1.2x.sh @@ -6,7 +6,8 @@ AUTHOR="(C) 2016 by Orsiris de Jong" CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr" OLD_PROGRAM_VERSION="v1.0x-v1.1x" NEW_PROGRAM_VERSION="v1.2x" -PROGRAM_BUILD=2016081902 # Will go into config file rev +CONFIG_FILE_VERSION=2016081901 +PROGRAM_BUILD=2016101701 ## 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 @@ -14,6 +15,141 @@ if ! type "$BASH" > /dev/null; then exit 127 fi +# Defines all keywords / value sets in osync configuration files +# bash does not support two dimensional arrays, so we declare two arrays: +# ${KEYWORDS[index]}=${VALUES[index]} + +KEYWORDS=( +INSTANCE_ID +INITIATOR_SYNC_DIR +TARGET_SYNC_DIR +SSH_RSA_PRIVATE_KEY +CREATE_DIRS +LOGFILE +MINIMUM_SPACE +BANDWIDTH +SUDO_EXEC +RSYNC_EXECUTABLE +RSYNC_REMOTE_PATH +RSYNC_PATTERN_FIRST +RSYNC_INCLUDE_PATTERN +RSYNC_EXCLUDE_PATTERN +RSYNC_INCLUDE_FROM +RSYNC_EXCLUDE_FROM +PATH_SEPARATOR_CHAR +SSH_COMPRESSION +SSH_IGNORE_KNOWN_HOSTS +REMOTE_HOST_PING +REMOTE_3RD_PARTY_HOSTS +PRESERVE_PERMISSIONS +PRESERVE_OWNER +PRESERVE_GROUP +PRESERVE_EXECUTABILITY +PRESERVE_ACL +PRESERVE_XATTR +COPY_SYMLINKS +KEEP_DIRLINKS +PRESERVE_HARDLINKS +CHECKSUM +RSYNC_COMPRESS +SOFT_MAX_EXEC_TIME +HARD_MAX_EXEC_TIME +KEEP_LOGGING +MIN_WAIT +MAX_WAIT +CONFLICT_BACKUP +CONFLICT_BACKUP_MULTIPLE +CONFLICT_BACKUP_DAYS +CONFLICT_PREVALANCE +SOFT_DELETE +SOFT_DELETE_DAYS +RESUME_SYNC +RESUME_TRY +FORCE_STRANGER_LOCK_RESUME +PARTIAL +DELTA_COPIES +DESTINATION_MAILS +SENDER_MAIL +SMTP_SERVER +SMTP_PORT +SMTP_ENCRYPTION +SMTP_USER +SMTP_PASSWORD +LOCAL_RUN_BEFORE_CMD +LOCAL_RUN_AFTER_CMD +REMOTE_RUN_BEFORE_CMD +REMOTE_RUN_AFTER_CMD +MAX_EXEC_TIME_PER_CMD_BEFORE +MAX_EXEC_TIME_PER_CMD_AFTER +STOP_ON_CMD_ERROR +RUN_AFTER_CMD_ON_ERROR +) + +VALUES=( +sync-test +'' +'' +${HOME}/backupuser/.ssh/id_rsa +no +'' +10240 +0 +no +rsync +'' +include +'' +'' +'' +'' +\; +yes +no +no +www.kernel.org www.google.com +yes +yes +yes +yes +no +no +no +no +no +yes +7200 +10600 +1801 +60 +7200 +yes +no +30 +initiator +yes +30 +yes +2 +no +no +yes +'' +alert@your.system.tld +smtp.your.isp.tld +25 +none +'' +'' +'' +'' +'' +'' +0 +0 +yes +no +) + function Init { OSYNC_DIR=".osync_workdir" STATE_DIR="state" @@ -309,7 +445,7 @@ function RenameStateFiles { fi } -function RewriteConfigFiles { +function RewriteOldConfigFiles { local config_file="${1}" if ((! grep "MASTER_SYNC_DIR=" "$config_file" > /dev/null) && (! grep "INITIATOR_SYNC_DIR=" "$config_file" > /dev/null)); then @@ -334,67 +470,38 @@ function RewriteConfigFiles { sed -i'.tmp' 's/^CONFLICT_PREVALANCE=slave/CONFLICT_PREVALANCE=target/g' "$config_file" sed -i'.tmp' 's/^SYNC_ID=/INSTANCE_ID=/g' "$config_file" - # Add new config file values from v1.1x - if ! grep "^RSYNC_PATTERN_FIRST=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^LOGFILE=*/a\'$'\n''RSYNC_PATTERN_FIRST=include\'$'\n''' "$config_file" - fi - - if ! grep "^SSH_IGNORE_KNOWN_HOSTS=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^SSH_COMPRESSION=*/a\'$'\n''SSH_IGNORE_KNOWN_HOSTS=no\'$'\n''' "$config_file" - fi - - if ! grep "^RSYNC_INCLUDE_PATTERN=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^RSYNC_EXCLUDE_PATTERN=*/a\'$'\n''RSYNC_INCLUDE_PATTERN=""\'$'\n''' "$config_file" - fi - - if ! grep "^RSYNC_INCLUDE_FROM=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^RSYNC_EXCLUDE_FROM=*/a\'$'\n''RSYNC_INCLUDE_FROM=""\'$'\n''' "$config_file" - fi - - if ! grep "^PRESERVE_PERMISSIONS=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^REMOTE_3RD_PARTY_HOSTS=*/a\'$'\n''PRESERVE_PERMISSIONS=yes\'$'\n''' "$config_file" - fi - - if ! grep "^PRESERVE_OWNER=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^PRESERVE_PERMISSIONS=*/a\'$'\n''PRESERVE_OWNER=yes\'$'\n''' "$config_file" - fi - - if ! grep "^PRESERVE_GROUP=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^PRESERVE_OWNER=*/a\'$'\n''PRESERVE_GROUP=yes\'$'\n''' "$config_file" - fi - - if ! grep "^PRESERVE_EXECUTABILITY=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^PRESERVE_GROUP=*/a\'$'\n''PRESERVE_EXECUTABILITY=yes\'$'\n''' "$config_file" - fi - - if ! grep "^CHECKSUM=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^PRESERVE_HARDLINKS=*/a\'$'\n''CHECKSUM=no\'$'\n''' "$config_file" - fi - - if ! grep "^KEEP_LOGGING=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^HARD_MAX_EXEC_TIME=*/a\'$'\n''KEEP_LOGGING=1801\'$'\n''' "$config_file" - fi - - if ! grep "^MAX_WAIT=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^MIN_WAIT=*/a\'$'\n''MAX_WAIT=300\'$'\n''' "$config_file" - fi - - if ! grep "^PARTIAL=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^FORCE_STRANGER_LOCK_RESUME=*/a\'$'\n''PARTIAL=no\'$'\n''' "$config_file" - fi + rm -f "$config_file.tmp" +} - if ! grep "^DELTA_COPIES=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^PARTIAL=*/a\'$'\n''DELTA_COPIES=yes\'$'\n''' "$config_file" - fi +function AddMissingConfigOptions { + local config_file="${1}" + local counter=0 + + while [ $counter -lt ${#KEYWORDS[@]} ]; do + if ! grep "^${KEYWORDS[$counter]}=" > /dev/null "$config_file"; then + echo "${KEYWORDS[$counter]} not found" + if [ $counter -gt 0 ]; then + sed -i'.tmp' '/^'${KEYWORDS[$((counter-1))]}'=*/a\'$'\n'${KEYWORDS[$counter]}'="'"${VALUES[$counter]}"'"\'$'\n''' "$config_file" + if [ $? -ne 0 ]; then + echo "Cannot add missing ${[KEYWORDS[$counter]}." + exit 1 + fi + else + sed -i'.tmp' '/onfig file rev*/a\'$'\n'${KEYWORDS[$counter]}'="'"${VALUES[$counter]}"'"\'$'\n''' "$config_file" + fi + echo "Added missing ${KEYWORDS[$counter]} config option with default option [${VALUES[$counter]}]" + fi + counter=$((counter+1)) + done +} - if ! grep "^RUN_AFTER_CMD_ON_ERROR=" "$config_file" > /dev/null; then - sed -i'.tmp' '/^STOP_ON_CMD_ERROR=*/a\'$'\n''RUN_AFTER_CMD_ON_ERROR=no\'$'\n''' "$config_file" - fi +function UpdateConfigHeader { + local config_file="${1}" - # "onfig file rev" to deal with earlier variants of the file - sed -i'.tmp' '/onfig file rev/c\###### '$SUBPROGRAM' config file rev '$PROGRAM_BUILD "$config_file" + # "onfig file rev" to deal with earlier variants of the file + sed -i'.tmp' '/onfig file rev/c\###### '$SUBPROGRAM' config file rev '$CONFIG_FILE_VERSION' '$NEW_PROGRAM_VERSION "$config_file" - rm -f "$config_file.tmp" + rm -f "$config_file.tmp" } _QUICKSYNC=0 @@ -431,7 +538,9 @@ elif [ "$1" != "" ] && [ -f "$1" ] && [ -w "$1" ]; then CONF_FILE="${CONF_FILE%/}" LoadConfigFile "$CONF_FILE" Init - RewriteConfigFiles "$CONF_FILE" + RewriteOldConfigFiles "$CONF_FILE" + AddMissingConfigOptions "$CONF_FILE" + UpdateConfigHeader "$CONF_FILE" RenameStateFiles else Usage