Skip to content
Merged
96 changes: 46 additions & 50 deletions misc/run-command-shim
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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 <command>"
Expand All @@ -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
Comment thread
viveklingaiah marked this conversation as resolved.
# & 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)
Comment thread
viveklingaiah marked this conversation as resolved.
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..."
Comment thread
viveklingaiah marked this conversation as resolved.
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
Comment thread
viveklingaiah marked this conversation as resolved.

echo "Starting run-command-handler..."
$commandToExecute
echo "run-command-handler finished."
set +x

set -e
Loading