-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 - cancel() - cancel the scheduled offline update - clean() - cancel the scheduled offline update and remove all stored offline transaction data. - set_finish_action() - to set whether after applying the offline transaction the system should be rebooted (default) or powered off.
- Loading branch information
Showing
7 changed files
with
322 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
dnf5daemon-server/dbus/interfaces/org.rpm.dnf.v0.Offline.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" | ||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> | ||
|
||
<!-- | ||
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 Lesser General Public License as published by | ||
the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. | ||
You should have received a copy of the GNU Lesser General Public License | ||
along with libdnf. If not, see <https://www.gnu.org/licenses/>. | ||
--> | ||
|
||
<node> | ||
<!-- org.rpm.dnf.v0.Offline: | ||
@short_description: Interface to offline transactions | ||
--> | ||
<interface name="org.rpm.dnf.v0.Offline"> | ||
<!-- | ||
check_pending: | ||
@pending: boolean, true if there is a pending offline transaction | ||
Check whether there is an offline transaction configured for the next reboot initiated by dnf5. | ||
--> | ||
<method name="check_pending"> | ||
<arg name="pending" type="b" direction="out" /> | ||
</method> | ||
|
||
|
||
<!-- | ||
cancel: | ||
@success: boolean, returns `false` if there was an error during the transaction cancellation, or if the offline transaction was initiated by another tool than dnf5. Returns `true` if the offline transaction was successfully cancelled or if no offline transaction was configured. | ||
@error_msg: string, contains error encountered while cancelling the transaction | ||
Cancel the dnf5 offline transaction configured for the next reboot. Offline updates scheduled by another tool are not cancelled. | ||
--> | ||
<method name="cancel"> | ||
<arg name="success" type="b" direction="out" /> | ||
<arg name="error_msg" type="s" direction="out" /> | ||
</method> | ||
|
||
<!-- | ||
clean: | ||
@success: boolean, returns `false` if there was an error during the transaction cleanup. Returns `true` if the offline transaction was successfully cleaned or if no offline transaction was configured. | ||
@error_msg: string, contains error encountered while cleaning the transaction | ||
Cancel the dnf5 offline transaction configured for the next reboot and remove all stored offline transaction data, including downloaded packages. Offline updates scheduled by another tool are not affected. | ||
--> | ||
<method name="clean"> | ||
<arg name="success" type="b" direction="out" /> | ||
<arg name="error_msg" type="s" direction="out" /> | ||
</method> | ||
|
||
<!-- | ||
set_finish_action: | ||
@action: string, if set to "poweroff", the system will be powered off after applying the offline transaction. Otherwise the system will reboot. | ||
@success: boolean, true if the action was successfully set | ||
@error_msg: string, contains error encountered while setting the action | ||
Set the action that should be performed after the offline transaction is applied. If the `action` is "poweroff", the system will be powered off, otherwise it will be rebooted (which is default). | ||
The call might fail in case there is no scheduled offline transaction, or the transaction was not scheduled using libdnf5. | ||
--> | ||
<method name="set_finish_action"> | ||
<arg name="action" type="s" direction="in" /> | ||
<arg name="success" type="b" direction="out" /> | ||
<arg name="error_msg" type="s" direction="out" /> | ||
</method> | ||
|
||
</interface> | ||
|
||
</node> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
/* | ||
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/>. | ||
*/ | ||
|
||
#include "offline.hpp" | ||
|
||
#include "dbus.hpp" | ||
#include "utils/string.hpp" | ||
|
||
#include <libdnf5/transaction/offline.hpp> | ||
#include <sdbus-c++/sdbus-c++.h> | ||
|
||
#include <exception> | ||
#include <filesystem> | ||
|
||
const char * const ERR_ANOTHER_TOOL = "Offline transaction was initiated by another tool."; | ||
|
||
std::filesystem::path Offline::get_datadir() { | ||
auto base = session.get_base(); | ||
const auto & installroot = base->get_config().get_installroot_option().get_value(); | ||
return installroot / libdnf5::offline::DEFAULT_DATADIR.relative_path(); | ||
} | ||
|
||
Offline::Scheduled Offline::offline_transaction_scheduled() { | ||
std::error_code ec; | ||
// magic symlink exists | ||
if (std::filesystem::exists(libdnf5::offline::MAGIC_SYMLINK, ec)) { | ||
// and points to dnf5 location | ||
if (std::filesystem::equivalent(libdnf5::offline::MAGIC_SYMLINK, get_datadir())) { | ||
return Scheduled::SCHEDULED; | ||
} else { | ||
return Scheduled::ANOTHER_TOOL; | ||
} | ||
} | ||
return Scheduled::NOT_SCHEDULED; | ||
} | ||
|
||
void Offline::dbus_register() { | ||
auto dbus_object = session.get_dbus_object(); | ||
dbus_object->registerMethod( | ||
dnfdaemon::INTERFACE_OFFLINE, | ||
"cancel", | ||
{}, | ||
{}, | ||
"bs", | ||
{"success", "error_msg"}, | ||
[this](sdbus::MethodCall call) -> void { | ||
session.get_threads_manager().handle_method(*this, &Offline::cancel, call, session.session_locale); | ||
}); | ||
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", | ||
{}, | ||
{}, | ||
"bs", | ||
{"success", "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) { | ||
auto reply = call.createReply(); | ||
reply << (offline_transaction_scheduled() == Scheduled::SCHEDULED); | ||
return reply; | ||
} | ||
|
||
sdbus::MethodReply Offline::cancel(sdbus::MethodCall & call) { | ||
if (!session.check_authorization(dnfdaemon::POLKIT_EXECUTE_RPM_TRANSACTION, call.getSender())) { | ||
throw std::runtime_error("Not authorized"); | ||
} | ||
bool success = true; | ||
std::string error_msg; | ||
switch (offline_transaction_scheduled()) { | ||
case Scheduled::SCHEDULED: { | ||
std::error_code ec; | ||
if (!std::filesystem::remove(libdnf5::offline::MAGIC_SYMLINK, ec) && ec) { | ||
success = false; | ||
error_msg = ec.message(); | ||
} | ||
} break; | ||
case Scheduled::ANOTHER_TOOL: | ||
success = false; | ||
error_msg = ERR_ANOTHER_TOOL; | ||
break; | ||
case Scheduled::NOT_SCHEDULED: | ||
break; | ||
} | ||
auto reply = call.createReply(); | ||
reply << success; | ||
reply << error_msg; | ||
return reply; | ||
} | ||
|
||
sdbus::MethodReply Offline::clean(sdbus::MethodCall & call) { | ||
if (!session.check_authorization(dnfdaemon::POLKIT_EXECUTE_RPM_TRANSACTION, call.getSender())) { | ||
throw std::runtime_error("Not authorized"); | ||
} | ||
std::vector<std::string> error_msgs; | ||
bool success = true; | ||
if (offline_transaction_scheduled() == Scheduled::SCHEDULED) { | ||
// remove the magic symlink if it was created by dnf5 | ||
std::error_code ec; | ||
if (!std::filesystem::remove(libdnf5::offline::MAGIC_SYMLINK, ec) && ec) { | ||
success = false; | ||
error_msgs.push_back(ec.message()); | ||
} | ||
} | ||
// clean dnf5 offline transaction files | ||
for (const auto & entry : std::filesystem::directory_iterator(get_datadir())) { | ||
std::error_code ec; | ||
std::filesystem::remove_all(entry.path(), ec); | ||
if (ec) { | ||
success = false; | ||
error_msgs.push_back(ec.message()); | ||
} | ||
} | ||
auto reply = call.createReply(); | ||
reply << success; | ||
reply << libdnf5::utils::string::join(error_msgs, ", "); | ||
return reply; | ||
} | ||
|
||
sdbus::MethodReply Offline::set_finish_action(sdbus::MethodCall & call) { | ||
if (!session.check_authorization(dnfdaemon::POLKIT_EXECUTE_RPM_TRANSACTION, call.getSender())) { | ||
throw std::runtime_error("Not authorized"); | ||
} | ||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
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_SERVICES_OFFLINE_OFFLINE_HPP | ||
#define DNF5DAEMON_SERVER_SERVICES_OFFLINE_OFFLINE_HPP | ||
|
||
#include "session.hpp" | ||
|
||
#include <sdbus-c++/sdbus-c++.h> | ||
|
||
#include <filesystem> | ||
|
||
class Offline : public IDbusSessionService { | ||
public: | ||
using IDbusSessionService::IDbusSessionService; | ||
~Offline() = default; | ||
void dbus_register(); | ||
void dbus_deregister(); | ||
|
||
private: | ||
sdbus::MethodReply cancel(sdbus::MethodCall & call); | ||
sdbus::MethodReply check_pending(sdbus::MethodCall & call); | ||
sdbus::MethodReply clean(sdbus::MethodCall & call); | ||
sdbus::MethodReply set_finish_action(sdbus::MethodCall & call); | ||
|
||
enum class Scheduled { NOT_SCHEDULED, ANOTHER_TOOL, SCHEDULED }; | ||
Scheduled offline_transaction_scheduled(); | ||
std::filesystem::path get_datadir(); | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters