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