• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-or-later
3# Copyright (c) Linux Test Project, 2014-2022
4# Author: Cyril Hrubis <chrubis@suse.cz>
5#
6# LTP test library for shell.
7
8[ -n "$TST_LIB_LOADED" ] && return 0
9
10export TST_PASS=0
11export TST_FAIL=0
12export TST_BROK=0
13export TST_WARN=0
14export TST_CONF=0
15export TST_COUNT=1
16export TST_ITERATIONS=1
17export TST_TMPDIR_RHOST=0
18export TST_LIB_LOADED=1
19
20if [ -z "$TST_FS_TYPE" ]; then
21	export TST_FS_TYPE="${LTP_DEV_FS_TYPE:-ext2}"
22fi
23
24. tst_ansi_color.sh
25. tst_security.sh
26
27# default trap function
28trap "tst_brk TBROK 'test interrupted'" INT
29trap "unset _tst_setup_timer_pid; tst_brk TBROK 'test terminated'" TERM
30
31_tst_do_cleanup()
32{
33	if [ -n "$TST_DO_CLEANUP" -a -n "$TST_CLEANUP" -a -z "$TST_NO_CLEANUP" ]; then
34		if command -v $TST_CLEANUP >/dev/null 2>/dev/null; then
35			$TST_CLEANUP
36		else
37			tst_res TWARN "TST_CLEANUP=$TST_CLEANUP declared, but function not defined (or cmd not found)"
38		fi
39	fi
40	TST_DO_CLEANUP=
41}
42
43_tst_do_exit()
44{
45	local ret=0
46	TST_DO_EXIT=1
47
48	_tst_do_cleanup
49
50	cd "$LTPROOT"
51	[ "$TST_MOUNT_FLAG" = 1 ] && tst_umount
52
53	if [ "$TST_NEEDS_DEVICE" = 1 -a "$TST_DEVICE_FLAG" = 1 ]; then
54		if ! tst_device release "$TST_DEVICE"; then
55			tst_res TWARN "Failed to release device '$TST_DEVICE'"
56		fi
57	fi
58
59	if [ "$TST_NEEDS_TMPDIR" = 1 -a -n "$TST_TMPDIR" ]; then
60		rm -r "$TST_TMPDIR"
61		[ "$TST_TMPDIR_RHOST" = 1 ] && tst_cleanup_rhost
62	fi
63
64	if [ -n "$TST_NEEDS_CHECKPOINTS" -a -f "$LTP_IPC_PATH" ]; then
65		rm $LTP_IPC_PATH
66	fi
67
68	_tst_cleanup_timer
69
70	if [ $TST_FAIL -gt 0 ]; then
71		ret=$((ret|1))
72	fi
73
74	if [ $TST_BROK -gt 0 ]; then
75		ret=$((ret|2))
76	fi
77
78	if [ $TST_WARN -gt 0 ]; then
79		ret=$((ret|4))
80	fi
81
82	if [ $TST_CONF -gt 0 -a $TST_PASS -eq 0 ]; then
83		ret=$((ret|32))
84	fi
85
86	if [ $TST_BROK -gt 0 -o $TST_FAIL -gt 0 -o $TST_WARN -gt 0 ]; then
87		_tst_check_security_modules
88	fi
89
90	cat >&2 << EOF
91
92Summary:
93passed   $TST_PASS
94failed   $TST_FAIL
95broken   $TST_BROK
96skipped  $TST_CONF
97warnings $TST_WARN
98EOF
99
100	exit $ret
101}
102
103_tst_inc_res()
104{
105	case "$1" in
106	TPASS) TST_PASS=$((TST_PASS+1));;
107	TFAIL) TST_FAIL=$((TST_FAIL+1));;
108	TBROK) TST_BROK=$((TST_BROK+1));;
109	TWARN) TST_WARN=$((TST_WARN+1));;
110	TCONF) TST_CONF=$((TST_CONF+1));;
111	TINFO) ;;
112	*) tst_brk TBROK "Invalid res type '$1'";;
113	esac
114}
115
116tst_res()
117{
118	local res=$1
119	shift
120
121	_tst_inc_res "$res"
122
123	printf "$TST_ID $TST_COUNT " >&2
124	tst_print_colored $res "$res: " >&2
125	echo "$@" >&2
126}
127
128tst_brk()
129{
130	local res=$1
131	shift
132
133	if [ "$TST_DO_EXIT" = 1 ]; then
134		tst_res TWARN "$@"
135		return
136	fi
137
138	tst_res "$res" "$@"
139	_tst_do_exit
140}
141
142ROD_SILENT()
143{
144	local tst_out
145
146	tst_out="$(tst_rod $@ 2>&1)"
147	if [ $? -ne 0 ]; then
148		echo "$tst_out"
149		tst_brk TBROK "$@ failed"
150	fi
151}
152
153ROD()
154{
155	tst_rod "$@"
156	if [ $? -ne 0 ]; then
157		tst_brk TBROK "$@ failed"
158	fi
159}
160
161_tst_expect_pass()
162{
163	local fnc="$1"
164	shift
165
166	tst_rod "$@"
167	if [ $? -eq 0 ]; then
168		tst_res TPASS "$@ passed as expected"
169		return 0
170	else
171		$fnc TFAIL "$@ failed unexpectedly"
172		return 1
173	fi
174}
175
176_tst_expect_fail()
177{
178	local fnc="$1"
179	shift
180
181	# redirect stderr since we expect the command to fail
182	tst_rod "$@" 2> /dev/null
183	if [ $? -ne 0 ]; then
184		tst_res TPASS "$@ failed as expected"
185		return 0
186	else
187		$fnc TFAIL "$@ passed unexpectedly"
188		return 1
189	fi
190}
191
192EXPECT_PASS()
193{
194	_tst_expect_pass tst_res "$@"
195}
196
197EXPECT_PASS_BRK()
198{
199	_tst_expect_pass tst_brk "$@"
200}
201
202EXPECT_FAIL()
203{
204	_tst_expect_fail tst_res "$@"
205}
206
207EXPECT_FAIL_BRK()
208{
209	_tst_expect_fail tst_brk "$@"
210}
211
212TST_RETRY_FN_EXP_BACKOFF()
213{
214	local tst_fun="$1"
215	local tst_exp=$2
216	local tst_sec=$(($3 * 1000000))
217	local tst_delay=1
218
219	_tst_multiply_timeout tst_sec
220
221	if [ $# -ne 3 ]; then
222		tst_brk TBROK "TST_RETRY_FN_EXP_BACKOFF expects 3 parameters"
223	fi
224
225	if ! tst_is_int "$tst_sec"; then
226		tst_brk TBROK "TST_RETRY_FN_EXP_BACKOFF: tst_sec must be integer ('$tst_sec')"
227	fi
228
229	while true; do
230		eval "$tst_fun"
231		if [ "$?" = "$tst_exp" ]; then
232			break
233		fi
234
235		if [ $tst_delay -lt $tst_sec ]; then
236			tst_sleep ${tst_delay}us
237			tst_delay=$((tst_delay*2))
238		else
239			tst_brk TBROK "\"$tst_fun\" timed out"
240		fi
241	done
242
243	return $tst_exp
244}
245
246TST_RETRY_FUNC()
247{
248	if [ $# -ne 2 ]; then
249		tst_brk TBROK "TST_RETRY_FUNC expects 2 parameters"
250	fi
251
252	TST_RETRY_FN_EXP_BACKOFF "$1" "$2" 1
253	return $2
254}
255
256TST_RTNL_CHK()
257{
258	local msg1="RTNETLINK answers: Function not implemented"
259	local msg2="RTNETLINK answers: Operation not supported"
260	local msg3="RTNETLINK answers: Protocol not supported"
261	local output="$($@ 2>&1 || echo 'LTP_ERR')"
262	local msg
263
264	echo "$output" | grep -q "LTP_ERR" || return 0
265
266	for msg in "$msg1" "$msg2" "$msg3"; do
267		echo "$output" | grep -q "$msg" && tst_brk TCONF "'$@': $msg"
268	done
269
270	tst_brk TBROK "$@ failed: $output"
271}
272
273TST_CHECKPOINT_WAIT()
274{
275	ROD tst_checkpoint wait 10000 "$1"
276}
277
278TST_CHECKPOINT_WAKE()
279{
280	ROD tst_checkpoint wake 10000 "$1" 1
281}
282
283TST_CHECKPOINT_WAKE2()
284{
285	ROD tst_checkpoint wake 10000 "$1" "$2"
286}
287
288TST_CHECKPOINT_WAKE_AND_WAIT()
289{
290	TST_CHECKPOINT_WAKE "$1"
291	TST_CHECKPOINT_WAIT "$1"
292}
293
294tst_mount()
295{
296	local mnt_opt mnt_err mnt_real
297
298	if [ -n "$TST_FS_TYPE" ]; then
299		mnt_opt="-t $TST_FS_TYPE"
300		mnt_err=" $TST_FS_TYPE type"
301	fi
302	local cmd="mount $mnt_opt $TST_DEVICE $TST_MNTPOINT $TST_MNT_PARAMS"
303
304	ROD_SILENT mkdir -p $TST_MNTPOINT
305	tst_res TINFO "Mounting device: $cmd"
306	$cmd
307	local ret=$?
308
309	if [ $ret -eq 32 ]; then
310		tst_brk TCONF "Cannot mount${mnt_err}, missing driver?"
311	fi
312
313	if [ $ret -ne 0 ]; then
314		tst_brk TBROK "Failed to mount device${mnt_err}: mount exit = $ret"
315	fi
316}
317
318tst_umount()
319{
320	local mntpoint="${1:-$TST_MNTPOINT}"
321	local i=0
322
323	[ -z "$mntpoint" ] && return
324
325	if ! echo "$mntpoint" | grep -q ^/; then
326		tst_brk TCONF "The '$mntpoint' is not an absolute path"
327	fi
328
329	if ! grep -q "${mntpoint%/}" /proc/mounts; then
330		tst_res TINFO "The '$mntpoint' is not mounted, skipping umount"
331		return
332	fi
333
334	while [ "$i" -lt 50 ]; do
335		if umount "$mntpoint" > /dev/null; then
336			return
337		fi
338
339		i=$((i+1))
340
341		tst_res TINFO "umount($mntpoint) failed, try $i ..."
342		tst_res TINFO "Likely gvfsd-trash is probing newly mounted "\
343		              "fs, kill it to speed up tests."
344
345		tst_sleep 100ms
346	done
347
348	tst_res TWARN "Failed to umount($mntpoint) after 50 retries"
349}
350
351tst_mkfs()
352{
353	local opts
354	local fs_type=${1:-$TST_FS_TYPE}
355	[ $# -ge 1 ] && shift
356
357	opts="$@"
358
359	if [ "$fs_type" = tmpfs ]; then
360		tst_res TINFO "Skipping mkfs for TMPFS filesystem"
361		return
362	fi
363
364	if [ -z "$opts" ]; then
365		if [ "$TST_NEEDS_DEVICE" != 1 ]; then
366			tst_brk "Using default parameters in tst_mkfs requires TST_NEEDS_DEVICE=1"
367		fi
368		opts="$TST_DEVICE"
369	fi
370
371	tst_require_cmds mkfs.$fs_type
372
373	tst_res TINFO "Formatting $fs_type with opts='$opts'"
374	ROD_SILENT mkfs.$fs_type $opts
375}
376
377# Detect whether running under hypervisor: Microsoft Hyper-V
378# Return 0: running under Hyper-V
379# Return 1: not running under Hyper-V (bare metal, other hypervisor or
380#           failure of detection)
381tst_virt_hyperv()
382{
383	local v
384
385	tst_cmd_available systemd-detect-virt || return 1
386
387	v="$(systemd-detect-virt)"
388
389	[ $? -eq 0 ] || return 1
390	[ "$v" = "microsoft" ] || return 1
391
392	return 0
393}
394
395tst_cmd_available()
396{
397	command -v $1 >/dev/null 2>&1
398}
399
400tst_require_cmds()
401{
402	local cmd
403	for cmd in $*; do
404		tst_cmd_available $cmd || tst_brk TCONF "'$cmd' not found"
405	done
406}
407
408tst_check_cmds()
409{
410	local cmd
411	for cmd in $*; do
412		if ! tst_cmd_available $cmd; then
413			tst_res TCONF "'$cmd' not found"
414			return 1
415		fi
416	done
417	return 0
418}
419
420tst_require_drivers()
421{
422	[ $# -eq 0 ] && return 0
423
424	local drv
425
426	drv="$(tst_check_drivers $@ 2>&1)"
427
428	[ $? -ne 0 ] && tst_brk TCONF "$drv driver not available"
429	return 0
430}
431
432tst_require_kconfigs()
433{
434	local delim
435
436	if [ $# -gt 2 ]; then
437		return 0
438	elif [ $# -eq 1 ]; then
439		delim="$TST_NEEDS_KCONFIGS_IFS"
440	else
441		delim="$2"
442	fi
443
444	[ -z "$1" ] && return 0
445
446	tst_check_kconfigs "$1" "$delim" > /dev/null
447
448	[ $? -ne 0 ] && tst_brk TCONF "Aborting due to unsuitable kernel config, see above!"
449	return 0
450}
451
452tst_is_int()
453{
454	[ "$1" -eq "$1" ] 2>/dev/null
455	return $?
456}
457
458tst_is_num()
459{
460	echo "$1" | grep -Eq '^[-+]?[0-9]+\.?[0-9]*$'
461}
462
463tst_usage()
464{
465	if [ -n "$TST_USAGE" ]; then
466		$TST_USAGE
467	else
468		echo "usage: $0"
469		echo
470		echo "Options"
471		echo "-------"
472	fi
473
474	echo "-h      Prints this help"
475	echo "-i n    Execute test n times"
476
477	cat << EOF
478
479Environment Variables
480---------------------
481KCONFIG_PATH         Specify kernel config file
482KCONFIG_SKIP_CHECK   Skip kernel config check if variable set (not set by default)
483LTPROOT              Prefix for installed LTP (default: /opt/ltp)
484LTP_COLORIZE_OUTPUT  Force colorized output behaviour (y/1 always, n/0: never)
485LTP_DEV              Path to the block device to be used (for .needs_device)
486LTP_DEV_FS_TYPE      Filesystem used for testing (default: ext2)
487LTP_SINGLE_FS_TYPE   Testing only - specifies filesystem instead all supported (for TST_ALL_FILESYSTEMS=1)
488LTP_TIMEOUT_MUL      Timeout multiplier (must be a number >=1, ceiled to int)
489TMPDIR               Base directory for template directory (for .needs_tmpdir, default: /tmp)
490EOF
491}
492
493_tst_resstr()
494{
495	echo "$TST_PASS$TST_FAIL$TST_CONF"
496}
497
498_tst_rescmp()
499{
500	local res=$(_tst_resstr)
501
502	if [ "$1" = "$res" ]; then
503		tst_brk TBROK "Test didn't report any results"
504	fi
505}
506
507_tst_multiply_timeout()
508{
509	[ $# -ne 1 ] && tst_brk TBROK "_tst_multiply_timeout expect 1 parameter"
510	eval "local timeout=\$$1"
511
512	LTP_TIMEOUT_MUL=${LTP_TIMEOUT_MUL:-1}
513
514	local err="LTP_TIMEOUT_MUL must be number >= 1!"
515
516	tst_is_num "$LTP_TIMEOUT_MUL" || tst_brk TBROK "$err ($LTP_TIMEOUT_MUL)"
517
518	if ! tst_is_int "$LTP_TIMEOUT_MUL"; then
519		LTP_TIMEOUT_MUL=$(echo "$LTP_TIMEOUT_MUL" | cut -d. -f1)
520		LTP_TIMEOUT_MUL=$((LTP_TIMEOUT_MUL+1))
521		tst_res TINFO "ceiling LTP_TIMEOUT_MUL to $LTP_TIMEOUT_MUL"
522	fi
523
524	[ "$LTP_TIMEOUT_MUL" -ge 1 ] || tst_brk TBROK "$err ($LTP_TIMEOUT_MUL)"
525	[ "$timeout" -ge 1 ] || tst_brk TBROK "timeout need to be >= 1 ($timeout)"
526
527	eval "$1='$((timeout * LTP_TIMEOUT_MUL))'"
528	return 0
529}
530
531_tst_cleanup_timer()
532{
533	if [ -n "$_tst_setup_timer_pid" ]; then
534		kill -TERM $_tst_setup_timer_pid 2>/dev/null
535		# kill is succesful only on test timeout
536		wait $_tst_setup_timer_pid 2>/dev/null || true
537	fi
538}
539
540_tst_setup_timer()
541{
542	TST_TIMEOUT=${TST_TIMEOUT:-300}
543
544	if [ "$TST_TIMEOUT" = -1 ]; then
545		tst_res TINFO "Timeout per run is disabled"
546		return
547	fi
548
549	if ! tst_is_int "$TST_TIMEOUT" || [ "$TST_TIMEOUT" -lt 1 ]; then
550		tst_brk TBROK "TST_TIMEOUT must be int >= 1! ($TST_TIMEOUT)"
551	fi
552
553	local sec=$TST_TIMEOUT
554	_tst_multiply_timeout sec
555	local h=$((sec / 3600))
556	local m=$((sec / 60 % 60))
557	local s=$((sec % 60))
558	local pid=$$
559
560	tst_res TINFO "timeout per run is ${h}h ${m}m ${s}s"
561
562	_tst_cleanup_timer
563
564	tst_timeout_kill $sec $pid &
565
566	_tst_setup_timer_pid=$!
567
568	while true; do
569		local state
570
571		state=$(cut -d' ' -f3 "/proc/$_tst_setup_timer_pid/stat")
572
573		if [ "$state" = "S" ]; then
574			break;
575		fi
576
577		tst_sleep 1ms
578	done
579}
580
581tst_require_root()
582{
583	if [ "$(id -ru)" != 0 ]; then
584		tst_brk TCONF "Must be super/root for this test!"
585	fi
586}
587
588tst_require_module()
589{
590	local _tst_module=$1
591
592	for tst_module in "$_tst_module" \
593	                  "$LTPROOT/testcases/bin/$_tst_module" \
594	                  "$TST_STARTWD/$_tst_module"; do
595
596			if [ -f "$tst_module" ]; then
597				TST_MODPATH="$tst_module"
598				break
599			fi
600	done
601
602	if [ -z "$TST_MODPATH" ]; then
603		tst_brk TCONF "Failed to find module '$_tst_module'"
604	fi
605
606	tst_res TINFO "Found module at '$TST_MODPATH'"
607}
608
609tst_set_timeout()
610{
611	TST_TIMEOUT="$1"
612	_tst_setup_timer
613}
614
615_tst_init_checkpoints()
616{
617	local pagesize
618
619	LTP_IPC_PATH="/dev/shm/ltp_${TST_ID}_$$"
620	pagesize=$(tst_getconf PAGESIZE)
621	if [ $? -ne 0 ]; then
622		tst_brk TBROK "tst_getconf PAGESIZE failed"
623	fi
624	ROD_SILENT dd if=/dev/zero of="$LTP_IPC_PATH" bs="$pagesize" count=1
625	ROD_SILENT chmod 600 "$LTP_IPC_PATH"
626	export LTP_IPC_PATH
627}
628
629_prepare_device()
630{
631	if [ "$TST_FORMAT_DEVICE" = 1 ]; then
632		tst_device clear "$TST_DEVICE"
633		tst_mkfs $TST_FS_TYPE $TST_DEV_FS_OPTS $TST_DEVICE $TST_DEV_EXTRA_OPTS
634	fi
635
636	if [ "$TST_MOUNT_DEVICE" = 1 ]; then
637		tst_mount
638		TST_MOUNT_FLAG=1
639	fi
640}
641
642_tst_run_tcases_per_fs()
643{
644	local fs
645	local filesystems
646
647	filesystems="$(tst_supported_fs -s "$TST_SKIP_FILESYSTEMS")"
648	if [ $? -ne 0 ]; then
649		tst_brk TCONF "There are no supported filesystems or all skipped"
650	fi
651
652	for fs in $filesystems; do
653		tst_res TINFO "=== Testing on $fs ==="
654		TST_FS_TYPE="$fs"
655		_tst_run_iterations
656	done
657}
658
659tst_run()
660{
661	local _tst_i
662	local _tst_data
663	local _tst_max
664	local _tst_name
665	local _tst_pattern='[='\''"} \t\/:`$\;|].*'
666	local ret
667
668	if [ -n "$TST_TEST_PATH" ]; then
669		for _tst_i in $(grep '^[^#]*\bTST_' "$TST_TEST_PATH" | sed "s/.*TST_//; s/$_tst_pattern//"); do
670			case "$_tst_i" in
671			ALL_FILESYSTEMS|DISABLE_APPARMOR|DISABLE_SELINUX);;
672			SETUP|CLEANUP|TESTFUNC|ID|CNT|MIN_KVER);;
673			OPTS|USAGE|PARSE_ARGS|POS_ARGS);;
674			NEEDS_ROOT|NEEDS_TMPDIR|TMPDIR|NEEDS_DEVICE|DEVICE);;
675			NEEDS_CMDS|NEEDS_MODULE|MODPATH|DATAROOT);;
676			NEEDS_DRIVERS|FS_TYPE|MNTPOINT|MNT_PARAMS);;
677			NEEDS_KCONFIGS|NEEDS_KCONFIGS_IFS);;
678			IPV6|IPV6_FLAG|IPVER|TEST_DATA|TEST_DATA_IFS);;
679			RETRY_FUNC|RETRY_FN_EXP_BACKOFF|TIMEOUT);;
680			NET_DATAROOT|NET_MAX_PKT|NET_RHOST_RUN_DEBUG|NETLOAD_CLN_NUMBER);;
681			NET_SKIP_VARIABLE_INIT|NEEDS_CHECKPOINTS);;
682			CHECKPOINT_WAIT|CHECKPOINT_WAKE);;
683			CHECKPOINT_WAKE2|CHECKPOINT_WAKE_AND_WAIT);;
684			DEV_EXTRA_OPTS|DEV_FS_OPTS|FORMAT_DEVICE|MOUNT_DEVICE);;
685			SKIP_FILESYSTEMS);;
686			*) tst_res TWARN "Reserved variable TST_$_tst_i used!";;
687			esac
688		done
689
690		for _tst_i in $(grep '^[^#]*\b_tst_' "$TST_TEST_PATH" | sed "s/.*_tst_//; s/$_tst_pattern//"); do
691			tst_res TWARN "Private variable or function _tst_$_tst_i used!"
692		done
693	fi
694
695	if ! tst_is_int "$TST_ITERATIONS"; then
696		tst_brk TBROK "Expected number (-i) not '$TST_ITERATIONS'"
697	fi
698
699	if [ "$TST_ITERATIONS" -lt 0 ]; then
700		tst_brk TBROK "Number of iterations (-i) must be >= 0"
701	fi
702
703	[ "$TST_NEEDS_ROOT" = 1 ] && tst_require_root
704
705	[ "$TST_DISABLE_APPARMOR" = 1 ] && tst_disable_apparmor
706	[ "$TST_DISABLE_SELINUX" = 1 ] && tst_disable_selinux
707
708	tst_require_cmds $TST_NEEDS_CMDS
709	tst_require_kconfigs "$TST_NEEDS_KCONFIGS"
710	tst_require_drivers $TST_NEEDS_DRIVERS
711
712	if [ -n "$TST_MIN_KVER" ]; then
713		tst_kvcmp -lt "$TST_MIN_KVER" && \
714			tst_brk TCONF "test requires kernel $TST_MIN_KVER+"
715	fi
716
717	[ -n "$TST_NEEDS_MODULE" ] && tst_require_module "$TST_NEEDS_MODULE"
718
719	[ "$TST_MOUNT_DEVICE" = 1 ] && TST_FORMAT_DEVICE=1
720	[ "$TST_FORMAT_DEVICE" = 1 -o "$TST_ALL_FILESYSTEMS" = 1 ] && TST_NEEDS_DEVICE=1
721	[ "$TST_NEEDS_DEVICE" = 1 ] && TST_NEEDS_TMPDIR=1
722
723	if [ "$TST_NEEDS_TMPDIR" = 1 ]; then
724		if [ -z "$TMPDIR" ]; then
725			export TMPDIR="/tmp"
726		fi
727
728		TST_TMPDIR=$(mktemp -d "$TMPDIR/LTP_$TST_ID.XXXXXXXXXX")
729
730		chmod 777 "$TST_TMPDIR"
731
732		TST_STARTWD=$(pwd)
733		cd "$TST_TMPDIR"
734	fi
735
736	# needs to be after cd $TST_TMPDIR to keep test_dev.img under $TST_TMPDIR
737	if [ "$TST_NEEDS_DEVICE" = 1 ]; then
738		TST_DEVICE=$(tst_device acquire)
739
740		if [ ! -b "$TST_DEVICE" -o $? -ne 0 ]; then
741			unset TST_DEVICE
742			tst_brk TBROK "Failed to acquire device"
743		fi
744		TST_DEVICE_FLAG=1
745
746		if [ -z "$TST_FS_TYPE" ]; then
747			export TST_FS_TYPE="${LTP_DEV_FS_TYPE:-ext2}"
748		fi
749	fi
750
751	if [ "$TST_ALL_FILESYSTEMS" != 1 -a "$TST_SKIP_FILESYSTEMS" ]; then
752		if ! tst_supported_fs -s "$TST_SKIP_FILESYSTEMS" -d . > /dev/null; then
753			tst_brk TCONF "filesystem is not supported by the test"
754		fi
755
756		tst_res TINFO "filesystem is supported by the test"
757	fi
758
759	[ -n "$TST_NEEDS_CHECKPOINTS" ] && _tst_init_checkpoints
760
761	TST_MNTPOINT="${TST_MNTPOINT:-$PWD/mntpoint}"
762
763	if [ "$TST_ALL_FILESYSTEMS" = 1 ]; then
764		_tst_run_tcases_per_fs
765	else
766		_tst_run_iterations
767	fi
768
769	_tst_do_exit
770}
771
772_tst_run_iterations()
773{
774	local _tst_i=$TST_ITERATIONS
775	local _tst_j
776
777	[ "$TST_NEEDS_TMPDIR" = 1 ] && cd "$TST_TMPDIR"
778
779	_prepare_device
780
781	_tst_setup_timer
782
783	if [ -n "$TST_SETUP" ]; then
784		if command -v $TST_SETUP >/dev/null 2>/dev/null; then
785			TST_DO_CLEANUP=1
786			$TST_SETUP
787		else
788			tst_brk TBROK "TST_SETUP=$TST_SETUP declared, but function not defined (or cmd not found)"
789		fi
790	fi
791
792	#TODO check that test reports some results for each test function call
793	while [ $_tst_i -gt 0 ]; do
794		if [ -n "$TST_TEST_DATA" ]; then
795			tst_require_cmds cut tr wc
796			_tst_max=$(( $(echo $TST_TEST_DATA | tr -cd "$TST_TEST_DATA_IFS" | wc -c) +1))
797			for _tst_j in $(seq $_tst_max); do
798				_tst_data="$(echo "$TST_TEST_DATA" | cut -d"$TST_TEST_DATA_IFS" -f$_tst_j)"
799				_tst_run_tests "$_tst_data"
800			done
801		else
802			_tst_run_tests
803		fi
804		_tst_i=$((_tst_i-1))
805	done
806
807	_tst_do_cleanup
808
809	if [ "$TST_MOUNT_FLAG" = 1 ]; then
810		cd "$LTPROOT"
811		tst_umount
812		TST_MOUNT_FLAG=
813	fi
814}
815
816_tst_run_tests()
817{
818	local _tst_data="$1"
819	local _tst_i
820
821	TST_DO_CLEANUP=1
822	for _tst_i in $(seq ${TST_CNT:-1}); do
823		if command -v ${TST_TESTFUNC}1 > /dev/null 2>&1; then
824			_tst_run_test "$TST_TESTFUNC$_tst_i" $_tst_i "$_tst_data"
825		else
826			_tst_run_test "$TST_TESTFUNC" $_tst_i "$_tst_data"
827		fi
828	done
829}
830
831_tst_run_test()
832{
833	local _tst_res=$(_tst_resstr)
834	local _tst_fnc="$1"
835	shift
836
837	$_tst_fnc "$@"
838	_tst_rescmp "$_tst_res"
839	TST_COUNT=$((TST_COUNT+1))
840}
841
842export LC_ALL=C
843
844if [ -z "$TST_ID" ]; then
845	_tst_filename=$(basename $0) || \
846		tst_brk TCONF "Failed to set TST_ID from \$0 ('$0'), fix it with setting TST_ID before sourcing tst_test.sh"
847	TST_ID=${_tst_filename%%.*}
848fi
849export TST_ID="$TST_ID"
850
851if [ -z "$LTPROOT" ]; then
852	export LTPROOT="$PWD"
853	export TST_DATAROOT="$LTPROOT/datafiles"
854else
855	export TST_DATAROOT="$LTPROOT/testcases/data/$TST_ID"
856fi
857
858if [ -z "$TST_NO_DEFAULT_RUN" ]; then
859	if TST_TEST_PATH=$(command -v $0) 2>/dev/null; then
860		if ! grep -q tst_run "$TST_TEST_PATH"; then
861			tst_brk TBROK "Test $0 must call tst_run!"
862		fi
863	fi
864
865	if [ -z "$TST_TESTFUNC" ]; then
866		tst_brk TBROK "TST_TESTFUNC is not defined"
867	fi
868
869	TST_TEST_DATA_IFS="${TST_TEST_DATA_IFS:- }"
870
871	TST_NEEDS_KCONFIGS_IFS="${TST_NEEDS_KCONFIGS_IFS:-,}"
872
873	if [ -n "$TST_CNT" ]; then
874		if ! tst_is_int "$TST_CNT"; then
875			tst_brk TBROK "TST_CNT must be integer"
876		fi
877
878		if [ "$TST_CNT" -le 0 ]; then
879			tst_brk TBROK "TST_CNT must be > 0"
880		fi
881	fi
882
883	if [ -n "$TST_POS_ARGS" ]; then
884		if ! tst_is_int "$TST_POS_ARGS"; then
885			tst_brk TBROK "TST_POS_ARGS must be integer"
886		fi
887
888		if [ "$TST_POS_ARGS" -le 0 ]; then
889			tst_brk TBROK "TST_POS_ARGS must be > 0"
890		fi
891	fi
892
893	TST_ARGS="$@"
894
895	OPTIND=1
896
897	while getopts ":hi:$TST_OPTS" _tst_name $TST_ARGS; do
898		case $_tst_name in
899		'h') tst_usage; exit 0;;
900		'i') TST_ITERATIONS=$OPTARG;;
901		'?') tst_usage; exit 2;;
902		*) $TST_PARSE_ARGS "$_tst_name" "$OPTARG";;
903		esac
904	done
905
906	shift $((OPTIND - 1))
907
908	if [ -n "$TST_POS_ARGS" ]; then
909		if [ $# -ne "$TST_POS_ARGS" ]; then
910			tst_brk TBROK "Invalid number of positional parameters:"\
911					  "have ($@) $#, expected ${TST_POS_ARGS}"
912		fi
913	else
914		if [ $# -ne 0 ]; then
915			tst_brk TBROK "Unexpected positional arguments '$@'"
916		fi
917	fi
918fi
919