From 45daebd989cb64d299c2be2feaa36927455392d3 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 21 Sep 2021 12:42:58 +0200 Subject: [PATCH 1/8] [initcpiocfg] Refactor CPU-characteristics determination The code is still over-wrought, but the API for cpuinfo now exposes the interesting thing (is it Intel?) in a useful -- more readable -- way. --- src/modules/initcpiocfg/main.py | 71 +++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index 4fb0923cd..d5cb101a1 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -28,35 +28,57 @@ def pretty_name(): return _("Configuring mkinitcpio.") -def cpuinfo(): +class cpuinfo(object): """ - Return the information in /proc/cpuinfo as a dictionary in the following - format: + Object describing the current CPU's characteristics. It may be + be considered a named tuple, there's no behavior here. - cpu_info['proc0']={...} - cpu_info['proc1']={...} + Fields in the object: + - is_intel (if it's definitely an Intel CPU) + - is_amd (if it's definitely an AMD CPU) + - number_of_cores + It is possible for both is_* fields to be False. """ - cpu_info = OrderedDict() - procinfo = OrderedDict() + def __init__(self): + self.is_intel = False + self.is_amd = False + self.number_of_cores = 0 - nprocs = 0 + cpu = self._cpuinfo() + self.is_intel = cpu['proc0']['vendor_id'].lower() == "genuineintel" + self.is_amd = cpu['proc0']['vendor_id'].lower() == "authenticamd" + self.number_of_cores = len(cpu) - with open('/proc/cpuinfo') as cpuinfo_file: - for line in cpuinfo_file: - if not line.strip(): - # end of one processor - cpu_info["proc{!s}".format(nprocs)] = procinfo - nprocs += 1 - # Reset - procinfo = OrderedDict() - else: - if len(line.split(':')) == 2: - splitted_line = line.split(':')[1].strip() - procinfo[line.split(':')[0].strip()] = splitted_line + @staticmethod + def _cpuinfo(): + """ + Return the information in /proc/cpuinfo as a dictionary in the following + format: + + cpu_info['proc0']={...} + cpu_info['proc1']={...} + """ + cpu_info = OrderedDict() + procinfo = OrderedDict() + + nprocs = 0 + + with open('/proc/cpuinfo') as cpuinfo_file: + for line in cpuinfo_file: + if not line.strip(): + # end of one processor + cpu_info["proc{!s}".format(nprocs)] = procinfo + nprocs += 1 + # Reset + procinfo = OrderedDict() else: - procinfo[line.split(':')[0].strip()] = '' + if len(line.split(':')) == 2: + splitted_line = line.split(':')[1].strip() + procinfo[line.split(':')[0].strip()] = splitted_line + else: + procinfo[line.split(':')[0].strip()] = '' - return cpu_info + return cpu_info def write_mkinitcpio_lines(hooks, modules, files, root_mount_point): @@ -172,10 +194,9 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): else: hooks.extend(["filesystems"]) - if btrfs == "yes" and cpu['proc0']['vendor_id'].lower() != "genuineintel": + if btrfs == "yes" and not cpu.is_intel: modules.append("crc32c") - elif (btrfs == "yes" - and cpu['proc0']['vendor_id'].lower() == "genuineintel"): + elif (btrfs == "yes" and cpu.is_intel): modules.append("crc32c-intel") else: hooks.append("fsck") From 7f7dc04e8dda8add2454a9b88ad175d56e871aa7 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 21 Sep 2021 12:52:16 +0200 Subject: [PATCH 2/8] [initcpiocfg] Use bools for boolean values Having "" and "yes" as values is a bit shell-script-ish. Use a regular boolean value instead; simplify code while we're at it. --- src/modules/initcpiocfg/main.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index d5cb101a1..bdc3f9cde 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -132,9 +132,8 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): :param partitions: :param root_mount_point: """ - cpu = cpuinfo() swap_uuid = "" - btrfs = "" + uses_btrfs = False lvm2 = "" hooks = ["base", "udev", "autodetect", "modconf", "block", "keyboard", "keymap"] @@ -159,7 +158,7 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): openswap_hook = True if partition["fs"] == "btrfs": - btrfs = "yes" + uses_btrfs = True if "lvm2" in partition["fs"]: lvm2 = "yes" @@ -194,10 +193,8 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): else: hooks.extend(["filesystems"]) - if btrfs == "yes" and not cpu.is_intel: - modules.append("crc32c") - elif (btrfs == "yes" and cpu.is_intel): - modules.append("crc32c-intel") + if uses_btrfs: + modules.append("crc32c-intel" if cpuinfo().is_intel else "crc32c") else: hooks.append("fsck") From 7c3c7c4ff79a66bdb6e3253d0ea4d86a988405b2 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 21 Sep 2021 12:54:18 +0200 Subject: [PATCH 3/8] [initcpiocfg] Use booleans for boolean values (as previous) Use False/True rather than ""/"yes" for keeping track of does-the-system-use-lvm2. --- src/modules/initcpiocfg/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index bdc3f9cde..fe0712a9a 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -134,7 +134,7 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): """ swap_uuid = "" uses_btrfs = False - lvm2 = "" + uses_lvm2 = False hooks = ["base", "udev", "autodetect", "modconf", "block", "keyboard", "keymap"] modules = [] @@ -161,7 +161,7 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): uses_btrfs = True if "lvm2" in partition["fs"]: - lvm2 = "yes" + uses_lvm2 = True if partition["mountPoint"] == "/" and "luksMapperName" in partition: encrypt_hook = True @@ -183,7 +183,7 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): ): files.append("/crypto_keyfile.bin") - if lvm2: + if uses_lvm2: hooks.append("lvm2") if swap_uuid != "": From 118e18ac6060c5df285f808023b64d5ade4fa9bf Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 21 Sep 2021 13:03:13 +0200 Subject: [PATCH 4/8] [initcpiocfg] Code-shuffle - put the system-information and -detection functions at top and the "do the actual work" things below - don't mix the boolean do-we-use-this flags with the lists of files and modules which are the important parts of modify_mkinitcpio_conf --- src/modules/initcpiocfg/main.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index fe0712a9a..b91a46086 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -28,6 +28,16 @@ def pretty_name(): return _("Configuring mkinitcpio.") +def detect_plymouth(): + """ + Checks existence (runnability) of plymouth in the target system. + + @return True if plymouth exists in the target, False otherwise + """ + # Used to only check existence of path /usr/bin/plymouth in target + return target_env_call(["sh", "-c", "which plymouth"]) == 0 + + class cpuinfo(object): """ Object describing the current CPU's characteristics. It may be @@ -115,16 +125,6 @@ def write_mkinitcpio_lines(hooks, modules, files, root_mount_point): mkinitcpio_file.write("\n".join(mklins) + "\n") -def detect_plymouth(): - """ - Checks existence (runnability) of plymouth in the target system. - - @return True if plymouth exists in the target, False otherwise - """ - # Used to only check existence of path /usr/bin/plymouth in target - return target_env_call(["sh", "-c", "which plymouth"]) == 0 - - def modify_mkinitcpio_conf(partitions, root_mount_point): """ Modifies mkinitcpio.conf @@ -132,13 +132,13 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): :param partitions: :param root_mount_point: """ + hooks = ["base", "udev", "autodetect", "modconf", "block", "keyboard", "keymap"] + modules = [] + files = [] + swap_uuid = "" uses_btrfs = False uses_lvm2 = False - hooks = ["base", "udev", "autodetect", "modconf", "block", "keyboard", - "keymap"] - modules = [] - files = [] encrypt_hook = False openswap_hook = False unencrypted_separate_boot = False From 60e495bd8c7645f2368ffa9215e0118a750ce635 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 21 Sep 2021 13:13:21 +0200 Subject: [PATCH 5/8] [initcpiocfg] Refactor, improve testability - don't chain directly from modify_mkinitcpio_conf() to the function that writes the file write_mkinitcpio_lines(); split into "figure out what needs to be written" and calling that writing-function, so that we can test / check / log if needed between the two. --- src/modules/initcpiocfg/main.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index b91a46086..d89c0f94f 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -125,12 +125,16 @@ def write_mkinitcpio_lines(hooks, modules, files, root_mount_point): mkinitcpio_file.write("\n".join(mklins) + "\n") -def modify_mkinitcpio_conf(partitions, root_mount_point): +def find_initcpio_features(partitions, root_mount_point): """ - Modifies mkinitcpio.conf + Returns a tuple (hooks, modules, files) needed to support + the given @p partitions (filesystems types, encryption, etc) + in the target. - :param partitions: - :param root_mount_point: + :param partitions: (from GS) + :param root_mount_point: (from GS) + + :return 3-tuple of lists """ hooks = ["base", "udev", "autodetect", "modconf", "block", "keyboard", "keymap"] modules = [] @@ -198,7 +202,7 @@ def modify_mkinitcpio_conf(partitions, root_mount_point): else: hooks.append("fsck") - write_mkinitcpio_lines(hooks, modules, files, root_mount_point) + return (hooks, modules, files) def run(): @@ -219,6 +223,7 @@ def run(): return (_("Configuration Error"), _("No root mount point is given for
{!s}
to use." ).format("initcpiocfg")) - modify_mkinitcpio_conf(partitions, root_mount_point) + hooks, modules, files = find_initcpio_features(partitions, root_mount_point) + write_mkinitcpio_lines(hooks, modules, files, root_mount_point) return None From 12cd9dd5b22a9274a2486df656b81232b973ae3c Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 21 Sep 2021 13:18:01 +0200 Subject: [PATCH 6/8] [initcpiocfg] Refactor - Read the host /etc/mkinitcpio.cfg in one function rather than hiding it inside the writer --- src/modules/initcpiocfg/main.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index d89c0f94f..f209a7376 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -91,6 +91,23 @@ class cpuinfo(object): return cpu_info +def get_host_initcpio(): + """ + Reads the host system mkinitcpio.conf and returns all + the lines from that file, or an empty list if it does + not exist. + """ + hostfile = "/etc/mkinitcpio.conf" + try: + with open(hostfile, "r") as mkinitcpio_file: + mklins = [x.strip() for x in mkinitcpio_file.readlines()] + except FileNotFoundError: + libcalamares.utils.debug("Could not open host file '%s'" % hostfile) + mklins = [] + + return mklins + + def write_mkinitcpio_lines(hooks, modules, files, root_mount_point): """ Set up mkinitcpio.conf. @@ -100,13 +117,7 @@ def write_mkinitcpio_lines(hooks, modules, files, root_mount_point): :param files: :param root_mount_point: """ - hostfile = "/etc/mkinitcpio.conf" - try: - with open(hostfile, "r") as mkinitcpio_file: - mklins = [x.strip() for x in mkinitcpio_file.readlines()] - except FileNotFoundError: - libcalamares.utils.debug("Could not open host file '%s'" % hostfile) - mklins = [] + mklins = get_host_initcpio() for i in range(len(mklins)): if mklins[i].startswith("HOOKS"): From a4c714238fe1666814309efee861ed1564acb1a3 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 21 Sep 2021 13:39:29 +0200 Subject: [PATCH 7/8] [initcpio] Refactor file-writing - iterate over the lines of the source file, rather than over indexes, and make clear that the hooks, modules and files lines are replaced, rather than merged. - this calls write() more often, but it's only a few lines --- src/modules/initcpiocfg/main.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/modules/initcpiocfg/main.py b/src/modules/initcpiocfg/main.py index f209a7376..903ef635f 100644 --- a/src/modules/initcpiocfg/main.py +++ b/src/modules/initcpiocfg/main.py @@ -119,21 +119,18 @@ def write_mkinitcpio_lines(hooks, modules, files, root_mount_point): """ mklins = get_host_initcpio() - for i in range(len(mklins)): - if mklins[i].startswith("HOOKS"): - joined_hooks = ' '.join(hooks) - mklins[i] = "HOOKS=\"{!s}\"".format(joined_hooks) - elif mklins[i].startswith("MODULES"): - joined_modules = ' '.join(modules) - mklins[i] = "MODULES=\"{!s}\"".format(joined_modules) - elif mklins[i].startswith("FILES"): - joined_files = ' '.join(files) - mklins[i] = "FILES=\"{!s}\"".format(joined_files) - - path = os.path.join(root_mount_point, "etc/mkinitcpio.conf") - - with open(path, "w") as mkinitcpio_file: - mkinitcpio_file.write("\n".join(mklins) + "\n") + target_path = os.path.join(root_mount_point, "etc/mkinitcpio.conf") + with open(target_path, "w") as mkinitcpio_file: + for line in mklins: + # Replace HOOKS, MODULES and FILES lines with what we + # have found via find_initcpio_features() + if line.startswith("HOOKS"): + line = "HOOKS=\"{!s}\"".format(' '.join(hooks)) + elif line.startswith("MODULES"): + line = "MODULES=\"{!s}\"".format(' '.join(modules)) + elif lines.startswith("FILES"): + line = "FILES=\"{!s}\"".format(' '.join(files)) + mkinitcpio_file.write(line + "\n") def find_initcpio_features(partitions, root_mount_point): From cb92e49363a3dbb58cb5da7a693d8521ead86ab2 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 21 Sep 2021 15:16:08 +0200 Subject: [PATCH 8/8] [initcpiocfg] Document this module --- src/modules/initcpiocfg/module.desc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/initcpiocfg/module.desc b/src/modules/initcpiocfg/module.desc index a4476121b..a64fdf173 100644 --- a/src/modules/initcpiocfg/module.desc +++ b/src/modules/initcpiocfg/module.desc @@ -1,7 +1,13 @@ # SPDX-FileCopyrightText: no # SPDX-License-Identifier: CC0-1.0 +# +# Writes a mkinitcpio.conf into the target system. It copies +# the host system's /etc/mkinitcpio.conf, and replaces any +# HOOKS, MODULES, and FILES lines with calculated values +# based on what the installation (seems to) need. --- type: "job" name: "initcpiocfg" interface: "python" script: "main.py" +noconfig: true