#!/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
