#!/bin/bash # macOS TCC workaround (M3U96a): processes started by PM2/launchd have no "Full Disk Access" and block on the # external SSD (/Volumes/ssd). sshd-keygen-wrapper does have Full Disk Access, so PM2 runs this wrapper, which # executes the real command on localhost through sshd. PM2 supervises this wrapper; on stop/restart the wrapper # sends SIGTERM to the *remote* process (graceful: the worker finishes its current job) and waits for it, so no # orphan workers are left behind. A leftover remote process from a previous incarnation (same PM2 name) is # terminated first. # Usage: run-under-sshd.sh set -u WORKDIR="$1"; shift KEY="$HOME/.ssh/id_ed25519_maclustr" REMOTE_PATH="/opt/homebrew/opt/postgresql@17/bin:/opt/homebrew/bin:$HOME/.local/bin:/usr/bin:/bin:/usr/sbin:/sbin" NAME="${name:-findata-$$}" # PM2 exports the process name as $name PIDFILE="$WORKDIR/logs/sshd-$NAME.pid" GRACE="${FINDATA_STOP_GRACE:-3600}" # seconds to wait after SIGTERM before SIGKILL (workers finish their job) case "$NAME" in *api*) GRACE="${FINDATA_STOP_GRACE:-30}";; esac mkdir -p "$WORKDIR/logs" SSH=(ssh -T -q -o BatchMode=yes -o IdentitiesOnly=yes -i "$KEY" -o StrictHostKeyChecking=accept-new -o ServerAliveInterval=30 -o ServerAliveCountMax=3 localhost) if [ -f "$PIDFILE" ]; then OLD=$(cat "$PIDFILE" 2>/dev/null) if [ -n "$OLD" ] && kill -0 "$OLD" 2>/dev/null; then echo "run-under-sshd: terminating leftover remote process $OLD for $NAME" >&2 kill -TERM "$OLD" 2>/dev/null for _ in $(seq 1 "$GRACE"); do kill -0 "$OLD" 2>/dev/null || break; sleep 1; done kill -0 "$OLD" 2>/dev/null && { echo "run-under-sshd: SIGKILL leftover $OLD" >&2; kill -KILL "$OLD" 2>/dev/null; sleep 1; } fi fi CMD=$(printf '%q ' "$@") "${SSH[@]}" "ulimit -n 65536 2>/dev/null; cd $(printf '%q' "$WORKDIR") && export PATH=$REMOTE_PATH FINDATA_ROOT=$(printf '%q' "$WORKDIR") PYTHONUNBUFFERED=1 && echo \$\$ > $(printf '%q' "$PIDFILE") && exec $CMD" & SSHPID=$! stop() { REMOTE=$(cat "$PIDFILE" 2>/dev/null) if [ -n "$REMOTE" ]; then kill -TERM "$REMOTE" 2>/dev/null for _ in $(seq 1 "$GRACE"); do kill -0 "$REMOTE" 2>/dev/null || break; sleep 1; done kill -0 "$REMOTE" 2>/dev/null && kill -KILL "$REMOTE" 2>/dev/null fi wait "$SSHPID" 2>/dev/null rm -f "$PIDFILE" exit 0 } trap stop TERM INT HUP wait "$SSHPID" RC=$? rm -f "$PIDFILE" exit $RC