Imported Upstream version 20090930
[ltp-debian.git] / testscripts / test_fs_bind.sh
blob30eafa956a36d4efb88711a85b23c85be7f939ec
1 #!/bin/bash
4 # Copyright (c) International Business Machines Corp., 2005
5 # Authors: Avantika Mathur (mathurav@us.ibm.com)
6 # Matt Helsley (matthltc@us.ibm.com)
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 if tst_kvercmp 2 6 15 ; then
24 tst_resm TCONF "System kernel version is less than 2.6.15"
25 tst_resm TCONF "Cannot execute test"
26 exit 0
30 test_setup()
32 #######################################################################
33 ## Configure
34 #######################################################################
35 dopts='-dEBb'
37 ## Remove logged test state depending on results. 0 means do not remove,
38 ## 1 means OK to remove.
39 # rm saved state from tests that appear to have cleaned up properly?
40 rm_ok=1
41 # rm saved state from tests that don't appear to have fully cleaned up?
42 rm_err=0
44 #######################################################################
45 ## Initialize some variables
46 #######################################################################
47 TCID="$0"
48 TST_COUNT=0
50 test_dirs=( move bind rbind regression ) #cloneNS
51 nfailed=0
52 nsucceeded=0
54 # set the LTPROOT directory
55 cd `dirname $0`
56 LTPROOT="${PWD}"
57 echo "${LTPROOT}" | grep testscripts > /dev/null 2>&1
58 if [ $? -eq 0 ]; then
59 cd ..
60 LTPROOT="${PWD}"
63 FS_BIND_ROOT="${LTPROOT}/testcases/kernel/fs/fs_bind"
65 total=0 # total number of tests
66 for dir in "${test_dirs[@]}" ; do
67 ((total += `ls "${FS_BIND_ROOT}/${dir}/test"* | wc -l`))
68 done
69 TST_TOTAL=${total}
71 # set the PATH to include testcases/bin
72 LTPBIN="${LTPROOT}/testcases/bin"
73 PATH="${PATH}:/usr/sbin:${LTPBIN}:${FS_BIND_ROOT}/bin"
75 # Results directory
76 resdir="${LTPROOT}/results/fs_bind"
77 if [ ! -d "${resdir}" ]; then
78 mkdir -p "${resdir}" 2> /dev/null
81 TMPDIR="${TMPDIR:-/tmp}"
82 # A temporary directory where we can do stuff and that is
83 # safe to remove
84 sandbox="${TMPDIR}/sandbox"
86 ERR_MSG=""
88 export LTPBIN PATH FS_BIND_ROOT ERR_MSG TCID TST_COUNT TST_TOTAL
90 if [ ! -d "${resdir}" ]; then
91 tst_brkm TBROK true "$0: failed to make results directory"
92 exit 1
96 test_prereqs()
98 # Must be root to run the containers testsuite
99 if [ $UID != 0 ]; then
100 tst_brkm TBROK true "FAILED: Must be root to execute this script"
101 exit 1
104 mkdir "${sandbox}" >& /dev/null
105 if [ ! -d "${sandbox}" -o ! -x "${sandbox}" ]; then
106 tst_brkm TBROK true "$0: failed to make directory \"${sandbox}\""
107 exit -1
110 local mnt_bind=1
111 local mnt_move=1
113 pushd "${sandbox}" > /dev/null && {
114 mkdir bind_test move_test && {
115 mount --bind bind_test bind_test && {
116 mnt_bind=0
117 mount --move bind_test move_test && {
118 mnt_move=0
119 umount move_test
120 } || {
121 # bind mount succeeded but move mount
122 # failed
123 umount bind_test
125 } || {
126 # mount failed -- check if it's because we
127 # don't have privileges we need
128 if [ $? -eq 32 ]; then
129 tst_brkm TBROK true "$0 requires the privilege to use the mount command"
130 exit 32
133 rmdir bind_test move_test
135 popd > /dev/null
138 if [ ${mnt_bind} -eq 1 -o ${mnt_move} -eq 1 ]; then
139 tst_brkm TBROK true "$0: requires that mount support the --bind and --move options"
140 exit 1
143 tst_kvercmp 2 6 15
144 X=$?
145 if [ $X -lt 0 ]; then
146 tst_brkm TBROK "$0: failed to get the running kernel version"
147 exit 1
148 elif [ $X -lt 1 ]; then
149 tst_resm TWARN "$0: the remaining tests require 2.6.15 or later"
150 tst_exit 0
151 exit
152 else
153 tst_resm TINFO "$0: kernel >= 2.6.15 detected -- continuing"
156 mount --bind "${sandbox}" "${sandbox}" && {
157 mount --make-shared "${sandbox}" > /dev/null 2>&1 || "${FS_BIND_ROOT}/bin/smount" "${sandbox}" shared
158 umount "${sandbox}" || {
159 tst_resm TFAIL "$0: failed to umount simplest shared subtree"
160 exit 1
162 } || {
163 tst_brkm TBROK true "$0: failed to perform bind mount"
164 exit 1
167 tst_resm TPASS "$0: umounted simplest shared subtree"
171 # mounts we are concerned with in a well-defined order (helps diff)
172 # returns grep return codes
173 grep_proc_mounts()
175 local rc=0
177 # Save the pipefail shell option
178 shopt -o -q pipefail
179 local save=$?
180 set -o pipefail
182 # Grep /proc/mounts which is often more up-to-date than mounts
183 # We use pipefail because if the grep fails we want to pass that along
184 grep -F "${sandbox}" /proc/mounts | sort -b
185 rc=$?
187 # Restore the pipefail shell options
188 [ $save -eq 0 ] && shopt -o -s pipefail || shopt -o -u pipefail
190 return $rc
193 # Record the mount state
194 save_proc_mounts()
196 touch "$2/proc_mounts.before" >& /dev/null
197 if [ $? -ne 0 ]; then
198 tst_brkm TBROK true "$1: failed to record proc mounts"
199 return 1
202 grep_proc_mounts 2> /dev/null > "$2/proc_mounts.before"
203 return 0
206 # Compare mount list after the test with the list from before.
207 # If there are no differences then remove the before list and silently
208 # return 0. Else print the differences to stderr and return 1.
209 check_proc_mounts()
211 local tname="$1"
213 if [ ! -r "$2/proc_mounts.before" ]; then
214 tst_brkm TBROK true "${tname}: Could not find pre-test proc mount list"
215 return 1
218 grep_proc_mounts 2> /dev/null > "$2/proc_mounts.after"
219 # If the mounts are the same then just return
220 diff ${dopts} -q "$2/proc_mounts.before" "$2/proc_mounts.after" >& /dev/null
221 if [ $? -eq 0 ]; then
222 [ $rm_ok -eq 1 ] && rm -f "$2/proc_mounts."{before,after}
223 return 0
226 tst_resm TWARN "${tname}: did not properly clean up its proc mounts"
227 diff ${dopts} -U 0 "$2/proc_mounts.before" "$2/proc_mounts.after" | grep -vE '^\@\@' 1>&2
228 [ $rm_err -eq 1 ] && rm -f "$2/proc_mounts."{before,after}
229 return 1
232 # Undo leftover mounts
233 restore_proc_mounts()
235 #local tname="$1"
237 # do lazy umounts -- we're assuming that tests will only leave
238 # new mounts around and will never remove mounts outside the test
239 # directory
240 ( while grep_proc_mounts ; do
241 grep_proc_mounts | awk '{print $2}' | xargs -r --max-args=1 umount -l
242 done ) >& /dev/null
244 # mount list and exit with 0
245 [ $rm_err -eq 1 ] && rm -f "$2/proc_mounts."{before,after} 1>&2 # >& /dev/null
246 return 0
247 # if returning error do this:
248 # tst_brkm TBROK true "${tname}: failed to restore mounts"
251 # mounts we are concerned with in a well-defined order (helps diff)
252 # returns grep return codes
253 grep_mounts()
255 local rc=0
257 # Save the pipefail shell option
258 shopt -o -q pipefail
259 local save=$?
260 set -o pipefail
262 # Grep mount command output (which tends to come from /etc/mtab)
263 # We use pipefail because if the grep fails we want to pass that along
264 mount | grep -F "${sandbox}" | sort -b
265 rc=$?
267 # Restore the pipefail shell options
268 [ $save -eq 0 ] && shopt -o -s pipefail || shopt -o -u pipefail
270 return $rc
273 # Record the mount state
274 save_mounts()
276 touch "$2/mtab.before" >& /dev/null
277 if [ $? -ne 0 ]; then
278 tst_brkm TBROK true "$1: failed to record mtab mounts"
279 return 1
282 grep_mounts 2> /dev/null > "$2/mtab.before"
283 return 0
286 # Compare mount list after the test with the list from before.
287 # If there are no differences then remove the before list and silently
288 # return 0. Else print the differences to stderr and return 1.
289 check_mounts()
291 local tname="$1"
293 if [ ! -r "$2/mtab.before" ]; then
294 tst_brkm TBROK true "${tname}: Could not find pre-test mtab mount list"
295 return 1
298 grep_mounts 2> /dev/null > "$2/mtab.after"
299 # If the mounts are the same then just return
300 diff ${dopts} -q "$2/mtab.before" "$2/mtab.after" >& /dev/null
301 if [ $? -eq 0 ]; then
302 [ $rm_ok -eq 1 ] && rm -f "$2/mtab."{before,after}
303 return 0
306 tst_resm TWARN "${tname}: did not properly clean up its mtab mounts"
307 diff ${dopts} -U 0 "$2/mtab.before" "$2/mtab.after" | grep -vE '^\@\@' 1>&2
308 [ $rm_err -eq 1 ] && rm -f "$2/mtab."{before,after}
309 return 1
312 # Undo leftover mounts
313 restore_mounts()
315 #local tname="$1"
317 # do lazy umounts -- we're assuming that tests will only leave
318 # new mounts around and will never remove mounts outside the test
319 # directory
320 ( while grep_mounts ; do
321 grep_mounts | awk '{print $3}' | xargs -r --max-args=1 umount -l
322 done ) >& /dev/null
324 # mount list and exit with 0
325 [ $rm_err -eq 1 ] && rm -f "$2/mtab."{before,after} 1>&2 # >& /dev/null
326 return 0
327 # if returning error do this:
328 # tst_brkm TBROK true "${tname}: failed to restore mounts"
331 # Record the sandbox state
332 # We don't save full sandbox state -- just the names of files and dirs present
333 save_sandbox()
335 local when="before"
336 local tname="$1"
338 if [ -e "$2/files.before" ]; then
339 if [ -e "$2/files.after" ]; then
340 tst_brkm TBROK true "${tname}: stale catalog of \"${sandbox}\""
341 return 1
343 when="after"
346 ( find "${sandbox}" -type d -print | sort > "$2/dirs.$when"
347 find "${sandbox}" -type f -print | sort | \
348 grep -vE '^'"$2"'/(dirs|files)\.(before|after)$' > "$2/files.$when" ) >& /dev/null
349 return 0
352 # Save sandbox after test and then compare. If the sandbox state is not
353 # clean then print the differences to stderr and return 1. Else remove all
354 # saved sandbox state and silently return 0
355 check_sandbox()
357 local tname="$1"
359 if [ ! -r "$2/files.before" -o ! -r "$2/dirs.before" ]; then
360 tst_brkm TBROK true "${tname} missing saved catalog of \"${sandbox}\""
361 return 1
364 save_sandbox "${tname} (check)" "$2"
366 ( diff ${dopts} -q "$2/dirs.before" "$2/dirs.after" && \
367 diff ${dopts} -q "$2/files.before" "$2/files.after" ) >& /dev/null \
368 && {
369 [ $rm_ok -eq 1 ] && rm -f "$2/"{files,dirs}.{before,after}
370 return 0
373 tst_resm TWARN "${tname} did not properly clean up \"${sandbox}\""
374 diff ${dopts} -U 0 "$2/dirs.before" "$2/dirs.after" 1>&2
375 diff ${dopts} -U 0 "$2/files.before" "$2/files.after" 1>&2
376 [ $rm_err -eq 1 ] && rm -f "$2/"{files,dirs}.{before,after} 1>&2
377 return 1
380 # Robust sandbox cleanup
381 clean_sandbox()
383 local tname="$1"
385 { rm -rf "${sandbox}" ; mkdir "${sandbox}" ; } >& /dev/null
386 if [ ! -d "${sandbox}" -o ! -x "${sandbox}" ]; then
387 tst_brkm TBROK true "$tname: failed to make directory \"${sandbox}\""
388 return 1
390 return 0
393 # Check file for non-whitespace chars
394 is_file_empty()
396 awk '/^[[:space:]]*$/ { next }
397 { exit 1; }' < "$1"
401 # Run the specified test script.
403 # Return 1 if the test was broken but should not stop the remaining test
404 # categories from being run.
405 # Return 2 if the test was broken and no further tests should be run.
406 # Return 0 otherwise (if the test was broken but it shouldn't affect other
407 # test runs)
408 # Note that this means the return status is not the success or failure of the
409 # test itself.
411 run_test()
413 local t="$1"
414 local tname="$(basename "$(dirname "$t")")/$(basename "$t")"
415 local log="$resdir/$tname/log"
416 local errlog="$resdir/$tname/err"
417 local do_break=0
419 ERR_MSG=""
421 # Pre-test
422 mkdir -p "$resdir/$tname"
423 if [ ! -d "$resdir/$tname" -o ! -x "$resdir/$tname" ]; then
424 tst_brkm TBROK true "$0: can't make or use \"$resdir/$tname\" as a log directory"
425 return 1
428 save_sandbox "$tname" "$resdir/$tname" || do_break=1
429 save_mounts "$tname" "$resdir/$tname" || do_break=1
430 save_proc_mounts "$tname" "$resdir/$tname" || do_break=1
431 if [ $do_break -eq 1 ]; then
432 tst_brkm TBROK true "$tname: failed to save pre-test state of \"${sandbox}\""
433 return 2
435 pushd "${sandbox}" > /dev/null
437 # Run the test
439 TCID="$tname"
440 declare -r TST_COUNT
441 export LTPBIN PATH FS_BIND_ROOT ERR_MSG TCID TST_COUNT TST_TOTAL
442 "$t" #> "$log" 2> "$errlog"
444 local rc=$?
445 TCID="$0"
447 # Post-test
448 popd > /dev/null
449 if [ $rc -ne 0 ]; then
450 #echo "FAILED"
451 ((nfailed++))
452 else
453 #echo "SUCCEEDED"
454 ((nsucceeded++))
456 check_proc_mounts "$tname" "$resdir/$tname" || \
457 restore_proc_mounts "$tname" "$resdir/$tname" || do_break=1
458 check_mounts "$tname" "$resdir/$tname" || \
459 restore_mounts "$tname" "$resdir/$tname" || do_break=1
460 check_sandbox "$tname" "$resdir/$tname"
461 clean_sandbox "$tname" || do_break=1
462 if [ $do_break -eq 1 ]; then
463 tst_brkm TBROK true "$tname: failed to restore pre-test state of \"${sandbox}\""
464 return 2
467 # If we succeeded and the error log is empty remove it
468 if [ $rc -eq 0 -a -w "$errlog" ] && is_file_empty "$errlog" ; then
469 rm -f "$errlog"
471 return 0
474 main()
476 TST_COUNT=1
477 for dir in "${test_dirs[@]}" ; do
478 tests=( $(find "${FS_BIND_ROOT}/${dir}" -type f -name 'test*') )
479 clean_sandbox "$0" || break
480 for t in "${tests[@]}" ; do
481 run_test "$t"
482 local rc=$?
484 if [ $rc -ne 0 ]; then
485 break $rc
488 ((TST_COUNT++))
489 done
490 done
491 rm -rf "${sandbox}"
492 return 0
494 skipped=$((total - nsucceeded - nfailed))
495 if [ $nfailed -eq 0 -a $skipped -eq 0 ]; then
496 # Use PASSED for the summary rather than SUCCEEDED to make it
497 # easy to determine 100% success from a calling script
498 summary="PASSED"
499 else
500 # Use FAILED to make it easy to find > 0% failure from a
501 # calling script
502 summary="FAILED"
504 cat - <<-EOF
505 *********************************
506 RESULTS SUMMARY:
508 passed: $nsucceeded/$total
509 failed: $nfailed/$total
510 skipped: $skipped/$total
511 summary: $summary
513 *********************************
517 test_setup || exit 1
518 test_prereqs || exit 1
519 declare -r FS_BIND_ROOT
520 declare -r TST_TOTAL
521 main #2> "$resdir/errors" 1> "$resdir/summary"