From da19fcdff76d5eaea0f6d3d500063448f2fa1a2a Mon Sep 17 00:00:00 2001 From: Softer Date: Fri, 24 Apr 2026 14:21:13 +0300 Subject: [PATCH] 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. --- archinstall/lib/bootloader/utils.py | 34 +++++++++++++++++++++++++---- archinstall/lib/global_menu.py | 7 +----- archinstall/lib/installer.py | 1 + archinstall/scripts/guided.py | 2 ++ 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/archinstall/lib/bootloader/utils.py b/archinstall/lib/bootloader/utils.py index a732f4e1..2d0b5a81 100644 --- a/archinstall/lib/bootloader/utils.py +++ b/archinstall/lib/bootloader/utils.py @@ -9,6 +9,8 @@ from archinstall.lib.models.device import DiskLayoutConfiguration class BootloaderValidationFailureKind(Enum): LimineNonFatBoot = auto() LimineLayout = auto() + BootloaderRequiresUefi = auto() + EfistubNonFatBoot = auto() @dataclass(frozen=True) @@ -17,9 +19,13 @@ class BootloaderValidationFailure: description: str +_UEFI_ONLY_BOOTLOADERS = (Bootloader.Systemd, Bootloader.Efistub, Bootloader.Refind) + + def validate_bootloader_layout( bootloader_config: BootloaderConfiguration | None, disk_config: DiskLayoutConfiguration | None, + is_uefi: bool, ) -> BootloaderValidationFailure | None: """Validate bootloader configuration against disk layout. @@ -29,12 +35,32 @@ def validate_bootloader_layout( if not (bootloader_config and disk_config): return None - if bootloader_config.bootloader == Bootloader.Limine: - boot_part = next( - (p for m in disk_config.device_modifications if (p := m.get_boot_partition())), - None, + bootloader = bootloader_config.bootloader + + if bootloader == Bootloader.NO_BOOTLOADER: + return None + + if bootloader in _UEFI_ONLY_BOOTLOADERS and not is_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 # must be FAT. if boot_part and (boot_part.fs_type is None or not boot_part.fs_type.is_fat()): diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py index 3d94f31e..e961b5e7 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -461,8 +461,6 @@ class GlobalMenu(AbstractMenu[None]): if not bootloader_config or bootloader_config.bootloader == Bootloader.NO_BOOTLOADER: return None - bootloader = bootloader_config.bootloader - if disk_config := self._item_group.find_by_key('disk_config').value: for layout in disk_config.device_modifications: if root_partition := layout.get_root_partition(): @@ -490,10 +488,7 @@ class GlobalMenu(AbstractMenu[None]): if efi_partition.fs_type is None or not efi_partition.fs_type.is_fat(): 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, self._uefi): return failure.description return None diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 19560d75..c65c0843 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1472,6 +1472,7 @@ class Installer: if failure := validate_bootloader_layout( BootloaderConfiguration(bootloader=Bootloader.Limine, uki=uki_enabled), self._disk_config, + SysInfo.has_uefi(), ): raise DiskError(failure.description) diff --git a/archinstall/scripts/guided.py b/archinstall/scripts/guided.py index 5cdcdad9..32198c9b 100644 --- a/archinstall/scripts/guided.py +++ b/archinstall/scripts/guided.py @@ -11,6 +11,7 @@ from archinstall.lib.disk.filesystem import FilesystemHandler from archinstall.lib.disk.utils import disk_layouts from archinstall.lib.general.general_menu import PostInstallationAction, select_post_installation from archinstall.lib.global_menu import GlobalMenu +from archinstall.lib.hardware import SysInfo from archinstall.lib.installer import Installer, accessibility_tools_in_use, run_custom_user_commands from archinstall.lib.menu.util import delayed_warning from archinstall.lib.mirror.mirror_handler import MirrorListHandler @@ -217,6 +218,7 @@ def main(arch_config_handler: ArchConfigHandler | None = None) -> None: if failure := validate_bootloader_layout( arch_config_handler.config.bootloader_config, arch_config_handler.config.disk_config, + SysInfo.has_uefi(), ): error(failure.description) return