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