#!/bin/sh
#
# pmlogconf-setup - parse and process a group file to produce an
# initial configuration file control line
#
# Copyright (c) 2014,2017 Red Hat.
# Copyright (c) 2010 Ken McDonell.  All Rights Reserved.
# 
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
# 

# Get standard environment
. $PCP_DIR/etc/pcp.env

status=1
tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1
trap "rm -rf $tmp; exit \$status" 0 1 2 3 15
#debug# tmp=`pwd`/tmp-setup
prog=`basename $0`

cat > $tmp/usage << EOF
# Usage: [options] file

Options:
  --host
  -t
  -v,--verbose   increase diagnostic verbosity
  --help
EOF

_usage()
{
    pmgetopt --progname=$prog --config=$tmp/usage --usage
    exit 1
}

HOST=local:
verbose=false
probelist=''

ARGS=`pmgetopt --progname=$prog --config=$tmp/usage -- "$@"`
[ $? != 0 ] && exit 1

eval set -- "$ARGS"
while [ $# -gt 0 ]
do
    case "$1"
    in
	-h)	# host to contact for "probe" tests
		HOST="$2"
		shift
		;;

	-v)	# verbose
		verbose=true
		;;

	-t)     #list from pmprobe
	        probelist="$2"
		shift
	        ;;

	--)	shift
		break
		;;

	-\?)	# eh?
		_usage
		# NOTREACHED
		;;
    esac
    shift
done

[ $# -eq 1 ] || _usage

# find "probe metric [condition] [state_rule]" line to determine action
# or
# find "force state" line
#
metric=''
options=''
force=''
eval `sed -n <"$1" \
    -e '/^#/d' \
    -e 's/?/"\\\\?"/g' \
    -e 's/\*/"\\\\*"/g' \
    -e 's/\[/"\\\\["/g' \
    -e '/^probe[ 	]/{
s/^probe[ 	]*/metric="/
s/$/ /
s/[ 	]/" options="/
s/ *$/"/
p
q
}' \
    -e '/^force[ 	]/{
s/^force[ 	]*/force='"'"'/
s/ *$/'"'"'/
p
}'`
$verbose && $PCP_ECHO_PROG "$1: " >&2
if [ -n "$force" -a -n "$metric" ]
then
    $PCP_ECHO_PROG "$1: Warning: \"probe\" and \"force\" control lines ... ignoring \"force\"" >&2
    force=''
fi
if [ -z "$force" -a -z "$metric" ]
then
    $PCP_ECHO_PROG "$1: Warning: neither \"probe\" nor \"force\" control lines ... use \"force available\"" >&2
    force=available
fi

$verbose && [ -n "$metric" ] && $PCP_ECHO_PROG $PCP_ECHO_N "probe $metric $options""$PCP_ECHO_C" >&2
$verbose && [ -n "$force" ] && $PCP_ECHO_PROG $PCP_ECHO_N "force $force""$PCP_ECHO_C" >&2
rm -f $tmp/err
if [ -n "$metric" ]
then
    # probe
    echo "$options"
    if [ -s "$probelist" ]
    then
	echo "data `grep "^$metric" "$probelist"`"
    else
	echo "data `pmprobe -h $HOST -v $metric`"
    fi
    # need to handle these variants of pmprobe output
    # sample.string.hullo 1 "hullo world!"
    # sample.colour 3 101 202 303
    #
else
    # force
    $PCP_ECHO_PROG "force $force"
    # the '^G' character is used as a field separator in awk
fi \
| sed \
    -e '/^data /!{
s/ //g
}' \
    -e '/^data [^"]*$/{
s/^data //
s/ //g
}' \
    -e '/^data .*"/{
s/^data //
s/ "//
s/" "//g
s/"$//
s/ //
}' \
| $PCP_AWK_PROG -F '
BEGIN		{ # conditions
	      i = 0
	      exists = ++i; condition[exists] = "exists"
	      values = ++i; condition[values] = "values"
	      force = ++i; conditon[force] = "-"
	      regexp = ++i; condition[regexp] = "~" 
	      notregexp = ++i; condition[notregexp] = "!~" 
	      gt = ++i; condition[gt] = ">";
	      ge = ++i; condition[ge] = ">=";
	      eq = ++i; condition[eq] = "==";
	      neq = ++i; condition[neq] = "!=";
	      le = ++i; condition[le] = "<=";
	      lt = ++i; condition[lt] = "<";
	      # states
	      include = 100; state[include] = "include"
	      exclude = 101; state[exclude] = "exclude"
	      available = 102; state[available] = "available"
	    }
NR == 1 && $1 == "force" && NF == 2 {
	      # force variant
	      action = -1
	      for (i in state) {
		if ($2 == state[i]) {
		    action = i
		    break
		}
	      }
	      if (action == -1) {
		print "force state \"" $2 "\" not recognized" >"'$tmp/err'"
		exit
	      }
	      printf "probe=1 action=%d\n",action >>"'$tmp/out'"
	      exit
	    }
