#!/bin/sh
#
# common procedures for PCP QA scripts
#
# Copyright (c) 1997-2002 Silicon Graphics, Inc.  All Rights Reserved.
#

# for _wait_for_pmlogger() and _change_config() and _service()
. ./common.check 

# per product QA script customization
#
. ./common.setup
[ -z "$DEFAULT_HOST" ] && DEFAULT_HOST=`hostname`

_setenvironment()
{
    MSGVERB="text:action"
    export MSGVERB
    export PCP_BINADM_DIR
    export PCP_DERIVED_CONFIG=""
}

_log_fyi()
{
    echo "FYI ... here are the PMCD logs"
    for log
    do
	if [ ! -f $log ]
	then
	    # try in the other place
	    #
	    case $log
	    in
		$PCP_LOG_DIR/pmcd/*)
		    __try=`echo $log | sed -e "s;/pmcd/;/;"`
		    ;;
		*)
		    __try=`echo $log | sed -e "s;$PCP_LOG_DIR/;$PCP_LOG_DIR/pmcd/;"`
		    ;;
	    esac
	    [ -f $__try ] && log=$__try
	fi
	if [ -f $log ]
	then
	    echo ":::::::::  start $log  ::::::::"
	    cat $log
	    echo "::::::::::  end $log  :::::::::"
	    
	    [ $log != $PCP_LOG_DIR/pmcd/pmcd.log ] && $sudo rm -f $log
	else
	    echo "$log: not found"
	fi
    done
}

_havesudo()
{
    if [ -z "$PCP_DIR" ]
    then
	setuid=`$sudo id | sed -e 's/(.*//' -e 's/.*=//'`
	if [ "$setuid" != 0 ]
	then
	    echo "\"sudo\" is not an executable setuid root. This is fatal."
	    echo "As root, you need to setup your sudoers file for pcpqa."
	    exit 1
	fi
    fi
}

_haveagents()
{
    restart=false
    _here=`pwd`

    # PMDAs than need to be here for QA
    #
    COMMON_PMDAS="sample sampledso simple"
    if [ -d $PCP_PMDAS_DIR/cisco ]
    then
	# cisco PMDA requires that you can reach a router
	#
	if which ping >/dev/null 2>&1
	then
	    #  Note: PCP_QA_CISCOROUTER needs to be defined in common.rc
	    if ping -c 1 $PCP_QA_CISCOROUTER >/dev/null 2>&1
	    then
		COMMON_PMDAS="$COMMON_PMDAS cisco"
	    fi
	fi
    fi

    for agent in $COMMON_PMDAS
    do
	probe=$agent
	agentlog=$PCP_LOG_DIR/pmcd/$agent.log

	# make this empty to stop any attempt to reinstall
	#
	agentdir=$PCP_PMDAS_DIR/$agent

	case $agent
	in
	    cisco)
		probe=cisco.bytes_in
		;;
	    sample)
		probe=sample.milliseconds
		;;
	    sampledso)
		probe=sampledso.milliseconds
		agentdir=$PCP_PMDAS_DIR/sample
		;;
	    simple)
		probe=simple.numfetch
		;;
	esac
	reinstall=false
	while true
	do
	    [ $diff = true ] || echo "PMDA probe: pminfo -h $QA_HOST -f $probe"
	    if pminfo -h $QA_HOST -f $probe 2>&1 \
	       | tail -1 \
	       | egrep "^[ 	]*((value)|(inst))[ 	]" >/dev/null
	    then
		break
	    else
		echo "PMDA $agent is not responding"
		if $restart
		then
		    :
		else
		    _log_fyi $PCP_LOG_DIR/pmcd/pmcd.log $agentlog
		    echo "Restarting PMCD ..."
		    _service pcp restart
		    restart=true
		fi
		if $reinstall
		then
		    [ -f $_here/$iam.out ] && cat $_here/$iam.out
		    echo "Cannot make PMDA $agent work, ... giving up!"
		    exit 1
		else
		    if [ -z "$agentdir" ]
		    then
			echo "Skip PMDA re-install"
			break
		    elif [ -d "$agentdir" ]
		    then
			echo "Trying to re-install PMDA $agent from $agentdir ..."
			_log_fyi $PCP_LOG_DIR/pmcd/pmcd.log $agentlog
			cd $agentdir
			unset ROOT TOOLROOT MAKEFLAGS
			$sudo ./Remove </dev/null >>$_here/$iam.out
			case $agent
			in
			    cisco)
				cd $_here
				./common.install.cisco $iam $agentdir
				;;
			    *)
				$sudo ./Install </dev/null >>$_here/$iam.out
				;;
			esac
			cd $_here
			reinstall=true
		    else
			echo "Cannot find PMDA directory ($agentdir)"
			echo "to re-install, ... giving up!"
			exit 1
		    fi
		fi
	    fi
	done
    done
}

