1#! /bin/bash 2 3help=$" 4 dreport creates an archive(xz compressed) consisting of the following: 5 * Configuration information 6 * Debug information 7 * A summary report 8 The type parameter controls the content of the data. The generated 9 archive is stored in the user specified location. 10 11usage: dreport [OPTION] 12 13Options: 14 -n, —-name <name> Name to be used for the archive. 15 Default name format obmcdump_<id>_<epochtime> 16 -d, —-dir <directory> Archive directory to copy the compressed report. 17 Default output directory is /tmp 18 -i, —-id <id> Dump identifier to associate with the archive. 19 Identifiers include numeric characters. 20 Default dump identifier is 0 21 -t, —-type <type> Data collection type. Valid types are 22 "user", "core", "elog". 23 Default type is "user" initiated. 24 -p, —-path <path> Optional contents to be included in the archive. 25 Valid paths are absolute file path or d-bus path 26 based on type parameter. 27 -Absolute file path for "core" type. 28 -elog d-bus object for "elog" type. 29 -s, --size <size> Maximum allowed size(in KB) of the archive. 30 Report will be truncated in case size exceeds 31 this limit. Default size is unlimited. 32 -v, —-verbose Increase logging verbosity. 33 -V, --version Output version information. 34 -q, —-quiet Only log fatal errors to stderr 35 -h, —-help Display this help and exit. 36" 37 38#CONSTANTS 39declare -rx TRUE=1 40declare -rx FALSE=0 41declare -rx UNLIMITED="unlimited" 42declare -rx SUMMARY_DUMP="summary" 43declare -rx TYPE_USER="user" 44declare -rx TYPE_CORE="core" 45declare -rx TYPE_ELOG="elog" 46declare -rx TYPE_CHECKSTOP="checkstop" 47declare -rx SUMMARY_LOG="summary.log" 48declare -rx DREPORT_LOG="dreport.log" 49declare -rx TMP_DIR="/tmp" 50declare -rx EPOCHTIME=$(date +"%s") 51declare -rx TIME_STAMP="date -u" 52declare -rx PLUGIN="pl_" 53declare -rx DREPORT_SOURCE="/usr/share/dreport.d" 54declare -rx DREPORT_INCLUDE="$DREPORT_SOURCE/include.d" 55declare -rx ZERO="0" 56declare -rx JOURNAL_LINE_LIMIT="500" 57declare -rx HEADER_EXTENSION="$DREPORT_INCLUDE/gendumpheader" 58 59#Error Codes 60declare -rx SUCCESS="0" 61declare -rx INTERNAL_FAILURE="1" 62declare -rx RESOURCE_UNAVAILABLE="2" 63 64#VARIABLES 65declare -x name="" 66declare -x dump_dir="/tmp" 67declare -x dump_id="00000000" 68declare -x dump_type=$TYPE_USER 69declare -x verbose=$FALSE 70declare -x quiet=$FALSE 71declare -x dump_size="unlimited" 72declare -x name_dir="" 73declare -x optional_path="" 74declare -x dreport_log="" 75declare -x summary_log="" 76declare -x cur_dump_size=0 77declare -x pid=$ZERO 78declare -x elog_id="" 79 80#Source dreport common functions 81. $DREPORT_INCLUDE/functions 82 83# @brief Initiate data collection based on the type. 84# @return 0 on success, error code otherwise 85function collect_data() 86{ 87 case $dump_type in 88 $TYPE_USER) 89 ;; 90 $TYPE_CORE) 91 log_summary "Core: $optional_path" 92 set_core_pid 93 ;; 94 $TYPE_ELOG) 95 log_summary "ELOG: $optional_path" 96 elog_id=$(basename "$optional_path") 97 set_elog_pid 98 ;; 99 $TYPE_CHECKSTOP) 100 log_summary "CHECKSTOP: $optional_path" 101 elog_id=$(basename "$optional_path") 102 set_elog_pid 103 ;; 104 105 $SUMMARY_DUMP) 106 #No data collection is required. 107 return 108 ;; 109 *) # unknown option 110 log_error "Skipping: Unknown dump type: $dump_type" 111 return 112 ;; 113 esac 114 115 plugin_path=$DREPORT_SOURCE/$PLUGIN$dump_type.d 116 117 # check plugin directory for this dump type? 118 if [ ! -d $plugin_path ]; then 119 log_error "$plugin_path does not exist, skipping dump collection" 120 return 0 121 fi 122 123 #Executes plugins based on the type. 124 for i in $plugin_path/* ; do 125 $i 126 done 127} 128 129# @brief set pid by reading information from the optional path. 130# dreport "core" type user provides core file as optional path parameter. 131# As per coredump source code systemd-coredump uses below format 132# https://github.com/systemd/systemd/blob/master/src/coredump/coredump.c 133# /var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR “. 134# <process ID>.%s000000" 135function set_core_pid() 136{ 137 #Escape bash characters in file name 138 file=$(printf %q "$optional_path") 139 140 #matching systemd-coredump core file format. 141 pid=$(echo $file | awk -F . '{ print $5}') 142} 143 144# @brief set elog pid by reading _PID information from the elog d-bus object. 145# _PID information is stored elog Additional data field 146# Data format "_PID=<pid>" 147function set_elog_pid() 148{ 149 additional_data=$(busctl get-property xyz.openbmc_project.Logging \ 150 $optional_path \ 151 xyz.openbmc_project.Logging.Entry \ 152 AdditionalData) 153 154 #read _PID data. 155 if [ ! -z "$additional_data" ]; then 156 pid=$(echo $additional_data | \ 157 awk -F _PID= '{ print ($2+0)}') 158 fi 159} 160 161# @brief Initial version of the summary log 162init_summary() 163{ 164 log_summary "Name: $name.tar.xz" 165 log_summary "Epochtime: $EPOCHTIME" 166 log_summary "ID: $dump_id" 167 log_summary "Type: $dump_type" 168} 169 170# @brief Check the validity of user inputs and initialize global 171# variables. Create directory for temporary data collection 172# @return 0 on success, error code otherwise 173 174function initialize() 175{ 176 #Dump file name 177 if [ -z $name ]; then 178 name=$"obmcdump_"$dump_id"_$EPOCHTIME" 179 fi 180 181 #Create temporary data directory. 182 mkdir -p "$TMP_DIR/$name" 183 if [ $? -ne 0 ]; then 184 echo "Error: Failed to create the temporary directory." 185 return $RESOURCE_UNAVAILABLE; 186 fi 187 188 #name directory 189 name_dir="$TMP_DIR/$name" 190 191 #dreport log file 192 dreport_log="$name_dir/$DREPORT_LOG" 193 194 #summary log file 195 summary_log="$name_dir/$SUMMARY_LOG" 196 197 #Type 198 if [[ ! ($dump_type = $TYPE_USER || \ 199 $dump_type = $TYPE_CORE || \ 200 $dump_type = $TYPE_ELOG || \ 201 $dump_type = $TYPE_CHECKSTOP) ]]; then 202 log_error "Invalid -type, Only summary log is available" 203 dump_type=$SUMMARY_DUMP 204 fi 205 206 #Size 207 #Check the input is integer. 208 if [ "$dump_size" -eq "$dump_size" ] 2>/dev/null; then 209 #Converts in to bytes. 210 dump_size="$((dump_size * 1024))" 211 else 212 dump_size=$UNLIMITED 213 fi 214 215 return $SUCCESS 216} 217 218# @brief Packaging the dump and transferring to dump location. 219function package() 220{ 221 mkdir -p "$dump_dir" 222 if [ $? -ne 0 ]; then 223 log_error "Could not create the destination directory $dump_dir" 224 dest_dir=$TMP_DIR 225 fi 226 227 #tar and compress the files. 228 if [ -f "$HEADER_EXTENSION" ]; then 229 tar -Jcf "$name_dir.tar.xz" -C \ 230 $(dirname "$name_dir") $(basename "$name_dir") 231 echo "Adding Dump Header :"$HEADER_EXTENSION 232 ("$HEADER_EXTENSION") 233 cat "$name_dir.tar.xz" | tee -a "/tmp/dumpheader_$EPOCHTIME" > /dev/null 234 mv "/tmp/dumpheader_$EPOCHTIME" "$name_dir.tar.xz" 235 else 236 tar -Jcf "$name_dir.tar.xz" -C \ 237 $(dirname "$name_dir") $(basename "$name_dir") 238 fi 239 240 if [ $? -ne 0 ]; then 241 echo $($TIME_STAMP) "Could not create the compressed tar file" 242 rm -r "$name_dir" 243 return $INTERNAL_FAILURE 244 fi 245 246 #remove the temporary name specific directory 247 rm -r "$name_dir" 248 249 echo $($TIME_STAMP) "Report is available in $dump_dir" 250 251 if [ "$TMP_DIR" == "$dump_dir" ] || [ "$TMP_DIR/" == "$dump_dir" ]; then 252 return $SUCCESS 253 fi 254 255 #copy the compressed tar file into the destination 256 cp "$name_dir.tar.xz" "$dump_dir" 257 if [ $? -ne 0 ]; then 258 echo "Failed to copy the $name_dir.tar.xz to $dump_dir" 259 rm "$name_dir.tar.xz" 260 return $INTERNAL_FAILURE 261 fi 262 263 #Remove the temporary copy of the file 264 rm "$name_dir.tar.xz" 265} 266 267# @brief Main function 268function main() 269{ 270 #initialize the global variables and 271 #create temporary storage locations 272 initialize 273 result=$? 274 if [[ ${result} -ne $SUCCESS ]]; then 275 echo $($TIME_STAMP) "Error: Failed to initialize, Exiting" 276 exit; 277 fi 278 279 #Initialize the summary log 280 init_summary 281 282 #collect data based on the type. 283 collect_data 284 285 package #package the dump 286 result=$? 287 if [[ ${result} -ne $SUCCESS ]]; then 288 echo $($TIME_STAMP) "Error: Failed to package, Exiting" 289 else 290 echo $($TIME_STAMP) "Successfully completed" 291 exit; 292 fi 293} 294 295TEMP=`getopt -o n:d:i:t:s:p:vVqh \ 296 --long name:,dir:,dumpid:,type:,size:,path:,verbose,version,quiet,help \ 297 -- "$@"` 298 299if [ $? -ne 0 ] 300then 301 echo "Error: Invalid options" 302 exit 1 303fi 304 305eval set -- "$TEMP" 306 307while [[ $# -gt 1 ]]; do 308 key="$1" 309 case $key in 310 -n|--name) 311 name=$2 312 shift 2;; 313 -d|--dir) 314 dump_dir=$2 315 shift 2;; 316 -i|--dumpid) 317 dump_id=$2 318 shift 2;; 319 -t|--type) 320 dump_type=$2 321 shift 2;; 322 -s|--size) 323 dump_size=$2 324 shift 2;; 325 -p|--path) 326 optional_path=$2 327 shift 2;; 328 -v|—-verbose) 329 verbose=$TRUE 330 shift;; 331 -V|--version) 332 shift;; 333 -q|—-quiet) 334 quiet=$TRUE 335 shift;; 336 -h|--help) 337 echo "$help" 338 exit;; 339 *) # unknown option 340 log_error "Unknown argument: $1" 341 log_info "$help" 342 exit 1;; 343 esac 344done 345 346main #main program 347exit $? 348