diff options
author | Lei YU <mine260309@gmail.com> | 2017-02-27 14:30:35 +0800 |
---|---|---|
committer | Lei YU <mine260309@gmail.com> | 2017-10-16 20:40:04 +0800 |
commit | 91910e604cf5d779da2da1241a38f155017e3bfe (patch) | |
tree | ac0ceb0c853ba5bd6ad588b7c0e6ee805a249649 | |
parent | a5003ceb4425ebd4b2f71d3478027e8fa75d4860 (diff) | |
download | phosphor-time-manager-91910e604cf5d779da2da1241a38f155017e3bfe.tar.gz phosphor-time-manager-91910e604cf5d779da2da1241a38f155017e3bfe.zip |
Remove unused legacy files
Change-Id: Ieb667636963722d54dba93850dd0e3396e1e83c1
Signed-off-by: Lei YU <mine260309@gmail.com>
-rw-r--r-- | time-config.cpp | 726 | ||||
-rw-r--r-- | time-config.hpp | 345 | ||||
-rw-r--r-- | time-manager.cpp | 838 | ||||
-rw-r--r-- | time-manager.hpp | 306 | ||||
-rw-r--r-- | time-register.c | 25 | ||||
-rw-r--r-- | time-register.hpp | 17 |
6 files changed, 0 insertions, 2257 deletions
diff --git a/time-config.cpp b/time-config.cpp deleted file mode 100644 index 416ffc9..0000000 --- a/time-config.cpp +++ /dev/null @@ -1,726 +0,0 @@ -#include <cstdlib> -#include <fstream> -#include <iostream> -#include <memory> -#include <mapper.h> -#include <cassert> -#include <cctype> -#include <algorithm> -#include <phosphor-logging/log.hpp> -#include <phosphor-logging/elog-errors.hpp> -#include <xyz/openbmc_project/Common/error.hpp> -#include "time-manager.hpp" - -using namespace phosphor::logging; -using namespace sdbusplus::xyz::openbmc_project::Common::Error; - -std::map<std::string, TimeConfig::FUNCTOR> TimeConfig::iv_TimeParams = { - // TODO via openbmc/openbmc#668 - openbmc/openbmc#1770 is still work in - // progress at the time of writing this, so the use_dhcp_ntp is still using - // the old org.openbmc settings interfaces. The whole of time manager is - // anyway being rewritten to use new xyz.openbmc_project interfaces; as part - // of that switching to new setting interfaces is also covered. - { "use_dhcp_ntp", std::make_tuple(&TimeConfig::getSystemSettings, - &TimeConfig::updateNetworkSettings) - } -}; - -namespace internal -{ -namespace setting -{ - -/** @brief Convert d-bus enum string to native string. For eg, convert - * "xyz.openbmc_project.Time.Owner.Split" to "SPLIT". - * - * @param[in] value - setting enum string - * - * @return converted string - */ -inline auto dbusToNative(std::string&& value) -{ - auto setting = std::move(value); - auto index = setting.find_last_of('.') + 1; - setting = setting.substr(index, setting.length() - index); - std::transform(setting.begin(), setting.end(), setting.begin(), - [](unsigned char c){ return std::toupper(c); }); - return setting; -} - -} // namespace setting -} // namespace internal - -TimeConfig::TimeConfig() : - iv_dbus(nullptr), - iv_CurrTimeMode(timeModes::MANUAL), - iv_RequestedTimeMode(timeModes::MANUAL), - iv_CurrTimeOwner(timeOwners::BOTH), - iv_RequestedTimeOwner(timeOwners::BOTH), - iv_CurrDhcpNtp("yes"), - iv_SettingChangeAllowed(false), - iv_SplitModeChanged(false) -{ - // Not really having anything to do here. -} - -// Given a mode string, returns it's equivalent mode enum -TimeConfig::timeModes TimeConfig::getTimeMode(const char* timeMode) -{ - // We are forcing the values to be in specific case and range - if (!strcmp(timeMode,"NTP")) - { - return timeModes::NTP; - } - else - { - return timeModes::MANUAL; - } -} - -// Accepts a timeMode enum and returns it's string value -const char* TimeConfig::modeStr(TimeConfig::timeModes timeMode) -{ - switch(timeMode) - { - case timeModes::NTP: - { - return "NTP"; - } - case timeModes::MANUAL: - { - return "MANUAL"; - } - } - - assert(false); - return nullptr; -} - -// Given a owner string, returns it's equivalent owner enum -TimeConfig::timeOwners TimeConfig::getTimeOwner(const char* timeOwner) -{ - if (!strcmp(timeOwner,"BMC")) - { - return timeOwners::BMC; - } - else if (!strcmp(timeOwner,"HOST")) - { - return timeOwners::HOST; - } - else if (!strcmp(timeOwner,"SPLIT")) - { - return timeOwners::SPLIT; - } - else - { - return timeOwners::BOTH; - } -} - -// Accepts a timeOwner enum and returns it's string value -const char* TimeConfig::ownerStr(timeOwners timeOwner) -{ - switch(timeOwner) - { - case timeOwners::BMC: - { - return "BMC"; - } - case timeOwners::HOST: - { - return "HOST"; - } - case timeOwners::SPLIT: - { - return "SPLIT"; - } - case timeOwners::BOTH: - { - return "BOTH"; - } - } - - assert(false); - return nullptr; -} - -// Returns the busname that hosts objPath -std::unique_ptr<char> TimeConfig::getProvider(const char* objPath) -{ - char *provider = nullptr; - mapper_get_service(iv_dbus, objPath, &provider); - return std::unique_ptr<char>(provider); -} - -// Accepts a settings name and returns its value. -// for the variant of type 'string' now. -std::string TimeConfig::getSystemSettings(const char* key) -{ - constexpr auto settingsObj = "/org/openbmc/settings/host0"; - constexpr auto propertyIntf = "org.freedesktop.DBus.Properties"; - constexpr auto hostIntf = "org.openbmc.settings.Host"; - - const char* value = nullptr; - std::string settingsVal {}; - sd_bus_message* reply = nullptr; - - std::cout <<"Getting System Settings: " << key << std::endl; - - // Get the provider from object mapper - auto settingsProvider = getProvider(settingsObj); - if (!settingsProvider) - { - std::cerr << "Error Getting service for Settings" << std::endl; - return value; - } - - auto r = sd_bus_call_method(iv_dbus, - settingsProvider.get(), - settingsObj, - propertyIntf, - "Get", - nullptr, - &reply, - "ss", - hostIntf, - key); - if (r < 0) - { - std::cerr <<"Error" << strerror(-r) - <<" reading system settings" << std::endl; - goto finish; - } - - r = sd_bus_message_read(reply, "v", "s", &value); - if (r < 0) - { - std::cerr <<"Error " << strerror(-r) - <<" parsing settings data" << std::endl; - } -finish: - if (value) - { - settingsVal.assign(value); - } - reply = sd_bus_message_unref(reply); - return settingsVal; -} - -// Reads value from /org/openbmc/control/power0 -// This signature on purpose to plug into time parameter map -std::string TimeConfig::getPowerSetting(const char* key) -{ - constexpr auto powerObj = "/org/openbmc/control/power0"; - constexpr auto powerIntf = "org.openbmc.control.Power"; - constexpr auto propertyIntf = "org.freedesktop.DBus.Properties"; - - int value = -1; - std::string powerValue {}; - sd_bus_message* reply = nullptr; - - std::cout <<"Reading Power Control key: " << key << std::endl; - - // Get the provider from object mapper - auto powerProvider = getProvider(powerObj); - if (!powerProvider) - { - std::cerr <<" Error getting provider for Power Settings" << std::endl; - return powerValue; - } - - auto r = sd_bus_call_method(iv_dbus, - powerProvider.get(), - powerObj, - propertyIntf, - "Get", - nullptr, - &reply, - "ss", - powerIntf, - key); - if (r < 0) - { - std::cerr <<"Error " << strerror(-r) - << "reading: " << key << std::endl; - goto finish; - } - - r = sd_bus_message_read(reply, "v", "i", &value); - if (r < 0) - { - std::cerr <<"Error " << strerror(-r) - <<" parsing " << key << "value" << std::endl; - // For maintenance - goto finish; - } -finish: - if (value != -1) - { - powerValue = std::to_string(value); - } - reply = sd_bus_message_unref(reply); - return powerValue; -} - -// Updates .network file with UseNtp= -int TimeConfig::updateNetworkSettings(const std::string& useDhcpNtp) -{ - constexpr auto networkObj = "/org/openbmc/NetworkManager/Interface"; - constexpr auto networkIntf = "org.openbmc.NetworkManager"; - - std::cout << "use_dhcp_ntp = " << useDhcpNtp.c_str() << std::endl; - - // If what we have already is what it is, then just return. - if (iv_CurrDhcpNtp == useDhcpNtp) - { - return 0; - } - - // Get the provider from object mapper - auto networkProvider = getProvider(networkObj); - if (!networkProvider) - { - return -1; - } - - auto r = sd_bus_call_method(iv_dbus, - networkProvider.get(), - networkObj, - networkIntf, - "UpdateUseNtpField", - nullptr, - nullptr, - "s", - useDhcpNtp.c_str()); - if (r < 0) - { - std::cerr <<"Error " << strerror(-r) - << " updating UseNtp" << std::endl; - } - else - { - std::cout <<"Successfully updated UseNtp=[" - << useDhcpNtp << "]" << std::endl; - - r = writeData(cv_DhcpNtpFile, useDhcpNtp); - } - - return 0; -} - -// Reads the values from 'settingsd' and applies: -// 1) Time Mode -// 2) time Owner -// 3) UseNTP setting -// 4) Pgood -int TimeConfig::processInitialSettings(sd_bus* dbus) -{ - // First call from TimeManager to config manager - iv_dbus = dbus; - - auto timeOwnerFunctor = std::make_tuple(&TimeConfig::getTimeOwnerSetting, - &TimeConfig::updateTimeOwner); - iv_TimeParams.emplace(settings.timeOwner, std::move(timeOwnerFunctor)); - auto timeSyncFunctor = std::make_tuple( - &TimeConfig::getTimeSyncMethodSetting, - &TimeConfig::updateTimeMode); - iv_TimeParams.emplace(settings.timeSyncMethod, std::move(timeSyncFunctor)); - - using namespace sdbusplus::bus::match::rules; - sdbusplus::bus::bus bus(iv_dbus); - - settingsMatches.emplace_back( - bus, - propertiesChanged(settings.timeOwner, settings::timeOwnerIntf), - std::bind(std::mem_fn(&TimeConfig::settingsChanged), - this, std::placeholders::_1)); - - settingsMatches.emplace_back( - bus, - propertiesChanged(settings.timeSyncMethod, settings::timeSyncIntf), - std::bind(std::mem_fn(&TimeConfig::settingsChanged), - this, std::placeholders::_1)); - - // Read saved info like Who was the owner , what was the mode, - // what was the use_dhcp_ntp setting before etc.. - auto r = readPersistentData(); - if (r < 0) - { - std::cerr << "Error reading the data saved in flash." - << std::endl; - return r; - } - - // Now read whats in settings and apply if allowed. - for (auto& iter : iv_TimeParams) - { - // Get the settings value for various keys. - auto reader = std::get<READER>(iter.second); - auto value = (this->*reader)(iter.first.c_str()); - if (!value.empty()) - { - // Get the value for the key and validate. - auto updater = std::get<UPDATER>(iter.second); - auto r = (this->*updater)(value); - if (r < 0) - { - std::cerr << "Error setting up initial keys" << std::endl; - return r; - } - } - else - { - std::cerr << "key " << iter.first - <<" has no value: " << std::endl; - return -1; - } - } - - // Now that we have taken care of consuming, push this as well - // so that we can use the same map for handling pgood change too. - auto readerUpdater = std::make_tuple(&TimeConfig::getPowerSetting, - &TimeConfig::processPgoodChange); - iv_TimeParams.emplace("pgood", readerUpdater); - - return 0; -} - -// This is called by Property Change handler on the event of -// receiving notification on property value change. -int TimeConfig::updatePropertyVal(const char* key, const std::string& value) -{ - auto iter = iv_TimeParams.find(key); - if (iter != iv_TimeParams.end()) - { - auto updater = std::get<UPDATER>(iter->second); - return (this->*updater)(value); - } - // Coming here indicates that we never had a matching key. - return -1; -} - -// Called by sd_event when Properties are changed in Control/power0 -// Interested in change to 'pgood' -int TimeConfig::processPgoodChange(const std::string& newPgood) -{ - // Indicating that we are safe to apply any changes - if (!newPgood.compare("0")) - { - iv_SettingChangeAllowed = true; - std::cout <<"Changing time settings allowed now" << std::endl; - } - else - { - iv_SettingChangeAllowed = false; - std::cout <<"Changing time settings is *deferred* now" << std::endl; - } - - // if we have had users that changed the time settings - // when we were not ready yet, do it now. - if (iv_RequestedTimeOwner != iv_CurrTimeOwner) - { - auto r = updateTimeOwner(ownerStr(iv_RequestedTimeOwner)); - if (r < 0) - { - std::cerr << "Error updating new time owner" << std::endl; - return r; - } - std::cout << "New Owner is : " - << ownerStr(iv_RequestedTimeOwner) << std::endl; - } - - if (iv_RequestedTimeMode != iv_CurrTimeMode) - { - auto r = updateTimeMode(modeStr(iv_RequestedTimeMode)); - if (r < 0) - { - std::cerr << "Error updating new time mode" << std::endl; - return r; - } - std::cout <<"New Mode is : " - << modeStr(iv_RequestedTimeMode) << std::endl; - } - return 0; -} - -// Manipulates time owner if the system setting allows it -int TimeConfig::updateTimeMode(const std::string& newModeStr) -{ - auto r = 0; - iv_RequestedTimeMode = getTimeMode(newModeStr.c_str()); - - std::cout <<"Requested_Mode: " << newModeStr - << " Current_Mode: " << modeStr(iv_CurrTimeMode) - << std::endl; - - if (iv_RequestedTimeMode == iv_CurrTimeMode) - { - std::cout << "Mode is already set to : " - << newModeStr << std::endl; - return 0; - } - - // Also, if the time owner is HOST, then we should not allow NTP. - // However, it may so happen that there are 2 pending requests, one for - // changing to NTP and other for changing owner to something not HOST. - // So check if there is a pending timeOwner change and if so, allow NTP - // if the current is HOST and requested is non HOST. - if (iv_CurrTimeOwner == timeOwners::HOST && - iv_RequestedTimeOwner == timeOwners::HOST && - iv_RequestedTimeMode == timeModes::NTP) - { - std::cout <<"Can not set mode to NTP with HOST as owner" - << std::endl; - return 0; - } - - if (iv_SettingChangeAllowed) - { - r = modifyNtpSettings(iv_RequestedTimeMode); - if (r < 0) - { - std::cerr << "Error changing TimeMode settings" - << std::endl; - } - else - { - iv_CurrTimeMode = iv_RequestedTimeMode; - } - std::cout << "Current_Mode changed to: " - << newModeStr << " :: " << modeStr(iv_CurrTimeMode) << std::endl; - - // Need this when we either restart or come back from reset - r = writeData(cv_TimeModeFile, modeStr(iv_CurrTimeMode)); - } - else - { - std::cout <<"Deferring update until system state allows it" - << std::endl; - } - return r; -} - -// Manipulates time owner if the system setting allows it -int TimeConfig::updateTimeOwner(const std::string& newOwnerStr) -{ - int r = 0; - iv_RequestedTimeOwner = getTimeOwner(newOwnerStr.c_str()); - - // Needed when owner changes to HOST - std::string manualMode = "Manual"; - - // Needed by time manager to do some house keeping - iv_SplitModeChanged = false; - - if (iv_RequestedTimeOwner == iv_CurrTimeOwner) - { - std::cout <<"Owner is already set to : " - << newOwnerStr << std::endl; - return 0; - } - - std::cout <<"Requested_Owner: " << newOwnerStr - << " Current_Owner: " << ownerStr(iv_CurrTimeOwner) - << std::endl; - - if (iv_SettingChangeAllowed) - { - // If we are transitioning from SPLIT to something else, - // reset the host offset. - if (iv_CurrTimeOwner == timeOwners::SPLIT && - iv_RequestedTimeOwner != timeOwners::SPLIT) - { - // Needed by time manager to do some house keeping - iv_SplitModeChanged = true; - } - iv_CurrTimeOwner = iv_RequestedTimeOwner; - std::cout << "Current_Owner is now: " - << newOwnerStr << std::endl; - - // HOST and NTP are exclusive - if (iv_CurrTimeOwner == timeOwners::HOST) - { - std::cout <<"Forcing the mode to MANUAL" << std::endl; - r = updateTimeMode(manualMode); - if (r < 0) - { - std::cerr << "Error forcing the mode to MANUAL" << std::endl; - return r; - } - } - // Need this when we either restart or come back from reset - r = writeData(cv_TimeOwnerFile, ownerStr(iv_CurrTimeOwner)); - } - else - { - std::cout <<"Deferring update until system state allows it" - << std::endl; - } - - return r; -} - -// Accepts the time mode and makes necessary changes to timedate1 -int TimeConfig::modifyNtpSettings(const timeModes& newTimeMode) -{ - auto ntpChangeOp = 0; - - // Pass '1' -or- '0' to SetNTP method indicating Enable/Disable - ntpChangeOp = (newTimeMode == timeModes::NTP) ? 1 : 0; - - std::cout <<"Applying NTP setting..." << std::endl; - - auto r = sd_bus_call_method(iv_dbus, - "org.freedesktop.timedate1", - "/org/freedesktop/timedate1", - "org.freedesktop.timedate1", - "SetNTP", - nullptr, - nullptr, // timedate1 does not return response - "bb", - ntpChangeOp, // '1' means Enable - 0); // '0' meaning no policy-kit - if (r < 0) - { - std::cerr <<"Error: " << strerror(-r) - << "changing time Mode" << std::endl; - } - else - { - std::cout << "SUCCESS. NTP setting is now: " << - ((ntpChangeOp) ? "Enabled" : "Disabled"); - - // TODO : https://github.com/openbmc/phosphor-time-manager/issues/1 - if (ntpChangeOp) - { - r = system("systemctl restart systemd-timesyncd &"); - } - else - { - r = system("systemctl stop systemd-timesyncd &"); - } - } - return r; -} - -// Reads all the saved data from the last run -int TimeConfig::readPersistentData() -{ - // If we are coming back from a reset reload, then need to - // read what was the last successful Mode and Owner. - auto savedTimeMode = readData<std::string>(cv_TimeModeFile); - if (!savedTimeMode.empty()) - { - iv_CurrTimeMode = getTimeMode(savedTimeMode.c_str()); - std::cout <<"Last known time_mode: " - << savedTimeMode.c_str() << std::endl; - } - - auto savedTimeOwner = readData<std::string>(cv_TimeOwnerFile); - if (!savedTimeOwner.empty()) - { - iv_CurrTimeOwner = getTimeOwner(savedTimeOwner.c_str()); - std::cout <<"Last known time_owner: " - << savedTimeOwner.c_str() << std::endl; - } - - auto savedDhcpNtp = readData<std::string>(cv_DhcpNtpFile); - if (!savedDhcpNtp.empty()) - { - iv_CurrDhcpNtp = savedDhcpNtp; - std::cout <<"Last known use_dhcp_ntp: " - << iv_CurrDhcpNtp.c_str() << std::endl; - } - else - { - // This seems to be the first time. - std::cerr <<"Empty DhcpNtp string" << std::endl; - iv_CurrDhcpNtp = "yes"; - } - - // Doing this here to make sure 'pgood' is read and handled - // first before anything. - auto pgood = getPowerSetting("pgood"); - if (!pgood.compare("0")) - { - std::cout << "Changing settings *allowed* now" << std::endl; - iv_SettingChangeAllowed = true; - } - return 0; -} - -std::string TimeConfig::getTimeOwnerSetting(const char* path) -{ - sdbusplus::bus::bus bus{iv_dbus}; - auto method = bus.new_method_call( - settings.service(settings.timeOwner, - settings::timeOwnerIntf).c_str(), - path, - "org.freedesktop.DBus.Properties", - "Get"); - method.append(settings::timeOwnerIntf, "TimeOwner"); - auto reply = bus.call(method); - if (reply.is_method_error()) - { - log<level::ERR>("Error in TimeOwner Get"); - elog<InternalFailure>(); - } - - sdbusplus::message::variant<std::string> result; - reply.read(result); - // TODO via openbmc/openbmc#668 - because the old org.openbmc settings - // interfaces defined the time settings as strings, the code in this file - // is based around that fact. We use enums in the new settings interfaces, - // so code in this file can be changed to work with enums instead. That's - // being covered by the time manager rework (#668). For now, converting the - // settings to the string format that this object expects it to be. - // For eg, convert "xyz.openbmc_project.Time.Owner.Split" to "SPLIT". - auto setting = result.get<std::string>(); - return internal::setting::dbusToNative(std::move(setting)); -} - -std::string TimeConfig::getTimeSyncMethodSetting(const char* path) -{ - sdbusplus::bus::bus bus{iv_dbus}; - auto method = bus.new_method_call( - settings.service(settings.timeSyncMethod, - settings::timeSyncIntf).c_str(), - path, - "org.freedesktop.DBus.Properties", - "Get"); - method.append(settings::timeSyncIntf, "TimeSyncMethod"); - auto reply = bus.call(method); - if (reply.is_method_error()) - { - log<level::ERR>("Error in TimeSyncMethod Get"); - elog<InternalFailure>(); - } - - sdbusplus::message::variant<std::string> result; - reply.read(result); - auto setting = result.get<std::string>(); - return internal::setting::dbusToNative(std::move(setting)); -} - -int TimeConfig::settingsChanged(sdbusplus::message::message& msg) -{ - using Interface = std::string; - using Property = std::string; - using Value = std::string; - using Properties = std::map<Property, sdbusplus::message::variant<Value>>; - - Interface interface; - Properties properties; - - msg.read(interface, properties); - - auto path = msg.get_path(); - for(const auto& p : properties) - { - auto setting = p.second.get<std::string>(); - updatePropertyVal(path, - internal::setting::dbusToNative(std::move(setting))); - } - - return 0; -} diff --git a/time-config.hpp b/time-config.hpp deleted file mode 100644 index 257ab30..0000000 --- a/time-config.hpp +++ /dev/null @@ -1,345 +0,0 @@ -#include <map> -#include <systemd/sd-bus.h> -#include <sdbusplus/bus/match.hpp> -#include "settings.hpp" - -/** @class TimeConfig - * @brief Maintains various time modes and time owners. - */ -class TimeConfig -{ -public: - /** @brief Supported time modes - * NTP Time sourced by Network Time Server - * MANUAL User of the system need to set the time - */ - enum class timeModes - { - NTP, - MANUAL - }; - - /** @brief Supported time owners - * BMC Time source may be NTP or MANUAL but it has to be set natively - * on the BMC. Meaning, host can not set the time. What it also - * means is that when BMC gets IPMI_SET_SEL_TIME, then its ignored. - * similarly, when BMC gets IPMI_GET_SEL_TIME, then the BMC's time - * is returned. - * - * HOST Its only IPMI_SEL_SEL_TIME that will set the time on BMC. - * Meaning, IPMI_GET_SEL_TIME and request to get BMC time will - * result in same value. - * - * SPLIT Both BMC and HOST will maintain their individual clocks but then - * the time information is stored in BMC. BMC can have either NTP - * or MANUAL as it's source of time and will set the time directly - * on the BMC. When IPMI_SET_SEL_TIME is received, then the delta - * between that and BMC's time is calculated and is stored. - * When BMC reads the time, the current time is returned. - * When IPMI_GET_SEL_TIME is received, BMC's time is retrieved and - * then the delta offset is factored in prior to returning. - * - * BOTH: BMC's time is set with whoever that sets the time. Similarly, - * BMC's time is returned to whoever that asks the time. - */ - enum class timeOwners - { - BMC, - HOST, - SPLIT, - BOTH - }; - - // Do not have a usecase of copying this object so disable - TimeConfig(); - ~TimeConfig() = default; - TimeConfig(const TimeConfig&) = delete; - TimeConfig& operator=(const TimeConfig&) = delete; - TimeConfig(TimeConfig&&) = delete; - TimeConfig& operator=(TimeConfig&&) = delete; - - inline auto getCurrTimeMode() const - { - return iv_CurrTimeMode; - } - - inline auto getCurrTimeOwner() const - { - return iv_CurrTimeOwner; - } - - inline auto getRequestedTimeMode() const - { - return iv_RequestedTimeMode; - } - - inline auto getRequestedTimeOwner() const - { - return iv_RequestedTimeOwner; - } - - inline auto isSplitModeChanged() const - { - return iv_SplitModeChanged; - } - - inline void updateSplitModeFlag(const bool& value) - { - iv_SplitModeChanged = value; - } - - inline sd_bus* getDbus() const - { - return iv_dbus; - } - - /** brief Generic file reader used to read time mode, - * time owner, host time, host offset and useDhcpNtp - * - * @param[in] filename - Name of file where data is preserved. - * @return - File content - */ - template <typename T> - T readData(const char* fileName) - { - T data = T(); - if(std::ifstream(fileName)) - { - std::ifstream file(fileName, std::ios::in); - file >> data; - file.close(); - } - return data; - } - - /** @brief Generic file writer used to write time mode, - * time owner, host time, host offset and useDhcpNtp - * - * @param[in] filename - Name of file where data is preserved. - * @param[in] data - Data to be written to file - * @return - 0 for now. But will be changed to raising - * - Exception - */ - template <typename T> - auto writeData(const char* fileName, T&& data) - { - std::ofstream file(fileName, std::ios::out); - file << data; - file.close(); - return 0; - } - - /** @brief Reads saved data and populates below properties - * - Current Time Mode - * - Current Time Owner - * - Whether to use NTP settings given by DHCP - * - Last known host offset - * - * @param[in] dbus - Handler to sd_bus used by time manager - * - * @return - < 0 for failure and others for success - */ - int processInitialSettings(sd_bus* dbus); - - /** @brief Accepts time mode string, returns the equivalent enum - * - * @param[in] timeModeStr - Current Time Mode in string - * - * @return - Equivalent ENUM - * - Input : "NTP", Output: timeModes::NTP - */ - static timeModes getTimeMode(const char* timeModeStr); - - /** @brief Accepts timeMode enum and returns it's string equivalent - * - * @param[in] timeMode - Current Time Mode Enum - * - * @return - Equivalent string - * - Input : timeModes::NTP, Output : "NTP" - */ - static const char* modeStr(const timeModes timeMode); - - /** @brief Accepts timeOwner string and returns it's equivalent enum - * - * @param[in] timeOwnerStr - Current Time Owner in string - * - * @return - Equivalent ENUM - * - Input : "BMC", output : timeOwners::BMC - */ - static timeOwners getTimeOwner(const char* timeOwnerStr); - - /** @brief Accepts timeOwner enum and returns it's string equivalent - * - * @param[in] timeOwner - Current Time Mode Enum - * - * @return - Equivalent string - * - Input : timeOwners::BMC, Output : "BMC" - */ - static const char* ownerStr(const timeOwners timeOwner); - - /** @brief Gets called when the settings property changes. - * Walks the map and then applies the changes - * - * @param[in] key - Name of the property - * @param[in] value - Value - * - * @return - < 0 on failure, success otherwise - */ - int updatePropertyVal(const char* key, const std::string& value); - - // Acts on the time property changes / reads initial property - using READER = std::string (TimeConfig::*) (const char*); - using UPDATER = int (TimeConfig::*) (const std::string&); - using FUNCTOR = std::tuple<READER, UPDATER>; - - // Most of this is statically constructed and PGOOD is added later. - static std::map<std::string, FUNCTOR> iv_TimeParams; - - /** @brief Callback to handle change in a setting - * - * @param[in] msg - sdbusplus dbusmessage - * - * @return 0 on success, < 0 on failure. - */ - int settingsChanged(sdbusplus::message::message& msg); - -private: - // Bus initialised by manager on a call to process initial settings - sd_bus *iv_dbus; - - /** @brief 'Requested' is what is asked by user in settings - * 'Current' is what the TimeManager is really using since its not - * possible to apply the mode and owner as and when the user updates - * Settings. They are only applied when the system power is off. - */ - timeModes iv_CurrTimeMode; - timeModes iv_RequestedTimeMode; - - timeOwners iv_CurrTimeOwner; - timeOwners iv_RequestedTimeOwner; - - /** @brief One of the entry in .network file indicates whether the - * systemd-timesyncd should use the NTP server list that are sent by DHCP - * server or not. If the value is 'yes', then NTP server list sent by DHCP - * are used. else entries that are configured statically with NTP= are used - */ - std::string iv_CurrDhcpNtp; - - /** @brief Dictated by state of pgood. When the pgood value is 'zero', then - * its an indication that we are okay to apply any pending Mode / Owner - * values. Meaning, Current will be updated with what is in Requested. - */ - bool iv_SettingChangeAllowed; - - // Needed to nudge Time Manager to reset offset - bool iv_SplitModeChanged; - - /** @brief Settings objects of intereset */ - settings::Objects settings; - - /** @brief sbdbusplus match objects */ - std::vector<sdbusplus::bus::match_t> settingsMatches; - - static constexpr auto cv_TimeModeFile = "/var/lib/obmc/saved_timeMode"; - static constexpr auto cv_TimeOwnerFile = "/var/lib/obmc/saved_timeOwner"; - static constexpr auto cv_DhcpNtpFile = "/var/lib/obmc/saved_dhcpNtp"; - - /** @brief Wrapper that looks up in the mapper service for a given - * object path and returns the service name - * - * @param[in] objpath - dbus object path - * - * @return - unique_ptr holding service name. - * - Caller needs to validate if its populated - */ - std::unique_ptr<char> getProvider(const char* objPath); - - /** @brief Helper function for processInitialSettings. - * Reads saved data and populates below properties. Only the values are - * read from the file system. but it will not take the action on those. - * Actions on these are taken by processInitialSettings - * - * - Current Time Mode - * - Current Time Owner - * - Whether to use NTP settings given by DHCP - * - Current Pgood state - * - * @return - < 0 for failure and success on others - */ - int readPersistentData(); - - /** @brief Updates the 'ntp' field in systemd/timedate1, - * which enables / disables NTP syncing - * - * @param[in] newTimeMode - Time Mode Enum - * - * @return - < 0 on failure and success on others - */ - int modifyNtpSettings(const timeModes& newTimeMode); - - /** @brief Accepts system setting parameter and returns its value - * - * @param[in] key - Name of the property - * - * @return - Value as string - */ - std::string getSystemSettings(const char* key); - - /** @brief Returns the time owner setting - * - * @param[in] path - Time owner setting object path - * - * @return - Value as string - */ - std::string getTimeOwnerSetting(const char* path); - - /** @brief Returns the time sync method setting - * - * @param[in] path - Time sync method setting object path - * - * @return - Value as string - */ - std::string getTimeSyncMethodSetting(const char* path); - - /** @brief Reads the data hosted by /org/openbmc/control/power0 - * - * @param[in] key - Name of the property - * - * @return - Value as string - */ - std::string getPowerSetting(const char* key); - - /** @brief Accepts Mode string and applies only if conditions allow it. - * - * @param[in] newModeStr - Requested Time Mode - * - * @return - < 0 on failure, success otherwise - */ - int updateTimeMode(const std::string& newModeStr); - - /** @brief Accepts Ownere string and applies only if conditions allow it. - * - * @param[in] newOwnerStr - Requested Time Owner - * - * @return - < 0 on failure, success otherwise - */ - - int updateTimeOwner(const std::string& newownerStr); - - /** @brief Updates .network file with UseNtp= provided by NetworkManager - * - * @param[in] useDhcpNtp - will be 'yes' or 'no' - * - * @return - < 0 on failure, success otherwise - */ - int updateNetworkSettings(const std::string& useDhcpNtp); - - /** @brief Accepts current pgood value and then updates any pending mode - * or owner requests - * - * @param[in] useDhcpNtp - will be 'yes' or 'no' - * - * @return - < 0 on failure, success otherwise - */ - int processPgoodChange(const std::string& newPgood); -}; diff --git a/time-manager.cpp b/time-manager.cpp deleted file mode 100644 index d0e7113..0000000 --- a/time-manager.cpp +++ /dev/null @@ -1,838 +0,0 @@ -#define _XOPEN_SOURCE -#include <chrono> -#include <sstream> -#include <iostream> -#include <iomanip> -#include <array> -#include <unistd.h> -#include <assert.h> -#include <sys/timerfd.h> -#include <systemd/sd-event.h> -#include <systemd/sd-bus.h> -#include <systemd/sd-daemon.h> -#include "time-register.hpp" -#include "time-manager.hpp" - -// Neeed to do this since its not exported outside of the kernel. -// Refer : https://gist.github.com/lethean/446cea944b7441228298 -#ifndef TFD_TIMER_CANCEL_ON_SET -#define TFD_TIMER_CANCEL_ON_SET (1 << 1) -#endif - -// Needed to make sure timerfd does not misfire eventhough we set CANCEL_ON_SET -#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) - -// Used in time-register.c -extern sd_bus_vtable timeServicesVtable[]; - -Time::Time(const TimeConfig& timeConfig) : config(timeConfig) -{ - // Nothing to do here -} - -BmcTime::BmcTime(const TimeConfig& timeConfig) : Time(timeConfig) -{ - // Nothing to do here -} - -HostTime::HostTime(const TimeConfig& timeConfig, - const std::chrono::microseconds& hostOffset) - : Time(timeConfig), - iv_Offset(hostOffset) -{ - // Nothing to do here -} - -TimeManager::TimeManager() : - iv_HostOffset(std::chrono::microseconds(0)), - iv_UptimeUsec(std::chrono::microseconds(0)), - iv_EventSource(nullptr), - iv_Event(nullptr) -{ - assert(setupTimeManager() >= 0); -} - -// Needed to be standalone extern "C" to register -// as a callback routine with sd_bus_vtable -int GetTime(sd_bus_message* m, void* userdata, - sd_bus_error* retError) -{ - auto tmgr = static_cast<TimeManager*>(userdata); - return tmgr->getTime(m, userdata, retError); -} - -int SetTime(sd_bus_message* m, void* userdata, - sd_bus_error* retError) -{ - auto tmgr = static_cast<TimeManager*>(userdata); - return tmgr->setTime(m, userdata, retError); -} - -// Property reader -int getCurrTimeModeProperty(sd_bus* bus, const char* path, - const char* interface, const char* property, - sd_bus_message* m, void* userdata, - sd_bus_error* error) -{ - auto tmgr = static_cast<TimeManager*>(userdata); - return sd_bus_message_append(m, "s", - TimeConfig::modeStr(tmgr->config.getCurrTimeMode())); -} - -int getCurrTimeOwnerProperty(sd_bus* bus, const char* path, - const char* interface, const char* property, - sd_bus_message* m, void* userdata, - sd_bus_error* error) -{ - auto tmgr = static_cast<TimeManager*>(userdata); - return sd_bus_message_append(m, "s", - TimeConfig::ownerStr(tmgr->config.getCurrTimeOwner())); -} - -int getReqTimeModeProperty(sd_bus* bus, const char* path, - const char* interface, const char* property, - sd_bus_message* m, void* userdata, - sd_bus_error* error) -{ - auto tmgr = static_cast<TimeManager*>(userdata); - return sd_bus_message_append(m, "s", - TimeConfig::modeStr(tmgr->config.getRequestedTimeMode())); -} - -int getReqTimeOwnerProperty(sd_bus* bus, const char* path, - const char* interface, const char* property, - sd_bus_message* m, void* userdata, - sd_bus_error* error) -{ - auto tmgr = static_cast<TimeManager*>(userdata); - return sd_bus_message_append(m, "s", - TimeConfig::ownerStr(tmgr->config.getRequestedTimeOwner())); -} - -int TimeManager::getTime(sd_bus_message* m, void* userdata, - sd_bus_error* retError) -{ - const char* target = nullptr; - - // Extract the target and call respective GetTime - auto r = sd_bus_message_read(m, "s", &target); - if (r < 0) - { - std::cerr << "Error:" << strerror(-r) - <<" reading user time" << std::endl; - *retError = SD_BUS_ERROR_MAKE_CONST( - SD_BUS_ERROR_IO_ERROR, "Error reading input"); - - return sd_bus_reply_method_error(m, retError); - } - - if (!strcasecmp(target, "bmc")) - { - auto time = BmcTime(config); - return time.getTime(m, retError); - } - else if (!strcasecmp(target, "host")) - { - auto time = HostTime(config, iv_HostOffset); - return time.getTime(m, retError); - } - else - { - std::cerr << "Error:" << strerror(-r) - <<" Invalid Target" << std::endl; - *retError = SD_BUS_ERROR_MAKE_CONST( - SD_BUS_ERROR_IO_ERROR, "Valid targets are BMC or HOST"); - - return sd_bus_reply_method_error(m, retError); - } -} - -int TimeManager::setTime(sd_bus_message* m, void* userdata, - sd_bus_error* retError) -{ - const char* target = nullptr; - auto r = sd_bus_message_read(m, "s", &target); - if (r < 0) - { - std::cerr << "Error:" << strerror(-r) - <<" reading user time" << std::endl; - *retError = SD_BUS_ERROR_MAKE_CONST( - SD_BUS_ERROR_IO_ERROR, "Error reading input"); - - return sd_bus_reply_method_error(m, retError); - } - - if (!strcasecmp(target, "bmc")) - { - auto time = BmcTime(config); - auto r = time.setTime(m, retError); - if (r < 0) - { - // This would have the error populated - return sd_bus_reply_method_error(m, retError); - } - } - else if (!strcasecmp(target, "host")) - { - auto time = HostTime(config, iv_HostOffset); - - auto r = time.setTime(m, retError); - if (r < 0) - { - // This would have the error populated - return sd_bus_reply_method_error(m, retError); - } - - if (config.getCurrTimeOwner() == TimeConfig::timeOwners::SPLIT) - { - iv_HostOffset = time.getChangedOffset(); - r = config.writeData(cv_HostOffsetFile, iv_HostOffset.count()); - if (r < 0) - { - // probably does not make sense to crash on these.. - // The next NTP sync will set things right. - std::cerr << "Error saving host_offset: " - << iv_HostOffset.count() << std::endl; - } - } - } - return sd_bus_reply_method_return(m, "i", 0); -} - -int Time::setTimeOfDay(const std::chrono::microseconds& timeOfDayUsec, - sd_bus_error *retError) -{ - // These 2 are for bypassing some policy - // checking in the timedate1 service - auto relative = false; - auto interactive = false; - - return sd_bus_call_method(config.getDbus(), - "org.freedesktop.timedate1", - "/org/freedesktop/timedate1", - "org.freedesktop.timedate1", - "SetTime", - retError, - nullptr, // timedate1 does not return response - "xbb", - (int64_t)timeOfDayUsec.count(), //newTimeUsec, - relative, // Time in absolute seconds since epoch - interactive); // bypass polkit checks -} - -// Common routine for BMC and HOST Get Time operations -std::chrono::microseconds Time::getBaseTime() -{ - auto currBmcTime = std::chrono::system_clock::now(); - return std::chrono::duration_cast<std::chrono::microseconds> - (currBmcTime.time_since_epoch()); -} - -// Accepts the time in microseconds and converts to Human readable format. -std::string Time::convertToStr(const std::chrono::microseconds& timeInUsec) -{ - using namespace std::chrono; - - // Convert this to number of seconds; - auto timeInSec = duration_cast<seconds>(microseconds(timeInUsec)); - auto time_T = static_cast<std::time_t>(timeInSec.count()); - - std::ostringstream timeFormat {}; - timeFormat << std::put_time(std::gmtime(&time_T), "%c %Z"); - - auto timeStr = timeFormat.str(); - std::cout << timeStr.c_str() << std::endl; - return timeStr; -} - -// Reads timeofday and returns time string -// and also number of microseconds. -// Ex : Tue Aug 16 22:49:43 2016 -int BmcTime::getTime(sd_bus_message *m, sd_bus_error *retError) -{ - std::cout << "Request to get BMC time: "; - - // Get BMC time - auto timeInUsec = getBaseTime(); - auto timeStr = convertToStr(timeInUsec); - return sd_bus_reply_method_return( - m, "sx", timeStr.c_str(), (uint64_t)timeInUsec.count()); -} - -// Designated to be called by IPMI_GET_SEL time from host -int HostTime::getTime(sd_bus_message *m, sd_bus_error *retError) -{ - using namespace std::chrono; - - std::cout << "Request to get HOST time" << std::endl; - - // Get BMC time and add Host's offset - // Referencing the iv_hostOffset of TimeManager object - auto timeInUsec = getBaseTime(); - auto hostTime = timeInUsec.count() + iv_Offset.count(); - - auto timeStr = convertToStr(duration_cast<microseconds> - (microseconds(hostTime))); - - std::cout << " Host_time_str: [ " << timeStr - << " ] host_time usec: [ " << hostTime - << " ] host_offset: [ " << iv_Offset.count() - << " ] " << std::endl; - - return sd_bus_reply_method_return(m, "sx", timeStr.c_str(), - (uint64_t)hostTime); - return 0; -} - -// Gets the time string and verifies if it conforms to format %Y-%m-%d %H:%M:%S -// and then sets the BMC time. If the input time string does not conform to the -// format, an error message is returned. -int BmcTime::setTime(sd_bus_message *m, sd_bus_error *retError) -{ - tm userTm {}; - const char* userTimeStr = nullptr; - - std::cout << "Request to set BMC time" << std::endl; - - std::cout << "Curr_Mode: " << TimeConfig::modeStr(config.getCurrTimeMode()) - << " Curr_Owner: " << TimeConfig::ownerStr(config.getCurrTimeOwner()) - << std::endl; - - if(config.getCurrTimeOwner() == TimeConfig::timeOwners::HOST) - { - std::cerr << "Can not set time. Owner is HOST" << std::endl; - *retError = SD_BUS_ERROR_MAKE_CONST( - SD_BUS_ERROR_FAILED, "Current owner is HOST"); - - return -1; - } - - auto r = sd_bus_message_read(m, "s", &userTimeStr); - if (r < 0) - { - std::cerr << "Error:" << strerror(-r) - <<" reading user time" << std::endl; - *retError = SD_BUS_ERROR_MAKE_CONST( - SD_BUS_ERROR_IO_ERROR, "Error reading input"); - return r; - } - - std::cout <<" BMC TIME : " << userTimeStr << std::endl; - - // Convert the time string into tm structure - std::istringstream timeString {}; - timeString.str(userTimeStr); - timeString >> std::get_time(&userTm, "%Y-%m-%d %H:%M:%S"); - if (timeString.fail()) - { - std::cerr << "Error: Incorrect time format" << std::endl; - *retError = SD_BUS_ERROR_MAKE_CONST( - SD_BUS_ERROR_INVALID_ARGS, "Incorrect time format"); - return -1; - } - - // Convert the time structure into number of - // seconds maintained in GMT. Followed the same that is in - // systemd/timedate1 - auto timeOfDay = timegm(&userTm); - if (timeOfDay < 0) - { - std::cerr <<"Error converting tm to seconds" << std::endl; - *retError = SD_BUS_ERROR_MAKE_CONST( - SD_BUS_ERROR_FAILED, "Error converting tm to seconds"); - return -1; - } - - // Set REALTIME and also update hwclock - auto timeInUsec = std::chrono::microseconds( - std::chrono::seconds(timeOfDay)); - return setTimeOfDay(timeInUsec, retError); -} - -// Gets the time string from IPMI ( which is currently in seconds since epoch ) -// and then sets the BMC time / adjusts the offset depending on current owner -// policy. -int HostTime::setTime(sd_bus_message *m, sd_bus_error *retError) -{ - using namespace std::chrono; - - std::cout << "Request to SET Host time" << std::endl; - - std::cout << "Curr_Mode: " << TimeConfig::modeStr(config.getCurrTimeMode()) - << "Curr_Owner: " << TimeConfig::ownerStr(config.getCurrTimeOwner()) - << "host_offset: " << iv_Offset.count() << std::endl; - - if (config.getCurrTimeOwner() == TimeConfig::timeOwners::BMC) - { - *retError = SD_BUS_ERROR_MAKE_CONST( - SD_BUS_ERROR_FAILED, "Current Owner is BMC"); - return -1; - } - - const char* newHostTime = nullptr; - auto r = sd_bus_message_read(m, "s", &newHostTime); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - << "reading host time" << std::endl; - *retError = SD_BUS_ERROR_MAKE_CONST( - SD_BUS_ERROR_IO_ERROR, "Error reading input"); - return -1; - } - - // We need to convert the string input to decimal. - auto hostTimeSec = std::stol(std::string(newHostTime)); - - // And then to microseconds - auto hostTimeUsec = duration_cast<microseconds>(seconds(hostTimeSec)); - std::cout << "setHostTime: HostTimeInUSec: " - << hostTimeUsec.count() << std::endl; - - if (config.getCurrTimeOwner() == TimeConfig::timeOwners::SPLIT) - { - // Adjust the host offset - auto bmcTimeUsec = duration_cast<microseconds> - (system_clock::now().time_since_epoch()); - - // We are not doing any time settings in BMC - std::cout << "Updated: host_time: [ " << hostTimeUsec.count() - << " ] host_offset: [ " << iv_Offset.count() - << " ] " << std::endl; - - // Communicate the offset back to manager to update needed. - changedOffset = hostTimeUsec - bmcTimeUsec; - - return 0; - } - - // We are okay to update time in as long as BMC is not the owner - return setTimeOfDay(hostTimeUsec, retError); -} - -// Gets called into by sd_event on an activity seen on sd_bus -int TimeManager::processSdBusMessage(sd_event_source* es, int fd, - uint32_t revents, void* userdata) -{ - auto tmgr = static_cast<TimeManager*>(userdata); - auto r = sd_bus_process(tmgr->getTimeBus(), nullptr); - if (r < 0) - { - std::cerr <<"Error: " << strerror(-r) - <<" processing sd_bus message:" << std::endl; - } - return r; -} - -// Gets called into by sd_event on any time SET event -int TimeManager::processTimeChange(sd_event_source* es, int fd, - uint32_t revents, void* userdata) -{ - using namespace std::chrono; - std::cout << "BMC time changed" << std::endl; - - auto tmgr = static_cast<TimeManager*>(userdata); - - std::array<char, 64> time {}; - - // We are not interested in the data here. Need to read time again . - // So read until there is something here in the FD - while (read(fd, time.data(), time.max_size()) > 0); - - std::cout <<" Curr_Mode: " << TimeConfig::modeStr(tmgr->config.getCurrTimeMode()) - << " Curr_Owner : " << TimeConfig::ownerStr(tmgr->config.getCurrTimeOwner()) - << " Host_Offset: " << tmgr->getHostOffset().count() << std::endl; - - // Read the current BMC time and adjust the - // host time offset if the mode is SPLIT - if (tmgr->config.getCurrTimeOwner() == TimeConfig::timeOwners::SPLIT) - { - // Delta between REAL and Monotonic. - auto uptimeUsec = duration_cast<microseconds> - (system_clock::now().time_since_epoch() - - steady_clock::now().time_since_epoch()); - - auto deltaTimeUsec = uptimeUsec - tmgr->getUptimeUsec(); - - // If the BMC time goes backwards, then - of - will handle that. - auto newHostOffset = tmgr->getHostOffset() - deltaTimeUsec; - tmgr->updateHostOffset(newHostOffset); - - std::cout << " UPDATED HOST_OFFSET: " - << tmgr->getHostOffset().count() << std::endl; - tmgr->updateUptimeUsec(uptimeUsec); - - // Persist this - auto r = tmgr->config.writeData(TimeManager::cv_HostOffsetFile, - tmgr->getHostOffset().count()); - if (r < 0) - { - std::cerr << "Error saving host_offset: " - << tmgr->getHostOffset().count() << std::endl; - return r; - } - std::cout << " Updated: Host_Offset: " - << tmgr->getHostOffset().count() << std::endl; - } - return 0; -} - -// Resets iv_HostOffset. Needed when we move away from SPLIT. -int TimeManager::resetHostOffset() -{ - iv_HostOffset = std::chrono::microseconds(0); - auto r = config.writeData(cv_HostOffsetFile, iv_HostOffset.count()); - config.updateSplitModeFlag(false); - return r; -} - -// Called by sd_event when Pgood is changed in Power -int TimeManager::processPgoodChange(sd_bus_message* m, void* userdata, - sd_bus_error* retError) -{ - auto tmgr = static_cast<TimeManager*>(userdata); - const char* key = nullptr; - - auto newPgood = -1; - auto r = 0; - - std::cout <<" PGOOD has changed.." << std::endl; - - // input data is "sa{sv}as" and we are just interested in a{sv} - r = sd_bus_message_skip(m, "s"); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) << - "skipping interface name in data" << std::endl; - return r; - } - - r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - <<"entering the dictionary" << std::endl; - return r; - } - - while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, - "sv")) > 0) - { - r = sd_bus_message_read(m, "s", &key); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - <<" reading the key from dict" << std::endl; - // Can not continue here since the next - // enter would result in error anyway - return r; - } - - if (!strcmp(key, "pgood")) - { - r = sd_bus_message_read(m, "v", "i", &newPgood); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - << "reading pgood" << std::endl; - return r; - } - r = tmgr->config.updatePropertyVal(key, std::to_string(newPgood)); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - << "processing pgood" << std::endl; - return r; - } - } - else - { - sd_bus_message_skip(m, "v"); - } - } - return 0; -} - -// Called by sd_event when Properties are changed in settingsd. -// Interested in changes to 'timeMode', 'timeOwner' and 'use_dhcp_ntp' -int TimeManager::processPropertyChange(sd_bus_message* m, void* userdata, - sd_bus_error* retError) -{ - auto tmgr = static_cast<TimeManager*>(userdata); - const char* key = nullptr; - const char* value = nullptr; - auto r = 0; - - std::cout <<" User Settings have changed.." << std::endl; - - // input data is "sa{sv}as" and we are just interested in a{sv} - r = sd_bus_message_skip(m, "s"); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) << - "skipping interface name in data" << std::endl; - goto finish; - } - - r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - <<"entering the dictionary" << std::endl; - goto finish; - } - - while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, - "sv")) > 0) - { - r = sd_bus_message_read(m, "s", &key); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - <<" reading the key from dict" << std::endl; - // Can not continue here since the next - // enter would result in error anyway - goto finish; - } - - if (!strcmp(key, "use_dhcp_ntp")) - { - r = sd_bus_message_read(m, "v", "s", &value); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - <<"reading use_dhcp_ntp" << std::endl; - goto finish; - } - r = tmgr->config.updatePropertyVal(key, value); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - << "processing dhcp_ntp" << std::endl; - goto finish; - } - } - else - { - sd_bus_message_skip(m, "v"); - } - } -finish: - return r; -} - -// Sets up callback handlers for activities on : -// 1) user request on SD_BUS -// 2) Time change -// 3) Settings change -// 4) System state change; -int TimeManager::registerCallbackHandlers() -{ - constexpr auto WATCH_SETTING_CHANGE = - "type='signal',interface='org.freedesktop.DBus.Properties'," - "path='/org/openbmc/settings/host0',member='PropertiesChanged'"; - - constexpr auto WATCH_PGOOD_CHANGE = - "type='signal',interface='org.freedesktop.DBus.Properties'," - "path='/org/openbmc/control/power0',member='PropertiesChanged'"; - - // Extract the descriptor out of sd_bus construct. - auto sdBusFd = sd_bus_get_fd(iv_TimeBus); - - auto r = sd_event_add_io(iv_Event, &iv_EventSource, sdBusFd, EPOLLIN, - processSdBusMessage, this); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - <<" adding sd_bus_message handler" << std::endl; - return r; - } - - // Choose the MAX time that is possible to aviod mis fires. - itimerspec maxTime {}; - maxTime.it_value.tv_sec = TIME_T_MAX; - - auto timeFd = timerfd_create(CLOCK_REALTIME, 0); - if (timeFd < 0) - { - std::cerr << "Errorno: " << errno << " creating timerfd" << std::endl; - return -1; - } - - r = timerfd_settime(timeFd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, - &maxTime, nullptr); - if (r) - { - std::cerr << "Errorno: " << errno << "Setting timerfd" << std::endl; - return -1; - } - - // Wake me up *only* if someone SETS the time - r = sd_event_add_io(iv_Event, &iv_EventSource, timeFd, EPOLLIN, - processTimeChange, this); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - << "adding time_change handler" << std::endl; - return r; - } - - // Watch for property changes in settingsd - r = sd_bus_add_match(iv_TimeBus, NULL, WATCH_SETTING_CHANGE, - processPropertyChange, this); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - <<" adding property change listener" << std::endl; - return r; - } - - // Watch for state change. Only reliable one to count on is - // state of [pgood]. value of [1] meaning host is powering on / powered - // on. [0] means powered off. - r = sd_bus_add_match(iv_TimeBus, NULL, WATCH_PGOOD_CHANGE, - processPgoodChange, this); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - << " adding pgood change listener" << std::endl; - } - return r; -} - -int TimeManager::setupTimeManager() -{ - auto r = sd_bus_default_system(&iv_TimeBus); - if (r < 0) - { - std::cerr << "Error" << strerror(-r) - <<" connecting to system bus" << std::endl; - goto finish; - } - - r = sd_bus_add_object_manager(iv_TimeBus, NULL, cv_ObjPath); - if (r < 0) - { - std::cerr << "Error" << strerror(-r) - <<" adding object manager" << std::endl; - goto finish; - } - - std::cout <<"Registering dbus methods" << std::endl; - r = sd_bus_add_object_vtable(iv_TimeBus, - NULL, - cv_ObjPath, - cv_BusName, - timeServicesVtable, - this); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - <<" adding timer services vtable" << std::endl; - goto finish; - } - - // create a sd_event object and add handlers - r = sd_event_default(&iv_Event); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - <<"creating an sd_event" << std::endl; - goto finish; - } - - // Handlers called by sd_event when an activity - // is observed in event loop - r = registerCallbackHandlers(); - if (r < 0) - { - std::cerr << "Error setting up callback handlers" << std::endl; - goto finish; - } - - // Need to do this here since TimeConfig may update the necessary owners - r = config.processInitialSettings(iv_TimeBus); - if (r < 0) - { - std::cerr << "Error setting up configuration params" << std::endl; - goto finish; - } - - // Read saved values from previous run - r = readPersistentData(); - if (r < 0) - { - std::cerr << "Error reading persistent data" << std::endl; - goto finish; - } - - // Claim the bus - r = sd_bus_request_name(iv_TimeBus, cv_BusName, 0); - if (r < 0) - { - std::cerr << "Error: " << strerror(-r) - << "acquiring service name" << std::endl; - goto finish; - } -finish: - if (r < 0) - { - iv_EventSource = sd_event_source_unref(iv_EventSource); - iv_Event = sd_event_unref(iv_Event); - } - return r; -} - -int TimeManager::readPersistentData() -{ - using namespace std::chrono; - - // Get current host_offset - // When we reach here, TimeConfig would have been populated and would have - // applied the owner to SPLIT *if* the system allowed it. So check if we - // moved away from SPLIT and if so, make offset:0 - if (config.isSplitModeChanged()) - { - iv_HostOffset = microseconds(0); - auto r = config.writeData(cv_HostOffsetFile, iv_HostOffset.count()); - if (r < 0) - { - std::cerr <<" Error saving offset to file" << std::endl; - return r; - } - } - else - { - auto hostTimeOffset = config.readData<long long int>(cv_HostOffsetFile); - iv_HostOffset = microseconds(hostTimeOffset); - std::cout <<"Last known host_offset:" << hostTimeOffset << std::endl; - } - - //How long was the FSP up prior to 'this' start - iv_UptimeUsec = duration_cast<microseconds> - (system_clock::now().time_since_epoch() - - steady_clock::now().time_since_epoch()); - if (iv_UptimeUsec.count() < 0) - { - std::cerr <<"Error reading uptime" << std::endl; - return -1; - } - std::cout <<"Initial Uptime Usec: " - << iv_UptimeUsec.count() << std::endl; - return 0; -} - -// Forever loop -int TimeManager::waitForClientRequest() -{ - return sd_event_loop(iv_Event); -} - -int main(int argc, char* argv[]) -{ - auto tmgr = std::make_unique<TimeManager>(); - - // Wait for the work - auto r = tmgr->waitForClientRequest(); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/time-manager.hpp b/time-manager.hpp deleted file mode 100644 index 23560a4..0000000 --- a/time-manager.hpp +++ /dev/null @@ -1,306 +0,0 @@ -#include <systemd/sd-bus.h> -#include <fstream> -#include <string> -#include <chrono> -#include "time-config.hpp" - -/** @class Time - * @brief Base class catering to common data needed by implementations - */ -class Time -{ -public: - /** @brief Takes time in microseconds and uses systemd/timedated - * to set the system time - * - * @param[in] timeOfDayUsec - Time value in microseconds - * @param[out] retError - Error message on failure - * @return - Status of time set operation - * @error - Error message populated - */ - int setTimeOfDay(const std::chrono::microseconds& timeOfDayUsec, - sd_bus_error *retError); - - /** @brief Reads BMC time - * - * @param[in] - None - * @return - time read in microseconds - */ - std::chrono::microseconds getBaseTime(); - - /** @brief Converts microseconds to human readable time value - * - * @param[in] timeInUsec - Time value in microseconds - * @return - Time converted to human readable format - */ - std::string convertToStr(const std::chrono::microseconds& timeInUsec); - - /** @brief Reference to config information due to need of policy data */ - const TimeConfig& config; - - /** Needed to access configuration variables */ - Time(const TimeConfig&); - -private: - Time(); -}; - -/** @class BmcTime - * @brief Provides time Set and time Get operations for BMC target - */ -class BmcTime: public Time -{ -public: - /** @brief Called when the time is to be read on BMC - * - * @param[in] m - sd_bus message. - * @param[out] retError - Error reporting structure - * @return - On no error, time read which is specified in - * microseonds and also in human readable format. - * - * - On error, retError populated - */ - int getTime(sd_bus_message* m, sd_bus_error* retError); - - /** @brief Called when the time is to be set on BMC - * - * @param[in] m - sd_bus message encapsulating time string - * @param[out] retError - Error reporting structure - * @return - On no error, 0, -1 otherwise or retError thrown - */ - int setTime(sd_bus_message* m, sd_bus_error* retError); - - /** @brief constructor */ - BmcTime(const TimeConfig&); - -private: - BmcTime(); -}; - -/** @class HostTime - * @brief Provides time Set and time Get operations for BMC target - */ -class HostTime: public Time -{ -public: - /** @brief Called when IPMI_GET_SEL_TIME is called - * - * @param[in] m - sd_bus message. - * @param[out] retError - Error reporting structure - * @return - On no error, time read which is specified in - * microseonds and also in human readable format. - * - * - On error, retError populated - */ - int getTime(sd_bus_message*, sd_bus_error*); - - /** @brief Called when the IPMI_SET_SEL_TIME is called - * - * @param[in] m - sd_bus message encapsulating time in seconds - * @param[out] retError - Error reporting structure - * @return - On no error, 0, -1 otherwise or retError thrown - */ - int setTime(sd_bus_message*, sd_bus_error*); - - /** @brief constructor */ - HostTime(const TimeConfig&, const std::chrono::microseconds&); - - /** @brief When the owner is SPLIT, the delta between HOST's time and BMC's - * time needs to be saved and this function returns current delta. - * - * @param[in] - None - * @return - offset in microseconds - */ - inline std::chrono::microseconds getChangedOffset() const - { - return changedOffset; - } - - /** @brief Reference to host's offset in case of SPLIT owner */ - const std::chrono::microseconds& iv_Offset; - -private: - HostTime(); - - /** @brief The delta offset of Host and BMC time */ - std::chrono::microseconds changedOffset; -}; - -/** @class TimeManager - * @brief Caters to client requests with Set and Get time and configuration - * changes - */ -class TimeManager -{ -public: - // Do not have a usecase of copying this object so disable - TimeManager(); - ~TimeManager() = default; - TimeManager(const TimeManager&) = delete; - TimeManager& operator=(const TimeManager&) = delete; - TimeManager(TimeManager&&) = delete; - TimeManager& operator=(TimeManager&&) = delete; - - // Maintains *all* the config that is needed for TimeManager. - TimeConfig config; - - /** @brief Callback handlers invoked by dbus on GetTime client requests - * - * @param[in] m - sd_bus message encapsulating the time target - * @param[in] userdata - context that is filled while registering this - * @param[out] retError - Error reporting mechanism - * - * @return - On no error, time in microseconds and human - * readable string. retError otherwise. - */ - int getTime(sd_bus_message* m, void* userdata, sd_bus_error* retError); - - /** @brief Callback handlers invoked by dbus on SetTime client requests - * - * @param[in] m - sd_bus message encapsulating the time target and - * time value either in string or in seconds. - * @param[in] userdata - client context that is filled while registering - * @param[out] retError - Error reporting mechanism - * - * @return - On no error, time in microseconds and human - * readable string. retError otherwise. - */ - int setTime(sd_bus_message* m, void* userdata, sd_bus_error* retError); - - /** @brief sd_event callback handlers on the requests coming in dbus - * These are actually GetTime and SetTime requests - * - * @param[in] es - Event Structure - * @param[in] fd - file descriptor that had 'read' activity - * @param[in] revents - generic linux style return event - * @param[in] userdata - Client context filled while registering - * - * @return - 0 for success, failure otherwise. - */ - static int processSdBusMessage(sd_event_source* es, int fd, - uint32_t revents, void* userdata); - - /** @brief sd_event callback handler called whenever there is a - * time change event indicated by timerfd expiring. This happens - * whenever the time is set on BMC by any source. - * - * @param[in] es - Event Structure - * @param[in] fd - file descriptor that had 'read' activity - * @param[in] revents - generic linux style return event - * @param[in] userdata - Client context filled while registering - * - * @return - 0 for success, failure otherwise. - */ - static int processTimeChange(sd_event_source* es, int fd, - uint32_t revents, void* userdata); - - /** @brief sd_event callback handler called whenever a settings - * property is changed. - * This gets called into whenever "time_mode", "time_owner", - * "use_dhcp_ntp" properties are changed - * - * @param[in] es - Event Structure - * @param[in] fd - file descriptor that had 'read' activity - * @param[in] revents - generic linux style return event - * @param[in] userdata - Client context filled while registering - * - * @return - 0 for success, failure otherwise. - */ - static int processPropertyChange(sd_bus_message*, - void*,sd_bus_error*); - - /** @brief sd_event callback handler called whenever Pgood property is - * changed - * - * @param[in] es - Event Structure - * @param[in] fd - file descriptor that had 'read' activity - * @param[in] revents - generic linux style return event - * @param[in] userdata - Client context filled while registering - * - * @return - 0 for success, failure otherwise. - */ - static int processPgoodChange(sd_bus_message*, - void*,sd_bus_error*); - - /** @brief registers callsback handlers for sd_event loop - * - * @param[in] - None - * @return - 0 if everything goes well, -1 otherwise - */ - int registerCallbackHandlers(); - - /** @brief Makes the Delta between Host and BMC time as 'ZERO'. This - * essentially only means that time owner was SPLIT before - * and now changed to something else. - * - * @param[in] - None - * @return - 0 if everything goes well, -1 otherwise. - */ - int resetHostOffset(); - - /** @brief Reads what was the last delta offset stored in file - * - * @param[in] - None - * @return - 0 if everything goes well, -1 otherwise. - */ - int readPersistentData(); - - /** @brief waits on sd_events loop for client requests - * - * @param[in] - None - * @return - 0 if everything goes well, -1 otherwise. - */ - int waitForClientRequest(); - - inline auto getHostOffset() const - { - return iv_HostOffset; - } - - inline auto updateHostOffset(const std::chrono::microseconds& newOffset) - { - iv_HostOffset = newOffset; - } - - inline auto getUptimeUsec() const - { - return iv_UptimeUsec; - } - - inline auto updateUptimeUsec(const std::chrono::microseconds& newUpTime) - { - iv_UptimeUsec = newUpTime; - } - - inline sd_bus* getTimeBus() const - { - return iv_TimeBus; - } - -private: - // What was the last known host offset. - std::chrono::microseconds iv_HostOffset; - - // How long was the BMC up for prior to this boot - std::chrono::microseconds iv_UptimeUsec; - - // Used for registering sd_bus callback handlers. - sd_event_source* iv_EventSource; - sd_event* iv_Event; - sd_bus* iv_TimeBus; - - // Dbus communication enablers. - static constexpr auto cv_BusName = "org.openbmc.TimeManager"; - static constexpr auto cv_ObjPath = "/org/openbmc/TimeManager"; - static constexpr auto cv_IntfName = "org.openbmc.TimeManager"; - - // Store the offset in File System. Read back when TimeManager starts. - static constexpr auto cv_HostOffsetFile = "/var/lib/obmc/saved_host_offset"; - - /** @brief Sets up internal data structures and callback handler at startup - * - * @param[in] - None - * @return - 0 if everything goes well, -1 otherwise - */ - int setupTimeManager(void); -}; diff --git a/time-register.c b/time-register.c deleted file mode 100644 index cdc1dd2..0000000 --- a/time-register.c +++ /dev/null @@ -1,25 +0,0 @@ -#include <systemd/sd-bus.h> -#include "time-register.hpp" -#include <sys/timerfd.h> -#include <errno.h> -#include <stdio.h> - -/* Function pointer of APIs exposed via Dbus */ -//const sd_bus_vtable timeServicesVtable[] = -const sd_bus_vtable timeServicesVtable [] = -{ - SD_BUS_VTABLE_START(0), - SD_BUS_PROPERTY("curr_time_mode", "s", getCurrTimeModeProperty, 0, - SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("curr_time_owner", "s", getCurrTimeOwnerProperty, 0, - SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("requested_time_mode", "s", getReqTimeModeProperty, 0, - SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("requested_time_owner", "s", getReqTimeOwnerProperty, 0, - SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_METHOD("GetTime", "s", "sx", &GetTime, - SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetTime", "ss", "i", &SetTime, - SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_VTABLE_END, -}; diff --git a/time-register.hpp b/time-register.hpp deleted file mode 100644 index bf776d3..0000000 --- a/time-register.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#include <systemd/sd-bus.h> -#ifdef __cplusplus -extern "C" { -#endif -int getCurrTimeModeProperty(sd_bus*, const char*, const char*, const char*, - sd_bus_message*, void*, sd_bus_error*); -int getCurrTimeOwnerProperty(sd_bus*, const char*, const char*, const char*, - sd_bus_message*, void*, sd_bus_error*); -int getReqTimeModeProperty(sd_bus*, const char*, const char*, const char*, - sd_bus_message*, void*, sd_bus_error*); -int getReqTimeOwnerProperty(sd_bus*, const char*, const char*, const char*, - sd_bus_message*, void*, sd_bus_error*); -int GetTime(sd_bus_message*, void*, sd_bus_error*); -int SetTime(sd_bus_message*, void*, sd_bus_error*); -#ifdef __cplusplus -}; -#endif |