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 9 namespace rules = sdbusplus::bus::match::rules; 10 11 namespace // anonymous 12 { 13 constexpr auto SETTINGS_PATH = "/org/openbmc/settings/host0"; 14 constexpr auto SETTINGS_INTERFACE = "org.openbmc.settings.Host"; 15 16 // TODO: Use new settings in xyz.openbmc_project 17 const auto MATCH_PROPERTY_CHANGE = 18 rules::type::signal() + 19 rules::member("PropertiesChanged") + 20 rules::path("/org/openbmc/settings/host0") + 21 rules::interface("org.freedesktop.DBus.Properties"); 22 23 const auto MATCH_PGOOD_CHANGE = 24 rules::type::signal() + 25 rules::member("PropertiesChanged") + 26 rules::path("/org/openbmc/control/power0") + 27 rules::interface("org.freedesktop.DBus.Properties"); 28 29 constexpr auto POWER_PATH = "/org/openbmc/control/power0"; 30 constexpr auto POWER_INTERFACE = "org.openbmc.control.Power"; 31 constexpr auto PGOOD_STR = "pgood"; 32 33 constexpr auto SYSTEMD_TIME_SERVICE = "org.freedesktop.timedate1"; 34 constexpr auto SYSTEMD_TIME_PATH = "/org/freedesktop/timedate1"; 35 constexpr auto SYSTEMD_TIME_INTERFACE = "org.freedesktop.timedate1"; 36 constexpr auto METHOD_SET_NTP = "SetNTP"; 37 38 constexpr auto OBMC_NETWORK_PATH = "/org/openbmc/NetworkManager/Interface"; 39 constexpr auto OBMC_NETWORK_INTERFACE = "org.openbmc.NetworkManager"; 40 constexpr auto METHOD_UPDATE_USE_NTP = "UpdateUseNtpField"; 41 } 42 43 namespace phosphor 44 { 45 namespace time 46 { 47 48 using namespace phosphor::logging; 49 50 const std::set<std::string> 51 Manager::managedProperties = {PROPERTY_TIME_MODE, PROPERTY_TIME_OWNER}; 52 53 Manager::Manager(sdbusplus::bus::bus& bus) 54 : bus(bus), 55 propertyChangeMatch(bus, MATCH_PROPERTY_CHANGE, onPropertyChanged, this), 56 pgoodChangeMatch(bus, MATCH_PGOOD_CHANGE, onPgoodChanged, this) 57 { 58 checkHostOn(); 59 60 // Restore settings from persistent storage 61 restoreSettings(); 62 63 // Check the settings daemon to process the new settings 64 onPropertyChanged(PROPERTY_TIME_MODE, getSettings(PROPERTY_TIME_MODE)); 65 onPropertyChanged(PROPERTY_TIME_OWNER, getSettings(PROPERTY_TIME_OWNER)); 66 67 checkDhcpNtp(); 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 std::string powerService = utils::getService(bus, 96 POWER_PATH, 97 POWER_INTERFACE); 98 99 int pgood = utils::getProperty<int>(bus, 100 powerService.c_str(), 101 POWER_PATH, 102 POWER_INTERFACE, 103 PGOOD_STR); 104 hostOn = static_cast<bool>(pgood); 105 } 106 107 void Manager::checkDhcpNtp() 108 { 109 std::string useDhcpNtp = getSettings(PROPERTY_DHCP_NTP); 110 updateDhcpNtpSetting(useDhcpNtp); 111 } 112 113 void Manager::onPropertyChanged(const std::string& key, 114 const std::string& value) 115 { 116 if (hostOn) 117 { 118 // If host is on, set the values as requested time mode/owner. 119 // And when host becomes off, notify the listners. 120 setPropertyAsRequested(key, value); 121 } 122 else 123 { 124 // If host is off, notify listners 125 if (key == PROPERTY_TIME_MODE) 126 { 127 setCurrentTimeMode(value); 128 onTimeModeChanged(value); 129 } 130 else if (key == PROPERTY_TIME_OWNER) 131 { 132 setCurrentTimeOwner(value); 133 onTimeOwnerChanged(); 134 } 135 } 136 } 137 138 int Manager::onPropertyChanged(sd_bus_message* msg, 139 void* userData, 140 sd_bus_error* retError) 141 { 142 using properties = std::map < std::string, 143 sdbusplus::message::variant<std::string> >; 144 auto m = sdbusplus::message::message(msg); 145 // message type: sa{sv}as 146 std::string ignore; 147 properties props; 148 m.read(ignore, props); 149 auto manager = static_cast<Manager*>(userData); 150 for (const auto& item : props) 151 { 152 if (managedProperties.find(item.first) != managedProperties.end()) 153 { 154 // For managed properties, notify listeners 155 manager->onPropertyChanged( 156 item.first, item.second.get<std::string>()); 157 } 158 else if (item.first == PROPERTY_DHCP_NTP) 159 { 160 // For other manager interested properties, handle specifically 161 manager->updateDhcpNtpSetting(item.second.get<std::string>()); 162 } 163 } 164 return 0; 165 } 166 167 void Manager::setPropertyAsRequested(const std::string& key, 168 const std::string& value) 169 { 170 if (key == PROPERTY_TIME_MODE) 171 { 172 setRequestedMode(value); 173 } 174 else if (key == PROPERTY_TIME_OWNER) 175 { 176 setRequestedOwner(value); 177 } 178 else 179 { 180 // The key shall be already the supported one 181 using InvalidArgumentError = 182 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument; 183 using namespace xyz::openbmc_project::Common; 184 elog<InvalidArgumentError>( 185 InvalidArgument::ARGUMENT_NAME(key.c_str()), 186 InvalidArgument::ARGUMENT_VALUE(value.c_str())); 187 } 188 } 189 190 void Manager::setRequestedMode(const std::string& mode) 191 { 192 requestedMode = mode; 193 } 194 195 void Manager::setRequestedOwner(const std::string& owner) 196 { 197 requestedOwner = owner; 198 } 199 200 void Manager::updateNtpSetting(const std::string& value) 201 { 202 bool isNtp = (value == "NTP"); 203 auto method = bus.new_method_call(SYSTEMD_TIME_SERVICE, 204 SYSTEMD_TIME_PATH, 205 SYSTEMD_TIME_INTERFACE, 206 METHOD_SET_NTP); 207 method.append(isNtp, false); // isNtp: 'true/false' means Enable/Disable 208 // 'false' meaning no policy-kit 209 210 if (bus.call(method)) 211 { 212 log<level::INFO>("Updated NTP setting", 213 entry("ENABLED:%d", isNtp)); 214 } 215 else 216 { 217 log<level::ERR>("Failed to update NTP setting"); 218 } 219 } 220 221 void Manager::updateDhcpNtpSetting(const std::string& useDhcpNtp) 222 { 223 std::string networkService = utils::getService(bus, 224 OBMC_NETWORK_PATH, 225 OBMC_NETWORK_INTERFACE); 226 227 auto method = bus.new_method_call(networkService.c_str(), 228 OBMC_NETWORK_PATH, 229 OBMC_NETWORK_INTERFACE, 230 METHOD_UPDATE_USE_NTP); 231 method.append(useDhcpNtp); 232 233 if (bus.call(method)) 234 { 235 log<level::INFO>("Updated use ntp field", 236 entry("USENTPFIELD:%s", useDhcpNtp.c_str())); 237 } 238 else 239 { 240 log<level::ERR>("Failed to update UseNtpField"); 241 } 242 } 243 244 void Manager::onPgoodChanged(bool pgood) 245 { 246 hostOn = pgood; 247 if (hostOn) 248 { 249 return; 250 } 251 if (!requestedMode.empty()) 252 { 253 if (setCurrentTimeMode(requestedMode)) 254 { 255 onTimeModeChanged(requestedMode); 256 } 257 setRequestedMode({}); // Clear requested mode 258 } 259 if (!requestedOwner.empty()) 260 { 261 if (setCurrentTimeOwner(requestedOwner)) 262 { 263 onTimeOwnerChanged(); 264 } 265 setRequestedOwner({}); // Clear requested owner 266 } 267 } 268 269 int Manager::onPgoodChanged(sd_bus_message* msg, 270 void* userData, 271 sd_bus_error* retError) 272 { 273 using properties = std::map < std::string, 274 sdbusplus::message::variant<int> >; 275 auto m = sdbusplus::message::message(msg); 276 // message type: sa{sv}as 277 std::string ignore; 278 properties props; 279 m.read(ignore, props); 280 for (const auto& item : props) 281 { 282 if (item.first == PGOOD_STR) 283 { 284 static_cast<Manager*>(userData) 285 ->onPgoodChanged(static_cast<bool>(item.second.get<int>())); 286 } 287 } 288 return 0; 289 } 290 291 bool Manager::setCurrentTimeMode(const std::string& mode) 292 { 293 auto newMode = utils::strToMode(mode); 294 if (newMode != timeMode) 295 { 296 log<level::INFO>("Time mode is changed", 297 entry("MODE=%s", mode.c_str())); 298 timeMode = newMode; 299 utils::writeData(modeFile, mode); 300 return true; 301 } 302 else 303 { 304 return false; 305 } 306 } 307 308 bool Manager::setCurrentTimeOwner(const std::string& owner) 309 { 310 auto newOwner = utils::strToOwner(owner); 311 if (newOwner != timeOwner) 312 { 313 log<level::INFO>("Time owner is changed", 314 entry("OWNER=%s", owner.c_str())); 315 timeOwner = newOwner; 316 utils::writeData(ownerFile, owner); 317 return true; 318 } 319 else 320 { 321 return false; 322 } 323 } 324 325 void Manager::onTimeModeChanged(const std::string& mode) 326 { 327 for (const auto listener : listeners) 328 { 329 listener->onModeChanged(timeMode); 330 } 331 // When time_mode is updated, update the NTP setting 332 updateNtpSetting(mode); 333 } 334 335 void Manager::onTimeOwnerChanged() 336 { 337 for (const auto& listener : listeners) 338 { 339 listener->onOwnerChanged(timeOwner); 340 } 341 } 342 343 std::string Manager::getSettings(const char* setting) const 344 { 345 std::string settingsService = utils::getService(bus, 346 SETTINGS_PATH, 347 SETTINGS_INTERFACE); 348 349 return utils::getProperty<std::string>(bus, 350 settingsService.c_str(), 351 SETTINGS_PATH, 352 SETTINGS_INTERFACE, 353 setting); 354 } 355 356 } 357 } 358