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