Add opdreport tool to OpenPOWER Debug Collector
This commit introduces the opdreport tool, which creates an archive
consisting of host dump files and applies headers on top of it. The
tool includes options to specify the name, directory, dump ID,
maximum allowed size, failing unit, error log ID, and type of the dump
to be collected.
Changes:
- Added meson.build files to integrate opdreport tool.
- Updated meson.build to conditionally include the dump subdirectory
based on the dump-collection option.
- Added opdreport script to the tools/opdump directory.
- Modified meson.build to handle installation of opdreport.
Change-Id: I1a83b2bf4ffa6f8f47191df17b35f8d5b13e4115
Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
diff --git a/.shellcheck-ignore b/.shellcheck-ignore
index fccc1d9..e5c4d18 100644
--- a/.shellcheck-ignore
+++ b/.shellcheck-ignore
@@ -1 +1,2 @@
-dump/tools/common/include/gendumpheader
\ No newline at end of file
+dump/tools/common/include/gendumpheader
+dump/tools/opdump/opdreport
diff --git a/dump/meson.build b/dump/meson.build
index 9667e33..a826197 100644
--- a/dump/meson.build
+++ b/dump/meson.build
@@ -27,3 +27,17 @@
implicit_include_directories: true,
install: true
)
+
+bindir = get_option('bindir')
+
+scripts_to_install = []
+
+subdir('tools')
+# Install collected files if any
+if scripts_to_install.length() > 0
+ install_data(scripts_to_install,
+ install_dir: get_option('bindir'),
+ install_mode: 'rwxr-xr-x'
+ )
+endif
+
diff --git a/dump/tools/meson.build b/dump/tools/meson.build
new file mode 100644
index 0000000..af9c6b0
--- /dev/null
+++ b/dump/tools/meson.build
@@ -0,0 +1 @@
+subdir('opdump')
\ No newline at end of file
diff --git a/dump/tools/opdump/meson.build b/dump/tools/opdump/meson.build
new file mode 100644
index 0000000..9f9b4ba
--- /dev/null
+++ b/dump/tools/opdump/meson.build
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: Apache-2.0
+
+scripts_to_install += meson.current_source_dir() / 'opdreport'
\ No newline at end of file
diff --git a/dump/tools/opdump/opdreport b/dump/tools/opdump/opdreport
new file mode 100644
index 0000000..76f76fb
--- /dev/null
+++ b/dump/tools/opdump/opdreport
@@ -0,0 +1,264 @@
+#!/bin/bash
+# shellcheck disable=SC2034 # Variable is used elsewhere
+
+help=$(cat << EOF
+ opdreport creates an archive consisting of the following:
+ * host dump files and header applied on top of it
+ The type parameter controls the content of the data. The generated
+ archive is stored in the user specified location.
+
+usage: opdreport [OPTION]
+
+Options:
+ -n, --name <name> Name to be used for the archive.
+ Default name format
+ SYSDUMP.<serial number>.<dump_id>.<time>
+ Optional parameter.
+ -d, --dir <directory> Archive directory to copy the compressed report.
+ Default output directory is current working
+ directory. Optional parameter.
+ -i, --dumpid <id> Dump identifier to associate with the archive.
+ Identifiers include numeric characters.
+ Default dump identifier is 0
+ -s, --size <size> Maximum allowed size (in KB) of the archive.
+ Report will be truncated if size exceeds
+ this limit. Default size is unlimited.
+ -f, --failingunit The id of the failed unit
+ -e, --eid Error log associated with the failure
+ -t, --type Type of the dump to be collected
+ 1 - Hardware dump
+ 3 - Performance dump
+ 5 - Hostboot dump
+ 10 - SBE Dump
+ -h, --help Display this help and exit.
+EOF
+)
+
+# Constants
+readonly OP_DUMP="opdump"
+readonly DREPORT_SOURCE="/usr/share/dreport.d"
+readonly TRUE=1
+readonly FALSE=0
+readonly TIME_STAMP="date -u"
+readonly UNLIMITED="unlimited"
+readonly DREPORT_INCLUDE="$DREPORT_SOURCE/include.d"
+readonly INVENTORY_MANAGER='xyz.openbmc_project.Inventory.Manager'
+readonly INVENTORY_PATH='/xyz/openbmc_project/inventory/system'
+readonly INVENTORY_ASSET_INT='xyz.openbmc_project.Inventory.Decorator.Asset'
+readonly INVENTORY_BMC_BOARD='/xyz/openbmc_project/inventory/system/chassis/motherboard'
+readonly HEADER_EXTENSION="$DREPORT_INCLUDE/gendumpheader"
+readonly FILE_SCRIPT="$DREPORT_SOURCE/include.d/gendumpinfo"
+
+# Error Codes
+readonly SUCCESS=0
+readonly INTERNAL_FAILURE=1
+readonly RESOURCE_UNAVAILABLE=2
+
+# Variables
+declare -x dump_type="$OP_DUMP"
+declare -x dump_sbe_type=100
+declare -x size_dump=""
+declare -x elog_id="00000000"
+declare -x EPOCHTIME
+EPOCHTIME=$(date +"%s")
+declare -x name=""
+declare -x dump_dir="/tmp"
+declare -x dump_id="00000000"
+declare -x dump_size="unlimited"
+declare -x content_path=""
+declare -x name_dir=""
+declare -x serialNo="0000000"
+declare -x dDay
+dDay=$(date -d @"$EPOCHTIME" +'%Y%m%d%H%M%S')
+declare -x dump_content_type=""
+declare -x FILE=""
+
+# @brief Get serial number property from inventory
+function fetch_serial_number() {
+ serialNo=$(busctl get-property "$INVENTORY_MANAGER" "$INVENTORY_PATH" \
+ "$INVENTORY_ASSET_INT" SerialNumber | cut -d " " -f 2 | \
+ sed 's/^"\(.*\)"$/\1/')
+
+ if [ -z "$serialNo" ]; then
+ serialNo="0000000"
+ fi
+}
+
+# @brief Check the validity of user inputs and initialize global variables
+function initialize() {
+ # shellcheck disable=SC2154 # name comes from elsewhere
+ if [ -z "$name" ]; then
+ name="SYSDUMP"
+ fi
+ fetch_serial_number
+ # shellcheck disable=SC2154 # dump_id comes from elsewhere
+ name="${name}.${serialNo}.${dump_id}.${dDay}"
+
+ if [ -z "$dump_sbe_type" ]; then
+ echo "Error: Dump type is not provided."
+ return "$RESOURCE_UNAVAILABLE"
+ fi
+
+ if [ -z "$dump_dir" ]; then
+ dump_dir=$PWD
+ fi
+
+ if [[ "$dump_size" =~ ^[0-9]+$ ]]; then
+ dump_size=$((dump_size * 1024))
+ else
+ dump_size=$UNLIMITED
+ fi
+
+ return "$SUCCESS"
+}
+
+# @brief Collect the dump
+function collect() {
+ content_path="/tmp/dump_${dump_id}_${EPOCHTIME}"
+ dump_outpath="$content_path/plat_dump"
+ if ! mkdir -p "$dump_outpath"; then
+ echo "Could not create the destination directory $dump_outpath"
+ return "$INTERNAL_FAILURE"
+ fi
+
+ dump-collect --type "$dump_sbe_type" --id "0x$dump_id" \
+ --failingunit "$failing_unit" --path "$dump_outpath"
+}
+
+# @brief Package the dump and transfer to dump location
+function package() {
+ FILE="/tmp/dumpheader_${dump_id}_${EPOCHTIME}"
+ if ! mkdir -p "$dump_dir"; then
+ echo "Could not create the destination directory $dump_dir"
+ dump_dir="/tmp"
+ fi
+
+ cd "$content_path" || exit "$INTERNAL_FAILURE"
+
+ dump_content_type=${id:0:2}
+ "$FILE_SCRIPT"
+ elog_id=$eid
+
+ if ! tar -cvzf "$name" plat_dump/*Sbe* info.yaml; then
+ echo "$($TIME_STAMP)" "Could not create the compressed tar file"
+ return "$INTERNAL_FAILURE"
+ fi
+
+ size_dump=$(stat -c %s "$name")
+
+ if [ "$dump_size" != "$UNLIMITED" ] && \
+ [ "$size_dump" -gt "$dump_size" ]; then
+ rm "$name"
+ return "$RESOURCE_UNAVAILABLE"
+ fi
+
+ echo "Adding Dump Header: $HEADER_EXTENSION"
+ "$HEADER_EXTENSION"
+
+ if ! tee -a "$FILE" < "$name" > /dev/null; then
+ echo "$($TIME_STAMP)" "Could not create the compressed file"
+ rm -rf "$name" "$FILE"
+ return "$INTERNAL_FAILURE"
+ fi
+
+ if ! mv "$FILE" "$name"; then
+ echo "$($TIME_STAMP)" "Could not create the compressed file"
+ rm -rf "$name" "$FILE"
+ return "$INTERNAL_FAILURE"
+ fi
+
+ mv "$name" "$dump_dir"
+
+ rm -rf "$content_path"
+ rm -rf "$FILE" "$name"
+
+ return "$SUCCESS"
+}
+
+# @brief Initiate BMC dump
+function initiate_bmc_dump() {
+ bmcDumpPath=$(busctl call xyz.openbmc_project.Dump.Manager \
+ /xyz/openbmc_project/dump/bmc \
+ xyz.openbmc_project.Dump.Create CreateDump a\{sv\} 0)
+ result=$?
+ if [[ $result -ne $SUCCESS ]]; then
+ echo "Error in creating BMC dump associated with system dump"
+ else
+ echo "BMC dump initiated $bmcDumpPath"
+ fi
+}
+
+# @brief Main function
+function main() {
+ initialize
+ result=$?
+ if [[ $result -ne $SUCCESS ]]; then
+ echo "$($TIME_STAMP)" "Error: Failed to initialize, Exiting"
+ return "$INTERNAL_FAILURE"
+ fi
+
+ collect
+ result=$?
+ if [[ $result -ne $SUCCESS ]]; then
+ echo "$($TIME_STAMP)" "Error: Failed to collect dump, Exiting"
+ return "$INTERNAL_FAILURE"
+ fi
+
+ package
+ result=$?
+ if [[ $result -ne $SUCCESS ]]; then
+ echo "$($TIME_STAMP)" "Error: Failed to package, Exiting"
+ return "$INTERNAL_FAILURE"
+ else
+ echo "$($TIME_STAMP)" "Successfully completed"
+ fi
+
+ initiate_bmc_dump
+ return "$SUCCESS"
+}
+
+if ! TEMP=$(getopt -o n:d:i:s:t:e:f:h \
+ --long name:,dir:,dumpid:,size:,type:,eid:,failingunit:,help \
+ -- "$@"); 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 ;;
+ -s|--size)
+ dump_size=$2
+ shift 2 ;;
+ -f|--failingunit)
+ failing_unit=$2
+ shift 2 ;;
+ -e|--eid)
+ eid=$2
+ shift 2 ;;
+ -t|--type)
+ dump_sbe_type=$2
+ shift 2 ;;
+ -h|--help)
+ echo "$help"
+ exit ;;
+ *) # unknown option
+ echo "Unknown argument: $1"
+ echo "$help"
+ exit 1 ;;
+ esac
+done
+
+main
+exit $?
diff --git a/meson.build b/meson.build
index 9c01593..4bb1003 100644
--- a/meson.build
+++ b/meson.build
@@ -49,7 +49,7 @@
configure_file(output: 'config.h', configuration: conf_data)
if get_option('dump-collection').enabled()
- subdir('dump')
+ subdir('dump')
endif
deps = [