]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - tools/testing/selftests/sysctl/sysctl.sh
Merge tag 'linux-kselftest-4.13-rc6-fixes' of git://git.kernel.org/pub/scm/linux...
[mirror_ubuntu-artful-kernel.git] / tools / testing / selftests / sysctl / sysctl.sh
CommitLineData
64b67120
LR
1#!/bin/bash
2# Copyright (C) 2017 Luis R. Rodriguez <mcgrof@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
17TEST_NAME="sysctl"
18TEST_DRIVER="test_${TEST_NAME}"
19TEST_DIR=$(dirname $0)
20TEST_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.
32ALL_TESTS="0001:1:1"
33ALL_TESTS="$ALL_TESTS 0002:1:1"
eb965eda 34ALL_TESTS="$ALL_TESTS 0003:1:1"
2920fad3 35ALL_TESTS="$ALL_TESTS 0004:1:1"
7c43a657 36ALL_TESTS="$ALL_TESTS 0005:3:1"
64b67120
LR
37
38test_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
48function 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
67function 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
1c0357c8
LR
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
eb965eda
LR
88 if [ -z $INT_MAX ]; then
89 INT_MAX=$(getconf INT_MAX)
90 fi
2920fad3
LR
91 if [ -z $UINT_MAX ]; then
92 UINT_MAX=$(getconf UINT_MAX)
93 fi
64b67120
LR
94}
95
96test_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
1c0357c8
LR
108 if ! which getconf 2> /dev/null > /dev/null; then
109 echo "$0: You need getconf installed"
110 exit 1
111 fi
7c43a657
LR
112 if ! which diff 2> /dev/null > /dev/null; then
113 echo "$0: You need diff installed"
114 exit 1
115 fi
64b67120
LR
116}
117
118function 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
1c0357c8
LR
130reset_vals()
131{
132 VAL=""
133 TRIGGER=$(basename ${TARGET})
134 case "$TRIGGER" in
135 int_0001)
136 VAL="60"
137 ;;
eb965eda
LR
138 int_0002)
139 VAL="1"
140 ;;
2920fad3
LR
141 uint_0001)
142 VAL="314"
143 ;;
1c0357c8
LR
144 string_0001)
145 VAL="(none)"
146 ;;
147 *)
148 ;;
149 esac
150 echo -n $VAL > $TARGET
151}
152
64b67120
LR
153set_orig()
154{
155 if [ ! -z $TARGET ]; then
156 echo "${ORIG}" > "${TARGET}"
157 fi
158}
159
160set_test()
161{
162 echo "${TEST_STR}" > "${TARGET}"
163}
164
165verify()
166{
167 local seen
168 seen=$(cat "$1")
169 if [ "${seen}" != "${TEST_STR}" ]; then
170 return 1
171 fi
172 return 0
173}
174
7c43a657
LR
175verify_diff_w()
176{
177 echo "$TEST_STR" | diff -q -w -u - $1
178 return $?
179}
180
64b67120
LR
181test_rc()
182{
183 if [[ $rc != 0 ]]; then
184 echo "Failed test, return value: $rc" >&2
185 exit $rc
186 fi
187}
188
189test_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
200run_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
1c0357c8
LR
285 test_rc
286}
287
288# Your test must accept digits 3 and 4 to use this
289run_limit_digit()
290{
291 echo -n "Checking ignoring spaces up to PAGE_SIZE works on write ..."
292 reset_vals
64b67120 293
1c0357c8
LR
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
64b67120
LR
321 test_rc
322}
323
eb965eda
LR
324# You are using an int
325run_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
7c43a657
LR
366# You used an int array
367run_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
2920fad3
LR
434# You are using an unsigned int
435run_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
64b67120
LR
477run_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
546sysctl_test_0001()
547{
548 TARGET="${SYSCTL}/int_0001"
1c0357c8 549 reset_vals
64b67120
LR
550 ORIG=$(cat "${TARGET}")
551 TEST_STR=$(( $ORIG + 1 ))
552
553 run_numerictests
1c0357c8 554 run_limit_digit
64b67120
LR
555}
556
557sysctl_test_0002()
558{
559 TARGET="${SYSCTL}/string_0001"
1c0357c8 560 reset_vals
64b67120
LR
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
eb965eda
LR
570sysctl_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
2920fad3
LR
582sysctl_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
7c43a657
LR
594sysctl_test_0005()
595{
596 TARGET="${SYSCTL}/int_0003"
597 reset_vals
598 ORIG=$(cat "${TARGET}")
599
600 run_limit_digit_int_array
601}
602
64b67120
LR
603list_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()"
eb965eda 613 echo "0003 x $(get_test_count 0003) - tests proc_dointvec()"
2920fad3 614 echo "0004 x $(get_test_count 0004) - tests proc_douintvec()"
7c43a657 615 echo "0005 x $(get_test_count 0005) - tests proc_douintvec() array"
64b67120
LR
616}
617
618test_reqs
619
620usage()
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
655function test_num()
656{
657 re='^[0-9]+$'
658 if ! [[ $1 =~ $re ]]; then
659 usage
660 fi
661}
662
663function 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
671function get_test_enabled()
672{
673 test_num $1
674 TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
675 echo ${TEST_DATA#*:*:}
676}
677
678function 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
690function watch_log()
691{
692 if [ $# -ne 3 ]; then
693 clear
694 fi
695 date
696 echo "Running test: $2 - run #$1"
697}
698
699function 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
716function 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
733function 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
765test_reqs
766allow_user_defaults
767check_production_sysctl_writes_strict
768load_req_mod
769
770trap "test_finish" EXIT
771
772parse_args $@
773
774exit 0