]> granicus.if.org Git - strace/blob - tests/init.sh
40e621889ab8b27a2bb640c424492e75131e95e2
[strace] / tests / init.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2011-2016 Dmitry V. Levin <ldv@altlinux.org>
4 # Copyright (c) 2011-2018 The strace developers.
5 # All rights reserved.
6 #
7 # SPDX-License-Identifier: GPL-2.0-or-later
8
9 export LC_ALL=C
10 ME_="${0##*/}"
11 LOG="log"
12 OUT="out"
13 EXP="exp"
14
15 warn_() { printf >&2 '%s\n' "$*"; }
16 fail_() { warn_ "$ME_: failed test: $*"; exit 1; }
17 skip_() { warn_ "$ME_: skipped test: $*"; exit 77; }
18 framework_failure_() { warn_ "$ME_: framework failure: $*"; exit 99; }
19 framework_skip_() { warn_ "$ME_: framework skip: $*"; exit 77; }
20
21 check_prog()
22 {
23         type "$@" > /dev/null 2>&1 ||
24                 framework_skip_ "$* is not available"
25 }
26
27 dump_log_and_fail_with()
28 {
29         cat < "$LOG" >&2
30         fail_ "$*"
31 }
32
33 run_prog()
34 {
35         if [ $# -eq 0 ]; then
36                 set -- "../$NAME"
37         fi
38         args="$*"
39         "$@" || {
40                 rc=$?
41                 if [ $rc -eq 77 ]; then
42                         skip_ "$args exited with code 77"
43                 else
44                         fail_ "$args failed with code $rc"
45                 fi
46         }
47 }
48
49
50 run_prog_skip_if_failed()
51 {
52         args="$*"
53         "$@" || framework_skip_ "$args failed with code $?"
54 }
55
56 try_run_prog()
57 {
58         local rc
59
60         "$@" > /dev/null || {
61                 rc=$?
62                 if [ $rc -eq 77 ]; then
63                         return 1
64                 else
65                         fail_ "$* failed with code $rc"
66                 fi
67         }
68 }
69
70 run_strace()
71 {
72         > "$LOG" || fail_ "failed to write $LOG"
73         args="$*"
74         $STRACE -o "$LOG" "$@" ||
75                 dump_log_and_fail_with "$STRACE $args failed with code $?"
76 }
77
78 run_strace_merge()
79 {
80         rm -f -- "$LOG".[0-9]*
81         run_strace -ff -tt "$@"
82         "$srcdir"/../strace-log-merge "$LOG" > "$LOG" ||
83                 dump_log_and_fail_with 'strace-log-merge failed with code $?'
84         rm -f -- "$LOG".[0-9]*
85 }
86
87 check_gawk()
88 {
89         check_prog gawk
90         check_prog grep
91
92         local program="$1"; shift
93         if grep '^@include[[:space:]]' < "$program" > /dev/null; then
94                 gawk '@include "/dev/null"' < /dev/null ||
95                         framework_skip_ 'gawk does not support @include'
96         fi
97 }
98
99 # Usage: [FILE_TO_CHECK [AWK_PROGRAM [ERROR_MESSAGE [EXTRA_AWK_OPTIONS...]]]]
100 # Check whether AWK_PROGRAM matches FILE_TO_CHECK using gawk.
101 # If it doesn't, dump FILE_TO_CHECK and fail with ERROR_MESSAGE.
102 match_awk()
103 {
104         local output program error
105         if [ $# -eq 0 ]; then
106                 output="$LOG"
107         else
108                 output="$1"; shift
109         fi
110         if [ $# -eq 0 ]; then
111                 program="$srcdir/$NAME.awk"
112         else
113                 program="$1"; shift
114         fi
115         if [ $# -eq 0 ]; then
116                 error="$STRACE $args output mismatch"
117         else
118                 error="$1"; shift
119         fi
120
121         check_gawk "$program"
122
123         AWKPATH="$srcdir" gawk -f "$program" "$@" < "$output" || {
124                 cat < "$output"
125                 fail_ "$error"
126         }
127 }
128
129 # Usage: [FILE_TO_CHECK [FILE_TO_COMPATE_WITH [ERROR_MESSAGE]]]
130 # Check whether FILE_TO_CHECK differs from FILE_TO_COMPATE_WITH.
131 # If it does, dump the difference and fail with ERROR_MESSAGE.
132 match_diff()
133 {
134         local output expected error
135         if [ $# -eq 0 ]; then
136                 output="$LOG"
137         else
138                 output="$1"; shift
139         fi
140         if [ $# -eq 0 ]; then
141                 expected="$srcdir/$NAME.expected"
142         else
143                 expected="$1"; shift
144         fi
145         if [ $# -eq 0 ]; then
146                 error="$STRACE $args output mismatch"
147         else
148                 error="$1"; shift
149         fi
150
151         check_prog diff
152
153         diff -u -- "$expected" "$output" ||
154                 fail_ "$error"
155 }
156
157 # Usage: [FILE_TO_CHECK [FILE_WITH_PATTERNS [ERROR_MESSAGE]]]
158 # Check whether all patterns listed in FILE_WITH_PATTERNS
159 # match FILE_TO_CHECK using egrep.
160 # If at least one of these patterns does not match,
161 # dump both files and fail with ERROR_MESSAGE.
162 match_grep()
163 {
164         local output patterns error pattern cnt failed=
165         if [ $# -eq 0 ]; then
166                 output="$LOG"
167         else
168                 output="$1"; shift
169         fi
170         if [ $# -eq 0 ]; then
171                 patterns="$srcdir/$NAME.expected"
172         else
173                 patterns="$1"; shift
174         fi
175         if [ $# -eq 0 ]; then
176                 error="$STRACE $args output mismatch"
177         else
178                 error="$1"; shift
179         fi
180
181         check_prog wc
182         check_prog grep
183
184         cnt=1
185         while read -r pattern; do
186                 LC_ALL=C grep -E -x -e "$pattern" < "$output" > /dev/null || {
187                         test -n "$failed" || {
188                                 echo 'Failed patterns of expected output:'
189                                 failed=1
190                         }
191                         printf '#%d: %s\n' "$cnt" "$pattern"
192                 }
193                 cnt=$(($cnt + 1))
194         done < "$patterns"
195         test -z "$failed" || {
196                 echo 'Actual output:'
197                 cat < "$output"
198                 fail_ "$error"
199         }
200 }
201
202 # Usage: run_strace_match_diff [args to run_strace]
203 run_strace_match_diff()
204 {
205         args="$*"
206         [ -n "$args" -a -z "${args##*-e trace=*}" ] ||
207                 set -- -e trace="$NAME" "$@"
208         run_prog > /dev/null
209         run_strace "$@" $args > "$EXP"
210         match_diff "$LOG" "$EXP"
211 }
212
213 # Usage: run_strace_match_grep [args to run_strace]
214 run_strace_match_grep()
215 {
216         args="$*"
217         [ -n "$args" -a -z "${args##*-e trace=*}" ] ||
218                 set -- -e trace="$NAME" "$@"
219         run_prog > /dev/null
220         run_strace "$@" $args > "$EXP"
221         match_grep "$LOG" "$EXP"
222 }
223
224 # Print kernel version code.
225 # usage: kernel_version_code $(uname -r)
226 kernel_version_code()
227 {
228         (
229                 set -f
230                 IFS=.
231                 set -- $1 0 0
232                 v1="${1%%[!0-9]*}" && [ -n "$v1" ] || v1=0
233                 v2="${2%%[!0-9]*}" && [ -n "$v2" ] || v2=0
234                 v3="${3%%[!0-9]*}" && [ -n "$v3" ] || v3=0
235                 echo "$(($v1 * 65536 + $v2 * 256 + $v3))"
236         )
237 }
238
239 # Usage: require_min_kernel_version_or_skip 3.0
240 require_min_kernel_version_or_skip()
241 {
242         local uname_r
243         uname_r="$(uname -r)"
244
245         [ "$(kernel_version_code "$uname_r")" -ge \
246           "$(kernel_version_code "$1")" ] ||
247                 skip_ "the kernel release $uname_r is not $1 or newer"
248 }
249
250 # Usage: grep_pid_status $pid GREP-OPTIONS...
251 grep_pid_status()
252 {
253         local pid
254         pid=$1; shift
255         cat < "/proc/$pid/status" | grep "$@"
256 }
257
258 # Subtracts one program set from another.
259 # If an optional regular expression is specified, the lines in the minuend file
260 # that match this regular expression are elso excluded from the output.
261 #
262 # Usage: prog_set_subtract minuend_file subtrahend_file [subtrahend_regexp]
263 prog_set_subtract()
264 {
265         local min sub re pat
266         min="$1"; shift
267         sub="$1"; shift
268         re="${1-}"
269         pat="$re|$(sed 's/[[:space:]].*//' < "$sub" | tr -s '\n' '|')"
270         grep -E -v -x -e "$pat" < "$min"
271 }
272
273 # Usage: test_pure_prog_set [--expfile FILE] COMMON_ARGS < tests_file
274 # stdin should consist of lines in "test_name strace_args..." format.
275 test_pure_prog_set()
276 {
277         local expfile
278
279         expfile="$EXP"
280
281         while [ -n "$1" ]; do
282                 case "$1" in
283                 --expfile)
284                         shift
285                         expfile="$1"
286                         shift
287                         ;;
288                 *)
289                         break
290                         ;;
291                 esac
292         done
293
294         while read -r t prog_args; do {
295                 # skip lines beginning with "#" symbol
296                 [ "${t###}" = "$t" ] || continue
297
298                 try_run_prog "../$t" || continue
299                 run_strace $prog_args "$@" "../$t" > "$expfile"
300                 match_diff "$LOG" "$expfile"
301         } < /dev/null; done
302 }
303
304 # Run strace against list of programs put in "$NAME.in" and then against the
305 # rest of pure_executables.list with the expectation of empty output in the
306 # latter case.
307 #
308 # Usage: source this file after init.sh and call:
309 #   test_trace_expr subtrahend_regexp strace_args
310 # Environment:
311 #   $NAME:      test name, used for "$NAME.in" file containing list of tests
312 #               for positive trace expression match;
313 #   $srcdir:    used to find pure_executables.list and "$NAME.in" files.
314 # Files created:
315 #   negative.list: File containing list of tests for negative match.
316 test_trace_expr()
317 {
318         local subtrahend_regexp
319         subtrahend_regexp="$1"; shift
320         test_pure_prog_set "$@" < "$srcdir/$NAME.in"
321         prog_set_subtract "$srcdir/pure_executables.list" "$srcdir/$NAME.in" \
322                 "$subtrahend_regexp" > negative.list
323         test_pure_prog_set --expfile /dev/null -qq -esignal=none "$@" \
324                 < negative.list
325 }
326
327 check_prog cat
328 check_prog rm
329
330 case "$ME_" in
331         *.gen.test) NAME="${ME_%.gen.test}" ;;
332         *.test) NAME="${ME_%.test}" ;;
333         *) NAME=
334 esac
335
336 STRACE_EXE=
337 if [ -n "$NAME" ]; then
338         TESTDIR="$NAME.dir"
339         rm -rf -- "$TESTDIR"
340         mkdir -- "$TESTDIR"
341         cd "$TESTDIR"
342
343         case "$srcdir" in
344                 /*) ;;
345                 *) srcdir="../$srcdir" ;;
346         esac
347
348         [ -n "${STRACE-}" ] || {
349                 STRACE=../../strace
350                 case "${LOG_COMPILER-} ${LOG_FLAGS-}" in
351                         *--suppressions=*--error-exitcode=*--tool=*)
352                         STRACE_EXE="$STRACE"
353                         # add valgrind command prefix
354                         STRACE="${LOG_COMPILER-} ${LOG_FLAGS-} $STRACE"
355                         ;;
356                 esac
357         }
358
359         trap 'dump_log_and_fail_with "time limit ($TIMEOUT_DURATION) exceeded"' XCPU
360 else
361         : "${STRACE:=../strace}"
362 fi
363
364 # Export $STRACE_EXE to check_PROGRAMS.
365 : "${STRACE_EXE:=$STRACE}"
366 export STRACE_EXE
367
368 : "${TIMEOUT_DURATION:=600}"
369 : "${SLEEP_A_BIT:=sleep 1}"
370
371 [ -z "${VERBOSE-}" ] ||
372         set -x