#!/bin/bash cd /root/keyhunter # v7.11: flock — check-then-act guards are not atomic; concurrent invocations # (cron + manual) both seeing 0 would double-spawn. -n: second instance exits. # v7.13: spawns MUST close fd 200 (200>&-) — an inherited lock fd held by the # 39 long-lived lanes/validator would keep the flock forever and silently # disable every subsequent keeper tick (Sentinel). Lock outside world-writable # /tmp; verify between ticks with: flock -n data/lane_keeper.lock -c true. exec 200>/root/keyhunter/data/lane_keeper.lock flock -n 200 || exit 0 # v7.10: one-generation .out rotate at 8MB — PYTHONUNBUFFERED made logs grow # between respawns; keep .1 as evidence (Sentinel). for _lf in data/*_eternal.out; do if [ -f "$_lf" ] && [ "$(stat -c %s "$_lf" 2>/dev/null || echo 0)" -gt 8388608 ]; then cp "$_lf" "$_lf.1" && : > "$_lf" # copytruncate NOT mv: lanes hold O_APPEND # FDs — mv would leave the writer appending to .1 while .out goes stale fi done # jenkins/dockerhub also renamed to .disabled in canon (off the glob entirely); # this list guards stale copies that may linger on the VPS. # sourcegraph PAUSED pending user decision (Sentinel flag): continuous Chrome-UA # WAF-bypass from the shared VPS IP; yield 6 unvalidated matches (GOOGLE-heavy, # 89%-DEAD family). Resume = remove from DISABLED + tighter caps (SLEEP>=600, # lower MAX_ITEMS) — or retire. Safer unattended default: paused. DISABLED="jenkins_eternal.py dockerhub_eternal.py sourcegraph_eternal.py" for f in *_eternal.py; do case " $DISABLED " in *" $f "*) continue;; esac pgrep -f "$f" > /dev/null || { # v7.6: bare-filename pgrep also matches the stagger wrapper (no double-start # when keeper runs twice within 30s); .out truncated per respawn (bounded, # shows only current incarnation) : > "data/${f%.py}.out" setsid nohup bash -c "sleep $((RANDOM % 30)); exec env PYTHONUNBUFFERED=1 python3 '$f'" >> "data/${f%.py}.out" 2>&1 < /dev/null 200>&- & echo "$(date '+%F %T') respawn $f" >> data/lane_keeper.log } done # v7.1: keep the eternal validator alive with VISIBLE logs. # v7.12: ANCHORED interpreter guard — a lingering `bash -c` wrapper's cmdline # mentions validator_loop.py and would satisfy any substring guard while the # real interpreter is dead (silent no-respawn, observed at bg_168/169). # ^python3 matches only the interpreter; keeper's env-startup execs, so the # cmdline is exactly "python3 validator_loop.py". Starters MUST use this # relative form; pkill keeps the bracket form '[v]alidator_loop\.py'. pgrep -f "^python3 (.* )?validator_loop\.py" > /dev/null || { # flag-tolerant anchor (python3 -u / env forms) setsid nohup env PYTHONUNBUFFERED=1 python3 validator_loop.py >> data/validator_loop.log 2>&1 < /dev/null 200>&- & echo "$(date '+%F %T') respawn validator_loop.py" >> data/lane_keeper.log }