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