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