diff --git a/misc/run-command-shim b/misc/run-command-shim old mode 100644 new mode 100755 index b6f1bbf..9784d4c --- a/misc/run-command-shim +++ b/misc/run-command-shim @@ -13,53 +13,12 @@ fi # in multiconfig case $ConfigExtensionName and $ConfigSequenceNumber should be set by the agent readonly EXTENSION_NAME=$ConfigExtensionName readonly SEQNO=$ConfigSequenceNumber + echo "ConfigExtensionName: $EXTENSION_NAME" echo "ConfigSequenceNumber: $SEQNO" echo Architecture: $ARCHITECTURE echo Binary: $HANDLER_BIN -check_binary_write_lock() { - set +e # disable exit on non-zero return code - local retry_attempts=0 - while (( retry_attempts < 10 )); do - lsof_result="$(lsof -F ac ${bin})" - lsof_return_code=$? - if [ "$lsof_return_code" -eq 0 ]; then - #"lsof -F" outputs results in more parse-able format, "-F ac" option prints access mode and command name for process - #access mode and command names are prepended with a and c - file_mode="$(echo "$lsof_result" | awk 'match($0, /^a(.*)$/) {print $0}')" - process_name="$(echo "$lsof_result" | awk 'match($0, /^c(.*)$/) {print substr($0, RSTART+1, RLENGTH-1)}')" - - found_write_lock=0 - file_mode_array=($file_mode) - i=0 - for name in $process_name - do - file_handle_mode=${file_mode_array[$i]} - echo "$name has access mode '$file_handle_mode' file handle on ${HANDLER_BIN}" - ## w and u are file descriptor modes for write and read/write access - if [[ $file_handle_mode == "aw" ]] || [[ $file_handle_mode == "au" ]]; then - found_write_lock=1 - fi - ((++i)) - done - if [ "$found_write_lock" -eq 0 ]; then - # did not find write lock on any file no need to wait or retry - break - fi - ((++retry_attempts)) - echo "waiting for process(es) with write handle on ${HANDLER_BIN}" - echo "sleeping for 3 seconds before retry, attempt ${retry_attempts} of 10" - sleep 3 - else - break - fi - done - # do not return error if file descriptor is open after retries expire, make a best effort attempt to start custom-script-extension - set -e - return 0 -} - if [ "$#" -ne 1 ]; then echo "Incorrect usage." echo "Usage: $0 " @@ -74,17 +33,54 @@ exec &> >(tee -ia "$LOG_DIR/$LOG_FILE") bin="$(readlink -f "$SCRIPT_DIR/$HANDLER_BIN")" cmd="$1" +# For commands other than 'enable', execute the handler process as a child process +commandToExecute="'$bin' '$cmd'" + if [[ "$cmd" == "enable" ]]; then # for 'enable' command, double fork # to detach from the handler process tree to avoid getting terminated # after the 15-minute extension enabling timeout. - check_binary_write_lock - set -x - # & will execute the binary on the backgraound and will not block current shell execution - nohup "$bin" "$cmd" & + # & will execute the binary on the background and will not block current shell execution + commandToExecute="nohup '$bin' '$cmd' &" +fi + +### Retry logic to check if RunCommand binary is open for write and execute the command +set +e # disable exit on non-zero return code +retry_attempts=0 + +set -x +if command -v fuser &>/dev/null; then # check if fuser command is available + while (( retry_attempts < 10 )); do + # Use fuser to detect if the run command binary is open for write to help detect potential conflicts like 'text file busy' errors that prevents execution of Run Command binary. + fuser_output=$(fuser -vw "$bin" 2>&1) + fuser_status=$? + + # Use 10 retries with 3 seconds sleep between retries to allow for any potential conflicts to resolve before executing the Run Command binary. + if [ $fuser_status -eq 0 ]; then # atleast one process was found which has opened the binary in write mode. + echo "RunCommand binary $bin is open for write. User(s) with write access:" + echo "$fuser_output" + echo "Binary is open for write. Allowing execution via best-effort path after all retries have been exhausted..." + ((++retry_attempts)) + echo "sleeping for 3 seconds before retry, attempt ${retry_attempts} of 10" + sleep 3 + continue + elif [ $fuser_status -eq 1 ]; then + echo "Binary $bin is not open for write. All good. Proceeding with execution..." + break + else + echo "$fuser_output" + echo "Unexpected fuser error with error code $fuser_status while checking if $bin is open for write using fuser command. Proceeding with best-effort execution..." + break + fi + done else - # execute the handler process as a child process - check_binary_write_lock - set -x - "$bin" "$cmd" + echo "INFO: Not an error. fuser command not found. Install 'psmic' package to use fuser for checking if the Run Command binary is open for write to detect potential conflicts like 'text file busy' errors while executing Run Command binary. Proceeding with best-effort execution..." fi +### End of retry logic + +echo "Starting run-command-handler..." +$commandToExecute +echo "run-command-handler finished." +set +x + +set -e