| #!/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=${dump_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 $? |