NR == 1		{
	      op = exists	# default predicate
	      yes = available	# default success action
	      no = exclude	# default failure action
	      if (NF > 0) {
		have_condition = 0
		for (i in condition) {
		    if ($1 == condition[i]) {
			have_condition = 1
			op = i
			yes = available	# default success action
			no = exclude	# default failure action
			break
		    }
		}
		if (have_condition == 0 && $1 != "?") {
		    print "condition operator \"" $1 "\" not recognized" >"'$tmp/err'"
		    exit
		}
		if (op == exists || op == values) {
		    if (have_condition)
			actarg = 2
		    else
			actarg = 1
		}
		else {
		    if (NF < 2) {
			print "missing condition operand after " condition[op] " operator" >"'$tmp/err'"
			exit
		    }
		    oprnd = $2
		    actarg = 3
		}
		if (NF < actarg) next
		str = $actarg
		for (i = actarg+1; i <= NF; i++) {
		    str = str " " $i
		}
		if (NF >= actarg && $actarg != "?") {
		    print "expected \"?\" after condition, found \"" str "\"" >"'$tmp/err'"
		    exit
		}
		if (NF >= actarg && NF < actarg+3) {
		    print "missing state rule components: \"" str "\"" >"'$tmp/err'"
		    exit
		}
		if (NF >= actarg && NF > actarg+3) {
		    print "extra state rule components: \"" str "\"" >"'$tmp/err'"
		    exit
		}
		actarg++
		yes = -1
		for (i in state) {
		    if ($actarg == state[i]) {
			yes = i
			break
		    }
		}
		if (yes == -1) {
		    print "sucess state \"" $actarg "\" not recognized" >"'$tmp/err'"
		    exit
		}
		actarg++
		if ($actarg != ":") {
		    print "expected \":\" in state rule, found \"" $actarg "\"" >"'$tmp/err'"
		    exit
		}
		actarg++
		no = -1
		for (i in state) {
		    if ($actarg == state[i]) {
			no = i
			break
		    }
		}
		if (no == -1) {
		    print "failure state \"" $actarg "\" not recognized" >"'$tmp/err'"
		    exit
		}
	      } 
	    }
NR == 2		{
	      #debug# printf "op: %d %s pmprobe: %s",op, condition[op],$0
	      probe = 0
	      if ($2 < 0) {
		# error from pmprobe
		;
	      }
	      else {
		if (op == exists) {
		    probe = 1
		}
		else if (op == values) {
		    if ($2 > 0) probe = 1
		}
		else if (op == regexp) {
		    for (i = 3; i <= NF; i++) {
			if ($i ~ oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == notregexp) {
		    for (i = 3; i <= NF; i++) {
			if ($i !~ oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == gt) {
		    for (i = 3; i <= NF; i++) {
			if ($i > oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == ge) {
		    for (i = 3; i <= NF; i++) {
			if ($i >= oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == eq) {
		    for (i = 3; i <= NF; i++) {
			if ($i == oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == neq) {
		    for (i = 3; i <= NF; i++) {
			if ($i != oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == le) {
		    for (i = 3; i <= NF; i++) {
			if ($i <= oprnd) {
			    probe = 1
			    break
			}
		    }
		}
		else if (op == lt) {
		    for (i = 3; i <= NF; i++) {
			if ($i < oprnd) {
			    probe = 1
			    break
			}
		    }
		}
	      }
	      if (probe == 1) 
		action = yes
	      else
		action = no
	      printf "probe=%d action=%d\n",probe,action >>"'$tmp/out'"
	    }'

if [ -f $tmp/err ]
then
    $verbose && $PCP_ECHO_PROG >&2
    $PCP_ECHO_PROG "$1: Error: `cat $tmp/err`" >&2
elif [ -f $tmp/out ]
then
    probe=''
    action=''
    eval `cat $tmp/out`
    if $verbose
    then
	case $probe
	in
	    0)
		probe_s="failure"
		;;
	    1)
		probe_s="success"
		;;
	    *)
		probe_s="unknown ($probe)"
		;;
	esac
	case $action
	in
	    100)
		action_s="include"
		;;
	    101)
		action_s="exclude"
		;;
	    102)
		action_s="available"
		;;
	    *)
		action_s="unknown ($action)"
		;;
	esac
	$PCP_ECHO_PROG " -> probe=$probe_s action=$action_s" >&2
    fi
    if [ $action = 100 -o $action = 102 ]
    then
	mode='n'
	[ $action = 100 ] && mode='y'
	delta=`sed -n <"$1" -e /'^delta[ 	]/s/delta[ 	]*//p'`
	[ -z "$delta" ] && delta='default'
	echo "#+ $1:$mode:$delta:"
    else
	echo "#+ $1:x::"
    fi
    status=0
else
    $verbose && $PCP_ECHO_PROG >&2
    $PCP_ECHO_PROG "$1: Botch: no errors and no probe results ... try verbose mode" >&2
fi

exit
