diff --git a/desktopenvs/sway/greetd-tuigreet/config.toml b/desktopenvs/sway/greetd-tuigreet/config.toml new file mode 100644 index 0000000..c39c502 --- /dev/null +++ b/desktopenvs/sway/greetd-tuigreet/config.toml @@ -0,0 +1,16 @@ +[terminal] +# The VT to run the greeter on. Can be "next", "current" or a number +# designating the VT. +vt = 1 + +# The default session, also known as the greeter. +[default_session] + +# `agreety` is the bundled agetty/login-lookalike. You can replace `/bin/sh` +# with whatever you want started, such as `sway`. +command = "tuigreet --cmd sway" + +# The user to run the command as. The privileges this user must have depends +# on the greeter. A graphical greeter may for example require the user to be +# in the `video` group. +user = "greeter" diff --git a/setup/arch-autoinstall.sh b/setup/arch-autoinstall.sh index bd40c47..900eb6f 100755 --- a/setup/arch-autoinstall.sh +++ b/setup/arch-autoinstall.sh @@ -5,7 +5,12 @@ # all prompts are answered from it. Missing fields fall back to interactive prompts. # # Answerfile fields: drive, kernel, keymap, hostname, username, encrypt, fido2_root, -# fido2_user, run_tui, password, luks_password +# fido2_user, run_tui, clone_skel_dotfiles, password, luks_password +# "clone_skel_dotfiles" is independent of "run_tui": it controls only whether the +# dotfiles repo is cloned into /etc/skel. When omitted it defaults to run_tui's +# value, preserving the old coupled behaviour. Set both false for a fully bare +# install: no encryption (encrypt:false), no dotfiles, no DE, no modules, plain +# bash + agetty login. # The user "password" (and "luks_password" for encrypted installs) may be supplied # in the answerfile for fully unattended deployment; when omitted they are prompted # interactively. Storing secrets in the answerfile is a convenience/secret-handling @@ -261,6 +266,15 @@ if $AF_MODE; then FIDO_ROOT=$(af_bool '.fido2_root') FIDO_USER=$(af_bool '.fido2_user') RUN_TUI=$(af_bool '.run_tui') + # Independent of run_tui: whether to clone the raw dotfiles repo into + # /etc/skel for future users. Falls back to RUN_TUI when the answerfile + # omits the field, preserving the old coupled behaviour for existing files. + CLONE_SKEL_DOTFILES=$(jq -r '.clone_skel_dotfiles // empty' "$ANSWERFILE" 2>/dev/null || true) + case "$CLONE_SKEL_DOTFILES" in + true) CLONE_SKEL_DOTFILES="YES" ;; + false) CLONE_SKEL_DOTFILES="NO" ;; + *) CLONE_SKEL_DOTFILES="$RUN_TUI" ;; + esac echo "Kernel: $KERNEL" echo "Hostname: $HOSTNAME" echo "Username: $USERNAME" @@ -294,10 +308,21 @@ fi # In interactive mode, decide now whether to run the dotfiles TUI inside chroot. # AF_MODE already has RUN_TUI set from the answerfile. if ! $AF_MODE; then - read -rp "Run dotfiles TUI setup inside chroot now? [YES/no]: " _RUN_TUI_IN + # Answering "no" also skips cloning dotfiles into /etc/skel and leaves the new + # user's shell as /bin/bash, producing a bare Arch install with no DE, no + # modules, and plain agetty login (a display manager only gets installed as a + # module inside the TUI, so skipping the TUI means none is ever installed). + read -rp "Run dotfiles TUI setup inside chroot now? (NO = bare Arch install: no dotfiles, no DE, plain bash + agetty) [YES/no]: " _RUN_TUI_IN # Default to YES if the user presses Enter without typing anything. _RUN_TUI_IN="${_RUN_TUI_IN:-YES}" [[ "${_RUN_TUI_IN^^}" == "YES" ]] && RUN_TUI="YES" || RUN_TUI="NO" + + # Independent toggle: cloning the raw dotfiles repo into /etc/skel doesn't + # require running the TUI, and declining it keeps a fully bare install even + # if the TUI does run. + read -rp "Clone dotfiles repo into /etc/skel for future users? [YES/no]: " _CLONE_IN + _CLONE_IN="${_CLONE_IN:-YES}" + [[ "${_CLONE_IN^^}" == "YES" ]] && CLONE_SKEL_DOTFILES="YES" || CLONE_SKEL_DOTFILES="NO" fi ############################################ @@ -505,7 +530,7 @@ fi # Variables must be exported so the arch-chroot heredoc inherits them. # The heredoc uses single-quote delimiter ('CHROOT_EOF') which prevents expansion # outside the chroot, so env vars must be in the environment, not inline. -export HOSTNAME USERNAME USERPASS ROOT_PART KERNEL FIDO_ROOT FIDO_USER ENCRYPT_DISK KEYMAP +export HOSTNAME USERNAME USERPASS ROOT_PART KERNEL FIDO_ROOT FIDO_USER ENCRYPT_DISK KEYMAP RUN_TUI CLONE_SKEL_DOTFILES ############################################ # CHROOT CONFIGURATION @@ -541,15 +566,29 @@ systemctl enable sshd sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config echo "root:${USERPASS}" | chpasswd -# Populate /etc/skel before user creation so useradd -m copies everything -echo "Cloning dotfiles into /etc/skel..." -git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git /etc/skel/Dotfiles \ - || echo "Warning: dotfiles clone failed — clone manually after first boot." -mkdir -p /etc/skel/{Desktop,Documents,Downloads,Music,Pictures,Public,Templates,Videos} +# Populate /etc/skel before user creation so useradd -m copies everything. +# Gated by its own toggle, independent of RUN_TUI: declining it means the new +# user gets a bare /etc/skel (system defaults) instead of a clone of the +# dotfiles repo sitting in their home directory. +if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" ]]; then + echo "Cloning dotfiles into /etc/skel..." + git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git /etc/skel/Dotfiles \ + || echo "Warning: dotfiles clone failed — clone manually after first boot." + mkdir -p /etc/skel/{Desktop,Documents,Downloads,Music,Pictures,Public,Templates,Videos} +else + echo "Skipping dotfiles clone — clone_skel_dotfiles=NO." +fi # User -# -m: create home dir; -G wheel: add to sudoers group; -s /bin/zsh: default shell. -useradd -m -G wheel -s /bin/zsh "$USERNAME" +# -m: create home dir (from /etc/skel above); -G wheel: add to sudoers group. +# Default shell follows the same bare/configured choice as the skel clone: zsh +# only when the dotfiles TUI will run to set it up, plain bash otherwise. +if [[ "${RUN_TUI^^}" == "YES" ]]; then + NEW_USER_SHELL="/bin/zsh" +else + NEW_USER_SHELL="/bin/bash" +fi +useradd -m -G wheel -s "$NEW_USER_SHELL" "$USERNAME" # chpasswd reads "user:pass" from stdin to set the password non-interactively. echo "$USERNAME:$USERPASS" | chpasswd # Grant wheel group full sudo access (ALL:ALL covers any user/group runas context). @@ -710,6 +749,9 @@ echo "FIDO2 root unlock: $FIDO_ROOT" echo "FIDO2 user login: $FIDO_USER" [[ "$ENCRYPT_DISK" == "YES" ]] && echo "LUKS backup key: /_LUKS_BACKUP_KEY (in new system)" echo +echo "Run TUI: $RUN_TUI" +echo "Clone to skel: $CLONE_SKEL_DOTFILES" +echo echo "Boot size: $BOOT_SIZE" echo "Root size: ${ROOT_GIB}GiB" echo "Swap size: $SWAP_SIZE" @@ -726,6 +768,11 @@ echo "Installation complete! Unmount and reboot:" echo " umount -R /mnt && reboot" if [[ "${RUN_TUI^^}" != "YES" ]]; then echo - echo "After first boot, login as $USERNAME and run:" - echo " ~/Dotfiles/setup/tui-install.sh" + if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" ]]; then + echo "After first boot, login as $USERNAME and run:" + echo " ~/Dotfiles/setup/tui-install.sh" + else + echo "Bare install — no dotfiles were cloned. To set up dotfiles/DE later, run:" + echo " git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git ~/Dotfiles && ~/Dotfiles/setup/tui-install.sh" + fi fi diff --git a/setup/archbaseos-guided-install.sh b/setup/archbaseos-guided-install.sh index 241e151..caa0aeb 100755 --- a/setup/archbaseos-guided-install.sh +++ b/setup/archbaseos-guided-install.sh @@ -202,6 +202,15 @@ if $AF_MODE; then ENABLE_FIDO_ROOT=$(af_bool '.fido2_root') ENABLE_FIDO_USER=$(af_bool '.fido2_user') RUN_TUI=$(af_bool '.run_tui') + # Independent of run_tui: whether to clone the raw dotfiles repo into + # /etc/skel for future users. Falls back to RUN_TUI when the answerfile + # omits the field, preserving the old coupled behaviour for existing files. + CLONE_SKEL_DOTFILES=$(jq -r '.clone_skel_dotfiles // empty' "$ANSWERFILE" 2>/dev/null || true) + case "$CLONE_SKEL_DOTFILES" in + true) CLONE_SKEL_DOTFILES="YES" ;; + false) CLONE_SKEL_DOTFILES="NO" ;; + *) CLONE_SKEL_DOTFILES="$RUN_TUI" ;; + esac KEYMAP=$(af_get '.keymap' 'us') echo "Kernel: $KERNEL / Hostname: $HOSTNAME / Username: $USERNAME" echo "Encrypt: $ENCRYPT_DISK / FIDO2 root: $ENABLE_FIDO_ROOT / FIDO2 user: $ENABLE_FIDO_USER" @@ -240,9 +249,20 @@ else # Whether to run the dotfiles TUI inside the chroot — asked now so the whole # back half of the install can proceed without further interaction. - read -rp "Run dotfiles TUI setup inside chroot after base install? [YES/no]: " _TUI_IN + # Answering "no" also skips cloning dotfiles into /etc/skel and leaves the + # new user's shell as /bin/bash, producing a bare Arch install with no DE, + # no modules, and plain agetty login (no display manager gets installed + # since that only happens as a module inside the TUI). + read -rp "Run dotfiles TUI setup inside chroot after base install? (NO = bare Arch install: no dotfiles, no DE, plain bash + agetty) [YES/no]: " _TUI_IN _TUI_IN="${_TUI_IN:-YES}" [[ "${_TUI_IN^^}" == "YES" ]] && RUN_TUI="YES" || RUN_TUI="NO" + + # Independent toggle: cloning the raw dotfiles repo into /etc/skel doesn't + # require running the TUI (e.g. staging it for later manual use), and + # declining it keeps a fully bare install even if the TUI does run. + read -rp "Clone dotfiles repo into /etc/skel for future users? [YES/no]: " _CLONE_IN + _CLONE_IN="${_CLONE_IN:-YES}" + [[ "${_CLONE_IN^^}" == "YES" ]] && CLONE_SKEL_DOTFILES="YES" || CLONE_SKEL_DOTFILES="NO" fi # ── Target drive ────────────────────────────────────────────────────────────── @@ -292,6 +312,7 @@ echo " Encrypt disk: $ENCRYPT_DISK" echo " FIDO2 root: $ENABLE_FIDO_ROOT" echo " FIDO2 user: $ENABLE_FIDO_USER" echo " Run TUI: $RUN_TUI" +echo " Clone to skel: $CLONE_SKEL_DOTFILES" echo " Target drive: $DRIVE" echo "──────────────────────────────────────────────" echo " WARNING: ALL DATA on $DRIVE will be PERMANENTLY ERASED." @@ -491,27 +512,34 @@ if $AF_MODE; then fi ############################################ -# DOTFILES CLONE TO SKEL (with retry) +# DOTFILES CLONE TO SKEL (with retry, gated by its own toggle) ############################################ +# Independent of RUN_TUI: declining this means the new user gets a bare +# /etc/skel (system defaults) rather than a clone of the dotfiles repo sitting +# in their home directory. # Clone before entering the chroot so useradd -m inside will copy Dotfiles to # the new user's home. Interactive retry is available so a transient network # failure doesn't silently leave the system without dotfiles. -echo "Cloning dotfiles into /mnt/etc/skel..." -_clone_ok=false -while ! $_clone_ok; do - if git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git /mnt/etc/skel/Dotfiles; then - mkdir -p /mnt/etc/skel/{Desktop,Documents,Downloads,Music,Pictures,Public,Templates,Videos} - _clone_ok=true - else - if $AF_MODE; then - echo "Warning: dotfiles clone failed — continuing without dotfiles." +if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" ]]; then + echo "Cloning dotfiles into /mnt/etc/skel..." + _clone_ok=false + while ! $_clone_ok; do + if git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git /mnt/etc/skel/Dotfiles; then + mkdir -p /mnt/etc/skel/{Desktop,Documents,Downloads,Music,Pictures,Public,Templates,Videos} _clone_ok=true else - read -rp "Clone failed — retry? [y/N]: " _retry - [[ "${_retry,,}" == "y" ]] || { echo "Skipping dotfiles — clone manually after first boot."; _clone_ok=true; } + if $AF_MODE; then + echo "Warning: dotfiles clone failed — continuing without dotfiles." + _clone_ok=true + else + read -rp "Clone failed — retry? [y/N]: " _retry + [[ "${_retry,,}" == "y" ]] || { echo "Skipping dotfiles — clone manually after first boot."; _clone_ok=true; } + fi fi - fi -done + done +else + echo "Skipping dotfiles clone — clone_skel_dotfiles=NO." +fi ############################################ # CHROOT Configuration @@ -534,6 +562,7 @@ arch-chroot /mnt /usr/bin/env \ ROOT_UUID="$ROOT_UUID" \ ROOT_PART="$ROOT_PART" \ KEYMAP="$KEYMAP" \ + RUN_TUI="$RUN_TUI" \ /bin/bash <<'CHROOT_EOF' set -euo pipefail @@ -554,8 +583,15 @@ echo "$HOSTNAME" > /etc/hostname # Enable NetworkManager at boot so the installed system has networking on first login. systemctl enable NetworkManager -# -m: create home from /etc/skel (dotfiles cloned before chroot); -G wheel: allow sudo; -s /bin/zsh: default shell. -useradd -m -G wheel -s /bin/zsh "$USERNAME" +# -m: create home from /etc/skel (dotfiles cloned before chroot, gated by its own toggle above); -G wheel: allow sudo. +# Default shell follows RUN_TUI, not the skel toggle: zsh only when the dotfiles +# TUI will actually run to set it up, plain bash (Arch's stock shell) otherwise. +if [[ "${RUN_TUI^^}" == "YES" ]]; then + NEW_USER_SHELL="/bin/zsh" +else + NEW_USER_SHELL="/bin/bash" +fi +useradd -m -G wheel -s "$NEW_USER_SHELL" "$USERNAME" # chpasswd reads "user:pass" from stdin to set the password non-interactively. echo "$USERNAME:$USERPASS" | chpasswd # Ensure all files under the new home dir are owned by the user (skel copy may be root-owned). @@ -696,8 +732,13 @@ echo "Installation complete! Log saved to /mnt/boot/$(basename "$LOGFILE")" echo " umount -R /mnt && reboot" if [[ "${_DO_TUI^^}" != "YES" ]]; then echo - echo "After first boot, login as ${USERNAME} and run:" - echo " ~/Dotfiles/setup/tui-install.sh" + if [[ "${CLONE_SKEL_DOTFILES^^}" == "YES" ]]; then + echo "After first boot, login as ${USERNAME} and run:" + echo " ~/Dotfiles/setup/tui-install.sh" + else + echo "Bare install — no dotfiles were cloned. To set up dotfiles/DE later, run:" + echo " git clone https://git.abdelbaki.eu/The_miro/Dotfiles.git ~/Dotfiles && ~/Dotfiles/setup/tui-install.sh" + fi fi if [[ "$ENCRYPT_DISK" == "YES" ]]; then echo diff --git a/setup/modules/Desktop-Environments/cosmic.sh b/setup/modules/Desktop-Environments/cosmic.sh index b384cfd..fbfed10 100755 --- a/setup/modules/Desktop-Environments/cosmic.sh +++ b/setup/modules/Desktop-Environments/cosmic.sh @@ -59,6 +59,16 @@ sudo pacman -S --noconfirm --needed \ log "Enabling services..." +# getty@tty1 is the default text-mode login prompt; COSMIC's own greeter (or +# the SDDM fallback below) replaces it. '|| true' prevents abort if the unit +# is already disabled or doesn't exist. +sudo systemctl disable getty@tty1.service || true + +# Disable greetd, which core.sh enables by default for every install. This DE +# uses its own display manager below, so leaving greetd enabled means two +# display managers both race to claim tty1. +disable_service greetd.service + # COSMIC ships its own display manager (cosmic-greeter) built with iced. # Prefer it over SDDM for a cohesive look-and-feel; fall back to SDDM when # the package is not present (e.g. on systems where cosmic-greeter is still diff --git a/setup/modules/Desktop-Environments/gnome.sh b/setup/modules/Desktop-Environments/gnome.sh index 4012427..50baf09 100755 --- a/setup/modules/Desktop-Environments/gnome.sh +++ b/setup/modules/Desktop-Environments/gnome.sh @@ -61,6 +61,15 @@ sudo pacman -S --noconfirm --needed \ log "Enabling services..." +# getty@tty1 is the default text-mode login prompt; GDM replaces it. +# '|| true' prevents abort if the unit is already disabled or doesn't exist. +sudo systemctl disable getty@tty1.service || true + +# Disable greetd, which core.sh enables by default for every install. GDM is +# this DE's own display manager, so leaving greetd enabled means two display +# managers both race to claim tty1. +disable_service greetd.service + # GDM (GNOME Display Manager) handles the login screen and session startup. # It is bundled with the 'gnome' group and is the canonical choice for GNOME. sudo systemctl enable gdm.service diff --git a/setup/modules/Desktop-Environments/kde-plasma.sh b/setup/modules/Desktop-Environments/kde-plasma.sh index 70a8c5c..497b5bb 100755 --- a/setup/modules/Desktop-Environments/kde-plasma.sh +++ b/setup/modules/Desktop-Environments/kde-plasma.sh @@ -28,6 +28,15 @@ sudo pacman -S --noconfirm --needed \ flatpak log "Enabling services..." +# getty@tty1 is the default text-mode login prompt; SDDM replaces it. +# '|| true' prevents abort if the unit is already disabled or doesn't exist. +sudo systemctl disable getty@tty1.service || true + +# Disable greetd, which core.sh enables by default for every install. SDDM is +# this DE's own display manager, so leaving greetd enabled means two display +# managers both race to claim tty1. +disable_service greetd.service + # sddm provides the graphical login screen; must be enabled before rebooting. sudo systemctl enable sddm.service sudo systemctl enable NetworkManager.service diff --git a/setup/modules/Desktop-Environments/lxqt.sh b/setup/modules/Desktop-Environments/lxqt.sh index 6e1911e..7db9c4c 100755 --- a/setup/modules/Desktop-Environments/lxqt.sh +++ b/setup/modules/Desktop-Environments/lxqt.sh @@ -17,6 +17,15 @@ sudo pacman -S --noconfirm --needed \ flatpak log "Enabling services..." +# getty@tty1 is the default text-mode login prompt; SDDM replaces it. +# '|| true' prevents abort if the unit is already disabled or doesn't exist. +sudo systemctl disable getty@tty1.service || true + +# Disable greetd, which core.sh enables by default for every install. SDDM is +# this DE's own display manager, so leaving greetd enabled means two display +# managers both race to claim tty1. +disable_service greetd.service + sudo systemctl enable sddm.service sudo systemctl enable NetworkManager.service sudo systemctl enable bluetooth.service diff --git a/setup/modules/Desktop-Environments/sway.sh b/setup/modules/Desktop-Environments/sway.sh index 60ff14b..0ff5405 100644 --- a/setup/modules/Desktop-Environments/sway.sh +++ b/setup/modules/Desktop-Environments/sway.sh @@ -9,7 +9,7 @@ log "Installing required packages..." sudo pacman -Syu --noconfirm --needed \ brightnessctl btop dmenu foot glfw grim \ greetd-tuigreet gst-plugin-pipewire imagemagick iwd libpulse \ - libva-intel-driver libva-mesa-driver lightdm lightdm-gtk-greeter \ + libva-intel-driver libva-mesa-driver \ networkmanager pavucontrol pipewire pipewire-alsa pipewire-jack pipewire-pulse \ slurp sway swaybg swayidle swaylock alacritty \ ttf-jetbrains-mono vulkan-intel vulkan-radeon waybar wget \ @@ -22,9 +22,16 @@ sudo pacman -Syu --noconfirm --needed \ log "Enabling services..." sudo systemctl enable NetworkManager.service +# getty@tty1 is the default text-mode login prompt; greetd replaces it. +# '|| true' prevents abort if the unit is already disabled or doesn't exist. +sudo systemctl disable getty@tty1.service || true + # 3. greetd config +# Use the sway-specific tuigreet config (`--cmd sway`), not the Hyprland one — +# core.sh's default greeter launches Hyprland, which was never installed here. log "Deploying greetd config..." -sudo cp -f ~/Dotfiles/desktopenvs/hyprland/greetd-tuigreet/config.toml /etc/greetd/config.toml +sudo mkdir -p /etc/greetd +sudo cp -f ~/Dotfiles/desktopenvs/sway/greetd-tuigreet/config.toml /etc/greetd/config.toml sudo systemctl enable greetd.service # 4. Copy DE configs diff --git a/setup/modules/Desktop-Environments/xfce.sh b/setup/modules/Desktop-Environments/xfce.sh index 0f72a07..b52b04d 100755 --- a/setup/modules/Desktop-Environments/xfce.sh +++ b/setup/modules/Desktop-Environments/xfce.sh @@ -15,6 +15,15 @@ sudo pacman -S --noconfirm --needed \ flatpak log "Enabling services..." +# getty@tty1 is the default text-mode login prompt; LightDM replaces it. +# '|| true' prevents abort if the unit is already disabled or doesn't exist. +sudo systemctl disable getty@tty1.service || true + +# Disable greetd, which core.sh enables by default for every install. LightDM +# is this DE's own display manager, so leaving greetd enabled means two +# display managers both race to claim tty1. +disable_service greetd.service + sudo systemctl enable lightdm.service sudo systemctl enable NetworkManager.service sudo systemctl enable bluetooth.service diff --git a/setup/modules/core.sh b/setup/modules/core.sh index 1a18d06..e50ce8d 100644 --- a/setup/modules/core.sh +++ b/setup/modules/core.sh @@ -48,15 +48,25 @@ enable_service cronie.service # then enable the service. The config.toml specifies which greeter to run # and optionally auto-login settings. # -f flag forces overwrite of any existing config. -log "Deploying greetd config..." -# greetd may not be installed yet at this point (the DE module pulls in -# greetd-tuigreet later), so /etc/greetd does not exist and the cp would fail — -# aborting the module under `set -e` before fail2ban/udisks2 get enabled. Create -# the directory first so the config is staged regardless; greetd reads it once -# installed. enable_service is already non-fatal if the unit is absent. -sudo mkdir -p /etc/greetd -sudo cp -f ~/Dotfiles/desktopenvs/hyprland/greetd-tuigreet/config.toml /etc/greetd/config.toml -enable_service greetd.service +# +# MARCHY_DE is exported by tui-install.sh once the DE menu is answered. When no +# DE was selected ("none"), staging a greeter that launches Hyprland — which +# was never installed — leaves a broken login screen racing tty1's own agetty +# instead of a working plain-console login. Every DE module that actually wants +# this greeter also re-enables it itself, so it's safe to skip here entirely. +if [[ "${MARCHY_DE:-none}" != "none" ]]; then + log "Deploying greetd config..." + # greetd may not be installed yet at this point (the DE module pulls in + # greetd-tuigreet later), so /etc/greetd does not exist and the cp would fail — + # aborting the module under `set -e` before fail2ban/udisks2 get enabled. Create + # the directory first so the config is staged regardless; greetd reads it once + # installed. enable_service is already non-fatal if the unit is absent. + sudo mkdir -p /etc/greetd + sudo cp -f ~/Dotfiles/desktopenvs/hyprland/greetd-tuigreet/config.toml /etc/greetd/config.toml + enable_service greetd.service +else + skip "No desktop environment selected — leaving greetd disabled (plain agetty login)." +fi # ── fail2ban ────────────────────────────────────────────────────────────────── # WHY: Protects against brute-force attacks by monitoring log files and diff --git a/setup/tools/generate-answerfile.sh b/setup/tools/generate-answerfile.sh index f4611e0..7c80c63 100755 --- a/setup/tools/generate-answerfile.sh +++ b/setup/tools/generate-answerfile.sh @@ -191,8 +191,16 @@ dialog --backtitle "$BACKTITLE" \ # ── Run TUI installer after base install ────────────────────────────────────── dialog --backtitle "$BACKTITLE" \ --title " Dotfiles Setup " \ - --yesno "\n Automatically run the dotfiles TUI installer\n inside the chroot after base install completes?\n" \ - 9 58 && AF_RUN_TUI="true" || AF_RUN_TUI="false" + --yesno "\n Automatically run the dotfiles TUI installer\n inside the chroot after base install completes?\n\n No = no DE, no modules, no shell setup — installed\n user's default shell is plain bash + agetty login.\n" \ + 12 60 && AF_RUN_TUI="true" || AF_RUN_TUI="false" + +# ── Clone dotfiles repo into /etc/skel ────────────────────────────────────────── +# Independent of run_tui: staging the raw repo doesn't require running the TUI, +# and declining it keeps a fully bare install even if the TUI does run. +dialog --backtitle "$BACKTITLE" \ + --title " Skel Dotfiles Clone " \ + --yesno "\n Clone the dotfiles repo into /etc/skel so every\n user created on this machine gets a ~/Dotfiles\n checkout automatically?\n\n No = fully bare install, nothing dotfiles-related\n staged anywhere on disk.\n" \ + 12 60 && AF_CLONE_SKEL_DOTFILES="true" || AF_CLONE_SKEL_DOTFILES="false" # ═══════════════════════════════════════════════════════════════ # PART 2 — Dotfiles / TUI installer options @@ -201,6 +209,7 @@ dialog --backtitle "$BACKTITLE" \ AF_COMPONENTS="" AF_DE="none" AF_APPS="" +AF_SYNC_SKEL_CONFIG="true" AF_COLOR_TEXT="" AF_COLOR_BG="" AF_COLOR_HIGHLIGHT="" @@ -326,6 +335,12 @@ if [[ "$AF_RUN_TUI" == "true" ]]; then 3>&1 1>&2 2>&3) || AF_APPS="" # END GENERATED MODULES: module-checklist + # ── Skel template sync ─────────────────────────────────────────────────────── + dialog --backtitle "$BACKTITLE" \ + --title " Skel Template " \ + --yesno "\n Copy this user's configured ~/.config (and shell\n rc's, if selected) into /etc/skel once setup\n finishes, so users created later on this machine\n inherit the same setup automatically?\n" \ + 11 62 && AF_SYNC_SKEL_CONFIG="true" || AF_SYNC_SKEL_CONFIG="false" + # ── Colorway ────────────────────────────────────────────────────────────── # Read defaults from repo colors.conf declare -A _cdef @@ -386,7 +401,9 @@ SUMMARY="" SUMMARY+=" Encrypt: $AF_ENCRYPT\n" SUMMARY+=" FIDO2 root: $AF_FIDO2_ROOT / FIDO2 user: $AF_FIDO2_USER\n" SUMMARY+=" Run TUI: $AF_RUN_TUI\n" +SUMMARY+=" Clone skel: $AF_CLONE_SKEL_DOTFILES\n" [[ -n "$AF_DE" && "$AF_DE" != "none" ]] && SUMMARY+=" DE: $AF_DE\n" +[[ "$AF_RUN_TUI" == "true" ]] && SUMMARY+=" Sync skel: $AF_SYNC_SKEL_CONFIG\n" [[ -n "$AF_COLOR_TEXT" ]] && SUMMARY+=" Colors: custom\n" dialog --backtitle "$BACKTITLE" \ @@ -426,9 +443,11 @@ mkdir -p "$(dirname "$OUTPUT")" printf ' "fido2_root": %s,\n' "$AF_FIDO2_ROOT" printf ' "fido2_user": %s,\n' "$AF_FIDO2_USER" printf ' "run_tui": %s,\n' "$AF_RUN_TUI" + printf ' "clone_skel_dotfiles": %s,\n' "$AF_CLONE_SKEL_DOTFILES" printf ' "components": %s,\n' "$(_words_to_json_array "$AF_COMPONENTS")" printf ' "desktop_environment": %s,\n' "$(json_str "$AF_DE")" - printf ' "apps": %s' "$(_words_to_json_array "$AF_APPS")" + printf ' "apps": %s,\n' "$(_words_to_json_array "$AF_APPS")" + printf ' "sync_skel_config": %s' "$AF_SYNC_SKEL_CONFIG" if [[ -n "$AF_COLOR_TEXT" ]]; then printf ',\n "colors": {\n' diff --git a/setup/tui-install.sh b/setup/tui-install.sh index d8116bf..97c361d 100755 --- a/setup/tui-install.sh +++ b/setup/tui-install.sh @@ -426,6 +426,7 @@ count_steps() { AF_COMPONENTS="" AF_DE="none" AF_APPS="" +AF_SYNC_SKEL_CONFIG="true" AF_COLOR_TEXT="" AF_COLOR_BG="" AF_COLOR_HIGHLIGHT="" @@ -442,6 +443,9 @@ load_answerfile() { AF_COMPONENTS=$(jq -r '(.components // []) | join(" ")' "$ANSWERFILE") AF_DE=$(jq -r '.desktop_environment // "none"' "$ANSWERFILE") AF_APPS=$(jq -r '(.apps // []) | join(" ")' "$ANSWERFILE") + # Default true: preserves the historical behaviour (always synced) for + # answerfiles written before this toggle existed. + AF_SYNC_SKEL_CONFIG=$(jq -r '.sync_skel_config // true' "$ANSWERFILE") # Color values are optional; an empty string means "keep the repo default". AF_COLOR_TEXT=$(jq -r '.colors.COLOR_TEXT // ""' "$ANSWERFILE") AF_COLOR_BG=$(jq -r '.colors.COLOR_BG // ""' "$ANSWERFILE") @@ -551,6 +555,10 @@ else "lxqt" "LXQt — lightweight Qt X11 DE" \ "none" "Skip DE installation") || DE="none" fi +# Exported so modules launched via `bash "$script"` in run_module() (namely +# core.sh, which stages a default greeter) can see the DE choice — a plain +# subshell does not inherit unexported shell variables. +export MARCHY_DE="$DE" # ── Apps selection ──────────────────────────────────────────────────────────── if $ANSWERFILE_MODE; then @@ -655,6 +663,23 @@ else SHELL_RC="defaults" fi +# ── Skel template preference ────────────────────────────────────────────────── +# Whether to copy this user's fully-configured ~/.config (and shell rc's, if +# SHELL_RC is "dotfiles") into /etc/skel once setup finishes, so any user +# created later on this machine inherits the same setup automatically. Asked +# separately from the dotfiles-clone/component choices above since it's a +# post-install propagation step, not a package/config decision for THIS user. +if $ANSWERFILE_MODE; then + SYNC_SKEL_CONFIG="$AF_SYNC_SKEL_CONFIG" +else + ui_yesno " Skel Template " "\ + Copy this user's configured ~/.config (and shell rc's,\n\ + if selected above) into /etc/skel once setup finishes?\n\n\ + Any user created later on this machine will then inherit\n\ + the same setup automatically." yes \ + && SYNC_SKEL_CONFIG="true" || SYNC_SKEL_CONFIG="false" +fi + # ── Confirmation (interactive mode only) ────────────────────────────────────── if ! $ANSWERFILE_MODE; then # Build a human-readable summary of everything that will be installed so the @@ -666,8 +691,12 @@ if ! $ANSWERFILE_MODE; then [[ " $COMPONENTS " == *" shell "* ]] && SUMMARY+=" ✦ Shell setup (plugins & programs)\n" [[ "$SHELL_RC" == "dotfiles" ]] && SUMMARY+=" ✦ Personal shell rc's (.bashrc/.zshrc/.vimrc)\n" [[ "$DE" != "none" && "$DE" != "" ]] && SUMMARY+=" ✦ Desktop environment: $DE\n" - [[ "$SHELL_RC" == "dotfiles" ]] && SUMMARY+=" ✦ Shell rc's → /etc/skel for new users (dotfiles)\n" \ - || SUMMARY+=" ✦ Shell rc's → /etc/skel for new users (system defaults)\n" + if [[ "$SYNC_SKEL_CONFIG" == "true" ]]; then + [[ "$SHELL_RC" == "dotfiles" ]] && SUMMARY+=" ✦ ~/.config + shell rc's → /etc/skel for new users (dotfiles)\n" \ + || SUMMARY+=" ✦ ~/.config → /etc/skel for new users (shell rc's stay system defaults)\n" + else + SUMMARY+=" ✦ /etc/skel left untouched — new users get system defaults\n" + fi if [[ -n "$SELECTED_APPS" ]]; then SUMMARY+="\n Applications:\n" @@ -1035,23 +1064,27 @@ else fi fi -# ── Sync user config to /etc/skel ───────────────────────────────────────────── +# ── Sync user config to /etc/skel (gated by SYNC_SKEL_CONFIG) ───────────────── # /etc/skel is the skeleton directory Linux copies to new user home dirs on creation. # Propagating the post-install config here means any new user added to this machine # automatically gets the full dotfiles environment without a manual copy step. -if [[ -d "$HOME/.config" ]]; then - printf "\n Syncing ~/.config to /etc/skel...\n" - sudo mkdir -p /etc/skel/.config - # '.' suffix on the source copies directory contents rather than the directory - # itself, making the merge non-destructive if /etc/skel/.config already exists. - sudo cp -r "$HOME/.config/." /etc/skel/.config/ -fi -[[ -d "$HOME/.themes" ]] && { sudo mkdir -p /etc/skel/.themes; sudo cp -r "$HOME/.themes/." /etc/skel/.themes/; } -# Copy shell rc files to skel only if the user opted in to the dotfiles configs. -if [[ "$SHELL_RC" == "dotfiles" ]]; then - [[ -f "$HOME/.zshrc" ]] && sudo cp "$HOME/.zshrc" /etc/skel/.zshrc - [[ -f "$HOME/.bashrc" ]] && sudo cp "$HOME/.bashrc" /etc/skel/.bashrc - [[ -f "$HOME/.vimrc" ]] && sudo cp "$HOME/.vimrc" /etc/skel/.vimrc +if [[ "$SYNC_SKEL_CONFIG" == "true" ]]; then + if [[ -d "$HOME/.config" ]]; then + printf "\n Syncing ~/.config to /etc/skel...\n" + sudo mkdir -p /etc/skel/.config + # '.' suffix on the source copies directory contents rather than the directory + # itself, making the merge non-destructive if /etc/skel/.config already exists. + sudo cp -r "$HOME/.config/." /etc/skel/.config/ + fi + [[ -d "$HOME/.themes" ]] && { sudo mkdir -p /etc/skel/.themes; sudo cp -r "$HOME/.themes/." /etc/skel/.themes/; } + # Copy shell rc files to skel only if the user opted in to the dotfiles configs. + if [[ "$SHELL_RC" == "dotfiles" ]]; then + [[ -f "$HOME/.zshrc" ]] && sudo cp "$HOME/.zshrc" /etc/skel/.zshrc + [[ -f "$HOME/.bashrc" ]] && sudo cp "$HOME/.bashrc" /etc/skel/.bashrc + [[ -f "$HOME/.vimrc" ]] && sudo cp "$HOME/.vimrc" /etc/skel/.vimrc + fi +else + printf "\n Skipping /etc/skel config sync (declined).\n" fi # ── Done ──────────────────────────────────────────────────────────────────────