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