From 4e82862787d431bd375ac86542eebfee60502fd5 Mon Sep 17 00:00:00 2001 From: justbispo <38961424+justbispo@users.noreply.github.com> Date: Mon, 4 Aug 2025 00:53:32 +0100 Subject: [PATCH 1/6] Add support for rEFInd boot manager --- archinstall/lib/global_menu.py | 4 ++ archinstall/lib/installer.py | 74 +++++++++++++++++++++++++++- archinstall/lib/models/bootloader.py | 3 +- 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/archinstall/lib/global_menu.py b/archinstall/lib/global_menu.py index 7995a27ae5..c65959f6d1 100644 --- a/archinstall/lib/global_menu.py +++ b/archinstall/lib/global_menu.py @@ -456,6 +456,10 @@ def _validate_bootloader(self) -> str | None: if boot_partition.fs_type not in [FilesystemType.Fat12, FilesystemType.Fat16, FilesystemType.Fat32]: return 'Limine does not support booting with a non-FAT boot partition' + elif bootloader == Bootloader.Refind: + if not SysInfo.has_uefi(): + return 'rEFInd can only be used on UEFI systems' + return None def _prev_install_invalid_config(self, item: MenuItem) -> str | None: diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 0c8571fa6e..2ea9622508 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1530,6 +1530,75 @@ def _add_efistub_bootloader( self._helper_flags['bootloader'] = 'efistub' + def _add_refind_bootloader( + self, + boot_partition: PartitionModification, + efi_partition: PartitionModification | None, + root: PartitionModification | LvmVolume, + uki_enabled: bool = False, + ) -> None: + debug('Installing rEFInd bootloader') + + self.pacman.strap('refind') + + if not SysInfo.has_uefi(): + raise HardwareIncompatibilityError + + if not efi_partition: + raise ValueError('Could not detect EFI system partition') + elif not efi_partition.mountpoint: + raise ValueError('EFI system partition is not mounted') + + info(f'rEFInd EFI partition: {efi_partition.dev_path}') + + try: + SysCommand(f'arch-chroot {self.target} refind-install') + except SysCallError as err: + raise DiskError(f'Could not install rEFInd to {self.target}{efi_partition.mountpoint}: {err}') + + if not boot_partition.mountpoint: + raise ValueError("Boot partition is not mounted, cannot write rEFInd config") + + config_path = self.target / boot_partition.mountpoint.relative_to('/') / 'refind_linux.conf' + config_contents = [] + + kernel_params = ' '.join(self._get_kernel_params(root)) + + for kernel in self.kernels: + for variant in ('', '-fallback'): + if uki_enabled: + entry = f'"Arch Linux ({kernel}{variant}) UKI" "{kernel_params}"' + else: + initrd_path = f'initrd=\\initramfs-{kernel}{variant}.img' + entry = f'"Arch Linux ({kernel}{variant})" "{kernel_params} {initrd_path}"' + + config_contents.append(entry) + + config_path.write_text('\n'.join(config_contents) + '\n') + + hook_contents = textwrap.dedent( + '''\ + [Trigger] + Operation = Install + Operation = Upgrade + Type = Package + Target = refind + + [Action] + Description = Updating rEFInd on ESP + When = PostTransaction + Exec = /usr/bin/refind-install + ''' + ) + + hooks_dir = self.target / 'etc' / 'pacman.d' / 'hooks' + hooks_dir.mkdir(parents=True, exist_ok=True) + + hook_path = hooks_dir / '99-refind.hook' + hook_path.write_text(hook_contents) + + self._helper_flags['bootloader'] = 'refind' + def _config_uki( self, root: PartitionModification | LvmVolume, @@ -1583,11 +1652,12 @@ def _config_uki( def add_bootloader(self, bootloader: Bootloader, uki_enabled: bool = False) -> None: """ Adds a bootloader to the installation instance. - Archinstall supports one of three types: + Archinstall supports one of five types: * systemd-bootctl * grub * limine (beta) * efistub (beta) + * refnd (beta) :param bootloader: Type of bootloader to be added """ @@ -1623,6 +1693,8 @@ def add_bootloader(self, bootloader: Bootloader, uki_enabled: bool = False) -> N self._add_efistub_bootloader(boot_partition, root, uki_enabled) case Bootloader.Limine: self._add_limine_bootloader(boot_partition, efi_partition, root, uki_enabled) + case Bootloader.Refind: + self._add_refind_bootloader(boot_partition, efi_partition, root, uki_enabled) def add_additional_packages(self, packages: str | list[str]) -> None: return self.pacman.strap(packages) diff --git a/archinstall/lib/models/bootloader.py b/archinstall/lib/models/bootloader.py index 1eb3562cad..a6cb4353d5 100644 --- a/archinstall/lib/models/bootloader.py +++ b/archinstall/lib/models/bootloader.py @@ -13,10 +13,11 @@ class Bootloader(Enum): Grub = 'Grub' Efistub = 'Efistub' Limine = 'Limine' + Refind = 'rEFInd' def has_uki_support(self) -> bool: match self: - case Bootloader.Efistub | Bootloader.Limine | Bootloader.Systemd: + case Bootloader.Efistub | Bootloader.Limine | Bootloader.Systemd | Bootloader.Refind: return True case _: return False From fcbacdbf7dba8fd1f192af8fd8e05dfe89c3fe1e Mon Sep 17 00:00:00 2001 From: justbispo <38961424+justbispo@users.noreply.github.com> Date: Mon, 4 Aug 2025 11:34:27 +0100 Subject: [PATCH 2/6] Fix ruff formatting complaints --- archinstall/lib/installer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 2ea9622508..49049264dc 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1557,7 +1557,7 @@ def _add_refind_bootloader( raise DiskError(f'Could not install rEFInd to {self.target}{efi_partition.mountpoint}: {err}') if not boot_partition.mountpoint: - raise ValueError("Boot partition is not mounted, cannot write rEFInd config") + raise ValueError('Boot partition is not mounted, cannot write rEFInd config') config_path = self.target / boot_partition.mountpoint.relative_to('/') / 'refind_linux.conf' config_contents = [] @@ -1577,7 +1577,7 @@ def _add_refind_bootloader( config_path.write_text('\n'.join(config_contents) + '\n') hook_contents = textwrap.dedent( - '''\ + """\ [Trigger] Operation = Install Operation = Upgrade @@ -1588,7 +1588,7 @@ def _add_refind_bootloader( Description = Updating rEFInd on ESP When = PostTransaction Exec = /usr/bin/refind-install - ''' + """ ) hooks_dir = self.target / 'etc' / 'pacman.d' / 'hooks' From 9ae94117b700115147d4ec23e862eac080747aa8 Mon Sep 17 00:00:00 2001 From: justbispo <38961424+justbispo@users.noreply.github.com> Date: Sat, 25 Oct 2025 00:28:29 +0100 Subject: [PATCH 3/6] Added support for different mountpoints for /efi and /boot Also fixed issue where if /boot is located in a BTRFS root partition, the initrd path wasn't including the subvol name. --- archinstall/lib/installer.py | 36 ++++++++++++++++++++++++++-- archinstall/lib/models/bootloader.py | 2 +- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 49049264dc..7ad6fa5882 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1544,6 +1544,8 @@ def _add_refind_bootloader( if not SysInfo.has_uefi(): raise HardwareIncompatibilityError + info(f'rEFInd boot partition: {boot_partition.dev_path}') + if not efi_partition: raise ValueError('Could not detect EFI system partition') elif not efi_partition.mountpoint: @@ -1559,7 +1561,22 @@ def _add_refind_bootloader( if not boot_partition.mountpoint: raise ValueError('Boot partition is not mounted, cannot write rEFInd config') - config_path = self.target / boot_partition.mountpoint.relative_to('/') / 'refind_linux.conf' + boot_is_separate = (boot_partition != efi_partition and + boot_partition.dev_path != efi_partition.dev_path) + + if boot_is_separate: + # Separate boot partition (not ESP, not root) + config_path = self.target / boot_partition.mountpoint.relative_to('/') / 'refind_linux.conf' + boot_on_root = False + elif efi_partition.mountpoint == Path('/boot'): + # ESP is mounted at /boot, kernels are on ESP + config_path = self.target / 'boot' / 'refind_linux.conf' + boot_on_root = False + else: + # ESP is elsewhere (/efi, /boot/efi, etc.), kernels are on root filesystem at /boot + config_path = self.target / 'boot' / 'refind_linux.conf' + boot_on_root = True + config_contents = [] kernel_params = ' '.join(self._get_kernel_params(root)) @@ -1569,7 +1586,22 @@ def _add_refind_bootloader( if uki_enabled: entry = f'"Arch Linux ({kernel}{variant}) UKI" "{kernel_params}"' else: - initrd_path = f'initrd=\\initramfs-{kernel}{variant}.img' + if boot_on_root: + # Kernels are in /boot subdirectory of root filesystem + if hasattr(root, 'btrfs_subvols') and root.btrfs_subvols: + # Root is btrfs with subvolume, find the root subvolume + root_subvol = next((sv for sv in root.btrfs_subvols if sv.is_root()), None) + if root_subvol: + subvol_name = root_subvol.name + initrd_path = f'initrd={subvol_name}\\boot\\initramfs-{kernel}{variant}.img' + else: + initrd_path = f'initrd=\\boot\\initramfs-{kernel}{variant}.img' + else: + # Root without btrfs subvolume + initrd_path = f'initrd=\\boot\\initramfs-{kernel}{variant}.img' + else: + # Kernels are at root of their partition (ESP or separate boot partition) + initrd_path = f'initrd=\\initramfs-{kernel}{variant}.img' entry = f'"Arch Linux ({kernel}{variant})" "{kernel_params} {initrd_path}"' config_contents.append(entry) diff --git a/archinstall/lib/models/bootloader.py b/archinstall/lib/models/bootloader.py index a6cb4353d5..f48d08f4b3 100644 --- a/archinstall/lib/models/bootloader.py +++ b/archinstall/lib/models/bootloader.py @@ -13,7 +13,7 @@ class Bootloader(Enum): Grub = 'Grub' Efistub = 'Efistub' Limine = 'Limine' - Refind = 'rEFInd' + Refind = 'Refind' def has_uki_support(self) -> bool: match self: From 3cdb158cf5cb03e1ecc9d01f533ff49deff67030 Mon Sep 17 00:00:00 2001 From: justbispo <38961424+justbispo@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:02:34 +0000 Subject: [PATCH 4/6] Fix ruff formatting complaints --- archinstall/lib/installer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 8f58278c27..15e490de91 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1582,8 +1582,7 @@ def _add_refind_bootloader( if not boot_partition.mountpoint: raise ValueError('Boot partition is not mounted, cannot write rEFInd config') - boot_is_separate = (boot_partition != efi_partition and - boot_partition.dev_path != efi_partition.dev_path) + boot_is_separate = boot_partition != efi_partition and boot_partition.dev_path != efi_partition.dev_path if boot_is_separate: # Separate boot partition (not ESP, not root) From 3c49d69d3a18c63af01daa21eb2759e60bcda545 Mon Sep 17 00:00:00 2001 From: justbispo <38961424+justbispo@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:16:35 +0000 Subject: [PATCH 5/6] Replace SysCommand with self.arch_chroot call --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 568201d7f2..5050a9e474 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1577,7 +1577,7 @@ def _add_refind_bootloader( info(f'rEFInd EFI partition: {efi_partition.dev_path}') try: - SysCommand(f'arch-chroot {self.target} refind-install') + self.arch_chroot(f'refind-install') except SysCallError as err: raise DiskError(f'Could not install rEFInd to {self.target}{efi_partition.mountpoint}: {err}') From f9650abd6ee8d807c1f37b8e6ddc6d9b6df6f472 Mon Sep 17 00:00:00 2001 From: Diogo Bispo Date: Wed, 26 Nov 2025 19:43:21 +0000 Subject: [PATCH 6/6] Fix ruff formatting complaints --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 98972c3fec..895568d836 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1589,7 +1589,7 @@ def _add_refind_bootloader( info(f'rEFInd EFI partition: {efi_partition.dev_path}') try: - self.arch_chroot(f'refind-install') + self.arch_chroot('refind-install') except SysCallError as err: raise DiskError(f'Could not install rEFInd to {self.target}{efi_partition.mountpoint}: {err}')