2023-04-28 00:17:52 +03:00
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
systemctl log-level info
if systemd-detect-virt -cq; then
echo "Running in a container, skipping the systemd-pstore test..."
exit 0
fi
2023-06-01 21:02:20 +03:00
DUMMY_DMESG_0 = " $( mktemp) "
cat >" $DUMMY_DMESG_0 " <<\E OF
2023-04-28 00:17:52 +03:00
6,17159,5340096332127,-; usb 1-4: USB disconnect, device number 124
6,17160,5340109662397,-; input: WH-1000XM3 ( AVRCP) as /devices/virtual/input/input293
6,17161,5343126458360,-; loop0: detected capacity change from 0 to 3145728
6,17162,5343126766065,-; loop0: p1 p2
6,17163,5343126815038,-; EXT4-fs ( loop0p1) : mounted filesystem with ordered data mode. Quota mode: none.
6,17164,5343158037334,-; EXT4-fs ( loop0p1) : unmounting filesystem.
6,17165,5343158072598,-; loop0: detected capacity change from 0 to 3145728
6,17166,5343158073563,-; loop0: p1 p2
6,17167,5343158074325,-; loop0: p1 p2
6,17168,5343158140859,-; EXT4-fs ( loop0p1) : mounted filesystem with ordered data mode. Quota mode: none.
6,17169,5343158182977,-; EXT4-fs ( loop0p1) : unmounting filesystem.
6,17170,5343158700241,-; loop0: detected capacity change from 0 to 3145728
6,17171,5343158700439,-; loop0: p1 p2
6,17172,5343158701120,-; loop0: p1 p2
EOF
2023-06-01 21:02:20 +03:00
DUMMY_DMESG_1 = " $( mktemp) "
cat >" $DUMMY_DMESG_1 " <<\E OF
2023-04-28 00:17:52 +03:00
Nechť již hříšné saxofony ďáblů rozezvučí síň úděsnými tóny waltzu, tanga a quickstepu.
Příliš žluťoučký kůň úpěl ďábelské ódy.
Zvlášť zákeřný učeň s ďolíčky běží podél zóny úlů.
Vyciď křišťálový nůž, ó učiň úděsné líbivým!
Loď čeří kýlem tůň obzvlášť v Grónské úžině
Ó, náhlý déšť již zvířil prach a čilá laň teď běží s houfcem gazel k úkrytům.
Vypätá dcéra grófa Maxwella s IQ nižším ako kôň núti čeľaď hrýzť hŕbu jabĺk.
Kŕdeľ šťastných ďatľov učí pri ústí Váhu mĺkveho koňa obhrýzať kôru a žrať čerstvé mäso.
Stróż pchnął kość w quiz gędźb vel fax myjń.
Portez ce vieux whisky au juge blond qui fume!
EOF
file_count( ) { find " ${ 1 : ? } " -type f | wc -l; }
file_size( ) { wc -l <" ${ 1 : ? } " ; }
random_efi_timestamp( ) { printf "%0.10d" " $(( 1000000000 + RANDOM)) " ; }
# The dmesg- filename contains the backend-type and the Common Platform Error Record, CPER,
# record id, a 64-bit number.
#
# Files are processed in reverse lexigraphical order so as to properly reconstruct original dmesg.
prepare_efi_logs( ) {
local file = " ${ 1 : ? } "
local timestamp = " ${ 2 : ? } "
local chunk count filename
# For the EFI backend, the 3 least significant digits of record id encodes a
# "count" number, the next 2 least significant digits for the dmesg part
# (chunk) number, and the remaining digits as the timestamp. See
# linux/drivers/firmware/efi/efi-pstore.c in efi_pstore_write().
count = " $( file_size " $file " ) "
chunk = 0
# The sed in the process substitution below just reverses the file
while read -r line; do
filename = " $( printf "dmesg-efi-%0.10d%0.2d%0.3d" " $timestamp " " $chunk " " $count " ) "
echo " $line " >" /sys/fs/pstore/ $filename "
chunk = $(( chunk + 1 ))
done < <( sed '1!G;h;$!d' " $file " )
if [ [ " $chunk " -eq 0 ] ] ; then
echo >& 2 "No dmesg-efi files were created"
exit 1
fi
}
prepare_erst_logs( ) {
local file = " ${ 1 : ? } "
local start_id = " ${ 2 : ? } "
local id filename
# For the ERST backend, the record is a monotonically increasing number, seeded as
# a timestamp. See linux/drivers/acpi/apei/erst.c in erst_writer().
id = " $start_id "
# The sed in the process substitution below just reverses the file
while read -r line; do
filename = " $( printf "dmesg-erst-%0.16d" " $id " ) "
echo " $line " >" /sys/fs/pstore/ $filename "
id = $(( id + 1 ))
done < <( sed '1!G;h;$!d' " $file " )
if [ [ " $id " -eq " $start_id " ] ] ; then
echo >& 2 "No dmesg-erst files were created"
exit 1
fi
# ID of the last dmesg file will be the ID of the erst subfolder
echo " $(( id - 1 )) "
}
prepare_pstore_config( ) {
local storage = " ${ 1 : ? } "
local unlink = " ${ 2 : ? } "
systemctl stop systemd-pstore
rm -fr /sys/fs/pstore/* /var/lib/systemd/pstore/*
mkdir -p /run/systemd/pstore.conf.d
2023-06-01 21:02:20 +03:00
cat >/run/systemd/pstore.conf.d/99-test.conf <<EOF
2023-04-28 00:17:52 +03:00
[ PStore]
Storage = $storage
Unlink = $unlink
EOF
systemd-analyze cat-config systemd/pstore.conf | grep " $storage "
systemd-analyze cat-config systemd/pstore.conf | grep " $unlink "
}
start_pstore( ) {
rm -f /tmp/journal.cursor
journalctl -q -n 0 --cursor-file= /tmp/journal.cursor
2023-06-01 21:02:20 +03:00
systemctl restart systemd-pstore
2023-04-28 00:17:52 +03:00
journalctl --sync
}
2023-06-02 11:07:57 +03:00
at_exit( ) {
set +e
mountpoint -q /sys/fs/pstore && umount /sys/fs/pstore
rm -fr /var/lib/systemd/pstore/*
rm -f /run/systemd/system/systemd-pstore.service.d/99-StartLimitInterval.conf
rm -f /run/systemd/pstore.conf.d/99-test.conf
}
trap at_exit EXIT
2023-04-28 00:17:52 +03:00
# To avoid having to depend on the VM providing the pstore, let's simulate
# it using a simple bind mount
PSTORE_DIR = " $( mktemp -d) "
mount --bind " ${ PSTORE_DIR : ? } " "/sys/fs/pstore"
2023-06-01 21:02:20 +03:00
# Disable the start limit since we're going to restart the systemd-pstore
# service quite a lot in a short time span
mkdir -p /run/systemd/system/systemd-pstore.service.d
cat >/run/systemd/system/systemd-pstore.service.d/99-StartLimitInterval.conf <<EOF
[ Unit]
StartLimitInterval = 0
EOF
systemctl daemon-reload
2023-04-28 00:17:52 +03:00
# systemd-pstore is a no-op with Storage=none
for unlink in yes no; do
: " Backend: N/A; Storage: none; Unlink: $unlink "
timestamp = " $( random_efi_timestamp) "
prepare_pstore_config "none" " $unlink "
2023-06-01 21:02:20 +03:00
prepare_efi_logs " $DUMMY_DMESG_0 " " $timestamp "
2023-04-28 00:17:52 +03:00
old_count = " $( file_count /sys/fs/pstore/) "
start_pstore
[ [ " $( file_count /sys/fs/pstore) " -ge " $old_count " ] ]
[ [ " $( file_count /var/lib/systemd/pstore/) " -eq 0 ] ]
: " Backend: EFI; Storage: external; Unlink: $unlink "
timestamp = " $( random_efi_timestamp) "
prepare_pstore_config "external" " $unlink "
2023-06-01 21:02:20 +03:00
prepare_efi_logs " $DUMMY_DMESG_0 " " $timestamp "
2023-04-28 00:17:52 +03:00
[ [ " $unlink " = = yes ] ] && exp_count = 0 || exp_count = " $( file_count /sys/fs/pstore/) "
start_pstore
[ [ " $( file_count /sys/fs/pstore) " -ge " $exp_count " ] ]
[ [ " $( file_count /var/lib/systemd/pstore/) " -ne 0 ] ]
# We always log to journal
2023-06-01 21:02:20 +03:00
diff " $DUMMY_DMESG_0 " <( journalctl -o cat --output-fields= FILE --cursor-file= /tmp/journal.cursor | sed " /^ $/d " )
filename = " $( printf "/var/lib/systemd/pstore/%s/%0.3d/dmesg.txt" " $timestamp " " $( file_size " $DUMMY_DMESG_0 " ) " ) "
diff " $DUMMY_DMESG_0 " " $filename "
2023-04-28 00:17:52 +03:00
: " Backend: EFI; Storage: external; Unlink: $unlink ; multiple dmesg files "
2023-06-01 21:02:20 +03:00
timestamps = ( )
timestamp = " $( random_efi_timestamp) "
2023-04-28 00:17:52 +03:00
prepare_pstore_config "external" " $unlink "
2023-06-01 21:02:20 +03:00
for i in { 0..6} ; do
timestamp = " $(( timestamp + ( i * 10 )) ) "
timestamps += ( " $timestamp " )
# Create a name reference to one of the $DUMMY_DMESG_X variables
dmesg = " DUMMY_DMESG_ $(( i % 2 )) "
prepare_efi_logs " ${ !dmesg } " " $timestamp "
# Add one "random" (non-dmesg) file as well
echo "hello world" >/sys/fs/pstore/foo.bar
[ [ " $unlink " = = yes ] ] && exp_count = 0 || exp_count = " $( file_count /sys/fs/pstore/) "
start_pstore
[ [ " $( file_count /sys/fs/pstore) " -ge " $exp_count " ] ]
[ [ " $( file_count /var/lib/systemd/pstore/) " -ne 0 ] ]
filename = " $( printf "/var/lib/systemd/pstore/%s/%0.3d/dmesg.txt" " $timestamp " " $( file_size " ${ !dmesg } " ) " ) "
diff " ${ !dmesg } " " $filename "
grep "hello world" "/var/lib/systemd/pstore/foo.bar"
done
# Check that we kept all previous records as well
for timestamp in " ${ timestamps [@] } " ; do
[ [ -d " /var/lib/systemd/pstore/ $timestamp " ] ]
[ [ " $( file_count " /var/lib/systemd/pstore/ $timestamp / " ) " -gt 0 ] ]
done
2023-04-28 00:17:52 +03:00
: " Backend: EFI; Storage: journal; Unlink: $unlink "
timestamp = " $( random_efi_timestamp) "
prepare_pstore_config "journal" " $unlink "
2023-06-01 21:02:20 +03:00
prepare_efi_logs " $DUMMY_DMESG_0 " " $timestamp "
2023-04-28 00:17:52 +03:00
[ [ " $unlink " = = yes ] ] && exp_count = 0 || exp_count = " $( file_count /sys/fs/pstore/) "
start_pstore
[ [ " $( file_count /sys/fs/pstore) " -ge " $exp_count " ] ]
[ [ " $( file_count /var/lib/systemd/pstore/) " -eq 0 ] ]
2023-06-01 21:02:20 +03:00
diff " $DUMMY_DMESG_0 " <( journalctl -o cat --output-fields= FILE --cursor-file= /tmp/journal.cursor | sed " /^ $/d " )
2023-04-28 00:17:52 +03:00
: " Backend: ERST; Storage: external; Unlink: $unlink "
prepare_pstore_config "external" " $unlink "
2023-06-01 21:02:20 +03:00
last_id = " $( prepare_erst_logs " $DUMMY_DMESG_0 " 0) "
2023-04-28 00:17:52 +03:00
[ [ " $unlink " = = yes ] ] && exp_count = 0 || exp_count = " $( file_count /sys/fs/pstore/) "
start_pstore
[ [ " $( file_count /sys/fs/pstore) " -ge " $exp_count " ] ]
[ [ " $( file_count /var/lib/systemd/pstore/) " -ne 0 ] ]
# We always log to journal
2023-06-01 21:02:20 +03:00
diff " $DUMMY_DMESG_0 " <( journalctl -o cat --output-fields= FILE --cursor-file= /tmp/journal.cursor | sed " /^ $/d " )
2023-04-28 00:17:52 +03:00
filename = " $( printf "/var/lib/systemd/pstore/%0.16d/dmesg.txt" " $last_id " ) "
2023-06-01 21:02:20 +03:00
diff " $DUMMY_DMESG_0 " " $filename "
2023-04-28 00:17:52 +03:00
: " Backend: ERST; Storage: external; Unlink: $unlink ; multiple dmesg files "
2023-06-01 21:02:20 +03:00
last_ids = ( )
2023-04-28 00:17:52 +03:00
prepare_pstore_config "external" " $unlink "
2023-06-01 21:02:20 +03:00
for i in { 0..9} ; do
# Create a name reference to one of the $DUMMY_DMESG_X variables
dmesg = " DUMMY_DMESG_ $(( i % 2 )) "
last_id = " $( prepare_erst_logs " ${ !dmesg } " " $(( i * 100 )) " ) "
last_ids += ( " $last_id " )
# Add one "random" (non-dmesg) file as well
echo "hello world" >/sys/fs/pstore/foo.bar
[ [ " $unlink " = = yes ] ] && exp_count = 0 || exp_count = " $( file_count /sys/fs/pstore/) "
start_pstore
[ [ " $( file_count /sys/fs/pstore) " -ge " $exp_count " ] ]
[ [ " $( file_count /var/lib/systemd/pstore/) " -ne 0 ] ]
filename = " $( printf "/var/lib/systemd/pstore/%0.16d/dmesg.txt" " $last_id " ) "
diff " ${ !dmesg } " " $filename "
grep "hello world" "/var/lib/systemd/pstore/foo.bar"
done
# Check that we kept all previous records as well
for last_id in " ${ last_ids [@] } " ; do
directory = " $( printf "/var/lib/systemd/pstore/%0.16d" " $last_id " ) "
[ [ -d " $directory " ] ]
[ [ " $( file_count " $directory " ) " -gt 0 ] ]
done
2023-04-28 00:17:52 +03:00
: " Backend: ERST; Storage: journal; Unlink: $unlink "
prepare_pstore_config "journal" " $unlink "
2023-06-01 21:02:20 +03:00
last_id = " $( prepare_erst_logs " $DUMMY_DMESG_0 " 0) "
2023-04-28 00:17:52 +03:00
[ [ " $unlink " = = yes ] ] && exp_count = 0 || exp_count = " $( file_count /sys/fs/pstore/) "
start_pstore
[ [ " $( file_count /sys/fs/pstore) " -ge " $exp_count " ] ]
[ [ " $( file_count /var/lib/systemd/pstore/) " -eq 0 ] ]
2023-06-01 21:02:20 +03:00
diff " $DUMMY_DMESG_0 " <( journalctl -o cat --output-fields= FILE --cursor-file= /tmp/journal.cursor | sed " /^ $/d " )
2023-04-28 00:17:52 +03:00
done