Improve partition type detection, assignment, and misconfig handling (#3336)
This commit is contained in:
parent
e6b0ebb5f3
commit
fa581021eb
|
|
@ -95,13 +95,19 @@ class PartitioningList(ListManager):
|
||||||
'assign_mountpoint': str(_('Assign mountpoint')),
|
'assign_mountpoint': str(_('Assign mountpoint')),
|
||||||
'mark_formatting': str(_('Mark/Unmark to be formatted (wipes data)')),
|
'mark_formatting': str(_('Mark/Unmark to be formatted (wipes data)')),
|
||||||
'mark_bootable': str(_('Mark/Unmark as bootable')),
|
'mark_bootable': str(_('Mark/Unmark as bootable')),
|
||||||
'mark_xbootldr': str(_('Mark/Unmark as XBOOTLDR')),
|
}
|
||||||
|
if self._using_gpt:
|
||||||
|
self._actions.update({
|
||||||
|
'mark_esp': str(_('Mark/Unmark as ESP')),
|
||||||
|
'mark_xbootldr': str(_('Mark/Unmark as XBOOTLDR'))
|
||||||
|
})
|
||||||
|
self._actions.update({
|
||||||
'set_filesystem': str(_('Change filesystem')),
|
'set_filesystem': str(_('Change filesystem')),
|
||||||
'btrfs_mark_compressed': str(_('Mark/Unmark as compressed')), # btrfs only
|
'btrfs_mark_compressed': str(_('Mark/Unmark as compressed')), # btrfs only
|
||||||
'btrfs_mark_nodatacow': str(_('Mark/Unmark as nodatacow')), # btrfs only
|
'btrfs_mark_nodatacow': str(_('Mark/Unmark as nodatacow')), # btrfs only
|
||||||
'btrfs_set_subvolumes': str(_('Set subvolumes')), # btrfs only
|
'btrfs_set_subvolumes': str(_('Set subvolumes')), # btrfs only
|
||||||
'delete_partition': str(_('Delete partition'))
|
'delete_partition': str(_('Delete partition'))
|
||||||
}
|
})
|
||||||
|
|
||||||
device_partitions = []
|
device_partitions = []
|
||||||
|
|
||||||
|
|
@ -239,8 +245,14 @@ class PartitioningList(ListManager):
|
||||||
# how do we know it was the original one?
|
# how do we know it was the original one?
|
||||||
not_filter += [
|
not_filter += [
|
||||||
self._actions['set_filesystem'],
|
self._actions['set_filesystem'],
|
||||||
self._actions['mark_bootable'],
|
self._actions['mark_bootable']
|
||||||
self._actions['mark_xbootldr'],
|
]
|
||||||
|
if self._using_gpt:
|
||||||
|
not_filter += [
|
||||||
|
self._actions['mark_esp'],
|
||||||
|
self._actions['mark_xbootldr']
|
||||||
|
]
|
||||||
|
not_filter += [
|
||||||
self._actions['btrfs_mark_compressed'],
|
self._actions['btrfs_mark_compressed'],
|
||||||
self._actions['btrfs_mark_nodatacow'],
|
self._actions['btrfs_mark_nodatacow'],
|
||||||
self._actions['btrfs_set_subvolumes']
|
self._actions['btrfs_set_subvolumes']
|
||||||
|
|
@ -287,23 +299,46 @@ class PartitioningList(ListManager):
|
||||||
action_key = [k for k, v in self._actions.items() if v == action][0]
|
action_key = [k for k, v in self._actions.items() if v == action][0]
|
||||||
match action_key:
|
match action_key:
|
||||||
case 'assign_mountpoint':
|
case 'assign_mountpoint':
|
||||||
partition.mountpoint = self._prompt_mountpoint()
|
new_mountpoint = self._prompt_mountpoint()
|
||||||
if partition.mountpoint == Path('/boot'):
|
if not partition.is_swap():
|
||||||
partition.set_flag(PartitionFlag.BOOT)
|
if partition.is_home():
|
||||||
if self._using_gpt:
|
partition.invert_flag(PartitionFlag.LINUX_HOME)
|
||||||
partition.set_flag(PartitionFlag.ESP)
|
partition.mountpoint = new_mountpoint
|
||||||
|
if partition.is_root():
|
||||||
|
partition.flags = []
|
||||||
|
if partition.is_boot():
|
||||||
|
partition.flags = []
|
||||||
|
partition.set_flag(PartitionFlag.BOOT)
|
||||||
|
if self._using_gpt:
|
||||||
|
partition.set_flag(PartitionFlag.ESP)
|
||||||
|
if partition.is_home():
|
||||||
|
partition.flags = []
|
||||||
|
partition.set_flag(PartitionFlag.LINUX_HOME)
|
||||||
case 'mark_formatting':
|
case 'mark_formatting':
|
||||||
self._prompt_formatting(partition)
|
self._prompt_formatting(partition)
|
||||||
case 'mark_bootable':
|
case 'mark_bootable':
|
||||||
partition.invert_flag(PartitionFlag.BOOT)
|
if not partition.is_swap():
|
||||||
if self._using_gpt:
|
partition.invert_flag(PartitionFlag.BOOT)
|
||||||
|
case 'mark_esp':
|
||||||
|
if not partition.is_root() and not partition.is_home() and not partition.is_swap():
|
||||||
|
if PartitionFlag.XBOOTLDR in partition.flags:
|
||||||
|
partition.invert_flag(PartitionFlag.XBOOTLDR)
|
||||||
partition.invert_flag(PartitionFlag.ESP)
|
partition.invert_flag(PartitionFlag.ESP)
|
||||||
case 'mark_xbootldr':
|
case 'mark_xbootldr':
|
||||||
partition.invert_flag(PartitionFlag.XBOOTLDR)
|
if not partition.is_root() and not partition.is_home() and not partition.is_swap():
|
||||||
|
if PartitionFlag.ESP in partition.flags:
|
||||||
|
partition.invert_flag(PartitionFlag.ESP)
|
||||||
|
partition.invert_flag(PartitionFlag.XBOOTLDR)
|
||||||
case 'set_filesystem':
|
case 'set_filesystem':
|
||||||
fs_type = self._prompt_partition_fs_type()
|
fs_type = self._prompt_partition_fs_type()
|
||||||
if fs_type:
|
if fs_type:
|
||||||
|
if partition.is_swap():
|
||||||
|
partition.invert_flag(PartitionFlag.SWAP)
|
||||||
partition.fs_type = fs_type
|
partition.fs_type = fs_type
|
||||||
|
if partition.is_swap():
|
||||||
|
partition.mountpoint = None
|
||||||
|
partition.flags = []
|
||||||
|
partition.set_flag(PartitionFlag.SWAP)
|
||||||
# btrfs subvolumes will define mountpoints
|
# btrfs subvolumes will define mountpoints
|
||||||
if fs_type == FilesystemType.Btrfs:
|
if fs_type == FilesystemType.Btrfs:
|
||||||
partition.mountpoint = None
|
partition.mountpoint = None
|
||||||
|
|
@ -390,7 +425,6 @@ class PartitioningList(ListManager):
|
||||||
|
|
||||||
def _prompt_mountpoint(self) -> Path:
|
def _prompt_mountpoint(self) -> Path:
|
||||||
header = str(_('Partition mount-points are relative to inside the installation, the boot would be /boot as an example.')) + '\n'
|
header = str(_('Partition mount-points are relative to inside the installation, the boot would be /boot as an example.')) + '\n'
|
||||||
header += str(_('If mountpoint /boot is set, then the partition will also be marked as bootable.')) + '\n'
|
|
||||||
prompt = str(_('Mountpoint'))
|
prompt = str(_('Mountpoint'))
|
||||||
|
|
||||||
mountpoint = prompt_dir(prompt, header, validate=False, allow_skip=False)
|
mountpoint = prompt_dir(prompt, header, validate=False, allow_skip=False)
|
||||||
|
|
@ -520,6 +554,8 @@ class PartitioningList(ListManager):
|
||||||
if self._using_gpt:
|
if self._using_gpt:
|
||||||
partition.set_flag(PartitionFlag.ESP)
|
partition.set_flag(PartitionFlag.ESP)
|
||||||
elif partition.is_swap():
|
elif partition.is_swap():
|
||||||
|
partition.mountpoint = None
|
||||||
|
partition.flags = []
|
||||||
partition.set_flag(PartitionFlag.SWAP)
|
partition.set_flag(PartitionFlag.SWAP)
|
||||||
|
|
||||||
return partition
|
return partition
|
||||||
|
|
|
||||||
|
|
@ -425,21 +425,40 @@ class GlobalMenu(AbstractMenu):
|
||||||
shim if necessary.
|
shim if necessary.
|
||||||
"""
|
"""
|
||||||
bootloader = self._item_group.find_by_key('bootloader').value
|
bootloader = self._item_group.find_by_key('bootloader').value
|
||||||
|
root_partition: PartitionModification | None = None
|
||||||
boot_partition: PartitionModification | None = None
|
boot_partition: PartitionModification | None = None
|
||||||
|
efi_partition: PartitionModification | None = None
|
||||||
|
|
||||||
if disk_config := self._item_group.find_by_key('disk_config').value:
|
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():
|
||||||
|
break
|
||||||
for layout in disk_config.device_modifications:
|
for layout in disk_config.device_modifications:
|
||||||
if boot_partition := layout.get_boot_partition():
|
if boot_partition := layout.get_boot_partition():
|
||||||
break
|
break
|
||||||
|
if SysInfo.has_uefi():
|
||||||
|
for layout in disk_config.device_modifications:
|
||||||
|
if efi_partition := layout.get_efi_partition():
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
return "No disk layout selected"
|
return "No disk layout selected"
|
||||||
|
|
||||||
|
if root_partition is None:
|
||||||
|
return "Root partition not found"
|
||||||
|
|
||||||
if boot_partition is None:
|
if boot_partition is None:
|
||||||
return "Boot partition not found"
|
return "Boot partition not found"
|
||||||
|
|
||||||
|
if SysInfo.has_uefi():
|
||||||
|
if efi_partition is None:
|
||||||
|
return "EFI system partition (ESP) not found"
|
||||||
|
|
||||||
|
if efi_partition.fs_type not in [FilesystemType.Fat12, FilesystemType.Fat16, FilesystemType.Fat32]:
|
||||||
|
return "ESP must be formatted as a FAT filesystem"
|
||||||
|
|
||||||
if bootloader == Bootloader.Limine:
|
if bootloader == Bootloader.Limine:
|
||||||
if boot_partition.fs_type != FilesystemType.Fat32:
|
if boot_partition.fs_type not in [FilesystemType.Fat12, FilesystemType.Fat16, FilesystemType.Fat32]:
|
||||||
return "Limine does not support booting without a FAT boot partition"
|
return "Limine does not support booting with a non-FAT boot partition"
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -871,9 +871,6 @@ class PartitionModification:
|
||||||
partuuid: str | None = None
|
partuuid: str | None = None
|
||||||
uuid: str | None = None
|
uuid: str | None = None
|
||||||
|
|
||||||
_efi_indicator_flags = (PartitionFlag.BOOT, PartitionFlag.ESP)
|
|
||||||
_boot_indicator_flags = (PartitionFlag.BOOT, PartitionFlag.XBOOTLDR)
|
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
def __post_init__(self) -> None:
|
||||||
# needed to use the object as a dictionary key due to hash func
|
# needed to use the object as a dictionary key due to hash func
|
||||||
if not hasattr(self, '_obj_id'):
|
if not hasattr(self, '_obj_id'):
|
||||||
|
|
@ -951,26 +948,16 @@ class PartitionModification:
|
||||||
raise ValueError('Mountpoint is not specified')
|
raise ValueError('Mountpoint is not specified')
|
||||||
|
|
||||||
def is_efi(self) -> bool:
|
def is_efi(self) -> bool:
|
||||||
return (
|
return PartitionFlag.ESP in self.flags
|
||||||
any(set(self.flags) & set(self._efi_indicator_flags))
|
|
||||||
and (
|
|
||||||
self.fs_type == FilesystemType.Fat12
|
|
||||||
or self.fs_type == FilesystemType.Fat16
|
|
||||||
or self.fs_type == FilesystemType.Fat32
|
|
||||||
)
|
|
||||||
and PartitionFlag.XBOOTLDR not in self.flags
|
|
||||||
)
|
|
||||||
|
|
||||||
def is_boot(self) -> bool:
|
def is_boot(self) -> bool:
|
||||||
"""
|
if self.mountpoint is not None:
|
||||||
Returns True if any of the boot indicator flags are found in self.flags
|
return self.mountpoint == Path('/boot')
|
||||||
or if the partition is mounted on /boot
|
return False
|
||||||
"""
|
|
||||||
return any(set(self.flags) & set(self._boot_indicator_flags)) or Path('/boot') == self.mountpoint
|
|
||||||
|
|
||||||
def is_root(self) -> bool:
|
def is_root(self) -> bool:
|
||||||
if self.mountpoint is not None:
|
if self.mountpoint is not None:
|
||||||
return Path('/') == self.mountpoint
|
return self.mountpoint == Path('/')
|
||||||
else:
|
else:
|
||||||
for subvol in self.btrfs_subvols:
|
for subvol in self.btrfs_subvols:
|
||||||
if subvol.is_root():
|
if subvol.is_root():
|
||||||
|
|
@ -979,10 +966,9 @@ class PartitionModification:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def is_home(self) -> bool:
|
def is_home(self) -> bool:
|
||||||
return (
|
if self.mountpoint is not None:
|
||||||
self.mountpoint == Path('/home')
|
return self.mountpoint == Path('/home')
|
||||||
or PartitionFlag.LINUX_HOME in self.flags
|
return False
|
||||||
)
|
|
||||||
|
|
||||||
def is_swap(self) -> bool:
|
def is_swap(self) -> bool:
|
||||||
return self.fs_type == FilesystemType.LinuxSwap
|
return self.fs_type == FilesystemType.LinuxSwap
|
||||||
|
|
@ -1377,26 +1363,12 @@ class DeviceModification:
|
||||||
self.partitions.append(partition)
|
self.partitions.append(partition)
|
||||||
|
|
||||||
def get_efi_partition(self) -> PartitionModification | None:
|
def get_efi_partition(self) -> PartitionModification | None:
|
||||||
"""
|
|
||||||
Similar to get_boot_partition() but excludes XBOOTLDR partitions from it's candidates.
|
|
||||||
"""
|
|
||||||
filtered = filter(lambda x: x.is_efi() and x.mountpoint, self.partitions)
|
filtered = filter(lambda x: x.is_efi() and x.mountpoint, self.partitions)
|
||||||
return next(filtered, None)
|
return next(filtered, None)
|
||||||
|
|
||||||
def get_boot_partition(self) -> PartitionModification | None:
|
def get_boot_partition(self) -> PartitionModification | None:
|
||||||
"""
|
filtered = filter(lambda x: x.is_boot() and x.mountpoint, self.partitions)
|
||||||
Returns the first partition marked as XBOOTLDR (PARTTYPE id of bc13c2ff-...) or Boot and has a mountpoint.
|
return next(filtered, None)
|
||||||
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
|
|
||||||
else:
|
|
||||||
filtered = filter(lambda x: x.is_boot() and x.mountpoint, self.partitions)
|
|
||||||
return next(filtered, None)
|
|
||||||
|
|
||||||
def get_root_partition(self) -> PartitionModification | None:
|
def get_root_partition(self) -> PartitionModification | None:
|
||||||
filtered = filter(lambda x: x.is_root(), self.partitions)
|
filtered = filter(lambda x: x.is_root(), self.partitions)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue