Project

General

Profile

report_sata_backplane_usage.sh

Charles Atkinson, 10/02/2022 11:25

Download (20.8 KB)

 
1
#!/bin/bash
2

    
3
# Report SATA backplane usage
4
#   * Report is created in /var/backup/sata_backplane_usage if different from
5
#     the previous report
6

    
7
# Programmers' notes: function call tree
8
#    +
9
#    |
10
#    +-- initialise
11
#    |
12
#    +-- generate_report
13
#    |
14
#    +-- finalise
15
#
16
# Utility functions called from various places:
17
#     ck_file ck_uint fct msg
18

    
19
# Function definitions in alphabetical order.  Execution begins after the last function definition.
20

    
21
#--------------------------
22
# Name: ck_file
23
# Purpose: for each file listed in the argument list: checks that it is
24
#   * reachable and exists
25
#   * is of the type specified (block special, ordinary file or directory)
26
#   * has the requested permission(s) for the user
27
#   * optionally, is absolute (begins with /)
28
# Usage: ck_file [ path <file_type>:<permissions>[:[a]] ] ...
29
#   where
30
#     file  is a file name (path)
31
#     file_type  is b (block special file), f (file) or d (directory)
32
#     permissions  is none or more of r, w and x
33
#     a  requests an absoluteness test (that the path begins with /)
34
#   Example: ck_file foo d:rwx:
35
# Outputs:
36
#   * For the first requested property each file does not have, a message to
37
#     stderr
38
#   * For the first detected programminng error, a message to
39
#     stderr
40
# Returns:
41
#   0 when all files have the requested properties
42
#   1 when at least one of the files have the requested properties
43
#   2 when a programming error is detected
44
#--------------------------
45
function ck_file {
46

    
47
    local absolute_flag buf file_name file_type perm perms retval
48

    
49
    # For each file ...
50
    # ~~~~~~~~~~~~~~~~~
51
    retval=0
52
    while [[ $# -gt 0 ]]
53
    do
54
        file_name=$1
55
        file_type=${2%%:*}
56
        buf=${2#$file_type:}
57
        perms=${buf%%:*}
58
        absolute=${buf#$perms:}
59
        [[ $absolute = $buf ]] && absolute=
60
        case $absolute in
61
            '' | a )
62
                ;;
63
            * )
64
                echo "ck_file: invalid absoluteness flag in '$2' specified for file '$file_name'" >&2
65
                return 2
66
        esac
67
        shift 2
68

    
69
        # Is the file reachable and does it exist?
70
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
71
        case $file_type in
72
            b )
73
                if [[ ! -b $file_name ]]; then
74
                    echo "file '$file_name' is unreachable, does not exist or is not a block special file" >&2
75
                    retval=1
76
                    continue
77
                fi
78
                ;;
79
            f )
80
                if [[ ! -f $file_name ]]; then
81
                    echo "file '$file_name' is unreachable, does not exist or is not an ordinary file" >&2
82
                    retval=1
83
                    continue
84
                fi
85
                ;;
86
            d )
87
                if [[ ! -d $file_name ]]; then
88
                    echo "directory '$file_name' is unreachable, does not exist or is not a directory" >&2
89
                    retval=1
90
                    continue
91
                fi
92
                ;;
93
            * )
94
                echo "Programming error: ck_file: invalid file type '$file_type' specified for file '$file_name'" >&2
95
                return 2
96
        esac
97

    
98
        # Does the file have the requested permissions?
99
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100
        buf="$perms"
101
        while [[ $buf ]]
102
        do
103
            perm="${buf:0:1}"
104
            buf="${buf:1}"
105
            case $perm in
106
                r )
107
                    if [[ ! -r $file_name ]]; then
108
                        echo "$file_name: no read permission" >&2
109
                        retval=1
110
                        continue
111
                    fi
112
                    ;;
113
                w )
114
                    if [[ ! -w $file_name ]]; then
115
                        echo "$file_name: no write permission" >&2
116
                        retval=1
117
                        continue
118
                    fi
119
                    ;;
120
                x )
121
                    if [[ ! -x $file_name ]]; then
122
                        echo "$file_name: no execute permission" >&2
123
                        retval=1
124
                        continue
125
                    fi
126
                    ;;
127
                * )
128
                    echo "Programming error: ck_file: invalid permisssion '$perm' requested for file '$file_name'" >&2