_havelogger()
{
    if [ -z "`_get_pids_by_name -a 'pmlogger.*-P'`" ]
    then
	echo "Primary pmlogger not running ..."
	echo "chkconfig pmlogger on, and restart PMCD"
	_change_config pmlogger on
	if sed -e '/^#/d' "${PCP_PMLOGGERCONTROL_PATH}" \
	   | $PCP_AWK_PROG '$2 == "y" && $3 == "n" { sts=1 } END { exit 1-sts }'
	then
	    : echo "have primary pmlogger line in main control file"
	elif sed -e '/^#/d' "${PCP_PMLOGGERCONTROL_PATH}.d/local" \
	   | $PCP_AWK_PROG '$2 == "y" && $3 == "n" { sts=1 } END { exit 1-sts }'
	then
	    : echo "have primary pmlogger line in local control file"
	else
	    : echo "no primary pmlogger line in control file"
	    if $PCP_AWK_PROG '$2 == "y" && $3 == "n" { sts=1} END { exit 1-sts }' <$PCP_PMLOGGERCONTROL_PATH
	    then
		: echo uncomment
		sed <$PCP_PMLOGGERCONTROL_PATH >$tmp.tmp \
		    -e '/^#[^ 	][^ 	]*[ 	][ 	]*y/s/#//'
		$sudo cp $tmp.tmp $PCP_PMLOGGERCONTROL_PATH
	    elif $PCP_AWK_PROG '$2 == "y" && $3 == "n" { sts=1} END { exit 1-sts }' <$PCP_PMLOGGERCONTROL_PATH.d/local
	    then
		: echo uncomment
		sed <$PCP_PMLOGGERCONTROL_PATH.d/local >$tmp.tmp \
		    -e '/^#[^ 	][^ 	]*[ 	][ 	]*y/s/#//'
		$sudo cp $tmp.tmp $PCP_PMLOGGERCONTROL_PATH.d/local
	    else
		: echo add
		cp $PCP_PMLOGGERCONTROL_PATH.d/local $tmp.tmp
		cat >>$tmp.tmp <<'End-of-File'

# added by PCP QA
LOCALHOSTNAME	y   n	PCP_LOG_DIR/pmlogger/LOCALHOSTNAME	-c config.default
End-of-File
		$sudo cp $tmp.tmp $PCP_PMLOGGERCONTROL_PATH.d/local
	    fi
	fi
	_service pcp restart
	_wait_for_pmlogger
    fi
}

_haveremote()
{
    # ensure critical daemons allow for remote access

    if test -f "${PCP_SYSCONFIG_DIR}/pmcd"
    then
	sed <$PCP_SYSCONFIG_DIR/pmcd >$tmp.tmp \
		-e '/^PMCD_LOCAL=1/s/^/#/g'
	diff $PCP_SYSCONFIG_DIR/pmcd $tmp.tmp >/dev/null || \
	$sudo cp $tmp.tmp $PCP_SYSCONFIG_DIR/pmcd
    fi

    if test -f "${PCP_SYSCONFIG_DIR}/pmproxy"
    then
	sed <$PCP_SYSCONFIG_DIR/pmproxy >$tmp.tmp \
		-e '/^PMPROXY_LOCAL=1/s/^/#/g'
	diff $PCP_SYSCONFIG_DIR/pmproxy $tmp.tmp >/dev/null || \
	$sudo cp $tmp.tmp $PCP_SYSCONFIG_DIR/pmproxy
    fi

    if test -f "${PCP_SYSCONFIG_DIR}/pmlogger"
    then
	sed <$PCP_SYSCONFIG_DIR/pmlogger >$tmp.tmp \
		-e '/^PMLOGGER_LOCAL=1/s/^/#/g'
	diff $PCP_SYSCONFIG_DIR/pmlogger $tmp.tmp >/dev/null || \
	$sudo cp $tmp.tmp $PCP_SYSCONFIG_DIR/pmlogger
    fi
}

