mirror of
https://github.com/linuxboot/heads.git
synced 2024-12-20 05:28:08 +00:00
functions: Add visibility to DO_WITH_DEBUG without affecting command
DO_WITH_DEBUG traces command exit status (if failed), stdout/stderr (if not empty), and PATH (if command was not found). The caller still observes the exit status, and stdout/stderr still go to the caller as well. This way, DO_WITH_DEBUG can be inserted anywhere with minimal spam in the logs and without affecting the script. Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
This commit is contained in:
parent
ae5f9c5416
commit
015af7e6c7
@ -12,35 +12,106 @@ mask_param() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Trace a command with DEBUG, then execute it.
|
# Pipe input to this to sink it to the debug log, with a name prefix.
|
||||||
|
# If the input is empty, no output is produced, so actual output is
|
||||||
|
# readily visible in logs.
|
||||||
|
#
|
||||||
|
# For example:
|
||||||
|
# ls /boot/vmlinux* | SINK_DEBUG "/boot kernels"
|
||||||
|
SINK_DEBUG() {
|
||||||
|
local name="$1"
|
||||||
|
local line haveblank
|
||||||
|
# If the input doesn't end with a line break, read won't give us the
|
||||||
|
# last (unterminated) line. Add a line break with echo to ensure we
|
||||||
|
# don't lose any input. Buffer up to one blank line so we can avoid
|
||||||
|
# emitting a final (or only) blank line.
|
||||||
|
(cat; echo) | while IFS= read -r line; do
|
||||||
|
[[ -n "$haveblank" ]] && DEBUG "$name: " # Emit buffered blank line
|
||||||
|
if [[ -z "$line" ]]; then
|
||||||
|
haveblank=y
|
||||||
|
else
|
||||||
|
haveblank=
|
||||||
|
DEBUG "$name: $line"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Trace a command with DEBUG, then execute it. Trace failed exit status, stdout
|
||||||
|
# and stderr, etc.
|
||||||
|
#
|
||||||
|
# DO_WITH_DEBUG is designed so it can be dropped in to most command invocations
|
||||||
|
# without side effects - it adds visibility without actually affecting the
|
||||||
|
# execution of the script. Exit statuses, stdout, and stderr are traced, but
|
||||||
|
# they are still returned/written to the caller.
|
||||||
|
#
|
||||||
# A password parameter can be masked by passing --mask-position N before the
|
# A password parameter can be masked by passing --mask-position N before the
|
||||||
# command to execute, the debug trace will just indicate whether the password
|
# command to execute, the debug trace will just indicate whether the password
|
||||||
# was empty or nonempty (which is important when use of a password is optional).
|
# was empty or nonempty (which is important when use of a password is optional).
|
||||||
# N=0 is the name of the command to be executed, N=1 is its first parameter,
|
# N=0 is the name of the command to be executed, N=1 is its first parameter,
|
||||||
# etc.
|
# etc.
|
||||||
|
#
|
||||||
|
# DO_WITH_DEBUG() can be added in most places where a command is executed to
|
||||||
|
# add visibility in the debug log. For example:
|
||||||
|
#
|
||||||
|
# [DO_WITH_DEBUG] mount "$BLOCK" "$MOUNTPOINT"
|
||||||
|
# ^-- adding DO_WITH_DEBUG will show the block device, mountpoint, and whether
|
||||||
|
# the mount fails
|
||||||
|
#
|
||||||
|
# [DO_WITH_DEBUG --mask-position 7] tpmr seal "$KEY" "$IDX" "$pcrs" "$pcrf" "$size" "$PASSWORD"
|
||||||
|
# ^-- trace the resulting invocation, but mask the password in the log
|
||||||
|
#
|
||||||
|
# if ! [DO_WITH_DEBUG] umount "$MOUNTPOINT"; then [...]
|
||||||
|
# ^-- it can be used when the exit status is checked, like the condition of `if`
|
||||||
|
#
|
||||||
|
# hotp_token_info="$([DO_WITH_DEBUG] hotp_verification info)"
|
||||||
|
# ^-- output of hotp_verification info becomes visible in debug log while
|
||||||
|
# still being captured by script
|
||||||
|
#
|
||||||
|
# [DO_WITH_DEBUG] umount "$MOUNTPOINT" &>/dev/null || true
|
||||||
|
# ^-- if the command's stdout/stderr/failure are ignored, this still works the
|
||||||
|
# same way with DO_WITH_DEBUG
|
||||||
DO_WITH_DEBUG() {
|
DO_WITH_DEBUG() {
|
||||||
local exit_status
|
local exit_status=0
|
||||||
local cmd_output
|
local cmd_output
|
||||||
DEBUG "PATH: $PATH"
|
|
||||||
local cmd=("$@")
|
|
||||||
if [[ "$1" == "--mask-position" ]]; then
|
if [[ "$1" == "--mask-position" ]]; then
|
||||||
local mask_position="$2"
|
local mask_position="$2"
|
||||||
shift
|
shift
|
||||||
shift
|
shift
|
||||||
cmd=("$@")
|
local show_args=("$@")
|
||||||
cmd[$mask_position]="$(mask_param "${cmd[$mask_position]}")"
|
show_args[$mask_position]="$(mask_param "${show_args[$mask_position]}")"
|
||||||
|
DEBUG "${show_args[@]}"
|
||||||
|
else
|
||||||
|
DEBUG "$@"
|
||||||
fi
|
fi
|
||||||
if [[ ${#cmd[@]} -eq 1 ]]; then
|
|
||||||
# If there's only one argument, try to split it into multiple arguments
|
# Execute the command and capture the exit status. Tee stdout/stderr to
|
||||||
read -a cmd <<< "${cmd[0]}"
|
# debug sinks, so they're visible but still can be used by the caller
|
||||||
|
#
|
||||||
|
# This is tricky when set -e / set -o pipefail may or may not be in
|
||||||
|
# effect.
|
||||||
|
# - Putting the command in an `if` ensures set -e won't terminate us,
|
||||||
|
# and also does not overwrite $? (like `|| true` would).
|
||||||
|
# - We capture PIPESTATUS[0] whether the command succeeds or fails,
|
||||||
|
# since we don't know whether the pipeline status will be that of the
|
||||||
|
# command or 'tee' (depends on set -o pipefail).
|
||||||
|
if ! "$@" 2> >(tee /dev/stderr | SINK_DEBUG "$1 err") | tee >(SINK_DEBUG "$1 out"); then
|
||||||
|
exit_status="${PIPESTATUS[0]}"
|
||||||
|
else
|
||||||
|
exit_status="${PIPESTATUS[0]}"
|
||||||
fi
|
fi
|
||||||
DEBUG "Executing command with cmd: ${cmd[*]}"
|
if [[ "$exit_status" -ne 0 ]]; then
|
||||||
# Sanitize the command output by removing special characters
|
# Trace unsuccessful exit status, but only at DEBUG because this
|
||||||
cmd_output=$("${cmd[@]}" 2>&1 | sed 's/[&;|`$(){}<>]//g')
|
# may be expected. Include the command name in case the command
|
||||||
exit_status=$?
|
# also invoked a DO_WITH_DEBUG (it could be a script).
|
||||||
DEBUG "Command output: $cmd_output"
|
DEBUG "$1: exited with status $exit_status"
|
||||||
DEBUG "Command exited with status: $exit_status"
|
fi
|
||||||
return $exit_status
|
# If the command was (probably) not found, trace PATH in case it
|
||||||
|
# prevented the command from being found
|
||||||
|
if [[ "$exit_status" -eq 127 ]]; then
|
||||||
|
DEBUG "$1: PATH=$PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return "$exit_status"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Trace the current script and function.
|
# Trace the current script and function.
|
||||||
|
Loading…
Reference in New Issue
Block a user