129
                    return 2
130
            esac
131
        done
132

    
133
        # Does the file have the requested absoluteness?
134
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
135
        if [[ $absolute = a && ${file_name:0:1} != / ]]; then
136
            echo "$file_name: does not begin with /" >&2
137
            retval=1
138
        fi
139

    
140
    done
141

    
142
    return $retval
143

    
144
}  #  end of function ck_file
145

    
146
#--------------------------
147
# Name: ck_uint
148
# Purpose: checks for a valid unsigned integer
149
# Usage: ck_uint <putative uint>
150
# Outputs: none
151
# Returns:
152
#   0 when $1 is a valid unsigned integer
153
#   1 otherwise
154
#--------------------------
155
function ck_uint {
156
    local regex='^[[:digit:]]+$'
157
    [[ $1 =~ $regex ]] && return 0 || return 1
158
}  #  end of function ck_uint
159

    
160
#--------------------------
161
# Name: fct
162
# Purpose: function call trace (for debugging)
163
# $1 - name of calling function
164
# $2 - message.  If it starts with "started" or "returning" then the output is prettily indented
165
#--------------------------
166
function fct {
167

    
168
    if [[ ! $debugging_flag ]]; then
169
        return 0
170
    fi
171

    
172
    fct_indent="${fct_indent:=}"
173

    
174
    case $2 in
175
        'started'* )
176
            fct_indent="$fct_indent  "
177
            msg D "$fct_indent$1: $2"
178
            ;;
179
        'returning'* )
180
            msg D "$fct_indent$1: $2"
181
            fct_indent="${fct_indent#  }"
182
            ;;
183
        * )
184
            msg D "$fct_indent$1: $2"
185
    esac
186

    
187
}  # end of function fct
188

    
189
#--------------------------
190
# Name: finalise
191
# Purpose: cleans up and exits
192
# Arguments:
193
#    $1  return value
194
# Return code (on exit):
195
#   The sum of zero plus
196
#      1 if any warnings
197
#      2 if any errors
198
#      4,8,16 unused
199
#      32 if terminated by a signal
200
#--------------------------
201
function finalise {
202
    fct "${FUNCNAME[0]}" 'started'
203
    finalising_flag=$true
204

    
205
    # Temporary directory removal
206
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~
207
    tmp_dir_regex="^/tmp/$my_name\..{6}$"
208
    [[ $tmp_dir_created_flag \
209
        && ${tmp_dir:-} =~ $tmp_dir_regex \
210
    ]] && rm -fr "$tmp_dir"
211

    
212
    # Interrupted?  Message and exit return value
213
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
214
    my_retval=0
215
    if ck_uint "${1:-}" && (($1>128)); then
216
        ((my_retval+=32))
217
        case $1 in
218
            129 )
219
                buf=SIGHUP
220
                ;;
221
            130 )
222
                buf=SIGINT
223
                ;;
224
            131 )
225
                buf=SIGQUIT
226
                ;;
227
            132 )
228
                buf=SIGILL
229
                ;;
230
            134 )
231
                buf=SIGABRT
232
                ;;
233
            135 )
234
                buf=SIGBUS
235
                ;;
236
            136 )
237
                buf=SIGFPE
238
                ;;
239
            138 )
240
                buf=SIGUSR1
241
                ;;
242
            139 )
243
                buf=SIGSEGV
244
                ;;
245
            140 )
246
                buf=SIGUSR2
247
                ;;
248
            141 )
249
                buf=SIGPIPE
250
                ;;
251
            142 )
252
                buf=SIGALRM
253
                ;;
254
            143 )
255
                buf=SIGTERM
256
                ;;
257
            146 )
258
                buf=SIGCONT
259
                ;;
260
            147 )
261
                buf=SIGSTOP
262
                ;;
263
            148 )
264
                buf=SIGTSTP
265
                ;;
266
            149 )
267
                buf=SIGTTIN
268
                ;;
269
            150 )
270
                buf=SIGTTOU
271
                ;;
272
            151 )
273
                buf=SIGURG
274
                ;;
275
            152 )
276
                buf=SIGCPU
277
                ;;
278
            153 )
279
                buf=SIGXFSZ
280
                ;;
281
            154 )
282
                buf=SIGVTALRM
283
                ;;
284
            155 )
285
                buf=SIGPROF
286
                ;;
