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