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