#!/usr/bin/env bash # set-dankclaw-bootline.sh — install the tracked GRUB command line # (dankclaw/host/grub) on Dankclaw and refresh grub.cfg. # # Kernel command-line state is HOST state: the deployer owns containers and # LLM units, never /etc/default/grub, so this script is the only sanctioned way # to change it, and the tracked file is the only sanctioned source. Run it from # the checkout on Dankclaw. # # ./scripts/set-dankclaw-bootline.sh # show the diff, install, update-grub # ./scripts/set-dankclaw-bootline.sh --reboot # ... and reboot into it # # The boot line is decided in # serverAppConfigs-docs/LLM/dankclaw-iommu-translation-off.md; changing it # without updating that decision record is a bug. Reboot takes the whole stack # down (Caddy edge, Authentik, Pi-hole, Gitea, OpenWebUI, both LLM units) — # plan the window, and remember frank-archon is on Dankserver and unaffected. set -euo pipefail REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" SRC="$REPO/dankclaw/host/grub" DST="/etc/default/grub" REBOOT=0 [ "${1:-}" = "--reboot" ] && REBOOT=1 [ $# -gt 1 ] && { echo "usage: $0 [--reboot]" >&2; exit 2; } [ -r "$SRC" ] || { echo "missing tracked boot line: $SRC" >&2; exit 1; } # Refuse to touch any machine but Dankclaw: this file is Dankclaw's, and the # same checkout exists on hosts with a different command line. HOST_ID="$(hostname -s 2>/dev/null || cat /etc/hostname)" case "$HOST_ID" in *dankclaw*) ;; *) echo "refusing: this boot line belongs to Dankclaw, host is '$HOST_ID'" >&2; exit 1 ;; esac echo "== diff (live $DST -> tracked $SRC)" if diff -u "$DST" "$SRC" || true; then :; fi if cmp -s "$DST" "$SRC"; then echo "== boot line already matches the tracked copy" else echo "== installing" sudo install -m 0644 -o root -g root "$SRC" "$DST" echo "== update-grub" sudo update-grub fi # The DEFAULT entry is the first 'Ubuntu' menuentry's linux line: that is the # command line the next boot actually gets. (GRUB_DEFAULT=0 here, so first it is.) echo "== grub.cfg default entry" CFG="$(sudo awk '/menuentry .Ubuntu/ && !seen {seen=1} seen && /^[[:space:]]*linux/ {print; exit}' /boot/grub/grub.cfg)" [ -n "$CFG" ] || { echo "could not read the default linux line from grub.cfg" >&2; exit 1; } printf '%s\n' "$CFG" | tr ' \t' '\n' | grep -E '^(iommu|amd_iommu)=' || echo "(no iommu token in the default entry)" echo "== running kernel" tr '\0' ' ' < /proc/cmdline; echo WANT="$(sed -n 's/^GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/\1/p' "$SRC")" NOW="$(cat /proc/cmdline)" for tok in $WANT; do case " $NOW " in *" $tok "*) ;; *) echo "PENDING: '$tok' is not in the running kernel" ;; esac done WANT_IOMMU="$(printf '%s\n' $WANT | grep -E '^(iommu|amd_iommu)=' | head -1)" CFG_IOMMU="$(printf '%s\n' "$CFG" | tr ' \t' '\n' | grep -E '^(iommu|amd_iommu)=' | head -1)" if [ "$WANT_IOMMU" != "$CFG_IOMMU" ]; then echo "WARN: grub.cfg default entry says '${CFG_IOMMU:-none}', tracked file says '${WANT_IOMMU:-none}'" >&2 fi if [ "$REBOOT" = 1 ]; then echo "== rebooting now" sudo systemctl reboot else echo "== not rebooting (pass --reboot)" fi