Repository: archlinux/archinstall

Issue:
EFI system partition can't be mounted at /efi
If I create a partition setup as follows:

partition 1: esp fat32 mounted at /efi
partition 2: btrfs with three subvs:
arch_boot mounted at /boot
arch_root mounted at /
arch_home mounted at /home

Then select grub as boot loader; the installation starts, but fails spectacularly when it's installing grub. If I change the esp mount point to /boot, the installation succeeds.

https://wiki.archlinux.org/title/EFI_system_partition

4.1 Typical mount points

- mount the ESP to /boot

- mount the ESP to /efi


Discussion:
[This line in installer.py](https://github.com/archlinux/archinstall/blob/master/archinstall/lib/installer.py#L908) is the culprit.

On efi systems with a different ESP mountpoint (other than `/boot`), it will attempt to use the `boot_partition` mountpoint (`/efi`) as the prefix directory.

Resolving patch:
diff --git a/archinstall/lib/disk/device_model.py b/archinstall/lib/disk/device_model.py
--- a/archinstall/lib/disk/device_model.py
+++ b/archinstall/lib/disk/device_model.py
@@ -800,20 +800,25 @@ def add_partition(self, partition: PartitionModification):
 	def get_efi_partition(self) -> Optional[PartitionModification]:
 		"""
 		Similar to get_boot_partition() but excludes XBOOTLDR partitions from it's candidates.
+		Also works with ESP flag.
 		"""
-		filtered = filter(lambda x: x.is_boot() and x.fs_type == FilesystemType.Fat32 and PartitionFlag.XBOOTLDR not in x.flags, self.partitions)
+		filtered = filter(lambda x: (x.is_boot() or PartitionFlag.ESP in x.flags) and x.fs_type == FilesystemType.Fat32 and PartitionFlag.XBOOTLDR not in x.flags, self.partitions)
 		return next(filtered, None)
 
 	def get_boot_partition(self) -> Optional[PartitionModification]:
 		"""
 		Returns the first partition marked as XBOOTLDR (PARTTYPE id of bc13c2ff-...) or Boot and has a mountpoint.
 		Only returns XBOOTLDR if separate EFI is detected using self.get_efi_partition()
+		Will return None if no suitable partition is found.
 		"""
 		if efi_partition := self.get_efi_partition():
 			filtered = filter(lambda x: x.is_boot() and x != efi_partition and x.mountpoint, self.partitions)
 			if boot_partition := next(filtered, None):
 				return boot_partition
-			return efi_partition
+			if efi_partition.is_boot():
+				return efi_partition
+			else:
+				return None
 		else:
 			filtered = filter(lambda x: x.is_boot() and x.mountpoint, self.partitions)
 			return next(filtered, None)
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py
--- a/archinstall/lib/installer.py
+++ b/archinstall/lib/installer.py
@@ -874,7 +874,8 @@ def _add_systemd_bootloader(
 	def _add_grub_bootloader(
 		self,
 		boot_partition: disk.PartitionModification,
-		root_partition: disk.PartitionModification
+		root_partition: disk.PartitionModification,
+		efi_partition: Optional[disk.PartitionModification]
 	):
 		self.pacman.strap('grub')  # no need?
 
@@ -895,12 +896,15 @@ def _add_grub_bootloader(
 			'--debug'
 		]
 
-		if SysInfo.has_uefi():
+		if SysInfo.has_uefi() and efi_partition is not None:
+			info(f"GRUB EFI partition: {efi_partition.dev_path}")
+
 			self.pacman.strap('efibootmgr') # TODO: Do we need? Yes, but remove from minimal_installation() instead?
 
 			add_options = [
 				'--target=x86_64-efi',
-				f'--efi-directory={boot_partition.mountpoint}',
+				f'--efi-directory={efi_partition.mountpoint}'
+				f'--boot-directory={boot_partition.mountpoint if boot_partition else "/boot"}'
 				'--bootloader-id=GRUB',
 				'--removable'
 			]
@@ -913,8 +917,10 @@ def _add_grub_bootloader(
 				try:
 					SysCommand(command, peek_output=True)
 				except SysCallError as err:
-					raise DiskError(f"Could not install GRUB to {self.target}{boot_partition.mountpoint}: {err}")
+					raise DiskError(f"Could not install GRUB to {self.target}{efi_partition.mountpoint}: {err}")
 		else:
+			info(f"GRUB boot partition: {boot_partition.dev_path}")
+
 			parent_dev_path = disk.device_handler.get_parent_device_path(boot_partition.safe_dev_path)
 
 			add_options = [
@@ -931,7 +937,7 @@ def _add_grub_bootloader(
 		try:
 			SysCommand(
 				f'/usr/bin/arch-chroot {self.target} '
-				f'grub-mkconfig -o {boot_partition.mountpoint}/grub/grub.cfg'
+				f'grub-mkconfig -o {boot_partition.mountpoint if boot_partition else "/boot"}/grub/grub.cfg'
 			)
 		except SysCallError as err:
 			raise DiskError(f"Could not configure GRUB: {err}")
@@ -1131,7 +1137,7 @@ def add_bootloader(self, bootloader: Bootloader):
 			case Bootloader.Systemd:
 				self._add_systemd_bootloader(boot_partition, root_partition, efi_partition)
 			case Bootloader.Grub:
-				self._add_grub_bootloader(boot_partition, root_partition)
+				self._add_grub_bootloader(boot_partition, root_partition, efi_partition)
 			case Bootloader.Efistub:
 				self._add_efistub_bootloader(boot_partition, root_partition)
 			case Bootloader.Limine:


Test patch: