1184ba17d9
Fix two bugs in the anaconda post-installation script: 1. Hostname handling: Anaconda writes an empty /etc/hostname to the target system. Now we preserve the hostname set during installation from the live environment, falling back to 'fws' if using default values. 2. Keyboard mapping: Anaconda derives keyboard layout from language only, ignoring territory. For locales with territory variants (e.g., fr_CH for Switzerland), we now apply territory-specific keyboard maps to both console (vconsole.conf) and X11 (xorg.conf.d) using langtable for proper mapping.
296 lines
16 KiB
Plaintext
296 lines
16 KiB
Plaintext
# ============================================================================
|
|
# FWS — interactive-defaults.ks
|
|
#
|
|
# Kickstart de base, lu AUTOMATIQUEMENT par Anaconda quand l'install est
|
|
# lancée en mode interactif (chemin fixe codé en dur dans Anaconda :
|
|
# /usr/share/anaconda/interactive-defaults.ks). Aucun inst.ks= n'est requis.
|
|
#
|
|
# RÔLE : empêcher Anaconda d'installer Fedora.
|
|
# ----------------------------------------------------------------------------
|
|
# Sans payload défini, Anaconda utilise DNF → des RPM depuis les dépôts
|
|
# Fedora = il installe Fedora. Anaconda n'a AUCUN backend pacman. La seule
|
|
# façon de poser FWS/Arch est le payload « liveimg » : il recopie une image
|
|
# de système de fichiers (ici le squashfs du live = FWS) sur le disque, puis
|
|
# on finalise nous-mêmes (grub, mkinitcpio, bureau) en %post. C'est le modèle
|
|
# « Sabayon » : le système installé EST une copie du live.
|
|
#
|
|
# L'utilisateur garde la main dans le GUI sur tout ce qui N'EST PAS fixé ici :
|
|
# partitionnement, fuseau, clavier, langue, création d'utilisateur, mot de
|
|
# passe root, etc.
|
|
# ============================================================================
|
|
|
|
# --- Source d'installation : l'image du live (FWS), surtout pas Fedora -------
|
|
# Squashfs archiso sur le média booté :
|
|
# /run/archiso/bootmnt/<install_dir>/<arch>/airootfs.sfs
|
|
# install_dir=fws, arch=x86_64, airootfs_image_type=squashfs (cf. profiledef.sh).
|
|
# Anaconda loop-monte ce .sfs et rsync son contenu vers la cible.
|
|
#
|
|
# ⚠ À VALIDER sur ISO réelle : certaines versions d'Anaconda attendent une
|
|
# structure « LiveOS/rootfs.img » à l'intérieur du squashfs (format Fedora
|
|
# Live) et non un squashfs « plat » comme celui d'archiso. Si l'install
|
|
# échoue à monter la source, basculer sur un tarball de rootfs dédié :
|
|
# liveimg --url=file:///run/archiso/bootmnt/fws/x86_64/fws-rootfs.tar.gz
|
|
# (un build-rootfs.sh produirait alors ce tar via pacstrap).
|
|
liveimg --url=file:///run/archiso/bootmnt/fws/x86_64/airootfs.sfs
|
|
|
|
# --- Disque : repartir d'un disque PROPRE, même s'il a déjà servi ------------
|
|
# Sans ça, une réinstallation sur un disque déjà partitionné (typiquement une
|
|
# install FWS précédente : partitions + VG LVM « anaconda_archiso ») pose deux
|
|
# problèmes : le partitionnement auto n'a plus d'espace libre, et blivet
|
|
# rescanne/auto-active un LVM existant au boot du live → l'installateur se
|
|
# comporte mal voire plante au 2e passage (alors qu'un disque vierge passe).
|
|
# zerombr : réinitialise toute table de partitions invalide
|
|
# (répond « oui » au lieu de bloquer sur un disque
|
|
# non reconnu).
|
|
# clearpart --all : supprime TOUTES les partitions de TOUS les disques.
|
|
# --initlabel : réécrit une étiquette de disque neuve.
|
|
# --disklabel=msdos : force une table MBR (et non GPT). CRUCIAL en BIOS :
|
|
# en BIOS+GPT, GRUB i386-pc exige une partition « BIOS
|
|
# Boot » (~1 Mo, type EF02) pour embarquer core.img,
|
|
# qu'Anaconda NE crée PAS avec « bootloader --disabled
|
|
# » → « this GPT partition label contains no BIOS Boot
|
|
# Partition; embedding won't be possible » →
|
|
# grub-install échoue. En MBR, core.img se loge dans
|
|
# l'espace post-MBR, aucune partition dédiée requise.
|
|
# ⚠ Ce choix vise le BIOS (cas VMware actuel). Pour l'UEFI il faudra du GPT
|
|
# (+ ESP) — à rendre dépendant du firmware (%pre) le jour où on cible l'UEFI.
|
|
# L'utilisateur garde la main dans le GUI (il peut repasser en manuel), mais le
|
|
# DÉFAUT est désormais un disque net → réinstall fiable à chaque fois.
|
|
# ⚠ VM mono-disque : « --all » efface le seul disque, c'est voulu. Sur une
|
|
# machine multi-disques il faudrait cibler avec « --drives=sda ».
|
|
zerombr
|
|
clearpart --all --initlabel --disklabel=msdos
|
|
|
|
# --- Bootloader : géré à la main en %post ------------------------------------
|
|
# Anaconda lancerait « grub2-install » / « grub2-mkconfig » (binaires Fedora,
|
|
# préfixe grub2-) qui n'existent pas dans un rootfs Arch (lequel fournit
|
|
# grub-install / grub-mkconfig). On désactive donc l'étape native d'Anaconda.
|
|
# L'ESP (UEFI) ou la partition bios_boot (BIOS/GPT) reste créée par le
|
|
# partitionnement (auto ou manuel) car la plateforme l'impose.
|
|
bootloader --disabled
|
|
|
|
# Pas de section %packages : le payload liveimg n'installe aucun paquet
|
|
# (il copie une image). Toute installation de paquets se fait en %post.
|
|
|
|
|
|
# ============================================================================
|
|
# %post --nochroot — s'exécute dans le LIVE, la cible montée sous /mnt/sysroot
|
|
# But : déposer dans la cible ce dont le %post chrooté aura besoin (DNS pour
|
|
# pacman, choix de bureau écrit par l'addon de sélection).
|
|
# ============================================================================
|
|
%post --nochroot --log=/tmp/fws-post-nochroot.log
|
|
set -x
|
|
|
|
# Selon la version d'Anaconda la cible est sous /mnt/sysroot (récent) ou
|
|
# /mnt/sysimage (ancien).
|
|
SYSROOT=/mnt/sysroot
|
|
[ -d "$SYSROOT" ] || SYSROOT=/mnt/sysimage
|
|
|
|
# DNS pour que « pacman -S <bureau> » fonctionne dans le chroot.
|
|
cp -f /etc/resolv.conf "$SYSROOT/etc/resolv.conf" 2>/dev/null || true
|
|
|
|
# --- Hostname : reprendre celui saisi dans Anaconda, sinon « fws » -----------
|
|
# BUG observé : Anaconda écrit un /etc/hostname VIDE dans la cible (le hostname
|
|
# du spoke Réseau n'est pas capté). On reprend donc le hostname COURANT du LIVE
|
|
# (Anaconda l'applique au live quand on le saisit dans le spoke) s'il diffère du
|
|
# défaut archiso, sinon on pose un défaut propre « fws » — jamais de hostname
|
|
# vide. (Ce %post tourne APRÈS l'écriture d'Anaconda → on écrase son fichier
|
|
# vide.)
|
|
HN="$(cat /proc/sys/kernel/hostname 2>/dev/null)"
|
|
case "$HN" in
|
|
""|archlinux|localhost|localhost.localdomain) HN="fws" ;;
|
|
esac
|
|
echo "$HN" > "$SYSROOT/etc/hostname"
|
|
|
|
# Choix du bureau (écrit par l'addon « Choix du bureau », à venir ; valeur lue
|
|
# par le %post chrooté ci-dessous). « cli » par défaut si absent.
|
|
if [ -f /tmp/fws-desktop ]; then
|
|
cp -f /tmp/fws-desktop "$SYSROOT/tmp/fws-desktop" 2>/dev/null || true
|
|
fi
|
|
|
|
# --- Noyau : archiso RETIRE /boot/vmlinuz-linux du squashfs ------------------
|
|
# mkarchiso boote le noyau depuis l'ISO et l'EXCLUT de l'airootfs squashfs (gain
|
|
# de place). Conséquence : le payload LiveOS recopie un rootfs SANS noyau →
|
|
# « mkinitcpio: /boot/vmlinuz-linux must be readable » puis aucun OS à booter
|
|
# (« Operating System not found »). On récupère donc le noyau depuis le média
|
|
# booté (/run/archiso/bootmnt/<install_dir>/boot/<arch>/vmlinuz-linux) et on le
|
|
# dépose dans la cible. Les modules (/usr/lib/modules) sont, eux, dans le
|
|
# squashfs → déjà recopiés. Avec le noyau présent, le %post chrooté peut bâtir
|
|
# l'initramfs (mkinitcpio) et GRUB trouve de quoi booter.
|
|
SRC_KERN="$(find /run/archiso/bootmnt -name 'vmlinuz-linux' 2>/dev/null | head -1)"
|
|
if [ -n "$SRC_KERN" ]; then
|
|
cp -f "$SRC_KERN" "$SYSROOT/boot/vmlinuz-linux"
|
|
else
|
|
echo "[FWS] AVERTISSEMENT : noyau vmlinuz-linux introuvable sur le média"
|
|
fi
|
|
%end
|
|
|
|
|
|
# ============================================================================
|
|
# %post (chroot) — DANS le rootfs FWS recopié. pacman, grub-install,
|
|
# mkinitcpio existent ici : ce sont les outils Arch de l'image copiée.
|
|
# Log persistant : /var/log/fws-post.log sur le système installé.
|
|
# ============================================================================
|
|
%post --log=/var/log/fws-post.log
|
|
set -x
|
|
|
|
# --- 1) Purge des résidus « live » (modèle Sabayon = live copié tel quel) ----
|
|
# Ce qui est propre au live casserait ou pollue le système installé.
|
|
rm -f /etc/mkinitcpio.conf.d/archiso.conf
|
|
rm -f /etc/systemd/system/getty@tty1.service.d/autologin.conf
|
|
for svc in choose-mirror.service pacman-init.service \
|
|
livecd-talk.service livecd-alsa-unmuter.service \
|
|
etc-pacman.d-gnupg.mount; do
|
|
rm -f "/etc/systemd/system/$svc"
|
|
rm -f /etc/systemd/system/*.target.wants/"$svc"
|
|
done
|
|
# cloud-init (présent dans l'airootfs archiso) : inutile sur un poste installé.
|
|
rm -f /etc/systemd/system/cloud-init.target.wants/* 2>/dev/null || true
|
|
# Hooks initramfs archiso, s'ils ont été recopiés en tant que paquet.
|
|
if pacman -Q mkinitcpio-archiso &>/dev/null; then
|
|
pacman -Rns --noconfirm mkinitcpio-archiso || true
|
|
fi
|
|
|
|
# --- 2) initramfs propre (preset Arch standard, sans archiso) ----------------
|
|
# Le live fournit un preset 'archiso' (/etc/mkinitcpio.d/linux.preset qui pointe
|
|
# vers conf.d/archiso.conf + hooks archiso) → inadapté à un disque normal. On
|
|
# pose un preset Arch standard (config par défaut /etc/mkinitcpio.conf).
|
|
cat > /etc/mkinitcpio.d/linux.preset <<'PRESET'
|
|
ALL_kver="/boot/vmlinuz-linux"
|
|
PRESETS=('default' 'fallback')
|
|
default_image="/boot/initramfs-linux.img"
|
|
fallback_image="/boot/initramfs-linux-fallback.img"
|
|
fallback_options="-S autodetect"
|
|
PRESET
|
|
# Le partitionnement auto d'Anaconda met « / » sur LVM (/dev/mapper/...-root).
|
|
# Sans le hook 'lvm2' dans l'initramfs, le VG n'est pas activé au boot → la
|
|
# racine est introuvable → kernel panic. On l'insère avant 'filesystems' s'il
|
|
# manque (inoffensif si la racine n'est finalement pas sur LVM).
|
|
if ! grep -qE '^HOOKS=.*\blvm2\b' /etc/mkinitcpio.conf; then
|
|
sed -i -E 's/^(HOOKS=\(.*)\bfilesystems\b/\1lvm2 filesystems/' /etc/mkinitcpio.conf
|
|
fi
|
|
mkinitcpio -P || echo "[FWS] AVERTISSEMENT : mkinitcpio a échoué"
|
|
|
|
# --- 3) GRUB installé à la main (cf. bootloader --disabled) ------------------
|
|
install_grub() {
|
|
if [ -d /sys/firmware/efi ]; then
|
|
# UEFI. efibootmgr crée l'entrée NVRAM « FWS », mais il peut MANQUER de
|
|
# l'airootfs et son install dépend du réseau → on ne BLOQUE pas dessus.
|
|
pacman -Q efibootmgr &>/dev/null || pacman -Sy --noconfirm efibootmgr || true
|
|
# (a) Entrée NVRAM dédiée (best effort, si efibootmgr dispo) :
|
|
grub-install --target=x86_64-efi --efi-directory=/boot/efi \
|
|
--bootloader-id=FWS --recheck || true
|
|
# (b) Chemin de SECOURS EFI/BOOT/BOOTX64.EFI (--removable) : boote SANS
|
|
# aucune entrée NVRAM. INDISPENSABLE en VM / sans réseau / firmware
|
|
# qui « oublie » l'entrée — c'est lui qui garantit le 1er boot UEFI.
|
|
grub-install --target=x86_64-efi --efi-directory=/boot/efi \
|
|
--bootloader-id=FWS --removable --recheck
|
|
else
|
|
# BIOS : installer GRUB dans le MBR du DISQUE physique (PAS une partition)
|
|
# portant « / », même quand « / » est sur du LVM (chaîne
|
|
# LV → PV partition → disque). « lsblk -s » descend vers le physique ; on
|
|
# prend la ligne de type « disk ». ATTENTION : « lsblk -s » dessine un
|
|
# ARBRE → les caractères de branche (└─) se collent au chemin (on
|
|
# obtenait disk='-/dev/sda' → « grub-install: cannot find a GRUB drive
|
|
# for `-/dev/sda' »). On EXTRAIT donc le chemin propre avec grep.
|
|
local rootsrc disk
|
|
rootsrc="$(findmnt -no SOURCE / 2>/dev/null)"
|
|
disk="$(lsblk -spno NAME,TYPE "$rootsrc" 2>/dev/null \
|
|
| awk '$2=="disk"{print $1; exit}' | grep -oE '/dev/[a-z0-9]+')"
|
|
[ -n "$disk" ] || { echo "[FWS] Disque BIOS introuvable pour '$rootsrc'"; return 1; }
|
|
grub-install --target=i386-pc --recheck "$disk"
|
|
fi
|
|
}
|
|
if install_grub; then
|
|
grub-mkconfig -o /boot/grub/grub.cfg || echo "[FWS] grub-mkconfig a échoué"
|
|
else
|
|
echo "[FWS] AVERTISSEMENT : grub-install a échoué — bootloader à refaire à la main"
|
|
fi
|
|
|
|
# --- 3bis) Clavier : corriger le keymap selon le TERRITOIRE de la locale ------
|
|
# BUG observé : Anaconda dérive le clavier de la LANGUE en IGNORANT le territoire
|
|
# → fr_CH (Suisse) donne « fr » (France) au lieu du clavier SUISSE. On corrige :
|
|
# si un keymap console spécifique au territoire existe (fr_CH, de_CH…), on
|
|
# l'impose dans /etc/vconsole.conf, et on règle aussi le clavier X11 (pour un
|
|
# bureau installé ensuite) via langtable. Locale lue dans /etc/locale.conf, à
|
|
# défaut dans /root/anaconda-ks.cfg (« lang … »).
|
|
fix_keyboard() {
|
|
local langv loc lng terr font xk xl xv
|
|
langv="$(. /etc/locale.conf 2>/dev/null; printf '%s' "${LANG:-}")"
|
|
[ -n "$langv" ] || langv="$(sed -n 's/^lang[[:space:]]\+//p' /root/anaconda-ks.cfg 2>/dev/null | head -1)"
|
|
loc="${langv%%.*}" # fr_CH.UTF-8 → fr_CH
|
|
lng="${loc%%_*}" # fr
|
|
terr="${loc#*_}"; [ "$terr" = "$loc" ] && terr="" # CH
|
|
[ -n "$terr" ] || return 0
|
|
find /usr/share/kbd/keymaps -name "${lng}_${terr}.map.gz" 2>/dev/null | grep -q . || return 0
|
|
# vconsole (console TTY) : keymap du territoire (ex. fr_CH). On préserve FONT.
|
|
font="$(grep '^FONT=' /etc/vconsole.conf 2>/dev/null)"
|
|
{ echo "KEYMAP=${lng}_${terr}"; [ -n "$font" ] && echo "$font"; } > /etc/vconsole.conf
|
|
# X11 (bureau) : layout/variant via langtable (ex. fr_CH → 'ch(fr)' → ch/fr).
|
|
xk="$(python3 -c "import langtable; k=langtable.list_keyboards(languageId='$lng', territoryId='$terr'); print(k[0] if k else '')" 2>/dev/null)"
|
|
case "$xk" in
|
|
*'('*')') xl="${xk%%(*}"; xv="${xk#*(}"; xv="${xv%)}" ;;
|
|
?*) xl="$xk"; xv="" ;;
|
|
*) return 0 ;;
|
|
esac
|
|
mkdir -p /etc/X11/xorg.conf.d
|
|
cat > /etc/X11/xorg.conf.d/00-keyboard.conf <<EOF
|
|
Section "InputClass"
|
|
Identifier "system-keyboard"
|
|
MatchIsKeyboard "on"
|
|
Option "XkbLayout" "$xl"
|
|
Option "XkbVariant" "$xv"
|
|
EndSection
|
|
EOF
|
|
}
|
|
fix_keyboard || echo "[FWS] clavier : ajustement territoire ignoré"
|
|
|
|
# --- 4) Bureau choisi : pacman -S du DE (non bloquant si pas de réseau) -------
|
|
DESK="cli"
|
|
[ -f /tmp/fws-desktop ] && DESK="$(tr -d '[:space:]' < /tmp/fws-desktop)"
|
|
DM=""
|
|
case "$DESK" in
|
|
kde) PKGS="plasma-meta sddm konsole dolphin"; DM="sddm" ;;
|
|
gnome) PKGS="gnome gdm"; DM="gdm" ;;
|
|
xfce) PKGS="xfce4 xfce4-goodies lightdm lightdm-gtk-greeter"; DM="lightdm" ;;
|
|
hyprland) PKGS="hyprland kitty wofi waybar sddm"; DM="sddm" ;;
|
|
cli|*) PKGS="" ;;
|
|
esac
|
|
if [ -n "$PKGS" ]; then
|
|
pacman-key --init &>/dev/null || true
|
|
pacman-key --populate archlinux &>/dev/null || true
|
|
if pacman -Sy --noconfirm $PKGS; then
|
|
[ -n "$DM" ] && systemctl enable "$DM" || true
|
|
systemctl set-default graphical.target || true
|
|
else
|
|
echo "[FWS] Bureau '$DESK' non installé (réseau ?) — à refaire après le 1er boot."
|
|
fi
|
|
fi
|
|
|
|
# --- 5) Sécurité : verrouiller root s'il est resté SANS mot de passe ----------
|
|
# L'airootfs live a souvent un root sans mot de passe ; si l'utilisateur n'en a
|
|
# pas défini dans le GUI, on verrouille plutôt que de laisser le compte ouvert.
|
|
if passwd -S root 2>/dev/null | grep -qE '\bNP\b'; then
|
|
passwd -l root || true
|
|
fi
|
|
|
|
# --- 6) Le resolv.conf du live ne doit pas rester figé -----------------------
|
|
# NetworkManager (activé sur le système installé) régénère /etc/resolv.conf.
|
|
rm -f /tmp/fws-desktop /etc/resolv.conf 2>/dev/null || true
|
|
%end
|
|
|
|
|
|
# ============================================================================
|
|
# %post --nochroot (FINAL) — exfiltre le log du %post chrooté vers le LIVE.
|
|
# À ce stade la cible est ENCORE montée sous /mnt/sysroot (l'unmount n'a pas
|
|
# encore eu lieu). On copie /var/log/fws-post.log (résultat de grub-install /
|
|
# mkinitcpio) vers le live /tmp pour que le harnais de debug (.xinitrc)
|
|
# l'affiche SANS avoir à remonter le disque démonté — c'est ce log qui dit si
|
|
# le disque va booter.
|
|
# ============================================================================
|
|
%post --nochroot
|
|
SYSROOT=/mnt/sysroot
|
|
[ -d "$SYSROOT" ] || SYSROOT=/mnt/sysimage
|
|
cp -f "$SYSROOT/var/log/fws-post.log" /tmp/fws-post-chroot.log 2>/dev/null || true
|
|
%end
|