From 6d5d9a1798e97b5e2d1db3339197ca2a767a6715 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 10 May 2021 14:32:39 +0200 Subject: Added Partition() properties: sector_size, start, end, boot, partition_type and a __dump__() function. As well as kept working on the partition logic of guided to have a more traditional workflow of adding/deleting partitions in a guided manner, as well as the ability to mark partitions as encrypted/boot and set target mountpoints. --- archinstall/lib/disk.py | 96 +++++++++++++++++++++++++++++++++++-- archinstall/lib/user_interaction.py | 34 ++++++++++--- 2 files changed, 121 insertions(+), 9 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 1865c4fb..dd704261 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -27,6 +27,7 @@ class BlockDevice(): self.info = info self.keep_partitions = True self.part_cache = OrderedDict() + # TODO: Currently disk encryption is a BIT misleading. # It's actually partition-encryption, but for future-proofing this # I'm placing the encryption password on a BlockDevice level. @@ -43,6 +44,9 @@ class BlockDevice(): raise KeyError(f'{self} does not contain information: "{key}"') return self.info[key] + def __len__(self): + return len(self.partitions) + def json(self): """ json() has precedence over __dump__, so this is a way @@ -56,11 +60,21 @@ class BlockDevice(): def __dump__(self): return { - 'path': self.path, - 'info': self.info, - 'partition_cache': self.part_cache + self.path : { + 'partuuid' : self.uuid, + 'wipe' : self.info.get('wipe', None), + 'partitions' : [part.__dump__() for part in self.partitions.values()] + } } + @property + def partition_type(self): + output = b"".join(sys_command(f"lsblk --json -o+PTTYPE {self.path}")) + output = json.loads(output.decode('UTF-8')) + + for device in output['blockdevices']: + return device['pttype'] + @property def device(self): """ @@ -203,6 +217,82 @@ class Partition(): else: return f'Partition(path={self.path}, size={self.size}, fs={self.filesystem}{mount_repr})' + def __dump__(self): + return { + 'type' : 'primary', + 'PARTUUID' : self.uuid, + 'wipe' : self.allow_formatting, + 'boot' : self.boot, + 'ESP' : self.boot, + 'mountpoint' : self.target_mountpoint, + 'encrypted' : self._encrypted, + 'start' : self.start, + 'size' : self.end, + 'filesystem' : { + 'format' : get_filesystem_type(self.path) + } + } + + @property + def sector_size(self): + output = b"".join(sys_command(f"lsblk --json -o+LOG-SEC {self.path}")) + output = json.loads(output.decode('UTF-8')) + + for device in output['blockdevices']: + return device.get('log-sec', None) + + @property + def start(self): + output = b"".join(sys_command(f"sfdisk --json {self.block_device.path}")) + output = json.loads(output.decode('UTF-8')) + + for partition in output.get('partitionstable', {}).get('partitions', []): + if partition['node'] == self.path: + return partition['start']# * self.sector_size + + @property + def end(self): + # TODO: Verify that the logic holds up, that 'size' is the size without 'start' added to it. + output = b"".join(sys_command(f"sfdisk --json {self.block_device.path}")) + output = json.loads(output.decode('UTF-8')) + + for partition in output.get('partitionstable', {}).get('partitions', []): + if partition['node'] == self.path: + return partition['size']# * self.sector_size + + @property + def boot(self): + output = b"".join(sys_command(f"sfdisk --json {self.block_device.path}")) + output = json.loads(output.decode('UTF-8')) + + # Get the bootable flag from the sfdisk output: + # { + # "partitiontable": { + # "label":"dos", + # "id":"0xd202c10a", + # "device":"/dev/loop0", + # "unit":"sectors", + # "sectorsize":512, + # "partitions": [ + # {"node":"/dev/loop0p1", "start":2048, "size":10483712, "type":"83", "bootable":true} + # ] + # } + # } + + for partition in output.get('partitionstable', {}).get('partitions', []): + if partition['node'] == self.path: + return partition.get('bootable', False) + + return False + + @property + def partition_type(self): + output = b"".join(sys_command(f"lsblk --json -o+PTTYPE {self.path}")) + output = json.loads(output.decode('UTF-8')) + + for device in output['blockdevices']: + return device['pttype'] + @property def uuid(self) -> str: """ diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 57ea5349..050825cb 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -542,7 +542,7 @@ def wipe_and_create_partitions(block_device): else: partition_type = 'msdos' - partitions_result = [] + partitions_result = [block_device.__dump__()] while True: modes = [ @@ -581,11 +581,33 @@ def wipe_and_create_partitions(block_device): else: log(f"Invalid start, end or fstype for this partition. Ignoring this partition creation.", fg="red") continue - - elif task == "Delete partition": - elif task == "Assign mount-point for partition": - elif task == "Mark a partition as encrypted": - elif task == "Mark a partition as bootable (automatic for /boot)": + else: + for index, partition in enumerate(partitions_result): + print(partition) + print(f"{index}: {partition['start']} -> {partition['size']} ({partition['filesystem']['format']}{', mounting at: '+partition['mountpoint'] if partition['mountpoint'] else ''})") + + if task == "Delete partition": + partition = generic_select(partitions_result, 'Select which partition to delete: ', options_output=False) + del(partitions_result[partition]) + elif task == "Assign mount-point for partition": + partition = generic_select(partitions_result, 'Select which partition to mount where: ', options_output=False) + mountpoint = input('Select where to mount partition (leave blank to remove mountpoint): ').strip() + + if len(mountpoint): + partitions_result[partition]['mountpoint'] = mountpoint + if mountpoint == '/boot': + log(f"Marked partition as bootable because mountpoint was set to /boot.", fg="yellow") + partitions_result[partition]['boot'] = True + else: + del(partitions_result[partition]['mountpoint']) + + elif task == "Mark a partition as encrypted": + partition = generic_select(partitions_result, 'Select which partition to mark as encrypted: ', options_output=False) + partitions_result[partition]['encrypted'] = True + + elif task == "Mark a partition as bootable (automatic for /boot)": + partition = generic_select(partitions_result, 'Select which partition to mark as bootable: ', options_output=False) + partitions_result[partition]['boot'] = True def select_individual_blockdevice_usage(block_devices :list): result = {} -- cgit v1.2.3-70-g09d2