#!/bin/sh
#
# Control program for managing pmlogger and pmie instances.
#
# Copyright (c) 2020 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.
#
# TODO
# - more than 1 -c option ... what does it mean?  the current code simply
#   and silently uses the last -c option from the command line (this
#   warrants at least a warning) ... if supported the likely semantics
#   are the union of the named classes ... unless this is allowed, a regex
#   pattern for the -c arg (classname) makes no sense
# - regex expansion for <class>
# - other sections in the "policy" files, especially with pmfind to
#   (a) at destroy, decide not to or wait some time before destroying
#       (the latter is really hard)
#

. "$PCP_DIR/etc/pcp.env"
. "$PCP_SHARE_DIR/lib/rc-proc.sh"

prog=`basename "$0"`
case "$prog"
in
    pmlogctl*)	IAM=pmlogger
		CONTROLFILE=$PCP_PMLOGGERCONTROL_PATH
    		;;
    pmiectl*)	IAM=pmie
		CONTROLFILE=$PCP_PMIECONTROL_PATH
    		;;
    *)		echo >&2 "$0: who the hell are you, bozo?"
    		exit 1
		;;
esac
CONTROLDIR=${CONTROLFILE}.d

tmp=`mktemp -d "$PCP_TMPFILE_DIR/$prog.XXXXXXXXX"` || exit 1
status=0

_cleanup()
{
    [ -n "$ACTION" -a "$ACTION" != status ] && _unlock
    rm -rf $tmp
}
trap "_cleanup; exit \$status" 0 1 2 3 15

cat >$tmp/usage <<End-of-File
# Usage: [options] command [host ...]

Options:
  -a,--all                      apply action to all matching hosts
  -c=NAME,--class=NAME    	${IAM} instances belong to the NAME class [default: default]
  -f,--force                    force action if possible
  -i=IDENT,--ident=IDENT        over-ride instance id (only for create and cond-create)
  -N,--showme             	perform a dry run, showing what would be done
  -p=POLICY,--policy=POLICY	use POLICY as the class policy file [default: $PCP_ETC_DIR/pcp/${IAM}/class.d/<class>]
  -V,--verbose            	increase verbosity
  --help
End-of-File

_warning()
{
    echo >&2 "Warning: $1"
}

_error()
{
    echo >&2 "Error: $1"
    status=1
    exit
}

_lock()
{
    $SHOWME && return

    # can assume $__dir is writeable ... if we get this far we're running
    # as root ...
    #
    __dir="$PCP_ETC_DIR/pcp/${IAM}"
    # demand mutual exclusion
    #
    rm -f $tmp/stamp $tmp/out
    __delay=200		# 1/10 of a second, so max wait is 20 sec
    while [ $__delay -gt 0 ]
    do
	if pmlock -v "$__dir/lock" >>$tmp/out 2>&1
	then
	    echo "$$" >"$__dir/lock"
	    break
	else
	    [ -f $tmp/stamp ] || touch -t `pmdate -30M %Y%m%d%H%M` $tmp/stamp
	    find $tmp/stamp -newer "$__dir/lock" -print 2>/dev/null >$tmp/tmp
	    if [ -s $tmp/tmp ]
	    then
		if [ -f "$__dir/lock" ]
		then
		    _warning "removing lock file older than 30 minutes (PID `cat $__dir/lock`)"
		    LC_TIME=POSIX ls -l "$__dir/lock"
		    rm -f "$__dir/lock"
		else
		    # there is a small timing window here where pmlock
		    # might fail, but the lock file has been removed by
		    # the time we get here, so just keep trying
		    #
		    :
		fi
	    fi
	fi
	pmsleep 0.1
	__delay=`expr $__delay - 1`
    done

    if [ $__delay -eq 0 ]
    then
	# failed to gain mutex lock
	#
	if [ -f "$__dir/lock" ]
	then
	    _warning "is another $prog job running concurrently?"
	    LC_TIME=POSIX ls -l "$__dir/lock"
	else
	    _error "`cat $tmp/out`"
	fi
	_error "failed to acquire exclusive lock ($__dir/lock) ..."
	return 1
    else
	if $VERY_VERBOSE
	then
	    echo "Lock acquired `cat $__dir/lock` `ls -l $__dir/lock`"
	fi
    fi

    return 0
}

