#! /bin/sh
##  $Revision: 1.7 $
##  Watch the state of the system relative to the news subsystem.
##  As controlled by the control file, when space or inodes are almost
##  exhausted innd is throttled, or paused, similarly if the load is
##  too high - when conditions revert to normal, innd is restarted.
##  No logging is done here, watch for syslog reports from innd.
##  Written by Mike Cooper <mcooper@usc.edu>.
##  Extensively modified by <kre@munnari.oz.au>.

# =()<NEWSBIN=@<_PATH_NEWSBIN>@>()=
NEWSBIN=/usr/local/news/bin
PATH=${NEWSBIN}:${PATH}:/bin:/usr/bin ; export PATH
# =()<AWK=@<_PATH_AWK>@>()=
AWK=/usr/local/bin/gawk

# =()<SPOOL=@<_PATH_SPOOL>@>()=
SPOOL=/var/spool/news
# =()<LOCK=@<_PATH_LOCKS>@/LOCK.watch>()=
LOCK=/usr/local/news/LOCK.watch
# =()<DAILY=@<_PATH_LOCKS>@/LOCK.news.daily>()=
DAILY=/usr/local/news/LOCK.news.daily
# =()<FILE=@<_PATH_CTLWATCH>@>()=
FILE=/usr/local/news/innwatch.ctl
# =()<SLEEPTIME=@<INNWATCH_SLEEPTIME>@>()=
SLEEPTIME=600

PROGNAME=innwatch

##  Parse JCL.
while [ $# -gt 0 ] ; do
    case X"$1" in
    X-f)
	FILE="$2"
	shift
	;;
    X-f*)
	FILE=`expr "$1" : '-s\(.*\)'`
	;;
    X-t)
	SLEEPTIME="$2"
	shift
	;;
    X-t*)
	SLEEPTIME=`expr "$1" : '-t\(.*\)'`
	;;
    X--)
	shift
	break
	;;
    X-*)
	echo "${PROGNAME}:  Unknown flag $1" 1>&2
	exit 1
	;;
    *)
	break
	;;
    esac
    shift
done

##  Process arguments.
if [ $# -ne 0 ] ; then
    echo "Usage:  ${PROGNAME} [flags]" 1>&2
    exit 1
fi

##  Anyone else there?
trap 'rm -f ${LOCK} ; exit 1' 1 2 3 15
shlock -p $$ -f ${LOCK} || {
    echo "${PROGNAME}: [$$] locked by [`cat ${LOCK}`]"
    exit 0
}

##  The reason why we turned INND off.
STATE=''
REASON=''

cd ${SPOOL}

NEXTSLEEP=1

while sleep "${NEXTSLEEP}" ; do
    NEXTSLEEP="${SLEEPTIME}"

    ##  If news.daily is running, idle:  we don't want to change the
    ##  status of anything while news.daily may be depending on what we
    ##  have done.
    test -f "${DAILY}" && continue

    VALUE=0
    PREVEXP=''

    exec 3<&0
    exec 0<${FILE}

    LINE=0
    while read line ; do
	LINE=`expr ${LINE} + 1`
	test -z "$line" && continue

	##  The first character on the line is the field delimiter,
	##  except '#' which marks the line as a comment
	delim=`expr "${line}" : '\(.\).*'`
	test "X${delim}" = 'X#' && continue

	##  Parse the line into seven fields, and assign them to local vars.
	##  You're welcome to work out what's going on with quoting in
	##  the next few lines if you feel inclined.
	eval `echo "${line}" \
		| sed -e "s/'/'\"'\"'/g" \
		    -e "s/[ 	]*\\\\${delim}[ 	]*/\\\\${delim}/g" \
		| awk -F"${delim}" '{ print	"LAB='"'"'" $2 "'"'"'", \
						"CND='"'"'" $3 "'"'"'", \
						"EXP='"'"'" $4 "'"'"'", \
						"TST='"'"'" $5 "'"'"'", \
						"LIM='"'"'" $6 "'"'"'", \
						"CMD='"'"'" $7 "'"'"'", \
						"CMT='"'"'" $8 "'"'"'" }'`

	##  If there's no label, the label is the line number.
	test -z "${LAB}" && LAB=${LINE}

	##  Should we act on this line?  We will if one (or more) of the
	##  specified conditions is satisfied.
	for X in a b; do	# meaningless trash because we have no goto
	    set -$- X ${CND:-'-'}; shift
	    for cnd
	    do
		case "${cnd}" in
		-)
		    test -n "${STATE}" -a "X${STATE}" != "X${LAB}" && continue
		    ;;
		+)
		    test -n "${STATE}" && continue
		    ;;
		'*')
		    ;;
		-*)
		    test "X-${STATE}" = "X${cnd}" && continue
		    ;;
		*)
		    test "X${STATE}" != "X${cnd}" && continue;
		    ;;
		esac
		break 2;	# OK, continue with this line
	    done
	    continue 2;		# No, skip it.
	done

	##  Evaluate the expression, if there is one, and if that works.
	if [ -z "${EXP}" -o "${EXP}" = "${PREVEXP}" ] \
	 || { PREVEXP="${EXP}"; VALUE=`eval "${EXP}"`; }; then
	    ##  If innd is running, and test "succeeds", stop it.
	    case "${CMD}" in
	    throttle|pause)
		OK=n
		;;
	    *)
		OK=y
		;;
	    esac

	    if [ \( -z "${STATE}" -o "${STATE}" != "${LAB}" -o "${OK}" = y \) \
		    -a "${VALUE}" "-${TST}" "${LIM}" ] ; then
		R="${CMT} [${PROGNAME}:${LAB}] ${VALUE} ${TST} ${LIM}"
		O=
		case "${CMD}" in
		throttle)
		    case "${STATE}" in
		    '')
			REASON="${R}"
			;;
		    *)
			;;
		    esac
		    O="${LAB}"
		    ;;
		pause)
		    REASON="${R}"
		    O="${LAB}"
		    ;;
		shutdown)
		    REASON="${R}"
		    ;;
		flush)
		    REASON=''
		    O="${STATE}"
		    ;;
		go)
		    NEXTSLEEP=1
		    ;;
		exit)
		    exit 0
		    ;;
		*)
		    break
		    ;;
		esac

		ctlinnd -s "${CMD}" "${REASON}" && STATE="${O}"
		break

	    ##  Otherwise, if innd is not running, and reverse test succeeds
	    ##  restart it.
	    elif [ "${STATE}" = "${LAB}" -a \
		    \( "${CMD}" = "throttle" -o "${CMD}" = pause \) -a \
		    ! "${VALUE}" "-${TST}" "${LIM}" ] ; then
		ctlinnd -s go "${REASON}"
		STATE=''
		REASON=''

		##  If we have started innd, run all tests again quickly in
		##  case there is some other condition that should stop it.
		NEXTSLEEP=1
		break
	    fi
	fi

    done

    exec 0<&3
    exec 3<&-

done

rm -f "${LOCK}"
