#!/bin/sh
#
# Copyright (c) 2012-2017, Parallels International GmbH
#
# Our contact details: Parallels International GmbH, Vordergasse 59, 8200
# Schaffhausen, Switzerland.
#

RUN=1
DAEMON="/usr/sbin/shaman-monitor"
SHAMAN="/usr/sbin/shaman"
PID_FILE="/var/run/shamand-monitor.pid"
LOGGER="/usr/bin/logger"
PARAMS="$@"
NAME="`basename $0`"
AWK="/bin/awk"

function shutdown_req() {
	RUN=0
	local pid="$PID"
	if [ "$pid" ]; then
		kill "$pid"
	fi
}

function trigger() {
	echo "$1" > /proc/sysrq-trigger
}

function fence()
{
	# on its start, shaman establishes a new connection to the cluster, so
	# it's perfectly fine to call it here, even if access to the cluster was revoked
	conf="`$SHAMAN --quiet get-config`"
	res=$?
	if [ $res -ne 0 ]; then
		logger -t "$NAME" -i "Failed to read shaman's global config ($res), do nothing"
		return
	fi
	local action="`echo "$conf" | $AWK -F\= '$1=="LEASE_LOST_ACTION" {print $2}'`"
	logger -t "$NAME" -i "Executing '$action' action..."

	case $action in
	crash)
		trigger "c"
		;;
	halt)
		trigger "o"
		;;
	reboot)
		trigger "b"
		;;
	none)
		;;
	*)
		logger -t "$NAME" -i "Unknown action, do nothing"
		;;
	esac
}

function monitor_func()
{
	trap shutdown_req 2 3 15
	logger -t "$NAME" -i "Monitor started"
	while true; do
		logger -t "$NAME" -i "Starting $DAEMON $PARAMS ..."
		"$DAEMON" "$PARAMS" > /dev/null 2>&1 &
		PID=$!
		while true; do
			wait "$PID"
			# We need to restart wait if it was interrupted by a signal.
			# The problem is that we can't distinguish situations, (1) when wait is
			# interrupted by a signal, and (2) when the background service was
			# terminated by a signal. In both situations wait will return 128 + signo.
			# The solution is to restart wait if it's exit code is in (128, 160)
			# interval. If it's situation 2, restarted wait will return 127, which
			# means, that the background service was terminated.
			code=$?
			[ "$code" -ne 127 ] || break;
			EXIT_CODE="$code"
			[ "$EXIT_CODE" -gt 128 -a "$EXIT_CODE" -lt 160 ] || break;
		done

		if [ $EXIT_CODE -lt 127 ]; then
			logger -t "$NAME" -i "$DAEMON exited with code $EXIT_CODE"
			case $EXIT_CODE in
				0 | 3 | 4 | 5 | 7 | 19)
					# 0 - shaman-monitor successfully exited
					# 3 - shaman-monitor is already running
					# 4 - cluster name not defined
					# 5 - node is not registered in cluster
					# 7 - local lock lease is lost
					# 19- cluster mount point is dead
				break
					;;
				122)
					# 122 is returned when pcs library finds that
					# our access to the cluster was revoked and
					# exits unconditionally (with code -134).
					fence
				break
					;;
				esac
			else
			logger -t "$NAME" -i "$DAEMON killed with signal $((EXIT_CODE-128))"
			fi
		[ "$RUN" -eq 1 ] || break
			sleep 5
		[ "$RUN" -eq 1 ] || break
			logger -t "$NAME" -i "Will restart $DAEMON"
	done
	logger -t $NAME -i "Monitor stopped"
	rm -f $PID_FILE > /dev/null 2>&1
}

[ ! -x $LOGGER -o ! -x $DAEMON ] && exit 1

exec </dev/null >/dev/null 2>&1
monitor_func &
echo $! > $PID_FILE
disown -h
exit 0
