1#!/usr/bin/env bash 2# SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.1 3# Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org> 4 5# Reduce noise by disabling "unreachable" check. 6# shellcheck disable=SC2317 7 8# This performs a series of tests against the proc sysctl interface. 9 10DIR="$(dirname "$(readlink -f "$0")")" 11source "${DIR}"/../kselftest/ktap_helpers.sh 12 13TEST_DRIVER="test_sysctl" 14 15assert_write_rejected() # <file> <value> 16{ 17 local file=$1 val=$2 18 if printf '%s' "$val" > "$file" 2>/dev/null; then 19 ktap_print_msg "$file: write of '$val' succeeded, expected rejection" 20 return 1 21 fi 22 return 0 23} 24 25assert_content() # <file> <want-file> 26{ 27 local file=$1 want_file=$2 got 28 got=$(cat "$file") 29 if [ "$got" == "$want_file" ]; then 30 return 0 31 fi 32 ktap_print_msg "$file: got '$got', want '$want_file'" 33 return 1 34} 35 36# compare ignoring whitespaces 37assert_content_loose() # <file> <want-file> 38{ 39 local file=$1 want_file=$2 40 if echo "$want_file" | diff -q -w -u - "$file" > /dev/null; then 41 return 0 42 fi 43 ktap_print_msg "$file: content does not match '$want_file' (whitespace-insensitive)" 44 return 1 45} 46 47# For checks where writes must NOT take effect 48assert_content_rejected() # <file> <bad> 49{ 50 local file=$1 bad=$2 51 if echo "$bad" | diff -q -w -u - "$file" > /dev/null; then 52 ktap_print_msg "$file: unexpectedly now holds rejected value '$bad'" 53 return 1 54 fi 55 return 0 56} 57 58# proc files get read a page at a time, which can confuse diff resulting in 59# incorrect results. Use a temp file to diff. 60assert_diff_proc_file() # <file> <want-file> 61{ 62 local file=$1 want_file=$2 tmp 63 tmp=$(mktemp) 64 cat "$file" > "$tmp" 65 66 if diff -w -q "$tmp" "$want_file" > /dev/null; then 67 rm -f "$tmp" 68 return 0 69 fi 70 ktap_print_msg "$file: content does not match expected file $want_file" 71 rm -f "$tmp" 72 return 1 73} 74 75# Verify that an erroneous update fails and does not change the baseline. 76assert_no_partial_update() # <file> <baseline> <bad-value> 77{ 78 local file=$1 baseline=$2 bad=$3 79 80 printf '%s' "$baseline" > "$file" 81 assert_write_rejected "$file" "$bad" || return 1 82 assert_content_loose "$file" "$baseline" 83} 84 85assert_grep() # <file> <pattern> - <pattern> must appear in <file> 86{ 87 local file=$1 pattern=$2 88 if grep -q "$pattern" "$file"; then 89 return 0 90 fi 91 ktap_print_msg "$file: pattern '$pattern' not found" 92 return 1 93} 94 95assert_grep_absent() # <file> <pattern> - <pattern> must NOT appear 96{ 97 local file=$1 pattern=$2 98 if ! grep -q "$pattern" "$file"; then 99 return 0 100 fi 101 ktap_print_msg "$file: pattern '$pattern' unexpectedly found" 102 return 1 103} 104 105assert_dmesg_count() # <pattern> <want-count> 106{ 107 local pattern=$1 want=$2 got 108 got=$(dmesg | grep -c "$pattern") 109 if [ "$got" -eq "$want" ]; then 110 return 0 111 fi 112 ktap_print_msg "dmesg: pattern '$pattern' seen $got times, want $want" 113 return 1 114} 115 116# write <str> through dd in <bs>-sized chunks 117write_in_chunks() # <file> <str> <bs> 118{ 119 local file=$1 str=$2 bs=$3 120 printf '%s' "$str" | dd of="$file" bs="$bs" 2>/dev/null 121} 122 123# write <str> through dd in <bs>-sized chunks. seeking <seek> blocks of size 124# <bs> into the output. skipping <skip> blocks of size <bs> from the input. 125# Unsyncrhonized when skip is not passed. 126write_at_offset() # <file> <str> <bs> <seek> [skip] 127{ 128 local file=$1 str=$2 bs=$3 seek=$4 skip=${5:-} 129 if [ -n "$skip" ]; then 130 printf '%s' "$str" | dd of="$file" bs="$bs" seek="$seek" skip="$skip" 2>/dev/null 131 else 132 printf '%s' "$str" | dd of="$file" bs="$bs" seek="$seek" 2>/dev/null 133 fi 134} 135 136# pad (prefix) <str> with <pad> 'A' characters, then write it all to <file> 137# with dd block size <bs> (defaults to <pad>). 138write_overlong() # <file> <pad> <str> [bs] 139{ 140 local file=$1 pad=$2 str=$3 bs=$4 p 141 : "${bs:=$pad}" 142 143 # save a string with $pad spaces in $p 144 printf -v p '%*s' "$pad" '' 145 # replace " " with "A" 146 printf '%s%s' "${p// /A}" "$str" | dd of="$file" bs="$bs" 2>/dev/null 147} 148 149# pad (prefix) <str> with <pad> ASCII spaces, then write with default block size. 150write_padded_digits() # <file> <pad> <val> 151{ 152 local file=$1 pad=$2 val=$3 p 153 printf -v p '%*s' "$pad" '' 154 printf '%s%s' "$p" "$val" | dd of="$file" 2>/dev/null 155} 156 157test_int_array_writes() 158{ 159 local t="${SYSCTL}/int_0003" 160 local limit 161 162 [[ -f "$t" ]] || { RET=$KSFT_SKIP; return; } 163 164 printf '%s' "4 3 2 1" > "$t" 165 assert_content_loose "$t" "4 3 2 1" || RET=$KSFT_FAIL 166 167 # Skipping trailing elements leaves them intact 168 printf '%s' "100 101" > "$t" 169 assert_content_loose "$t" "100 101 2 1" || RET=$KSFT_FAIL 170 171 # Even for an int array, a single write is still capped at MAX_DIGITS 172 # (PAGE_SIZE/8) bytes; check right at, and just past, that boundary. 173 # Carries on the state from the writes above. 174 limit=$((MAX_DIGITS - 1)) 175 write_padded_digits "$t" "$limit" "9" 176 assert_content_loose "$t" "9 101 2 1" || RET=$KSFT_FAIL 177 178 limit=$((MAX_DIGITS)) 179 write_padded_digits "$t" "$limit" "7" 180 assert_content_rejected "$t" "7 101 2 1" || RET=$KSFT_FAIL 181} 182 183test_int_array_no_partial_update() 184{ 185 local t="${SYSCTL}/int_0003" 186 187 [[ -f "$t" ]] || { RET=$KSFT_SKIP; return; } 188 189 # bad 3rd element (not a number) 190 assert_no_partial_update "$t" "1 2 3 4" "10 20 abc 40" || RET=$KSFT_FAIL 191 192 # bad 3rd element (overflows int) 193 assert_no_partial_update "$t" "1 2 3 4" "10 20 $((INT_MAX + 1)) 40" || RET=$KSFT_FAIL 194 195 # bad 1st element 196 assert_no_partial_update "$t" "1 2 3 4" "abc 20 30 40" || RET=$KSFT_FAIL 197} 198 199# Exercise the write patterns 200assert_write_patterns() # <file> <baseline> <val> 201{ 202 local file=$1 baseline=$2 val=$3 status=0 203 204 printf '%s' "$val" > "$file" 205 assert_content "$file" "$val" || status=1 206 printf '%s' "$baseline" > "$file" 207 assert_content "$file" "$baseline" || status=1 208 209 printf '%s' "$baseline" > "$file" 210 write_in_chunks "$file" "$val" 4096 211 assert_content "$file" "$val" || status=1 212 213 printf '%s' "$val" > "$file" 214 write_at_offset "$file" "$val" 1 1 1 215 assert_content "$file" "$val" || status=1 216 217 printf '%s' "$baseline" > "$file" 218 write_at_offset "$file" "$val" 20 2 219 assert_content_rejected "$file" "$val" || status=1 220 221 printf '%s' "$baseline" > "$file" 222 write_overlong "$file" 50 "$val" 223 assert_content_rejected "$file" "$val" || status=1 224 225 return "$status" 226} 227 228# None of these fit in 32 bits, so writing them to an int/uint sysctl must fail 229assert_wideint_writes_rejected() # <file> <baseline> 230{ 231 local file=$1 baseline=$2 sign mag status=0 232 local magnitudes=( 233 0x0000000100000000 234 0x0000000100000001 235 0x00000001ffffffff 236 0x0000000180000000 237 0x000000017fffffff 238 0xffffffff00000000 239 0xffffffff00000001 240 0xffffffffffffffff 241 0xffffffff80000000 242 0xffffffff7fffffff 243 ) 244 245 for sign in '' '-'; do 246 for mag in "${magnitudes[@]}"; do 247 assert_no_partial_update "$file" "$baseline" "${sign}${mag}" || status=1 248 done 249 done 250 return "$status" 251} 252 253# A single write is capped at MAX_DIGITS (PAGE_SIZE/8) bytes; check that 254# leading whitespace up to that limit is ignored, and that PAGE_SIZE of 255# leading whitespace pushes the value past the limit and fails. 256assert_digit_limit() # <file> <baseline> 257{ 258 local file=$1 baseline=$2 status=0 259 260 printf '%s' "$baseline" > "$file" 261 write_padded_digits "$file" "$((MAX_DIGITS - 1))" "3" 262 assert_content "$file" "3" || status=1 263 264 printf '%s' "$baseline" > "$file" 265 write_padded_digits "$file" "$MAX_DIGITS" "4" 266 assert_content_rejected "$file" "4" || status=1 267 268 return "$status" 269} 270 271# proc_dointvec()-specific range checks: INT_MAX must be accepted, INT_MAX+1 272# must be rejected, and negative values must be accepted. 273assert_int_range() # <file> <baseline> 274{ 275 local file=$1 baseline=$2 status=0 276 277 printf '%s' "$baseline" > "$file" 278 printf '%s' "$INT_MAX" > "$file" 279 assert_content "$file" "$INT_MAX" || status=1 280 281 assert_no_partial_update "$file" "$baseline" "$((INT_MAX + 1))" || status=1 282 283 printf '%s' "$baseline" > "$file" 284 printf '%s' "-3" > "$file" 2>/dev/null 285 assert_content "$file" "-3" || status=1 286 287 return "$status" 288} 289 290# proc_douintvec()-specific range checks: UINT_MAX must be accepted, 291# UINT_MAX+1 must be rejected, and negative values must be rejected too. 292assert_uint_range() # <file> <baseline> 293{ 294 local file=$1 baseline=$2 status=0 295 296 printf '%s' "$baseline" > "$file" 297 printf '%s' "$UINT_MAX" > "$file" 298 assert_content "$file" "$UINT_MAX" || status=1 299 300 assert_no_partial_update "$file" "$baseline" "$((UINT_MAX + 1))" || status=1 301 assert_no_partial_update "$file" "$baseline" "-3" || status=1 302 303 return "$status" 304} 305 306test_int_minmax() 307{ 308 local t="${SYSCTL}/int_0001" 309 local baseline="60" val="61" 310 311 [[ -f "$t" ]] || { RET=$KSFT_SKIP; return; } 312 313 assert_write_patterns "$t" "$baseline" "$val" || RET=$KSFT_FAIL 314 assert_wideint_writes_rejected "$t" "$baseline" || RET=$KSFT_FAIL 315 assert_digit_limit "$t" "$baseline" || RET=$KSFT_FAIL 316} 317 318test_int_plain() 319{ 320 local t="${SYSCTL}/int_0002" 321 local baseline="1" val="2" 322 323 [[ -f "$t" ]] || { RET=$KSFT_SKIP; return; } 324 325 assert_write_patterns "$t" "$baseline" "$val" || RET=$KSFT_FAIL 326 assert_wideint_writes_rejected "$t" "$baseline" || RET=$KSFT_FAIL 327 assert_digit_limit "$t" "$baseline" || RET=$KSFT_FAIL 328 assert_int_range "$t" "$baseline" || RET=$KSFT_FAIL 329} 330 331# The jiffies converters report the sign separately from the magnitude, so a 332# negative value must survive the round trip through the converter. Each 333# value below is chosen to convert exactly at every CONFIG_HZ. 334test_int_jiffies_negative() 335{ 336 local t="${SYSCTL}/int_jiffies" 337 local m="${SYSCTL}/int_ms_jiffies" 338 local u="${SYSCTL}/int_userhz_jiffies" 339 340 [[ -f "$t" && -f "$m" && -f "$u" ]] || { RET=$KSFT_SKIP; return; } 341 342 printf '%s' "-1" > "$t" 343 assert_content "$t" "-1" || RET=$KSFT_FAIL 344 printf '%s' "-1000" > "$m" 345 assert_content "$m" "-1000" || RET=$KSFT_FAIL 346 printf '%s' "-100" > "$u" 347 assert_content "$u" "-100" || RET=$KSFT_FAIL 348 349 # The positive path was never broken; keep it covered. 350 printf '%s' "1" > "$t" 351 assert_content "$t" "1" || RET=$KSFT_FAIL 352} 353 354test_uint_plain() 355{ 356 local t="${SYSCTL}/uint_0001" 357 local baseline="314" val="315" 358 359 [[ -f "$t" ]] || { RET=$KSFT_SKIP; return; } 360 361 assert_write_patterns "$t" "$baseline" "$val" || RET=$KSFT_FAIL 362 assert_wideint_writes_rejected "$t" "$baseline" || RET=$KSFT_FAIL 363 assert_digit_limit "$t" "$baseline" || RET=$KSFT_FAIL 364 assert_uint_range "$t" "$baseline" || RET=$KSFT_FAIL 365} 366 367# proc_dostring()-specific write patterns 368assert_string_write_patterns() # <file> <baseline> <val> <maxlen> 369{ 370 local file=$1 baseline=$2 val=$3 maxlen=$4 status=0 371 372 printf '%s' "$baseline" > "$file" 373 write_in_chunks "$file" "$val" 1 374 assert_content "$file" "$val" || status=1 375 376 printf '%s' "$val" > "$file" 377 write_at_offset "$file" "$val" 1 1 378 assert_content_rejected "$file" "$val" || status=1 379 380 # sysctl maxlen is at least $maxlen 381 printf '%s' "$baseline" > "$file" 382 write_overlong "$file" "$((maxlen - 2))" "B" "$maxlen" 383 assert_grep "$file" "B" || status=1 384 385 # keep original string on overflow append 386 printf '%s' "$baseline" > "$file" 387 write_overlong "$file" "$((maxlen - 1))" "B" "$((maxlen - 1))" 388 assert_grep_absent "$file" "B" || status=1 389 390 # sysctl stays NULL terminated on write 391 printf '%s' "$baseline" > "$file" 392 write_overlong "$file" "$((maxlen - 1))" "B" "$maxlen" 393 assert_grep_absent "$file" "B" || status=1 394 395 # sysctl stays NULL terminated on overwrite 396 printf '%s' "$baseline" > "$file" 397 write_overlong "$file" "$((maxlen - 1))" "BB" "$((maxlen + 1))" 398 assert_grep_absent "$file" "B" || status=1 399 400 return "$status" 401} 402 403test_string_dostring() 404{ 405 local t="${SYSCTL}/string_0001" 406 local baseline="(none)" val="Testing sysctl" maxlen=65 407 408 [[ -f "$t" ]] || { RET=$KSFT_SKIP; return; } 409 410 assert_write_patterns "$t" "$baseline" "$val" || RET=$KSFT_FAIL 411 assert_string_write_patterns "$t" "$baseline" "$val" "$maxlen" || RET=$KSFT_FAIL 412} 413 414# Emit a random sysctl bit map 415random_bitmap_spec() 416{ 417 local length=$((RANDOM % 65000)) 418 local bit=$((RANDOM % 1024)) 419 local spec=$bit 420 local range_end 421 422 while [ "${#spec}" -le "$length" ]; do 423 # Keep entries discontiguous, skip ahead by at least 2. 424 bit=$((bit + 2 + RANDOM % 10)) 425 spec="${spec},${bit}" 426 427 if [ "$((RANDOM % 2))" -eq 1 ]; then 428 range_end=$((bit + 1 + RANDOM % 10)) 429 spec="${spec}-${range_end}" 430 bit=$range_end 431 fi 432 done 433 434 echo -n "$spec" 435} 436 437# Do *not* prefix with "test_". All autogenerate bitmap tests call this helper 438bitmap_range_check_once() # <iter> 439{ 440 local t="${SYSCTL}/bitmap_0001" 441 local spec_file seed 442 443 [[ -f "$t" ]] || { RET=$KSFT_SKIP; return; } 444 445 seed=$((BITMAP_SEED + $1)) 446 RANDOM=$seed 447 448 spec_file=$(mktemp) 449 random_bitmap_spec > "$spec_file" 450 451 if ! cat "$spec_file" > "$t" 2>/dev/null; then 452 ktap_print_msg "$t: write of random bitmap spec rejected (seed $seed)" 453 RET=$KSFT_FAIL 454 elif ! assert_diff_proc_file "$t" "$spec_file"; then 455 ktap_print_msg "$t: readback mismatch (seed $seed)" 456 RET=$KSFT_FAIL 457 fi 458 459 rm -f "$spec_file" 460} 461 462test_unregister_removes_dir() 463{ 464 local t="${SYSCTL}/unregister_error" 465 466 if [[ -d "$t" ]]; then 467 ktap_print_msg "$t: directory still exists, expected it to be unregistered" 468 RET=$KSFT_FAIL 469 fi 470} 471 472test_mount_point_error() 473{ 474 local t="${SYSCTL}/mnt/mnt_error" 475 476 if [[ -d "$t" ]]; then 477 ktap_print_msg "$t: directory unexpectedly created" 478 RET=$KSFT_FAIL 479 fi 480} 481 482test_empty_dir_registration() 483{ 484 local t="${SYSCTL}/empty_add" 485 486 if [[ ! -d "$t" ]]; then 487 ktap_print_msg "$t: directory was not created" 488 RET=$KSFT_FAIL 489 return 490 fi 491 if [[ ! -d "$t/empty" ]]; then 492 ktap_print_msg "$t/empty: directory was not created" 493 RET=$KSFT_FAIL 494 fi 495} 496 497test_u8_range_check() 498{ 499 local t="${SYSCTL}/u8_valid" 500 501 if [[ ! -f "$t" ]]; then 502 ktap_print_msg "$t: file was not created" 503 RET=$KSFT_FAIL 504 return 505 fi 506 507 assert_dmesg_count "u8_over range value" 1 || RET=$KSFT_FAIL 508 assert_dmesg_count "u8_under range value" 1 || RET=$KSFT_FAIL 509} 510 511test_boot_param_int() 512{ 513 local t="${SYSCTL}/boot_int" 514 local orig found 515 516 [[ -f "$t" ]] || { RET=$KSFT_SKIP; return; } 517 518 # Boot cmdline params only apply when test_sysctl is built in, not 519 # loaded as a module. 520 if [[ -d "$MODULE_DIR" ]]; then 521 ktap_print_msg "$t: test only possible if test_sysctl is built-in, not a module" 522 RET=$KSFT_SKIP 523 return 524 fi 525 526 orig=$(cat "$t") 527 if [[ "$orig" == "1" ]]; then 528 return 529 fi 530 531 if [[ ! -f /proc/cmdline ]]; then 532 ktap_print_msg "$t: no /proc/cmdline to check for the boot parameter" 533 RET=$KSFT_SKIP 534 return 535 fi 536 537 found=$(grep -c "sysctl[./]debug[./]test_sysctl[./]boot_int=1" /proc/cmdline) 538 if [[ "$found" == "1" ]]; then 539 ktap_print_msg "$t: kernel param found on cmdline but value is not 1" 540 RET=$KSFT_FAIL 541 return 542 fi 543 544 ktap_print_msg "$t: kernel not booted with sysctl.debug.test_sysctl.boot_int=1" 545 RET=$KSFT_SKIP 546} 547 548test_sysctl_macro_match() 549{ 550 local t="${SYSCTL}/match_int" 551 552 [[ -f "$t" ]] || { RET=$KSFT_SKIP; return; } 553 554 assert_content "$t" "1" || RET=$KSFT_FAIL 555} 556 557run_one() 558{ 559 local name=$1 560 561 # Subshell: a test cannot leak vars/cwd/traps into the next one, and an 562 # accidental `exit` inside a test kills only its own subshell. 563 ( RET=$KSFT_PASS; "$name"; exit $RET ) 564 565 case $? in 566 "$KSFT_PASS") ktap_test_pass "$name" ;; 567 "$KSFT_SKIP") ktap_test_skip "$name" ;; 568 *) ktap_test_fail "$name" ;; 569 esac 570} 571 572usage() 573{ 574 cat <<-EOF 575 Usage: $0 [-r N] [-l] [-t T] [-s N] [-h|--help] 576 577 Runs every auto-discovered test_* function. Setting SYSCTL_TESTS will 578 override the default and passing -t will override both env var and the 579 default. 580 581 -r N repeat selected tests N times (default 1) 582 -l list discovered tests 583 -t T space separated tests list. For example "test_1 test_2" 584 -s N base seed for the randomized bitmap iterations. 585 -h, --help help 586 587 SYSCTL_TESTS='test_1 test_2' $0 run only the named tests 588 EOF 589} 590 591list_tests() 592{ 593 echo "Discovered tests:" 594 local t 595 for t in $ALL_TESTS; do 596 echo " $t" 597 done 598} 599 600check_reqs() 601{ 602 local uid 603 uid=$(id -u) 604 605 if [ "$uid" -ne 0 ]; then 606 ktap_skip_all "must be run as root" 607 exit "$KSFT_SKIP" 608 fi 609 610 if ! which getconf > /dev/null 2>&1; then 611 ktap_skip_all "$0: You need getconf installed" 612 exit "$KSFT_SKIP" 613 fi 614 615 if ! which diff > /dev/null 2>&1; then 616 ktap_skip_all "$0: You need diff installed" 617 exit "$KSFT_SKIP" 618 fi 619} 620 621check_args() # <repeat> <selected> <seed> 622{ 623 local repeat_arg="$1" 624 local selected_arg="$2" 625 local seed_arg="$3" 626 local t 627 628 if [ -z "$selected_arg" ]; then 629 ktap_exit_fail_msg "no test selected" 630 fi 631 632 if ! [[ "$repeat_arg" =~ ^[0-9]+$ ]]; then 633 ktap_exit_fail_msg "repeat argument '$repeat_arg' is not a number" 634 fi 635 636 if ! [[ "$seed_arg" =~ ^[0-9]+$ ]]; then 637 ktap_exit_fail_msg "seed argument '$seed_arg' is not a number" 638 fi 639 640 for t in $selected_arg; do 641 if ! declare -F "$t" > /dev/null; then 642 ktap_exit_fail_msg "unknown selected test '$t'" 643 fi 644 done 645} 646 647allow_user_defaults() 648{ 649 if [ -z "${MODULE_DIR}" ]; then 650 MODULE_DIR="/sys/module/test_sysctl/" 651 fi 652 if [ -z "${SYSCTL}" ]; then 653 SYSCTL="/proc/sys/debug/test_sysctl" 654 fi 655 if [ -z "${PROD_SYSCTL}" ]; then 656 PROD_SYSCTL="/proc/sys" 657 fi 658 if [ -z "${WRITES_STRICT}" ]; then 659 WRITES_STRICT="${PROD_SYSCTL}/kernel/sysctl_writes_strict" 660 fi 661 if [ -z "${BITMAP_ITERATIONS}" ]; then 662 BITMAP_ITERATIONS=50 663 fi 664 # Set seed for bitmap random tests 665 if [ -z "${BITMAP_SEED}" ]; then 666 BITMAP_SEED=$RANDOM 667 fi 668} 669 670check_production_sysctl_writes_strict() 671{ 672 if [ ! -e "${WRITES_STRICT}" ]; then 673 ktap_print_msg "${WRITES_STRICT} missing, skipping strict write check (old kernel?)" 674 else 675 old_strict=$(cat "${WRITES_STRICT}") 676 if [ "$old_strict" != "1" ]; then 677 ktap_print_msg "forcing ${WRITES_STRICT} to 1 (was ${old_strict})" 678 echo "1" > "${WRITES_STRICT}" 679 fi 680 fi 681 682 if [ -z "${PAGE_SIZE}" ]; then 683 PAGE_SIZE=$(getconf PAGESIZE) 684 fi 685 if [ -z "${MAX_DIGITS}" ]; then 686 MAX_DIGITS=$((PAGE_SIZE / 8)) 687 fi 688 if [ -z "${INT_MAX}" ]; then 689 INT_MAX=$(getconf INT_MAX) 690 fi 691 if [ -z "${UINT_MAX}" ]; then 692 UINT_MAX=$(getconf UINT_MAX) 693 fi 694} 695 696load_req_mod() 697{ 698 if [ ! -d "${SYSCTL}" ]; then 699 if ! modprobe -q -n "${TEST_DRIVER}"; then 700 ktap_skip_all "module ${TEST_DRIVER} not found. \ 701 You must set CONFIG_TEST_SYSCTL=m in your kernel" 702 exit "$KSFT_SKIP" 703 fi 704 if ! modprobe "${TEST_DRIVER}"; then 705 ktap_exit_fail_msg "modprobe ${TEST_DRIVER} failed" 706 fi 707 fi 708} 709 710# Cleanup only! Do not call exit here or it will silently override KTAP exit status 711restore_sysctl_writes_strict() 712{ 713 if [ -n "${old_strict}" ]; then 714 echo "${old_strict}" > "${WRITES_STRICT}" 715 fi 716} 717 718allow_user_defaults 719 720# Each bitmap iteration is one function to generate one KTAP report per iteration 721for i in $(seq 1 "$BITMAP_ITERATIONS"); do 722 eval "test_bitmap_range_check_$(printf '%02d' "$i")() \ 723 { \ 724 bitmap_range_check_once $i; \ 725 }" 726done 727 728# Discover test_* functions above this line 729ALL_TESTS=$(declare -F | awk '{print $3}' | grep '^test_' | sort) 730 731REPEAT=1 732while [ $# -gt 0 ]; do 733 case "$1" in 734 -r ) 735 shift 736 REPEAT=$1 737 ;; 738 -l ) 739 list_tests 740 exit 0 741 ;; 742 -h | --help ) 743 usage 744 exit 0 745 ;; 746 -t ) 747 shift 748 SYSCTL_TESTS="$1" 749 ;; 750 -s ) 751 shift 752 BITMAP_SEED="$1" 753 ;; 754 * ) 755 usage 756 exit 1 757 ;; 758 esac 759 shift 760done 761 762SELECTED=${SYSCTL_TESTS-$ALL_TESTS} 763 764ktap_print_header 765trap restore_sysctl_writes_strict EXIT 766check_args "$REPEAT" "$SELECTED" "$BITMAP_SEED" 767check_reqs 768check_production_sysctl_writes_strict 769load_req_mod 770 771ktap_print_msg "bitmap base seed: $BITMAP_SEED (replay with -s $BITMAP_SEED)" 772 773ktap_set_plan "$(( $(wc -w <<< "$SELECTED") * REPEAT ))" 774 775for ((i = 0; i < REPEAT; i++)); do 776 for t in $SELECTED; do 777 run_one "$t" 778 done 779done 780 781ktap_finished 782