_unlock()
{
    $SHOWME && return
    __dir="$PCP_ETC_DIR/pcp/${IAM}"
    if [ -f "$__dir/lock" ]
    then
	rm -f "$__dir/lock"
	$VERY_VERBOSE && echo "Lock released"
    fi
}

# FreeBSD's egrep does not support -r nor -Z
#
# This variant accepts -r or -rl as the first argument ...
# -r always outputs the filename at the start of the line (no matter
# how may filenames are processed, followed by a | (using a : causes
# all manner of problems with the hostname local:) followed by line
# of text from the file that matches the pattern
#
_egrep()
{
    if [ "$1" = "-rl" ]
    then
	__text=false
    elif [ "$1" = "-r" ]
    then
	__text=true
    else
	echo >&2 "Botch: _egrep() requires -r or -rl, not $1"
	return
    fi
    shift
    __pat="$1"
    shift

    # skip errors from find(1) and egrep(1), only interested in matches for
    # real, existing files
    #
    find "$@" -type f 2>/dev/null \
    | while read __f
    do
	if echo "$__f" | grep -q -e '\.rpmsave$' -e '\.rpmnew$' -e '\.rpmorig$' \
	    -e '\.dpkg-dist$' -e '\.dpkg-old$' -e '\.dpkg-new$' >/dev/null 2>&1
	then
	    # ignore backup packaging files (daily and check scripts warn).
	    continue
	fi
	# possible race here with async execution of ${IAM}_check removing
	# the file after find saw it ... so check again for existance
	#
	[ -f "$__f" ] && egrep "$__pat" "$__f" 2>/dev/null >$tmp/_egrep
	if [ -s $tmp/_egrep ]
	then
	    if $__text
	    then
		sed -e "s;^;$__f|;" $tmp/_egrep
	    else
		echo "$__f"
	    fi
	fi
    done
    rm -f $tmp/_egrep
}

_usage()
{
    pmgetopt --progname=$prog --config=$tmp/usage --usage 2>&1 \
    | sed >&2 -e 's/ \[default/\
                        [default/'
    cat >&2 <<End-of-File

Avaliable commands:
   [-c classname] create  host ...
   {-c classname|-i ident} cond-create host ...
   [-c classname] {start|stop|restart|destroy|status} [host ...]

   and host may be a valid hostname or an egrep(1) pattern that matches
   the start of a hostname
End-of-File
    status=1
    exit
}

# find matching hosts from command line args ...
# 1. find control lines that contain each named host (or all hosts in the
#    case of no hosts on the command line)
# 2. if --class is specified, then restrict the hosts from 1. to those that
#    are in the named class
#
# Output file $tmp/args has this format
# <controlfile> <class> <host> <primary> <socks> <dir> <args> ...
#
_get_matching_hosts()
{
    rm -f $tmp/args
    if [ $# -eq 0 ]
    then
	# this regexp matches the start of all possible lines that
	# could be ${IAM} control lines, e.g
	# somehostname n ...
	#
	set -- '[^#$]'
    fi
    for host
    do
	$VERY_VERBOSE && echo "Looking for host $host in class $CLASS ..."
	rm -f $tmp/primary_seen
	if [ "$host" = "$LOCALHOST" ]
	then
	    pat="($host|LOCALHOSTNAME)"
	else
	    pat="$host"
	fi
	_egrep -r "^($pat|#!#$pat)" $CONTROLFILE $CONTROLDIR \
	| sed -e 's/|/ /' \
	| while read ctl_file ctl_line
	do
	    # the pattern above returns all possible control lines, but
	    # may need some further culling
	    #
	    ctl_host="`echo "$ctl_line" | sed -e 's/[ 	].*//'`"
	    if echo "$host" | grep '^[a-zA-Z0-9][a-zA-Z0-9.-]*$' >/dev/null
	    then
		# $host is a syntactically correct hostname so we ne                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      