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