From 0f5b91c7d733e94ffcad2fd8dd01774631b0c15a Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 30 Aug 2022 22:59:23 +0200 Subject: Fixing issue where blkid causes SysCallException (#1445) * Moving a partprobe() call to better allow for cache updates * Trying to improve Partition()._fetch_information() * Removed a sleep() for debugging purposes * Tweaked a sleep --- archinstall/lib/disk/filesystem.py | 6 ++++-- archinstall/lib/disk/helpers.py | 5 +++++ archinstall/lib/disk/partition.py | 18 ++++++++++++++++-- archinstall/lib/exceptions.py | 8 ++++++-- archinstall/lib/general.py | 2 +- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/archinstall/lib/disk/filesystem.py b/archinstall/lib/disk/filesystem.py index 90656308..5d5952a0 100644 --- a/archinstall/lib/disk/filesystem.py +++ b/archinstall/lib/disk/filesystem.py @@ -253,7 +253,6 @@ class Filesystem: if self.parted(parted_string): for count in range(storage.get('DISK_RETRY_ATTEMPTS', 3)): - self.partprobe() self.blockdevice.flush_cache() new_partition_uuids = [partition.part_uuid for partition in self.blockdevice.partitions.values()] @@ -271,7 +270,10 @@ class Filesystem: raise err else: log(f"Could not get UUID for partition. Waiting {storage.get('DISK_TIMEOUTS', 1) * count}s before retrying.",level=logging.DEBUG) - time.sleep(storage.get('DISK_TIMEOUTS', 1) * count) + self.partprobe() + time.sleep(max(0.1, storage.get('DISK_TIMEOUTS', 1))) + else: + print("Parted did not return True during partition creation") total_partitions = set([partition.part_uuid for partition in self.blockdevice.partitions.values()]) total_partitions.update(previous_partuuids) diff --git a/archinstall/lib/disk/helpers.py b/archinstall/lib/disk/helpers.py index 60efe724..a148a5db 100644 --- a/archinstall/lib/disk/helpers.py +++ b/archinstall/lib/disk/helpers.py @@ -229,12 +229,17 @@ def all_blockdevices(mappers=False, partitions=False, error=False) -> Dict[str, try: information = get_loop_info(device_path) if not information: + print("Exit code for blkid -p -o export was:", ex.exit_code) raise SysCallError("Could not get loop information", exit_code=1) except SysCallError: + print("Not a loop device, trying uevent rules.") information = get_blockdevice_uevent(pathlib.Path(block_device).readlink().name) else: + # We could not reliably get any information, perhaps the disk is clean of information? + print("Raising ex because:", ex.exit_code) raise ex + # return instances information = enrich_blockdevice_information(information) diff --git a/archinstall/lib/disk/partition.py b/archinstall/lib/disk/partition.py index f70bf907..56a7d436 100644 --- a/archinstall/lib/disk/partition.py +++ b/archinstall/lib/disk/partition.py @@ -139,7 +139,19 @@ class Partition: def _call_lsblk(self) -> Dict[str, Any]: self.partprobe() - output = SysCommand(f"lsblk --json -b -o+LOG-SEC,SIZE,PTTYPE,PARTUUID,UUID,FSTYPE {self.device_path}").decode('UTF-8') + # This sleep might be overkill, but lsblk is known to + # work against a chaotic cache that can change during call + # causing no information to be returned (blkid is better) + # time.sleep(1) + + # TODO: Maybe incorporate a re-try system here based on time.sleep(max(0.1, storage.get('DISK_TIMEOUTS', 1))) + + try: + output = SysCommand(f"lsblk --json -b -o+LOG-SEC,SIZE,PTTYPE,PARTUUID,UUID,FSTYPE {self.device_path}").decode('UTF-8') + except SysCallError as error: + # It appears as if lsblk can return exit codes like 8192 to indicate something. + # But it does return output so we'll try to catch it. + output = error.worker.decode('UTF-8') if output: lsblk_info = json.loads(output) @@ -165,7 +177,9 @@ class Partition: def _fetch_information(self) -> PartitionInfo: lsblk_info = self._call_lsblk() sfdisk_info = self._call_sfdisk() - device = lsblk_info['blockdevices'][0] + + if not (device := lsblk_info.get('blockdevices', [None])[0]): + raise DiskError(f'Failed to retrieve information for "{self.device_path}" with lsblk') mountpoints = [Path(mountpoint) for mountpoint in device['mountpoints'] if mountpoint] bootable = sfdisk_info.get('bootable', False) or sfdisk_info.get('type', '') == 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py index a16faa3f..a66e4e04 100644 --- a/archinstall/lib/exceptions.py +++ b/archinstall/lib/exceptions.py @@ -1,4 +1,7 @@ -from typing import Optional +from typing import Optional, TYPE_CHECKING + +if TYPE_CHECKING: + from .general import SysCommandWorker class RequirementError(BaseException): pass @@ -17,10 +20,11 @@ class ProfileError(BaseException): class SysCallError(BaseException): - def __init__(self, message :str, exit_code :Optional[int] = None) -> None: + def __init__(self, message :str, exit_code :Optional[int] = None, worker :Optional['SysCommandWorker'] = None) -> None: super(SysCallError, self).__init__(message) self.message = message self.exit_code = exit_code + self.worker = worker class PermissionError(BaseException): diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index 61c4358e..d76b7036 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -272,7 +272,7 @@ class SysCommandWorker: log(args[1], level=logging.DEBUG, fg='red') if self.exit_code != 0: - raise SysCallError(f"{self.cmd} exited with abnormal exit code [{self.exit_code}]: {self._trace_log[-500:]}", self.exit_code) + raise SysCallError(f"{self.cmd} exited with abnormal exit code [{self.exit_code}]: {self._trace_log[-500:]}", self.exit_code, worker=self) def is_alive(self) -> bool: self.poll() -- cgit v1.2.3-54-g00ecf