Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions archinstall/lib/bootloader/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
class BootloaderValidationFailureKind(Enum):
LimineNonFatBoot = auto()
LimineLayout = auto()
BootloaderRequiresUefi = auto()
EfistubNonFatBoot = auto()


@dataclass(frozen=True)
Expand All @@ -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.

Expand All @@ -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()):
Expand Down
7 changes: 1 addition & 6 deletions archinstall/lib/global_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,6 @@ def _validate_bootloader(self) -> str | 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():
Expand Down Expand Up @@ -490,10 +488,7 @@ def _validate_bootloader(self) -> str | 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
Expand Down
1 change: 1 addition & 0 deletions archinstall/lib/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1472,6 +1472,7 @@ def _add_limine_bootloader(
if failure := validate_bootloader_layout(
BootloaderConfiguration(bootloader=Bootloader.Limine, uki=uki_enabled),
self._disk_config,
SysInfo.has_uefi(),
):
raise DiskError(failure.description)

Expand Down
2 changes: 2 additions & 0 deletions archinstall/scripts/guided.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
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
Expand Down Expand Up @@ -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
Expand Down