diff --git a/dev/debug_osync.sh b/dev/debug_osync.sh index 8248772..ff96b0b 100755 --- a/dev/debug_osync.sh +++ b/dev/debug_osync.sh @@ -4,7 +4,7 @@ PROGRAM="osync" # Rsync based two way sync engine with fault tolerance AUTHOR="(L) 2013-2016 by Orsiris de Jong" CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr" PROGRAM_VERSION=1.1-dev -PROGRAM_BUILD=2016021602 +PROGRAM_BUILD=2016021703 IS_STABLE=no FUNC_BUILD=2016021604 @@ -924,7 +924,7 @@ function InitRemoteOSSettings { ## END Generic functions -## Working directory. This is the name of the osync subdirectory contained in every replica. +## Working directory. This directory exists in any replica and contains state files, backups, soft deleted files etc OSYNC_DIR=".osync_workdir" function TrapStop { @@ -964,6 +964,7 @@ function TrapQuit { fi CleanUp Logger "$PROGRAM finished with warnings." "WARN" + exitcode=2 else UnlockReplicas CleanUp @@ -1066,7 +1067,7 @@ function _CreateStateDirsRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if ! [ -d \"'$replica_state_dir'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_state_dir'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "if ! [ -d \"'$replica_state_dir'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_state_dir'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1080,11 +1081,11 @@ function _CreateStateDirsRemote { function CreateStateDirs { __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG - _CreateStateDirsLocal "$INITIATOR_STATE_DIR" + _CreateStateDirsLocal "${INITIATOR[1]}${INITIATOR[3]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CreateStateDirsLocal "$TARGET_STATE_DIR" + _CreateStateDirsLocal "${TARGET[1]}${TARGET[3]}" else - _CreateStateDirsRemote "$TARGET_STATE_DIR" + _CreateStateDirsRemote "${TARGET[1]}${TARGET[3]}" fi } @@ -1120,7 +1121,7 @@ function _CheckReplicaPathsRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if ! [ -d \"'$replica_path'\" ]; then if [ \"'$CREATE_DIRS'\" == \"yes\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_path'\"; fi; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "if ! [ -d \"'$replica_path'\" ]; then if [ \"'$CREATE_DIRS'\" == \"yes\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_path'\"; fi; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1130,7 +1131,7 @@ function _CheckReplicaPathsRemote { exit 1 fi - cmd=$SSH_CMD' "if [ ! -w \"'$replica_path'\" ];then exit 1; fi" 2>&1' + local cmd=$SSH_CMD' "if [ ! -w \"'$replica_path'\" ];then exit 1; fi" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1144,7 +1145,7 @@ function CheckReplicaPaths { __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG #INITIATOR_SYNC_DIR_CANN=$(realpath "$INITIATOR_SYNC_DIR") #TODO: investigate realpath & readlink issues on MSYS and busybox here - #TARGET_SYNC_DIR_CANN=$(realpath "$TARGET_SYNC_DIR") + #TARGET_SYNC_DIR_CANN=$(realpath "$TARGET_SYNC_DIR") #TODO2: replace all variables with INITIATOR object #if [ "$REMOTE_OPERATION" != "yes" ]; then # if [ "$INITIATOR_SYNC_DIR_CANN" == "$TARGET_SYNC_DIR_CANN" ]; then @@ -1153,11 +1154,11 @@ function CheckReplicaPaths { # fi #fi - _CheckReplicaPathsLocal "$INITIATOR_SYNC_DIR" + _CheckReplicaPathsLocal "${INITIATOR[1]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckReplicaPathsLocal "$TARGET_SYNC_DIR" + _CheckReplicaPathsLocal "${TARGET[1]}" else - _CheckReplicaPathsRemote "$TARGET_SYNC_DIR" + _CheckReplicaPathsRemote "${TARGET[1]}" fi } @@ -1167,9 +1168,9 @@ function _CheckDiskSpaceLocal { Logger "Checking minimum disk space in [$replica_path]." "NOTICE" - local initiator_space=$(df -P "$replica_path" | tail -1 | awk '{print $4}') - if [ $initiator_space -lt $MINIMUM_SPACE ]; then - Logger "There is not enough free space on initiator [$initiator_space KB]." "WARN" + local disk_space=$(df -P "$replica_path" | tail -1 | awk '{print $4}') + if [ $disk_space -lt $MINIMUM_SPACE ]; then + Logger "There is not enough free space on replica [$replica_path] ($disk_space KB)." "WARN" fi } @@ -1182,7 +1183,7 @@ function _CheckDiskSpaceRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "'$COMMAND_SUDO' df -P \"'$replica_path'\"" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "'$COMMAND_SUDO' df -P \"'$replica_path'\"" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1190,9 +1191,9 @@ function _CheckDiskSpaceRemote { Logger "Cannot get free space on target [$replica_path]." "ERROR" Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID)" "NOTICE" else - local target_space=$(cat $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID | tail -1 | awk '{print $4}') - if [ $target_space -lt $MINIMUM_SPACE ]; then - Logger "There is not enough free space on target [$replica_path]." "WARN" + local disk_space=$(cat $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID | tail -1 | awk '{print $4}') + if [ $tdisk_space -lt $MINIMUM_SPACE ]; then + Logger "There is not enough free space on replica [$replica_path] ($disk_space KB)." "WARN" fi fi } @@ -1200,11 +1201,11 @@ function _CheckDiskSpaceRemote { function CheckDiskSpace { __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG - _CheckDiskSpaceLocal "$INITIATOR_SYNC_DIR" + _CheckDiskSpaceLocal "${INITIATOR[1]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckDiskSpaceLocal "$TARGET_SYNC_DIR" + _CheckDiskSpaceLocal "${TARGET[1]}" else - _CheckDiskSpaceRemote "$TARGET_SYNC_DIR" + _CheckDiskSpaceRemote "${TARGET[1]}" fi } @@ -1216,7 +1217,7 @@ function RsyncPatternsAdd { # Disable globbing so wildcards from exclusions do not get expanded set -f - rest="$pattern" + local rest="$pattern" while [ -n "$rest" ] do # Take the string until first occurence until $PATH_SEPARATOR_CHAR @@ -1299,7 +1300,7 @@ function _WriteLockFilesRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\"" > /dev/null 2>&1' + local cmd=$SSH_CMD' "echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\"" > /dev/null 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1314,11 +1315,11 @@ function _WriteLockFilesRemote { function WriteLockFiles { __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG - _WriteLockFilesLocal "$INITIATOR_LOCKFILE" + _WriteLockFilesLocal "${INITIATOR[2]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _WriteLockFilesLocal "$TARGET_LOCKFILE" + _WriteLockFilesLocal "${TARGET[2]}" else - _WriteLockFilesRemote "$TARGET_LOCKFILE" + _WriteLockFilesRemote "${TARGET[2]}" fi } @@ -1348,7 +1349,7 @@ function _CheckLocksRemote { #TODO: Rewrite this a bit more beautiful CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then cat \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'"' + local cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then cat \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'"' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1400,11 +1401,11 @@ function CheckLocks { exit 1 fi fi - _CheckLocksLocal "$INITIATOR_LOCKFILE" + _CheckLocksLocal "${INITIATOR[2]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckLocksLocal "$TARGET_LOCKFILE" + _CheckLocksLocal "${TARGET[2]}" else - _CheckLocksRemote "$TARGET_LOCKFILE" + _CheckLocksRemote "${TARGET{2]}" fi WriteLockFiles @@ -1431,7 +1432,7 @@ function _UnlockReplicasRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then '$COMMAND_SUDO' rm -f \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then '$COMMAND_SUDO' rm -f \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1450,11 +1451,11 @@ function UnlockReplicas { return 0 fi - _UnlockReplicasLocal "$INITIATOR_LOCKFILE" + _UnlockReplicasLocal "${INITIATOR[2]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _UnlockReplicasLocal "$TARGET_LOCKFILE" + _UnlockReplicasLocal "${TARGET[2]}" else - _UnlockReplicasRemote "$TARGET_LOCKFILE" + _UnlockReplicasRemote "${TARGET[2]}" fi } @@ -1477,9 +1478,9 @@ function tree_list { if [ "$REMOTE_OPERATION" == "yes" ] && [ "$replica_type" == "target" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_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\" &" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" --list-only $REMOTE_USER@$REMOTE_HOST:\"$escaped_replica_path/\" | grep \"^-\|^d\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID\" &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_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\" &" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --list-only \"$replica_path/\" | grep \"^-\|^d\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID\" &" fi Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" ## Redirect commands stderr here to get rsync stderr output in logfile @@ -1488,7 +1489,7 @@ function tree_list { retval=$? ## Retval 24 = some files vanished while creating list if ([ $retval == 0 ] || [ $retval == 24 ]) && [ -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" ]; then - mv -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" "$INITIATOR_STATE_DIR/$replica_type$tree_filename" + mv -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_filename" return $? else Logger "Cannot create replica file list." "CRITICAL" @@ -1508,13 +1509,13 @@ function delete_list { # TODO: Check why external filenames are used (see _DRYRUN option because of NOSUFFIX) Logger "Creating $replica_type replica deleted file list." "NOTICE" - if [ -f "$INITIATOR_STATE_DIR/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX" ]; then + if [ -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX" ]; then ## Same functionnality, comm is much faster than grep but is not available on every platform if type comm > /dev/null 2>&1 ; then - cmd="comm -23 \"$INITIATOR_STATE_DIR/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" \"$INITIATOR_STATE_DIR/$replica_type$tree_file_current\" > \"$INITIATOR_STATE_DIR/$replica_type$deleted_list_file\"" + cmd="comm -23 \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_file_current\" > \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file\"" else ## The || : forces the command to have a good result - cmd="(grep -F -x -v -f \"$INITIATOR_STATE_DIR/$replica_type$tree_file_current\" \"$INITIATOR_STATE_DIR/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" || :) > \"$INITIATOR_STATE_DIR/$replica_type$deleted_list_file\"" + cmd="(grep -F -x -v -f \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_file_current\" \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" || :) > \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file\"" fi Logger "CMD: $cmd" "DEBUG" @@ -1522,24 +1523,37 @@ function delete_list { retval=$? # Add delete failed file list to current delete list and then empty it - if [ -f "$INITIATOR_STATE_DIR/$replica_type$deleted_failed_list_file" ]; then - cat "$INITIATOR_STATE_DIR/$replica_type$deleted_failed_list_file" >> "$INITIATOR_STATE_DIR/$replica_type$deleted_list_file" - rm -f "$INITIATOR_STATE_DIR/$replica_type$deleted_failed_list_file" + if [ -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" ]; then + cat "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" >> "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file" + rm -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" fi return $retval else - touch "$INITIATOR_STATE_DIR/$replica_type$deleted_list_file" + touch "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file" return $retval fi } function _get_file_attrs_local { - __CheckArguments 1 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG + 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 "$@" #__WITH_PARANOIA_DEBUG + + cd "$replica_path" + cat "$file_list" | xargs -I {} stat -c '%n|%Z|%Y' "{}" | sort > "$RUN_DIR/$PROGRAM.$FUNCNAME.$replica_type.$SCRIPT_PID" } function _get_file_attrs_remote { - __CheckArguments 1 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG + local replica_path="${1}" # Contains replica path + local replica_type="${2}" + local file_list="${3}" + __CheckArguments 3 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG + + #cmd='cat "'$file_list'" | '$SSH_CMD' cd "'$replica_path'"; xargs -I {} stat -c \'%n|%Z|%Y\' "{}" | sort > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$replica_type.$SCRIPT_PID'"' + Logger "CMD: $cmd" "DEBUG" + eval "$cmd" } function sync_attrs { @@ -1547,12 +1561,14 @@ function sync_attrs { local target_replica="${2}" __CheckArguments 2 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG + Logger "Getting file attributes." "NOTICE" + if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" \"$initiator_replica/\" $REMOTE_USER@$REMOTE_HOST:\"$target_replica/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiator_replica\" $REMOTE_USER@$REMOTE_HOST:\"$target_replica\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" \"$initiator_replica/\" \"$target_replica/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiator_replica\" \"$target_replica\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" fi Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" @@ -1569,15 +1585,18 @@ function sync_attrs { fi exit $retval else - cat "$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID" | grep -Ev "^[^ ]*(c|s|t)[^ ]* " | grep -E "^[^ ]*(p|o|g|a)[^ ]* " | sed -e 's/^[^ ]* //' > "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" - Logger "Getting file attributes on replicas succeded." "NOTICE" + cat "$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID" | ( grep -Ev "^[^ ]*(c|s|t)[^ ]* " || :) | ( grep -E "^[^ ]*(p|o|g|a)[^ ]* " || :) | ( sed -e 's/^[^ ]* //' || :) > "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" + if [ $? != 0 ]; then + Logger "Cannot prepare file attribute list." "CRITICAL" + exit 1 + fi fi - _get_file_attrs_local "$INITIATOR_SYNC_DIR" + _get_file_attrs_local "${INITIATOR[1]}" "${INITIATOR[0]}" "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" if [ "$REMOTE_OPERATION" != "yes" ]; then - _get_file_attrs_remote $(EscapeSpaces "$TARGET_SYNC_DIR") + _get_file_attrs_remote "${TARGET[1]}" "${TARGET[0]}" "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" else - _get_file_attrs_local "$TARGET_SYNC_DIR" + _get_file_attrs_local "${TARGET[1]}" "${TARGET[0]}" "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" fi #WIP @@ -1594,30 +1613,30 @@ function sync_update { __CheckArguments 3 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG Logger "Updating $destination_replica replica." "NOTICE" - if [ "$source_replica" == "initiator" ]; then - SOURCE_DIR="$INITIATOR_SYNC_DIR" - ESC_SOURCE_DIR=$(EscapeSpaces "$INITIATOR_SYNC_DIR") - DEST_DIR="$TARGET_SYNC_DIR" - ESC_DEST_DIR=$(EscapeSpaces "$TARGET_SYNC_DIR") - BACKUP_DIR="$TARGET_BACKUP" + if [ "$source_replica" == "${INITIATOR[0]}" ]; then + local source_dir="${INITIATOR[1]}" + local esc_source_dir=$(EscapeSpaces "${INITIATOR[1]}") + local dest_dir="${TARGET[1]}" + local esc_dest_dir=$(EscapeSpaces "${TARGET[1]}") + local backup_args="$TARGET_BACKUP_ARGS" else - SOURCE_DIR="$TARGET_SYNC_DIR" - ESC_SOURCE_DIR=$(EscapeSpaces "$TARGET_SYNC_DIR") - DEST_DIR="$INITIATOR_SYNC_DIR" - ESC_DEST_DIR=$(EscapeSpaces "$INITIATOR_SYNC_DIR") - BACKUP_DIR="$INITIATOR_BACKUP" + local source_dir="${TARGET[1]}" + local esc_source_dir=$(EscapeSpaces "${TARGET[1]}") + local dest_dir="${INITIATOR[1]}" + local esc_dest_dir=$(EscapeSpaces "${INITIATOR[1]}") + local backup_args="$INITIATOR_BACKUP" fi if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - if [ "$source_replica" == "initiator" ]; then - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$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 [ "$source_replica" == "${INITIATOR[0]}" ]; then + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" \"$source_dir\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" $REMOTE_USER@$REMOTE_HOST:\"$ESC_SOURCE_DIR/\" \"$DEST_DIR/\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" fi else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" \"$SOURCE_DIR/\" \"$DEST_DIR/\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" \"$source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" fi Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" @@ -1651,7 +1670,7 @@ function _delete_local { previous_file="" OLD_IFS=$IFS IFS=$'\r\n' - for files in $(cat "$INITIATOR_STATE_DIR/$deleted_list_file") + for files in $(cat "${INITIATOR[1]}${INITIATOR[3]}/$deleted_list_file") do if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then if [ "$SOFT_DELETE" != "no" ]; then @@ -1668,7 +1687,7 @@ function _delete_local { if [ $_DRYRUN -ne 1 ]; then if [ -e "$replica_dir$deletion_dir/$files" ]; then - rm -rf "${replica_dir:?}$deletion_dir/$files" + rm -rf "${replica_dir:?}$deletion_dir/$files" #TODO: WTF :? fi # In order to keep full path on soft deletion, create parent directories before move parentdir="$(dirname "$files")" @@ -1680,7 +1699,7 @@ function _delete_local { fi if [ $? != 0 ]; then Logger "Cannot move $replica_dir$files to deletion directory." "ERROR" - echo "$files" >> "$INITIATOR_STATE_DIR/$deleted_failed_list_file" + echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file" fi fi else @@ -1692,7 +1711,7 @@ function _delete_local { rm -rf "$replica_dir$files" if [ $? != 0 ]; then Logger "Cannot delete $replica_dir$files" "ERROR" - echo "$files" >> "$INITIATOR_STATE_DIR/$deleted_failed_list_file" + echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file" fi fi fi @@ -1713,8 +1732,8 @@ function _delete_remote { ## 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_STATE_DIR")" - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" \"$INITIATOR_STATE_DIR/$2\" $REMOTE_USER@$REMOTE_HOST:\"$ESC_DEST_DIR/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.precopy.$SCRIPT_PID 2>&1" + local esc_dest_dir="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}")" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" \"${INITIATOR[1]}$INITIATOR[3]}/$2\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.precopy.$SCRIPT_PID 2>&1" Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" 2>> "$LOG_FILE" if [ $? != 0 ]; then @@ -1725,7 +1744,7 @@ function _delete_remote { exit 1 fi -$SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_list_file")" REPLICA_DIR="$(EscapeSpaces "$replica_dir")" DELETE_DIR="$(EscapeSpaces "$deletion_dir")" FAILED_DELETE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$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 _SILENT=$_SILENT _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_list_file")" REPLICA_DIR="$(EscapeSpaces "$replica_dir")" DELETE_DIR="$(EscapeSpaces "$deletion_dir")" FAILED_DELETE_LIST="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}/$deleted_failed_list_file")" 'bash -s' << 'ENDSSH' > "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 & ## The following lines are executed remotely function _logger { @@ -1741,12 +1760,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG= local value="${1}" # What to log local level="${2}" # Log level: DEBUG, NOTICE, WARN, ERROR, CRITIAL - # Special case in daemon mode we should timestamp instead of counting seconds - if [ $sync_on_changes -eq 1 ]; then - prefix="$(date) - " - else - prefix="RTIME: $SECONDS - " - fi + prefix="RTIME: $SECONDS - " if [ "$level" == "CRITICAL" ]; then _logger "$prefix\e[41m$value\e[0m" @@ -1830,9 +1844,9 @@ ENDSSH sleep 5 ## Copy back the deleted failed file list - ESC_SOURCE_FILE="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_failed_list_file")" + local esc_source_file="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}/$deleted_failed_list_file")" #TODO: Need to check if file exists prior to copy (or add a filemask and copy all state files) - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$ESC_SOURCE_FILE\" \"$INITIATOR_STATE_DIR\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_file\" \"${INITIATOR[1]}${INITIATOR[3]}\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" 2>> "$LOG_FILE" if [ $? != 0 ]; then @@ -1857,11 +1871,11 @@ function deletion_propagation { Logger "Propagating deletions to $replica_type replica." "NOTICE" - if [ "$replica_type" == "initiator" ]; then - REPLICA_DIR="$INITIATOR_SYNC_DIR" - DELETE_DIR="$INITIATOR_DELETE_DIR" + if [ "$replica_type" == "{$INITIATOR[0]}" ]; then + local replica_dir="${INITIATOR[1]}${INITIATOR[3]}/" + local delete_dir="${INITIATOR[5]}" - _delete_local "$REPLICA_DIR" "target$deleted_list_file" "$DELETE_DIR" "target$deleted_failed_list_file" & + _delete_local "$replica_dir" "${TARGET[0]}$deleted_list_file" "$delete_dir" "${TARGET[0]}$deleted_failed_list_file" & WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME $FUNCNAME retval=$? if [ $retval != 0 ]; then @@ -1869,13 +1883,13 @@ function deletion_propagation { exit 1 fi else - REPLICA_DIR="$TARGET_SYNC_DIR" - DELETE_DIR="$TARGET_DELETE_DIR" + local replica_dir="${TARGET[1]}${TARGET[3]}/" + local delete_dir="${TARGET[5]}" if [ "$REMOTE_OPERATION" == "yes" ]; then - _delete_remote "$REPLICA_DIR" "initiator$deleted_list_file" "$DELETE_DIR" "initiator$deleted_failed_list_file" & + _delete_remote "$replica_dir" "${INITIATOR[0]}$deleted_list_file" "$delete_dir" "${INITIATOR[0]}$deleted_failed_list_file" & else - _delete_local "$REPLICA_DIR" "initiator$deleted_list_file" "$DELETE_DIR" "initiator$deleted_failed_list_file" & + _delete_local "$replica_dir" "${INITIATOR[0]}$deleted_list_file" "$delete_dir" "${INITIATOR[0]}$deleted_failed_list_file" & fi WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME $FUNCNAME retval=$? @@ -1904,31 +1918,33 @@ function deletion_propagation { ###### Step 5: Create after run tree list for initiator and target replicas (Steps 5M and 5S) function Sync { + local resume count + local resume_sync __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG Logger "Starting synchronization task." "NOTICE" CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - if [ -f "$INITIATOR_LAST_ACTION" ] && [ "$RESUME_SYNC" != "no" ]; then - resume_sync=$(cat "$INITIATOR_LAST_ACTION") - if [ -f "$INITIATOR_RESUME_COUNT" ]; then - resume_count=$(cat "$INITIATOR_RESUME_COUNT") + if [ -f "${INITIATOR[7]}" ] && [ "$RESUME_SYNC" != "no" ]; then + resume_sync=$(cat "${INITIATOR[7]}") + if [ -f "${INITIATOR[8]}" ]; then + resume_count=$(cat "${INITIATOR[8]}") else resume_count=0 fi if [ $resume_count -lt $RESUME_TRY ]; then if [ "$resume_sync" != "sync.success" ]; then - Logger "WARNING: Trying to resume aborted osync execution on $($STAT_CMD "$INITIATOR_LAST_ACTION") at task [$resume_sync]. [$resume_count] previous tries." "WARN" - echo $(($resume_count+1)) > "$INITIATOR_RESUME_COUNT" + Logger "WARNING: Trying to resume aborted osync execution on $($STAT_CMD "${INITIATOR[7]}") at task [$resume_sync]. [$resume_count] previous tries." "WARN" + echo $(($resume_count+1)) > "${INITIATOR[8]}" else resume_sync=none fi else Logger "Will not resume aborted osync execution. Too many resume tries [$resume_count]." "WARN" - echo "noresume" > "$INITIATOR_LAST_ACTION" - echo "0" > "$INITIATOR_RESUME_COUNT" + echo "noresume" > "${INITIATOR[7]}" + echo "0" > "${INITIATOR[8]}" resume_sync=none fi else @@ -1941,87 +1957,87 @@ function Sync { ## This replaces the case statement because ;& operator is not supported in bash 3.2... Code is more messy than case :( if [ "$resume_sync" == "none" ] || [ "$resume_sync" == "noresume" ] || [ "$resume_sync" == "${SYNC_ACTION[0]}.fail" ]; then #initiator_tree_current - tree_list "$INITIATOR_SYNC_DIR" initiator "$TREE_CURRENT_FILENAME" + tree_list "${INITIATOR[1]}${INITIATOR[3]}" initiator "$TREE_CURRENT_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[0]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[0]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[0]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[0]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[0]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[1]}.fail" ]; then #target_tree_current - tree_list "$TARGET_SYNC_DIR" target "$TREE_CURRENT_FILENAME" + tree_list "${TARGET[1]}${TARGET[3]}" target "$TREE_CURRENT_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[1]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[1]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[1]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[1]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[1]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[2]}.fail" ]; then delete_list initiator "$TREE_AFTER_FILENAME" "$TREE_CURRENT_FILENAME" "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[2]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[2]}.success" > "${INITIATOR[7]}" else - echo "${SYNc_ACTION[2]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNc_ACTION[2]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[2]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[3]}.fail" ]; then delete_list target "$TREE_AFTER_FILENAME" "$TREE_CURRENT_FILENAME" "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[3]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[3]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[3]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[3]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[3]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.fail" ]; then sync_attrs "$INITIATOR_SYNC_DIR" "$TARGET_SYNC_DIR" if [ $? == 0 ]; then - echo "${SYNC_ACTION[4]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[4]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[4]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[4]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ]; then if [ "$CONFLICT_PREVALANCE" != "initiator" ]; then if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ]; then - sync_update target initiator "$DELETED_LIST_FILENAME" + sync_update ${TARGET[0]} ${INITIATOR[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[5]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[5]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ]; then - sync_update initiator target "$DELETED_LIST_FILENAME" + sync_update ${INITIATOR[0]} ${TARGET[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[6]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[6]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi else if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ]; then - sync_update initiator target "$DELETED_LIST_FILENAME" + sync_update ${INITIATOR[0]} ${TARGET[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[6]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[6]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ]; then - sync_update target initiator "$DELETED_LIST_FILENAME" + sync_update ${TARGET[0]} ${INITIATOR[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[5]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[5]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi @@ -2030,46 +2046,46 @@ function Sync { if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[7]}.fail" ]; then deletion_propagation target "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[7]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[7]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[7]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[7]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[7]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[8]}.fail" ]; then deletion_propagation initiator "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[8]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[8]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[8]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[8]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[8]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[9]}.fail" ]; then #initiator_tree_after - tree_list "$INITIATOR_SYNC_DIR" initiator "$TREE_AFTER_FILENAME" + tree_list "${INITIATOR[1]}${INITIATOR[3]}" ${INITIATOR[0]} "$TREE_AFTER_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[9]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[9]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[9]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[9]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[9]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[10]}.fail" ]; then #target_tree_after - tree_list "$TARGET_SYNC_DIR" target "$TREE_AFTER_FILENAME" + tree_list "${TARGET[1]}${TARGET[3]}" ${TARGET[0]} "$TREE_AFTER_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[10]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[10]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[10]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[10]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi Logger "Finished synchronization task." "NOTICE" - echo "${SYNC_ACTION[11]}" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[11]}" > "${INITIATOR[7]}" - echo "0" > "$INITIATOR_RESUME_COUNT" + echo "0" > "${INITIATOR[8]}" } function _SoftDeleteLocal { @@ -2157,22 +2173,22 @@ function SoftDelete { if [ "$CONFLICT_BACKUP" != "no" ] && [ $CONFLICT_BACKUP_DAYS -ne 0 ]; then Logger "Running conflict backup cleanup." "NOTICE" - _SoftDeleteLocal "intiator" "$INITIATOR_SYNC_DIR$INITIATOR_BACKUP_DIR" $CONFLICT_BACKUP_DAYS + _SoftDeleteLocal "${INITIATOR[0]}" "${INITIATOR[1]}${INITIATOR[4]}" $CONFLICT_BACKUP_DAYS if [ "$REMOTE_OPERATION" != "yes" ]; then - _SoftDeleteLocal "target" "$TARGET_SYNC_DIR$TARGET_BACKUP_DIR" $CONFLICT_BACKUP_DAYS + _SoftDeleteLocal "${TARGET[0]}" "${TARGET[1]}${TARGET[4]}" $CONFLICT_BACKUP_DAYS else - _SoftDeleteRemote "target" "$TARGET_SYNC_DIR$TARGET_BACKUP_DIR" $CONFLICT_BACKUP_DAYS + _SoftDeleteRemote "${TARGET[0]}" "${TARGET[1]}${TARGET[4]}" $CONFLICT_BACKUP_DAYS fi fi if [ "$SOFT_DELETE" != "no" ] && [ $SOFT_DELETE_DAYS -ne 0 ]; then Logger "Running soft deletion cleanup." "NOTICE" - _SoftDeleteLocal "initiator" "$INITIATOR_SYNC_DIR$INITIATOR_DELETE_DIR" $SOFT_DELETE_DAYS + _SoftDeleteLocal "${INITIATOR[0]}" "${INITIATOR[1]}${INITIATOR[5]}" $SOFT_DELETE_DAYS if [ "$REMOTE_OPERATION" != "yes" ]; then - _SoftDeleteLocal "target" "$TARGET_SYNC_DIR$TARGET_DELETE_DIR" $SOFT_DELETE_DAYS + _SoftDeleteLocal "${TARGET[0]}" "${TARGET[1]}${TARGET[5]}" $SOFT_DELETE_DAYS else - _SoftDeleteRemote "target" "$TARGET_SYNC_DIR$TARGET_DELETE_DIR" $SOFT_DELETE_DAYS + _SoftDeleteRemote "${TARGET[0]}" "${TARGET[1]}${TARGET[5]}" $SOFT_DELETE_DAYS fi fi } @@ -2228,23 +2244,56 @@ function Init { INITIATOR_SYNC_DIR="${INITIATOR_SYNC_DIR%/}/" TARGET_SYNC_DIR="${TARGET_SYNC_DIR%/}/" - INITIATOR_STATE_DIR="$INITIATOR_SYNC_DIR$OSYNC_DIR/state" - TARGET_STATE_DIR="$TARGET_SYNC_DIR$OSYNC_DIR/state" - STATE_DIR="$OSYNC_DIR/state" - INITIATOR_LOCKFILE="$INITIATOR_STATE_DIR/lock" - TARGET_LOCKFILE="$TARGET_STATE_DIR/lock" + ## Replica format + ## Why the f*** does bash not have simple objects ? + + #${REPLICA[0]} contains replica type (initiator / target) + #${REPLICA[1]} contains full replica path (can be absolute or relative) with ending slash + #${REPLICA[2]} contains full lock file path + #${REPLICA[3]} contains state dir path, relative to replica path + #${REPLICA[4]} contains backup dir path, relative to replica path + #${REPLICA[5]} contains deletion dir path, relative to replica path + #${REPLICA[6]} contains partial dir path, relative to replica path + #${REPLICA[7]} contains full last action file path + #${REPLICA[8]} contains full resume count file path + + # Local variables used for state filenames + local lock_filename="lock" + local state_dir="state" + local backup_dir="backup" + local delete_dir="deleted" + local partial_dir="_partial" + local last_action="last-action" + local resume_count="resume-count" + local dry_suffix="dry" + + #TODO: replace all other instances by the following + INITIATOR=( + 'initiator' + "$INITIATOR_SYNC_DIR" + "$INITIATOR_SYNC_DIR$OSYNC_DIR/$lock_filename" + "$OSYNC_DIR/$state_dir" + "$OSYNC_DIR/$backup_dir" + "$OSYNC_DIR/$delete_dir" + "$OSYNC_DIR/$partial_dir" + "$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$last_action-$INSTANCE_ID$dry_suffix" + "$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix" + ) - ## Working directories to keep backups of updated / deleted files - INITIATOR_BACKUP_DIR="$OSYNC_DIR/backups" - INITIATOR_DELETE_DIR="$OSYNC_DIR/deleted" - TARGET_BACKUP_DIR="$OSYNC_DIR/backups" - TARGET_DELETE_DIR="$OSYNC_DIR/deleted" + TARGET=( + 'target' + "$TARGET_SYNC_DIR" + "$TARGET_SYNC_DIR$OSYNC_DIR/$lock_filename" + "$OSYNC_DIR/$state_dir" + "$OSYNC_DIR/$backup_dir" + "$OSYNC_DIR/$delete_dir" + "$OSYNC_DIR/$partial_dir" + "$TARGET_SYNC_DIR$OSYNC_DIR/$state_dir/$last_action-$INSTANCE_ID$dry_suffix" + "$TARGET_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix" + ) - ## Partial downloads dirs PARTIAL_DIR=$OSYNC_DIR"_partial" - ## TODO: checksum=no / yes not implemented, be careful with sync_attrs which must itemize based on mtime - ## Set sync only function arguments for rsync SYNC_OPTS="-u" @@ -2256,19 +2305,6 @@ function Init { SYNC_OPTS=$SYNC_OPTS" --stats" fi - ## Conflict options - if [ "$CONFLICT_BACKUP" != "no" ]; then - INITIATOR_BACKUP="--backup --backup-dir=\"$INITIATOR_BACKUP_DIR\"" - TARGET_BACKUP="--backup --backup-dir=\"$TARGET_BACKUP_DIR\"" - if [ "$CONFLICT_BACKUP_MULTIPLE" == "yes" ]; then - INITIATOR_BACKUP="$INITIATOR_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" - TARGET_BACKUP="$TARGET_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" - fi - else - INITIATOR_BACKUP= - TARGET_BACKUP= - fi - ## Add Rsync include / exclude patterns if [ $_QUICK_SYNC -lt 2 ]; then RsyncPatterns @@ -2279,13 +2315,24 @@ function Init { dry_suffix="-dry" fi + ## Conflict options + if [ "$CONFLICT_BACKUP" != "no" ]; then + INITIATOR_BACKUP="--backup --backup-dir=\"${INITIATOR[1]}${INITIATOR[4]}\"" + TARGET_BACKUP="--backup --backup-dir=\"${TARGET[1]}${TARGET[4]}\"" + if [ "$CONFLICT_BACKUP_MULTIPLE" == "yes" ]; then + INITIATOR_BACKUP="$INITIATOR_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" + TARGET_BACKUP="$TARGET_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" + fi + else + INITIATOR_BACKUP=" + TARGET_BACKUP=" + fi + TREE_CURRENT_FILENAME="-tree-current-$INSTANCE_ID$dry_suffix" TREE_AFTER_FILENAME="-tree-after-$INSTANCE_ID$dry_suffix" TREE_AFTER_FILENAME_NO_SUFFIX="-tree-after-$INSTANCE_ID" DELETED_LIST_FILENAME="-deleted-list-$INSTANCE_ID$dry_suffix" FAILED_DELETE_LIST_FILENAME="-failed-delete-$INSTANCE_ID$dry_suffix" - INITIATOR_LAST_ACTION="$INITIATOR_STATE_DIR/last-action-$INSTANCE_ID$dry_suffix" - INITIATOR_RESUME_COUNT="$INITIATOR_STATE_DIR/resume-count-$INSTANCE_ID$dry_suffix" ## Sync function actions (0-10) SYNC_ACTION=( diff --git a/dev/n_osync.sh b/dev/n_osync.sh index af21ad3..5bc79dc 100755 --- a/dev/n_osync.sh +++ b/dev/n_osync.sh @@ -4,12 +4,12 @@ PROGRAM="osync" # Rsync based two way sync engine with fault tolerance AUTHOR="(L) 2013-2016 by Orsiris de Jong" CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr" PROGRAM_VERSION=1.1-dev -PROGRAM_BUILD=2016021602 +PROGRAM_BUILD=2016021703 IS_STABLE=no source "./ofunctions.sh" -## Working directory. This is the name of the osync subdirectory contained in every replica. +## Working directory. This directory exists in any replica and contains state files, backups, soft deleted files etc OSYNC_DIR=".osync_workdir" function TrapStop { @@ -49,6 +49,7 @@ function TrapQuit { fi CleanUp Logger "$PROGRAM finished with warnings." "WARN" + exitcode=2 else UnlockReplicas CleanUp @@ -151,7 +152,7 @@ function _CreateStateDirsRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if ! [ -d \"'$replica_state_dir'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_state_dir'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "if ! [ -d \"'$replica_state_dir'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_state_dir'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -165,11 +166,11 @@ function _CreateStateDirsRemote { function CreateStateDirs { __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG - _CreateStateDirsLocal "$INITIATOR_STATE_DIR" + _CreateStateDirsLocal "${INITIATOR[1]}${INITIATOR[3]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CreateStateDirsLocal "$TARGET_STATE_DIR" + _CreateStateDirsLocal "${TARGET[1]}${TARGET[3]}" else - _CreateStateDirsRemote "$TARGET_STATE_DIR" + _CreateStateDirsRemote "${TARGET[1]}${TARGET[3]}" fi } @@ -205,7 +206,7 @@ function _CheckReplicaPathsRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if ! [ -d \"'$replica_path'\" ]; then if [ \"'$CREATE_DIRS'\" == \"yes\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_path'\"; fi; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "if ! [ -d \"'$replica_path'\" ]; then if [ \"'$CREATE_DIRS'\" == \"yes\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_path'\"; fi; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -215,7 +216,7 @@ function _CheckReplicaPathsRemote { exit 1 fi - cmd=$SSH_CMD' "if [ ! -w \"'$replica_path'\" ];then exit 1; fi" 2>&1' + local cmd=$SSH_CMD' "if [ ! -w \"'$replica_path'\" ];then exit 1; fi" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -229,7 +230,7 @@ function CheckReplicaPaths { __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG #INITIATOR_SYNC_DIR_CANN=$(realpath "$INITIATOR_SYNC_DIR") #TODO: investigate realpath & readlink issues on MSYS and busybox here - #TARGET_SYNC_DIR_CANN=$(realpath "$TARGET_SYNC_DIR") + #TARGET_SYNC_DIR_CANN=$(realpath "$TARGET_SYNC_DIR") #TODO2: replace all variables with INITIATOR object #if [ "$REMOTE_OPERATION" != "yes" ]; then # if [ "$INITIATOR_SYNC_DIR_CANN" == "$TARGET_SYNC_DIR_CANN" ]; then @@ -238,11 +239,11 @@ function CheckReplicaPaths { # fi #fi - _CheckReplicaPathsLocal "$INITIATOR_SYNC_DIR" + _CheckReplicaPathsLocal "${INITIATOR[1]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckReplicaPathsLocal "$TARGET_SYNC_DIR" + _CheckReplicaPathsLocal "${TARGET[1]}" else - _CheckReplicaPathsRemote "$TARGET_SYNC_DIR" + _CheckReplicaPathsRemote "${TARGET[1]}" fi } @@ -252,9 +253,9 @@ function _CheckDiskSpaceLocal { Logger "Checking minimum disk space in [$replica_path]." "NOTICE" - local initiator_space=$(df -P "$replica_path" | tail -1 | awk '{print $4}') - if [ $initiator_space -lt $MINIMUM_SPACE ]; then - Logger "There is not enough free space on initiator [$initiator_space KB]." "WARN" + local disk_space=$(df -P "$replica_path" | tail -1 | awk '{print $4}') + if [ $disk_space -lt $MINIMUM_SPACE ]; then + Logger "There is not enough free space on replica [$replica_path] ($disk_space KB)." "WARN" fi } @@ -267,7 +268,7 @@ function _CheckDiskSpaceRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "'$COMMAND_SUDO' df -P \"'$replica_path'\"" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "'$COMMAND_SUDO' df -P \"'$replica_path'\"" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -275,9 +276,9 @@ function _CheckDiskSpaceRemote { Logger "Cannot get free space on target [$replica_path]." "ERROR" Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID)" "NOTICE" else - local target_space=$(cat $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID | tail -1 | awk '{print $4}') - if [ $target_space -lt $MINIMUM_SPACE ]; then - Logger "There is not enough free space on target [$replica_path]." "WARN" + local disk_space=$(cat $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID | tail -1 | awk '{print $4}') + if [ $tdisk_space -lt $MINIMUM_SPACE ]; then + Logger "There is not enough free space on replica [$replica_path] ($disk_space KB)." "WARN" fi fi } @@ -285,11 +286,11 @@ function _CheckDiskSpaceRemote { function CheckDiskSpace { __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG - _CheckDiskSpaceLocal "$INITIATOR_SYNC_DIR" + _CheckDiskSpaceLocal "${INITIATOR[1]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckDiskSpaceLocal "$TARGET_SYNC_DIR" + _CheckDiskSpaceLocal "${TARGET[1]}" else - _CheckDiskSpaceRemote "$TARGET_SYNC_DIR" + _CheckDiskSpaceRemote "${TARGET[1]}" fi } @@ -301,7 +302,7 @@ function RsyncPatternsAdd { # Disable globbing so wildcards from exclusions do not get expanded set -f - rest="$pattern" + local rest="$pattern" while [ -n "$rest" ] do # Take the string until first occurence until $PATH_SEPARATOR_CHAR @@ -384,7 +385,7 @@ function _WriteLockFilesRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\"" > /dev/null 2>&1' + local cmd=$SSH_CMD' "echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\"" > /dev/null 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -399,11 +400,11 @@ function _WriteLockFilesRemote { function WriteLockFiles { __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG - _WriteLockFilesLocal "$INITIATOR_LOCKFILE" + _WriteLockFilesLocal "${INITIATOR[2]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _WriteLockFilesLocal "$TARGET_LOCKFILE" + _WriteLockFilesLocal "${TARGET[2]}" else - _WriteLockFilesRemote "$TARGET_LOCKFILE" + _WriteLockFilesRemote "${TARGET[2]}" fi } @@ -433,7 +434,7 @@ function _CheckLocksRemote { #TODO: Rewrite this a bit more beautiful CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then cat \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'"' + local cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then cat \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'"' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -485,11 +486,11 @@ function CheckLocks { exit 1 fi fi - _CheckLocksLocal "$INITIATOR_LOCKFILE" + _CheckLocksLocal "${INITIATOR[2]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckLocksLocal "$TARGET_LOCKFILE" + _CheckLocksLocal "${TARGET[2]}" else - _CheckLocksRemote "$TARGET_LOCKFILE" + _CheckLocksRemote "${TARGET{2]}" fi WriteLockFiles @@ -516,7 +517,7 @@ function _UnlockReplicasRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then '$COMMAND_SUDO' rm -f \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then '$COMMAND_SUDO' rm -f \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -535,11 +536,11 @@ function UnlockReplicas { return 0 fi - _UnlockReplicasLocal "$INITIATOR_LOCKFILE" + _UnlockReplicasLocal "${INITIATOR[2]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _UnlockReplicasLocal "$TARGET_LOCKFILE" + _UnlockReplicasLocal "${TARGET[2]}" else - _UnlockReplicasRemote "$TARGET_LOCKFILE" + _UnlockReplicasRemote "${TARGET[2]}" fi } @@ -562,9 +563,9 @@ function tree_list { if [ "$REMOTE_OPERATION" == "yes" ] && [ "$replica_type" == "target" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_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\" &" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" --list-only $REMOTE_USER@$REMOTE_HOST:\"$escaped_replica_path/\" | grep \"^-\|^d\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID\" &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_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\" &" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --list-only \"$replica_path/\" | grep \"^-\|^d\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID\" &" fi Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" ## Redirect commands stderr here to get rsync stderr output in logfile @@ -573,7 +574,7 @@ function tree_list { retval=$? ## Retval 24 = some files vanished while creating list if ([ $retval == 0 ] || [ $retval == 24 ]) && [ -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" ]; then - mv -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" "$INITIATOR_STATE_DIR/$replica_type$tree_filename" + mv -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_filename" return $? else Logger "Cannot create replica file list." "CRITICAL" @@ -593,13 +594,13 @@ function delete_list { # TODO: Check why external filenames are used (see _DRYRUN option because of NOSUFFIX) Logger "Creating $replica_type replica deleted file list." "NOTICE" - if [ -f "$INITIATOR_STATE_DIR/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX" ]; then + if [ -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX" ]; then ## Same functionnality, comm is much faster than grep but is not available on every platform if type comm > /dev/null 2>&1 ; then - cmd="comm -23 \"$INITIATOR_STATE_DIR/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" \"$INITIATOR_STATE_DIR/$replica_type$tree_file_current\" > \"$INITIATOR_STATE_DIR/$replica_type$deleted_list_file\"" + cmd="comm -23 \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_file_current\" > \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file\"" else ## The || : forces the command to have a good result - cmd="(grep -F -x -v -f \"$INITIATOR_STATE_DIR/$replica_type$tree_file_current\" \"$INITIATOR_STATE_DIR/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" || :) > \"$INITIATOR_STATE_DIR/$replica_type$deleted_list_file\"" + cmd="(grep -F -x -v -f \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_file_current\" \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" || :) > \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file\"" fi Logger "CMD: $cmd" "DEBUG" @@ -607,24 +608,37 @@ function delete_list { retval=$? # Add delete failed file list to current delete list and then empty it - if [ -f "$INITIATOR_STATE_DIR/$replica_type$deleted_failed_list_file" ]; then - cat "$INITIATOR_STATE_DIR/$replica_type$deleted_failed_list_file" >> "$INITIATOR_STATE_DIR/$replica_type$deleted_list_file" - rm -f "$INITIATOR_STATE_DIR/$replica_type$deleted_failed_list_file" + if [ -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" ]; then + cat "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" >> "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file" + rm -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" fi return $retval else - touch "$INITIATOR_STATE_DIR/$replica_type$deleted_list_file" + touch "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file" return $retval fi } function _get_file_attrs_local { - __CheckArguments 1 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG + 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 "$@" #__WITH_PARANOIA_DEBUG + + cd "$replica_path" + cat "$file_list" | xargs -I {} stat -c '%n|%Z|%Y' "{}" | sort > "$RUN_DIR/$PROGRAM.$FUNCNAME.$replica_type.$SCRIPT_PID" } function _get_file_attrs_remote { - __CheckArguments 1 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG + local replica_path="${1}" # Contains replica path + local replica_type="${2}" + local file_list="${3}" + __CheckArguments 3 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG + + #cmd='cat "'$file_list'" | '$SSH_CMD' cd "'$replica_path'"; xargs -I {} stat -c \'%n|%Z|%Y\' "{}" | sort > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$replica_type.$SCRIPT_PID'"' + Logger "CMD: $cmd" "DEBUG" + eval "$cmd" } function sync_attrs { @@ -632,12 +646,14 @@ function sync_attrs { local target_replica="${2}" __CheckArguments 2 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG + Logger "Getting file attributes." "NOTICE" + if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" \"$initiator_replica/\" $REMOTE_USER@$REMOTE_HOST:\"$target_replica/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiator_replica\" $REMOTE_USER@$REMOTE_HOST:\"$target_replica\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" \"$initiator_replica/\" \"$target_replica/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiator_replica\" \"$target_replica\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" fi Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" @@ -654,15 +670,18 @@ function sync_attrs { fi exit $retval else - cat "$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID" | grep -Ev "^[^ ]*(c|s|t)[^ ]* " | grep -E "^[^ ]*(p|o|g|a)[^ ]* " | sed -e 's/^[^ ]* //' > "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" - Logger "Getting file attributes on replicas succeded." "NOTICE" + cat "$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID" | ( grep -Ev "^[^ ]*(c|s|t)[^ ]* " || :) | ( grep -E "^[^ ]*(p|o|g|a)[^ ]* " || :) | ( sed -e 's/^[^ ]* //' || :) > "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" + if [ $? != 0 ]; then + Logger "Cannot prepare file attribute list." "CRITICAL" + exit 1 + fi fi - _get_file_attrs_local "$INITIATOR_SYNC_DIR" + _get_file_attrs_local "${INITIATOR[1]}" "${INITIATOR[0]}" "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" if [ "$REMOTE_OPERATION" != "yes" ]; then - _get_file_attrs_remote $(EscapeSpaces "$TARGET_SYNC_DIR") + _get_file_attrs_remote "${TARGET[1]}" "${TARGET[0]}" "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" else - _get_file_attrs_local "$TARGET_SYNC_DIR" + _get_file_attrs_local "${TARGET[1]}" "${TARGET[0]}" "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" fi #WIP @@ -679,30 +698,30 @@ function sync_update { __CheckArguments 3 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG Logger "Updating $destination_replica replica." "NOTICE" - if [ "$source_replica" == "initiator" ]; then - SOURCE_DIR="$INITIATOR_SYNC_DIR" - ESC_SOURCE_DIR=$(EscapeSpaces "$INITIATOR_SYNC_DIR") - DEST_DIR="$TARGET_SYNC_DIR" - ESC_DEST_DIR=$(EscapeSpaces "$TARGET_SYNC_DIR") - BACKUP_DIR="$TARGET_BACKUP" + if [ "$source_replica" == "${INITIATOR[0]}" ]; then + local source_dir="${INITIATOR[1]}" + local esc_source_dir=$(EscapeSpaces "${INITIATOR[1]}") + local dest_dir="${TARGET[1]}" + local esc_dest_dir=$(EscapeSpaces "${TARGET[1]}") + local backup_args="$TARGET_BACKUP_ARGS" else - SOURCE_DIR="$TARGET_SYNC_DIR" - ESC_SOURCE_DIR=$(EscapeSpaces "$TARGET_SYNC_DIR") - DEST_DIR="$INITIATOR_SYNC_DIR" - ESC_DEST_DIR=$(EscapeSpaces "$INITIATOR_SYNC_DIR") - BACKUP_DIR="$INITIATOR_BACKUP" + local source_dir="${TARGET[1]}" + local esc_source_dir=$(EscapeSpaces "${TARGET[1]}") + local dest_dir="${INITIATOR[1]}" + local esc_dest_dir=$(EscapeSpaces "${INITIATOR[1]}") + local backup_args="$INITIATOR_BACKUP" fi if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - if [ "$source_replica" == "initiator" ]; then - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$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 [ "$source_replica" == "${INITIATOR[0]}" ]; then + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" \"$source_dir\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" $REMOTE_USER@$REMOTE_HOST:\"$ESC_SOURCE_DIR/\" \"$DEST_DIR/\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" fi else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" \"$SOURCE_DIR/\" \"$DEST_DIR/\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" \"$source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" fi Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" @@ -736,7 +755,7 @@ function _delete_local { previous_file="" OLD_IFS=$IFS IFS=$'\r\n' - for files in $(cat "$INITIATOR_STATE_DIR/$deleted_list_file") + for files in $(cat "${INITIATOR[1]}${INITIATOR[3]}/$deleted_list_file") do if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then if [ "$SOFT_DELETE" != "no" ]; then @@ -753,7 +772,7 @@ function _delete_local { if [ $_DRYRUN -ne 1 ]; then if [ -e "$replica_dir$deletion_dir/$files" ]; then - rm -rf "${replica_dir:?}$deletion_dir/$files" + rm -rf "${replica_dir:?}$deletion_dir/$files" #TODO: WTF :? fi # In order to keep full path on soft deletion, create parent directories before move parentdir="$(dirname "$files")" @@ -765,7 +784,7 @@ function _delete_local { fi if [ $? != 0 ]; then Logger "Cannot move $replica_dir$files to deletion directory." "ERROR" - echo "$files" >> "$INITIATOR_STATE_DIR/$deleted_failed_list_file" + echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file" fi fi else @@ -777,7 +796,7 @@ function _delete_local { rm -rf "$replica_dir$files" if [ $? != 0 ]; then Logger "Cannot delete $replica_dir$files" "ERROR" - echo "$files" >> "$INITIATOR_STATE_DIR/$deleted_failed_list_file" + echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file" fi fi fi @@ -798,8 +817,8 @@ function _delete_remote { ## 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_STATE_DIR")" - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" \"$INITIATOR_STATE_DIR/$2\" $REMOTE_USER@$REMOTE_HOST:\"$ESC_DEST_DIR/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.precopy.$SCRIPT_PID 2>&1" + local esc_dest_dir="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}")" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" \"${INITIATOR[1]}$INITIATOR[3]}/$2\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.precopy.$SCRIPT_PID 2>&1" Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" 2>> "$LOG_FILE" if [ $? != 0 ]; then @@ -810,7 +829,7 @@ function _delete_remote { exit 1 fi -$SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_list_file")" REPLICA_DIR="$(EscapeSpaces "$replica_dir")" DELETE_DIR="$(EscapeSpaces "$deletion_dir")" FAILED_DELETE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$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 _SILENT=$_SILENT _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_list_file")" REPLICA_DIR="$(EscapeSpaces "$replica_dir")" DELETE_DIR="$(EscapeSpaces "$deletion_dir")" FAILED_DELETE_LIST="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}/$deleted_failed_list_file")" 'bash -s' << 'ENDSSH' > "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 & ## The following lines are executed remotely function _logger { @@ -826,12 +845,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG= local value="${1}" # What to log local level="${2}" # Log level: DEBUG, NOTICE, WARN, ERROR, CRITIAL - # Special case in daemon mode we should timestamp instead of counting seconds - if [ $sync_on_changes -eq 1 ]; then - prefix="$(date) - " - else - prefix="RTIME: $SECONDS - " - fi + prefix="RTIME: $SECONDS - " if [ "$level" == "CRITICAL" ]; then _logger "$prefix\e[41m$value\e[0m" @@ -915,9 +929,9 @@ ENDSSH sleep 5 ## Copy back the deleted failed file list - ESC_SOURCE_FILE="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_failed_list_file")" + local esc_source_file="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}/$deleted_failed_list_file")" #TODO: Need to check if file exists prior to copy (or add a filemask and copy all state files) - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$ESC_SOURCE_FILE\" \"$INITIATOR_STATE_DIR\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_file\" \"${INITIATOR[1]}${INITIATOR[3]}\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" 2>> "$LOG_FILE" if [ $? != 0 ]; then @@ -942,11 +956,11 @@ function deletion_propagation { Logger "Propagating deletions to $replica_type replica." "NOTICE" - if [ "$replica_type" == "initiator" ]; then - REPLICA_DIR="$INITIATOR_SYNC_DIR" - DELETE_DIR="$INITIATOR_DELETE_DIR" + if [ "$replica_type" == "{$INITIATOR[0]}" ]; then + local replica_dir="${INITIATOR[1]}${INITIATOR[3]}/" + local delete_dir="${INITIATOR[5]}" - _delete_local "$REPLICA_DIR" "target$deleted_list_file" "$DELETE_DIR" "target$deleted_failed_list_file" & + _delete_local "$replica_dir" "${TARGET[0]}$deleted_list_file" "$delete_dir" "${TARGET[0]}$deleted_failed_list_file" & WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME $FUNCNAME retval=$? if [ $retval != 0 ]; then @@ -954,13 +968,13 @@ function deletion_propagation { exit 1 fi else - REPLICA_DIR="$TARGET_SYNC_DIR" - DELETE_DIR="$TARGET_DELETE_DIR" + local replica_dir="${TARGET[1]}${TARGET[3]}/" + local delete_dir="${TARGET[5]}" if [ "$REMOTE_OPERATION" == "yes" ]; then - _delete_remote "$REPLICA_DIR" "initiator$deleted_list_file" "$DELETE_DIR" "initiator$deleted_failed_list_file" & + _delete_remote "$replica_dir" "${INITIATOR[0]}$deleted_list_file" "$delete_dir" "${INITIATOR[0]}$deleted_failed_list_file" & else - _delete_local "$REPLICA_DIR" "initiator$deleted_list_file" "$DELETE_DIR" "initiator$deleted_failed_list_file" & + _delete_local "$replica_dir" "${INITIATOR[0]}$deleted_list_file" "$delete_dir" "${INITIATOR[0]}$deleted_failed_list_file" & fi WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME $FUNCNAME retval=$? @@ -989,31 +1003,33 @@ function deletion_propagation { ###### Step 5: Create after run tree list for initiator and target replicas (Steps 5M and 5S) function Sync { + local resume count + local resume_sync __CheckArguments 0 $# $FUNCNAME "$@" #__WITH_PARANOIA_DEBUG Logger "Starting synchronization task." "NOTICE" CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - if [ -f "$INITIATOR_LAST_ACTION" ] && [ "$RESUME_SYNC" != "no" ]; then - resume_sync=$(cat "$INITIATOR_LAST_ACTION") - if [ -f "$INITIATOR_RESUME_COUNT" ]; then - resume_count=$(cat "$INITIATOR_RESUME_COUNT") + if [ -f "${INITIATOR[7]}" ] && [ "$RESUME_SYNC" != "no" ]; then + resume_sync=$(cat "${INITIATOR[7]}") + if [ -f "${INITIATOR[8]}" ]; then + resume_count=$(cat "${INITIATOR[8]}") else resume_count=0 fi if [ $resume_count -lt $RESUME_TRY ]; then if [ "$resume_sync" != "sync.success" ]; then - Logger "WARNING: Trying to resume aborted osync execution on $($STAT_CMD "$INITIATOR_LAST_ACTION") at task [$resume_sync]. [$resume_count] previous tries." "WARN" - echo $(($resume_count+1)) > "$INITIATOR_RESUME_COUNT" + Logger "WARNING: Trying to resume aborted osync execution on $($STAT_CMD "${INITIATOR[7]}") at task [$resume_sync]. [$resume_count] previous tries." "WARN" + echo $(($resume_count+1)) > "${INITIATOR[8]}" else resume_sync=none fi else Logger "Will not resume aborted osync execution. Too many resume tries [$resume_count]." "WARN" - echo "noresume" > "$INITIATOR_LAST_ACTION" - echo "0" > "$INITIATOR_RESUME_COUNT" + echo "noresume" > "${INITIATOR[7]}" + echo "0" > "${INITIATOR[8]}" resume_sync=none fi else @@ -1026,87 +1042,87 @@ function Sync { ## This replaces the case statement because ;& operator is not supported in bash 3.2... Code is more messy than case :( if [ "$resume_sync" == "none" ] || [ "$resume_sync" == "noresume" ] || [ "$resume_sync" == "${SYNC_ACTION[0]}.fail" ]; then #initiator_tree_current - tree_list "$INITIATOR_SYNC_DIR" initiator "$TREE_CURRENT_FILENAME" + tree_list "${INITIATOR[1]}${INITIATOR[3]}" initiator "$TREE_CURRENT_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[0]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[0]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[0]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[0]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[0]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[1]}.fail" ]; then #target_tree_current - tree_list "$TARGET_SYNC_DIR" target "$TREE_CURRENT_FILENAME" + tree_list "${TARGET[1]}${TARGET[3]}" target "$TREE_CURRENT_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[1]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[1]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[1]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[1]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[1]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[2]}.fail" ]; then delete_list initiator "$TREE_AFTER_FILENAME" "$TREE_CURRENT_FILENAME" "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[2]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[2]}.success" > "${INITIATOR[7]}" else - echo "${SYNc_ACTION[2]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNc_ACTION[2]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[2]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[3]}.fail" ]; then delete_list target "$TREE_AFTER_FILENAME" "$TREE_CURRENT_FILENAME" "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[3]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[3]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[3]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[3]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[3]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.fail" ]; then sync_attrs "$INITIATOR_SYNC_DIR" "$TARGET_SYNC_DIR" if [ $? == 0 ]; then - echo "${SYNC_ACTION[4]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[4]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[4]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[4]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ]; then if [ "$CONFLICT_PREVALANCE" != "initiator" ]; then if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ]; then - sync_update target initiator "$DELETED_LIST_FILENAME" + sync_update ${TARGET[0]} ${INITIATOR[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[5]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[5]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ]; then - sync_update initiator target "$DELETED_LIST_FILENAME" + sync_update ${INITIATOR[0]} ${TARGET[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[6]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[6]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi else if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ]; then - sync_update initiator target "$DELETED_LIST_FILENAME" + sync_update ${INITIATOR[0]} ${TARGET[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[6]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[6]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ]; then - sync_update target initiator "$DELETED_LIST_FILENAME" + sync_update ${TARGET[0]} ${INITIATOR[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[5]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[5]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi @@ -1115,46 +1131,46 @@ function Sync { if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[7]}.fail" ]; then deletion_propagation target "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[7]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[7]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[7]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[7]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[7]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[8]}.fail" ]; then deletion_propagation initiator "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[8]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[8]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[8]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[8]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[8]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[9]}.fail" ]; then #initiator_tree_after - tree_list "$INITIATOR_SYNC_DIR" initiator "$TREE_AFTER_FILENAME" + tree_list "${INITIATOR[1]}${INITIATOR[3]}" ${INITIATOR[0]} "$TREE_AFTER_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[9]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[9]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[9]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[9]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[9]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[10]}.fail" ]; then #target_tree_after - tree_list "$TARGET_SYNC_DIR" target "$TREE_AFTER_FILENAME" + tree_list "${TARGET[1]}${TARGET[3]}" ${TARGET[0]} "$TREE_AFTER_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[10]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[10]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[10]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[10]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi Logger "Finished synchronization task." "NOTICE" - echo "${SYNC_ACTION[11]}" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[11]}" > "${INITIATOR[7]}" - echo "0" > "$INITIATOR_RESUME_COUNT" + echo "0" > "${INITIATOR[8]}" } function _SoftDeleteLocal { @@ -1242,22 +1258,22 @@ function SoftDelete { if [ "$CONFLICT_BACKUP" != "no" ] && [ $CONFLICT_BACKUP_DAYS -ne 0 ]; then Logger "Running conflict backup cleanup." "NOTICE" - _SoftDeleteLocal "intiator" "$INITIATOR_SYNC_DIR$INITIATOR_BACKUP_DIR" $CONFLICT_BACKUP_DAYS + _SoftDeleteLocal "${INITIATOR[0]}" "${INITIATOR[1]}${INITIATOR[4]}" $CONFLICT_BACKUP_DAYS if [ "$REMOTE_OPERATION" != "yes" ]; then - _SoftDeleteLocal "target" "$TARGET_SYNC_DIR$TARGET_BACKUP_DIR" $CONFLICT_BACKUP_DAYS + _SoftDeleteLocal "${TARGET[0]}" "${TARGET[1]}${TARGET[4]}" $CONFLICT_BACKUP_DAYS else - _SoftDeleteRemote "target" "$TARGET_SYNC_DIR$TARGET_BACKUP_DIR" $CONFLICT_BACKUP_DAYS + _SoftDeleteRemote "${TARGET[0]}" "${TARGET[1]}${TARGET[4]}" $CONFLICT_BACKUP_DAYS fi fi if [ "$SOFT_DELETE" != "no" ] && [ $SOFT_DELETE_DAYS -ne 0 ]; then Logger "Running soft deletion cleanup." "NOTICE" - _SoftDeleteLocal "initiator" "$INITIATOR_SYNC_DIR$INITIATOR_DELETE_DIR" $SOFT_DELETE_DAYS + _SoftDeleteLocal "${INITIATOR[0]}" "${INITIATOR[1]}${INITIATOR[5]}" $SOFT_DELETE_DAYS if [ "$REMOTE_OPERATION" != "yes" ]; then - _SoftDeleteLocal "target" "$TARGET_SYNC_DIR$TARGET_DELETE_DIR" $SOFT_DELETE_DAYS + _SoftDeleteLocal "${TARGET[0]}" "${TARGET[1]}${TARGET[5]}" $SOFT_DELETE_DAYS else - _SoftDeleteRemote "target" "$TARGET_SYNC_DIR$TARGET_DELETE_DIR" $SOFT_DELETE_DAYS + _SoftDeleteRemote "${TARGET[0]}" "${TARGET[1]}${TARGET[5]}" $SOFT_DELETE_DAYS fi fi } @@ -1313,23 +1329,56 @@ function Init { INITIATOR_SYNC_DIR="${INITIATOR_SYNC_DIR%/}/" TARGET_SYNC_DIR="${TARGET_SYNC_DIR%/}/" - INITIATOR_STATE_DIR="$INITIATOR_SYNC_DIR$OSYNC_DIR/state" - TARGET_STATE_DIR="$TARGET_SYNC_DIR$OSYNC_DIR/state" - STATE_DIR="$OSYNC_DIR/state" - INITIATOR_LOCKFILE="$INITIATOR_STATE_DIR/lock" - TARGET_LOCKFILE="$TARGET_STATE_DIR/lock" + ## Replica format + ## Why the f*** does bash not have simple objects ? + + #${REPLICA[0]} contains replica type (initiator / target) + #${REPLICA[1]} contains full replica path (can be absolute or relative) with ending slash + #${REPLICA[2]} contains full lock file path + #${REPLICA[3]} contains state dir path, relative to replica path + #${REPLICA[4]} contains backup dir path, relative to replica path + #${REPLICA[5]} contains deletion dir path, relative to replica path + #${REPLICA[6]} contains partial dir path, relative to replica path + #${REPLICA[7]} contains full last action file path + #${REPLICA[8]} contains full resume count file path + + # Local variables used for state filenames + local lock_filename="lock" + local state_dir="state" + local backup_dir="backup" + local delete_dir="deleted" + local partial_dir="_partial" + local last_action="last-action" + local resume_count="resume-count" + local dry_suffix="dry" + + #TODO: replace all other instances by the following + INITIATOR=( + 'initiator' + "$INITIATOR_SYNC_DIR" + "$INITIATOR_SYNC_DIR$OSYNC_DIR/$lock_filename" + "$OSYNC_DIR/$state_dir" + "$OSYNC_DIR/$backup_dir" + "$OSYNC_DIR/$delete_dir" + "$OSYNC_DIR/$partial_dir" + "$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$last_action-$INSTANCE_ID$dry_suffix" + "$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix" + ) - ## Working directories to keep backups of updated / deleted files - INITIATOR_BACKUP_DIR="$OSYNC_DIR/backups" - INITIATOR_DELETE_DIR="$OSYNC_DIR/deleted" - TARGET_BACKUP_DIR="$OSYNC_DIR/backups" - TARGET_DELETE_DIR="$OSYNC_DIR/deleted" + TARGET=( + 'target' + "$TARGET_SYNC_DIR" + "$TARGET_SYNC_DIR$OSYNC_DIR/$lock_filename" + "$OSYNC_DIR/$state_dir" + "$OSYNC_DIR/$backup_dir" + "$OSYNC_DIR/$delete_dir" + "$OSYNC_DIR/$partial_dir" + "$TARGET_SYNC_DIR$OSYNC_DIR/$state_dir/$last_action-$INSTANCE_ID$dry_suffix" + "$TARGET_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix" + ) - ## Partial downloads dirs PARTIAL_DIR=$OSYNC_DIR"_partial" - ## TODO: checksum=no / yes not implemented, be careful with sync_attrs which must itemize based on mtime - ## Set sync only function arguments for rsync SYNC_OPTS="-u" @@ -1341,19 +1390,6 @@ function Init { SYNC_OPTS=$SYNC_OPTS" --stats" fi - ## Conflict options - if [ "$CONFLICT_BACKUP" != "no" ]; then - INITIATOR_BACKUP="--backup --backup-dir=\"$INITIATOR_BACKUP_DIR\"" - TARGET_BACKUP="--backup --backup-dir=\"$TARGET_BACKUP_DIR\"" - if [ "$CONFLICT_BACKUP_MULTIPLE" == "yes" ]; then - INITIATOR_BACKUP="$INITIATOR_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" - TARGET_BACKUP="$TARGET_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" - fi - else - INITIATOR_BACKUP= - TARGET_BACKUP= - fi - ## Add Rsync include / exclude patterns if [ $_QUICK_SYNC -lt 2 ]; then RsyncPatterns @@ -1364,13 +1400,24 @@ function Init { dry_suffix="-dry" fi + ## Conflict options + if [ "$CONFLICT_BACKUP" != "no" ]; then + INITIATOR_BACKUP="--backup --backup-dir=\"${INITIATOR[1]}${INITIATOR[4]}\"" + TARGET_BACKUP="--backup --backup-dir=\"${TARGET[1]}${TARGET[4]}\"" + if [ "$CONFLICT_BACKUP_MULTIPLE" == "yes" ]; then + INITIATOR_BACKUP="$INITIATOR_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" + TARGET_BACKUP="$TARGET_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" + fi + else + INITIATOR_BACKUP=" + TARGET_BACKUP=" + fi + TREE_CURRENT_FILENAME="-tree-current-$INSTANCE_ID$dry_suffix" TREE_AFTER_FILENAME="-tree-after-$INSTANCE_ID$dry_suffix" TREE_AFTER_FILENAME_NO_SUFFIX="-tree-after-$INSTANCE_ID" DELETED_LIST_FILENAME="-deleted-list-$INSTANCE_ID$dry_suffix" FAILED_DELETE_LIST_FILENAME="-failed-delete-$INSTANCE_ID$dry_suffix" - INITIATOR_LAST_ACTION="$INITIATOR_STATE_DIR/last-action-$INSTANCE_ID$dry_suffix" - INITIATOR_RESUME_COUNT="$INITIATOR_STATE_DIR/resume-count-$INSTANCE_ID$dry_suffix" ## Sync function actions (0-10) SYNC_ACTION=( diff --git a/osync.sh b/osync.sh index 08d0242..267578a 100755 --- a/osync.sh +++ b/osync.sh @@ -4,7 +4,7 @@ PROGRAM="osync" # Rsync based two way sync engine with fault tolerance AUTHOR="(L) 2013-2016 by Orsiris de Jong" CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr" PROGRAM_VERSION=1.1-dev -PROGRAM_BUILD=2016021602 +PROGRAM_BUILD=2016021703 IS_STABLE=no FUNC_BUILD=2016021604 @@ -823,7 +823,7 @@ function InitRemoteOSSettings { ## END Generic functions -## Working directory. This is the name of the osync subdirectory contained in every replica. +## Working directory. This directory exists in any replica and contains state files, backups, soft deleted files etc OSYNC_DIR=".osync_workdir" function TrapStop { @@ -863,6 +863,7 @@ function TrapQuit { fi CleanUp Logger "$PROGRAM finished with warnings." "WARN" + exitcode=2 else UnlockReplicas CleanUp @@ -961,7 +962,7 @@ function _CreateStateDirsRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if ! [ -d \"'$replica_state_dir'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_state_dir'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "if ! [ -d \"'$replica_state_dir'\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_state_dir'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -974,11 +975,11 @@ function _CreateStateDirsRemote { function CreateStateDirs { - _CreateStateDirsLocal "$INITIATOR_STATE_DIR" + _CreateStateDirsLocal "${INITIATOR[1]}${INITIATOR[3]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CreateStateDirsLocal "$TARGET_STATE_DIR" + _CreateStateDirsLocal "${TARGET[1]}${TARGET[3]}" else - _CreateStateDirsRemote "$TARGET_STATE_DIR" + _CreateStateDirsRemote "${TARGET[1]}${TARGET[3]}" fi } @@ -1012,7 +1013,7 @@ function _CheckReplicaPathsRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if ! [ -d \"'$replica_path'\" ]; then if [ \"'$CREATE_DIRS'\" == \"yes\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_path'\"; fi; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "if ! [ -d \"'$replica_path'\" ]; then if [ \"'$CREATE_DIRS'\" == \"yes\" ]; then '$COMMAND_SUDO' mkdir -p \"'$replica_path'\"; fi; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1022,7 +1023,7 @@ function _CheckReplicaPathsRemote { exit 1 fi - cmd=$SSH_CMD' "if [ ! -w \"'$replica_path'\" ];then exit 1; fi" 2>&1' + local cmd=$SSH_CMD' "if [ ! -w \"'$replica_path'\" ];then exit 1; fi" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1035,7 +1036,7 @@ function _CheckReplicaPathsRemote { function CheckReplicaPaths { #INITIATOR_SYNC_DIR_CANN=$(realpath "$INITIATOR_SYNC_DIR") #TODO: investigate realpath & readlink issues on MSYS and busybox here - #TARGET_SYNC_DIR_CANN=$(realpath "$TARGET_SYNC_DIR") + #TARGET_SYNC_DIR_CANN=$(realpath "$TARGET_SYNC_DIR") #TODO2: replace all variables with INITIATOR object #if [ "$REMOTE_OPERATION" != "yes" ]; then # if [ "$INITIATOR_SYNC_DIR_CANN" == "$TARGET_SYNC_DIR_CANN" ]; then @@ -1044,11 +1045,11 @@ function CheckReplicaPaths { # fi #fi - _CheckReplicaPathsLocal "$INITIATOR_SYNC_DIR" + _CheckReplicaPathsLocal "${INITIATOR[1]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckReplicaPathsLocal "$TARGET_SYNC_DIR" + _CheckReplicaPathsLocal "${TARGET[1]}" else - _CheckReplicaPathsRemote "$TARGET_SYNC_DIR" + _CheckReplicaPathsRemote "${TARGET[1]}" fi } @@ -1057,9 +1058,9 @@ function _CheckDiskSpaceLocal { Logger "Checking minimum disk space in [$replica_path]." "NOTICE" - local initiator_space=$(df -P "$replica_path" | tail -1 | awk '{print $4}') - if [ $initiator_space -lt $MINIMUM_SPACE ]; then - Logger "There is not enough free space on initiator [$initiator_space KB]." "WARN" + local disk_space=$(df -P "$replica_path" | tail -1 | awk '{print $4}') + if [ $disk_space -lt $MINIMUM_SPACE ]; then + Logger "There is not enough free space on replica [$replica_path] ($disk_space KB)." "WARN" fi } @@ -1071,7 +1072,7 @@ function _CheckDiskSpaceRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "'$COMMAND_SUDO' df -P \"'$replica_path'\"" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "'$COMMAND_SUDO' df -P \"'$replica_path'\"" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1079,20 +1080,20 @@ function _CheckDiskSpaceRemote { Logger "Cannot get free space on target [$replica_path]." "ERROR" Logger "Command output:\n$(cat $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID)" "NOTICE" else - local target_space=$(cat $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID | tail -1 | awk '{print $4}') - if [ $target_space -lt $MINIMUM_SPACE ]; then - Logger "There is not enough free space on target [$replica_path]." "WARN" + local disk_space=$(cat $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID | tail -1 | awk '{print $4}') + if [ $tdisk_space -lt $MINIMUM_SPACE ]; then + Logger "There is not enough free space on replica [$replica_path] ($disk_space KB)." "WARN" fi fi } function CheckDiskSpace { - _CheckDiskSpaceLocal "$INITIATOR_SYNC_DIR" + _CheckDiskSpaceLocal "${INITIATOR[1]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckDiskSpaceLocal "$TARGET_SYNC_DIR" + _CheckDiskSpaceLocal "${TARGET[1]}" else - _CheckDiskSpaceRemote "$TARGET_SYNC_DIR" + _CheckDiskSpaceRemote "${TARGET[1]}" fi } @@ -1103,7 +1104,7 @@ function RsyncPatternsAdd { # Disable globbing so wildcards from exclusions do not get expanded set -f - rest="$pattern" + local rest="$pattern" while [ -n "$rest" ] do # Take the string until first occurence until $PATH_SEPARATOR_CHAR @@ -1182,7 +1183,7 @@ function _WriteLockFilesRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\"" > /dev/null 2>&1' + local cmd=$SSH_CMD' "echo '$SCRIPT_PID@$INSTANCE_ID' | '$COMMAND_SUDO' tee \"'$lockfile'\"" > /dev/null 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1196,11 +1197,11 @@ function _WriteLockFilesRemote { function WriteLockFiles { - _WriteLockFilesLocal "$INITIATOR_LOCKFILE" + _WriteLockFilesLocal "${INITIATOR[2]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _WriteLockFilesLocal "$TARGET_LOCKFILE" + _WriteLockFilesLocal "${TARGET[2]}" else - _WriteLockFilesRemote "$TARGET_LOCKFILE" + _WriteLockFilesRemote "${TARGET[2]}" fi } @@ -1228,7 +1229,7 @@ function _CheckLocksRemote { #TODO: Rewrite this a bit more beautiful CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then cat \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'"' + local cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then cat \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'"' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1279,11 +1280,11 @@ function CheckLocks { exit 1 fi fi - _CheckLocksLocal "$INITIATOR_LOCKFILE" + _CheckLocksLocal "${INITIATOR[2]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _CheckLocksLocal "$TARGET_LOCKFILE" + _CheckLocksLocal "${TARGET[2]}" else - _CheckLocksRemote "$TARGET_LOCKFILE" + _CheckLocksRemote "${TARGET{2]}" fi WriteLockFiles @@ -1308,7 +1309,7 @@ function _UnlockReplicasRemote { CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then '$COMMAND_SUDO' rm -f \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' + local cmd=$SSH_CMD' "if [ -f \"'$lockfile'\" ]; then '$COMMAND_SUDO' rm -f \"'$lockfile'\"; fi" > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & WaitForTaskCompletion $! 720 1800 $FUNCNAME @@ -1326,11 +1327,11 @@ function UnlockReplicas { return 0 fi - _UnlockReplicasLocal "$INITIATOR_LOCKFILE" + _UnlockReplicasLocal "${INITIATOR[2]}" if [ "$REMOTE_OPERATION" != "yes" ]; then - _UnlockReplicasLocal "$TARGET_LOCKFILE" + _UnlockReplicasLocal "${TARGET[2]}" else - _UnlockReplicasRemote "$TARGET_LOCKFILE" + _UnlockReplicasRemote "${TARGET[2]}" fi } @@ -1352,9 +1353,9 @@ function tree_list { if [ "$REMOTE_OPERATION" == "yes" ] && [ "$replica_type" == "target" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_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\" &" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" --list-only $REMOTE_USER@$REMOTE_HOST:\"$escaped_replica_path/\" | grep \"^-\|^d\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID\" &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_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\" &" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS -8 --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --list-only \"$replica_path/\" | grep \"^-\|^d\" | awk '{\$1=\$2=\$3=\$4=\"\" ;print}' | awk '{\$1=\$1 ;print}' | (grep -v \"^\.$\" || :) | sort > \"$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID\" &" fi Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" ## Redirect commands stderr here to get rsync stderr output in logfile @@ -1363,7 +1364,7 @@ function tree_list { retval=$? ## Retval 24 = some files vanished while creating list if ([ $retval == 0 ] || [ $retval == 24 ]) && [ -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" ]; then - mv -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" "$INITIATOR_STATE_DIR/$replica_type$tree_filename" + mv -f "$RUN_DIR/$PROGRAM.$replica_type.$SCRIPT_PID" "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_filename" return $? else Logger "Cannot create replica file list." "CRITICAL" @@ -1382,13 +1383,13 @@ function delete_list { # TODO: Check why external filenames are used (see _DRYRUN option because of NOSUFFIX) Logger "Creating $replica_type replica deleted file list." "NOTICE" - if [ -f "$INITIATOR_STATE_DIR/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX" ]; then + if [ -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX" ]; then ## Same functionnality, comm is much faster than grep but is not available on every platform if type comm > /dev/null 2>&1 ; then - cmd="comm -23 \"$INITIATOR_STATE_DIR/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" \"$INITIATOR_STATE_DIR/$replica_type$tree_file_current\" > \"$INITIATOR_STATE_DIR/$replica_type$deleted_list_file\"" + cmd="comm -23 \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_file_current\" > \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file\"" else ## The || : forces the command to have a good result - cmd="(grep -F -x -v -f \"$INITIATOR_STATE_DIR/$replica_type$tree_file_current\" \"$INITIATOR_STATE_DIR/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" || :) > \"$INITIATOR_STATE_DIR/$replica_type$deleted_list_file\"" + cmd="(grep -F -x -v -f \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$tree_file_current\" \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$TREE_AFTER_FILENAME_NO_SUFFIX\" || :) > \"${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file\"" fi Logger "CMD: $cmd" "DEBUG" @@ -1396,34 +1397,49 @@ function delete_list { retval=$? # Add delete failed file list to current delete list and then empty it - if [ -f "$INITIATOR_STATE_DIR/$replica_type$deleted_failed_list_file" ]; then - cat "$INITIATOR_STATE_DIR/$replica_type$deleted_failed_list_file" >> "$INITIATOR_STATE_DIR/$replica_type$deleted_list_file" - rm -f "$INITIATOR_STATE_DIR/$replica_type$deleted_failed_list_file" + if [ -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" ]; then + cat "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" >> "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file" + rm -f "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_failed_list_file" fi return $retval else - touch "$INITIATOR_STATE_DIR/$replica_type$deleted_list_file" + touch "${INITIATOR[1]}${INITIATOR[3]}/$replica_type$deleted_list_file" return $retval fi } function _get_file_attrs_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 + + cd "$replica_path" + cat "$file_list" | xargs -I {} stat -c '%n|%Z|%Y' "{}" | sort > "$RUN_DIR/$PROGRAM.$FUNCNAME.$replica_type.$SCRIPT_PID" } function _get_file_attrs_remote { + local replica_path="${1}" # Contains replica path + local replica_type="${2}" + local file_list="${3}" + + #cmd='cat "'$file_list'" | '$SSH_CMD' cd "'$replica_path'"; xargs -I {} stat -c \'%n|%Z|%Y\' "{}" | sort > "'$RUN_DIR/$PROGRAM.$FUNCNAME.$replica_type.$SCRIPT_PID'"' + Logger "CMD: $cmd" "DEBUG" + eval "$cmd" } function sync_attrs { local initiator_replica="${1}" # Contains #TODO: Write ACL update function, check other ctime related attributes (xattr ?) local target_replica="${2}" + Logger "Getting file attributes." "NOTICE" + if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" \"$initiator_replica/\" $REMOTE_USER@$REMOTE_HOST:\"$target_replica/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiator_replica\" $REMOTE_USER@$REMOTE_HOST:\"$target_replica\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" \"$initiator_replica/\" \"$target_replica/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" -i $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_PARTIAL_EXCLUDE --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE \"$initiator_replica\" \"$target_replica\" > $RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID 2>&1 &" fi Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" @@ -1440,15 +1456,18 @@ function sync_attrs { fi exit $retval else - cat "$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID" | grep -Ev "^[^ ]*(c|s|t)[^ ]* " | grep -E "^[^ ]*(p|o|g|a)[^ ]* " | sed -e 's/^[^ ]* //' > "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" - Logger "Getting file attributes on replicas succeded." "NOTICE" + cat "$RUN_DIR/$PROGRAM.$FUNCNAME.$SCRIPT_PID" | ( grep -Ev "^[^ ]*(c|s|t)[^ ]* " || :) | ( grep -E "^[^ ]*(p|o|g|a)[^ ]* " || :) | ( sed -e 's/^[^ ]* //' || :) > "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" + if [ $? != 0 ]; then + Logger "Cannot prepare file attribute list." "CRITICAL" + exit 1 + fi fi - _get_file_attrs_local "$INITIATOR_SYNC_DIR" + _get_file_attrs_local "${INITIATOR[1]}" "${INITIATOR[0]}" "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" if [ "$REMOTE_OPERATION" != "yes" ]; then - _get_file_attrs_remote $(EscapeSpaces "$TARGET_SYNC_DIR") + _get_file_attrs_remote "${TARGET[1]}" "${TARGET[0]}" "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" else - _get_file_attrs_local "$TARGET_SYNC_DIR" + _get_file_attrs_local "${TARGET[1]}" "${TARGET[0]}" "$RUN_DIR/$PROGRAM.$FUNCNAME-cleaned.$SCRIPT_PID" fi #WIP @@ -1464,30 +1483,30 @@ function sync_update { local delete_list_filename="${3}" # Contains deleted list filename, will be prefixed with replica type Logger "Updating $destination_replica replica." "NOTICE" - if [ "$source_replica" == "initiator" ]; then - SOURCE_DIR="$INITIATOR_SYNC_DIR" - ESC_SOURCE_DIR=$(EscapeSpaces "$INITIATOR_SYNC_DIR") - DEST_DIR="$TARGET_SYNC_DIR" - ESC_DEST_DIR=$(EscapeSpaces "$TARGET_SYNC_DIR") - BACKUP_DIR="$TARGET_BACKUP" + if [ "$source_replica" == "${INITIATOR[0]}" ]; then + local source_dir="${INITIATOR[1]}" + local esc_source_dir=$(EscapeSpaces "${INITIATOR[1]}") + local dest_dir="${TARGET[1]}" + local esc_dest_dir=$(EscapeSpaces "${TARGET[1]}") + local backup_args="$TARGET_BACKUP_ARGS" else - SOURCE_DIR="$TARGET_SYNC_DIR" - ESC_SOURCE_DIR=$(EscapeSpaces "$TARGET_SYNC_DIR") - DEST_DIR="$INITIATOR_SYNC_DIR" - ESC_DEST_DIR=$(EscapeSpaces "$INITIATOR_SYNC_DIR") - BACKUP_DIR="$INITIATOR_BACKUP" + local source_dir="${TARGET[1]}" + local esc_source_dir=$(EscapeSpaces "${TARGET[1]}") + local dest_dir="${INITIATOR[1]}" + local esc_dest_dir=$(EscapeSpaces "${INITIATOR[1]}") + local backup_args="$INITIATOR_BACKUP" fi if [ "$REMOTE_OPERATION" == "yes" ]; then CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - if [ "$source_replica" == "initiator" ]; then - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$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 [ "$source_replica" == "${INITIATOR[0]}" ]; then + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSYNC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" \"$source_dir\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" $REMOTE_USER@$REMOTE_HOST:\"$ESC_SOURCE_DIR/\" \"$DEST_DIR/\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" fi else - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS $BACKUP_DIR --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"$INITIATOR_STATE_DIR/$source_replica$delete_list_filename\" --exclude-from=\"$INITIATOR_STATE_DIR/$destination_replica$delete_list_filename\" \"$SOURCE_DIR/\" \"$DEST_DIR/\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" + rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $RSYNC_ARGS $RSYNC_ATTR_ARGS $RSNYC_TYPE_ARGS $SYNC_OPTS $backup_args --exclude \"$OSYNC_DIR\" $RSYNC_PATTERNS $RSYNC_PARTIAL_EXCLUDE --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$source_replica$delete_list_filename\" --exclude-from=\"${INITIATOR[1]}${INITIATOR[3]}/$destination_replica$delete_list_filename\" \"$source_dir\" \"$dest_dir\" > $RUN_DIR/$PROGRAM.update.$destination_replica.$SCRIPT_PID 2>&1 &" fi Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" @@ -1520,7 +1539,7 @@ function _delete_local { previous_file="" OLD_IFS=$IFS IFS=$'\r\n' - for files in $(cat "$INITIATOR_STATE_DIR/$deleted_list_file") + for files in $(cat "${INITIATOR[1]}${INITIATOR[3]}/$deleted_list_file") do if [[ "$files" != "$previous_file/"* ]] && [ "$files" != "" ]; then if [ "$SOFT_DELETE" != "no" ]; then @@ -1537,7 +1556,7 @@ function _delete_local { if [ $_DRYRUN -ne 1 ]; then if [ -e "$replica_dir$deletion_dir/$files" ]; then - rm -rf "${replica_dir:?}$deletion_dir/$files" + rm -rf "${replica_dir:?}$deletion_dir/$files" #TODO: WTF :? fi # In order to keep full path on soft deletion, create parent directories before move parentdir="$(dirname "$files")" @@ -1549,7 +1568,7 @@ function _delete_local { fi if [ $? != 0 ]; then Logger "Cannot move $replica_dir$files to deletion directory." "ERROR" - echo "$files" >> "$INITIATOR_STATE_DIR/$deleted_failed_list_file" + echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file" fi fi else @@ -1561,7 +1580,7 @@ function _delete_local { rm -rf "$replica_dir$files" if [ $? != 0 ]; then Logger "Cannot delete $replica_dir$files" "ERROR" - echo "$files" >> "$INITIATOR_STATE_DIR/$deleted_failed_list_file" + echo "$files" >> "${INITIATOR[1]}${INITIATOR[3]}/$deleted_failed_list_file" fi fi fi @@ -1581,8 +1600,8 @@ function _delete_remote { ## 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_STATE_DIR")" - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" \"$INITIATOR_STATE_DIR/$2\" $REMOTE_USER@$REMOTE_HOST:\"$ESC_DEST_DIR/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.precopy.$SCRIPT_PID 2>&1" + local esc_dest_dir="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}")" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" \"${INITIATOR[1]}$INITIATOR[3]}/$2\" $REMOTE_USER@$REMOTE_HOST:\"$esc_dest_dir/\" > $RUN_DIR/$PROGRAM.$FUNCNAME.precopy.$SCRIPT_PID 2>&1" Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" 2>> "$LOG_FILE" if [ $? != 0 ]; then @@ -1593,7 +1612,7 @@ function _delete_remote { exit 1 fi -$SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_list_file")" REPLICA_DIR="$(EscapeSpaces "$replica_dir")" DELETE_DIR="$(EscapeSpaces "$deletion_dir")" FAILED_DELETE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$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 _SILENT=$_SILENT _DEBUG=$_DEBUG _DRYRUN=$_DRYRUN _VERBOSE=$_VERBOSE COMMAND_SUDO=$COMMAND_SUDO FILE_LIST="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_list_file")" REPLICA_DIR="$(EscapeSpaces "$replica_dir")" DELETE_DIR="$(EscapeSpaces "$deletion_dir")" FAILED_DELETE_LIST="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}/$deleted_failed_list_file")" 'bash -s' << 'ENDSSH' > "$RUN_DIR/$PROGRAM.remote_deletion.$SCRIPT_PID" 2>&1 & ## The following lines are executed remotely function _logger { @@ -1609,12 +1628,7 @@ $SSH_CMD ERROR_ALERT=0 sync_on_changes=$sync_on_changes _SILENT=$_SILENT _DEBUG= local value="${1}" # What to log local level="${2}" # Log level: DEBUG, NOTICE, WARN, ERROR, CRITIAL - # Special case in daemon mode we should timestamp instead of counting seconds - if [ $sync_on_changes -eq 1 ]; then - prefix="$(date) - " - else - prefix="RTIME: $SECONDS - " - fi + prefix="RTIME: $SECONDS - " if [ "$level" == "CRITICAL" ]; then _logger "$prefix\e[41m$value\e[0m" @@ -1698,9 +1712,9 @@ ENDSSH sleep 5 ## Copy back the deleted failed file list - ESC_SOURCE_FILE="$(EscapeSpaces "$TARGET_STATE_DIR/$deleted_failed_list_file")" + local esc_source_file="$(EscapeSpaces "${TARGET[1]}${TARGET[3]}/$deleted_failed_list_file")" #TODO: Need to check if file exists prior to copy (or add a filemask and copy all state files) - rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$ESC_SOURCE_FILE\" \"$INITIATOR_STATE_DIR\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" + local rsync_cmd="$(type -p $RSYNC_EXECUTABLE) --rsync-path=\"$RSYNC_PATH\" $SYNC_OPTS -e \"$RSYNC_SSH_CMD\" $REMOTE_USER@$REMOTE_HOST:\"$esc_source_file\" \"${INITIATOR[1]}${INITIATOR[3]}\" > \"$RUN_DIR/$PROGRAM.remote_failed_deletion_list_copy.$SCRIPT_PID\"" Logger "RSYNC_CMD: $rsync_cmd" "DEBUG" eval "$rsync_cmd" 2>> "$LOG_FILE" if [ $? != 0 ]; then @@ -1724,11 +1738,11 @@ function deletion_propagation { Logger "Propagating deletions to $replica_type replica." "NOTICE" - if [ "$replica_type" == "initiator" ]; then - REPLICA_DIR="$INITIATOR_SYNC_DIR" - DELETE_DIR="$INITIATOR_DELETE_DIR" + if [ "$replica_type" == "{$INITIATOR[0]}" ]; then + local replica_dir="${INITIATOR[1]}${INITIATOR[3]}/" + local delete_dir="${INITIATOR[5]}" - _delete_local "$REPLICA_DIR" "target$deleted_list_file" "$DELETE_DIR" "target$deleted_failed_list_file" & + _delete_local "$replica_dir" "${TARGET[0]}$deleted_list_file" "$delete_dir" "${TARGET[0]}$deleted_failed_list_file" & WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME $FUNCNAME retval=$? if [ $retval != 0 ]; then @@ -1736,13 +1750,13 @@ function deletion_propagation { exit 1 fi else - REPLICA_DIR="$TARGET_SYNC_DIR" - DELETE_DIR="$TARGET_DELETE_DIR" + local replica_dir="${TARGET[1]}${TARGET[3]}/" + local delete_dir="${TARGET[5]}" if [ "$REMOTE_OPERATION" == "yes" ]; then - _delete_remote "$REPLICA_DIR" "initiator$deleted_list_file" "$DELETE_DIR" "initiator$deleted_failed_list_file" & + _delete_remote "$replica_dir" "${INITIATOR[0]}$deleted_list_file" "$delete_dir" "${INITIATOR[0]}$deleted_failed_list_file" & else - _delete_local "$REPLICA_DIR" "initiator$deleted_list_file" "$DELETE_DIR" "initiator$deleted_failed_list_file" & + _delete_local "$replica_dir" "${INITIATOR[0]}$deleted_list_file" "$delete_dir" "${INITIATOR[0]}$deleted_failed_list_file" & fi WaitForCompletion $! $SOFT_MAX_EXEC_TIME $HARD_MAX_EXEC_TIME $FUNCNAME retval=$? @@ -1771,30 +1785,32 @@ function deletion_propagation { ###### Step 5: Create after run tree list for initiator and target replicas (Steps 5M and 5S) function Sync { + local resume count + local resume_sync Logger "Starting synchronization task." "NOTICE" CheckConnectivity3rdPartyHosts CheckConnectivityRemoteHost - if [ -f "$INITIATOR_LAST_ACTION" ] && [ "$RESUME_SYNC" != "no" ]; then - resume_sync=$(cat "$INITIATOR_LAST_ACTION") - if [ -f "$INITIATOR_RESUME_COUNT" ]; then - resume_count=$(cat "$INITIATOR_RESUME_COUNT") + if [ -f "${INITIATOR[7]}" ] && [ "$RESUME_SYNC" != "no" ]; then + resume_sync=$(cat "${INITIATOR[7]}") + if [ -f "${INITIATOR[8]}" ]; then + resume_count=$(cat "${INITIATOR[8]}") else resume_count=0 fi if [ $resume_count -lt $RESUME_TRY ]; then if [ "$resume_sync" != "sync.success" ]; then - Logger "WARNING: Trying to resume aborted osync execution on $($STAT_CMD "$INITIATOR_LAST_ACTION") at task [$resume_sync]. [$resume_count] previous tries." "WARN" - echo $(($resume_count+1)) > "$INITIATOR_RESUME_COUNT" + Logger "WARNING: Trying to resume aborted osync execution on $($STAT_CMD "${INITIATOR[7]}") at task [$resume_sync]. [$resume_count] previous tries." "WARN" + echo $(($resume_count+1)) > "${INITIATOR[8]}" else resume_sync=none fi else Logger "Will not resume aborted osync execution. Too many resume tries [$resume_count]." "WARN" - echo "noresume" > "$INITIATOR_LAST_ACTION" - echo "0" > "$INITIATOR_RESUME_COUNT" + echo "noresume" > "${INITIATOR[7]}" + echo "0" > "${INITIATOR[8]}" resume_sync=none fi else @@ -1807,87 +1823,87 @@ function Sync { ## This replaces the case statement because ;& operator is not supported in bash 3.2... Code is more messy than case :( if [ "$resume_sync" == "none" ] || [ "$resume_sync" == "noresume" ] || [ "$resume_sync" == "${SYNC_ACTION[0]}.fail" ]; then #initiator_tree_current - tree_list "$INITIATOR_SYNC_DIR" initiator "$TREE_CURRENT_FILENAME" + tree_list "${INITIATOR[1]}${INITIATOR[3]}" initiator "$TREE_CURRENT_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[0]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[0]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[0]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[0]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[0]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[1]}.fail" ]; then #target_tree_current - tree_list "$TARGET_SYNC_DIR" target "$TREE_CURRENT_FILENAME" + tree_list "${TARGET[1]}${TARGET[3]}" target "$TREE_CURRENT_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[1]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[1]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[1]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[1]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[1]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[2]}.fail" ]; then delete_list initiator "$TREE_AFTER_FILENAME" "$TREE_CURRENT_FILENAME" "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[2]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[2]}.success" > "${INITIATOR[7]}" else - echo "${SYNc_ACTION[2]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNc_ACTION[2]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[2]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[3]}.fail" ]; then delete_list target "$TREE_AFTER_FILENAME" "$TREE_CURRENT_FILENAME" "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[3]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[3]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[3]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[3]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[3]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.fail" ]; then sync_attrs "$INITIATOR_SYNC_DIR" "$TARGET_SYNC_DIR" if [ $? == 0 ]; then - echo "${SYNC_ACTION[4]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[4]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[4]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[4]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ]; then if [ "$CONFLICT_PREVALANCE" != "initiator" ]; then if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ]; then - sync_update target initiator "$DELETED_LIST_FILENAME" + sync_update ${TARGET[0]} ${INITIATOR[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[5]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[5]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ]; then - sync_update initiator target "$DELETED_LIST_FILENAME" + sync_update ${INITIATOR[0]} ${TARGET[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[6]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[6]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi else if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[4]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.fail" ]; then - sync_update initiator target "$DELETED_LIST_FILENAME" + sync_update ${INITIATOR[0]} ${TARGET[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[6]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[6]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[6]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.fail" ]; then - sync_update target initiator "$DELETED_LIST_FILENAME" + sync_update ${TARGET[0]} ${INITIATOR[0]} "$DELETED_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[5]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[5]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[5]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi @@ -1896,46 +1912,46 @@ function Sync { if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[5]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[6]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[7]}.fail" ]; then deletion_propagation target "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[7]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[7]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[7]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[7]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[7]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[8]}.fail" ]; then deletion_propagation initiator "$DELETED_LIST_FILENAME" "$FAILED_DELETE_LIST_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[8]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[8]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[8]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[8]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[8]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[9]}.fail" ]; then #initiator_tree_after - tree_list "$INITIATOR_SYNC_DIR" initiator "$TREE_AFTER_FILENAME" + tree_list "${INITIATOR[1]}${INITIATOR[3]}" ${INITIATOR[0]} "$TREE_AFTER_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[9]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[9]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[9]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[9]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi if [ "$resume_sync" == "resumed" ] || [ "$resume_sync" == "${SYNC_ACTION[9]}.success" ] || [ "$resume_sync" == "${SYNC_ACTION[10]}.fail" ]; then #target_tree_after - tree_list "$TARGET_SYNC_DIR" target "$TREE_AFTER_FILENAME" + tree_list "${TARGET[1]}${TARGET[3]}" ${TARGET[0]} "$TREE_AFTER_FILENAME" if [ $? == 0 ]; then - echo "${SYNC_ACTION[10]}.success" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[10]}.success" > "${INITIATOR[7]}" else - echo "${SYNC_ACTION[10]}.fail" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[10]}.fail" > "${INITIATOR[7]}" fi resume_sync="resumed" fi Logger "Finished synchronization task." "NOTICE" - echo "${SYNC_ACTION[11]}" > "$INITIATOR_LAST_ACTION" + echo "${SYNC_ACTION[11]}" > "${INITIATOR[7]}" - echo "0" > "$INITIATOR_RESUME_COUNT" + echo "0" > "${INITIATOR[8]}" } function _SoftDeleteLocal { @@ -2020,22 +2036,22 @@ function SoftDelete { if [ "$CONFLICT_BACKUP" != "no" ] && [ $CONFLICT_BACKUP_DAYS -ne 0 ]; then Logger "Running conflict backup cleanup." "NOTICE" - _SoftDeleteLocal "intiator" "$INITIATOR_SYNC_DIR$INITIATOR_BACKUP_DIR" $CONFLICT_BACKUP_DAYS + _SoftDeleteLocal "${INITIATOR[0]}" "${INITIATOR[1]}${INITIATOR[4]}" $CONFLICT_BACKUP_DAYS if [ "$REMOTE_OPERATION" != "yes" ]; then - _SoftDeleteLocal "target" "$TARGET_SYNC_DIR$TARGET_BACKUP_DIR" $CONFLICT_BACKUP_DAYS + _SoftDeleteLocal "${TARGET[0]}" "${TARGET[1]}${TARGET[4]}" $CONFLICT_BACKUP_DAYS else - _SoftDeleteRemote "target" "$TARGET_SYNC_DIR$TARGET_BACKUP_DIR" $CONFLICT_BACKUP_DAYS + _SoftDeleteRemote "${TARGET[0]}" "${TARGET[1]}${TARGET[4]}" $CONFLICT_BACKUP_DAYS fi fi if [ "$SOFT_DELETE" != "no" ] && [ $SOFT_DELETE_DAYS -ne 0 ]; then Logger "Running soft deletion cleanup." "NOTICE" - _SoftDeleteLocal "initiator" "$INITIATOR_SYNC_DIR$INITIATOR_DELETE_DIR" $SOFT_DELETE_DAYS + _SoftDeleteLocal "${INITIATOR[0]}" "${INITIATOR[1]}${INITIATOR[5]}" $SOFT_DELETE_DAYS if [ "$REMOTE_OPERATION" != "yes" ]; then - _SoftDeleteLocal "target" "$TARGET_SYNC_DIR$TARGET_DELETE_DIR" $SOFT_DELETE_DAYS + _SoftDeleteLocal "${TARGET[0]}" "${TARGET[1]}${TARGET[5]}" $SOFT_DELETE_DAYS else - _SoftDeleteRemote "target" "$TARGET_SYNC_DIR$TARGET_DELETE_DIR" $SOFT_DELETE_DAYS + _SoftDeleteRemote "${TARGET[0]}" "${TARGET[1]}${TARGET[5]}" $SOFT_DELETE_DAYS fi fi } @@ -2090,23 +2106,56 @@ function Init { INITIATOR_SYNC_DIR="${INITIATOR_SYNC_DIR%/}/" TARGET_SYNC_DIR="${TARGET_SYNC_DIR%/}/" - INITIATOR_STATE_DIR="$INITIATOR_SYNC_DIR$OSYNC_DIR/state" - TARGET_STATE_DIR="$TARGET_SYNC_DIR$OSYNC_DIR/state" - STATE_DIR="$OSYNC_DIR/state" - INITIATOR_LOCKFILE="$INITIATOR_STATE_DIR/lock" - TARGET_LOCKFILE="$TARGET_STATE_DIR/lock" + ## Replica format + ## Why the f*** does bash not have simple objects ? + + #${REPLICA[0]} contains replica type (initiator / target) + #${REPLICA[1]} contains full replica path (can be absolute or relative) with ending slash + #${REPLICA[2]} contains full lock file path + #${REPLICA[3]} contains state dir path, relative to replica path + #${REPLICA[4]} contains backup dir path, relative to replica path + #${REPLICA[5]} contains deletion dir path, relative to replica path + #${REPLICA[6]} contains partial dir path, relative to replica path + #${REPLICA[7]} contains full last action file path + #${REPLICA[8]} contains full resume count file path + + # Local variables used for state filenames + local lock_filename="lock" + local state_dir="state" + local backup_dir="backup" + local delete_dir="deleted" + local partial_dir="_partial" + local last_action="last-action" + local resume_count="resume-count" + local dry_suffix="dry" + + #TODO: replace all other instances by the following + INITIATOR=( + 'initiator' + "$INITIATOR_SYNC_DIR" + "$INITIATOR_SYNC_DIR$OSYNC_DIR/$lock_filename" + "$OSYNC_DIR/$state_dir" + "$OSYNC_DIR/$backup_dir" + "$OSYNC_DIR/$delete_dir" + "$OSYNC_DIR/$partial_dir" + "$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$last_action-$INSTANCE_ID$dry_suffix" + "$INITIATOR_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix" + ) - ## Working directories to keep backups of updated / deleted files - INITIATOR_BACKUP_DIR="$OSYNC_DIR/backups" - INITIATOR_DELETE_DIR="$OSYNC_DIR/deleted" - TARGET_BACKUP_DIR="$OSYNC_DIR/backups" - TARGET_DELETE_DIR="$OSYNC_DIR/deleted" + TARGET=( + 'target' + "$TARGET_SYNC_DIR" + "$TARGET_SYNC_DIR$OSYNC_DIR/$lock_filename" + "$OSYNC_DIR/$state_dir" + "$OSYNC_DIR/$backup_dir" + "$OSYNC_DIR/$delete_dir" + "$OSYNC_DIR/$partial_dir" + "$TARGET_SYNC_DIR$OSYNC_DIR/$state_dir/$last_action-$INSTANCE_ID$dry_suffix" + "$TARGET_SYNC_DIR$OSYNC_DIR/$state_dir/$resume_count-$INSTANCE_ID$dry_suffix" + ) - ## Partial downloads dirs PARTIAL_DIR=$OSYNC_DIR"_partial" - ## TODO: checksum=no / yes not implemented, be careful with sync_attrs which must itemize based on mtime - ## Set sync only function arguments for rsync SYNC_OPTS="-u" @@ -2118,19 +2167,6 @@ function Init { SYNC_OPTS=$SYNC_OPTS" --stats" fi - ## Conflict options - if [ "$CONFLICT_BACKUP" != "no" ]; then - INITIATOR_BACKUP="--backup --backup-dir=\"$INITIATOR_BACKUP_DIR\"" - TARGET_BACKUP="--backup --backup-dir=\"$TARGET_BACKUP_DIR\"" - if [ "$CONFLICT_BACKUP_MULTIPLE" == "yes" ]; then - INITIATOR_BACKUP="$INITIATOR_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" - TARGET_BACKUP="$TARGET_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" - fi - else - INITIATOR_BACKUP= - TARGET_BACKUP= - fi - ## Add Rsync include / exclude patterns if [ $_QUICK_SYNC -lt 2 ]; then RsyncPatterns @@ -2141,13 +2177,24 @@ function Init { dry_suffix="-dry" fi + ## Conflict options + if [ "$CONFLICT_BACKUP" != "no" ]; then + INITIATOR_BACKUP="--backup --backup-dir=\"${INITIATOR[1]}${INITIATOR[4]}\"" + TARGET_BACKUP="--backup --backup-dir=\"${TARGET[1]}${TARGET[4]}\"" + if [ "$CONFLICT_BACKUP_MULTIPLE" == "yes" ]; then + INITIATOR_BACKUP="$INITIATOR_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" + TARGET_BACKUP="$TARGET_BACKUP --suffix .$(date +%Y.%m.%d-%H.%M.%S)" + fi + else + INITIATOR_BACKUP=" + TARGET_BACKUP=" + fi + TREE_CURRENT_FILENAME="-tree-current-$INSTANCE_ID$dry_suffix" TREE_AFTER_FILENAME="-tree-after-$INSTANCE_ID$dry_suffix" TREE_AFTER_FILENAME_NO_SUFFIX="-tree-after-$INSTANCE_ID" DELETED_LIST_FILENAME="-deleted-list-$INSTANCE_ID$dry_suffix" FAILED_DELETE_LIST_FILENAME="-failed-delete-$INSTANCE_ID$dry_suffix" - INITIATOR_LAST_ACTION="$INITIATOR_STATE_DIR/last-action-$INSTANCE_ID$dry_suffix" - INITIATOR_RESUME_COUNT="$INITIATOR_STATE_DIR/resume-count-$INSTANCE_ID$dry_suffix" ## Sync function actions (0-10) SYNC_ACTION=(