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