blob: 792fff2efef46d95c4d91dc65ce1c73d1f389e86 [file] [log] [blame]
Chris Dearman37550cf2012-10-17 19:54:01 -07001#!/bin/bash
subrata_modak1d1937a2008-05-13 10:44:02 +00002
3#
4# Copyright (c) International Business Machines Corp., 2005
5# Authors: Avantika Mathur (mathurav@us.ibm.com)
6# Matt Helsley (matthltc@us.ibm.com)
7#
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.
12#
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.
17#
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
21#
22
subrata_modak20fff632008-06-28 19:30:19 +000023if 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
27fi
28
29
subrata_modak1d1937a2008-05-13 10:44:02 +000030test_setup()
31{
32 #######################################################################
33 ## Configure
34 #######################################################################
35 dopts='-dEBb'
36
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
43
44 #######################################################################
45 ## Initialize some variables
46 #######################################################################
47 TCID="$0"
48 TST_COUNT=0
49
50 test_dirs=( move bind rbind regression ) #cloneNS
51 nfailed=0
52 nsucceeded=0
53
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}"
61 fi
Chris Dearman37550cf2012-10-17 19:54:01 -070062
yaberauneyaf94a46d2009-12-22 03:28:25 +000063 FS_BIND_ROOT="${LTPROOT}/testcases/bin/fs_bind"
subrata_modak1d1937a2008-05-13 10:44:02 +000064
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}
70
71 # set the PATH to include testcases/bin
72 LTPBIN="${LTPROOT}/testcases/bin"
73 PATH="${PATH}:/usr/sbin:${LTPBIN}:${FS_BIND_ROOT}/bin"
74
75 # Results directory
76 resdir="${LTPROOT}/results/fs_bind"
77 if [ ! -d "${resdir}" ]; then
Chris Dearman37550cf2012-10-17 19:54:01 -070078 mkdir -p "${resdir}" 2> /dev/null
subrata_modak1d1937a2008-05-13 10:44:02 +000079 fi
80
81 TMPDIR="${TMPDIR:-/tmp}"
82 # A temporary directory where we can do stuff and that is
83 # safe to remove
84 sandbox="${TMPDIR}/sandbox"
Chris Dearman37550cf2012-10-17 19:54:01 -070085
subrata_modak1d1937a2008-05-13 10:44:02 +000086 ERR_MSG=""
87
88 export LTPBIN PATH FS_BIND_ROOT ERR_MSG TCID TST_COUNT TST_TOTAL
89
90 if [ ! -d "${resdir}" ]; then
91 tst_brkm TBROK true "$0: failed to make results directory"
92 exit 1
93 fi
94}
95
96test_prereqs()
97{
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
102 fi
103
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
108 fi
109
DAN LI0390eb42013-04-09 15:57:52 +0800110 mount --bind "${sandbox}" "${sandbox}" >& /dev/null
111 if [ $? -ne 0 ]; then
112 tst_brkm TBROK true "$0: failed to perform bind mount on directory \"${sandbox}\""
113 exit 1
114 fi
115
116 mount --make-private "${sandbox}" >& /dev/null
117 if [ $? -ne 0 ]; then
118 tst_brkm TBROK true "$0: failed to make private mountpoint on directory \"${sandbox}\""
119 exit 1
120 fi
121
subrata_modak1d1937a2008-05-13 10:44:02 +0000122 local mnt_bind=1
123 local mnt_move=1
124
125 pushd "${sandbox}" > /dev/null && {
126 mkdir bind_test move_test && {
127 mount --bind bind_test bind_test && {
128 mnt_bind=0
129 mount --move bind_test move_test && {
130 mnt_move=0
131 umount move_test
132 } || {
133 # bind mount succeeded but move mount
134 # failed
135 umount bind_test
136 }
137 } || {
138 # mount failed -- check if it's because we
139 # don't have privileges we need
140 if [ $? -eq 32 ]; then
141 tst_brkm TBROK true "$0 requires the privilege to use the mount command"
142 exit 32
143 fi
144 }
145 rmdir bind_test move_test
146 }
147 popd > /dev/null
148 }
149
150 if [ ${mnt_bind} -eq 1 -o ${mnt_move} -eq 1 ]; then
151 tst_brkm TBROK true "$0: requires that mount support the --bind and --move options"
152 exit 1
153 fi
154
subrata_modak454dad42008-06-14 07:50:49 +0000155 tst_kvercmp 2 6 15
156 X=$?
157 if [ $X -lt 0 ]; then
158 tst_brkm TBROK "$0: failed to get the running kernel version"
159 exit 1
160 elif [ $X -lt 1 ]; then
161 tst_resm TWARN "$0: the remaining tests require 2.6.15 or later"
162 tst_exit 0
163 exit
164 else
165 tst_resm TINFO "$0: kernel >= 2.6.15 detected -- continuing"
166 fi
167
DAN LI0390eb42013-04-09 15:57:52 +0800168 mount --make-shared "${sandbox}" > /dev/null 2>&1 || "${FS_BIND_ROOT}/bin/smount" "${sandbox}" shared
169 umount "${sandbox}" || {
170 tst_resm TFAIL "$0: failed to umount simplest shared subtree"
subrata_modak1d1937a2008-05-13 10:44:02 +0000171 exit 1
172 }
subrata_modak1d1937a2008-05-13 10:44:02 +0000173 tst_resm TPASS "$0: umounted simplest shared subtree"
174
subrata_modak1d1937a2008-05-13 10:44:02 +0000175}
176
177# mounts we are concerned with in a well-defined order (helps diff)
178# returns grep return codes
179grep_proc_mounts()
180{
181 local rc=0
Chris Dearman37550cf2012-10-17 19:54:01 -0700182
subrata_modak1d1937a2008-05-13 10:44:02 +0000183 # Save the pipefail shell option
184 shopt -o -q pipefail
185 local save=$?
186 set -o pipefail
187
188 # Grep /proc/mounts which is often more up-to-date than mounts
189 # We use pipefail because if the grep fails we want to pass that along
190 grep -F "${sandbox}" /proc/mounts | sort -b
191 rc=$?
192
193 # Restore the pipefail shell options
194 [ $save -eq 0 ] && shopt -o -s pipefail || shopt -o -u pipefail
195
196 return $rc
197}
198
199# Record the mount state
200save_proc_mounts()
201{
202 touch "$2/proc_mounts.before" >& /dev/null
203 if [ $? -ne 0 ]; then
204 tst_brkm TBROK true "$1: failed to record proc mounts"
205 return 1
206 fi
207
208 grep_proc_mounts 2> /dev/null > "$2/proc_mounts.before"
209 return 0
210}
211
212# Compare mount list after the test with the list from before.
213# If there are no differences then remove the before list and silently
214# return 0. Else print the differences to stderr and return 1.
215check_proc_mounts()
216{
217 local tname="$1"
218
219 if [ ! -r "$2/proc_mounts.before" ]; then
220 tst_brkm TBROK true "${tname}: Could not find pre-test proc mount list"
221 return 1
222 fi
223
224 grep_proc_mounts 2> /dev/null > "$2/proc_mounts.after"
225 # If the mounts are the same then just return
226 diff ${dopts} -q "$2/proc_mounts.before" "$2/proc_mounts.after" >& /dev/null
227 if [ $? -eq 0 ]; then
228 [ $rm_ok -eq 1 ] && rm -f "$2/proc_mounts."{before,after}
229 return 0
230 fi
231
232 tst_resm TWARN "${tname}: did not properly clean up its proc mounts"
233 diff ${dopts} -U 0 "$2/proc_mounts.before" "$2/proc_mounts.after" | grep -vE '^\@\@' 1>&2
234 [ $rm_err -eq 1 ] && rm -f "$2/proc_mounts."{before,after}
235 return 1
236}
237
238# Undo leftover mounts
239restore_proc_mounts()
240{
241 #local tname="$1"
242
243 # do lazy umounts -- we're assuming that tests will only leave
244 # new mounts around and will never remove mounts outside the test
245 # directory
246 ( while grep_proc_mounts ; do
Rishikesh K Rajakd9f3d252010-04-26 13:19:40 +0530247 grep_proc_mounts | awk '{print $2}' | xargs -r -n 1 umount -l
subrata_modak1d1937a2008-05-13 10:44:02 +0000248 done ) >& /dev/null
Chris Dearman37550cf2012-10-17 19:54:01 -0700249
subrata_modak1d1937a2008-05-13 10:44:02 +0000250 # mount list and exit with 0
251 [ $rm_err -eq 1 ] && rm -f "$2/proc_mounts."{before,after} 1>&2 # >& /dev/null
252 return 0
253 # if returning error do this:
254 # tst_brkm TBROK true "${tname}: failed to restore mounts"
255}
256
257# mounts we are concerned with in a well-defined order (helps diff)
258# returns grep return codes
259grep_mounts()
260{
261 local rc=0
Chris Dearman37550cf2012-10-17 19:54:01 -0700262
subrata_modak1d1937a2008-05-13 10:44:02 +0000263 # Save the pipefail shell option
264 shopt -o -q pipefail
265 local save=$?
266 set -o pipefail
267
268 # Grep mount command output (which tends to come from /etc/mtab)
269 # We use pipefail because if the grep fails we want to pass that along
270 mount | grep -F "${sandbox}" | sort -b
271 rc=$?
272
273 # Restore the pipefail shell options
274 [ $save -eq 0 ] && shopt -o -s pipefail || shopt -o -u pipefail
275
276 return $rc
277}
278
279# Record the mount state
280save_mounts()
281{
282 touch "$2/mtab.before" >& /dev/null
283 if [ $? -ne 0 ]; then
284 tst_brkm TBROK true "$1: failed to record mtab mounts"
285 return 1
286 fi
287
288 grep_mounts 2> /dev/null > "$2/mtab.before"
289 return 0
290}
291
292# Compare mount list after the test with the list from before.
293# If there are no differences then remove the before list and silently
294# return 0. Else print the differences to stderr and return 1.
295check_mounts()
296{
297 local tname="$1"
298
299 if [ ! -r "$2/mtab.before" ]; then
300 tst_brkm TBROK true "${tname}: Could not find pre-test mtab mount list"
301 return 1
302 fi
303
304 grep_mounts 2> /dev/null > "$2/mtab.after"
305 # If the mounts are the same then just return
306 diff ${dopts} -q "$2/mtab.before" "$2/mtab.after" >& /dev/null
307 if [ $? -eq 0 ]; then
308 [ $rm_ok -eq 1 ] && rm -f "$2/mtab."{before,after}
309 return 0
310 fi
311
312 tst_resm TWARN "${tname}: did not properly clean up its mtab mounts"
313 diff ${dopts} -U 0 "$2/mtab.before" "$2/mtab.after" | grep -vE '^\@\@' 1>&2
314 [ $rm_err -eq 1 ] && rm -f "$2/mtab."{before,after}
315 return 1
316}
317
318# Undo leftover mounts
319restore_mounts()
320{
321 #local tname="$1"
322
323 # do lazy umounts -- we're assuming that tests will only leave
324 # new mounts around and will never remove mounts outside the test
325 # directory
326 ( while grep_mounts ; do
Andrew Chen78950272011-06-30 14:19:41 +0800327 grep_mounts | awk '{print $3}' | xargs -r -n 1 umount -l
subrata_modak1d1937a2008-05-13 10:44:02 +0000328 done ) >& /dev/null
329
330 # mount list and exit with 0
331 [ $rm_err -eq 1 ] && rm -f "$2/mtab."{before,after} 1>&2 # >& /dev/null
332 return 0
333 # if returning error do this:
334 # tst_brkm TBROK true "${tname}: failed to restore mounts"
335}
336
337# Record the sandbox state
338# We don't save full sandbox state -- just the names of files and dirs present
339save_sandbox()
340{
341 local when="before"
342 local tname="$1"
343
344 if [ -e "$2/files.before" ]; then
345 if [ -e "$2/files.after" ]; then
346 tst_brkm TBROK true "${tname}: stale catalog of \"${sandbox}\""
347 return 1
348 fi
349 when="after"
350 fi
351
352 ( find "${sandbox}" -type d -print | sort > "$2/dirs.$when"
353 find "${sandbox}" -type f -print | sort | \
354 grep -vE '^'"$2"'/(dirs|files)\.(before|after)$' > "$2/files.$when" ) >& /dev/null
355 return 0
356}
357
358# Save sandbox after test and then compare. If the sandbox state is not
359# clean then print the differences to stderr and return 1. Else remove all
360# saved sandbox state and silently return 0
361check_sandbox()
362{
363 local tname="$1"
364
365 if [ ! -r "$2/files.before" -o ! -r "$2/dirs.before" ]; then
366 tst_brkm TBROK true "${tname} missing saved catalog of \"${sandbox}\""
367 return 1
368 fi
369
370 save_sandbox "${tname} (check)" "$2"
371
372 ( diff ${dopts} -q "$2/dirs.before" "$2/dirs.after" && \
373 diff ${dopts} -q "$2/files.before" "$2/files.after" ) >& /dev/null \
374 && {
375 [ $rm_ok -eq 1 ] && rm -f "$2/"{files,dirs}.{before,after}
376 return 0
377 }
378
379 tst_resm TWARN "${tname} did not properly clean up \"${sandbox}\""
380 diff ${dopts} -U 0 "$2/dirs.before" "$2/dirs.after" 1>&2
381 diff ${dopts} -U 0 "$2/files.before" "$2/files.after" 1>&2
382 [ $rm_err -eq 1 ] && rm -f "$2/"{files,dirs}.{before,after} 1>&2
383 return 1
384}
385
386# Robust sandbox cleanup
387clean_sandbox()
388{
389 local tname="$1"
Chris Dearman37550cf2012-10-17 19:54:01 -0700390
subrata_modak1d1937a2008-05-13 10:44:02 +0000391 { rm -rf "${sandbox}" ; mkdir "${sandbox}" ; } >& /dev/null
392 if [ ! -d "${sandbox}" -o ! -x "${sandbox}" ]; then
393 tst_brkm TBROK true "$tname: failed to make directory \"${sandbox}\""
394 return 1
395 fi
396 return 0
397}
398
399# Check file for non-whitespace chars
400is_file_empty()
401{
402 awk '/^[[:space:]]*$/ { next }
403 { exit 1; }' < "$1"
404}
405
406#
407# Run the specified test script.
408#
409# Return 1 if the test was broken but should not stop the remaining test
410# categories from being run.
411# Return 2 if the test was broken and no further tests should be run.
412# Return 0 otherwise (if the test was broken but it shouldn't affect other
413# test runs)
414# Note that this means the return status is not the success or failure of the
415# test itself.
Chris Dearman37550cf2012-10-17 19:54:01 -0700416#
subrata_modak1d1937a2008-05-13 10:44:02 +0000417run_test()
418{
419 local t="$1"
420 local tname="$(basename "$(dirname "$t")")/$(basename "$t")"
421 local log="$resdir/$tname/log"
422 local errlog="$resdir/$tname/err"
423 local do_break=0
424
425 ERR_MSG=""
426
427 # Pre-test
428 mkdir -p "$resdir/$tname"
429 if [ ! -d "$resdir/$tname" -o ! -x "$resdir/$tname" ]; then
430 tst_brkm TBROK true "$0: can't make or use \"$resdir/$tname\" as a log directory"
431 return 1
432 fi
433
434 save_sandbox "$tname" "$resdir/$tname" || do_break=1
435 save_mounts "$tname" "$resdir/$tname" || do_break=1
436 save_proc_mounts "$tname" "$resdir/$tname" || do_break=1
DAN LI0390eb42013-04-09 15:57:52 +0800437 mount --bind "${sandbox}" "${sandbox}" >& /dev/null || do_break=1
438 mount --make-private "${sandbox}" >& /dev/null || do_break=1
439
subrata_modak1d1937a2008-05-13 10:44:02 +0000440 if [ $do_break -eq 1 ]; then
441 tst_brkm TBROK true "$tname: failed to save pre-test state of \"${sandbox}\""
442 return 2
443 fi
444 pushd "${sandbox}" > /dev/null
445
446 # Run the test
447 (
448 TCID="$tname"
449 declare -r TST_COUNT
450 export LTPBIN PATH FS_BIND_ROOT ERR_MSG TCID TST_COUNT TST_TOTAL
451 "$t" #> "$log" 2> "$errlog"
452 )
453 local rc=$?
454 TCID="$0"
455
456 # Post-test
457 popd > /dev/null
458 if [ $rc -ne 0 ]; then
459 #echo "FAILED"
460 ((nfailed++))
461 else
462 #echo "SUCCEEDED"
463 ((nsucceeded++))
464 fi
DAN LI0390eb42013-04-09 15:57:52 +0800465 umount -l "${sandbox}" >& /dev/null
subrata_modak1d1937a2008-05-13 10:44:02 +0000466 check_proc_mounts "$tname" "$resdir/$tname" || \
467 restore_proc_mounts "$tname" "$resdir/$tname" || do_break=1
468 check_mounts "$tname" "$resdir/$tname" || \
469 restore_mounts "$tname" "$resdir/$tname" || do_break=1
470 check_sandbox "$tname" "$resdir/$tname"
471 clean_sandbox "$tname" || do_break=1
472 if [ $do_break -eq 1 ]; then
473 tst_brkm TBROK true "$tname: failed to restore pre-test state of \"${sandbox}\""
474 return 2
475 fi
476
477 # If we succeeded and the error log is empty remove it
478 if [ $rc -eq 0 -a -w "$errlog" ] && is_file_empty "$errlog" ; then
479 rm -f "$errlog"
480 fi
481 return 0
482}
483
484main()
485{
486 TST_COUNT=1
487 for dir in "${test_dirs[@]}" ; do
488 tests=( $(find "${FS_BIND_ROOT}/${dir}" -type f -name 'test*') )
489 clean_sandbox "$0" || break
490 for t in "${tests[@]}" ; do
491 run_test "$t"
492 local rc=$?
493
494 if [ $rc -ne 0 ]; then
495 break $rc
496 fi
497
498 ((TST_COUNT++))
499 done
500 done
501 rm -rf "${sandbox}"
502 return 0
503
504 skipped=$((total - nsucceeded - nfailed))
505 if [ $nfailed -eq 0 -a $skipped -eq 0 ]; then
506 # Use PASSED for the summary rather than SUCCEEDED to make it
507 # easy to determine 100% success from a calling script
508 summary="PASSED"
509 else
510 # Use FAILED to make it easy to find > 0% failure from a
511 # calling script
512 summary="FAILED"
513 fi
514 cat - <<-EOF
515 *********************************
516 RESULTS SUMMARY:
517
518 passed: $nsucceeded/$total
519 failed: $nfailed/$total
520 skipped: $skipped/$total
521 summary: $summary
522
523 *********************************
524 EOF
525}
526
527test_setup || exit 1
528test_prereqs || exit 1
529declare -r FS_BIND_ROOT
530declare -r TST_TOTAL
531main #2> "$resdir/errors" 1> "$resdir/summary"