blob: 257ab3043ec73e06bb056e3a13c0cfe4a772926e [file] [log] [blame]
Vishwanatha81ee91f2016-08-30 17:17:13 +05301#include <map>
2#include <systemd/sd-bus.h>
Deepak Kodihalli41885672017-07-25 06:49:45 -05003#include <sdbusplus/bus/match.hpp>
Deepak Kodihalli20ed79e2017-07-25 05:48:58 -05004#include "settings.hpp"
Vishwanatha81ee91f2016-08-30 17:17:13 +05305
6/** @class TimeConfig
7 * @brief Maintains various time modes and time owners.
8 */
9class TimeConfig
10{
11public:
12 /** @brief Supported time modes
13 * NTP Time sourced by Network Time Server
14 * MANUAL User of the system need to set the time
15 */
16 enum class timeModes
17 {
18 NTP,
19 MANUAL
20 };
21
22 /** @brief Supported time owners
23 * BMC Time source may be NTP or MANUAL but it has to be set natively
24 * on the BMC. Meaning, host can not set the time. What it also
25 * means is that when BMC gets IPMI_SET_SEL_TIME, then its ignored.
26 * similarly, when BMC gets IPMI_GET_SEL_TIME, then the BMC's time
27 * is returned.
28 *
29 * HOST Its only IPMI_SEL_SEL_TIME that will set the time on BMC.
30 * Meaning, IPMI_GET_SEL_TIME and request to get BMC time will
31 * result in same value.
32 *
33 * SPLIT Both BMC and HOST will maintain their individual clocks but then
34 * the time information is stored in BMC. BMC can have either NTP
35 * or MANUAL as it's source of time and will set the time directly
36 * on the BMC. When IPMI_SET_SEL_TIME is received, then the delta
37 * between that and BMC's time is calculated and is stored.
38 * When BMC reads the time, the current time is returned.
39 * When IPMI_GET_SEL_TIME is received, BMC's time is retrieved and
40 * then the delta offset is factored in prior to returning.
41 *
42 * BOTH: BMC's time is set with whoever that sets the time. Similarly,
43 * BMC's time is returned to whoever that asks the time.
44 */
45 enum class timeOwners
46 {
47 BMC,
48 HOST,
49 SPLIT,
50 BOTH
51 };
52
53 // Do not have a usecase of copying this object so disable
54 TimeConfig();
55 ~TimeConfig() = default;
56 TimeConfig(const TimeConfig&) = delete;
57 TimeConfig& operator=(const TimeConfig&) = delete;
58 TimeConfig(TimeConfig&&) = delete;
59 TimeConfig& operator=(TimeConfig&&) = delete;
60
61 inline auto getCurrTimeMode() const
62 {
63 return iv_CurrTimeMode;
64 }
65
66 inline auto getCurrTimeOwner() const
67 {
68 return iv_CurrTimeOwner;
69 }
70
71 inline auto getRequestedTimeMode() const
72 {
73 return iv_RequestedTimeMode;
74 }
75
76 inline auto getRequestedTimeOwner() const
77 {
78 return iv_RequestedTimeOwner;
79 }
80
81 inline auto isSplitModeChanged() const
82 {
83 return iv_SplitModeChanged;
84 }
85
86 inline void updateSplitModeFlag(const bool& value)
87 {
88 iv_SplitModeChanged = value;
89 }
90
91 inline sd_bus* getDbus() const
92 {
93 return iv_dbus;
94 }
95
96 /** brief Generic file reader used to read time mode,
97 * time owner, host time, host offset and useDhcpNtp
98 *
99 * @param[in] filename - Name of file where data is preserved.
100 * @return - File content
101 */
102 template <typename T>
103 T readData(const char* fileName)
104 {
105 T data = T();
106 if(std::ifstream(fileName))
107 {
108 std::ifstream file(fileName, std::ios::in);
109 file >> data;
110 file.close();
111 }
112 return data;
113 }
114
115 /** @brief Generic file writer used to write time mode,
116 * time owner, host time, host offset and useDhcpNtp
117 *
118 * @param[in] filename - Name of file where data is preserved.
119 * @param[in] data - Data to be written to file
120 * @return - 0 for now. But will be changed to raising
121 * - Exception
122 */
123 template <typename T>
Patrick Williamsf0c91c02016-11-09 21:35:04 -0600124 auto writeData(const char* fileName, T&& data)
Vishwanatha81ee91f2016-08-30 17:17:13 +0530125 {
126 std::ofstream file(fileName, std::ios::out);
127 file << data;
128 file.close();
129 return 0;
130 }
131
132 /** @brief Reads saved data and populates below properties
133 * - Current Time Mode
134 * - Current Time Owner
135 * - Whether to use NTP settings given by DHCP
136 * - Last known host offset
137 *
138 * @param[in] dbus - Handler to sd_bus used by time manager
139 *
140 * @return - < 0 for failure and others for success
141 */
142 int processInitialSettings(sd_bus* dbus);
143
144 /** @brief Accepts time mode string, returns the equivalent enum
145 *
146 * @param[in] timeModeStr - Current Time Mode in string
147 *
148 * @return - Equivalent ENUM
149 * - Input : "NTP", Output: timeModes::NTP
150 */
151 static timeModes getTimeMode(const char* timeModeStr);
152
153 /** @brief Accepts timeMode enum and returns it's string equivalent
154 *
155 * @param[in] timeMode - Current Time Mode Enum
156 *
157 * @return - Equivalent string
158 * - Input : timeModes::NTP, Output : "NTP"
159 */
160 static const char* modeStr(const timeModes timeMode);
161
162 /** @brief Accepts timeOwner string and returns it's equivalent enum
163 *
164 * @param[in] timeOwnerStr - Current Time Owner in string
165 *
166 * @return - Equivalent ENUM
167 * - Input : "BMC", output : timeOwners::BMC
168 */
169 static timeOwners getTimeOwner(const char* timeOwnerStr);
170
171 /** @brief Accepts timeOwner enum and returns it's string equivalent
172 *
173 * @param[in] timeOwner - Current Time Mode Enum
174 *
175 * @return - Equivalent string
176 * - Input : timeOwners::BMC, Output : "BMC"
177 */
178 static const char* ownerStr(const timeOwners timeOwner);
179
180 /** @brief Gets called when the settings property changes.
181 * Walks the map and then applies the changes
182 *
183 * @param[in] key - Name of the property
184 * @param[in] value - Value
185 *
186 * @return - < 0 on failure, success otherwise
187 */
188 int updatePropertyVal(const char* key, const std::string& value);
189
190 // Acts on the time property changes / reads initial property
191 using READER = std::string (TimeConfig::*) (const char*);
192 using UPDATER = int (TimeConfig::*) (const std::string&);
193 using FUNCTOR = std::tuple<READER, UPDATER>;
194
195 // Most of this is statically constructed and PGOOD is added later.
196 static std::map<std::string, FUNCTOR> iv_TimeParams;
197
Deepak Kodihalli41885672017-07-25 06:49:45 -0500198 /** @brief Callback to handle change in a setting
199 *
200 * @param[in] msg - sdbusplus dbusmessage
201 *
202 * @return 0 on success, < 0 on failure.
203 */
204 int settingsChanged(sdbusplus::message::message& msg);
205
Vishwanatha81ee91f2016-08-30 17:17:13 +0530206private:
207 // Bus initialised by manager on a call to process initial settings
208 sd_bus *iv_dbus;
209
210 /** @brief 'Requested' is what is asked by user in settings
211 * 'Current' is what the TimeManager is really using since its not
212 * possible to apply the mode and owner as and when the user updates
213 * Settings. They are only applied when the system power is off.
214 */
215 timeModes iv_CurrTimeMode;
216 timeModes iv_RequestedTimeMode;
217
218 timeOwners iv_CurrTimeOwner;
219 timeOwners iv_RequestedTimeOwner;
220
221 /** @brief One of the entry in .network file indicates whether the
222 * systemd-timesyncd should use the NTP server list that are sent by DHCP
223 * server or not. If the value is 'yes', then NTP server list sent by DHCP
224 * are used. else entries that are configured statically with NTP= are used
225 */
226 std::string iv_CurrDhcpNtp;
227
228 /** @brief Dictated by state of pgood. When the pgood value is 'zero', then
229 * its an indication that we are okay to apply any pending Mode / Owner
230 * values. Meaning, Current will be updated with what is in Requested.
231 */
232 bool iv_SettingChangeAllowed;
233
234 // Needed to nudge Time Manager to reset offset
235 bool iv_SplitModeChanged;
236
Deepak Kodihalli20ed79e2017-07-25 05:48:58 -0500237 /** @brief Settings objects of intereset */
238 settings::Objects settings;
239
Deepak Kodihalli41885672017-07-25 06:49:45 -0500240 /** @brief sbdbusplus match objects */
241 std::vector<sdbusplus::bus::match_t> settingsMatches;
242
Vishwanatha81ee91f2016-08-30 17:17:13 +0530243 static constexpr auto cv_TimeModeFile = "/var/lib/obmc/saved_timeMode";
244 static constexpr auto cv_TimeOwnerFile = "/var/lib/obmc/saved_timeOwner";
245 static constexpr auto cv_DhcpNtpFile = "/var/lib/obmc/saved_dhcpNtp";
246
247 /** @brief Wrapper that looks up in the mapper service for a given
248 * object path and returns the service name
249 *
250 * @param[in] objpath - dbus object path
251 *
252 * @return - unique_ptr holding service name.
253 * - Caller needs to validate if its populated
254 */
255 std::unique_ptr<char> getProvider(const char* objPath);
256
257 /** @brief Helper function for processInitialSettings.
258 * Reads saved data and populates below properties. Only the values are
259 * read from the file system. but it will not take the action on those.
260 * Actions on these are taken by processInitialSettings
261 *
262 * - Current Time Mode
263 * - Current Time Owner
264 * - Whether to use NTP settings given by DHCP
265 * - Current Pgood state
266 *
267 * @return - < 0 for failure and success on others
268 */
269 int readPersistentData();
270
271 /** @brief Updates the 'ntp' field in systemd/timedate1,
272 * which enables / disables NTP syncing
273 *
274 * @param[in] newTimeMode - Time Mode Enum
275 *
276 * @return - < 0 on failure and success on others
277 */
278 int modifyNtpSettings(const timeModes& newTimeMode);
279
280 /** @brief Accepts system setting parameter and returns its value
281 *
282 * @param[in] key - Name of the property
283 *
284 * @return - Value as string
285 */
286 std::string getSystemSettings(const char* key);
287
Deepak Kodihalli41885672017-07-25 06:49:45 -0500288 /** @brief Returns the time owner setting
289 *
290 * @param[in] path - Time owner setting object path
291 *
292 * @return - Value as string
293 */
294 std::string getTimeOwnerSetting(const char* path);
295
296 /** @brief Returns the time sync method setting
297 *
298 * @param[in] path - Time sync method setting object path
299 *
300 * @return - Value as string
301 */
302 std::string getTimeSyncMethodSetting(const char* path);
303
Vishwanatha81ee91f2016-08-30 17:17:13 +0530304 /** @brief Reads the data hosted by /org/openbmc/control/power0
305 *
306 * @param[in] key - Name of the property
307 *
308 * @return - Value as string
309 */
310 std::string getPowerSetting(const char* key);
311
312 /** @brief Accepts Mode string and applies only if conditions allow it.
313 *
314 * @param[in] newModeStr - Requested Time Mode
315 *
316 * @return - < 0 on failure, success otherwise
317 */
318 int updateTimeMode(const std::string& newModeStr);
319
320 /** @brief Accepts Ownere string and applies only if conditions allow it.
321 *
322 * @param[in] newOwnerStr - Requested Time Owner
323 *
324 * @return - < 0 on failure, success otherwise
325 */
326
327 int updateTimeOwner(const std::string& newownerStr);
328
329 /** @brief Updates .network file with UseNtp= provided by NetworkManager
330 *
331 * @param[in] useDhcpNtp - will be 'yes' or 'no'
332 *
333 * @return - < 0 on failure, success otherwise
334 */
335 int updateNetworkSettings(const std::string& useDhcpNtp);
336
337 /** @brief Accepts current pgood value and then updates any pending mode
338 * or owner requests
339 *
340 * @param[in] useDhcpNtp - will be 'yes' or 'no'
341 *
342 * @return - < 0 on failure, success otherwise
343 */
344 int processPgoodChange(const std::string& newPgood);
345};