Home | History | Annotate | Download | only in tests-m32
      1 #!/bin/sh
      2 #
      3 # Copyright (c) 2011-2016 Dmitry V. Levin <ldv (at] 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 STRACE_EXE=
    345 if [ -n "$NAME" ]; then
    346 	TESTDIR="$NAME.dir"
    347 	rm -rf -- "$TESTDIR"
    348 	mkdir -- "$TESTDIR"
    349 	cd "$TESTDIR"
    350 
    351 	case "$srcdir" in
    352 		/*) ;;
    353 		*) srcdir="../$srcdir" ;;
    354 	esac
    355 
    356 	[ -n "${STRACE-}" ] || {
    357 		STRACE=../../strace
    358 		case "${LOG_COMPILER-} ${LOG_FLAGS-}" in
    359 			*--suppressions=*--error-exitcode=*--tool=*)
    360 			STRACE_EXE="$STRACE"
    361 			# add valgrind command prefix
    362 			STRACE="${LOG_COMPILER-} ${LOG_FLAGS-} $STRACE"
    363 			;;
    364 		esac
    365 	}
    366 
    367 	trap 'dump_log_and_fail_with "time limit ($TIMEOUT_DURATION) exceeded"' XCPU
    368 else
    369 	: "${STRACE:=../strace}"
    370 fi
    371 
    372 # Export $STRACE_EXE to check_PROGRAMS.
    373 : "${STRACE_EXE:=$STRACE}"
    374 export STRACE_EXE
    375 
    376 : "${TIMEOUT_DURATION:=600}"
    377 : "${SLEEP_A_BIT:=sleep 1}"
    378 
    379 [ -z "${VERBOSE-}" ] ||
    380 	set -x
    381