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