Linux-libre 5.3.12-gnu
[librecmc/linux-libre.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:TARGET
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 # TARGET: test target file required on the test_sysctl module
33 #
34 # Once these are enabled please leave them as-is. Write your own test,
35 # we have tons of space.
36 ALL_TESTS="0001:1:1:int_0001"
37 ALL_TESTS="$ALL_TESTS 0002:1:1:string_0001"
38 ALL_TESTS="$ALL_TESTS 0003:1:1:int_0002"
39 ALL_TESTS="$ALL_TESTS 0004:1:1:uint_0001"
40 ALL_TESTS="$ALL_TESTS 0005:3:1:int_0003"
41 ALL_TESTS="$ALL_TESTS 0006:50:1:bitmap_0001"
42
43 test_modprobe()
44 {
45        if [ ! -d $DIR ]; then
46                echo "$0: $DIR not present" >&2
47                echo "You must have the following enabled in your kernel:" >&2
48                cat $TEST_DIR/config >&2
49                exit $ksft_skip
50        fi
51 }
52
53 function allow_user_defaults()
54 {
55         if [ -z $DIR ]; then
56                 DIR="/sys/module/test_sysctl/"
57         fi
58         if [ -z $DEFAULT_NUM_TESTS ]; then
59                 DEFAULT_NUM_TESTS=50
60         fi
61         if [ -z $SYSCTL ]; then
62                 SYSCTL="/proc/sys/debug/test_sysctl"
63         fi
64         if [ -z $PROD_SYSCTL ]; then
65                 PROD_SYSCTL="/proc/sys"
66         fi
67         if [ -z $WRITES_STRICT ]; then
68                 WRITES_STRICT="${PROD_SYSCTL}/kernel/sysctl_writes_strict"
69         fi
70 }
71
72 function check_production_sysctl_writes_strict()
73 {
74         echo -n "Checking production write strict setting ... "
75         if [ ! -e ${WRITES_STRICT} ]; then
76                 echo "FAIL, but skip in case of old kernel" >&2
77         else
78                 old_strict=$(cat ${WRITES_STRICT})
79                 if [ "$old_strict" = "1" ]; then
80                         echo "ok"
81                 else
82                         echo "FAIL, strict value is 0 but force to 1 to continue" >&2
83                         echo "1" > ${WRITES_STRICT}
84                 fi
85         fi
86
87         if [ -z $PAGE_SIZE ]; then
88                 PAGE_SIZE=$(getconf PAGESIZE)
89         fi
90         if [ -z $MAX_DIGITS ]; then
91                 MAX_DIGITS=$(($PAGE_SIZE/8))
92         fi
93         if [ -z $INT_MAX ]; then
94                 INT_MAX=$(getconf INT_MAX)
95         fi
96         if [ -z $UINT_MAX ]; then
97                 UINT_MAX=$(getconf UINT_MAX)
98         fi
99 }
100
101 test_reqs()
102 {
103         uid=$(id -u)
104         if [ $uid -ne 0 ]; then
105                 echo $msg must be run as root >&2
106                 exit $ksft_skip
107         fi
108
109         if ! which perl 2> /dev/null > /dev/null; then
110                 echo "$0: You need perl installed"
111                 exit $ksft_skip
112         fi
113         if ! which getconf 2> /dev/null > /dev/null; then
114                 echo "$0: You need getconf installed"
115                 exit $ksft_skip
116         fi
117         if ! which diff 2> /dev/null > /dev/null; then
118                 echo "$0: You need diff installed"
119                 exit $ksft_skip
120         fi
121 }
122
123 function load_req_mod()
124 {
125         if [ ! -d $DIR ]; then
126                 if ! modprobe -q -n $TEST_DRIVER; then
127                         echo "$0: module $TEST_DRIVER not found [SKIP]"
128                         exit $ksft_skip
129                 fi
130                 modprobe $TEST_DRIVER
131                 if [ $? -ne 0 ]; then
132                         exit
133                 fi
134         fi
135 }
136
137 reset_vals()
138 {
139         VAL=""
140         TRIGGER=$(basename ${TARGET})
141         case "$TRIGGER" in
142                 int_0001)
143                         VAL="60"
144                         ;;
145                 int_0002)
146                         VAL="1"
147                         ;;
148                 uint_0001)
149                         VAL="314"
150                         ;;
151                 string_0001)
152                         VAL="(none)"
153                         ;;
154                 bitmap_0001)
155                         VAL=""
156                         ;;
157                 *)
158                         ;;
159         esac
160         echo -n $VAL > $TARGET
161 }
162
163 set_orig()
164 {
165         if [ ! -z $TARGET ] && [ ! -z $ORIG ]; then
166                 if [ -f ${TARGET} ]; then
167                         echo "${ORIG}" > "${TARGET}"
168                 fi
169         fi
170 }
171
172 set_test()
173 {
174         echo "${TEST_STR}" > "${TARGET}"
175 }
176
177 verify()
178 {
179         local seen
180         seen=$(cat "$1")
181         if [ "${seen}" != "${TEST_STR}" ]; then
182                 return 1
183         fi
184         return 0
185 }
186
187 # proc files get read a page at a time, which can confuse diff,
188 # and get you incorrect results on proc files with long data. To use
189 # diff against them you must first extract the output to a file, and
190 # then compare against that file.
191 verify_diff_proc_file()
192 {
193         TMP_DUMP_FILE=$(mktemp)
194         cat $1 > $TMP_DUMP_FILE
195
196         if ! diff -w -q $TMP_DUMP_FILE $2; then
197                 return 1
198         else
199                 return 0
200         fi
201 }
202
203 verify_diff_w()
204 {
205         echo "$TEST_STR" | diff -q -w -u - $1 > /dev/null
206         return $?
207 }
208
209 test_rc()
210 {
211         if [[ $rc != 0 ]]; then
212                 echo "Failed test, return value: $rc" >&2
213                 exit $rc
214         fi
215 }
216
217 test_finish()
218 {
219         set_orig
220         rm -f "${TEST_FILE}"
221
222         if [ ! -z ${old_strict} ]; then
223                 echo ${old_strict} > ${WRITES_STRICT}
224         fi
225         exit $rc
226 }
227
228 run_numerictests()
229 {
230         echo "== Testing sysctl behavior against ${TARGET} =="
231
232         rc=0
233
234         echo -n "Writing test file ... "
235         echo "${TEST_STR}" > "${TEST_FILE}"
236         if ! verify "${TEST_FILE}"; then
237                 echo "FAIL" >&2
238                 exit 1
239         else
240                 echo "ok"
241         fi
242
243         echo -n "Checking sysctl is not set to test value ... "
244         if verify "${TARGET}"; then
245                 echo "FAIL" >&2
246                 exit 1
247         else
248                 echo "ok"
249         fi
250
251         echo -n "Writing sysctl from shell ... "
252         set_test
253         if ! verify "${TARGET}"; then
254                 echo "FAIL" >&2
255                 exit 1
256         else
257                 echo "ok"
258         fi
259
260         echo -n "Resetting sysctl to original value ... "
261         set_orig
262         if verify "${TARGET}"; then
263                 echo "FAIL" >&2
264                 exit 1
265         else
266                 echo "ok"
267         fi
268
269         # Now that we've validated the sanity of "set_test" and "set_orig",
270         # we can use those functions to set starting states before running
271         # specific behavioral tests.
272
273         echo -n "Writing entire sysctl in single write ... "
274         set_orig
275         dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null
276         if ! verify "${TARGET}"; then
277                 echo "FAIL" >&2
278                 rc=1
279         else
280                 echo "ok"
281         fi
282
283         echo -n "Writing middle of sysctl after synchronized seek ... "
284         set_test
285         dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null
286         if ! verify "${TARGET}"; then
287                 echo "FAIL" >&2
288                 rc=1
289         else
290                 echo "ok"
291         fi
292
293         echo -n "Writing beyond end of sysctl ... "
294         set_orig
295         dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null
296         if verify "${TARGET}"; then
297                 echo "FAIL" >&2
298                 rc=1
299         else
300                 echo "ok"
301         fi
302
303         echo -n "Writing sysctl with multiple long writes ... "
304         set_orig
305         (perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \
306                 dd of="${TARGET}" bs=50 2>/dev/null
307         if verify "${TARGET}"; then
308                 echo "FAIL" >&2
309                 rc=1
310         else
311                 echo "ok"
312         fi
313         test_rc
314 }
315
316 check_failure()
317 {
318         echo -n "Testing that $1 fails as expected..."
319         reset_vals
320         TEST_STR="$1"
321         orig="$(cat $TARGET)"
322         echo -n "$TEST_STR" > $TARGET 2> /dev/null
323
324         # write should fail and $TARGET should retain its original value
325         if [ $? = 0 ] || [ "$(cat $TARGET)" != "$orig" ]; then
326                 echo "FAIL" >&2
327                 rc=1
328         else
329                 echo "ok"
330         fi
331         test_rc
332 }
333
334 run_wideint_tests()
335 {
336         # sysctl conversion functions receive a boolean sign and ulong
337         # magnitude; here we list the magnitudes we want to test (each of
338         # which will be tested in both positive and negative forms).  Since
339         # none of these values fit in 32 bits, writing them to an int- or
340         # uint-typed sysctl should fail.
341         local magnitudes=(
342                 # common boundary-condition values (zero, +1, -1, INT_MIN,
343                 # and INT_MAX respectively) if truncated to lower 32 bits
344                 # (potential for being falsely deemed in range)
345                 0x0000000100000000
346                 0x0000000100000001
347                 0x00000001ffffffff
348                 0x0000000180000000
349                 0x000000017fffffff
350
351                 # these look like negatives, but without a leading '-' are
352                 # actually large positives (should be rejected as above
353                 # despite being zero/+1/-1/INT_MIN/INT_MAX in the lower 32)
354                 0xffffffff00000000
355                 0xffffffff00000001
356                 0xffffffffffffffff
357                 0xffffffff80000000
358                 0xffffffff7fffffff
359         )
360
361         for sign in '' '-'; do
362                 for mag in "${magnitudes[@]}"; do
363                         check_failure "${sign}${mag}"
364                 done
365         done
366 }
367
368 # Your test must accept digits 3 and 4 to use this
369 run_limit_digit()
370 {
371         echo -n "Checking ignoring spaces up to PAGE_SIZE works on write ..."
372         reset_vals
373
374         LIMIT=$((MAX_DIGITS -1))
375         TEST_STR="3"
376         (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
377                 dd of="${TARGET}" 2>/dev/null
378
379         if ! verify "${TARGET}"; then
380                 echo "FAIL" >&2
381                 rc=1
382         else
383                 echo "ok"
384         fi
385         test_rc
386
387         echo -n "Checking passing PAGE_SIZE of spaces fails on write ..."
388         reset_vals
389
390         LIMIT=$((MAX_DIGITS))
391         TEST_STR="4"
392         (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
393                 dd of="${TARGET}" 2>/dev/null
394
395         if verify "${TARGET}"; then
396                 echo "FAIL" >&2
397                 rc=1
398         else
399                 echo "ok"
400         fi
401         test_rc
402 }
403
404 # You are using an int
405 run_limit_digit_int()
406 {
407         echo -n "Testing INT_MAX works ..."
408         reset_vals
409         TEST_STR="$INT_MAX"
410         echo -n $TEST_STR > $TARGET
411
412         if ! verify "${TARGET}"; then
413                 echo "FAIL" >&2
414                 rc=1
415         else
416                 echo "ok"
417         fi
418         test_rc
419
420         echo -n "Testing INT_MAX + 1 will fail as expected..."
421         reset_vals
422         let TEST_STR=$INT_MAX+1
423         echo -n $TEST_STR > $TARGET 2> /dev/null
424
425         if verify "${TARGET}"; then
426                 echo "FAIL" >&2
427                 rc=1
428         else
429                 echo "ok"
430         fi
431         test_rc
432
433         echo -n "Testing negative values will work as expected..."
434         reset_vals
435         TEST_STR="-3"
436         echo -n $TEST_STR > $TARGET 2> /dev/null
437         if ! verify "${TARGET}"; then
438                 echo "FAIL" >&2
439                 rc=1
440         else
441                 echo "ok"
442         fi
443         test_rc
444 }
445
446 # You used an int array
447 run_limit_digit_int_array()
448 {
449         echo -n "Testing array works as expected ... "
450         TEST_STR="4 3 2 1"
451         echo -n $TEST_STR > $TARGET
452
453         if ! verify_diff_w "${TARGET}"; then
454                 echo "FAIL" >&2
455                 rc=1
456         else
457                 echo "ok"
458         fi
459         test_rc
460
461         echo -n "Testing skipping trailing array elements works ... "
462         # Do not reset_vals, carry on the values from the last test.
463         # If we only echo in two digits the last two are left intact
464         TEST_STR="100 101"
465         echo -n $TEST_STR > $TARGET
466         # After we echo in, to help diff we need to set on TEST_STR what
467         # we expect the result to be.
468         TEST_STR="100 101 2 1"
469
470         if ! verify_diff_w "${TARGET}"; then
471                 echo "FAIL" >&2
472                 rc=1
473         else
474                 echo "ok"
475         fi
476         test_rc
477
478         echo -n "Testing PAGE_SIZE limit on array works ... "
479         # Do not reset_vals, carry on the values from the last test.
480         # Even if you use an int array, you are still restricted to
481         # MAX_DIGITS, this is a known limitation. Test limit works.
482         LIMIT=$((MAX_DIGITS -1))
483         TEST_STR="9"
484         (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
485                 dd of="${TARGET}" 2>/dev/null
486
487         TEST_STR="9 101 2 1"
488         if ! verify_diff_w "${TARGET}"; then
489                 echo "FAIL" >&2
490                 rc=1
491         else
492                 echo "ok"
493         fi
494         test_rc
495
496         echo -n "Testing exceeding PAGE_SIZE limit fails as expected ... "
497         # Do not reset_vals, carry on the values from the last test.
498         # Now go over limit.
499         LIMIT=$((MAX_DIGITS))
500         TEST_STR="7"
501         (perl -e 'print " " x '$LIMIT';'; echo "${TEST_STR}") | \
502                 dd of="${TARGET}" 2>/dev/null
503
504         TEST_STR="7 101 2 1"
505         if verify_diff_w "${TARGET}"; then
506                 echo "FAIL" >&2
507                 rc=1
508         else
509                 echo "ok"
510         fi
511         test_rc
512 }
513
514 # You are using an unsigned int
515 run_limit_digit_uint()
516 {
517         echo -n "Testing UINT_MAX works ..."
518         reset_vals
519         TEST_STR="$UINT_MAX"
520         echo -n $TEST_STR > $TARGET
521
522         if ! verify "${TARGET}"; then
523                 echo "FAIL" >&2
524                 rc=1
525         else
526                 echo "ok"
527         fi
528         test_rc
529
530         echo -n "Testing UINT_MAX + 1 will fail as expected..."
531         reset_vals
532         TEST_STR=$(($UINT_MAX+1))
533         echo -n $TEST_STR > $TARGET 2> /dev/null
534
535         if verify "${TARGET}"; then
536                 echo "FAIL" >&2
537                 rc=1
538         else
539                 echo "ok"
540         fi
541         test_rc
542
543         echo -n "Testing negative values will not work as expected ..."
544         reset_vals
545         TEST_STR="-3"
546         echo -n $TEST_STR > $TARGET 2> /dev/null
547
548         if verify "${TARGET}"; then
549                 echo "FAIL" >&2
550                 rc=1
551         else
552                 echo "ok"
553         fi
554         test_rc
555 }
556
557 run_stringtests()
558 {
559         echo -n "Writing entire sysctl in short writes ... "
560         set_orig
561         dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null
562         if ! verify "${TARGET}"; then
563                 echo "FAIL" >&2
564                 rc=1
565         else
566                 echo "ok"
567         fi
568
569         echo -n "Writing middle of sysctl after unsynchronized seek ... "
570         set_test
571         dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null
572         if verify "${TARGET}"; then
573                 echo "FAIL" >&2
574                 rc=1
575         else
576                 echo "ok"
577         fi
578
579         echo -n "Checking sysctl maxlen is at least $MAXLEN ... "
580         set_orig
581         perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \
582                 dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
583         if ! grep -q B "${TARGET}"; then
584                 echo "FAIL" >&2
585                 rc=1
586         else
587                 echo "ok"
588         fi
589
590         echo -n "Checking sysctl keeps original string on overflow append ... "
591         set_orig
592         perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
593                 dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null
594         if grep -q B "${TARGET}"; then
595                 echo "FAIL" >&2
596                 rc=1
597         else
598                 echo "ok"
599         fi
600
601         echo -n "Checking sysctl stays NULL terminated on write ... "
602         set_orig
603         perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \
604                 dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null
605         if grep -q B "${TARGET}"; then
606                 echo "FAIL" >&2
607                 rc=1
608         else
609                 echo "ok"
610         fi
611
612         echo -n "Checking sysctl stays NULL terminated on overwrite ... "
613         set_orig
614         perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \
615                 dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null
616         if grep -q B "${TARGET}"; then
617                 echo "FAIL" >&2
618                 rc=1
619         else
620                 echo "ok"
621         fi
622
623         test_rc
624 }
625
626 target_exists()
627 {
628         TARGET="${SYSCTL}/$1"
629         TEST_ID="$2"
630
631         if [ ! -f ${TARGET} ] ; then
632                 echo "Target for test $TEST_ID: $TARGET not exist, skipping test ..."
633                 return 0
634         fi
635         return 1
636 }
637
638 run_bitmaptest() {
639         # Total length of bitmaps string to use, a bit under
640         # the maximum input size of the test node
641         LENGTH=$((RANDOM % 65000))
642
643         # First bit to set
644         BIT=$((RANDOM % 1024))
645
646         # String containing our list of bits to set
647         TEST_STR=$BIT
648
649         # build up the string
650         while [ "${#TEST_STR}" -le "$LENGTH" ]; do
651                 # Make sure next entry is discontiguous,
652                 # skip ahead at least 2
653                 BIT=$((BIT + $((2 + RANDOM % 10))))
654
655                 # Add new bit to the list
656                 TEST_STR="${TEST_STR},${BIT}"
657
658                 # Randomly make it a range
659                 if [ "$((RANDOM % 2))" -eq "1" ]; then
660                         RANGE_END=$((BIT + $((1 + RANDOM % 10))))
661                         TEST_STR="${TEST_STR}-${RANGE_END}"
662                         BIT=$RANGE_END
663                 fi
664         done
665
666         echo -n "Checking bitmap handler... "
667         TEST_FILE=$(mktemp)
668         echo -n "$TEST_STR" > $TEST_FILE
669
670         cat $TEST_FILE > $TARGET 2> /dev/null
671         if [ $? -ne 0 ]; then
672                 echo "FAIL" >&2
673                 rc=1
674                 test_rc
675         fi
676
677         if ! verify_diff_proc_file "$TARGET" "$TEST_FILE"; then
678                 echo "FAIL" >&2
679                 rc=1
680         else
681                 echo "ok"
682                 rc=0
683         fi
684         test_rc
685 }
686
687 sysctl_test_0001()
688 {
689         TARGET="${SYSCTL}/$(get_test_target 0001)"
690         reset_vals
691         ORIG=$(cat "${TARGET}")
692         TEST_STR=$(( $ORIG + 1 ))
693
694         run_numerictests
695         run_wideint_tests
696         run_limit_digit
697 }
698
699 sysctl_test_0002()
700 {
701         TARGET="${SYSCTL}/$(get_test_target 0002)"
702         reset_vals
703         ORIG=$(cat "${TARGET}")
704         TEST_STR="Testing sysctl"
705         # Only string sysctls support seeking/appending.
706         MAXLEN=65
707
708         run_numerictests
709         run_stringtests
710 }
711
712 sysctl_test_0003()
713 {
714         TARGET="${SYSCTL}/$(get_test_target 0003)"
715         reset_vals
716         ORIG=$(cat "${TARGET}")
717         TEST_STR=$(( $ORIG + 1 ))
718
719         run_numerictests
720         run_wideint_tests
721         run_limit_digit
722         run_limit_digit_int
723 }
724
725 sysctl_test_0004()
726 {
727         TARGET="${SYSCTL}/$(get_test_target 0004)"
728         reset_vals
729         ORIG=$(cat "${TARGET}")
730         TEST_STR=$(( $ORIG + 1 ))
731
732         run_numerictests
733         run_wideint_tests
734         run_limit_digit
735         run_limit_digit_uint
736 }
737
738 sysctl_test_0005()
739 {
740         TARGET="${SYSCTL}/$(get_test_target 0005)"
741         reset_vals
742         ORIG=$(cat "${TARGET}")
743
744         run_limit_digit_int_array
745 }
746
747 sysctl_test_0006()
748 {
749         TARGET="${SYSCTL}/bitmap_0001"
750         reset_vals
751         ORIG=""
752         run_bitmaptest
753 }
754
755 list_tests()
756 {
757         echo "Test ID list:"
758         echo
759         echo "TEST_ID x NUM_TEST"
760         echo "TEST_ID:   Test ID"
761         echo "NUM_TESTS: Number of recommended times to run the test"
762         echo
763         echo "0001 x $(get_test_count 0001) - tests proc_dointvec_minmax()"
764         echo "0002 x $(get_test_count 0002) - tests proc_dostring()"
765         echo "0003 x $(get_test_count 0003) - tests proc_dointvec()"
766         echo "0004 x $(get_test_count 0004) - tests proc_douintvec()"
767         echo "0005 x $(get_test_count 0005) - tests proc_douintvec() array"
768         echo "0006 x $(get_test_count 0006) - tests proc_do_large_bitmap()"
769 }
770
771 usage()
772 {
773         NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .)
774         let NUM_TESTS=$NUM_TESTS+1
775         MAX_TEST=$(printf "%04d\n" $NUM_TESTS)
776         echo "Usage: $0 [ -t <4-number-digit> ] | [ -w <4-number-digit> ] |"
777         echo "           [ -s <4-number-digit> ] | [ -c <4-number-digit> <test- count>"
778         echo "           [ all ] [ -h | --help ] [ -l ]"
779         echo ""
780         echo "Valid tests: 0001-$MAX_TEST"
781         echo ""
782         echo "    all     Runs all tests (default)"
783         echo "    -t      Run test ID the number amount of times is recommended"
784         echo "    -w      Watch test ID run until it runs into an error"
785         echo "    -c      Run test ID once"
786         echo "    -s      Run test ID x test-count number of times"
787         echo "    -l      List all test ID list"
788         echo " -h|--help  Help"
789         echo
790         echo "If an error every occurs execution will immediately terminate."
791         echo "If you are adding a new test try using -w <test-ID> first to"
792         echo "make sure the test passes a series of tests."
793         echo
794         echo Example uses:
795         echo
796         echo "$TEST_NAME.sh            -- executes all tests"
797         echo "$TEST_NAME.sh -t 0002    -- Executes test ID 0002 number of times is recomended"
798         echo "$TEST_NAME.sh -w 0002    -- Watch test ID 0002 run until an error occurs"
799         echo "$TEST_NAME.sh -s 0002    -- Run test ID 0002 once"
800         echo "$TEST_NAME.sh -c 0002 3  -- Run test ID 0002 three times"
801         echo
802         list_tests
803         exit 1
804 }
805
806 function test_num()
807 {
808         re='^[0-9]+$'
809         if ! [[ $1 =~ $re ]]; then
810                 usage
811         fi
812 }
813
814 function get_test_count()
815 {
816         test_num $1
817         TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
818         echo ${TEST_DATA} | awk -F":" '{print $2}'
819 }
820
821 function get_test_enabled()
822 {
823         test_num $1
824         TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
825         echo ${TEST_DATA} | awk -F":" '{print $3}'
826 }
827
828 function get_test_target()
829 {
830         test_num $1
831         TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}')
832         echo ${TEST_DATA} | awk -F":" '{print $4}'
833 }
834
835 function run_all_tests()
836 {
837         for i in $ALL_TESTS ; do
838                 TEST_ID=${i%:*:*:*}
839                 ENABLED=$(get_test_enabled $TEST_ID)
840                 TEST_COUNT=$(get_test_count $TEST_ID)
841                 TEST_TARGET=$(get_test_target $TEST_ID)
842                 if target_exists $TEST_TARGET $TEST_ID; then
843                         continue
844                 fi
845                 if [[ $ENABLED -eq "1" ]]; then
846                         test_case $TEST_ID $TEST_COUNT $TEST_TARGET
847                 fi
848         done
849 }
850
851 function watch_log()
852 {
853         if [ $# -ne 3 ]; then
854                 clear
855         fi
856         date
857         echo "Running test: $2 - run #$1"
858 }
859
860 function watch_case()
861 {
862         i=0
863         while [ 1 ]; do
864
865                 if [ $# -eq 1 ]; then
866                         test_num $1
867                         watch_log $i ${TEST_NAME}_test_$1
868                         ${TEST_NAME}_test_$1
869                 else
870                         watch_log $i all
871                         run_all_tests
872                 fi
873                 let i=$i+1
874         done
875 }
876
877 function test_case()
878 {
879         NUM_TESTS=$2
880
881         i=0
882
883         if target_exists $3 $1; then
884                 continue
885         fi
886
887         while [ $i -lt $NUM_TESTS ]; do
888                 test_num $1
889                 watch_log $i ${TEST_NAME}_test_$1 noclear
890                 RUN_TEST=${TEST_NAME}_test_$1
891                 $RUN_TEST
892                 let i=$i+1
893         done
894 }
895
896 function parse_args()
897 {
898         if [ $# -eq 0 ]; then
899                 run_all_tests
900         else
901                 if [[ "$1" = "all" ]]; then
902                         run_all_tests
903                 elif [[ "$1" = "-w" ]]; then
904                         shift
905                         watch_case $@
906                 elif [[ "$1" = "-t" ]]; then
907                         shift
908                         test_num $1
909                         test_case $1 $(get_test_count $1) $(get_test_target $1)
910                 elif [[ "$1" = "-c" ]]; then
911                         shift
912                         test_num $1
913                         test_num $2
914                         test_case $1 $2 $(get_test_target $1)
915                 elif [[ "$1" = "-s" ]]; then
916                         shift
917                         test_case $1 1 $(get_test_target $1)
918                 elif [[ "$1" = "-l" ]]; then
919                         list_tests
920                 elif [[ "$1" = "-h" || "$1" = "--help" ]]; then
921                         usage
922                 else
923                         usage
924                 fi
925         fi
926 }
927
928 test_reqs
929 allow_user_defaults
930 check_production_sysctl_writes_strict
931 load_req_mod
932 test_modprobe
933
934 trap "test_finish" EXIT
935
936 parse_args $@
937
938 exit 0