#!/bin/sh
# service - see and control services, a front end to dinitctl
#
#   service                          every service, whether it starts at boot, its state
#   service status <name>
#   service start|stop|restart <name>
#   service enable|disable <name>    start at boot or not, applied right away too
set -u
PATH=/usr/bin
D=/etc/dinit.d

if [ -t 1 ]; then
	R=$(printf '\033[0m') B=$(printf '\033[1m') OK=$(printf '\033[32m') DIM=$(printf '\033[90m') WARN=$(printf '\033[33m')
else
	R= B= OK= DIM= WARN=
fi

die() { echo "service: $*" >&2; exit 1; }
need_root() { [ "$(id -u)" = 0 ] || die "must be run as root"; }
exists() { [ -f "$D/$1" ]; }

# dinit is not running in a chroot or an image being built
online() { dinitctl list >/dev/null 2>&1; }

# the program a service runs, empty for scripted ones
program() {
	grep -q '^type *= *process' "$D/$1" 2>/dev/null || return 0
	sed -n 's/^command *= *\([^ ]*\).*/\1/p' "$D/$1" | head -1
}
installed() { _p=$(program "$1"); [ -z "$_p" ] || [ -x "$_p" ]; }

# boot plumbing is everything system pulls in, it is not for enabling by hand
core() {
	_seen=" boot recovery single getty " _todo=system
	while [ -n "$_todo" ]; do
		_next=""
		for _c in $_todo; do
			case "$_seen" in *" $_c "*) continue ;; esac
			_seen="$_seen$_c "
			_next="$_next $(sed -n 's/^\(depends-on\|waits-for\) *: *//p' "$D/$_c" 2>/dev/null)"
		done
		_todo=$_next
	done
	echo "$_seen"
}

list() {
	_core=$(core)
	printf '\n  %s%-16s %-9s %s%s\n' "$B" SERVICE BOOT STATE "$R"
	for f in "$D"/*; do
		[ -f "$f" ] || continue
		n=${f##*/}
		case "$_core" in *" $n "*) continue ;; esac
		case "$n" in *-prepare|*-keygen) continue ;; esac
		if [ -e "$D/boot.d/$n" ]; then e="${OK}yes      ${R}"; else e="${DIM}no       ${R}"; fi
		if ! installed "$n"; then s="${DIM}not installed${R}"
		elif [ "$(id -u)" != 0 ]; then s="${DIM}?${R}"
		elif dinitctl is-started "$n" >/dev/null 2>&1; then s="${OK}running${R}"
		elif dinitctl is-failed "$n" >/dev/null 2>&1; then s="${WARN}failed${R}"
		else s="${DIM}stopped${R}"; fi
		printf '  %-16s %s %s\n' "$n" "$e" "$s"
	done
	echo
}

verb=${1:-list}
[ "$verb" = list ] || [ "$verb" = ls ] && { list; exit 0; }
n=${2:-}
[ -n "$n" ] || die "usage: service $verb <name>"
case "$n" in */*|.*) die "invalid service name: $n" ;; esac
exists "$n" || die "no such service: $n"

case "$verb" in
status)
	installed "$n" || { echo "$n is not installed, $(program "$n") is missing"; exit 4; }
	exec dinitctl status "$n" ;;
start|stop|restart)
	need_root
	installed "$n" || die "$n is not installed, $(program "$n") is missing"
	exec dinitctl "$verb" "$n" ;;
enable|disable)
	need_root
	if online; then dinitctl "$verb" "$n" >/dev/null || exit 1
	else dinitctl --offline "$verb" "$n" >/dev/null || exit 1; fi
	if [ "$verb" = enable ]; then
		echo "$n will start at boot"
		installed "$n" || echo "  ${WARN}$(program "$n") is not installed yet${R}"
	else
		echo "$n will no longer start at boot"
	fi ;;
*)
	sed -n '2,8p' "$0" | sed 's/^# \{0,1\}//'
	exit 2 ;;
esac
