From 6799f77bf79fb4055f68cf13a6f093a513134ad7 Mon Sep 17 00:00:00 2001 From: Evan Goode Date: Thu, 14 Mar 2024 18:04:29 +0000 Subject: [PATCH] system-upgrade: misc fixes --- dnf5.spec | 8 +++- dnf5/CMakeLists.txt | 16 ++++--- dnf5/commands/offline/offline.cpp | 48 +++++++++++++++---- .../system-upgrade/system-upgrade.cpp | 4 +- dnf5/context.cpp | 3 +- 5 files changed, 57 insertions(+), 22 deletions(-) diff --git a/dnf5.spec b/dnf5.spec index 42c25959c9..852361eb32 100644 --- a/dnf5.spec +++ b/dnf5.spec @@ -262,8 +262,6 @@ It supports RPM packages, modulemd modules, and comps groups & environments. %dir %{_datadir}/dnf5 %dir %{_datadir}/dnf5/aliases.d %config %{_datadir}/dnf5/aliases.d/compatibility.conf -%config %{_unitdir}/dnf5-offline-transaction.service -%config %{_unitdir}/dnf5-offline-transaction-cleanup.service %dir %{_libdir}/dnf5 %dir %{_libdir}/dnf5/plugins %dir %{_datadir}/dnf5/dnf5-plugins @@ -317,6 +315,12 @@ It supports RPM packages, modulemd modules, and comps groups & environments. %{_mandir}/man5/dnf5.conf-todo.5.* %{_mandir}/man5/dnf5.conf-deprecated.5.* +%if %{with systemd} +%{_unitdir}/dnf5-offline-transaction.service +%{_unitdir}/dnf5-offline-transaction-cleanup.service +%{_unitdir}/system-update.target.wants/dnf5-offline-transaction.service +%endif + # ========== libdnf5 ========== %package -n libdnf5 Summary: Package management library diff --git a/dnf5/CMakeLists.txt b/dnf5/CMakeLists.txt index 63313eac4f..36ef083630 100644 --- a/dnf5/CMakeLists.txt +++ b/dnf5/CMakeLists.txt @@ -2,7 +2,8 @@ if(NOT WITH_DNF5) return() endif() -set(SYSTEMD_SYSTEM_UNIT_DIR /usr/lib/systemd/system) +pkg_check_modules(SYSTEMD REQUIRED systemd) +pkg_get_variable(SYSTEMD_SYSTEM_UNIT_DIR systemd systemdsystemunitdir) find_package(Threads) @@ -56,11 +57,14 @@ install(FILES bash-completion/dnf5 DESTINATION ${BASH_COMPLETION_COMPLETIONSDIR} install(FILES "README.plugins" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/dnf5/plugins" RENAME "README") install(DIRECTORY "config/usr/" DESTINATION "${CMAKE_INSTALL_PREFIX}" PATTERN ".gitkeep" EXCLUDE) install(DIRECTORY "config/etc/" DESTINATION "${CMAKE_INSTALL_FULL_SYSCONFDIR}" PATTERN ".gitkeep" EXCLUDE) -install(DIRECTORY "config/systemd/system/" DESTINATION "${SYSTEMD_SYSTEM_UNIT_DIR}" PATTERN ".gitkeep" EXCLUDE) -install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink - ${SYSTEMD_SYSTEM_UNIT_DIR}/dnf5-offline-transaction.service - ${SYSTEMD_SYSTEM_UNIT_DIR}/system-update.target.wants/dnf5-offline-transaction.service)" -) + +if(WITH_SYSTEMD) + install(DIRECTORY "config/systemd/system/" DESTINATION "${SYSTEMD_SYSTEM_UNIT_DIR}" PATTERN ".gitkeep" EXCLUDE) + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink + ${SYSTEMD_SYSTEM_UNIT_DIR}/dnf5-offline-transaction.service + ${SYSTEMD_SYSTEM_UNIT_DIR}/system-update.target.wants/dnf5-offline-transaction.service)" + ) +endif() # Makes an empty directory for dnf5-plugins configuration files install(DIRECTORY DESTINATION "${CMAKE_INSTALL_FULL_SYSCONFDIR}/dnf/dnf5-plugins") diff --git a/dnf5/commands/offline/offline.cpp b/dnf5/commands/offline/offline.cpp index 99630ec5f6..c4d018a331 100644 --- a/dnf5/commands/offline/offline.cpp +++ b/dnf5/commands/offline/offline.cpp @@ -45,6 +45,12 @@ using namespace libdnf5::cli; const std::string & ID_TO_IDENTIFY_BOOTS = dnf5::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 std::string SYSTEMD_SERVICE_NAME{"dnf5-offline-transaction.service"}; + int call(const std::string & command, const std::vector & args) { std::vector c_args; c_args.emplace_back(const_cast(command.c_str())); @@ -192,6 +198,9 @@ OfflineSubcommand::OfflineSubcommand(Context & context, const std::string & name void OfflineSubcommand::configure() { auto & ctx = get_context(); + // This value comes from systemd, see + // https://www.freedesktop.org/wiki/Software/systemd/SystemUpdates or + // systemd.offline-updates(7). magic_symlink = "/system-update"; const std::filesystem::path installroot = ctx.base.get_config().get_installroot_option().get_value(); @@ -223,10 +232,6 @@ void check_state(const dnf5::offline::OfflineTransactionState & state) { } void reboot([[maybe_unused]] bool poweroff = false) { - 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"}; - if (std::getenv("DNF_SYSTEM_UPGRADE_NO_REBOOT")) { std::cerr << "DNF_SYSTEM_UPGRADE_NO_REBOOT is set, not rebooting." << std::endl; return; @@ -241,11 +246,11 @@ void reboot([[maybe_unused]] bool poweroff = false) { const std::string error_message{ex.what()}; throw libdnf5::cli::CommandExitError(1, M_("Couldn't connect to D-Bus: {}"), error_message); } - auto proxy = sdbus::createProxy(systemd_destination_name, systemd_object_path); + auto proxy = sdbus::createProxy(SYSTEMD_DESTINATION_NAME, SYSTEMD_OBJECT_PATH); if (poweroff) { - proxy->callMethod("Poweroff").onInterface(systemd_manager_interface); + proxy->callMethod("Poweroff").onInterface(SYSTEMD_MANAGER_INTERFACE); } else { - proxy->callMethod("Reboot").onInterface(systemd_manager_interface); + proxy->callMethod("Reboot").onInterface(SYSTEMD_MANAGER_INTERFACE); } #else std::cerr << "Can't connect to D-Bus; this build of DNF 5 does not support D-Bus." << std::endl; @@ -290,9 +295,33 @@ void OfflineRebootCommand::run() { throw libdnf5::cli::CommandExitError(1, M_("System is not ready for offline transaction.")); } if (!std::filesystem::is_directory(get_datadir())) { - throw libdnf5::cli::CommandExitError(1, M_("data directory {} does not exist"), get_datadir().string()); + throw libdnf5::cli::CommandExitError(1, M_("Data directory {} does not exist."), get_datadir().string()); } +#ifdef WITH_SYSTEMD + // Check that dnf5-offline-transaction.service is present and wanted by system-update.target + std::unique_ptr connection; + try { + connection = sdbus::createSystemBusConnection(); + } catch (const sdbus::Error & ex) { + const std::string error_message{ex.what()}; + throw libdnf5::cli::CommandExitError(1, M_("Couldn't connect to D-Bus: {}"), error_message); + } + auto systemd_proxy = sdbus::createProxy(SYSTEMD_DESTINATION_NAME, SYSTEMD_OBJECT_PATH); + + sdbus::ObjectPath unit_object_path; + systemd_proxy->callMethod("LoadUnit") + .onInterface(SYSTEMD_MANAGER_INTERFACE) + .withArguments("system-update.target") + .storeResultsTo(unit_object_path); + + auto unit_proxy = sdbus::createProxy(SYSTEMD_DESTINATION_NAME, unit_object_path); + const std::vector & wants = 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); + } +#endif + if (state->get_data().verb == "system-upgrade download") { std::cout << _("The system will now reboot to upgrade to release version ") << state->get_data().target_releasever << "." << std::endl; @@ -396,8 +425,7 @@ void OfflineExecuteCommand::run() { throw libdnf5::cli::CommandExitError(0, M_("Trigger file does not exist. Exiting.")); } - const auto & symlinked_path = std::filesystem::read_symlink(get_magic_symlink()); - if (symlinked_path != get_datadir()) { + if (!std::filesystem::equivalent(get_magic_symlink(), get_datadir())) { throw libdnf5::cli::CommandExitError(0, M_("Another offline transaction tool is running. Exiting.")); } diff --git a/dnf5/commands/system-upgrade/system-upgrade.cpp b/dnf5/commands/system-upgrade/system-upgrade.cpp index e1fb0d6ae6..a6297c768f 100644 --- a/dnf5/commands/system-upgrade/system-upgrade.cpp +++ b/dnf5/commands/system-upgrade/system-upgrade.cpp @@ -123,9 +123,7 @@ void SystemUpgradeDownloadCommand::run() { ctx.set_should_store_offline(true); ctx.download_and_run(transaction); - std::cout << _("Download complete! Use `dnf5 system-upgrade reboot` to start the upgrade.\n" - "To cancel the upgrade and delete the downloaded upgrade files, use `dnf5 system-upgrade clean`.") - << std::endl; + std::cout << _("Download complete!") << std::endl; dnf5::offline::log_status( ctx, "Download finished.", dnf5::offline::DOWNLOAD_FINISHED_ID, system_releasever, target_releasever); diff --git a/dnf5/context.cpp b/dnf5/context.cpp index 5b411525fe..2310716992 100644 --- a/dnf5/context.cpp +++ b/dnf5/context.cpp @@ -451,7 +451,8 @@ void Context::download_and_run(libdnf5::base::Transaction & transaction) { if (should_store_offline) { store_offline(transaction); std::cout << "Transaction stored to be performed offline. Run `dnf5 offline reboot` to reboot and run the " - "transaction." + "transaction. To cancel the transaction and delete the downloaded files, use `dnf5 " + "offline clean`." << std::endl; } }