#!/bin/ksh
# One probe command for reed2, by argv: reed2 never hands a string to a shell.
#
#   reed2-run err|out|all timeout command [arg ...]
#
# err: stderr of the command is the captured stream, its stdout goes to /dev/null. The probe
#      contract puts the one-line summary on stderr, the detail on stdout [infra.git
#      docs/PROBES.md].
# out: stdout is captured, stderr dropped -- df -kP, read for its capacity column.
# all: stdout and stderr, merged -- rcctl check: the rc.d verdict `<name>(failed)` is on stdout
#      (_rc_printname, _rc_exit: plain echo), rcctl's own errors on stderr (rcctl_err ->
#      _rc_err, 1>&2) [verifie:openbsd/src etc/rc.d/rc.subr, usr.sbin/rcctl/rcctl.sh].
#
# An Erlang port reads the stdout of its child; stderr is inherited, or merged into stdout, never
# a stream of its own [verifie:erlang/otp OTP-28.0 erts/preloaded/src/erlang.erl, open_port
# options: stderr_to_stdout only]. Hence this swap, in front of the command.
#
# hn-timeout (sysutils/hn-timeout, a RUN_DEPENDS of this port) is timeout(1) of base with its
# signals blocked before fork(): base timeout 1.26 blocks them after, and a command that exits in
# between leaves it asleep until the deadline, then rc of the command -- 3 runs out of 4000 of
# `timeout 3 /usr/bin/true` on dev, OpenBSD 7.9, none out of 8000 with the fix [constate:dev,
# 2026-09-27]. A probe of a few milliseconds would hold its slot for its whole timeout.
#
# hn-timeout sends SIGTERM at the deadline, SIGKILL 5 s later, exits 124 when the first signal
# ended the command [verifie:man.openbsd.org/timeout.1], and signals the process group of the
# command [verifie:openbsd/src usr.bin/timeout/timeout.c 1.26]. The group holds hn-timeout
# itself, so the SIGKILL ends it too, and a probe that ignored SIGTERM comes back 137, not 124
# [verifie:openbsd/src sys/kern/kern_sig.c, killpg1; sysutils/hn-timeout/files/
# test-hn-timeout.sh]. stdin is /dev/null: the port keeps the child's stdin open, and a probe
# reading it would wait for the deadline.
#
# hn-timeout runs as a child, never by exec: the port child calls setsid() before its exec
# [verifie:erlang/otp OTP-28.0 erts/emulator/sys/unix/erl_child_setup.c, start_new_child], and
# setpgid() refuses a session leader, EPERM [verifie:openbsd/src sys/kern/kern_prot.c,
# sys_setpgid]: exec'd, it inherits the leadership and dies on "setpgid: Operation not
# permitted" [constate:dev, 2026-09-26]. Its exit status is passed on.
#
# PATH: the one of the daemon login class, fixed here so a probe sees the same whether reed2
# was started by rc.d, by hand or by ansible [infra.git docs/OPENBSD.md, PATH de cron].
#
# Usage errors go to stdout: that is the stream reed2 reads in every mode.

export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

usage() {
	echo "usage: ${0##*/} err|out|all timeout command [arg ...]"
	exit 2
}

[ $# -ge 3 ] || usage
mode=$1
t=$2
shift 2
case $t in ''|*[!0-9]*) usage ;; esac

case $mode in
err) /usr/local/bin/hn-timeout -k 5 "$t" "$@" 2>&1 >/dev/null </dev/null ;;
out) /usr/local/bin/hn-timeout -k 5 "$t" "$@" 2>/dev/null </dev/null ;;
all) /usr/local/bin/hn-timeout -k 5 "$t" "$@" 2>&1 </dev/null ;;
*) usage ;;
esac
