diff --git a/0014-context-use-rpmtsAddReinstallElement-when-doing-a-re.patch b/0014-context-use-rpmtsAddReinstallElement-when-doing-a-re.patch new file mode 100644 index 0000000..30ab697 --- /dev/null +++ b/0014-context-use-rpmtsAddReinstallElement-when-doing-a-re.patch @@ -0,0 +1,232 @@ +From bb652b9b1a6a1746413ae43e6bbe1e9ec2aa1a90 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= +Date: Mon, 8 Apr 2024 07:32:31 +0200 +Subject: [PATCH 1/2] context: use `rpmtsAddReinstallElement()` when doing a + reinstall +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit: 85432dfd048912083897ab687488087038a9ac96 + +`rpmtsAddInstallElement()` doesn't work for all reinstall cases, such as +when a package `Provides` and `Conflicts` with the same capability. + +Fixes: https://github.com/rpm-software-management/microdnf/issues/137 +Resolves: https://issues.redhat.com/browse/RHEL-1454 +Signed-off-by: Petr Písař +--- + libdnf/dnf-rpmts-private.hpp | 6 ++ + libdnf/dnf-rpmts.cpp | 108 +++++++++++++++++++++++------------ + libdnf/dnf-transaction.cpp | 8 ++- + 3 files changed, 85 insertions(+), 37 deletions(-) + +diff --git a/libdnf/dnf-rpmts-private.hpp b/libdnf/dnf-rpmts-private.hpp +index 94ad6b45..7a8f70fb 100644 +--- a/libdnf/dnf-rpmts-private.hpp ++++ b/libdnf/dnf-rpmts-private.hpp +@@ -31,4 +31,10 @@ gboolean dnf_rpmts_add_install_filename2(rpmts ts, + DnfPackage *pkg, + GError **error); + ++gboolean dnf_rpmts_add_reinstall_filename(rpmts ts, ++ const gchar *filename, ++ gboolean allow_untrusted, ++ GError **error); ++ ++ + #endif /* __DNF_RPMTS_PRIVATE_HPP */ +diff --git a/libdnf/dnf-rpmts.cpp b/libdnf/dnf-rpmts.cpp +index ec3d3706..9c0152fc 100644 +--- a/libdnf/dnf-rpmts.cpp ++++ b/libdnf/dnf-rpmts.cpp +@@ -88,94 +88,132 @@ test_fail_safe(Header * hdr, DnfPackage * pkg, GError **error) + return ret; + } + +-gboolean +-dnf_rpmts_add_install_filename2(rpmts ts, +- const gchar *filename, +- gboolean allow_untrusted, +- gboolean is_update, +- DnfPackage * pkg, +- GError **error) try +-{ +- gboolean ret = TRUE; +- gint res; +- Header hdr; +- FD_t fd; +- +- /* open this */ +- fd = Fopen(filename, "r.ufdio"); +- res = rpmReadPackageFile(ts, fd, filename, &hdr); +- ++static gboolean ++result_is_accepted(gint result, gboolean allow_untrusted, const gchar *filename, GError **error) { + /* be less strict when we're allowing untrusted transactions */ + if (allow_untrusted) { +- switch(res) { ++ switch(result) { + case RPMRC_NOKEY: + case RPMRC_NOTFOUND: + case RPMRC_NOTTRUSTED: + case RPMRC_OK: +- break; ++ return TRUE; + case RPMRC_FAIL: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("signature does not verify for %s"), + filename); +- goto out; ++ return FALSE; + default: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("failed to open(generic error): %s"), + filename); +- goto out; ++ return FALSE; + } + } else { +- switch(res) { ++ switch(result) { + case RPMRC_OK: +- break; ++ return TRUE; + case RPMRC_NOTTRUSTED: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("failed to verify key for %s"), + filename); +- goto out; ++ return FALSE; + case RPMRC_NOKEY: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("public key unavailable for %s"), + filename); +- goto out; ++ return FALSE; + case RPMRC_NOTFOUND: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("signature not found for %s"), + filename); +- goto out; ++ return FALSE; + case RPMRC_FAIL: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("signature does not verify for %s"), + filename); +- goto out; ++ return FALSE; + default: +- ret = FALSE; + g_set_error(error, + DNF_ERROR, + DNF_ERROR_INTERNAL_ERROR, + _("failed to open(generic error): %s"), + filename); +- goto out; ++ return FALSE; + } + } ++} ++ ++gboolean ++dnf_rpmts_add_reinstall_filename(rpmts ts, ++ const gchar *filename, ++ gboolean allow_untrusted, ++ GError **error) try ++{ ++ gboolean ret = TRUE; ++ gint res; ++ Header hdr; ++ FD_t fd; ++ ++ /* open this */ ++ fd = Fopen(filename, "r.ufdio"); ++ res = rpmReadPackageFile(ts, fd, filename, &hdr); ++ ++ if (!result_is_accepted(res, allow_untrusted, filename, error)) { ++ ret = FALSE; ++ goto out; ++ } ++ ++ /* add to the transaction */ ++ res = rpmtsAddReinstallElement(ts, hdr, (fnpyKey) filename); ++ if (res != 0) { ++ ret = FALSE; ++ g_set_error(error, ++ DNF_ERROR, ++ DNF_ERROR_INTERNAL_ERROR, ++ _("failed to add reinstall element: %1$s [%2$i]"), ++ filename, res); ++ goto out; ++ } ++out: ++ Fclose(fd); ++ headerFree(hdr); ++ return ret; ++} CATCH_TO_GERROR(FALSE) ++ ++gboolean ++dnf_rpmts_add_install_filename2(rpmts ts, ++ const gchar *filename, ++ gboolean allow_untrusted, ++ gboolean is_update, ++ DnfPackage * pkg, ++ GError **error) try ++{ ++ gboolean ret = TRUE; ++ gint res; ++ Header hdr; ++ FD_t fd; ++ ++ /* open this */ ++ fd = Fopen(filename, "r.ufdio"); ++ res = rpmReadPackageFile(ts, fd, filename, &hdr); ++ ++ if (!result_is_accepted(res, allow_untrusted, filename, error)) { ++ ret = FALSE; ++ goto out; ++ } + if (pkg) { + if (!test_fail_safe(&hdr, pkg, error)) { + ret = FALSE; +diff --git a/libdnf/dnf-transaction.cpp b/libdnf/dnf-transaction.cpp +index d93c5ec6..d57e463d 100644 +--- a/libdnf/dnf-transaction.cpp ++++ b/libdnf/dnf-transaction.cpp +@@ -1221,8 +1221,12 @@ dnf_transaction_commit(DnfTransaction *transaction, HyGoal goal, DnfState *state + filename = dnf_package_get_filename(pkg); + allow_untrusted = (priv->flags & DNF_TRANSACTION_FLAG_ONLY_TRUSTED) == 0; + is_update = action == DNF_STATE_ACTION_UPDATE || action == DNF_STATE_ACTION_DOWNGRADE; +- ret = dnf_rpmts_add_install_filename2( +- priv->ts, filename, allow_untrusted, is_update, pkg, error); ++ if (action == DNF_STATE_ACTION_REINSTALL) { ++ ret = dnf_rpmts_add_reinstall_filename(priv->ts, filename, allow_untrusted, error); ++ } else { ++ ret = dnf_rpmts_add_install_filename2( ++ priv->ts, filename, allow_untrusted, is_update, pkg, error); ++ } + if (!ret) + goto out; + +-- +2.45.0 + diff --git a/0015-Since-we-use-rpmtsAddReinstallElement-rpm-also-unins.patch b/0015-Since-we-use-rpmtsAddReinstallElement-rpm-also-unins.patch new file mode 100644 index 0000000..53938f8 --- /dev/null +++ b/0015-Since-we-use-rpmtsAddReinstallElement-rpm-also-unins.patch @@ -0,0 +1,81 @@ +From 7a3d4ed40276d2667cf48f83672ef1f142a8f0a7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= +Date: Fri, 3 May 2024 08:55:47 +0200 +Subject: [PATCH 2/2] Since we use rpmtsAddReinstallElement rpm also uninstalls + the package +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream commit: bc371683ab69d51127952b037bde209a56e44105 + +It calls callbacks for `RPMCALLBACK_INST_START` and +`RPMCALLBACK_INST_PROGRESS` just like before when the reinstall was done +through regural install (rpmtsAddInstallElement) but in addition it also +calls `RPMCALLBACK_UNINST_START` and `RPMCALLBACK_UNINST_PROGRESS`. To +ensure they find the `DnfPackage` add it to `remove_helper` array. + +Unfortunaly this means that the reinstall action is reported twice to +the clients (one install and one uninstall). We could try to hide one of +the them but I think a better solution is to report what is actually +happening and report one install and one uninstall. + +This is for the context part of libdnf (microdnf, packagekit, ...) + +Fixes: https://github.com/rpm-software-management/libdnf/issues/1653 +Resolves: https://issues.redhat.com/browse/RHEL-1454 +Signed-off-by: Petr Písař +--- + libdnf/dnf-transaction.cpp | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/libdnf/dnf-transaction.cpp b/libdnf/dnf-transaction.cpp +index d57e463d..8e17ba2d 100644 +--- a/libdnf/dnf-transaction.cpp ++++ b/libdnf/dnf-transaction.cpp +@@ -602,7 +602,7 @@ dnf_transaction_ts_progress_cb(const void *arg, + + /* map to correct action code */ + action = dnf_package_get_action(pkg); +- if (action == DNF_STATE_ACTION_UNKNOWN) ++ if (action == DNF_STATE_ACTION_UNKNOWN || action == DNF_STATE_ACTION_REINSTALL) + action = DNF_STATE_ACTION_INSTALL; + + /* set the pkgid if not already set */ +@@ -641,7 +641,7 @@ dnf_transaction_ts_progress_cb(const void *arg, + + /* map to correct action code */ + action = dnf_package_get_action(pkg); +- if (action == DNF_STATE_ACTION_UNKNOWN) ++ if (action == DNF_STATE_ACTION_UNKNOWN || action == DNF_STATE_ACTION_REINSTALL) + action = DNF_STATE_ACTION_REMOVE; + + /* remove start */ +@@ -716,7 +716,7 @@ dnf_transaction_ts_progress_cb(const void *arg, + + /* map to correct action code */ + action = dnf_package_get_action(pkg); +- if (action == DNF_STATE_ACTION_UNKNOWN) ++ if (action == DNF_STATE_ACTION_UNKNOWN || action == DNF_STATE_ACTION_REINSTALL) + action = DNF_STATE_ACTION_REMOVE; + + dnf_state_set_package_progress( +@@ -1338,6 +1338,15 @@ dnf_transaction_commit(DnfTransaction *transaction, HyGoal goal, DnfState *state + g_ptr_array_unref(pkglist); + } + ++ /* add reinstalled packages to a helper array which is used to ++ * map removed packages auto-added by rpm to actual DnfPackage's */ ++ pkglist = dnf_goal_get_packages(goal, DNF_PACKAGE_INFO_REINSTALL, -1); ++ for (i = 0; i < pkglist->len; i++) { ++ pkg_tmp = static_cast< DnfPackage * >(g_ptr_array_index(pkglist, i)); ++ g_ptr_array_add(priv->remove_helper, g_object_ref(pkg_tmp)); ++ } ++ g_ptr_array_unref(pkglist); ++ + /* this section done */ + ret = dnf_state_done(state, error); + if (!ret) +-- +2.45.0 + diff --git a/libdnf.spec b/libdnf.spec index 5f9a0cc..2694573 100644 --- a/libdnf.spec +++ b/libdnf.spec @@ -58,7 +58,7 @@ Name: libdnf Version: %{libdnf_major_version}.%{libdnf_minor_version}.%{libdnf_micro_version} -Release: 10%{?dist} +Release: 11%{?dist} Summary: Library providing simplified C and Python API to libsolv License: LGPLv2+ URL: https://github.com/rpm-software-management/libdnf @@ -76,6 +76,8 @@ Patch10: 0010-subject-py-Fix-memory-leak.patch Patch11: 0011-Add-virtual-destructor-to-TransactionItem.patch Patch12: 0012-MergedTransaction-Calculate-RPM-difference-between-t.patch Patch13: 0013-MergedTransaction-Fix-invalid-memory-access-when-dro.patch +Patch14: 0014-context-use-rpmtsAddReinstallElement-when-doing-a-re.patch +Patch15: 0015-Since-we-use-rpmtsAddReinstallElement-rpm-also-unins.patch BuildRequires: cmake @@ -325,6 +327,10 @@ popd %endif %changelog +* Thu May 16 2024 Petr Pisar - 0.69.0-11 +- Fix reinstalling packages which conflicts with themselves in + dnf_transaction_commit() (RHEL-1454) + * Tue Apr 23 2024 Petr Pisar - 0.69.0-10 - Fix calculating a difference between two same-version RPM transacations (RHEL-17494)