[packages/dnf5] - new, based on upstream spec

baggins baggins at pld-linux.org
Sat Feb 15 01:58:27 CET 2025


commit f10efed33decbce5fbdcfa7f5adac1fdae684176
Author: Jan Rękorajski <baggins at pld-linux.org>
Date:   Sat Feb 15 01:03:21 2025 +0100

    - new, based on upstream spec

 0001-cmake-Move-sdbus-c-check-to-one-place.patch   |  89 +++
 ...emon-sdbus-cpp-v.-2-requires-strong-types.patch | 403 ++++++++++++
 ...mon-sdbus-Variant-constructor-is-explicit.patch | 425 +++++++++++++
 ...fdaemon-Explicit-sdbus-Variant-conversion.patch | 374 +++++++++++
 ...dnfdaemon-Make-signal-handlers-compatible.patch | 122 ++++
 ...egister-interface-methods-for-sdbus-cpp-2.patch | 687 +++++++++++++++++++++
 ...lient-Use-correct-data-type-for-callbacks.patch |  34 +
 0008-dnfdaemon-Properly-leave-event-loop.patch     |  26 +
 ...mon-client-Separate-context-and-callbacks.patch | 359 +++++++++++
 dnf5.spec                                          | 672 ++++++++++++++++++++
 systemdunitdir.patch                               |  29 +
 11 files changed, 3220 insertions(+)
