#!/bin/sh
# Copyright (C) 2017 Dmitry Bogatov <KAction@gnu.org>

# Author: Dmitry Bogatov <KAction@gnu.org>

# 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 3
# 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.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

set -e

# rescan and invoke-rc.d actions are done only if runit is init
is_runit () {
	[ -f  /run/runit.stopit ]
}

is_installed () {
	[ -f  /sbin/runit ]
}

# No-Op if the service is not enabled
# sv can't send signals to a disabled service
is_enabled () {
	[ -h /etc/service/"$NAME" ]
}

sv_warn () {
	echo "warning: sv: failed to signal $NAME"
	true
}

# workaround for races as in #919296
ok_pipe () {
	[ -p "/etc/sv/$NAME/supervise/ok" ]
}

postinst () {
	local action="${1}" previous="${2:-}"

	if [ -x /usr/sbin/policy-rc.d ]; then
		set +e ; /usr/sbin/policy-rc.d "${NAME}" start ; rc=$? ; set -e
		if [ "$rc" = "101" ]; then
			echo "runit: ${NAME}: start action denied by policy-rc.d" && return 0
		fi
	fi
	# create supervise links at runtime, only if runit is installed
	mkdir -p /run/runit/supervise
	if [ -e /lib/runit/make_svlinks ]; then
		/lib/runit/make_svlinks "$NAME"
	fi

	# It is important to not override local admin
	# decision (see #899242 and 942323 ).
	if [ "${ENABLE}" = yes ]; then
		if [ ! -h "/etc/runit/runsvdir/default/.$NAME" ] && \
		    [ ! -h "/etc/runit/runsvdir/default/$NAME" ]; then
			# $NAME link tested to avoid infinte loop of symlinks
			ln -sf "/etc/sv/$NAME" "/etc/runit/runsvdir/default/$NAME"
			if is_runit && pidof runsvdir > /dev/null ; then
				# always force a rescan after enable
				kill -s ALRM 1
			fi
		fi
	# ENABLE=no is always a no-op
	fi

	#invoke-rc.d
	if is_runit && is_enabled ; then
		if [ "${action}" = 'configure' ] || [ "${action}" = 'abort-upgrade' ] || \
			[ "${action}" = 'abort-deconfigure' ] || [ "${action}" = 'abort-remove' ] ; then
			if [ "${ONUPGRADE}" = restart ] && [ -n "${previous}" ] && ok_pipe ; then
				sv restart ${NAME} || sv_warn
			elif [ "${ONUPGRADE}" = reload ] && [ -n "${previous}" ] && ok_pipe ; then
				sv reload ${NAME} || sv_warn
			elif  ok_pipe ; then
				# ONUPGRADE=stop || ONUPGRADE=nostop
				# ONUPGRADE= restart || reload and [ ! -n "${previous}" ]
				sv start ${NAME} || sv_warn
			else
				return 0
			fi
		fi
	fi
}

prerm () {
	local action="${1}"
	# invoke-rc.d
	if is_runit && is_enabled ; then
		if [ -x /usr/sbin/policy-rc.d ]; then
			set +e ; /usr/sbin/policy-rc.d "${NAME}" stop ; rc=$? ; set -e
			if [ "$rc" = "101" ]; then
				echo "runit: ${NAME}: stop action denied by policy-rc.d" && return 0
			fi
		fi
		if [ "${ONUPGRADE}" = stop ] && ok_pipe ; then
			sv stop ${NAME} || sv_warn
		elif [ "${action}" = 'remove' ] && ok_pipe ; then
			# ONUPGRADE=restart || ONUPGRADE=nostop
			sv stop ${NAME} || sv_warn
		else
			return 0
		fi
	fi	
}