_havepmcdtrace()
{
    fix=false
    for trace in traceconn tracepdu
    do
	bit=`pminfo -h $QA_HOST -f pmcd.control.$trace | sed -n -e '/value/s/ *value *//p'`
	if [ "X$bit" != X1 ]
	then
	    pminfo -h $QA_HOST -f pmcd.control.$trace
	    echo "PMCD event tracing not enabled!"
	    fix=true
	fi
    done
    if $fix
    then
	echo "fix options, and restart PMCD"
	[ -z "PCP_PMCDOPTIONS_PATH" ] && \
	      PCP_PMCDOPTIONS_PATH="$PCP_SYSCONF_DIR/pmcd/pmcd.options"
	PCPQA_PMCDOPTIONS="$PCP_PMCDOPTIONS_PATH"
	sed <$PCPQA_PMCDOPTIONS >$tmp.tmp -e '/^-T/s/^/#/'
	cat >>$tmp.tmp <<'End-of-File'

# added by PCP QA
-T 3
End-of-File
	$sudo cp $tmp.tmp $PCPQA_PMCDOPTIONS
	grp=root
	case $PCP_PLATFORM
	in
	    freebsd|netbsd|openbsd)
		    grp=wheel
		    ;;
	esac
	$sudo chown root:$grp $PCPQA_PMCDOPTIONS
	_service pcp restart
	_wait_for_pmlogger
    fi

}

here=`pwd`
rm -f $here/$iam.out
_setenvironment

check=${check-true}
quick=${quick-false}

# Try and guess what "make" is called ... configure leaves a comment
# like this
#NB: don't override $(MAKE); gnumake sets it well, propagating -j etc.
#MAKE	= /usr/local/bin/gmake
# in builddefs, so try there ...
#
if [ -f $PCP_INC_DIR/builddefs ]
then
    make=`sed <$PCP_INC_DIR/builddefs -n -e '/^#NB: don.t override \$(MAKE);/{
N
s/.*MAKE[ 	]*=[ 	]*//p
}'`
    [ -n "$make" ] && export MAKE=$make
fi

if $check
then
    if $quick
    then
	:
    else
	if [ -f GNUmakefile.install ]
	then
	    # running QA in the tree
	    ${MAKE:-make} -f GNUmakefile.install >/tmp/$$.make 2>&1
	    ( cd qt; ./setup-executables )
	else
	    ${MAKE:-make} >/tmp/$$.make 2>&1
	fi
	if [ $? != 0 ]
	then
	    cat /tmp/$$.make
	    echo "Warning: ${MAKE:-make} failed -- some tests may be missing"
	    warn=1
	fi
	rm -f /tmp/$$.make
    fi
fi

diff=diff
if [ ! -z "$DISPLAY" ]
then
    which tkdiff >/dev/null 2>&1 && diff=tkdiff
    which xdiff >/dev/null 2>&1 && diff=xdiff
    which xxdiff >/dev/null 2>&1 && diff=xxdiff
    which gdiff >/dev/null 2>&1 && diff=gdiff
fi

color=false
verbose=false
paranoid=false
group=false
xgroup=false
exclude=false
rflag=false
selbygroup=false
snarf=''
showme=false
sortme=false
have_test_arg=false
check_config=false
rm -f $tmp.list $tmp.tmp $tmp.sed $tmp.exclude

