#!/bin/sh
# Select s6-rc (s6-linux-init PID1) or 66 (66 boot as PID1).
# Usage: genuen-init-select [s6-rc|66|status]
set -e

STATE=/etc/default/genuen-init
MANAGER_LINK=/etc/s6-linux-init/manager
SKEL=/etc/s6-linux-init/skel
SCRIPTS='rc.init rc.shutdown rc.shutdown.final runlevel'
LIBDIR=/usr/lib/genuen-init-select
STATEDIR=/var/lib/genuen-init-select
# Canonical tree seeds ship in 66-policy → /usr/share/66/seed/.
POLICY_SEED_66=/usr/share/66/seed


migrate_legacy() {
	# Package rename genuen-rc-select → genuen-init-select
	if [ -d /var/lib/genuen-rc-select ] && [ ! -e "$STATEDIR" ]; then
		mv /var/lib/genuen-rc-select "$STATEDIR"
	fi
	if [ -f /etc/default/genuen-rc ] && [ ! -f "$STATE" ]; then
		mv /etc/default/genuen-rc "$STATE"
	fi
	# Transfer dpkg-divert ownership if still registered under the old name
	if dpkg-divert --list /usr/bin/66-scandir 2>/dev/null | grep -q genuen-rc-select; then
		dpkg-divert --package genuen-rc-select --remove --no-rename /usr/bin/66-scandir >/dev/null 2>&1 || true
		if ! dpkg-divert --list /usr/bin/66-scandir 2>/dev/null | grep -q .; then
			dpkg-divert --package genuen-init-select --add --no-rename \
				--divert /usr/bin/66-scandir.real /usr/bin/66-scandir >/dev/null 2>&1 || true
		fi
	fi
}


s6_rc_scripts() {
	echo /etc/s6-rc/current/scripts
}

sixty_scripts() {
	echo /etc/66/current/scripts
}

backend_for() {
	case "$1" in
		s6-rc) s6_rc_scripts ;;
		66) sixty_scripts ;;
		*) return 1 ;;
	esac
}

pid1_for() {
	case "$1" in
		s6-rc) echo s6-linux-init ;;
		66) echo 66 ;;
		*) return 1 ;;
	esac
}

policy_ok() {
	case "$1" in
		s6-rc)
			[ -x /etc/s6-rc/current/scripts/rc.init ] || {
				echo "genuen-init-select: s6-rc backend missing (install s6-rc-policy)" >&2
				return 1
			}
			command -v s6-linux-init >/dev/null 2>&1 || [ -x /usr/bin/s6-linux-init ] || {
				echo "genuen-init-select: s6-linux-init binary missing" >&2
				return 1
			}
			;;
		66)
			[ -x /etc/66/current/scripts/rc.init ] || {
				echo "genuen-init-select: 66 backend missing (install 66-policy)" >&2
				return 1
			}
			command -v 66 >/dev/null 2>&1 || {
				echo "genuen-init-select: 66 binary missing" >&2
				return 1
			}
			command -v 66-hpr >/dev/null 2>&1 || [ -x /usr/bin/66-hpr ] || [ -x /usr/libexec/66/66-hpr ] || {
				echo "genuen-init-select: 66-hpr missing (need 66 package)" >&2
				return 1
			}
			;;
	esac
}

write_state() {
	mkdir -p "$(dirname "$STATE")"
	cat >"$STATE" <<EOF
# Managed by genuen-init-select.
# MANAGER: s6-rc | 66
# PID1:    s6-linux-init | 66
MANAGER=$1
PID1=$2
EOF
}

