18d2f868cSEd Tanous #pragma once
28d2f868cSEd Tanous
38d2f868cSEd Tanous #include "app.hpp"
48d2f868cSEd Tanous #include "generated/enums/log_service.hpp"
58d2f868cSEd Tanous #include "query.hpp"
68d2f868cSEd Tanous #include "registries/openbmc_message_registry.hpp"
78d2f868cSEd Tanous #include "registries/privilege_registry.hpp"
88d2f868cSEd Tanous #include "utils/time_utils.hpp"
98d2f868cSEd Tanous
108d2f868cSEd Tanous #include <cstdint>
118d2f868cSEd Tanous #include <memory>
128d2f868cSEd Tanous #include <string_view>
138d2f868cSEd Tanous #include <utility>
148d2f868cSEd Tanous #include <vector>
158d2f868cSEd Tanous
168d2f868cSEd Tanous namespace redfish
178d2f868cSEd Tanous {
1834fe470aSEd Tanous
handleSystemsLogServicesPostCodesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)1934fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesGet(
2034fe470aSEd Tanous App& app, const crow::Request& req,
218d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2234fe470aSEd Tanous const std::string& systemName)
2334fe470aSEd Tanous {
248d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp))
258d2f868cSEd Tanous {
268d2f868cSEd Tanous return;
278d2f868cSEd Tanous }
288d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
298d2f868cSEd Tanous {
308d2f868cSEd Tanous // Option currently returns no systems. TBD
318d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
328d2f868cSEd Tanous systemName);
338d2f868cSEd Tanous return;
348d2f868cSEd Tanous }
358d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
368d2f868cSEd Tanous {
378d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
388d2f868cSEd Tanous systemName);
398d2f868cSEd Tanous return;
408d2f868cSEd Tanous }
418d2f868cSEd Tanous asyncResp->res.jsonValue["@odata.id"] =
428d2f868cSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes",
438d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME);
4434fe470aSEd Tanous asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
458d2f868cSEd Tanous asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
468d2f868cSEd Tanous asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
478d2f868cSEd Tanous asyncResp->res.jsonValue["Id"] = "PostCodes";
488d2f868cSEd Tanous asyncResp->res.jsonValue["OverWritePolicy"] =
498d2f868cSEd Tanous log_service::OverWritePolicy::WrapsWhenFull;
5034fe470aSEd Tanous asyncResp->res.jsonValue["Entries"]["@odata.id"] =
5134fe470aSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
528d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME);
538d2f868cSEd Tanous
548d2f868cSEd Tanous std::pair<std::string, std::string> redfishDateTimeOffset =
558d2f868cSEd Tanous redfish::time_utils::getDateTimeOffsetNow();
568d2f868cSEd Tanous asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
578d2f868cSEd Tanous asyncResp->res.jsonValue["DateTimeLocalOffset"] =
588d2f868cSEd Tanous redfishDateTimeOffset.second;
598d2f868cSEd Tanous
6034fe470aSEd Tanous asyncResp->res
6134fe470aSEd Tanous .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = std::format(
628d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog",
638d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME);
648d2f868cSEd Tanous }
658d2f868cSEd Tanous
handleSystemsLogServicesPostCodesPost(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)6634fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesPost(
6734fe470aSEd Tanous App& app, const crow::Request& req,
688d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6934fe470aSEd Tanous const std::string& systemName)
7034fe470aSEd Tanous {
718d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp))
728d2f868cSEd Tanous {
738d2f868cSEd Tanous return;
748d2f868cSEd Tanous }
758d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
768d2f868cSEd Tanous {
778d2f868cSEd Tanous // Option currently returns no systems. TBD
788d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
798d2f868cSEd Tanous systemName);
808d2f868cSEd Tanous return;
818d2f868cSEd Tanous }
828d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
838d2f868cSEd Tanous {
848d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
858d2f868cSEd Tanous systemName);
868d2f868cSEd Tanous return;
878d2f868cSEd Tanous }
888d2f868cSEd Tanous BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
898d2f868cSEd Tanous
908d2f868cSEd Tanous // Make call to post-code service to request clear all
918d2f868cSEd Tanous crow::connections::systemBus->async_method_call(
928d2f868cSEd Tanous [asyncResp](const boost::system::error_code& ec) {
938d2f868cSEd Tanous if (ec)
948d2f868cSEd Tanous {
958d2f868cSEd Tanous // TODO Handle for specific error code
9634fe470aSEd Tanous BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}",
978d2f868cSEd Tanous ec);
9834fe470aSEd Tanous asyncResp->res.result(
9934fe470aSEd Tanous boost::beast::http::status::internal_server_error);
1008d2f868cSEd Tanous messages::internalError(asyncResp->res);
1018d2f868cSEd Tanous return;
1028d2f868cSEd Tanous }
1038d2f868cSEd Tanous messages::success(asyncResp->res);
1048d2f868cSEd Tanous },
1058d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0",
1068d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0",
1078d2f868cSEd Tanous "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
1088d2f868cSEd Tanous }
1098d2f868cSEd Tanous
1108d2f868cSEd Tanous /**
1118d2f868cSEd Tanous * @brief Parse post code ID and get the current value and index value
1128d2f868cSEd Tanous * eg: postCodeID=B1-2, currentValue=1, index=2
1138d2f868cSEd Tanous *
1148d2f868cSEd Tanous * @param[in] postCodeID Post Code ID
1158d2f868cSEd Tanous * @param[out] currentValue Current value
1168d2f868cSEd Tanous * @param[out] index Index value
1178d2f868cSEd Tanous *
1188d2f868cSEd Tanous * @return bool true if the parsing is successful, false the parsing fails
1198d2f868cSEd Tanous */
parsePostCode(std::string_view postCodeID,uint64_t & currentValue,uint16_t & index)1208d2f868cSEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue,
1218d2f868cSEd Tanous uint16_t& index)
1228d2f868cSEd Tanous {
1238d2f868cSEd Tanous std::vector<std::string> split;
1248d2f868cSEd Tanous bmcweb::split(split, postCodeID, '-');
1258d2f868cSEd Tanous if (split.size() != 2)
1268d2f868cSEd Tanous {
1278d2f868cSEd Tanous return false;
1288d2f868cSEd Tanous }
1298d2f868cSEd Tanous std::string_view postCodeNumber = split[0];
1308d2f868cSEd Tanous if (postCodeNumber.size() < 2)
1318d2f868cSEd Tanous {
1328d2f868cSEd Tanous return false;
1338d2f868cSEd Tanous }
1348d2f868cSEd Tanous if (postCodeNumber[0] != 'B')
1358d2f868cSEd Tanous {
1368d2f868cSEd Tanous return false;
1378d2f868cSEd Tanous }
1388d2f868cSEd Tanous postCodeNumber.remove_prefix(1);
1398d2f868cSEd Tanous auto [ptrIndex, ecIndex] =
1408d2f868cSEd Tanous std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index);
1418d2f868cSEd Tanous if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc())
1428d2f868cSEd Tanous {
1438d2f868cSEd Tanous return false;
1448d2f868cSEd Tanous }
1458d2f868cSEd Tanous
1468d2f868cSEd Tanous std::string_view postCodeIndex = split[1];
1478d2f868cSEd Tanous
1488d2f868cSEd Tanous auto [ptrValue, ecValue] = std::from_chars(
1498d2f868cSEd Tanous postCodeIndex.begin(), postCodeIndex.end(), currentValue);
1508d2f868cSEd Tanous
1518d2f868cSEd Tanous return ptrValue == postCodeIndex.end() && ecValue == std::errc();
1528d2f868cSEd Tanous }
1538d2f868cSEd Tanous
fillPostCodeEntry(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::container::flat_map<uint64_t,std::tuple<uint64_t,std::vector<uint8_t>>> & postcode,const uint16_t bootIndex,const uint64_t codeIndex=0,const uint64_t skip=0,const uint64_t top=0)1548d2f868cSEd Tanous static bool fillPostCodeEntry(
1558d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1568d2f868cSEd Tanous const boost::container::flat_map<
1578d2f868cSEd Tanous uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
1588d2f868cSEd Tanous const uint16_t bootIndex, const uint64_t codeIndex = 0,
1598d2f868cSEd Tanous const uint64_t skip = 0, const uint64_t top = 0)
1608d2f868cSEd Tanous {
1618d2f868cSEd Tanous // Get the Message from the MessageRegistry
1628d2f868cSEd Tanous const registries::Message* message =
1638d2f868cSEd Tanous registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
1648d2f868cSEd Tanous if (message == nullptr)
1658d2f868cSEd Tanous {
1668d2f868cSEd Tanous BMCWEB_LOG_ERROR("Couldn't find known message?");
1678d2f868cSEd Tanous return false;
1688d2f868cSEd Tanous }
1698d2f868cSEd Tanous uint64_t currentCodeIndex = 0;
1708d2f868cSEd Tanous uint64_t firstCodeTimeUs = 0;
1718d2f868cSEd Tanous for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
1728d2f868cSEd Tanous code : postcode)
1738d2f868cSEd Tanous {
1748d2f868cSEd Tanous currentCodeIndex++;
1758d2f868cSEd Tanous std::string postcodeEntryID =
1768d2f868cSEd Tanous "B" + std::to_string(bootIndex) + "-" +
1778d2f868cSEd Tanous std::to_string(currentCodeIndex); // 1 based index in EntryID string
1788d2f868cSEd Tanous
1798d2f868cSEd Tanous uint64_t usecSinceEpoch = code.first;
1808d2f868cSEd Tanous uint64_t usTimeOffset = 0;
1818d2f868cSEd Tanous
1828d2f868cSEd Tanous if (1 == currentCodeIndex)
1838d2f868cSEd Tanous { // already incremented
1848d2f868cSEd Tanous firstCodeTimeUs = code.first;
1858d2f868cSEd Tanous }
1868d2f868cSEd Tanous else
1878d2f868cSEd Tanous {
1888d2f868cSEd Tanous usTimeOffset = code.first - firstCodeTimeUs;
1898d2f868cSEd Tanous }
1908d2f868cSEd Tanous
1918d2f868cSEd Tanous // skip if no specific codeIndex is specified and currentCodeIndex does
1928d2f868cSEd Tanous // not fall between top and skip
1938d2f868cSEd Tanous if ((codeIndex == 0) &&
1948d2f868cSEd Tanous (currentCodeIndex <= skip || currentCodeIndex > top))
1958d2f868cSEd Tanous {
1968d2f868cSEd Tanous continue;
1978d2f868cSEd Tanous }
1988d2f868cSEd Tanous
1998d2f868cSEd Tanous // skip if a specific codeIndex is specified and does not match the
2008d2f868cSEd Tanous // currentIndex
2018d2f868cSEd Tanous if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
2028d2f868cSEd Tanous {
2038d2f868cSEd Tanous // This is done for simplicity. 1st entry is needed to calculate
2048d2f868cSEd Tanous // time offset. To improve efficiency, one can get to the entry
2058d2f868cSEd Tanous // directly (possibly with flatmap's nth method)
2068d2f868cSEd Tanous continue;
2078d2f868cSEd Tanous }
2088d2f868cSEd Tanous
2098d2f868cSEd Tanous // currentCodeIndex is within top and skip or equal to specified code
2108d2f868cSEd Tanous // index
2118d2f868cSEd Tanous
2128d2f868cSEd Tanous // Get the Created time from the timestamp
2138d2f868cSEd Tanous std::string entryTimeStr;
2148d2f868cSEd Tanous entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
2158d2f868cSEd Tanous
2168d2f868cSEd Tanous // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
2178d2f868cSEd Tanous std::ostringstream hexCode;
2188d2f868cSEd Tanous hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
2198d2f868cSEd Tanous << std::get<0>(code.second);
2208d2f868cSEd Tanous std::ostringstream timeOffsetStr;
2218d2f868cSEd Tanous // Set Fixed -Point Notation
2228d2f868cSEd Tanous timeOffsetStr << std::fixed;
2238d2f868cSEd Tanous // Set precision to 4 digits
2248d2f868cSEd Tanous timeOffsetStr << std::setprecision(4);
2258d2f868cSEd Tanous // Add double to stream
2268d2f868cSEd Tanous timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
2278d2f868cSEd Tanous
2288d2f868cSEd Tanous std::string bootIndexStr = std::to_string(bootIndex);
2298d2f868cSEd Tanous std::string timeOffsetString = timeOffsetStr.str();
2308d2f868cSEd Tanous std::string hexCodeStr = hexCode.str();
2318d2f868cSEd Tanous
2328d2f868cSEd Tanous std::array<std::string_view, 3> messageArgs = {
2338d2f868cSEd Tanous bootIndexStr, timeOffsetString, hexCodeStr};
2348d2f868cSEd Tanous
2358d2f868cSEd Tanous std::string msg =
2368d2f868cSEd Tanous redfish::registries::fillMessageArgs(messageArgs, message->message);
2378d2f868cSEd Tanous if (msg.empty())
2388d2f868cSEd Tanous {
2398d2f868cSEd Tanous messages::internalError(asyncResp->res);
2408d2f868cSEd Tanous return false;
2418d2f868cSEd Tanous }
2428d2f868cSEd Tanous
2438d2f868cSEd Tanous // Get Severity template from message registry
2448d2f868cSEd Tanous std::string severity;
2458d2f868cSEd Tanous if (message != nullptr)
2468d2f868cSEd Tanous {
2478d2f868cSEd Tanous severity = message->messageSeverity;
2488d2f868cSEd Tanous }
2498d2f868cSEd Tanous
2508d2f868cSEd Tanous // Format entry
2518d2f868cSEd Tanous nlohmann::json::object_t bmcLogEntry;
2528d2f868cSEd Tanous bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
2538d2f868cSEd Tanous bmcLogEntry["@odata.id"] = boost::urls::format(
2548d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}",
2558d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID);
2568d2f868cSEd Tanous bmcLogEntry["Name"] = "POST Code Log Entry";
2578d2f868cSEd Tanous bmcLogEntry["Id"] = postcodeEntryID;
2588d2f868cSEd Tanous bmcLogEntry["Message"] = std::move(msg);
2598d2f868cSEd Tanous bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
2608d2f868cSEd Tanous bmcLogEntry["MessageArgs"] = messageArgs;
2618d2f868cSEd Tanous bmcLogEntry["EntryType"] = "Event";
2628d2f868cSEd Tanous bmcLogEntry["Severity"] = std::move(severity);
2638d2f868cSEd Tanous bmcLogEntry["Created"] = entryTimeStr;
2648d2f868cSEd Tanous if (!std::get<std::vector<uint8_t>>(code.second).empty())
2658d2f868cSEd Tanous {
2668d2f868cSEd Tanous bmcLogEntry["AdditionalDataURI"] =
2678d2f868cSEd Tanous std::format(
2688d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/",
2698d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) +
2708d2f868cSEd Tanous postcodeEntryID + "/attachment";
2718d2f868cSEd Tanous }
2728d2f868cSEd Tanous
2738d2f868cSEd Tanous // codeIndex is only specified when querying single entry, return only
2748d2f868cSEd Tanous // that entry in this case
2758d2f868cSEd Tanous if (codeIndex != 0)
2768d2f868cSEd Tanous {
2778d2f868cSEd Tanous asyncResp->res.jsonValue.update(bmcLogEntry);
2788d2f868cSEd Tanous return true;
2798d2f868cSEd Tanous }
2808d2f868cSEd Tanous
2818d2f868cSEd Tanous nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2828d2f868cSEd Tanous logEntryArray.emplace_back(std::move(bmcLogEntry));
2838d2f868cSEd Tanous }
2848d2f868cSEd Tanous
2858d2f868cSEd Tanous // Return value is always false when querying multiple entries
2868d2f868cSEd Tanous return false;
2878d2f868cSEd Tanous }
2888d2f868cSEd Tanous
28934fe470aSEd Tanous inline void
getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & entryId)2908d2f868cSEd Tanous getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2918d2f868cSEd Tanous const std::string& entryId)
2928d2f868cSEd Tanous {
2938d2f868cSEd Tanous uint16_t bootIndex = 0;
2948d2f868cSEd Tanous uint64_t codeIndex = 0;
2958d2f868cSEd Tanous if (!parsePostCode(entryId, codeIndex, bootIndex))
2968d2f868cSEd Tanous {
2978d2f868cSEd Tanous // Requested ID was not found
2988d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
2998d2f868cSEd Tanous return;
3008d2f868cSEd Tanous }
3018d2f868cSEd Tanous
3028d2f868cSEd Tanous if (bootIndex == 0 || codeIndex == 0)
3038d2f868cSEd Tanous {
3048d2f868cSEd Tanous // 0 is an invalid index
3058d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
3068d2f868cSEd Tanous return;
3078d2f868cSEd Tanous }
3088d2f868cSEd Tanous
3098d2f868cSEd Tanous crow::connections::systemBus->async_method_call(
3108d2f868cSEd Tanous [asyncResp, entryId, bootIndex,
3118d2f868cSEd Tanous codeIndex](const boost::system::error_code& ec,
3128d2f868cSEd Tanous const boost::container::flat_map<
3138d2f868cSEd Tanous uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3148d2f868cSEd Tanous postcode) {
3158d2f868cSEd Tanous if (ec)
3168d2f868cSEd Tanous {
3178d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
3188d2f868cSEd Tanous messages::internalError(asyncResp->res);
3198d2f868cSEd Tanous return;
3208d2f868cSEd Tanous }
3218d2f868cSEd Tanous
3228d2f868cSEd Tanous if (postcode.empty())
3238d2f868cSEd Tanous {
3248d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
3258d2f868cSEd Tanous return;
3268d2f868cSEd Tanous }
3278d2f868cSEd Tanous
3288d2f868cSEd Tanous if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
3298d2f868cSEd Tanous {
3308d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
3318d2f868cSEd Tanous return;
3328d2f868cSEd Tanous }
3338d2f868cSEd Tanous },
3348d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0",
3358d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0",
3368d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3378d2f868cSEd Tanous bootIndex);
3388d2f868cSEd Tanous }
3398d2f868cSEd Tanous
34034fe470aSEd Tanous inline void
getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const uint16_t bootIndex,const uint16_t bootCount,const uint64_t entryCount,size_t skip,size_t top)3418d2f868cSEd Tanous getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3428d2f868cSEd Tanous const uint16_t bootIndex, const uint16_t bootCount,
3438d2f868cSEd Tanous const uint64_t entryCount, size_t skip, size_t top)
3448d2f868cSEd Tanous {
3458d2f868cSEd Tanous crow::connections::systemBus->async_method_call(
3468d2f868cSEd Tanous [asyncResp, bootIndex, bootCount, entryCount, skip,
3478d2f868cSEd Tanous top](const boost::system::error_code& ec,
3488d2f868cSEd Tanous const boost::container::flat_map<
3498d2f868cSEd Tanous uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3508d2f868cSEd Tanous postcode) {
3518d2f868cSEd Tanous if (ec)
3528d2f868cSEd Tanous {
3538d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
3548d2f868cSEd Tanous messages::internalError(asyncResp->res);
3558d2f868cSEd Tanous return;
3568d2f868cSEd Tanous }
3578d2f868cSEd Tanous
3588d2f868cSEd Tanous uint64_t endCount = entryCount;
3598d2f868cSEd Tanous if (!postcode.empty())
3608d2f868cSEd Tanous {
3618d2f868cSEd Tanous endCount = entryCount + postcode.size();
3628d2f868cSEd Tanous if (skip < endCount && (top + skip) > entryCount)
3638d2f868cSEd Tanous {
3648d2f868cSEd Tanous uint64_t thisBootSkip =
3658d2f868cSEd Tanous std::max(static_cast<uint64_t>(skip), entryCount) -
3668d2f868cSEd Tanous entryCount;
3678d2f868cSEd Tanous uint64_t thisBootTop =
3688d2f868cSEd Tanous std::min(static_cast<uint64_t>(top + skip), endCount) -
3698d2f868cSEd Tanous entryCount;
3708d2f868cSEd Tanous
3718d2f868cSEd Tanous fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
3728d2f868cSEd Tanous thisBootSkip, thisBootTop);
3738d2f868cSEd Tanous }
3748d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = endCount;
3758d2f868cSEd Tanous }
3768d2f868cSEd Tanous
3778d2f868cSEd Tanous // continue to previous bootIndex
3788d2f868cSEd Tanous if (bootIndex < bootCount)
3798d2f868cSEd Tanous {
3808d2f868cSEd Tanous getPostCodeForBoot(asyncResp,
3818d2f868cSEd Tanous static_cast<uint16_t>(bootIndex + 1),
3828d2f868cSEd Tanous bootCount, endCount, skip, top);
3838d2f868cSEd Tanous }
3848d2f868cSEd Tanous else if (skip + top < endCount)
3858d2f868cSEd Tanous {
3868d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.nextLink"] =
3878d2f868cSEd Tanous std::format(
3888d2f868cSEd Tanous "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=",
3898d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME) +
3908d2f868cSEd Tanous std::to_string(skip + top);
3918d2f868cSEd Tanous }
3928d2f868cSEd Tanous },
3938d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0",
3948d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0",
3958d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3968d2f868cSEd Tanous bootIndex);
3978d2f868cSEd Tanous }
3988d2f868cSEd Tanous
39934fe470aSEd Tanous inline void
getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,size_t skip,size_t top)4008d2f868cSEd Tanous getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4018d2f868cSEd Tanous size_t skip, size_t top)
4028d2f868cSEd Tanous {
4038d2f868cSEd Tanous uint64_t entryCount = 0;
4048d2f868cSEd Tanous sdbusplus::asio::getProperty<uint16_t>(
4058d2f868cSEd Tanous *crow::connections::systemBus,
4068d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0",
4078d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0",
4088d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
4098d2f868cSEd Tanous [asyncResp, entryCount, skip,
4108d2f868cSEd Tanous top](const boost::system::error_code& ec, const uint16_t bootCount) {
4118d2f868cSEd Tanous if (ec)
4128d2f868cSEd Tanous {
4138d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
4148d2f868cSEd Tanous messages::internalError(asyncResp->res);
4158d2f868cSEd Tanous return;
4168d2f868cSEd Tanous }
4178d2f868cSEd Tanous getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
4188d2f868cSEd Tanous });
4198d2f868cSEd Tanous }
4208d2f868cSEd Tanous
handleSystemsLogServicesPostCodesEntriesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)42134fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesGet(
42234fe470aSEd Tanous App& app, const crow::Request& req,
4238d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
42434fe470aSEd Tanous const std::string& systemName)
42534fe470aSEd Tanous {
4268d2f868cSEd Tanous query_param::QueryCapabilities capabilities = {
4278d2f868cSEd Tanous .canDelegateTop = true,
4288d2f868cSEd Tanous .canDelegateSkip = true,
4298d2f868cSEd Tanous };
4308d2f868cSEd Tanous query_param::Query delegatedQuery;
43134fe470aSEd Tanous if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
43234fe470aSEd Tanous delegatedQuery, capabilities))
4338d2f868cSEd Tanous {
4348d2f868cSEd Tanous return;
4358d2f868cSEd Tanous }
4368d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
4378d2f868cSEd Tanous {
4388d2f868cSEd Tanous // Option currently returns no systems. TBD
4398d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4408d2f868cSEd Tanous systemName);
4418d2f868cSEd Tanous return;
4428d2f868cSEd Tanous }
4438d2f868cSEd Tanous
4448d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
4458d2f868cSEd Tanous {
4468d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4478d2f868cSEd Tanous systemName);
4488d2f868cSEd Tanous return;
4498d2f868cSEd Tanous }
4508d2f868cSEd Tanous asyncResp->res.jsonValue["@odata.type"] =
4518d2f868cSEd Tanous "#LogEntryCollection.LogEntryCollection";
45234fe470aSEd Tanous asyncResp->res.jsonValue["@odata.id"] =
45334fe470aSEd Tanous std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
4548d2f868cSEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME);
4558d2f868cSEd Tanous asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
4568d2f868cSEd Tanous asyncResp->res.jsonValue["Description"] =
4578d2f868cSEd Tanous "Collection of POST Code Log Entries";
4588d2f868cSEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
4598d2f868cSEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0;
4608d2f868cSEd Tanous size_t skip = delegatedQuery.skip.value_or(0);
46134fe470aSEd Tanous size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
4628d2f868cSEd Tanous getCurrentBootNumber(asyncResp, skip, top);
4638d2f868cSEd Tanous }
4648d2f868cSEd Tanous
handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & postCodeID)46534fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet(
46634fe470aSEd Tanous App& app, const crow::Request& req,
4678d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
46834fe470aSEd Tanous const std::string& systemName, const std::string& postCodeID)
46934fe470aSEd Tanous {
4708d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp))
4718d2f868cSEd Tanous {
4728d2f868cSEd Tanous return;
4738d2f868cSEd Tanous }
4748d2f868cSEd Tanous if (!http_helpers::isContentTypeAllowed(
4758d2f868cSEd Tanous req.getHeaderValue("Accept"),
4768d2f868cSEd Tanous http_helpers::ContentType::OctetStream, true))
4778d2f868cSEd Tanous {
4788d2f868cSEd Tanous asyncResp->res.result(boost::beast::http::status::bad_request);
4798d2f868cSEd Tanous return;
4808d2f868cSEd Tanous }
4818d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
4828d2f868cSEd Tanous {
4838d2f868cSEd Tanous // Option currently returns no systems. TBD
4848d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4858d2f868cSEd Tanous systemName);
4868d2f868cSEd Tanous return;
4878d2f868cSEd Tanous }
4888d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
4898d2f868cSEd Tanous {
4908d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4918d2f868cSEd Tanous systemName);
4928d2f868cSEd Tanous return;
4938d2f868cSEd Tanous }
4948d2f868cSEd Tanous
4958d2f868cSEd Tanous uint64_t currentValue = 0;
4968d2f868cSEd Tanous uint16_t index = 0;
4978d2f868cSEd Tanous if (!parsePostCode(postCodeID, currentValue, index))
4988d2f868cSEd Tanous {
49934fe470aSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
5008d2f868cSEd Tanous return;
5018d2f868cSEd Tanous }
5028d2f868cSEd Tanous
5038d2f868cSEd Tanous crow::connections::systemBus->async_method_call(
5048d2f868cSEd Tanous [asyncResp, postCodeID, currentValue](
5058d2f868cSEd Tanous const boost::system::error_code& ec,
50634fe470aSEd Tanous const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
50734fe470aSEd Tanous postcodes) {
5088d2f868cSEd Tanous if (ec.value() == EBADR)
5098d2f868cSEd Tanous {
5108d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry",
5118d2f868cSEd Tanous postCodeID);
5128d2f868cSEd Tanous return;
5138d2f868cSEd Tanous }
5148d2f868cSEd Tanous if (ec)
5158d2f868cSEd Tanous {
5168d2f868cSEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
5178d2f868cSEd Tanous messages::internalError(asyncResp->res);
5188d2f868cSEd Tanous return;
5198d2f868cSEd Tanous }
5208d2f868cSEd Tanous
5218d2f868cSEd Tanous size_t value = static_cast<size_t>(currentValue) - 1;
52234fe470aSEd Tanous if (value == std::string::npos || postcodes.size() < currentValue)
5238d2f868cSEd Tanous {
5248d2f868cSEd Tanous BMCWEB_LOG_WARNING("Wrong currentValue value");
5258d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry",
5268d2f868cSEd Tanous postCodeID);
5278d2f868cSEd Tanous return;
5288d2f868cSEd Tanous }
5298d2f868cSEd Tanous
5308d2f868cSEd Tanous const auto& [tID, c] = postcodes[value];
5318d2f868cSEd Tanous if (c.empty())
5328d2f868cSEd Tanous {
5338d2f868cSEd Tanous BMCWEB_LOG_WARNING("No found post code data");
5348d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "LogEntry",
5358d2f868cSEd Tanous postCodeID);
5368d2f868cSEd Tanous return;
5378d2f868cSEd Tanous }
5388d2f868cSEd Tanous // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
5398d2f868cSEd Tanous const char* d = reinterpret_cast<const char*>(c.data());
5408d2f868cSEd Tanous std::string_view strData(d, c.size());
5418d2f868cSEd Tanous
54234fe470aSEd Tanous asyncResp->res.addHeader(boost::beast::http::field::content_type,
5438d2f868cSEd Tanous "application/octet-stream");
5448d2f868cSEd Tanous asyncResp->res.addHeader(
54534fe470aSEd Tanous boost::beast::http::field::content_transfer_encoding, "Base64");
5468d2f868cSEd Tanous asyncResp->res.write(crow::utility::base64encode(strData));
5478d2f868cSEd Tanous },
5488d2f868cSEd Tanous "xyz.openbmc_project.State.Boot.PostCode0",
5498d2f868cSEd Tanous "/xyz/openbmc_project/State/Boot/PostCode0",
55034fe470aSEd Tanous "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
5518d2f868cSEd Tanous }
5528d2f868cSEd Tanous
handleSystemsLogServicesPostCodesEntriesEntryGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & targetID)55334fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryGet(
55434fe470aSEd Tanous App& app, const crow::Request& req,
5558d2f868cSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
55634fe470aSEd Tanous const std::string& systemName, const std::string& targetID)
55734fe470aSEd Tanous {
5588d2f868cSEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp))
5598d2f868cSEd Tanous {
5608d2f868cSEd Tanous return;
5618d2f868cSEd Tanous }
5628d2f868cSEd Tanous if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
5638d2f868cSEd Tanous {
5648d2f868cSEd Tanous // Option currently returns no systems. TBD
5658d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5668d2f868cSEd Tanous systemName);
5678d2f868cSEd Tanous return;
5688d2f868cSEd Tanous }
5698d2f868cSEd Tanous if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
5708d2f868cSEd Tanous {
5718d2f868cSEd Tanous messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5728d2f868cSEd Tanous systemName);
5738d2f868cSEd Tanous return;
5748d2f868cSEd Tanous }
5758d2f868cSEd Tanous
5768d2f868cSEd Tanous getPostCodeForEntry(asyncResp, targetID);
5778d2f868cSEd Tanous }
5788d2f868cSEd Tanous
requestRoutesSystemsLogServicesPostCode(App & app)5798d2f868cSEd Tanous inline void requestRoutesSystemsLogServicesPostCode(App& app)
5808d2f868cSEd Tanous {
58134fe470aSEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
58234fe470aSEd Tanous .privileges(redfish::privileges::getLogService)
58334fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front(
58434fe470aSEd Tanous handleSystemsLogServicesPostCodesGet, std::ref(app)));
58534fe470aSEd Tanous
58634fe470aSEd Tanous BMCWEB_ROUTE(
58734fe470aSEd Tanous app,
58834fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
589*9d62d126SGunnar Mills // The following privilege is correct; we need "SubordinateOverrides"
590*9d62d126SGunnar Mills // before we can automate it.
59134fe470aSEd Tanous .privileges({{"ConfigureComponents"}})
59234fe470aSEd Tanous .methods(boost::beast::http::verb::post)(std::bind_front(
59334fe470aSEd Tanous handleSystemsLogServicesPostCodesPost, std::ref(app)));
59434fe470aSEd Tanous
59534fe470aSEd Tanous BMCWEB_ROUTE(app,
59634fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
59734fe470aSEd Tanous .privileges(redfish::privileges::getLogEntryCollection)
59834fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front(
59934fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesGet, std::ref(app)));
60034fe470aSEd Tanous
60134fe470aSEd Tanous BMCWEB_ROUTE(
60234fe470aSEd Tanous app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
60334fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry)
60434fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front(
60534fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryGet, std::ref(app)));
60634fe470aSEd Tanous
60734fe470aSEd Tanous BMCWEB_ROUTE(
60834fe470aSEd Tanous app,
60934fe470aSEd Tanous "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
61034fe470aSEd Tanous .privileges(redfish::privileges::getLogEntry)
61134fe470aSEd Tanous .methods(boost::beast::http::verb::get)(std::bind_front(
61234fe470aSEd Tanous handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet,
61334fe470aSEd Tanous std::ref(app)));
6148d2f868cSEd Tanous }
6158d2f868cSEd Tanous } // namespace redfish
616