1 #include "manager.hpp" 2 3 #include "utils.hpp" 4 5 #include <phosphor-logging/elog-errors.hpp> 6 #include <phosphor-logging/elog.hpp> 7 #include <phosphor-logging/log.hpp> 8 #include <xyz/openbmc_project/Common/error.hpp> 9 #include <xyz/openbmc_project/State/Host/server.hpp> 10 11 namespace rules = sdbusplus::bus::match::rules; 12 13 namespace // anonymous 14 { 15 constexpr auto HOST_CURRENT_STATE = "CurrentHostState"; 16 17 constexpr auto SYSTEMD_TIME_SERVICE = "org.freedesktop.timedate1"; 18 constexpr auto SYSTEMD_TIME_PATH = "/org/freedesktop/timedate1"; 19 constexpr auto SYSTEMD_TIME_INTERFACE = "org.freedesktop.timedate1"; 20 constexpr auto METHOD_SET_NTP = "SetNTP"; 21 } // namespace 22 23 namespace phosphor 24 { 25 namespace time 26 { 27 28 using namespace phosphor::logging; 29 30 const std::set<std::string> Manager::managedProperties = {PROPERTY_TIME_MODE, 31 PROPERTY_TIME_OWNER}; 32 33 Manager::Manager(sdbusplus::bus::bus& bus) : bus(bus) 34 { 35 using namespace sdbusplus::bus::match::rules; 36 hostStateChangeMatch = 37 std::make_unique<decltype(hostStateChangeMatch)::element_type>( 38 bus, propertiesChanged(settings.hostState, settings::hostStateIntf), 39 std::bind(std::mem_fn(&Manager::onHostStateChanged), this, 40 std::placeholders::_1)); 41 settingsMatches.emplace_back( 42 bus, propertiesChanged(settings.timeOwner, settings::timeOwnerIntf), 43 std::bind(std::mem_fn(&Manager::onSettingsChanged), this, 44 std::placeholders::_1)); 45 settingsMatches.emplace_back( 46 bus, propertiesChanged(settings.timeSyncMethod, settings::timeSyncIntf), 47 std::bind(std::mem_fn(&Manager::onSettingsChanged), this, 48 std::placeholders::_1)); 49 50 checkHostOn(); 51 52 // Restore settings from persistent storage 53 restoreSettings(); 54 55 // Check the settings daemon to process the new settings 56 auto mode = getSetting(settings.timeSyncMethod.c_str(), 57 settings::timeSyncIntf, PROPERTY_TIME_MODE); 58 auto owner = getSetting(settings.timeOwner.c_str(), settings::timeOwnerIntf, 59 PROPERTY_TIME_OWNER); 60 61 onPropertyChanged(PROPERTY_TIME_MODE, mode); 62 onPropertyChanged(PROPERTY_TIME_OWNER, owner); 63 } 64 65 void Manager::addListener(PropertyChangeListner* listener) 66 { 67 // Notify listener about the initial value 68 listener->onModeChanged(timeMode); 69 listener->onOwnerChanged(timeOwner); 70 71 listeners.insert(listener); 72 } 73 74 void Manager::restoreSettings() 75 { 76 auto mode = utils::readData<std::string>(modeFile); 77 if (!mode.empty()) 78 { 79 timeMode = utils::strToMode(mode); 80 } 81 auto owner = utils::readData<std::string>(ownerFile); 82 if (!owner.empty()) 83 { 84 timeOwner = utils::strToOwner(owner); 85 } 86 } 87 88 void Manager::checkHostOn() 89 { 90 using Host = sdbusplus::xyz::openbmc_project::State::server::Host; 91 auto hostService = utils::getService(bus, settings.hostState.c_str(), 92 settings::hostStateIntf); 93 auto stateStr = utils::getProperty<std::string>( 94 bus, hostService.c_str(), settings.hostState.c_str(), 95 settings::hostStateIntf, HOST_CURRENT_STATE); 96 auto state = Host::convertHostStateFromString(stateStr); 97 hostOn = (state == Host::HostState::Running); 98 } 99 100 void Manager::onPropertyChanged(const std::string& key, 101 const std::string& value) 102 { 103 if (hostOn) 104 { 105 // If host is on, set the values as requested time mode/owner. 106 // And when host becomes off, notify the listeners. 107 setPropertyAsRequested(key, value); 108 } 109 else 110 { 111 // If host is off, notify listeners 112 if (key == PROPERTY_TIME_MODE) 113 { 114 setCurrentTimeMode(value); 115 onTimeModeChanged(value); 116 } 117 else if (key == PROPERTY_TIME_OWNER) 118 { 119 setCurrentTimeOwner(value); 120 onTimeOwnerChanged(); 121 } 122 } 123 } 124 125 int Manager::onSettingsChanged(sdbusplus::message::message& msg) 126 { 127 using Interface = std::string; 128 using Property = std::string; 129 using Value = std::string; 130 using Properties = std::map<Property, sdbusplus::message::variant<Value>>; 131 132 Interface interface; 133 Properties properties; 134 135 msg.read(interface, properties); 136 137 for (const auto& p : properties) 138 { 139 onPropertyChanged(p.first, p.second.get<std::string>()); 140 } 141 142 return 0; 143 } 144 145 void Manager::setPropertyAsRequested(const std::string& key, 146 const std::string& value) 147 { 148 if (key == PROPERTY_TIME_MODE) 149 { 150 setRequestedMode(value); 151 } 152 else if (key == PROPERTY_TIME_OWNER) 153 { 154 setRequestedOwner(value); 155 } 156 else 157 { 158 // The key shall be already the supported one 159 using InvalidArgumentError = 160 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 161 using namespace xyz::openbmc_project::Common; 162 elog<InvalidArgumentError>( 163 InvalidArgument::ARGUMENT_NAME(key.c_str()), 164 InvalidArgument::ARGUMENT_VALUE(value.c_str())); 165 } 166 } 167 168 void Manager::setRequestedMode(const std::string& mode) 169 { 170 requestedMode = mode; 171 } 172 173 void Manager::setRequestedOwner(const std::string& owner) 174 { 175 requestedOwner = owner; 176 } 177 178 void Manager::updateNtpSetting(const std::string& value) 179 { 180 bool isNtp = 181 (value == "xyz.openbmc_project.Time.Synchronization.Method.NTP"); 182 auto method = bus.new_method_call(SYSTEMD_TIME_SERVICE, SYSTEMD_TIME_PATH, 183 SYSTEMD_TIME_INTERFACE, METHOD_SET_NTP); 184 method.append(isNtp, false); // isNtp: 'true/false' means Enable/Disable 185 // 'false' meaning no policy-kit 186 187 try 188 { 189 bus.call_noreply(method); 190 log<level::INFO>("Updated NTP setting", entry("ENABLED=%d", isNtp)); 191 } 192 catch (const sdbusplus::exception::SdBusError& ex) 193 { 194 log<level::ERR>("Failed to update NTP setting", 195 entry("ERR=%s", ex.what())); 196 } 197 } 198 199 void Manager::onHostStateChanged(sdbusplus::message::message& msg) 200 { 201 using Interface = std::string; 202 using Property = std::string; 203 using Value = std::string; 204 using Properties = std::map<Property, sdbusplus::message::variant<Value>>; 205 using Host = sdbusplus::xyz::openbmc_project::State::server::Host; 206 207 Interface interface; 208 Properties properties; 209 210 msg.read(interface, properties); 211 212 for (const auto& p : properties) 213 { 214 if (p.first == HOST_CURRENT_STATE) 215 { 216 auto state = 217 Host::convertHostStateFromString(p.second.get<std::string>()); 218 onHostState(state == Host::HostState::Running); 219 break; 220 } 221 } 222 } 223 224 void Manager::onHostState(bool on) 225 { 226 hostOn = on; 227 if (hostOn) 228 { 229 log<level::INFO>("Changing time settings is *deferred* now"); 230 return; 231 } 232 log<level::INFO>("Changing time settings allowed now"); 233 if (!requestedMode.empty()) 234 { 235 if (setCurrentTimeMode(requestedMode)) 236 { 237 onTimeModeChanged(requestedMode); 238 } 239 setRequestedMode({}); // Clear requested mode 240 } 241 if (!requestedOwner.empty()) 242 { 243 if (setCurrentTimeOwner(requestedOwner)) 244 { 245 onTimeOwnerChanged(); 246 } 247 setRequestedOwner({}); // Clear requested owner 248 } 249 } 250 251 bool Manager::setCurrentTimeMode(const std::string& mode) 252 { 253 auto newMode = utils::strToMode(mode); 254 if (newMode != timeMode) 255 { 256 log<level::INFO>("Time mode is changed", 257 entry("MODE=%s", mode.c_str())); 258 timeMode = newMode; 259 utils::writeData(modeFile, mode); 260 return true; 261 } 262 else 263 { 264 return false; 265 } 266 } 267 268 bool Manager::setCurrentTimeOwner(const std::string& owner) 269 { 270 auto newOwner = utils::strToOwner(owner); 271 if (newOwner != timeOwner) 272 { 273 log<level::INFO>("Time owner is changed", 274 entry("OWNER=%s", owner.c_str())); 275 timeOwner = newOwner; 276 utils::writeData(ownerFile, owner); 277 return true; 278 } 279 else 280 { 281 return false; 282 } 283 } 284 285 void Manager::onTimeModeChanged(const std::string& mode) 286 { 287 for (const auto listener : listeners) 288 { 289 listener->onModeChanged(timeMode); 290 } 291 // When time_mode is updated, update the NTP setting 292 updateNtpSetting(mode); 293 } 294 295 void Manager::onTimeOwnerChanged() 296 { 297 for (const auto& listener : listeners) 298 { 299 listener->onOwnerChanged(timeOwner); 300 } 301 } 302 303 std::string Manager::getSetting(const char* path, const char* interface, 304 const char* setting) const 305 { 306 std::string settingManager = utils::getService(bus, path, interface); 307 return utils::getProperty<std::string>(bus, settingManager.c_str(), path, 308 interface, setting); 309 } 310 311 } // namespace time 312 } // namespace phosphor 313