]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - tools/testing/selftests/sysctl/sysctl.sh
test_sysctl: add simple proc_douintvec() case
[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
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