287
            * )
288
                msg E "${FUNCNAME[0]}: programming error: \$1 ($1) not serviced"
289
                ;;
290
        esac
291
        interrupt_flag=$true
292
        msg="Finalising on $buf"
293
        msg E "$msg"    # Returns because finalising_flag is set
294
    fi
295

    
296
    # Old log removal
297
    # ~~~~~~~~~~~~~~~
298
    buf=$(find "$log_dir" -name '*.log' -mtime +$log_retention -execdir rm {} + 2>&1)
299
    [[ $buf != '' ]] && msg W "Problem removing old logs: $buf"
300

    
301
    # Exit return value adjustment
302
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
303
    if [[ $warning_flag ]]; then
304
        ((my_retval+=1))
305
    fi
306
    if [[ $error_flag ]]; then
307
        ((my_retval+=2))
308
    fi
309

    
310
    # Exit
311
    # ~~~~
312
    exit $my_retval
313
}  # end of function finalise
314

    
315
#--------------------------
316
# Name: generate_report
317
# Purpose:
318
#    * Generates SATA backplane usage report
319
# Usage: generate_report
320
# Global variable set: none
321
# Outputs: writes dated report file; removes if same as last one
322
# Returns:
323
#   0 on success and warning.  Does not return on error
324
#--------------------------
325
function generate_report {
326
    fct "${FUNCNAME[0]}" 'started'
327
    local ata buf cmd last_out_fn oIFS out out_dir out_fn
328
    declare -A ata
329

    
330
    #  Get the ATA number for each sdX
331
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
332
    # Based on syntaxerror's script in
333
    # https://serverfault.com/questions/244944/linux-ata-errors-translating-to-a-device-name
334
    oIFS=$IFS
335
    while IFS=' ' read Path HostFull sdx
336
    do
337
        IFS=: h=($HostFull)
338
        HostMain=${h[0]}; HostMid=${h[1]}; HostSub=${h[2]}
339
        if echo $Path | grep -q '/usb[0-9]*/'; then
340
            msg I "Device $sdx is not an ATA device, it is a USB device"
341
        else
342
            ata["$sdx"]=ata$(< "$Path/host$HostMain/scsi_host/host$HostMain/unique_id").$HostMid$HostSub
343
        fi
344
    done < <(
345
        for i in /sys/block/sd*
346
        do
347
            readlink $i \
348
                | sed \
349
                    -e 's|\.\./devices|/sys/devices|' \
350
                    -e 's|/host[0-9]\{1,2\}/target| |' \
351
                    -e 's|/[0-9]\{1,2\}\(:[0-9]\)\{3\}/block/| |'
352
        done
353
    )
354
    IFS=$oIFS
355

    
356
    # Generate report data
357
    # ~~~~~~~~~~~~~~~~~~~~
358
    out=$'Backplane Socket  sdx ata      Serial\n'
359
    out+=$(
360
        while read backplane socket sdx serno
361
        do
362
            msg D "backplane: $backplane, socket: $socket, sdx: $sdx, serno: $serno"
363
            ((backplane=backplane-6+1))
364
            ((socket++))
365
            printf '%9s %6s %4s %8s %s\n' $backplane $socket $sdx ${ata[$sdx]} $serno
366
        done < <(
367
            lshw -class disk 2>&1 \
368
                | grep -E '^       (bus info|logical name|serial)' \
369
                | sed -e 's/^[[:space:]]*//' \
370
                | xargs -L 3 \
371
                | grep -Ev 'scsi@(0|1):0.0.0' \
372
                | sed -e 's/bus info: scsi@//' -e 's|logical name: /dev/||' \
373
                | sed -e 's/serial: //' -e 's/:/ /' -e 's/\.0\.0//' \
374
                | sort -n
375
            )
376
    )
377

    
378
    # Check reports directory
379
    # ~~~~~~~~~~~~~~~~~~~~~~~
380
    out_dir=/var/backup/sata_backplane_usage
381
    buf=$(ck_file "$out_dir" d:rwx 2>&1)
382
    [[ $buf != '' ]] && msg E "$buf"
383

    
384
    # Get name of most recent report
385
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
386
    last_out_fn=$(ls -1rt "$out_dir" | tail -1)
387
    [[ $last_out_fn != '' ]] && last_out_fn=$out_dir/$last_out_fn
388

    
389
    # Write report to file
390
    # ~~~~~~~~~~~~~~~~~~~~
391
    out_fn=$out_dir/$(date +%Y-%m-%d@%H:%M:%S).report
392
    msg I "Writing report $out_fn"
393
    buf=$(echo "$out" > "$out_fn" 2>&1)
394
    [[ $buf != '' ]] && msg E "Writing report: $buf"
395

    
396
    # Remove report file if same as previous one
397
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
398
    if [[ $last_out_fn != '' ]]; then
399
        cmd=(diff --brief "$last_out_fn" "$out_fn")
400
        buf=$("${cmd[@]}" 2>&1)
401
        if (($?==0)); then
402
            msg I "Removing report $out_fn because identical to the last report"
403
            buf=$(rm "$out_fn" 2>&1)
404
            [[ $buf != '' ]] && msg E "Removing $out_fn: $buf"
405
        elif (($?==1)); then
406
            msg W "SATA backplane usage changed.  Reports in $out_dir"
407
        elif (($?==2)); then
408
            msg E "${cmd[*]}: $buf"
409
        fi
410
    fi
411

    
412
    fct "${FUNCNAME[0]}" 'returning'
413
    return 0
414
}  #  end of function generate_report
415

    
416
#--------------------------
417
# Name: initialise
418
# Purpose: sets up environment, parses command line, reads config file
419
#--------------------------
420
function initialise {
421
    local args buf emsg msg_part opt_c_flag opt_l_flag
422
    local -r fn_date_format='%Y-%m-%d@%H:%M:%S'
423

    
424
    # Configure shell environment
425
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~
426
    export LANG=en_GB.UTF-8
427
    export LANGUAGE=en_GB.UTF-8
428
    for var_name in LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
429
        LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
430
        LC_TELEPHONE LC_TIME
431
    do
432
        unset $var_name
433
    done
434

    
435
    export PATH=/usr/sbin:/sbin:/usr/bin:/bin
436
    IFS=$' \n\t'
437
    set -o nounset
438
    shopt -s extglob            # Enable extended pattern matching operators
439
    unset CDPATH                # Ensure cd behaves as expected
440
    umask 022
441

    
442
    # Initialise some global logic variables
443
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
444
    readonly false=
445
    readonly true=true
446

    
447
    debugging_flag=$false
448
    error_flag=$false
449
    finalising_flag=$false
450
    interrupt_flag=$false
451
    logging_flag=$false
452
    tmp_dir_created_flag=$false
453
    warning_flag=$false
454

    
455
    # Initialise some global string variables
456
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
457
    readonly log_date_format='+%H:%M:%S'
458
    readonly log_retention=28
459
    readonly msg_lf=$'\n    '
460
    readonly my_name=${0##*/}
461
    readonly script_ver=0.1
462

    
463
    # Set traps
464
    # ~~~~~~~~~
465
    trap 'finalise 129' 'HUP'
466
    trap 'finalise 130' 'INT'
467
    trap 'finalise 131' 'QUIT'
468
    trap 'finalise 132' 'ILL'
469
    trap 'finalise 134' 'ABRT'
470
    trap 'finalise 135' 'BUS'
471
    trap 'finalise 136' 'FPE'
472
    trap 'finalise 138' 'USR1'
473
    trap 'finalise 139' 'SEGV'
474
    trap 'finalise 140' 'USR2'
475
    trap 'finalise 141' 'PIPE'
476
    trap 'finalise 142' 'ALRM'
477
    trap 'finalise 143' 'TERM'
478
    trap 'finalise 146' 'CONT'
479
    trap 'finalise 147' 'STOP'
480
    trap 'finalise 148' 'TSTP'
481
    trap 'finalise 149' 'TTIN'
482
    trap 'finalise 150' 'TTOU'
483
    trap 'finalise 151' 'URG'
484
    trap 'finalise 152' 'XCPU'
485
    trap 'finalise 153' 'XFSZ'
486
    trap 'finalise 154' 'VTALRM'
487
    trap 'finalise 155' 'PROF'
488

    
489
    # Parse command line
490
    # ~~~~~~~~~~~~~~~~~~
491
    args=("$@")
492
    conf_fn=/usr/local/etc/report_sata_backplane_usage.conf
493
    emsg=
494
    log_dir=/var/log/${my_name%.sh}
495
    log_fn=$log_dir/$(date +$fn_date_format)
496
    opt_c_flag=$false
497
    opt_l_flag=$false
498
    while getopts :c:dhl:v opt "$@"
499
    do
500
        case $opt in
501
            c )
502
                conf_fn=$OPTARG
503
                opt_c_flag=$true
504
                ;;
505
            d )
