Vishwanatha | 81ee91f | 2016-08-30 17:17:13 +0530 | [diff] [blame] | 1 | #include <map> |
| 2 | #include <systemd/sd-bus.h> |
| 3 | |
| 4 | /** @class TimeConfig |
| 5 | * @brief Maintains various time modes and time owners. |
| 6 | */ |
| 7 | class TimeConfig |
| 8 | { |
| 9 | public: |
| 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 Williams | f0c91c0 | 2016-11-09 21:35:04 -0600 | [diff] [blame] | 122 | auto writeData(const char* fileName, T&& data) |
Vishwanatha | 81ee91f | 2016-08-30 17:17:13 +0530 | [diff] [blame] | 123 | { |
| 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 | |
| 196 | private: |
| 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 | }; |