#include "manager.hpp" #include "utils.hpp" #include #include #include #include #include namespace rules = sdbusplus::bus::match::rules; namespace // anonymous { constexpr auto HOST_CURRENT_STATE = "CurrentHostState"; constexpr auto SYSTEMD_TIME_SERVICE = "org.freedesktop.timedate1"; constexpr auto SYSTEMD_TIME_PATH = "/org/freedesktop/timedate1"; constexpr auto SYSTEMD_TIME_INTERFACE = "org.freedesktop.timedate1"; constexpr auto METHOD_SET_NTP = "SetNTP"; } namespace phosphor { namespace time { using namespace phosphor::logging; const std::set Manager::managedProperties = {PROPERTY_TIME_MODE, PROPERTY_TIME_OWNER}; Manager::Manager(sdbusplus::bus::bus& bus) : bus(bus) { using namespace sdbusplus::bus::match::rules; hostStateChangeMatch = std::make_unique( bus, propertiesChanged(settings.hostState, settings::hostStateIntf), std::bind(std::mem_fn(&Manager::onHostStateChanged), this, std::placeholders::_1)); settingsMatches.emplace_back( bus, propertiesChanged(settings.timeOwner, settings::timeOwnerIntf), std::bind(std::mem_fn(&Manager::onSettingsChanged), this, std::placeholders::_1)); settingsMatches.emplace_back( bus, propertiesChanged(settings.timeSyncMethod, settings::timeSyncIntf), std::bind(std::mem_fn(&Manager::onSettingsChanged), this, std::placeholders::_1)); checkHostOn(); // Restore settings from persistent storage restoreSettings(); // Check the settings daemon to process the new settings auto mode = getSetting(settings.timeSyncMethod.c_str(), settings::timeSyncIntf, PROPERTY_TIME_MODE); auto owner = getSetting(settings.timeOwner.c_str(), settings::timeOwnerIntf, PROPERTY_TIME_OWNER); onPropertyChanged(PROPERTY_TIME_MODE, mode); onPropertyChanged(PROPERTY_TIME_OWNER, owner); } void Manager::addListener(PropertyChangeListner* listener) { // Notify listener about the initial value listener->onModeChanged(timeMode); listener->onOwnerChanged(timeOwner); listeners.insert(listener); } void Manager::restoreSettings() { auto mode = utils::readData(modeFile); if (!mode.empty()) { timeMode = utils::strToMode(mode); } auto owner = utils::readData(ownerFile); if (!owner.empty()) { timeOwner = utils::strToOwner(owner); } } void Manager::checkHostOn() { using Host = sdbusplus::xyz::openbmc_project::State::server::Host; auto hostService = utils::getService(bus, settings.hostState.c_str(), settings::hostStateIntf); auto stateStr = utils::getProperty(bus, hostService.c_str(), settings.hostState.c_str(), settings::hostStateIntf, HOST_CURRENT_STATE); auto state = Host::convertHostStateFromString(stateStr); hostOn = (state == Host::HostState::Running); } void Manager::onPropertyChanged(const std::string& key, const std::string& value) { if (hostOn) { // If host is on, set the values as requested time mode/owner. // And when host becomes off, notify the listners. setPropertyAsRequested(key, value); } else { // If host is off, notify listners if (key == PROPERTY_TIME_MODE) { setCurrentTimeMode(value); onTimeModeChanged(value); } else if (key == PROPERTY_TIME_OWNER) { setCurrentTimeOwner(value); onTimeOwnerChanged(); } } } int Manager::onSettingsChanged(sdbusplus::message::message& 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, p.second.get()); } return 0; } void Manager::setPropertyAsRequested(const std::string& key, const std::string& value) { if (key == PROPERTY_TIME_MODE) { setRequestedMode(value); } else if (key == PROPERTY_TIME_OWNER) { setRequestedOwner(value); } else { // The key shall be already the supported one using InvalidArgumentError = sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; using namespace xyz::openbmc_project::Common; elog( InvalidArgument::ARGUMENT_NAME(key.c_str()), InvalidArgument::ARGUMENT_VALUE(value.c_str())); } } void Manager::setRequestedMode(const std::string& mode) { requestedMode = mode; } void Manager::setRequestedOwner(const std::string& owner) { requestedOwner = owner; } void Manager::updateNtpSetting(const std::string& value) { bool isNtp = (value == "xyz.openbmc_project.Time.Synchronization.Method.NTP"); auto method = bus.new_method_call(SYSTEMD_TIME_SERVICE, SYSTEMD_TIME_PATH, SYSTEMD_TIME_INTERFACE, METHOD_SET_NTP); method.append(isNtp, false); // isNtp: 'true/false' means Enable/Disable // 'false' meaning no policy-kit if (bus.call(method)) { log("Updated NTP setting", entry("ENABLED:%d", isNtp)); } else { log("Failed to update NTP setting"); } } void Manager::onHostStateChanged(sdbusplus::message::message& msg) { using Interface = std::string; using Property = std::string; using Value = std::string; using Properties = std::map>; using Host = sdbusplus::xyz::openbmc_project::State::server::Host; Interface interface; Properties properties; msg.read(interface, properties); for(const auto& p : properties) { if (p.first == HOST_CURRENT_STATE) { auto state = Host::convertHostStateFromString(p.second.get()); onHostState(state == Host::HostState::Running); break; } } } void Manager::onHostState(bool on) { hostOn = on; if (hostOn) { log("Changing time settings is *deferred* now"); return; } log("Changing time settings allowed now"); if (!requestedMode.empty()) { if (setCurrentTimeMode(requestedMode)) { onTimeModeChanged(requestedMode); } setRequestedMode({}); // Clear requested mode } if (!requestedOwner.empty()) { if (setCurrentTimeOwner(requestedOwner)) { onTimeOwnerChanged(); } setRequestedOwner({}); // Clear requested owner } } bool Manager::setCurrentTimeMode(const std::string& mode) { auto newMode = utils::strToMode(mode); if (newMode != timeMode) { log("Time mode is changed", entry("MODE=%s", mode.c_str())); timeMode = newMode; utils::writeData(modeFile, mode); return true; } else { return false; } } bool Manager::setCurrentTimeOwner(const std::string& owner) { auto newOwner = utils::strToOwner(owner); if (newOwner != timeOwner) { log("Time owner is changed", entry("OWNER=%s", owner.c_str())); timeOwner = newOwner; utils::writeData(ownerFile, owner); return true; } else { return false; } } void Manager::onTimeModeChanged(const std::string& mode) { for (const auto listener : listeners) { listener->onModeChanged(timeMode); } // When time_mode is updated, update the NTP setting updateNtpSetting(mode); } void Manager::onTimeOwnerChanged() { for (const auto& listener : listeners) { listener->onOwnerChanged(timeOwner); } } std::string Manager::getSetting(const char* path, const char* interface, const char* setting) const { std::string settingManager = utils::getService(bus, path, interface); return utils::getProperty(bus, settingManager.c_str(), path, interface, setting); } } }