From 416f2c1e4510568cd4c92a8fa45023621708ac53 Mon Sep 17 00:00:00 2001 From: deajan Date: Thu, 18 Aug 2016 23:28:41 +0200 Subject: [PATCH] Updated ofunctions from obackup project --- dev/ofunctions.sh | 93 ++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/dev/ofunctions.sh b/dev/ofunctions.sh index cf20df1..a1183d6 100644 --- a/dev/ofunctions.sh +++ b/dev/ofunctions.sh @@ -1,6 +1,6 @@ #### MINIMAL-FUNCTION-SET BEGIN #### -## FUNC_BUILD=2016081201 +## FUNC_BUILD=2016081805 ## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr ## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode @@ -9,9 +9,6 @@ if ! type "$BASH" > /dev/null; then exit 127 fi -## Log a state message every $KEEP_LOGGING seconds. Should not be equal to soft or hard execution time so your log will not be unnecessary big. -KEEP_LOGGING=1801 - ## Correct output of sort command (language agnostic sorting) export LC_ALL=C @@ -23,7 +20,9 @@ _DRYRUN=0 _SILENT=0 _LOGGER_PREFIX="date" _LOGGER_STDERR=0 - +if [ "$KEEP_LOGGING" == "" ]; then + KEEP_LOGGING=1801 +fi # Initial error status, logging 'WARN', 'ERROR' or 'CRITICAL' will enable alerts flags ERROR_ALERT=0 @@ -171,8 +170,8 @@ function QuickLogger { # Portable child (and grandchild) kill function tester under Linux, BSD and MacOS X function KillChilds { - local pid="${1}" # Parent pid to kill - local self="${2:-false}" + local pid="${1}" # Parent pid to kill childs + local self="${2:-false}" # Should parent be killed too ? if children="$(pgrep -P "$pid")"; then @@ -203,6 +202,7 @@ function KillChilds { function KillAllChilds { local pids="${1}" # List of parent pids to kill separated by semi-colon + local self="${2:-false}" # Should parent be killed too ? __CheckArguments 1 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG @@ -210,7 +210,7 @@ function KillAllChilds { IFS=';' read -a pidsArray <<< "$pids" for pid in "${pidsArray[@]}"; do - KillChilds $pid + KillChilds $pid $self if [ $? != 0 ]; then errorcount=$((errorcount+1)) fi @@ -574,8 +574,8 @@ function WaitForTaskCompletion { local soft_max_time="${2}" # If program with pid $pid takes longer than $soft_max_time seconds, will log a warning, unless $soft_max_time equals 0. local hard_max_time="${3}" # If program with pid $pid takes longer than $hard_max_time seconds, will stop execution, unless $hard_max_time equals 0. local caller_name="${4}" # Who called this function - local exit_on_error="${5:-false}" # Should the function exit on subprocess errors - local counting="${6:-true}" # Count time since function launch if true, script launch if false + local counting="${5:-true}" # Count time since function has been launched if true, since script has been launched if false + local keep_logging="${6:-0}" # Log a standby message every X seconds. Set to zero to disable logging Logger "${FUNCNAME[0]} called by [$caller_name]." "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG __CheckArguments 6 $# ${FUNCNAME[0]} "$@" #__WITH_PARANOIA_DEBUG @@ -590,6 +590,7 @@ function WaitForTaskCompletion { local errorcount=0 # Number of pids that finished with errors local pidCount # number of given pids + local pidState # State of the process IFS=';' read -a pidsArray <<< "$pids" pidCount=${#pidsArray[@]} @@ -600,11 +601,17 @@ function WaitForTaskCompletion { newPidsArray=() for pid in "${pidsArray[@]}"; do if kill -0 $pid > /dev/null 2>&1; then - newPidsArray+=($pid) + # Handle uninterruptible sleep state or zombies by ommiting them from running process array (How to kill that is already dead ? :) + #TODO(high): have this tested on *BSD, Mac & Win + pidState=$(ps -p$pid -o state= 2 > /dev/null) + if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then + newPidsArray+=($pid) + fi else + # pid is dead, get it's exit code from wait command wait $pid - result=$? - if [ $result -ne 0 ]; then + retval=$? + if [ $retval -ne 0 ]; then errorcount=$((errorcount+1)) Logger "${FUNCNAME[0]} called by [$caller_name] finished monitoring [$pid] with exitcode [$result]." "DEBUG" if [ "$WAIT_FOR_TASK_COMPLETION" == "" ]; then @@ -623,10 +630,12 @@ function WaitForTaskCompletion { exec_time=$SECONDS fi - if [ $((($exec_time + 1) % $KEEP_LOGGING)) -eq 0 ]; then - if [ $log_ttime -ne $exec_time ]; then - log_ttime=$exec_time - Logger "Current tasks still running with pids [$(joinString , ${pidsArray[@]})]." "NOTICE" + if [ $keep_logging -ne 0 ]; then + if [ $((($exec_time + 1) % $keep_logging)) -eq 0 ]; then + if [ $log_ttime -ne $exec_time ]; then # Fix when sleep time lower than 1s + log_ttime=$exec_time + Logger "Current tasks still running with pids [$(joinString , ${pidsArray[@]})]." "NOTICE" + fi fi fi @@ -639,12 +648,14 @@ function WaitForTaskCompletion { fi if [ $exec_time -gt $hard_max_time ] && [ $hard_max_time -ne 0 ]; then Logger "Max hard execution time exceeded for task [$caller_name] with pids [$(joinString , ${pidsArray[@]})]. Stopping task execution." "ERROR" - KillChilds $pid - if [ $? == 0 ]; then - Logger "Task stopped successfully." "NOTICE" - else - Logger "Could not stop task." "ERROR" - fi + for pid in "${pidsArray[@]}"; do + KillChilds $pid true + if [ $? == 0 ]; then + Logger "Task with pid [$pid] stopped successfully." "NOTICE" + else + Logger "Could not stop task with pid [$pid]." "ERROR" + fi + done SendAlert errrorcount=$((errorcount+1)) fi @@ -655,9 +666,10 @@ function WaitForTaskCompletion { done Logger "${FUNCNAME[0]} ended for [$caller_name] using [$pidCount] subprocesses with [$errorcount] errors." "PARANOIA_DEBUG" #__WITH_PARANOIA_DEBUG - if [ $exit_on_error == true ] && [ $errorcount -gt 0 ]; then - Logger "Stopping execution." "CRITICAL" - exit 1337 + + # Return exit code if only one process was monitored, else return number of errors + if [ $pidCount -eq 1 ] && [ $errorcount -eq 0 ]; then + return $errorcount else return $errorcount fi @@ -707,7 +719,7 @@ function EscapeSpaces { } function IsNumeric { - eval "local value=\"${1}\"" # Needed so variable variables can be processed + eval "local value=\"${1}\"" # Needed eval so variable variables can be processed local re="^-?[0-9]+([.][0-9]+)?$" if [[ $value =~ $re ]]; then @@ -736,9 +748,9 @@ function urlEncode { } function urlDecode { - local url_encoded="${1//+/ }" + local url_encoded="${1//+/ }" - printf '%b' "${url_encoded//%/\\x}" + printf '%b' "${url_encoded//%/\\x}" } function GetLocalOS { @@ -792,19 +804,19 @@ function GetRemoteOS { cmd=$SSH_CMD' "uname -spio" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & - WaitForTaskCompletion $! 120 240 ${FUNCNAME[0]}"-1" false true + WaitForTaskCompletion $! 120 240 ${FUNCNAME[0]}"-1" true $KEEP_LOGGING retval=$? if [ $retval != 0 ]; then cmd=$SSH_CMD' "uname -v" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & - WaitForTaskCompletion $! 120 240 ${FUNCNAME[0]}"-2" false true + WaitForTaskCompletion $! 120 240 ${FUNCNAME[0]}"-2" true $KEEP_LOGGING retval=$? if [ $retval != 0 ]; then cmd=$SSH_CMD' "uname" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & - WaitForTaskCompletion $! 120 240 ${FUNCNAME[0]}"-3" false true + WaitForTaskCompletion $! 120 240 ${FUNCNAME[0]}"-3" true $KEEP_LOGGING retval=$? if [ $retval != 0 ]; then Logger "Cannot Get remote OS type." "ERROR" @@ -857,7 +869,7 @@ function RunLocalCommand { Logger "Running command [$command] on local host." "NOTICE" eval "$command" > "$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID" 2>&1 & - WaitForTaskCompletion $! 0 $hard_max_time ${FUNCNAME[0]} false true + WaitForTaskCompletion $! 0 $hard_max_time ${FUNCNAME[0]} true $KEEP_LOGGING retval=$? if [ $retval -eq 0 ]; then Logger "Command succeded." "NOTICE" @@ -892,7 +904,7 @@ function RunRemoteCommand { cmd=$SSH_CMD' "$command" > "'$RUN_DIR/$PROGRAM.${FUNCNAME[0]}.$SCRIPT_PID'" 2>&1' Logger "cmd: $cmd" "DEBUG" eval "$cmd" & - WaitForTaskCompletion $! 0 $hard_max_time ${FUNCNAME[0]} false true + WaitForTaskCompletion $! 0 $hard_max_time ${FUNCNAME[0]} true $KEEP_LOGGING retval=$? if [ $retval -eq 0 ]; then Logger "Command succeded." "NOTICE" @@ -926,7 +938,7 @@ function RunBeforeHook { pids="$pids;$!" fi if [ "$pids" != "" ]; then - WaitForTaskCompletion $pids 0 0 ${FUNCNAME[0]} false true + WaitForTaskCompletion $pids 0 0 ${FUNCNAME[0]} true $KEEP_LOGGING fi } @@ -945,7 +957,7 @@ function RunAfterHook { pids="$pids;$!" fi if [ "$pids" != "" ]; then - WaitForTaskCompletion $pids 0 0 ${FUNCNAME[0]} false true + WaitForTaskCompletion $pids 0 0 ${FUNCNAME[0]} true $KEEP_LOGGING fi } @@ -956,7 +968,7 @@ function CheckConnectivityRemoteHost { if [ "$REMOTE_HOST_PING" != "no" ] && [ "$REMOTE_OPERATION" != "no" ]; then eval "$PING_CMD $REMOTE_HOST > /dev/null 2>&1" & - WaitForTaskCompletion $! 10 180 ${FUNCNAME[0]} false true + WaitForTaskCompletion $! 10 180 ${FUNCNAME[0]} true $KEEP_LOGGING if [ $? != 0 ]; then Logger "Cannot ping $REMOTE_HOST" "ERROR" return 1 @@ -978,7 +990,7 @@ function CheckConnectivity3rdPartyHosts { for i in $REMOTE_3RD_PARTY_HOSTS do eval "$PING_CMD $i > /dev/null 2>&1" & - WaitForTaskCompletion $! 10 360 ${FUNCNAME[0]} false true + WaitForTaskCompletion $! 10 360 ${FUNCNAME[0]} true $KEEP_LOGGING if [ $? != 0 ]; then Logger "Cannot ping 3rd party host $i" "NOTICE" else @@ -1299,4 +1311,9 @@ function InitRemoteOSSettings { } +## IFS debug function +function PrintIFS { + printf "IFS is: %q" "$IFS" +} + ## END Generic functions