#!/bin/sh # # SPDX-License-Identifier: LGPL-2.1+ # # Copyright (c) 2021 Valve. # Maintainer: Guilherme G. Piccoli # # This is the kdump/pstore log collector; this script prepares the # collected data and save it in the local disk, in the next successful boot. # # Load the necessary external variables, otherwise it'll fail later. HAVE_CFG_FILES=0 shopt -s nullglob for cfg in "/usr/share/kdump.d"/*; do if [ -f "$cfg" ]; then . "$cfg" HAVE_CFG_FILES=1 fi done shopt -u nullglob if [ ${HAVE_CFG_FILES} -eq 0 ]; then logger "kdump: no config files in /usr/share/kdump.d/ - aborting." exit 1 fi KDUMP_MAIN_FOLDER="$(cat "${KDUMP_MNT}")" rm -f "${KDUMP_MNT}" if [ ! -d "${KDUMP_MAIN_FOLDER}" ]; then logger "kdump: invalid folder (${KDUMP_MAIN_FOLDER}) - aborting..." exit 0 fi LOGS_FOUND=0 KDUMP_TMP_FOLDER="${KDUMP_MAIN_FOLDER}/.tmp" # Use UTC timezone to match kdump collection CURRENT_TSTAMP=$(date -u +"%Y%m%d%H%M") # By default, pstore is mounted in this location; if it isn't, we bail-out. # Notice we currently only support the logs generated by the ramoops backend. PSTORE_CNT=$(find /sys/fs/pstore/* 2>/dev/null | grep -c ramoops) if [ "${PSTORE_CNT}" -ne 0 ]; then PSTORE_FOLDER="${KDUMP_TMP_FOLDER}/pstore" mkdir -p "${PSTORE_FOLDER}" LOOP_CNT=0 while [ "${PSTORE_CNT}" -gt 0 ]; do PSTORE_FILE="$(find /sys/fs/pstore/* | grep ramoops | sort | head -n1)" SAVED_FILE="${PSTORE_FOLDER}/dmesg-pstore.${CURRENT_TSTAMP}-${LOOP_CNT}" cat "${PSTORE_FILE}" > "${SAVED_FILE}" sync "${SAVED_FILE}" rm -f "${PSTORE_FILE}" PSTORE_CNT=$((PSTORE_CNT - 1)) LOOP_CNT=$((LOOP_CNT + 1)) done LOGS_FOUND=${LOOP_CNT} # Logs should live on <...>/.tmp folder, due to the zip compression. mv "${PSTORE_FOLDER}"/* "${KDUMP_TMP_FOLDER}/" 2>/dev/null rm -rf "${PSTORE_FOLDER}" fi # Now, we proceed the same way if there are kdump data. KDUMP_CRASH_FOLDER="${KDUMP_MAIN_FOLDER}/crash" KDUMP_CNT=$(find "${KDUMP_CRASH_FOLDER}"/* -type d 2>/dev/null | wc -l) if [ "${KDUMP_CNT}" -ne 0 ]; then KD_FOLDER="${KDUMP_TMP_FOLDER}/kdump" mkdir -p "${KD_FOLDER}" LOOP_CNT=0 while [ "${KDUMP_CNT}" -gt 0 ]; do CRASH_CURRENT=$(find "${KDUMP_CRASH_FOLDER}"/* -type d 2>/dev/null | head -n1) # When collecting the vmcore/dmesg during kdump, folder is # saved with its name == the timestamp of the collection. CRASH_TSTAMP=$(basename "${CRASH_CURRENT}") if [ -s "${CRASH_CURRENT}/dmesg.txt" ]; then SAVED_FILE="${KD_FOLDER}/dmesg-kdump.${CRASH_TSTAMP}" mv "${CRASH_CURRENT}/dmesg.txt" "${SAVED_FILE}" sync "${SAVED_FILE}" fi # We won't pack vmcores in the zip blob, but let's save # it in case it was collected as well. if [ -s "${CRASH_CURRENT}/vmcore.compressed" ]; then SAVED_FILE="${KDUMP_CRASH_FOLDER}/vmcore.${CRASH_TSTAMP}" mv "${CRASH_CURRENT}/vmcore.compressed" "${SAVED_FILE}" sync "${SAVED_FILE}" fi rm -rf "${CRASH_CURRENT}" KDUMP_CNT=$((KDUMP_CNT - 1)) LOOP_CNT=$((LOOP_CNT + 1)) done LOGS_FOUND=$((LOGS_FOUND + LOOP_CNT)) # Logs should live on .tmp folder, due to the zip compression. mv "${KD_FOLDER}"/* "${KDUMP_TMP_FOLDER}/" 2>/dev/null rm -rf "${KD_FOLDER}" fi # If we have pstore and/or kdump logs, let's process them... KDUMP_LOGS_FOLDER="${KDUMP_MAIN_FOLDER}/logs" if [ ${LOGS_FOUND} -ne 0 ]; then mkdir -p "${KDUMP_LOGS_FOLDER}" # First we collect some more info, like DMI data, os-release, etc; DMI_FNAME="${KDUMP_TMP_FOLDER}/dmidecode.${CURRENT_TSTAMP}" dmidecode > "${DMI_FNAME}" BUILD_FNAME="${KDUMP_TMP_FOLDER}/build.${CURRENT_TSTAMP}" cp "/etc/os-release" "${BUILD_FNAME}" VERSION_FNAME="${KDUMP_TMP_FOLDER}/version.${CURRENT_TSTAMP}" uname -r > "${VERSION_FNAME}" sync "${DMI_FNAME}" "${BUILD_FNAME}" "${VERSION_FNAME}" # Create the dump compressed pack. LOG_FNAME="kdump-${CURRENT_TSTAMP}.zip" LOG_FNAME="${KDUMP_LOGS_FOLDER}/${LOG_FNAME}" zip -9 -jq "${LOG_FNAME}" "${KDUMP_TMP_FOLDER}"/* 1>/dev/null sync "${LOG_FNAME}" 2>/dev/null if [ ! -s "${LOG_FNAME}" ]; then logger "kdump: couldn't create the compressed log archive" logger "kdump: check folder \"${KDUMP_TMP_FOLDER}\" for logs" else logger "kdump: logs saved in \"${KDUMP_LOGS_FOLDER}\"" fi fi rm -rf "${KDUMP_TMP_FOLDER}"