]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - tools/testing/selftests/sysctl/sysctl.sh
Merge tag 'powerpc-4.13-8' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[mirror_ubuntu-artful-kernel.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 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