#!/bin/sh /etc/rc.common
# shellcheck shell=sh
# shellcheck disable=SC2016,SC2034
# One-shot first-boot registration with headscale.
#
# Reads:
#   /etc/tailscale/authkey            (0600, from config-overlay)
#   /etc/config/r01-tailscale         option login_server
# Runs at boot AFTER tailscaled (START=80) and travelmate. Registers only while
# tailscaled reports NeedsLogin: any other state means the node is enrolled, and
# re-running `tailscale up` there would reset a manual tag back to tag:bootstrap.
# No --advertise-tags, so nodes enrol as tag:bootstrap and are promoted by hand
# with `headscale nodes tag`. See README "Node Promotion".
# Idempotent: safe to leave enabled forever. Only acts on first successful boot.
#
# Suppressed lints:
#   SC2016: procd command string is intentionally single-quoted. $VAR expands
#            at exec time inside the wrapped /bin/sh, not at parse time here
#   SC2034: USE_PROCD/START are contract vars consumed by /etc/rc.common

USE_PROCD=1
START=96

AUTHKEY=/etc/tailscale/authkey

boot() {
	start
}

start_service() {
	procd_open_instance
	procd_set_param command /bin/sh -c '
		set -eu

		LOGIN=$(uci -q get r01-tailscale.main.login_server 2>/dev/null || true)

		if [ -z "$LOGIN" ]; then
			logger -t r01-tailscale "r01-tailscale UCI missing login_server. Skipping"
			exit 0
		fi

		if [ ! -r '"$AUTHKEY"' ]; then
			logger -t r01-tailscale "no '"$AUTHKEY"'. Skipping first-boot registration"
			exit 0
		fi

		# tailscaled settles asynchronously after its own START=80, so poll for a
		# conclusive state rather than acting on NoState or an unavailable socket.
		# Starting is transient and always resolves to Running: keep waiting.
		i=0
		STATE=
		while [ "$i" -lt 60 ]; do
			STATE=$(tailscale status --json 2>/dev/null \
				| sed -n "s/.*\"BackendState\":[[:space:]]*\"\([^\"]*\)\".*/\1/p" \
				| head -n1 || true)
			case "$STATE" in
			NeedsLogin | NeedsMachineAuth | Stopped | Running)
				break
				;;
			esac
			i=$((i + 1))
			sleep 1
		done

		# Fails closed: anything other than NeedsLogin leaves the node alone.
		if [ "$STATE" != "NeedsLogin" ]; then
			logger -t r01-tailscale "backend state ${STATE:-unavailable} is not NeedsLogin. Nothing to do"
			exit 0
		fi

		HOST=$(uci -q get system.@system[0].hostname 2>/dev/null || echo "$(cat /proc/sys/kernel/hostname)")
		AK=$(cat '"$AUTHKEY"')

		logger -t r01-tailscale "registering with $LOGIN as $HOST"

		if tailscale up \
			--login-server="https://$LOGIN" \
			--auth-key="$AK" \
			--hostname="$HOST" \
			>/tmp/tailscale-bootstrap.log 2>&1
		then
			logger -t r01-tailscale "registration OK as tag:bootstrap. Promote with headscale nodes tag"
		else
			logger -t r01-tailscale "registration FAILED. See /tmp/tailscale-bootstrap.log"
			exit 1
		fi
	'
	procd_set_param respawn 0 0 0
	procd_set_param stdout 1
	procd_set_param stderr 1
	procd_close_instance
}
