From 02b5eb093a36ec55fe446d9700249ecff2004398 Mon Sep 17 00:00:00 2001
From: eabdullin <ed.abdullin.1@gmail.com>
Date: Tue, 11 Mar 2025 07:09:56 +0000
Subject: [PATCH] import CS dnf-plugins-core-4.3.0-20.el9

---
 ...espect-norepopath-with-metadata-path.patch |  26 +++
 ...-Get-boot-time-from-systemd-UnitsLoa.patch | 159 ++++++++++++++++++
 ...-on-Asahi-Fedora-Linux-Remix-guesses.patch |  45 +++++
 SPECS/dnf-plugins-core.spec                   |  17 +-
 4 files changed, 246 insertions(+), 1 deletion(-)
 create mode 100644 SOURCES/0019-reposync-Respect-norepopath-with-metadata-path.patch
 create mode 100644 SOURCES/0020-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
 create mode 100644 SOURCES/0021-dnf-copr-enable-on-Asahi-Fedora-Linux-Remix-guesses.patch

diff --git a/SOURCES/0019-reposync-Respect-norepopath-with-metadata-path.patch b/SOURCES/0019-reposync-Respect-norepopath-with-metadata-path.patch
new file mode 100644
index 0000000..0a1281f
--- /dev/null
+++ b/SOURCES/0019-reposync-Respect-norepopath-with-metadata-path.patch
@@ -0,0 +1,26 @@
+From 1177f339dc3c428d57aef9ec6ae5d1db09ff7b95 Mon Sep 17 00:00:00 2001
+From: Pavla Kratochvilova <pkratoch@redhat.com>
+Date: Wed, 24 Jul 2024 11:05:18 +0200
+Subject: [PATCH] reposync: Respect --norepopath with --metadata-path
+
+Resolves: https://issues.redhat.com/browse/RHEL-40914
+---
+ plugins/reposync.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/plugins/reposync.py b/plugins/reposync.py
+index 0ff936f..ab513e7 100644
+--- a/plugins/reposync.py
++++ b/plugins/reposync.py
+@@ -180,7 +180,7 @@ class RepoSyncCommand(dnf.cli.Command):
+ 
+     def metadata_target(self, repo):
+         if self.opts.metadata_path:
+-            return _pkgdir(self.opts.metadata_path, repo.id)
++            return _pkgdir(self.opts.metadata_path, repo.id if not self.opts.norepopath else '')
+         else:
+             return self.repo_target(repo)
+ 
+-- 
+2.46.2
+
diff --git a/SOURCES/0020-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch b/SOURCES/0020-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
new file mode 100644
index 0000000..cdc66cf
--- /dev/null
+++ b/SOURCES/0020-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
@@ -0,0 +1,159 @@
+From 8cf40027b920b3760d6d1df9eb280b4f3772f290 Mon Sep 17 00:00:00 2001
+From: Evan Goode <mail@evangoo.de>
+Date: Thu, 3 Oct 2024 21:37:58 +0000
+Subject: [PATCH] needs-restarting: Get boot time from systemd
+ UnitsLoadStartTimestamp
+
+Resolves https://issues.redhat.com/browse/RHEL-35577.
+
+Get the boot time from UnitsLoadStartTimestamp if systemd is available,
+but make sure to use the kernel boot time for calculating process start
+times using data from procfs. The previous attempt [1] at this failed to
+do so and introduced a regression [2].
+
+Also, get the kernel boot time from the btime field of /proc/stat instead of
+calculating it from /proc/uptime, to be consistent with what procps-ng
+does.
+
+[1] https://github.com/rpm-software-management/dnf-plugins-core/pull/527
+[2] https://issues.redhat.com/browse/RHEL-39775
+---
+ plugins/needs_restarting.py | 106 +++++++++++++++++++++++++++---------
+ 1 file changed, 81 insertions(+), 25 deletions(-)
+
+diff --git a/plugins/needs_restarting.py b/plugins/needs_restarting.py
+index 309a216..9c77af7 100644
+--- a/plugins/needs_restarting.py
++++ b/plugins/needs_restarting.py
+@@ -203,36 +203,89 @@ class OpenedFile(object):
+                 return match.group(1)
+         return self.name
+ 
+-
+ class ProcessStart(object):
+     def __init__(self):
+-        self.boot_time = self.get_boot_time()
+-        self.sc_clk_tck = self.get_sc_clk_tck()
++        self.kernel_boot_time = ProcessStart.get_kernel_boot_time()
++        self.boot_time = ProcessStart.get_boot_time(self.kernel_boot_time)
++        self.sc_clk_tck = ProcessStart.get_sc_clk_tck()
++
++    @staticmethod
++    def get_kernel_boot_time():
++        try:
++            with open('/proc/stat', 'r') as file:
++                for line in file:
++                    if line.startswith("btime "):
++                        key, value = line.split()
++                        return float(value)
++        except OSError as e:
++            logger.debug("Couldn't read /proc/stat: %s", e)
++        return 0
+ 
+     @staticmethod
+-    def get_boot_time():
++    def get_boot_time(kernel_boot_time):
+         """
+-        We have two sources from which to derive the boot time. These values vary
++        We have three sources from which to derive the boot time. These values vary
+         depending on containerization, existence of a Real Time Clock, etc.
+-        For our purposes we want the latest derived value.
++        - UnitsLoadStartTimestamp property on /org/freedesktop/systemd1
++             The start time of the service manager, according to systemd itself.
++             Seems to be more reliable than UserspaceTimestamp when the RTC is
++             in local time. Works unless the system was not booted with systemd,
++             such as in (most) containers.
+         - st_mtime of /proc/1
+-             Reflects the time the first process was run after booting
+-             This works for all known cases except machines without
+-             a RTC - they awake at the start of the epoch.
+-        - /proc/uptime
+-             Seconds field of /proc/uptime subtracted from the current time
+-             Works for machines without RTC iff the current time is reasonably correct.
+-             Does not work on containers which share their kernel with the
+-             host - there the host kernel uptime is returned
++             Reflects the time the first process was run after booting. This
++             works for all known cases except machines without a RTC---they
++             awake at the start of the epoch.
++        - btime field of /proc/stat
++             Reflects the time when the kernel started. Works for machines
++             without RTC iff the current time is reasonably correct. Does not
++             work on containers which share their kernel with the host---there,
++             the host kernel uptime is returned.
+         """
+ 
+-        proc_1_boot_time = int(os.stat('/proc/1').st_mtime)
+-        if os.path.isfile('/proc/uptime'):
+-            with open('/proc/uptime', 'rb') as f:
+-                uptime = f.readline().strip().split()[0].strip()
+-                proc_uptime_boot_time = int(time.time() - float(uptime))
+-                return max(proc_1_boot_time, proc_uptime_boot_time)
+-        return proc_1_boot_time
++        units_load_start_timestamp = None
++        try:
++            # systemd timestamps are the preferred method to determine boot
++            # time. max(proc_1_boot_time, kernel_boot_time) does not allow us
++            # to disambiguate between an unreliable RTC (e.g. the RTC is in
++            # UTC+1 instead of UTC) and a container with a proc_1_boot_time >
++            # kernel_boot_time. So we use UnitsLoadStartTimestamp if it's
++            # available, else fall back to the other methods.
++            bus = dbus.SystemBus()
++            systemd1 = bus.get_object(
++                'org.freedesktop.systemd1',
++                '/org/freedesktop/systemd1'
++            )
++            props = dbus.Interface(
++                systemd1,
++                dbus.PROPERTIES_IFACE
++            )
++            units_load_start_timestamp = props.Get(
++                'org.freedesktop.systemd1.Manager',
++                'UnitsLoadStartTimestamp'
++            )
++            if units_load_start_timestamp != 0:
++                systemd_boot_time = units_load_start_timestamp / (1000 * 1000)
++                logger.debug("Got boot time from systemd: %s", systemd_boot_time)
++                return systemd_boot_time
++        except dbus.exceptions.DBusException as e:
++            logger.debug("D-Bus error getting boot time from systemd: %s", e)
++
++        logger.debug("Couldn't get boot time from systemd, checking st_mtime of /proc/1 and btime field of /proc/stat.")
++
++        try:
++            proc_1_boot_time = float(os.stat('/proc/1').st_mtime)
++        except OSError as e:
++            logger.debug("Couldn't stat /proc/1: %s", e)
++            proc_1_boot_time = 1
++        kernel_boot_time = kernel_boot_time
++
++        boot_time = max(proc_1_boot_time, kernel_boot_time)
++
++        logger.debug("st_mtime of /proc/1: %s", proc_1_boot_time)
++        logger.debug("btime field of /proc/stat: %s", kernel_boot_time)
++        logger.debug("Using %s as the system boot time.", boot_time)
++
++        return boot_time
+ 
+     @staticmethod
+     def get_sc_clk_tck():
+@@ -241,10 +294,13 @@ class ProcessStart(object):
+     def __call__(self, pid):
+         stat_fn = '/proc/%d/stat' % pid
+         with open(stat_fn) as stat_file:
+-            stats = stat_file.read().strip().split()
+-        ticks_after_boot = int(stats[21])
+-        secs_after_boot = ticks_after_boot // self.sc_clk_tck
+-        return self.boot_time + secs_after_boot
++            stats = stat_file.read().split()
++        ticks_after_kernel_boot = int(stats[21])
++        secs_after_kernel_boot = ticks_after_kernel_boot / self.sc_clk_tck
++
++        # The process's start time is always measured relative to the kernel
++        # start time, not either of the other methods we use to get "boot time".
++        return self.kernel_boot_time + secs_after_kernel_boot
+ 
+ 
+ @dnf.plugin.register_command
+-- 
+2.47.0
+
diff --git a/SOURCES/0021-dnf-copr-enable-on-Asahi-Fedora-Linux-Remix-guesses.patch b/SOURCES/0021-dnf-copr-enable-on-Asahi-Fedora-Linux-Remix-guesses.patch
new file mode 100644
index 0000000..9d6493d
--- /dev/null
+++ b/SOURCES/0021-dnf-copr-enable-on-Asahi-Fedora-Linux-Remix-guesses.patch
@@ -0,0 +1,45 @@
+From 275b858c8b90f880fe71c99bd07aeb76637a0926 Mon Sep 17 00:00:00 2001
+From: Eric Curtin <ecurtin@redhat.com>
+Date: Wed, 7 Jun 2023 20:04:25 +0100
+Subject: [PATCH] "dnf copr enable" on "Asahi Fedora Linux Remix" guesses
+ epel..x86_64
+
+Resolves https://issues.redhat.com/browse/RHEL-56143.
+
+On Asahi Fedora Linux Remix, this can occur when doing a dnf copr
+enable:
+
+Repository 'epel-37-x86_64' does not exist in project '@asahi/mesa'
+
+There are two bugs here, the code doesn't recongize this as a Fedora
+distro and defaults to x86_64 when in this case it's actually an aarch64
+system.
+---
+ plugins/copr.py | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/plugins/copr.py b/plugins/copr.py
+index 16946b7..ae4f2e0 100644
+--- a/plugins/copr.py
++++ b/plugins/copr.py
+@@ -444,7 +444,7 @@ Bugzilla. In case of problems, contact the owner of this repository.
+             dist = linux_distribution()
+         # Get distribution architecture
+         distarch = self.base.conf.substitutions['basearch']
+-        if any([name in dist for name in ["Fedora", "Fedora Linux"]]):
++        if "Fedora" in dist[0]:
+             if "Rawhide" in dist:
+                 chroot = ("fedora-rawhide-" + distarch)
+             # workaround for enabling repos in Rawhide when VERSION in os-release
+@@ -470,7 +470,7 @@ Bugzilla. In case of problems, contact the owner of this repository.
+             else:
+                 chroot = ("opensuse-leap-{0}-{1}".format(dist[1], distarch))
+         else:
+-            chroot = ("epel-%s-x86_64" % dist[1].split(".", 1)[0])
++            chroot = ("epel-{}-{}".format(dist[1].split(".", 1)[0], distarch if distarch else "x86_64"))
+         return chroot
+ 
+     def _download_repo(self, project_name, repo_filename):
+-- 
+2.47.1
+
diff --git a/SPECS/dnf-plugins-core.spec b/SPECS/dnf-plugins-core.spec
index 0282712..b2c4b94 100644
--- a/SPECS/dnf-plugins-core.spec
+++ b/SPECS/dnf-plugins-core.spec
@@ -34,7 +34,7 @@
 
 Name:           dnf-plugins-core
 Version:        4.3.0
