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