Home | History | Annotate | Download | only in sysctl
      1 #!/bin/bash
      2 # Copyright (C) 2017 Luis R. Rodriguez <mcgrof (at] kernel.org>
      3 #
      4 # This program is free software; you can redistribute it and/or modify it
      5 # under the terms of the GNU General Public License as published by the Free
      6 # Software Foundation; either version 2 of the License, or at your option any
      7 # later version; or, when distributed separately from the Linux kernel or
      8 # when incorporated into other software packages, subject to the following
      9 # license:
     10 #
     11 # This program is free software; you can redistribute it and/or modify it
     12 # under the terms of copyleft-next (version 0.3.1 or later) as published
     13 # at http://copyleft-next.org/.
     14 
     15 # This performs a series tests against the proc sysctl interface.
     16 
     17 TEST_NAME="sysctl"
     18 TEST_DRIVER="test_${TEST_NAME}"
     19 TEST_DIR=$(dirname $0)
     20 TEST_FILE=$(mktemp)
     21 
     22 # This represents
     23 #
     24 # TEST_ID:TEST_COUNT:ENABLED
     25 #
     26 # TEST_ID: is the test id number
     27 # TEST_COUNT: number of times we should run the test
     28 # ENABLED: 1 if enabled, 0 otherwise
     29 #
     30 # Once these are enabled please leave them as-is. Write your own test,
     31 # we have tons of space.
     32 ALL_TESTS="0001:1:1"
     33 ALL_TESTS="$ALL_TESTS 0002:1:1"
     34 ALL_TESTS="$ALL_TESTS 0003:1:1"
     35 ALL_TESTS="$ALL_TESTS 0004:1:1"
     36 ALL_TESTS="$ALL_TESTS 0005:3:1"
     37 
     38 test_modprobe()
     39 {
     40        if [ ! -d $DIR ]; then
     41                echo "$0: $DIR not present" >&2
     42                echo "You must have the following enabled in your kernel:" >&2
     43                cat $TEST_DIR/config >&2
     44                exit 1
     45        fi
     46 }
     47 
     48 function allow_user_defaults()
     49 {
     50 	if [ -z $DIR ]; then
     51 		DIR="/sys/module/test_sysctl/"
     52 	fi
     53 	if [ -z $DEFAULT_NUM_TESTS ]; then
     54 		DEFAULT_NUM_TESTS=50
     55 	fi
     56 	if [ -z $SYSCTL ]; then
     57 		SYSCTL="/proc/sys/debug/test_sysctl"
     58 	fi
     59 	if [ -z $PROD_SYSCTL ]; then
     60 		PROD_SYSCTL="/proc/sys"
     61 	fi
     62 	if [ -z $WRITES_STRICT ]; then
     63 		WRITES_STRICT="${PROD_SYSCTL}/kernel/sysctl_writes_strict"
     64 	fi
     65 }
     66 
     67 function check_production_sysctl_writes_strict()
     68 {
     69 	echo -n "Checking production write strict setting ... "
     70 	if [ ! -e ${WRITES_STRICT} ]; then
     71 		echo "FAIL, but skip in case of old kernel" >&2
     72 	else
     73 		old_strict=$(cat ${WRITES_STRICT})
     74 		if [ "$old_strict" = "1" ]; then
     75 			echo "ok"
     76 		else
     77 			echo "FAIL, strict value is 0 but force to 1 to continue" >&2
     78 			echo "1" > ${WRITES_STRICT}
     79 		fi
     80 	fi
     81 
     82 	if [ -z $PAGE_SIZE ]; then
     83 		PAGE_SIZE=$(getconf PAGESIZE)
     84 	fi
     85 	if [ -z $MAX_DIGITS ]; then
     86 		MAX_DIGITS=$(($PAGE_SIZE/8))
     87 	fi
     88 	if [ -z $INT_MAX ]; then
     89 		INT_MAX=$(getconf INT_MAX)
     90 	fi
     91 	if [ -z $UINT_MAX ]; then
     92 		UINT_MAX=$(getconf UINT_MAX)
     93 	fi
     94 }
     95 
     96 test_reqs()
     97 {
     98 	uid=$(id -u)
     99 	if [ $uid -ne 0 ]; then
    100 		echo $msg must be run as root >&2
    101 		exit 0
    102 	fi
    103 
    104 	if ! which perl 2> /dev/null > /dev/null; then
    105 		echo "$0: You need perl installed"
    106 		exit 1
    107 	fi
    108 	if ! which getconf 2> /dev/null > /dev/null; then
    109 		echo "$0: You need getconf installed"
    110 		exit 1
    111 	fi
    112 	if ! which diff 2> /dev/null > /dev/null; then
    113 		echo "$0: You need diff installed"
    114 		exit 1
    115 	fi
    116 }
    117 
    118 function load_req_mod()
    119 {
    120 	trap "test_modprobe" EXIT
    121 
    122 	if [ ! -d $DIR ]; then
    123 		modprobe $TEST_DRIVER
    124 		if [ $? -ne 0 ]; then
    125 			exit
    126 		fi
    127 	fi
    128 }
    129 
    130 reset_vals()
    131 {
    132 	VAL=""
    133 	TRIGGER=$(basename ${TARGET})
    134 	case "$TRIGGER" in
    135 		int_0001)
    136 			VAL="60"
    137 			;;
    138 		int_0002)
    139 			VAL="1"
    140 			;;
    141 		uint_0001)
    142 			VAL="314"
    143 			;;
    144 		string_0001)
    145 			VAL="(none)"
    146 			;;
    147 		*)
    148 			;;
    149 	esac
    150 	echo -n $VAL > $TARGET
    151 }
    152 
    153 set_orig()
    154 {
    155 	if [ ! -z $TARGET ]; then
    156 		echo "${ORIG}" > "${TARGET}"
    157 	fi
    158 }
    159 
    160 set_test()
    161 {
    162 	echo "${TEST_STR}" > "${TARGET}"
    163 }
    164 
    165 verify()
    166 {
    167 	local seen
    168 	seen=$(cat "$1")
    169 	if [ "${seen}" != "${TEST_STR}" ]; then
    170 		return 1
    171 	fi
    172 	return 0
    173 }
    174 
    175 verify_diff_w()
    176 {
    177 	echo "$TEST_STR" | diff -q -w -u - $1
    178 	return $?
    179 }
    180 
    181 test_rc()
    182 {
    183 	if [[ $rc != 0 ]]; then
    184 		echo "Failed test, return value: $rc" >&2
    185 		exit $rc
    186 	fi
    187 }
    188 
    189 test_finish()
    190 {
    191 	set_orig
    192 	rm -f "${TEST_FILE}"
    193 
    194 	if [ ! -z ${old_strict} ]; then
    195 		echo ${old_strict} > ${WRITES_STRICT}
    196 	fi
    197 	exit $rc
    198 }
    199 
    200 run_numerictests()
    201 {
    202 	echo "== Testing sysctl behavior against ${TARGET} =="
    203 
    204 	rc=0
    205 
    206 	echo -n "Writing test file ... "
    207 	echo "${TEST_STR}" > "${TEST_FILE}"
    208 	if ! verify "${TEST_FILE}"; then
    209 		echo "FAIL" >&2
    210 		exit 1
    211 	else
    212 		echo "ok"
    213 	fi
    214 
    215 	echo -n "Checking sysctl is not set to test value ... "
    216 	if verify "${TARGET}"; then
    217 		echo "FAIL" >&2
    218 		exit 1
    219 	else
    220 		echo "ok"
    221 	fi
    222 
    223 	echo -n "Writing sysctl from shell ... "
    224 	set_test
    225 	if ! verify "${TARGET}"; then
    226 		echo "FAIL" >&2
    227 		exit 1
    228 	else
    229 		echo "ok"
    230 	fi
    231 
    232 	echo -n "Resetting sysctl to original value ... "
    233 	set_orig
    234 	if verify "${TARGET}"; then
    235 		echo "FAIL" >&2
    236 		exit 1
    237 	else
    238 		echo "ok"
    239 	fi
    240 
    241 	# Now that we've validated the sanity of "set_test" and "set_orig",
    242 	# we can use those functions to set starting states before running
    243 	# specific behavioral tests.
    244 
    245 	echo -n "Writing entire sysctl in single write ... "
    246 	set_orig
    247 	dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null
    248 	if ! verify "${TARGET}"; then
    249 		echo "FAIL" >&2
    250 		rc=1
    251 	else
    252 		echo "ok"
    253 	fi
    254 
    255 	echo -n "Writing middle of sysctl after synchronized seek ... "
    256 	set_test
    257 	dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null
    258 	if ! verify "${TARGET}"; then
    259 		echo "FAIL" >&2
    260 		rc=1
    261 	else
    262 		echo "ok"
    263 	fi
    264 
    265 	echo -n "Writing beyond end of sysctl ... "
    266 	set_orig
    267 	dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null
    268 	if verify "${TARGET}"; then
    269 		echo "FAIL" >&2
    270 		rc=1
    271 	else
    272 		echo "ok"
    273 	fi
    274 
    275 	echo -n "Writing sysctl with multiple long writes ... "
    276 	set_orig
    277 	(perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \
    278 		dd of="${TARGET}" bs=50 2>/dev/null
    279 	if verify "${TARGET}"; then
    280 		echo "FAIL" >&2
    281 		rc=1
    282 	else
    283 		echo "ok"
    284 	fi
    285 	test_rc
    286 }
    287 
    288 # Your test must accept digits 3 and 4 to use this
    289 run_limit_digit()
    290 {
    291 	echo -n "Checking ignoring spaces up to PAGE_SIZE works on write ..."
    292 	reset_vals
    293 
    294 	LIMIT=$((MAX_DIGITS -1))
    295 	TEST_STR="3"
    296 	(perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
    297 		dd of="${TARGET}" 2>/dev/null
    298 
    299 	if ! verify "${TARGET}"; then
    300 		echo "FAIL" >&2
    301 		rc=1
    302 	else
    303 		echo "ok"
    304 	fi
    305 	test_rc
    306 
    307 	echo -n "Checking passing PAGE_SIZE of spaces fails on write ..."
    308 	reset_vals
    309 
    310 	LIMIT=$((MAX_DIGITS))
    311 	TEST_STR="4"
    312 	(perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
    313 		dd of="${TARGET}" 2>/dev/null
    314 
    315 	if verify "${TARGET}"; then
    316 		echo "FAIL" >&2
    317 		rc=1
    318 	else
    319 		echo "ok"
    320 	fi
    321 	test_rc
    322 }
    323 
    324 # You are using an int
    325 run_limit_digit_int()
    326 {
    327 	echo -n "Testing INT_MAX works ..."
    328 	reset_vals
    329 	TEST_STR="$INT_MAX"
    330 	echo -n $TEST_STR > $TARGET
    331 
    332 	if ! verify "${TARGET}"; then
    333 		echo "FAIL" >&2
    334 		rc=1
    335 	else
    336 		echo "ok"
    337 	fi
    338 	test_rc
    339 
    340 	echo -n "Testing INT_MAX + 1 will fail as expected..."
    341 	reset_vals
    342 	let TEST_STR=$INT_MAX+1
    343 	echo -n $TEST_STR > $TARGET 2> /dev/null
    344 
    345 	if verify "${TARGET}"; then
    346 		echo "FAIL" >&2
    347 		rc=1
    348 	else
    349 		echo "ok"
    350 	fi
    351 	test_rc
    352 
    353 	echo -n "Testing negative values will work as expected..."
    354 	reset_vals
    355 	TEST_STR="-3"
    356 	echo -n $TEST_STR > $TARGET 2> /dev/null
    357 	if ! verify "${TARGET}"; then
    358 		echo "FAIL" >&2
    359 		rc=1
    360 	else
    361 		echo "ok"
    362 	fi
    363 	test_rc
    364 }
    365 
    366 # You used an int array
    367 run_limit_digit_int_array()
    368 {
    369 	echo -n "Testing array works as expected ... "
    370 	TEST_STR="4 3 2 1"
    371 	echo -n $TEST_STR > $TARGET
    372 
    373 	if ! verify_diff_w "${TARGET}"; then
    374 		echo "FAIL" >&2
    375 		rc=1
    376 	else
    377 		echo "ok"
    378 	fi
    379 	test_rc
    380 
    381 	echo -n "Testing skipping trailing array elements works ... "
    382 	# Do not reset_vals, carry on the values from the last test.
    383 	# If we only echo in two digits the last two are left intact
    384 	TEST_STR="100 101"
    385 	echo -n $TEST_STR > $TARGET
    386 	# After we echo in, to help diff we need to set on TEST_STR what
    387 	# we expect the result to be.
    388 	TEST_STR="100 101 2 1"
    389 
    390 	if ! verify_diff_w "${TARGET}"; then
    391 		echo "FAIL" >&2
    392 		rc=1
    393 	else
    394 		echo "ok"
    395 	fi
    396 	test_rc
    397 
    398 	echo -n "Testing PAGE_SIZE limit on array works ... "
    399 	# Do not reset_vals, carry on the values from the last test.
    400 	# Even if you use an int array, you are still restricted to
    401 	# MAX_DIGITS, this is a known limitation. Test limit works.
    402 	LIMIT=$((MAX_DIGITS -1))
    403 	TEST_STR="9"
    404 	(perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
    405 		dd of="${TARGET}" 2>/dev/null
    406 
    407 	TEST_STR="9 101 2 1"
    408 	if ! verify_diff_w "${TARGET}"; then
    409 		echo "FAIL" >&2
    410 		rc=1
    411 	else
    412 		echo "ok"
    413 	fi
    414 	test_rc
    415 
    416 	echo -n "Testing exceeding PAGE_SIZE limit fails as expected ... "
    417 	# Do not reset_vals, carry on the values from the last test.
    418 	# Now go over limit.
    419 	LIMIT=$((MAX_DIGITS))
    420 	TEST_STR="7"
    421 	(perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
    422 		dd of="${TARGET}" 2>/dev/null
    423 
    424 	TEST_STR="7 101 2 1"
    425 	if verify_diff_w "${TARGET}"; then
    426 		echo "FAIL" >&2
    427 		rc=1
    428 	else
    429 		echo "ok"
    430 	fi
    431 	test_rc
    432 }
    433 
    434 # You are using an unsigned int
    435 run_limit_digit_uint()
    436 {
    437 	echo -n "Testing UINT_MAX works ..."
    438 	reset_vals
    439 	TEST_STR="$UINT_MAX"
    440 	echo -n $TEST_STR > $TARGET
    441 
    442 	if ! verify "${TARGET}"; then
    443 		echo "FAIL" >&2
    444 		rc=1
    445 	else
    446 		echo "ok"
    447 	fi
    448 	test_rc
    449 
    450 	echo -n "Testing UINT_MAX + 1 will fail as expected..."
    451 	reset_vals
    452 	TEST_STR=$(($UINT_MAX+1))
    453 	echo -n $TEST_STR > $TARGET 2> /dev/null
    454 
    455 	if verify "${TARGET}"; then
    456 		echo "FAIL" >&2
    457 		rc=1
    458 	else
    459 		echo "ok"
    460 	fi
    461 	test_rc
    462 
    463 	echo -n "Testing negative values will not work as expected ..."
    464 	reset_vals
    465 	TEST_STR="-3"
    466 	echo -n $TEST_STR > $TARGET 2> /dev/null
    467 
    468 	if verify "${TARGET}"; then
    469 		echo "FAIL" >&2
    470 		rc=1
    471 	else
    472 		echo "ok"
    473 	fi
    474 	test_rc
    475 }
    476 
    477 run_stringtests()
    478 {
    479 	echo -n "Writing entire sysctl in short writes ... "
    480 	set_orig
    481 	dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null
    482 	if ! verify "${TARGET}"; then
    483 		echo "FAIL" >&2
    484 		rc=1
    485 	else
    486 		echo "ok"
    487 	fi
    488 
    489 	echo -n "Writing middle of sysctl after unsynchronized seek ... "
    490 	set_test
    491 	dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null
    492 	if verify "${TARGET}"; then
    493 		echo "FAIL" >&2
    494 		rc=1
    495 	else
    496 		echo "ok"
    497 	fi
    498 
    499 	echo -n "Checking sysctl maxlen is at least $MAXLEN ... "
    500 	set_orig
    501 	perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \
    502 		dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
    503 	if ! grep -q B "${TARGET}"; then
    504 		echo "FAIL" >&2
    505 		rc=1
    506 	else
    507 		echo "ok"
    508 	fi
    509 
    510 	echo -n "Checking sysctl keeps original string on overflow append ... "
    511 	set_orig
    512 	perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
    513 		dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null
    514 	if grep -q B "${TARGET}"; then
    515 		echo "FAIL" >&2
    516 		rc=1
    517 	else
    518 		echo "ok"
    519 	fi
    520 
    521 	echo -n "Checking sysctl stays NULL terminated on write ... "
    522 	set_orig
    523 	perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
    524 		dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
    525 	if grep -q B "${TARGET}"; then
    526 		echo "FAIL" >&2
    527 		rc=1
    528 	else
    529 		echo "ok"
    530 	fi
    531 
    532 	echo -n "Checking sysctl stays NULL terminated on overwrite ... "
    533 	set_orig
    534 	perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \
    535 		dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null
    536 	if grep -q B "${TARGET}"; then
    537 		echo "FAIL" >&2
    538 		rc=1
    539 	else
    540 		echo "ok"
    541 	fi
    542 
    543 	test_rc
    544 }
    545 
    546 sysctl_test_0001()
    547 {
    548 	TARGET="${SYSCTL}/int_0001"
    549 	reset_vals
    550 	ORIG=$(cat "${TARGET}")
    551 	TEST_STR=$(( $ORIG + 1 ))
    552 
    553 	run_numerictests
    554 	run_limit_digit
    555 }
    556 
    557 sysctl_test_0002()
    558 {
    559 	TARGET="${SYSCTL}/string_0001"
    560 	reset_vals
    561 	ORIG=$(cat "${TARGET}")
    562 	TEST_STR="Testing sysctl"
    563 	# Only string sysctls support seeking/appending.
    564 	MAXLEN=65
    565 
    566 	run_numerictests
    567 	run_stringtests
    568 }
    569 
    570 sysctl_test_0003()
    571 {
    572 	TARGET="${SYSCTL}/int_0002"
    573 	reset_vals
    574 	ORIG=$(cat "${TARGET}")
    575 	TEST_STR=$(( $ORIG + 1 ))
    576 
    577 	run_numerictests
    578 	run_limit_digit
    579 	run_limit_digit_int
    580 }
    581 
    582 sysctl_test_0004()
    583 {
    584 	TARGET="${SYSCTL}/uint_0001"
    585 	reset_vals
    586 	ORIG=$(cat "${TARGET}")
    587 	TEST_STR=$(( $ORIG + 1 ))
    588 
    589 	run_numerictests
    590 	run_limit_digit
    591 	run_limit_digit_uint
    592 }
    593 
    594 sysctl_test_0005()
    595 {
    596 	TARGET="${SYSCTL}/int_0003"
    597 	reset_vals
    598 	ORIG=$(cat "${TARGET}")
    599 
    600 	run_limit_digit_int_array
    601 }
    602 
    603 list_tests()
    604 {
    605 	echo "Test ID list:"
    606 	echo
    607 	echo "TEST_ID x NUM_TEST"
    608 	echo "TEST_ID:   Test ID"
    609 	echo "NUM_TESTS: Number of recommended times to run the test"
    610 	echo
    611 	echo "0001 x $(get_test_count 0001) - tests proc_dointvec_minmax()"
    612 	echo "0002 x $(get_test_count 0002) - tests proc_dostring()"
    613 	echo "0003 x $(get_test_count 0003) - tests proc_dointvec()"
    614 	echo "0004 x $(get_test_count 0004) - tests proc_douintvec()"
    615 	echo "0005 x $(get_test_count 0005) - tests proc_douintvec() array"
    616 }
    617 
    618 test_reqs
    619 
    620 usage()
    621 {
    622 	NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .)
    623 	let NUM_TESTS=$NUM_TESTS+1
    624 	MAX_TEST=$(printf "%04d\n" $NUM_TESTS)
    625 	echo "Usage: $0 [ -t <4-number-digit> ] | [ -w <4-number-digit> ] |"
    626 	echo "		 [ -s <4-number-digit> ] | [ -c <4-number-digit> <test- count>"
    627 	echo "           [ all ] [ -h | --help ] [ -l ]"
    628 	echo ""
    629 	echo "Valid tests: 0001-$MAX_TEST"
    630 	echo ""
    631 	echo "    all     Runs all tests (default)"
    632 	echo "    -t      Run test ID the number amount of times is recommended"
    633 	echo "    -w      Watch test ID run until it runs into an error"
    634 	echo "    -c      Run test ID once"
    635 	echo "    -s      Run test ID x test-count number of times"
    636 	echo "    -l      List all test ID list"
    637 	echo " -h|--help  Help"
    638 	echo
    639 	echo "If an error every occurs execution will immediately terminate."
    640 	echo "If you are adding a new test try using -w <test-ID> first to"
    641 	echo "make sure the test passes a series of tests."
    642 	echo
    643 	echo Example uses:
    644 	echo
    645 	echo "$TEST_NAME.sh            -- executes all tests"
    646 	echo "$TEST_NAME.sh -t 0002    -- Executes test ID 0002 number of times is recomended"
    647 	echo "$TEST_NAME.sh -w 0002    -- Watch test ID 0002 run until an error occurs"
    648 	echo "$TEST_NAME.sh -s 0002    -- Run test ID 0002 once"
    649 	echo "$TEST_NAME.sh -c 0002 3  -- Run test ID 0002 three times"
    650 	echo
    651 	list_tests
    652 	exit 1
    653 }
    654 
    655 function test_num()
    656 {
    657 	re='^[0-9]+$'
    658 	if ! [[ $1 =~ $re ]]; then
    659 		usage
    660 	fi
    661 }
    662 
    663 function get_test_count()
    664 {
    665 	test_num $1
    666 	TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
    667 	LAST_TWO=${TEST_DATA#*:*}
    668 	echo ${LAST_TWO%:*}
    669 }
    670 
    671 function get_test_enabled()
    672 {
    673 	test_num $1
    674 	TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
    675 	echo ${TEST_DATA#*:*:}
    676 }
    677 
    678 function run_all_tests()
    679 {
    680 	for i in $ALL_TESTS ; do
    681 		TEST_ID=${i%:*:*}
    682 		ENABLED=$(get_test_enabled $TEST_ID)
    683 		TEST_COUNT=$(get_test_count $TEST_ID)
    684 		if [[ $ENABLED -eq "1" ]]; then
    685 			test_case $TEST_ID $TEST_COUNT
    686 		fi
    687 	done
    688 }
    689 
    690 function watch_log()
    691 {
    692 	if [ $# -ne 3 ]; then
    693 		clear
    694 	fi
    695 	date
    696 	echo "Running test: $2 - run #$1"
    697 }
    698 
    699 function watch_case()
    700 {
    701 	i=0
    702 	while [ 1 ]; do
    703 
    704 		if [ $# -eq 1 ]; then
    705 			test_num $1
    706 			watch_log $i ${TEST_NAME}_test_$1
    707 			${TEST_NAME}_test_$1
    708 		else
    709 			watch_log $i all
    710 			run_all_tests
    711 		fi
    712 		let i=$i+1
    713 	done
    714 }
    715 
    716 function test_case()
    717 {
    718 	NUM_TESTS=$DEFAULT_NUM_TESTS
    719 	if [ $# -eq 2 ]; then
    720 		NUM_TESTS=$2
    721 	fi
    722 
    723 	i=0
    724 	while [ $i -lt $NUM_TESTS ]; do
    725 		test_num $1
    726 		watch_log $i ${TEST_NAME}_test_$1 noclear
    727 		RUN_TEST=${TEST_NAME}_test_$1
    728 		$RUN_TEST
    729 		let i=$i+1
    730 	done
    731 }
    732 
    733 function parse_args()
    734 {
    735 	if [ $# -eq 0 ]; then
    736 		run_all_tests
    737 	else
    738 		if [[ "$1" = "all" ]]; then
    739 			run_all_tests
    740 		elif [[ "$1" = "-w" ]]; then
    741 			shift
    742 			watch_case $@
    743 		elif [[ "$1" = "-t" ]]; then
    744 			shift
    745 			test_num $1
    746 			test_case $1 $(get_test_count $1)
    747 		elif [[ "$1" = "-c" ]]; then
    748 			shift
    749 			test_num $1
    750 			test_num $2
    751 			test_case $1 $2
    752 		elif [[ "$1" = "-s" ]]; then
    753 			shift
    754 			test_case $1 1
    755 		elif [[ "$1" = "-l" ]]; then
    756 			list_tests
    757 		elif [[ "$1" = "-h" || "$1" = "--help" ]]; then
    758 			usage
    759 		else
    760 			usage
    761 		fi
    762 	fi
    763 }
    764 
    765 test_reqs
    766 allow_user_defaults
    767 check_production_sysctl_writes_strict
    768 load_req_mod
    769 
    770 trap "test_finish" EXIT
    771 
    772 parse_args $@
    773 
    774 exit 0
    775