From 5483b218fd62fcea8648525eb8aa6b7af4cc200b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 14 Mar 2021 11:53:59 +0100 Subject: Removing hardcoded boot-loader config name. #51. --- archinstall/lib/installer.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 06bdd05a..b45ad1dc 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -311,18 +311,24 @@ class Installer(): self.log(f'Adding bootloader {bootloader} to {self.boot_partition}', level=LOG_LEVELS.Info) if bootloader == 'systemd-bootctl': + # TODO: Ideally we would want to check if another config + # points towards the same disk and/or partition. + # And in which case we should do some clean up. + unique_loader_conf_name = hashlib.md5(os.urandom(12)+bytes(str(time.time()), 'UTF-8')).hexdigest() + o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} bootctl --no-variables --path=/boot install')) with open(f'{self.mountpoint}/boot/loader/loader.conf', 'w') as loader: - loader.write('default arch\n') - loader.write('timeout 5\n') + loader.write(f'default {unique_loader_conf_name}\n') + loader.write(f'timeout 5\n') ## For some reason, blkid and /dev/disk/by-uuid are not getting along well. ## And blkid is wrong in terms of LUKS. #UUID = sys_command('blkid -s PARTUUID -o value {drive}{partition_2}'.format(**args)).decode('UTF-8').strip() - with open(f'{self.mountpoint}/boot/loader/entries/arch.conf', 'w') as entry: - entry.write('title Arch Linux\n') - entry.write('linux /vmlinuz-linux\n') - entry.write('initrd /initramfs-linux.img\n') + + with open(f'{self.mountpoint}/boot/loader/entries/{unique_loader_conf_name}.conf', 'w') as entry: + entry.write(f'title Arch Linux\n') + entry.write(f'linux /vmlinuz-linux\n') + entry.write(f'initrd /initramfs-linux.img\n') ## blkid doesn't trigger on loopback devices really well, ## so we'll use the old manual method until we get that sorted out. -- cgit v1.2.3-70-g09d2 From abd15f9ff5a53face8b5d8efc29118b7362735b2 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 14 Mar 2021 14:41:13 +0100 Subject: Added error handling for install_profile() if string vs Profile() is given as an argument. --- archinstall/lib/installer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index b45ad1dc..3daf96f4 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -363,7 +363,8 @@ class Installer(): return self.pacstrap(*packages) def install_profile(self, profile): - profile = Profile(self, profile) + if type(profile) == str: + profile = Profile(self, profile) self.log(f'Installing network profile {profile}', level=LOG_LEVELS.Info) return profile.install() -- cgit v1.2.3-70-g09d2 From b90820c1c0e4848b683bbee8e3ffe489b4031935 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 14 Mar 2021 14:58:06 +0100 Subject: Made add_bootloader() a little bit more robust, it shouldn't overwrite the existing loader.conf completely, only the default option. We're still left with a lot of garbage entries if installed multiple times on the same boot partition. #51 --- archinstall/lib/installer.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 3daf96f4..39e3447d 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -314,18 +314,35 @@ class Installer(): # TODO: Ideally we would want to check if another config # points towards the same disk and/or partition. # And in which case we should do some clean up. - unique_loader_conf_name = hashlib.md5(os.urandom(12)+bytes(str(time.time()), 'UTF-8')).hexdigest() - o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} bootctl --no-variables --path=/boot install')) + # Install the boot loader + sys_command(f'/usr/bin/arch-chroot {self.mountpoint} bootctl --no-variables --path=/boot install') + + # Modify or create a loader.conf + if os.path.isfile(f'{self.mountpoint}/boot/loader/loader.conf'): + with open(f'{self.mountpoint}/boot/loader/loader.conf', 'r') as loader: + loader_data = loader.read().split('\n') + else: + loader_data = [ + f"default {self.init_time}", + f"timeout 5" + ] + with open(f'{self.mountpoint}/boot/loader/loader.conf', 'w') as loader: - loader.write(f'default {unique_loader_conf_name}\n') - loader.write(f'timeout 5\n') + for line in loader_data: + if line[:8] == 'default ': + loader.write(f'default {self.init_time}\n') + else: + loader.write(f"{line}") ## For some reason, blkid and /dev/disk/by-uuid are not getting along well. ## And blkid is wrong in terms of LUKS. #UUID = sys_command('blkid -s PARTUUID -o value {drive}{partition_2}'.format(**args)).decode('UTF-8').strip() - with open(f'{self.mountpoint}/boot/loader/entries/{unique_loader_conf_name}.conf', 'w') as entry: + # Setup the loader entry + with open(f'{self.mountpoint}/boot/loader/entries/{self.init_time}.conf', 'w') as entry: + entry.write(f'# Created by: archinstall\n') + entry.write(f'# Created on: {self.init_time}\n') entry.write(f'title Arch Linux\n') entry.write(f'linux /vmlinuz-linux\n') entry.write(f'initrd /initramfs-linux.img\n') -- cgit v1.2.3-70-g09d2 From b67257233f43fa8d34dacd6ecc3dc7cbbf60d221 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sat, 20 Mar 2021 17:26:48 +0100 Subject: Fixed #64. installation.set_timezone() already excisted since earlier versions of archinstall in the library section. The guided.py example simply never asked for a time-zone. There's still no NTP option, which I'll add in later. Mostly because there's a lot of settings one can do to a time-client configuration, and I'm not sure all users want the default time servers etc. --- archinstall/lib/installer.py | 5 +++-- archinstall/lib/user_interaction.py | 7 ++++++- examples/guided.py | 6 ++++++ 3 files changed, 15 insertions(+), 3 deletions(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 39e3447d..2604e77d 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -1,4 +1,4 @@ -import os, stat, time, shutil +import os, stat, time, shutil, pathlib from .exceptions import * from .disk import * @@ -171,7 +171,8 @@ class Installer(): def set_timezone(self, zone, *args, **kwargs): if not len(zone): return True - o = b''.join(sys_command(f'/usr/bin/arch-chroot {self.mountpoint} ln -s /usr/share/zoneinfo/{zone} /etc/localtime')) + (pathlib.Path(self.mountpoint)/"etc"/"localtime").unlink(missing_ok=True) + sys_command(f'/usr/bin/arch-chroot {self.mountpoint} ln -s /usr/share/zoneinfo/{zone} /etc/localtime') return True def activate_ntp(self): diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index ab2b19bc..6b3e5faa 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -1,4 +1,4 @@ -import getpass +import getpass, pathlib from .exceptions import * from .profiles import Profile from .locale_helpers import search_keyboard_layout @@ -50,6 +50,11 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan return users, super_users +def ask_for_a_timezone(): + timezone = input('Enter a valid timezone (Example: Europe/Stockholm): ').strip() + if pathlib.Path(timezone).exists(): + return timezone + def ask_to_configure_network(): # Optionally configure one network interface. #while 1: diff --git a/examples/guided.py b/examples/guided.py index 655fc29f..e9edac09 100644 --- a/examples/guided.py +++ b/examples/guided.py @@ -190,6 +190,9 @@ def ask_user_questions(): if not archinstall.arguments['nic']: archinstall.log(f"No network configuration was selected. Network is going to be unavailable until configured manually!", fg="yellow") + if not archinstall.arguments.get('timezone', None): + archinstall.arguments['timezone'] = archinstall.ask_for_a_timezone() + def perform_installation_steps(): global SIG_TRIGGER @@ -323,6 +326,9 @@ def perform_installation(device, boot_partition, language, mirrors): for superuser, user_info in archinstall.arguments.get('superusers', {}).items(): installation.user_create(superuser, user_info["!password"], sudo=True) + if (timezone := archinstall.arguments.get('timezone', None)): + installation.set_timezone(timezone) + if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw): installation.user_set_pw('root', root_pw) -- cgit v1.2.3-70-g09d2 From 93faf07b6948074e9071faf75f96ff220714d5f9 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 21 Mar 2021 15:25:24 +0100 Subject: Moved the globalization of 'installation' variable. Since Profile() might be created before the installation instance, we need to move the global variable declaration after installation has begun and there's an installation instance. --- archinstall/lib/installer.py | 9 +++++++++ archinstall/lib/profiles.py | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 2604e77d..8d7d6967 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -381,6 +381,15 @@ class Installer(): return self.pacstrap(*packages) def install_profile(self, profile): + # TODO: Replace this with a import archinstall.session instead in the profiles. + # The tricky thing with doing the import archinstall.session instead is that + # profiles might be run from a different chroot, and there's no way we can + # guarantee file-path safety when accessing the installer object that way. + # Doing the __builtins__ replacement, ensures that the global vriable "installation" + # is always kept up to date. It's considered a nasty hack - but it's a safe way + # of ensuring 100% accuracy of archinstall session variables. + __builtins__['installation'] = self.installer + if type(profile) == str: profile = Profile(self, profile) diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index 34ba09da..ee2ff39a 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -142,7 +142,6 @@ class Script(): if not self.namespace in sys.modules or self.spec is None: self.load_instructions() - __builtins__['installation'] = self.installer # TODO: Replace this with a import archinstall.session instead self.spec.loader.exec_module(sys.modules[self.namespace]) return sys.modules[self.namespace] -- cgit v1.2.3-70-g09d2 From 35e774f5f60e09f5a9a4deb7fb6317d87c9a131f Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 21 Mar 2021 15:28:11 +0100 Subject: Spelling error on variable. --- archinstall/lib/installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 8d7d6967..db73d324 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -388,7 +388,7 @@ class Installer(): # Doing the __builtins__ replacement, ensures that the global vriable "installation" # is always kept up to date. It's considered a nasty hack - but it's a safe way # of ensuring 100% accuracy of archinstall session variables. - __builtins__['installation'] = self.installer + __builtins__['installation'] = self if type(profile) == str: profile = Profile(self, profile) -- cgit v1.2.3-70-g09d2 From 2fab088314d4d7e9f580376d035db1c2a96e043a Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 21 Mar 2021 16:48:22 +0100 Subject: Added some debugging to help identify why archinstall cannot find unencrypted devices when setting up the boot loader. --- archinstall/lib/installer.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index db73d324..4b964773 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -352,6 +352,7 @@ class Installer(): if self.partition.encrypted: + log(f"Identifying root partition {self.partition} to boot based on disk UUID, looking for '{os.path.basename(self.partition.real_device)}'.", level=LOG_LEVELS.Info) for root, folders, uids in os.walk('/dev/disk/by-uuid'): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) @@ -363,6 +364,7 @@ class Installer(): return True break else: + log(f"Identifying root partition {self.partition} to boot based on partition UUID, looking for '{os.path.basename(self.partition.path)}'.", level=LOG_LEVELS.Info) for root, folders, uids in os.walk('/dev/disk/by-partuuid'): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) @@ -373,6 +375,7 @@ class Installer(): self.helper_flags['bootloader'] = bootloader return True break + raise RequirementError(f"Could not identify the UUID of {self.partition}, there for {self.mountpoint}/boot/loader/entries/arch.conf will be broken until fixed.") else: raise RequirementError(f"Unknown (or not yet implemented) bootloader added to add_bootloader(): {bootloader}") -- cgit v1.2.3-70-g09d2 From dbe086024d5fc1ab25218f1ea0e063881e66efd6 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 21 Mar 2021 16:58:27 +0100 Subject: Moved some info logs into debug instead to minimize user splash. --- archinstall/lib/installer.py | 4 ++-- archinstall/lib/profiles.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 4b964773..1c66f6ac 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -352,7 +352,7 @@ class Installer(): if self.partition.encrypted: - log(f"Identifying root partition {self.partition} to boot based on disk UUID, looking for '{os.path.basename(self.partition.real_device)}'.", level=LOG_LEVELS.Info) + log(f"Identifying root partition {self.partition} to boot based on disk UUID, looking for '{os.path.basename(self.partition.real_device)}'.", level=LOG_LEVELS.Debug) for root, folders, uids in os.walk('/dev/disk/by-uuid'): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) @@ -364,7 +364,7 @@ class Installer(): return True break else: - log(f"Identifying root partition {self.partition} to boot based on partition UUID, looking for '{os.path.basename(self.partition.path)}'.", level=LOG_LEVELS.Info) + log(f"Identifying root partition {self.partition} to boot based on partition UUID, looking for '{os.path.basename(self.partition.path)}'.", level=LOG_LEVELS.Debug) for root, folders, uids in os.walk('/dev/disk/by-partuuid'): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) diff --git a/archinstall/lib/profiles.py b/archinstall/lib/profiles.py index e9639451..08b1d618 100644 --- a/archinstall/lib/profiles.py +++ b/archinstall/lib/profiles.py @@ -77,7 +77,7 @@ class Script(): self.examples = None self.namespace = os.path.splitext(os.path.basename(self.path))[0] self.original_namespace = self.namespace - log(f"Script {self} has been loaded with namespace '{self.namespace}'") + log(f"Script {self} has been loaded with namespace '{self.namespace}'", level=LOG_LEVELS.Debug) def __enter__(self, *args, **kwargs): self.execute() -- cgit v1.2.3-70-g09d2 From fd4594d08cbf6de37bdd82e31af64fbec6cce4b5 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 21 Mar 2021 20:56:15 +0100 Subject: Added a mkinitcpio configuration for non-btrfs volumes but where encryption is still used. Also added keymap to the HOOKS so that we can get non-us layouts depending on the locale chosen during installation. --- archinstall/lib/installer.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 1c66f6ac..2200db8e 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -290,13 +290,22 @@ class Installer(): # TODO: Use python functions for this sys_command(f'/usr/bin/arch-chroot {self.mountpoint} chmod 700 /root') + # Configure mkinitcpio to handle some specific use cases. + # TODO: Yes, we should not overwrite the entire thing, but for now this should be fine + # since we just installed the base system. if self.partition.filesystem == 'btrfs': with open(f'{self.mountpoint}/etc/mkinitcpio.conf', 'w') as mkinit: - ## TODO: Don't replace it, in case some update in the future actually adds something. mkinit.write('MODULES=(btrfs)\n') mkinit.write('BINARIES=(/usr/bin/btrfs)\n') mkinit.write('FILES=()\n') - mkinit.write('HOOKS=(base udev autodetect modconf block encrypt filesystems keyboard fsck)\n') + mkinit.write('HOOKS=(base udev autodetect modconf block encrypt filesystems keymap keyboard fsck)\n') + sys_command(f'/usr/bin/arch-chroot {self.mountpoint} mkinitcpio -p linux') + elif self.partition.encrypted: + with open(f'{self.mountpoint}/etc/mkinitcpio.conf', 'w') as mkinit: + mkinit.write('MODULES=()\n') + mkinit.write('BINARIES=()\n') + mkinit.write('FILES=()\n') + mkinit.write('HOOKS=(base udev autodetect modconf block encrypt filesystems keymap keyboard fsck)\n') sys_command(f'/usr/bin/arch-chroot {self.mountpoint} mkinitcpio -p linux') self.helper_flags['base'] = True -- cgit v1.2.3-70-g09d2 From 37a6018aaeed53ca95d9c7f81981db98aab24eab Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 28 Mar 2021 22:36:47 +0200 Subject: Fixed a path-check issue with Time Zones. --- archinstall/lib/installer.py | 16 ++++++++++++---- archinstall/lib/user_interaction.py | 8 +++++++- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index 2200db8e..ff47be01 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -169,11 +169,19 @@ class Installer(): return True if sys_command(f'/usr/bin/arch-chroot {self.mountpoint} locale-gen').exit_code == 0 else False def set_timezone(self, zone, *args, **kwargs): - if not len(zone): return True + if not zone: return True + if not len(zone): return True # Redundant - (pathlib.Path(self.mountpoint)/"etc"/"localtime").unlink(missing_ok=True) - sys_command(f'/usr/bin/arch-chroot {self.mountpoint} ln -s /usr/share/zoneinfo/{zone} /etc/localtime') - return True + if (pathlib.Path("/usr")/"share"/"zoneinfo"/zone).exists(): + (pathlib.Path(self.mountpoint)/"etc"/"localtime").unlink(missing_ok=True) + sys_command(f'/usr/bin/arch-chroot {self.mountpoint} ln -s /usr/share/zoneinfo/{zone} /etc/localtime') + return True + else: + self.log( + f"Time zone {zone} does not exist, continuing with system default.", + level=LOG_LEVELS.Warning, + fg='red' + ) def activate_ntp(self): self.log(f'Installing and activating NTP.', level=LOG_LEVELS.Info) diff --git a/archinstall/lib/user_interaction.py b/archinstall/lib/user_interaction.py index e462c370..a79b4847 100644 --- a/archinstall/lib/user_interaction.py +++ b/archinstall/lib/user_interaction.py @@ -77,8 +77,14 @@ def ask_for_additional_users(prompt='Any additional users to install (leave blan def ask_for_a_timezone(): timezone = input('Enter a valid timezone (Example: Europe/Stockholm): ').strip() - if pathlib.Path(timezone).exists(): + if (pathlib.Path("/usr")/"share"/"zoneinfo"/timezone).exists(): return timezone + else: + log( + f"Time zone {timezone} does not exist, continuing with system default.", + level=LOG_LEVELS.Warning, + fg='red' + ) def ask_to_configure_network(): # Optionally configure one network interface. -- cgit v1.2.3-70-g09d2 From 37ad64147f4f20823e789a16a2e48016299d0607 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 28 Mar 2021 23:10:23 +0200 Subject: Added some more useful debug data to the log. --- archinstall/lib/installer.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'archinstall/lib/installer.py') diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py index ff47be01..d161c3b7 100644 --- a/archinstall/lib/installer.py +++ b/archinstall/lib/installer.py @@ -369,10 +369,12 @@ class Installer(): if self.partition.encrypted: - log(f"Identifying root partition {self.partition} to boot based on disk UUID, looking for '{os.path.basename(self.partition.real_device)}'.", level=LOG_LEVELS.Debug) + log(f"Identifying root partition by DISK-UUID on {self.partition}, looking for '{os.path.basename(self.partition.real_device)}'.", level=LOG_LEVELS.Debug) for root, folders, uids in os.walk('/dev/disk/by-uuid'): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) + + log(f"Checking root partition match {os.path.basename(real_path)} against {os.path.basename(self.partition.real_device)}: {os.path.basename(real_path) == os.path.basename(self.partition.real_device)}", level=LOG_LEVELS.Debug) if not os.path.basename(real_path) == os.path.basename(self.partition.real_device): continue entry.write(f'options cryptdevice=UUID={uid}:luksdev root=/dev/mapper/luksdev rw intel_pstate=no_hwp\n') @@ -381,10 +383,12 @@ class Installer(): return True break else: - log(f"Identifying root partition {self.partition} to boot based on partition UUID, looking for '{os.path.basename(self.partition.path)}'.", level=LOG_LEVELS.Debug) + log(f"Identifying root partition by PART-UUID on {self.partition}, looking for '{os.path.basename(self.partition.path)}'.", level=LOG_LEVELS.Debug) for root, folders, uids in os.walk('/dev/disk/by-partuuid'): for uid in uids: real_path = os.path.realpath(os.path.join(root, uid)) + + log(f"Checking root partition match {os.path.basename(real_path)} against {os.path.basename(self.partition.path)}: {os.path.basename(real_path) == os.path.basename(self.partition.path)}", level=LOG_LEVELS.Debug) if not os.path.basename(real_path) == os.path.basename(self.partition.path): continue entry.write(f'options root=PARTUUID={uid} rw intel_pstate=no_hwp\n') -- cgit v1.2.3-70-g09d2