2023-10-06 18:14:34 +03:00
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
if systemd-detect-virt -cq; then
2024-08-02 11:13:47 +03:00
echo "This test requires a VM, skipping the test"
2024-05-05 14:58:38 +03:00
exit 0
fi
if [ [ ! -x /usr/lib/systemd/systemd-bsod ] ] ; then
2024-08-02 11:13:47 +03:00
echo "systemd-bsod is not installed, skipping the test"
2023-10-06 18:14:34 +03:00
exit 0
fi
# shellcheck disable=SC2317
at_exit( ) {
local EC = $?
if [ [ $EC -ne 0 ] ] && [ [ -e /tmp/console.dump ] ] ; then
cat /tmp/console.dump
fi
if mountpoint -q /var/log/journal; then
2024-02-15 23:13:07 +03:00
# In order to preserve the journal from the just run test we need to do a little dance, as
# --relinquish-var is not a "true" opposite of --flush, meaning that it won't move the existing
# journal(s) from /var/log/ to /run/log/. To do that, let's rotate the journal first, so all
# important bits are in the archived journal(s)...
journalctl --rotate
# ...then instruct sd-journald to write further entries to the runtime journal...
2023-10-06 18:14:34 +03:00
journalctl --relinquish-var
2024-02-15 23:13:07 +03:00
# ...make sure there are no outstanding writes to the persistent journal that might block us from
# unmounting the tmpfs...
journalctl --sync
# ...move the archived journals to the runtime storage...
mv -v " /var/log/journal/ $( </etc/machine-id) " /system@*.journal " /run/log/journal/ $( </etc/machine-id) / "
# ...get rid of the tmpfs on /var/log/journal/...
2023-10-06 18:14:34 +03:00
umount /var/log/journal
2024-02-15 23:13:07 +03:00
# ...and finally flush everything to the "real" persistent journal, so we can collect it after the
# test finishes.
2023-10-06 18:14:34 +03:00
journalctl --flush
fi
return 0
}
vcs_dump_and_check( ) {
local expected_message = " ${ 1 : ? } "
# It might take a while before the systemd-bsod stuff appears on the VCS,
# so try it a couple of times
for _ in { 0..9} ; do
setterm --term linux --dump --file /tmp/console.dump
2023-12-18 20:02:41 +03:00
if grep -aq "Press any key to exit" /tmp/console.dump &&
grep -aq " $expected_message " /tmp/console.dump &&
grep -aq "The current boot has failed" /tmp/console.dump; then
2023-10-06 18:14:34 +03:00
return 0
fi
sleep .5
done
return 1
}
# Since systemd-bsod always fetches only the first emergency message from the
# current boot, let's temporarily overmount /var/log/journal with a tmpfs,
# as we're going to wipe it multiple times, but we need to keep the original
# journal intact for the other tests to work correctly.
trap at_exit EXIT
mount -t tmpfs tmpfs /var/log/journal
systemctl restart systemd-journald
systemctl stop systemd-bsod
# Since we just wiped the journal, there should be no emergency messages and
# systemd-bsod should be just a no-op
timeout 10s /usr/lib/systemd/systemd-bsod
setterm --term linux --dump --file /tmp/console.dump
( ! grep "The current boot has failed" /tmp/console.dump)
# systemd-bsod should pick up emergency messages only with UID=0, so let's check
# that as well
systemd-run --user --machine testuser@ --wait --pipe systemd-cat -p emerg echo "User emergency message"
systemd-cat -p emerg echo "Root emergency message"
journalctl --sync
# Set $SYSTEMD_COLORS so systemd-bsod also prints out the QR code
SYSTEMD_COLORS = 256 /usr/lib/systemd/systemd-bsod &
PID = $!
vcs_dump_and_check "Root emergency message"
2024-10-28 15:51:25 +03:00
grep -aq "Scan the error message" /tmp/console.dump
2023-10-06 18:14:34 +03:00
# TODO: check if systemd-bsod exits on a key press (didn't figure this one out yet)
kill $PID
timeout 10 bash -c " while kill -0 $PID ; do sleep .5; done "
# Wipe the journal
journalctl --vacuum-size= 1 --rotate
( ! journalctl -q -b -p emerg --grep .)
# Check the systemd-bsod.service as well
# Note: the systemd-bsod.service unit has ConditionVirtualization=no, so let's
# temporarily override it just for the test
mkdir /run/systemd/system/systemd-bsod.service.d
printf '[Unit]\nConditionVirtualization=\n' >/run/systemd/system/systemd-bsod.service.d/99-override.conf
systemctl daemon-reload
systemctl start systemd-bsod
systemd-cat -p emerg echo "Service emergency message"
vcs_dump_and_check "Service emergency message"
2024-02-15 23:13:07 +03:00
systemctl status systemd-bsod
2023-11-21 17:55:08 +03:00
systemctl stop systemd-bsod
# Wipe the journal
journalctl --vacuum-size= 1 --rotate
( ! journalctl -q -b -p emerg --grep .)
# Same as above, but make sure the service responds to signals even when there are
# no "emerg" messages, see systemd/systemd#30084
( ! systemctl is-active systemd-bsod)
systemctl start systemd-bsod
timeout 5s bash -xec 'until systemctl is-active systemd-bsod; do sleep .5; done'
timeout 5s systemctl stop systemd-bsod
timeout 5s bash -xec 'while systemctl is-active systemd-bsod; do sleep .5; done'