#!/sbin/openrc-run
#
# OpenRC init script for the ISC DHCP server.
# Based on the former SysV /etc/init.d/isc-dhcp-server script.
#

description="ISC DHCP server"

PATH=/sbin:/bin:/usr/sbin:/usr/bin

command="/usr/sbin/dhcpd"
DHCPD_DEFAULT="${DHCPD_DEFAULT:-/etc/default/isc-dhcp-server}"

NAME4=dhcpd
NAME6=dhcpd6
DESC4="ISC DHCPv4 server"
DESC6="ISC DHCPv6 server"

DHCPDv4_CONF=${DHCPDv4_CONF:-/etc/dhcp/dhcpd.conf}
DHCPDv6_CONF=${DHCPDv6_CONF:-/etc/dhcp/dhcpd6.conf}
DHCPDv4_PID=${DHCPDv4_PID:-/var/run/dhcpd.pid}
DHCPDv6_PID=${DHCPDv6_PID:-/var/run/dhcpd6.pid}

depend() {
	need net localmount
	use slapd named logger
	after syslog
}

_read_config() {
	[ -f "$DHCPD_DEFAULT" ] || {
		eerror "$DHCPD_DEFAULT does not exist"
		if [ "$DHCPD_DEFAULT" = "/etc/default/isc-dhcp-server" ]; then
			eerror "Run 'dpkg-reconfigure isc-dhcp-server' to fix the problem."
		fi
		return 1
	}
	. "$DHCPD_DEFAULT"

	if [ -z "$DHCPDv4_PID" ]; then
		DHCPDv4_PID=$(sed -n -e 's/^[ \t]*pid-file-name[ \t]*"\(.*\)"[ \t]*;.*$/\1/p' \
			< "$DHCPDv4_CONF" 2>/dev/null | head -n 1)
	fi
	if [ -z "$DHCPDv6_PID" ]; then
		DHCPDv6_PID=$(sed -n -e 's/^[ \t]*dhcpv6-pid-file-name[ \t]*"\(.*\)"[ \t]*;.*$/\1/p' \
			< "$DHCPDv6_CONF" 2>/dev/null | head -n 1)
	fi
	DHCPDv4_PID="${DHCPDv4_PID:-/var/run/dhcpd.pid}"
	DHCPDv6_PID="${DHCPDv6_PID:-/var/run/dhcpd6.pid}"
}

_test_config() {
	local version="$1" conf="$2"

	if ! dhcpd -t "$version" -q -cf "$conf" >/dev/null 2>&1; then
		eerror "dhcpd self-test failed. Please fix $conf."
		dhcpd -t "$version" -cf "$conf" >&2
		return 1
	fi
}

_check_status() {
	local option="$1" pidfile="$2" name="$3" pid

	if [ ! -r "$pidfile" ]; then
		[ "$option" != -v ] || echo "$name is not running."
		return 3
	fi

	if read -r pid < "$pidfile" && ps -p "$pid" >/dev/null 2>&1; then
		[ "$option" != -v ] || echo "$name is running."
		return 0
	fi

	[ "$option" != -v ] || echo "$name is not running but $pidfile exists."
	return 1
}

_start_daemon() {
	local version="$1" conf="$2" name="$3" pidfile="$4" desc="$5"
	shift 5
	local interfaces="$*"

	_test_config "$version" "$conf" || return 1

	if [ -e "$pidfile" ]; then
		local pid
		if read -r pid < "$pidfile" && ps -p "$pid" >/dev/null 2>&1; then
			eerror "dhcpd service already running (pid file $pidfile currently exists)"
			return 1
		else
			ewarn "ignore stale pid file $pidfile"
		fi
	fi

	touch "/var/lib/dhcp/${name}.leases"

	ebegin "Starting $desc"
	start-stop-daemon -S -q -p "$pidfile" \
		-x "$command" -- "$version" -q -cf "$conf" $interfaces
	sleep 2
	if _check_status -q "$pidfile" "$name"; then
		eend 0
	else
		eerror "check syslog for diagnostics."
		eend 1
		return 1
	fi
}

_stop_daemon() {
	if _check_status -q "$DHCPDv4_PID" "$NAME4"; then
		ebegin "Stopping $DESC4"
		start-stop-daemon -K -q -p "$DHCPDv4_PID"
		eend $?
		rm -f "$DHCPDv4_PID"
	fi

	if _check_status -q "$DHCPDv6_PID" "$NAME6"; then
		ebegin "Stopping $DESC6"
		start-stop-daemon -K -q -p "$DHCPDv6_PID"
		eend $?
		rm -f "$DHCPDv6_PID"
	fi
}

start() {
	[ -x "$command" ] || return 0
	_read_config || return 0

	if [ -n "$INTERFACES" ] && [ -z "$INTERFACESv4" ]; then
		ewarn "DHCPv4 interfaces are no longer set by the INTERFACES variable in"
		ewarn "/etc/default/isc-dhcp-server. Please use INTERFACESv4 instead."
		ewarn "Migrating automatically for now, but this will go away in the future."
		INTERFACESv4="$INTERFACES"
	fi

	if [ -n "$INTERFACESv4" ]; then
		einfo "Launching IPv4 server only."
		_start_daemon "-4" "$DHCPDv4_CONF" "$NAME4" \
			"$DHCPDv4_PID" "$DESC4" "$INTERFACESv4" || return 1
	fi
	if [ -n "$INTERFACESv6" ]; then
		einfo "Launching IPv6 server only."
		_start_daemon "-6" "$DHCPDv6_CONF" "$NAME6" \
			"$DHCPDv6_PID" "$DESC6" "$INTERFACESv6" || return 1
	fi
	if [ -z "$INTERFACESv4" ] && [ -z "$INTERFACESv6" ]; then
		einfo "Launching both IPv4 and IPv6 servers (configure INTERFACES in /etc/default/isc-dhcp-server if you only want one or the other)."
		_start_daemon "-4" "$DHCPDv4_CONF" "$NAME4" \
			"$DHCPDv4_PID" "$DESC4" "" || return 1
		_start_daemon "-6" "$DHCPDv6_CONF" "$NAME6" \
			"$DHCPDv6_PID" "$DESC6" "" || return 1
	fi
}

stop() {
	[ -x "$command" ] || return 0
	_read_config || return 0
	_stop_daemon
}

status() {
	[ -x "$command" ] || return 0
	_read_config || return 0

	if [ -n "$INTERFACES" ] && [ -z "$INTERFACESv4" ]; then
		INTERFACESv4="$INTERFACES"
	fi
	if [ -n "$INTERFACESv4" ]; then
		printf "Status of %s: " "$DESC4"
		_check_status -v "$DHCPDv4_PID" "$NAME4" || return $?
	fi
	if [ -n "$INTERFACESv6" ]; then
		printf "Status of %s: " "$DESC6"
		_check_status -v "$DHCPDv6_PID" "$NAME6" || return $?
	fi
}
