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