506
                debugging_flag=$true
507
                ;;
508
            h )
509
                debugging_flag=$false
510
                usage verbose
511
                exit 0
512
                ;;
513
            l )
514
                log_fn=$OPTARG
515
                opt_l_flag=$true
516
                ;;
517
            v )
518
                echo "$script_name version $script_ver" >&2
519
                exit 0
520
                ;;
521
            : )
522
                emsg+=$msg_lf"Option $OPTARG must have an argument"
523
                [[ $OPTARG = c ]] && { opt_c_flag=$true; conf_fn=/bin/bash; }
524
                ;;
525
            * )
526
                emsg+=$msg_lf"Invalid option '-$OPTARG'"
527
        esac
528
    done
529

    
530
    # Check option arguments
531
    # ~~~~~~~~~~~~~~~~~~~~~~
532
    if [[ $opt_l_flag && $log_fn != /dev/tty ]]; then
533
        log_dir=${log_fn%/*}
534
        log_dir_realpath=$(readlink --canonicalize-missing -- "$log_dir" 2>&1)
535
        if (($?==0)); then
536
            buf=$(ck_file "$log_dir_realpath" d:rwx: 2>&1)
537
            [[ $buf != '' ]] && emsg+=$msg_lf"Invalid -l option value '$log_fn': $buf"
538
        else
539
           emsg+=$msg_lf"Invalid -l option value '$log_fn' ($log_dir_realpath)"
540
        fi
541
    fi
542

    
543
    # Test for mutually exclusive options
544
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
545
    # There are no mutually exclusive options
546

    
547
    # Test for mandatory options not set
548
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
549
    # There are no mandatory options
550

    
551
    # Test for extra arguments
552
    # ~~~~~~~~~~~~~~~~~~~~~~~~
553
    shift $(($OPTIND-1))
554
    if [[ $* != '' ]]; then
555
        emsg+=$msg_lf"Invalid extra argument(s) '$*'"
556
    fi
557

    
558
    # Report any command line errors
559
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
560
    if [[ $emsg != '' ]]; then
561
        emsg+=$msg_lf'(use -h option for help)'
562
        msg E "$emsg"
563
    fi
564

    
565
    # Check the config file
566
    # ~~~~~~~~~~~~~~~~~~~~~
567
    buf=$(ck_file "$conf_fn" f:r: 2>&1)
568
    [[ $buf != '' ]] && msg E "$buf"
569

    
570
    # Set up logging
571
    # ~~~~~~~~~~~~~~
572
    if [[ ! $opt_l_flag ]]; then    # No -l option; directory not yet error trapped
573
        buf=$(ck_file "$log_dir" d:rwx: 2>&1)
574
        if [[ $buf = '' ]]; then
575
            log_fn=$log_dir/$(date +$fn_date_format).log
576
            buf=$(touch "$log_fn" 2>&1)
577
            if (($?>0)); then
578
                msg E "cannot create $log_fn: $buf"
579
            fi
580
            chmod 600 "$log_fn"
581
        else
582
            msg E "cannot create log: $buf"
583
        fi
584
    fi
585
    exec >>"$log_fn"
586
    exec 2>>"$log_fn"
587
    [[ $log_fn != /dev/tty ]] && logging_flag=$true
588

    
589
    fct 'initialise' 'started (this message delayed until logging initialised)'
590
    msg I "$(date '+%A %-d %B %Y %Z')"
591
    msg I "$my_name version $script_ver started (PID: $$, PPID: $PPID)"
592
    msg I "Command line:$msg_lf$0 $(printf '%q ' "${args[@]}" | sed "s/''//")"
593

    
594
    # Read config file
595
    # ~~~~~~~~~~~~~~~~
596
    buf=$(ck_file "$conf_fn" f:r 2>&1)
597
    [[ $buf != '' ]] && msg E "$buf"
598
    source "$conf_fn"
599
    emsg=
600

    
601
    # Report any errors
602
    # ~~~~~~~~~~~~~~~~~
603
    if [[ $emsg != '' ]]; then
604
        msg E "$conf_fn: ${emsg#, }"
605
    fi
606

    
607
    # Create temporary directory
608
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~
609
    # TODO: remove this code if tmp_dir not used
610
    # If the mktemplate is changed, tmp_dir_regex in the finalise function
611
    # may also need to be changed.
612
    buf=$(mktemp -d "/tmp/$my_name.XXXXXX" 2>&1)
613
    if (($?==0)); then
614
        tmp_dir=$buf
615
        tmp_dir_created_flag=$true
616
        chmod 700 "$tmp_dir"
617
    else
618
        msg E "Unable to create temporary directory:$buf"
619
    fi
620

    
621
    fct "${FUNCNAME[0]}" 'returning'
622
}  # end of function initialise
623

    
624
#--------------------------
625
# Name: msg
626
# Purpose: generalised messaging interface
627
# Arguments:
628
#    $1 class: E, I or W indicating Error, Information or Warning
629
#    $2 message text
630
# Global variables read:
631
#     my_name
632
# Global variables written:
633
#     error_flag
634
#     warning_flag
635
# Output: information messages to stdout; the rest to stderr
636
# Returns:
637
#   Does not return (calls finalise) when class is E for error
638
#   Otherwise returns 0
639
#--------------------------
640
function msg {
641
    local class level message_text prefix
642

    
643
    # Process arguments
644
    # ~~~~~~~~~~~~~~~~~
645
    class="${1:-}"
646
    message_text="${2:-}"
647

    
648
    # Class-dependent set-up
649
    # ~~~~~~~~~~~~~~~~~~~~~~
650
    case "$class" in
651
        D )
652
            [[ ! $debugging_flag ]] && return
653
            prefix='DEBUG: '
654
            ;;
655
        E )
656
            error_flag=$true
657
            level=err
658
            prefix='ERROR: '
659
            ;;
660
        I )
661
            prefix=
662
            level=info
663
            ;;
664
        W )
665
            warning_flag=$true
666
            level=warning
667
            prefix='WARN: '
668
            ;;
669
        * )
670
            msg E "msg: invalid class '$class': '$*'"
671
    esac
672

    
673
    # Output
674
    # ~~~~~~
675
    message_text="$prefix$message_text"
676
    [[ $class = E ]] && \
677
        logger --tag $my_name[$$] --priority syslog.$level -- "$message_text"
678
    [[ $logging_flag ]] && \
679
        message_text="$(date "$log_date_format") $message_text"
680
    if [[ $class = I ]]; then
681
        printf '%s\n' "$message_text"
682
    else
683
        printf '%s\n' " $message_text" >&2
684
    fi
685

    
686
    # Return or not
687
    # ~~~~~~~~~~~~~
688
    if [[ $class = E ]]; then
689
        [[ ! $finalising_flag ]] && finalise 1
690
    fi
691

    
692
    return 0
693
}  #  end of function msg
694

    
695
#--------------------------
696
# Name: usage
697
# Purpose: prints usage message
698
#--------------------------
699
function usage {
700
    fct "${FUNCNAME[0]}" 'started'
701
    local msg usage
702

    
703
    # Build the messages
704
    # ~~~~~~~~~~~~~~~~~~
705
    usage="usage: $my_name -c conf [-d] [-h] [-l log] [-v]"
706
    msg='  where:'
707
    msg+=$'\n    -c configuration file name'
708
    msg+=$'\n    -d debugging on'
709
    msg+=$'\n    -h prints this help and exits'
710
    msg+=$'\n    -l log file'
711
    msg+=$'\n        Use /dev/tty to log to screen'
712
    msg+=$'\n        '
713
    msg+="Default: log to $log_fn"
714
    msg+=$'\n    '"-v prints the script's version and exits"
715

    
716
    # Display the message(s)
717
    # ~~~~~~~~~~~~~~~~~~~~~~
718
    echo "$usage" >&2
719
    if [[ ${1:-} != 'verbose' ]]; then
720
        echo "(use -h for help)" >&2
721
    else
722
        echo "$msg" >&2
723
    fi
724

    
725
    fct "${FUNCNAME[0]}" 'returning'
726
}  # end of function usage
727

    
728
#--------------------------
729
# Name: main
730
# Purpose: where it all happens
731
#--------------------------
732
initialise "${@:-}"
733
generate_report
734
finalise 0