From cfd7bb5a9175a2fa01aa314cace2c3fd0be85d07 Mon Sep 17 00:00:00 2001 From: roly Date: Tue, 26 Nov 2024 16:49:35 +0800 Subject: [PATCH] Support redfish set bmc timezone --- redfish-core/include/utils/time_utils.hpp | 40 ++++++++++++- redfish-core/lib/managers.hpp | 68 ++++++++++++++++++++++- 2 files changed, 105 insertions(+), 3 deletions(-) diff --git a/redfish-core/include/utils/time_utils.hpp b/redfish-core/include/utils/time_utils.hpp index 314ea85d..c69eec28 100644 --- a/redfish-core/include/utils/time_utils.hpp +++ b/redfish-core/include/utils/time_utils.hpp @@ -13,6 +13,7 @@ #include #include #include +#include // IWYU pragma: no_include // IWYU pragma: no_include @@ -284,6 +285,15 @@ std::string toISO8061ExtendedStr(std::chrono::duration t) using days = std::chrono::duration< IntType, std::ratio_multiply>>; + time_t timep; + time(&timep); + struct tm* localTime = localtime(&timep); + auto validLocalTime = mktime(localTime); + struct tm* gmTime = gmtime(&timep); + auto validGmTime = mktime(gmTime); + auto timeEquation = validLocalTime - validGmTime; + + t += std::chrono::seconds(timeEquation); // d is days since 1970-01-01 days d = std::chrono::duration_cast(t); @@ -348,8 +358,9 @@ std::string toISO8061ExtendedStr(std::chrono::duration t) MicroDuration subsec = duration_cast(t); out += details::padZeros(subsec.count(), 6); } - - out += "+00:00"; + char tzstring[32] = {0}; + std::snprintf(tzstring, sizeof(tzstring), "%+03lld:00", timeEquation/3600); + out += tzstring; return out; } } // namespace details @@ -445,5 +456,30 @@ inline std::optional dateStringToEpoch(std::string_view datetime) return std::chrono::duration{durMicroSecs}; } +inline bool isValidTimeOffset(const std::string& timeOffset) { + std::regex timeOffsetRegex(R"(^([-+][0-1][0-9]:[0-5][0-9])$)"); + + return std::regex_match(timeOffset, timeOffsetRegex); +} + +int convertTimeOffsetToMinutes(const std::string& timeOffset) { + + if (!isValidTimeOffset(timeOffset)) { + return -1; + } + + int hours = std::stoi(timeOffset.substr(1, 2)); + if(hours < -13 || hours > 12) + { + return -1; + } + int totalMinutes = hours * 60; + + if (timeOffset[0] == '-') { + totalMinutes = -totalMinutes; + } + return totalMinutes; +} + } // namespace time_utils } // namespace redfish diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp index a114d440..30395284 100644 --- a/redfish-core/lib/managers.hpp +++ b/redfish-core/lib/managers.hpp @@ -1879,6 +1879,67 @@ inline void setDateTime(std::shared_ptr asyncResp, }); } +inline void setDateTimeLocalOffset(std::shared_ptr asyncResp, + std::string datetimelocaloffset) +{ + int hrs = 0; + char ZoneInfoFile[128] = {0}, file[32] = {0}; + static constexpr int16_t SEL_UTC_MAX_RANGE = 1440; + static constexpr int16_t SEL_UTC_MIN_RANGE = -1440; + static constexpr int16_t UNSPECIFIED_UTC_OFFSET = 0x7ff; + constexpr auto LOCALTIME = "/etc/localtime"; + int UTCOffset = redfish::time_utils::convertTimeOffsetToMinutes(datetimelocaloffset); + if (((UTCOffset > SEL_UTC_MAX_RANGE ) || (UTCOffset < SEL_UTC_MIN_RANGE) || (UTCOffset % 60 != 0)) && UTCOffset != UNSPECIFIED_UTC_OFFSET) + { + messages::propertyValueOutOfRange(asyncResp->res, datetimelocaloffset, + "DateTimeLocalOffset"); + return; + } + + hrs = UTCOffset / 60; + if(UTCOffset == UNSPECIFIED_UTC_OFFSET) + { + hrs = 0; + } + + if (0 > UTCOffset) + { + if (snprintf(file,sizeof(file), "GMT+%d", -hrs) >= static_cast(sizeof(file))) + { + messages::internalError(asyncResp->res); + return; + } + } + else + { + if (snprintf(file,sizeof(file), "GMT-%d", hrs) >= static_cast(sizeof(file))) + { + messages::internalError(asyncResp->res); + return; + } + } + + if (snprintf (ZoneInfoFile, sizeof(ZoneInfoFile), "%s/%s", "/usr/share/zoneinfo/Etc", file) >= static_cast(sizeof(ZoneInfoFile))) + { + messages::internalError(asyncResp->res); + return; + } + + if((0 > unlink(LOCALTIME)) && errno != ENOENT) + { + messages::internalError(asyncResp->res); + return; + } + + if(symlink(ZoneInfoFile, LOCALTIME) < 0) + { + messages::internalError(asyncResp->res); + return; + } + + asyncResp->res.jsonValue["DateTimeLocalOffset"] = datetimelocaloffset; +} + inline void checkForQuiesced(const std::shared_ptr& asyncResp) { @@ -2189,9 +2250,10 @@ inline void requestRoutesManager(App& app) std::optional oem; std::optional links; std::optional datetime; + std::optional datatimelocaloffset; if (!json_util::readJsonPatch(req, asyncResp->res, "Oem", oem, - "DateTime", datetime, "Links", links)) + "DateTime", datetime, "Links", links, "DateTimeLocalOffset", datatimelocaloffset)) { return; } @@ -2252,6 +2314,10 @@ inline void requestRoutesManager(App& app) { setDateTime(asyncResp, std::move(*datetime)); } + if (datatimelocaloffset) + { + setDateTimeLocalOffset(asyncResp, std::move(*datatimelocaloffset)); + } }); } -- 2.25.1