for r
do

    if $group
    then
    	selbygroup=true

	# arg after -g
	group_list=`
	if $rflag
	then
	    sed -e 's/\([0-9]\):\(retired\|reserved\) /\1 /' <group
	else
	    sed -e '/[0-9]:\(retired\|reserved\) /d' <group
	fi \
	| sed -n -e 's/$/ /' -e "/^[0-9][0-9]*.* $r /"'{
s/ .*//p
}'`
	if [ -z "$group_list" ]
	then
	    echo "Group \"$r\" is empty or not defined; ignored" >&2
	else
	    [ ! -s $tmp.list ] && touch $tmp.list
	    for t in $group_list
	    do
		if grep -s "^$t\$" $tmp.list >/dev/null
		then
		    :
		else
		    echo "$t" >>$tmp.list
		fi
	    done
    	fi
	group=false
	continue

    elif $xgroup
    then
    	selbygroup=true

	# if no test numbers, do everything from group file
	[ -s $tmp.list ] || \
	if $rflag
	then
	    sed -e 's/\([0-9]\):\(retired\|reserved\) /\1 /' <group
	else
	    sed -e '/[0-9]:\(retired\|reserved\) /d' <group
	fi \
	| sed -n -e '/^[0-9]/s/[ 	].*//p' >$tmp.list

	# arg after -x
	group_list=`
	if $rflag
	then
	    sed -e 's/\([0-9]\):\(retired\|reserved\) /\1 /' <group
	else
	    sed -e '/[0-9]:\(retired\|reserved\) /d' <group
	fi \
	| sed -n \
	    -e "/^[0-9].* $r /s/[ 	].*//p" \
	    -e "/^[0-9].* $r\$/s/[ 	].*//p"`
	if [ -z "$group_list" ]
	then
	    echo "Group \"$r\" is empty or not defined; ignored" >&2
	else
	    numsed=0
	    rm -f $tmp.sed
	    for t in $group_list
	    do
		if [ $numsed -gt 100 ]
		then
		    sed -f $tmp.sed <$tmp.list >$tmp.tmp
		    mv $tmp.tmp $tmp.list
		    numsed=0
		    rm -f $tmp.sed
		fi
		echo "/^$t\$/d" >>$tmp.sed
		numsed=`expr $numsed + 1`
	    done
	    sed -f $tmp.sed <$tmp.list >$tmp.tmp
	    mv $tmp.tmp $tmp.list
    	fi
	xgroup=false
	continue

    elif $exclude
    then
	# if no test numbers, do everything from group file
	[ -s $tmp.list ] || \
	if $rflag
	then
	    sed -e 's/\([0-9]\):\(retired\|reserved\) /\1 /' <group
	else
	    sed -e '/[0-9]:\(retired\|reserved\) /d' <group
	fi \
	| sed -n -e '/^[0-9]/s/[ 	].*//p' >$tmp.list

	for t in `echo "$r" | sed -e 's/,/ /g'`
	do
	    echo "/^0*$t\$/d" >>$tmp.exclude
	    echo "/^0*$t:/d" >>$tmp.exclude
	done
	exclude=false
	continue

    elif [ ! -z "$snarf" ]
    then
	case $snarf
	in
	    d)
		QA_DIR=$r
		;;
	    h)
		QA_HOST=$r
		;;
	    u)
		QA_USER=$r
		;;
	esac
	snarf=''
	continue
    fi

    xpand=true
    range=false
    case "$r"
    in

	-\?)	# usage
	    echo "Usage: $0 [options] [testlist]"'

common options
    -v			verbose

check options
    -c		check configuration files [off]
    -C		color mode output [off]
    -g group	include tests from these groups (multiple flags allowed)
    -G          report groups and number of tests per group
    -l		line mode diff [xdiff]
    -s		sssh mode diff [no diff, regular output]
    -n		show me, do not run tests
    -q		quick, no PMDA checks (you are on your own)
    -r		include reserved and retired tests
    -t		turn on tracing
    -T		output timestamps
    -x group	exclude tests from these groups (multiple flags allowed)
    -X seq[,seq...]
		exclude these tests

show-me options
    -d QA_DIR		[isms/pcp2.0/qa]
    -h QA_HOST		['`hostname`']
    -u QA_USER		[pcpqa]
