#!/usr/bin/env bash
# shim-guard.sh — shared re-entry bound and self-rejecting resolution for the PATH
# shims in ../bin (_git-guard-shim.sh, _cpu-guard-shim.sh, _tmpjail-shim.sh,
# _kill-guard-shim.sh). Each wraps a command by its own name, so a resolution that
# lands on another copy of a shim makes the wrapper invoke itself without bound —
# that is the fork loop this file exists to make structurally impossible.
#
# Both functions use builtins only: no fork happens before the bound is in place.

# shim_guard_enter <name> — exits non-zero past the bound; sets SHIM_REENTRY=1 when
# this process is already inside the shim for <name>, meaning the caller must exec
# the real binary immediately and do no further work.
shim_guard_enter() {
  local name="$1" var depth
  var="_OD_SHIM_DEPTH_${name//[^A-Za-z0-9]/_}"
  depth="${!var:-0}"
  [[ "$depth" =~ ^[0-9]+$ ]] || depth=0
  if ((depth >= 2)); then
    echo "$name: PATH shim re-entered at depth $depth — refusing (its resolution points back at a shim)" >&2
    exit 79
  fi
  export "$var=$((depth + 1))"
  if ((depth > 0)); then SHIM_REENTRY=1; else SHIM_REENTRY=0; fi
}

# shim_is_shim <path> — 0 when the file is a script carrying OD_PATH_SHIM_MARKER.
shim_is_shim() {
  local f="$1" line i=0
  IFS= read -r line <"$f" 2>/dev/null || return 1
  [[ "$line" == '#!'* ]] || return 1
  while IFS= read -r line; do
    if [[ "$line" == *OD_PATH_SHIM_MARKER* ]]; then return 0; fi
    i=$((i + 1))
    if ((i >= 60)); then break; fi
  done <"$f"
  return 1
}

# shim_resolve_real <name> <shim_dir> — first PATH entry outside <shim_dir> holding an
# executable <name> that is not itself a shim. Prints it; rc 1 when there is none.
shim_resolve_real() {
  local name="$1" shim_dir="$2" d
  local -a parts
  IFS=':' read -ra parts <<<"$PATH"
  for d in "${parts[@]}"; do
    [[ -n "$d" && "$d" != "$shim_dir" ]] || continue
    [[ -x "$d/$name" && ! -d "$d/$name" ]] || continue
    if shim_is_shim "$d/$name"; then continue; fi
    printf '%s\n' "$d/$name"
    return 0
  done
  return 1
}
