From a618ebd6111de0cab9c0f04449cf1a8483156615 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 12:34:39 +0100 Subject: Adding a check to see if the disk contains a parition table already. has_partitions() TBI --- examples/guided.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/guided.py b/examples/guided.py index f0620b05..f55047d9 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -104,6 +104,15 @@ while (disk_password := getpass.getpass(prompt='Enter disk encryption password ( archinstall.storage['_guided']['disk_encryption'] = True break archinstall.storage['_guided']['harddrive'] = harddrive +print(harddrive) +if archinstall.has_partitions(harddrive): + 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!") + else: + print('Formatting woop woop!') +exit(1) + # Ask for a hostname hostname = input('Desired hostname for the installation: ') -- cgit v1.2.3-54-g00ecf 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 +++ examples/guided.py | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) 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): diff --git a/examples/guided.py b/examples/guided.py index f55047d9..1e879316 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -96,16 +96,9 @@ archinstall.storage['_guided']['mirrors'] = mirror_regions # Ask which harddrive/block-device we will install to harddrive = archinstall.select_disk(archinstall.all_disks()) -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 archinstall.storage['_guided']['harddrive'] = harddrive -print(harddrive) -if archinstall.has_partitions(harddrive): + +if harddrive.has_partitions(harddrive): 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!") @@ -113,6 +106,14 @@ if archinstall.has_partitions(harddrive): 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: ') + if disk_password != disk_password_verification: + archinstall.log(' * Passwords did not match * ', bg='black', fg='red') + continue + archinstall.storage['_guided']['disk_encryption'] = True + break + # Ask for a hostname hostname = input('Desired hostname for the installation: ') -- cgit v1.2.3-54-g00ecf From e06603f0e143360ccb932ce39df37eac22969f90 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 12:53:01 +0100 Subject: has_partitions() doesn't take any parameters, old reminant of prototype code. --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 1e879316..5268042d 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -98,7 +98,7 @@ archinstall.storage['_guided']['mirrors'] = mirror_regions harddrive = archinstall.select_disk(archinstall.all_disks()) archinstall.storage['_guided']['harddrive'] = harddrive -if harddrive.has_partitions(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!") -- cgit v1.2.3-54-g00ecf From 9c7f689dd620739062b8248bc9798a522fc4c7e2 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 13:29:33 +0100 Subject: Can't unmount during startup if we want to support existing partitioning schemes. --- examples/guided.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 5268042d..a5298328 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -75,11 +75,6 @@ def perform_installation(device, boot_partition, language, mirrors): if 'root_pw' in archinstall.storage['_guided_hidden'] and archinstall.storage['_guided_hidden']['root_pw']: installation.user_set_pw('root', archinstall.storage['_guided_hidden']['root_pw']) -# Unmount and close previous runs (in case the installer is restarted) -archinstall.sys_command(f'umount -R /mnt', suppress_errors=True) -archinstall.sys_command(f'cryptsetup close /dev/mapper/luksloop', suppress_errors=True) - - """ First, we'll ask the user for a bunch of user input. Not until we're satisfied with what we want to install -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf From 7123da1c564bd88f9c3101c6e5e1773d0d2cdf62 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 13:39:39 +0100 Subject: Threw the wrong exception --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index b6c6dd45..ac1e7fe2 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -100,7 +100,7 @@ if harddrive.has_partitions(): # 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.") + 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.") else: print('Formatting woop woop!') exit(1) -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf From d527e215fce1da04e07556d2dbe787e16dba550b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 15:03:32 +0100 Subject: Added some log outputs for existing drives. --- examples/guided.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/guided.py b/examples/guided.py index ac1e7fe2..d6029f46 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -101,6 +101,10 @@ if harddrive.has_partitions(): # 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.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: + archinstall.log(f" {partition}") else: print('Formatting woop woop!') exit(1) -- cgit v1.2.3-54-g00ecf 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(+) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf From 93985425590a27745445a432fa19a4de92ec5089 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:16:00 +0100 Subject: Added in command line arguments to guided and simplified the laout of guided a bit. Also added some more comments. --- examples/guided.py | 65 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 8033a8a5..12209858 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -5,11 +5,10 @@ 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. +is used to trigger the "Are you sure you want to abort?" question further down. """ SIG_TRIGGER = False def kill_handler(sig, frame): @@ -81,34 +80,46 @@ def perform_installation(device, boot_partition, language, mirrors): Not until we're satisfied with what we want to install will we continue with the actual installation steps. """ +archinstall.arguments['keyboard-language'] = archinstall.arguments.get('keyboard-language', + default=archinstall.select_language(archinstall.list_keyboard_languages()).strip()) -if len(keyboard_language := archinstall.select_language(archinstall.list_keyboard_languages()).strip()): - archinstall.set_keyboard_language(keyboard_language) - archinstall.storage['_guided']['keyboard_layout'] = keyboard_language +# Before continuing, set the preferred keyboard layout/language in the current terminal. +# This will just help the user with the next following questions. +if len(archinstall.arguments['keyboard-language']): + archinstall.set_keyboard_language(archinstall.arguments['keyboard-language']) # Set which region to download packages from during the installation -mirror_regions = archinstall.select_mirror_regions(archinstall.list_mirrors()) -archinstall.storage['_guided']['mirrors'] = mirror_regions +archinstall.arguments['mirror-region'] = archinstall.arguments.get('mirror-region', + default=archinstall.select_mirror_regions(archinstall.list_mirrors())) # Ask which harddrive/block-device we will install to -harddrive = archinstall.select_disk(archinstall.all_disks()) -archinstall.storage['_guided']['harddrive'] = harddrive +archinstall.arguments['harddrive'] = archinstall.arguments.get('harddrive', + default=archinstall.select_disk(archinstall.all_disks())) +# Perform a quick sanity check on the selected harddrive. +# 1. Check if it has partitions +# 3. Check that we support the current partitions +# 2. If so, ask if we should keep them or wipe everything 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 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 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 reported above.') + try: + for partition in harddrive: + if partition.filesystem_supported(): + archinstall.log(f" {partition}") + + 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 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 reported above.') + except 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):") +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: @@ -294,7 +305,13 @@ with archinstall.Filesystem(harddrive, archinstall.GPT) as fs: with archinstall.luks2(harddrive.partition[1], 'luksloop', disk_password) as unlocked_device: unlocked_device.format('btrfs') - perform_installation(unlocked_device, harddrive.partition[0], keyboard_language, mirror_regions) + perform_installation(unlocked_device, + harddrive.partition[0], + archinstall.arguments['keyboard-language'], + archinstall.arguments['mirror-region']) else: harddrive.partition[1].format('ext4') - perform_installation(harddrive.partition[1], harddrive.partition[0], keyboard_language, mirror_regions) \ No newline at end of file + perform_installation(harddrive.partition[1], + harddrive.partition[0], + archinstall.arguments['keyboard-language'], + archinstall.arguments['mirror-region']) \ No newline at end of file -- cgit v1.2.3-54-g00ecf From a320ce3341d898adf71b5893551a7b20551fd91a Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:33:27 +0100 Subject: Thought I could get away with a little default-parameter hack to make the code look nice, but the JIT doesn't do lazy resolving on .get() calls. --- examples/guided.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 12209858..d4413969 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -80,8 +80,8 @@ def perform_installation(device, boot_partition, language, mirrors): Not until we're satisfied with what we want to install will we continue with the actual installation steps. """ -archinstall.arguments['keyboard-language'] = archinstall.arguments.get('keyboard-language', - default=archinstall.select_language(archinstall.list_keyboard_languages()).strip()) +if not archinstall.arguments.get('keyboard-language', None): + archinstall.arguments['keyboard-language'] = archinstall.select_language(archinstall.list_keyboard_languages()).strip() # Before continuing, set the preferred keyboard layout/language in the current terminal. # This will just help the user with the next following questions. @@ -89,12 +89,12 @@ if len(archinstall.arguments['keyboard-language']): archinstall.set_keyboard_language(archinstall.arguments['keyboard-language']) # Set which region to download packages from during the installation -archinstall.arguments['mirror-region'] = archinstall.arguments.get('mirror-region', - default=archinstall.select_mirror_regions(archinstall.list_mirrors())) +if not archinstall.arguments.get('mirror-region', None): + archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors()) # Ask which harddrive/block-device we will install to -archinstall.arguments['harddrive'] = archinstall.arguments.get('harddrive', - default=archinstall.select_disk(archinstall.all_disks())) +if not archinstall.arguments.get('harddrive', None) + archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) # Perform a quick sanity check on the selected harddrive. # 1. Check if it has partitions -- cgit v1.2.3-54-g00ecf From ea65e3599a21ceb51ec9ed75ea888f98c33f857d Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:34:43 +0100 Subject: Forgot a semicolon --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index d4413969..f86e2d51 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -93,7 +93,7 @@ if not archinstall.arguments.get('mirror-region', None): archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors()) # Ask which harddrive/block-device we will install to -if not archinstall.arguments.get('harddrive', None) +if not archinstall.arguments.get('harddrive', None): archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) # Perform a quick sanity check on the selected harddrive. -- cgit v1.2.3-54-g00ecf From 819a8f742ea3177890077754db04a731ad3cb35a Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:43:05 +0100 Subject: Replacing static variables with more dynamic ones that can live across scopes. No need to pass things around unless strictly nessecary --- examples/guided.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index f86e2d51..f807e734 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -93,17 +93,19 @@ if not archinstall.arguments.get('mirror-region', None): archinstall.arguments['mirror-region'] = archinstall.select_mirror_regions(archinstall.list_mirrors()) # Ask which harddrive/block-device we will install to -if not archinstall.arguments.get('harddrive', None): +if archinstall.arguments.get('harddrive', None): + archinstall.arguments['harddrive'] = archinstall.BlockDevice(archinstall.arguments['harddrive']) +else: archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) # Perform a quick sanity check on the selected harddrive. # 1. Check if it has partitions # 3. Check that we support the current partitions # 2. If so, ask if we should keep them or wipe everything -if harddrive.has_partitions(): - archinstall.log(f" ! {harddrive} contains existing partitions", fg='red') +if archinstall.arguments['harddrive'].has_partitions(): + archinstall.log(f" ! {archinstall.arguments['harddrive']} contains existing partitions", fg='red') try: - for partition in harddrive: + for partition in archinstall.arguments['harddrive']: if partition.filesystem_supported(): archinstall.log(f" {partition}") @@ -111,8 +113,8 @@ if harddrive.has_partitions(): # 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.DiskError(f"The selected drive {harddrive} is not pre-mounted to {archinstall.storage['MOUNT_POINT']}. This is required when keeping a existing partitioning scheme.") + 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.") archinstall.log('Using existing partition table reported above.') except UnknownFilesystemFormat as err: @@ -261,7 +263,7 @@ input('Press Enter to continue.') We mention the drive one last time, and count from 5 to 0. """ -print(f' ! Formatting {harddrive} in ', end='') +print(f' ! Formatting {archinstall.arguments['harddrive']} in ', end='') for i in range(5, 0, -1): print(f"{i}", end='') -- cgit v1.2.3-54-g00ecf From 47649074b8e182505b9def828b8cc344c96a3cb0 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 18:44:26 +0100 Subject: Quotation issue --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index f807e734..a9af24bd 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -263,7 +263,7 @@ input('Press Enter to continue.') We mention the drive one last time, and count from 5 to 0. """ -print(f' ! Formatting {archinstall.arguments['harddrive']} in ', end='') +print(f" ! Formatting {archinstall.arguments['harddrive']} in ", end='') for i in range(5, 0, -1): print(f"{i}", end='') -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf From 62a14d09455c7f7b1b6dbcf5810c8e452d2858d7 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 7 Feb 2021 19:26:47 +0100 Subject: Forgot importpath for exceptions --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index a9af24bd..c5e1474e 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -117,7 +117,7 @@ if archinstall.arguments['harddrive'].has_partitions(): 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.") archinstall.log('Using existing partition table reported above.') - except UnknownFilesystemFormat as err: + 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-54-g00ecf 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(+) 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-54-g00ecf 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(-) 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-54-g00ecf From 76d3976df6d148e31a0aab04037a7c191b4054fe Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 16 Feb 2021 08:51:00 +0100 Subject: Re-worked guided to allow for unsupported fileformats when checking which are supported, as well as selecting mount-points. --- examples/guided.py | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 5e8a64c1..abbecd3a 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -104,26 +104,35 @@ 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') - try: - partition_mountpoints = {} - for partition in archinstall.arguments['harddrive']: + partition_mountpoints = {} + for partition in archinstall.arguments['harddrive']: + try: if partition.filesystem_supported(): archinstall.log(f" {partition}") 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'): + 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. **") + while True: + partition = archinstall.generic_select(partition_mountpoints.keys(), "Select a partition to assign mount-point to: ") + if not partition: + break - 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") + mountpoint = input(f"Select a mount-point for {partition}: ") + #partition.mountpoint = mountpoint + partition.allow_formatting = True + partition.target_mountpoint = mountpoint - 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):") + archinstall.log('Using existing partition table reported above.') + else: + archinstall.arguments['harddrive'].keep_partitions = False exit(0) while (disk_password := getpass.getpass(prompt='Enter disk encryption password (leave blank for no encryption): ')): -- cgit v1.2.3-54-g00ecf From 10f0567ead96655b933598bfb7729b18956ef4dc Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 12:06:15 +0100 Subject: Adding filesystem selection for partitions --- examples/guided.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index abbecd3a..315be0d0 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -121,14 +121,18 @@ if archinstall.arguments['harddrive'].has_partitions(): 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. **") while True: - partition = archinstall.generic_select(partition_mountpoints.keys(), "Select a partition to assign mount-point to: ") + partition = archinstall.generic_select(partition_mountpoints.keys(), "Select a partition to assign mount-point to (leave blank when done): ") if not partition: break - mountpoint = input(f"Select a mount-point for {partition}: ") - #partition.mountpoint = mountpoint - partition.allow_formatting = True - partition.target_mountpoint = mountpoint + mountpoint = input(f"Enter a mount-point for {partition}: ").strip(' ') + new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') + + if len(mountpoint): + partition.allow_formatting = True + partition.target_mountpoint = mountpoint + if len(new_filesystem): + partition.filesystem = new_filesystem archinstall.log('Using existing partition table reported above.') else: -- cgit v1.2.3-54-g00ecf From 6e2d0c98eba28fa120c67378611deee442df1e30 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 12:12:49 +0100 Subject: Added some error handling when selecting a filesystem for partitions. --- examples/guided.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 315be0d0..07b345f1 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -126,7 +126,18 @@ if archinstall.arguments['harddrive'].has_partitions(): break mountpoint = input(f"Enter a mount-point for {partition}: ").strip(' ') - new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') + + while 1: + new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') + try: + partition.format(new_filesystem, path='/dev/null') + except 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 SysCallError: + pass # Supported, but mkfs could not format /dev/null which is the whole point of /dev/null in path :) + break if len(mountpoint): partition.allow_formatting = True -- cgit v1.2.3-54-g00ecf From 28adc20a30142ed93c2f730f6a653d76211a1399 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 12:13:59 +0100 Subject: Added more flags to the dummy-format --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 07b345f1..aca3520b 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -130,7 +130,7 @@ if archinstall.arguments['harddrive'].has_partitions(): while 1: new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') try: - partition.format(new_filesystem, path='/dev/null') + partition.format(new_filesystem, path='/dev/null', log_formating=False, allow_formatting=True) except 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.") -- cgit v1.2.3-54-g00ecf From b5c862549a7b52c8eb53227db1a97e1a6114c040 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 12:14:43 +0100 Subject: Added more error handling for filesystem selection --- examples/guided.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/guided.py b/examples/guided.py index aca3520b..7798ca08 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -129,6 +129,9 @@ if archinstall.arguments['harddrive'].has_partitions(): while 1: new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') + if len(new_filesystem) <= 0: + break + try: partition.format(new_filesystem, path='/dev/null', log_formating=False, allow_formatting=True) except UnknownFilesystemFormat: -- cgit v1.2.3-54-g00ecf From 3a8a25982a273081cd845723a2d794438e960a13 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 12:15:48 +0100 Subject: Forgot relative path for exceptions. --- examples/guided.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 7798ca08..0efc438c 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -131,14 +131,14 @@ if archinstall.arguments['harddrive'].has_partitions(): new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') if len(new_filesystem) <= 0: break - + try: partition.format(new_filesystem, path='/dev/null', log_formating=False, allow_formatting=True) - except UnknownFilesystemFormat: + 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 SysCallError: + except archinstall.SysCallError: pass # Supported, but mkfs could not format /dev/null which is the whole point of /dev/null in path :) break -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf From 03a69eba2e882e430fc9c668c9d334e8818a63c3 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 13:54:34 +0100 Subject: Cleaned up guided.py further by stream-lining the profiles and NIC configuration. --- examples/guided.py | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 119f22b3..3226c69b 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -180,27 +180,19 @@ archinstall.arguments['superusers'] = {**archinstall.arguments['superusers'], ** # Ask for archinstall-specific profiles (such as desktop environments etc) 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 + archinstall.arguments['profile'] = archinstall.select_profile(archinstall.list_profiles()) +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. +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) # Additional packages (with some light weight error handling for invalid package names) if not archinstall.arguments.get('packages', None): -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf From 930fc994d94132fc7676f4297465a2ad90487b75 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 14:29:51 +0100 Subject: Removed redundant variable --- examples/guided.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 4cd37972..5fdc318b 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -213,7 +213,6 @@ if not archinstall.arguments.get('nic', None): 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() -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf From c55fc11cae264445579dc34674c24922c96f63d4 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Wed, 17 Feb 2021 15:13:45 +0100 Subject: Added a comment --- examples/guided.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/guided.py b/examples/guided.py index cf7c3ef3..bccedb0a 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -243,6 +243,9 @@ for i in range(5, 0, -1): sys.stdin.read() SIG_TRIGGER = False signal.signal(signal.SIGINT, sig_handler) + +# Put back the default/original signal handler now that we're done catching +# and interrupting SIGINT with "Do you really want to abort". print() signal.signal(signal.SIGINT, original_sigint_handler) -- cgit v1.2.3-54-g00ecf From bbf9face05fe573d760eb8ca662fdf5d34ed6902 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 13:08:44 +0100 Subject: Removing make script for building binary and pypi dist. These should be done separately and should be done with build instructions not a bash script (i think). --- make.sh | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100755 make.sh diff --git a/make.sh b/make.sh deleted file mode 100755 index f733ce10..00000000 --- a/make.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# Description: Binary builder for https://archlinux.life/bin/ - -VERSION=$(cat VERSION) - -rm -rf archinstall.egg-info/ build/ src/ pkg/ dist/ archinstall.build/ "archinstall-v${VERSION}-x86_64/" *.pkg.*.xz archinstall-*.tar.gz - -#nuitka3 --standalone --show-progress archinstall -#cp -r examples/ archinstall.dist/ -#mv archinstall.dist "archinstall-v${VERSION}-x86_64" -#tar -czvf "archinstall-v${VERSION}.tar.gz" "archinstall-v${VERSION}-x86_64" - -# makepkg -f -python3 setup.py sdist bdist_wheel -echo 'python3 -m twine upload dist/* && rm -rf dist/' -python3 -m twine upload dist/* && rm -rf dist/ - -rm -rf archinstall.egg-info/ build/ src/ pkg/ archinstall.build/ "archinstall-v${VERSION}-x86_64/" -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf From e537a57a8878f71d4592ff030b22ad073a3e64da Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:43:48 +0100 Subject: Fixed indentation on output. --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 27c005d6..3e86cdf0 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -100,7 +100,7 @@ else: # 3. Check that we support the current partitions # 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') + 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. -- cgit v1.2.3-54-g00ecf From dd66aeda9afac70c087d7a399eec456510d4bca8 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:44:51 +0100 Subject: Re-formatted a question a bit. --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 3e86cdf0..2b49d88a 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -100,7 +100,7 @@ else: # 3. Check that we support the current partitions # 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') + archinstall.log(f"{archinstall.arguments['harddrive']} contains the following partitions:", fg='red') # We curate a list pf supported paritions # and print those that we don't support. -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(+) 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-54-g00ecf 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(-) 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-54-g00ecf From 30467ca50f289dc474d4cf906d05778c85d8d86d Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:57:47 +0100 Subject: Added some debugging. --- examples/guided.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/guided.py b/examples/guided.py index fbe6ea47..364e0a50 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -94,6 +94,7 @@ if archinstall.arguments.get('harddrive', None): archinstall.arguments['harddrive'] = archinstall.BlockDevice(archinstall.arguments['harddrive']) else: archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) +print(type(archinstall.arguments['harddrive']), archinstall.arguments['harddrive']) # Perform a quick sanity check on the selected harddrive. # 1. Check if it has partitions -- cgit v1.2.3-54-g00ecf From 2fe8a173f487f7bed76a4745a8c957aca10f07f9 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:58:31 +0100 Subject: Added some debugging. --- examples/guided.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 364e0a50..bfe8b4f3 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -94,7 +94,6 @@ if archinstall.arguments.get('harddrive', None): archinstall.arguments['harddrive'] = archinstall.BlockDevice(archinstall.arguments['harddrive']) else: archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) -print(type(archinstall.arguments['harddrive']), archinstall.arguments['harddrive']) # Perform a quick sanity check on the selected harddrive. # 1. Check if it has partitions @@ -168,6 +167,8 @@ if archinstall.arguments['harddrive'].has_partitions(): elif option == 'format-all': archinstall.arguments['harddrive'].keep_partitions = False +print(type(archinstall.arguments['harddrive']), archinstall.arguments['harddrive']) + # 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): ') -- cgit v1.2.3-54-g00ecf From ffbb952eb35b25c7538dca3426854292b67e2cc3 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 14:58:58 +0100 Subject: Added some debugging. --- examples/guided.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index bfe8b4f3..264ff44e 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -167,8 +167,6 @@ if archinstall.arguments['harddrive'].has_partitions(): elif option == 'format-all': archinstall.arguments['harddrive'].keep_partitions = False -print(type(archinstall.arguments['harddrive']), archinstall.arguments['harddrive']) - # 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): ') @@ -230,12 +228,15 @@ 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf From 948878e9e3c2f4e9c8c77b11704d529f952d478c Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 16:09:51 +0100 Subject: Added some debugging. --- examples/guided.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/guided.py b/examples/guided.py index 15f9ba1c..9c4f208a 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -271,6 +271,9 @@ 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'].partitions: + print(partition) + exit(0) # Use partitioning helper to set up the disk partitions. if disk_password: fs.use_entire_disk('luks2') -- cgit v1.2.3-54-g00ecf From 979d162551d0796f4cbefd7a450149896e094caf Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 16:14:44 +0100 Subject: Added some debugging. --- examples/guided.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/guided.py b/examples/guided.py index 9c4f208a..e9ceae19 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -271,7 +271,7 @@ 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'].partitions: + for partition in archinstall.arguments['harddrive']: print(partition) exit(0) # Use partitioning helper to set up the disk partitions. -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(+) 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-54-g00ecf From f1cb3209ad9deb609d9fff35c52ec76027ceffb4 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Mon, 8 Mar 2021 17:21:23 +0100 Subject: Tweaked the guided steps up until the installation. --- examples/guided.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index fbdba776..91158f9a 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -290,16 +290,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(harddrive.partition[1], 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_device: + 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')) perform_installation(unlocked_device, - harddrive.partition[0], + archinstall.arguments['harddrive'].partition[0], archinstall.arguments['keyboard-language'], archinstall.arguments['mirror-region']) else: - harddrive.partition[1].format('ext4') - perform_installation(harddrive.partition[1], - harddrive.partition[0], + 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 -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(+) 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-54-g00ecf 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(+) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf From 586f8bc32ef81695f31f10f41472443ad5f280cd Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:44:17 +0100 Subject: Adding enforcement to select a filesystem-type for encrypted volumes unless the specified pasword can be used to unlock the device and auto-detect this. --- examples/guided.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/guided.py b/examples/guided.py index 722e1e36..3f57ec88 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -137,6 +137,12 @@ if archinstall.arguments['harddrive'].has_partitions(): while 1: new_filesystem = input(f"Enter a valid filesystem for {partition} (leave blank for {partition.filesystem}): ").strip(' ') if len(new_filesystem) <= 0: + if partition.encrypted and partition.filesystem == 'crypto_LUKS': + if (autodetected_filesystem := partition.detect_inner_filesystem(archinstall.arguments.get('!encryption-password', None))): + else: + archinstall.log(f"Could not auto-detect the filesystem inside the encrypted volume.", fg='red') + archinstall.log(f"A filesystem must be defined for the unlocked encrypted partition.") + continue break # Since the potentially new filesystem is new -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf From ce646a93948a6d6f5260a9e6e7f47282f956a56c Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 11:49:20 +0100 Subject: Forgot a variable. --- examples/guided.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/guided.py b/examples/guided.py index 3f57ec88..55643933 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -139,6 +139,7 @@ if archinstall.arguments['harddrive'].has_partitions(): if len(new_filesystem) <= 0: if partition.encrypted and partition.filesystem == 'crypto_LUKS': if (autodetected_filesystem := partition.detect_inner_filesystem(archinstall.arguments.get('!encryption-password', None))): + new_filesystem = autodetected_filesystem else: archinstall.log(f"Could not auto-detect the filesystem inside the encrypted volume.", fg='red') archinstall.log(f"A filesystem must be defined for the unlocked encrypted partition.") -- cgit v1.2.3-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(+) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf 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(+) 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-54-g00ecf 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(-) 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-54-g00ecf 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(-) 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-54-g00ecf From aafe3d19c67eb32ab8559021cc1ab984ca48b5ee Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 16:10:57 +0100 Subject: Fixed remaining installation steps and remove legacy references to archinstall.storage['_guided'] and archinstall.storage['_guided_hidden']. Which were great at the time, but they are not deprecated and moved into archinstall.arguments instead to support parameters on command-line. As well as being a bit more description, since they are arguments afterall to various setup instructions. --- examples/guided.py | 487 +++++++++++++++++++++++++++-------------------------- 1 file changed, 245 insertions(+), 242 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 08ad70d9..28d07d0f 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -43,280 +43,283 @@ def perform_installation(device, boot_partition, language, mirrors): # If user selected to copy the current ISO network configuration # Perform a copy of the config - if archinstall.storage['_guided']['network'] == 'Copy ISO network configuration to installation': + if archinstall.arguments.get('nic', None) == 'Copy ISO network configuration to installation': installation.copy_ISO_network_config(enable_services=True) # Sources the ISO network configuration to the install medium. # Otherwise, if a interface was selected, configure that interface - elif archinstall.storage['_guided']['network']: - installation.configure_nic(**archinstall.storage['_guided']['network']) + elif archinstall.arguments.get('nic', None): + installation.configure_nic(**archinstall.arguments.get('nic', {})) installation.enable_service('systemd-networkd') installation.enable_service('systemd-resolved') - if archinstall.storage['_guided']['packages'] and archinstall.storage['_guided']['packages'][0] != '': - installation.add_additional_packages(archinstall.storage['_guided']['packages']) + if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '': + installation.add_additional_packages(archinstall.arguments.get('packages', None)) - if 'profile' in archinstall.storage['_guided'] and len(profile := archinstall.storage['_guided']['profile']['path'].strip()): + if archinstall.arguments.get('profile', None) and len(profile := archinstall.arguments.get('profile').strip()): installation.install_profile(profile) - if archinstall.storage['_guided']['users']: - for user in archinstall.storage['_guided']['users']: - password = users[user] + if archinstall.arguments.get('users', None): + for user, password in archinstall.arguments.get('users').items(): + installation.user_create(user, password, sudo=False) - sudo = False - if 'root_pw' not in archinstall.storage['_guided_hidden'] or len(archinstall.storage['_guided_hidden']['root_pw'].strip()) == 0: - sudo = True + if archinstall.arguments.get('superusers', None): + for user, password in archinstall.arguments.get('superusers').items(): + installation.user_create(user, password, sudo=True) - installation.user_create(user, password, sudo=sudo) + if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): + installation.user_set_pw('root', root_pw) - if 'root_pw' in archinstall.storage['_guided_hidden'] and archinstall.storage['_guided_hidden']['root_pw']: - installation.user_set_pw('root', archinstall.storage['_guided_hidden']['root_pw']) +def ask_user_questions(): + """ + First, we'll ask the user for a bunch of user input. + Not until we're satisfied with what we want to install + will we continue with the actual installation steps. + """ + if not archinstall.arguments.get('keyboard-language', None): + archinstall.arguments['keyboard-language'] = archinstall.select_language(archinstall.list_keyboard_languages()).strip() -""" - First, we'll ask the user for a bunch of user input. - Not until we're satisfied with what we want to install - will we continue with the actual installation steps. -""" -if not archinstall.arguments.get('keyboard-language', None): - archinstall.arguments['keyboard-language'] = archinstall.select_language(archinstall.list_keyboard_languages()).strip() - -# Before continuing, set the preferred keyboard layout/language in the current terminal. -# This will just help the user with the next following questions. -if len(archinstall.arguments['keyboard-language']): - archinstall.set_keyboard_language(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): - archinstall.arguments['harddrive'] = archinstall.BlockDevice(archinstall.arguments['harddrive']) -else: - archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) - -# Perform a quick sanity check on the selected harddrive. -# 1. Check if it has partitions -# 3. Check that we support the current partitions -# 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 the following 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: - if partition.filesystem_supported(): - archinstall.log(f" {partition}") - partition_mountpoints[partition] = None - except archinstall.UnknownFilesystemFormat as err: - 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()) == '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). **") - archinstall.log(f" ** The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation). **") - while True: - # 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): - - # 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: - if partition.encrypted and partition.filesystem == 'crypto_LUKS': - if (autodetected_filesystem := partition.detect_inner_filesystem(archinstall.arguments.get('!encryption-password', None))): - new_filesystem = autodetected_filesystem - else: - archinstall.log(f"Could not auto-detect the filesystem inside the encrypted volume.", fg='red') - archinstall.log(f"A filesystem must be defined for the unlocked encrypted partition.") - continue - break + # Before continuing, set the preferred keyboard layout/language in the current terminal. + # This will just help the user with the next following questions. + if len(archinstall.arguments['keyboard-language']): + archinstall.set_keyboard_language(archinstall.arguments['keyboard-language']) - # 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 + # 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]} - # 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.') - 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) -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): - archinstall.arguments['hostname'] = input('Desired hostname for the installation: ').strip(' ') - -# Ask for a root password (optional, but triggers requirement for super-user if skipped) -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) -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) -if not archinstall.arguments.get('profile', None): - archinstall.arguments['profile'] = archinstall.select_profile(archinstall.list_profiles()) -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. -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' - ) + + # Ask which harddrive/block-device we will install to + if archinstall.arguments.get('harddrive', None): + archinstall.arguments['harddrive'] = archinstall.BlockDevice(archinstall.arguments['harddrive']) + else: + archinstall.arguments['harddrive'] = archinstall.select_disk(archinstall.all_disks()) + + # Perform a quick sanity check on the selected harddrive. + # 1. Check if it has partitions + # 3. Check that we support the current partitions + # 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 the following 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: + if partition.filesystem_supported(): + archinstall.log(f" {partition}") + partition_mountpoints[partition] = None + except archinstall.UnknownFilesystemFormat as err: + 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()) == '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). **") + archinstall.log(f" ** The root would be a simple / and the boot partition /boot (as all paths are relative inside the installation). **") + while True: + # 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 -# Additional packages (with some light weight error handling for invalid package names) -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)] + # Select a mount-point + mountpoint = input(f"Enter a mount-point for {partition}: ").strip(' ') + if len(mountpoint): + + # 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: + if partition.encrypted and partition.filesystem == 'crypto_LUKS': + if (autodetected_filesystem := partition.detect_inner_filesystem(archinstall.arguments.get('!encryption-password', None))): + new_filesystem = autodetected_filesystem + else: + archinstall.log(f"Could not auto-detect the filesystem inside the encrypted volume.", fg='red') + archinstall.log(f"A filesystem must be defined for the unlocked encrypted partition.") + continue + 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 -# 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) + # 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.') + 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) + 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): + archinstall.arguments['hostname'] = input('Desired hostname for the installation: ').strip(' ') + + # Ask for a root password (optional, but triggers requirement for super-user if skipped) + 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) + 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) + if not archinstall.arguments.get('profile', None): + archinstall.arguments['profile'] = archinstall.select_profile(archinstall.list_profiles()) + 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. + 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): + archinstall.arguments['packages'] = [package for package in input('Additional packages aside from base (space separated): ').split(' ') if len(package)] + + # 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) -# 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() + # 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.arguments, indent=4, sort_keys=True, cls=archinstall.JSON), level=archinstall.LOG_LEVELS.Info) -print() +def perform_installation_steps(): + 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() -input('Press Enter to continue.') + input('Press Enter to continue.') -""" - Issue a final warning before we continue with something un-revertable. - We mention the drive one last time, and count from 5 to 0. -""" + """ + Issue a final warning before we continue with something un-revertable. + We mention the drive one last time, and count from 5 to 0. + """ -print(f" ! Formatting {archinstall.arguments['harddrive']} in ", end='') + print(f" ! Formatting {archinstall.arguments['harddrive']} in ", end='') -for i in range(5, 0, -1): - print(f"{i}", end='') + for i in range(5, 0, -1): + print(f"{i}", end='') - for x in range(4): - sys.stdout.flush() - time.sleep(0.25) - print(".", end='') + for x in range(4): + sys.stdout.flush() + time.sleep(0.25) + print(".", end='') - if SIG_TRIGGER: - abort = input('\nDo you really want to abort (y/n)? ') - if abort.strip() != 'n': - exit(0) + if SIG_TRIGGER: + abort = input('\nDo you really want to abort (y/n)? ') + if abort.strip() != 'n': + exit(0) - if SIG_TRIGGER is False: - sys.stdin.read() - SIG_TRIGGER = False - signal.signal(signal.SIGINT, sig_handler) + if SIG_TRIGGER is False: + sys.stdin.read() + SIG_TRIGGER = False + signal.signal(signal.SIGINT, sig_handler) -# Put back the default/original signal handler now that we're done catching -# and interrupting SIGINT with "Do you really want to abort". -print() -signal.signal(signal.SIGINT, original_sigint_handler) + # Put back the default/original signal handler now that we're done catching + # and interrupting SIGINT with "Do you really want to abort". + print() + signal.signal(signal.SIGINT, original_sigint_handler) -""" - Setup the blockdevice, filesystem (and optionally encryption). - 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: - 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_partition('/') - root_partition.encrypted = True - - # 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)) + """ + Setup the blockdevice, filesystem (and optionally encryption). + 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: + 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_partition('/') + root_partition.encrypted = True + + # 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: + partition.format() else: - partition.format() + 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. + # 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(fs.find_partition('/'), 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_device: + unlocked_device.format(fs.find_partition('/').filesystem) + + perform_installation(device=unlocked_device, + boot_partition=fs.find_partition('/boot'), + language=archinstall.arguments['keyboard-language'], + mirrors=archinstall.arguments['mirror-region']) 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. - # 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(fs.find_partition('/'), 'luksloop', archinstall.arguments.get('!encryption-password', None)) as unlocked_device: - unlocked_device.format(fs.find_partition('/').filesystem) - - perform_installation(device=unlocked_device, + archinstall.arguments['harddrive'].partition[1].format('ext4') + perform_installation(device=fs.find_partition('/'), 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(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 + +ask_user_questions() +perform_pre_installation_steps() \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 2bd220c28016ca46b5e44235c08f384ea1e8f44f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 16:13:21 +0100 Subject: Moved everything into a function block rather than having everything on a line by line situation. This just helps separate what the two major components/blocks are of the guided profile. The change was done in the previous commit, but a spelling mistake was made here and I forgot to mention it in the already long commit log. But user-questions is now in one function. Installation steps are now in a two-tier function, one for setup and one for install steps. --- examples/guided.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 28d07d0f..9d242842 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -60,15 +60,21 @@ def perform_installation(device, boot_partition, language, mirrors): installation.install_profile(profile) if archinstall.arguments.get('users', None): - for user, password in archinstall.arguments.get('users').items(): + for user in archinstall.arguments.get('users'): + password = users[user] installation.user_create(user, password, sudo=False) - if archinstall.arguments.get('superusers', None): - for user, password in archinstall.arguments.get('superusers').items(): - installation.user_create(user, password, sudo=True) + for user in archinstall.arguments.get('users'): + password = users[user] + installation.user_create(user, password, sudo=Tru) + + # sudo = False + # if 'root_pw' not in archinstall.storage['_guided_hidden'] or len(archinstall.storage['_guided_hidden']['root_pw'].strip()) == 0: + # sudo = True + - if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): - installation.user_set_pw('root', root_pw) + if 'root_pw' in archinstall.storage['_guided_hidden'] and archinstall.storage['_guided_hidden']['root_pw']: + installation.user_set_pw('root', archinstall.storage['_guided_hidden']['root_pw']) def ask_user_questions(): """ @@ -322,4 +328,4 @@ def perform_installation_steps(): mirrors=archinstall.arguments['mirror-region']) ask_user_questions() -perform_pre_installation_steps() \ No newline at end of file +perform_installation_steps() \ No newline at end of file -- cgit v1.2.3-54-g00ecf From aabdce9286b9b39bbf89bb2ed65c4de5dcf61caa Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 16:16:05 +0100 Subject: fixed a global variable as well as re-organized the guided.py to better match the flow of steps.. 1) Ask user questions function, 2) Perform installation steps, 3) Perform actual installation --- examples/guided.py | 117 ++++++++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 9d242842..2a7414ea 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -20,62 +20,6 @@ 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.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 - # We need to wait for it before we continue since we opted in to use a custom mirror/region. - installation.log(f'Waiting for automatic mirror selection has completed before using custom mirrors.') - while 'dead' not in (status := archinstall.service_state('reflector')): - time.sleep(1) - - archinstall.use_mirrors(mirrors) # Set the mirrors for the live medium - if installation.minimal_installation(): - installation.set_mirrors(mirrors) # Set the mirrors in the installation medium - installation.set_keyboard_language(language) - installation.add_bootloader() - - # If user selected to copy the current ISO network configuration - # Perform a copy of the config - if archinstall.arguments.get('nic', None) == 'Copy ISO network configuration to installation': - installation.copy_ISO_network_config(enable_services=True) # Sources the ISO network configuration to the install medium. - - # Otherwise, if a interface was selected, configure that interface - elif archinstall.arguments.get('nic', None): - installation.configure_nic(**archinstall.arguments.get('nic', {})) - installation.enable_service('systemd-networkd') - installation.enable_service('systemd-resolved') - - - if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '': - installation.add_additional_packages(archinstall.arguments.get('packages', None)) - - if archinstall.arguments.get('profile', None) and len(profile := archinstall.arguments.get('profile').strip()): - installation.install_profile(profile) - - if archinstall.arguments.get('users', None): - for user in archinstall.arguments.get('users'): - password = users[user] - installation.user_create(user, password, sudo=False) - if archinstall.arguments.get('superusers', None): - for user in archinstall.arguments.get('users'): - password = users[user] - installation.user_create(user, password, sudo=Tru) - - # sudo = False - # if 'root_pw' not in archinstall.storage['_guided_hidden'] or len(archinstall.storage['_guided_hidden']['root_pw'].strip()) == 0: - # sudo = True - - - if 'root_pw' in archinstall.storage['_guided_hidden'] and archinstall.storage['_guided_hidden']['root_pw']: - installation.user_set_pw('root', archinstall.storage['_guided_hidden']['root_pw']) - def ask_user_questions(): """ First, we'll ask the user for a bunch of user input. @@ -245,7 +189,10 @@ def ask_user_questions(): if not archinstall.arguments.get('nic', None): archinstall.arguments['nic'] = archinstall.ask_to_configure_network() + def perform_installation_steps(): + global SIG_TRIGGER + print() print('This is your chosen configuration:') archinstall.log("-- Guided template chosen (with below config) --", level=archinstall.LOG_LEVELS.Debug) @@ -327,5 +274,63 @@ def perform_installation_steps(): language=archinstall.arguments['keyboard-language'], mirrors=archinstall.arguments['mirror-region']) + +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.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 + # We need to wait for it before we continue since we opted in to use a custom mirror/region. + installation.log(f'Waiting for automatic mirror selection has completed before using custom mirrors.') + while 'dead' not in (status := archinstall.service_state('reflector')): + time.sleep(1) + + archinstall.use_mirrors(mirrors) # Set the mirrors for the live medium + if installation.minimal_installation(): + installation.set_mirrors(mirrors) # Set the mirrors in the installation medium + installation.set_keyboard_language(language) + installation.add_bootloader() + + # If user selected to copy the current ISO network configuration + # Perform a copy of the config + if archinstall.arguments.get('nic', None) == 'Copy ISO network configuration to installation': + installation.copy_ISO_network_config(enable_services=True) # Sources the ISO network configuration to the install medium. + + # Otherwise, if a interface was selected, configure that interface + elif archinstall.arguments.get('nic', None): + installation.configure_nic(**archinstall.arguments.get('nic', {})) + installation.enable_service('systemd-networkd') + installation.enable_service('systemd-resolved') + + + if archinstall.arguments.get('packages', None) and archinstall.arguments.get('packages', None)[0] != '': + installation.add_additional_packages(archinstall.arguments.get('packages', None)) + + if archinstall.arguments.get('profile', None) and len(profile := archinstall.arguments.get('profile').strip()): + installation.install_profile(profile) + + if archinstall.arguments.get('users', None): + for user in archinstall.arguments.get('users'): + password = users[user] + installation.user_create(user, password, sudo=False) + if archinstall.arguments.get('superusers', None): + for user in archinstall.arguments.get('users'): + password = users[user] + installation.user_create(user, password, sudo=Tru) + + # sudo = False + # if 'root_pw' not in archinstall.storage['_guided_hidden'] or len(archinstall.storage['_guided_hidden']['root_pw'].strip()) == 0: + # sudo = True + + + if 'root_pw' in archinstall.storage['_guided_hidden'] and archinstall.storage['_guided_hidden']['root_pw']: + installation.user_set_pw('root', archinstall.storage['_guided_hidden']['root_pw']) + + ask_user_questions() perform_installation_steps() \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 3f8f0020f5ee8985806b1b62c8826f113ee9df51 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Tue, 9 Mar 2021 16:22:36 +0100 Subject: Purged last legacy, setting the root pw --- examples/guided.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/examples/guided.py b/examples/guided.py index 2a7414ea..9339f969 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -141,12 +141,6 @@ def ask_user_questions(): 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) archinstall.arguments['users'] = {} archinstall.arguments['superusers'] = {} @@ -323,13 +317,9 @@ def perform_installation(device, boot_partition, language, mirrors): password = users[user] installation.user_create(user, password, sudo=Tru) - # sudo = False - # if 'root_pw' not in archinstall.storage['_guided_hidden'] or len(archinstall.storage['_guided_hidden']['root_pw'].strip()) == 0: - # sudo = True - - if 'root_pw' in archinstall.storage['_guided_hidden'] and archinstall.storage['_guided_hidden']['root_pw']: - installation.user_set_pw('root', archinstall.storage['_guided_hidden']['root_pw']) + if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): + installation.user_set_pw('root', root_pw) ask_user_questions() -- cgit v1.2.3-54-g00ecf