#!/bin/sh
### BEGIN INIT INFO
# Provides:          mlu-openvpn-client
# Required-Start:    $remote_fs $network
# Required-Stop:     $remote_fs $network
# Should-Start:      $named
# Should-Stop:       $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: OpenVPN client tunnels
### END INIT INFO

set -e

. /lib/lsb/init-functions

DAEMON=/usr/sbin/openvpn
CONFIG_DIR=/etc/openvpn/client
RUN_DIR=/var/run/openvpn-client
LEGACY_PIDFILE=/var/run/openvpn.client.pid
LEGACY_COMPAT_PIDFILE=/var/run/openvpn.pid
LOG_FILE=/var/log/openvpn/openvpn.log
STATUS_FILE=/var/log/openvpn/openvpn-status.log

ensure_legacy_config()
{
	legacy_config=/etc/openvpn/client.conf
	profile_config="$CONFIG_DIR/client.conf"

	# Keep the old file authoritative when it already exists.  This makes
	# existing update scripts and configuration editors continue to work.
	if test -f "$legacy_config" || test -L "$legacy_config"; then
		if test ! -L "$legacy_config" && test ! -e "$profile_config" && test ! -L "$profile_config"; then
			ln -s ../client.conf "$profile_config"
		fi
	# A directory-only installation still gets the old path as a read/write
	# compatibility alias for the first profile.
	else
		for candidate in "$CONFIG_DIR"/*.conf; do
			if test -f "$candidate"; then
				ln -s "client/`basename "$candidate"`" "$legacy_config"
				break
			fi
		done
	fi
}

link_legacy_pidfile()
{
	if test -f "$LEGACY_PIDFILE"; then
		rm -f "$LEGACY_COMPAT_PIDFILE"
		ln -s openvpn.client.pid "$LEGACY_COMPAT_PIDFILE"
	fi
}

wait_for_pidfile()
{
	pidfile="$1"
	i=0
	while test "$i" -lt 5; do
		if test -s "$pidfile"; then
			return 0
		fi
		i=`expr "$i" + 1`
		sleep 1
	done
	return 1
}

start_instance()
{
	config="$1"
	name=`basename "$config" .conf`
	pidfile="$RUN_DIR/$name.pid"
	is_legacy=0
	legacy_target=`readlink -f /etc/openvpn/client.conf 2>/dev/null || true`
	config_target=`readlink -f "$config" 2>/dev/null || true`
	if test "$name" = client || { test -n "$legacy_target" && test "$legacy_target" = "$config_target"; }; then
		is_legacy=1
		# check4deadTUN() identifies duplicate client tunnels from this
		# exact command-line path, so this must remain a real OpenVPN
		# --writepid argument rather than only a post-start symlink.
		pidfile="$LEGACY_PIDFILE"
	fi

	if test -f "$pidfile" && kill -0 `cat "$pidfile"` 2>/dev/null; then
		if test "$is_legacy" -eq 1; then
			link_legacy_pidfile
		fi
		return 0
	fi

	rm -f "$pidfile"
	"$DAEMON" --daemon "mlu-openvpn-client-$name" --nobind \
		--config "$config" --writepid "$pidfile" \
		--log-append "$LOG_FILE" --status "$STATUS_FILE" \
		--status-version 2
	if test "$is_legacy" -eq 1; then
		wait_for_pidfile "$pidfile" || return 1
		link_legacy_pidfile
	fi
}

stop_pidfile()
{
	pidfile="$1"

	if test -f "$pidfile"; then
		start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
			--pidfile "$pidfile" || true
		rm -f "$pidfile"
	fi
}

reload_pidfile()
{
	pidfile="$1"

	if test -f "$pidfile"; then
		kill -HUP `cat "$pidfile"` 2>/dev/null || true
	fi
}

case "$1" in
	start)
		mkdir -p "$RUN_DIR"
		mkdir -p /var/log/openvpn
		touch "$LOG_FILE" "$STATUS_FILE"
		ensure_legacy_config
		cd "$CONFIG_DIR"
		found=0
		for config in *.conf; do
			test -f "$config" || continue
			found=1
			start_instance "$CONFIG_DIR/$config"
		done
		if test "$found" -eq 0; then
			echo "ERROR: no OpenVPN client configuration found in $CONFIG_DIR (expected /etc/openvpn/client.conf or $CONFIG_DIR/*.conf)" >&2
			exit 1
		fi
		;;
	stop)
		stop_pidfile "$LEGACY_PIDFILE"
		for pidfile in "$RUN_DIR"/*.pid; do
			test -f "$pidfile" || continue
			stop_pidfile "$pidfile"
		done
		rm -f "$LEGACY_COMPAT_PIDFILE"
		;;
	reload|force-reload)
		reload_pidfile "$LEGACY_PIDFILE"
		for pidfile in "$RUN_DIR"/*.pid; do
			test -f "$pidfile" || continue
			reload_pidfile "$pidfile"
		done
		;;
	restart)
		"$0" stop
		"$0" start
		;;
	fw-restart)
		# The legacy SUSE caller uses this action.  The custom package does
		# not own firewall policy, but it must retain the service contract.
		"$0" restart
		;;
	status)
		status=0
		found=0
		for pidfile in "$LEGACY_PIDFILE" "$RUN_DIR"/*.pid; do
			test -f "$pidfile" || continue
			found=1
			name=`basename "$pidfile" .pid`
			if test -f "$pidfile" && kill -0 `cat "$pidfile"` 2>/dev/null; then
				echo "$name is running"
			else
				echo "$name is not running"
				status=3
			fi
		done
		if test "$found" -eq 0; then
			echo "ERROR: no OpenVPN client PID file found" >&2
			status=3
		fi
		exit "$status"
		;;
*)
		echo "Usage: $0 {start|stop|reload|force-reload|restart|fw-restart|status}" >&2
		exit 1
		;;
esac

exit 0
