feat(baseline): add fws-hw-detect script for hardware detection and configuration

Add new fws-hw-detect script that detects hypervisor type and GPU hardware, outputting either machine-readable environment variables for kickstart processing or human-readable French text summary for live environment.

The script serves as the single source of truth for hardware detection, consumed by:
- Live environment display via zenity before installation starts
- Anaconda %post chroot to apply appropriate guest tools and GPU drivers

Supported hypervisors: VMware, VirtualBox, QEMU/KVM, and physical machines
Supported GPUs: NVIDIA, AMD, Intel, and VMware/VirtualBox virtual graphics

No hard dependencies; gracefully degrades when lspci and ip are unavailable.
This commit is contained in:
2026-07-03 03:21:31 +02:00
parent 2c9e4e6260
commit 19c16006fb
@@ -0,0 +1,173 @@
#!/bin/bash
# ============================================================================
# fws-hw-detect — détection matériel FWS (hyperviseur + GPU).
#
# SOURCE UNIQUE de vérité, consommée par DEUX endroits :
# • l'écran « Récapitulatif avant installation » du live (--text, affiché
# par /root/.xinitrc via zenity juste avant de lancer liveinst) ;
# • le %post chrooté du kickstart Anaconda (--env), qui APPLIQUE :
# activation des guest tools du bon hyperviseur, purge des autres,
# installation des drivers GPU.
# → ce que l'écran ANNONCE = ce que l'install FERA (aucune divergence
# possible, la détection vit ici et nulle part ailleurs).
#
# Fonctionne dans le LIVE comme dans le CHROOT d'Anaconda : celui-ci
# bind-monte /sys et /proc du live → même matériel visible. Le script est
# livré par l'airootfs (/usr/local/bin) → recopié dans la cible par le
# payload liveimg → présent dans le chroot du %post. Aucune dépendance
# dure : lspci (pciutils) et ip (iproute2) ne servent qu'aux libellés
# humains de --text, avec repli si absents.
#
# Usage : fws-hw-detect --env lignes FWS_*='…' à eval par le kickstart
# fws-hw-detect --text récapitulatif humain en français (zenity)
# ============================================================================
set -u
MODE="${1:---text}"
# --- Hyperviseur --------------------------------------------------------------
# systemd-detect-virt lit CPUID/DMI → OK en chroot, sans systemd actif.
# ATTENTION : hors VM il AFFICHE « none » ET sort en code ≠ 0 → surtout pas de
# « || echo none » DANS le $() (on récolterait « none » en double).
VIRT="$(systemd-detect-virt 2>/dev/null | head -n1)"
[ -n "$VIRT" ] || VIRT=none
# Les guest tools des 3 hyperviseurs sont DÉJÀ dans l'image live
# (packages.x86_64 : open-vm-tools, virtualbox-guest-utils-nox,
# qemu-guest-agent) → activer un service marche HORS LIGNE ; on retire ceux
# des autres hyperviseurs (inutiles sur cette machine).
VIRT_SVC="" VIRT_RM="" VIRT_LABEL=""
case "$VIRT" in
vmware)
VIRT_LABEL="VMware"
VIRT_SVC="vmtoolsd.service vmware-vmblock-fuse.service"
VIRT_RM="virtualbox-guest-utils-nox qemu-guest-agent" ;;
oracle) # = VirtualBox (nom renvoyé par systemd-detect-virt)
VIRT_LABEL="VirtualBox"
VIRT_SVC="vboxservice.service"
VIRT_RM="open-vm-tools qemu-guest-agent" ;;
kvm|qemu)
VIRT_LABEL="QEMU/KVM"
VIRT_SVC="qemu-guest-agent.service"
VIRT_RM="open-vm-tools virtualbox-guest-utils-nox" ;;
none)
VIRT_LABEL="aucune (machine physique)"
VIRT_RM="open-vm-tools virtualbox-guest-utils-nox qemu-guest-agent" ;;
*) # Hyperviseur non géré (hyper-v…) : aucun de nos guest tools ne sert.
VIRT_LABEL="$VIRT (intégration non gérée)"
VIRT_RM="open-vm-tools virtualbox-guest-utils-nox qemu-guest-agent" ;;
esac
# --- GPU ----------------------------------------------------------------------
# Classe PCI 0x03xxxx = contrôleur d'affichage ; lecture DIRECTE de /sys, pas
# besoin de lspci. Vendors : 0x10de NVIDIA, 0x1002 AMD, 0x8086 Intel,
# 0x15ad VMware (le VMSVGA de VirtualBox porte AUSSI 0x15ad → couvert).
# QEMU virtio-gpu/QXL et VBoxVGA : modesetting + mesa (déjà tirés par
# xorg-server dans l'image) suffisent → rien à installer.
DRV_PKGS="" GPU_TEXT=""
for _dev in /sys/bus/pci/devices/*; do
case "$(cat "$_dev/class" 2>/dev/null)" in 0x03*) ;; *) continue ;; esac
_vendor="$(cat "$_dev/vendor" 2>/dev/null)"
_pkgs=""
case "$_vendor" in
# NVIDIA : le module des dépôts est bâti pour le NOYAU des dépôts →
# « linux » DOIT partir dans la même transaction pacman (le noyau
# installé est celui du live, plus vieux), sinon module ≠ noyau au
# 1er boot. Les chemins /boot/* sont stables → grub.cfg reste bon.
0x10de) _pkgs="linux nvidia nvidia-utils" ;;
0x1002) _pkgs="mesa vulkan-radeon xf86-video-amdgpu" ;;
0x8086) _pkgs="mesa vulkan-intel" ;;
0x15ad) _pkgs="mesa xf86-video-vmware" ;;
esac
# Libellé humain : lspci si dispo, sinon adresse PCI + vendor brut.
_name=""
if command -v lspci >/dev/null 2>&1; then
_name="$(lspci -s "${_dev##*/}" 2>/dev/null | head -n1 \
| cut -d: -f3- | sed 's/^ //')"
fi
[ -n "$_name" ] || _name="GPU PCI ${_dev##*/} (vendor $_vendor)"
if [ -n "$_pkgs" ]; then
GPU_TEXT="${GPU_TEXT} • ${_name}\n → paquets : ${_pkgs}\n"
DRV_PKGS="$DRV_PKGS $_pkgs"
else
GPU_TEXT="${GPU_TEXT} • ${_name}\n → rien à installer (modesetting + mesa, déjà dans l'image)\n"
fi
done
# Dédoublonnage (machine multi-GPU : « mesa » listé 2× ferait échouer pacman
# sur « duplicate target »).
if [ -n "$DRV_PKGS" ]; then
DRV_PKGS="$(printf '%s\n' $DRV_PKGS | sort -u | tr '\n' ' ')"
DRV_PKGS="${DRV_PKGS% }"
fi
# --- Mode machine : sortie shell pour le kickstart ----------------------------
if [ "$MODE" = "--env" ]; then
printf "FWS_VIRT='%s'\n" "$VIRT"
printf "FWS_VIRT_SVC='%s'\n" "$VIRT_SVC"
printf "FWS_VIRT_RM='%s'\n" "$VIRT_RM"
printf "FWS_DRV_PKGS='%s'\n" "$DRV_PKGS"
exit 0
fi
# --- Mode humain : récapitulatif --text (zenity, avant liveinst) ---------------
CPU="$(awk -F': +' '/^model name/{print $2; exit}' /proc/cpuinfo)"
[ -n "$CPU" ] || CPU="inconnu"
case "$(awk -F': +' '/^vendor_id/{print $2; exit}' /proc/cpuinfo)" in
GenuineIntel) UCODE="intel-ucode" ;;
AuthenticAMD) UCODE="amd-ucode" ;;
*) UCODE="" ;;
esac
RAM="$(awk '/^MemTotal/{printf "%.1f Gio", $2/1048576}' /proc/meminfo)"
if [ -d /sys/firmware/efi ]; then
BOOT="UEFI — GRUB x86_64-efi + entrée de secours EFI/BOOT/BOOTX64.EFI"
else
BOOT="BIOS hérité — GRUB i386-pc, table de partitions MBR forcée"
fi
if command -v ip >/dev/null 2>&1 && ip route get 1.1.1.1 >/dev/null 2>&1; then
NET="disponible ✔"
else
NET="INDISPONIBLE ✖ — drivers GPU et bureau ne s'installeront PAS (rattrapable au 1er boot)"
fi
# Type « disk » uniquement (exclut lecteur ISO sr0/loop). La clé USB du live,
# elle, EST un disque → il est juste qu'elle apparaisse sous l'avertissement
# d'effacement (clearpart --all du kickstart efface bien TOUS les disques).
DISKS="$(lsblk -dno NAME,SIZE,MODEL,TYPE 2>/dev/null \
| awk '$NF=="disk"{NF--; print " • " $0}')"
[ -n "$DISKS" ] || DISKS=" (aucun disque détecté)"
[ -n "$GPU_TEXT" ] || GPU_TEXT=" (aucune carte graphique détectée)\n"
printf '%b' \
"══════════════════════════════════════════════════════════
FWS — RÉCAPITULATIF AVANT INSTALLATION
══════════════════════════════════════════════════════════
MACHINE
• Démarrage : ${BOOT}
• Virtualisation : ${VIRT_LABEL}
• Processeur : ${CPU}"
[ -n "$UCODE" ] && printf '%b' "
• Microcode : ${UCODE} — déjà intégré à l'image, rien à faire"
printf '%b' "
• Mémoire : ${RAM}
• Réseau : ${NET}
DISQUES DÉTECTÉS
⚠ Par défaut, TOUS les disques ci-dessous seront ENTIÈREMENT
EFFACÉS (partitionnement automatique). Le partitionnement
manuel reste possible dans l'installateur.
${DISKS}
CARTES GRAPHIQUES → drivers installés AUTOMATIQUEMENT en fin d'install
${GPU_TEXT}
INTÉGRATION HYPERVISEUR (automatique, fonctionne hors ligne)
• Services activés : ${VIRT_SVC:-aucun}
• Guest tools retirés (inutiles) : ${VIRT_RM:-aucun}
DÉROULEMENT DE L'INSTALLATION
1. Réglages dans Anaconda : langue, clavier, fuseau, disque, utilisateur
2. Copie du système live FWS sur le disque (payload liveimg)
3. Noyau + initramfs régénérés (mkinitcpio), GRUB installé
4. Drivers GPU + intégration hyperviseur appliqués (voir ci-dessus)
5. Bureau choisi installé (réseau requis)
« Lancer l'installateur » pour continuer — « Éteindre » pour annuler.
"