88# required return code may also be supplied.
99function check_cmd_output() {
1010 local CMD_TIMEOUT=5 CMD_RETVAL CHECKNAME="$FUNCNAME" OUTPUT_VAR CMD_START_TS=$SECONDS
11- local IFS PID TIMER RET CMD
11+ local IFS PID TIMER RET CMD MSG
1212 local LINENO=0 MATCH_CNT=0 NEG_MATCH_CNT=0 i
13- local -a CMD_LIST LINES MATCHES MATCHED
13+ local -a CMD_LIST LINES MATCHES MATCHED MSGS
1414
15- MATCHES=( )
1615 OPTIND=1
17- while getopts ":C:O:e:m:r:t:" OPTION ; do
16+ while getopts ":C:M: O:e:m:r:t:" OPTION ; do
1817 case "$OPTION" in
19- C) CHECKNAME="$OPTARG" ;; # INTERNAL USE ONLY
20- O) OUTPUT_VAR="$OPTARG" ;; # INTERNAL USE ONLY
18+ C) CHECKNAME="$OPTARG" ;; # Used for writing wrapper checks
19+ O) OUTPUT_VAR="$OPTARG" ;; # Used for writing wrapper checks
20+ M) MSGS[${#MSGS[*]}]="$OPTARG" ;; # Used for writing wrapper checks
2121 e) CMD="$OPTARG" ;;
2222 m) MATCHES[${#MATCHES[*]}]="$OPTARG" ;;
2323 r) CMD_RETVAL="$OPTARG" ;;
@@ -70,29 +70,36 @@ function check_cmd_output() {
7070 fi
7171 IFS=$' \t\n'
7272
73- # Iterate through $LINES[] array to gather process data.
74- for ((LINENO = 0; LINENO <= ${#LINES[*]}; LINENO++)); do
75- for ((i = 0; i < ${#MATCHES[*]}; i++)); do
76- if [[ "${MATCHES[$i]:0:1}" = '!' ]]; then
77- # Match expression is negated. Fail if the line matches this expression.
78- if mcheck "${LINES[$LINENO]}" "${MATCHES[$i]:1}" ; then
79- die 1 "$CHECKNAME: \"${MATCHES[$i]:1}\" matched at line $((LINENO+1)) output from \"$CMD\"."
80- return 1
81- fi
82- elif [ ${MATCHED[$i]} -eq 0 ] && mcheck "${LINES[$LINENO]}" "${MATCHES[$i]}" ; then
83- MATCHED[$i]=1
84- ((MATCH_CNT++))
85- if [[ $MATCH_CNT == ${#MATCHED[*]} ]]; then
86- # All match expression(s) are positive and have
87- # matched successfully. Stop processing output.
88- break
73+ if [[ ${#MATCHES[*]} -gt 0 ]]; then
74+ # Iterate through $LINES[] array to gather process data.
75+ for ((LINENO = 0; LINENO <= ${#LINES[*]}; LINENO++)); do
76+ for ((i = 0; i < ${#MATCHES[*]}; i++)); do
77+ if [[ "${MATCHES[$i]:0:1}" = '!' ]]; then
78+ # Match expression is negated. Fail if the line matches this expression.
79+ if mcheck "${LINES[$LINENO]}" "${MATCHES[$i]:1}" ; then
80+ MSG=${MSGS[$i]:-\"%m\" matched at line %l of \"%c\"}
81+ MSG=${MSG//\%m/${MATCHES[$i]:1}}
82+ MSG=${MSG//\%l/$((LINENO+1))}
83+ MSG=${MSG//\%L/${LINES[$LINENO]//[\"\`\$]}}
84+ MSG=${MSG//\%c/$CMD}
85+ die 1 "$CHECKNAME: $MSG."
86+ return 1
87+ fi
88+ elif [ ${MATCHED[$i]} -eq 0 ] && mcheck "${LINES[$LINENO]}" "${MATCHES[$i]}" ; then
89+ MATCHED[$i]=1
90+ ((MATCH_CNT++))
91+ if [[ $MATCH_CNT == ${#MATCHED[*]} ]]; then
92+ # All match expression(s) are positive and have
93+ # matched successfully. Stop processing output.
94+ break
95+ fi
8996 fi
90- fi
97+ done
9198 done
92- done
9399
94- # None of the negated matches matched, so add them to our success count.
95- ((MATCH_CNT += NEG_MATCH_CNT))
100+ # None of the negated matches matched, so add them to our success count.
101+ ((MATCH_CNT += NEG_MATCH_CNT))
102+ fi
96103
97104 if [[ $RET -ne ${CMD_RETVAL:-0} ]]; then
98105 if [[ $SECONDS -ge $((CMD_START_TS+CMD_TIMEOUT)) && $RET -eq 143 ]]; then
@@ -111,13 +118,20 @@ function check_cmd_output() {
111118 # At least one expression failed to match. Locate the first such expression.
112119 if [[ $MATCH_CNT == 0 && ${#MATCHES[*]} == 1 ]]; then
113120 # Special case for cleaner output.
114- die 1 "$CHECKNAME: \"${MATCHES[0]}\" failed to match \"$CMD\" output."
121+ MSG=${MSGS[0]:-\"%m\" failed to match \"%c\" output}
122+ MSG=${MSG//\%m/${MATCHES[0]}}
123+ MSG=${MSG//\%c/$CMD}
124+ die 1 "$CHECKNAME: $MSG."
115125 return 1
116126 fi
117127
118128 for ((i = 0; i < ${#MATCHES[*]}; i++)); do
119129 if [[ ${MATCHED[$i]} == 0 ]]; then
120- die 1 "$CHECKNAME: \"${MATCHES[$i]}\" failed to match \"$CMD\" output ($((${#MATCHES[*]}-MATCH_CNT))/${#MATCHES[*]} patterns failed)."
130+ MSG=${MSGS[$i]:-\"%m\" failed to match \"%c\" output (%f patterns failed)}
131+ MSG=${MSG//\%m/${MATCHES[0]}}
132+ MSG=${MSG//\%c/$CMD}
133+ MSG=${MSG//\%f/$((${#MATCHES[*]}-MATCH_CNT))/${#MATCHES[*]}}
134+ die 1 "$CHECKNAME: $MSG."
121135 return 1
122136 fi
123137 done
@@ -168,3 +182,25 @@ function check_cmd_status() {
168182 fi
169183 return 0
170184}
185+
186+ # Check dmesg output for matching lines. Fairly simple wrapper for check_cmd_output() (above).
187+ function check_cmd_dmesg() {
188+ local CMD_TIMEOUT CMD_RETVAL CMD="dmesg"
189+ local -a MATCHES MSGS
190+
191+ OPTIND=1
192+ while getopts ":M:e:m:r:t:" OPTION ; do
193+ case "$OPTION" in
194+ M) MSGS[${#MSGS[*]}]=-M ; MSGS[${#MSGS[*]}]="$OPTARG" ;;
195+ e) CMD="$OPTARG" ;;
196+ m) MATCHES[${#MATCHES[*]}]=-m ; MATCHES[${#MATCHES[*]}]="$OPTARG" ;;
197+ r) CMD_RETVAL="$OPTARG" ;;
198+ t) CMD_TIMEOUT="$OPTARG" ;;
199+ :) die 1 "$FUNCNAME: Option -$OPTARG requires an argument." ; return 1 ;;
200+ \?) die 1 "$FUNCNAME: Invalid option: -$OPTARG" ; return 1 ;;
201+ esac
202+ done
203+ shift $((OPTIND-1))
204+
205+ check_cmd_output -C $FUNCNAME ${CMD_RETVAL:+-r $CMD_RETVAL} ${CMD_TIMEOUT:+-t $CMD_TIMEOUT} -e "$CMD" "${MSGS[@]}" "${MATCHES[@]}"
206+ }
0 commit comments