Extend validate_bootloader_layout with UEFI-dependent checks (#4474)

* Extend validate_bootloader_layout with UEFI-dependent checks

Add is_uefi parameter and three new validations: Systemd-boot, Efistub
and rEFInd require UEFI; Efistub additionally requires a FAT boot
partition. Move the rEFInd UEFI-only check out of GlobalMenu so
guided.py and Installer silent-install paths get the same coverage.

* Encapsulate UEFI-only flag in Bootloader enum

Replace module-level _UEFI_ONLY_BOOTLOADERS tuple with an
is_uefi_only() method on the Bootloader enum, mirroring the
existing has_uki_support() / has_removable_support() pattern.

* Drop is_uefi parameter from validate_bootloader_layout

The UEFI flag is a constant system fact for the run, so the
validator retrieves it via SysInfo.has_uefi() directly instead
of having every caller pass it in. Updates all three call sites
in global_menu.py, installer.py and guided.py, and removes the
now-unused SysInfo import from guided.py.
This commit is contained in:
Softer 2026-04-26 12:14:23 +03:00 committed by GitHub
parent 3c4c87bdd6
commit d836ab0a66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 34 additions and 9 deletions

View File

@ -2,6 +2,7 @@ from dataclasses import dataclass
from enum import Enum, auto from enum import Enum, auto
from pathlib import Path from pathlib import Path
from archinstall.lib.hardware import SysInfo
from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration from archinstall.lib.models.bootloader import Bootloader, BootloaderConfiguration
from archinstall.lib.models.device import DiskLayoutConfiguration from archinstall.lib.models.device import DiskLayoutConfiguration
@ -9,6 +10,8 @@ from archinstall.lib.models.device import DiskLayoutConfiguration
class BootloaderValidationFailureKind(Enum): class BootloaderValidationFailureKind(Enum):
LimineNonFatBoot = auto() LimineNonFatBoot = auto()
LimineLayout = auto() LimineLayout = auto()
BootloaderRequiresUefi = auto()
EfistubNonFatBoot = auto()
@dataclass(frozen=True) @dataclass(frozen=True)
@ -29,12 +32,32 @@ def validate_bootloader_layout(
if not (bootloader_config and disk_config): if not (bootloader_config and disk_config):
return None return None
if bootloader_config.bootloader == Bootloader.Limine: bootloader = bootloader_config.bootloader
boot_part = next(
(p for m in disk_config.device_modifications if (p := m.get_boot_partition())), if bootloader == Bootloader.NO_BOOTLOADER:
None, return None
if bootloader.is_uefi_only() and not SysInfo.has_uefi():
return BootloaderValidationFailure(
kind=BootloaderValidationFailureKind.BootloaderRequiresUefi,
description=f'{bootloader.value} requires a UEFI system.',
) )
boot_part = next(
(p for m in disk_config.device_modifications if (p := m.get_boot_partition())),
None,
)
if bootloader == Bootloader.Efistub:
# The UEFI firmware reads the kernel directly from the boot partition,
# which must be FAT.
if boot_part and (boot_part.fs_type is None or not boot_part.fs_type.is_fat()):
return BootloaderValidationFailure(
kind=BootloaderValidationFailureKind.EfistubNonFatBoot,
description='Efistub does not support booting with a non-FAT boot partition.',
)
if bootloader == Bootloader.Limine:
# Limine reads its config and kernels from the boot partition, which # Limine reads its config and kernels from the boot partition, which
# must be FAT. # must be FAT.
if boot_part and (boot_part.fs_type is None or not boot_part.fs_type.is_fat()): if boot_part and (boot_part.fs_type is None or not boot_part.fs_type.is_fat()):

View File

@ -461,8 +461,6 @@ class GlobalMenu(AbstractMenu[None]):
if not bootloader_config or bootloader_config.bootloader == Bootloader.NO_BOOTLOADER: if not bootloader_config or bootloader_config.bootloader == Bootloader.NO_BOOTLOADER:
return None return None
bootloader = bootloader_config.bootloader
if disk_config := self._item_group.find_by_key('disk_config').value: if disk_config := self._item_group.find_by_key('disk_config').value:
for layout in disk_config.device_modifications: for layout in disk_config.device_modifications:
if root_partition := layout.get_root_partition(): if root_partition := layout.get_root_partition():
@ -490,9 +488,6 @@ class GlobalMenu(AbstractMenu[None]):
if efi_partition.fs_type is None or not efi_partition.fs_type.is_fat(): if efi_partition.fs_type is None or not efi_partition.fs_type.is_fat():
return 'ESP must be formatted as a FAT filesystem' return 'ESP must be formatted as a FAT filesystem'
if bootloader == Bootloader.Refind and not self._uefi:
return 'rEFInd can only be used on UEFI systems'
if failure := validate_bootloader_layout(bootloader_config, disk_config): if failure := validate_bootloader_layout(bootloader_config, disk_config):
return failure.description return failure.description

View File

@ -25,6 +25,13 @@ class Bootloader(Enum):
case _: case _:
return False return False
def is_uefi_only(self) -> bool:
match self:
case Bootloader.Systemd | Bootloader.Efistub | Bootloader.Refind:
return True
case _:
return False
def json(self) -> str: def json(self) -> str:
return self.value return self.value