summaryrefslogtreecommitdiff
path: root/src/slack-timedate.cpp
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2024-06-18 10:20:18 +0200
committerEugen Wissner <belka@caraus.de>2024-06-18 10:20:18 +0200
commit7b5fe4b9d1edf5d3eecc71bb0bf50ac0f4487f7e (patch)
treecd3856476abae7b5d24848e420ba04c0ecf8f12e /src/slack-timedate.cpp
parentbbb4efde187ec2a9546f2b9ff54e0db7d275fc5d (diff)
downloadslack-timedate-7b5fe4b9d1edf5d3eecc71bb0bf50ac0f4487f7e.tar.gz
Separate service implementation from the main
Diffstat (limited to 'src/slack-timedate.cpp')
-rw-r--r--src/slack-timedate.cpp328
1 files changed, 0 insertions, 328 deletions
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 <belka@caraus.de>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <cstring>
-#include <filesystem>
-#include <fstream>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-
-#include "slack-timedate.h"
-
-static void slack_method_call(const Glib::RefPtr<Gio::DBus::Connection>& 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<Gio::DBus::MethodInvocation>& invocation)
-{
- // Set time zone
- if (method_name == "SetTimezone")
- {
- Glib::Variant<Glib::ustring> timezone;
- Glib::Variant<bool> 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<gint64> usec_utc;
- Glib::Variant<bool> relative;
- Glib::Variant<bool> 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<bool> use_ntp;
- Glib::Variant<bool> 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<std::vector<Glib::ustring>>::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<Gio::DBus::Connection>& 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<Glib::ustring>::create(dlackware::timedate::timezone());
- }
- else if (prop_name == "LocalRTC")
- {
- result = Glib::Variant<bool>::create(dlackware::timedate::local_rtc());
- }
- else if (prop_name == "NTP")
- {
- result = Glib::Variant<bool>::create(dlackware::timedate::ntp());
- }
-}
-
-gboolean timeout_callback(Glib::RefPtr<Glib::MainLoop> loop2quit)
-{
- loop2quit->quit();
- return false;
-}
-
-int main(int argc, char **argv)
-{
- Gio::init();
- auto timedate1 = std::make_unique<dlackware::timedate::timedate1>();
-
- 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<Glib::MainLoop> 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<Gio::DBus::Connection>& 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<Gio::DBus::Connection>& connection, const Glib::ustring& name)
- {
- Glib::RefPtr<Gio::DBus::NodeInfo> 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<Glib::ustring>& 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<Glib::ustring> list_timezones()
- {
- std::vector<Glib::ustring> result;
-
- list_timezones("", result);
- return result;
- }
-
- Glib::ustring timezone()
- {
- std::unique_ptr<gchar[], decltype(&g_free)> 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<char, 10> 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<time_t>(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<time_t>(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());
- }
- }
-}