'
	    exit 0
	    ;;

	-c)	# check config files
	    check_config=true
	    xpand=false
	    ;;

	-C)	# color mode for results and summaries
	    color=true
	    xpand=false
	    ;;

	-d)	# directory for show-me
	    snarf=d
	    xpand=false
	    ;;

	-G)	# -G report groups and number of tests per group
	    sed -n -e '/^[a-z]/{
s/[ 	].*//
p
}' <group >$tmp.group
	    cat $tmp.group
	    echo ===
	    LC_COLLATE=POSIX sort $tmp.group \
	    | while read group
	    do
		num=`
		    if $rflag
		    then
			sed -e 's/\([0-9]\):\(retired\|reserved\) /\1 /' <group
		    else
			sed -e '/[0-9]:\(retired\|reserved\) /d' <group
		    fi \
		    | egrep "^[0-9].*[ 	]$group([ 	]|$)" \
		    | wc -l \
		    | sed -e 's/ //g'`
		printf "%-20.20s %3d\n" $group $num
	    done
	    exit 0
	    ;;

	-g)	# -g group ... pick from group file
	    group=true
	    xpand=false
	    ;;

	-h)	# host for show-me
	    snarf=h
	    xpand=false
	    ;;

	-l)	# line mode for diff, not gdiff over modems
	    diff=diff
	    xpand=false
	    ;;

	-n)	# show me, don't do it
	    showme=true
	    quick=true
	    xpand=false
	    ;;

	-q)	# "quick", no PMDA checks (you are on your own)
	    quick=true
	    xpand=false
	    ;;

	-r)	# include reserved and retired tests
	    rflag=true
	    xpand=false
	    ;;

	-s)	# sssh mode for diff, no diff at all 
	    diff=true
	    xpand=false
	    ;;

	-t)	# turn on tracing
	    qatrace=true
	    xpand=false
	    ;;

	-T)	# turn on timestamp output
	    timestamp=true
	    xpand=false
	    ;;

	-u)	# user for show-me
	    snarf=u
	    xpand=false
	    ;;

	-v)
	    verbose=true
	    xpand=false
	    ;;

	-x)	# -x group ... exclude from group file
	    xgroup=true
	    xpand=false
	    ;;

	-X)	# -X seq[,seq...] ... exclude explicit tests
	    exclude=true
	    xpand=false
	    ;;

	'[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]')
	    echo "No tests?" >&2
	    status=1
	    exit $status
	    ;;

	[0-9]*-[0-9]*)
	    eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'`
	    range=true
	    ;;

	[0-9]*-)
	    eval `echo $r | sed -e 's/^/start=/' -e 's/-//'`
	    end=`echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/  *$//' -e 's/.* //'`
	    if [ -z "$end" ]
	    then
		echo "No tests in range \"$r\"?" >&2
		status=1
		exit $status
	    fi
	    range=true
	    ;;

	*)
	    start=$r
	    end=$r
	    ;;

    esac

    if $xpand
    then
	start=`echo $start | sed -e 's/^0*\(.\)/\1/'`
	end=`echo $end | sed -e 's/^0*\(.\)/\1/'`
	have_test_arg=true
	if $rflag
	then
	    sed -e 's/\([0-9]\):\(retired\|reserved\) /\1 /' <group
	else
	    sed -e '/[0-9]:\(retired\|reserved\) /d' <group
	fi >$tmp.group
	$PCP_AWK_PROG </dev/null '
