The pending-entry grep anchored on "menuentry 'Ubuntu'" with -A4 and matched no linux line, so the script printed nothing where it should have shown the next boot's command line; the PENDING line then said "is in grub.cfg" when the loop only ever compared the tracked file against /proc/cmdline. Now the default entry's linux line is parsed with awk (first linux line of the first Ubuntu menuentry, which is what GRUB_DEFAULT=0 selects), its iommu token is printed, and a mismatch against the tracked file warns by name.
80 lines
3.1 KiB
Bash
Executable File
80 lines
3.1 KiB
Bash
Executable File
#!/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
|