Author SHA1 Message Date
alvinlollo 00c89f23f0 feat(installer): Skip login manager when unl0kr handles the passphrase
Tests / tests (push) Successful in 2m56s
unl0kr already prompts for the LUKS passphrase on screen, so a login
manager on top of it would be a second prompt. The login screen now only
collects a fallback (none/greetd/sddm/gdm) when unl0kr is selected;
resolve_login_manager applies it only when install_unl0kr falls back to
the systemd initramfs, and the summary shows both states.

Also ships /etc/unl0kr.conf (breezy-dark) plus the empty
/usr/share/unl0kr/unl0kr.conf the package omits so unl0kr stops warning
about an unparseable config, and pins Hyprland in the user's
AccountsService record so gdm autologin does not fall back to
gnome.desktop.
2026-10-13 19:33:57 +11:00
2 changed files with 99 additions and 2 deletions
+1 -1
View File
@@ -74,7 +74,7 @@ The airootfs overlay ships it as `/usr/local/bin/alvin-install` (mode `0755` for
locale, login manager, sshd, summary) then a fixed order of `install_*` steps
(partition → LUKS → format/mount → pacstrap → fstab → repos → timezone → locale →
hostname → network → sshd → user → git/SSH → end-4 dots → mkinitcpio → bootloader →
TPM/unl0kr → login manager → autologin → update (reflector + keyrings + `pacman -Syu`, warn-only) → cleanup). Screens and install steps are
TPM/unl0kr → login manager (none if unl0kr succeeded; with unl0kr selected the login screen only asks for a fallback) → autologin → update (reflector + keyrings + `pacman -Syu`, warn-only) → cleanup). Screens and install steps are
independent — edit one without
touching the other. An `EXIT` trap unmounts `$TARGET` and closes `cryptroot` on any exit.
- **Package list**: `install_pacstrap` builds the *installed* system's list from the medium's
+98 -1
View File
@@ -31,6 +31,9 @@ GH_USERNAME=""
UNL0KR="false"
TPM_STATUS=""
LOGIN_MANAGER="none"
# true when unl0kr was picked: no login manager is installed if unl0kr
# succeeds, and LOGIN_MANAGER only holds the fallback for when it doesn't.
LOGIN_MANAGER_SKIP="false"
AUTOLOGIN=""
# SSHD is the choice made on the sshd screen; SSHD_APPLIED is only flipped once
# the target's sshd.service has actually been enabled, so the final banner can
@@ -527,6 +530,11 @@ screen_locale() {
}
screen_login_manager() {
if [[ "$LUKS" == "true" && "$UNL0KR" == "true" ]]; then
screen_unl0kr_login
return
fi
LOGIN_MANAGER_SKIP="false"
clear
header "Login Manager"
echo ""
@@ -543,6 +551,33 @@ screen_login_manager() {
log "Login manager: $LOGIN_MANAGER"
}
# unl0kr already asks for the passphrase on screen at boot, so a login
# manager on top would be a second prompt. Skip it, but collect a fallback
# now: install_unl0kr can still fall back to the systemd initramfs, and the
# installer must not stop to ask mid-install.
screen_unl0kr_login() {
LOGIN_MANAGER_SKIP="true"
clear
header "Login Manager (unl0kr)"
echo ""
gum style --foreground 15 \
"unl0kr is selected, so no login manager will be installed:" \
"after the LUKS passphrase is entered with unl0kr, the system logs in on" \
"tty1 and Hyprland starts automatically (autologin is asked during install)." \
"" \
"If unl0kr fails to install, the installer falls back to the standard" \
"passphrase prompt. Pick the login manager to use in that case:" \
"" \
" none - plain tty login, Hyprland starts automatically" \
" greetd - lightweight TUI greeter (tuigreet)" \
" sddm - Qt display manager (already installed)" \
" gdm - GNOME display manager (large download)"
echo ""
LOGIN_MANAGER=$(gum choose --header "+ Fallback login manager (Enter = none)" \
"none" "greetd" "sddm" "gdm") || die "No fallback login manager selected."
log "Login manager: skipped for unl0kr (fallback: $LOGIN_MANAGER)"
}
screen_sshd() {
clear
header "SSH Server"
@@ -592,6 +627,11 @@ screen_summary() {
ssh_line="gh:${GH_USERNAME}"
fi
local login_line="${LOGIN_MANAGER}"
if [[ "$LOGIN_MANAGER_SKIP" == "true" ]]; then
login_line="none - unl0kr (fallback: ${LOGIN_MANAGER})"
fi
gum style --foreground 15 --border normal --border-foreground 8 \
--padding "0 2" --width 60 \
"Disk: ${DISK}" \
@@ -603,7 +643,7 @@ screen_summary() {
"Keymap: ${KEYMAP}" \
"Locale: ${LOCALE}" \
"Timezone: ${TIMEZONE}" \
"Login mgr: ${LOGIN_MANAGER}" \
"Login mgr: ${login_line}" \
"SSH server: $([[ "$SSHD" == "true" ]] && echo enabled || echo skipped)" \
"SSH keys: ${ssh_line}" \
"Git: ${git_line}"
@@ -1715,6 +1755,34 @@ install_unl0kr() {
page_log_tail "unl0kr hook file output (q to quit)" 40 || true
}
# unl0kr parses /usr/share/unl0kr/unl0kr.conf first; the package doesn't
# ship it, so inih fails to open it and unl0kr prints "Ignoring invalid
# config file" on every boot. An empty file parses cleanly - FILES+= puts
# it in the image (the hook only adds /etc/unl0kr.conf). Our own
# /etc/unl0kr.conf pins the dark theme instead of trusting the PKGBUILD's
# sed on the upstream (light) default.
mkdir -p "${TARGET}/usr/share/unl0kr"
: >"${TARGET}/usr/share/unl0kr/unl0kr.conf"
cat >"${TARGET}/etc/unl0kr.conf" <<'UNL0KR'
[general]
animations=true
[keyboard]
autohide=false
layout=us
popovers=true
[textarea]
obscured=true
[theme]
default=breezy-dark
alternate=breezy-light
UNL0KR
echo 'FILES+=(/usr/share/unl0kr/unl0kr.conf)' \
>>"${TARGET}/etc/mkinitcpio.conf.d/alvin.conf"
log "unl0kr: wrote /etc/unl0kr.conf (breezy-dark) + empty /usr/share/unl0kr/unl0kr.conf"
# Touchscreen/input stack for the initramfs: mkinitcpio fails the build
# on a MODULES entry it cannot resolve, and -P applies the list to every
# preset - so a module may enter MODULES only if EVERY installed kernel
@@ -1904,6 +1972,21 @@ FISH
log "tty profile: ${profile} (exec Hyprland on VT1)"
}
# Runs after install_unl0kr, which resets UNL0KR to false when it falls
# back to the systemd initramfs - so UNL0KR still being true here means
# unl0kr really is in the image and no login manager is wanted.
resolve_login_manager() {
[[ "$LOGIN_MANAGER_SKIP" == "true" ]] || return 0
if [[ "$UNL0KR" == "true" ]]; then
LOGIN_MANAGER="none"
info "unl0kr is installed - skipping the login manager (tty1 + Hyprland)."
log "Login manager: none (unl0kr installed)"
else
warn "unl0kr fell back - using the fallback login manager: ${LOGIN_MANAGER}."
log "Login manager: fallback ${LOGIN_MANAGER} (unl0kr not installed)"
fi
}
install_login_manager() {
info "Configuring login manager: ${LOGIN_MANAGER}..."
@@ -2009,6 +2092,19 @@ TOML
return
fi
ensure_hyprland_session
# gdm (autologin included) starts the session stored in the user's
# AccountsService record; without one it picks gnome.desktop, which
# the gdm install drags in. Pin Hyprland.
local as_dir="${TARGET}/var/lib/AccountsService/users"
mkdir -p "$as_dir"
cat >"${as_dir}/${USERNAME}" <<'ACCOUNT'
[User]
Session=hyprland
SessionType=wayland
SystemAccount=false
ACCOUNT
chmod 600 "${as_dir}/${USERNAME}"
log "gdm: AccountsService session pinned to hyprland"
if run_logged "Could not enable gdm.service" \
arch-chroot "$TARGET" systemctl enable gdm.service; then
run_logged "Could not disable getty@tty1.service" \
@@ -2286,6 +2382,7 @@ main() {
install_bootloader
install_tpm
install_unl0kr
resolve_login_manager
install_login_manager
install_autologin
install_update