| Jayanth Othayoth | 5ce1550 | 2017-10-16 00:02:44 -0500 | [diff] [blame] | 1 | #! /bin/bash | 
 | 2 |  | 
 | 3 | help=$" | 
 | 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 |  | 
 | 11 | usage: dreport [OPTION] | 
 | 12 |  | 
 | 13 | Options: | 
 | 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 | 
 | 39 | declare -rx TRUE=1 | 
 | 40 | declare -rx FALSE=0 | 
 | 41 | declare -rx UNLIMITED="unlimited" | 
 | 42 | declare -rx SUMMARY_DUMP="summary" | 
 | 43 | declare -rx TYPE_USER="user" | 
 | 44 | declare -rx TYPE_CORE="core" | 
 | 45 | declare -rx TYPE_ELOG="elog" | 
| Marri Devender Rao | 0deb287 | 2018-11-12 07:45:54 -0600 | [diff] [blame] | 46 | declare -rx TYPE_CHECKSTOP="checkstop" | 
| Jayanth Othayoth | 5ce1550 | 2017-10-16 00:02:44 -0500 | [diff] [blame] | 47 | declare -rx SUMMARY_LOG="summary.log" | 
 | 48 | declare -rx DREPORT_LOG="dreport.log" | 
 | 49 | declare -rx TMP_DIR="/tmp" | 
 | 50 | declare -rx EPOCHTIME=$(date +"%s") | 
 | 51 | declare -rx TIME_STAMP="date -u" | 
 | 52 | declare -rx PLUGIN="pl_" | 
 | 53 | declare -rx DREPORT_SOURCE="/usr/share/dreport.d" | 
 | 54 | declare -rx DREPORT_INCLUDE="$DREPORT_SOURCE/include.d" | 
| Jayanth Othayoth | aa146d6 | 2018-01-08 06:57:53 -0600 | [diff] [blame] | 55 | declare -rx ZERO="0" | 
 | 56 | declare -rx JOURNAL_LINE_LIMIT="500" | 
| Jayanth Othayoth | 5ce1550 | 2017-10-16 00:02:44 -0500 | [diff] [blame] | 57 |  | 
 | 58 | #Error Codes | 
 | 59 | declare -rx SUCCESS="0" | 
 | 60 | declare -rx INTERNAL_FAILURE="1" | 
 | 61 | declare -rx RESOURCE_UNAVAILABLE="2" | 
 | 62 |  | 
 | 63 | #VARIABLES | 
 | 64 | declare -x name="" | 
 | 65 | declare -x dump_dir="/tmp" | 
 | 66 | declare -x dump_id="00000000" | 
 | 67 | declare -x dump_type=$TYPE_USER | 
 | 68 | declare -x verbose=$FALSE | 
 | 69 | declare -x quiet=$FALSE | 
 | 70 | declare -x dump_size="unlimited" | 
 | 71 | declare -x name_dir="" | 
 | 72 | declare -x optional_path="" | 
 | 73 | declare -x dreport_log="" | 
 | 74 | declare -x summary_log="" | 
 | 75 | declare -x cur_dump_size=0 | 
| Jayanth Othayoth | aa146d6 | 2018-01-08 06:57:53 -0600 | [diff] [blame] | 76 | declare -x pid=$ZERO | 
| Jayanth Othayoth | 5ce1550 | 2017-10-16 00:02:44 -0500 | [diff] [blame] | 77 | declare -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 | 
 | 84 | function 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 |             ;; | 
| Marri Devender Rao | 0deb287 | 2018-11-12 07:45:54 -0600 | [diff] [blame] | 98 |         $TYPE_CHECKSTOP) | 
 | 99 |             log_summary "CHECKSTOP: $optional_path" | 
 | 100 |             elog_id=$(basename "$optional_path") | 
 | 101 |             set_elog_pid | 
 | 102 |             ;; | 
| Jayanth Othayoth | 5ce1550 | 2017-10-16 00:02:44 -0500 | [diff] [blame] | 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" | 
 | 134 | function 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>" | 
 | 146 | function 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 | 
 | 161 | init_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 |  | 
 | 173 | function 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 || \ | 
| Marri Devender Rao | 0deb287 | 2018-11-12 07:45:54 -0600 | [diff] [blame] | 199 |             $dump_type = $TYPE_ELOG || \ | 
 | 200 |             $dump_type = $TYPE_CHECKSTOP) ]]; then | 
| Jayanth Othayoth | 5ce1550 | 2017-10-16 00:02:44 -0500 | [diff] [blame] | 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. | 
 | 218 | function 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" ]; 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 | 
 | 258 | function 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 |  | 
| Gunnar Mills | 95a7298 | 2017-10-25 17:00:14 -0500 | [diff] [blame] | 269 |     #Initialize the summary log | 
| Jayanth Othayoth | 5ce1550 | 2017-10-16 00:02:44 -0500 | [diff] [blame] | 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 | 
| Gunnar Mills | 95a7298 | 2017-10-25 17:00:14 -0500 | [diff] [blame] | 280 |         echo $($TIME_STAMP) "Successfully completed" | 
| Jayanth Othayoth | 5ce1550 | 2017-10-16 00:02:44 -0500 | [diff] [blame] | 281 |         exit; | 
 | 282 |     fi | 
 | 283 | } | 
 | 284 |  | 
 | 285 | TEMP=`getopt -o n:d:i:t:s:p:vVqh \ | 
 | 286 |       --long name:,dir:,dumpid:,type:,size:,path:,verbose,version,quiet,help \ | 
 | 287 |       -- "$@"` | 
 | 288 |  | 
 | 289 | if [ $? -ne 0 ] | 
 | 290 | then | 
 | 291 |     echo "Error: Invalid options" | 
 | 292 |     exit 1 | 
 | 293 | fi | 
 | 294 |  | 
 | 295 | eval set -- "$TEMP" | 
 | 296 |  | 
 | 297 | while [[ $# -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 | 
 | 334 | done | 
 | 335 |  | 
 | 336 | main #main program | 
 | 337 | exit $? |