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
33 changes: 25 additions & 8 deletions archinstall/lib/disk/device_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,24 @@ def _determine_fs_type(
lsblk_info: LsblkInfo | None = None,
) -> FilesystemType | None:
try:
if lsblk_info is not None:
if crypt_child := lsblk_info.find_child_by_type('crypt'):
if crypt_child.fstype:
try:
return FilesystemType(crypt_child.fstype)
except ValueError:
pass
if lsblk_info.fstype == FilesystemType.CRYPTO_LUKS:
return FilesystemType.CRYPTO_LUKS

if partition.fileSystem:
if partition.fileSystem.type == FilesystemType.LINUX_SWAP.parted_value:
return FilesystemType.LINUX_SWAP
return FilesystemType(partition.fileSystem.type)
if lsblk_info is not None:
return FilesystemType(lsblk_info.fstype) if lsblk_info.fstype else None

if lsblk_info is not None and lsblk_info.fstype:
return FilesystemType(lsblk_info.fstype)

return None
except ValueError:
debug(f'Could not determine the filesystem: {partition.fileSystem}')
Expand Down Expand Up @@ -191,16 +203,21 @@ def get_btrfs_info(

subvol_infos: list[_BtrfsSubvolumeInfo] = []

if not lsblk_info.mountpoint:
mount(dev_path, self._TMP_BTRFS_MOUNT, create_target_mountpoint=True)
target_lsblk = lsblk_info
if crypt_child := lsblk_info.find_child_by_type('crypt'):
if crypt_child.fstype == FilesystemType.BTRFS:
target_lsblk = crypt_child

if not target_lsblk.mountpoint and not target_lsblk.mountpoints:
mount(target_lsblk.path, self._TMP_BTRFS_MOUNT, create_target_mountpoint=True)
mountpoint = self._TMP_BTRFS_MOUNT
else:
# when multiple subvolumes are mounted then the lsblk output may look like
# "mountpoint": "/mnt/archinstall/var/log"
# "mountpoints": ["/mnt/archinstall/var/log", "/mnt/archinstall/home", ..]
# so we'll determine the minimum common path and assume that's the root
try:
common_path = os.path.commonpath(lsblk_info.mountpoints)
common_path = os.path.commonpath(target_lsblk.mountpoints)
except ValueError:
return subvol_infos

Expand All @@ -217,7 +234,7 @@ def get_btrfs_info(
# "fsroots": ["/@log", "/@home", "/@"...]
# we'll thereby map the fsroot, which are the mounted filesystem roots
# to the corresponding mountpoints
btrfs_subvol_info = dict(zip(lsblk_info.fsroots, lsblk_info.mountpoints, strict=True))
btrfs_subvol_info = dict(zip(target_lsblk.fsroots, target_lsblk.mountpoints, strict=True))

# ID 256 gen 16 top level 5 path @
for line in result.splitlines():
Expand All @@ -227,8 +244,8 @@ def get_btrfs_info(
sub_vol_mountpoint = btrfs_subvol_info.get('/' / name, None)
subvol_infos.append(_BtrfsSubvolumeInfo(name, sub_vol_mountpoint))

if not lsblk_info.mountpoint:
umount(dev_path)
if not target_lsblk.mountpoint and not target_lsblk.mountpoints:
umount(self._TMP_BTRFS_MOUNT)

return subvol_infos

Expand Down
15 changes: 8 additions & 7 deletions archinstall/lib/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ def minimal_installation(

self._prepare_fs_type(part.fs_type)

if part in self._disk_encryption.partitions:
if part in self._disk_encryption.partitions or part.is_encrypted:
self._prepare_encrypt()

if ucode := self._get_microcode():
Expand Down Expand Up @@ -1105,26 +1105,27 @@ def _get_kernel_params_partition(
) -> list[str]:
kernel_parameters = []

if root_partition in self._disk_encryption.partitions:
if root_partition in self._disk_encryption.partitions or root_partition.is_encrypted:
# TODO: We need to detect if the encrypted device is a whole disk encryption,
# or simply a partition encryption. Right now we assume it's a partition (and we always have)
mapper_name = root_partition.mapper_name or 'root'

if self._disk_encryption.hsm_device:
debug(f'Root partition is an encrypted device, identifying by UUID: {root_partition.uuid}')
# Note: UUID must be used, not PARTUUID for sd-encrypt to work
kernel_parameters.append(f'rd.luks.name={root_partition.uuid}=root')
kernel_parameters.append(f'rd.luks.name={root_partition.uuid}={mapper_name}')
# Note: tpm2-device and fido2-device don't play along very well:
# https://github.com/archlinux/archinstall/pull/1196#issuecomment-1129715645
kernel_parameters.append('rd.luks.options=fido2-device=auto,password-echo=no')
elif partuuid:
elif partuuid and root_partition.partuuid:
debug(f'Root partition is an encrypted device, identifying by PARTUUID: {root_partition.partuuid}')
kernel_parameters.append(f'cryptdevice=PARTUUID={root_partition.partuuid}:root')
kernel_parameters.append(f'cryptdevice=PARTUUID={root_partition.partuuid}:{mapper_name}')
else:
debug(f'Root partition is an encrypted device, identifying by UUID: {root_partition.uuid}')
kernel_parameters.append(f'cryptdevice=UUID={root_partition.uuid}:root')
kernel_parameters.append(f'cryptdevice=UUID={root_partition.uuid}:{mapper_name}')

if id_root:
kernel_parameters.append('root=/dev/mapper/root')
kernel_parameters.append(f'root=/dev/mapper/{mapper_name}')
elif id_root:
if partuuid:
debug(f'Identifying root partition by PARTUUID: {root_partition.partuuid}')
Expand Down
39 changes: 38 additions & 1 deletion archinstall/lib/models/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ class _PartitionInfo:
disk: Disk
mountpoints: list[Path]
btrfs_subvol_infos: list[_BtrfsSubvolumeInfo] = field(default_factory=list)
is_encrypted: bool = False
mapper_name: str | None = None

@property
def sector_size(self) -> SectorSize:
Expand Down Expand Up @@ -604,6 +606,12 @@ def from_partition(
if btrfs_subvol_infos is None:
btrfs_subvol_infos = []

crypt_child = lsblk_info.find_child_by_type('crypt')
is_encrypted = (lsblk_info.fstype == FilesystemType.CRYPTO_LUKS) or (crypt_child is not None)
mapper_name = crypt_child.name if crypt_child else None

mountpoints = lsblk_info.all_mountpoints if not lsblk_info.mountpoints else lsblk_info.mountpoints

return cls(
partition=partition,
name=partition.name,
Expand All @@ -617,8 +625,10 @@ def from_partition(
partuuid=lsblk_info.partuuid,
uuid=lsblk_info.uuid,
disk=partition.disk,
mountpoints=lsblk_info.mountpoints,
mountpoints=mountpoints,
btrfs_subvol_infos=btrfs_subvol_infos,
is_encrypted=is_encrypted,
mapper_name=mapper_name,
)


Expand Down Expand Up @@ -914,6 +924,8 @@ class PartitionModification(SubConfig):
partn: int | None = None
partuuid: str | None = None
uuid: str | None = None
is_encrypted: bool = False
_mapper_name: str | None = None

_obj_id: UUID | str = field(init=False)

Expand Down Expand Up @@ -982,6 +994,8 @@ def from_existing_partition(cls, partition_info: _PartitionInfo) -> Self:
flags=partition_info.flags,
mountpoint=mountpoint,
btrfs_subvols=subvol_mods,
is_encrypted=partition_info.is_encrypted,
_mapper_name=partition_info.mapper_name,
)

@property
Expand Down Expand Up @@ -1040,6 +1054,8 @@ def is_create_or_modify(self) -> bool:

@property
def mapper_name(self) -> str | None:
if self._mapper_name:
return self._mapper_name
if self.is_root():
return 'root'
if self.is_home():
Expand All @@ -1048,6 +1064,10 @@ def mapper_name(self) -> str | None:
return f'{ENC_IDENTIFIER}{self.dev_path.name}'
return None

@mapper_name.setter
def mapper_name(self, value: str | None) -> None:
self._mapper_name = value

def set_flag(self, flag: PartitionFlag) -> None:
if flag not in self.flags:
self.flags.append(flag)
Expand Down Expand Up @@ -1807,6 +1827,23 @@ def remove_none(cls, value: Any) -> Any:
def serialize_size(self, size: Size) -> str:
return size.format_size(Unit.MiB)

@property
def all_mountpoints(self) -> list[Path]:
mountpoints = list(self.mountpoints)
for child in self.children:
for mp in child.all_mountpoints:
if mp not in mountpoints:
mountpoints.append(mp)
return mountpoints

def find_child_by_type(self, device_type: str) -> LsblkInfo | None:
for child in self.children:
if child.type == device_type:
return child
if found := child.find_child_by_type(device_type):
return found
return None

@classmethod
def fields(cls) -> list[str]:
return [field.alias or name for name, field in cls.model_fields.items() if name != 'children']
Loading