diff --git a/anaconda.spec b/anaconda.spec index bea58de..d2229bb 100644 --- a/anaconda.spec +++ b/anaconda.spec @@ -1,7 +1,7 @@ %define _empty_manifest_terminate_build 0 Name: anaconda Version: 36.16.5 -Release: 15 +Release: 18 Summary: Graphical system installer License: GPLv2+ and MIT URL: http://fedoraproject.org/wiki/Anaconda @@ -37,10 +37,17 @@ Patch9015: bugfix-change-gnome-kiosk-to-use-metacity.patch Patch9016: bugfix-add-log-and-background.patch Patch9017: bugfix-add-SM3-with-tui.patch Patch9018: bugfix-change-product-name-do-not-with-upper.patch +Patch6003: backport-dracut-handle-compressed-kernel-modules.patch +Patch6004: backport-Ignore-SIGINT-in-D-Bus-launcher-and-x11-too.patch +Patch6005: backport-network-use-separate-main-conext-for-NM-client-in-threads.patch +Patch6006: backport-Sort-RPM-versions-via-rpm.labelCompare-and-not-via-p.patch + Patch9019: bugfix-adapt-active-connection-without-interface-name.patch Patch9020: bugfix-password-tooltip-text-adapt-language.patch +Patch9021: bugfix-revert-Unify-GRUB-configuration-file-location-across-all-platforms.patch + %define dasbusver 1.3 %define dbusver 1.2.3 %define dnfver 3.6.0 @@ -282,6 +289,27 @@ update-desktop-database &> /dev/null || : %{_prefix}/libexec/anaconda/dd_* %changelog +* Fri Jun 09 2023 sunhai - 36.16.5-18 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: set grub configuration file is as original + +* Fri Jun 09 2023 sunhai - 36.16.5-17 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: Ignore SIGINT in D Bus launcher and x11 too + network use separate main conext for NM client in threads + dracut handle compressed kernel modules + Sort RPM versions via rpm.labelCompare + +* Sat Jun 03 2023 sunhai - 36.16.5-16 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix gui hostname warn info + * Tue May 16 2023 Chenxi Mao - 36.16.5-15 - Type:bugfix - ID:NA diff --git a/backport-Ignore-SIGINT-in-D-Bus-launcher-and-x11-too.patch b/backport-Ignore-SIGINT-in-D-Bus-launcher-and-x11-too.patch new file mode 100644 index 0000000..ad950d4 --- /dev/null +++ b/backport-Ignore-SIGINT-in-D-Bus-launcher-and-x11-too.patch @@ -0,0 +1,76 @@ +From d8060d01a01e3d5b187ae4388f10b0d0c2c0c4f3 Mon Sep 17 00:00:00 2001 +From: iasunsea +Date: Tue, 6 Dec 2022 18:24:50 +0800 +Subject: [PATCH] Ignore SIGINT in D-Bus launcher and x11 too + +When we do install, especially use TUI to install, we some time have take +a mistake to put "CTRL+C", then there will be stop with traceback. And we +know the main process have shielded SIGINT, so we to shield subprocesses also. + +Conflict:NA +Reference:https://github.com/rhinstaller/anaconda/commit/d8060d01a01e3d5b187ae4388f10b0d0c2c0c4f3 +--- + pyanaconda/core/startup/dbus_launcher.py | 6 ++++++ + pyanaconda/display.py | 8 +++++++- + 2 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/pyanaconda/core/startup/dbus_launcher.py b/pyanaconda/core/startup/dbus_launcher.py +index 2881c28..a866df0 100644 +--- a/pyanaconda/core/startup/dbus_launcher.py ++++ b/pyanaconda/core/startup/dbus_launcher.py +@@ -24,6 +24,7 @@ + # Author(s): Jiri Konecny + # + import os ++import signal + from subprocess import TimeoutExpired + + from pyanaconda.core.configuration.anaconda import conf +@@ -109,6 +110,10 @@ class AnacondaDBusLauncher(object): + "--syslog", + "--config-file={}".format(ANACONDA_BUS_CONF_FILE) + ] ++ ++ def dbus_preexec(): ++ # to set dbus subprocess SIGINT handler ++ signal.signal(signal.SIGINT, signal.SIG_IGN) + + self._log_file = open('/tmp/dbus.log', 'a') + self._dbus_daemon_process = startProgram( +@@ -117,6 +122,7 @@ class AnacondaDBusLauncher(object): + env_add={"LANG": DEFAULT_LANG}, + env_prune=["LANGUAGE", "LC_ALL", "LC_MESSAGES"], + reset_lang=False, ++ preexec_fn=dbus_preexec + ) + + if self._dbus_daemon_process.poll() is not None: +diff --git a/pyanaconda/display.py b/pyanaconda/display.py +index ddf24fb..ed163e7 100644 +--- a/pyanaconda/display.py ++++ b/pyanaconda/display.py +@@ -24,6 +24,7 @@ import subprocess + import time + import textwrap + import pkgutil ++import signal + + from pyanaconda.core.configuration.anaconda import conf + from pyanaconda.core.process_watchers import WatchProcesses +@@ -192,8 +193,13 @@ def do_startup_x11_actions(): + else: + xdg_data_dirs = datadir + '/window-manager:/usr/share' + ++ def x11_preexec(): ++ # to set GUI subprocess SIGINT handler ++ signal.signal(signal.SIGINT, signal.SIG_IGN) ++ + childproc = util.startProgram(["metacity", "--display", ":1", "--sm-disable"], +- env_add={'XDG_DATA_DIRS': xdg_data_dirs}) ++ env_add={'XDG_DATA_DIRS': xdg_data_dirs}, ++ preexec_fn=x11_preexec) + WatchProcesses.watch_process(childproc, "metacity") + + +-- +2.23.0 \ No newline at end of file diff --git a/backport-Sort-RPM-versions-via-rpm.labelCompare-and-not-via-p.patch b/backport-Sort-RPM-versions-via-rpm.labelCompare-and-not-via-p.patch new file mode 100644 index 0000000..447c5b9 --- /dev/null +++ b/backport-Sort-RPM-versions-via-rpm.labelCompare-and-not-via-p.patch @@ -0,0 +1,109 @@ +From 1742188518c9af7e3cd060a26f3a3b1e4cb61e91 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= +Date: Fri, 3 Feb 2023 21:46:15 +0100 +Subject: [PATCH] Sort RPM versions via rpm.labelCompare() and not via + packaging.version.LegacyVersion() + +Packaging 22+ removed the long-deprecated packaging.version.LegacyVersion class. +The packaging.version library is intended to parse Python (PEP 440) versions, +not arbitrary versions and definitively not RPM versions. + +Even if LegacyVersion was still available, it may produce incorrect results +if the version contains ~, ^ or other characters with special meaning in RPM. + +This assumes the Python rpm module is always available. +If that assumption is wrong +the logic from rpm.labelCompare() needs to be reimplemented instead. + +Reference:https://github.com/rhinstaller/anaconda/commit/1742188518c9af7e3cd060a26f3a3b1e4cb61e91 +Conflict:NA +--- + pyanaconda/core/payload.py | 5 +++++ + pyanaconda/modules/payloads/base/utils.py | 13 ++----------- + pyanaconda/modules/storage/checker/utils.py | 4 ++-- + 3 files changed, 9 insertions(+), 13 deletions(-) + +diff --git a/pyanaconda/core/payload.py b/pyanaconda/core/payload.py +index 17277b7..7817150 100644 +--- a/pyanaconda/core/payload.py ++++ b/pyanaconda/core/payload.py +@@ -15,11 +15,16 @@ + # License and may only be used or replicated with the express permission of + # Red Hat, Inc. + # ++from functools import cmp_to_key + from urllib.parse import quote, unquote + ++import rpm ++ + from pyanaconda.core.i18n import _ + from pyanaconda.core.regexes import URL_PARSE + ++rpm_version_key = cmp_to_key(rpm.labelCompare) ++ + + def parse_nfs_url(nfs_url): + """Parse NFS URL into components. +diff --git a/pyanaconda/modules/payloads/base/utils.py b/pyanaconda/modules/payloads/base/utils.py +index 738ae66..5f19b57 100644 +--- a/pyanaconda/modules/payloads/base/utils.py ++++ b/pyanaconda/modules/payloads/base/utils.py +@@ -17,13 +17,11 @@ + # License and may only be used or replicated with the express permission of + # Red Hat, Inc. + # +-import functools + import os + import stat + +-from packaging.version import LegacyVersion as parse_version +- + from pyanaconda.anaconda_loggers import get_module_logger ++from pyanaconda.core.payload import rpm_version_key + log = get_module_logger(__name__) + + +@@ -70,11 +68,4 @@ def get_dir_size(directory): + + def sort_kernel_version_list(kernel_version_list): + """Sort the given kernel version list.""" +- kernel_version_list.sort(key=functools.cmp_to_key(_compare_versions)) +- +- +-def _compare_versions(v1, v2): +- """Compare two version number strings.""" +- first_version = parse_version(v1) +- second_version = parse_version(v2) +- return (first_version > second_version) - (first_version < second_version) ++ kernel_version_list.sort(key=rpm_version_key) +diff --git a/pyanaconda/modules/storage/checker/utils.py b/pyanaconda/modules/storage/checker/utils.py +index 180c351..9ccd398 100644 +--- a/pyanaconda/modules/storage/checker/utils.py ++++ b/pyanaconda/modules/storage/checker/utils.py +@@ -20,7 +20,6 @@ gi.require_version("BlockDev", "2.0") + from gi.repository import BlockDev as blockdev + + from collections import defaultdict +-from packaging.version import LegacyVersion as parse_version + + from blivet import arch, util + from blivet.devicefactory import get_device_type +@@ -34,6 +33,7 @@ from pyanaconda.core.constants import productName, STORAGE_REFORMAT_BLOCKLIST, \ + STORAGE_LUKS2_MIN_RAM, STORAGE_ROOT_DEVICE_TYPES, STORAGE_REQ_PARTITION_SIZES, \ + STORAGE_MUST_NOT_BE_ON_ROOT + from pyanaconda.core.i18n import _ ++from pyanaconda.core.payload import rpm_version_key + from pyanaconda.core.storage import DEVICE_TEXT_MAP + from pyanaconda.modules.storage.platform import platform + +@@ -259,7 +259,7 @@ def _check_opal_firmware_kernel_version(detected_version, required_version): + """ + try: + if detected_version and required_version: +- return parse_version(detected_version) >= parse_version(required_version) ++ return rpm_version_key(detected_version) >= rpm_version_key(required_version) + except Exception as e: # pylint: disable=broad-except + log.warning("Couldn't check the firmware kernel version: %s", str(e)) + +-- +2.23.0 \ No newline at end of file diff --git a/backport-dracut-handle-compressed-kernel-modules.patch b/backport-dracut-handle-compressed-kernel-modules.patch new file mode 100644 index 0000000..651da26 --- /dev/null +++ b/backport-dracut-handle-compressed-kernel-modules.patch @@ -0,0 +1,47 @@ +From c4a388d3956088c96631b72f0631db2a380127b0 Mon Sep 17 00:00:00 2001 +From: Mikhail Novosyolov +Date: Fri, 10 Jun 2022 22:03:43 +0300 +Subject: [PATCH] dracut: handle compressed kernel modules + +Compressed kernel modules could not be loaded. +Now both compressed and not compressed ones will be loaded. + +$ uname -r +5.10.74-generic-2rosa2021.1-x86_64 +$ ls -1v /lib/modules/$(uname -r)/kernel/drivers/scsi/device_handler/ +scsi_dh_alua.ko.zst +scsi_dh_emc.ko.zst +scsi_dh_hp_sw.ko.zst +scsi_dh_rdac.ko.zst + +Replaces https://github.com/rhinstaller/anaconda/pull/3501 +Noted by slava86@ +Reference:https://github.com/rhinstaller/anaconda/commit/c4a388d3956088c96631b72f0631db2a380127b0 +Conflict:NA +--- + dracut/anaconda-modprobe.sh | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/dracut/anaconda-modprobe.sh b/dracut/anaconda-modprobe.sh +index 97ee53bcb1..3640b4d42f 100755 +--- a/dracut/anaconda-modprobe.sh ++++ b/dracut/anaconda-modprobe.sh +@@ -14,11 +14,12 @@ MODULE_LIST="cramfs squashfs iscsi_tcp " + shopt -s nullglob + + SCSI_MODULES=/lib/modules/$KERNEL/kernel/drivers/scsi/device_handler/ +-for m in "$SCSI_MODULES"/*.ko; do ++for m in "$SCSI_MODULES"/*.ko*; do + # Shell spew to work around not having basename +- # Trim the paths off the prefix, then the . suffix +- a="${m##*/}" +- MODULE_LIST+=" ${a%.*}" ++ m="${m##*/}" ++ # Handle *.ko, *.ko.zst, *.ko.gz, *.ko.xz etc. ++ IFS='.ko' read -r -a m <<< "$m" ++ MODULE_LIST+=" ${m[0]}" + done + + shopt -u nullglob +-- +2.23.0 \ No newline at end of file diff --git a/backport-network-use-separate-main-conext-for-NM-client-in-threads.patch b/backport-network-use-separate-main-conext-for-NM-client-in-threads.patch new file mode 100644 index 0000000..8ba07d7 --- /dev/null +++ b/backport-network-use-separate-main-conext-for-NM-client-in-threads.patch @@ -0,0 +1,824 @@ +From 3972b5dadcadd355d2ff25eae601bc35c336c45a Mon Sep 17 00:00:00 2001 +From: Radek Vykydal +Date: Thu, 29 Sep 2022 12:38:55 +0200 +Subject: [PATCH] network: use separate main conext for NM client in threads + +Resolves: rhbz#1931389 + +Create a special NM client with separate main context for calling NM +client from installation tasks which run in separate threads. + +Based on a pull request by t.feng who deserves +the biggest credit, and upated with suggestions by poncovka + +The created client should be used only in a limited scope as documented +in nm_client_in_thread docstring. If we want to extend it and address +potential issues with client instance releasing and reusing we'd need to +follow recommendations from Thomas Haller's kind reviews: + + + +first of all, initializing a NMClient instance takes relatively long, +because it makes D-Bus calls and the round trip time adds up. Btw, if +you'd pass +instance_flags=NM.ClientInstanceFlags.NO_AUTO_FETCH_PERMISSIONS it can +make it faster, see here. If it's too slow, then the solution would be +to re-use the nmclient instance or use async initialization and do stuff +in parallel. Both is more complicated however, so not necessary unless +we find that it's a problem. + +What is maybe more a problem is that each GMainContext consumes at least +one file descriptor. When you use the sync nm_client_new() method, then +NMClient has an additional internal GMainContext, so possibly there are +2 or more file descriptors involved. The way to "stop" NMClient is by +unrefing it. However, with all async operations in glib, they cannot +complete right away. That is because when NMClient gets unrefed, it will +cancel all (internally) pending operations, but even when you cancel a +glib operation, the callback still will be invoked with the cancellation +error. And callbacks only get invoked by iterating/running the +mainloop/maincontext. This means, if you have a short-running +application (e.g. not a GUI) and a reasonable small number of NMClient +instances, then you don't need to care. Otherwise, you unfortunately +need to make sure that the GMainContext is still iterated just long +enough, for all operations to be cancelled. That's slightly cumbersome, +and you can use nm_client_get_context_busy_watcher() to find that out. + +Btw, what you also cannot do, is having a NMClient instance alive and +just not iterating the GMainContext anymore. NMClient will subscribe to +D-Bus events, and those come (because GDBus has a separate worker +thread) and will be enqueued in the GMainContext. This applies to all +applications that register DBus signals via GDBus: you must iterate the +context enough, so that those events get eventually processed. I think +this does not apply to you here, but it would apply, if you try to keep +the nmclient instance alive and reuse later. + + + +Reference:https://github.com/rhinstaller/anaconda/commit/3972b5dadcadd355d2ff25eae601bc35c336c45a +Conflict:NA +--- + pyanaconda/core/glib.py | 109 +++++++++++- + pyanaconda/modules/network/initialization.py | 56 +++--- + pyanaconda/modules/network/installation.py | 19 +- + pyanaconda/modules/network/network.py | 26 +-- + pyanaconda/modules/network/nm_client.py | 167 +++++++++++------- + 5 files changed, 254 insertions(+), 123 deletions(-) + +diff --git a/pyanaconda/core/glib.py b/pyanaconda/core/glib.py +index 03c598db43..32925384bb 100644 +--- a/pyanaconda/core/glib.py ++++ b/pyanaconda/core/glib.py +@@ -24,34 +24,42 @@ + + import gi + gi.require_version("GLib", "2.0") ++gi.require_version("Gio", "2.0") + + from gi.repository.GLib import markup_escape_text, format_size_full, \ + timeout_add_seconds, timeout_add, idle_add, \ + io_add_watch, child_watch_add, \ +- source_remove, \ ++ source_remove, timeout_source_new, \ + spawn_close_pid, spawn_async_with_pipes, \ + MainLoop, MainContext, \ + GError, Variant, VariantType, Bytes, \ + IOCondition, IOChannel, SpawnFlags, \ + MAXUINT ++from gi.repository.Gio import Cancellable ++ ++from pyanaconda.anaconda_loggers import get_module_logger ++log = get_module_logger(__name__) ++ + + __all__ = ["create_main_loop", "create_new_context", + "markup_escape_text", "format_size_full", + "timeout_add_seconds", "timeout_add", "idle_add", + "io_add_watch", "child_watch_add", +- "source_remove", ++ "source_remove", "timeout_source_new", + "spawn_close_pid", "spawn_async_with_pipes", + "GError", "Variant", "VariantType", "Bytes", + "IOCondition", "IOChannel", "SpawnFlags", +- "MAXUINT"] ++ "MAXUINT", "Cancellable"] + + +-def create_main_loop(): ++def create_main_loop(main_context=None): + """Create GLib main loop. + ++ :param main_context: main context to be used for the loop ++ :type main_context: GLib.MainContext + :returns: GLib.MainLoop instance. + """ +- return MainLoop() ++ return MainLoop(main_context) + + + def create_new_context(): +@@ -59,3 +67,94 @@ def create_new_context(): + + :returns: GLib.MainContext.""" + return MainContext.new() ++ ++ ++class GLibCallResult(): ++ """Result of GLib async finish callback.""" ++ def __init__(self): ++ self.received_data = None ++ self.error_message = "" ++ self.timeout = False ++ ++ @property ++ def succeeded(self): ++ """The async call has succeeded.""" ++ return not self.failed ++ ++ @property ++ def failed(self): ++ """The async call has failed.""" ++ return bool(self.error_message) or self.timeout ++ ++ ++def sync_call_glib(context, async_call, async_call_finish, timeout, *call_args): ++ """Call GLib asynchronous method synchronously with timeout. ++ ++ :param context: context for the new loop in which the method will be called ++ :type context: GMainContext ++ :param async_call: asynchronous GLib method to be called ++ :type async_call: GLib method ++ :param async_call_finish: finish method of the asynchronous call ++ :type async_call_finish: GLib method ++ :param timeout: timeout for the loop in seconds (0 == no timeout) ++ :type timeout: int ++ ++ *call_args should hold all positional arguments preceding the cancellable argument ++ """ ++ ++ info = async_call.get_symbol() ++ result = GLibCallResult() ++ ++ loop = create_main_loop(context) ++ callbacks = [loop.quit] ++ ++ def _stop_loop(): ++ log.debug("sync_call_glib[%s]: quit", info) ++ while callbacks: ++ callback = callbacks.pop() ++ callback() ++ ++ def _cancellable_cb(): ++ log.debug("sync_call_glib[%s]: cancelled", info) ++ ++ cancellable = Cancellable() ++ cancellable_id = cancellable.connect(_cancellable_cb) ++ callbacks.append(lambda: cancellable.disconnect(cancellable_id)) ++ ++ def _timeout_cb(user_data): ++ log.debug("sync_call_glib[%s]: timeout", info) ++ result.timeout = True ++ cancellable.cancel() ++ return False ++ ++ timeout_source = timeout_source_new(int(timeout * 1000)) ++ timeout_source.set_callback(_timeout_cb) ++ timeout_source.attach(context) ++ callbacks.append(timeout_source.destroy) ++ ++ def _finish_cb(source_object, async_result): ++ log.debug("sync_call_glib[%s]: call %s", ++ info, ++ async_call_finish.get_symbol()) ++ try: ++ result.received_data = async_call_finish(async_result) ++ except Exception as e: # pylint: disable=broad-except ++ result.error_message = str(e) ++ finally: ++ _stop_loop() ++ ++ context.push_thread_default() ++ ++ log.debug("sync_call_glib[%s]: call", info) ++ try: ++ async_call( ++ *call_args, ++ cancellable=cancellable, ++ callback=_finish_cb ++ ) ++ loop.run() ++ finally: ++ _stop_loop() ++ context.pop_thread_default() ++ ++ return result +diff --git a/pyanaconda/modules/network/initialization.py b/pyanaconda/modules/network/initialization.py +index c7f0ba4cf8..bf1ffd12af 100644 +--- a/pyanaconda/modules/network/initialization.py ++++ b/pyanaconda/modules/network/initialization.py +@@ -25,7 +25,7 @@ from pyanaconda.modules.network.network_interface import NetworkInitializationTa + from pyanaconda.modules.network.nm_client import get_device_name_from_network_data, \ + update_connection_from_ksdata, add_connection_from_ksdata, bound_hwaddr_of_device, \ + update_connection_values, commit_changes_with_autoconnection_blocked, \ +- get_config_file_connection_of_device, clone_connection_sync ++ get_config_file_connection_of_device, clone_connection_sync, nm_client_in_thread + from pyanaconda.modules.network.device_configuration import supported_wired_device_types, \ + virtual_device_types + from pyanaconda.modules.network.utils import guard_by_system_configuration +@@ -40,11 +40,9 @@ from gi.repository import NM + class ApplyKickstartTask(Task): + """Task for application of kickstart network configuration.""" + +- def __init__(self, nm_client, network_data, supported_devices, bootif, ifname_option_values): ++ def __init__(self, network_data, supported_devices, bootif, ifname_option_values): + """Create a new task. + +- :param nm_client: NetworkManager client used as configuration backend +- :type nm_client: NM.Client + :param network_data: kickstart network data to be applied + :type: list(NetworkData) + :param supported_devices: list of names of supported network devices +@@ -55,7 +53,6 @@ class ApplyKickstartTask(Task): + :type ifname_option_values: list(str) + """ + super().__init__() +- self._nm_client = nm_client + self._network_data = network_data + self._supported_devices = supported_devices + self._bootif = bootif +@@ -76,13 +73,17 @@ class ApplyKickstartTask(Task): + :returns: names of devices to which kickstart was applied + :rtype: list(str) + """ ++ with nm_client_in_thread() as nm_client: ++ return self._run(nm_client) ++ ++ def _run(self, nm_client): + applied_devices = [] + + if not self._network_data: + log.debug("%s: No kickstart data.", self.name) + return applied_devices + +- if not self._nm_client: ++ if not nm_client: + log.debug("%s: No NetworkManager available.", self.name) + return applied_devices + +@@ -92,7 +93,7 @@ class ApplyKickstartTask(Task): + log.info("%s: Wireless devices configuration is not supported.", self.name) + continue + +- device_name = get_device_name_from_network_data(self._nm_client, ++ device_name = get_device_name_from_network_data(nm_client, + network_data, + self._supported_devices, + self._bootif) +@@ -102,28 +103,28 @@ class ApplyKickstartTask(Task): + + applied_devices.append(device_name) + +- connection = self._find_initramfs_connection_of_iface(device_name) ++ connection = self._find_initramfs_connection_of_iface(nm_client, device_name) + + if connection: + # if the device was already configured in initramfs update the settings + log.debug("%s: updating connection %s of device %s", + self.name, connection.get_uuid(), device_name) + update_connection_from_ksdata( +- self._nm_client, ++ nm_client, + connection, + network_data, + device_name, + ifname_option_values=self._ifname_option_values + ) + if network_data.activate: +- device = self._nm_client.get_device_by_iface(device_name) +- self._nm_client.activate_connection_async(connection, device, None, None) ++ device = nm_client.get_device_by_iface(device_name) ++ nm_client.activate_connection_async(connection, device, None, None) + log.debug("%s: activating updated connection %s with device %s", + self.name, connection.get_uuid(), device_name) + else: + log.debug("%s: adding connection for %s", self.name, device_name) + add_connection_from_ksdata( +- self._nm_client, ++ nm_client, + network_data, + device_name, + activate=network_data.activate, +@@ -132,8 +133,8 @@ class ApplyKickstartTask(Task): + + return applied_devices + +- def _find_initramfs_connection_of_iface(self, iface): +- device = self._nm_client.get_device_by_iface(iface) ++ def _find_initramfs_connection_of_iface(self, nm_client, iface): ++ device = nm_client.get_device_by_iface(iface) + if device: + cons = device.get_available_connections() + for con in cons: +@@ -145,18 +146,15 @@ class ApplyKickstartTask(Task): + class DumpMissingConfigFilesTask(Task): + """Task for dumping of missing config files.""" + +- def __init__(self, nm_client, default_network_data, ifname_option_values): ++ def __init__(self, default_network_data, ifname_option_values): + """Create a new task. + +- :param nm_client: NetworkManager client used as configuration backend +- :type nm_client: NM.Client + :param default_network_data: kickstart network data of default device configuration + :type default_network_data: NetworkData + :param ifname_option_values: list of ifname boot option values + :type ifname_option_values: list(str) + """ + super().__init__() +- self._nm_client = nm_client + self._default_network_data = default_network_data + self._ifname_option_values = ifname_option_values + +@@ -186,7 +184,7 @@ class DumpMissingConfigFilesTask(Task): + return con + return None + +- def _update_connection(self, con, iface): ++ def _update_connection(self, nm_client, con, iface): + log.debug("%s: updating id and binding (interface-name) of connection %s for %s", + self.name, con.get_uuid(), iface) + s_con = con.get_setting_connection() +@@ -196,7 +194,7 @@ class DumpMissingConfigFilesTask(Task): + if s_wired: + # By default connections are bound to interface name + s_wired.set_property(NM.SETTING_WIRED_MAC_ADDRESS, None) +- bound_mac = bound_hwaddr_of_device(self._nm_client, iface, self._ifname_option_values) ++ bound_mac = bound_hwaddr_of_device(nm_client, iface, self._ifname_option_values) + if bound_mac: + s_wired.set_property(NM.SETTING_WIRED_MAC_ADDRESS, bound_mac) + log.debug("%s: iface %s bound to mac address %s by ifname boot option", +@@ -216,19 +214,23 @@ class DumpMissingConfigFilesTask(Task): + :returns: names of devices for which config file was created + :rtype: list(str) + """ ++ with nm_client_in_thread() as nm_client: ++ return self._run(nm_client) ++ ++ def _run(self, nm_client): + new_configs = [] + +- if not self._nm_client: ++ if not nm_client: + log.debug("%s: No NetworkManager available.", self.name) + return new_configs + + dumped_device_types = supported_wired_device_types + virtual_device_types +- for device in self._nm_client.get_devices(): ++ for device in nm_client.get_devices(): + if device.get_device_type() not in dumped_device_types: + continue + + iface = device.get_iface() +- if get_config_file_connection_of_device(self._nm_client, iface): ++ if get_config_file_connection_of_device(nm_client, iface): + continue + + cons = device.get_available_connections() +@@ -259,10 +261,10 @@ class DumpMissingConfigFilesTask(Task): + # Try to clone the persistent connection for the device + # from the connection which should be a generic (not bound + # to iface) connection created by NM in initramfs +- con = clone_connection_sync(self._nm_client, cons[0], con_id=iface) ++ con = clone_connection_sync(nm_client, cons[0], con_id=iface) + + if con: +- self._update_connection(con, iface) ++ self._update_connection(nm_client, con, iface) + # Update some values of connection generated in initramfs so it + # can be used as persistent configuration. + if has_initramfs_con: +@@ -285,7 +287,7 @@ class DumpMissingConfigFilesTask(Task): + ) + log.debug("%s: dumping connection %s to config file for %s", + self.name, con.get_uuid(), iface) +- commit_changes_with_autoconnection_blocked(con) ++ commit_changes_with_autoconnection_blocked(con, nm_client) + else: + log.debug("%s: none of the connections can be dumped as persistent", + self.name) +@@ -298,7 +300,7 @@ class DumpMissingConfigFilesTask(Task): + if has_initramfs_con: + network_data.onboot = True + add_connection_from_ksdata( +- self._nm_client, ++ nm_client, + network_data, + iface, + activate=False, +diff --git a/pyanaconda/modules/network/installation.py b/pyanaconda/modules/network/installation.py +index 3ac65e0df0..d91eb51ae7 100644 +--- a/pyanaconda/modules/network/installation.py ++++ b/pyanaconda/modules/network/installation.py +@@ -23,7 +23,7 @@ from pyanaconda.modules.common.errors.installation import NetworkInstallationErr + from pyanaconda.modules.common.task import Task + from pyanaconda.anaconda_loggers import get_module_logger + from pyanaconda.modules.network.nm_client import update_connection_values, \ +- commit_changes_with_autoconnection_blocked ++ commit_changes_with_autoconnection_blocked, nm_client_in_thread + from pyanaconda.modules.network.utils import guard_by_system_configuration + from pyanaconda.modules.network.nm_client import get_config_file_connection_of_device + from pyanaconda.modules.network.config_file import IFCFG_DIR, KEYFILE_DIR +@@ -281,16 +281,13 @@ Name={} + class ConfigureActivationOnBootTask(Task): + """Task for configuration of automatic activation of devices on boot""" + +- def __init__(self, nm_client, onboot_ifaces): ++ def __init__(self, onboot_ifaces): + """Create a new task. + +- :param nm_client: NetworkManager client used as configuration backend +- :type nm_client: NM.Client + :param onboot_ifaces: interfaces that should be autoactivated on boot + :type onboot_ifaces: list(str) + """ + super().__init__() +- self._nm_client = nm_client + self._onboot_ifaces = onboot_ifaces + + @property +@@ -299,18 +296,22 @@ class ConfigureActivationOnBootTask(Task): + + @guard_by_system_configuration(return_value=None) + def run(self): +- if not self._nm_client: ++ with nm_client_in_thread() as nm_client: ++ return self._run(nm_client) ++ ++ def _run(self, nm_client): ++ if not nm_client: + log.debug("%s: No NetworkManager available.", self.name) + return None + + for iface in self._onboot_ifaces: +- con_uuid = get_config_file_connection_of_device(self._nm_client, iface) ++ con_uuid = get_config_file_connection_of_device(nm_client, iface) + if con_uuid: +- con = self._nm_client.get_connection_by_uuid(con_uuid) ++ con = nm_client.get_connection_by_uuid(con_uuid) + update_connection_values( + con, + [("connection", NM.SETTING_CONNECTION_AUTOCONNECT, True)] + ) +- commit_changes_with_autoconnection_blocked(con) ++ commit_changes_with_autoconnection_blocked(con, nm_client) + else: + log.warning("Configure ONBOOT: can't find config for %s", iface) +diff --git a/pyanaconda/modules/network/network.py b/pyanaconda/modules/network/network.py +index 445c9d8b46..a905ee31d6 100644 +--- a/pyanaconda/modules/network/network.py ++++ b/pyanaconda/modules/network/network.py +@@ -23,7 +23,7 @@ from pyanaconda.core.async_utils import run_in_loop + from pyanaconda.core.configuration.anaconda import conf + from pyanaconda.core.configuration.network import NetworkOnBoot + from pyanaconda.core.kernel import kernel_arguments +-from pyanaconda.core.dbus import DBus, SystemBus ++from pyanaconda.core.dbus import DBus + from pyanaconda.core.signal import Signal + from pyanaconda.modules.common.base import KickstartService + from pyanaconda.modules.common.containers import TaskContainer +@@ -37,7 +37,7 @@ from pyanaconda.modules.network.firewall import FirewallModule + from pyanaconda.modules.network.device_configuration import DeviceConfigurations, \ + supported_device_types, supported_wired_device_types + from pyanaconda.modules.network.nm_client import devices_ignore_ipv6, get_connections_dump, \ +- get_dracut_arguments_from_connection, get_kickstart_network_data ++ get_dracut_arguments_from_connection, get_kickstart_network_data, get_new_nm_client + from pyanaconda.modules.network.config_file import get_config_files_content, \ + is_config_file_for_system + from pyanaconda.modules.network.installation import NetworkInstallationTask, \ +@@ -70,17 +70,12 @@ class NetworkService(KickstartService): + self._hostname_service_proxy = self._get_hostname_proxy() + + self.connected_changed = Signal() +- self.nm_client = None + # TODO fallback solution - use Gio/GNetworkMonitor ? +- if SystemBus.check_connection(): +- nm_client = NM.Client.new(None) +- if nm_client.get_nm_running(): +- self.nm_client = nm_client +- self.nm_client.connect("notify::%s" % NM.CLIENT_STATE, self._nm_state_changed) +- initial_state = self.nm_client.get_state() +- self.set_connected(self._nm_state_connected(initial_state)) +- else: +- log.debug("NetworkManager is not running.") ++ self.nm_client = get_new_nm_client() ++ if self.nm_client: ++ self.nm_client.connect("notify::%s" % NM.CLIENT_STATE, self._nm_state_changed) ++ initial_state = self.nm_client.get_state() ++ self.set_connected(self._nm_state_connected(initial_state)) + + self._original_network_data = [] + self._device_configurations = None +@@ -393,7 +388,6 @@ class NetworkService(KickstartService): + all_onboot_ifaces = list(set(onboot_ifaces + onboot_ifaces_by_policy)) + + task = ConfigureActivationOnBootTask( +- self.nm_client, + all_onboot_ifaces + ) + task.succeeded_signal.connect(lambda: self.log_task_result(task)) +@@ -616,8 +610,7 @@ class NetworkService(KickstartService): + :returns: a task applying the kickstart + """ + supported_devices = [dev_info.device_name for dev_info in self.get_supported_devices()] +- task = ApplyKickstartTask(self.nm_client, +- self._original_network_data, ++ task = ApplyKickstartTask(self._original_network_data, + supported_devices, + self.bootif, + self.ifname_option_values) +@@ -645,8 +638,7 @@ class NetworkService(KickstartService): + """ + data = self.get_kickstart_handler() + default_network_data = data.NetworkData(onboot=False, ipv6="auto") +- task = DumpMissingConfigFilesTask(self.nm_client, +- default_network_data, ++ task = DumpMissingConfigFilesTask(default_network_data, + self.ifname_option_values) + task.succeeded_signal.connect(lambda: self.log_task_result(task, check_result=True)) + return task +diff --git a/pyanaconda/modules/network/nm_client.py b/pyanaconda/modules/network/nm_client.py +index 3cc28ec48e..421ef1e0d9 100644 +--- a/pyanaconda/modules/network/nm_client.py ++++ b/pyanaconda/modules/network/nm_client.py +@@ -21,18 +21,20 @@ + import gi + gi.require_version("NM", "1.0") + from gi.repository import NM ++from contextlib import contextmanager + + import socket +-from queue import Queue, Empty + from pykickstart.constants import BIND_TO_MAC ++from pyanaconda.core.glib import create_new_context, GError, sync_call_glib + from pyanaconda.modules.network.constants import NM_CONNECTION_UUID_LENGTH, \ +- CONNECTION_ACTIVATION_TIMEOUT, NM_CONNECTION_TYPE_WIFI, NM_CONNECTION_TYPE_ETHERNET, \ ++ CONNECTION_ADDING_TIMEOUT, NM_CONNECTION_TYPE_WIFI, NM_CONNECTION_TYPE_ETHERNET, \ + NM_CONNECTION_TYPE_VLAN, NM_CONNECTION_TYPE_BOND, NM_CONNECTION_TYPE_TEAM, \ +- NM_CONNECTION_TYPE_BRIDGE, NM_CONNECTION_TYPE_INFINIBAND, CONNECTION_ADDING_TIMEOUT ++ NM_CONNECTION_TYPE_BRIDGE, NM_CONNECTION_TYPE_INFINIBAND + from pyanaconda.modules.network.kickstart import default_ks_vlan_interface_name + from pyanaconda.modules.network.utils import is_s390, get_s390_settings, netmask2prefix, \ + prefix2netmask + from pyanaconda.modules.network.config_file import is_config_file_for_system ++from pyanaconda.core.dbus import SystemBus + + from pyanaconda.anaconda_loggers import get_module_logger + log = get_module_logger(__name__) +@@ -51,6 +53,51 @@ NM_BRIDGE_DUMPED_SETTINGS_DEFAULTS = { + } + + ++@contextmanager ++def nm_client_in_thread(): ++ """Create NM Client with new GMainContext to be run in thread. ++ ++ Expected to be used only in installer environment for a few ++ one-shot isolated network configuration tasks. ++ Destroying of the created NM Client instance and release of ++ related resources is not implemented. ++ ++ For more information see NetworkManager example examples/python/gi/gmaincontext.py ++ """ ++ mainctx = create_new_context() ++ mainctx.push_thread_default() ++ ++ try: ++ yield get_new_nm_client() ++ finally: ++ mainctx.pop_thread_default() ++ ++ ++def get_new_nm_client(): ++ """Get new instance of NMClient. ++ ++ :returns: an instance of NetworkManager NMClient or None if system bus ++ is not available or NM is not running ++ :rtype: NM.NMClient ++ """ ++ if not SystemBus.check_connection(): ++ log.debug("get new NM Client failed: SystemBus connection check failed.") ++ return None ++ ++ try: ++ nm_client = NM.Client.new(None) ++ except GError as e: ++ log.debug("get new NM Client constructor failed: %s", e) ++ return None ++ ++ if not nm_client.get_nm_running(): ++ log.debug("get new NM Client failed: NetworkManager is not running.") ++ return None ++ ++ log.debug("get new NM Client succeeded.") ++ return nm_client ++ ++ + def get_iface_from_connection(nm_client, uuid): + """Get the name of device that would be used for the connection. + +@@ -268,7 +315,7 @@ def _add_existing_virtual_device_to_bridge(nm_client, device_name, bridge_spec): + bridge_spec), + ] + ) +- commit_changes_with_autoconnection_blocked(port_connection) ++ commit_changes_with_autoconnection_blocked(port_connection, nm_client) + return port_connection.get_uuid() + + +@@ -532,7 +579,7 @@ def add_connection_from_ksdata(nm_client, network_data, device_name, activate=Fa + connection.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS)) + added_connection = add_connection_sync( + nm_client, +- connection, ++ connection + ) + + if not added_connection: +@@ -557,37 +604,39 @@ def add_connection_from_ksdata(nm_client, network_data, device_name, activate=Fa + def add_connection_sync(nm_client, connection): + """Add a connection synchronously and optionally activate asynchronously. + ++ Synchronous run is implemented by running a blocking GMainLoop with ++ GMainContext belonging to the nm_client created for the calling Task. ++ ++ :param nm_client: NetoworkManager client ++ :type nm_client: NM.NMClient + :param connection: connection to be added + :type connection: NM.SimpleConnection + :return: added connection or None on timeout + :rtype: NM.RemoteConnection + """ +- sync_queue = Queue() +- +- def finish_callback(nm_client, result, sync_queue): +- con, result = nm_client.add_connection2_finish(result) +- log.debug("connection %s added:\n%s", con.get_uuid(), +- con.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS)) +- sync_queue.put(con) +- +- nm_client.add_connection2( ++ result = sync_call_glib( ++ nm_client.get_main_context(), ++ nm_client.add_connection2, ++ nm_client.add_connection2_finish, ++ CONNECTION_ADDING_TIMEOUT, + connection.to_dbus(NM.ConnectionSerializationFlags.ALL), + (NM.SettingsAddConnection2Flags.TO_DISK | + NM.SettingsAddConnection2Flags.BLOCK_AUTOCONNECT), + None, +- False, +- None, +- finish_callback, +- sync_queue ++ False + ) + +- try: +- ret = sync_queue.get(timeout=CONNECTION_ADDING_TIMEOUT) +- except Empty: +- log.error("Adding of connection %s timed out.", connection.get_uuid()) +- ret = None ++ if result.failed: ++ log.error("adding of a connection %s failed: %s", ++ connection.get_uuid(), ++ result.error_message) ++ return None ++ ++ con, _res = result.received_data ++ log.debug("connection %s added:\n%s", connection.get_uuid(), ++ connection.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS)) + +- return ret ++ return con + + + def create_port_connection(port_type, port_idx, port, controller, autoconnect, settings=None): +@@ -713,7 +762,7 @@ def update_connection_from_ksdata(nm_client, connection, network_data, device_na + else: + bind_connection(nm_client, connection, network_data.bindto, device_name) + +- commit_changes_with_autoconnection_blocked(connection) ++ commit_changes_with_autoconnection_blocked(connection, nm_client) + + log.debug("updated connection %s:\n%s", connection.get_uuid(), + connection.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS)) +@@ -1013,42 +1062,47 @@ def get_connections_dump(nm_client): + return "\n".join(con_dumps) + + +-def commit_changes_with_autoconnection_blocked(connection, save_to_disk=True): ++def commit_changes_with_autoconnection_blocked(connection, nm_client, save_to_disk=True): + """Implementation of NM CommitChanges() method with blocked autoconnection. + +- Update2() API is used to implement the functionality (called synchronously). +- ++ Update2() API is used to implement the functionality. + Prevents autoactivation of the connection on its update which would happen + with CommitChanges if "autoconnect" is set True. + ++ Synchronous run is implemented by running a blocking GMainLoop with ++ GMainContext belonging to the nm_client created for the calling Task. ++ + :param connection: NetworkManager connection + :type connection: NM.RemoteConnection ++ :param nm_client: NetoworkManager client ++ :type nm_client: NM.NMClient + :param save_to_disk: should the changes be written also to disk? + :type save_to_disk: bool + :return: on success result of the Update2() call, None of failure + :rtype: GVariant of type "a{sv}" or None + """ +- sync_queue = Queue() +- +- def finish_callback(connection, result, sync_queue): +- ret = connection.update2_finish(result) +- sync_queue.put(ret) +- + flags = NM.SettingsUpdate2Flags.BLOCK_AUTOCONNECT + if save_to_disk: + flags |= NM.SettingsUpdate2Flags.TO_DISK +- + con2 = NM.SimpleConnection.new_clone(connection) +- connection.update2( ++ ++ result = sync_call_glib( ++ nm_client.get_main_context(), ++ connection.update2, ++ connection.update2_finish, ++ CONNECTION_ADDING_TIMEOUT, + con2.to_dbus(NM.ConnectionSerializationFlags.ALL), + flags, +- None, +- None, +- finish_callback, +- sync_queue ++ None + ) + +- return sync_queue.get() ++ if result.failed: ++ log.error("comitting changes of connection %s failed: %s", ++ connection.get_uuid(), ++ result.error_message) ++ return None ++ ++ return result.received_data + + + def clone_connection_sync(nm_client, connection, con_id=None, uuid=None): +@@ -1063,36 +1117,19 @@ def clone_connection_sync(nm_client, connection, con_id=None, uuid=None): + :return: NetworkManager connection or None on timeout + :rtype: NM.RemoteConnection + """ +- sync_queue = Queue() +- +- def finish_callback(nm_client, result, sync_queue): +- con, result = nm_client.add_connection2_finish(result) +- log.debug("connection %s cloned:\n%s", con.get_uuid(), +- con.to_dbus(NM.ConnectionSerializationFlags.NO_SECRETS)) +- sync_queue.put(con) +- + cloned_connection = NM.SimpleConnection.new_clone(connection) + s_con = cloned_connection.get_setting_connection() + s_con.props.uuid = uuid or NM.utils_uuid_generate() + s_con.props.id = con_id or "{}-clone".format(connection.get_id()) +- nm_client.add_connection2( +- cloned_connection.to_dbus(NM.ConnectionSerializationFlags.ALL), +- (NM.SettingsAddConnection2Flags.TO_DISK | +- NM.SettingsAddConnection2Flags.BLOCK_AUTOCONNECT), +- None, +- False, +- None, +- finish_callback, +- sync_queue +- ) + +- try: +- ret = sync_queue.get(timeout=CONNECTION_ACTIVATION_TIMEOUT) +- except Empty: +- log.error("Cloning of a connection timed out.") +- ret = None ++ log.debug("cloning connection %s", connection.get_uuid()) ++ added_connection = add_connection_sync(nm_client, cloned_connection) + +- return ret ++ if added_connection: ++ log.debug("connection was cloned into %s", added_connection.get_uuid()) ++ else: ++ log.debug("connection cloning failed") ++ return added_connection + + + def get_dracut_arguments_from_connection(nm_client, connection, iface, target_ip, +-- +2.23.0 \ No newline at end of file diff --git a/bugfix-adapt-active-connection-without-interface-name.patch b/bugfix-adapt-active-connection-without-interface-name.patch index 393a8ea..d64ab0c 100644 --- a/bugfix-adapt-active-connection-without-interface-name.patch +++ b/bugfix-adapt-active-connection-without-interface-name.patch @@ -11,9 +11,9 @@ diff --git a/pyanaconda/modules/network/initialization.py b/pyanaconda/modules/n index c7f0ba4..85a1da7 100644 --- a/pyanaconda/modules/network/initialization.py +++ b/pyanaconda/modules/network/initialization.py -@@ -135,6 +135,9 @@ class ApplyKickstartTask(Task): - def _find_initramfs_connection_of_iface(self, iface): - device = self._nm_client.get_device_by_iface(iface) +@@ -136,6 +136,9 @@ class ApplyKickstartTask(Task): + def _find_initramfs_connection_of_iface(self, nm_client, iface): + device = nm_client.get_device_by_iface(iface) if device: + active_connection = device.get_active_connection() + if active_connection: diff --git a/bugfix-revert-Unify-GRUB-configuration-file-location-across-all-platforms.patch b/bugfix-revert-Unify-GRUB-configuration-file-location-across-all-platforms.patch new file mode 100644 index 0000000..2f2e29d --- /dev/null +++ b/bugfix-revert-Unify-GRUB-configuration-file-location-across-all-platforms.patch @@ -0,0 +1,104 @@ +From d5d6b1498db9f9e3378c11421caa523556c04752 Mon Sep 17 00:00:00 2001 +From: sun_hai_10 +Date: Tue, 28 Mar 2023 14:22:39 +0800 +Subject: [PATCH] revert Unify GRUB configuration file location across all platforms +Reference:https://github.com/rhinstaller/anaconda/commit/15c3b2044367d375db6739e8b8f419ef3e17cae7 +--- + pyanaconda/modules/storage/bootloader/efi.py | 38 +------------------ + .../modules/storage/bootloader/utils.py | 8 +++- + 2 files changed, 9 insertions(+), 37 deletions(-) + +diff --git a/pyanaconda/modules/storage/bootloader/efi.py b/pyanaconda/modules/storage/bootloader/efi.py +index 1b47e24..6135699 100644 +--- a/pyanaconda/modules/storage/bootloader/efi.py ++++ b/pyanaconda/modules/storage/bootloader/efi.py +@@ -35,11 +35,7 @@ class EFIBase(object): + """A base class for EFI-based boot loaders.""" + + @property +- def efi_config_dir(self): +- return "/boot/" + self._efi_config_dir +- +- @property +- def _efi_config_dir(self): ++ def _config_dir(self): + return "efi/EFI/{}".format(conf.bootloader.efi_dir) + + def efibootmgr(self, *args, **kwargs): +@@ -62,7 +58,7 @@ class EFIBase(object): + + @property + def efi_dir_as_efifs_dir(self): +- ret = self._efi_config_dir.replace('efi/', '') ++ ret = self._config_dir.replace('efi/', '') + return "\\" + ret.replace('/', '\\') + + def _add_single_efi_boot_target(self, partition): +@@ -164,36 +160,6 @@ class EFIGRUB(EFIBase, GRUB2): + return self._packages32 + self._packages_common + return self._packages64 + self._packages_common + +- @property +- def efi_config_file(self): +- """ Full path to EFI configuration file. """ +- return "%s/%s" % (self.efi_config_dir, self._config_file) +- +- def write_config(self): +- config_path = "%s%s" % (conf.target.system_root, self.efi_config_file) +- +- with open(config_path, "w") as fd: +- grub_dir = self.config_dir +- if self.stage2_device.format.type != "btrfs": +- fs_uuid = self.stage2_device.format.uuid +- else: +- fs_uuid = self.stage2_device.format.vol_uuid +- +- if fs_uuid is None: +- raise BootLoaderError("Could not get stage2 filesystem UUID") +- +- grub_dir = util.execWithCapture("grub2-mkrelpath", [grub_dir], +- root=conf.target.system_root) +- if not grub_dir: +- raise BootLoaderError("Could not get GRUB directory path") +- +- fd.write("search --no-floppy --fs-uuid --set=dev %s\n" % fs_uuid) +- fd.write("set prefix=($dev)%s\n" % grub_dir) +- fd.write("export $prefix\n") +- fd.write("configfile $prefix/grub.cfg\n") +- +- super().write_config() +- + + class Aarch64EFIGRUB(EFIGRUB): + _serial_consoles = ["ttyAMA", "ttyS"] +diff --git a/pyanaconda/modules/storage/bootloader/utils.py b/pyanaconda/modules/storage/bootloader/utils.py +index 27fc2a0..84e45b6 100644 +--- a/pyanaconda/modules/storage/bootloader/utils.py ++++ b/pyanaconda/modules/storage/bootloader/utils.py +@@ -19,6 +19,7 @@ import os + from glob import glob + + from pyanaconda.modules.common.errors.installation import BootloaderInstallationError ++from pyanaconda.modules.storage.bootloader.efi import EFIBase + from pyanaconda.modules.storage.bootloader.image import LinuxBootLoaderImage + from pyanaconda.core.configuration.anaconda import conf + from pyanaconda.core.util import execWithRedirect +@@ -244,9 +245,14 @@ def create_bls_entries(sysroot, storage, kernel_versions): + # Update the bootloader configuration to make sure that the BLS + # entries will have the correct kernel cmdline and not the value + # taken from /proc/cmdline, that is used to boot the live image. ++ if isinstance(storage.bootloader, EFIBase): ++ grub_cfg_path = "/etc/grub2-efi.cfg" ++ else: ++ grub_cfg_path = "/etc/grub2.cfg" ++ + rc = execWithRedirect( + "grub2-mkconfig", +- ["-o", "/etc/grub2.cfg"], ++ ["-o", grub_cfg_path], + root=sysroot + ) + +-- +2.23.0 + diff --git a/fix-hostname-info.patch b/fix-hostname-info.patch index dee2e84..a217dca 100644 --- a/fix-hostname-info.patch +++ b/fix-hostname-info.patch @@ -4,19 +4,20 @@ Date: Thu, 18 Jun 2020 17:13:47 +0800 Subject: [PATCH] fix hostname info --- - po/zh_CN.po | 5 +++-- + po/zh_CN.po | 6 +++--- pyanaconda/core/regexes.py | 2 +- - pyanaconda/network.py | 3 ++- - 3 files changed, 6 insertions(+), 4 deletions(-) + pyanaconda/network.py | 4 ++-- + 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/po/zh_CN.po b/po/zh_CN.po -index e31f0b2..c02ce1e 100644 +index 18b0925..c2216e6 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po -@@ -4090,10 +4090,11 @@ msgstr "本地主机名不能以英文句号“.”结尾。" +@@ -4089,11 +4089,11 @@ msgstr "本地主机名不能以英文句号“.”结尾。" + #: pyanaconda/network.py:119 msgid "" "Host names can only contain the characters 'a-z', 'A-Z', '0-9', '-', or '.', " - "parts between periods must contain something and cannot start or end with " +-"parts between periods must contain something and cannot start or end with " -"'-'." +"parts between periods must contain something being 63 or fewer " +"characters and cannot start or end with '.' and '-'." @@ -41,13 +42,14 @@ index cc00702..388d1ff 100644 # URL Hostname # This matches any hostname, IPv4 literal or properly encased IPv6 literal diff --git a/pyanaconda/network.py b/pyanaconda/network.py -index 38fe957..c52cf1d 100644 +index 38fe957..8f04d63 100644 --- a/pyanaconda/network.py +++ b/pyanaconda/network.py -@@ -115,7 +115,8 @@ def is_valid_hostname(hostname, local=False): +@@ -114,8 +114,8 @@ def is_valid_hostname(hostname, local=False): + if not re.match('^' + HOSTNAME_PATTERN_WITHOUT_ANCHORS + '$', hostname): return (False, _("Host names can only contain the characters 'a-z', " "'A-Z', '0-9', '-', or '.', parts between periods " - "must contain something and cannot start or end with " +- "must contain something and cannot start or end with " - "'-'.")) + "must contain something being 63 or fewer " + "characters and cannot start or end with '.' and '-'."))