1 #include "manager.hpp" 2 3 #include "utils.hpp" 4 5 #include <phosphor-logging/lg2.hpp> 6 7 #include <cassert> 8 9 namespace rules = sdbusplus::bus::match::rules; 10 11 namespace // anonymous 12 { 13 14 constexpr auto systemdTimeService = "org.freedesktop.timedate1"; 15 constexpr auto systemdTimePath = "/org/freedesktop/timedate1"; 16 constexpr auto systemdTimeInterface = "org.freedesktop.timedate1"; 17 constexpr auto methodSetNtp = "SetNTP"; 18 constexpr auto propertyNtp = "NTP"; 19 } // namespace 20 21 namespace phosphor 22 { 23 namespace time 24 { 25 26 PHOSPHOR_LOG2_USING; 27 28 Manager::Manager(sdbusplus::bus_t& bus) : bus(bus), settings(bus) 29 { 30 using namespace sdbusplus::bus::match::rules; 31 timedateMatches.emplace_back( 32 bus, propertiesChanged(systemdTimePath, systemdTimeInterface), 33 [&](sdbusplus::message_t& m) { onTimedateChanged(m); }); 34 settingsMatches.emplace_back( 35 bus, propertiesChanged(settings.timeSyncMethod, settings::timeSyncIntf), 36 [&](sdbusplus::message_t& m) { onSettingsChanged(m); }); 37 38 // Check the settings daemon to process the new settings 39 auto mode = getSetting(settings.timeSyncMethod.c_str(), 40 settings::timeSyncIntf, propertyTimeMode); 41 42 onPropertyChanged(propertyTimeMode, mode, true); 43 } 44 45 void Manager::onPropertyChanged(const std::string& key, 46 const std::string& value, bool forceSet) 47 { 48 assert(key == propertyTimeMode); 49 50 bool newNtpMode = (settings::ntpSync == value); 51 bool oldNtpMode = (Mode::NTP == getTimeMode()); 52 if (forceSet || (newNtpMode != oldNtpMode)) 53 { 54 // Notify listeners 55 onTimeModeChanged(value); 56 setCurrentTimeMode(value); 57 debug("NTP property changed in phosphor-settings, update to systemd" 58 " time service."); 59 } 60 else 61 { 62 debug("NTP mode is already the same, skip setting to systemd time" 63 " service again."); 64 } 65 } 66 67 int Manager::onSettingsChanged(sdbusplus::message_t& msg) 68 { 69 using Interface = std::string; 70 using Property = std::string; 71 using Value = std::string; 72 using Properties = std::map<Property, std::variant<Value>>; 73 74 Interface interface; 75 Properties properties; 76 77 msg.read(interface, properties); 78 79 for (const auto& p : properties) 80 { 81 onPropertyChanged(p.first, std::get<std::string>(p.second)); 82 } 83 84 return 0; 85 } 86 87 int Manager::onTimedateChanged(sdbusplus::message_t& msg) 88 { 89 using Properties = std::map<std::string, std::variant<std::string, bool>>; 90 91 std::string interface; 92 Properties properties; 93 94 msg.read(interface, properties); 95 96 auto iter = properties.find(propertyNtp); 97 if (iter == properties.end()) 98 { 99 return -1; 100 } 101 102 try 103 { 104 bool newNtpMode = std::get<bool>(iter->second); 105 bool oldNtpMode = (Mode::NTP == getTimeMode()); 106 if (newNtpMode != oldNtpMode) 107 { 108 const auto& timeMode = 109 newNtpMode ? settings::ntpSync : settings::manualSync; 110 std::string settingManager = utils::getService( 111 bus, settings.timeSyncMethod.c_str(), settings::timeSyncIntf); 112 utils::setProperty(bus, settingManager, settings.timeSyncMethod, 113 settings::timeSyncIntf, propertyTimeMode, 114 timeMode); 115 setCurrentTimeMode(timeMode); 116 debug("NTP property changed in systemd time service, update to" 117 " phosphor-settings."); 118 } 119 else 120 { 121 debug("NTP mode is already the same, skip setting to" 122 " phosphor-settings again."); 123 } 124 } 125 catch (const std::exception& ex) 126 { 127 error("Failed to sync NTP: {ERROR}", "ERROR", ex); 128 } 129 130 return 0; 131 } 132 133 void Manager::updateNtpSetting(const std::string& value) 134 { 135 try 136 { 137 bool isNtp = 138 (value == "xyz.openbmc_project.Time.Synchronization.Method.NTP"); 139 auto method = bus.new_method_call(systemdTimeService, systemdTimePath, 140 systemdTimeInterface, methodSetNtp); 141 method.append(isNtp, false); // isNtp: 'true/false' means Enable/Disable 142 // 'false' meaning no policy-kit 143 144 bus.call_noreply(method); 145 info("Updated NTP setting: {ENABLED}", "ENABLED", isNtp); 146 } 147 catch (const sdbusplus::exception_t& ex) 148 { 149 error("Failed to update NTP setting: {ERROR}", "ERROR", ex); 150 } 151 } 152 153 bool Manager::setCurrentTimeMode(const std::string& mode) 154 { 155 try 156 { 157 auto newMode = utils::strToMode(mode); 158 if (newMode != timeMode) 159 { 160 info("Time mode has been changed to {MODE}", "MODE", newMode); 161 timeMode = newMode; 162 return true; 163 } 164 } 165 catch (const sdbusplus::exception_t& ex) 166 { 167 error("Failed to convert mode from string: {ERROR}", "ERROR", ex); 168 } 169 170 return false; 171 } 172 173 void Manager::onTimeModeChanged(const std::string& mode) 174 { 175 // When time_mode is updated, update the NTP setting 176 updateNtpSetting(mode); 177 } 178 179 std::string Manager::getSetting(const char* path, const char* interface, 180 const char* setting) const 181 { 182 try 183 { 184 std::string settingManager = utils::getService(bus, path, interface); 185 return utils::getProperty<std::string>(bus, settingManager.c_str(), 186 path, interface, setting); 187 } 188 catch (const std::exception& ex) 189 { 190 error( 191 "Failed to get property: {ERROR}, path: {PATH}, interface: {INTERFACE}, name: {NAME}", 192 "ERROR", ex, "PATH", path, "INTERFACE", interface, "NAME", setting); 193 return {}; 194 } 195 } 196 197 } // namespace time 198 } // namespace phosphor 199