From fa2270a11b833928186727812a3a3f82d18ef5ce Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 12:52:12 +0100 Subject: Created has_partitions() on BlockDevice's --- archinstall/lib/disk.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index caf5c4e1..1d78d127 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -100,6 +100,9 @@ class BlockDevice(): all_partitions = self.partitions return [all_partitions[k] for k in all_partitions] + def has_partitions(self): + return len(self.partitions) + class Partition(): def __init__(self, path, part_id=None, size=-1, filesystem=None, mountpoint=None, encrypted=False): -- cgit v1.2.3-70-g09d2 From 53cdb607bc9204b69d3f1aac42baea5ddcb94c12 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 13:36:30 +0100 Subject: Added the ability to check if a harddrive has any mountpoint related to a given parameter. --- archinstall/lib/disk.py | 6 ++++++ archinstall/lib/storage.py | 3 ++- examples/guided.py | 6 +++++- 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 1d78d127..aafb07a8 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -103,6 +103,12 @@ class BlockDevice(): def has_partitions(self): return len(self.partitions) + def has_mount_point(self, mountpoint): + for partition in self.partitions: + if self.partitions[partition].mountpoint == mountpoint: + return True + return False + class Partition(): def __init__(self, path, part_id=None, size=-1, filesystem=None, mountpoint=None, encrypted=False): diff --git a/archinstall/lib/storage.py b/archinstall/lib/storage.py index e881700f..9bda017d 100644 --- a/archinstall/lib/storage.py +++ b/archinstall/lib/storage.py @@ -17,5 +17,6 @@ storage = { 'UPSTREAM_URL' : 'https://raw.githubusercontent.com/Torxed/archinstall/master/profiles', 'PROFILE_DB' : None, # Used in cases when listing profiles is desired, not mandatory for direct profile grabing. 'LOG_PATH' : '/var/log/archinstall', - 'LOG_FILE' : 'install.log' + 'LOG_FILE' : 'install.log', + 'MOUNT_POINT' : '/mnt' } diff --git a/examples/guided.py b/examples/guided.py index a5298328..b6c6dd45 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -96,7 +96,11 @@ archinstall.storage['_guided']['harddrive'] = harddrive if harddrive.has_partitions(): archinstall.log(f" ! {harddrive} contains existing partitions", fg='red') if (option := input('Do you wish to keep existing partition setup or format the entire disk? (k/f): ')).lower() in ('k', 'keep'): - print("We're keeping it!") + # If we want to keep the existing partitioning table + # Make sure that it's the selected drive mounted under /mnt + # That way, we can rely on genfstab and some manual post-installation steps. + if harddrive.has_mount_point(archinstall.storage['MOUNT_POINT']) is False: + raise archinstall.DiskException(f"The selected drive {harddrive} is not pre-mounted to {archinstall.storage['MOUNT_POINT']}. This is required when keeping a existing partitioning scheme.") else: print('Formatting woop woop!') exit(1) -- cgit v1.2.3-70-g09d2 From 826119bb998789a8db8c2b96cfd2cd443b41bbae Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:00:34 +0100 Subject: Added partition info on Partition() creation. This will help detect potential mountpoints as well as filesystem types if any --- archinstall/lib/disk.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index aafb07a8..588054a0 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -116,11 +116,21 @@ class Partition(): part_id = os.path.basename(path) self.path = path self.part_id = part_id - self.mountpoint = mountpoint + self.mountpoint = None self.filesystem = filesystem # TODO: Autodetect if we're reusing a partition self.size = size # TODO: Refresh? self.encrypted = encrypted + if mountpoint: + self.mount(mountpoint) + + if not self.mountpoint: + # As a last step, check if we've mounted outside of the script + partition_info = get_partition_info(self.path) + self.mountpoint = partition_info['target'] + if partition_info['fstype'] != self.filesystem and filesystem: + raise DiskError(f"{self} was given a filesystem format, but a existing format was detected: {partition_info['fstype']}") + def __repr__(self, *args, **kwargs): if self.encrypted: return f'Partition(path={self.path}, real_device={self.real_device}, fs={self.filesystem}, mounted={self.mountpoint})' @@ -311,3 +321,13 @@ def harddrive(size=None, model=None, fuzzy=False): continue return collection[drive] + +def get_partition_info(path): + output = b''.join(sys_command(f'/usr/bin/findmnt --json {path}')) + output = output.decode('UTF-8') + output = json.loads(output) + if 'filesystems' in output: + if len(output['filesystems']) > 1: + raise DiskError(f"Path '{path}' contains multiple mountpoints: {output['filesystems']}") + + return output['filesystems'][0] \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 2262cd6196dd487b3dfc4524de1eea9b747db0c0 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:05:23 +0100 Subject: Made BlockDevices() iterable, iterting over each partition --- archinstall/lib/disk.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 588054a0..ffd3e044 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -22,6 +22,10 @@ class BlockDevice(): def __repr__(self, *args, **kwargs): return f"BlockDevice({self.device})" + def __iter__(self): + for partition in self.partitions: + yield partition + def __getitem__(self, key, *args, **kwargs): if key not in self.info: raise KeyError(f'{self} does not contain information: "{key}"') -- cgit v1.2.3-70-g09d2 From 976709525816a8a47c30ae02abba9062499ad8b2 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:05:57 +0100 Subject: Yielding actual partitions and not just the partition number :) --- archinstall/lib/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index ffd3e044..7ffc866c 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -24,7 +24,7 @@ class BlockDevice(): def __iter__(self): for partition in self.partitions: - yield partition + yield self.partitions[partition] def __getitem__(self, key, *args, **kwargs): if key not in self.info: -- cgit v1.2.3-70-g09d2 From 759b7787439e49c03cc330cf0500977c0b83696e Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:09:40 +0100 Subject: Added some more failsafe's to the Partition() object. --- archinstall/lib/disk.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 7ffc866c..93d24613 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -120,20 +120,23 @@ class Partition(): part_id = os.path.basename(path) self.path = path self.part_id = part_id - self.mountpoint = None - self.filesystem = filesystem # TODO: Autodetect if we're reusing a partition + self.mountpoint = mountpoint + self.filesystem = filesystem self.size = size # TODO: Refresh? self.encrypted = encrypted if mountpoint: self.mount(mountpoint) - if not self.mountpoint: - # As a last step, check if we've mounted outside of the script - partition_info = get_partition_info(self.path) - self.mountpoint = partition_info['target'] - if partition_info['fstype'] != self.filesystem and filesystem: - raise DiskError(f"{self} was given a filesystem format, but a existing format was detected: {partition_info['fstype']}") + partition_info = get_partition_info(self.path) + + if self.mountpoint != partition_info['target'] and mountpoint: + raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {partition_info['target']}") + if partition_info['fstype'] != self.filesystem and filesystem: + raise DiskError(f"{self} was given a filesystem format, but a existing format was detected: {partition_info['fstype']}") + + self.mountpoint = partition_info['target'] + self.filesystem = partition_info['fstype'] def __repr__(self, *args, **kwargs): if self.encrypted: -- cgit v1.2.3-70-g09d2 From a5a6ff4d31aa23dfaceca3973166a24dba4ccd0f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:25:34 +0100 Subject: Added an early check for filesystem compatability. Since we need to handle unique packages etc for certain filesystem formats. This early check can be caught and ignored if the programmer/user wants to override the check and continue anyway. But the default should be to stop all execution to not install a half-working system. --- archinstall/lib/disk.py | 18 +++++++++++++++--- archinstall/lib/exceptions.py | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 93d24613..e23e354c 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -138,14 +138,26 @@ class Partition(): self.mountpoint = partition_info['target'] self.filesystem = partition_info['fstype'] + # We perform a dummy format on /dev/null with the given filesystem-type + # in order to determain if we support it or not. + try: + self.format(self.filesystem, '/dev/null') + except DiskError: + pass # We supported it, but /dev/null is not formatable as expected + except UnknownFilesystemFormat as err: + raise err + def __repr__(self, *args, **kwargs): if self.encrypted: return f'Partition(path={self.path}, real_device={self.real_device}, fs={self.filesystem}, mounted={self.mountpoint})' else: return f'Partition(path={self.path}, fs={self.filesystem}, mounted={self.mountpoint})' - def format(self, filesystem): - log(f'Formatting {self} -> {filesystem}', level=LOG_LEVELS.Info) + def format(self, filesystem, path=None): + if not path: + path = self.path + + log(f'Formatting {path} -> {filesystem}', level=LOG_LEVELS.Info) if filesystem == 'btrfs': o = b''.join(sys_command(f'/usr/bin/mkfs.btrfs -f {self.path}')) if b'UUID' not in o: @@ -169,7 +181,7 @@ class Partition(): raise DiskError(f'Could not format {self.path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'f2fs' else: - raise DiskError(f'Fileformat {filesystem} is not yet implemented.') + raise UnknownFilesystemFormat(f'Fileformat '{filesystem}' is not yet implemented.') return True def find_parent_of(self, data, name, parent=None): diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py index 84e6a766..a7864a23 100644 --- a/archinstall/lib/exceptions.py +++ b/archinstall/lib/exceptions.py @@ -2,6 +2,8 @@ class RequirementError(BaseException): pass class DiskError(BaseException): pass +class UnknownFilesystemFormat(BaseException): + pass class ProfileError(BaseException): pass class SysCallError(BaseException): -- cgit v1.2.3-70-g09d2 From a88a41abfb519582933e2e4b04a279f0887b91d1 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:26:04 +0100 Subject: Quotation issue --- archinstall/lib/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index e23e354c..2ac198cb 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -181,7 +181,7 @@ class Partition(): raise DiskError(f'Could not format {self.path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'f2fs' else: - raise UnknownFilesystemFormat(f'Fileformat '{filesystem}' is not yet implemented.') + raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.") return True def find_parent_of(self, data, name, parent=None): -- cgit v1.2.3-70-g09d2 From 15aa16c4256079de97d530df280def65e92fd30b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:27:12 +0100 Subject: Renamed fat32 to vfat to work more seamlessly with findmnt and other tools that report fat32 as vfat --- archinstall/lib/disk.py | 6 +++--- examples/guided.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 2ac198cb..b416780c 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -163,11 +163,11 @@ class Partition(): if b'UUID' not in o: raise DiskError(f'Could not format {self.path} with {filesystem} because: {o}') self.filesystem = 'btrfs' - elif filesystem == 'fat32': + elif filesystem == 'vfat': o = b''.join(sys_command(f'/usr/bin/mkfs.vfat -F32 {self.path}')) if (b'mkfs.fat' not in o and b'mkfs.vfat' not in o) or b'command not found' in o: raise DiskError(f'Could not format {self.path} with {filesystem} because: {o}') - self.filesystem = 'fat32' + self.filesystem = 'vfat' elif filesystem == 'ext4': if (handle := sys_command(f'/usr/bin/mkfs.ext4 -F {self.path}')).exit_code != 0: raise DiskError(f'Could not format {self.path} with {filesystem} because: {b"".join(handle)}') @@ -259,7 +259,7 @@ class Filesystem(): return self.raw_parted(string).exit_code def use_entire_disk(self, prep_mode=None): - self.add_partition('primary', start='1MiB', end='513MiB', format='fat32') + self.add_partition('primary', start='1MiB', end='513MiB', format='vfat') self.set_name(0, 'EFI') self.set(0, 'boot on') self.set(0, 'esp on') # TODO: Redundant, as in GPT mode it's an alias for "boot on"? https://www.gnu.org/software/parted/manual/html_node/set.html diff --git a/examples/guided.py b/examples/guided.py index d6029f46..4f7da99f 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -285,7 +285,7 @@ with archinstall.Filesystem(harddrive, archinstall.GPT) as fs: if harddrive.partition[1].size == '512M': raise OSError('Trying to encrypt the boot partition for petes sake..') - harddrive.partition[0].format('fat32') + harddrive.partition[0].format('vfat') if disk_password: # First encrypt and unlock, then format the desired partition inside the encrypted part. -- cgit v1.2.3-70-g09d2 From 3dcf8ced6ceed483d1eb6a8212ae5fd79d14ad6c Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:28:26 +0100 Subject: Fixed correct variable usage for path when formatting, enabling temporary override. --- archinstall/lib/disk.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index b416780c..c721c90e 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -159,26 +159,26 @@ class Partition(): log(f'Formatting {path} -> {filesystem}', level=LOG_LEVELS.Info) if filesystem == 'btrfs': - o = b''.join(sys_command(f'/usr/bin/mkfs.btrfs -f {self.path}')) + o = b''.join(sys_command(f'/usr/bin/mkfs.btrfs -f {path}')) if b'UUID' not in o: - raise DiskError(f'Could not format {self.path} with {filesystem} because: {o}') + raise DiskError(f'Could not format {path} with {filesystem} because: {o}') self.filesystem = 'btrfs' elif filesystem == 'vfat': - o = b''.join(sys_command(f'/usr/bin/mkfs.vfat -F32 {self.path}')) + o = b''.join(sys_command(f'/usr/bin/mkfs.vfat -F32 {path}')) if (b'mkfs.fat' not in o and b'mkfs.vfat' not in o) or b'command not found' in o: - raise DiskError(f'Could not format {self.path} with {filesystem} because: {o}') + raise DiskError(f'Could not format {path} with {filesystem} because: {o}') self.filesystem = 'vfat' elif filesystem == 'ext4': - if (handle := sys_command(f'/usr/bin/mkfs.ext4 -F {self.path}')).exit_code != 0: - raise DiskError(f'Could not format {self.path} with {filesystem} because: {b"".join(handle)}') + if (handle := sys_command(f'/usr/bin/mkfs.ext4 -F {path}')).exit_code != 0: + raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'ext4' elif filesystem == 'xfs': - if (handle:= sys_command(f'/usr/bin/mkfs.xfs -f {self.path}')).exit_code != 0: - raise DiskError(f'Could not format {self.path} with {filesystem} because: {b"".join(handle)}') + if (handle:= sys_command(f'/usr/bin/mkfs.xfs -f {path}')).exit_code != 0: + raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'xfs' elif filesystem == 'f2fs': - if (handle:= sys_command(f'/usr/bin/mkfs.f2fs -f {self.path}')).exit_code != 0: - raise DiskError(f'Could not format {self.path} with {filesystem} because: {b"".join(handle)}') + if (handle:= sys_command(f'/usr/bin/mkfs.f2fs -f {path}')).exit_code != 0: + raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'f2fs' else: raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.") -- cgit v1.2.3-70-g09d2 From 1253982c30c5d2454f8e1b285e586a6f48929e3c Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:31:00 +0100 Subject: Added correct exception handling to the pre-format check. --- archinstall/lib/disk.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index c721c90e..8eb4b54d 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -142,8 +142,8 @@ class Partition(): # in order to determain if we support it or not. try: self.format(self.filesystem, '/dev/null') - except DiskError: - pass # We supported it, but /dev/null is not formatable as expected + except SysCallError: + pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code except UnknownFilesystemFormat as err: raise err -- cgit v1.2.3-70-g09d2 From acf39296efd905e6b2a495468555c6b8a8976cbc Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:34:11 +0100 Subject: Added a check in guided to make it more visible that we check for filesystem supportation. --- archinstall/lib/disk.py | 21 +++++++++++---------- examples/guided.py | 3 ++- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 8eb4b54d..d2bac3d2 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -113,7 +113,6 @@ class BlockDevice(): return True return False - class Partition(): def __init__(self, path, part_id=None, size=-1, filesystem=None, mountpoint=None, encrypted=False): if not part_id: @@ -138,15 +137,6 @@ class Partition(): self.mountpoint = partition_info['target'] self.filesystem = partition_info['fstype'] - # We perform a dummy format on /dev/null with the given filesystem-type - # in order to determain if we support it or not. - try: - self.format(self.filesystem, '/dev/null') - except SysCallError: - pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code - except UnknownFilesystemFormat as err: - raise err - def __repr__(self, *args, **kwargs): if self.encrypted: return f'Partition(path={self.path}, real_device={self.real_device}, fs={self.filesystem}, mounted={self.mountpoint})' @@ -217,6 +207,17 @@ class Partition(): self.mountpoint = target return True + def filesystem_supported(self): + # We perform a dummy format on /dev/null with the given filesystem-type + # in order to determain if we support it or not. + try: + self.format(self.filesystem, '/dev/null') + except SysCallError: + pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code + except UnknownFilesystemFormat as err: + raise err + return True + class Filesystem(): # TODO: # When instance of a HDD is selected, check all usages and gracefully unmount them diff --git a/examples/guided.py b/examples/guided.py index 4f7da99f..384c4e17 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -104,7 +104,8 @@ if harddrive.has_partitions(): archinstall.log('Using existing partition table:') for partition in harddrive: - archinstall.log(f" {partition}") + if partition.filesystem_supported(): + archinstall.log(f" {partition}") else: print('Formatting woop woop!') exit(1) -- cgit v1.2.3-70-g09d2 From 530edb5ece1350cbba568529cbba1f6c2eb36938 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:36:24 +0100 Subject: Moved the output of the current fileformat structure in guided, as well as added an option to supress the log message from format() in order to hide (for users) the some what confusing formating of /dev/null. --- archinstall/lib/disk.py | 8 +++++--- examples/guided.py | 9 +++++---- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index d2bac3d2..7b3a9b66 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -143,11 +143,13 @@ class Partition(): else: return f'Partition(path={self.path}, fs={self.filesystem}, mounted={self.mountpoint})' - def format(self, filesystem, path=None): + def format(self, filesystem, path=None, log_formating=True): if not path: path = self.path - log(f'Formatting {path} -> {filesystem}', level=LOG_LEVELS.Info) + if log_formating: + log(f'Formatting {path} -> {filesystem}', level=LOG_LEVELS.Info) + if filesystem == 'btrfs': o = b''.join(sys_command(f'/usr/bin/mkfs.btrfs -f {path}')) if b'UUID' not in o: @@ -211,7 +213,7 @@ class Partition(): # We perform a dummy format on /dev/null with the given filesystem-type # in order to determain if we support it or not. try: - self.format(self.filesystem, '/dev/null') + self.format(self.filesystem, '/dev/null', log_formating=False) except SysCallError: pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code except UnknownFilesystemFormat as err: diff --git a/examples/guided.py b/examples/guided.py index 384c4e17..d538d5cd 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -95,6 +95,10 @@ archinstall.storage['_guided']['harddrive'] = harddrive if harddrive.has_partitions(): archinstall.log(f" ! {harddrive} contains existing partitions", fg='red') + for partition in harddrive: + if partition.filesystem_supported(): + archinstall.log(f" {partition}") + if (option := input('Do you wish to keep existing partition setup or format the entire disk? (k/f): ')).lower() in ('k', 'keep'): # If we want to keep the existing partitioning table # Make sure that it's the selected drive mounted under /mnt @@ -102,10 +106,7 @@ if harddrive.has_partitions(): if harddrive.has_mount_point(archinstall.storage['MOUNT_POINT']) is False: raise archinstall.DiskError(f"The selected drive {harddrive} is not pre-mounted to {archinstall.storage['MOUNT_POINT']}. This is required when keeping a existing partitioning scheme.") - archinstall.log('Using existing partition table:') - for partition in harddrive: - if partition.filesystem_supported(): - archinstall.log(f" {partition}") + archinstall.log('Using existing partition table reported above.') else: print('Formatting woop woop!') exit(1) -- cgit v1.2.3-70-g09d2 From c983976394cda6e0db5f3ae7079e172804d91885 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 17:57:16 +0100 Subject: Added in argument support to archinstall for easier testing and debugging --- archinstall/__init__.py | 17 ++++++++++++++++- examples/guided.py | 8 +++----- 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'archinstall') diff --git a/archinstall/__init__.py b/archinstall/__init__.py index ee2d0361..d4452d38 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -12,4 +12,19 @@ from .lib.services import * from .lib.packages import * from .lib.output import * from .lib.storage import * -from .lib.hardware import * \ No newline at end of file +from .lib.hardware import * + +## Basic version of arg.parse() supporting: +## --key=value +## --boolean +arguments = {} +positionals = [] +for arg in sys.argv[1:]: + if '--' == arg[:2]: + if '=' in arg: + key, val = [x.strip() for x in arg[2:].split('=', 1)] + else: + key, val = arg[2:], True + arguments[key] = val + else: + positionals.append(arg) \ No newline at end of file diff --git a/examples/guided.py b/examples/guided.py index d538d5cd..8033a8a5 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -5,7 +5,8 @@ import archinstall # We'll print this right before the user gets informed about the formatting timer. archinstall.storage['_guided'] = {} archinstall.storage['_guided_hidden'] = {} # This will simply be hidden from printouts and things. - +print(archinstall.arguments, archinstall.positionals) +exit(0) """ This signal-handler chain (and global variable) is used to trigger the "Are you sure you want to abort?" question. @@ -99,7 +100,7 @@ if harddrive.has_partitions(): if partition.filesystem_supported(): archinstall.log(f" {partition}") - if (option := input('Do you wish to keep existing partition setup or format the entire disk? (k/f): ')).lower() in ('k', 'keep'): + if (option := input('Do you wish to keep existing disk setup or format entire drive? (k/f): ')).lower() in ('k', 'keep'): # If we want to keep the existing partitioning table # Make sure that it's the selected drive mounted under /mnt # That way, we can rely on genfstab and some manual post-installation steps. @@ -107,9 +108,6 @@ if harddrive.has_partitions(): raise archinstall.DiskError(f"The selected drive {harddrive} is not pre-mounted to {archinstall.storage['MOUNT_POINT']}. This is required when keeping a existing partitioning scheme.") archinstall.log('Using existing partition table reported above.') - else: - print('Formatting woop woop!') -exit(1) while (disk_password := getpass.getpass(prompt='Enter disk encryption password (leave blank for no encryption): ')): disk_password_verification = getpass.getpass(prompt='And one more time for verification: ') -- cgit v1.2.3-70-g09d2 From 9db589f10a1ba5e96f2343c25cba8fff32e0332c Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:45:25 +0100 Subject: Added a default no-info value to BlockDevice() --- archinstall/lib/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 7b3a9b66..6c7e63ba 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -14,7 +14,7 @@ GPT = 0b00000001 #libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p) class BlockDevice(): - def __init__(self, path, info): + def __init__(self, path, info={}): self.path = path self.info = info self.part_cache = OrderedDict() -- cgit v1.2.3-70-g09d2 From 9038fda9911f40ede813c5492f34b68411db65b8 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:50:30 +0100 Subject: Added error handling for get_mount_info() --- archinstall/lib/disk.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 6c7e63ba..80e9c740 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -127,15 +127,17 @@ class Partition(): if mountpoint: self.mount(mountpoint) - partition_info = get_partition_info(self.path) + mount_information = get_mount_info(self.path) - if self.mountpoint != partition_info['target'] and mountpoint: - raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {partition_info['target']}") - if partition_info['fstype'] != self.filesystem and filesystem: - raise DiskError(f"{self} was given a filesystem format, but a existing format was detected: {partition_info['fstype']}") + if self.mountpoint != mount_information['target'] and mountpoint: + raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information['target']}") + if mount_information['fstype'] != self.filesystem and filesystem: + raise DiskError(f"{self} was given a filesystem format, but a existing format was detected: {mount_information['fstype']}") - self.mountpoint = partition_info['target'] - self.filesystem = partition_info['fstype'] + if (target := mount_information.get('target', None)): + self.mountpoint = target + if (fstype := mount_information.get('fstype', None)): + self.filesystem = fstype def __repr__(self, *args, **kwargs): if self.encrypted: @@ -344,8 +346,12 @@ def harddrive(size=None, model=None, fuzzy=False): return collection[drive] -def get_partition_info(path): - output = b''.join(sys_command(f'/usr/bin/findmnt --json {path}')) +def get_mount_info(path): + try: + output = b''.join(sys_command(f'/usr/bin/findmnt --json {path}')) + except SysCallError: + return {} + output = output.decode('UTF-8') output = json.loads(output) if 'filesystems' in output: -- cgit v1.2.3-70-g09d2 From a9d49a52eca85a471e79018fdc952190e2071e10 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:51:45 +0100 Subject: Corrected two variables. --- archinstall/lib/disk.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 80e9c740..d999e626 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -129,10 +129,10 @@ class Partition(): mount_information = get_mount_info(self.path) - if self.mountpoint != mount_information['target'] and mountpoint: - raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information['target']}") - if mount_information['fstype'] != self.filesystem and filesystem: - raise DiskError(f"{self} was given a filesystem format, but a existing format was detected: {mount_information['fstype']}") + if self.mountpoint != mount_information.get('target', None) and mountpoint: + raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information.get('target', None)}") + if mount_information.get('fstype', None) != self.filesystem and filesystem: + raise DiskError(f"{self} was given a filesystem format, but a existing format was detected: {mount_information.get('fstype', None)}") if (target := mount_information.get('target', None)): self.mountpoint = target -- cgit v1.2.3-70-g09d2 From 4349512ef3f24c48c1c0903064d518e44c11101b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:53:55 +0100 Subject: Added error handling for BlockDevice() that was given no information. --- archinstall/lib/disk.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index d999e626..5a2857f3 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -14,7 +14,12 @@ GPT = 0b00000001 #libc.mount.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_ulong, ctypes.c_char_p) class BlockDevice(): - def __init__(self, path, info={}): + def __init__(self, path, info=None): + if not info: + # If we don't give any information, we need to auto-fill it. + # Otherwise any subsequent usage will break. + info = all_disks().get(path, {}) + self.path = path self.info = info self.part_cache = OrderedDict() -- cgit v1.2.3-70-g09d2 From d184777a1b8a2cccddf6127d8ea7ce5a38d509f1 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:57:47 +0100 Subject: Reworked fault handling a bit --- archinstall/lib/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 5a2857f3..52afffcf 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -18,7 +18,7 @@ class BlockDevice(): if not info: # If we don't give any information, we need to auto-fill it. # Otherwise any subsequent usage will break. - info = all_disks().get(path, {}) + info = all_disks()[path].info self.path = path self.info = info -- cgit v1.2.3-70-g09d2 From 03c46cce2b62b41c5b73f86dffb90eff6a1b8eb2 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 20:46:12 +0100 Subject: Added a dummy function call to grab the partition fstype, since unmounted filesystems won't return the fstype obviously. --- archinstall/lib/disk.py | 1 + 1 file changed, 1 insertion(+) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 52afffcf..5cb95226 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -133,6 +133,7 @@ class Partition(): self.mount(mountpoint) mount_information = get_mount_info(self.path) + actual_fstype = get_filesystem_type(self.path) # blkid -o value -s TYPE self.path if self.mountpoint != mount_information.get('target', None) and mountpoint: raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information.get('target', None)}") -- cgit v1.2.3-70-g09d2 From e2cd617d05d87bbe3fe8f1809faecd8c1ebd230e Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Thu, 11 Feb 2021 14:11:21 +0100 Subject: Reworked the way partition formatting works. As well as added some flags to the partition if it's locked/unlocked for partitioning. By defaults partitions will now be in a locked state - prohibiting formatting unless set or overridden in the formatting call. This allows us to selectively format partitions individually later on. There's also a target_mountpoint that is the desired relative mount point inside a installation. This can be pre-pended with the installation base directory during mount. These changes also function as indicators for the installation (and guided installation) for which partitions to use and/or wipe. If an entire drive is selected for wiping, these changes will have no affect in the decision making as all partitions will be new and have formatable set to true. --- archinstall/lib/disk.py | 63 +++++++++++++++++++++++++++++++++---------- archinstall/lib/exceptions.py | 2 ++ archinstall/lib/luks.py | 7 ++++- examples/guided.py | 16 ++++++----- 4 files changed, 67 insertions(+), 21 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 5cb95226..aa3632d8 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -125,35 +125,57 @@ class Partition(): self.path = path self.part_id = part_id self.mountpoint = mountpoint + self.target_mountpoint = mountpoint self.filesystem = filesystem self.size = size # TODO: Refresh? self.encrypted = encrypted + self.allow_formatting = False # A fail-safe for unconfigured partitions, such as windows NTFS partitions. if mountpoint: self.mount(mountpoint) mount_information = get_mount_info(self.path) - actual_fstype = get_filesystem_type(self.path) # blkid -o value -s TYPE self.path + fstype = get_filesystem_type(self.path) # blkid -o value -s TYPE self.path if self.mountpoint != mount_information.get('target', None) and mountpoint: raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information.get('target', None)}") - if mount_information.get('fstype', None) != self.filesystem and filesystem: - raise DiskError(f"{self} was given a filesystem format, but a existing format was detected: {mount_information.get('fstype', None)}") if (target := mount_information.get('target', None)): self.mountpoint = target - if (fstype := mount_information.get('fstype', None)): + if (fstype := mount_information.get('fstype', fstype)): self.filesystem = fstype + def __lt__(self, left_comparitor): + if type(left_comparitor) == Partition: + left_comparitor = left_comparitor.path + else: + left_comparitor = str(left_comparitor) + return self.path < left_comparitor # Not quite sure the order here is correct. But /dev/nvme0n1p1 comes before /dev/nvme0n1p5 so seems correct. + def __repr__(self, *args, **kwargs): + mount_repr = '' + if self.mountpoint: + mount_repr = f", mounted={self.mountpoint}" + elif self.target_mountpoint: + mount_repr = f", rel_mountpoint={self.target_mountpoint}" + if self.encrypted: - return f'Partition(path={self.path}, real_device={self.real_device}, fs={self.filesystem}, mounted={self.mountpoint})' + return f'Partition(path={self.path}, real_device={self.real_device}, fs={self.filesystem}{mount_repr})' else: - return f'Partition(path={self.path}, fs={self.filesystem}, mounted={self.mountpoint})' + return f'Partition(path={self.path}, fs={self.filesystem}{mount_repr})' - def format(self, filesystem, path=None, log_formating=True): - if not path: + def format(self, filesystem, path=None, allow_formatting=None, log_formating=True): + """ + Format can be given an overriding path, for instance /dev/null to test + the formating functionality and in essence the support for the given filesystem. + """ + if path is None: path = self.path + if allow_formatting is None: + allow_formatting = self.allow_formatting + + if not allow_formatting: + raise PermissionError(f"{self} is not formatable either because instance is locked ({self.allow_formatting}) or a blocking flag was given ({allow_formatting})") if log_formating: log(f'Formatting {path} -> {filesystem}', level=LOG_LEVELS.Info) @@ -173,13 +195,18 @@ class Partition(): raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'ext4' elif filesystem == 'xfs': - if (handle:= sys_command(f'/usr/bin/mkfs.xfs -f {path}')).exit_code != 0: + if (handle := sys_command(f'/usr/bin/mkfs.xfs -f {path}')).exit_code != 0: raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'xfs' elif filesystem == 'f2fs': - if (handle:= sys_command(f'/usr/bin/mkfs.f2fs -f {path}')).exit_code != 0: + if (handle := sys_command(f'/usr/bin/mkfs.f2fs -f {path}')).exit_code != 0: raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'f2fs' + elif filesystem == 'crypto_LUKS': + from .luks import luks2 + encrypted_partition = luks2(self, None, None) + encrypted_partition.format(path) + self.filesystem = 'crypto_LUKS' else: raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.") return True @@ -218,10 +245,14 @@ class Partition(): return True def filesystem_supported(self): - # We perform a dummy format on /dev/null with the given filesystem-type - # in order to determain if we support it or not. + """ + The support for a filesystem (this partition) is tested by calling + partition.format() with a path set to '/dev/null' which returns two exceptions: + 1. SysCallError saying that /dev/null is not formattable - but the filesystem is supported + 2. UnknownFilesystemFormat that indicates that we don't support the given filesystem type + """ try: - self.format(self.filesystem, '/dev/null', log_formating=False) + self.format(self.filesystem, '/dev/null', log_formating=False, allow_formatting=True) except SysCallError: pass # We supported it, but /dev/null is not formatable as expected so the mkfs call exited with an error code except UnknownFilesystemFormat as err: @@ -364,4 +395,8 @@ def get_mount_info(path): if len(output['filesystems']) > 1: raise DiskError(f"Path '{path}' contains multiple mountpoints: {output['filesystems']}") - return output['filesystems'][0] \ No newline at end of file + return output['filesystems'][0] + +def get_filesystem_type(path): + output = b''.join(sys_command(f"blkid -o value -s TYPE {path}")) + return output.strip().decode('UTF-8') \ No newline at end of file diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py index a7864a23..5186bfd4 100644 --- a/archinstall/lib/exceptions.py +++ b/archinstall/lib/exceptions.py @@ -11,4 +11,6 @@ class SysCallError(BaseException): class ProfileNotFound(BaseException): pass class HardwareIncompatibilityError(BaseException): + pass +class PermissionError(BaseException): pass \ No newline at end of file diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index e1f14bab..d62c2d4b 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -12,6 +12,7 @@ class luks2(): self.mountpoint = mountpoint self.args = args self.kwargs = kwargs + self.filesystem = 'crypto_LUKS' def __enter__(self): key_file = self.encrypt(self.partition, self.password, *self.args, **self.kwargs) @@ -57,4 +58,8 @@ class luks2(): def close(self, mountpoint): sys_command(f'cryptsetup close /dev/mapper/{mountpoint}') - return os.path.islink(f'/dev/mapper/{mountpoint}') is False \ No newline at end of file + return os.path.islink(f'/dev/mapper/{mountpoint}') is False + + def format(self, path): + if (handle := sys_command(f"/usr/bin/cryptsetup -q -v luksErase {path}")).exit_code != 0: + raise DiskError(f'Could not format {path} with {self.filesystem} because: {b"".join(handle)}') \ No newline at end of file diff --git a/examples/guided.py b/examples/guided.py index c5e1474e..5e8a64c1 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -105,18 +105,22 @@ else: if archinstall.arguments['harddrive'].has_partitions(): archinstall.log(f" ! {archinstall.arguments['harddrive']} contains existing partitions", fg='red') try: + partition_mountpoints = {} for partition in archinstall.arguments['harddrive']: if partition.filesystem_supported(): archinstall.log(f" {partition}") + partition_mountpoints[partition] = None - if (option := input('Do you wish to keep existing disk setup or format entire drive? (k/f): ')).lower() in ('k', 'keep'): - # If we want to keep the existing partitioning table - # Make sure that it's the selected drive mounted under /mnt - # That way, we can rely on genfstab and some manual post-installation steps. - if archinstall.arguments['harddrive'].has_mount_point(archinstall.storage['MOUNT_POINT']) is False: - raise archinstall.DiskError(f"The selected drive {archinstall.arguments['harddrive']} is not pre-mounted to {archinstall.storage['MOUNT_POINT']}. This is required when keeping a existing partitioning scheme.") + if (option := input('Do you wish to keep one/more existing partitions or format entire drive? (k/f): ')).lower() in ('k', 'keep'): + archinstall.arguments['harddrive'].keep_partitions = True + while True: + partition = archinstall.generic_select(partition_mountpoints.values(), "Select a partition to assign mount-point to") + + archinstall.arguments['harddrive'].allocate_partitions(selections) archinstall.log('Using existing partition table reported above.') + else: + archinstall.arguments['harddrive'].keep_partitions = False except archinstall.UnknownFilesystemFormat as err: archinstall.log(f"Current filesystem is not supported: {err}", fg='red') input(f"Do you wish to erase all data? (y/n):") -- cgit v1.2.3-70-g09d2 From 5cb3b0d176fff9d2c2fb814530b29eca5819fe8e Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 12:24:56 +0100 Subject: Implemented #106 in branch skip-partitioning. Also moving the disk_password from being a local variable to a BlockDevice setting/variable. --- archinstall/lib/disk.py | 4 ++++ archinstall/lib/user_interaction.py | 10 ++++++++++ examples/guided.py | 11 +++-------- 3 files changed, 17 insertions(+), 8 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index aa3632d8..d76c6d7e 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -23,6 +23,10 @@ class BlockDevice(): self.path = path self.info = info self.part_cache = OrderedDict() + # TODO: Currently disk encryption is a BIT missleading. + # It's actually partition-encryption, but for future-proofing this + # I'm placing the encryption password on a BlockDevice level. + self.encryption_passwoed = None def __repr__(self, *args, **kwargs): return f"BlockDevice({self.device})" diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index fdbabe96..f92cd008 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -1,10 +1,20 @@ +import getpass from .exceptions import * from .profiles import Profile from .locale_helpers import search_keyboard_layout +from .output import log ## TODO: Some inconsistencies between the selection processes. ## Some return the keys from the options, some the values? +def get_password(prompt="Enter a password: "): + while (passwd := getpass.getpass(prompt)): + passwd_verification = getpass.getpass(prompt='And one more time for verification: ') + if passwd != passwd_verification: + log(' * Passwords did not match * ', bg='black', fg='red') + continue + return passwd + def generic_select(options, input_text="Select one of the above by index or absolute value: ", sort=True): """ A generic select function that does not output anything diff --git a/examples/guided.py b/examples/guided.py index 0efc438c..84676284 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -152,16 +152,11 @@ if archinstall.arguments['harddrive'].has_partitions(): else: archinstall.arguments['harddrive'].keep_partitions = False -exit(0) -while (disk_password := getpass.getpass(prompt='Enter disk encryption password (leave blank for no encryption): ')): - disk_password_verification = getpass.getpass(prompt='And one more time for verification: ') - if disk_password != disk_password_verification: - archinstall.log(' * Passwords did not match * ', bg='black', fg='red') - continue - archinstall.storage['_guided']['disk_encryption'] = True - break +disk_password = archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): ') +archinstall.arguments['harddrive'].encryption_passwoed = disk_password +exit(0) # Ask for a hostname hostname = input('Desired hostname for the installation: ') if len(hostname) == 0: -- cgit v1.2.3-70-g09d2 From 572d59e5607811c4f7456d09ad1744b2da3ea394 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 13:30:14 +0100 Subject: Cleaning up guided.py a bit to be less complex and convoluted, while still performing the same task. --- archinstall/lib/exceptions.py | 2 + archinstall/lib/user_interaction.py | 71 +++++++++++++++ examples/guided.py | 177 ++++++++++++------------------------ 3 files changed, 133 insertions(+), 117 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/exceptions.py b/archinstall/lib/exceptions.py index 5186bfd4..5a5d47c6 100644 --- a/archinstall/lib/exceptions.py +++ b/archinstall/lib/exceptions.py @@ -13,4 +13,6 @@ class ProfileNotFound(BaseException): class HardwareIncompatibilityError(BaseException): pass class PermissionError(BaseException): + pass +class UserError(BaseException): pass \ No newline at end of file diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index f92cd008..440e41a1 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -14,6 +14,77 @@ def get_password(prompt="Enter a password: "): log(' * Passwords did not match * ', bg='black', fg='red') continue return passwd + return None + +def ask_for_superuser_account(prompt='Create a required super-user with sudo privileges: ', forced=False): + while 1: + new_user = input(prompt).strip(' ') + + if not new_user and forced: + # TODO: make this text more generic? + # It's only used to create the first sudo user when root is disabled in guided.py + log(' * Since root is disabled, you need to create a least one (super) user!', bg='black', fg='red') + continue + elif not new_user and not forced: + raise UserError("No superuser was created.") + + password = get_password(prompt=f'Password for user {new_user}: ') + return {new_user: password} + +def ask_for_additional_users(prompt='Any additional users to install (leave blank for no users): '): + users = {} + super_users = {} + + while 1: + new_user = input(prompt).strip(' ') + if not new_user: + break + password = get_password(prompt=f'Password for user {new_user}: ') + + if input("Should this user be a sudo (super) user (y/N): ").strip(' ').lower() in ('y', 'yes'): + super_users[new_user] = password + else: + users[new_user] = password + + return users, super_users + +def ask_to_configure_network(): + # Optionally configure one network interface. + #while 1: + # {MAC: Ifname} + interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation', **archinstall.list_interfaces()} + archinstall.storage['_guided']['network'] = None + + nic = archinstall.generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") + if nic and nic != 'Copy ISO network configuration to installation': + mode = archinstall.generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") + if mode == 'IP (static)': + while 1: + ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip() + if ip: + break + else: + ArchInstall.log( + "You need to enter a valid IP in IP-config mode.", + level=archinstall.LOG_LEVELS.Warning, + bg='black', + fg='red' + ) + + if not len(gateway := input('Enter your gateway (router) IP address or leave blank for none: ').strip()): + gateway = None + + dns = None + if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()): + dns = dns_input.split(' ') + + return {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} + else: + return {'nic': nic} + elif nic: + return nic + + return None def generic_select(options, input_text="Select one of the above by index or absolute value: ", sort=True): """ diff --git a/examples/guided.py b/examples/guided.py index 84676284..119f22b3 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -1,14 +1,10 @@ import getpass, time, json, sys, signal, os import archinstall -# Create a storage structure for all our information. -# We'll print this right before the user gets informed about the formatting timer. -archinstall.storage['_guided'] = {} -archinstall.storage['_guided_hidden'] = {} # This will simply be hidden from printouts and things. - """ This signal-handler chain (and global variable) is used to trigger the "Are you sure you want to abort?" question further down. +It might look a bit odd, but have a look at the line: "if SIG_TRIGGER:" """ SIG_TRIGGER = False def kill_handler(sig, frame): @@ -23,13 +19,14 @@ def sig_handler(sig, frame): original_sigint_handler = signal.getsignal(signal.SIGINT) signal.signal(signal.SIGINT, sig_handler) + def perform_installation(device, boot_partition, language, mirrors): """ Performs the installation steps on a block device. Only requirement is that the block devices are formatted and setup prior to entering this function. """ - with archinstall.Installer(device, boot_partition=boot_partition, hostname=archinstall.storage['_guided']['hostname']) as installation: + with archinstall.Installer(device, boot_partition=boot_partition, hostname=archinstall.arguments.get('hostname', 'Archinstall')) as installation: ## if len(mirrors): # Certain services might be running that affects the system during installation. # Currently, only one such service is "reflector.service" which updates /etc/pacman.d/mirrorlist @@ -152,137 +149,83 @@ if archinstall.arguments['harddrive'].has_partitions(): else: archinstall.arguments['harddrive'].keep_partitions = False +# Get disk encryption password (or skip if blank) +if not archinstall.arguments.get('encryption-password', None): + archinstall.arguments['encryption-password'] = archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): ') +archinstall.arguments['harddrive'].encryption_password = archinstall.arguments['encryption-password'] -disk_password = archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): ') -archinstall.arguments['harddrive'].encryption_passwoed = disk_password - -exit(0) -# Ask for a hostname -hostname = input('Desired hostname for the installation: ') -if len(hostname) == 0: - hostname = 'ArchInstall' -archinstall.storage['_guided']['hostname'] = hostname +# Get the hostname for the machine +if not archinstall.arguments.get('hostname', None): + archinstall.arguments['hostname'] = input('Desired hostname for the installation: ').strip(' ') # Ask for a root password (optional, but triggers requirement for super-user if skipped) -while (root_pw := getpass.getpass(prompt='Enter root password (leave blank to leave root disabled): ')): - root_pw_verification = getpass.getpass(prompt='And one more time for verification: ') - if root_pw != root_pw_verification: - archinstall.log(' * Passwords did not match * ', bg='black', fg='red') - continue - - # Storing things in _guided_hidden helps us avoid printing it - # when echoing user configuration: archinstall.storage['_guided'] - archinstall.storage['_guided_hidden']['root_pw'] = root_pw - archinstall.storage['_guided']['root_unlocked'] = True - break +if not archinstall.arguments.get('!root-password', None): + archinstall.arguments['!root-password'] = archinstall.get_password(prompt='Enter root password (Recommended: leave blank to leave root disabled): ') + +# # Storing things in _guided_hidden helps us avoid printing it +# # when echoing user configuration: archinstall.storage['_guided'] +# archinstall.storage['_guided_hidden']['root_pw'] = root_pw +# archinstall.storage['_guided']['root_unlocked'] = True +# break # Ask for additional users (super-user if root pw was not set) -users = {} -new_user_text = 'Any additional users to install (leave blank for no users): ' -if len(root_pw.strip()) == 0: - new_user_text = 'Create a super-user with sudo privileges: ' - -archinstall.storage['_guided']['users'] = None -while 1: - new_user = input(new_user_text) - if len(new_user.strip()) == 0: - if len(root_pw.strip()) == 0: - archinstall.log(' * Since root is disabled, you need to create a least one (super) user!', bg='black', fg='red') - continue - break - - if not archinstall.storage['_guided']['users']: - archinstall.storage['_guided']['users'] = [] - archinstall.storage['_guided']['users'].append(new_user) - - new_user_passwd = getpass.getpass(prompt=f'Password for user {new_user}: ') - new_user_passwd_verify = getpass.getpass(prompt=f'Enter password again for verification: ') - if new_user_passwd != new_user_passwd_verify: - archinstall.log(' * Passwords did not match * ', bg='black', fg='red') - continue - - users[new_user] = new_user_passwd - break +archinstall.arguments['users'] = {} +archinstall.arguments['superusers'] = {} +if not archinstall.arguments.get('!root-password', None): + archinstall.arguments['superusers'] = archinstall.ask_for_superuser_account('Create a required super-user with sudo privileges: ', forced=True) + +users, superusers = archinstall.ask_for_additional_users('Any additional users to install (leave blank for no users): ') +archinstall.arguments['users'] = users +archinstall.arguments['superusers'] = {**archinstall.arguments['superusers'], **superusers} # Ask for archinstall-specific profiles (such as desktop environments etc) -while 1: - profile = archinstall.select_profile(archinstall.list_profiles()) - if profile: - archinstall.storage['_guided']['profile'] = profile - - if type(profile) != str: # Got a imported profile - archinstall.storage['_guided']['profile'] = profile[0] # The second return is a module, and not a handle/object. - if not profile[1]._prep_function(): - # TODO: See how we can incorporate this into - # the general log flow. As this is pre-installation - # session setup. Which creates the installation.log file. - archinstall.log( - ' * Profile\'s preparation requirements was not fulfilled.', - bg='black', - fg='red' - ) - continue +if not archinstall.arguments.get('profile', None): + while 1: + profile = archinstall.select_profile(archinstall.list_profiles()) + print(profile) + if profile: + archinstall.storage['_guided']['profile'] = profile + + if type(profile) != str: # Got a imported profile + archinstall.storage['_guided']['profile'] = profile[0] # The second return is a module, and not a handle/object. + if not profile[1]._prep_function(): + # TODO: See how we can incorporate this into + # the general log flow. As this is pre-installation + # session setup. Which creates the installation.log file. + archinstall.log( + ' * Profile\'s preparation requirements was not fulfilled.', + bg='black', + fg='red' + ) + continue + break + else: break - else: - break # Additional packages (with some light weight error handling for invalid package names) -archinstall.storage['_guided']['packages'] = None -while 1: - packages = [package for package in input('Additional packages aside from base (space separated): ').split(' ') if len(package)] +if not archinstall.arguments.get('packages', None): + archinstall.arguments['packages'] = [package for package in input('Additional packages aside from base (space separated): ').split(' ') if len(package)] - if not packages: - break +# Verify packages that were given +try: + archinstall.validate_package_list(archinstall.arguments['packages']) +except archinstall.RequirementError as e: + archinstall.log(e, fg='red') + exit(1) - try: - if archinstall.validate_package_list(packages): - archinstall.storage['_guided']['packages'] = packages - break - except archinstall.RequirementError as e: - print(e) - -# Optionally configure one network interface. -#while 1: -# {MAC: Ifname} -interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation', **archinstall.list_interfaces()} -archinstall.storage['_guided']['network'] = None - -nic = archinstall.generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") -if nic and nic != 'Copy ISO network configuration to installation': - mode = archinstall.generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") - if mode == 'IP (static)': - while 1: - ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip() - if ip: - break - else: - ArchInstall.log( - "You need to enter a valid IP in IP-config mode.", - level=archinstall.LOG_LEVELS.Warning, - bg='black', - fg='red' - ) - - if not len(gateway := input('Enter your gateway (router) IP address or leave blank for none: ').strip()): - gateway = None - - dns = None - if len(dns_input := input('Enter your DNS servers (space separated, blank for none): ').strip()): - dns = dns_input.split(' ') - - archinstall.storage['_guided']['network'] = {'nic': nic, 'dhcp': False, 'ip': ip, 'gateway' : gateway, 'dns' : dns} - else: - archinstall.storage['_guided']['network'] = {'nic': nic} -elif nic: - archinstall.storage['_guided']['network'] = nic +# Ask or Call the helper function that asks the user to optionally configure a network. +if not archinstall.arguments.get('nic', None): + archinstall.arguments['nic'] = archinstall.ask_to_configure_network() print() print('This is your chosen configuration:') archinstall.log("-- Guided template chosen (with below config) --", level=archinstall.LOG_LEVELS.Debug) archinstall.log(json.dumps(archinstall.storage['_guided'], indent=4, sort_keys=True, cls=archinstall.JSON), level=archinstall.LOG_LEVELS.Info) +archinstall.log(json.dumps(archinstall.arguments, indent=4, sort_keys=True, cls=archinstall.JSON), level=archinstall.LOG_LEVELS.Info) print() input('Press Enter to continue.') +exit(0) """ Issue a final warning before we continue with something un-revertable. -- cgit v1.2.3-70-g09d2 From 758b12e6746ac76c57e7725d4e35abbb4805ad23 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 13:59:44 +0100 Subject: Simplifying the profile loading a bit, and adding some debugging for it. --- archinstall/lib/user_interaction.py | 4 ++-- examples/guided.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 440e41a1..bdf8acaf 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -188,9 +188,9 @@ def select_profile(options): if '__name__' in source_data and '_prep_function' in source_data: with profile.load_instructions(namespace=f"{selected_profile}.py") as imported: if hasattr(imported, '_prep_function'): - return profile, imported + return imported - return selected_profile + return profile raise RequirementError("Selecting profiles require a least one profile to be given as an option.") diff --git a/examples/guided.py b/examples/guided.py index 3226c69b..1758a397 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -185,6 +185,7 @@ else: archinstall.arguments['profile'] = archinstall.list_profiles()[archinstall.arguments['profile']] # Check the potentially selected profiles preperations to get early checks if some additional questions are needed. +print(archinstall.arguments['profile']) if archinstall.arguments['profile']: if not archinstall.arguments['profile']._prep_function(): archinstall.log( -- cgit v1.2.3-70-g09d2 From ad4733bbd0b0e889ad902a7d954ec985fc7a24fe Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 14:21:46 +0100 Subject: Simplified profile prep-execution slightly in guided.py. The code can be improved further but it's now more easily read what's going on. --- archinstall/lib/profiles.py | 17 +++++++++++++++++ archinstall/lib/user_interaction.py | 18 +----------------- examples/guided.py | 18 +++++++++--------- 3 files changed, 27 insertions(+), 26 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index f9aa206c..7b0e78e4 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -157,6 +157,23 @@ class Profile(Script): def install(self): return self.execute() + def has_prep_function(self): + with open(self.path, 'r') as source: + source_data = source.read() + + # Some crude safety checks, make sure the imported profile has + # a __name__ check and if so, check if it's got a _prep_function() + # we can call to ask for more user input. + # + # If the requirements are met, import with .py in the namespace to not + # trigger a traditional: + # if __name__ == 'moduleName' + if '__name__' in source_data and '_prep_function' in source_data: + with profile.load_instructions(namespace=f"{selected_profile}.py") as imported: + if hasattr(imported, '_prep_function'): + return True + return False + class Application(Profile): def __repr__(self, *args, **kwargs): return f'Application({os.path.basename(self.profile)})' diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index bdf8acaf..5941903d 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -174,23 +174,7 @@ def select_profile(options): else: RequirementError("Selected profile does not exist.") - profile = Profile(None, selected_profile) - with open(profile.path, 'r') as source: - source_data = source.read() - - # Some crude safety checks, make sure the imported profile has - # a __name__ check and if so, check if it's got a _prep_function() - # we can call to ask for more user input. - # - # If the requirements are met, import with .py in the namespace to not - # trigger a traditional: - # if __name__ == 'moduleName' - if '__name__' in source_data and '_prep_function' in source_data: - with profile.load_instructions(namespace=f"{selected_profile}.py") as imported: - if hasattr(imported, '_prep_function'): - return imported - - return profile + return Profile(None, selected_profile) raise RequirementError("Selecting profiles require a least one profile to be given as an option.") diff --git a/examples/guided.py b/examples/guided.py index 1758a397..4cd37972 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -185,15 +185,15 @@ else: archinstall.arguments['profile'] = archinstall.list_profiles()[archinstall.arguments['profile']] # Check the potentially selected profiles preperations to get early checks if some additional questions are needed. -print(archinstall.arguments['profile']) -if archinstall.arguments['profile']: - if not archinstall.arguments['profile']._prep_function(): - archinstall.log( - ' * Profile\'s preparation requirements was not fulfilled.', - bg='black', - fg='red' - ) - exit(1) +if archinstall.arguments['profile'] and archinstall.arguments['profile'].has_prep_function(): + with archinstall.arguments['profile'].load_instructions(namespace=f"{archinstall.arguments['profile'].namespace}.py") as imported: + if not imported._prep_function(): + archinstall.log( + ' * Profile\'s preparation requirements was not fulfilled.', + bg='black', + fg='red' + ) + exit(1) # Additional packages (with some light weight error handling for invalid package names) if not archinstall.arguments.get('packages', None): -- cgit v1.2.3-70-g09d2 From a6bfe54951b09afd73dd61340107bbe5d5747f7f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 14:22:26 +0100 Subject: Variable mistake --- archinstall/lib/profiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 7b0e78e4..1487c277 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -169,7 +169,7 @@ class Profile(Script): # trigger a traditional: # if __name__ == 'moduleName' if '__name__' in source_data and '_prep_function' in source_data: - with profile.load_instructions(namespace=f"{selected_profile}.py") as imported: + with profile.load_instructions(namespace=f"{self.namespace}.py") as imported: if hasattr(imported, '_prep_function'): return True return False -- cgit v1.2.3-70-g09d2 From 196b8884324c2646b7e4b06cf3c711df8582e651 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 14:22:53 +0100 Subject: Variable mistake --- archinstall/lib/profiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 1487c277..01c3288c 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -169,7 +169,7 @@ class Profile(Script): # trigger a traditional: # if __name__ == 'moduleName' if '__name__' in source_data and '_prep_function' in source_data: - with profile.load_instructions(namespace=f"{self.namespace}.py") as imported: + with self.load_instructions(namespace=f"{self.namespace}.py") as imported: if hasattr(imported, '_prep_function'): return True return False -- cgit v1.2.3-70-g09d2 From 20b343c99376f4132c41e6c3085c33248e7b15b6 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 14:24:48 +0100 Subject: Added some forgotten imports --- archinstall/lib/user_interaction.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 5941903d..0ca4a636 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -2,7 +2,9 @@ import getpass from .exceptions import * from .profiles import Profile from .locale_helpers import search_keyboard_layout -from .output import log +from .output import log, LOG_LEVELS +from .storage import storage +from .networking import list_interfaces ## TODO: Some inconsistencies between the selection processes. ## Some return the keys from the options, some the values? @@ -52,21 +54,21 @@ def ask_to_configure_network(): # Optionally configure one network interface. #while 1: # {MAC: Ifname} - interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation', **archinstall.list_interfaces()} - archinstall.storage['_guided']['network'] = None + interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation', **list_interfaces()} + storage['_guided']['network'] = None - nic = archinstall.generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") + nic = generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") if nic and nic != 'Copy ISO network configuration to installation': - mode = archinstall.generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") + mode = generic_select(['DHCP (auto detect)', 'IP (static)'], f"Select which mode to configure for {nic}: ") if mode == 'IP (static)': while 1: ip = input(f"Enter the IP and subnet for {nic} (example: 192.168.0.5/24): ").strip() if ip: break else: - ArchInstall.log( + log( "You need to enter a valid IP in IP-config mode.", - level=archinstall.LOG_LEVELS.Warning, + level=LOG_LEVELS.Warning, bg='black', fg='red' ) -- cgit v1.2.3-70-g09d2 From ad8389ccaf403f18f1ed35b51c5f03bc3f86166a Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 14:29:13 +0100 Subject: Removed redundant variable --- archinstall/lib/user_interaction.py | 1 - 1 file changed, 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 0ca4a636..6a55df9c 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -55,7 +55,6 @@ def ask_to_configure_network(): #while 1: # {MAC: Ifname} interfaces = {'ISO-CONFIG' : 'Copy ISO network configuration to installation', **list_interfaces()} - storage['_guided']['network'] = None nic = generic_select(interfaces.values(), "Select one network interface to configure (leave blank to skip): ") if nic and nic != 'Copy ISO network configuration to installation': -- cgit v1.2.3-70-g09d2 From a9ce3e539028b2484991d21528a09cc3f41210de Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 14:54:45 +0100 Subject: Testing auto-filter in the JSON encoder based on ! points markering sensitive data. --- archinstall/lib/general.py | 5 ++++- examples/guided.py | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index dc94b063..97ad1565 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -45,7 +45,10 @@ class JSON_Encoder: else: val = JSON_Encoder._encode(val) del(obj[key]) - obj[JSON_Encoder._encode(key)] = val + if type(key) == str and key[0] == '!': + obj[JSON_Encoder._encode(key)] = '******' + else: + obj[JSON_Encoder._encode(key)] = val return obj elif hasattr(obj, 'json'): return obj.json() diff --git a/examples/guided.py b/examples/guided.py index 5fdc318b..cf7c3ef3 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -150,9 +150,9 @@ if archinstall.arguments['harddrive'].has_partitions(): archinstall.arguments['harddrive'].keep_partitions = False # Get disk encryption password (or skip if blank) -if not archinstall.arguments.get('encryption-password', None): - archinstall.arguments['encryption-password'] = archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): ') -archinstall.arguments['harddrive'].encryption_password = archinstall.arguments['encryption-password'] +if not archinstall.arguments.get('!encryption-password', None): + archinstall.arguments['!encryption-password'] = archinstall.get_password(prompt='Enter disk encryption password (leave blank for no encryption): ') +archinstall.arguments['harddrive'].encryption_password = archinstall.arguments['!encryption-password'] # Get the hostname for the machine if not archinstall.arguments.get('hostname', None): -- cgit v1.2.3-70-g09d2 From 8da8608e220a62c993f7bdf49c2c3d7c9b4a43aa Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:42:43 +0100 Subject: Added a small menu instead of a one-liner to select what to do with the disk if it has partitions. --- archinstall/lib/user_interaction.py | 8 +++++ examples/guided.py | 59 +++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 22 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 6a55df9c..e20e98b1 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -87,6 +87,14 @@ def ask_to_configure_network(): return None +def ask_for_disk_layout(): + options = { + 'keep-existing' : 'Keep existing partition layout and select which ones to use where.', + 'format-all' : 'Format entire drive and setup a basic partition scheme.' + } + + return generic_select(options.values(), "Found partitions on the selected drive, (select by number) what do you want to do: ") + def generic_select(options, input_text="Select one of the above by index or absolute value: ", sort=True): """ A generic select function that does not output anything diff --git a/examples/guided.py b/examples/guided.py index bccedb0a..27c005d6 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -101,6 +101,9 @@ else: # 2. If so, ask if we should keep them or wipe everything if archinstall.arguments['harddrive'].has_partitions(): archinstall.log(f" ! {archinstall.arguments['harddrive']} contains existing partitions", fg='red') + + # We curate a list pf supported paritions + # and print those that we don't support. partition_mountpoints = {} for partition in archinstall.arguments['harddrive']: try: @@ -109,44 +112,56 @@ if archinstall.arguments['harddrive'].has_partitions(): partition_mountpoints[partition] = None except archinstall.UnknownFilesystemFormat as err: archinstall.log(f" {partition} (Filesystem not supported)", fg='red') - #archinstall.log(f"Current filesystem is not supported: {err}", fg='red') - #input(f"Do you wish to erase all data? (y/n):") - if (option := input('Do you wish to keep one/more existing partitions or format entire drive? (k/f): ')).lower() in ('k', 'keep'): + # We then ask what to do with the paritions. + if (option := archinstall.ask_for_disk_layout()) == 'keep-existing': archinstall.arguments['harddrive'].keep_partitions = True - archinstall.log(f" ** You will now select where (inside the installation) to mount partitions. **") - archinstall.log(f" ** The root would be a simple / and the boot partition /boot as it's relative paths. **") + archinstall.log(f" ** You will now select which partitions to use by selecting mount points (inside the installation). **") + archinstall.log(f" ** The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation). **") while True: - partition = archinstall.generic_select(partition_mountpoints.keys(), "Select a partition to assign mount-point to (leave blank when done): ") + # Select a partition + partition = archinstall.generic_select(partition_mountpoints.keys(), + "Select a partition by number that you want to set a mount-point for (leave blank when done): ") if not partition: break + # Select a mount-point mountpoint = input(f"Enter a mount-point for {partition}: ").strip(' ') + if len(mountpoint): - while 1: - new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') - if len(new_filesystem) <= 0: + # Get a valid & supported filesystem for the parition: + while 1: + new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') + if len(new_filesystem) <= 0: + break + + # Since the potentially new filesystem is new + # we have to check if we support it. We can do this by formatting /dev/null with the partitions filesystem. + # There's a nice wrapper for this on the partition object itself that supports a path-override during .format() + try: + partition.format(new_filesystem, path='/dev/null', log_formating=False, allow_formatting=True) + except archinstall.UnknownFilesystemFormat: + archinstall.log(f"Selected filesystem is not supported yet. If you want archinstall to support '{new_filesystem}', please create a issue-ticket suggesting it on github at https://github.com/Torxed/archinstall/issues.") + archinstall.log(f"Until then, please enter another supported filesystem.") + continue + except archinstall.SysCallError: + pass # Expected exception since mkfs. can not format /dev/null. + # But that means our .format() function supported it. break - try: - partition.format(new_filesystem, path='/dev/null', log_formating=False, allow_formatting=True) - except archinstall.UnknownFilesystemFormat: - archinstall.log(f"Selected filesystem is not supported yet, if you wish archinstall should support '{new_filesystem}' please create a issue-ticket suggesting it on github at https://github.com/Torxed/archinstall/issues.") - archinstall.log(f"Until then, please enter another supported filesystem.") - continue - except archinstall.SysCallError: - pass # Supported, but mkfs could not format /dev/null which is the whole point of /dev/null in path :) - break - - if len(mountpoint): + # When we've selected all three criterias, + # We can safely mark the partition for formatting and where to mount it. + # TODO: allow_formatting might be redundant since target_mountpoint should only be + # set if we actually want to format it anyway. partition.allow_formatting = True partition.target_mountpoint = mountpoint + # Only overwrite the filesystem definition if we selected one: if len(new_filesystem): partition.filesystem = new_filesystem archinstall.log('Using existing partition table reported above.') - else: + elif option == 'format-all': archinstall.arguments['harddrive'].keep_partitions = False # Get disk encryption password (or skip if blank) @@ -217,7 +232,6 @@ archinstall.log(json.dumps(archinstall.arguments, indent=4, sort_keys=True, cls= print() input('Press Enter to continue.') -exit(0) """ Issue a final warning before we continue with something un-revertable. @@ -249,6 +263,7 @@ for i in range(5, 0, -1): print() signal.signal(signal.SIGINT, original_sigint_handler) +exit(0) """ Setup the blockdevice, filesystem (and optionally encryption). Once that's done, we'll hand over to perform_installation() -- cgit v1.2.3-70-g09d2 From 775a26f738002ad124200716b68f92ebc9e91a5c Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:47:24 +0100 Subject: Added a abort message --- archinstall/lib/user_interaction.py | 5 +++-- examples/guided.py | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index e20e98b1..01e3372c 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -90,10 +90,11 @@ def ask_to_configure_network(): def ask_for_disk_layout(): options = { 'keep-existing' : 'Keep existing partition layout and select which ones to use where.', - 'format-all' : 'Format entire drive and setup a basic partition scheme.' + 'format-all' : 'Format entire drive and setup a basic partition scheme.', + 'abort' : 'abort' } - return generic_select(options.values(), "Found partitions on the selected drive, (select by number) what do you want to do: ") + return generic_select(options.values(), "Found partitions on the selected drive, (select by number) what you want to do: ") def generic_select(options, input_text="Select one of the above by index or absolute value: ", sort=True): """ diff --git a/examples/guided.py b/examples/guided.py index 2b49d88a..0077b505 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -114,7 +114,10 @@ if archinstall.arguments['harddrive'].has_partitions(): archinstall.log(f" {partition} (Filesystem not supported)", fg='red') # We then ask what to do with the paritions. - if (option := archinstall.ask_for_disk_layout()) == 'keep-existing': + if (option := archinstall.ask_for_disk_layout()) == 'abort': + archinstall.log(f"Safely aborting the installation. No changes to the disk or system has been made.") + exit(1) + elif option == 'keep-existing': archinstall.arguments['harddrive'].keep_partitions = True archinstall.log(f" ** You will now select which partitions to use by selecting mount points (inside the installation). **") -- cgit v1.2.3-70-g09d2 From 94daa8b98b8dba328e45b11ba51b25963c5dcf76 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:47:41 +0100 Subject: Added a abort message --- archinstall/lib/user_interaction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 01e3372c..2c8c30f8 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -91,7 +91,7 @@ def ask_for_disk_layout(): options = { 'keep-existing' : 'Keep existing partition layout and select which ones to use where.', 'format-all' : 'Format entire drive and setup a basic partition scheme.', - 'abort' : 'abort' + 'abort' : 'Abort the installation.' } return generic_select(options.values(), "Found partitions on the selected drive, (select by number) what you want to do: ") -- cgit v1.2.3-70-g09d2 From 476006abe8060235299fd3bddbfe69e597f7f988 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:51:18 +0100 Subject: Fixed expected return value from ask_for_disk_layout(). I think I have to throw an eye on generic_select() and it's expected return value in general.. But that's later. --- archinstall/lib/user_interaction.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 2c8c30f8..5861fff3 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -94,7 +94,8 @@ def ask_for_disk_layout(): 'abort' : 'Abort the installation.' } - return generic_select(options.values(), "Found partitions on the selected drive, (select by number) what you want to do: ") + value = generic_select(options.values(), "Found partitions on the selected drive, (select by number) what you want to do: ") + return next((key for key, val in options.items() if val == value), None) def generic_select(options, input_text="Select one of the above by index or absolute value: ", sort=True): """ -- cgit v1.2.3-70-g09d2 From 1d913f50ed630c7a1a2985e6ed8b9f4aa0bc08dd Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:55:21 +0100 Subject: Added some debugging. --- archinstall/lib/disk.py | 15 ++++++++------- examples/guided.py | 5 +++-- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index d76c6d7e..e77f2cd1 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -272,13 +272,14 @@ class Filesystem(): self.mode = mode def __enter__(self, *args, **kwargs): - if self.mode == GPT: - if sys_command(f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt',).exit_code == 0: - return self - else: - raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt') - else: - raise DiskError(f'Unknown mode selected to format in: {self.mode}') + #if self.mode == GPT: + # if sys_command(f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt',).exit_code == 0: + # return self + # else: + # raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt') + #else: + # raise DiskError(f'Unknown mode selected to format in: {self.mode}') + print('Keep partitions:', self.blockdevice.keep_partitions) def __repr__(self): return f"Filesystem(blockdevice={self.blockdevice}, mode={self.mode})" diff --git a/examples/guided.py b/examples/guided.py index 0077b505..fbe6ea47 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -266,12 +266,13 @@ for i in range(5, 0, -1): print() signal.signal(signal.SIGINT, original_sigint_handler) -exit(0) """ Setup the blockdevice, filesystem (and optionally encryption). Once that's done, we'll hand over to perform_installation() """ -with archinstall.Filesystem(harddrive, archinstall.GPT) as fs: +with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: + print('Debug') + exit(0) # Use partitioning helper to set up the disk partitions. if disk_password: fs.use_entire_disk('luks2') -- cgit v1.2.3-70-g09d2 From 9fe4b7b5c79064e67949bc690c9c9563839d56f9 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:56:18 +0100 Subject: Added some debugging. --- archinstall/lib/disk.py | 1 + 1 file changed, 1 insertion(+) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index e77f2cd1..70d2c29f 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -279,6 +279,7 @@ class Filesystem(): # raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt') #else: # raise DiskError(f'Unknown mode selected to format in: {self.mode}') + print(self.blockdevice) print('Keep partitions:', self.blockdevice.keep_partitions) def __repr__(self): -- cgit v1.2.3-70-g09d2 From 75eb42be5111697b325a5ca5d400d49dc3e30c45 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:57:17 +0100 Subject: Added some debugging. --- archinstall/lib/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 70d2c29f..f01300b3 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -279,7 +279,7 @@ class Filesystem(): # raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt') #else: # raise DiskError(f'Unknown mode selected to format in: {self.mode}') - print(self.blockdevice) + print(type(self.blockdevice)) print('Keep partitions:', self.blockdevice.keep_partitions) def __repr__(self): -- cgit v1.2.3-70-g09d2 From c5694393c6a9d53cbc7a2886e733b354d5055772 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 15:10:58 +0100 Subject: Fixed the JSON_Encoder. The issue was that dictionaries are mutable, and dumping dictionaries and replacing keys also replaces the original value. --- archinstall/lib/general.py | 9 +++++---- examples/guided.py | 3 --- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/general.py b/archinstall/lib/general.py index 97ad1565..e87e4102 100644 --- a/archinstall/lib/general.py +++ b/archinstall/lib/general.py @@ -37,6 +37,7 @@ class JSON_Encoder: ## We'll need to iterate not just the value that default() usually gets passed ## But also iterate manually over each key: value pair in order to trap the keys. + copy = {} for key, val in list(obj.items()): if isinstance(val, dict): val = json.loads(json.dumps(val, cls=JSON)) # This, is a EXTREMELY ugly hack.. @@ -44,12 +45,12 @@ class JSON_Encoder: # trigger a encoding of sub-dictionaries. else: val = JSON_Encoder._encode(val) - del(obj[key]) + if type(key) == str and key[0] == '!': - obj[JSON_Encoder._encode(key)] = '******' + copy[JSON_Encoder._encode(key)] = '******' else: - obj[JSON_Encoder._encode(key)] = val - return obj + copy[JSON_Encoder._encode(key)] = val + return copy elif hasattr(obj, 'json'): return obj.json() elif hasattr(obj, '__dump__'): diff --git a/examples/guided.py b/examples/guided.py index 264ff44e..fbe6ea47 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -228,15 +228,12 @@ except archinstall.RequirementError as e: if not archinstall.arguments.get('nic', None): archinstall.arguments['nic'] = archinstall.ask_to_configure_network() -print(type(archinstall.arguments['harddrive']), archinstall.arguments['harddrive']) - print() print('This is your chosen configuration:') archinstall.log("-- Guided template chosen (with below config) --", level=archinstall.LOG_LEVELS.Debug) archinstall.log(json.dumps(archinstall.arguments, indent=4, sort_keys=True, cls=archinstall.JSON), level=archinstall.LOG_LEVELS.Info) print() -print(type(archinstall.arguments['harddrive']), archinstall.arguments['harddrive']) input('Press Enter to continue.') """ -- cgit v1.2.3-70-g09d2 From 1ef63147d0eeb002dcc9475f2fcec3abddc1298d Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 15:54:23 +0100 Subject: Tweaked logging slightly. --- archinstall/lib/disk.py | 29 ++++++++++++++++++++--------- archinstall/lib/output.py | 11 +++++++---- examples/guided.py | 2 -- 3 files changed, 27 insertions(+), 15 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index f01300b3..a0fcfddf 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -7,6 +7,7 @@ from .storage import storage ROOT_DIR_PATTERN = re.compile('^.*?/devices') GPT = 0b00000001 +MBR = 0b00000010 #import ctypes #import ctypes.util @@ -113,6 +114,10 @@ class BlockDevice(): all_partitions = self.partitions return [all_partitions[k] for k in all_partitions] + @property + def partition_table_type(self): + return GPT + def has_partitions(self): return len(self.partitions) @@ -272,15 +277,21 @@ class Filesystem(): self.mode = mode def __enter__(self, *args, **kwargs): - #if self.mode == GPT: - # if sys_command(f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt',).exit_code == 0: - # return self - # else: - # raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt') - #else: - # raise DiskError(f'Unknown mode selected to format in: {self.mode}') - print(type(self.blockdevice)) - print('Keep partitions:', self.blockdevice.keep_partitions) + if self.blockdevice.keep_partitions is False: + log(f'Wiping {self.blockdevice} by using partition format {self.mode}', level=LOG_LEVELS.Debug) + if self.mode == GPT: + if sys_command(f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt',).exit_code == 0: + return self + else: + raise DiskError(f'Problem setting the partition format to GPT:', f'/usr/bin/parted -s {self.blockdevice.device} mklabel gpt') + else: + raise DiskError(f'Unknown mode selected to format in: {self.mode}') + + # TODO: partition_table_type is hardcoded to GPT at the moment. This has to be changed. + elif self.mode == self.blockdevice.partition_table_type: + log(f'Kept partition format {self.mode} for {self.blockdevice}', level=LOG_LEVELS.Debug) + else: + raise DiskError(f'The selected partition table format {self.mode} does not match that of {self.blockdevice}.') def __repr__(self): return f"Filesystem(blockdevice={self.blockdevice}, mode={self.mode})" diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index 956ad0c4..0e0a295b 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -5,6 +5,9 @@ import logging from pathlib import Path from .storage import storage +# TODO: use logging's built in levels instead. +# Altough logging is threaded and I wish to avoid that. +# It's more Pythonistic or w/e you want to call it. class LOG_LEVELS: Critical = 0b001 Error = 0b010 @@ -108,10 +111,10 @@ def log(*args, **kwargs): # In that case, we'll drop it. return None - try: - journald.log(string, level=kwargs['level']) - except ModuleNotFoundError: - pass # Ignore writing to journald + try: + journald.log(string, level=kwargs.get('level', LOG_LEVELS.Info)) + except ModuleNotFoundError: + pass # Ignore writing to journald # Finally, print the log unless we skipped it based on level. # We use sys.stdout.write()+flush() instead of print() to try and diff --git a/examples/guided.py b/examples/guided.py index fbe6ea47..15f9ba1c 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -271,8 +271,6 @@ signal.signal(signal.SIGINT, original_sigint_handler) Once that's done, we'll hand over to perform_installation() """ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: - print('Debug') - exit(0) # Use partitioning helper to set up the disk partitions. if disk_password: fs.use_entire_disk('luks2') -- cgit v1.2.3-70-g09d2 From 0b3879ac58d2896ad01270f835fc2819817c6fc1 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 16:18:56 +0100 Subject: Removing part of the old formatting scheme. New implementation roughly 80% done. --- archinstall/lib/disk.py | 4 +++- examples/guided.py | 22 ++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index a0fcfddf..2be26585 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -173,11 +173,13 @@ class Partition(): else: return f'Partition(path={self.path}, fs={self.filesystem}{mount_repr})' - def format(self, filesystem, path=None, allow_formatting=None, log_formating=True): + def format(self, filesystem=None, path=None, allow_formatting=None, log_formating=True): """ Format can be given an overriding path, for instance /dev/null to test the formating functionality and in essence the support for the given filesystem. """ + if filesystem is None: + filesystem = self.filesystem if path is None: path = self.path if allow_formatting is None: diff --git a/examples/guided.py b/examples/guided.py index e9ceae19..7aec0611 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -271,19 +271,17 @@ signal.signal(signal.SIGINT, original_sigint_handler) Once that's done, we'll hand over to perform_installation() """ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: - for partition in archinstall.arguments['harddrive']: - print(partition) - exit(0) - # Use partitioning helper to set up the disk partitions. - if disk_password: - fs.use_entire_disk('luks2') + if archinstall.arguments['harddrive'].keep_partitions is False: + if disk_password: + fs.use_entire_disk('luks2') + else: + fs.use_entire_disk('ext4') else: - fs.use_entire_disk('ext4') - - if harddrive.partition[1].size == '512M': - raise OSError('Trying to encrypt the boot partition for petes sake..') - harddrive.partition[0].format('vfat') - + for partition in archinstall.arguments['harddrive']: + if partition.allow_formatting: + partition.format() + + exit(0) if disk_password: # First encrypt and unlock, then format the desired partition inside the encrypted part. # archinstall.luks2() encrypts the partition when entering the with context manager, and -- cgit v1.2.3-70-g09d2 From 6306de4bfee2d44ab1f362078a47d6d9a05835ef Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 16:52:06 +0100 Subject: Reworked the guided partitioning logic to better match new expectations of flexability. Still some work to be done and features to be implemented, but the structure is taking place --- archinstall/lib/disk.py | 8 +++++++- archinstall/lib/luks.py | 28 +++++++++++++++++++++++----- archinstall/lib/user_interaction.py | 12 ++++++++++++ examples/guided.py | 16 +++++++++------- 4 files changed, 51 insertions(+), 13 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 2be26585..2f3d8233 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -196,28 +196,34 @@ class Partition(): if b'UUID' not in o: raise DiskError(f'Could not format {path} with {filesystem} because: {o}') self.filesystem = 'btrfs' + elif filesystem == 'vfat': o = b''.join(sys_command(f'/usr/bin/mkfs.vfat -F32 {path}')) if (b'mkfs.fat' not in o and b'mkfs.vfat' not in o) or b'command not found' in o: raise DiskError(f'Could not format {path} with {filesystem} because: {o}') self.filesystem = 'vfat' + elif filesystem == 'ext4': if (handle := sys_command(f'/usr/bin/mkfs.ext4 -F {path}')).exit_code != 0: raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'ext4' + elif filesystem == 'xfs': if (handle := sys_command(f'/usr/bin/mkfs.xfs -f {path}')).exit_code != 0: raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'xfs' + elif filesystem == 'f2fs': if (handle := sys_command(f'/usr/bin/mkfs.f2fs -f {path}')).exit_code != 0: raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'f2fs' + elif filesystem == 'crypto_LUKS': from .luks import luks2 encrypted_partition = luks2(self, None, None) encrypted_partition.format(path) self.filesystem = 'crypto_LUKS' + else: raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.") return True @@ -327,7 +333,7 @@ class Filesystem(): if prep_mode == 'luks2': self.add_partition('primary', start='513MiB', end='100%') else: - self.add_partition('primary', start='513MiB', end='100%', format='ext4') + self.add_partition('primary', start='513MiB', end='100%', format=prep_mode) def add_partition(self, type, start, end, format=None): log(f'Adding partition to {self.blockdevice}', level=LOG_LEVELS.Info) diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index d62c2d4b..b98994ef 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -6,17 +6,28 @@ from .output import log, LOG_LEVELS from .storage import storage class luks2(): - def __init__(self, partition, mountpoint, password, *args, **kwargs): + def __init__(self, partition, mountpoint, password, key_file=None, *args, **kwargs): self.password = password self.partition = partition self.mountpoint = mountpoint self.args = args self.kwargs = kwargs + self.key_file = key_file self.filesystem = 'crypto_LUKS' def __enter__(self): - key_file = self.encrypt(self.partition, self.password, *self.args, **self.kwargs) - return self.unlock(self.partition, self.mountpoint, key_file) + if self.partition.allow_formatting: + self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs) + else: + if not self.key_file: + self.key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique? + + if type(self.password) != bytes: self.password = bytes(self.password, 'UTF-8') + + with open(self.key_file, 'wb') as fh: + fh.write(self.password) + + return self.unlock(self.partition, self.mountpoint, self.key_file) def __exit__(self, *args, **kwargs): # TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager @@ -24,13 +35,20 @@ class luks2(): raise args[1] return True - def encrypt(self, partition, password, key_size=512, hash_type='sha512', iter_time=10000, key_file=None): + def encrypt(self, partition, password=None, key_size=512, hash_type='sha512', iter_time=10000, key_file=None): # TODO: We should be able to integrate this into the main log some how. # Perhaps post-mortem? log(f'Encrypting {partition} (This might take a while)', level=LOG_LEVELS.Info) if not key_file: - key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique? + if self.key_file: + key_file = self.key_file + else: + key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique? + + if not password: + password = self.password + if type(password) != bytes: password = bytes(password, 'UTF-8') with open(key_file, 'wb') as fh: diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index 5861fff3..7e7f5873 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -97,6 +97,18 @@ def ask_for_disk_layout(): value = generic_select(options.values(), "Found partitions on the selected drive, (select by number) what you want to do: ") return next((key for key, val in options.items() if val == value), None) +def ask_for_main_filesystem_format(): + options = { + 'btrfs' : 'btrfs', + 'ext4' : 'ext4', + 'xfs' : 'xfs', + 'f2fs' : 'f2fs', + 'vfat' : 'vfat' + } + + value = generic_select(options.values(), "Select your main partitions filesystem by number or free-text: ") + return next((key for key, val in options.items() if val == value), None) + def generic_select(options, input_text="Select one of the above by index or absolute value: ", sort=True): """ A generic select function that does not output anything diff --git a/examples/guided.py b/examples/guided.py index 7aec0611..b289016b 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -165,6 +165,7 @@ if archinstall.arguments['harddrive'].has_partitions(): archinstall.log('Using existing partition table reported above.') elif option == 'format-all': + archinstall.arguments['filesystem'] = archinstall.ask_for_main_filesystem_format() archinstall.arguments['harddrive'].keep_partitions = False # Get disk encryption password (or skip if blank) @@ -272,22 +273,23 @@ signal.signal(signal.SIGINT, original_sigint_handler) """ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: if archinstall.arguments['harddrive'].keep_partitions is False: - if disk_password: + if archinstall.arguments.get('!encryption-password', None): + # Set a temporary partition format to indicate that the partitions is encrypted. + # Later on, we'll mount it and put an actual filesystem inside this encrypted container. fs.use_entire_disk('luks2') else: - fs.use_entire_disk('ext4') + fs.use_entire_disk(archinstall.arguments.get('filesystem', 'ext4')) else: for partition in archinstall.arguments['harddrive']: if partition.allow_formatting: partition.format() - - exit(0) - if disk_password: + + if archinstall.arguments.get('!encryption-password', None): # First encrypt and unlock, then format the desired partition inside the encrypted part. # archinstall.luks2() encrypts the partition when entering the with context manager, and # unlocks the drive so that it can be used as a normal block-device within archinstall. - with archinstall.luks2(harddrive.partition[1], 'luksloop', disk_password) as unlocked_device: - unlocked_device.format('btrfs') + with archinstall.luks2(harddrive.partition[1], 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_device: + unlocked_device.format(archinstall.arguments.get('filesystem', 'btrfs')) perform_installation(unlocked_device, harddrive.partition[0], -- cgit v1.2.3-70-g09d2 From fb55e318e5dc87d05da4c636722d24ab9e9cb5b1 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 17:13:21 +0100 Subject: Added two new functions. partition.safe_to_format() and partition.has_content(). The first does some sanity checks to verify if we can format the partition or not. The second temporarly mounts the parition and checks if there's content inside and returns accordingly. --- archinstall/lib/disk.py | 20 ++++++++++++++++++-- examples/guided.py | 4 +++- 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 2f3d8233..16d6f704 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -1,4 +1,4 @@ -import glob, re, os, json, time # Time is only used to gracefully wait for new paritions to come online +import glob, re, os, json, time, hashlib from collections import OrderedDict from .exceptions import DiskError from .general import * @@ -173,6 +173,22 @@ class Partition(): else: return f'Partition(path={self.path}, fs={self.filesystem}{mount_repr})' + def has_content(self): + temporary_mountpoint = '/tmp/'+hashlib.md5(bytes(f"{time.time()}", 'UTF-8')+os.urandom(12)).hexdigest() + if (handle := sys_command(f'/usr/bin/mount {self.path} {temporary_mountpoint}')).exit_code != 0: + raise DiskError(f'Could not mount and check for content on {self.path} because: {b"".join(handle)}') + + files = len(glob.glob(f"{temporary_mountpoint}/*")) + sys_command(f'/usr/bin/umount {temporary_mountpoint}') + + return True if files > 0 else False + + def safe_to_format(self): + if self.target_mountpoint == '/boot' and self.has_content(): + return False + + return True + def format(self, filesystem=None, path=None, allow_formatting=None, log_formating=True): """ Format can be given an overriding path, for instance /dev/null to test @@ -223,7 +239,7 @@ class Partition(): encrypted_partition = luks2(self, None, None) encrypted_partition.format(path) self.filesystem = 'crypto_LUKS' - + else: raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.") return True diff --git a/examples/guided.py b/examples/guided.py index b289016b..fc1fe88d 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -281,8 +281,10 @@ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) fs.use_entire_disk(archinstall.arguments.get('filesystem', 'ext4')) else: for partition in archinstall.arguments['harddrive']: - if partition.allow_formatting: + if partition.allow_formatting and partition.safe_to_format(): partition.format() + else: + archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False", level=archinstall.LOG_LEVELS.Debug) if archinstall.arguments.get('!encryption-password', None): # First encrypt and unlock, then format the desired partition inside the encrypted part. -- cgit v1.2.3-70-g09d2 From 8bf3296749ebfddc5dfdcbb116547395438d371f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 17:14:21 +0100 Subject: Optimization, safe_to_format() now checks partition.allow_formatting as a condition. --- archinstall/lib/disk.py | 4 +++- examples/guided.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 16d6f704..56c75767 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -184,7 +184,9 @@ class Partition(): return True if files > 0 else False def safe_to_format(self): - if self.target_mountpoint == '/boot' and self.has_content(): + if self.allow_formatting is False: + return False + elif self.target_mountpoint == '/boot' and self.has_content(): return False return True diff --git a/examples/guided.py b/examples/guided.py index fc1fe88d..fbdba776 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -281,7 +281,7 @@ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) fs.use_entire_disk(archinstall.arguments.get('filesystem', 'ext4')) else: for partition in archinstall.arguments['harddrive']: - if partition.allow_formatting and partition.safe_to_format(): + if partition.safe_to_format(): partition.format() else: archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False", level=archinstall.LOG_LEVELS.Debug) -- cgit v1.2.3-70-g09d2 From 0306209f3a494b00bab6b89b07e8c009b4b3c581 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 17:17:55 +0100 Subject: Fixed 'mount point does not exist' on temporary mount point. --- archinstall/lib/disk.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 56c75767..01a736a3 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -1,4 +1,5 @@ import glob, re, os, json, time, hashlib +import pathlib from collections import OrderedDict from .exceptions import DiskError from .general import * @@ -175,12 +176,17 @@ class Partition(): def has_content(self): temporary_mountpoint = '/tmp/'+hashlib.md5(bytes(f"{time.time()}", 'UTF-8')+os.urandom(12)).hexdigest() + temporary_path = pathlib.Path(temporary_mountpoint) + + temporary_path.mkdir(parents=True, exist_ok=True) if (handle := sys_command(f'/usr/bin/mount {self.path} {temporary_mountpoint}')).exit_code != 0: raise DiskError(f'Could not mount and check for content on {self.path} because: {b"".join(handle)}') files = len(glob.glob(f"{temporary_mountpoint}/*")) sys_command(f'/usr/bin/umount {temporary_mountpoint}') + temporary_path.rmdir() + return True if files > 0 else False def safe_to_format(self): -- cgit v1.2.3-70-g09d2 From 7ee48156486101a43e90f834825dfeb0742247bd Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 00:12:03 +0100 Subject: Adding encryption helpers to the Partition() class, that sets up and utilizes luks2.encrypt() in extension. --- archinstall/lib/disk.py | 36 ++++++++++++++++++++++++++++++------ archinstall/lib/luks.py | 25 +++++++++++++++---------- examples/guided.py | 24 +++++++++++++----------- 3 files changed, 58 insertions(+), 27 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 01a736a3..3397d7cb 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -197,6 +197,21 @@ class Partition(): return True + def encrypt(self, *args, **kwargs): + """ + A wrapper function for luks2() instances and the .encrypt() method of that instance. + """ + from .luks import luks2 + + if not self.encrypted: + raise DiskError(f"Attempting to encrypt a partition that was not marked for encryption: {self}") + + if not self.safe_to_format(): + return False + + handle = luks2(self, None, None) + return handle.encrypt(self, *args, **kwargs) + def format(self, filesystem=None, path=None, allow_formatting=None, log_formating=True): """ Format can be given an overriding path, for instance /dev/null to test @@ -204,6 +219,7 @@ class Partition(): """ if filesystem is None: filesystem = self.filesystem + if path is None: path = self.path if allow_formatting is None: @@ -349,15 +365,23 @@ class Filesystem(): """ return self.raw_parted(string).exit_code - def use_entire_disk(self, prep_mode=None): + def use_entire_disk(self, root_filesystem_type='ext4', encrypt_root_partition=True): self.add_partition('primary', start='1MiB', end='513MiB', format='vfat') self.set_name(0, 'EFI') self.set(0, 'boot on') - self.set(0, 'esp on') # TODO: Redundant, as in GPT mode it's an alias for "boot on"? https://www.gnu.org/software/parted/manual/html_node/set.html - if prep_mode == 'luks2': - self.add_partition('primary', start='513MiB', end='100%') - else: - self.add_partition('primary', start='513MiB', end='100%', format=prep_mode) + # TODO: Probably redundant because in GPT mode 'esp on' is an alias for "boot on"? + # https://www.gnu.org/software/parted/manual/html_node/set.html + self.set(0, 'esp on') + self.add_partition('primary', start='513MiB', end='100%') + + self.blockdevice.partition[0].filesystem = 'vfat' + self.blockdevice.partition[1].filesystem = root_filesystem_type + + self.blockdevice.partition[0].target_mountpoint = '/boot' + self.blockdevice.partition[1].target_mountpoint = '/' + + if encrypt_root_partition: + self.blockdevice.partition[1].encrypted = True def add_partition(self, type, start, end, format=None): log(f'Adding partition to {self.blockdevice}', level=LOG_LEVELS.Info) diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index b98994ef..c9946239 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -16,16 +16,17 @@ class luks2(): self.filesystem = 'crypto_LUKS' def __enter__(self): - if self.partition.allow_formatting: - self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs) - else: - if not self.key_file: - self.key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique? - - if type(self.password) != bytes: self.password = bytes(self.password, 'UTF-8') + #if self.partition.allow_formatting: + # self.key_file = self.encrypt(self.partition, *self.args, **self.kwargs) + #else: + if not self.key_file: + self.key_file = f"/tmp/{os.path.basename(self.partition.path)}.disk_pw" # TODO: Make disk-pw-file randomly unique? + + if type(self.password) != bytes: + self.password = bytes(self.password, 'UTF-8') - with open(self.key_file, 'wb') as fh: - fh.write(self.password) + with open(self.key_file, 'wb') as fh: + fh.write(self.password) return self.unlock(self.partition, self.mountpoint, self.key_file) @@ -38,6 +39,9 @@ class luks2(): def encrypt(self, partition, password=None, key_size=512, hash_type='sha512', iter_time=10000, key_file=None): # TODO: We should be able to integrate this into the main log some how. # Perhaps post-mortem? + if not self.partition.allow_formatting: + raise DiskError(f'Could not encrypt volume {self.partition} due to it having a formatting lock.') + log(f'Encrypting {partition} (This might take a while)', level=LOG_LEVELS.Info) if not key_file: @@ -49,7 +53,8 @@ class luks2(): if not password: password = self.password - if type(password) != bytes: password = bytes(password, 'UTF-8') + if type(password) != bytes: + password = bytes(password, 'UTF-8') with open(key_file, 'wb') as fh: fh.write(password) diff --git a/examples/guided.py b/examples/guided.py index 91158f9a..13bf2414 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -272,19 +272,21 @@ signal.signal(signal.SIGINT, original_sigint_handler) Once that's done, we'll hand over to perform_installation() """ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) as fs: + # Wipe the entire drive if the disk flag `keep_partitions`is False. if archinstall.arguments['harddrive'].keep_partitions is False: - if archinstall.arguments.get('!encryption-password', None): - # Set a temporary partition format to indicate that the partitions is encrypted. - # Later on, we'll mount it and put an actual filesystem inside this encrypted container. - fs.use_entire_disk('luks2') - else: - fs.use_entire_disk(archinstall.arguments.get('filesystem', 'ext4')) - else: - for partition in archinstall.arguments['harddrive']: - if partition.safe_to_format(): - partition.format() + fs.use_entire_disk(root_filesystem_type=archinstall.arguments.get('filesystem', 'btrfs'), + encrypt_root_partition=archinstall.arguments.get('!encryption-password', False)) + + # After the disk is ready, iterate the partitions and check + # which ones are safe to format, and format those. + for partition in archinstall.arguments['harddrive']: + if partition.safe_to_format(): + if partition.encrypted: + partition.encrypt(password=archinstall.arguments.get('!encryption-password', None)) else: - archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False", level=archinstall.LOG_LEVELS.Debug) + partition.format() + else: + archinstall.log(f"Did not format {partition} because .safe_to_format() returned False or .allow_formatting was False.", level=archinstall.LOG_LEVELS.Debug) if archinstall.arguments.get('!encryption-password', None): # First encrypt and unlock, then format the desired partition inside the encrypted part. -- cgit v1.2.3-70-g09d2 From 16b0f4a4a48e6e0363db653a6ec1cedbb4741647 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 10:38:04 +0100 Subject: Fixed an issue where Partition() instances got overwritten every time disk.partitions were called. Causing flags such as .encrypted to be dropped. This should make for a more stable experience when working with the partitions. --- archinstall/lib/disk.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 3397d7cb..92982499 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -106,7 +106,8 @@ class BlockDevice(): part_id = part['name'][len(os.path.basename(self.path)):] if part_id not in self.part_cache: ## TODO: Force over-write even if in cache? - self.part_cache[part_id] = Partition(root_path + part_id, part_id=part_id, size=part['size']) + if part_id not in self.part_cache or self.part_cache[part_id].size != part['size']: + self.part_cache[part_id] = Partition(root_path + part_id, part_id=part_id, size=part['size']) return {k: self.part_cache[k] for k in sorted(self.part_cache)} -- cgit v1.2.3-70-g09d2 From 1f62a97c902bf0697e7502ec7f9e17c13147390b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 10:41:57 +0100 Subject: Marking the root partitions as encrypted if a disk password is set. In the future, we need to make this a bit more flexible by allowing multiple partitions to be encrypted. But for now, the main partition should be enough. --- archinstall/lib/disk.py | 5 +++++ examples/guided.py | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 92982499..7d4a34c6 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -352,6 +352,11 @@ class Filesystem(): b''.join(sys_command(f'sync')) return True + def find_root_partition(self): + for partition in self.blockdevice: + if partition.target_mountpoint == '/' or partition.mountpoint == '/': + return partition + def raw_parted(self, string:str): x = sys_command(f'/usr/bin/parted -s {string}') o = b''.join(x) diff --git a/examples/guided.py b/examples/guided.py index 13bf2414..ebdd3678 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -276,6 +276,10 @@ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) if archinstall.arguments['harddrive'].keep_partitions is False: fs.use_entire_disk(root_filesystem_type=archinstall.arguments.get('filesystem', 'btrfs'), encrypt_root_partition=archinstall.arguments.get('!encryption-password', False)) + # Otherwise, check if encryption is desired and mark the root partition as encrypted. + elif archinstall.arguments.get('!encryption-password', None): + root_partition = fs.find_root_partition() + root_partition.encrypted = True # After the disk is ready, iterate the partitions and check # which ones are safe to format, and format those. -- cgit v1.2.3-70-g09d2 From c97d5f12021a8ca8b1e90a750a6f4c95229c6509 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 10:45:45 +0100 Subject: Forgot to return self in Filesystem() --- archinstall/lib/disk.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 7d4a34c6..a8cba53b 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -342,6 +342,8 @@ class Filesystem(): else: raise DiskError(f'The selected partition table format {self.mode} does not match that of {self.blockdevice}.') + return self + def __repr__(self): return f"Filesystem(blockdevice={self.blockdevice}, mode={self.mode})" -- cgit v1.2.3-70-g09d2 From f230140ba99f7c7ddbe8e0f7a6c7f80572cbf2ce Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 10:50:05 +0100 Subject: Removed hardcoded partition numbers when acessing partitions. As the order is not fixed and more options to disk layouts have been added. --- archinstall/lib/disk.py | 4 ++-- examples/guided.py | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index a8cba53b..73d913d0 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -354,9 +354,9 @@ class Filesystem(): b''.join(sys_command(f'sync')) return True - def find_root_partition(self): + def find_partition(self, mountpoint): for partition in self.blockdevice: - if partition.target_mountpoint == '/' or partition.mountpoint == '/': + if partition.target_mountpoint == mountpoint or partition.mountpoint == mountpoint: return partition def raw_parted(self, string:str): diff --git a/examples/guided.py b/examples/guided.py index ebdd3678..722e1e36 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -278,7 +278,7 @@ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) encrypt_root_partition=archinstall.arguments.get('!encryption-password', False)) # Otherwise, check if encryption is desired and mark the root partition as encrypted. elif archinstall.arguments.get('!encryption-password', None): - root_partition = fs.find_root_partition() + root_partition = fs.find_partition('/') root_partition.encrypted = True # After the disk is ready, iterate the partitions and check @@ -296,16 +296,16 @@ with archinstall.Filesystem(archinstall.arguments['harddrive'], archinstall.GPT) # First encrypt and unlock, then format the desired partition inside the encrypted part. # archinstall.luks2() encrypts the partition when entering the with context manager, and # unlocks the drive so that it can be used as a normal block-device within archinstall. - with archinstall.luks2(archinstall.arguments['harddrive'].partition[1], 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_device: - unlocked_device.format(archinstall.arguments.get('filesystem', 'btrfs')) + with archinstall.luks2(fs.find_partition('/'), 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_device: + unlocked_device.format(fs.find_partition('/').filesystem) - perform_installation(unlocked_device, - archinstall.arguments['harddrive'].partition[0], - archinstall.arguments['keyboard-language'], - archinstall.arguments['mirror-region']) + perform_installation(device=unlocked_device, + boot_partition=fs.find_partition('/boot'), + language=archinstall.arguments['keyboard-language'], + mirrors=archinstall.arguments['mirror-region']) else: archinstall.arguments['harddrive'].partition[1].format('ext4') - perform_installation(archinstall.arguments['harddrive'].partition[1], - archinstall.arguments['harddrive'].partition[0], - archinstall.arguments['keyboard-language'], - archinstall.arguments['mirror-region']) \ No newline at end of file + perform_installation(device=fs.find_partition('/'), + boot_partition=fs.find_partition('/boot'), + language=archinstall.arguments['keyboard-language'], + mirrors=archinstall.arguments['mirror-region']) \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 56d673d2a509bdd881fff51892f564a66384c0c2 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:07:46 +0100 Subject: Debugging some tweaks --- archinstall/lib/disk.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 73d913d0..958284cf 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -146,7 +146,7 @@ class Partition(): self.mount(mountpoint) mount_information = get_mount_info(self.path) - fstype = get_filesystem_type(self.path) # blkid -o value -s TYPE self.path + fstype = get_filesystem_type(self.real_device) # blkid -o value -s TYPE self.path if self.mountpoint != mount_information.get('target', None) and mountpoint: raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information.get('target', None)}") @@ -175,6 +175,16 @@ class Partition(): else: return f'Partition(path={self.path}, fs={self.filesystem}{mount_repr})' + @property + def real_device(self): + if not self.encrypted: + return self.path + else: + for blockdevice in json.loads(b''.join(sys_command('lsblk -J')).decode('UTF-8'))['blockdevices']: + if (parent := self.find_parent_of(blockdevice, os.path.basename(self.path))): + return f"/dev/{parent}" + raise DiskError(f'Could not find appropriate parent for encrypted partition {self}') + def has_content(self): temporary_mountpoint = '/tmp/'+hashlib.md5(bytes(f"{time.time()}", 'UTF-8')+os.urandom(12)).hexdigest() temporary_path = pathlib.Path(temporary_mountpoint) @@ -277,16 +287,6 @@ class Partition(): if (parent := self.find_parent_of(child, name, parent=data['name'])): return parent - @property - def real_device(self): - if not self.encrypted: - return self.path - else: - for blockdevice in json.loads(b''.join(sys_command('lsblk -J')).decode('UTF-8'))['blockdevices']: - if (parent := self.find_parent_of(blockdevice, os.path.basename(self.path))): - return f"/dev/{parent}" - raise DiskError(f'Could not find appropriate parent for encrypted partition {self}') - def mount(self, target, fs=None, options=''): if not self.mountpoint: log(f'Mounting {self} to {target}', level=LOG_LEVELS.Info) -- cgit v1.2.3-70-g09d2 From c56d4d958ef1797bbdebb883801a905169d454f6 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:36:15 +0100 Subject: Debugging some tweaks --- archinstall/lib/disk.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 958284cf..3bbd9344 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -146,7 +146,7 @@ class Partition(): self.mount(mountpoint) mount_information = get_mount_info(self.path) - fstype = get_filesystem_type(self.real_device) # blkid -o value -s TYPE self.path + fstype = get_filesystem_type(self.real_devicecryptse) # blkid -o value -s TYPE self.path if self.mountpoint != mount_information.get('target', None) and mountpoint: raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information.get('target', None)}") @@ -156,6 +156,12 @@ class Partition(): if (fstype := mount_information.get('fstype', fstype)): self.filesystem = fstype + if self.filesystem == 'crypto_LUKS': + # TODO: Explore other options in terms of handling a two-layer filesystem option. + # Currently if we keep crypto_LUKS then the installer won't know what to format inside. + self.encrypted = True + self.filesystem = None + def __lt__(self, left_comparitor): if type(left_comparitor) == Partition: left_comparitor = left_comparitor.path @@ -269,11 +275,11 @@ class Partition(): raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'f2fs' - elif filesystem == 'crypto_LUKS': - from .luks import luks2 - encrypted_partition = luks2(self, None, None) - encrypted_partition.format(path) - self.filesystem = 'crypto_LUKS' + #elif filesystem == 'crypto_LUKS': + # from .luks import luks2 + # encrypted_partition = luks2(self, None, None) + # encrypted_partition.format(path) + # self.filesystem = 'crypto_LUKS' else: raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.") -- cgit v1.2.3-70-g09d2 From 6680f744624af5b0be746525ea4ba4bbcf44401d Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:36:59 +0100 Subject: Debugging some tweaks --- archinstall/lib/disk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 3bbd9344..32dbcbc2 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -146,7 +146,7 @@ class Partition(): self.mount(mountpoint) mount_information = get_mount_info(self.path) - fstype = get_filesystem_type(self.real_devicecryptse) # blkid -o value -s TYPE self.path + fstype = get_filesystem_type(self.real_device) # blkid -o value -s TYPE self.path if self.mountpoint != mount_information.get('target', None) and mountpoint: raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information.get('target', None)}") -- cgit v1.2.3-70-g09d2 From 3b849ca07462dd80734373b3428cd0e128812f60 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:38:36 +0100 Subject: Debugging some tweaks --- archinstall/lib/disk.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 32dbcbc2..335ec42e 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -157,10 +157,7 @@ class Partition(): self.filesystem = fstype if self.filesystem == 'crypto_LUKS': - # TODO: Explore other options in terms of handling a two-layer filesystem option. - # Currently if we keep crypto_LUKS then the installer won't know what to format inside. self.encrypted = True - self.filesystem = None def __lt__(self, left_comparitor): if type(left_comparitor) == Partition: @@ -275,11 +272,11 @@ class Partition(): raise DiskError(f'Could not format {path} with {filesystem} because: {b"".join(handle)}') self.filesystem = 'f2fs' - #elif filesystem == 'crypto_LUKS': + elif filesystem == 'crypto_LUKS': # from .luks import luks2 # encrypted_partition = luks2(self, None, None) # encrypted_partition.format(path) - # self.filesystem = 'crypto_LUKS' + self.filesystem = 'crypto_LUKS' else: raise UnknownFilesystemFormat(f"Fileformat '{filesystem}' is not yet implemented.") -- cgit v1.2.3-70-g09d2 From 9f0d25bce302459efa5ab5b9eaf22bb1f1feb575 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:48:40 +0100 Subject: Added functions to auto-detect filesystems inside encrypted partitions (given a password) --- archinstall/lib/disk.py | 5 +++++ archinstall/lib/luks.py | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 335ec42e..75cecb0b 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -188,6 +188,11 @@ class Partition(): return f"/dev/{parent}" raise DiskError(f'Could not find appropriate parent for encrypted partition {self}') + def detect_inner_filesystem(self, password): + from .luks import luks2 + with luks2(self, 'luksloop', password, auto_unmount=True) as unlocked_device: + return unlocked_device.filesystem + def has_content(self): temporary_mountpoint = '/tmp/'+hashlib.md5(bytes(f"{time.time()}", 'UTF-8')+os.urandom(12)).hexdigest() temporary_path = pathlib.Path(temporary_mountpoint) diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index c9946239..fa040788 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -6,13 +6,14 @@ from .output import log, LOG_LEVELS from .storage import storage class luks2(): - def __init__(self, partition, mountpoint, password, key_file=None, *args, **kwargs): + def __init__(self, partition, mountpoint, password, key_file=None, auto_unmount=False, *args, **kwargs): self.password = password self.partition = partition self.mountpoint = mountpoint self.args = args self.kwargs = kwargs self.key_file = key_file + self.auto_unmount = auto_unmount self.filesystem = 'crypto_LUKS' def __enter__(self): @@ -32,6 +33,9 @@ class luks2(): def __exit__(self, *args, **kwargs): # TODO: https://stackoverflow.com/questions/28157929/how-to-safely-handle-an-exception-inside-a-context-manager + if self.auto_unmount: + self.close() + if len(args) >= 2 and args[1]: raise args[1] return True @@ -73,11 +77,12 @@ class luks2(): :param mountpoint: The name without absolute path, for instance "luksdev" will point to /dev/mapper/luksdev :type mountpoint: str """ + from .disk import get_filesystem_type if '/' in mountpoint: os.path.basename(mountpoint) # TODO: Raise exception instead? sys_command(f'/usr/bin/cryptsetup open {partition.path} {mountpoint} --key-file {os.path.abspath(key_file)} --type luks2') if os.path.islink(f'/dev/mapper/{mountpoint}'): - return Partition(f'/dev/mapper/{mountpoint}', encrypted=True) + return Partition(f'/dev/mapper/{mountpoint}', encrypted=True, filesystem=get_filesystem_type(f'/dev/mapper/{mountpoint}')) def close(self, mountpoint): sys_command(f'cryptsetup close /dev/mapper/{mountpoint}') -- cgit v1.2.3-70-g09d2 From 4e8084bddb989646bf74b6c8883fc66622441221 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:54:03 +0100 Subject: Fixed a issue with blkid where it would raise an exception when there was not filesystem on the partition. --- archinstall/lib/disk.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 75cecb0b..db58f3ce 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -487,5 +487,6 @@ def get_mount_info(path): return output['filesystems'][0] def get_filesystem_type(path): - output = b''.join(sys_command(f"blkid -o value -s TYPE {path}")) - return output.strip().decode('UTF-8') \ No newline at end of file + if (handle := sys_command(f"blkid -o value -s TYPE {path}")).exit_code != 0: + return None + return b''.join(handle).strip().decode('UTF-8') \ No newline at end of file -- cgit v1.2.3-70-g09d2 From f045462c9a105b6272db4c61e8b29fc1ae059c8a Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:56:33 +0100 Subject: Fixed a issue with blkid where it would raise an exception when there was not filesystem on the partition. --- archinstall/lib/disk.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index db58f3ce..3f51733a 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -487,6 +487,8 @@ def get_mount_info(path): return output['filesystems'][0] def get_filesystem_type(path): - if (handle := sys_command(f"blkid -o value -s TYPE {path}")).exit_code != 0: - return None - return b''.join(handle).strip().decode('UTF-8') \ No newline at end of file + try: + handle = sys_command(f"blkid -o value -s TYPE {path}") + return b''.join(handle).strip().decode('UTF-8') + except SysCallError: + return None \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 251624734faa7a01590cb35b3416b72c2271ba55 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:58:35 +0100 Subject: Fixed luks2().close() to properly detect it's own path --- archinstall/lib/luks.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index fa040788..283a1b51 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -84,7 +84,10 @@ class luks2(): if os.path.islink(f'/dev/mapper/{mountpoint}'): return Partition(f'/dev/mapper/{mountpoint}', encrypted=True, filesystem=get_filesystem_type(f'/dev/mapper/{mountpoint}')) - def close(self, mountpoint): + def close(self, mountpoint=None): + if not mountpoint: + mountpoint = self.partition.path + sys_command(f'cryptsetup close /dev/mapper/{mountpoint}') return os.path.islink(f'/dev/mapper/{mountpoint}') is False -- cgit v1.2.3-70-g09d2 From 3bf8ba081967a041f3552b68efff84340edb5138 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 12:00:40 +0100 Subject: Fixed luks2().close() to properly detect it's own mapped path --- archinstall/lib/luks.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index 283a1b51..7c5d3e55 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -15,6 +15,7 @@ class luks2(): self.key_file = key_file self.auto_unmount = auto_unmount self.filesystem = 'crypto_LUKS' + self.mappoint = None def __enter__(self): #if self.partition.allow_formatting: @@ -82,14 +83,15 @@ class luks2(): os.path.basename(mountpoint) # TODO: Raise exception instead? sys_command(f'/usr/bin/cryptsetup open {partition.path} {mountpoint} --key-file {os.path.abspath(key_file)} --type luks2') if os.path.islink(f'/dev/mapper/{mountpoint}'): + self.mappoint = f'/dev/mapper/{mountpoint}' return Partition(f'/dev/mapper/{mountpoint}', encrypted=True, filesystem=get_filesystem_type(f'/dev/mapper/{mountpoint}')) def close(self, mountpoint=None): if not mountpoint: - mountpoint = self.partition.path - - sys_command(f'cryptsetup close /dev/mapper/{mountpoint}') - return os.path.islink(f'/dev/mapper/{mountpoint}') is False + mountpoint = self.mappoint + + sys_command(f'/usr/bin/cryptsetup close {self.mappoint}') + return os.path.islink(self.mappoint) is False def format(self, path): if (handle := sys_command(f"/usr/bin/cryptsetup -q -v luksErase {path}")).exit_code != 0: -- cgit v1.2.3-70-g09d2 From 747d620596c41094a66a8ae1e39104bc05d90846 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 12:02:14 +0100 Subject: Added some debugging. --- archinstall/lib/disk.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index 3f51733a..f78907d7 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -189,8 +189,10 @@ class Partition(): raise DiskError(f'Could not find appropriate parent for encrypted partition {self}') def detect_inner_filesystem(self, password): + log(f'Trying to detect inner filesystem format on {self} (This might take a while)', level=LOG_LEVELS.Info) from .luks import luks2 with luks2(self, 'luksloop', password, auto_unmount=True) as unlocked_device: + print('Found:', unlocked_device.filesystem) return unlocked_device.filesystem def has_content(self): -- cgit v1.2.3-70-g09d2 From b3a5afea60ada944905b45a7150c91a5a8a09fcc Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 12:05:39 +0100 Subject: Tweaked the filesystem definition setup for Partition(). Overriding it programatically should be possible for some meta stuff. --- archinstall/lib/disk.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index f78907d7..d3f4b069 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -146,14 +146,13 @@ class Partition(): self.mount(mountpoint) mount_information = get_mount_info(self.path) - fstype = get_filesystem_type(self.real_device) # blkid -o value -s TYPE self.path if self.mountpoint != mount_information.get('target', None) and mountpoint: raise DiskError(f"{self} was given a mountpoint but the actual mountpoint differs: {mount_information.get('target', None)}") if (target := mount_information.get('target', None)): self.mountpoint = target - if (fstype := mount_information.get('fstype', fstype)): + if not self.filesystem and (fstype := mount_information.get('fstype', get_filesystem_type(self.real_device))): self.filesystem = fstype if self.filesystem == 'crypto_LUKS': -- cgit v1.2.3-70-g09d2 From 585e0f4b869c270ec0482d628033463af74516a7 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 12:10:30 +0100 Subject: Added some debugging. --- archinstall/lib/luks.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index 7c5d3e55..706a8bd9 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -15,7 +15,7 @@ class luks2(): self.key_file = key_file self.auto_unmount = auto_unmount self.filesystem = 'crypto_LUKS' - self.mappoint = None + self.mapdev = None def __enter__(self): #if self.partition.allow_formatting: @@ -83,15 +83,17 @@ class luks2(): os.path.basename(mountpoint) # TODO: Raise exception instead? sys_command(f'/usr/bin/cryptsetup open {partition.path} {mountpoint} --key-file {os.path.abspath(key_file)} --type luks2') if os.path.islink(f'/dev/mapper/{mountpoint}'): - self.mappoint = f'/dev/mapper/{mountpoint}' - return Partition(f'/dev/mapper/{mountpoint}', encrypted=True, filesystem=get_filesystem_type(f'/dev/mapper/{mountpoint}')) + self.mapdev = f'/dev/mapper/{mountpoint}' + inner_fs = get_filesystem_type(self.mapdev) + print('Inner FS:', inner_fs) + return Partition(self.mapdev, encrypted=True, filesystem=inner_fs) def close(self, mountpoint=None): if not mountpoint: - mountpoint = self.mappoint + mountpoint = self.mapdev - sys_command(f'/usr/bin/cryptsetup close {self.mappoint}') - return os.path.islink(self.mappoint) is False + sys_command(f'/usr/bin/cryptsetup close {self.mapdev}') + return os.path.islink(self.mapdev) is False def format(self, path): if (handle := sys_command(f"/usr/bin/cryptsetup -q -v luksErase {path}")).exit_code != 0: -- cgit v1.2.3-70-g09d2 From 8f42a9f4ff647f84818cc01b84ba79e8256caa5f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 12:16:40 +0100 Subject: Added option to skip autodetection of filesystem. This is so for instance luks2() can override any auto-detection that revers back to the parent device of the mapped device, which would be crypto_LUKS instead of None for the inner partition. --- archinstall/lib/disk.py | 8 +++++--- archinstall/lib/luks.py | 5 +---- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index d3f4b069..fe21dcf7 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -130,7 +130,7 @@ class BlockDevice(): return False class Partition(): - def __init__(self, path, part_id=None, size=-1, filesystem=None, mountpoint=None, encrypted=False): + def __init__(self, path, part_id=None, size=-1, filesystem=None, mountpoint=None, encrypted=False, autodetect_filesystem=True): if not part_id: part_id = os.path.basename(path) self.path = path @@ -152,8 +152,10 @@ class Partition(): if (target := mount_information.get('target', None)): self.mountpoint = target - if not self.filesystem and (fstype := mount_information.get('fstype', get_filesystem_type(self.real_device))): - self.filesystem = fstype + + if not self.filesystem and autodetect_filesystem: + if (fstype := mount_information.get('fstype', get_filesystem_type(self.real_device))): + self.filesystem = fstype if self.filesystem == 'crypto_LUKS': self.encrypted = True diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index 706a8bd9..e03e26ca 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -83,10 +83,7 @@ class luks2(): os.path.basename(mountpoint) # TODO: Raise exception instead? sys_command(f'/usr/bin/cryptsetup open {partition.path} {mountpoint} --key-file {os.path.abspath(key_file)} --type luks2') if os.path.islink(f'/dev/mapper/{mountpoint}'): - self.mapdev = f'/dev/mapper/{mountpoint}' - inner_fs = get_filesystem_type(self.mapdev) - print('Inner FS:', inner_fs) - return Partition(self.mapdev, encrypted=True, filesystem=inner_fs) + return Partition(self.mapdev, encrypted=True, filesystem=get_filesystem_type(self.mapdev), autodetect_filesystem=False) def close(self, mountpoint=None): if not mountpoint: -- cgit v1.2.3-70-g09d2 From 3e9031821aa3bb6f85ce33405cf65aa2003d42d1 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 13:36:47 +0100 Subject: Forgot to set a variable --- archinstall/lib/luks.py | 1 + 1 file changed, 1 insertion(+) (limited to 'archinstall') diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index e03e26ca..7873f76b 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -83,6 +83,7 @@ class luks2(): os.path.basename(mountpoint) # TODO: Raise exception instead? sys_command(f'/usr/bin/cryptsetup open {partition.path} {mountpoint} --key-file {os.path.abspath(key_file)} --type luks2') if os.path.islink(f'/dev/mapper/{mountpoint}'): + self.mapdev = f'/dev/mapper/{mountpoint}' return Partition(self.mapdev, encrypted=True, filesystem=get_filesystem_type(self.mapdev), autodetect_filesystem=False) def close(self, mountpoint=None): -- cgit v1.2.3-70-g09d2 From cf21b477640ec284f1355140694d22a2c9a21ac3 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 14:00:30 +0100 Subject: Carried over the allow_formatting from the parent device of luks2() devices. --- archinstall/lib/disk.py | 1 - archinstall/lib/luks.py | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'archinstall') diff --git a/archinstall/lib/disk.py b/archinstall/lib/disk.py index fe21dcf7..c05ba757 100644 --- a/archinstall/lib/disk.py +++ b/archinstall/lib/disk.py @@ -193,7 +193,6 @@ class Partition(): log(f'Trying to detect inner filesystem format on {self} (This might take a while)', level=LOG_LEVELS.Info) from .luks import luks2 with luks2(self, 'luksloop', password, auto_unmount=True) as unlocked_device: - print('Found:', unlocked_device.filesystem) return unlocked_device.filesystem def has_content(self): diff --git a/archinstall/lib/luks.py b/archinstall/lib/luks.py index 7873f76b..e54641b8 100644 --- a/archinstall/lib/luks.py +++ b/archinstall/lib/luks.py @@ -84,7 +84,9 @@ class luks2(): sys_command(f'/usr/bin/cryptsetup open {partition.path} {mountpoint} --key-file {os.path.abspath(key_file)} --type luks2') if os.path.islink(f'/dev/mapper/{mountpoint}'): self.mapdev = f'/dev/mapper/{mountpoint}' - return Partition(self.mapdev, encrypted=True, filesystem=get_filesystem_type(self.mapdev), autodetect_filesystem=False) + unlocked_partition = Partition(self.mapdev, encrypted=True, filesystem=get_filesystem_type(self.mapdev), autodetect_filesystem=False) + unlocked_partition.allow_formatting = self.partition.allow_formatting + return unlocked_partition def close(self, mountpoint=None): if not mountpoint: -- cgit v1.2.3-70-g09d2 From 1167cf589b65e121b8b3322980a83ddba2043b57 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 14:09:17 +0100 Subject: Fixed mirror-region parameter selection. Converting to actual mirrors. --- archinstall/lib/installer.py | 2 +- examples/guided.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'archinstall') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 4fb6b706..06bdd05a 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -78,7 +78,7 @@ class Installer(): if len(args) >= 2 and args[1]: #self.log(self.trace_log.decode('UTF-8'), level=LOG_LEVELS.Debug) - self.log(args[1], level=LOG_LEVELS.Error) + self.log(args[1], level=LOG_LEVELS.Error, fg='red') self.sync_log_to_install_medium() diff --git a/examples/guided.py b/examples/guided.py index 55643933..08ad70d9 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -88,6 +88,10 @@ if len(archinstall.arguments['keyboard-language']): # Set which region to download packages from during the installation if not archinstall.arguments.get('mirror-region', None): archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors()) +else: + selected_region = archinstall.arguments['mirror-region'] + archinstall.arguments['mirror-region'] = {selected_region : archinstall.list_mirrors()[selected_region]} + # Ask which harddrive/block-device we will install to if archinstall.arguments.get('harddrive', None): -- cgit v1.2.3-70-g09d2