#!/bin/sh
# grabpanic — take the PREVIOUS boot's /panic.log aside before the kernel's
# debuglog thread overwrites it.
#
# WHY THIS EXISTS AT ALL. With `debuglog=<n>` on the cmdline the kernel writes
# the network flight recorder into /panic.log every n seconds, which is the only
# way to see the last seconds of a machine that wedges without panicking. The
# same file is the crash dump's destination. So the boot AFTER a wedge is the
# one chance to read what the wedge looked like, and the kernel holds its first
# write off for twenty seconds for precisely this copy.
#
# WHY IT IS NOT OPTIONAL, AND WHY IT WAS SILENT. The rc loop runs a script only
# when <name>_enable="YES" is set, and for its whole first life nothing set
# grabpanic_enable. It sat in /etc/rc.d/ looking installed, never ran, and every
# read of /root/panic-prev.log returned a record from an older boot that looked
# exactly like fresh evidence. Two wedge investigations were reasoned about on
# that stale copy before anyone checked. The verification line below is here so
# that can never be silent again: a copy that did not happen SAYS SO.
PREV=/root/panic-prev.log
[ -r /panic.log ] || { echo "grabpanic: no /panic.log — nothing to preserve"; exit 0; }
cp /panic.log "$PREV" 2>/dev/null || { echo "grabpanic: COPY FAILED — this boot will read the wrong evidence"; exit 0; }
sync
# Prove the copy landed and say what it holds, so the next reader can tell a
# fresh preservation from a leftover without opening the file.
printf 'grabpanic: preserved %s bytes -> %s (%s)\n' \
       "$(wc -c < "$PREV" 2>/dev/null || echo '?')" "$PREV" \
       "$(head -3 "$PREV" 2>/dev/null | tr -d '\000' | command grep -a '^write #' || echo 'no write# header — a crash dump, not a debuglog record')"
