64 lines
2.6 KiB
Bash
Executable File
64 lines
2.6 KiB
Bash
Executable File
#!/bin/sh
|
|
# Is SIGINT deliverable to this process tree?
|
|
#
|
|
# WHY THIS EXISTS. A shell running a command in the background without
|
|
# job control sets SIGINT (and SIGQUIT) to SIG_IGN in the child; nohup
|
|
# adds SIGHUP. SIG_IGN is inherited across fork AND survives exec, so
|
|
# the disposition reaches every descendant --- cargo, a test binary, and
|
|
# anything either of them spawns. Tests that signal a child then wait
|
|
# for it to die will hang until their own deadline and report that as a
|
|
# teardown defect. One lane spent nine framing revisions on exactly that
|
|
# misreading; see docs/gpu-probe-sigint-framing.md §4c.
|
|
#
|
|
# INTERFACE (docs/gpu-probe-sigint-framing.md §7c) --- a validated
|
|
# (status, token) PAIR. Callers rely on both halves and MUST NOT
|
|
# re-derive the classification:
|
|
#
|
|
# 0 safe stdout: pmacs-sigint-v1:safe no diagnostic
|
|
# 1 ignored stdout: pmacs-sigint-v1:ignored canonical diagnostic
|
|
# 2 error stdout: pmacs-sigint-v1:error distinct diagnostic
|
|
#
|
|
# The token is the ONLY thing on stdout; diagnostics go to stderr. Any
|
|
# other pair --- including a plausible status with no token --- is a
|
|
# BOUNDARY error for the caller, mapped to 2.
|
|
#
|
|
# WHY A TOKEN AND NOT A STATUS ALONE. CI proved a status-only ABI
|
|
# unsound: on macOS a shell that cannot execute this file exits 1,
|
|
# which the old ABI read as `ignored`, so a broken guard told the
|
|
# operator their environment ignores SIGINT. No exit status can prove
|
|
# this script ran; a token it must have printed can.
|
|
#
|
|
# `error` is never folded into `ignored`. "Your environment ignores
|
|
# SIGINT" and "the guard could not run" are different problems, and
|
|
# conflating them fails callers for the wrong reason.
|
|
#
|
|
# THE PROBE. A child sends itself SIGINT. Deliverable => the trap runs
|
|
# => 23. Ignored => the kill is a no-op => the child falls through to
|
|
# `exit 0`. The `|| exit 24` arms matter: without them a FAILED kill
|
|
# would also fall through to `exit 0` and be misread as `ignored`,
|
|
# which is the one wrong answer this helper exists to avoid.
|
|
#
|
|
# POSIX shell only --- trap, kill, $$ --- so no /proc and no sigaction:
|
|
# the mechanism is not Linux-specific and adds no unsafe code.
|
|
|
|
probe_status=0
|
|
sh -c 'trap "exit 23" 2 || exit 24; kill -INT "$$" || exit 24; exit 0' \
|
|
|| probe_status=$?
|
|
|
|
case "$probe_status" in
|
|
23)
|
|
echo 'pmacs-sigint-v1:safe'
|
|
exit 0
|
|
;;
|
|
0)
|
|
echo 'pmacs-sigint-v1:ignored'
|
|
echo 'pmacs: SIGINT is ignored; run this command with SIGINT deliverable' >&2
|
|
exit 1
|
|
;;
|
|
*)
|
|
echo 'pmacs-sigint-v1:error'
|
|
echo "pmacs: could not determine whether SIGINT is deliverable (probe status $probe_status)" >&2
|
|
exit 2
|
|
;;
|
|
esac
|