Skip to content

Commit cb6fe6b

Browse files
justbispoDiogo Bispo
andauthored
Add support for rEFInd boot manager (#3707)
* Add support for rEFInd boot manager * Fix ruff formatting complaints * 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. * Fix ruff formatting complaints * Replace SysCommand with self.arch_chroot call * Fix ruff formatting complaints --------- Co-authored-by: Diogo Bispo <gpg.jta36@slmail.me>
1 parent 446d23c commit cb6fe6b

File tree

3 files changed

+110
-2
lines changed

3 files changed

+110
-2
lines changed

archinstall/lib/global_menu.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,10 @@ def _validate_bootloader(self) -> str | None:
466466
if boot_partition.fs_type not in [FilesystemType.Fat12, FilesystemType.Fat16, FilesystemType.Fat32]:
467467
return 'Limine does not support booting with a non-FAT boot partition'
468468

469+
elif bootloader == Bootloader.Refind:
470+
if not SysInfo.has_uefi():
471+
return 'rEFInd can only be used on UEFI systems'
472+
469473
return None
470474

471475
def _prev_install_invalid_config(self, item: MenuItem) -> str | None:

archinstall/lib/installer.py

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,106 @@ def _add_efistub_bootloader(
16041604

16051605
self._helper_flags['bootloader'] = 'efistub'
16061606

1607+
def _add_refind_bootloader(
1608+
self,
1609+
boot_partition: PartitionModification,
1610+
efi_partition: PartitionModification | None,
1611+
root: PartitionModification | LvmVolume,
1612+
uki_enabled: bool = False,
1613+
) -> None:
1614+
debug('Installing rEFInd bootloader')
1615+
1616+
self.pacman.strap('refind')
1617+
1618+
if not SysInfo.has_uefi():
1619+
raise HardwareIncompatibilityError
1620+
1621+
info(f'rEFInd boot partition: {boot_partition.dev_path}')
1622+
1623+
if not efi_partition:
1624+
raise ValueError('Could not detect EFI system partition')
1625+
elif not efi_partition.mountpoint:
1626+
raise ValueError('EFI system partition is not mounted')
1627+
1628+
info(f'rEFInd EFI partition: {efi_partition.dev_path}')
1629+
1630+
try:
1631+
self.arch_chroot('refind-install')
1632+
except SysCallError as err:
1633+
raise DiskError(f'Could not install rEFInd to {self.target}{efi_partition.mountpoint}: {err}')
1634+
1635+
if not boot_partition.mountpoint:
1636+
raise ValueError('Boot partition is not mounted, cannot write rEFInd config')
1637+
1638+
boot_is_separate = boot_partition != efi_partition and boot_partition.dev_path != efi_partition.dev_path
1639+
1640+
if boot_is_separate:
1641+
# Separate boot partition (not ESP, not root)
1642+
config_path = self.target / boot_partition.mountpoint.relative_to('/') / 'refind_linux.conf'
1643+
boot_on_root = False
1644+
elif efi_partition.mountpoint == Path('/boot'):
1645+
# ESP is mounted at /boot, kernels are on ESP
1646+
config_path = self.target / 'boot' / 'refind_linux.conf'
1647+
boot_on_root = False
1648+
else:
1649+
# ESP is elsewhere (/efi, /boot/efi, etc.), kernels are on root filesystem at /boot
1650+
config_path = self.target / 'boot' / 'refind_linux.conf'
1651+
boot_on_root = True
1652+
1653+
config_contents = []
1654+
1655+
kernel_params = ' '.join(self._get_kernel_params(root))
1656+
1657+
for kernel in self.kernels:
1658+
for variant in ('', '-fallback'):
1659+
if uki_enabled:
1660+
entry = f'"Arch Linux ({kernel}{variant}) UKI" "{kernel_params}"'
1661+
else:
1662+
if boot_on_root:
1663+
# Kernels are in /boot subdirectory of root filesystem
1664+
if hasattr(root, 'btrfs_subvols') and root.btrfs_subvols:
1665+
# Root is btrfs with subvolume, find the root subvolume
1666+
root_subvol = next((sv for sv in root.btrfs_subvols if sv.is_root()), None)
1667+
if root_subvol:
1668+
subvol_name = root_subvol.name
1669+
initrd_path = f'initrd={subvol_name}\\boot\\initramfs-{kernel}{variant}.img'
1670+
else:
1671+
initrd_path = f'initrd=\\boot\\initramfs-{kernel}{variant}.img'
1672+
else:
1673+
# Root without btrfs subvolume
1674+
initrd_path = f'initrd=\\boot\\initramfs-{kernel}{variant}.img'
1675+
else:
1676+
# Kernels are at root of their partition (ESP or separate boot partition)
1677+
initrd_path = f'initrd=\\initramfs-{kernel}{variant}.img'
1678+
entry = f'"Arch Linux ({kernel}{variant})" "{kernel_params} {initrd_path}"'
1679+
1680+
config_contents.append(entry)
1681+
1682+
config_path.write_text('\n'.join(config_contents) + '\n')
1683+
1684+
hook_contents = textwrap.dedent(
1685+
"""\
1686+
[Trigger]
1687+
Operation = Install
1688+
Operation = Upgrade
1689+
Type = Package
1690+
Target = refind
1691+
1692+
[Action]
1693+
Description = Updating rEFInd on ESP
1694+
When = PostTransaction
1695+
Exec = /usr/bin/refind-install
1696+
"""
1697+
)
1698+
1699+
hooks_dir = self.target / 'etc' / 'pacman.d' / 'hooks'
1700+
hooks_dir.mkdir(parents=True, exist_ok=True)
1701+
1702+
hook_path = hooks_dir / '99-refind.hook'
1703+
hook_path.write_text(hook_contents)
1704+
1705+
self._helper_flags['bootloader'] = 'refind'
1706+
16071707
def _config_uki(
16081708
self,
16091709
root: PartitionModification | LvmVolume,
@@ -1657,11 +1757,12 @@ def _config_uki(
16571757
def add_bootloader(self, bootloader: Bootloader, uki_enabled: bool = False, bootloader_removable: bool = False) -> None:
16581758
"""
16591759
Adds a bootloader to the installation instance.
1660-
Archinstall supports one of three types:
1760+
Archinstall supports one of five types:
16611761
* systemd-bootctl
16621762
* grub
16631763
* limine
16641764
* efistub (beta)
1765+
* refnd (beta)
16651766
16661767
:param bootloader: Type of bootloader to be added
16671768
:param uki_enabled: Whether to use unified kernel images
@@ -1713,6 +1814,8 @@ def add_bootloader(self, bootloader: Bootloader, uki_enabled: bool = False, boot
17131814
self._add_efistub_bootloader(boot_partition, root, uki_enabled)
17141815
case Bootloader.Limine:
17151816
self._add_limine_bootloader(boot_partition, efi_partition, root, uki_enabled, bootloader_removable)
1817+
case Bootloader.Refind:
1818+
self._add_refind_bootloader(boot_partition, efi_partition, root, uki_enabled)
17161819

17171820
def add_additional_packages(self, packages: str | list[str]) -> None:
17181821
return self.pacman.strap(packages)

archinstall/lib/models/bootloader.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ class Bootloader(Enum):
1717
Grub = 'Grub'
1818
Efistub = 'Efistub'
1919
Limine = 'Limine'
20+
Refind = 'Refind'
2021

2122
def has_uki_support(self) -> bool:
2223
match self:
23-
case Bootloader.Efistub | Bootloader.Limine | Bootloader.Systemd:
24+
case Bootloader.Efistub | Bootloader.Limine | Bootloader.Systemd | Bootloader.Refind:
2425
return True
2526
case _:
2627
return False

0 commit comments

Comments
 (0)