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
Manager(sdbusplus::bus_t & bus)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
onPropertyChanged(const std::string & key,const std::string & value,bool forceSet)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
onSettingsChanged(sdbusplus::message_t & msg)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
onTimedateChanged(sdbusplus::message_t & msg)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
updateNtpSetting(const std::string & value)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
setCurrentTimeMode(const std::string & mode)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
onTimeModeChanged(const std::string & mode)173 void Manager::onTimeModeChanged(const std::string& mode)
174 {
175 // When time_mode is updated, update the NTP setting
176 updateNtpSetting(mode);
177 }
178
getSetting(const char * path,const char * interface,const char * setting) const179 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