#!/bin/sh
# Apply /etc/default/console without a reboot.
# Usage: console-mode apply

set -eu

DEFAULTS=/etc/default/console
SYSTEMD_DIR=/etc/systemd/system
UNITDIR=/usr/lib/systemd/system
CONSOLE=cruft
CONSOLE_TTYS="1 2 3 4 5 6"

if [ -f "$DEFAULTS" ]; then
	# shellcheck disable=SC1090
	. "$DEFAULTS"
fi

usage() {
	echo "Usage: $0 apply" >&2
	echo "  Reads $DEFAULTS (CONSOLE=cruft|kernel, CONSOLE_TTYS=...)." >&2
	echo "  Rewrites the static VT wiring and switches the backend." >&2
	exit 1
}

[ "${1:-}" = "apply" ] || usage

case "$CONSOLE" in
cruft|kernel) ;;
*)
	echo "console-mode: unknown CONSOLE='$CONSOLE'" >&2
	exit 1
	;;
esac

# shellcheck disable=SC2086
set -- $CONSOLE_TTYS
boot_tty=${1:-1}

# Static wiring (what the install-time postinst writes): alias
# on-demand VTs (logind autovt@) to cruft@, want the boot VT's cruft@
# on getty.target, mask the managed kernel gettys.
rewire() {
	rm -f "$SYSTEMD_DIR/autovt@.service"
	# shellcheck disable=SC2086
	for n in $CONSOLE_TTYS; do
		rm -f "$SYSTEMD_DIR/getty@tty${n}.service" \
			"$SYSTEMD_DIR/getty.target.wants/cruft@tty${n}.service"
	done
	if [ "$CONSOLE" = "cruft" ]; then
		mkdir -p "$SYSTEMD_DIR/getty.target.wants"
		ln -sf "$UNITDIR/cruft@.service" "$SYSTEMD_DIR/autovt@.service"
		ln -sf "$UNITDIR/cruft@.service" \
			"$SYSTEMD_DIR/getty.target.wants/cruft@tty${boot_tty}.service"
		# shellcheck disable=SC2086
		for n in $CONSOLE_TTYS; do
			ln -sf /dev/null "$SYSTEMD_DIR/getty@tty${n}.service"
		done
	fi
}
rewire

# What is currently running on the managed TTYs?
running_cruft=0
running_getty=0
for n in $CONSOLE_TTYS; do
	if systemctl is-active --quiet "cruft@tty${n}.service" 2>/dev/null || \
	   systemctl is-active --quiet "autovt@tty${n}.service" 2>/dev/null; then
		running_cruft=1
	fi
	if systemctl is-active --quiet "getty@tty${n}.service" 2>/dev/null; then
		running_getty=1
	fi
done

need_backend_switch=0
if [ "$CONSOLE" = "cruft" ] && [ "$running_getty" -eq 1 ]; then
	need_backend_switch=1
fi
if [ "$CONSOLE" = "kernel" ] && [ "$running_cruft" -eq 1 ]; then
	need_backend_switch=1
fi
# Fresh boot / nothing up yet: start the requested backend.
if [ "$running_cruft" -eq 0 ] && [ "$running_getty" -eq 0 ]; then
	need_backend_switch=1
fi

systemctl daemon-reload

failed=0

if [ "$need_backend_switch" -eq 1 ]; then
	# Switching cruft ↔ kernel (or first bring-up).
	for n in $CONSOLE_TTYS; do
		systemctl stop "cruft@tty${n}.service" "autovt@tty${n}.service" \
			"getty@tty${n}.service" 2>/dev/null || true
	done
	if [ "$CONSOLE" = "cruft" ]; then
		# Only the boot VT - others start on first Alt-Fn via logind/autovt@.
		if ! systemctl start "cruft@tty${boot_tty}.service"; then
			echo "console-mode: failed to start cruft@tty${boot_tty}" >&2
			systemctl --no-pager -l status "cruft@tty${boot_tty}.service" 2>&1 | tail -n 20 >&2 || true
			failed=1
		fi
	else
		for n in $CONSOLE_TTYS; do
			if ! systemctl start "getty@tty${n}.service"; then
				echo "console-mode: failed to start getty@tty${n}" >&2
				failed=1
			fi
		done
	fi
	echo "console-mode: switched backend to CONSOLE=$CONSOLE"
else
	echo "console-mode: wiring updated (daemon-reload); not restarting active VTs"
fi

if [ "$CONSOLE" = "cruft" ]; then
	echo "console-mode: boot VT=tty${boot_tty}; tty2+ start on first switch (autovt@ → cruft@)"
	# Font / bar / scrollback changes take effect on logout: a logout
	# ends agetty, systemd restarts cruft, and cruft re-reads
	# /etc/cruft.conf.
	for n in $CONSOLE_TTYS; do
		u="autovt@tty${n}.service"
		[ "$n" = "$boot_tty" ] && u="cruft@tty${n}.service"
		state=$(systemctl is-active "$u" 2>/dev/null || echo inactive)
		# Legacy name if someone still has an old wants symlink.
		if { [ "$state" = "inactive" ] || [ "$state" = "unknown" ]; } && \
		   [ "$n" != "$boot_tty" ] && \
		   [ "$(systemctl is-active "cruft@tty${n}.service" 2>/dev/null)" = "active" ]; then
			u="cruft@tty${n}.service"
			state=active
		fi
		echo "console-mode: $u is-active=$state"
	done
else
	echo "console-mode: CONSOLE=kernel on tty$(echo "$CONSOLE_TTYS" | tr ' ' ',')"
fi

exit "$failed"
