Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/disk/partition.py
diff options
context:
space:
mode:
Diffstat (limited to 'archinstall/lib/disk/partition.py')
-rw-r--r--archinstall/lib/disk/partition.py167
1 files changed, 118 insertions, 49 deletions
diff --git a/archinstall/lib/disk/partition.py b/archinstall/lib/disk/partition.py
index e7568258..73c88597 100644
--- a/archinstall/lib/disk/partition.py
+++ b/archinstall/lib/disk/partition.py
@@ -13,7 +13,8 @@ from ..storage import storage
from ..exceptions import DiskError, SysCallError, UnknownFilesystemFormat
from ..output import log
from ..general import SysCommand
-from .btrfs import get_subvolumes_from_findmnt, BtrfsSubvolume
+from .btrfs.btrfs_helpers import subvolume_info_from_path
+from .btrfs.btrfssubvolume import BtrfsSubvolume
class Partition:
def __init__(self,
@@ -96,11 +97,11 @@ class Partition:
try:
data = json.loads(SysCommand(f"findmnt --json -R {self.path}").decode())
for filesystem in data['filesystems']:
- return filesystem.get('target')
+ return pathlib.Path(filesystem.get('target'))
except SysCallError as error:
# Not mounted anywhere most likely
- log(f"Could not locate mount information for {self.path}: {error}", level=logging.DEBUG)
+ log(f"Could not locate mount information for {self.path}: {error}", level=logging.DEBUG, fg="grey")
pass
return None
@@ -184,7 +185,7 @@ class Partition:
return device['pttype']
@property
- def uuid(self) -> Optional[str]:
+ def part_uuid(self) -> Optional[str]:
"""
Returns the PARTUUID as returned by lsblk.
This is more reliable than relying on /dev/disk/by-partuuid as
@@ -197,6 +198,26 @@ class Partition:
time.sleep(max(0.1, storage['DISK_TIMEOUTS'] * i))
+ partuuid = self._safe_part_uuid
+ if partuuid:
+ return partuuid
+
+ raise DiskError(f"Could not get PARTUUID for {self.path} using 'blkid -s PARTUUID -o value {self.path}'")
+
+ @property
+ def uuid(self) -> Optional[str]:
+ """
+ Returns the UUID as returned by lsblk for the **partition**.
+ This is more reliable than relying on /dev/disk/by-uuid as
+ it doesn't seam to be able to detect md raid partitions.
+ For bind mounts all the subvolumes share the same uuid
+ """
+ for i in range(storage['DISK_RETRY_ATTEMPTS']):
+ if not self.partprobe():
+ raise DiskError(f"Could not perform partprobe on {self.device_path}")
+
+ time.sleep(storage.get('DISK_TIMEOUTS', 1) * i)
+
partuuid = self._safe_uuid
if partuuid:
return partuuid
@@ -217,6 +238,28 @@ class Partition:
log(f"Could not reliably refresh PARTUUID of partition {self.device_path} due to partprobe error.", level=logging.DEBUG)
try:
+ return SysCommand(f'blkid -s UUID -o value {self.device_path}').decode('UTF-8').strip()
+ except SysCallError as error:
+ if self.block_device.info.get('TYPE') == 'iso9660':
+ # Parent device is a Optical Disk (.iso dd'ed onto a device for instance)
+ return None
+
+ log(f"Could not get PARTUUID of partition using 'blkid -s UUID -o value {self.device_path}': {error}")
+
+ @property
+ def _safe_part_uuid(self) -> Optional[str]:
+ """
+ A near copy of self.uuid but without any delays.
+ This function should only be used where uuid is not crucial.
+ For instance when you want to get a __repr__ of the class.
+ """
+ if not self.partprobe():
+ if self.block_device.info.get('TYPE') == 'iso9660':
+ return None
+
+ log(f"Could not reliably refresh PARTUUID of partition {self.device_path} due to partprobe error.", level=logging.DEBUG)
+
+ try:
return SysCommand(f'blkid -s PARTUUID -o value {self.device_path}').decode('UTF-8').strip()
except SysCallError as error:
if self.block_device.info.get('TYPE') == 'iso9660':
@@ -262,9 +305,26 @@ class Partition:
@property
def subvolumes(self) -> Iterator[BtrfsSubvolume]:
+ from .helpers import findmnt
+
+ def iterate_children_recursively(information):
+ for child in information.get('children', []):
+ if target := child.get('target'):
+ if subvolume := subvolume_info_from_path(pathlib.Path(target)):
+ yield subvolume
+
+ if child.get('children'):
+ for subchild in iterate_children_recursively(child):
+ yield subchild
+
for mountpoint in self.mount_information:
- for result in get_subvolumes_from_findmnt(mountpoint):
- yield result
+ if result := findmnt(pathlib.Path(mountpoint['target'])):
+ for filesystem in result.get('filesystems', []):
+ if subvolume := subvolume_info_from_path(pathlib.Path(mountpoint['target'])):
+ yield subvolume
+
+ for child in iterate_children_recursively(filesystem):
+ yield child
def partprobe(self) -> bool:
try:
@@ -315,7 +375,7 @@ class Partition:
handle = luks2(self, None, None)
return handle.encrypt(self, *args, **kwargs)
- def format(self, filesystem :Optional[str] = None, path :Optional[str] = None, log_formatting :bool = True, options :List[str] = []) -> bool:
+ def format(self, filesystem :Optional[str] = None, path :Optional[str] = None, log_formatting :bool = True, options :List[str] = [], retry :bool = True) -> bool:
"""
Format can be given an overriding path, for instance /dev/null to test
the formatting functionality and in essence the support for the given filesystem.
@@ -337,63 +397,71 @@ class Partition:
if log_formatting:
log(f'Formatting {path} -> {filesystem}', level=logging.INFO)
- if filesystem == 'btrfs':
- options = ['-f'] + options
+ try:
+ if filesystem == 'btrfs':
+ options = ['-f'] + options
- if 'UUID:' not in (mkfs := SysCommand(f"/usr/bin/mkfs.btrfs {' '.join(options)} {path}").decode('UTF-8')):
- raise DiskError(f'Could not format {path} with {filesystem} because: {mkfs}')
- self.filesystem = filesystem
+ if 'UUID:' not in (mkfs := SysCommand(f"/usr/bin/mkfs.btrfs {' '.join(options)} {path}").decode('UTF-8')):
+ raise DiskError(f'Could not format {path} with {filesystem} because: {mkfs}')
+ self.filesystem = filesystem
- elif filesystem == 'vfat':
- options = ['-F32'] + options
+ elif filesystem == 'vfat':
+ options = ['-F32'] + options
- if (handle := SysCommand(f"/usr/bin/mkfs.vfat {' '.join(options)} {path}")).exit_code != 0:
- raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
- self.filesystem = filesystem
+ if (handle := SysCommand(f"/usr/bin/mkfs.vfat {' '.join(options)} {path}")).exit_code != 0:
+ raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
+ self.filesystem = filesystem
- elif filesystem == 'ext4':
- options = ['-F'] + options
+ elif filesystem == 'ext4':
+ options = ['-F'] + options
- if (handle := SysCommand(f"/usr/bin/mkfs.ext4 {' '.join(options)} {path}")).exit_code != 0:
- raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
- self.filesystem = filesystem
+ if (handle := SysCommand(f"/usr/bin/mkfs.ext4 {' '.join(options)} {path}")).exit_code != 0:
+ raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
+ self.filesystem = filesystem
- elif filesystem == 'ext2':
- options = ['-F'] + options
+ elif filesystem == 'ext2':
+ options = ['-F'] + options
- if (handle := SysCommand(f"/usr/bin/mkfs.ext2 {' '.join(options)} {path}")).exit_code != 0:
- raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}')
- self.filesystem = 'ext2'
+ if (handle := SysCommand(f"/usr/bin/mkfs.ext2 {' '.join(options)} {path}")).exit_code != 0:
+ raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}')
+ self.filesystem = 'ext2'
- elif filesystem == 'xfs':
- options = ['-f'] + options
+ elif filesystem == 'xfs':
+ options = ['-f'] + options
- if (handle := SysCommand(f"/usr/bin/mkfs.xfs {' '.join(options)} {path}")).exit_code != 0:
- raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
- self.filesystem = filesystem
+ if (handle := SysCommand(f"/usr/bin/mkfs.xfs {' '.join(options)} {path}")).exit_code != 0:
+ raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
+ self.filesystem = filesystem
- elif filesystem == 'f2fs':
- options = ['-f'] + options
+ elif filesystem == 'f2fs':
+ options = ['-f'] + options
- if (handle := SysCommand(f"/usr/bin/mkfs.f2fs {' '.join(options)} {path}")).exit_code != 0:
- raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
- self.filesystem = filesystem
+ if (handle := SysCommand(f"/usr/bin/mkfs.f2fs {' '.join(options)} {path}")).exit_code != 0:
+ raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
+ self.filesystem = filesystem
- elif filesystem == 'ntfs3':
- options = ['-f'] + options
+ elif filesystem == 'ntfs3':
+ options = ['-f'] + options
- if (handle := SysCommand(f"/usr/bin/mkfs.ntfs -Q {' '.join(options)} {path}")).exit_code != 0:
- raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
- self.filesystem = filesystem
+ if (handle := SysCommand(f"/usr/bin/mkfs.ntfs -Q {' '.join(options)} {path}")).exit_code != 0:
+ raise DiskError(f"Could not format {path} with {filesystem} because: {handle.decode('UTF-8')}")
+ self.filesystem = filesystem
- elif filesystem == 'crypto_LUKS':
- # from ..luks import luks2
- # encrypted_partition = luks2(self, None, None)
- # encrypted_partition.format(path)
- self.filesystem = filesystem
+ elif filesystem == 'crypto_LUKS':
+ # from ..luks import luks2
+ # encrypted_partition = luks2(self, None, None)
+ # encrypted_partition.format(path)
+ self.filesystem = filesystem
- else:
- raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.")
+ else:
+ raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.")
+ except SysCallError as error:
+ log(f"Formatting ran in to an error: {error}", level=logging.WARNING, fg="orange")
+ if retry is True:
+ log(f"Retrying in {storage.get('DISK_TIMEOUTS', 1)} seconds.", level=logging.WARNING, fg="orange")
+ time.sleep(storage.get('DISK_TIMEOUTS', 1))
+
+ return self.format(filesystem, path, log_formatting, options, retry=False)
if get_filesystem_type(path) == 'crypto_LUKS' or get_filesystem_type(self.real_device) == 'crypto_LUKS':
self.encrypted = True
@@ -413,6 +481,7 @@ class Partition:
def mount(self, target :str, fs :Optional[str] = None, options :str = '') -> bool:
if not self.mountpoint:
log(f'Mounting {self} to {target}', level=logging.INFO)
+
if not fs:
if not self.filesystem:
raise DiskError(f'Need to format (or define) the filesystem on {self} before mounting.')