-Release:        16%{?dist}
+Release:        20%{?dist}
 Summary:        Core Plugins for DNF
 License:        GPLv2+
 URL:            https://github.com/rpm-software-management/dnf-plugins-core
@@ -54,6 +54,9 @@ Patch12:        0012-RHEL-6394-Fix-incorrect-spanish-translation-file.patch
 Patch13:        0013-Fix-for-issue-with-binary-garbage-in-smaps-files.patch
 Patch14:        0014-needs-restarting-Add-microcode_ctl-to-a-reboot-list.patch
 Patch18:        0018-system-upgrade-change-http-to-https-in-unit-file.patch
+Patch19:        0019-reposync-Respect-norepopath-with-metadata-path.patch
+Patch20:        0020-needs-restarting-Get-boot-time-from-systemd-UnitsLoa.patch
+Patch21:        0021-dnf-copr-enable-on-Asahi-Fedora-Linux-Remix-guesses.patch
 
 BuildArch:      noarch
 BuildRequires:  cmake
@@ -801,6 +804,18 @@ ln -sf %{_mandir}/man1/%{yum_utils_subpackage_name}.1.gz %{buildroot}%{_mandir}/
 %endif
 
 %changelog
+* Mon Dec 16 2024 Jan Kolarik <jkolarik@redhat.com> - 4.3.0-20
+- Add forgotten changelog
+
+* Mon Dec 16 2024 Jan Kolarik <jkolarik@redhat.com> - 4.3.0-19
+- Backport patch: "dnf copr enable" on "Asahi Fedora Linux Remix" guesses (RHEL-56143)
+
+* Thu Nov 21 2024 Evan Goode <egoode@redhat.com> - 4.3.0-18
+- needs-restarting: Get boot time from systemd UnitsLoadStartTimestamp (RHEL-14900)
+
+* Thu Oct 10 2024 Pavla Kratochvilova <pkratoch@redhat.com> - 4.3.0-17
+- reposync: Respect --norepopath with --metadata-path (RHEL-40914)
+
 * Thu Jun 06 2024 Petr Pisar <ppisar@redhat.com> - 4.3.0-16
 - Revert needs-restarting prefers to obtain a boot time from systemd to deal
   with RTCs running in local time (RHEL-39775)