From 7b5fe4b9d1edf5d3eecc71bb0bf50ac0f4487f7e Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Tue, 18 Jun 2024 10:20:18 +0200 Subject: Separate service implementation from the main --- src/CMakeLists.txt | 4 +- src/main.cpp | 49 ++++++++ src/slack-timedate.cpp | 328 ------------------------------------------------- src/slack-timedate.h | 72 ----------- src/timedate.cpp | 294 ++++++++++++++++++++++++++++++++++++++++++++ src/timedate.h | 70 +++++++++++ 6 files changed, 415 insertions(+), 402 deletions(-) create mode 100644 src/main.cpp delete mode 100644 src/slack-timedate.cpp delete mode 100644 src/slack-timedate.h create mode 100644 src/timedate.cpp create mode 100644 src/timedate.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 469379a..c626a41 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,8 @@ find_package(PkgConfig) pkg_check_modules(GDBUS REQUIRED gio-2.0 dbus-1 glibmm-2.4 giomm-2.4) -add_executable(slack-timedate - slack-timedate.cpp slack-timedate.h +add_executable(slack-timedate main.cpp + timedate.cpp timedate.h ) target_include_directories(slack-timedate PRIVATE ${GDBUS_INCLUDE_DIRS}) target_link_libraries(slack-timedate ${GDBUS_LIBRARIES}) diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..bd6c0c0 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013-2024 Eugen Wissner + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + * + */ +#include "timedate.h" + +bool timeout_callback(Glib::RefPtr loop2quit) +{ + loop2quit->quit(); + return false; +} + +constexpr unsigned int default_exit_sec = 300; + +int main(int argc, char **argv) +{ + Gio::init(); + auto timedate1 = std::make_unique(); + + guint owner_id = Gio::DBus::own_name(Gio::DBus::BUS_TYPE_SYSTEM, BUS_NAME, + std::bind(&dlackware::timedate::timedate1::on_bus_acquired, timedate1.get(), + std::placeholders::_1, std::placeholders::_2), + Gio::DBus::SlotNameAcquired(), + std::bind(&dlackware::timedate::timedate1::on_name_lost, timedate1.get(), + std::placeholders::_1, std::placeholders::_2), + Gio::DBus::BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | Gio::DBus::BUS_NAME_OWNER_FLAGS_REPLACE); + + Glib::RefPtr loop = Glib::MainLoop::create(false); + + Glib::signal_timeout().connect_seconds(sigc::bind(&timeout_callback, loop), default_exit_sec); + loop->run(); + + Gio::DBus::unown_name(owner_id); + + return EXIT_SUCCESS; +} diff --git a/src/slack-timedate.cpp b/src/slack-timedate.cpp deleted file mode 100644 index 7b4c194..0000000 --- a/src/slack-timedate.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (C) 2013-2024 Eugen Wissner - * - * This program 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 3 of the License, or - * (at your option) any later version. - * - * This program 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 this program. If not, see . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "slack-timedate.h" - -static void slack_method_call(const Glib::RefPtr& connection, const Glib::ustring& sender, - const Glib::ustring& object_path, const Glib::ustring& interface_name, const Glib::ustring& method_name, - const Glib::VariantContainerBase& parameters, const Glib::RefPtr& invocation) -{ - // Set time zone - if (method_name == "SetTimezone") - { - Glib::Variant timezone; - Glib::Variant user_interaction; - - parameters.get_child(timezone, 0); - parameters.get_child(user_interaction, 1); - try - { - dlackware::timedate::set_timezone(timezone.get(), user_interaction.get()); - invocation->return_value(Glib::VariantContainerBase()); - } - catch (const std::filesystem::filesystem_error& filesystem_error) - { - invocation->return_error(Gio::DBus::Error{ Gio::DBus::Error::FAILED, filesystem_error.what() }); - } - } - else if (method_name == "SetTime") - { - Glib::Variant usec_utc; - Glib::Variant relative; - Glib::Variant user_interaction; - - parameters.get_child(usec_utc, 0); - parameters.get_child(relative, 1); - parameters.get_child(user_interaction, 2); - - try - { - dlackware::timedate::set_time(usec_utc.get(), relative.get(), user_interaction.get()); - invocation->return_value(Glib::VariantContainerBase()); - } - catch (const std::system_error& error) - { - invocation->return_error(Gio::DBus::Error{ Gio::DBus::Error::FAILED, error.what() }); - } - } - else if (method_name == "SetNTP") - { - Glib::Variant use_ntp; - Glib::Variant user_interaction; - - parameters.get_child(use_ntp, 0); - parameters.get_child(user_interaction, 1); - - // Enable NTP - try - { - dlackware::timedate::set_ntp(use_ntp.get(), user_interaction.get()); - invocation->return_value(Glib::VariantContainerBase()); - } - catch (const std::filesystem::filesystem_error& filesystem_error) - { - invocation->return_error(Gio::DBus::Error{ Gio::DBus::Error::FAILED, filesystem_error.what() }); - } - } - else if (method_name == "ListTimezones") - { - try - { - auto return_tuple = Glib::VariantContainerBase::create_tuple({ - Glib::Variant>::create(dlackware::timedate::list_timezones()) - }); - invocation->return_value(return_tuple); - } - catch (const std::exception& exception) - { - Gio::DBus::Error error{ Gio::DBus::Error::FAILED, exception.what() }; - invocation->return_error(error); - } - } -} - -static void slack_get_property(Glib::VariantBase& result, const Glib::RefPtr& connection, - const Glib::ustring& sender, const Glib::ustring& object_path, const Glib::ustring& interface_name, - const Glib::ustring& prop_name) -{ - if (prop_name == "Timezone") - { - result = Glib::Variant::create(dlackware::timedate::timezone()); - } - else if (prop_name == "LocalRTC") - { - result = Glib::Variant::create(dlackware::timedate::local_rtc()); - } - else if (prop_name == "NTP") - { - result = Glib::Variant::create(dlackware::timedate::ntp()); - } -} - -gboolean timeout_callback(Glib::RefPtr loop2quit) -{ - loop2quit->quit(); - return false; -} - -int main(int argc, char **argv) -{ - Gio::init(); - auto timedate1 = std::make_unique(); - - guint owner_id = Gio::DBus::own_name(Gio::DBus::BUS_TYPE_SYSTEM, BUS_NAME, - std::bind(&dlackware::timedate::timedate1::on_bus_acquired, timedate1.get(), - std::placeholders::_1, std::placeholders::_2), - Gio::DBus::SlotNameAcquired(), - std::bind(&dlackware::timedate::timedate1::on_name_lost, timedate1.get(), - std::placeholders::_1, std::placeholders::_2), - Gio::DBus::BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | Gio::DBus::BUS_NAME_OWNER_FLAGS_REPLACE); - - Glib::RefPtr loop = Glib::MainLoop::create(false); - - Glib::signal_timeout().connect_seconds(sigc::bind(&timeout_callback, loop), DEFAULT_EXIT_SEC); - loop->run(); - - Gio::DBus::unown_name(owner_id); - - return EXIT_SUCCESS; -} - -namespace dlackware::timedate -{ - timedate1::timedate1() - : interface_vtable{ &slack_method_call, &slack_get_property } - { - } - - void timedate1::on_name_lost(const Glib::RefPtr& connection, const Glib::ustring& name) - { - g_warning("Failed to acquire the service %s.\n", name.data()); - exit(1); - } - - void timedate1::on_bus_acquired(const Glib::RefPtr& connection, const Glib::ustring& name) - { - Glib::RefPtr introspection_data; - - try - { - auto introspection_xml = Glib::file_get_contents(dlackware::timedate::introspection_xml); - - introspection_data = Gio::DBus::NodeInfo::create_for_xml(introspection_xml); - } - catch (Glib::Error& slack_err) - { - g_error("Failed to parse D-Bus introspection XML: %s\n", slack_err.what().data()); - } - try - { - guint registration_id = connection->register_object(BUS_PATH, - introspection_data->lookup_interface(), this->interface_vtable); - } - catch (Glib::Error& slack_err) - { - g_critical("Failed to register callbacks for the exported object with the D-Bus interface: %s\n", - slack_err.what().data()); - } - } - - static void list_timezones(const std::string& prefix, std::vector& accumulator) - { - auto zoneinfo_path = std::filesystem::path(zoneinfo_database) / prefix; - - for (auto zoneinfo_entry : std::filesystem::directory_iterator(zoneinfo_path)) - { - auto new_prefix = prefix + zoneinfo_entry.path().filename().string(); - - if (zoneinfo_entry.is_directory()) - { - list_timezones(new_prefix + "/", accumulator); - } - else if (zoneinfo_entry.is_regular_file() && !zoneinfo_entry.path().has_extension() - && zoneinfo_entry.path().filename() != "leapseconds") - { - accumulator.emplace_back(new_prefix); - } - } - } - - std::vector list_timezones() - { - std::vector result; - - list_timezones("", result); - return result; - } - - Glib::ustring timezone() - { - std::unique_ptr zone_copied_from( - g_file_read_link("/etc/localtime", NULL), &g_free); - - if (zone_copied_from == nullptr) - { - return nullptr; - } - return Glib::ustring{ zone_copied_from.get() + strlen(zoneinfo_database) + 1 }; - } - - void set_timezone(const Glib::ustring& zone, bool) - { - auto zone_file = std::filesystem::path("/usr/share/zoneinfo") / zone.data(); - std::error_code ec{}; - - if (!std::filesystem::is_regular_file(zone_file, ec)) - { - throw std::filesystem::filesystem_error("Zone info is not a regular file", zone_file, ec); - } - std::filesystem::path etc_localtime = "/etc/localtime"; - - std::filesystem::remove(etc_localtime); - std::filesystem::create_symlink(zone_file, etc_localtime); - } - - void set_ntp(bool use_ntp, bool) - { - std::filesystem::perms rc_mode = std::filesystem::perms::owner_read | std::filesystem::perms::owner_write - | std::filesystem::perms::group_read | std::filesystem::perms::others_read; - - if (use_ntp) - { - rc_mode |= std::filesystem::perms::owner_exec - | std::filesystem::perms::group_exec | std::filesystem::perms::others_exec; - } - std::error_code ec; - const std::filesystem::path service_path{ "/etc/rc.d/rc.ntpd" }; - - if (std::filesystem::is_regular_file(service_path, ec)) - { - std::filesystem::permissions("/etc/rc.d/rc.ntpd", rc_mode); - } - else - { - throw std::filesystem::filesystem_error("The NTP daemon isn't installed", service_path, ec); - } - } - - bool local_rtc() - { - std::ifstream fh{ "/etc/hardwareclock", std::ios::in }; - if (!fh.is_open()) - { - return false; - } - std::array time_str; // "localtime" is longer than "UTC" and has 9 letters + \0 - - while (fh.good()) - { - fh.getline(time_str.data(), time_str.size()); - fh.clear(fh.rdstate() & (~std::ios_base::failbit)); - - if (std::strncmp(time_str.data(), "localtime", time_str.size()) == 0) - { - return true; - } - } - return false; - } - - bool ntp() - { - return Glib::file_test("/etc/rc.d/rc.ntpd", Glib::FileTest::FILE_TEST_IS_EXECUTABLE); - } - - void set_time(gint64 seconds_since_epoch, bool relative, bool) - { - timespec ts; - - if (relative) - { - if (clock_gettime(CLOCK_REALTIME, &ts) == -1) - { - throw std::system_error(errno, std::generic_category()); - } - ts.tv_sec += static_cast(seconds_since_epoch / dlackware::timedate::usec_per_sec); - ts.tv_nsec += (seconds_since_epoch % dlackware::timedate::usec_per_sec) * dlackware::timedate::nsec_per_usec; - - if (ts.tv_nsec < 0) - { - --ts.tv_sec; - ts.tv_nsec += dlackware::timedate::usec_per_sec; - } - } - else - { - ts.tv_sec = static_cast(seconds_since_epoch / dlackware::timedate::usec_per_sec); - ts.tv_nsec = (seconds_since_epoch % dlackware::timedate::usec_per_sec) * dlackware::timedate::nsec_per_usec; - } - if (clock_settime(CLOCK_REALTIME, &ts) == -1) - { - throw std::system_error(errno, std::generic_category()); - } - } -} diff --git a/src/slack-timedate.h b/src/slack-timedate.h deleted file mode 100644 index 2dd4223..0000000 --- a/src/slack-timedate.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2013-2024 Eugen Wissner - * - * This program 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 3 of the License, or - * (at your option) any later version. - * - * This program 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 this program. If not, see . - * - */ - -#include -#include -#include -#include - -#define BUS_NAME "org.freedesktop.timedate1" -#define BUS_PATH "/org/freedesktop/timedate1" - -#define DEFAULT_EXIT_SEC 300 - -namespace dlackware::timedate -{ - constexpr const char *zoneinfo_database = "/usr/share/zoneinfo"; - constexpr const char *introspection_xml = "/usr/share/dbus-1/interfaces/org.freedesktop.timedate1.xml"; - - constexpr const gint32 usec_per_sec = 1000000ULL; - constexpr const gint32 nsec_per_usec = 1000ULL; - - // Returns the system time zone. - Glib::ustring timezone(); - - // Returns if the hardware clock is set to local time or not - bool local_rtc(); - - // Returns if NTP is enabled - bool ntp(); - - // Returns the timezones available on the system. - std::vector list_timezones(); - - // Sets the system time zone to the one passed by the argument - // Throws std::filesystem::filesystem_error. - void set_timezone(const Glib::ustring& zone, bool user_interaction); - - // Sets NTP - // Throws std::filesystem::filesystem_error. - void set_ntp(bool use_ntp, bool user_interaction); - - // Changes the date/time - // Takes the amount of seconds since UNIX epoche and - // Throws std::system_error. - void set_time(gint64 seconds_since_epoch, bool relative, bool user_interaction); - - class timedate1 - { - const Gio::DBus::InterfaceVTable interface_vtable; - - public: - timedate1(); - - void on_bus_acquired(const Glib::RefPtr& connection, const Glib::ustring& name); - void on_name_lost(const Glib::RefPtr& connection, const Glib::ustring& name); - }; -} diff --git a/src/timedate.cpp b/src/timedate.cpp new file mode 100644 index 0000000..a320384 --- /dev/null +++ b/src/timedate.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2013-2024 Eugen Wissner + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + * + */ +#include +#include +#include +#include + +#include "timedate.h" + +static void slack_method_call(const Glib::RefPtr& connection, const Glib::ustring& sender, + const Glib::ustring& object_path, const Glib::ustring& interface_name, const Glib::ustring& method_name, + const Glib::VariantContainerBase& parameters, const Glib::RefPtr& invocation) +{ + // Set time zone + if (method_name == "SetTimezone") + { + Glib::Variant timezone; + Glib::Variant user_interaction; + + parameters.get_child(timezone, 0); + parameters.get_child(user_interaction, 1); + try + { + dlackware::timedate::set_timezone(timezone.get(), user_interaction.get()); + invocation->return_value(Glib::VariantContainerBase()); + } + catch (const std::filesystem::filesystem_error& filesystem_error) + { + invocation->return_error(Gio::DBus::Error{ Gio::DBus::Error::FAILED, filesystem_error.what() }); + } + } + else if (method_name == "SetTime") + { + Glib::Variant usec_utc; + Glib::Variant relative; + Glib::Variant user_interaction; + + parameters.get_child(usec_utc, 0); + parameters.get_child(relative, 1); + parameters.get_child(user_interaction, 2); + + try + { + dlackware::timedate::set_time(usec_utc.get(), relative.get(), user_interaction.get()); + invocation->return_value(Glib::VariantContainerBase()); + } + catch (const std::system_error& error) + { + invocation->return_error(Gio::DBus::Error{ Gio::DBus::Error::FAILED, error.what() }); + } + } + else if (method_name == "SetNTP") + { + Glib::Variant use_ntp; + Glib::Variant user_interaction; + + parameters.get_child(use_ntp, 0); + parameters.get_child(user_interaction, 1); + + // Enable NTP + try + { + dlackware::timedate::set_ntp(use_ntp.get(), user_interaction.get()); + invocation->return_value(Glib::VariantContainerBase()); + } + catch (const std::filesystem::filesystem_error& filesystem_error) + { + invocation->return_error(Gio::DBus::Error{ Gio::DBus::Error::FAILED, filesystem_error.what() }); + } + } + else if (method_name == "ListTimezones") + { + try + { + auto return_tuple = Glib::VariantContainerBase::create_tuple({ + Glib::Variant>::create(dlackware::timedate::list_timezones()) + }); + invocation->return_value(return_tuple); + } + catch (const std::exception& exception) + { + Gio::DBus::Error error{ Gio::DBus::Error::FAILED, exception.what() }; + invocation->return_error(error); + } + } +} + +static void slack_get_property(Glib::VariantBase& result, const Glib::RefPtr& connection, + const Glib::ustring& sender, const Glib::ustring& object_path, const Glib::ustring& interface_name, + const Glib::ustring& prop_name) +{ + if (prop_name == "Timezone") + { + result = Glib::Variant::create(dlackware::timedate::timezone()); + } + else if (prop_name == "LocalRTC") + { + result = Glib::Variant::create(dlackware::timedate::local_rtc()); + } + else if (prop_name == "NTP") + { + result = Glib::Variant::create(dlackware::timedate::ntp()); + } +} + +namespace dlackware::timedate +{ + timedate1::timedate1() + : interface_vtable{ &slack_method_call, &slack_get_property } + { + } + + void timedate1::on_name_lost(const Glib::RefPtr& connection, const Glib::ustring& name) + { + g_warning("Failed to acquire the service %s.\n", name.data()); + exit(1); + } + + void timedate1::on_bus_acquired(const Glib::RefPtr& connection, const Glib::ustring& name) + { + Glib::RefPtr introspection_data; + + try + { + auto introspection_xml = Glib::file_get_contents(dlackware::timedate::introspection_xml); + + introspection_data = Gio::DBus::NodeInfo::create_for_xml(introspection_xml); + } + catch (Glib::Error& slack_err) + { + g_error("Failed to parse D-Bus introspection XML: %s\n", slack_err.what().data()); + } + try + { + guint registration_id = connection->register_object(bus_path, + introspection_data->lookup_interface(), this->interface_vtable); + } + catch (Glib::Error& slack_err) + { + g_critical("Failed to register callbacks for the exported object with the D-Bus interface: %s\n", + slack_err.what().data()); + } + } + + static void list_timezones(const std::string& prefix, std::vector& accumulator) + { + auto zoneinfo_path = std::filesystem::path(zoneinfo_database) / prefix; + + for (auto zoneinfo_entry : std::filesystem::directory_iterator(zoneinfo_path)) + { + auto new_prefix = prefix + zoneinfo_entry.path().filename().string(); + + if (zoneinfo_entry.is_directory()) + { + list_timezones(new_prefix + "/", accumulator); + } + else if (zoneinfo_entry.is_regular_file() && !zoneinfo_entry.path().has_extension() + && zoneinfo_entry.path().filename() != "leapseconds") + { + accumulator.emplace_back(new_prefix); + } + } + } + + std::vector list_timezones() + { + std::vector result; + + list_timezones("", result); + return result; + } + + Glib::ustring timezone() + { + std::unique_ptr zone_copied_from( + g_file_read_link("/etc/localtime", NULL), &g_free); + + if (zone_copied_from == nullptr) + { + return nullptr; + } + return Glib::ustring{ zone_copied_from.get() + strlen(zoneinfo_database) + 1 }; + } + + void set_timezone(const Glib::ustring& zone, bool) + { + auto zone_file = std::filesystem::path("/usr/share/zoneinfo") / zone.data(); + std::error_code ec{}; + + if (!std::filesystem::is_regular_file(zone_file, ec)) + { + throw std::filesystem::filesystem_error("Zone info is not a regular file", zone_file, ec); + } + std::filesystem::path etc_localtime = "/etc/localtime"; + + std::filesystem::remove(etc_localtime); + std::filesystem::create_symlink(zone_file, etc_localtime); + } + + void set_ntp(bool use_ntp, bool) + { + std::filesystem::perms rc_mode = std::filesystem::perms::owner_read | std::filesystem::perms::owner_write + | std::filesystem::perms::group_read | std::filesystem::perms::others_read; + + if (use_ntp) + { + rc_mode |= std::filesystem::perms::owner_exec + | std::filesystem::perms::group_exec | std::filesystem::perms::others_exec; + } + std::error_code ec; + const std::filesystem::path service_path{ "/etc/rc.d/rc.ntpd" }; + + if (std::filesystem::is_regular_file(service_path, ec)) + { + std::filesystem::permissions("/etc/rc.d/rc.ntpd", rc_mode); + } + else + { + throw std::filesystem::filesystem_error("The NTP daemon isn't installed", service_path, ec); + } + } + + bool local_rtc() + { + std::ifstream fh{ "/etc/hardwareclock", std::ios::in }; + if (!fh.is_open()) + { + return false; + } + std::array time_str; // "localtime" is longer than "UTC" and has 9 letters + \0 + + while (fh.good()) + { + fh.getline(time_str.data(), time_str.size()); + fh.clear(fh.rdstate() & (~std::ios_base::failbit)); + + if (std::strncmp(time_str.data(), "localtime", time_str.size()) == 0) + { + return true; + } + } + return false; + } + + bool ntp() + { + return Glib::file_test("/etc/rc.d/rc.ntpd", Glib::FileTest::FILE_TEST_IS_EXECUTABLE); + } + + void set_time(gint64 seconds_since_epoch, bool relative, bool) + { + timespec ts; + + if (relative) + { + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) + { + throw std::system_error(errno, std::generic_category()); + } + ts.tv_sec += static_cast(seconds_since_epoch / dlackware::timedate::usec_per_sec); + ts.tv_nsec += (seconds_since_epoch % dlackware::timedate::usec_per_sec) * dlackware::timedate::nsec_per_usec; + + if (ts.tv_nsec < 0) + { + --ts.tv_sec; + ts.tv_nsec += dlackware::timedate::usec_per_sec; + } + } + else + { + ts.tv_sec = static_cast(seconds_since_epoch / dlackware::timedate::usec_per_sec); + ts.tv_nsec = (seconds_since_epoch % dlackware::timedate::usec_per_sec) * dlackware::timedate::nsec_per_usec; + } + if (clock_settime(CLOCK_REALTIME, &ts) == -1) + { + throw std::system_error(errno, std::generic_category()); + } + } +} diff --git a/src/timedate.h b/src/timedate.h new file mode 100644 index 0000000..82336de --- /dev/null +++ b/src/timedate.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013-2024 Eugen Wissner + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + * + */ +#pragma once + +#include +#include +#include + +#define BUS_NAME "org.freedesktop.timedate1" + +namespace dlackware::timedate +{ + constexpr const char *bus_path = "/org/freedesktop/timedate1"; + constexpr const char *zoneinfo_database = "/usr/share/zoneinfo"; + constexpr const char *introspection_xml = "/usr/share/dbus-1/interfaces/org.freedesktop.timedate1.xml"; + + constexpr const gint32 usec_per_sec = 1000000ULL; + constexpr const gint32 nsec_per_usec = 1000ULL; + + // Returns the system time zone. + Glib::ustring timezone(); + + // Returns if the hardware clock is set to local time or not + bool local_rtc(); + + // Returns if NTP is enabled + bool ntp(); + + // Returns the timezones available on the system. + std::vector list_timezones(); + + // Sets the system time zone to the one passed by the argument + // Throws std::filesystem::filesystem_error. + void set_timezone(const Glib::ustring& zone, bool user_interaction); + + // Sets NTP + // Throws std::filesystem::filesystem_error. + void set_ntp(bool use_ntp, bool user_interaction); + + // Changes the date/time + // Takes the amount of seconds since UNIX epoche and + // Throws std::system_error. + void set_time(gint64 seconds_since_epoch, bool relative, bool user_interaction); + + class timedate1 + { + const Gio::DBus::InterfaceVTable interface_vtable; + + public: + timedate1(); + + void on_bus_acquired(const Glib::RefPtr& connection, const Glib::ustring& name); + void on_name_lost(const Glib::RefPtr& connection, const Glib::ustring& name); + }; +} -- cgit v1.2.3