#!/bin/sh
### BEGIN INIT INFO
# Provides:          securqbitd
# Required-Start:    $network $remote_fs $syslog
# Required-Stop:     $network $remote_fs $syslog
# Should-Start:      $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: SecurQbit VPN Daemon
# Description:       Manages the SecurQbit VPN tunnel, credentials and local control plane.
### END INIT INFO
# Generated by `securqbitd install`. Edits are overwritten on reinstall.

NAME=securqbitd
DAEMON=/usr/local/bin/securqbitd
DAEMON_ARGS='--config /etc/securqbit/config.yaml'
PIDFILE=/run/securqbit/securqbitd.pid
LOGFILE=/var/log/securqbit/securqbitd.out.log
RUNDIR=/run/securqbit
STATEDIR=/var/lib/securqbit
LOGDIR=/var/log/securqbit
STOP_TIMEOUT=20

[ -x "$DAEMON" ] || { echo "$DAEMON is missing" >&2; exit 5; }

prepare() {
	mkdir -p "$RUNDIR" && chmod 0755 "$RUNDIR"
	mkdir -p "$STATEDIR" && chmod 0700 "$STATEDIR"
	mkdir -p "$LOGDIR" && chmod 0750 "$LOGDIR"
	# /dev/net/tun has to exist before the first connect.
	modprobe -q tun 2>/dev/null
	return 0
}

# running succeeds when the pid file names a live process. A pid file outlives
# the crash that left it behind, so its existence alone proves nothing.
running() {
	[ -f "$PIDFILE" ] || return 1
	pid=$(cat "$PIDFILE" 2>/dev/null) || return 1
	[ -n "$pid" ] || return 1
	kill -0 "$pid" 2>/dev/null
}

start() {
	if running; then
		echo "$NAME is already running (pid $pid)"
		return 0
	fi
	prepare
	# shellcheck disable=SC2086
	"$DAEMON" $DAEMON_ARGS >>"$LOGFILE" 2>&1 &
	echo $! > "$PIDFILE"
	# A daemon that exits immediately — a bad config, a socket it cannot bind —
	# must not be reported as started.
	sleep 1
	if running; then
		echo "$NAME started (pid $pid)"
		return 0
	fi
	rm -f "$PIDFILE"
	echo "$NAME failed to start; see $LOGFILE" >&2
	return 1
}

stop() {
	if ! running; then
		rm -f "$PIDFILE"
		echo "$NAME is not running"
		return 0
	fi
	kill -TERM "$pid" 2>/dev/null
	# The daemon restores the host's routing and DNS on the way out; giving it
	# time to finish is the difference between a clean stop and a machine with
	# no network.
	i=0
	while [ "$i" -lt "$STOP_TIMEOUT" ] && kill -0 "$pid" 2>/dev/null; do
		sleep 1
		i=$((i + 1))
	done
	if kill -0 "$pid" 2>/dev/null; then
		echo "$NAME did not stop in ${STOP_TIMEOUT}s; killing it" >&2
		kill -KILL "$pid" 2>/dev/null
	fi
	rm -f "$PIDFILE"
	echo "$NAME stopped"
	return 0
}

status() {
	if running; then
		echo "$NAME is running (pid $pid)"
		return 0
	fi
	if [ -f "$PIDFILE" ]; then
		echo "$NAME is not running, but $PIDFILE exists"
		return 1
	fi
	echo "$NAME is not running"
	return 3
}

case "$1" in
	start)   start ;;
	stop)    stop ;;
	restart|force-reload)
		stop
		start
		;;
	status)  status ;;
	*)
		echo "Usage: $0 {start|stop|restart|force-reload|status}" >&2
		exit 2
		;;
esac
