diff --git a/openfut-redirector-host/redirector.sh b/openfut-redirector-host/redirector.sh index 3741b80..789d5eb 100755 --- a/openfut-redirector-host/redirector.sh +++ b/openfut-redirector-host/redirector.sh @@ -22,8 +22,36 @@ PORTFILE="$RUNDIR/redirector.port" # when the branch ref moves) can silently advance past the live process. STAMPFILE="$RUNDIR/redirector.commit" LOGFILE="${OPENFUT_REDIRECTOR_LOG:-$RUNDIR/redirector.log}" -BIN="$ROOT/target/debug/openfut-redirector-host" -[[ -x "$BIN" ]] || BIN="$ROOT/target/release/openfut-redirector-host" +# Which artifact is under test must never be ambiguous. Preferring debug and +# falling back to release meant `cargo build --release` could produce a fresh +# binary while this kept launching a stale debug one — the guard then compared +# the WRONG artifact against HEAD and refused with a message naming a commit +# nobody was trying to run. Both present and disagreeing is an error, not a +# preference. Set OPENFUT_REDIRECTOR_BIN to choose deliberately. +DEBUG_BIN="$ROOT/target/debug/openfut-redirector-host" +RELEASE_BIN="$ROOT/target/release/openfut-redirector-host" +BIN_ERR="" +if [[ -n "${OPENFUT_REDIRECTOR_BIN:-}" ]]; then + BIN="$OPENFUT_REDIRECTOR_BIN" + [[ -x "$BIN" ]] || { echo "redirector: OPENFUT_REDIRECTOR_BIN is not executable: $BIN" >&2; exit 1; } +elif [[ -x "$DEBUG_BIN" && -x "$RELEASE_BIN" ]]; then + d="$("$DEBUG_BIN" --identity 2>&1 | sed -nE 's/.*commit=([0-9a-f]+).*/\1/p' | head -1)" + r="$("$RELEASE_BIN" --identity 2>&1 | sed -nE 's/.*commit=([0-9a-f]+).*/\1/p' | head -1)" + if [[ "$d" != "$r" ]]; then + # Recorded, NOT fatal here: `stop` and `status` must keep working no matter + # what state the build tree is in. Rolling back can never be blocked by a + # question about which artifact would have been started. + BIN_ERR="REFUSING — two binaries exist and disagree. + debug $DEBUG_BIN commit=$d + release $RELEASE_BIN commit=$r + Rebuild both, delete one, or set OPENFUT_REDIRECTOR_BIN." + fi + BIN="$RELEASE_BIN" +elif [[ -x "$DEBUG_BIN" ]]; then + BIN="$DEBUG_BIN" +else + BIN="$RELEASE_BIN" +fi die() { echo "redirector: $*" >&2; exit 1; } pid_alive() { kill -0 "$1" 2>/dev/null; } @@ -48,16 +76,21 @@ list_procs() { return 0 } +# Only the commands that actually run a binary care which one it is. +need_bin() { [[ -z "$BIN_ERR" ]] || die "$BIN_ERR"; } + # The binary prints `commit=` in its banner; ask it rather than guessing. stamped_commit() { "$BIN" --identity 2>&1 | sed -nE 's/.*commit=([0-9a-f]+).*/\1/p' | head -1; } cmd_verify() { + need_bin local c; c="$(stamped_commit)" [[ -n "$c" ]] || die "could not read the binary's commit stamp" "$ROOT/scripts/verify-build-identity.sh" "$c" } cmd_start() { + need_bin [[ -x "$BIN" ]] || die "not built: cargo build -p openfut-redirector-host" : "${OPENFUT_REDIRECTOR_HOST_PORT:?set OPENFUT_REDIRECTOR_HOST_PORT (no default: runs beside Python)}" local strays; strays="$(list_procs)" @@ -115,6 +148,15 @@ cmd_status() { } cmd_verify_running() { + # The stamp outlives the process it describes. Without this check the command + # happily reports on a corpse — either "OK" or a REFUSAL naming a commit, + # both implying something is running when nothing is. + local pid="" + [[ -f "$PIDFILE" ]] && pid="$(cat "$PIDFILE" 2>/dev/null)" + if [[ -z "$pid" ]] || ! pid_alive "$pid"; then + echo "REFUSING: nothing is running — the stamp describes a process that has exited." >&2 + return 1 + fi [[ -f "$STAMPFILE" ]] || die "no running-process stamp — was it started by this script?" local running head running="$(cat "$STAMPFILE")"; head="$(git -C "$ROOT" rev-parse --short=7 HEAD 2>/dev/null)"