blob: 6d6c659b51501927f6846bb4798c508bb52fcd3b [file] [log] [blame]
Lei YU415b9642017-02-09 11:37:26 +08001#include "manager.hpp"
Gunnar Millsab4cc6a2018-09-14 14:42:39 -05002
Lei YU7f4fca52017-02-23 15:15:51 +08003#include "utils.hpp"
Lei YU415b9642017-02-09 11:37:26 +08004
Lei YU86d80412017-07-12 13:12:12 +08005#include <phosphor-logging/elog-errors.hpp>
Gunnar Millsab4cc6a2018-09-14 14:42:39 -05006#include <phosphor-logging/elog.hpp>
Lei YU415b9642017-02-09 11:37:26 +08007#include <phosphor-logging/log.hpp>
Lei YU86d80412017-07-12 13:12:12 +08008#include <xyz/openbmc_project/Common/error.hpp>
Lei YUdebe1d82017-10-13 13:21:37 +08009#include <xyz/openbmc_project/State/Host/server.hpp>
Lei YU415b9642017-02-09 11:37:26 +080010
11namespace rules = sdbusplus::bus::match::rules;
12
13namespace // anonymous
14{
Lei YUdebe1d82017-10-13 13:21:37 +080015constexpr auto HOST_CURRENT_STATE = "CurrentHostState";
Lei YUa7417132017-02-23 15:24:05 +080016
17constexpr auto SYSTEMD_TIME_SERVICE = "org.freedesktop.timedate1";
18constexpr auto SYSTEMD_TIME_PATH = "/org/freedesktop/timedate1";
Lei YUdd8e9e42017-04-19 17:46:58 +080019constexpr auto SYSTEMD_TIME_INTERFACE = "org.freedesktop.timedate1";
Lei YUa7417132017-02-23 15:24:05 +080020constexpr auto METHOD_SET_NTP = "SetNTP";
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050021} // namespace
Lei YU415b9642017-02-09 11:37:26 +080022
23namespace phosphor
24{
25namespace time
26{
27
28using namespace phosphor::logging;
29
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050030const std::set<std::string> Manager::managedProperties = {PROPERTY_TIME_MODE,
31 PROPERTY_TIME_OWNER};
Lei YU415b9642017-02-09 11:37:26 +080032
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050033Manager::Manager(sdbusplus::bus::bus& bus) : bus(bus)
Lei YU415b9642017-02-09 11:37:26 +080034{
Lei YU710d49b2017-08-01 17:10:17 +080035 using namespace sdbusplus::bus::match::rules;
Lei YUdebe1d82017-10-13 13:21:37 +080036 hostStateChangeMatch =
37 std::make_unique<decltype(hostStateChangeMatch)::element_type>(
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050038 bus, propertiesChanged(settings.hostState, settings::hostStateIntf),
39 std::bind(std::mem_fn(&Manager::onHostStateChanged), this,
40 std::placeholders::_1));
Lei YU710d49b2017-08-01 17:10:17 +080041 settingsMatches.emplace_back(
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050042 bus, propertiesChanged(settings.timeOwner, settings::timeOwnerIntf),
43 std::bind(std::mem_fn(&Manager::onSettingsChanged), this,
44 std::placeholders::_1));
Lei YU710d49b2017-08-01 17:10:17 +080045 settingsMatches.emplace_back(
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050046 bus, propertiesChanged(settings.timeSyncMethod, settings::timeSyncIntf),
47 std::bind(std::mem_fn(&Manager::onSettingsChanged), this,
48 std::placeholders::_1));
Lei YU710d49b2017-08-01 17:10:17 +080049
Lei YUc6fe8692017-02-23 15:12:07 +080050 checkHostOn();
Lei YU7f4fca52017-02-23 15:15:51 +080051
52 // Restore settings from persistent storage
53 restoreSettings();
54
55 // Check the settings daemon to process the new settings
Lei YU710d49b2017-08-01 17:10:17 +080056 auto mode = getSetting(settings.timeSyncMethod.c_str(),
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050057 settings::timeSyncIntf, PROPERTY_TIME_MODE);
58 auto owner = getSetting(settings.timeOwner.c_str(), settings::timeOwnerIntf,
Lei YU710d49b2017-08-01 17:10:17 +080059 PROPERTY_TIME_OWNER);
60
61 onPropertyChanged(PROPERTY_TIME_MODE, mode);
62 onPropertyChanged(PROPERTY_TIME_OWNER, owner);
Lei YU415b9642017-02-09 11:37:26 +080063}
64
65void 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
Lei YU7f4fca52017-02-23 15:15:51 +080074void Manager::restoreSettings()
75{
76 auto mode = utils::readData<std::string>(modeFile);
77 if (!mode.empty())
78 {
Lei YUddd54422017-04-18 16:38:44 +080079 timeMode = utils::strToMode(mode);
Lei YU7f4fca52017-02-23 15:15:51 +080080 }
81 auto owner = utils::readData<std::string>(ownerFile);
82 if (!owner.empty())
83 {
Lei YUddd54422017-04-18 16:38:44 +080084 timeOwner = utils::strToOwner(owner);
Lei YU7f4fca52017-02-23 15:15:51 +080085 }
86}
87
Lei YUc6fe8692017-02-23 15:12:07 +080088void Manager::checkHostOn()
89{
Lei YUdebe1d82017-10-13 13:21:37 +080090 using Host = sdbusplus::xyz::openbmc_project::State::server::Host;
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050091 auto hostService = utils::getService(bus, settings.hostState.c_str(),
Lei YUdebe1d82017-10-13 13:21:37 +080092 settings::hostStateIntf);
Gunnar Millsab4cc6a2018-09-14 14:42:39 -050093 auto stateStr = utils::getProperty<std::string>(
94 bus, hostService.c_str(), settings.hostState.c_str(),
95 settings::hostStateIntf, HOST_CURRENT_STATE);
Lei YUdebe1d82017-10-13 13:21:37 +080096 auto state = Host::convertHostStateFromString(stateStr);
97 hostOn = (state == Host::HostState::Running);
Lei YUa7417132017-02-23 15:24:05 +080098}
Lei YUc6fe8692017-02-23 15:12:07 +080099
Lei YU415b9642017-02-09 11:37:26 +0800100void Manager::onPropertyChanged(const std::string& key,
101 const std::string& value)
102{
Lei YU7f4fca52017-02-23 15:15:51 +0800103 if (hostOn)
Lei YU415b9642017-02-09 11:37:26 +0800104 {
Lei YU7f4fca52017-02-23 15:15:51 +0800105 // If host is on, set the values as requested time mode/owner.
Gunnar Mills7f25c532017-10-25 20:45:28 -0500106 // And when host becomes off, notify the listeners.
Lei YU7f4fca52017-02-23 15:15:51 +0800107 setPropertyAsRequested(key, value);
Lei YU415b9642017-02-09 11:37:26 +0800108 }
Lei YU7f4fca52017-02-23 15:15:51 +0800109 else
Lei YU415b9642017-02-09 11:37:26 +0800110 {
Gunnar Mills7f25c532017-10-25 20:45:28 -0500111 // If host is off, notify listeners
Lei YU7f4fca52017-02-23 15:15:51 +0800112 if (key == PROPERTY_TIME_MODE)
Lei YU415b9642017-02-09 11:37:26 +0800113 {
Lei YU7f4fca52017-02-23 15:15:51 +0800114 setCurrentTimeMode(value);
Lei YUa5003ce2017-02-24 15:35:25 +0800115 onTimeModeChanged(value);
Lei YU7f4fca52017-02-23 15:15:51 +0800116 }
117 else if (key == PROPERTY_TIME_OWNER)
118 {
119 setCurrentTimeOwner(value);
Lei YUa5003ce2017-02-24 15:35:25 +0800120 onTimeOwnerChanged();
Lei YU415b9642017-02-09 11:37:26 +0800121 }
122 }
123}
124
Lei YU710d49b2017-08-01 17:10:17 +0800125int 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
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500137 for (const auto& p : properties)
Lei YU710d49b2017-08-01 17:10:17 +0800138 {
139 onPropertyChanged(p.first, p.second.get<std::string>());
140 }
141
142 return 0;
143}
144
Lei YU7f4fca52017-02-23 15:15:51 +0800145void 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
Lei YU86d80412017-07-12 13:12:12 +0800159 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()));
Lei YU7f4fca52017-02-23 15:15:51 +0800165 }
166}
167
168void Manager::setRequestedMode(const std::string& mode)
169{
170 requestedMode = mode;
171}
172
173void Manager::setRequestedOwner(const std::string& owner)
174{
175 requestedOwner = owner;
176}
177
Lei YUa7417132017-02-23 15:24:05 +0800178void Manager::updateNtpSetting(const std::string& value)
179{
Lei YU710d49b2017-08-01 17:10:17 +0800180 bool isNtp =
181 (value == "xyz.openbmc_project.Time.Synchronization.Method.NTP");
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500182 auto method = bus.new_method_call(SYSTEMD_TIME_SERVICE, SYSTEMD_TIME_PATH,
183 SYSTEMD_TIME_INTERFACE, METHOD_SET_NTP);
Lei YUa7417132017-02-23 15:24:05 +0800184 method.append(isNtp, false); // isNtp: 'true/false' means Enable/Disable
185 // 'false' meaning no policy-kit
186
Lei YU89efe6e2018-07-24 10:38:01 +0800187 try
Lei YUa7417132017-02-23 15:24:05 +0800188 {
Lei YU89efe6e2018-07-24 10:38:01 +0800189 bus.call_noreply(method);
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500190 log<level::INFO>("Updated NTP setting", entry("ENABLED=%d", isNtp));
Lei YUa7417132017-02-23 15:24:05 +0800191 }
Lei YU89efe6e2018-07-24 10:38:01 +0800192 catch (const sdbusplus::exception::SdBusError& ex)
Lei YUa7417132017-02-23 15:24:05 +0800193 {
Lei YU89efe6e2018-07-24 10:38:01 +0800194 log<level::ERR>("Failed to update NTP setting",
195 entry("ERR=%s", ex.what()));
Lei YUa7417132017-02-23 15:24:05 +0800196 }
197}
198
Lei YUdebe1d82017-10-13 13:21:37 +0800199void Manager::onHostStateChanged(sdbusplus::message::message& msg)
Lei YUc6fe8692017-02-23 15:12:07 +0800200{
Lei YUdebe1d82017-10-13 13:21:37 +0800201 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
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500212 for (const auto& p : properties)
Lei YUdebe1d82017-10-13 13:21:37 +0800213 {
214 if (p.first == HOST_CURRENT_STATE)
215 {
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500216 auto state =
217 Host::convertHostStateFromString(p.second.get<std::string>());
Lei YUdebe1d82017-10-13 13:21:37 +0800218 onHostState(state == Host::HostState::Running);
219 break;
220 }
221 }
222}
223
224void Manager::onHostState(bool on)
225{
226 hostOn = on;
Lei YU7f4fca52017-02-23 15:15:51 +0800227 if (hostOn)
228 {
Lei YUdebe1d82017-10-13 13:21:37 +0800229 log<level::INFO>("Changing time settings is *deferred* now");
Lei YU7f4fca52017-02-23 15:15:51 +0800230 return;
231 }
Lei YUdebe1d82017-10-13 13:21:37 +0800232 log<level::INFO>("Changing time settings allowed now");
Lei YU7f4fca52017-02-23 15:15:51 +0800233 if (!requestedMode.empty())
234 {
Lei YUa5003ce2017-02-24 15:35:25 +0800235 if (setCurrentTimeMode(requestedMode))
Lei YU7f4fca52017-02-23 15:15:51 +0800236 {
Lei YUa5003ce2017-02-24 15:35:25 +0800237 onTimeModeChanged(requestedMode);
Lei YU7f4fca52017-02-23 15:15:51 +0800238 }
239 setRequestedMode({}); // Clear requested mode
240 }
241 if (!requestedOwner.empty())
242 {
Lei YUa5003ce2017-02-24 15:35:25 +0800243 if (setCurrentTimeOwner(requestedOwner))
Lei YU7f4fca52017-02-23 15:15:51 +0800244 {
Lei YUa5003ce2017-02-24 15:35:25 +0800245 onTimeOwnerChanged();
Lei YU7f4fca52017-02-23 15:15:51 +0800246 }
247 setRequestedOwner({}); // Clear requested owner
248 }
Lei YUc6fe8692017-02-23 15:12:07 +0800249}
250
Lei YUa5003ce2017-02-24 15:35:25 +0800251bool Manager::setCurrentTimeMode(const std::string& mode)
Lei YU415b9642017-02-09 11:37:26 +0800252{
Lei YUddd54422017-04-18 16:38:44 +0800253 auto newMode = utils::strToMode(mode);
Lei YUa5003ce2017-02-24 15:35:25 +0800254 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 }
Lei YU415b9642017-02-09 11:37:26 +0800266}
267
Lei YUa5003ce2017-02-24 15:35:25 +0800268bool Manager::setCurrentTimeOwner(const std::string& owner)
Lei YU415b9642017-02-09 11:37:26 +0800269{
Lei YUddd54422017-04-18 16:38:44 +0800270 auto newOwner = utils::strToOwner(owner);
Lei YUa5003ce2017-02-24 15:35:25 +0800271 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
285void 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
295void Manager::onTimeOwnerChanged()
296{
297 for (const auto& listener : listeners)
298 {
299 listener->onOwnerChanged(timeOwner);
300 }
Lei YU415b9642017-02-09 11:37:26 +0800301}
302
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500303std::string Manager::getSetting(const char* path, const char* interface,
Lei YU710d49b2017-08-01 17:10:17 +0800304 const char* setting) const
305{
306 std::string settingManager = utils::getService(bus, path, interface);
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500307 return utils::getProperty<std::string>(bus, settingManager.c_str(), path,
308 interface, setting);
Lei YU710d49b2017-08-01 17:10:17 +0800309}
310
Gunnar Millsab4cc6a2018-09-14 14:42:39 -0500311} // namespace time
312} // namespace phosphor