#! /bin/bash help=$" dreport creates an archive(xz compressed) consisting of the following: * Configuration information * Debug information * A summary report The type parameter controls the content of the data. The generated archive is stored in the user specified location. usage: dreport [OPTION] Options: -n, —-name Name to be used for the archive. Default name format obmcdump__ -d, —-dir Archive directory to copy the compressed report. Default output directory is /tmp -i, —-id Dump identifier to associate with the archive. Identifiers include numeric characters. Default dump identifier is 0 -t, —-type Data collection type. Valid types are "user", "core", "elog". Default type is "user" initiated. -p, —-path Optional contents to be included in the archive. Valid paths are absolute file path or d-bus path based on type parameter. -Absolute file path for "core" type. -elog d-bus object for "elog" type. -s, --size Maximum allowed size(in KB) of the archive. Report will be truncated in case size exceeds this limit. Default size is unlimited. -v, —-verbose Increase logging verbosity. -V, --version Output version information. -q, —-quiet Only log fatal errors to stderr -h, —-help Display this help and exit. " #CONSTANTS declare -rx TRUE=1 declare -rx FALSE=0 declare -rx UNLIMITED="unlimited" declare -rx SUMMARY_DUMP="summary" declare -rx TYPE_USER="user" declare -rx TYPE_CORE="core" declare -rx TYPE_ELOG="elog" declare -rx TYPE_CHECKSTOP="checkstop" declare -rx SUMMARY_LOG="summary.log" declare -rx DREPORT_LOG="dreport.log" declare -rx TMP_DIR="/tmp" declare -rx EPOCHTIME=$(date +"%s") declare -rx TIME_STAMP="date -u" declare -rx PLUGIN="pl_" declare -rx DREPORT_SOURCE="/usr/share/dreport.d" declare -rx DREPORT_INCLUDE="$DREPORT_SOURCE/include.d" declare -rx ZERO="0" declare -rx JOURNAL_LINE_LIMIT="500" declare -rx HEADER_EXTENSION="$DREPORT_INCLUDE/gendumpheader" #Error Codes declare -rx SUCCESS="0" declare -rx INTERNAL_FAILURE="1" declare -rx RESOURCE_UNAVAILABLE="2" #VARIABLES declare -x name="" declare -x dump_dir="/tmp" declare -x dump_id="00000000" declare -x dump_type=$TYPE_USER declare -x verbose=$FALSE declare -x quiet=$FALSE declare -x dump_size="unlimited" declare -x name_dir="" declare -x optional_path="" declare -x dreport_log="" declare -x summary_log="" declare -x cur_dump_size=0 declare -x pid=$ZERO declare -x elog_id="" #Source dreport common functions . $DREPORT_INCLUDE/functions # @brief Initiate data collection based on the type. # @return 0 on success, error code otherwise function collect_data() { case $dump_type in $TYPE_USER) ;; $TYPE_CORE) log_summary "Core: $optional_path" set_core_pid ;; $TYPE_ELOG) log_summary "ELOG: $optional_path" elog_id=$(basename "$optional_path") set_elog_pid ;; $TYPE_CHECKSTOP) log_summary "CHECKSTOP: $optional_path" elog_id=$(basename "$optional_path") set_elog_pid ;; $SUMMARY_DUMP) #No data collection is required. return ;; *) # unknown option log_error "Skipping: Unknown dump type: $dump_type" return ;; esac plugin_path=$DREPORT_SOURCE/$PLUGIN$dump_type.d # check plugin directory for this dump type? if [ ! -d $plugin_path ]; then log_error "$plugin_path does not exist, skipping dump collection" return 0 fi #Executes plugins based on the type. for i in $plugin_path/* ; do $i done } # @brief set pid by reading information from the optional path. # dreport "core" type user provides core file as optional path parameter. # As per coredump source code systemd-coredump uses below format # https://github.com/systemd/systemd/blob/master/src/coredump/coredump.c # /var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR “. # .%s000000" function set_core_pid() { #Escape bash characters in file name file=$(printf %q "$optional_path") #matching systemd-coredump core file format. pid=$(echo $file | awk -F . '{ print $5}') } # @brief set elog pid by reading _PID information from the elog d-bus object. # _PID information is stored elog Additional data field # Data format "_PID=" function set_elog_pid() { additional_data=$(busctl get-property xyz.openbmc_project.Logging \ $optional_path \ xyz.openbmc_project.Logging.Entry \ AdditionalData) #read _PID data. if [ ! -z "$additional_data" ]; then pid=$(echo $additional_data | \ awk -F _PID= '{ print ($2+0)}') fi } # @brief Initial version of the summary log init_summary() { log_summary "Name: $name.tar.xz" log_summary "Epochtime: $EPOCHTIME" log_summary "ID: $dump_id" log_summary "Type: $dump_type" } # @brief Check the validity of user inputs and initialize global # variables. Create directory for temporary data collection # @return 0 on success, error code otherwise function initialize() { #Dump file name if [ -z $name ]; then name=$"obmcdump_"$dump_id"_$EPOCHTIME" fi #Create temporary data directory. mkdir -p "$TMP_DIR/$name" if [ $? -ne 0 ]; then echo "Error: Failed to create the temporary directory." return $RESOURCE_UNAVAILABLE; fi #name directory name_dir="$TMP_DIR/$name" #dreport log file dreport_log="$name_dir/$DREPORT_LOG" #summary log file summary_log="$name_dir/$SUMMARY_LOG" #Type if [[ ! ($dump_type = $TYPE_USER || \ $dump_type = $TYPE_CORE || \ $dump_type = $TYPE_ELOG || \ $dump_type = $TYPE_CHECKSTOP) ]]; then log_error "Invalid -type, Only summary log is available" dump_type=$SUMMARY_DUMP fi #Size #Check the input is integer. if [ "$dump_size" -eq "$dump_size" ] 2>/dev/null; then #Converts in to bytes. dump_size="$((dump_size * 1024))" else dump_size=$UNLIMITED fi return $SUCCESS } # @brief Packaging the dump and transferring to dump location. function package() { mkdir -p "$dump_dir" if [ $? -ne 0 ]; then log_error "Could not create the destination directory $dump_dir" dest_dir=$TMP_DIR fi #tar and compress the files. if [ -f "$HEADER_EXTENSION" ]; then tar -Jcf "$name_dir.tar.xz" -C \ $(dirname "$name_dir") $(basename "$name_dir") echo "Adding Dump Header :"$HEADER_EXTENSION ("$HEADER_EXTENSION") cat "$name_dir.tar.xz" | tee -a "/tmp/dumpheader_$EPOCHTIME" > /dev/null mv "/tmp/dumpheader_$EPOCHTIME" "$name_dir.tar.xz" else tar -Jcf "$name_dir.tar.xz" -C \ $(dirname "$name_dir") $(basename "$name_dir") fi if [ $? -ne 0 ]; then echo $($TIME_STAMP) "Could not create the compressed tar file" rm -r "$name_dir" return $INTERNAL_FAILURE fi #remove the temporary name specific directory rm -r "$name_dir" echo $($TIME_STAMP) "Report is available in $dump_dir" if [ "$TMP_DIR" == "$dump_dir" ] || [ "$TMP_DIR/" == "$dump_dir" ]; then return $SUCCESS fi #copy the compressed tar file into the destination cp "$name_dir.tar.xz" "$dump_dir" if [ $? -ne 0 ]; then echo "Failed to copy the $name_dir.tar.xz to $dump_dir" rm "$name_dir.tar.xz" return $INTERNAL_FAILURE fi #Remove the temporary copy of the file rm "$name_dir.tar.xz" } # @brief Main function function main() { #initialize the global variables and #create temporary storage locations initialize result=$? if [[ ${result} -ne $SUCCESS ]]; then echo $($TIME_STAMP) "Error: Failed to initialize, Exiting" exit; fi #Initialize the summary log init_summary #collect data based on the type. collect_data package #package the dump result=$? if [[ ${result} -ne $SUCCESS ]]; then echo $($TIME_STAMP) "Error: Failed to package, Exiting" else echo $($TIME_STAMP) "Successfully completed" exit; fi } TEMP=`getopt -o n:d:i:t:s:p:vVqh \ --long name:,dir:,dumpid:,type:,size:,path:,verbose,version,quiet,help \ -- "$@"` if [ $? -ne 0 ] then echo "Error: Invalid options" exit 1 fi eval set -- "$TEMP" while [[ $# -gt 1 ]]; do key="$1" case $key in -n|--name) name=$2 shift 2;; -d|--dir) dump_dir=$2 shift 2;; -i|--dumpid) dump_id=$2 shift 2;; -t|--type) dump_type=$2 shift 2;; -s|--size) dump_size=$2 shift 2;; -p|--path) optional_path=$2 shift 2;; -v|—-verbose) verbose=$TRUE shift;; -V|--version) shift;; -q|—-quiet) quiet=$TRUE shift;; -h|--help) echo "$help" exit;; *) # unknown option log_error "Unknown argument: $1" log_info "$help" exit 1;; esac done main #main program exit $?