postrm () {
	local action="${1}"

	if [ "${action}" != 'purge' ] && [ "${action}" != 'remove' ] ; then
	    return
	fi

	# When "ENABLE=no" the $NAME link is an admin decision
	# so we don't remove it.
	# Links in other runsvdirs is responsibility of administrator.
	if [ "${action}" = 'remove' ] && [ "${ENABLE}" = yes ] ; then
		rm -f "/etc/runit/runsvdir/default/$NAME"
	fi
	if [ "${action}" = 'purge' ] ; then
		rm -f "/etc/runit/runsvdir/default/$NAME"
		rm -f "/etc/runit/runsvdir/default/.$NAME"
		#TODO: make sure runsv exit before we remove supervise files, printf x on supervise
	fi

	# If runscript was never invoked, there will be no files
	# in this directory, and `dpkg' will remove it. In this case,
	# we have nothing to do.
	for supervise in "/etc/sv/$NAME/supervise" \
	                 "/etc/sv/$NAME/log/supervise"; do
		if [ -d "$supervise" ] ; then
			#TODO test/loop that runsv is gone before remove supervise files
			# Actually only `down' may be absent, but it does not
			# matter.

			for file in control lock ok pid stat status down ; do
				rm -f "$supervise/$file"
			done

			# It should be empty now. If it is not, it means that
			# system administrator put something there. It is very
			# stupid, but will of user is sacred, and directory is
			# left as-is in such case.
			#
			# NOTE: Non-POSIX option is used. The day coreutils will
			# no longer be essential, it will require a fix.
			if [ -h "$supervise" ]; then
				rm "$supervise"
			else
				rmdir --ignore-fail-on-non-empty "$supervise"
			fi
		fi
	done

	if [ "${action}" = 'purge' ] ; then
		#rm -f "/etc/runit/runsvdir/default/$NAME"
		#rm -f "/etc/runit/runsvdir/default/.$NAME"
		readonly logdir="/var/log/runit/${NAME}"
		if [ -d "${logdir}" ] ; then
			rm -r "${logdir}"
		fi
	fi
}

#called as NAME='servicename' PKG='pkgname' /usr/lib/runit-helper/runit-helper sv_purge
sv_purge () {
	[ -z "$PKG" ] && echo "$PKG empty" && return 0
	[ -z "$NAME" ] && echo "$NAME empty" && return 0
	if echo "$NAME" | grep -E '.*/$' >/dev/null ; then
		echo "warning: $NAME : not allowed, ends with /"
		return 0  #ends with / , dangerous with rm -rf
	fi
	servicesdir=/usr/share/runit/sv.now
	#if it's enabled, make sure runsv exits before the dir is removed
	if [ -h /etc/runit/runsvdir/default/$NAME ]; then
		if [ -r  /etc/runit/runsvdir/default/$NAME/supervise/stat ]; then
			svstatus="$(cat /etc/runit/runsvdir/default/$NAME/supervise/stat)"
		fi
		case "$svstatus" in
			run|down|'run, want down' )  #maybe also 'down, want up' and 'finish'
			touch "/etc/runit/runsvdir/default/$NAME/down" || true
			printf x >  "/etc/runit/runsvdir/default/$NAME/supervise/control" && \
			  unlink "/etc/runit/runsvdir/default/$NAME"
			;;
			*)
			unlink  "/etc/runit/runsvdir/default/$NAME"
			;;
		esac
	fi
	if [ -r "$servicesdir/$NAME/.meta/pkg" ]; then
		thispkg="$(cat $servicesdir/$NAME/.meta/pkg)"
		if [ "$thispkg" = "$PKG" ]; then
			#TODO: also clean supervise in /run ?
			rm -r  "$servicesdir/$NAME"
			logdir="/var/log/runit/${NAME}"
			if [ -d "${logdir}" ] ; then
				rm -r "${logdir}"
			fi
		fi
	else
		#give up if not from this package
		#should not happen in /usr/share/runit/sv.now/ but still..
		return 0
	fi
}

"$@"
# vim: sw=4:et
