5
# Test infrastructure support.
7
# This file should be included by each test case
8
# It does a lot of hidden 'magic', Downside is that
9
# this magic makes debugging fauling tests more difficult.
10
# Running the test with the '-r' option can help.
12
# Userchangeable variables (tmpdir etc) should be specified in
15
# Cleanup is automatically performed by epilogue.inc
17
# For this file, functions are first, entry point code is at end, see "MAIN"
24
_fatal=true # avoid cascading fatal errors
25
echo "Fatal Error ($testname): $*" >&2
32
fatalerror "Unable to run test sub-executable"
37
# global num_testfailures teststatus
38
num_testfailures=$(($num_testfailures + 1))
44
#invoke exit_handler to cleanup
47
fatalerror "Unexpected shell error. Run with -x to debug"
50
# invoked whenever we exit (normally, interrupt
51
# or exit due to testfailure()/error_handler()
63
# create a log so we can run test again if -retain specified
66
#global tmpdir profile outfile
68
if [ "$retaintmpdir" = "true" ]
70
runfile=$tmpdir/runtest
71
echo "$subdomain ${parser_args} < $profile" > $runfile
72
echo "$testexec \"$@\" 2>&1 > $outfile" >> $runfile
73
echo "echo $testname: \`cat $outfile\`" >> $runfile
74
echo "$subdomain ${parser_args} -R < $profile" >> $runfile
80
if [ -z "${__NO_TRAP_ERR}" ]
82
trap "error_handler" ERR
85
local link linkdir targetdir targetname
91
if [ -x /usr/bin/readlink ] ; then
92
target=$(/usr/bin/readlink ${link})
94
# I'm sure there's a more perlish way to do this
95
target=$( perl -e "printf (\"%s\n\", readlink(\"${link}\"));")
96
#target=$( perl -e "if (\$foo = readlink(\"${link}\")){ \
97
# printf (\"%s\n\", \$foo) \
99
# print \"${link}\n\"; \
105
*) linkdir=$(dirname ${link})
106
targetdir=$(dirname ${target})
107
targetname=$(basename ${target})
108
linkdir=$(cd ${linkdir}/${targetdir} ; pwd)
109
link=${linkdir}/${targetname}
126
if [ -z "${__NO_TRAP_ERR}" ]
128
trap "error_handler" ERR
131
local exec mode libpath libs
138
fatalerror "invalid test executable $test"
141
# Suck. SuSE's ldd has a line "linux-gate.so.1 => (0xffffe000)"
142
# Red Hat's ldd has "/lib/ld-linux.so.2 (0x007b1000)"
143
# good ${DIETY}, what gross kludgage.
144
libs=$(ldd $exec | egrep -v "linux-(vdso(32|64)|gate).so.1" | sed 's~^.*=> \(/.*\) (.*$~\1~' | awk '{print $1}')
146
dynlibs="/etc/ld.so.cache:r"
148
# bleah, this is cheeseball. on systems with a stackguard
149
# compiler, we also need access to /dev/urandom
150
for i in $libs /dev/urandom
153
# resolve possible symlinks before checking for ld pattern
154
# this is necessary because some architectures (zSeries)
155
# use nonconforming ld symlink names, like ld64.so
156
libpath=`resolve_symlink $i`
158
/lib/ld[.-]*) mode=${mode}px
160
/lib64/ld[.-]*) mode=${mode}px
165
dynlibs="$dynlibs ${libpath}:${mode}"
171
if [ -z "${__NO_TRAP_ERR}" ]
173
trap "error_handler" ERR
176
# global _testdesc _pfmode _pid outfile
184
$testexec "$@" > $outfile 2>&1 &
191
# global _pid _rc outfile
198
echo "SIGNAL$(($rc - 128))" > $outfile
205
# global _testdesc _pfmode outfile
212
$testexec "$@" > $outfile 2>&1
214
if [ $test_rc -gt 128 ]
216
echo "SIGNAL$(($test_rc - 128))" > $outfile
222
# global _pfmode _testdesc outfile teststatus testname
223
local ret expectedsig killedsig
225
ret=`cat $outfile 2>/dev/null`
229
PASS) if [ "$_pfmode" != "pass" ]
231
echo "Error: ${testname} passed. Test '${_testdesc}' was expected to '${_pfmode}'"
235
FAIL*) if [ "$_pfmode" != "fail" ]
237
echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'. Reason for failure '${ret}'"
241
SIGNAL*) killedsig=`echo $ret | sed 's/SIGNAL//'`
243
signal*) expectedsig=`echo $_pfmode | sed 's/signal//'`
244
if [ -n "${expectedsig}" -a ${expectedsig} != ${killedsig} ]
246
echo "Error: ${testname} failed. Test '${_testdesc}' was expected to terminate with signal ${expectedsig}. Instead it terminated with signal ${killedsig}"
250
*) echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'. Reason for failure 'killed by signal ${killedsig}'"
262
if [ -z "${__NO_TRAP_ERR}" ]
264
trap "error_handler" ERR
273
local errno=$(perl -MPOSIX -e 'printf "%d\n", '$1';')
276
if [ -z "${__NO_TRAP_ERR}" ]
278
trap "error_handler" ERR
282
if [ "$test_rc" == "$errno" ] ; then
285
echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'. Reason for failure expect errno ${errno} != ${test_rc}"
292
if [ -z "${__NO_TRAP_ERR}" ]
294
trap "error_handler" ERR
297
local subprofile wflag
298
#global name outfile profile dynlibs profilenames
304
*^*) wflag="--nowarn"
309
mkflags="${wflag} ${escapeflag}"
311
name=$1; perm=$2; shift 2
313
if [ "$subprofile" -eq 1 -o "$nodefaults" -eq 1 ]
315
# skip dynamic libs for subprofiles
316
$bin/mkprofile.pl ${mkflags} $name ${outfile}:w "$@" >> $profile
318
$bin/mkprofile.pl ${mkflags} $name ${name}:${perm} $dynlibs ${outfile}:w "$@" >> $profile
321
echo $name >> $profilenames
326
if [ -z "${__NO_TRAP_ERR}" ]
328
trap "error_handler" ERR
331
local num_emitted imagename hat args arg names1 names2
332
#global complainflag escapeflag nodefaults profile profilenames
340
"-C") complainflag="-C"
342
"-E") escapeflag="-E"
352
# save previous profile
355
mv $profile ${profile}.old
356
mv $profilenames ${profilenames}.old
366
# image/subhat allows overriding of the default
367
# imagename which is based on the testname
369
# it is most often used after --, in fact it is basically
372
image=*) imagename=`echo $1 | sed 's/^image=[rix]*//'`
373
if [ ! -x "$imagename" ]
375
fatalerror "invalid imagename specified in input '$1'"
377
perm=`echo $1 | sed -n 's/^image=\([rix]*\).*$/\1/p'`
385
subhat=*) fatalerror "'subhat=hatname' is no longer supported ('$1')"
396
# -- is the seperator between profiles
397
if [ "$arg" == "--" ]
399
eval emit_profile \"$imagename\" \"$imageperm\" \
400
$(for i in $(seq 0 $((${num_args} - 1))) ; do echo \"\${args[${i}]}\" ; done)
401
num_emitted=$((num_emitted + 1))
405
args[${num_args}]=${arg}
406
num_args=$(($num_args + 1))
410
# output what is in args, or force empty profile
411
if [ -n "$args" -o $num_emitted -eq 0 ] ; then
412
eval emit_profile \"$imagename\" \"$imageperm\" \
413
$(for i in $(seq 0 $((${num_args} - 1))) ; do echo \"\${args[${i}]}\" ; done)
419
# if old and new profiles consist of the same entries
420
# we can do a replace, else remove/reload
421
if [ $profileloaded -eq 1 ]
423
names1=$tmpdir/sorted1
424
names2=$tmpdir/sorted2
425
sort $profilenames > $names1
426
sort ${profilenames}.old > $names2
428
if cmp -s $names1 $names2
432
removeprofile ${profile}.old
436
rm -f $names1 $names2
442
rm -f ${profile}.old ${profilenames}.old
447
#global complainflaf profile profileloaded
449
$subdomain ${parser_args} $complainflag < $profile > /dev/null
453
fatalerror "Unable to load profile $profile"
461
#global complainflag profile
463
$subdomain ${parser_args} -r $complainflag < $profile > /dev/null
466
fatalerror "Unable to replace profile $profile"
473
#global profile profileloaded
482
$subdomain ${parser_args} -R < $remprofile > /dev/null
485
fatalerror "Unable to remove profile $remprofile"
493
if [ -z "${__NO_TRAP_ERR}" ]
495
trap "error_handler" ERR
498
#global test testname testexec outfile profileloaded
500
#testname is the basename of the test, i,e 'open'
501
#test is the full path to the test executable.
502
#testexec is the path than will be run, normally this is the same
503
# as $test, but occasionally, you may want to invoke a wrapper which
504
# will run the test. In this case 'settest <testname> "wrapper {}'
505
# will result in testexec invoking wrapper. {} will be replaced with
517
testexec=`echo $2 | sed "s~{}~$test~"`
519
fatalerror "settest, illegal usage"
522
outfile=$tmpdir/output.$1
526
# build list of dynamic libraries required by this executable
530
# Remove any current profile if loaded
531
if [ $profileloaded -eq 1 ]
537
# ----------------------------------------------------------------------------
541
trap "exit_handler" EXIT
542
trap "error_handler" ERR 2> /dev/null
549
if [ `whoami` != "root" ]
551
fatalerror "Must be root to run $0"
556
fatalerror "$0 requires \$bin pointing to binary directory"
560
# -r/-retain: flag to retain last failing testcase in tmpdir
561
if [ "$1" == "-retain" -o "$1" == "-r" ]
568
# load user changeable variables
571
if [ ! -x $subdomain ]
573
fatalerror "AppArmor parser '$subdomain' is not executable"
578
tmpdir=$(mktemp -d $tmpdir-XXXXXX)
582
#set initial testname based on name of script
583
settest `basename $0 | sed 's/\.sh$//'`
585
profile=$tmpdir/profile
586
profilenames=$tmpdir/profile.names
587
num_testfailures=0 # exit code of script is set to #failures