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