#!/bin/bash

## Copyright (C) 2025 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
shopt -s inherit_errexit
shopt -s shift_verbose

## Emit a GRUB SMBIOS cmdline reader near the top of the generated grub.cfg (the
## '01_' prefix runs before the '10_' menuentry generators, so the variable is set
## before any menuentry body executes). It lets a boot-tester inject extra kernel
## cmdline through the real firmware -> GRUB -> kernel chain via 'qemu -smbios'
## ('dm-qemu --smbios-append') with no image edit. The literal '${dm_smbios_extra}'
## placeholder on each kernel line is added by /etc/default/grub.d/99_smbios-cmdline.cfg.
##
## Because this is a grub-mkconfig helper, the reader is regenerated on every
## 'update-grub' (e.g. on a kernel update), unlike a direct edit of the generated
## /boot/grub/grub.cfg which 'update-grub' would wipe.
##
## Read the SMBIOS Type 1 system serial number (qemu -smbios
## type=1,serial=dm-cmdline=...; offset 7 is a real string-reference field GRUB can
## read -- Type 11 OEM strings have no such field, offset 5 is past the 5-byte
## formatted area and faults) and, if it carries the 'dm-cmdline=' sentinel, expose
## the rest as ${dm_smbios_extra}. The regexp and smbios modules are in Debian's
## signed grub, so this works on BIOS and EFI; with no SMBIOS string set the reader
## is a no-op and ${dm_smbios_extra} stays empty.
##
## The heredoc is single-quoted so the shell writes ${dm_smbios_oem} literally for
## GRUB to expand at boot.
## When a boot-tester injected a cmdline via SMBIOS (dm_smbios_extra non-empty),
## drive the serial console and boot the default entry immediately (timeout=0):
## the tester drives the guest over the serial ROOT shell and cannot interact with
## the GRUB menu, so a menu wait hangs the headless boot. A normal boot (no
## injection) is unaffected -- dm_smbios_extra is empty and the block is skipped.
##
## 'terminal_output serial console' keeps 'console' deliberately.
## serial-console-enable's etc/default/grub.d/30_serial_console.cfg argues against
## pairing them, but that file sets GRUB_TERMINAL -- input AND output, on every
## boot, on real hardware -- where duplicated output and a serial-input hijack of
## the menu both matter. This sets OUTPUT only, on the injection-only test path,
## and never takes serial input. Keeping 'console' leaves video output working if
## serial init fails, and the EFI mirroring that file warns about would garble the
## harness log LOUDLY rather than silently.
##
## terminal_INPUT is left alone on purpose. serial-console-enable ships
## GRUB_TERMINAL="serial", which 00_header turns into 'terminal_input serial'
## before this '01_' snippet runs, so GRUB reads the same line the harness writes
## to. What makes that harmless is 'set timeout=0' below: with no menu countdown
## there is nothing for stray serial input to interrupt. Restoring a menu wait
## here without also pinning terminal_input would reintroduce the hang.
cat <<'EOF'
insmod regexp
insmod smbios
insmod serial
## Cleared first: 'smbios' and 'regexp' leave these untouched when they find no
## match, and GRUB variables survive from grub.cfg's earlier 'load_env'. A value
## left in grubenv would otherwise make an ordinary boot take the tester path.
set dm_smbios_oem=
set dm_smbios_extra=
smbios --type 1 --get-string 7 --set dm_smbios_oem
regexp --set 1:dm_smbios_extra "^dm-cmdline=(.*)" "${dm_smbios_oem}"
if [ -n "${dm_smbios_extra}" ]; then
    serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
    terminal_output serial console
    set timeout=0
fi
EOF