# Resolve /etc/s6-linux-init/current even when the symlink is absolute and we
# are operating on a chroot / mounted root (readlink -f would escape).
current_scripts_dir() {
	local base=/etc/s6-linux-init
	local cur link target

	cur="$base/current"
	[ -e "$cur" ] || [ -L "$cur" ] || return 1
	if [ -d "$cur/scripts" ]; then
		echo "$cur/scripts"
		return 0
	fi
	link=$(readlink "$cur" 2>/dev/null || true)
	case "$link" in
		/*)
			target="$base/$(basename "$link")"
			;;
		*)
			target="$base/$link"
			;;
	esac
	[ -d "$target/scripts" ] || return 1
	echo "$target/scripts"
}

# Used only when PID1 is s6-linux-init (manager = s6-rc, or legacy hybrid).
sync_boot_scripts() {
	local backend=$1
	local dest s

	mkdir -p "$SKEL"
	for s in $SCRIPTS; do
		if [ -e "$backend/$s" ]; then
			cp -a "$backend/$s" "$SKEL/$s"
			chmod 755 "$SKEL/$s" 2>/dev/null || true
		fi
	done

	dest=$(current_scripts_dir 2>/dev/null || true)
	if [ -n "$dest" ]; then
		for s in $SCRIPTS; do
			if [ -e "$backend/$s" ]; then
				cp -a "$backend/$s" "$dest/$s"
				chmod 755 "$dest/$s" 2>/dev/null || true
			fi
		done
		echo "genuen-init-select: synced boot scripts into $dest"
	else
		echo "genuen-init-select: warning: no s6-linux-init current/scripts; only skel updated" >&2
	fi
}

name_from_target() {
	target=$1
	case "$target" in
		*/s6-rc/*) echo s6-rc ;;
		*/66/*) echo 66 ;;
		*) echo "$target" ;;
	esac
}

# --- PID1 /sbin/init and halt|poweroff|reboot -------------------------

resolve_path() {
	# Prefer real file under /usr/sbin on merged-/usr systems.
	local p=$1
	if [ -e "$p" ] || [ -L "$p" ]; then
		echo "$p"
		return 0
	fi
	return 1
}

backup_file() {
	local src=$1
	local tag=$2
	local dest

	mkdir -p "$STATEDIR/backup"
	[ -e "$src" ] || [ -L "$src" ] || return 0
	dest="$STATEDIR/backup/${tag}$(echo "$src" | tr / _)"
	# Only backup once so we keep the pre-genuen original across toggles.
	if [ ! -e "$dest" ]; then
		cp -a "$src" "$dest"
		echo "$src" >>"$STATEDIR/backup/manifest"
	fi
}

install_execline_script() {
	local dest=$1
	local body=$2
	local dir

	dir=$(dirname "$dest")
	mkdir -p "$dir"
	printf '%s\n' "$body" >"$dest"
	chmod 755 "$dest"
}

# Write to /usr/sbin (and /sbin when it is a distinct path).
install_sbin_pair() {
	local name=$1
	local body=$2
	local usr="/usr/sbin/$name"
	local sbin="/sbin/$name"

	if [ -d /usr/sbin ]; then
		backup_file "$usr" "pre-"
		install_execline_script "$usr" "$body"
	fi
	# usr-merge: /sbin → usr/sbin, one write is enough
	if [ -L /sbin ]; then
		case "$(readlink /sbin)" in
			usr/sbin|/usr/sbin) return 0 ;;
		esac
	fi
	if [ -e "$sbin" ] || [ -L "$sbin" ] || [ -d /sbin ]; then
		if [ "$(readlink -f "$sbin" 2>/dev/null)" != "$(readlink -f "$usr" 2>/dev/null)" ]; then
			backup_file "$sbin" "pre-"
			install_execline_script "$sbin" "$body"
		fi
	fi
}

find_66_hpr() {
	if command -v 66-hpr >/dev/null 2>&1; then
		command -v 66-hpr
		return 0
	fi
	for c in /usr/bin/66-hpr /usr/sbin/66-hpr /usr/libexec/66/66-hpr /usr/libexec/66-hpr; do
		[ -x "$c" ] && echo "$c" && return 0
	done
	return 1
}

find_s6_hpr() {
	if command -v s6-linux-init-hpr >/dev/null 2>&1; then
		command -v s6-linux-init-hpr
		return 0
	fi
	for c in /usr/bin/s6-linux-init-hpr /usr/sbin/s6-linux-init-hpr; do
		[ -x "$c" ] && echo "$c" && return 0
	done
	return 1
}

install_pid1_66() {
	local hpr initbody haltb powerb rebooth
	hpr=$(find_66_hpr) || {
		echo "genuen-init-select: cannot find 66-hpr" >&2
		return 1
	}

	# Kernel runs /sbin/init (or /usr/sbin/init). Always install our wrapper;
	# do not reuse /usr/bin/init from the 66 package (wrong path for PID1).
	#
	# Remount / rw BEFORE "66 boot": sanitize_init writes oneshot status under
	# /var/lib/66 on the root FS. Depends=mount-rw is too late — that write
	# happens while building the graph, so modules hits EROFS and the boot
	# group fails (mount-* then show "already initialized" from the partial
	# pass). rc.init's remount is unused under 66-as-PID1.
	initbody='#!/usr/bin/execlineb -P

importas -sCuD "/usr/sbin:/usr/bin:/sbin:/bin" PATH PATH
foreground { mount -o remount,rw / }
66 boot'
	install_sbin_pair init "$initbody"

	haltb="#!/usr/bin/execlineb -S0

${hpr} -h \$@"
	powerb="#!/usr/bin/execlineb -S0

${hpr} -p \$@"
	rebooth="#!/usr/bin/execlineb -S0

${hpr} -r \$@"
	install_sbin_pair halt "$haltb"
	install_sbin_pair poweroff "$powerb"
	install_sbin_pair reboot "$rebooth"

	echo "genuen-init-select: PID1 set to 66 boot; halt/poweroff/reboot → 66-hpr"
}

install_pid1_s6() {
	local hpr initbody haltb powerb rebooth

	hpr=$(find_s6_hpr) || {
		echo "genuen-init-select: cannot find s6-linux-init-hpr" >&2
		return 1
	}

	initbody='#!/usr/bin/execlineb -S0

s6-linux-init -v 1 -m 0022 -c "/etc/s6-linux-init/current" -p "/usr/sbin:/usr/bin:/sbin:/bin" -- "$@"'
	install_sbin_pair init "$initbody"

	haltb="#!/usr/bin/execlineb -S0

${hpr} -h \$@"
	powerb="#!/usr/bin/execlineb -S0

${hpr} -p \$@"
	rebooth="#!/usr/bin/execlineb -S0

${hpr} -r \$@"
	install_sbin_pair halt "$haltb"
	install_sbin_pair poweroff "$powerb"
	install_sbin_pair reboot "$rebooth"

	echo "genuen-init-select: PID1 set to s6-linux-init; halt/poweroff/reboot → s6-linux-init-hpr"
}

# With CATCHLOG=0, 66-scandir notifies stage2 before the first scan, so
# oneshot services race oneshotd/s. Divert /usr/bin/66-scandir and install
# a gate that holds the -d notify until oneshotd/s exists.
install_66_scandir_gate() {
	local real=/usr/bin/66-scandir
	local diverted=/usr/bin/66-scandir.real
	local gate="$LIBDIR/66-scandir-gate"

	[ -x "$gate" ] || {
		echo "genuen-init-select: missing $gate" >&2
		return 1
	}
	[ -e "$real" ] || [ -L "$real" ] || [ -e "$diverted" ] || {
		echo "genuen-init-select: missing $real" >&2
		return 1
	}

	if ! dpkg-divert --list "$real" 2>/dev/null | grep -q .; then
		dpkg-divert --package genuen-init-select --add --rename \
			--divert "$diverted" "$real" >/dev/null
	fi
	# Point the gate at the diverted upstream binary
	if [ ! -x "$diverted" ]; then
		echo "genuen-init-select: divert left no $diverted" >&2
		return 1
	fi
	# Gate script hardcodes LIBDIR/66-scandir.real — keep a stable path copy
	cp -a "$diverted" "$LIBDIR/66-scandir.real"
	install -m755 "$gate" "$real"
	echo "genuen-init-select: diverted $real → delay stage2 until oneshotd/s"
}

remove_66_scandir_gate() {
	local real=/usr/bin/66-scandir
	local diverted=/usr/bin/66-scandir.real

	rm -f "$real"
	if dpkg-divert --list "$real" 2>/dev/null | grep -q genuen-rc-select; then
		dpkg-divert --package genuen-rc-select --remove --rename "$real" >/dev/null || true
	elif dpkg-divert --list "$real" 2>/dev/null | grep -q .; then
		dpkg-divert --package genuen-init-select --remove --rename "$real" >/dev/null || true
	fi
	rm -f "$LIBDIR/66-scandir.real"
	# If divert remove restored the binary, done; else leave diverted path
	if [ -x "$diverted" ] && [ ! -e "$real" ]; then
		mv "$diverted" "$real"
	fi
	echo "genuen-init-select: removed 66-scandir gate"
}

# Ensure logger account / dirs / tools exist for 66 boot.
# CATCHLOG=1 makes stage2 block forever on scandir-log's fifo if the
# catch-all logger never comes up — that matches the hang after
# "Starts boot logger at: /run/66/log/0". Default to CATCHLOG=0 so
# scandir start notifies readiness without the fifo wait; boot messages
# stay on console. The 66-scandir gate then holds stage2 until oneshotd/s.
prepare_66_boot() {
	local conf=/etc/66/init.conf

	if ! id s6log >/dev/null 2>&1; then
		useradd -r -s /usr/sbin/nologin s6log 2>/dev/null || true
	fi
	if id s6log >/dev/null 2>&1; then
		# SS_LOGGER_SYSDIR is /var/66 on Genuen ([Logger] Destination ignored).
		install -d -o s6log -g s6log -m0755 /var/66 /var/log/66
		chown -R s6log:s6log /var/66 /var/log/66 2>/dev/null || true
	else
		install -d -m0755 /var/66 /var/log/66
	fi

	command -v 66-log >/dev/null 2>&1 || [ -x /usr/bin/66-log ] || \
		echo "genuen-init-select: warning: 66-log not found (catch-all logger)" >&2
	command -v execl-runas >/dev/null 2>&1 || [ -x /usr/bin/execl-runas ] || \
		echo "genuen-init-select: warning: execl-runas not found" >&2

	install -d /etc/66
	if [ ! -f "$conf" ]; then
		cat >"$conf" <<'EOF'
VERBOSITY=3
PATH=/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/bin
UMASK=0022
# 0: do not block stage2 on catch-all logger fifo (see genuen-init-select README)
CATCHLOG=0
TREE=
EOF
	else
		grep -q '^VERBOSITY=' "$conf" || echo 'VERBOSITY=3' >>"$conf"
		grep -q '^PATH=' "$conf" || echo 'PATH=/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/bin' >>"$conf"
		grep -q '^UMASK=' "$conf" || echo 'UMASK=0022' >>"$conf"
		if grep -q '^CATCHLOG=' "$conf"; then
			sed -i 's/^CATCHLOG=.*/CATCHLOG=0/' "$conf"
		else
			echo 'CATCHLOG=0' >>"$conf"
		fi
		if grep -q '^TREE=' "$conf"; then
			sed -i 's/^TREE=.*/TREE=/' "$conf"
		else
			echo 'TREE=' >>"$conf"
		fi
	fi
	echo "genuen-init-select: wrote $conf (CATCHLOG=0, TREE=)"
}

