#!/bin/bash
# Probe-Boot mit Rückfall (bashclub-be reboot, bashclub-os #11), Phase
# early-setup: läuft bei jedem Start vor dem Pool-Import, unter UEFI und BIOS.
#
# Zustand: Datei bashclub/probe auf jeder ESP, eine Zeile
#   <neues BE>|<altes BE>|<versuch>|<watchdog-sekunden>
# bashclub-be legt sie mit Versuch 0 an und setzt bootfs auf das alte BE.
# Versuch 0 → 1: dieser Start probiert das neue BE (boot-sel-Hook kexect es),
#   der Watchdog wird scharfgeschaltet. Bestätigt das neue BE nicht (Hänger,
#   Panic, Reset), kommt der nächste Start hier mit Versuch 1 an.
# Versuch 1 → failed: ZFSBootMenu startet normal bootfs, also das alte BE;
#   bashclub-be meldet dort den Fehlschlag.
# Ohne diesen Hook (z. B. älteres ZBM als Rückfall) startet immer bootfs.
STATE=bashclub/probe
ESP_TYPE=c12a7328-f81f-11d2-ba4b-00a0c93ec93b
mnt=/run/bashclub-esp
log() { echo "<4>bashclub-probe: $*" >/dev/kmsg; }

udevadm settle -t 10 >/dev/null 2>&1
mkdir -p "$mnt"
line="" esps=()
while read -r part type; do
	[ "${type,,}" = "$ESP_TYPE" ] || continue
	mount -t vfat "$part" "$mnt" 2>/dev/null || continue
	if [ -f "$mnt/$STATE" ]; then
		[ -n "$line" ] || line=$(head -n 1 "$mnt/$STATE")
		esps+=("$part")
	fi
	umount "$mnt"
done < <(lsblk -lnpo NAME,PARTTYPE 2>/dev/null)
[ -n "$line" ] || exit 0

IFS='|' read -r new old tries wdsec <<<"$line"
case "$tries" in
0) next=1 ;;
1) next=failed ;;
*) exit 0 ;;
esac
for part in "${esps[@]}"; do
	mount -t vfat "$part" "$mnt" 2>/dev/null || continue
	printf '%s|%s|%s|%s\n' "$new" "$old" "$next" "$wdsec" >"$mnt/$STATE.new" && mv -f "$mnt/$STATE.new" "$mnt/$STATE"
	sync
	umount "$mnt"
done

if [ "$next" = failed ]; then
	log "$new nicht bestätigt, starte bootfs ($old)"
	exit 0
fi
# Für den boot-sel-Hook: diesen Start das neue BE probieren
printf '%s|%s\n' "$new" "$old" >/run/bashclub-probe
# Watchdog: Zeit setzen (wdctl schließt mit magischem „V“ = aus), dann ohne
# „V“ öffnen und schließen: er läuft weiter. kexec hält ihn dank
# watchdog.stop_on_reboot=0 nicht an; im neuen BE ist sein Treiber bis zur
# Bestätigung gesperrt (boot-sel-Hook), erst bashclub-be confirm lädt ihn.
for _ in 1 2 3 4 5 6 7 8 9 10; do [ -c /dev/watchdog ] && break; sleep 0.5; done
if [ -c /dev/watchdog ]; then
	# Nicht über das Maximum des Chips hinaus (iTCO etwa 613 s): wdctl -s
	# scheiterte sonst, und es bliebe die viel kürzere Vorgabe des Treibers
	sys=/sys/class/watchdog/watchdog0
	[[ $wdsec =~ ^[0-9]+$ ]] || wdsec=600
	max=$(cat "$sys/max_timeout" 2>/dev/null)
	if [[ $max =~ ^[0-9]+$ ]] && [ "$max" -gt 0 ] && [ "$wdsec" -gt "$max" ]; then
		log "Watchdog-Maximum $max s statt $wdsec s"
		wdsec=$max
	fi
	wdctl -s "$wdsec" >/dev/null 2>&1 || log "wdctl -s $wdsec gescheitert"
	printf x >/dev/watchdog
	log "Versuch mit $new, Watchdog $(cat "$sys/timeout" 2>/dev/null || echo "$wdsec") s ($(cat "$sys/identity" 2>/dev/null))"
else
	log "Versuch mit $new, ohne Watchdog (nur panic=10)"
fi
exit 0
