#!/bin/sh
# Copyright: 2026 Aitor <aitor@genuen.org>
# License: CC0-1.0
# s6-rc: seed early subsystems, promote listener; terminal coldplug (-1).
# Trail: /run/vdev/vdevd_1.log (headless-friendly).
# Worker not backgrounded by OpenRC/s6/runit; vdevd -1 itself detaches
# (coldplug_only, no -f) — do not wrap it in another &.

echo "vdev-coldplug: start $(date -u +%Y-%m-%dT%H:%M:%SZ) pid=$$"

if [ -r /run/vdev/env ]; then
	# shellcheck disable=SC1091
	. /run/vdev/env
elif [ -r /lib/vdev/vdev-env.sh ]; then
	# shellcheck disable=SC1091
	. /lib/vdev/vdev-env.sh
else
	echo "vdev-coldplug: no /run/vdev/env or vdev-env.sh"
	exit 0
fi

[ -x "${VDEV_BIN}" ] || exit 0

: "${VDEV_UDEV_CONTROL:=/run/udev/control}"
: "${VDEV_EARLY_SUBSYSTEMS:=graphics input hid i2c drm}"
: "${VDEV_PROMOTE_RETRIES:=5}"
: "${VDEV_EARLY_SETTLE_TIMEOUT:=15}"
: "${VDEV_LISTEN_GRACE:=1.0}"

VDEV_TERMINAL_CONFIG="${VDEV_CONFIG_DIR}/${VDEV_TERMINAL}"
VDEV_LONG_RUNNING_CONFIG="${VDEV_CONFIG_DIR}/${VDEV_LONG_RUNNING}"

# Prefer JSON array order (graphics/drm before input for display managers).
_gj="${VDEV_GLOBALS_JSON:-/etc/vdev/vdevd.globals.json}"
if [ -r "${_gj}" ] && command -v jq >/dev/null 2>&1; then
	_subs="$(sed -E 's|//.*||g' "${_gj}" | sed 's|/\*.*\*/||g' | grep -v '^$' |
		jq -r '(.profiles.early.subsystems // .states.early.subsystems // []) | .[]' 2>/dev/null |
		tr '\n' ' ')"
	[ -n "${_subs}" ] && VDEV_EARLY_SUBSYSTEMS="${_subs}"
elif [ -n "${VDEV_JSON_DATA:-}" ]; then
	_subs="$(printf '%s' "${VDEV_JSON_DATA}" | jq -r '
		(.profiles.early.subsystems // .states.early.subsystems // []) | .[]' 2>/dev/null |
		tr '\n' ' ')"
	[ -n "${_subs}" ] && VDEV_EARLY_SUBSYSTEMS="${_subs}"
fi

# shellcheck disable=SC1091
. /lib/vdev/vdev-boot-vga-kms.sh

vdev_promote_to_long_running() {
	_try=0
	_max="${VDEV_PROMOTE_RETRIES}"
	_cfg="${VDEV_LONG_RUNNING_CONFIG}"

	while [ "${_try}" -lt "${_max}" ]; do
		_try=$((_try + 1))
		if [ -n "${_cfg}" ]; then
			vdevadm control --promote="${_cfg}" && return 0
		else
			vdevadm control --promote && return 0
		fi
		sleep 0.1
	done
	return 1
}

# Do NOT use [ -e control ]: a dead AF_UNIX left by initrd vdevd survives on
# /dev/metadata/udev (via /run/udev symlink) and yields ECONNREFUSED.
# Wait until the live listener answers --print-pid.
vdev_wait_for_live_control() {
	_i=0
	_max=250
	_pid=""
	_err=""

	while [ "${_i}" -lt "${_max}" ]; do
		_err="$(vdevadm control --print-pid 2>&1)" && _pid="${_err}" || _pid=""
		if [ -n "${_pid}" ] && kill -0 "${_pid}" 2>/dev/null; then
			# Drop any race where we connected during rebind.
			sleep "${VDEV_LISTEN_GRACE}"
			_pid="$(vdevadm control --print-pid 2>/dev/null)" || _pid=""
			[ -n "${_pid}" ] && kill -0 "${_pid}" 2>/dev/null && return 0
		else
			# Stale socket: unlink so a late-starting vdevd can bind cleanly.
			if [ -e "${VDEV_UDEV_CONTROL}" ] && [ -z "${_pid}" ]; then
				case "${_err}" in
					*refused*|*Connection\ refused*|*No\ such\ file*)
						rm -f "${VDEV_UDEV_CONTROL}" 2>/dev/null || true
						;;
				esac
			fi
		fi
		sleep 0.1
		_i=$((_i + 1))
	done
	return 1
}

load_boot_vga_kms

if ! vdev_wait_for_live_control; then
	ls -la /run/udev "$VDEV_UDEV_CONTROL" 2>&1 || true
	exit 0
fi

echo "vdev-coldplug: seeding: ${VDEV_EARLY_SUBSYSTEMS}"
for _s in ${VDEV_EARLY_SUBSYSTEMS}; do
	if vdevadm trigger -s "${_s}" -a add; then
		echo "vdev-coldplug: trigger ${_s} ok"
	else
		echo "vdev-coldplug: trigger ${_s} rc=$?"
	fi
done

vdevadm settle -t "${VDEV_EARLY_SETTLE_TIMEOUT}" || \
	echo "vdev-coldplug: settle rc=$?"

if vdev_promote_to_long_running; then
	echo "vdev-coldplug: promoted to ${VDEV_LONG_RUNNING_CONFIG}"
    
else
	echo "vdev-coldplug: promote failed"
	vdevadm control --print-pid 2>&1 || true
fi

# coldplug_only (-1, no -f) already detaches; do not background again.
"${VDEV_BIN}" -1 -c "${VDEV_TERMINAL_CONFIG}" "${VDEV_MOUNTPOINT}"

exit 0