# Local-only history left Depends=(wait-oneshotd) in frontends and resolve CDB.
# 66 free is only stop -u — it does NOT drop resolves. Must 66 remove (or rm)
# contaminated svc dirs. Temp stub lets remove/parse succeed during purge.
strip_wait_oneshotd_depends() {
	local dir f s
	for dir in /usr/share/66/service /etc/66/service; do
		[ -d "$dir" ] || continue
		for f in "$dir"/*; do
			[ -f "$f" ] || continue
			s=$(basename "$f")
			[ "$s" = wait-oneshotd ] && continue
			grep -q wait-oneshotd "$f" 2>/dev/null || continue
			sed -i -E \
				-e 's/[[:space:]]*wait-oneshotd[[:space:]]*/ /g' \
				-e 's/Depends = \( +/Depends = ( /g' \
				-e 's/Contents = \( +/Contents = ( /g' \
				-e 's/ +\)/ )/g' \
				-e 's/Depends = \( \)/Depends = ( )/g' \
				-e 's/Contents = \( \)/Contents = ( )/g' \
				"$f"
			echo "$s"
		done
	done
}

resolve_wait_oneshotd_consumers() {
	local dir s
	for dir in /var/lib/66/system/service/svc/*/ \
		/var/lib/66/system/.resolve/service/*/
	do
		[ -e "$dir" ] || continue
		s=$(basename "$dir")
		[ "$s" = wait-oneshotd ] && continue
		if grep -rq --binary-files=text wait-oneshotd "$dir" 2>/dev/null; then
			printf '%s\n' "$s"
		fi
	done
}

purge_wait_oneshotd() {
	local stripped consumers s stub
	stub=/usr/share/66/service/wait-oneshotd
	install -d /usr/share/66/service
	cat >"$stub" <<'EOF'
[Main]
Type = oneshot
Version = 0.0.1
Description = "temporary purge stub — removed at end of purge"
User = ( root )
Options = ( !log )

[Start]
Execute = (
	true
)
EOF
	rm -f /etc/66/service/wait-oneshotd \

	stripped=$(strip_wait_oneshotd_depends)
	if [ -n "$stripped" ]; then
		printf '%s\n' "$stripped" | while read -r s; do
			[ -n "$s" ] || continue
			echo "genuen-init-select: stripped wait-oneshotd from frontend $s"
		done
	fi

	consumers=$(resolve_wait_oneshotd_consumers)
	if [ -n "$consumers" ]; then
		echo "genuen-init-select: removing resolves that still name wait-oneshotd:"
		printf '%s\n' "$consumers" | while read -r s; do
			[ -n "$s" ] || continue
			echo "genuen-init-select:   - $s"
			if command -v 66 >/dev/null 2>&1; then
				66 disable "$s" 2>/dev/null || true
				66 remove -P "$s" 2>/dev/null || true
			fi
			rm -rf "/var/lib/66/system/service/svc/$s" \
				"/var/lib/66/system/.resolve/service/$s" \
				/run/66/state/*/"$s" 2>/dev/null || true
		done
	fi

	if command -v 66 >/dev/null 2>&1; then
		66 disable wait-oneshotd 2>/dev/null || true
		66 remove -P wait-oneshotd 2>/dev/null || true
	fi
	rm -rf /var/lib/66/system/service/svc/wait-oneshotd \
		/var/lib/66/system/.resolve/service/wait-oneshotd \
		/run/66/state/*/wait-oneshotd 2>/dev/null || true
	rm -f "$stub" /etc/66/service/wait-oneshotd
	echo "genuen-init-select: wait-oneshotd removed (gate is 66-scandir-gate)"
}

# oneshotd execve()s livestate .../run — needs +x (same failure mode as
# wait-oneshotd "Permission denied").
fix_oneshot_run_modes() {
	local run
	for run in /var/lib/66/system/service/svc/*/run \
		/var/lib/66/system/service/svc/*/finish \
		/run/66/state/*/*/run \
		/run/66/state/*/*/finish
	do
		[ -e "$run" ] || continue
		chmod 0755 "$run" 2>/dev/null || true
	done
}

# Tree-named oneshot stubs: never keep under /etc/66/service (oneshotd EACCES).
_66_TREE_STUBS="boot cryptsetup cryptsetup-shutdown default enabled-services
	fake-hwclock fake-hwclock-shutdown getty live live-shutdown
	misc misc-essential mount recovery setup shutdown"

configure_66() {
	local name
	prepare_66_boot
	install_66_scandir_gate || return 1
	# Service frontends live in 66-policy (/usr/share/66/service). Do not
	# ship a parallel overlay tree here. Only drop stale admin stub copies.
	install -d /etc/66/service
	for name in $_66_TREE_STUBS; do
		rm -f "/etc/66/service/$name"
	done
	purge_wait_oneshotd
	# Best-effort tree graph + enables (frontends from 66-policy).
	# Getty/tty* are required under 66-as-PID1 (no rc.init stage2 console).
	if command -v 66 >/dev/null 2>&1; then
		# Do not enable tree-named empty stubs — they race oneshotd on boot.
		for s in live setup boot enabled-services default mount getty \
			misc misc-essential recovery shutdown cryptsetup \
			cryptsetup-shutdown fake-hwclock fake-hwclock-shutdown \
			live-shutdown
		do
			66 disable "$s" 2>/dev/null || true
			66 remove -P "$s" 2>/dev/null || true
			rm -rf "/var/lib/66/system/service/svc/$s" \
				"/var/lib/66/system/.resolve/service/$s" \
				/run/66/state/*/"$s" 2>/dev/null || true
		done
		# Drop parents + loggers: stale tree/resolve refs to missing *-log
		# fatals boot ("unable to read resolve file of: dbus-log").
		for s in vdevd-log dbus-log vdev-log dbus vdevd vdev-coldplug \
			vdev-env devmanager modules mount-filesystems mount-rw
		do
			66 disable "$s" 2>/dev/null || true
			66 remove -P "$s" 2>/dev/null || true
			rm -rf "/var/lib/66/system/service/svc/$s" \
				"/var/lib/66/system/.resolve/service/$s" \
				/run/66/state/*/"$s" 2>/dev/null || true
		done
		# Graph: mount-rw early (after mount-devfs), then populate-run/modules.
		# Oneshot status files live under /var/lib/66 on the root FS.
		for s in mount-procfs mount-sysfs mount-devfs mount-rw populate-run \
			mount-tmpfs modules mount-filesystems hostname rc.local \
			umountfs umountroot
		do
			[ -f "/usr/share/66/service/$s" ] || \
				[ -f "/etc/66/service/$s" ] || continue
			66 reconfigure "$s" 2>/dev/null || true
		done
		# Sync critical seeds from 66-policy into /etc (wins over share).
		# Drop /etc copies that were accidentally overwritten with a service
		# frontend ([Main]); never ship a parallel seed tree in this package.
		install -d /etc/66/seed
		if [ ! -d "$POLICY_SEED_66" ]; then
			echo "genuen-init-select: warning: $POLICY_SEED_66 missing (install 66-policy)" >&2
		else
			for name in boot getty mount misc-essential devmanager logind \
				enabled-services default
			do
				src="$POLICY_SEED_66/$name"
				[ -f "$src" ] || continue
				if grep -q '^\[Main\]' "$src" 2>/dev/null; then
					echo "genuen-init-select: warning: refusing non-seed $src" >&2
					continue
				fi
				install -m644 "$src" "/etc/66/seed/$name"
			done
		fi
		# Remove corrupted admin seeds left from bad install(1) multi-dest copies.
		for f in /etc/66/seed/*; do
			[ -f "$f" ] || continue
			grep -q '^\[Main\]' "$f" 2>/dev/null && rm -f "$f"
		done
		# Re-enable every SCRIPT/TREE from dpkg postinsts (ISO/chroot configures
		# often soft-fail when Depends frontends are not installed yet).
		if [ -x /usr/lib/66-helper/66-helper ]; then
			/usr/lib/66-helper/66-helper dpkg-sync 2>/dev/null || true
		fi
		# devmanager early: vdevd !log only needs /run+/dev.
		# Own the edge from boot.depends (requiredby=boot on devmanager does not stick).
		66 tree admin -o noseed:depends=none devmanager 2>/dev/null || true
		66 tree admin -o noseed:requiredby=none devmanager 2>/dev/null || true
		66 tree admin -o noseed:depends=none boot 2>/dev/null || true
		66 tree admin -o noseed:depends=mount,setup,devmanager,misc,misc-essential,live boot 2>/dev/null || true
		for s in vdev-env vdevd vdev-coldplug; do
			[ -f "/usr/share/66/service/$s" ] || \
				[ -f "/etc/66/service/$s" ] || continue
			66 -t devmanager enable "$s" 2>/dev/null || true
		done
		66 -t devmanager enable devmanager 2>/dev/null || true
		# Order: boot → logind (dbus/elogind) → enabled-services.
		# admin depends=none cannot clear reverse links; recreate logind.
		66 tree remove logind 2>/dev/null || true
		66 tree create -o noseed:depends=boot:requiredby=none:groups=admin logind 2>/dev/null || true
		# Edge enabled-services↔default is owned by default.depends (not
		# enabled-services.requiredby): the reverse link put default into
		# enabled-services.depends and inverted boot order.
		66 tree admin -o noseed:requiredby=none default 2>/dev/null || true
		66 tree admin -o noseed:depends=none:requiredby=none enabled-services 2>/dev/null || true
		66 tree admin -o noseed:depends=boot,logind enabled-services 2>/dev/null || true
		66 tree admin -o noseed:depends=none default 2>/dev/null || true
		66 tree admin -o noseed:depends=boot,enabled-services,getty default 2>/dev/null || true
		# dbus must live in logind tree: that tree is requiredby enabled-services
		# and starts first — elogind Needs the system bus before enabled-services.
		if [ -f /etc/66/service/dbus ] || [ -f /usr/share/66/service/dbus ]; then
			66 -t enabled-services disable dbus 2>/dev/null || true
			66 -t logind enable dbus 2>/dev/null || true
		fi
		if [ -f /usr/share/66/service/elogind ]; then
			66 -t logind enable elogind 2>/dev/null || true
			# libseat prefers seatd when /run/seatd.sock exists; that fights
			# elogind for seat0 and breaks LightDM/Xfce. Keep seatd disabled
			# unless the admin enables it for a seatd-only stack.
			if [ -f /usr/share/66/service/seatd ] || [ -f /etc/66/service/seatd ]; then
				66 disable seatd 2>/dev/null || true
				66 stop seatd 2>/dev/null || true
				echo "genuen-init-select: disabled seatd (elogind owns seats)"
			fi
		fi
		66 -t logind enable logind 2>/dev/null || true
		if [ -f /etc/66/service/lightdm ] || [ -f /usr/share/66/service/lightdm ]; then
			66 -t enabled-services enable lightdm 2>/dev/null || true
		fi
		# live-config after mount-rw (mount tree ⊂ boot) before LightDM.
		# tree=live raced the 66-policy "live" stub and left the oneshot unstarted.
		if [ -f /usr/share/66/service/live-config ] || [ -f /etc/66/service/live-config ]; then
			66 -t live disable live-config 2>/dev/null || true
			66 -t mount enable live-config 2>/dev/null || true
		fi
		# getty must wait for mount+devmanager (was cleared → early-getty before mounts).
		66 tree admin -o noseed:depends=none getty 2>/dev/null || true
		66 tree admin -o noseed:depends=mount,devmanager getty 2>/dev/null || true
		66 tree resolve getty >/dev/null 2>&1 || true
		for s in early-getty-down console-fallback \
			tty1 tty2 tty3 tty4 tty5 tty6 ttyS; do
			[ -f "/usr/share/66/service/$s" ] || continue
			66 -t getty enable "$s" 2>/dev/null || true
		done
		fix_oneshot_run_modes
		mount -o remount,exec /run 2>/dev/null || true
	fi
}

do_status() {
	local manager=none pid1=unknown

	migrate_legacy
	if [ -f "$STATE" ]; then
		# shellcheck disable=SC1090
		. "$STATE"
		manager=${MANAGER:-none}
		pid1=${PID1:-unknown}
	elif [ -L "$MANAGER_LINK" ]; then
		target=$(readlink "$MANAGER_LINK" 2>/dev/null || true)
		manager=$(name_from_target "$target")
		pid1=s6-linux-init
	fi

	printf 'MANAGER=%s\nPID1=%s\n' "$manager" "$pid1"
	[ "$manager" != none ]
}

do_select() {
	name=$1
	migrate_legacy
	backend=$(backend_for "$name") || {
		echo "genuen-init-select: unknown manager '$name' (use s6-rc or 66)" >&2
		return 1
	}
	pid1=$(pid1_for "$name")
	policy_ok "$name" || return 1

	mkdir -p /etc/s6-linux-init "$STATEDIR"
	ln -sfn "$backend" "$MANAGER_LINK"

	case "$name" in
		66)
			configure_66
			install_pid1_66
			# Keep scripts in place for documentation / hybrid rescue; not stage2 under 66-PID1.
			sync_boot_scripts "$backend" 2>/dev/null || true
			echo "genuen-init-select: note: with PID1=66, /etc/66/current/scripts are NOT stage2"
			echo "genuen-init-select: boot uses 66 boot → tree graph (boot group + enabled trees)"
			echo "genuen-init-select: shutdown uses 66-shutdownd; use: 66 poweroff | 66 reboot"
			;;
		s6-rc)
			remove_66_scandir_gate 2>/dev/null || true
			install_pid1_s6
			sync_boot_scripts "$backend"
			echo "genuen-init-select: note: with PID1=s6-linux-init, use s6-linux-init-hpr / poweroff wrappers"
			;;
	esac

	write_state "$name" "$pid1"

	echo "genuen-init-select: active MANAGER=$name PID1=$pid1 (-> $backend)"
	echo "genuen-init-select: reboot to apply at the next boot"
}

guess_default() {
	if [ -x /etc/s6-rc/current/scripts/rc.init ]; then
		echo s6-rc
	elif [ -x /etc/66/current/scripts/rc.init ]; then
		echo 66
	else
		echo s6-rc
	fi
}

case "${1:-}" in
	''|status)
		do_status
		;;
	s6-rc|66)
		do_select "$1"
		;;
	--default)
		migrate_legacy
		if [ -f "$STATE" ]; then
			# shellcheck disable=SC1090
			. "$STATE"
			[ -n "$MANAGER" ] && exit 0
		fi
		if do_status >/dev/null 2>&1; then
			exit 0
		fi
		do_select "$(guess_default)"
		;;
	-h|--help)
		cat <<'EOF'
Usage: genuen-init-select [s6-rc|66|status]

Select the service-management stack and matching PID 1:

  s6-rc   PID1 = s6-linux-init; stage 2/3 = s6-rc-policy rc.* scripts
  66      PID1 = 66 boot (creates 66-shutdownd); trees from 66-policy
          rc.init under /etc/66 is NOT used as stage2 with 66-as-PID1
  status  print MANAGER= and PID1= (default)

Also switches /sbin/init and halt/poweroff/reboot:
  66    → 66 boot / 66-hpr   (then: 66 poweroff)
  s6-rc → s6-linux-init / s6-linux-init-hpr

A reboot is required for PID1 to change.
EOF
		;;
	*)
		echo "genuen-init-select: unknown argument '$1'" >&2
		echo "Try 'genuen-init-select --help'" >&2
		exit 1
		;;
esac
