From b6fd5f5745dec02b97dc200829ec0de091363cbb Mon Sep 17 00:00:00 2001 From: chenhaixing Date: Fri, 29 Dec 2023 03:41:42 +0000 Subject: [PATCH] sync upstream patch (cherry picked from commit 58855a51dfc8cbb8bab6e0328a56bec41f7a2280) --- ...nstallonly-packages-marked-for-ERASE.patch | 97 +++++++++++++++++++ ...t-dnf-repo-Fix-utimes-error-messages.patch | 26 +++++ ...ory-if-our-local-cache-is-up-to-date.patch | 95 ++++++++++++++++++ ...gs-Load-all-modules-with-RTLD_GLOBAL.patch | 76 +++++++++++++++ libdnf.spec | 15 ++- 5 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 backport-Avoid-reinstalling-installonly-packages-marked-for-ERASE.patch create mode 100644 backport-dnf-repo-Fix-utimes-error-messages.patch create mode 100644 backport-dnf-repo-do-not-download-repository-if-our-local-cache-is-up-to-date.patch create mode 100644 backport-python-bindings-Load-all-modules-with-RTLD_GLOBAL.patch diff --git a/backport-Avoid-reinstalling-installonly-packages-marked-for-ERASE.patch b/backport-Avoid-reinstalling-installonly-packages-marked-for-ERASE.patch new file mode 100644 index 0000000..eaa39ab --- /dev/null +++ b/backport-Avoid-reinstalling-installonly-packages-marked-for-ERASE.patch @@ -0,0 +1,97 @@ +From 4b016cee3ff42c36349714c1b38b394b4317174f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= +Date: Mon, 25 Sep 2023 08:24:40 +0200 +Subject: [PATCH] Avoid reinstalling installonly packages marked for ERASE + +Without this patch reinstalling installonly pkg marked for ERASE might +be a valid smallest solution to our job. + +For example when user wants to install through a provide we select all +packages that provide it and put them inside a `job install oneof ...` +if one of the providers is also marked for ERASE due to installonly +limit libsolv might decide to reinstall it. + +To make sure it doesn't happen mark the available package also as ERASE. + +https://github.com/openSUSE/libsolv/issues/540 + +https://issues.redhat.com/browse/RHEL-1253 +(https://bugzilla.redhat.com/show_bug.cgi?id=2163474) + +Conflict:NA +Reference:https://github.com/rpm-software-management/libdnf/commit/4b016cee3ff42c36349714c1b38b394b4317174f +--- + libdnf/goal/Goal.cpp | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) + +diff --git a/libdnf/goal/Goal.cpp b/libdnf/goal/Goal.cpp +index 42c078286..269f6b398 100644 +--- a/libdnf/goal/Goal.cpp ++++ b/libdnf/goal/Goal.cpp +@@ -643,6 +643,12 @@ erase_flags2libsolv(int flags) + return ret; + } + ++static bool ++NameSolvableComparator(const Solvable * first, const Solvable * second) ++{ ++ return first->name < second->name; ++} ++ + Goal::Goal(const Goal & goal_src) : pImpl(new Impl(*goal_src.pImpl)) {} + + Goal::Impl::Impl(const Goal::Impl & goal_src) +@@ -1436,10 +1442,24 @@ Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job) + for (int i = 0; i < onlies->count; ++i) { + Id p, pp; + IdQueue q, installing; ++ std::vector available_unused_providers; + ++ // Add all providers of installonly provides that are marked for install ++ // to `q` IdQueue those that are not marked for install and are not already ++ // installed are added to available_unused_providers. + FOR_PKG_PROVIDES(p, pp, onlies->elements[i]) +- if (solver_get_decisionlevel(solv, p) > 0) ++ // According to libsolv-bindings the decision level is positive for installs ++ // and negative for conflicts (conflicts with another package or dependency ++ // conflicts = dependencies cannot be met). ++ if (solver_get_decisionlevel(solv, p) > 0) { + q.pushBack(p); ++ } else { ++ Solvable *s = pool_id2solvable(pool, p); ++ if (s->repo != pool->installed) { ++ available_unused_providers.push_back(s); ++ } ++ } ++ + if (q.size() <= (int) dnf_sack_get_installonly_limit(sack)) { + continue; + } +@@ -1457,6 +1477,7 @@ Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job) + + struct InstallonliesSortCallback s_cb = {pool, dnf_sack_running_kernel(sack)}; + solv_sort(q.data(), q.size(), sizeof(q[0]), sort_packages, &s_cb); ++ std::sort(available_unused_providers.begin(), available_unused_providers.end(), NameSolvableComparator); + IdQueue same_names; + while (q.size() > 0) { + same_name_subqueue(pool, q.getQueue(), same_names.getQueue()); +@@ -1466,8 +1487,18 @@ Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job) + for (int j = 0; j < same_names.size(); ++j) { + Id id = same_names[j]; + Id action = SOLVER_ERASE; +- if (j < (int) dnf_sack_get_installonly_limit(sack)) ++ if (j < (int) dnf_sack_get_installonly_limit(sack)) { + action = SOLVER_INSTALL; ++ } else { ++ // We want to avoid reinstalling packages marked for ERASE, therefore ++ // if some unused provider is also available we need to mark it ERASE as well. ++ Solvable *s = pool_id2solvable(pool, id); ++ auto low = std::lower_bound(available_unused_providers.begin(), available_unused_providers.end(), s, NameSolvableComparator); ++ while (low != available_unused_providers.end() && (*low)->name == s->name) { ++ queue_push2(job, SOLVER_ERASE | SOLVER_SOLVABLE, pool_solvable2id(pool, *low)); ++ ++low; ++ } ++ } + queue_push2(job, action | SOLVER_SOLVABLE, id); + } + } diff --git a/backport-dnf-repo-Fix-utimes-error-messages.patch b/backport-dnf-repo-Fix-utimes-error-messages.patch new file mode 100644 index 0000000..2a5120d --- /dev/null +++ b/backport-dnf-repo-Fix-utimes-error-messages.patch @@ -0,0 +1,26 @@ +From 933f00f5366e9935c9f00f842a4bb60b7da87ad4 Mon Sep 17 00:00:00 2001 +From: Alessandro Astone +Date: Sun, 1 Oct 2023 19:18:54 +0200 +Subject: [PATCH] dnf-repo: Fix utimes error message + +Oops, syscall returns 0 on success + +Conflict:NA +Reference:https://github.com/rpm-software-management/libdnf/commit/933f00f5366e9935c9f00f842a4bb60b7da87ad4 +--- + libdnf/dnf-repo.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp +index c2495f564..ca3d1920a 100644 +--- a/libdnf/dnf-repo.cpp ++++ b/libdnf/dnf-repo.cpp +@@ -1798,7 +1798,7 @@ dnf_repo_update(DnfRepo *repo, + if (repoImpl->isInSync()) { + /* reset timestamp */ + ret = utimes(repoImpl->repomdFn.c_str(), NULL); +- if (!ret) ++ if (ret != 0) + g_debug("Failed to reset timestamp on repomd.xml"); + ret = dnf_state_done(state, error); + if (!ret) diff --git a/backport-dnf-repo-do-not-download-repository-if-our-local-cache-is-up-to-date.patch b/backport-dnf-repo-do-not-download-repository-if-our-local-cache-is-up-to-date.patch new file mode 100644 index 0000000..4cbb1e1 --- /dev/null +++ b/backport-dnf-repo-do-not-download-repository-if-our-local-cache-is-up-to-date.patch @@ -0,0 +1,95 @@ +From e7cf3d198e7b107cffc788f96f51fde2d843dd82 Mon Sep 17 00:00:00 2001 +From: Alessandro Astone +Date: Thu, 28 Sep 2023 14:50:22 +0200 +Subject: [PATCH] dnf-repo: Don't download repository if our local cache is up + to date + +Verified by comparing the hash of repomd.xml + +Conflict:NA +Reference:https://github.com/rpm-software-management/libdnf/commit/e7cf3d198e7b107cffc788f96f51fde2d843dd82 +--- + libdnf/dnf-repo.cpp | 34 ++++++++++++++++++++++++++++++---- + 1 file changed, 30 insertions(+), 4 deletions(-) + +diff --git a/libdnf/dnf-repo.cpp b/libdnf/dnf-repo.cpp +index 48434fd9be..c2495f564e 100644 +--- a/libdnf/dnf-repo.cpp ++++ b/libdnf/dnf-repo.cpp +@@ -969,6 +969,9 @@ dnf_repo_set_keyfile_data(DnfRepo *repo, gboolean reloadFromGKeyFile, GError **e + dnf_repo_apply_setopts(*conf, repoId); + } + ++ if (dnf_context_get_cache_dir(priv->context)) ++ conf->basecachedir().set(libdnf::Option::Priority::REPOCONFIG, dnf_context_get_cache_dir(priv->context)); ++ + /* baseurl is optional; if missing, unset it */ + g_auto(GStrv) baseurls = NULL; + auto & repoBaseurls = conf->baseurl().getValue(); +@@ -1463,6 +1466,7 @@ dnf_repo_check_internal(DnfRepo *repo, + error_local->message); + return FALSE; + } ++ repoImpl->repomdFn = yum_repo->repomd; + + /* get timestamp */ + ret = lr_result_getinfo(priv->repo_result, &error_local, +@@ -1765,8 +1769,10 @@ dnf_repo_update(DnfRepo *repo, + if (!dnf_repo_set_keyfile_data(repo, TRUE, error)) + return FALSE; + ++ auto repoImpl = libdnf::repoGetImpl(priv->repo); ++ + /* countme support */ +- libdnf::repoGetImpl(priv->repo)->addCountmeFlag(priv->repo_handle); ++ repoImpl->addCountmeFlag(priv->repo_handle); + + /* take lock */ + ret = dnf_state_take_lock(state, +@@ -1784,6 +1790,28 @@ dnf_repo_update(DnfRepo *repo, + if (!ret) + goto out; + ++ state_local = dnf_state_get_child(state); ++ dnf_state_action_start(state_local, ++ DNF_STATE_ACTION_DOWNLOAD_METADATA, NULL); ++ ++ try { ++ if (repoImpl->isInSync()) { ++ /* reset timestamp */ ++ ret = utimes(repoImpl->repomdFn.c_str(), NULL); ++ if (!ret) ++ g_debug("Failed to reset timestamp on repomd.xml"); ++ ret = dnf_state_done(state, error); ++ if (!ret) ++ goto out; ++ ++ /* skip check */ ++ ret = dnf_state_finished(state, error); ++ goto out; ++ } ++ } catch (std::exception & ex) { ++ g_debug("Failed to verify if metadata is in sync: \"%s\". Proceding with download", ex.what()); ++ } ++ + /* remove the temporary space if it already exists */ + if (g_file_test(priv->location_tmp, G_FILE_TEST_EXISTS)) { + ret = dnf_remove_recursive(priv->location_tmp, error); +@@ -1842,7 +1870,7 @@ dnf_repo_update(DnfRepo *repo, + goto out; + + /* Callback to display progress of downloading */ +- state_local = updatedata.state = dnf_state_get_child(state); ++ updatedata.state = state_local; + ret = lr_handle_setopt(priv->repo_handle, error, + LRO_PROGRESSDATA, &updatedata); + if (!ret) +@@ -1867,8 +1895,6 @@ dnf_repo_update(DnfRepo *repo, + } + + lr_result_clear(priv->repo_result); +- dnf_state_action_start(state_local, +- DNF_STATE_ACTION_DOWNLOAD_METADATA, NULL); + ret = lr_handle_perform(priv->repo_handle, + priv->repo_result, + &error_local); diff --git a/backport-python-bindings-Load-all-modules-with-RTLD_GLOBAL.patch b/backport-python-bindings-Load-all-modules-with-RTLD_GLOBAL.patch new file mode 100644 index 0000000..961f2d8 --- /dev/null +++ b/backport-python-bindings-Load-all-modules-with-RTLD_GLOBAL.patch @@ -0,0 +1,76 @@ +From 8a8548de607e0488fd4b8ab05373749545a29342 Mon Sep 17 00:00:00 2001 +From: Mark Johnston +Date: Thu, 24 Aug 2023 17:43:36 -0400 +Subject: [PATCH] python bindings: Load all modules with RTLD_GLOBAL + +libdnf's python bindings are implemented by a set of C++ shared objects +generated by swig. Some generated code is duplicated between modules, +in particular the SwigPyIterator class templates, which use exceptions +of type swig::stop_iteration to signal an end-of-iteration condition. +The modules do not depend on each other and thus belong to different +DAGs from the perspective of the runtime linker. + +It turns out that this stop_iteration exception can be thrown between +modules. This happens at least during dnf startup with python 3.9: + +cli.py(935): subst.update_from_etc(from_root, varsdir=conf._get_value('varsdir')) + --- modulename: config, funcname: _get_value +config.py(102): method = getattr(self._config, name, None) +config.py(103): if method is None: +config.py(105): return method().getValue() + --- modulename: conf, funcname: varsdir +conf.py(1183): return _conf.ConfigMain_varsdir(self) + --- modulename: conf, funcname: getValue +conf.py(512): return _conf.OptionStringList_getValue(self) + --- modulename: substitutions, funcname: update_from_etc +substitutions.py(47): for vars_path in varsdir: + --- modulename: module, funcname: __iter__ +module.py(557): return self.iterator() + --- modulename: module, funcname: iterator +module.py(555): return _module.VectorString_iterator(self) + --- modulename: transaction, funcname: __next__ +transaction.py(94): return _transaction.SwigPyIterator___next__(self) + +In particular, the module and transaction modules are somehow both +involved: module returns the iterator, and transaction advances the +iterator. Both modules contain the same iterator code, so I'm not sure +why it works this way. The behaviour is sensitive to import order; for +example, if transaction is imported before module, then the code above +ends up using module's implementation of SwigPyItreator___next__. + +In any case, the use of swig::stop_iteration is broken in the above +scenario since the exception is thrown by module with module.so's copy +of the swig::stop_iteration type info, and caught by transaction.so +using transaction.so's copy of the type info, resulting in an uncaught +exception. + +Work around the problem by loading all modules with RTLD_GLOBAL to +ensure that RTTI is unique. This is required when throwing exceptions +across DSO boundaries, see https://gcc.gnu.org/faq.html#dso for example. + +Conflict:NA +Reference:https://github.com/rpm-software-management/libdnf/commit/8a8548de607e0488fd4b8ab05373749545a29342 +--- + bindings/python/__init__.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/bindings/python/__init__.py b/bindings/python/__init__.py +index 3bfd3a9441..07cf1959d5 100644 +--- a/bindings/python/__init__.py ++++ b/bindings/python/__init__.py +@@ -6,11 +6,14 @@ + import sys, os + sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL) + from . import error +-sys.setdlopenflags(os.RTLD_NOW) + ++# Other modules also need to be loaded with RTLD_GLOBAL to preserve uniqueness ++# of RTTI. There are code paths where an exception thrown in one module is ++# supposed to be caught in another. + from . import common_types + from . import conf + from . import module + from . import repo + from . import transaction + from . import utils ++sys.setdlopenflags(os.RTLD_NOW) diff --git a/libdnf.spec b/libdnf.spec index 453f362..5ce0916 100644 --- a/libdnf.spec +++ b/libdnf.spec @@ -18,7 +18,7 @@ Name: libdnf Version: 0.69.0 -Release: 6 +Release: 7 Summary: Library providing simplified C and Python API to libsolv License: LGPLv2+ URL: https://github.com/rpm-software-management/libdnf @@ -46,6 +46,10 @@ Patch6001: 0001-libdnf-0.65.0-add-loongarch-support.patch %endif Patch6002: backport-Add-check-after-malloc-allocation.patch Patch6003: backport-Disconnect-monitors-in-dnf_repo_loader_finalize.patch +Patch6004: backport-python-bindings-Load-all-modules-with-RTLD_GLOBAL.patch +Patch6005: backport-Avoid-reinstalling-installonly-packages-marked-for-ERASE.patch +Patch6006: backport-dnf-repo-do-not-download-repository-if-our-local-cache-is-up-to-date.patch +Patch6007: backport-dnf-repo-Fix-utimes-error-messages.patch %description A Library providing simplified C and Python API to libsolv. @@ -125,6 +129,15 @@ popd %{python3_sitearch}/hawkey/ %changelog +* Fri Dec 29 2023 chenhaixing - 0.69.0-7 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:libdnf:Avoid reinstalling installonly packages marked for ERASE + Fix utimes error message in dnf-repo + Do not download repository if our local cache is up to date in dnf-repo + python bindings:Load all modules with RTLD_GLOBAL + * Sat Aug 12 2023 sunhai - 0.69.0-6 - Type:bugfix - CVE:NA -- Gitee