1#!/bin/sh
2#
3# eval_tools.sh
4#
5# Output functions for script tests.  Source this from other test scripts
6# to establish a standardized repertory of test functions.
7#
8#
9# Except where noted, all functions return:
10#	0	On success,	(Bourne Shell's ``true'')
11#	non-0	Otherwise.
12#
13# Input arguments to each function are documented with each function.
14#
15#
16# XXX  Suggestions:
17#	DEBUG ON|OFF
18#	dump CAPTURE output to stdout as well as to junkoutputfile.
19#
20
21#
22# Only allow ourselves to be eval'ed once
23#
24if [ "x$EVAL_TOOLS_SH_EVALED" != "xyes" ]; then
25    EVAL_TOOLS_SH_EVALED=yes
26
27#
28# Variables used in global environment of calling script.
29#
30failcount=0
31testnum=0
32errnum=0
33junkoutputfilebase="$SNMP_TMPDIR/output-`basename $0`$$"
34junkoutputfile=$junkoutputfilebase
35outputcount=0
36separator="-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
37if [ -z "$OK_TO_SAVE_RESULT" ] ; then
38OK_TO_SAVE_RESULT=1
39export OK_TO_SAVE_RESULT
40fi
41
42if [ `uname -s` = SunOS ]
43then PATH=/usr/xpg4/bin:$PATH
44fi
45
46#
47# HEADER: returns a single line when SNMP_HEADERONLY mode and exits.
48#
49HEADER() {
50    if [ "x$SNMP_HEADERONLY" != "x" ]; then
51        echo test $*
52	exit 0;
53    else
54	{ echo "# testing $*"; echo ""; } >> $SNMP_TMPDIR/invoked
55    fi
56}
57
58
59#------------------------------------ -o-
60#
61OUTPUT() {	# <any_arguments>
62	cat <<GRONK
63
64
65$*
66
67
68GRONK
69}
70
71CAN_USLEEP() {
72   if [ "$SNMP_CAN_USLEEP" = 0 -o "$SNMP_CAN_USLEEP" = 1 ] ; then
73     return 0
74   fi
75   sleep .1 > /dev/null 2>&1
76   if [ $? = 0 ] ; then
77     SNMP_CAN_USLEEP=1
78   else
79     SNMP_CAN_USLEEP=0
80   fi
81   export SNMP_CAN_USLEEP
82}
83
84
85#------------------------------------ -o-
86#
87SUCCESS() {	# <any_arguments>
88	[ "$failcount" -ne 0 ] && return
89	cat <<GROINK
90
91SUCCESS: $*
92
93GROINK
94}
95
96
97
98#------------------------------------ -o-
99#
100FAILED() {	# <return_value>, <any_arguments>
101	[ "$1" -eq 0 ] && return
102	shift
103
104	failcount=`expr $failcount + 1`
105	cat <<GRONIK
106
107FAILED: $*
108
109GRONIK
110}
111
112#------------------------------------ -o-
113#
114SKIP() {
115	REMOVETESTDATA
116	echo "1..0 # SKIP $*"
117	exit 0
118}
119
120ISDEFINED() {
121	grep "^#define $1 " ${builddir}/include/net-snmp/net-snmp-config.h ${builddir}/include/net-snmp/agent/mib_module_config.h ${builddir}/include/net-snmp/agent/agent_module_config.h > /dev/null
122}
123
124SKIPIFNOT() {
125	ISDEFINED "$1" || SKIP "$1 is not defined"
126}
127
128SKIPIF() {
129	ISDEFINED "$1" && SKIP "$1 is defined"
130}
131
132#------------------------------------ -o-
133#
134VERIFY() {	# <path_to_file(s)>
135	missingfiles=""
136
137	for f in $*; do
138		[ -f "$f" ] && continue
139		echo "FAILED: Cannot find file \"$f\"."
140		missingfiles=true
141	done
142
143	[ "$missingfiles" = true ] && exit 1000
144}
145
146NEWOUTPUTFILE() {
147        outputcount=`expr $outputcount + 1`
148        junkoutputfile="${junkoutputfilebase}-$outputcount"
149}
150
151#------------------------------------ -o-
152#
153STARTTEST() {
154        NEWOUTPUTFILE
155	[ ! -f "$junkoutputfile" ] && {
156		touch $junkoutputfile
157		return
158	}
159	echo "FAILED: Output file already exists: \"$junkoutputfile\"."
160	exit 1000
161}
162
163
164#------------------------------------ -o-
165#
166STOPTEST() {
167	rm -f "$junkoutputfile"
168}
169
170
171#------------------------------------ -o-
172#
173REMOVETESTDATA() {
174#	ECHO "removing $SNMP_TMPDIR  "
175	rm -rf $SNMP_TMPDIR
176}
177
178#------------------------------------ -o-
179#
180OUTPUTENVVARS() {
181    echo "SNMPCONFPATH=$SNMPCONFPATH" >> $1
182    echo "SNMP_PERSISTENT_DIR=$SNMP_PERSISTENT_DIR" >> $1
183    echo "MIBDIRS=$MIBDIRS" >> $1
184    echo "PATH=$PATH" >> $1
185    echo "export SNMPCONFPATH" >> $1
186    echo "export SNMP_PERSISTENT_DIR" >> $1
187    echo "export MIBDIRS" >> $1
188    echo "export PATH" >> $1
189}
190
191#------------------------------------ -o-
192# Captures output from command, and returns the command's exit code.
193loggedvars=0
194CAPTURE() {	# <command_with_arguments_to_execute>
195    NEWOUTPUTFILE
196
197    # track invoked command per test when verbose
198    if [ $SNMP_VERBOSE -gt 0 ]; then
199        OUTPUTENVVARS $junkoutputfile.invoked
200        echo $* >> $junkoutputfile.invoked
201    fi
202
203    if [ $loggedvars = 0 ]; then
204        OUTPUTENVVARS $SNMP_TMPDIR/invoked
205        loggedvars=1
206    fi
207    echo $* >> $SNMP_TMPDIR/invoked
208
209	if [ $SNMP_VERBOSE -gt 0 ]; then
210		cat <<KNORG
211
212EXECUTING: $*
213
214KNORG
215
216	fi
217	echo "RUNNING: $*" > $junkoutputfile
218	( $DYNAMIC_ANALYZER $* 2>&1 ) >> $junkoutputfile 2>&1
219	RC=$?
220
221	if [ $SNMP_VERBOSE -gt 1 ]; then
222		echo "Command Output: "
223		echo "MIBDIR $MIBDIRS $MIBS"
224		echo "$separator"
225		cat $junkoutputfile | sed 's/^/  /'
226		echo "$separator"
227	fi
228	return $RC
229}
230
231#------------------------------------ -o-
232# Delay to let processes settle
233DELAY() {
234    if [ "$SNMP_SLEEP" != "0" ] ; then
235	sleep $SNMP_SLEEP
236    fi
237}
238
239SAVE_RESULTS() {
240   real_return_value=$return_value
241}
242
243#
244# Checks the output result against what we expect.
245#   Sets return_value to 0 or 1.
246#
247EXPECTRESULT() {
248  if [ $OK_TO_SAVE_RESULT -ne 0 ] ; then
249    if [ "$snmp_last_test_result" = "$1" ]; then
250	return_value=0
251    else
252	return_value=1
253    fi
254  fi
255}
256
257CHECKCOUNT() {
258   CHECKFILECOUNT "$junkoutputfile" $@
259}
260
261CHECKVALUEIS() {
262    value1=$1
263    value2=$2
264    if [ "x$value1" = "x$value2" ]; then
265      GOOD "$3"
266    else
267      BAD "$3"
268    fi
269}
270
271CHECKVALUEISNT() {
272    value1=$1
273    value2=$2
274    if [ "x$value1" = "x$value2" ]; then
275      BAD "$3"
276    else
277      GOOD "$3"
278    fi
279}
280
281#------------------------------------ -o-
282# Returns: Count of matched lines.
283#
284CHECKFILECOUNT() {	# <pattern_to_match>
285    chkfile=$1
286    ckfcount=$2
287    shift
288    shift
289    if [ $SNMP_VERBOSE -gt 0 ]; then
290	echo -n "checking $chkfile for $ckfcount \"$*\"..."
291    fi
292
293    if [ -f $chkfile ]; then
294	rval=`grep -c "$*" "$chkfile" 2>/dev/null`
295    else
296        COMMENT "Note: file $chkfile does not exist and we were asked to check it"
297	rval=0
298    fi
299
300    if [ $SNMP_VERBOSE -gt 0 ]; then
301	echo "$rval matches found"
302    fi
303
304    snmp_last_test_result=$rval
305    EXPECTRESULT $ckfcount  # default
306    if [ "$ckfcount" != "noerror" ]; then
307      if [ "$ckfcount" = "atleastone" ]; then
308        if [ "$rval" -ne "0" ]; then
309            GOOD "found $ckfcount copies of '$*' in output ($chkfile); needed one"
310        else
311            BAD "found $rval copies of '$*' in output ($chkfile); expected 1"
312            COMMENT "Outputfile: $chkfile"
313        fi
314      else
315        if [ "$rval" = "$ckfcount" ]; then
316           GOOD "found $ckfcount copies of '$*' in output ($chkfile)"
317        else
318           BAD "found $rval copies of '$*' in output ($chkfile); expected $ckfcount"
319           COMMENT "Outputfile: $chkfile"
320        fi
321      fi
322    fi
323    return $rval
324}
325
326CHECK() {
327    CHECKCOUNT 1 $@
328}
329
330CHECKFILE() {
331    file=$1
332    shift
333    CHECKFILECOUNT $file 1 $@
334}
335
336CHECKTRAPD() {
337    CHECKFILE $SNMP_SNMPTRAPD_LOG_FILE $@
338}
339
340CHECKTRAPDCOUNT() {
341    count=$1
342    shift
343    CHECKFILECOUNT $SNMP_SNMPTRAPD_LOG_FILE $count $@
344}
345
346CHECKTRAPDORDIE() {
347    CHECKORDIE $@ $SNMP_SNMPTRAPD_LOG_FILE
348}
349
350CHECKAGENT() {
351    CHECKFILE $SNMP_SNMPD_LOG_FILE $@
352}
353
354CHECKAGENTCOUNT() {
355    count=$1
356    shift
357    CHECKFILECOUNT $SNMP_SNMPD_LOG_FILE $count $@
358}
359
360# Return 0 (true) if a process with pid $1 exists and 1 (false) if no process
361# with pid $1 exists.
362ISRUNNING() {
363    if [ "x$OSTYPE" = "xmsys" ]; then
364	pslist.exe "$1" 2>&1 | while read name pspid rest; do
365	    if [ "$1" = "$pspid" ]; then
366		return 0
367	    fi
368	done
369	return 1
370    else
371        kill -0 "$1" 2>/dev/null
372    fi
373}
374
375# Echo a command that asks the process with pid $1 to stop.
376ECHOSENDSIGTERM() {
377    if [ "x$OSTYPE" = "xmsys" ]; then
378        echo pskill.exe $1
379    else
380        echo kill -TERM $1
381    fi
382}
383
384# Echo a command that stops the process with pid $1 forcibly.
385ECHOSENDSIGKILL() {
386    if [ "x$OSTYPE" = "xmsys" ]; then
387        echo pskill.exe $1
388    else
389        echo kill -KILL $1
390    fi
391}
392
393# Wait until the shell statement "$@" evaluates to false.
394WAITFORNOTCOND() {
395    CAN_USLEEP
396    if [ $SNMP_CAN_USLEEP = 1 ] ; then
397        sleeptime=`expr $SNMP_SLEEP '*' 50`
398    else
399        sleeptime=`expr $SNMP_SLEEP '*' 5`
400    fi
401    while [ $sleeptime -gt 0 ] && eval "$@"; do
402        if [ $SNMP_CAN_USLEEP = 1 ]; then
403            sleep .1
404        else
405            sleep 1
406        fi
407        sleeptime=`expr $sleeptime - 1`
408    done
409}
410
411# Wait until the shell statement "$@" evaluates to true.
412WAITFORCOND() {
413    WAITFORNOTCOND if "$@;" then false ";" else true ";" fi
414}
415
416WAITFORAGENT() {
417    WAITFOR "$@" $SNMP_SNMPD_LOG_FILE
418    if [ $SNMP_CAN_USLEEP = 1 ]; then
419        sleep .1
420    else
421        sleep 1
422    fi
423}
424
425WAITFORTRAPD() {
426    WAITFOR "$@" $SNMP_SNMPTRAPD_LOG_FILE
427    if [ $SNMP_CAN_USLEEP = 1 ]; then
428        sleep .1
429    else
430        sleep 1
431    fi
432}
433
434# Wait until pattern "$1" appears in file "$2".
435WAITFOR() {
436    WAITFORCOND grep "$1" "$2" ">/dev/null" "2>&1"
437}
438
439GOOD() {
440    testnum=`expr $testnum + 1`
441    echo "ok $testnum - $1"
442    echo "# ok $testnum - $1" >> $SNMP_TMPDIR/invoked
443}
444
445BAD() {
446    testnum=`expr $testnum + 1`
447    errnum=`expr $errnum + 1`
448    echo "not ok $testnum - $1"
449    echo "# not ok $testnum - $1" >> $SNMP_TMPDIR/invoked
450}
451
452COMMENT() {
453    echo "# $@"
454    echo "# $@" >> $SNMP_TMPDIR/invoked
455}
456
457# CHECKORDIE "grep string" ["file"] .. FAIL if "grep string" is *not* found
458CHECKORDIE() {
459    if [ "x$2" = "x" ]; then
460      CHECKFILE "$junkoutputfile" "$1"
461    else
462      CHECKFILECOUNT "$2" 1 "$1"
463    fi
464}
465
466# CHECKANDDIE "grep string" ["file"] .. FAIL if "grep string" *is* found
467CHECKANDDIE() {
468    if [ "x$2" = "x" ]; then
469      CHECKFILECOUNT "$junkoutputfile" 0 "$1"
470    else
471      CHECKFILECOUNT "$2" 0 "$1"
472    fi
473}
474
475#------------------------------------ -o-
476# Returns: Count of matched lines.
477#
478CHECKEXACT() {	# <pattern_to_match_exactly>
479	rval=`egrep -c "^$*\$|^$*[^a-zA-Z0-9_]|[^a-zA-Z0-9_]$*\$|[^a-zA-Z0-9_]$*[^a-zA-Z0-9_]" "$junkoutputfile" 2>/dev/null`
480	snmp_last_test_result=$rval
481	EXPECTRESULT 1  # default
482	return $rval
483}
484
485CONFIGAGENT() {
486    if [ "x$SNMP_CONFIG_FILE" = "x" ]; then
487	echo "$0: failed because var: SNMP_CONFIG_FILE wasn't set"
488	exit 1;
489    fi
490    echo $* >> $SNMP_CONFIG_FILE
491}
492
493CONFIGTRAPD() {
494    if [ "x$SNMPTRAPD_CONFIG_FILE" = "x" ]; then
495	echo "$0: failed because var: SNMPTRAPD_CONFIG_FILE wasn't set"
496	exit 1;
497    fi
498    echo $* >> $SNMPTRAPD_CONFIG_FILE
499}
500
501CONFIGAPP() {
502    if [ "x$SNMPAPP_CONFIG_FILE" = "x" ]; then
503	echo "$0: failed because var: SNMPAPP_CONFIG_FILE wasn't set"
504	exit 1;
505    fi
506    echo $* >> $SNMPAPP_CONFIG_FILE
507}
508
509#
510# common to STARTAGENT and STARTTRAPD
511# log command to "invoked" file
512#
513STARTPROG() {
514    if [ "x$DYNAMIC_ANALYZER" != "x" ]; then
515        COMMAND="$DYNAMIC_ANALYZER $COMMAND"
516    fi
517    if [ $SNMP_VERBOSE -gt 1 ]; then
518	echo "$CFG_FILE contains: "
519	if [ -f $CFG_FILE ]; then
520	    cat $CFG_FILE
521	else
522	    echo "[no config file]"
523	fi
524    fi
525    if test -f $CFG_FILE; then
526	COMMAND="$COMMAND -C -c $CFG_FILE"
527    fi
528    if [ "x$PORT_SPEC" != "x" ]; then
529        COMMAND="$COMMAND $PORT_SPEC"
530    fi
531    if [ $SNMP_VERBOSE -gt 0 ]; then
532	echo "running: $COMMAND"
533    fi
534    echo $COMMAND >> $SNMP_TMPDIR/invoked
535    if [ $SNMP_VERBOSE -gt 0 ]; then
536        OUTPUTENVVARS $LOG_FILE.command
537        echo $COMMAND >> $LOG_FILE.command
538    fi
539    if [ "x$OSTYPE" = "xmsys" ]; then
540      $COMMAND > $LOG_FILE.stdout 2>&1 &
541      ## COMMAND="cmd.exe //c start //min $COMMAND"
542      ## start $COMMAND > $LOG_FILE.stdout 2>&1
543    else
544      $COMMAND > $LOG_FILE.stdout 2>&1
545    fi
546}
547
548#------------------------------------ -o-
549STARTAGENT() {
550    SNMPDSTARTED=1
551    COMMAND="snmpd $SNMP_FLAGS -r -U -p $SNMP_SNMPD_PID_FILE -Lf $SNMP_SNMPD_LOG_FILE $AGENT_FLAGS"
552    CFG_FILE=$SNMP_CONFIG_FILE
553    LOG_FILE=$SNMP_SNMPD_LOG_FILE
554    PORT_SPEC="$SNMP_SNMPD_PORT"
555    if [ "x$SNMP_TRANSPORT_SPEC" != "x" ]; then
556        PORT_SPEC="${SNMP_TRANSPORT_SPEC}:${SNMP_TEST_DEST}${PORT_SPEC}"
557    fi
558    STARTPROG
559    WAITFORCOND test -f $SNMP_SNMPD_PID_FILE
560    WAITFORAGENT "NET-SNMP.version"
561}
562
563#------------------------------------ -o-
564STARTTRAPD() {
565    TRAPDSTARTED=1
566    COMMAND="snmptrapd -d -p $SNMP_SNMPTRAPD_PID_FILE -Lf $SNMP_SNMPTRAPD_LOG_FILE $TRAPD_FLAGS"
567    CFG_FILE=$SNMPTRAPD_CONFIG_FILE
568    LOG_FILE=$SNMP_SNMPTRAPD_LOG_FILE
569    PORT_SPEC="$SNMP_SNMPTRAPD_PORT"
570    if [ "x$SNMP_TRANSPORT_SPEC" != "x" ]; then
571        PORT_SPEC="${SNMP_TRANSPORT_SPEC}:${SNMP_TEST_DEST}${PORT_SPEC}"
572    fi
573    STARTPROG
574    WAITFORCOND test -f $SNMP_SNMPTRAPD_PID_FILE
575    WAITFORTRAPD "NET-SNMP.version"
576}
577
578## sending SIGHUP for reconfiguration
579#
580HUPPROG() {
581    if [ -f $1 ]; then
582        if [ "x$OSTYPE" = "xmsys" ]; then
583          COMMAND='echo "Skipping SIGHUP (not possible with MinGW)"'
584        else
585          COMMAND="kill -HUP `cat $1`"
586        fi
587	echo $COMMAND >> $SNMP_TMPDIR/invoked
588	VERBOSE_OUT 0 $COMMAND
589	$COMMAND > /dev/null 2>&1
590    fi
591}
592
593HUPAGENT() {
594    HUPPROG $SNMP_SNMPD_PID_FILE
595    if [ "x$OSTYPE" != "xmsys" ]; then
596        WAITFORAGENT "restarted"
597    fi
598}
599
600HUPTRAPD() {
601    HUPPROG $SNMP_SNMPTRAPD_PID_FILE
602    if [ "x$OSTYPE" != "xmsys" ]; then
603        WAITFORTRAPD "restarted"
604    fi
605}
606
607
608## used by STOPAGENT and STOPTRAPD
609# delay before kill to allow previous action to finish
610#    this is especially important for interaction between
611#    master agent and sub agent.
612STOPPROG() {
613    pid="`cat $1 2>/dev/null`"
614    if [ "x$pid" != "x" ]; then
615	COMMAND="`ECHOSENDSIGTERM $pid`"
616	echo "$COMMAND ($1)" >> $SNMP_TMPDIR/invoked
617	VERBOSE_OUT 0 "$COMMAND ($1)"
618        $COMMAND >/dev/null 2>&1
619        WAITFORNOTCOND "ISRUNNING $pid"
620    fi
621}
622
623#------------------------------------ -o-
624#
625STOPAGENT() {
626    SAVE_RESULTS
627    STOPPROG $SNMP_SNMPD_PID_FILE
628    if [ $SNMP_VERBOSE -gt 1 ]; then
629	echo "Agent Output:"
630	echo "$separator [stdout]"
631	cat $SNMP_SNMPD_LOG_FILE.stdout
632	echo "$separator [logfile]"
633	cat $SNMP_SNMPD_LOG_FILE
634	echo "$separator"
635    fi
636}
637
638#------------------------------------ -o-
639#
640STOPTRAPD() {
641    SAVE_RESULTS
642    STOPPROG $SNMP_SNMPTRAPD_PID_FILE
643    if [ $SNMP_VERBOSE -gt 1 ]; then
644	echo "snmptrapd Output:"
645	echo "$separator [stdout]"
646	cat $SNMP_SNMPTRAPD_LOG_FILE.stdout
647	echo "$separator [logfile]"
648	cat $SNMP_SNMPTRAPD_LOG_FILE
649	echo "$separator"
650    fi
651}
652
653#------------------------------------ -o-
654#
655FINISHED() {
656
657    ## no more changes to test result.
658    OK_TO_SAVE_RESULT=0
659
660    pids="`cat $SNMP_TMPDIR/*pid* 2>/dev/null`"
661    if [ "$SNMPDSTARTED" = "1" ] ; then
662      STOPAGENT
663    fi
664    if [ "$TRAPDSTARTED" = "1" ] ; then
665      STOPTRAPD
666    fi
667    for pid in $pids; do
668        if ISRUNNING $pid; then
669	    SNMP_SAVE_TMPDIR=yes
670	    COMMAND="`ECHOSENDSIGKILL $pid`"
671	    echo "$COMMAND ($pfile)" >> $SNMP_TMPDIR/invoked
672	    VERBOSE_OUT 0 "$COMMAND ($pfile)"
673	    $COMMAND > /dev/null 2>&1
674	    return_value=1
675	fi
676    done
677
678    # report the number of tests done
679    GOOD "got to FINISHED"
680    echo "1..$testnum"
681
682    if [ "x$errnum" != "x0" ]; then
683	if [ -s core ] ; then
684	    # XX hope that only one prog cores !
685	    cp core $SNMP_TMPDIR/core.$$
686	    rm -f core
687	fi
688	echo "$headerStr...FAIL" >> $SNMP_TMPDIR/invoked
689	if [ -n "${TRAVIS_OS_NAME}" ] || [ -n "$APPVEYOR" ] ||
690	   [ -n "$CIRRUS_CI" ]; then
691	    {
692		find "$SNMP_TMPDIR" -type f |
693		    while read -r f; do
694			local lines
695			echo "==== $f"
696			lines=$(wc -l "$f" | { read -r a b; echo "$a"; })
697			if [ "$lines" -gt 512 ]; then
698			    head -n 256 "$f"
699			    echo "..."
700			    tail -n 256 "$f"
701			else
702			    cat "$f"
703			fi
704		    done;
705	    } 1>&2
706	fi
707	exit 1
708    fi
709
710    echo "$headerStr...ok" >> $SNMP_TMPDIR/invoked
711
712    if [ "x$SNMP_SAVE_TMPDIR" != "xyes" ]; then
713	REMOVETESTDATA
714    fi
715    exit 0
716}
717
718#------------------------------------ -o-
719#
720VERBOSE_OUT() {
721    if [ $SNMP_VERBOSE -gt $1 ]; then
722	shift
723	echo "$*"
724    fi
725}
726
727fi # Only allow ourselves to be eval'ed once
728