#include "manager.hpp" #include "utils.hpp" #include #include namespace rules = sdbusplus::bus::match::rules; namespace // anonymous { constexpr auto systemdTimeService = "org.freedesktop.timedate1"; constexpr auto systemdTimePath = "/org/freedesktop/timedate1"; constexpr auto systemdTimeInterface = "org.freedesktop.timedate1"; constexpr auto methodSetNtp = "SetNTP"; constexpr auto propertyNtp = "NTP"; } // namespace namespace phosphor { namespace time { PHOSPHOR_LOG2_USING; Manager::Manager(sdbusplus::bus_t& bus) : bus(bus), settings(bus) { using namespace sdbusplus::bus::match::rules; timedateMatches.emplace_back( bus, propertiesChanged(systemdTimePath, systemdTimeInterface), [&](sdbusplus::message_t& m) { onTimedateChanged(m); }); settingsMatches.emplace_back( bus, propertiesChanged(settings.timeSyncMethod, settings::timeSyncIntf), [&](sdbusplus::message_t& m) { onSettingsChanged(m); }); // Check the settings daemon to process the new settings auto mode = getSetting(settings.timeSyncMethod.c_str(), settings::timeSyncIntf, propertyTimeMode); onPropertyChanged(propertyTimeMode, mode, true); } void Manager::onPropertyChanged(const std::string& key, const std::string& value, bool forceSet) { assert(key == propertyTimeMode); bool newNtpMode = (settings::ntpSync == value); bool oldNtpMode = (Mode::NTP == getTimeMode()); if (forceSet || (newNtpMode != oldNtpMode)) { // Notify listeners onTimeModeChanged(value); setCurrentTimeMode(value); debug("NTP property changed in phosphor-settings, update to systemd" " time service."); } else { debug("NTP mode is already the same, skip setting to systemd time" " service again."); } } int Manager::onSettingsChanged(sdbusplus::message_t& msg) { using Interface = std::string; using Property = std::string; using Value = std::string; using Properties = std::map>; Interface interface; Properties properties; msg.read(interface, properties); for (const auto& p : properties) { onPropertyChanged(p.first, std::get(p.second)); } return 0; } int Manager::onTimedateChanged(sdbusplus::message_t& msg) { using Properties = std::map>; std::string interface; Properties properties; msg.read(interface, properties); auto iter = properties.find(propertyNtp); if (iter == properties.end()) { return -1; } try { bool newNtpMode = std::get(iter->second); bool oldNtpMode = (Mode::NTP == getTimeMode()); if (newNtpMode != oldNtpMode) { const auto& timeMode = newNtpMode ? settings::ntpSync : settings::manualSync; std::string settingManager = utils::getService( bus, settings.timeSyncMethod.c_str(), settings::timeSyncIntf); utils::setProperty(bus, settingManager, settings.timeSyncMethod, settings::timeSyncIntf, propertyTimeMode, timeMode); setCurrentTimeMode(timeMode); debug("NTP property changed in systemd time service, update to" " phosphor-settings."); } else { debug("NTP mode is already the same, skip setting to" " phosphor-settings again."); } } catch (const std::exception& ex) { error("Failed to sync NTP: {ERROR}", "ERROR", ex); } return 0; } void Manager::updateNtpSetting(const std::string& value) { try { bool isNtp = (value == "xyz.openbmc_project.Time.Synchronization.Method.NTP"); auto method = bus.new_method_call(systemdTimeService, systemdTimePath, systemdTimeInterface, methodSetNtp); method.append(isNtp, false); // isNtp: 'true/false' means Enable/Disable // 'false' meaning no policy-kit bus.call_noreply(method); info("Updated NTP setting: {ENABLED}", "ENABLED", isNtp); } catch (const sdbusplus::exception_t& ex) { error("Failed to update NTP setting: {ERROR}", "ERROR", ex); } } bool Manager::setCurrentTimeMode(const std::string& mode) { try { auto newMode = utils::strToMode(mode); if (newMode != timeMode) { info("Time mode has been changed to {MODE}", "MODE", newMode); timeMode = newMode; return true; } } catch (const sdbusplus::exception_t& ex) { error("Failed to convert mode from string: {ERROR}", "ERROR", ex); } return false; } void Manager::onTimeModeChanged(const std::string& mode) { // When time_mode is updated, update the NTP setting updateNtpSetting(mode); } std::string Manager::getSetting(const char* path, const char* interface, const char* setting) const { try { std::string settingManager = utils::getService(bus, path, interface); return utils::getProperty(bus, settingManager.c_str(), path, interface, setting); } catch (const std::exception& ex) { error( "Failed to get property: {ERROR}, path: {PATH}, interface: {INTERFACE}, name: {NAME}", "ERROR", ex, "PATH", path, "INTERFACE", interface, "NAME", setting); return {}; } } } // namespace time } // namespace phosphor