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