384a45f70e
Add support for injecting Intel VMD drivers during Windows deployment. The script now: - Parses the intel_vmd configuration option from the state file - Checks for Intel VMD drivers in /usr/local/share/fws/drivers/intel-vmd/ - Injects drivers via WinPE (dism) when requested and available - Falls back to Windows inbox VMD driver with a warning if no driver found - Forces WinPE path when VMD driver injection is needed - Passes driver path to fws-windows-bcdfix for processing
302 lines
17 KiB
Bash
302 lines
17 KiB
Bash
#!/bin/bash
|
|
# ============================================================
|
|
# fws-windows-deploy — déploie Windows 11 en OFFLINE-APPLY sur un disque dédié,
|
|
# depuis le live FWS (appelé en %post --nochroot, cible sous /mnt/sysroot).
|
|
#
|
|
# Windows Setup ne tourne JAMAIS : on carve les partitions, on applique
|
|
# install.wim (wimlib), on rend bootable (BCD), on injecte l'answer file offline
|
|
# + le composant gameboot, on provisionne l'hibernation FWS.
|
|
#
|
|
# SÉCURITÉ (risque n°1 = effacer le mauvais NVMe) : garde-fous FAIL-CLOSED —
|
|
# état PARSÉ (jamais sourcé → pas d'injection), disque cible VALIDÉ contre la
|
|
# liste des disques réels, comparé à TOUS les disques protégés (racine FWS
|
|
# multi-PV incluse, ESP, média ISO, support live), aucun label FWS résiduel
|
|
# ailleurs, adressage des partitions par NUMÉRO sur le disque cible (jamais par
|
|
# by-partlabel global) avec vérif du parent. Le moindre doute → abort. Échec →
|
|
# DEPLOY_FAILED, aucune entrée UEFI piégeuse, FWS reste seul bootable.
|
|
#
|
|
# ⚠ NON VALIDÉ SUR MATÉRIEL RÉEL (déploiement Windows réel + BCD).
|
|
# ============================================================
|
|
set -u
|
|
|
|
STATE=/tmp/fws-windows
|
|
SYSROOT=/mnt/sysroot
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--state) STATE="${2:-}"; shift 2 ;;
|
|
--sysroot) SYSROOT="${2:-}"; shift 2 ;;
|
|
*) shift ;;
|
|
esac
|
|
done
|
|
|
|
log(){ printf '\e[36m[win-deploy]\e[0m %s\n' "$*"; }
|
|
warn(){ printf '\e[33m[win-deploy] %s\e[0m\n' "$*" >&2; }
|
|
status(){ mkdir -p "$SYSROOT/var/lib/fws" 2>/dev/null; echo "$1" > "$SYSROOT/var/lib/fws/windows-deploy.status" 2>/dev/null || true; }
|
|
die(){ printf '\e[31m[win-deploy] ABORT : %s\e[0m\n' "$*" >&2; status "DEPLOY_FAILED: $*"; exit 1; }
|
|
canon(){ readlink -f "$1" 2>/dev/null || printf '%s' "$1"; }
|
|
# Device de la partition N sur le disque D (nvme/mmc → pN ; sata → N).
|
|
part_dev(){ case "$1" in *[0-9]) printf '%sp%s' "$1" "$2";; *) printf '%s%s' "$1" "$2";; esac; }
|
|
|
|
# --- 0) État du spoke : PARSÉ en clé=valeur littéral (JAMAIS sourcé) [M3] -----
|
|
[ -r "$STATE" ] || { log "pas de $STATE → dual-boot non demandé, rien à faire."; exit 0; }
|
|
enabled=0; disk=""; size_gib=0; iso=""; edition=""; confirm_erase=0; intel_vmd=0
|
|
while IFS='=' read -r k v; do
|
|
case "$k" in
|
|
enabled) enabled="$v" ;;
|
|
disk) disk="$v" ;;
|
|
size_gib) size_gib="$v" ;;
|
|
iso) iso="$v" ;;
|
|
edition) edition="$v" ;;
|
|
confirm_erase) confirm_erase="$v" ;;
|
|
intel_vmd) intel_vmd="$v" ;;
|
|
esac
|
|
done < "$STATE"
|
|
[ "${enabled:-0}" = 1 ] || { log "dual-boot désactivé, rien à faire."; exit 0; }
|
|
[ "${size_gib:-0}" -eq "${size_gib:-0}" ] 2>/dev/null || die "taille non numérique"
|
|
log "Dual-boot Windows demandé : disque=$disk taille=${size_gib}Gio iso=$iso"
|
|
|
|
# --- Résolveur : TOUS les disques physiques sous un montage (fail-closed) [M1]
|
|
fws_disks_of(){
|
|
local src
|
|
src="$(findmnt -no SOURCE "$1" 2>/dev/null)" || return 1
|
|
[ -n "$src" ] || return 1
|
|
lsblk -spno NAME,TYPE "$src" 2>/dev/null | awk '$2=="disk"{print $1}'
|
|
}
|
|
|
|
# --- 1) Garde-fous AVANT toute écriture (fail-closed) -----------------------
|
|
WIN_DISK="$disk"
|
|
[ -b "$WIN_DISK" ] || die "cible '$WIN_DISK' n'est pas un disque bloc"
|
|
# [M3] 'disk' DOIT être un vrai disque physique (neutralise toute valeur piégée).
|
|
lsblk -dpno NAME,TYPE 2>/dev/null | awk '$2=="disk"{print $1}' | grep -qxF "$WIN_DISK" \
|
|
|| die "cible '$WIN_DISK' absente de la liste des disques physiques"
|
|
findmnt -no SOURCE "$SYSROOT" >/dev/null 2>&1 || die "$SYSROOT non monté"
|
|
[ -f "$iso" ] || die "ISO introuvable : $iso"
|
|
[ "${size_gib:-0}" -ge 100 ] || die "taille < 100 Gio"
|
|
|
|
# Swap d'hibernation (RAM+VRAM+marge, plancher 96) — calculé ICI pour le garde taille [M7].
|
|
MEM=$(awk '/^MemTotal/{print int($2/1024)}' /proc/meminfo)
|
|
VRAM=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits 2>/dev/null | awk '{s+=$1}END{print s+0}')
|
|
SWAP_GIB=$(( (MEM + VRAM + 4096 + 1023) / 1024 )); [ "$SWAP_GIB" -lt 96 ] && SWAP_GIB=96
|
|
|
|
# Le disque cible ne doit être AUCUN disque protégé. On sonde uniquement de VRAIS
|
|
# montages [m1], et on compare à TOUS les disques porteurs [M1]. Resolver muet → abort.
|
|
WIN_C="$(canon "$WIN_DISK")"
|
|
for probe in "$SYSROOT" "$SYSROOT/boot/efi" "$SYSROOT/boot" /run/archiso/bootmnt; do
|
|
findmnt -M "$probe" >/dev/null 2>&1 || continue
|
|
mapfile -t pds < <(fws_disks_of "$probe")
|
|
[ "${#pds[@]}" -gt 0 ] || die "resolver muet sur '$probe' → abort (fail-closed)"
|
|
for d in "${pds[@]}"; do
|
|
[ "$WIN_C" != "$(canon "$d")" ] || die "$WIN_DISK == disque protégé ($probe via $d) — refus d'effacer"
|
|
done
|
|
done
|
|
# L'ISO ne doit pas vivre sur la cible — fail-closed si le média est indéterminable [m2].
|
|
iso_mnt="$(df --output=target "$iso" 2>/dev/null | tail -1)"
|
|
[ -n "$iso_mnt" ] || die "média de l'ISO indéterminable → abort (fail-closed)"
|
|
mapfile -t isods < <(fws_disks_of "$iso_mnt")
|
|
[ "${#isods[@]}" -gt 0 ] || die "resolver muet sur le média ISO → abort"
|
|
for d in "${isods[@]}"; do
|
|
[ "$WIN_C" != "$(canon "$d")" ] || die "l'ISO vit sur la cible $WIN_DISK — refus"
|
|
done
|
|
# Taille : NTFS + ESP + MSR + swap doivent tenir [M7].
|
|
DGIB=$(( $(lsblk -dbno SIZE "$WIN_DISK" 2>/dev/null || echo 0) / 1073741824 ))
|
|
[ "$DGIB" -gt 0 ] && [ "$size_gib" -le $(( DGIB - SWAP_GIB - 4 )) ] \
|
|
|| die "taille ${size_gib} + swap ${SWAP_GIB} + réserve dépasse le disque ${DGIB} Gio"
|
|
|
|
# [B1] Aucun label FWS résiduel ne doit exister sur un AUTRE disque (collision
|
|
# by-partlabel = risque d'écrire ailleurs). On refuse plutôt que de deviner.
|
|
while read -r dev lbl; do
|
|
case "$lbl" in
|
|
FWSWIN|WINESP|FWSSWAP)
|
|
pk="/dev/$(lsblk -no PKNAME "$dev" 2>/dev/null | head -1)"
|
|
[ "$(canon "$pk")" = "$WIN_C" ] \
|
|
|| die "label '$lbl' déjà présent sur $pk (≠ cible) — nettoie-le d'abord (wipefs -a $pk)" ;;
|
|
esac
|
|
done < <(lsblk -lnpo NAME,PARTLABEL 2>/dev/null)
|
|
log "Garde-fous OK : $WIN_DISK ($DGIB Gio) sûr à dédier à Windows (swap ${SWAP_GIB} Gio)."
|
|
|
|
# --- 2) Neutraliser toute activation du disque cible [M2] -------------------
|
|
log "Neutralisation des partitions de $WIN_DISK…"
|
|
for part in $(lsblk -lnpo NAME "$WIN_DISK" 2>/dev/null | tail -n +2); do
|
|
umount "$part" 2>/dev/null || true
|
|
swapoff "$part" 2>/dev/null || true
|
|
for vg in $(pvs --noheadings -o vg_name "$part" 2>/dev/null); do vgchange -an "$vg" 2>/dev/null || true; done
|
|
for h in $(lsblk -lno NAME "$part" 2>/dev/null | tail -n +2); do
|
|
case "$(lsblk -no TYPE "/dev/$h" 2>/dev/null | head -1)" in
|
|
raid*) mdadm --stop "/dev/$h" 2>/dev/null || true ;;
|
|
crypt) cryptsetup close "$h" 2>/dev/null || true ;;
|
|
esac
|
|
done
|
|
done
|
|
# Arrays md dont le disque cible est lui-même membre (détection par colonne TYPE).
|
|
for md in $(lsblk -lnpo NAME,TYPE "$WIN_DISK" 2>/dev/null | awk '$2 ~ /raid/{print $1}'); do
|
|
mdadm --stop "$md" 2>/dev/null || true
|
|
done
|
|
# Re-vérif fail-closed : plus rien d'actif sur le disque cible.
|
|
for part in $(lsblk -lnpo NAME "$WIN_DISK" 2>/dev/null | tail -n +2); do
|
|
findmnt -S "$part" >/dev/null 2>&1 && die "$part encore monté après neutralisation"
|
|
swapon --show=NAME --noheadings 2>/dev/null | grep -qx "$part" && die "$part encore en swap"
|
|
[ -n "$(lsblk -lno NAME "$part" 2>/dev/null | tail -n +2)" ] && die "$part a encore des holders (md/dm) actifs"
|
|
done
|
|
|
|
# --- 3) Carve (mode DEDICATE) — adressage par NUMÉRO sur le disque cible [B1]
|
|
log "Carve : ESP 1Gio + MSR 16Mio + NTFS ${size_gib}Gio + swap ${SWAP_GIB}Gio"
|
|
sgdisk --zap-all "$WIN_DISK" || die "sgdisk --zap-all a échoué"
|
|
sgdisk -n1:0:+1GiB -t1:ef00 -c1:WINESP "$WIN_DISK" || die "création WINESP"
|
|
sgdisk -n2:0:+16MiB -t2:0c01 -c2:MSR "$WIN_DISK" || warn "MSR non créée (non bloquant)"
|
|
sgdisk -n3:0:+${size_gib}GiB -t3:0700 -c3:FWSWIN "$WIN_DISK" || die "création partition Windows"
|
|
sgdisk -n4:0:+${SWAP_GIB}GiB -t4:8200 -c4:FWSSWAP "$WIN_DISK" || die "création swap"
|
|
partprobe "$WIN_DISK"; udevadm settle
|
|
ESP_PART="$(part_dev "$WIN_DISK" 1)"
|
|
WIN_PART="$(part_dev "$WIN_DISK" 3)"
|
|
SWAP_PART="$(part_dev "$WIN_DISK" 4)"
|
|
for p in "$ESP_PART" "$WIN_PART" "$SWAP_PART"; do
|
|
[ -b "$p" ] || die "partition $p absente après carve"
|
|
pk="/dev/$(lsblk -no PKNAME "$p" 2>/dev/null | head -1)"
|
|
[ "$(canon "$pk")" = "$WIN_C" ] || die "$p n'est PAS sur $WIN_DISK — abort"
|
|
done
|
|
mkfs.fat -F32 -n WINESP "$ESP_PART" || die "mkfs.fat WINESP"
|
|
mkswap -L FWSSWAP "$SWAP_PART" || die "mkswap FWSSWAP"
|
|
mkntfs -Q -f -L FWSWIN "$WIN_PART" || mkntfs -f -L FWSWIN "$WIN_PART" || die "mkntfs FWSWIN"
|
|
|
|
# --- 4) Appliquer install.wim (wimlib) sur la NTFS --------------------------
|
|
ISO_MNT="$(mktemp -d)"; WIN_MNT="$(mktemp -d)"; ESP_MNT="$(mktemp -d)"
|
|
cleanup(){ for m in "$WIN_MNT" "$ESP_MNT" "$ISO_MNT"; do umount "$m" 2>/dev/null || true; done; }
|
|
trap cleanup EXIT
|
|
mount -o loop,ro "$iso" "$ISO_MNT" || die "montage ISO échoué"
|
|
IMG="$ISO_MNT/sources/install.wim"; [ -f "$IMG" ] || IMG="$ISO_MNT/sources/install.esd"
|
|
[ -f "$IMG" ] || die "install.wim/.esd introuvable dans l'ISO"
|
|
# Édition par NOM (insensible à la casse) ; repli image unique [m4].
|
|
WANT="${edition:-Windows 11 Pro}"
|
|
IDX="$(wimlib-imagex info "$IMG" 2>/dev/null | awk -v w="$(printf '%s' "$WANT" | tr 'A-Z' 'a-z')" -F': *' '
|
|
tolower($1) ~ /^index/{i=$2} index(tolower($0), w){print i; exit}')"
|
|
if [ -z "$IDX" ]; then
|
|
CNT="$(wimlib-imagex info "$IMG" 2>/dev/null | awk -F': *' 'tolower($1) ~ /image count/{print $2; exit}')"
|
|
[ "${CNT:-0}" = 1 ] && IDX=1
|
|
fi
|
|
[ -n "$IDX" ] || die "édition « $WANT » absente de l'ISO (wimlib-imagex info) — ISO Home/N/tiny ?"
|
|
log "Application de l'image (index $IDX = $WANT) sur $WIN_PART — long…"
|
|
wimlib-imagex apply "$IMG" "$IDX" "$WIN_PART" || die "wimlib-imagex apply a échoué"
|
|
|
|
# --- 5) Bootabilité : BCD (hivex → repli WinPE-bcdboot) ---------------------
|
|
mount "$WIN_PART" "$WIN_MNT" || die "montage NTFS échoué"
|
|
mount "$ESP_PART" "$ESP_MNT" || die "montage WINESP échoué"
|
|
mkdir -p "$ESP_MNT/EFI/Microsoft/Boot"
|
|
cp -rn "$WIN_MNT/Windows/Boot/EFI/." "$ESP_MNT/EFI/Microsoft/Boot/" 2>/dev/null || true
|
|
WIN_PARTUUID="$(blkid -s PARTUUID -o value "$WIN_PART" 2>/dev/null)"
|
|
DISK_GUID="$(sgdisk -p "$WIN_DISK" 2>/dev/null | sed -n 's/^Disk identifier (GUID): *//p')"
|
|
# Pilote Intel VMD à injecter ? (case cochée dans le spoke + .inf présents).
|
|
DRV=""
|
|
if [ "${intel_vmd:-0}" = 1 ]; then
|
|
if ls /usr/local/share/fws/drivers/intel-vmd/*.inf >/dev/null 2>&1; then
|
|
DRV=/usr/local/share/fws/drivers/intel-vmd
|
|
log "Intel VMD demandé + pilote présent → injection via WinPE (dism)."
|
|
else
|
|
warn "Intel VMD demandé mais AUCUN pilote dans .../drivers/intel-vmd/ — Windows tentera son pilote VMD inbox (25H2). Dépose le pilote Intel si le boot échoue."
|
|
fi
|
|
fi
|
|
# Avec un pilote VMD à injecter, on FORCE la voie WinPE (dism y tourne). Sinon
|
|
# hivex (qui bascule de toute façon sur WinPE tant que non validé).
|
|
if [ -z "$DRV" ] && /usr/local/lib/fws/fws-bcd-write "$ESP_MNT" "$WIN_MNT" "$WIN_PARTUUID" "$DISK_GUID"; then
|
|
log "BCD écrit (voie hivex)."
|
|
BCDFIX=0
|
|
else
|
|
[ -n "$DRV" ] && log "Bascule WinPE (bcdboot + injection pilote VMD)." \
|
|
|| warn "Voie hivex non validée → repli WinPE-bcdboot (1 reboot auto)."
|
|
umount "$WIN_MNT" 2>/dev/null || true
|
|
/usr/local/bin/fws-windows-bcdfix "$ISO_MNT" "$ESP_MNT" "$WIN_DISK" 1 "$DRV" \
|
|
|| die "repli WinPE-bcdfix a échoué — Windows non bootable (FWS reste seul bootable)"
|
|
BCDFIX=1
|
|
mount "$WIN_PART" "$WIN_MNT" 2>/dev/null || die "remontage NTFS échoué"
|
|
fi
|
|
|
|
# --- 6) Anti-BitLocker HORS LIGNE (crucial : évite le lockout) --------------
|
|
HIVE="$WIN_MNT/Windows/System32/config/SYSTEM"
|
|
if command -v hivexget >/dev/null 2>&1 && [ -f "$HIVE" ]; then
|
|
SEL="$(hivexget "$HIVE" Select Current 2>/dev/null | tr -cd '0-9')"; [ -n "$SEL" ] || SEL=1
|
|
printf '[HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet%03d\\Control\\BitLocker]\n"PreventDeviceEncryption"=dword:00000001\n' "$SEL" \
|
|
| hivexregedit --merge --prefix 'HKEY_LOCAL_MACHINE\SYSTEM' "$HIVE" \
|
|
&& log "Anti-BitLocker offline posé (ControlSet$(printf '%03d' "$SEL"))." \
|
|
|| warn "écriture anti-BitLocker offline échouée (ceinture reg add en specialize)."
|
|
else
|
|
warn "hivex/SYSTEM absent → anti-BitLocker via la ceinture specialize seule."
|
|
fi
|
|
|
|
# --- 7) Answer file offline + injection du composant gameboot ---------------
|
|
TMPL=/usr/local/share/fws/gameboot-windows/unattend.offline.xml.tmpl
|
|
HN="$(tr -cd 'a-zA-Z0-9-' < /tmp/fws-hostname 2>/dev/null)"; [ -n "$HN" ] || HN=fws-win
|
|
LOC="$(. "$SYSROOT/etc/locale.conf" 2>/dev/null; printf '%s' "${LANG%%.*}")"; [ -n "$LOC" ] || LOC=fr-CH
|
|
LOC="${LOC/_/-}"
|
|
FIRSTBOOT='C:\ProgramData\FWS\deploy\FirstBoot-FwsGameboot.ps1'
|
|
mkdir -p "$WIN_MNT/Windows/Panther" "$WIN_MNT/ProgramData/FWS/deploy"
|
|
sed -e "s|__HOSTNAME__|$HN|g" -e "s|__USER__|gaming|g" -e "s|__DISPLAY__|Gaming|g" \
|
|
-e "s|__LOCALE__|$LOC|g" -e "s|__INPUT__|$LOC|g" -e "s|__FIRSTBOOT__|${FIRSTBOOT//\\/\\\\}|g" \
|
|
"$TMPL" > "$WIN_MNT/Windows/Panther/unattend.xml" || die "rendu unattend.xml échoué"
|
|
cp -rf /usr/local/share/fws/gameboot-windows/. "$WIN_MNT/ProgramData/FWS/deploy/" || die "injection gameboot échouée"
|
|
rm -f "$WIN_MNT/ProgramData/FWS/deploy/unattend.offline.xml.tmpl" 2>/dev/null || true
|
|
log "unattend.xml + composant gameboot injectés sur la NTFS."
|
|
|
|
# --- 8) Vérification AVANT toute écriture NVRAM -----------------------------
|
|
[ -f "$WIN_MNT/Windows/System32/ntoskrnl.exe" ] || die "ntoskrnl.exe absent → apply incomplet"
|
|
[ -f "$WIN_MNT/Windows/System32/winload.efi" ] || die "winload.efi absent"
|
|
[ -f "$ESP_MNT/EFI/Microsoft/Boot/bootmgfw.efi" ] || die "bootmgfw.efi absent de l'ESP"
|
|
[ "$BCDFIX" = 1 ] || [ -s "$ESP_MNT/EFI/Microsoft/Boot/BCD" ] || die "BCD absent/vide (voie hivex)"
|
|
sync
|
|
|
|
# --- 9) Entrées de boot : FWS TOUJOURS en tête [M5][M6] ---------------------
|
|
# Voie hivex directe : on crée l'entrée Windows persistante (en queue).
|
|
if [ "$BCDFIX" = 0 ]; then
|
|
efibootmgr -c -d "$WIN_DISK" -p 1 -L 'Windows Boot Manager' -l '\EFI\Microsoft\Boot\bootmgfw.efi' >/dev/null 2>&1 || warn "création entrée UEFI Windows échouée"
|
|
WBN="$(efibootmgr 2>/dev/null | sed -n 's/^Boot\([0-9A-Fa-f]\{4\}\)\*\? *Windows Boot Manager.*/\1/p' | head -1)"
|
|
[ -n "$WBN" ] && sed -i "s/^FWS_WINDOWS_BOOTNUM=.*/FWS_WINDOWS_BOOTNUM=\"$WBN\"/" \
|
|
"$SYSROOT/etc/fws/gameboot.conf" 2>/dev/null || true
|
|
fi
|
|
# Dans TOUS les cas : FWS en BootOrder[0] (Windows/WinPE jamais 1er). Si aucune
|
|
# entrée NVRAM FWS (booté via \EFI\BOOT\BOOTX64.EFI removable), en créer une.
|
|
FBN="$(efibootmgr 2>/dev/null | sed -n 's/^Boot\([0-9A-Fa-f]\{4\}\)\*\? *\(FWS\|GRUB\).*/\1/p' | head -1)"
|
|
if [ -z "$FBN" ]; then
|
|
esp_src="$(findmnt -no SOURCE "$SYSROOT/boot/efi" 2>/dev/null)"
|
|
if [ -b "$esp_src" ]; then
|
|
sdisk="/dev/$(lsblk -no PKNAME "$esp_src" 2>/dev/null | head -1)"
|
|
spn="$(lsblk -no PARTN "$esp_src" 2>/dev/null | head -1)"
|
|
efibootmgr -c -d "$sdisk" -p "${spn:-1}" -L 'FWS' -l '\EFI\BOOT\BOOTX64.EFI' >/dev/null 2>&1 || true
|
|
FBN="$(efibootmgr 2>/dev/null | sed -n 's/^Boot\([0-9A-Fa-f]\{4\}\)\*\? *FWS.*/\1/p' | head -1)"
|
|
fi
|
|
fi
|
|
order="$(efibootmgr 2>/dev/null | sed -n 's/^BootOrder: //p' | tr -d '[:space:]')"
|
|
if [ -n "$FBN" ] && [ -n "$order" ]; then
|
|
rest="$(printf '%s' "$order" | tr ',' '\n' | grep -vx "$FBN" | paste -sd, -)"
|
|
efibootmgr -o "${FBN}${rest:+,$rest}" >/dev/null 2>&1 || true # FWS 1er, reste (Windows/WinPE) derrière
|
|
fi
|
|
|
|
# --- 10) Hibernation FWS (chroot cible) : swap dédié → resume= --------------
|
|
SWAP_UUID="$(blkid -s UUID -o value "$SWAP_PART" 2>/dev/null)"
|
|
if [ -n "$SWAP_UUID" ] && command -v arch-chroot >/dev/null 2>&1; then
|
|
log "Config hibernation FWS (resume=UUID=$SWAP_UUID)…"
|
|
cat > "$SYSROOT/etc/fws-gameboot-swap.sh" <<CHROOT
|
|
set -u
|
|
grep -q "UUID=$SWAP_UUID" /etc/fstab 2>/dev/null || printf 'UUID=%s none swap defaults 0 0\n' "$SWAP_UUID" >> /etc/fstab
|
|
grep -qE '^HOOKS=.*\bresume\b' /etc/mkinitcpio.conf || sed -i -E 's/^(HOOKS=\(.*)\bfilesystems\b/\1resume filesystems/' /etc/mkinitcpio.conf
|
|
mkinitcpio -P || true
|
|
if grep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub; then
|
|
grep -q 'resume=UUID=$SWAP_UUID' /etc/default/grub || sed -i 's|^GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"|GRUB_CMDLINE_LINUX_DEFAULT="\1 resume=UUID=$SWAP_UUID hibernate.compressor=lz4"|' /etc/default/grub
|
|
fi
|
|
grep -q '^GRUB_DISABLE_OS_PROBER=' /etc/default/grub || echo 'GRUB_DISABLE_OS_PROBER=true' >> /etc/default/grub
|
|
grub-mkconfig -o /boot/grub/grub.cfg || true
|
|
install -Dm644 /dev/stdin /etc/modprobe.d/nvidia-hibernate.conf <<'NV'
|
|
options nvidia NVreg_PreserveVideoMemoryAllocations=1 NVreg_TemporaryFilePath=/var/tmp
|
|
NV
|
|
systemctl enable nvidia-suspend.service nvidia-hibernate.service nvidia-resume.service 2>/dev/null || true
|
|
systemctl enable fws-gameboot-bootfix.service 2>/dev/null || true
|
|
CHROOT
|
|
arch-chroot "$SYSROOT" bash /etc/fws-gameboot-swap.sh 2>&1 | tee -a /tmp/fws-windows-deploy.log || warn "config hibernation chroot partielle"
|
|
rm -f "$SYSROOT/etc/fws-gameboot-swap.sh"
|
|
else
|
|
warn "swap UUID introuvable ou arch-chroot absent → hibernation non configurée (reboot simple restera dispo)."
|
|
fi
|
|
|
|
sync
|
|
status "DEPLOY_OK: Windows sur $WIN_DISK (${size_gib}Gio) — SB à activer au firmware"
|
|
log "Déploiement Windows terminé.$([ "$BCDFIX" = 1 ] && echo ' (BCD via WinPE au 1er reboot)')"
|
|
log "⚠ Reste manuel : activer Secure Boot au firmware (sbctl verify déjà clean)."
|
|
exit 0
|