---
diff --git a/dnf5.spec b/dnf5.spec
new file mode 100644
index 0000000..955e837
--- /dev/null
+++ b/dnf5.spec
@@ -0,0 +1,672 @@
+#
+# Conditional build:
+%bcond_without	tests		# build without tests
+%bcond_without	docs		# build html documentation
+#
+%bcond_without	dnf5daemon_client
+%bcond_without	dnf5daemon_server
+%bcond_without	libdnf_cli
+%bcond_without	dnf5
+%bcond_without	dnf5_plugins
+# libdnf5 plugins
+%bcond_without	plugin_actions
+%bcond_without	plugin_appstream
+%bcond_without	plugin_expired_pgp_keys
+%bcond_without	python_plugins_loader
+
+%bcond_without	comps
+%bcond_without	modulemd
+%bcond_without	zchunk
+%bcond_without	systemd
+
+%bcond_with	go
+%bcond_without	perl
+%bcond_without	python3
+%bcond_with	ruby
+
+%define		libmodulemd_version	2.5.0
+%define		librepo_version		1.18.0
+%define		libsolv_version		0.7.31
+%define		sqlite_version		3.35.0
+%define		zchunk_version		0.9.11
+
+Summary:	Command-line package manager
+Name:		dnf5
+Version:	5.2.10.0
+Release:	1
+License:	GPL v2+
+Source0:	https://github.com/rpm-software-management/dnf5/archive/%{version}/%{name}-%{version}.tar.gz
+# Source0-md5:	118b176708e1c463ce56f371725c8905
+Patch0:		systemdunitdir.patch
+# sdbus-cpp 2.x
+Patch100:	0001-cmake-Move-sdbus-c-check-to-one-place.patch
+Patch101:	0002-dnfdaemon-sdbus-cpp-v.-2-requires-strong-types.patch
+Patch102:	0003-dnfdaemon-sdbus-Variant-constructor-is-explicit.patch
+Patch103:	0004-dnfdaemon-Explicit-sdbus-Variant-conversion.patch
+Patch104:	0005-dnfdaemon-Make-signal-handlers-compatible.patch
+Patch105:	0006-dnfdaemon-Register-interface-methods-for-sdbus-cpp-2.patch
+Patch106:	0007-dnfdaemon-client-Use-correct-data-type-for-callbacks.patch
+Patch107:	0008-dnfdaemon-Properly-leave-event-loop.patch
+Patch108:	0009-daemon-client-Separate-context-and-callbacks.patch
+URL:		https://github.com/rpm-software-management/dnf5
+BuildRequires:	AppStream-devel >= 0.16
+BuildRequires:	bash-completion-devel
+BuildRequires:	check-devel
+BuildRequires:	cmake
+BuildRequires:	doxygen
+BuildRequires:	gettext
+BuildRequires:	json-c-devel
+BuildRequires:	libfmt-devel
+BuildRequires:	librepo-devel >= %{librepo_version}
+BuildRequires:	libsolv-devel >= %{libsolv_version}
+BuildRequires:	openssl-devel
+BuildRequires:	rpm-devel >= 4.17.0
+BuildRequires:	sqlite3-devel >= %{sqlite_version}
+BuildRequires:	toml11
+%if %{with tests}
+BuildRequires:	cppunit-devel
+BuildRequires:	createrepo_c
+%endif
+%{?with_comps:BuildRequires:	libcomps-devel}
+%{?with_modulemd:BuildRequires:	libmodulemd-devel >= %{libmodulemd_version}}
+%{?with_zchunk:BuildRequires:	zchunk-devel >= %{zchunk_version}}
+%if %{with systemd}
+BuildRequires:	sdbus-cpp-devel >= 0.8.1
+BuildRequires:	systemd-devel
+%endif
+%if %{with docs}
+BuildRequires:	python3-Sphinx
+BuildRequires:	python3-breathe
+BuildRequires:	python3-sphinx_rtd_theme
+%endif
+%if %{with libdnf_cli}
+BuildRequires:	libsmartcols-devel
+%endif
+%if %{with dnf5_plugins}
+BuildRequires:	curl-devel >= 7.62.0
+%endif
+%if %{with dnf5daemon_server}
+BuildRequires:	sdbus-cpp-devel >= 0.9.0
+%endif
+%if %{with perl} || %{with ruby} || %{with python3}
+BuildRequires:	swig
+%endif
+%if %{with perl}
+BuildRequires:	perl-devel
+%if %{with tests}
+BuildRequires:	perl-Test-Exception
+BuildRequires:	perl-base
+BuildRequires:	perl-modules
+%endif
+%endif
+%if %{with ruby}
+BuildRequires:	ruby-devel
+%if %{with tests}
+BuildRequires:	rubygem-test-unit
+%endif
+%endif
+%if %{with python3}
+BuildRequires:	python3-devel
+%endif
+Requires:	coreutils
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+Requires:	libdnf5-cli%{?_isa} = %{version}-%{release}
+Provides:	dnf = %{version}-%{release}
+Provides:	yum = %{version}-%{release}
+Obsoletes:	dnf < 5
+Obsoletes:	yum < 5
+Conflicts:	python3-dnf-plugins-core < 4.7.0
+
+%description
+DNF5 is a command-line package manager that automates the process of
+installing, upgrading, configuring, and removing computer programs in
+a consistent manner. It supports RPM packages, modulemd modules, and
+comps groups & environments.
+
+%package -n libdnf5
+Summary:	Package management library
+License:	LGPL v2.1+
+#Requires:	libmodulemd{?_isa} >= {libmodulemd_version}
+Requires:	librepo%{?_isa} >= %{librepo_version}
+Requires:	libsolv%{?_isa} >= %{libsolv_version}
+Requires:	sqlite-libs%{?_isa} >= %{sqlite_version}
+Conflicts:	dnf-data < 4.20.0
+
+%description -n libdnf5
+Package management library.
+
+%package -n libdnf5-cli
+Summary:	Library for working with a terminal in a command-line package manager
+License:	LGPL v2.1+
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+
+%description -n libdnf5-cli
+Library for working with a terminal in a command-line package manager.
+
+%package -n dnf5-devel
+Summary:	Development files for dnf5
+License:	LGPL v2.1+
+Requires:	dnf5%{?_isa} = %{version}-%{release}
+Requires:	libdnf5-cli-devel%{?_isa} = %{version}-%{release}
+Requires:	libdnf5-devel%{?_isa} = %{version}-%{release}
+
+%description -n dnf5-devel
+Development files for dnf5.
+
+%package -n libdnf5-devel
+Summary:	Development files for libdnf
+License:	LGPL v2.1+
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+Requires:	libsolv-devel%{?_isa} >= %{libsolv_version}
+
+%description -n libdnf5-devel
+Development files for libdnf.
+
+%package -n libdnf5-cli-devel
+Summary:	Development files for libdnf5-cli
+License:	LGPL v2.1+
+Requires:	libdnf5-cli%{?_isa} = %{version}-%{release}
+
+%description -n libdnf5-cli-devel
+Development files for libdnf5-cli.
+
+%package -n perl-libdnf5
+Summary:	Perl 5 bindings for the libdnf library
+License:	LGPL v2.1+
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+
+%description -n perl-libdnf5
+Perl 5 bindings for the libdnf library.
+
+%package -n perl-libdnf5-cli
+Summary:	Perl 5 bindings for the libdnf5-cli library
+License:	LGPL v2.1+
+Requires:	libdnf5-cli%{?_isa} = %{version}-%{release}
+
+%description -n perl-libdnf5-cli
+Perl 5 bindings for the libdnf5-cli library.
+
+%package -n python3-libdnf5
+Summary:	Python 3 bindings for the libdnf5 library
+License:	LGPL v2.1+
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+
+%description -n python3-libdnf5
+Python 3 bindings for the libdnf library.
+
+%package -n python3-libdnf5-cli
+Summary:	Python 3 bindings for the libdnf5-cli library
+License:	LGPL v2.1+
+Requires:	libdnf5-cli%{?_isa} = %{version}-%{release}
+
+%description -n python3-libdnf5-cli
+Python 3 bindings for the libdnf5-cli library.
+
+%package -n ruby-libdnf5
+Summary:	Ruby bindings for the libdnf library
+License:	LGPL v2.1+
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+Requires:	ruby(release)
+Provides:	ruby(libdnf) = %{version}-%{release}
+
+%description -n ruby-libdnf5
+Ruby bindings for the libdnf library.
+
+%package -n ruby-libdnf5-cli
+Summary:	Ruby bindings for the libdnf5-cli library
+License:	LGPL v2.1+
+Requires:	libdnf5-cli%{?_isa} = %{version}-%{release}
+Requires:	ruby(release)
+Provides:	ruby(libdnf_cli) = %{version}-%{release}
+
+%description -n ruby-libdnf5-cli
+Ruby bindings for the libdnf5-cli library.
+
+%package -n libdnf5-plugin-actions
+Summary:	Libdnf5 plugin that allows to run actions (external executables) on hooks
+License:	LGPL v2.1+
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+
+%description -n libdnf5-plugin-actions
+Libdnf5 plugin that allows to run actions (external executables) on
+hooks.
+
+%package -n libdnf5-plugin-appstream
+Summary:	Libdnf5 plugin to install repo Appstream data
+License:	LGPL v2.1+
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+
+%description -n libdnf5-plugin-appstream
+Libdnf5 plugin that installs repository's Appstream data, for
+repositories which provide them.
+
+%package -n libdnf5-plugin-expired-pgp-keys
+Summary:	Libdnf5 plugin for detecting and removing expired PGP keys
+License:	LGPL v2.1+
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+
+%description -n libdnf5-plugin-expired-pgp-keys
+Libdnf5 plugin for detecting and removing expired PGP keys.
+
+%package -n python3-libdnf5-python-plugins-loader
+Summary:	Libdnf5 plugin that allows loading Python plugins
+License:	LGPL v2.1+
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+Requires:	python3-libdnf5%{?_isa} = %{version}-%{release}
+
+%description -n python3-libdnf5-python-plugins-loader
+Libdnf5 plugin that allows loading Python plugins.
+
+%package -n dnf5daemon-client
+Summary:	Command-line interface for dnf5daemon-server
+License:	GPL v2+
+Requires:	dnf5daemon-server
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+Requires:	libdnf5-cli%{?_isa} = %{version}-%{release}
+
+%description -n dnf5daemon-client
+Command-line interface for dnf5daemon-server.
+
+%package -n dnf5daemon-server
+Summary:	Package management service with a DBus interface
+License:	GPL v2+
+Requires:	dbus
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+Requires:	libdnf5-cli%{?_isa} = %{version}-%{release}
+Requires:	polkit
+
+%description -n dnf5daemon-server
+Package management service with a DBus interface.
+
+%package -n dnf5-plugins
+Summary:	Plugins for dnf5
+License:	LGPL v2.1+
+Requires:	dnf5%{?_isa} = %{version}-%{release}
+Requires:	libcurl%{?_isa} >= 7.62.0
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+Requires:	libdnf5-cli%{?_isa} = %{version}-%{release}
+
+%description -n dnf5-plugins
+Core DNF5 plugins that enhance dnf5 with builddep, changelog,
+config-manager, copr, repoclosure, and reposync commands.
+
+%package plugin-automatic
+Summary:	Package manager - automated upgrades
+License:	LGPL v2.1+
+Requires:	dnf5%{?_isa} = %{version}-%{release}
+Requires:	libcurl-full%{?_isa}
+Requires:	libdnf5%{?_isa} = %{version}-%{release}
+Requires:	libdnf5-cli%{?_isa} = %{version}-%{release}
+Provides:	dnf-automatic = %{version}-%{release}
+Obsoletes:	dnf-automatic < 5
+
+%description plugin-automatic
+Alternative command-line interface "dnf upgrade" suitable to be
+executed automatically and regularly from systemd timers, cron jobs or
+similar.
+
+%prep
+%setup -q
+%patch -P 0 -p1
+%patch -P 100 -p1
+%patch -P 101 -p1
+%patch -P 102 -p1
+%patch -P 103 -p1
+%patch -P 104 -p1
+%patch -P 105 -p1
+%patch -P 106 -p1
+%patch -P 107 -p1
+%patch -P 108 -p1
+
+%{__mv} dnf5-plugins/automatic_plugin/config/{usr/,}lib
+
+%build
+mkdir build
+cd build
+%cmake ../ \
+	-DPERL_INSTALLDIRS=vendor \
+	-DENABLE_SOLV_FOCUSNEW=ON \
+	-DWITH_DNF5DAEMON_CLIENT=%{?with_dnf5daemon_client:ON}%{!?with_dnf5daemon_client:OFF} \
+	-DWITH_DNF5DAEMON_SERVER=%{?with_dnf5daemon_server:ON}%{!?with_dnf5daemon_server:OFF} \
+	-DWITH_LIBDNF5_CLI=%{?with_libdnf_cli:ON}%{!?with_libdnf_cli:OFF} \
+	-DWITH_DNF5=%{?with_dnf5:ON}%{!?with_dnf5:OFF} \
+	-DWITH_PLUGIN_ACTIONS=%{?with_plugin_actions:ON}%{!?with_plugin_actions:OFF} \
+	-DWITH_PLUGIN_APPSTREAM=%{?with_plugin_appstream:ON}%{!?with_plugin_appstream:OFF} \
+	-DWITH_PLUGIN_RHSM=OFF \
+	-DWITH_PYTHON_PLUGINS_LOADER=%{?with_python_plugins_loader:ON}%{!?with_python_plugins_loader:OFF} \
+	\
+	%{cmake_on_off comps WITH_COMPS} \
+	%{cmake_on_off modulemd WITH_MODULEMD} \
+	%{cmake_on_off zchunk WITH_ZCHUNK} \
+	%{cmake_on_off systemd WITH_SYSTEMD} \
+	%{cmake_on_off docs WITH_HTML} \
+	%{cmake_on_off go WITH_GO} \
+	%{cmake_on_off perl WITH_PERL5} \
+	%{cmake_on_off python3 WITH_PYTHON3} \
+	%{cmake_on_off ruby WITH_RUBY} \
+	%{cmake_on_off tests WITH_TESTS}
+
+%{__make}
+%if %{with docs}
+%{__make} -j1 doc
+%endif
+
+%if %{with tests}
+TMPDIR=/tmp /usr/bin/ctest --force-new-ctest-process --output-on-failure
+%endif
+
+%install
+rm -rf $RPM_BUILD_ROOT
+install -d $RPM_BUILD_ROOT/var/{cache/libdnf5,lib/dnf}
+install -d $RPM_BUILD_ROOT%{_prefix}/lib/sysimage/libdnf5/{comps_groups,offline}
+
+%{__make} -C build install \
+	DESTDIR=$RPM_BUILD_ROOT
+
+ln -sr $RPM_BUILD_ROOT%{_bindir}/dnf5 $RPM_BUILD_ROOT%{_bindir}/dnf
+ln -sr $RPM_BUILD_ROOT%{_bindir}/dnf5 $RPM_BUILD_ROOT%{_bindir}/yum
+ln -sr $RPM_BUILD_ROOT%{bash_compdir}/dnf5 $RPM_BUILD_ROOT%{bash_compdir}/dnf
+(cd $RPM_BUILD_ROOT%{_mandir}
+for file in man[578]/dnf5[-.]*; do
+	echo ".so $file" > "$(dirname $file)/dnf${file##*/dnf5}"
+done)
+
+# own dirs and files that dnf5 creates on runtime
+for file in \
+    environments.toml groups.toml modules.toml nevras.toml packages.toml \
+    system.toml \
+    transaction_history.sqlite transaction_history.sqlite-shm \
+    transaction_history.sqlite-wal
+do
+    touch $RPM_BUILD_ROOT%{_prefix}/lib/sysimage/libdnf5/$file
+done
+touch $RPM_BUILD_ROOT%{_sysconfdir}/dnf/versionlock.toml
+touch $RPM_BUILD_ROOT%{_sysconfdir}/dnf/dnf5-plugins/automatic.conf
+
+%if %{with systemd}
+install -d $RPM_BUILD_ROOT%{systemdunitdir}/system-update.target.wants
+ln -sr $RPM_BUILD_ROOT%{systemdunitdir}{,/system-update.target.wants}/dnf5-offline-transaction.service
+%endif
+
+%find_lang dnf5
+%find_lang dnf5-plugin-builddep
+%find_lang dnf5-plugin-changelog
+%find_lang dnf5-plugin-config-manager
+%find_lang dnf5-plugin-copr
+%find_lang dnf5-plugin-needs-restarting
+%find_lang dnf5-plugin-repoclosure
+%find_lang dnf5daemon-client
+%find_lang dnf5daemon-server
+%find_lang libdnf5
+%find_lang libdnf5-cli
+%find_lang libdnf5-plugin-actions
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+%systemd_post dnf5-makecache.timer
+
+%preun
+%systemd_preun dnf5-makecache.timer
+
+%postun
+%systemd_postun_with_restart dnf5-makecache.timer
+
+%post -n dnf5daemon-server
+%systemd_post dnf5daemon-server.service
+
+%preun -n dnf5daemon-server
+%systemd_preun dnf5daemon-server.service
+
+%postun -n dnf5daemon-server
+%systemd_postun_with_restart dnf5daemon-server.service
+
+%post -n libdnf5 -p /sbin/ldconfig
+%postun -n libdnf5 -p /sbin/ldconfig
+%post -n libdnf5-cli -p /sbin/ldconfig
+%postun -n libdnf5-cli -p /sbin/ldconfig
+
+%files -f dnf5.lang
+%defattr(644,root,root,755)
+%doc COPYING.md
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_bindir}/dnf5
+%attr(755,root,root) %{_bindir}/dnf
+%attr(755,root,root) %{_bindir}/yum
+%{systemdunitdir}/dnf5-makecache.service
+%{systemdunitdir}/dnf5-makecache.timer
+
+%dir %{_sysconfdir}/dnf/dnf5-aliases.d
+%doc %{_sysconfdir}/dnf/dnf5-aliases.d/README
+%dir %{_datadir}/dnf5
+%dir %{_datadir}/dnf5/aliases.d
+%{_datadir}/dnf5/aliases.d/compatibility.conf
+%dir %{_libdir}/dnf5
+%dir %{_libdir}/dnf5/plugins
+%dir %{_datadir}/dnf5/dnf5-plugins
+%dir %{_sysconfdir}/dnf/dnf5-plugins
+%doc %{_libdir}/dnf5/plugins/README
+%dir %{_libdir}/libdnf5/plugins
+%dir %{_datadir}/bash-completion/
+%dir %{bash_compdir}/
+%{bash_compdir}/dnf*
+%dir %{_prefix}/lib/sysimage/libdnf5
+%dir %{_prefix}/lib/sysimage/libdnf5/comps_groups
+%dir %{_prefix}/lib/sysimage/libdnf5/offline
+%ghost %verify(not md5 mtime size) %{_prefix}/lib/sysimage/libdnf5/*.toml
+%ghost %verify(not md5 mtime size) %{_prefix}/lib/sysimage/libdnf5/transaction_history.sqlite*
+%{_mandir}/man8/dnf.8*
+%{_mandir}/man8/dnf5.8*
+%{_mandir}/man8/dnf*-advisory.8*
+%{_mandir}/man8/dnf*-autoremove.8*
+%{_mandir}/man8/dnf*-check.8*
+%{_mandir}/man8/dnf*-clean.8*
+%{_mandir}/man8/dnf*-distro-sync.8*
+%{_mandir}/man8/dnf*-downgrade.8*
+%{_mandir}/man8/dnf*-download.8*
+%{_mandir}/man8/dnf*-environment.8*
+%{_mandir}/man8/dnf*-group.8*
+%{_mandir}/man8/dnf*-history.8*
+%{_mandir}/man8/dnf*-info.8*
+%{_mandir}/man8/dnf*-install.8*
+%{_mandir}/man8/dnf*-leaves.8*
+%{_mandir}/man8/dnf*-list.8*
+%{_mandir}/man8/dnf*-makecache.8*
+%{_mandir}/man8/dnf*-mark.8*
+%{_mandir}/man8/dnf*-module.8*
+%{_mandir}/man8/dnf*-offline.8*
+%{_mandir}/man8/dnf*-provides.8*
+%{_mandir}/man8/dnf*-reinstall.8*
+%{_mandir}/man8/dnf*-remove.8*
+%{_mandir}/man8/dnf*-replay.8*
+%{_mandir}/man8/dnf*-repo.8*
+%{_mandir}/man8/dnf*-repoquery.8*
+%{_mandir}/man8/dnf*-search.8*
+%{_mandir}/man8/dnf*-swap.8*
+%{_mandir}/man8/dnf*-upgrade.8*
+%{_mandir}/man8/dnf*-versionlock.8*
+%{_mandir}/man7/dnf*-aliases.7*
+%{_mandir}/man7/dnf*-caching.7*
+%{_mandir}/man7/dnf*-comps.7*
+%{_mandir}/man7/dnf*-filtering.7*
+%{_mandir}/man7/dnf*-forcearch.7*
+%{_mandir}/man7/dnf*-installroot.7*
+%{_mandir}/man7/dnf*-modularity.7*
+%{_mandir}/man7/dnf*-specs.7*
+%{_mandir}/man7/dnf*-system-state.7*
+%{_mandir}/man7/dnf*-changes-from-dnf4.7*
+%{_mandir}/man5/dnf*.conf.5*
+%{_mandir}/man5/dnf*.conf-todo.5*
+%{_mandir}/man5/dnf*.conf-deprecated.5*
+
+%if %{with systemd}
+%{systemdunitdir}/dnf5-offline-transaction.service
+%{systemdunitdir}/dnf5-offline-transaction-cleanup.service
+%{systemdunitdir}/system-update.target.wants/dnf5-offline-transaction.service
+%endif
+
+%files -n libdnf5 -f libdnf5.lang
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/dnf/dnf.conf
+%dir %{_sysconfdir}/dnf/vars
+%dir %{_sysconfdir}/dnf/protected.d
+%ghost %{_sysconfdir}/dnf/versionlock.toml
+%dir %{_datadir}/dnf5/libdnf.conf.d
+%dir %{_sysconfdir}/dnf/libdnf5.conf.d
+%dir %{_datadir}/dnf5/repos.override.d
+%dir %{_sysconfdir}/dnf/repos.override.d
+%dir %{_sysconfdir}/dnf/libdnf5-plugins
+%dir %{_datadir}/dnf5/repos.d
+%dir %{_datadir}/dnf5/vars.d
+%dir %{_libdir}/libdnf5
+%{_libdir}/libdnf5.so.2*
+%dir %{_var}/cache/libdnf5
+%dir %{_sharedstatedir}/dnf
+
+%files -n libdnf5-cli -f libdnf5-cli.lang
+%defattr(644,root,root,755)
+%{_libdir}/libdnf5-cli.so.2*
+
+%files -n dnf5-devel
+%defattr(644,root,root,755)
+%{_includedir}/dnf5/
+
+%files -n libdnf5-devel
+%defattr(644,root,root,755)
+%{_includedir}/libdnf5/
+%dir %{_libdir}/libdnf5
+%{_libdir}/libdnf5.so
+%{_pkgconfigdir}/libdnf5.pc
+
+%files -n libdnf5-cli-devel
+%defattr(644,root,root,755)
+%{_includedir}/libdnf5-cli/
+%{_libdir}/libdnf5-cli.so
+%{_pkgconfigdir}/libdnf5-cli.pc
+
+%if %{with perl}
+%files -n perl-libdnf5
+%defattr(644,root,root,755)
+%{perl_vendorarch}/libdnf5
+%{perl_vendorarch}/auto/libdnf5
+%endif
+
+%if %{with perl} && %{with libdnf_cli}
+%files -n perl-libdnf5-cli
+%defattr(644,root,root,755)
+%{perl_vendorarch}/libdnf5_cli
+%{perl_vendorarch}/auto/libdnf5_cli
+%endif
+
+%if %{with python3}
+%files -n python3-libdnf5
+%defattr(644,root,root,755)
+%{py3_sitedir}/libdnf5
+%{py3_sitedir}/libdnf5-*.dist-info
+%endif
+
+%if %{with python3} && %{with libdnf_cli}
+%files -n python3-libdnf5-cli
+%defattr(644,root,root,755)
+%{py3_sitedir}/libdnf5_cli
+%{py3_sitedir}/libdnf5_cli-*.dist-info
+%endif
+
+%if %{with ruby}
+%files -n ruby-libdnf5
+%defattr(644,root,root,755)
+%{ruby_vendorarchdir}/libdnf5
+%endif
+
+%if %{with ruby} && %{with libdnf_cli}
+%files -n ruby-libdnf5-cli
+%defattr(644,root,root,755)
+%{ruby_vendorarchdir}/libdnf5_cli
+%endif
+
+%if %{with plugin_actions}
+%files -n libdnf5-plugin-actions -f libdnf5-plugin-actions.lang
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/dnf/libdnf5-plugins/actions.conf
+%dir %{_sysconfdir}/dnf/libdnf5-plugins/actions.d
+%{_libdir}/libdnf5/plugins/actions.*
+%{_mandir}/man8/libdnf5-actions.8*
+%endif
+
+%if %{with plugin_appstream}
+%files -n libdnf5-plugin-appstream
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/dnf/libdnf5-plugins/appstream.conf
+%{_libdir}/libdnf5/plugins/appstream.so
+%endif
+
+%if %{with plugin_expired_pgp_keys}
+%files -n libdnf5-plugin-expired-pgp-keys
+%defattr(644,root,root,755)
+%{_sysconfdir}/dnf/libdnf5-plugins/expired-pgp-keys.conf
+%{_libdir}/libdnf5/plugins/expired-pgp-keys.so
+%{_mandir}/man8/libdnf5-expired-pgp-keys.8*
+%endif
+
+%if %{with python_plugins_loader}
+%files -n python3-libdnf5-python-plugins-loader
+%defattr(644,root,root,755)
+%{_libdir}/libdnf5/plugins/python_plugins_loader.*
+%dir %{py3_sitescriptdir}/libdnf_plugins/
+%doc %{py3_sitescriptdir}/libdnf_plugins/README
+%endif
+
+%if %{with dnf5daemon_client}
+%files -n dnf5daemon-client -f dnf5daemon-client.lang
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_bindir}/dnf5daemon-client
+%{_mandir}/man8/dnf5daemon-client.8*
+%endif
+
+%if %{with dnf5daemon_server}
+%files -n dnf5daemon-server -f dnf5daemon-server.lang
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_sbindir}/dnf5daemon-server
+%{systemdunitdir}/dnf5daemon-server.service
+%{_datadir}/dbus-1/system.d/org.rpm.dnf.v0.conf
+%{_datadir}/dbus-1/system-services/org.rpm.dnf.v0.service
+%{_datadir}/dbus-1/interfaces/org.rpm.dnf.v0.*.xml
+%{_datadir}/polkit-1/actions/org.rpm.dnf.v0.policy
+%{_mandir}/man8/dnf5daemon-server.8*
+%{_mandir}/man8/dnf5daemon-dbus-api.8*
+%endif
+
+%if %{with dnf5_plugins}
+%files -n dnf5-plugins -f dnf5-plugin-builddep.lang -f dnf5-plugin-changelog.lang -f dnf5-plugin-config-manager.lang -f dnf5-plugin-copr.lang -f dnf5-plugin-needs-restarting.lang -f dnf5-plugin-repoclosure.lang
+%defattr(644,root,root,755)
+%{_libdir}/dnf5/plugins/builddep_cmd_plugin.so
+%{_libdir}/dnf5/plugins/changelog_cmd_plugin.so
+%{_libdir}/dnf5/plugins/config-manager_cmd_plugin.so
+%{_libdir}/dnf5/plugins/copr_cmd_plugin.so
+%{_libdir}/dnf5/plugins/needs_restarting_cmd_plugin.so
+%{_libdir}/dnf5/plugins/repoclosure_cmd_plugin.so
+%{_libdir}/dnf5/plugins/reposync_cmd_plugin.so
+%{_mandir}/man8/dnf*-builddep.8*
+%{_mandir}/man8/dnf*-changelog.8*
+%{_mandir}/man8/dnf*-config-manager.8*
+%{_mandir}/man8/dnf*-copr.8*
+%{_mandir}/man8/dnf*-needs-restarting.8*
+%{_mandir}/man8/dnf*-repoclosure.8*
+%{_mandir}/man8/dnf*-reposync.8*
+%{_datadir}/dnf5/aliases.d/compatibility-plugins.conf
+%{_datadir}/dnf5/aliases.d/compatibility-reposync.conf
+
+%files plugin-automatic
+%defattr(644,root,root,755)
+#%ghost %{_sysconfdir}/motd.d/dnf5-automatic
+%{_libdir}/dnf5/plugins/automatic_cmd_plugin.so
+%{_datadir}/dnf5/dnf5-plugins/automatic.conf
+%ghost %config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/dnf/dnf5-plugins/automatic.conf
+%{_mandir}/man8/dnf*-automatic.8*
+%{systemdunitdir}/dnf5-automatic.service
+%{systemdunitdir}/dnf5-automatic.timer
+%{systemdunitdir}/dnf-automatic.service
+%{systemdunitdir}/dnf-automatic.timer
+%attr(755,root,root) %{_bindir}/dnf-automatic
+%endif
diff --git a/0001-cmake-Move-sdbus-c-check-to-one-place.patch b/0001-cmake-Move-sdbus-c-check-to-one-place.patch
new file mode 100644
index 0000000..f0379b8
--- /dev/null
+++ b/0001-cmake-Move-sdbus-c-check-to-one-place.patch
@@ -0,0 +1,89 @@
+From 1e1a0627a5102f13f5e4515823ef2305bd4e9763 Mon Sep 17 00:00:00 2001
+From: Marek Blaha <mblaha at redhat.com>
+Date: Fri, 17 May 2024 12:11:06 +0200
+Subject: [PATCH 01/24] cmake: Move sdbus-c++ check to one place
+
+Also set SDBUS_CPP_VERSION_2 macro in case sdbus-c++ was found in
+version 2. This enables conditional compilation according the version of
+the library found.
+---
+ cmake/sdbus_cpp.cmake                               | 10 ++++++++++
+ dnf5-plugins/needs_restarting_plugin/CMakeLists.txt |  2 +-
+ dnf5/CMakeLists.txt                                 |  2 +-
+ dnf5daemon-client/CMakeLists.txt                    |  3 +--
+ dnf5daemon-server/CMakeLists.txt                    |  2 +-
+ 5 files changed, 14 insertions(+), 5 deletions(-)
+ create mode 100644 cmake/sdbus_cpp.cmake
+
+diff --git a/cmake/sdbus_cpp.cmake b/cmake/sdbus_cpp.cmake
+new file mode 100644
+index 00000000..77aced9e
+--- /dev/null
++++ b/cmake/sdbus_cpp.cmake
+@@ -0,0 +1,10 @@
++# Attempt to find sdbus-c++ version 2 (preferred)
++pkg_check_modules(SDBUS_CPP REQUIRED sdbus-c++>=1)
++
++if(SDBUS_CPP_VERSION LESS 2)
++    message(STATUS "Using sdbus-c++ version 1")
++else()
++    # Define macro for version 2 if found
++    add_definitions(-DSDBUS_CPP_VERSION_2)
++    message(STATUS "Using sdbus-c++ version 2")
++endif()
+diff --git a/dnf5-plugins/needs_restarting_plugin/CMakeLists.txt b/dnf5-plugins/needs_restarting_plugin/CMakeLists.txt
+index 651d9f3d..cf290146 100644
+--- a/dnf5-plugins/needs_restarting_plugin/CMakeLists.txt
++++ b/dnf5-plugins/needs_restarting_plugin/CMakeLists.txt
+@@ -7,7 +7,7 @@ add_library(needs_restarting_cmd_plugin MODULE needs_restarting.cpp needs_restar
+ # disable the 'lib' prefix in order to create needs_restarting_cmd_plugin.so
+ set_target_properties(needs_restarting_cmd_plugin PROPERTIES PREFIX "")
+ 
+-pkg_check_modules(SDBUS_CPP REQUIRED sdbus-c++)
++include(sdbus_cpp)
+ 
+ target_link_libraries(needs_restarting_cmd_plugin PRIVATE dnf5 libdnf5 libdnf5-cli ${SDBUS_CPP_LIBRARIES})
+ 
+diff --git a/dnf5/CMakeLists.txt b/dnf5/CMakeLists.txt
+index c127f626..d1438d30 100644
+--- a/dnf5/CMakeLists.txt
++++ b/dnf5/CMakeLists.txt
+@@ -45,7 +45,7 @@ install(TARGETS dnf5 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+ pkg_check_modules(RPM REQUIRED rpm>=4.17.0)
+ 
+ if(WITH_SYSTEMD)
+-  pkg_check_modules(SDBUS_CPP REQUIRED sdbus-c++)
++  include(sdbus_cpp)
+   pkg_check_modules(LIBSYSTEMD REQUIRED libsystemd)
+   add_definitions(-DWITH_SYSTEMD)
+   target_link_libraries(dnf5 PRIVATE ${RPM_LIBRARIES} ${SDBUS_CPP_LIBRARIES} ${LIBSYSTEMD_LIBRARIES})
+diff --git a/dnf5daemon-client/CMakeLists.txt b/dnf5daemon-client/CMakeLists.txt
+index 79e4cb41..195a825f 100644
+--- a/dnf5daemon-client/CMakeLists.txt
++++ b/dnf5daemon-client/CMakeLists.txt
+@@ -13,8 +13,7 @@ include_directories(.)
+ # TODO(mblaha) workaround for dnf5daemon-client using server's headers, fix
+ include_directories(..)
+ 
+-pkg_check_modules(SDBUS_CPP REQUIRED sdbus-c++>=0.9.0)
+-
++include(sdbus_cpp)
+ pkg_check_modules(JSONC REQUIRED json-c)
+ include_directories(${JSONC_INCLUDE_DIRS})
+ 
+diff --git a/dnf5daemon-server/CMakeLists.txt b/dnf5daemon-server/CMakeLists.txt
+index d683a09a..3cfc65c3 100644
+--- a/dnf5daemon-server/CMakeLists.txt
++++ b/dnf5daemon-server/CMakeLists.txt
+@@ -12,7 +12,7 @@ add_definitions(-DGETTEXT_DOMAIN=\"${GETTEXT_DOMAIN}\")
+ include_directories(.)
+ 
+ pkg_check_modules(JSONC REQUIRED json-c)
+-pkg_check_modules(SDBUS_CPP REQUIRED sdbus-c++>=0.9.0)
++include(sdbus_cpp)
+ find_package(Threads)
+ 
+ include_directories(${JSONC_INCLUDE_DIRS})
+-- 
+2.48.1
+
diff --git a/0002-dnfdaemon-sdbus-cpp-v.-2-requires-strong-types.patch b/0002-dnfdaemon-sdbus-cpp-v.-2-requires-strong-types.patch
new file mode 100644
index 0000000..9cb4ed6
--- /dev/null
+++ b/0002-dnfdaemon-sdbus-cpp-v.-2-requires-strong-types.patch
@@ -0,0 +1,403 @@
+From cdf99383de790a1c7497f297094c156b9b862d86 Mon Sep 17 00:00:00 2001
+From: Marek Blaha <mblaha at redhat.com>
+Date: Fri, 7 Jun 2024 11:52:55 +0200
+Subject: [PATCH 02/24] dnfdaemon: sdbus-cpp v. 2 requires strong types
+
+- Use InterfaceName type instead of char * for interface names
+- Use SignalName type instead of char * for signal names
+- Use ServiceName instead of char * for bus names
+- Use Error::Name type instead of char * for errors
+---
+ .../needs_restarting.cpp                      |  9 +-
+ dnf5/commands/offline/offline.cpp             |  9 +-
+ dnf5daemon-server/callbacks.cpp               |  9 +-
+ dnf5daemon-server/callbacks.hpp               | 11 ++-
+ dnf5daemon-server/dbus.hpp                    | 83 ++++++++++---------
+ dnf5daemon-server/services/rpm/rpm.cpp        |  3 +-
+ dnf5daemon-server/session.cpp                 | 10 +--
+ dnf5daemon-server/session.hpp                 |  6 +-
+ dnf5daemon-server/session_manager.cpp         |  5 +-
+ include/libdnf5/sdbus_compat.hpp              | 39 +++++++++
+ 10 files changed, 118 insertions(+), 66 deletions(-)
+ create mode 100644 include/libdnf5/sdbus_compat.hpp
+
+diff --git a/dnf5-plugins/needs_restarting_plugin/needs_restarting.cpp b/dnf5-plugins/needs_restarting_plugin/needs_restarting.cpp
+index e8f695ba..6d9de330 100644
+--- a/dnf5-plugins/needs_restarting_plugin/needs_restarting.cpp
++++ b/dnf5-plugins/needs_restarting_plugin/needs_restarting.cpp
+@@ -25,6 +25,7 @@ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ #include <libdnf5/conf/option_string.hpp>
+ #include <libdnf5/rpm/package.hpp>
+ #include <libdnf5/rpm/package_query.hpp>
++#include <libdnf5/sdbus_compat.hpp>
+ #include <libdnf5/utils/bgettext/bgettext-mark-domain.h>
+ #include <utils/string.hpp>
+ 
+@@ -33,10 +34,10 @@ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ #include <iostream>
+ #include <vector>
+ 
+-const std::string SYSTEMD_DESTINATION_NAME{"org.freedesktop.systemd1"};
+-const std::string SYSTEMD_OBJECT_PATH{"/org/freedesktop/systemd1"};
+-const std::string SYSTEMD_MANAGER_INTERFACE{"org.freedesktop.systemd1.Manager"};
+-const std::string SYSTEMD_UNIT_INTERFACE{"org.freedesktop.systemd1.Unit"};
++const SDBUS_SERVICE_NAME_TYPE SYSTEMD_DESTINATION_NAME{"org.freedesktop.systemd1"};
++const sdbus::ObjectPath SYSTEMD_OBJECT_PATH{"/org/freedesktop/systemd1"};
++const SDBUS_INTERFACE_NAME_TYPE SYSTEMD_MANAGER_INTERFACE{"org.freedesktop.systemd1.Manager"};
++const SDBUS_INTERFACE_NAME_TYPE SYSTEMD_UNIT_INTERFACE{"org.freedesktop.systemd1.Unit"};
+ 
+ namespace dnf5 {
+ 
+diff --git a/dnf5/commands/offline/offline.cpp b/dnf5/commands/offline/offline.cpp
+index 11ae1dad..fa1240e2 100644
+--- a/dnf5/commands/offline/offline.cpp
++++ b/dnf5/commands/offline/offline.cpp
+@@ -29,6 +29,7 @@ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ #include <libdnf5/base/goal.hpp>
+ #include <libdnf5/conf/const.hpp>
+ #include <libdnf5/conf/option_path.hpp>
++#include <libdnf5/sdbus_compat.hpp>
+ #include <libdnf5/transaction/offline.hpp>
+ #include <libdnf5/utils/bgettext/bgettext-lib.h>
+ #include <libdnf5/utils/bgettext/bgettext-mark-domain.h>
+@@ -48,10 +49,10 @@ using namespace libdnf5::cli;
+ 
+ const std::string & ID_TO_IDENTIFY_BOOTS = libdnf5::offline::OFFLINE_STARTED_ID;
+ 
+-const std::string SYSTEMD_DESTINATION_NAME{"org.freedesktop.systemd1"};
+-const std::string SYSTEMD_OBJECT_PATH{"/org/freedesktop/systemd1"};
+-const std::string SYSTEMD_MANAGER_INTERFACE{"org.freedesktop.systemd1.Manager"};
+-const std::string SYSTEMD_UNIT_INTERFACE{"org.freedesktop.systemd1.Unit"};
++const SDBUS_SERVICE_NAME_TYPE SYSTEMD_DESTINATION_NAME{"org.freedesktop.systemd1"};
++const sdbus::ObjectPath SYSTEMD_OBJECT_PATH{"/org/freedesktop/systemd1"};
++const SDBUS_INTERFACE_NAME_TYPE SYSTEMD_MANAGER_INTERFACE{"org.freedesktop.systemd1.Manager"};
++const SDBUS_INTERFACE_NAME_TYPE SYSTEMD_UNIT_INTERFACE{"org.freedesktop.systemd1.Unit"};
+ const std::string SYSTEMD_SERVICE_NAME{"dnf5-offline-transaction.service"};
+ 
+ int call(const std::string & command, const std::vector<std::string> & args) {
+diff --git a/dnf5daemon-server/callbacks.cpp b/dnf5daemon-server/callbacks.cpp
+index cefb9397..aa0ebb7e 100644
+--- a/dnf5daemon-server/callbacks.cpp
++++ b/dnf5daemon-server/callbacks.cpp
+@@ -35,7 +35,8 @@ DbusCallback::DbusCallback(Session & session) : session(session) {
+     dbus_object = session.get_dbus_object();
+ }
+ 
+-sdbus::Signal DbusCallback::create_signal(std::string interface, std::string signal_name) {
++sdbus::Signal DbusCallback::create_signal(
++    const SDBUS_INTERFACE_NAME_TYPE & interface, const SDBUS_SIGNAL_NAME_TYPE & signal_name) {
+     auto signal = dbus_object->createSignal(interface, signal_name);
+     signal.setDestination(session.get_sender());
+     signal << session.get_object_path();
+@@ -45,7 +46,7 @@ sdbus::Signal DbusCallback::create_signal(std::string interface, std::string sig
+ std::chrono::time_point<std::chrono::steady_clock> DbusCallback::prev_print_time = std::chrono::steady_clock::now();
+ 
+ 
+-sdbus::Signal DownloadCB::create_signal_download(const std::string & signal_name, void * user_data) {
++sdbus::Signal DownloadCB::create_signal_download(const SDBUS_SIGNAL_NAME_TYPE & signal_name, void * user_data) {
+     auto signal = create_signal(dnfdaemon::INTERFACE_BASE, signal_name);
+     if (user_data) {
+         auto * data = reinterpret_cast<DownloadUserData *>(user_data);
+@@ -121,7 +122,9 @@ bool KeyImportRepoCB::repokey_import(const libdnf5::rpm::KeyInfo & key_info) {
+ 
+ 
+ sdbus::Signal DbusTransactionCB::create_signal_pkg(
+-    std::string interface, std::string signal_name, const std::string & nevra) {
++    const SDBUS_INTERFACE_NAME_TYPE & interface,
++    const SDBUS_SIGNAL_NAME_TYPE & signal_name,
++    const std::string & nevra) {
+     auto signal = create_signal(interface, signal_name);
+     signal << nevra;
+     return signal;
+diff --git a/dnf5daemon-server/callbacks.hpp b/dnf5daemon-server/callbacks.hpp
+index 97ab8a1e..f165479d 100644
+--- a/dnf5daemon-server/callbacks.hpp
++++ b/dnf5daemon-server/callbacks.hpp
+@@ -25,6 +25,7 @@ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ #include <libdnf5/repo/repo_callbacks.hpp>
+ #include <libdnf5/rpm/rpm_signature.hpp>
+ #include <libdnf5/rpm/transaction_callbacks.hpp>
++#include <libdnf5/sdbus_compat.hpp>
+ #include <sdbus-c++/sdbus-c++.h>
+ 
+ #include <chrono>
+@@ -49,7 +50,8 @@ protected:
+     Session & session;
+     sdbus::IObject * dbus_object;
+ 
+-    virtual sdbus::Signal create_signal(std::string interface, std::string signal_name);
++    virtual sdbus::Signal create_signal(
++        const SDBUS_INTERFACE_NAME_TYPE & interface, const SDBUS_SIGNAL_NAME_TYPE & signal_name);
+     static bool is_time_to_print() {
+         auto now = std::chrono::steady_clock::now();
+         auto delta = now - prev_print_time;
+@@ -76,7 +78,7 @@ public:
+     int mirror_failure(void * user_cb_data, const char * msg, const char * url, const char * metadata) override;
+ 
+ private:
+-    sdbus::Signal create_signal_download(const std::string & signal_name, void * user_data);
++    sdbus::Signal create_signal_download(const SDBUS_SIGNAL_NAME_TYPE & signal_name, void * user_data);
+ };
+ 
+ 
+@@ -146,7 +148,10 @@ public:
+     void finish();
+ 
+ private:
+-    sdbus::Signal create_signal_pkg(std::string interface, std::string signal_name, const std::string & nevra);
++    sdbus::Signal create_signal_pkg(
++        const SDBUS_INTERFACE_NAME_TYPE & interface,
++        const SDBUS_SIGNAL_NAME_TYPE & signal_name,
++        const std::string & nevra);
+ };
+ 
+ }  // namespace dnf5daemon
+diff --git a/dnf5daemon-server/dbus.hpp b/dnf5daemon-server/dbus.hpp
+index 61482b90..68df8db1 100644
+--- a/dnf5daemon-server/dbus.hpp
++++ b/dnf5daemon-server/dbus.hpp
+@@ -20,6 +20,7 @@ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ #ifndef DNF5DAEMON_SERVER_DBUS_HPP
+ #define DNF5DAEMON_SERVER_DBUS_HPP
+ 
++#include <libdnf5/sdbus_compat.hpp>
+ #include <sdbus-c++/sdbus-c++.h>
+ 
+ #include <map>
+@@ -51,46 +52,46 @@ using AdvisoryReference = sdbus::Struct<std::string, std::string, std::string, s
+ 
+ // constants
+ 
+-const char * const DBUS_NAME = "org.rpm.dnf.v0";
+-const char * const DBUS_OBJECT_PATH = "/org/rpm/dnf/v0";
++const SDBUS_SERVICE_NAME_TYPE DBUS_NAME{"org.rpm.dnf.v0"};
++const sdbus::ObjectPath DBUS_OBJECT_PATH{"/org/rpm/dnf/v0"};
+ 
+ // interfaces
+-const char * const INTERFACE_BASE = "org.rpm.dnf.v0.Base";
+-const char * const INTERFACE_REPO = "org.rpm.dnf.v0.rpm.Repo";
+-const char * const INTERFACE_RPM = "org.rpm.dnf.v0.rpm.Rpm";
+-const char * const INTERFACE_GOAL = "org.rpm.dnf.v0.Goal";
+-const char * const INTERFACE_GROUP = "org.rpm.dnf.v0.comps.Group";
+-const char * const INTERFACE_ADVISORY = "org.rpm.dnf.v0.Advisory";
+-const char * const INTERFACE_OFFLINE = "org.rpm.dnf.v0.Offline";
+-const char * const INTERFACE_SESSION_MANAGER = "org.rpm.dnf.v0.SessionManager";
++const SDBUS_INTERFACE_NAME_TYPE INTERFACE_BASE{"org.rpm.dnf.v0.Base"};
++const SDBUS_INTERFACE_NAME_TYPE INTERFACE_REPO{"org.rpm.dnf.v0.rpm.Repo"};
++const SDBUS_INTERFACE_NAME_TYPE INTERFACE_RPM{"org.rpm.dnf.v0.rpm.Rpm"};
++const SDBUS_INTERFACE_NAME_TYPE INTERFACE_GOAL{"org.rpm.dnf.v0.Goal"};
++const SDBUS_INTERFACE_NAME_TYPE INTERFACE_GROUP{"org.rpm.dnf.v0.comps.Group"};
++const SDBUS_INTERFACE_NAME_TYPE INTERFACE_ADVISORY{"org.rpm.dnf.v0.Advisory"};
++const SDBUS_INTERFACE_NAME_TYPE INTERFACE_OFFLINE{"org.rpm.dnf.v0.Offline"};
++const SDBUS_INTERFACE_NAME_TYPE INTERFACE_SESSION_MANAGER{"org.rpm.dnf.v0.SessionManager"};
+ 
+ // signals
+-const char * const SIGNAL_DOWNLOAD_ADD_NEW = "download_add_new";
+-const char * const SIGNAL_DOWNLOAD_PROGRESS = "download_progress";
+-const char * const SIGNAL_DOWNLOAD_END = "download_end";
+-const char * const SIGNAL_DOWNLOAD_MIRROR_FAILURE = "download_mirror_failure";
+-
+-const char * const SIGNAL_REPO_KEY_IMPORT_REQUEST = "repo_key_import_request";
+-
+-const char * const SIGNAL_TRANSACTION_BEFORE_BEGIN = "transaction_before_begin";
+-const char * const SIGNAL_TRANSACTION_AFTER_COMPLETE = "transaction_after_complete";
+-const char * const SIGNAL_TRANSACTION_TRANSACTION_START = "transaction_transaction_start";
+-const char * const SIGNAL_TRANSACTION_TRANSACTION_PROGRESS = "transaction_transaction_progress";
+-const char * const SIGNAL_TRANSACTION_TRANSACTION_STOP = "transaction_transaction_stop";
+-const char * const SIGNAL_TRANSACTION_VERIFY_START = "transaction_verify_start";
+-const char * const SIGNAL_TRANSACTION_VERIFY_PROGRESS = "transaction_verify_progress";
+-const char * const SIGNAL_TRANSACTION_VERIFY_STOP = "transaction_verify_stop";
+-const char * const SIGNAL_TRANSACTION_ACTION_START = "transaction_action_start";
+-const char * const SIGNAL_TRANSACTION_ACTION_PROGRESS = "transaction_action_progress";
+-const char * const SIGNAL_TRANSACTION_ACTION_STOP = "transaction_action_stop";
+-const char * const SIGNAL_TRANSACTION_SCRIPT_START = "transaction_script_start";
+-const char * const SIGNAL_TRANSACTION_SCRIPT_STOP = "transaction_script_stop";
+-const char * const SIGNAL_TRANSACTION_SCRIPT_ERROR = "transaction_script_error";
+-const char * const SIGNAL_TRANSACTION_UNPACK_ERROR = "transaction_unpack_error";
+-const char * const SIGNAL_TRANSACTION_ELEM_PROGRESS = "transaction_elem_progress";
+-const char * const SIGNAL_TRANSACTION_FINISHED = "transaction_finished";
+-
+-const char * const SIGNAL_WRITE_TO_FD_FINISHED = "write_to_fd_finished";
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_DOWNLOAD_ADD_NEW{"download_add_new"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_DOWNLOAD_PROGRESS{"download_progress"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_DOWNLOAD_END{"download_end"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_DOWNLOAD_MIRROR_FAILURE{"download_mirror_failure"};
++
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_REPO_KEY_IMPORT_REQUEST{"repo_key_import_request"};
++
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_BEFORE_BEGIN{"transaction_before_begin"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_AFTER_COMPLETE{"transaction_after_complete"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_TRANSACTION_START{"transaction_transaction_start"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_TRANSACTION_PROGRESS{"transaction_transaction_progress"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_TRANSACTION_STOP{"transaction_transaction_stop"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_VERIFY_START{"transaction_verify_start"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_VERIFY_PROGRESS{"transaction_verify_progress"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_VERIFY_STOP{"transaction_verify_stop"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_ACTION_START{"transaction_action_start"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_ACTION_PROGRESS{"transaction_action_progress"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_ACTION_STOP{"transaction_action_stop"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_SCRIPT_START{"transaction_script_start"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_SCRIPT_STOP{"transaction_script_stop"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_SCRIPT_ERROR{"transaction_script_error"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_UNPACK_ERROR{"transaction_unpack_error"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_ELEM_PROGRESS{"transaction_elem_progress"};
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_TRANSACTION_FINISHED{"transaction_finished"};
++
++const SDBUS_SIGNAL_NAME_TYPE SIGNAL_WRITE_TO_FD_FINISHED{"write_to_fd_finished"};
+ 
+ // polkit actions
+ const char * const POLKIT_REPOCONF_WRITE = "org.rpm.dnf.v0.rpm.Repo.conf_write";
+@@ -99,11 +100,11 @@ const char * const POLKIT_CONFIRM_KEY_IMPORT = "org.rpm.dnf.v0.rpm.Repo.confirm_
+ const char * const POLKIT_CONFIG_OVERRIDE = "org.rpm.dnf.v0.base.Config.override";
+ 
+ // errors
+-const char * const ERROR = "org.rpm.dnf.v0.Error";
+-const char * const ERROR_REPOCONF = "org.rpm.dnf.v0.rpm.Repo.ConfError";
+-const char * const ERROR_REPO_ID_UNKNOWN = "org.rpm.dnf.v0.rpm.Repo.NoMatchingIdError";
+-const char * const ERROR_RESOLVE = "org.rpm.dnf.v0.rpm.Rpm.ResolveError";
+-const char * const ERROR_TRANSACTION = "org.rpm.dnf.v0.rpm.Rpm.TransactionError";
++const SDBUS_ERROR_NAME_TYPE ERROR{"org.rpm.dnf.v0.Error"};
++const SDBUS_ERROR_NAME_TYPE ERROR_REPOCONF{"org.rpm.dnf.v0.rpm.Repo.ConfError"};
++const SDBUS_ERROR_NAME_TYPE ERROR_REPO_ID_UNKNOWN{"org.rpm.dnf.v0.rpm.Repo.NoMatchingIdError"};
++const SDBUS_ERROR_NAME_TYPE ERROR_RESOLVE{"org.rpm.dnf.v0.rpm.Rpm.ResolveError"};
++const SDBUS_ERROR_NAME_TYPE ERROR_TRANSACTION{"org.rpm.dnf.v0.rpm.Rpm.TransactionError"};
+ 
+ }  // namespace dnfdaemon
+ 
+diff --git a/dnf5daemon-server/services/rpm/rpm.cpp b/dnf5daemon-server/services/rpm/rpm.cpp
+index 2a8ff695..83cf253e 100644
+--- a/dnf5daemon-server/services/rpm/rpm.cpp
++++ b/dnf5daemon-server/services/rpm/rpm.cpp
+@@ -467,7 +467,8 @@ void Rpm::list_fd(sdbus::MethodCall & call, const std::string & transfer_id) {
+ 
+     // signal client that the transfer has finished and the output file descriptor is closed
+     auto dbus_object = get_session().get_dbus_object();
+-    auto signal = dbus_object->createSignal(call.getInterfaceName(), dnfdaemon::SIGNAL_WRITE_TO_FD_FINISHED);
++    auto signal = dbus_object->createSignal(
++        SDBUS_INTERFACE_NAME_TYPE{call.getInterfaceName()}, dnfdaemon::SIGNAL_WRITE_TO_FD_FINISHED);
+     signal << error_msg.empty();
+     signal << transfer_id;
+     signal << error_msg;
+diff --git a/dnf5daemon-server/session.cpp b/dnf5daemon-server/session.cpp
+index 06911587..e5363521 100644
+--- a/dnf5daemon-server/session.cpp
++++ b/dnf5daemon-server/session.cpp
+@@ -133,8 +133,8 @@ void Session::setup_base() {
+ Session::Session(
+     sdbus::IConnection & connection,
+     dnfdaemon::KeyValueMap session_configuration,
+-    std::string object_path,
+-    std::string sender)
++    const sdbus::ObjectPath & object_path,
++    const std::string & sender)
+     : connection(connection),
+       session_configuration(session_configuration),
+       object_path(object_path),
+@@ -264,9 +264,9 @@ bool Session::read_all_repos() {
+ bool Session::check_authorization(
+     const std::string & actionid, const std::string & sender, bool allow_user_interaction) {
+     // create proxy for PolicyKit1 object
+-    const std::string destination_name = "org.freedesktop.PolicyKit1";
+-    const std::string object_path = "/org/freedesktop/PolicyKit1/Authority";
+-    const std::string interface_name = "org.freedesktop.PolicyKit1.Authority";
++    const SDBUS_SERVICE_NAME_TYPE destination_name{"org.freedesktop.PolicyKit1"};
++    const sdbus::ObjectPath object_path{"/org/freedesktop/PolicyKit1/Authority"};
++    const SDBUS_INTERFACE_NAME_TYPE interface_name{"org.freedesktop.PolicyKit1.Authority"};
+     auto polkit_proxy = sdbus::createProxy(connection, destination_name, object_path);
+     polkit_proxy->finishRegistration();
+ 
+diff --git a/dnf5daemon-server/session.hpp b/dnf5daemon-server/session.hpp
+index 046c89d0..9a90be8a 100644
+--- a/dnf5daemon-server/session.hpp
++++ b/dnf5daemon-server/session.hpp
+@@ -56,8 +56,8 @@ public:
+     Session(
+         sdbus::IConnection & connection,
+         dnfdaemon::KeyValueMap session_configuration,
+-        std::string object_path,
+-        std::string sender);
++        const sdbus::ObjectPath & object_path,
++        const std::string & sender);
+     ~Session();
+ 
+     template <typename ItemType>
+@@ -69,7 +69,7 @@ public:
+         return dnfdaemon::key_value_map_get<ItemType>(session_configuration, key);
+     }
+ 
+-    const sdbus::ObjectPath & get_object_path() const { return object_path; };
++    const sdbus::ObjectPath & get_object_path() { return object_path; };
+     sdbus::IConnection & get_connection() { return connection; };
+     libdnf5::Base * get_base() { return base.get(); };
+     ThreadsManager & get_threads_manager() { return threads_manager; };
+diff --git a/dnf5daemon-server/session_manager.cpp b/dnf5daemon-server/session_manager.cpp
+index f5d184b1..8ea9d2c8 100644
+--- a/dnf5daemon-server/session_manager.cpp
++++ b/dnf5daemon-server/session_manager.cpp
+@@ -70,7 +70,8 @@ void SessionManager::dbus_register() {
+     dbus_object->finishRegistration();
+ 
+     // register signal handler for NameOwnerChanged
+-    name_changed_proxy = sdbus::createProxy(*connection, "org.freedesktop.DBus", "/org/freedesktop/DBus");
++    name_changed_proxy = sdbus::createProxy(
++        *connection, SDBUS_SERVICE_NAME_TYPE{"org.freedesktop.DBus"}, sdbus::ObjectPath{"/org/freedesktop/DBus"});
+     name_changed_proxy->registerSignalHandler(
+         "org.freedesktop.DBus", "NameOwnerChanged", [this](sdbus::Signal signal) -> void {
+             threads_manager.handle_signal(*this, &SessionManager::on_name_owner_changed, signal);
+@@ -130,7 +131,7 @@ sdbus::MethodReply SessionManager::open_session(sdbus::MethodCall & call) {
+     call >> configuration;
+ 
+     // generate UUID-like session id
+-    const std::string sessionid = dnfdaemon::DBUS_OBJECT_PATH + std::string("/") + gen_session_id();
++    const sdbus::ObjectPath sessionid{dnfdaemon::DBUS_OBJECT_PATH + std::string("/") + gen_session_id()};
+     // store newly created session
+     {
+         std::lock_guard<std::mutex> lock(sessions_mutex);
+diff --git a/include/libdnf5/sdbus_compat.hpp b/include/libdnf5/sdbus_compat.hpp
+new file mode 100644
+index 00000000..029182dd
+--- /dev/null
++++ b/include/libdnf5/sdbus_compat.hpp
+@@ -0,0 +1,39 @@
++/*
++Copyright Contributors to the libdnf project.
++
++This file is part of libdnf: https://github.com/rpm-software-management/libdnf/
++
++Libdnf is free software: you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation, either version 2 of the License, or
++(at your option) any later version.
++
++Libdnf is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
++*/
++
++#ifndef DNF5DAEMON_SERVER_SDBUS_COMPAT_HPP
++#define DNF5DAEMON_SERVER_SDBUS_COMPAT_HPP
++
++#ifdef SDBUS_CPP_VERSION_2
++
++#define SDBUS_INTERFACE_NAME_TYPE sdbus::InterfaceName
++#define SDBUS_SIGNAL_NAME_TYPE    sdbus::SignalName
++#define SDBUS_SERVICE_NAME_TYPE   sdbus::ServiceName
++#define SDBUS_ERROR_NAME_TYPE     sdbus::Error::Name
++
++#else
++
++#define SDBUS_INTERFACE_NAME_TYPE std::string
++#define SDBUS_SIGNAL_NAME_TYPE    std::string
++#define SDBUS_SERVICE_NAME_TYPE   std::string
++#define SDBUS_ERROR_NAME_TYPE     std::string
++
++#endif
++
++#endif
+-- 
+2.48.1
+
diff --git a/0003-dnfdaemon-sdbus-Variant-constructor-is-explicit.patch b/0003-dnfdaemon-sdbus-Variant-constructor-is-explicit.patch
new file mode 100644
index 0000000..19773d8
--- /dev/null
+++ b/0003-dnfdaemon-sdbus-Variant-constructor-is-explicit.patch
@@ -0,0 +1,425 @@
+From af00463e6449f796dad0e4a4da2cb86a6373eb72 Mon Sep 17 00:00:00 2001
+From: Marek Blaha <mblaha at redhat.com>
+Date: Fri, 17 May 2024 13:01:30 +0200
+Subject: [PATCH 03/24] dnfdaemon: sdbus::Variant constructor is explicit
+
+In version 2 the sdbus::Variant constuctor was made explicit.
+---
+ .../commands/advisory/advisory_subcommand.cpp | 26 +++++++-------
+ dnf5daemon-client/commands/command.cpp        |  4 +--
+ .../commands/group/group_list.cpp             | 14 ++++----
+ .../commands/install/install.cpp              |  4 +--
+ .../commands/repolist/repolist.cpp            |  8 ++---
+ .../commands/repoquery/repoquery.cpp          | 14 ++++----
+ .../system-upgrade/system-upgrade.cpp         |  2 +-
+ dnf5daemon-client/context.cpp                 |  6 ++--
+ dnf5daemon-server/advisory.cpp                | 34 +++++++++----------
+ dnf5daemon-server/services/goal/goal.cpp      | 16 ++++-----
+ .../services/offline/offline.cpp              | 16 ++++-----
+ dnf5daemon-server/session.cpp                 |  2 +-
+ 12 files changed, 73 insertions(+), 73 deletions(-)
+
+diff --git a/dnf5daemon-client/commands/advisory/advisory_subcommand.cpp b/dnf5daemon-client/commands/advisory/advisory_subcommand.cpp
+index 9c612869..9fe38858 100644
+--- a/dnf5daemon-client/commands/advisory/advisory_subcommand.cpp
++++ b/dnf5daemon-client/commands/advisory/advisory_subcommand.cpp
+@@ -57,9 +57,9 @@ void AdvisorySubCommand::set_argument_parser() {
+ 
+ dnfdaemon::KeyValueMap AdvisorySubCommand::session_config() {
+     dnfdaemon::KeyValueMap cfg = {};
+-    cfg["load_system_repo"] = true;
+-    cfg["load_available_repos"] = true;
+-    cfg["optional_metadata_types"] = std::vector<std::string>{libdnf5::METADATA_TYPE_UPDATEINFO};
++    cfg["load_system_repo"] = sdbus::Variant(true);
++    cfg["load_available_repos"] = sdbus::Variant(true);
++    cfg["optional_metadata_types"] = sdbus::Variant(std::vector<std::string>{libdnf5::METADATA_TYPE_UPDATEINFO});
+     return cfg;
+ }
+ 
+@@ -69,7 +69,7 @@ void AdvisorySubCommand::run() {
+     // convert arguments to dbus call options
+     dnfdaemon::KeyValueMap options = {};
+ 
+-    options["names"] = advisory_names->get_value();
++    options["names"] = sdbus::Variant(advisory_names->get_value());
+ 
+     // by default return available advisories
+     std::string availability = "available";
+@@ -80,7 +80,7 @@ void AdvisorySubCommand::run() {
+     } else if (updates->get_value()) {
+         availability = "updates";
+     }
+-    options["availability"] = availability;  // string
++    options["availability"] = sdbus::Variant(availability);  // string
+ 
+     // advisory types
+     std::vector<std::string> advisory_types{};
+@@ -96,16 +96,16 @@ void AdvisorySubCommand::run() {
+     if (advisory_newpackage->get_value()) {
+         advisory_types.emplace_back("newpackage");
+     }
+-    options["types"] = advisory_types;  // vector<string>
++    options["types"] = sdbus::Variant(advisory_types);  // vector<string>
+ 
+-    options["contains_pkgs"] = contains_pkgs->get_value();     // vector<string>
+-    options["severities"] = advisory_severities->get_value();  // vector<string>
+-    options["reference_bzs"] = advisory_bzs->get_value();      // vector<string>
+-    options["reference_cves"] = advisory_cves->get_value();    // vector<string>
+-    options["with_bz"] = with_bz->get_value();                 // bool
+-    options["with_cve"] = with_cve->get_value();               // bool
++    options["contains_pkgs"] = sdbus::Variant(contains_pkgs->get_value());     // vector<string>
++    options["severities"] = sdbus::Variant(advisory_severities->get_value());  // vector<string>
++    options["reference_bzs"] = sdbus::Variant(advisory_bzs->get_value());      // vector<string>
++    options["reference_cves"] = sdbus::Variant(advisory_cves->get_value());    // vector<string>
++    options["with_bz"] = sdbus::Variant(with_bz->get_value());                 // bool
++    options["with_cve"] = sdbus::Variant(with_cve->get_value());               // bool
+ 
+-    options["advisory_attrs"] = advisory_attrs;
++    options["advisory_attrs"] = sdbus::Variant(advisory_attrs);
+ 
+     // call the server
+     dnfdaemon::KeyValueMapList raw_advisories;
+diff --git a/dnf5daemon-client/commands/command.cpp b/dnf5daemon-client/commands/command.cpp
+index 67a4e8ea..6f9f55ac 100644
+--- a/dnf5daemon-client/commands/command.cpp
++++ b/dnf5daemon-client/commands/command.cpp
+@@ -42,7 +42,7 @@ void TransactionCommand::run_transaction(bool offline) {
+     dnfdaemon::KeyValueMap options = {};
+ 
+     // resolve the transaction
+-    options["allow_erasing"] = ctx.allow_erasing.get_value();
++    options["allow_erasing"] = sdbus::Variant(ctx.allow_erasing.get_value());
+     std::vector<dnfdaemon::DbusTransactionItem> transaction;
+     unsigned int result_int;
+     ctx.session_proxy->callMethod("resolve")
+@@ -80,7 +80,7 @@ void TransactionCommand::run_transaction(bool offline) {
+ 
+     // do the transaction
+     options.clear();
+-    options["offline"] = offline;
++    options["offline"] = sdbus::Variant(offline);
+     ctx.session_proxy->callMethod("do_transaction")
+         .onInterface(dnfdaemon::INTERFACE_GOAL)
+         .withTimeout(static_cast<uint64_t>(-1))
+diff --git a/dnf5daemon-client/commands/group/group_list.cpp b/dnf5daemon-client/commands/group/group_list.cpp
+index 8bd7e194..e99c0c90 100644
+--- a/dnf5daemon-client/commands/group/group_list.cpp
++++ b/dnf5daemon-client/commands/group/group_list.cpp
+@@ -72,7 +72,7 @@ void GroupListCommand::run() {
+             patterns.emplace_back(option->get_value());
+         }
+     }
+-    options["patterns"] = patterns;
++    options["patterns"] = sdbus::Variant(patterns);
+ 
+     std::vector<std::string> attributes{"groupid", "name", "installed"};
+     if (command == "info") {
+@@ -81,10 +81,10 @@ void GroupListCommand::run() {
+         attributes.reserve(attributes.size() + more_attributes.size());
+         std::move(std::begin(more_attributes), std::end(more_attributes), std::back_inserter(attributes));
+     }
+-    options["attributes"] = attributes;
++    options["attributes"] = sdbus::Variant(attributes);
+ 
+     if (hidden->get_value() || !patterns.empty()) {
+-        options["with_hidden"] = true;
++        options["with_hidden"] = sdbus::Variant(true);
+     }
+ 
+     std::string scope = "all";
+@@ -93,14 +93,14 @@ void GroupListCommand::run() {
+     } else if (available->get_value()) {
+         scope = "available";
+     }
+-    options["scope"] = scope;
++    options["scope"] = sdbus::Variant(scope);
+ 
+     if (!contains_pkgs->get_value().empty()) {
+-        options["contains_pkgs"] = contains_pkgs->get_value();
++        options["contains_pkgs"] = sdbus::Variant(contains_pkgs->get_value());
+     }
+ 
+-    options["match_group_id"] = true;
+-    options["match_group_name"] = true;
++    options["match_group_id"] = sdbus::Variant(true);
++    options["match_group_name"] = sdbus::Variant(true);
+ 
+     dnfdaemon::KeyValueMapList raw_groups;
+     ctx.session_proxy->callMethod("list")
+diff --git a/dnf5daemon-client/commands/install/install.cpp b/dnf5daemon-client/commands/install/install.cpp
+index 4dba94f5..0db5acec 100644
+--- a/dnf5daemon-client/commands/install/install.cpp
++++ b/dnf5daemon-client/commands/install/install.cpp
+@@ -80,10 +80,10 @@ void InstallCommand::run() {
+     dnfdaemon::KeyValueMap options = {};
+     // pass the `skip_*` value to the server only when explicitly set by command line option
+     if (skip_broken_option.get_priority() >= libdnf5::Option::Priority::COMMANDLINE) {
+-        options["skip_broken"] = skip_broken_option.get_value();
++        options["skip_broken"] = sdbus::Variant(skip_broken_option.get_value());
+     }
+     if (skip_unavailable_option.get_priority() >= libdnf5::Option::Priority::COMMANDLINE) {
+-        options["skip_unavailable"] = skip_unavailable_option.get_value();
++        options["skip_unavailable"] = sdbus::Variant(skip_unavailable_option.get_value());
+     }
+ 
+     ctx.session_proxy->callMethod("install")
+diff --git a/dnf5daemon-client/commands/repolist/repolist.cpp b/dnf5daemon-client/commands/repolist/repolist.cpp
+index 6798bb64..a729b39e 100644
+--- a/dnf5daemon-client/commands/repolist/repolist.cpp
++++ b/dnf5daemon-client/commands/repolist/repolist.cpp
+@@ -107,17 +107,17 @@ void RepolistCommand::run() {
+ 
+     // prepare options from command line arguments
+     dnfdaemon::KeyValueMap options = {};
+-    options["enable_disable"] = enable_disable_option->get_value();
++    options["enable_disable"] = sdbus::Variant(enable_disable_option->get_value());
+     std::vector<std::string> patterns;
+     if (!patterns_options->empty()) {
+-        options["enable_disable"] = "all";
++        options["enable_disable"] = sdbus::Variant("all");
+         patterns.reserve(patterns_options->size());
+         for (auto & pattern : *patterns_options) {
+             auto option = dynamic_cast<libdnf5::OptionString *>(pattern.get());
+             patterns.emplace_back(option->get_value());
+         }
+     }
+-    options["patterns"] = patterns;
++    options["patterns"] = sdbus::Variant(patterns);
+ 
+     std::vector<std::string> attrs{"id", "name", "enabled"};
+     if (command == "repoinfo") {
+@@ -147,7 +147,7 @@ void RepolistCommand::run() {
+             "mirrors"};
+         attrs.insert(attrs.end(), repoinfo_attrs.begin(), repoinfo_attrs.end());
+     }
+-    options["repo_attrs"] = attrs;
++    options["repo_attrs"] = sdbus::Variant(attrs);
+ 
+     // call list() method on repo interface via dbus
+     dnfdaemon::KeyValueMapList repositories;
+diff --git a/dnf5daemon-client/commands/repoquery/repoquery.cpp b/dnf5daemon-client/commands/repoquery/repoquery.cpp
+index 10d39e89..f1f0ed75 100644
+--- a/dnf5daemon-client/commands/repoquery/repoquery.cpp
++++ b/dnf5daemon-client/commands/repoquery/repoquery.cpp
+@@ -102,9 +102,9 @@ void RepoqueryCommand::set_argument_parser() {
+ 
+ dnfdaemon::KeyValueMap RepoqueryCommand::session_config() {
+     dnfdaemon::KeyValueMap cfg = {};
+-    cfg["load_system_repo"] = installed_option->get_value();
+-    cfg["load_available_repos"] =
+-        (available_option->get_priority() >= libdnf5::Option::Priority::COMMANDLINE || !installed_option->get_value());
++    cfg["load_system_repo"] = sdbus::Variant(installed_option->get_value());
++    cfg["load_available_repos"] = sdbus::Variant(
++        (available_option->get_priority() >= libdnf5::Option::Priority::COMMANDLINE || !installed_option->get_value()));
+     return cfg;
+ }
+ 
+@@ -125,13 +125,13 @@ std::vector<DbusPackageWrapper> json_to_packages(std::string & json_stream) {
+             json_object_object_foreach(json_pkg, key, val) {
+                 switch (json_object_get_type(val)) {
+                     case json_type_boolean:
+-                        dbuspkg[key] = static_cast<bool>(json_object_get_boolean(val));
++                        dbuspkg[key] = sdbus::Variant(static_cast<bool>(json_object_get_boolean(val)));
+                         break;
+                     case json_type_int:
+-                        dbuspkg[key] = static_cast<uint64_t>(json_object_get_int64(val));
++                        dbuspkg[key] = sdbus::Variant(static_cast<uint64_t>(json_object_get_int64(val)));
+                         break;
+                     default:
+-                        dbuspkg[key] = json_object_get_string(val);
++                        dbuspkg[key] = sdbus::Variant(json_object_get_string(val));
+                 }
+             }
+             packages.emplace_back(DbusPackageWrapper(dbuspkg));
+@@ -180,7 +180,7 @@ void RepoqueryCommand::run() {
+             patterns.emplace_back(option->get_value());
+         }
+     }
+-    options["patterns"] = patterns;
++    options["patterns"] = sdbus::Variant(patterns);
+     if (info_option->get_value()) {
+         options.insert(std::pair<std::string, std::vector<std::string>>(
+             "package_attrs",
+diff --git a/dnf5daemon-client/commands/system-upgrade/system-upgrade.cpp b/dnf5daemon-client/commands/system-upgrade/system-upgrade.cpp
+index 9e09e812..4aa41c6d 100644
+--- a/dnf5daemon-client/commands/system-upgrade/system-upgrade.cpp
++++ b/dnf5daemon-client/commands/system-upgrade/system-upgrade.cpp
+@@ -67,7 +67,7 @@ void SystemUpgradeCommand::run() {
+ 
+     dnfdaemon::KeyValueMap options = {};
+     if (no_downgrade_option.get_value()) {
+-        options["mode"] = "upgrade";
++        options["mode"] = sdbus::Variant("upgrade");
+     }
+ 
+     ctx.session_proxy->callMethod("system_upgrade")
+diff --git a/dnf5daemon-client/context.cpp b/dnf5daemon-client/context.cpp
+index 2624b4dd..bcfd1bfa 100644
+--- a/dnf5daemon-client/context.cpp
++++ b/dnf5daemon-client/context.cpp
+@@ -47,12 +47,12 @@ void Context::init_session(sdbus::IConnection & connection) {
+     for (auto & opt : setopts) {
+         config[opt.first] = opt.second;
+     }
+-    cfg["config"] = config;
++    cfg["config"] = sdbus::Variant(config);
+ 
+     if (!releasever.get_value().empty()) {
+-        cfg["releasever"] = releasever.get_value();
++        cfg["releasever"] = sdbus::Variant(releasever.get_value());
+     }
+-    cfg["locale"] = setlocale(LC_MESSAGES, nullptr);
++    cfg["locale"] = sdbus::Variant(setlocale(LC_MESSAGES, nullptr));
+ 
+     session_manager_proxy->callMethod("open_session")
+         .onInterface(dnfdaemon::INTERFACE_SESSION_MANAGER)
+diff --git a/dnf5daemon-server/advisory.cpp b/dnf5daemon-server/advisory.cpp
+index 7bab9961..f6a6c9bf 100644
+--- a/dnf5daemon-server/advisory.cpp
++++ b/dnf5daemon-server/advisory.cpp
+@@ -71,12 +71,12 @@ KeyValueMapList collections_to_list(
+             auto name = pkg.get_name();
+             auto arch = pkg.get_arch();
+ 
+-            package["n"] = name;
+-            package["e"] = pkg.get_epoch();
+-            package["v"] = pkg.get_version();
+-            package["r"] = pkg.get_release();
+-            package["a"] = arch;
+-            package["nevra"] = pkg.get_nevra();
++            package["n"] = sdbus::Variant(name);
++            package["e"] = sdbus::Variant(pkg.get_epoch());
++            package["v"] = sdbus::Variant(pkg.get_version());
++            package["r"] = sdbus::Variant(pkg.get_release());
++            package["a"] = sdbus::Variant(arch);
++            package["nevra"] = sdbus::Variant(pkg.get_nevra());
+ 
+             std::string na{std::move(name)};
+             na.append(".");
+@@ -84,12 +84,12 @@ KeyValueMapList collections_to_list(
+             auto it = installed_versions.find(na);
+             if (it == installed_versions.end()) {
+                 // advisory package is not installed => not related to system
+-                package["applicability"] = "unrelated";
++                package["applicability"] = sdbus::Variant("unrelated");
+             } else if (libdnf5::rpm::evrcmp(it->second, pkg) < 0) {
+                 // installed version is lower than one in advisory
+-                package["applicability"] = "available";
++                package["applicability"] = sdbus::Variant("available");
+             } else {
+-                package["applicability"] = "installed";
++                package["applicability"] = sdbus::Variant("installed");
+             }
+ 
+             packages.emplace_back(std::move(package));
+@@ -99,18 +99,18 @@ KeyValueMapList collections_to_list(
+         auto libdnf_modules = col.get_modules();
+         for (const auto & mdl : libdnf_modules) {
+             KeyValueMap col_module;
+-            col_module["n"] = mdl.get_name();
+-            col_module["s"] = mdl.get_stream();
+-            col_module["v"] = mdl.get_version();
+-            col_module["c"] = mdl.get_context();
+-            col_module["a"] = mdl.get_arch();
+-            col_module["nsvca"] = mdl.get_nsvca();
++            col_module["n"] = sdbus::Variant(mdl.get_name());
++            col_module["s"] = sdbus::Variant(mdl.get_stream());
++            col_module["v"] = sdbus::Variant(mdl.get_version());
++            col_module["c"] = sdbus::Variant(mdl.get_context());
++            col_module["a"] = sdbus::Variant(mdl.get_arch());
++            col_module["nsvca"] = sdbus::Variant(mdl.get_nsvca());
+             modules.emplace_back(std::move(col_module));
+         }
+ 
+         KeyValueMap collection;
+-        collection["packages"] = std::move(packages);
+-        collection["modules"] = std::move(modules);
++        collection["packages"] = sdbus::Variant(std::move(packages));
++        collection["modules"] = sdbus::Variant(std::move(modules));
+         collections.emplace_back(std::move(collection));
+     }
+     return collections;
+diff --git a/dnf5daemon-server/services/goal/goal.cpp b/dnf5daemon-server/services/goal/goal.cpp
+index 1803ea5e..27cc93db 100644
+--- a/dnf5daemon-server/services/goal/goal.cpp
++++ b/dnf5daemon-server/services/goal/goal.cpp
+@@ -249,20 +249,20 @@ sdbus::MethodReply Goal::get_transaction_problems(sdbus::MethodCall & call) {
+     goal_resolve_log_list.reserve(resolve_logs.size());
+     for (const auto & log : resolve_logs) {
+         dnfdaemon::KeyValueMap goal_resolve_log_item;
+-        goal_resolve_log_item["action"] = static_cast<uint32_t>(log.get_action());
+-        goal_resolve_log_item["problem"] = static_cast<uint32_t>(log.get_problem());
++        goal_resolve_log_item["action"] = sdbus::Variant(static_cast<uint32_t>(log.get_action()));
++        goal_resolve_log_item["problem"] = sdbus::Variant(static_cast<uint32_t>(log.get_problem()));
+         if (log.get_job_settings()) {
+             dnfdaemon::KeyValueMap goal_job_settings;
+-            goal_job_settings["to_repo_ids"] = log.get_job_settings()->get_to_repo_ids();
+-            goal_resolve_log_item["goal_job_settings"] = goal_job_settings;
++            goal_job_settings["to_repo_ids"] = sdbus::Variant(log.get_job_settings()->get_to_repo_ids());
++            goal_resolve_log_item["goal_job_settings"] = sdbus::Variant(goal_job_settings);
+         }
+         if (log.get_spec()) {
+-            goal_resolve_log_item["spec"] = *log.get_spec();
++            goal_resolve_log_item["spec"] = sdbus::Variant(*log.get_spec());
+         }
+         if (log.get_additional_data().size() > 0) {
+             // convert std::set<std::string> to std::vector<std::string>
+-            goal_resolve_log_item["additional_data"] =
+-                std::vector<std::string>{log.get_additional_data().begin(), log.get_additional_data().end()};
++            goal_resolve_log_item["additional_data"] = sdbus::Variant(
++                std::vector<std::string>{log.get_additional_data().begin(), log.get_additional_data().end()});
+         }
+         if (log.get_solver_problems()) {
+             using DbusRule = sdbus::Struct<uint32_t, std::vector<std::string>>;
+@@ -274,7 +274,7 @@ sdbus::MethodReply Goal::get_transaction_problems(sdbus::MethodCall & call) {
+                 }
+                 dbus_problems.push_back(std::move(dbus_problem));
+             }
+-            goal_resolve_log_item["solver_problems"] = std::move(dbus_problems);
++            goal_resolve_log_item["solver_problems"] = sdbus::Variant(std::move(dbus_problems));
+         }
+         goal_resolve_log_list.push_back(std::move(goal_resolve_log_item));
+     }
+diff --git a/dnf5daemon-server/services/offline/offline.cpp b/dnf5daemon-server/services/offline/offline.cpp
+index 27e6d793..c9ff03fc 100644
+--- a/dnf5daemon-server/services/offline/offline.cpp
++++ b/dnf5daemon-server/services/offline/offline.cpp
+@@ -103,14 +103,14 @@ sdbus::MethodReply Offline::get_status(sdbus::MethodCall & call) {
+     libdnf5::offline::OfflineTransactionState state{state_path};
+     if (!state.get_read_exception()) {
+         const auto & state_data = state.get_data();
+-        transaction_state["status"] = state_data.get_status();
+-        transaction_state["cachedir"] = state_data.get_cachedir();
+-        transaction_state["target_releasever"] = state_data.get_target_releasever();
+-        transaction_state["system_releasever"] = state_data.get_system_releasever();
+-        transaction_state["verb"] = state_data.get_verb();
+-        transaction_state["cmd_line"] = state_data.get_cmd_line();
+-        transaction_state["poweroff_after"] = state_data.get_poweroff_after();
+-        transaction_state["module_platform_id"] = state_data.get_module_platform_id();
++        transaction_state["status"] = sdbus::Variant(state_data.get_status());
++        transaction_state["cachedir"] = sdbus::Variant(state_data.get_cachedir());
++        transaction_state["target_releasever"] = sdbus::Variant(state_data.get_target_releasever());
++        transaction_state["system_releasever"] = sdbus::Variant(state_data.get_system_releasever());
++        transaction_state["verb"] = sdbus::Variant(state_data.get_verb());
++        transaction_state["cmd_line"] = sdbus::Variant(state_data.get_cmd_line());
++        transaction_state["poweroff_after"] = sdbus::Variant(state_data.get_poweroff_after());
++        transaction_state["module_platform_id"] = sdbus::Variant(state_data.get_module_platform_id());
+     }
+ 
+     auto reply = call.createReply();
+diff --git a/dnf5daemon-server/session.cpp b/dnf5daemon-server/session.cpp
+index e5363521..2ff8ffea 100644
+--- a/dnf5daemon-server/session.cpp
++++ b/dnf5daemon-server/session.cpp
+@@ -272,7 +272,7 @@ bool Session::check_authorization(
+ 
+     // call CheckAuthorization method
+     sdbus::Struct<bool, bool, std::map<std::string, std::string>> auth_result;
+-    sdbus::Struct<std::string, dnfdaemon::KeyValueMap> subject{"system-bus-name", {{"name", sender}}};
++    sdbus::Struct<std::string, dnfdaemon::KeyValueMap> subject{"system-bus-name", {{"name", sdbus::Variant(sender)}}};
+     std::map<std::string, std::string> details{};
+     // allow polkit to ask user to enter root password
+     uint flags = allow_user_interaction ? 1 : 0;
+-- 
+2.48.1
+
diff --git a/0004-dnfdaemon-Explicit-sdbus-Variant-conversion.patch b/0004-dnfdaemon-Explicit-sdbus-Variant-conversion.patch
new file mode 100644
index 0000000..aa3c516
--- /dev/null
+++ b/0004-dnfdaemon-Explicit-sdbus-Variant-conversion.patch
@@ -0,0 +1,374 @@
+From 4714a43af45942a033caff85b8b1d5d9983c7035 Mon Sep 17 00:00:00 2001
+From: Marek Blaha <mblaha at redhat.com>
+Date: Fri, 17 May 2024 13:03:42 +0200
+Subject: [PATCH 04/24] dnfdaemon: Explicit sdbus::Variant conversion
+
+In version 2, conversion of sdbus::Variant to the underlying type is
+explicit.
+---
+ .../needs_restarting.cpp                      |  6 +--
+ dnf5/commands/offline/offline.cpp             |  3 +-
+ .../wrappers/dbus_advisory_wrapper.hpp        | 44 ++++++++--------
+ .../wrappers/dbus_environment_wrapper.cpp     |  2 +-
+ .../wrappers/dbus_environment_wrapper.hpp     |  9 ++--
+ .../wrappers/dbus_goal_wrapper.cpp            |  2 +-
+ .../wrappers/dbus_group_wrapper.cpp           |  4 +-
+ .../wrappers/dbus_group_wrapper.hpp           | 16 +++---
+ .../wrappers/dbus_package_wrapper.hpp         | 42 +++++++--------
+ .../wrappers/dbus_repo_wrapper.cpp            |  2 +-
+ .../wrappers/dbus_repo_wrapper.hpp            | 52 +++++++++----------
+ 11 files changed, 92 insertions(+), 90 deletions(-)
+
+diff --git a/dnf5-plugins/needs_restarting_plugin/needs_restarting.cpp b/dnf5-plugins/needs_restarting_plugin/needs_restarting.cpp
+index 6d9de330..846a95f5 100644
+--- a/dnf5-plugins/needs_restarting_plugin/needs_restarting.cpp
++++ b/dnf5-plugins/needs_restarting_plugin/needs_restarting.cpp
+@@ -119,8 +119,8 @@ time_t NeedsRestartingCommand::get_boot_time(Context & ctx) {
+         connection = sdbus::createSystemBusConnection();
+         auto proxy = sdbus::createProxy(SYSTEMD_DESTINATION_NAME, SYSTEMD_OBJECT_PATH);
+ 
+-        const uint64_t systemd_boot_time_us =
+-            proxy->getProperty("UnitsLoadStartTimestamp").onInterface(SYSTEMD_MANAGER_INTERFACE);
++        const auto systemd_boot_time_us =
++            uint64_t{proxy->getProperty("UnitsLoadStartTimestamp").onInterface(SYSTEMD_MANAGER_INTERFACE)};
+ 
+         const time_t systemd_boot_time = static_cast<long>(systemd_boot_time_us) / (1000L * 1000L);
+ 
+@@ -275,7 +275,7 @@ void NeedsRestartingCommand::services_need_restarting(Context & ctx) {
+         // FragmentPath is the path to the unit file that defines the service
+         const auto fragment_path = unit_proxy->getProperty("FragmentPath").onInterface(SYSTEMD_UNIT_INTERFACE);
+         const auto start_timestamp_us =
+-            unit_proxy->getProperty("ActiveEnterTimestamp").onInterface(SYSTEMD_UNIT_INTERFACE);
++            uint64_t{unit_proxy->getProperty("ActiveEnterTimestamp").onInterface(SYSTEMD_UNIT_INTERFACE)};
+ 
+         unit_file_to_service.insert(std::make_pair(fragment_path, Service{unit_name, start_timestamp_us}));
+     }
+diff --git a/dnf5/commands/offline/offline.cpp b/dnf5/commands/offline/offline.cpp
+index fa1240e2..eb937c0f 100644
+--- a/dnf5/commands/offline/offline.cpp
++++ b/dnf5/commands/offline/offline.cpp
+@@ -322,7 +322,8 @@ void OfflineRebootCommand::run() {
+             .storeResultsTo(unit_object_path);
+ 
+         auto unit_proxy = sdbus::createProxy(SYSTEMD_DESTINATION_NAME, unit_object_path);
+-        const std::vector<std::string> & wants = unit_proxy->getProperty("Wants").onInterface(SYSTEMD_UNIT_INTERFACE);
++        const auto & wants =
++            std::vector<std::string>{unit_proxy->getProperty("Wants").onInterface(SYSTEMD_UNIT_INTERFACE)};
+         if (std::find(wants.begin(), wants.end(), SYSTEMD_SERVICE_NAME) == wants.end()) {
+             throw libdnf5::cli::CommandExitError(
+                 1, M_("{} is not wanted by system-update.target."), SYSTEMD_SERVICE_NAME);
+diff --git a/dnf5daemon-client/wrappers/dbus_advisory_wrapper.hpp b/dnf5daemon-client/wrappers/dbus_advisory_wrapper.hpp
+index 150d6cc9..d8a62fc6 100644
+--- a/dnf5daemon-client/wrappers/dbus_advisory_wrapper.hpp
++++ b/dnf5daemon-client/wrappers/dbus_advisory_wrapper.hpp
+@@ -55,13 +55,13 @@ private:
+ class DbusAdvisoryPackageWrapper {
+ public:
+     DbusAdvisoryPackageWrapper(const dnfdaemon::KeyValueMap & rawdata, DbusAdvisoryWrapper * advisory);
+-    std::string get_name() const { return rawdata.at("n"); }
+-    std::string get_epoch() const { return rawdata.at("e"); }
+-    std::string get_version() const { return rawdata.at("v"); }
+-    std::string get_release() const { return rawdata.at("r"); }
+-    std::string get_arch() const { return rawdata.at("a"); }
++    std::string get_name() const { return std::string{rawdata.at("n")}; }
++    std::string get_epoch() const { return std::string{rawdata.at("e")}; }
++    std::string get_version() const { return std::string{rawdata.at("v")}; }
++    std::string get_release() const { return std::string{rawdata.at("r")}; }
++    std::string get_arch() const { return std::string{rawdata.at("a")}; }
+     std::string get_nevra() const { return libdnf5::rpm::to_nevra_string(*this); }
+-    std::string get_applicability() const { return rawdata.at("applicability"); }
++    std::string get_applicability() const { return std::string{rawdata.at("applicability")}; }
+ 
+     DbusAdvisoryWrapper get_advisory() const;
+ 
+@@ -74,11 +74,11 @@ private:
+ class DbusAdvisoryModuleWrapper {
+ public:
+     DbusAdvisoryModuleWrapper(const dnfdaemon::KeyValueMap & rawdata, DbusAdvisoryWrapper * advisory);
+-    std::string get_name() const { return rawdata.at("n"); }
+-    std::string get_stream() const { return rawdata.at("s"); }
+-    std::string get_version() const { return rawdata.at("v"); }
+-    std::string get_context() const { return rawdata.at("c"); }
+-    std::string get_arch() const { return rawdata.at("a"); }
++    std::string get_name() const { return std::string{rawdata.at("n")}; }
++    std::string get_stream() const { return std::string{rawdata.at("s")}; }
++    std::string get_version() const { return std::string{rawdata.at("v")}; }
++    std::string get_context() const { return std::string{rawdata.at("c")}; }
++    std::string get_arch() const { return std::string{rawdata.at("a")}; }
+     std::string get_nsvca() const {
+         return get_name() + ":" + get_stream() + ":" + get_version() + ":" + get_context() + ":" + get_arch();
+     }
+@@ -107,17 +107,17 @@ class DbusAdvisoryWrapper {
+ public:
+     explicit DbusAdvisoryWrapper(const dnfdaemon::KeyValueMap & rawdata);
+ 
+-    std::string get_advisoryid() const { return rawdata.at("advisoryid"); }
+-    std::string get_name() const { return rawdata.at("name"); }
+-    std::string get_severity() const { return rawdata.at("severity"); }
+-    std::string get_type() const { return rawdata.at("type"); }
+-    uint64_t get_buildtime() const { return rawdata.at("buildtime"); }
+-    std::string get_vendor() const { return rawdata.at("vendor"); }
+-    std::string get_description() const { return rawdata.at("description"); }
+-    std::string get_title() const { return rawdata.at("title"); }
+-    std::string get_status() const { return rawdata.at("status"); }
+-    std::string get_rights() const { return rawdata.at("rights"); }
+-    std::string get_message() const { return rawdata.at("message"); }
++    std::string get_advisoryid() const { return std::string{rawdata.at("advisoryid")}; }
++    std::string get_name() const { return std::string{rawdata.at("name")}; }
++    std::string get_severity() const { return std::string{rawdata.at("severity")}; }
++    std::string get_type() const { return std::string{rawdata.at("type")}; }
++    uint64_t get_buildtime() const { return uint64_t{rawdata.at("buildtime")}; }
++    std::string get_vendor() const { return std::string{rawdata.at("vendor")}; }
++    std::string get_description() const { return std::string{rawdata.at("description")}; }
++    std::string get_title() const { return std::string{rawdata.at("title")}; }
++    std::string get_status() const { return std::string{rawdata.at("status")}; }
++    std::string get_rights() const { return std::string{rawdata.at("rights")}; }
++    std::string get_message() const { return std::string{rawdata.at("message")}; }
+     std::vector<DbusAdvisoryReferenceWrapper> get_references() const { return references; }
+     std::vector<DbusAdvisoryCollectionWrapper> get_collections() const { return collections; }
+ 
+diff --git a/dnf5daemon-client/wrappers/dbus_environment_wrapper.cpp b/dnf5daemon-client/wrappers/dbus_environment_wrapper.cpp
+index e46935af..d885b064 100644
+--- a/dnf5daemon-client/wrappers/dbus_environment_wrapper.cpp
++++ b/dnf5daemon-client/wrappers/dbus_environment_wrapper.cpp
+@@ -24,7 +24,7 @@ namespace dnfdaemon::client {
+ DbusEnvironmentWrapper::DbusEnvironmentWrapper(const dnfdaemon::KeyValueMap & rawdata) : rawdata(rawdata) {};
+ 
+ std::set<std::string> DbusEnvironmentWrapper::get_repos() const {
+-    std::vector<std::string> repos_vector = rawdata.at("repos");
++    auto repos_vector = std::vector<std::string>(rawdata.at("repos"));
+     std::set<std::string> repos_set(repos_vector.begin(), repos_vector.end());
+     return repos_set;
+ };
+diff --git a/dnf5daemon-client/wrappers/dbus_environment_wrapper.hpp b/dnf5daemon-client/wrappers/dbus_environment_wrapper.hpp
+index 16e4a52d..aa8d9e17 100644
+--- a/dnf5daemon-client/wrappers/dbus_environment_wrapper.hpp
++++ b/dnf5daemon-client/wrappers/dbus_environment_wrapper.hpp
+@@ -24,6 +24,7 @@ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ #include <dnf5daemon-server/utils.hpp>
+ 
+ #include <set>
++#include <string>
+ #include <vector>
+ 
+ namespace dnfdaemon::client {
+@@ -32,10 +33,10 @@ class DbusEnvironmentWrapper {
+ public:
+     explicit DbusEnvironmentWrapper(const dnfdaemon::KeyValueMap & rawdata);
+ 
+-    std::string get_environmentid() const { return rawdata.at("environmentid"); }
+-    std::string get_name() const { return rawdata.at("name"); }
+-    std::string get_description() const { return rawdata.at("description"); }
+-    std::string get_order() const { return rawdata.at("order"); }
++    std::string get_environmentid() const { return std::string{rawdata.at("environmentid")}; }
++    std::string get_name() const { return std::string{rawdata.at("name")}; }
++    std::string get_description() const { return std::string{rawdata.at("description")}; }
++    std::string get_order() const { return std::string{rawdata.at("order")}; }
+     // TODO(mblaha) proper installed value
+     bool get_installed() const { return false; }
+     std::set<std::string> get_repos() const;
+diff --git a/dnf5daemon-client/wrappers/dbus_goal_wrapper.cpp b/dnf5daemon-client/wrappers/dbus_goal_wrapper.cpp
+index 044c13ac..f50bd652 100644
+--- a/dnf5daemon-client/wrappers/dbus_goal_wrapper.cpp
++++ b/dnf5daemon-client/wrappers/dbus_goal_wrapper.cpp
+@@ -59,7 +59,7 @@ DbusGoalWrapper::DbusGoalWrapper(std::vector<dnfdaemon::DbusTransactionItem> tra
+         auto ti_replaces = ti_attrs.find("replaces");
+         if (ti_replaces != ti_attrs.end()) {
+             std::vector<DbusPackageWrapper> replaces;
+-            std::vector<int> replaces_id = ti_replaces->second;
++            std::vector<int> replaces_id = std::vector<int>(ti_replaces->second);
+             for (const auto & pkg_id : replaces_id) {
+                 auto replaced_pkg_idx = transaction_packages_by_id.find(pkg_id);
+                 if (replaced_pkg_idx != transaction_packages_by_id.end()) {
+diff --git a/dnf5daemon-client/wrappers/dbus_group_wrapper.cpp b/dnf5daemon-client/wrappers/dbus_group_wrapper.cpp
+index 13faed85..2a0898b2 100644
+--- a/dnf5daemon-client/wrappers/dbus_group_wrapper.cpp
++++ b/dnf5daemon-client/wrappers/dbus_group_wrapper.cpp
+@@ -24,7 +24,7 @@ namespace dnfdaemon::client {
+ DbusGroupWrapper::DbusGroupWrapper(const dnfdaemon::KeyValueMap & rawdata) : rawdata(rawdata) {
+     auto packages_iter = rawdata.find("packages");
+     if (packages_iter != rawdata.end()) {
+-        dnfdaemon::KeyValueMapList raw_packages = packages_iter->second;
++        auto raw_packages = dnfdaemon::KeyValueMapList(packages_iter->second);
+         for (auto & raw_package : raw_packages) {
+             packages.push_back(DbusGroupPackageWrapper(raw_package));
+         }
+@@ -32,7 +32,7 @@ DbusGroupWrapper::DbusGroupWrapper(const dnfdaemon::KeyValueMap & rawdata) : raw
+ };
+ 
+ std::set<std::string> DbusGroupWrapper::get_repos() const {
+-    std::vector<std::string> repos_vector = rawdata.at("repos");
++    std::vector<std::string> repos_vector = std::vector<std::string>(rawdata.at("repos"));
+     std::set<std::string> repos_set(repos_vector.begin(), repos_vector.end());
+     return repos_set;
+ };
+diff --git a/dnf5daemon-client/wrappers/dbus_group_wrapper.hpp b/dnf5daemon-client/wrappers/dbus_group_wrapper.hpp
+index 87bdda6f..c6245fdd 100644
+--- a/dnf5daemon-client/wrappers/dbus_group_wrapper.hpp
++++ b/dnf5daemon-client/wrappers/dbus_group_wrapper.hpp
+@@ -34,7 +34,7 @@ public:
+     class DbusGroupPackageWrapper {
+     public:
+         explicit DbusGroupPackageWrapper(dnfdaemon::KeyValueMap & rawdata) : rawdata(rawdata) {}
+-        std::string get_name() const { return rawdata.at("name"); }
++        std::string get_name() const { return std::string{rawdata.at("name")}; }
+         libdnf5::comps::PackageType get_type() const {
+             return static_cast<libdnf5::comps::PackageType>(key_value_map_get<int>(rawdata, "type"));
+         }
+@@ -45,13 +45,13 @@ public:
+ 
+     explicit DbusGroupWrapper(const dnfdaemon::KeyValueMap & rawdata);
+ 
+-    std::string get_groupid() const { return rawdata.at("groupid"); }
+-    std::string get_name() const { return rawdata.at("name"); }
+-    std::string get_description() const { return rawdata.at("description"); }
+-    std::string get_order() const { return rawdata.at("order"); }
+-    std::string get_langonly() const { return rawdata.at("langonly"); }
+-    bool get_installed() const { return rawdata.at("installed"); }
+-    bool get_uservisible() const { return rawdata.at("uservisible"); }
++    std::string get_groupid() const { return std::string{rawdata.at("groupid")}; }
++    std::string get_name() const { return std::string{rawdata.at("name")}; }
++    std::string get_description() const { return std::string{rawdata.at("description")}; }
++    std::string get_order() const { return std::string{rawdata.at("order")}; }
++    std::string get_langonly() const { return std::string{rawdata.at("langonly")}; }
++    bool get_installed() const { return bool{rawdata.at("installed")}; }
++    bool get_uservisible() const { return bool{rawdata.at("uservisible")}; }
+     std::set<std::string> get_repos() const;
+     std::vector<DbusGroupPackageWrapper> get_packages() const { return packages; }
+ 
+diff --git a/dnf5daemon-client/wrappers/dbus_package_wrapper.hpp b/dnf5daemon-client/wrappers/dbus_package_wrapper.hpp
+index a59d3836..398fd8de 100644
+--- a/dnf5daemon-client/wrappers/dbus_package_wrapper.hpp
++++ b/dnf5daemon-client/wrappers/dbus_package_wrapper.hpp
+@@ -32,30 +32,30 @@ class DbusPackageWrapper {
+ public:
+     explicit DbusPackageWrapper(const dnfdaemon::KeyValueMap & rawdata) : rawdata(rawdata) {};
+ 
+-    int get_id() { return rawdata.at("id"); }
+-    std::string get_name() const { return rawdata.at("name"); }
++    int get_id() { return int{rawdata.at("id")}; }
++    std::string get_name() const { return std::string{rawdata.at("name")}; }
+     std::string get_na() const { return get_name() + "." + get_arch(); }
+-    std::string get_epoch() const { return rawdata.at("epoch"); }
+-    std::string get_version() const { return rawdata.at("version"); }
+-    std::string get_release() const { return rawdata.at("release"); }
+-    std::string get_arch() const { return rawdata.at("arch"); }
+-    std::string get_repo_id() const { return rawdata.at("repo_id"); }
+-    std::string get_from_repo_id() const { return rawdata.at("from_repo_id"); }
+-    std::string get_nevra() const { return rawdata.at("nevra"); }
+-    std::string get_full_nevra() const { return rawdata.at("full_nevra"); }
+-    std::string get_evr() const { return rawdata.at("evr"); }
+-    bool is_installed() const { return rawdata.at("is_installed"); }
+-    uint64_t get_install_size() const { return rawdata.at("install_size"); }
+-    uint64_t get_download_size() const { return rawdata.at("download_size"); }
+-    std::string get_sourcerpm() const { return rawdata.at("sourcerpm"); }
+-    std::string get_summary() const { return rawdata.at("summary"); }
+-    std::string get_url() const { return rawdata.at("url"); }
+-    std::string get_license() const { return rawdata.at("license"); }
+-    std::string get_description() const { return rawdata.at("description"); }
++    std::string get_epoch() const { return std::string{rawdata.at("epoch")}; }
++    std::string get_version() const { return std::string{rawdata.at("version")}; }
++    std::string get_release() const { return std::string{rawdata.at("release")}; }
++    std::string get_arch() const { return std::string{rawdata.at("arch")}; }
++    std::string get_repo_id() const { return std::string{rawdata.at("repo_id")}; }
++    std::string get_from_repo_id() const { return std::string{rawdata.at("from_repo_id")}; }
++    std::string get_nevra() const { return std::string{rawdata.at("nevra")}; }
++    std::string get_full_nevra() const { return std::string{rawdata.at("full_nevra")}; }
++    std::string get_evr() const { return std::string{rawdata.at("evr")}; }
++    bool is_installed() const { return bool{rawdata.at("is_installed")}; }
++    uint64_t get_install_size() const { return uint64_t{rawdata.at("install_size")}; }
++    uint64_t get_download_size() const { return uint64_t{rawdata.at("download_size")}; }
++    std::string get_sourcerpm() const { return std::string{rawdata.at("sourcerpm")}; }
++    std::string get_summary() const { return std::string{rawdata.at("summary")}; }
++    std::string get_url() const { return std::string{rawdata.at("url")}; }
++    std::string get_license() const { return std::string{rawdata.at("license")}; }
++    std::string get_description() const { return std::string{rawdata.at("description")}; }
+     libdnf5::transaction::TransactionItemReason get_reason() const {
+-        return libdnf5::transaction::transaction_item_reason_from_string(rawdata.at("reason"));
++        return libdnf5::transaction::transaction_item_reason_from_string(std::string{rawdata.at("reason")});
+     }
+-    std::string get_vendor() const { return rawdata.at("vendor"); }
++    std::string get_vendor() const { return std::string{rawdata.at("vendor")}; }
+ 
+ private:
+     dnfdaemon::KeyValueMap rawdata;
+diff --git a/dnf5daemon-client/wrappers/dbus_repo_wrapper.cpp b/dnf5daemon-client/wrappers/dbus_repo_wrapper.cpp
+index a5c5dd19..00530340 100644
+--- a/dnf5daemon-client/wrappers/dbus_repo_wrapper.cpp
++++ b/dnf5daemon-client/wrappers/dbus_repo_wrapper.cpp
+@@ -26,7 +26,7 @@ std::vector<std::pair<std::string, std::string>> DbusRepoWrapper::get_distro_tag
+     // serialized to vector<string>.
+     // convert [tag1, val1, tag2, val2,...] back to [(tag1, val1), (tag2, val2),...]
+     std::vector<std::pair<std::string, std::string>> dt{};
+-    std::vector<std::string> tags_raw = rawdata.at("distro_tags");
++    auto tags_raw = std::vector<std::string>(rawdata.at("distro_tags"));
+     if (!tags_raw.empty()) {
+         for (size_t i = 0; i < (tags_raw.size() - 1); i += 2) {
+             dt.emplace_back(tags_raw[i], tags_raw[i + 1]);
+diff --git a/dnf5daemon-client/wrappers/dbus_repo_wrapper.hpp b/dnf5daemon-client/wrappers/dbus_repo_wrapper.hpp
+index 254928ad..a4788ac8 100644
+--- a/dnf5daemon-client/wrappers/dbus_repo_wrapper.hpp
++++ b/dnf5daemon-client/wrappers/dbus_repo_wrapper.hpp
+@@ -31,33 +31,33 @@ class DbusRepoWrapper : public libdnf5::cli::output::IRepoInfo {
+ public:
+     explicit DbusRepoWrapper(dnfdaemon::KeyValueMap & rawdata) : rawdata(rawdata) {};
+ 
+-    std::string get_id() const { return rawdata.at("id"); }
+-    std::string get_name() const { return rawdata.at("name"); }
+-    std::string get_type() const { return rawdata.at("type"); }
+-    bool is_enabled() const { return rawdata.at("enabled"); }
+-    int get_priority() const { return rawdata.at("priority"); }
+-    int get_cost() const { return rawdata.at("cost"); }
+-    std::vector<std::string> get_baseurl() const { return rawdata.at("baseurl"); }
+-    std::string get_metalink() const { return rawdata.at("metalink"); }
+-    std::string get_mirrorlist() const { return rawdata.at("mirrorlist"); }
+-    int get_metadata_expire() const { return rawdata.at("metadata_expire"); }
+-    std::vector<std::string> get_excludepkgs() const { return rawdata.at("excludepkgs"); }
+-    std::vector<std::string> get_includepkgs() const { return rawdata.at("includepkgs"); }
+-    bool get_skip_if_unavailable() const { return rawdata.at("skip_if_unavailable"); }
+-    std::vector<std::string> get_gpgkey() const { return rawdata.at("gpgkey"); }
+-    bool get_gpgcheck() const { return rawdata.at("pkg_gpgcheck"); }
+-    bool get_pkg_gpgcheck() const { return rawdata.at("pkg_gpgcheck"); }
+-    bool get_repo_gpgcheck() const { return rawdata.at("repo_gpgcheck"); }
+-    std::string get_repo_file_path() const { return rawdata.at("repofile"); }
+-    std::string get_revision() const { return rawdata.at("revision"); }
+-    std::vector<std::string> get_content_tags() const { return rawdata.at("content_tags"); }
++    std::string get_id() const { return std::string{rawdata.at("id")}; }
++    std::string get_name() const { return std::string{rawdata.at("name")}; }
++    std::string get_type() const { return std::string{rawdata.at("type")}; }
++    bool is_enabled() const { return bool{rawdata.at("enabled")}; }
++    int get_priority() const { return int{rawdata.at("priority")}; }
++    int get_cost() const { return int{rawdata.at("cost")}; }
++    std::vector<std::string> get_baseurl() const { return std::vector<std::string>(rawdata.at("baseurl")); }
++    std::string get_metalink() const { return std::string{rawdata.at("metalink")}; }
++    std::string get_mirrorlist() const { return std::string{rawdata.at("mirrorlist")}; }
++    int get_metadata_expire() const { return int{rawdata.at("metadata_expire")}; }
++    std::vector<std::string> get_excludepkgs() const { return std::vector<std::string>(rawdata.at("excludepkgs")); }
++    std::vector<std::string> get_includepkgs() const { return std::vector<std::string>(rawdata.at("includepkgs")); }
++    bool get_skip_if_unavailable() const { return bool{rawdata.at("skip_if_unavailable")}; }
++    std::vector<std::string> get_gpgkey() const { return std::vector<std::string>(rawdata.at("gpgkey")); }
++    bool get_gpgcheck() const { return bool{rawdata.at("gpgcheck")}; }
++    bool get_pkg_gpgcheck() const { return bool{rawdata.at("pkg_gpgcheck")}; }
++    bool get_repo_gpgcheck() const { return bool{rawdata.at("repo_gpgcheck")}; }
++    std::string get_repo_file_path() const { return std::string{rawdata.at("repofile")}; }
++    std::string get_revision() const { return std::string{rawdata.at("revision")}; }
++    std::vector<std::string> get_content_tags() const { return std::vector<std::string>(rawdata.at("content_tags")); }
+     std::vector<std::pair<std::string, std::string>> get_distro_tags() const;
+-    int64_t get_timestamp() const { return rawdata.at("cache_updated"); }
+-    int get_max_timestamp() const { return rawdata.at("updated"); }
+-    uint64_t get_size() const { return rawdata.at("size"); }
+-    uint64_t get_pkgs() const { return rawdata.at("pkgs"); }
+-    uint64_t get_available_pkgs() const { return rawdata.at("available_pkgs"); }
+-    std::vector<std::string> get_mirrors() const { return rawdata.at("mirrors"); }
++    int64_t get_timestamp() const { return int64_t{rawdata.at("cache_updated")}; }
++    int get_max_timestamp() const { return int{rawdata.at("updated")}; }
++    uint64_t get_size() const { return uint64_t{rawdata.at("size")}; }
++    uint64_t get_pkgs() const { return uint64_t{rawdata.at("pkgs")}; }
++    uint64_t get_available_pkgs() const { return uint64_t{rawdata.at("available_pkgs")}; }
++    std::vector<std::string> get_mirrors() const { return std::vector<std::string>(rawdata.at("mirrors")); }
+ 
+ private:
+     dnfdaemon::KeyValueMap rawdata;
+-- 
+2.48.1
+
diff --git a/0005-dnfdaemon-Make-signal-handlers-compatible.patch b/0005-dnfdaemon-Make-signal-handlers-compatible.patch
new file mode 100644
index 0000000..da0b6b7
--- /dev/null
+++ b/0005-dnfdaemon-Make-signal-handlers-compatible.patch
@@ -0,0 +1,122 @@
+From 270094934dc6ecfce6136eb24c872757723c42ea Mon Sep 17 00:00:00 2001
+From: Marek Blaha <mblaha at redhat.com>
+Date: Fri, 17 May 2024 13:05:09 +0200
+Subject: [PATCH 05/24] dnfdaemon: Make signal handlers compatible
+
+sdbus-cpp version 2 requires signal handler to have signature
+(sdbus::Signal signal) -> void, which is also acceptable for version 1.
+---
+ dnf5daemon-client/callbacks.cpp | 48 ++++++++++++++++-----------------
+ 1 file changed, 24 insertions(+), 24 deletions(-)
+
+diff --git a/dnf5daemon-client/callbacks.cpp b/dnf5daemon-client/callbacks.cpp
+index c0379d28..98b7d6a8 100644
+--- a/dnf5daemon-client/callbacks.cpp
++++ b/dnf5daemon-client/callbacks.cpp
+@@ -46,23 +46,23 @@ DownloadCB::DownloadCB(Context & context) : DbusCallback(context) {
+     // register signal handlers
+     auto proxy = context.session_proxy.get();
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_ADD_NEW, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_ADD_NEW, [this](sdbus::Signal signal) -> void {
+             this->add_new_download(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_END, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_END, [this](sdbus::Signal signal) -> void {
+             this->end(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_PROGRESS, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_PROGRESS, [this](sdbus::Signal signal) -> void {
+             this->progress(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_MIRROR_FAILURE, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_MIRROR_FAILURE, [this](sdbus::Signal signal) -> void {
+             this->mirror_failure(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_REPO_KEY_IMPORT_REQUEST, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_REPO_KEY_IMPORT_REQUEST, [this](sdbus::Signal signal) -> void {
+             this->key_import(signal);
+         });
+ }
+@@ -242,55 +242,55 @@ TransactionCB::TransactionCB(Context & context) : DbusCallback(context) {
+     // register signal handlers
+     auto proxy = context.session_proxy.get();
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_VERIFY_START, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_VERIFY_START, [this](sdbus::Signal signal) -> void {
+             this->verify_start(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM,
+-        dnfdaemon::SIGNAL_TRANSACTION_VERIFY_PROGRESS,
+-        [this](sdbus::Signal & signal) -> void { this->verify_progress(signal); });
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_VERIFY_PROGRESS, [this](sdbus::Signal signal) -> void {
++            this->verify_progress(signal);
++        });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_VERIFY_STOP, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_VERIFY_STOP, [this](sdbus::Signal signal) -> void {
+             this->verify_end(signal);
+         });
+     proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM,
+         dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_START,
+-        [this](sdbus::Signal & signal) -> void { this->transaction_start(signal); });
++        [this](sdbus::Signal signal) -> void { this->transaction_start(signal); });
+     proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM,
+         dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_PROGRESS,
+-        [this](sdbus::Signal & signal) -> void { this->transaction_progress(signal); });
++        [this](sdbus::Signal signal) -> void { this->transaction_progress(signal); });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM,
+-        dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_STOP,
+-        [this](sdbus::Signal & signal) -> void { this->transaction_end(signal); });
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_STOP, [this](sdbus::Signal signal) -> void {
++            this->transaction_end(signal);
++        });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_ACTION_START, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_ACTION_START, [this](sdbus::Signal signal) -> void {
+             this->action_start(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM,
+-        dnfdaemon::SIGNAL_TRANSACTION_ACTION_PROGRESS,
+-        [this](sdbus::Signal & signal) -> void { this->action_progress(signal); });
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_ACTION_PROGRESS, [this](sdbus::Signal signal) -> void {
++            this->action_progress(signal);
++        });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_ACTION_STOP, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_ACTION_STOP, [this](sdbus::Signal signal) -> void {
+             this->action_end(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_START, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_START, [this](sdbus::Signal signal) -> void {
+             this->script_start(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_STOP, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_STOP, [this](sdbus::Signal signal) -> void {
+             this->script_stop(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_ERROR, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_ERROR, [this](sdbus::Signal signal) -> void {
+             this->script_error(signal);
+         });
+     proxy->registerSignalHandler(
+-        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_FINISHED, [this](sdbus::Signal & signal) -> void {
++        dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_FINISHED, [this](sdbus::Signal signal) -> void {
+             this->finished(signal);
+         });
+ }
+-- 
+2.48.1
+
diff --git a/0006-dnfdaemon-Register-interface-methods-for-sdbus-cpp-2.patch b/0006-dnfdaemon-Register-interface-methods-for-sdbus-cpp-2.patch
new file mode 100644
index 0000000..f057e95
--- /dev/null
+++ b/0006-dnfdaemon-Register-interface-methods-for-sdbus-cpp-2.patch
@@ -0,0 +1,687 @@
+From fb9cea1132b03fc22439d0e3f0d38e5240697ea7 Mon Sep 17 00:00:00 2001
+From: Marek Blaha <mblaha at redhat.com>
+Date: Fri, 7 Jun 2024 14:16:57 +0200
+Subject: [PATCH 06/24] dnfdaemon: Register interface methods for sdbus-cpp-2
+
+sdbus-cpp-2 uses different approach to registering methods and signals
+on the interface.
+---
+ dnf5daemon-client/context.cpp                 |   4 +
+ .../services/advisory/advisory.cpp            |  15 ++
+ dnf5daemon-server/services/base/base.cpp      |  62 ++++++
+ dnf5daemon-server/services/comps/group.cpp    |  23 ++-
+ dnf5daemon-server/services/goal/goal.cpp      |  61 +++++-
+ .../services/offline/offline.cpp              |  48 +++++
+ dnf5daemon-server/services/repo/repo.cpp      |  47 +++++
+ dnf5daemon-server/services/rpm/rpm.cpp        | 178 ++++++++++++++++++
+ dnf5daemon-server/session.cpp                 |   6 +
+ dnf5daemon-server/session_manager.cpp         |  33 +++-
+ 10 files changed, 473 insertions(+), 4 deletions(-)
+
+diff --git a/dnf5daemon-client/context.cpp b/dnf5daemon-client/context.cpp
+index bcfd1bfa..f2bb40ca 100644
+--- a/dnf5daemon-client/context.cpp
++++ b/dnf5daemon-client/context.cpp
+@@ -37,7 +37,9 @@ void Context::init_session(sdbus::IConnection & connection) {
+     // open dnf5daemon-server session
+     auto cfg = static_cast<DaemonCommand *>(get_selected_command())->session_config();
+     auto session_manager_proxy = sdbus::createProxy(connection, dnfdaemon::DBUS_NAME, dnfdaemon::DBUS_OBJECT_PATH);
++#ifndef SDBUS_CPP_VERSION_2
+     session_manager_proxy->finishRegistration();
++#endif
+ 
+     // set up the install root end setopts
+     std::map<std::string, std::string> empty_options{};
+@@ -63,7 +65,9 @@ void Context::init_session(sdbus::IConnection & connection) {
+     // register progress bars callbacks
+     download_cb = std::make_unique<DownloadCB>(*this);
+     transaction_cb = std::make_unique<TransactionCB>(*this);
++#ifndef SDBUS_CPP_VERSION_2
+     session_proxy->finishRegistration();
++#endif
+ }
+ 
+ 
+diff --git a/dnf5daemon-server/services/advisory/advisory.cpp b/dnf5daemon-server/services/advisory/advisory.cpp
+index 65e7e217..45434026 100644
+--- a/dnf5daemon-server/services/advisory/advisory.cpp
++++ b/dnf5daemon-server/services/advisory/advisory.cpp
+@@ -31,6 +31,20 @@ namespace dnfdaemon {
+ 
+ void Advisory::dbus_register() {
+     auto dbus_object = session.get_dbus_object();
++#ifdef SDBUS_CPP_VERSION_2
++    dbus_object
++        ->addVTable(sdbus::MethodVTableItem{
++            sdbus::MethodName{"list"},
++            sdbus::Signature{"a{sv}"},
++            {"options"},
++            sdbus::Signature{"aa{sv}"},
++            {"advisories"},
++            [this](sdbus::MethodCall call) -> void {
++                session.get_threads_manager().handle_method(*this, &Advisory::list, call, session.session_locale);
++            },
++            {}})
++        .forInterface(INTERFACE_ADVISORY);
++#else
+     dbus_object->registerMethod(
+         INTERFACE_ADVISORY,
+         "list",
+@@ -41,6 +55,7 @@ void Advisory::dbus_register() {
+         [this](sdbus::MethodCall call) -> void {
+             session.get_threads_manager().handle_method(*this, &Advisory::list, call, session.session_locale);
+         });
++#endif
+ }
+ 
+ libdnf5::advisory::AdvisoryQuery Advisory::advisory_query_from_options(
+diff --git a/dnf5daemon-server/services/base/base.cpp b/dnf5daemon-server/services/base/base.cpp
+index d1a35650..301c1c41 100644
+--- a/dnf5daemon-server/services/base/base.cpp
++++ b/dnf5daemon-server/services/base/base.cpp
+@@ -45,6 +45,67 @@ static const std::unordered_set<std::string> ALLOWED_CACHE_TYPES = {
+ 
+ void Base::dbus_register() {
+     auto dbus_object = session.get_dbus_object();
++#ifdef SDBUS_CPP_VERSION_2
++    dbus_object
++        ->addVTable(
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"read_all_repos"},
++                sdbus::Signature{""},
++                {},
++                sdbus::Signature{"b"},
++                {"success"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(
++                        *this, &Base::read_all_repos, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"clean"},
++                sdbus::Signature{"s"},
++                {"cache_type"},
++                sdbus::Signature{"bs"},
++                {"success", "error_msg"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Base::clean, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"reset"},
++                sdbus::Signature{""},
++                {},
++                sdbus::Signature{"bs"},
++                {"success", "error_msg"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Base::reset, call, session.session_locale);
++                },
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_DOWNLOAD_ADD_NEW,
++                sdbus::Signature{"ossx"},
++                {"session_object_path", "download_id", "description", "total_to_download"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_DOWNLOAD_PROGRESS,
++                sdbus::Signature{"osxx"},
++                {"session_object_path", "download_id", "total_to_download", "downloaded"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_DOWNLOAD_END,
++                sdbus::Signature{"osus"},
++                {"session_object_path", "download_id", "transfer_status", "message"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_DOWNLOAD_MIRROR_FAILURE,
++                sdbus::Signature{"ossss"},
++                {"session_object_path", "download_id", "message", "url", "metadata"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_REPO_KEY_IMPORT_REQUEST,
++                sdbus::Signature{"osasssx"},
++                {"session_object_path", "key_id", "user_ids", "key_fingerprint", "key_url", "timestamp"},
++                {}})
++        .forInterface(dnfdaemon::INTERFACE_BASE);
++#else
+     dbus_object->registerMethod(
+         dnfdaemon::INTERFACE_BASE, "read_all_repos", "", {}, "b", {"success"}, [this](sdbus::MethodCall call) -> void {
+             session.get_threads_manager().handle_method(*this, &Base::read_all_repos, call, session.session_locale);
+@@ -95,6 +156,7 @@ void Base::dbus_register() {
+         dnfdaemon::SIGNAL_REPO_KEY_IMPORT_REQUEST,
+         "osasssx",
+         {"session_object_path", "key_id", "user_ids", "key_fingerprint", "key_url", "timestamp"});
++#endif
+ }
+ 
+ sdbus::MethodReply Base::read_all_repos(sdbus::MethodCall & call) {
+diff --git a/dnf5daemon-server/services/comps/group.cpp b/dnf5daemon-server/services/comps/group.cpp
+index 178c4406..3164cac5 100644
+--- a/dnf5daemon-server/services/comps/group.cpp
++++ b/dnf5daemon-server/services/comps/group.cpp
+@@ -118,10 +118,31 @@ dnfdaemon::KeyValueMap group_to_map(libdnf5::comps::Group & libdnf_group, const
+ 
+ void Group::dbus_register() {
+     auto dbus_object = session.get_dbus_object();
++#ifdef SDBUS_CPP_VERSION_2
++    dbus_object
++        ->addVTable(sdbus::MethodVTableItem{
++            sdbus::MethodName{"list"},
++            sdbus::Signature{"a{sv}"},
++            {"options"},
++            sdbus::Signature{"aa{sv}"},
++            {"groups"},
++            [this](sdbus::MethodCall call) -> void {
++                session.get_threads_manager().handle_method(*this, &Group::list, call, session.session_locale);
++            },
++            {}})
++        .forInterface(dnfdaemon::INTERFACE_GROUP);
++#else
+     dbus_object->registerMethod(
+-        dnfdaemon::INTERFACE_GROUP, "list", "a{sv}", "aa{sv}", [this](sdbus::MethodCall call) -> void {
++        dnfdaemon::INTERFACE_GROUP,
++        "list",
++        "a{sv}",
++        {"options"},
++        "aa{sv}",
++        {"groups"},
++        [this](sdbus::MethodCall call) -> void {
+             session.get_threads_manager().handle_method(*this, &Group::list, call, session.session_locale);
+         });
++#endif
+ }
+ 
+ sdbus::MethodReply Group::list(sdbus::MethodCall & call) {
+diff --git a/dnf5daemon-server/services/goal/goal.cpp b/dnf5daemon-server/services/goal/goal.cpp
+index 27cc93db..5dce8975 100644
+--- a/dnf5daemon-server/services/goal/goal.cpp
++++ b/dnf5daemon-server/services/goal/goal.cpp
+@@ -60,8 +60,64 @@ static std::string dbus_transaction_item_type_to_string(dnfdaemon::DbusTransacti
+ 
+ void Goal::dbus_register() {
+     auto dbus_object = session.get_dbus_object();
+-    // TODO(mblaha) Adjust resolve method to accommodate also groups, environments,
+-    // and modules as part of the transaction
++#ifdef SDBUS_CPP_VERSION_2
++    dbus_object
++        ->addVTable(
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"resolve"},
++                sdbus::Signature{"a{sv}"},
++                {"options"},
++                sdbus::Signature{"a(sssa{sv}a{sv})u"},
++                {"transaction_items", "result"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Goal::resolve, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"get_transaction_problems_string"},
++                {},
++                {},
++                sdbus::Signature{"as"},
++                {"problems"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(
++                        *this, &Goal::get_transaction_problems_string, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"get_transaction_problems"},
++                {},
++                {},
++                sdbus::Signature{"aa{sv}"},
++                {"problems"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(
++                        *this, &Goal::get_transaction_problems, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"do_transaction"},
++                sdbus::Signature{"a{sv}"},
++                {"options"},
++                {},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(
++                        *this, &Goal::do_transaction, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"cancel"},
++                sdbus::Signature{""},
++                {},
++                sdbus::Signature{"bs"},
++                {"success", "error_msg"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Goal::cancel, call, session.session_locale);
++                },
++                {}})
++        .forInterface(dnfdaemon::INTERFACE_GOAL);
++#else
+     dbus_object->registerMethod(
+         dnfdaemon::INTERFACE_GOAL,
+         "resolve",
+@@ -118,6 +174,7 @@ void Goal::dbus_register() {
+         dnfdaemon::INTERFACE_GOAL, "reset", "", {}, "", {}, [this](sdbus::MethodCall call) -> void {
+             session.get_threads_manager().handle_method(*this, &Goal::reset, call, session.session_locale);
+         });
++#endif
+ }
+ 
+ sdbus::MethodReply Goal::resolve(sdbus::MethodCall & call) {
+diff --git a/dnf5daemon-server/services/offline/offline.cpp b/dnf5daemon-server/services/offline/offline.cpp
+index c9ff03fc..48968f86 100644
+--- a/dnf5daemon-server/services/offline/offline.cpp
++++ b/dnf5daemon-server/services/offline/offline.cpp
+@@ -52,6 +52,53 @@ Offline::Scheduled Offline::offline_transaction_scheduled() {
+ 
+ void Offline::dbus_register() {
+     auto dbus_object = session.get_dbus_object();
++#ifdef SDBUS_CPP_VERSION_2
++    dbus_object
++        ->addVTable(
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"cancel"},
++                {},
++                {},
++                sdbus::Signature{"bs"},
++                {"success", "error_msg"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Offline::cancel, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"get_status"},
++                {},
++                {},
++                sdbus::Signature{"ba{sv}"},
++                {"is_pending", "transaction_status"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(
++                        *this, &Offline::get_status, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"clean"},
++                {},
++                {},
++                sdbus::Signature{"bs"},
++                {"success", "error_msg"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Offline::clean, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"set_finish_action"},
++                sdbus::Signature{"s"},
++                {"action"},
++                sdbus::Signature{"bs"},
++                {"success", "error_msg"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(
++                        *this, &Offline::set_finish_action, call, session.session_locale);
++                },
++                {}})
++        .forInterface(dnfdaemon::INTERFACE_OFFLINE);
++#else
+     dbus_object->registerMethod(
+         dnfdaemon::INTERFACE_OFFLINE,
+         "cancel",
+@@ -93,6 +140,7 @@ void Offline::dbus_register() {
+             session.get_threads_manager().handle_method(
+                 *this, &Offline::set_finish_action, call, session.session_locale);
+         });
++#endif
+ }
+ 
+ sdbus::MethodReply Offline::get_status(sdbus::MethodCall & call) {
+diff --git a/dnf5daemon-server/services/repo/repo.cpp b/dnf5daemon-server/services/repo/repo.cpp
+index 8d082009..e8f2d838 100644
+--- a/dnf5daemon-server/services/repo/repo.cpp
++++ b/dnf5daemon-server/services/repo/repo.cpp
+@@ -262,6 +262,52 @@ bool keyval_repo_compare(const dnfdaemon::KeyValueMap & first, const dnfdaemon::
+ 
+ void Repo::dbus_register() {
+     auto dbus_object = session.get_dbus_object();
++
++#ifdef SDBUS_CPP_VERSION_2
++    dbus_object
++        ->addVTable(
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"list"},
++                sdbus::Signature{"a{sv}"},
++                {"options"},
++                sdbus::Signature{"aa{sv}"},
++                {"repositories"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Repo::list, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"confirm_key"},
++                sdbus::Signature{"sb"},
++                {"key_id", "confirmed"},
++                sdbus::Signature{""},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Repo::confirm_key, call);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"enable"},
++                sdbus::Signature{"as"},
++                {"repo_ids"},
++                sdbus::Signature{""},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Repo::enable, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"disable"},
++                sdbus::Signature{"as"},
++                {"repo_ids"},
++                sdbus::Signature{""},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Repo::disable, call, session.session_locale);
++                },
++                {}})
++        .forInterface(dnfdaemon::INTERFACE_REPO);
++#else
+     dbus_object->registerMethod(
+         dnfdaemon::INTERFACE_REPO,
+         "list",
+@@ -290,6 +336,7 @@ void Repo::dbus_register() {
+         dnfdaemon::INTERFACE_REPO, "disable", "as", {"repo_ids"}, "", {}, [this](sdbus::MethodCall call) -> void {
+             session.get_threads_manager().handle_method(*this, &Repo::disable, call, session.session_locale);
+         });
++#endif
+ }
+ 
+ sdbus::MethodReply Repo::confirm_key(sdbus::MethodCall & call) {
+diff --git a/dnf5daemon-server/services/rpm/rpm.cpp b/dnf5daemon-server/services/rpm/rpm.cpp
+index 83cf253e..aa8f5393 100644
+--- a/dnf5daemon-server/services/rpm/rpm.cpp
++++ b/dnf5daemon-server/services/rpm/rpm.cpp
+@@ -33,6 +33,183 @@ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ 
+ void Rpm::dbus_register() {
+     auto dbus_object = session.get_dbus_object();
++#ifdef SDBUS_CPP_VERSION_2
++    dbus_object
++        ->addVTable(
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"distro_sync"},
++                sdbus::Signature{"asa{sv}"},
++                {"pkg_specs", "options"},
++                {},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Rpm::distro_sync, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"downgrade"},
++                sdbus::Signature{"asa{sv}"},
++                {"pkg_specs", "options"},
++                {},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Rpm::downgrade, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"list"},
++                sdbus::Signature{"a{sv}"},
++                {"options"},
++                sdbus::Signature{"aa{sv}"},
++                {"packages"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Rpm::list, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"list_fd"},
++                sdbus::Signature{"a{sv}h"},
++                {"options", "file_descriptor"},
++                sdbus::Signature{"s"},
++                {"transfer_id"},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method_fd(*this, &Rpm::list_fd, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"install"},
++                sdbus::Signature{"asa{sv}"},
++                {"pkg_specs", "options"},
++                {},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Rpm::install, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"upgrade"},
++                sdbus::Signature{"asa{sv}"},
++                {"pkg_specs", "options"},
++                {},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Rpm::upgrade, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"reinstall"},
++                sdbus::Signature{"asa{sv}"},
++                {"pkg_specs", "options"},
++                {},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Rpm::reinstall, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"remove"},
++                sdbus::Signature{"asa{sv}"},
++                {"pkg_specs", "options"},
++                {},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(*this, &Rpm::remove, call, session.session_locale);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"system_upgrade"},
++                sdbus::Signature{"a{sv}"},
++                {"options"},
++                {},
++                {},
++                [this](sdbus::MethodCall call) -> void {
++                    session.get_threads_manager().handle_method(
++                        *this, &Rpm::system_upgrade, call, session.session_locale);
++                },
++                {}},
++
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_BEFORE_BEGIN,
++                sdbus::Signature{"ot"},
++                {"session_object_path", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_AFTER_COMPLETE,
++                sdbus::Signature{"ob"},
++                {"session_object_path", "success"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_ELEM_PROGRESS,
++                sdbus::Signature{"ostt"},
++                {"session_object_path", "nevra", "processed", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_ACTION_START,
++                sdbus::Signature{"osut"},
++                {"session_object_path", "nevra", "action", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_ACTION_PROGRESS,
++                sdbus::Signature{"ostt"},
++                {"session_object_path", "nevra", "processed", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_ACTION_STOP,
++                sdbus::Signature{"ost"},
++                {"session_object_path", "nevra", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_START,
++                sdbus::Signature{"osu"},
++                {"session_object_path", "nevra", "scriptlet_type"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_STOP,
++                sdbus::Signature{"osut"},
++                {"session_object_path", "nevra", "scriptlet_type", "return_code"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_ERROR,
++                sdbus::Signature{"osut"},
++                {"session_object_path", "nevra", "scriptlet_type", "return_code"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_VERIFY_START,
++                sdbus::Signature{"ot"},
++                {"session_object_path", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_VERIFY_PROGRESS,
++                sdbus::Signature{"ott"},
++                {"session_object_path", "processed", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_VERIFY_STOP,
++                sdbus::Signature{"ot"},
++                {"session_object_path", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_START,
++                sdbus::Signature{"ot"},
++                {"session_object_path", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_PROGRESS,
++                sdbus::Signature{"ott"},
++                {"session_object_path", "processed", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_STOP,
++                sdbus::Signature{"ot"},
++                {"session_object_path", "total"},
++                {}},
++            sdbus::SignalVTableItem{
++                dnfdaemon::SIGNAL_TRANSACTION_UNPACK_ERROR,
++                sdbus::Signature{"os"},
++                {"session_object_path", "nevra"},
++                {}})
++        .forInterface(dnfdaemon::INTERFACE_RPM);
++#else
+     dbus_object->registerMethod(
+         dnfdaemon::INTERFACE_RPM,
+         "distro_sync",
+@@ -192,6 +369,7 @@ void Rpm::dbus_register() {
+         {"session_object_path", "total"});
+     dbus_object->registerSignal(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_UNPACK_ERROR, "os", {"session_object_path", "nevra"});
++#endif
+ }
+ 
+ std::vector<std::string> get_filter_patterns(dnfdaemon::KeyValueMap options, const std::string & option) {
+diff --git a/dnf5daemon-server/session.cpp b/dnf5daemon-server/session.cpp
+index 2ff8ffea..ad677c38 100644
+--- a/dnf5daemon-server/session.cpp
++++ b/dnf5daemon-server/session.cpp
+@@ -159,7 +159,10 @@ Session::Session(
+     for (auto & s : services) {
+         s->dbus_register();
+     }
++
++#ifndef SDBUS_CPP_VERSION_2
+     dbus_object->finishRegistration();
++#endif
+ }
+ 
+ Session::~Session() {
+@@ -268,7 +271,10 @@ bool Session::check_authorization(
+     const sdbus::ObjectPath object_path{"/org/freedesktop/PolicyKit1/Authority"};
+     const SDBUS_INTERFACE_NAME_TYPE interface_name{"org.freedesktop.PolicyKit1.Authority"};
+     auto polkit_proxy = sdbus::createProxy(connection, destination_name, object_path);
++
++#ifndef SDBUS_CPP_VERSION_2
+     polkit_proxy->finishRegistration();
++#endif
+ 
+     // call CheckAuthorization method
+     sdbus::Struct<bool, bool, std::map<std::string, std::string>> auth_result;
+diff --git a/dnf5daemon-server/session_manager.cpp b/dnf5daemon-server/session_manager.cpp
+index 8ea9d2c8..e6494199 100644
+--- a/dnf5daemon-server/session_manager.cpp
++++ b/dnf5daemon-server/session_manager.cpp
+@@ -47,6 +47,31 @@ SessionManager::~SessionManager() {
+ 
+ void SessionManager::dbus_register() {
+     dbus_object = sdbus::createObject(*connection, dnfdaemon::DBUS_OBJECT_PATH);
++#ifdef SDBUS_CPP_VERSION_2
++    dbus_object
++        ->addVTable(
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"open_session"},
++                sdbus::Signature{"a{sv}"},
++                {"options"},
++                sdbus::Signature{"o"},
++                {"session_object_path"},
++                [this](sdbus::MethodCall call) -> void {
++                    threads_manager.handle_method(*this, &SessionManager::open_session, call);
++                },
++                {}},
++            sdbus::MethodVTableItem{
++                sdbus::MethodName{"close_session"},
++                sdbus::Signature{"o"},
++                {"session_object_path"},
++                sdbus::Signature{"b"},
++                {"success"},
++                [this](sdbus::MethodCall call) -> void {
++                    threads_manager.handle_method(*this, &SessionManager::close_session, call);
++                },
++                {}})
++        .forInterface(dnfdaemon::INTERFACE_SESSION_MANAGER);
++#else
+     dbus_object->registerMethod(
+         dnfdaemon::INTERFACE_SESSION_MANAGER,
+         "open_session",
+@@ -69,14 +94,20 @@ void SessionManager::dbus_register() {
+         });
+     dbus_object->finishRegistration();
+ 
++#endif
++
+     // register signal handler for NameOwnerChanged
+     name_changed_proxy = sdbus::createProxy(
+         *connection, SDBUS_SERVICE_NAME_TYPE{"org.freedesktop.DBus"}, sdbus::ObjectPath{"/org/freedesktop/DBus"});
+     name_changed_proxy->registerSignalHandler(
+-        "org.freedesktop.DBus", "NameOwnerChanged", [this](sdbus::Signal signal) -> void {
++        SDBUS_INTERFACE_NAME_TYPE{"org.freedesktop.DBus"},
++        SDBUS_SIGNAL_NAME_TYPE{"NameOwnerChanged"},
++        [this](sdbus::Signal signal) -> void {
+             threads_manager.handle_signal(*this, &SessionManager::on_name_owner_changed, signal);
+         });
++#ifndef SDBUS_CPP_VERSION_2
+     name_changed_proxy->finishRegistration();
++#endif
+ }
+ 
+ 
+-- 
+2.48.1
+
diff --git a/0007-dnfdaemon-client-Use-correct-data-type-for-callbacks.patch b/0007-dnfdaemon-client-Use-correct-data-type-for-callbacks.patch
new file mode 100644
index 0000000..4c717f6
--- /dev/null
+++ b/0007-dnfdaemon-client-Use-correct-data-type-for-callbacks.patch
@@ -0,0 +1,34 @@
+From c5df756b2e1a5c82801a24b9a296e5881ec80a70 Mon Sep 17 00:00:00 2001
+From: Marek Blaha <mblaha at redhat.com>
+Date: Thu, 2 Jan 2025 14:38:41 +0100
+Subject: [PATCH 07/24] dnfdaemon-client: Use correct data type for callbacks
+
+---
+ dnf5daemon-client/callbacks.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/dnf5daemon-client/callbacks.cpp b/dnf5daemon-client/callbacks.cpp
+index 98b7d6a8..056c0009 100644
+--- a/dnf5daemon-client/callbacks.cpp
++++ b/dnf5daemon-client/callbacks.cpp
+@@ -134,7 +134,7 @@ void DownloadCB::end(sdbus::Signal & signal) {
+             return;
+         }
+ 
+-        int status_i;
++        unsigned int status_i;
+         std::string msg;
+         signal >> status_i;
+         signal >> msg;
+@@ -364,7 +364,7 @@ void TransactionCB::transaction_end(sdbus::Signal & signal) {
+ void TransactionCB::action_start(sdbus::Signal & signal) {
+     if (signature_valid(signal)) {
+         std::string nevra;
+-        int action_i;
++        unsigned int action_i;
+         uint64_t total;
+         signal >> nevra;
+         signal >> action_i;
+-- 
+2.48.1
+
diff --git a/0008-dnfdaemon-Properly-leave-event-loop.patch b/0008-dnfdaemon-Properly-leave-event-loop.patch
new file mode 100644
index 0000000..7609ee9
--- /dev/null
+++ b/0008-dnfdaemon-Properly-leave-event-loop.patch
@@ -0,0 +1,26 @@
+From 60e5a6bbf4172079fb72aadbc3021a3de3cf937e Mon Sep 17 00:00:00 2001
+From: Marek Blaha <mblaha at redhat.com>
+Date: Fri, 3 Jan 2025 15:45:12 +0100
+Subject: [PATCH 08/24] dnfdaemon: Properly leave event loop
+
+Exit the event loop and properly join the serving thread.
+---
+ dnf5daemon-client/main.cpp | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/dnf5daemon-client/main.cpp b/dnf5daemon-client/main.cpp
+index bab0243b..e759bd33 100644
+--- a/dnf5daemon-client/main.cpp
++++ b/dnf5daemon-client/main.cpp
+@@ -292,6 +292,8 @@ int main(int argc, char * argv[]) {
+ 
+         // Run selected command
+         command->run();
++
++        connection->leaveEventLoop();
+     } catch (libdnf5::cli::ArgumentParserError & ex) {
+         std::cerr << ex.what() << _(". Add \"--help\" for more information about the arguments.") << std::endl;
+         return static_cast<int>(libdnf5::cli::ExitCode::ARGPARSER_ERROR);
+-- 
+2.48.1
+
diff --git a/0009-daemon-client-Separate-context-and-callbacks.patch b/0009-daemon-client-Separate-context-and-callbacks.patch
new file mode 100644
index 0000000..8f3e4e7
--- /dev/null
+++ b/0009-daemon-client-Separate-context-and-callbacks.patch
@@ -0,0 +1,359 @@
+From 4eb8ef299690ab4795f73d06bdf5883dc0a34f02 Mon Sep 17 00:00:00 2001
+From: Marek Blaha <mblaha at redhat.com>
+Date: Fri, 3 Jan 2025 15:35:29 +0100
+Subject: [PATCH 09/24] daemon-client: Separate context and callbacks
+
+To address race conditions between the lifetime of the context and
+callbacks, it is safer to manage them separately.
+
+With sdbus-cpp version 2, I observed various failures in
+dnf5daemon-client, typically following this pattern:
+
+- The main thread has already completed its work and is in the process
+  of destructing the Context class.
+
+- Meanwhile, the D-Bus event loop thread is still handling messages, and
+  the handler attempts to access the context instance that is currently
+  being destroyed.
+---
+ dnf5daemon-client/callbacks.cpp | 67 +++++++++++++++++++++------------
+ dnf5daemon-client/callbacks.hpp | 24 +++++++++---
+ dnf5daemon-client/context.cpp   |  3 --
+ dnf5daemon-client/context.hpp   |  6 +--
+ dnf5daemon-client/main.cpp      | 20 +++++++---
+ 5 files changed, 79 insertions(+), 41 deletions(-)
+
+diff --git a/dnf5daemon-client/callbacks.cpp b/dnf5daemon-client/callbacks.cpp
+index 056c0009..96fbf40d 100644
+--- a/dnf5daemon-client/callbacks.cpp
++++ b/dnf5daemon-client/callbacks.cpp
+@@ -33,38 +33,50 @@ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ 
+ namespace dnfdaemon::client {
+ 
++DbusCallback::DbusCallback(Context & context, sdbus::IConnection & connection)
++    : session_object_path(context.get_session_object_path()) {
++    session_proxy = sdbus::createProxy(connection, dnfdaemon::DBUS_NAME, session_object_path);
++}
+ 
+ bool DbusCallback::signature_valid(sdbus::Signal & signal) {
+     // check that signal is emitted by the correct session object
+     sdbus::ObjectPath object_path;
+     signal >> object_path;
+-    return object_path == context.get_session_object_path();
++    return object_path == session_object_path;
+ }
+ 
+ 
+-DownloadCB::DownloadCB(Context & context) : DbusCallback(context) {
++DownloadCB::DownloadCB(Context & context, sdbus::IConnection & connection)
++    : DbusCallback(context, connection),
++      assume_yes(context.get_assumeyes_option()),
++      assume_no(context.get_assumeno_option()),
++      default_yes(context.get_defaultyes_option()) {}
++
++void DownloadCB::register_signals() {
+     // register signal handlers
+-    auto proxy = context.session_proxy.get();
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_ADD_NEW, [this](sdbus::Signal signal) -> void {
+             this->add_new_download(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_END, [this](sdbus::Signal signal) -> void {
+             this->end(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_PROGRESS, [this](sdbus::Signal signal) -> void {
+             this->progress(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_DOWNLOAD_MIRROR_FAILURE, [this](sdbus::Signal signal) -> void {
+             this->mirror_failure(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_BASE, dnfdaemon::SIGNAL_REPO_KEY_IMPORT_REQUEST, [this](sdbus::Signal signal) -> void {
+             this->key_import(signal);
+         });
++#ifndef SDBUS_CPP_VERSION_2
++    session_proxy->finishRegistration();
++#endif
+ }
+ 
+ 
+@@ -224,11 +236,11 @@ void DownloadCB::key_import(sdbus::Signal & signal) {
+         std::cerr << " From       : " + url << std::endl;
+ 
+         // ask user for the key import confirmation
+-        auto confirmed = libdnf5::cli::utils::userconfirm::userconfirm(context);
++        auto confirmed = libdnf5::cli::utils::userconfirm::userconfirm(*this);
+ 
+         // signal the confirmation back to the server
+         try {
+-            context.session_proxy->callMethod("confirm_key")
++            session_proxy->callMethod("confirm_key")
+                 .onInterface(dnfdaemon::INTERFACE_REPO)
+                 .withTimeout(static_cast<uint64_t>(-1))
+                 .withArguments(key_id, confirmed);
+@@ -238,61 +250,66 @@ void DownloadCB::key_import(sdbus::Signal & signal) {
+     }
+ }
+ 
+-TransactionCB::TransactionCB(Context & context) : DbusCallback(context) {
++TransactionCB::TransactionCB(Context & context, sdbus::IConnection & connection) : DbusCallback(context, connection) {}
++
++
++void TransactionCB::register_signals() {
+     // register signal handlers
+-    auto proxy = context.session_proxy.get();
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_VERIFY_START, [this](sdbus::Signal signal) -> void {
+             this->verify_start(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_VERIFY_PROGRESS, [this](sdbus::Signal signal) -> void {
+             this->verify_progress(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_VERIFY_STOP, [this](sdbus::Signal signal) -> void {
+             this->verify_end(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM,
+         dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_START,
+         [this](sdbus::Signal signal) -> void { this->transaction_start(signal); });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM,
+         dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_PROGRESS,
+         [this](sdbus::Signal signal) -> void { this->transaction_progress(signal); });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_TRANSACTION_STOP, [this](sdbus::Signal signal) -> void {
+             this->transaction_end(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_ACTION_START, [this](sdbus::Signal signal) -> void {
+             this->action_start(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_ACTION_PROGRESS, [this](sdbus::Signal signal) -> void {
+             this->action_progress(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_ACTION_STOP, [this](sdbus::Signal signal) -> void {
+             this->action_end(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_START, [this](sdbus::Signal signal) -> void {
+             this->script_start(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_STOP, [this](sdbus::Signal signal) -> void {
+             this->script_stop(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_SCRIPT_ERROR, [this](sdbus::Signal signal) -> void {
+             this->script_error(signal);
+         });
+-    proxy->registerSignalHandler(
++    session_proxy->registerSignalHandler(
+         dnfdaemon::INTERFACE_RPM, dnfdaemon::SIGNAL_TRANSACTION_FINISHED, [this](sdbus::Signal signal) -> void {
+             this->finished(signal);
+         });
++#ifndef SDBUS_CPP_VERSION_2
++    session_proxy->finishRegistration();
++#endif
+ }
+ 
+ void TransactionCB::new_progress_bar(uint64_t total, const std::string & description) {
+diff --git a/dnf5daemon-client/callbacks.hpp b/dnf5daemon-client/callbacks.hpp
+index 7a4fbdac..9ccfe8af 100644
+--- a/dnf5daemon-client/callbacks.hpp
++++ b/dnf5daemon-client/callbacks.hpp
+@@ -22,6 +22,7 @@ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ 
+ #include <libdnf5-cli/progressbar/download_progress_bar.hpp>
+ #include <libdnf5-cli/progressbar/multi_progress_bar.hpp>
++#include <libdnf5/conf/option_bool.hpp>
+ #include <sdbus-c++/sdbus-c++.h>
+ 
+ #include <string>
+@@ -32,19 +33,20 @@ class Context;
+ 
+ class DbusCallback {
+ public:
+-    explicit DbusCallback(Context & context) : context(context) {};
++    explicit DbusCallback(Context & context, sdbus::IConnection & connection);
+     virtual ~DbusCallback() = default;
++    virtual void register_signals() = 0;
+ 
+ protected:
+-    Context & context;
+-
+     bool signature_valid(sdbus::Signal & signal);
++    sdbus::ObjectPath session_object_path;
++    std::unique_ptr<sdbus::IProxy> session_proxy;
+ };
+ 
+ 
+ class DownloadCB final : public DbusCallback {
+ public:
+-    explicit DownloadCB(Context & context);
++    explicit DownloadCB(Context & context, sdbus::IConnection & connection);
+     virtual ~DownloadCB() = default;
+ 
+     void add_new_download(sdbus::Signal & signal);
+@@ -57,6 +59,13 @@ public:
+     void set_number_widget_visible(bool value);
+     void set_show_total_bar_limit(std::size_t limit);
+ 
++    // methods required by cli::utils::userconfirm::userconfirm
++    libdnf5::OptionBool get_assumeno_option() const { return assume_no; }
++    libdnf5::OptionBool get_assumeyes_option() const { return assume_yes; }
++    libdnf5::OptionBool get_defaultyes_option() const { return default_yes; }
++
++    void register_signals() override;
++
+ private:
+     libdnf5::cli::progressbar::DownloadProgressBar * find_progress_bar(const std::string & download_id);
+     void print();
+@@ -67,12 +76,15 @@ private:
+     std::unique_ptr<libdnf5::cli::progressbar::MultiProgressBar> multi_progress_bar;
+     // map {download_id: progressbar}
+     std::unordered_map<std::string, libdnf5::cli::progressbar::DownloadProgressBar *> progress_bars;
++    libdnf5::OptionBool assume_yes{false};
++    libdnf5::OptionBool assume_no{false};
++    libdnf5::OptionBool default_yes{false};
+ };
+ 
+ 
+ class TransactionCB final : public DbusCallback {
+ public:
+-    explicit TransactionCB(Context & context);
++    explicit TransactionCB(Context & context, sdbus::IConnection & connection);
+     virtual ~TransactionCB() = default;
+ 
+     void verify_start(sdbus::Signal & signal);
+@@ -95,6 +107,8 @@ public:
+ 
+     void finished(sdbus::Signal & signal);
+ 
++    void register_signals() override;
++
+ private:
+     libdnf5::cli::progressbar::MultiProgressBar multi_progress_bar;
+     libdnf5::cli::progressbar::DownloadProgressBar * active_progress_bar{nullptr};
+diff --git a/dnf5daemon-client/context.cpp b/dnf5daemon-client/context.cpp
+index f2bb40ca..5acc0996 100644
+--- a/dnf5daemon-client/context.cpp
++++ b/dnf5daemon-client/context.cpp
+@@ -62,9 +62,6 @@ void Context::init_session(sdbus::IConnection & connection) {
+         .storeResultsTo(session_object_path);
+ 
+     session_proxy = sdbus::createProxy(connection, dnfdaemon::DBUS_NAME, session_object_path);
+-    // register progress bars callbacks
+-    download_cb = std::make_unique<DownloadCB>(*this);
+-    transaction_cb = std::make_unique<TransactionCB>(*this);
+ #ifndef SDBUS_CPP_VERSION_2
+     session_proxy->finishRegistration();
+ #endif
+diff --git a/dnf5daemon-client/context.hpp b/dnf5daemon-client/context.hpp
+index 8c4d9578..412796fd 100644
+--- a/dnf5daemon-client/context.hpp
++++ b/dnf5daemon-client/context.hpp
+@@ -45,7 +45,7 @@ public:
+ 
+     /// Initialize dbus connection and server session
+     void init_session(sdbus::IConnection & connection);
+-    sdbus::ObjectPath & get_session_object_path() { return session_object_path; };
++    sdbus::ObjectPath get_session_object_path() { return session_object_path; };
+ 
+     // signal handlers
+     void on_repositories_ready(const bool & result);
+@@ -68,12 +68,12 @@ public:
+     libdnf5::OptionString releasever{""};
+ 
+     void reset_download_cb();
++    void set_download_cb(DownloadCB * download_cb) { this->download_cb = download_cb; }
+ 
+ private:
+     sdbus::ObjectPath session_object_path;
+     dnfdaemon::RepoStatus repositories_status;
+-    std::unique_ptr<DownloadCB> download_cb;
+-    std::unique_ptr<TransactionCB> transaction_cb;
++    DownloadCB * download_cb{nullptr};
+ };
+ 
+ }  // namespace dnfdaemon::client
+diff --git a/dnf5daemon-client/main.cpp b/dnf5daemon-client/main.cpp
+index e759bd33..120216d7 100644
+--- a/dnf5daemon-client/main.cpp
++++ b/dnf5daemon-client/main.cpp
+@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
+ along with libdnf.  If not, see <https://www.gnu.org/licenses/>.
+ */
+ 
++#include "callbacks.hpp"
+ #include "commands/advisory/advisory.hpp"
+ #include "commands/clean/clean.hpp"
+ #include "commands/distro-sync/distro-sync.hpp"
+@@ -231,8 +232,6 @@ static void set_locale() {
+ 
+ 
+ int main(int argc, char * argv[]) {
+-    std::unique_ptr<sdbus::IConnection> connection;
+-
+     set_locale();
+ 
+     dnfdaemon::client::Context context;
+@@ -272,6 +271,7 @@ int main(int argc, char * argv[]) {
+     try {
+         command->pre_configure();
+ 
++        std::unique_ptr<sdbus::IConnection> connection;
+         try {
+             connection = sdbus::createSystemBusConnection();
+         } catch (const sdbus::Error & ex) {
+@@ -290,10 +290,20 @@ int main(int argc, char * argv[]) {
+             return static_cast<int>(libdnf5::cli::ExitCode::ERROR);
+         }
+ 
+-        // Run selected command
+-        command->run();
++        {
++            auto download_cb = std::make_unique<dnfdaemon::client::DownloadCB>(context, *connection);
++            auto transaction_cb = std::make_unique<dnfdaemon::client::TransactionCB>(context, *connection);
++            download_cb->register_signals();
++            transaction_cb->register_signals();
++
++            context.set_download_cb(download_cb.get());
+ 
+-        connection->leaveEventLoop();
++            // Run selected command
++            command->run();
++            context.set_download_cb(nullptr);
++
++            connection->leaveEventLoop();
++        }
+     } catch (libdnf5::cli::ArgumentParserError & ex) {
+         std::cerr << ex.what() << _(". Add \"--help\" for more information about the arguments.") << std::endl;
+         return static_cast<int>(libdnf5::cli::ExitCode::ARGPARSER_ERROR);
+-- 
+2.48.1
+
diff --git a/systemdunitdir.patch b/systemdunitdir.patch
new file mode 100644
index 0000000..8672a77
--- /dev/null
+++ b/systemdunitdir.patch
@@ -0,0 +1,29 @@
+--- dnf5-5.2.10.0/CMakeLists.txt~	2025-02-06 09:25:15.000000000 +0100
++++ dnf5-5.2.10.0/CMakeLists.txt	2025-02-14 23:41:34.466659638 +0100
+@@ -7,7 +7,7 @@
+ cmake_policy(VERSION ${CMAKE_VERSION})
+ 
+ set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+-set (SYSTEMD_DIR "/usr/lib/systemd/system")
++set (SYSTEMD_DIR "/lib/systemd/system")
+ 
+ message("Building ${PROJECT_NAME} version ${PROJECT_VERSION}")
+ 
+--- dnf5-5.2.10.0/dnf5daemon-server/dbus/CMakeLists.txt~	2025-02-06 09:25:15.000000000 +0100
++++ dnf5-5.2.10.0/dnf5daemon-server/dbus/CMakeLists.txt	2025-02-15 00:25:52.869992755 +0100
+@@ -1,4 +1,4 @@
+-set(SYSTEMD_UNIT_DIR /usr/lib/systemd/system)
++set(SYSTEMD_UNIT_DIR /lib/systemd/system)
+ set(DBUS_SHARE_DIR /usr/share/dbus-1)
+ set(DBUS_CONFIG_DIR ${DBUS_SHARE_DIR}/system.d)
+ 
+--- dnf5-5.2.10.0/dnf5-plugins/automatic_plugin/CMakeLists.txt~	2025-02-06 09:25:15.000000000 +0100
++++ dnf5-5.2.10.0/dnf5-plugins/automatic_plugin/CMakeLists.txt	2025-02-15 00:27:58.546659401 +0100
+@@ -13,6 +13,7 @@
+ 
+ install(TARGETS automatic_cmd_plugin LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/dnf5/plugins/)
+ install(DIRECTORY "config/usr/" DESTINATION "${CMAKE_INSTALL_PREFIX}")
++install(DIRECTORY "config/lib/" DESTINATION "/lib")
+ 
+ install(PROGRAMS bin/dnf-automatic TYPE BIN)
+ 
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/dnf5.git/commitdiff/f10efed33decbce5fbdcfa7f5adac1fdae684176



More information about the pld-cvs-commit mailing list