BEGIN	{ for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
	| while read id
	do
	    # if test not present, silently forget about it
	    if [ ! -f $id ]
	    then
		if [ "$iam" != "show-me" ]
		then
		    if [ $id = $start ]
		    then
			echo "$id - no such test, skipped"
		    elif [ $id = $end ]
		    then
			echo "$id - no such test, skipped"
		    fi
		fi
		continue
	    fi
	    if egrep -s "^$id([ 	]|$)" $tmp.group >/dev/null
	    then
		# in group file ... OK
		echo $id >>$tmp.list
	    elif egrep -s "^$id:retired([ 	]|$)" group >/dev/null
	    then
		# in group file, but retired
		if $rflag
		then
		    echo $id >>$tmp.list
		else
		   echo "$id - retired test, ignored"
		fi
	    elif egrep -s "^$id:reserved([ 	]|$)" group >/dev/null
	    then
		# in group file, but reserved
		if $rflag
		then
		    echo $id >>$tmp.list
		else
		    echo "$id - reserved test, ignored"
		fi
	    else
		# oops
		$range || echo "$id - unknown test, ignored"
	    fi
	done
    fi

done

if [ -s $tmp.list ]
then
    # found some valid test numbers ... this is good
    :
else
    if $have_test_arg
    then
	# had test numbers, but none in group file ... do nothing
	touch $tmp.list
    else
	if $selbygroup
    	then
    	    echo "No tests selected?" >&2
    	    exit 1
    	else
	    # no test numbers, do everything from group file
	    touch $tmp.list
	    if $rflag
	    then
		sed -e 's/\([0-9]\):\(retired\|reserved\) /\1 /' <group
	    else
		sed -e '/[0-9]:\(retired\|reserved\) /d' <group
	    fi \
	    | sed -n -e '/^[0-9]/{
s/[ 	].*//
p
}' \
	    | while read id
	    do
		[ -f $id ] || continue
		echo $id >>$tmp.list
	    done
    	fi
    fi
fi

# handle -X exclusions
#
if [ -s $tmp.exclude ]
then
    sed -f $tmp.exclude <$tmp.list >$tmp.tmp
    mv $tmp.tmp $tmp.list
fi

list=`sort -n $tmp.list`
rm -f $tmp.list $tmp.tmp $tmp.sed $tmp.exclude

# re-process the product-specific setup in case command line args have
# changed things, e.g. -h hostname
#
. ./common.setup

[ -z "$QA_HOST" ] && QA_HOST=$DEFAULT_HOST
export QA_HOST QA_DIR QA_USER

if $check
then
    x=`pminfo -h $QA_HOST -v pmcd.control.timeout 2>&1`
    if [ ! -z "$x" ]
    then
	echo "Is pmcd running on host $QA_HOST?  Simple test produces ..."
	echo "$x"
	exit 1
    fi
fi

case $iam
in
    show-me)
	# don't need sudo
	;;
    *)

	_havesudo
	;;
esac

case $iam
in
    check|remake)
	# $PCP_RC_DIR/pcp needs this to produce deterministic output now
	#
	_change_config verbose on
	;;
esac

if $quick
then
    :
else
    ./mk.localconfig

    $OPTION_AGENTS && _haveagents
    $OPTION_LOGGER && _havelogger
    $OPTION_REMOTE && _haveremote
    $OPTION_PMCD_TRACE && _havepmcdtrace

    if [ -f GNUmakefile.install ]
    then
	# running QA in the tree
	${MAKE:-make} -f GNUmakefile.install setup
	cd pmdas
	if ${MAKE:-make} -f GNUmakefile.install setup >$tmp.tmp 2>&1
	then
	    :
	else
	    cat $tmp.tmp
	    echo "Warning: pmdas: $MAKE -f GNUmakefile.install setup failed"
	fi
	cd broken
	if ${MAKE:-make} -f GNUmakefile.install broken_v2.dir >$tmp.tmp 2>&1
	then
	    :
	else
	    cat $tmp.tmp
	    echo "Warning: pmdas/broken: $MAKE -f GNUmakefile.install broken_v2.dir failed"
	fi
	cd ../..
    else
	${MAKE:-make} setup
    fi
    if [ $? != 0 ]
    then
	echo "Error: ${MAKE:-make} setup failed"
	exit 1
    fi

    # since pmcd no longer runs as root, normal users must be able
    # to read all dirs on the path to the qa home ...
    #
    x=`pwd`
    while [ -n "$x" -a "$x" != / ]
    do
	prot=`ls -ldL "$x" | sed -e 's/[ 	].*//'`
	case $prot
	in
	    dr?xr?xr?[xt]*)
		;;
	    *)
		echo "Warning: parent directory $x (mode=$prot) not world readable and searchable"
		;;
	esac
	x=`dirname $x`
    done
fi
