Fix reinstalling packages which conflicts with themselves in dnf_transaction_commit()

Resolves: RHEL-1454
This commit is contained in:
Petr Písař 2024-04-17 13:50:24 +02:00
parent f16cb5808d
commit b85a2c5ea2
3 changed files with 320 additions and 1 deletions

View File

@ -0,0 +1,232 @@
From bb652b9b1a6a1746413ae43e6bbe1e9ec2aa1a90 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
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ř <ppisar@redhat.com>
---
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

View File

@ -0,0 +1,81 @@
From 7a3d4ed40276d2667cf48f83672ef1f142a8f0a7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
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ř <ppisar@redhat.com>
---
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

View File

@ -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 <ppisar@redhat.com> - 0.69.0-11
- Fix reinstalling packages which conflicts with themselves in
dnf_transaction_commit() (RHEL-1454)
* Tue Apr 23 2024 Petr Pisar <ppisar@redhat.com> - 0.69.0-10
- Fix calculating a difference between two same-version RPM transacations
(RHEL-17494)