From 78d73905a58651a319b86893c8a6bf2b1685b36b Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Wed, 12 Jun 2024 18:45:15 +0200 Subject: [PATCH] dnfdaemon: Add new API for offline transactions Adds new `Offline` interface for interacting with offline transactions. The interface provides three methods: - check_pending() - check whether there is an offline update scheduled for the next reboot - clean() - cancel the scheduled offline update - set_finish_action() - to set whether after applying the offline transaction the system should be rebooted (default) or powered off. --- dnf5daemon-server/dbus.hpp | 1 + .../interfaces/org.rpm.dnf.v0.Offline.xml | 76 +++++++++++ dnf5daemon-server/services/goal/goal.cpp | 1 - .../services/offline/offline.cpp | 126 ++++++++++++++++++ .../services/offline/offline.hpp | 40 ++++++ dnf5daemon-server/session.cpp | 2 + 6 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 dnf5daemon-server/dbus/interfaces/org.rpm.dnf.v0.Offline.xml create mode 100644 dnf5daemon-server/services/offline/offline.cpp create mode 100644 dnf5daemon-server/services/offline/offline.hpp diff --git a/dnf5daemon-server/dbus.hpp b/dnf5daemon-server/dbus.hpp index 3c89814237..61482b90ea 100644 --- a/dnf5daemon-server/dbus.hpp +++ b/dnf5daemon-server/dbus.hpp @@ -61,6 +61,7 @@ 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"; // signals diff --git a/dnf5daemon-server/dbus/interfaces/org.rpm.dnf.v0.Offline.xml b/dnf5daemon-server/dbus/interfaces/org.rpm.dnf.v0.Offline.xml new file mode 100644 index 0000000000..307a60137a --- /dev/null +++ b/dnf5daemon-server/dbus/interfaces/org.rpm.dnf.v0.Offline.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dnf5daemon-server/services/goal/goal.cpp b/dnf5daemon-server/services/goal/goal.cpp index dc6927cc29..58797100cc 100644 --- a/dnf5daemon-server/services/goal/goal.cpp +++ b/dnf5daemon-server/services/goal/goal.cpp @@ -28,7 +28,6 @@ along with libdnf. If not, see . #include "utils.hpp" #include -#include #include #include #include diff --git a/dnf5daemon-server/services/offline/offline.cpp b/dnf5daemon-server/services/offline/offline.cpp new file mode 100644 index 0000000000..6c548e1088 --- /dev/null +++ b/dnf5daemon-server/services/offline/offline.cpp @@ -0,0 +1,126 @@ +/* +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 . +*/ + +#include "offline.hpp" + +#include "dbus.hpp" + +#include +#include + +#include +#include + + +void Offline::dbus_register() { + auto dbus_object = session.get_dbus_object(); + dbus_object->registerMethod( + dnfdaemon::INTERFACE_OFFLINE, + "check_pending", + {}, + {}, + "b", + {"pending"}, + [this](sdbus::MethodCall call) -> void { + session.get_threads_manager().handle_method(*this, &Offline::check_pending, call, session.session_locale); + }); + dbus_object->registerMethod( + dnfdaemon::INTERFACE_OFFLINE, + "clean", + "a{sv}", + {"options"}, + "bs", + {"transaction_cleaned", "error_msg"}, + [this](sdbus::MethodCall call) -> void { + session.get_threads_manager().handle_method(*this, &Offline::clean, call, session.session_locale); + }); + dbus_object->registerMethod( + dnfdaemon::INTERFACE_OFFLINE, + "set_finish_action", + "s", + {"action"}, + "bs", + {"success", "error_msg"}, + [this](sdbus::MethodCall call) -> void { + session.get_threads_manager().handle_method( + *this, &Offline::set_finish_action, call, session.session_locale); + }); +} + +sdbus::MethodReply Offline::check_pending(sdbus::MethodCall & call) { + // check the presence of the magic symlink + auto reply = call.createReply(); + std::error_code ec; + reply << std::filesystem::exists(libdnf5::offline::MAGIC_SYMLINK, ec); + return reply; +} + +sdbus::MethodReply Offline::clean(sdbus::MethodCall & call) { + std::string error_msg; + dnfdaemon::KeyValueMap options; + call >> options; + bool clean_datadir = dnfdaemon::key_value_map_get(options, "clean_datadir", false); + bool cleaned = true; + std::error_code ec; + if (!std::filesystem::remove(libdnf5::offline::MAGIC_SYMLINK, ec) && ec) { + cleaned = false; + error_msg = ec.message(); + } + if (clean_datadir) { + auto base = session.get_base(); + const auto & installroot = base->get_config().get_installroot_option().get_value(); + std::filesystem::path datadir = installroot / libdnf5::offline::DEFAULT_DATADIR.relative_path(); + for (const auto & entry : std::filesystem::directory_iterator(datadir)) { + std::filesystem::remove_all(entry.path(), ec); + } + } + auto reply = call.createReply(); + reply << cleaned; + reply << error_msg; + return reply; +} + +sdbus::MethodReply Offline::set_finish_action(sdbus::MethodCall & call) { + bool success{false}; + std::string error_msg{}; + // try load the offline transaction state + const std::filesystem::path state_path{ + libdnf5::offline::MAGIC_SYMLINK / libdnf5::offline::TRANSACTION_STATE_FILENAME}; + libdnf5::offline::OfflineTransactionState state{state_path}; + const auto & read_exception = state.get_read_exception(); + if (read_exception == nullptr) { + // set the poweroff_after item accordingly + std::string finish_action; + call >> finish_action; + state.get_data().set_poweroff_after(finish_action == "poweroff"); + // write the new state + state.write(); + success = true; + } else { + try { + std::rethrow_exception(read_exception); + } catch (const std::exception & ex) { + error_msg = ex.what(); + } + } + auto reply = call.createReply(); + reply << success; + reply << error_msg; + return reply; +} diff --git a/dnf5daemon-server/services/offline/offline.hpp b/dnf5daemon-server/services/offline/offline.hpp new file mode 100644 index 0000000000..042e08d002 --- /dev/null +++ b/dnf5daemon-server/services/offline/offline.hpp @@ -0,0 +1,40 @@ +/* +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 . +*/ + +#ifndef DNF5DAEMON_SERVER_SERVICES_OFFLINE_OFFLINE_HPP +#define DNF5DAEMON_SERVER_SERVICES_OFFLINE_OFFLINE_HPP + +#include "session.hpp" + +#include + +class Offline : public IDbusSessionService { +public: + using IDbusSessionService::IDbusSessionService; + ~Offline() = default; + void dbus_register(); + void dbus_deregister(); + +private: + sdbus::MethodReply check_pending(sdbus::MethodCall & call); + sdbus::MethodReply set_finish_action(sdbus::MethodCall & call); + sdbus::MethodReply clean(sdbus::MethodCall & call); +}; + +#endif diff --git a/dnf5daemon-server/session.cpp b/dnf5daemon-server/session.cpp index ea0c93ff04..1869dd4928 100644 --- a/dnf5daemon-server/session.cpp +++ b/dnf5daemon-server/session.cpp @@ -25,6 +25,7 @@ along with libdnf. If not, see . #include "services/base/base.hpp" #include "services/comps/group.hpp" #include "services/goal/goal.hpp" +#include "services/offline/offline.hpp" #include "services/repo/repo.hpp" #include "services/rpm/rpm.hpp" #include "utils.hpp" @@ -135,6 +136,7 @@ Session::Session( services.emplace_back(std::make_unique(*this)); services.emplace_back(std::make_unique(*this)); services.emplace_back(std::make_unique(*this)); + services.emplace_back(std::make_unique(*this)); services.emplace_back(std::make_unique(*this)); services.emplace_back(std::make_unique(*this));