xref: /openbmc/bmcweb/redfish-core/lib/systems_logservices_postcodes.hpp (revision 177612aaa0633cf9d5aef0b763a43135cf552d9b)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
38d2f868cSEd Tanous #pragma once
48d2f868cSEd Tanous 
5d7857201SEd Tanous #include "bmcweb_config.h"
6d7857201SEd Tanous 
78d2f868cSEd Tanous #include "app.hpp"
8d7857201SEd Tanous #include "async_resp.hpp"
9deae6a78SEd Tanous #include "dbus_utility.hpp"
10d7857201SEd Tanous #include "error_messages.hpp"
118d2f868cSEd Tanous #include "generated/enums/log_service.hpp"
12d7857201SEd Tanous #include "http_request.hpp"
13d7857201SEd Tanous #include "http_utility.hpp"
14d7857201SEd Tanous #include "logging.hpp"
158d2f868cSEd Tanous #include "query.hpp"
16d7857201SEd Tanous #include "registries.hpp"
178d2f868cSEd Tanous #include "registries/privilege_registry.hpp"
18d7857201SEd Tanous #include "str_utility.hpp"
19d7857201SEd Tanous #include "utility.hpp"
20d7857201SEd Tanous #include "utils/hex_utils.hpp"
21d7857201SEd Tanous #include "utils/query_param.hpp"
228d2f868cSEd Tanous #include "utils/time_utils.hpp"
238d2f868cSEd Tanous 
24d7857201SEd Tanous #include <asm-generic/errno.h>
25d7857201SEd Tanous 
26d7857201SEd Tanous #include <boost/beast/http/field.hpp>
27d7857201SEd Tanous #include <boost/beast/http/status.hpp>
28d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
29d7857201SEd Tanous #include <boost/container/flat_map.hpp>
30d7857201SEd Tanous #include <boost/url/format.hpp>
31d7857201SEd Tanous 
32d7857201SEd Tanous #include <algorithm>
33d7857201SEd Tanous #include <array>
34d7857201SEd Tanous #include <charconv>
35d7857201SEd Tanous #include <cstddef>
368d2f868cSEd Tanous #include <cstdint>
37d7857201SEd Tanous #include <format>
38d7857201SEd Tanous #include <functional>
39d7857201SEd Tanous #include <iomanip>
40d7857201SEd Tanous #include <ios>
418d2f868cSEd Tanous #include <memory>
42d7857201SEd Tanous #include <sstream>
43d7857201SEd Tanous #include <string>
448d2f868cSEd Tanous #include <string_view>
45d7857201SEd Tanous #include <system_error>
46d7857201SEd Tanous #include <tuple>
478d2f868cSEd Tanous #include <utility>
488d2f868cSEd Tanous #include <vector>
498d2f868cSEd Tanous 
508d2f868cSEd Tanous namespace redfish
518d2f868cSEd Tanous {
5234fe470aSEd Tanous 
handleSystemsLogServicesPostCodesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)5334fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesGet(
5434fe470aSEd Tanous     App& app, const crow::Request& req,
558d2f868cSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5634fe470aSEd Tanous     const std::string& systemName)
5734fe470aSEd Tanous {
588d2f868cSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
598d2f868cSEd Tanous     {
608d2f868cSEd Tanous         return;
618d2f868cSEd Tanous     }
628d2f868cSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
638d2f868cSEd Tanous     {
648d2f868cSEd Tanous         // Option currently returns no systems.  TBD
658d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
668d2f868cSEd Tanous                                    systemName);
678d2f868cSEd Tanous         return;
688d2f868cSEd Tanous     }
698d2f868cSEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
708d2f868cSEd Tanous     {
718d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
728d2f868cSEd Tanous                                    systemName);
738d2f868cSEd Tanous         return;
748d2f868cSEd Tanous     }
758d2f868cSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
768d2f868cSEd Tanous         std::format("/redfish/v1/Systems/{}/LogServices/PostCodes",
778d2f868cSEd Tanous                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
7834fe470aSEd Tanous     asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
798d2f868cSEd Tanous     asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
808d2f868cSEd Tanous     asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
818d2f868cSEd Tanous     asyncResp->res.jsonValue["Id"] = "PostCodes";
828d2f868cSEd Tanous     asyncResp->res.jsonValue["OverWritePolicy"] =
838d2f868cSEd Tanous         log_service::OverWritePolicy::WrapsWhenFull;
8434fe470aSEd Tanous     asyncResp->res.jsonValue["Entries"]["@odata.id"] =
8534fe470aSEd Tanous         std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
868d2f868cSEd Tanous                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
878d2f868cSEd Tanous 
888d2f868cSEd Tanous     std::pair<std::string, std::string> redfishDateTimeOffset =
898d2f868cSEd Tanous         redfish::time_utils::getDateTimeOffsetNow();
908d2f868cSEd Tanous     asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
918d2f868cSEd Tanous     asyncResp->res.jsonValue["DateTimeLocalOffset"] =
928d2f868cSEd Tanous         redfishDateTimeOffset.second;
938d2f868cSEd Tanous 
9434fe470aSEd Tanous     asyncResp->res
9534fe470aSEd Tanous         .jsonValue["Actions"]["#LogService.ClearLog"]["target"] = std::format(
968d2f868cSEd Tanous         "/redfish/v1/Systems/{}/LogServices/PostCodes/Actions/LogService.ClearLog",
978d2f868cSEd Tanous         BMCWEB_REDFISH_SYSTEM_URI_NAME);
988d2f868cSEd Tanous }
998d2f868cSEd Tanous 
handleSystemsLogServicesPostCodesPost(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)10034fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesPost(
10134fe470aSEd Tanous     App& app, const crow::Request& req,
1028d2f868cSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
10334fe470aSEd Tanous     const std::string& systemName)
10434fe470aSEd Tanous {
1058d2f868cSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1068d2f868cSEd Tanous     {
1078d2f868cSEd Tanous         return;
1088d2f868cSEd Tanous     }
1098d2f868cSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
1108d2f868cSEd Tanous     {
1118d2f868cSEd Tanous         // Option currently returns no systems.  TBD
1128d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1138d2f868cSEd Tanous                                    systemName);
1148d2f868cSEd Tanous         return;
1158d2f868cSEd Tanous     }
1168d2f868cSEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
1178d2f868cSEd Tanous     {
1188d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1198d2f868cSEd Tanous                                    systemName);
1208d2f868cSEd Tanous         return;
1218d2f868cSEd Tanous     }
1228d2f868cSEd Tanous     BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
1238d2f868cSEd Tanous 
1248d2f868cSEd Tanous     // Make call to post-code service to request clear all
125*177612aaSEd Tanous     dbus::utility::async_method_call(
126*177612aaSEd Tanous         asyncResp,
1278d2f868cSEd Tanous         [asyncResp](const boost::system::error_code& ec) {
1288d2f868cSEd Tanous             if (ec)
1298d2f868cSEd Tanous             {
1308d2f868cSEd Tanous                 // TODO Handle for specific error code
13134fe470aSEd Tanous                 BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}",
1328d2f868cSEd Tanous                                  ec);
13334fe470aSEd Tanous                 asyncResp->res.result(
13434fe470aSEd Tanous                     boost::beast::http::status::internal_server_error);
1358d2f868cSEd Tanous                 messages::internalError(asyncResp->res);
1368d2f868cSEd Tanous                 return;
1378d2f868cSEd Tanous             }
1388d2f868cSEd Tanous             messages::success(asyncResp->res);
1398d2f868cSEd Tanous         },
1408d2f868cSEd Tanous         "xyz.openbmc_project.State.Boot.PostCode0",
1418d2f868cSEd Tanous         "/xyz/openbmc_project/State/Boot/PostCode0",
1428d2f868cSEd Tanous         "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
1438d2f868cSEd Tanous }
1448d2f868cSEd Tanous 
1458d2f868cSEd Tanous /**
1468d2f868cSEd Tanous  * @brief Parse post code ID and get the current value and index value
1478d2f868cSEd Tanous  *        eg: postCodeID=B1-2, currentValue=1, index=2
1488d2f868cSEd Tanous  *
1498d2f868cSEd Tanous  * @param[in]  postCodeID     Post Code ID
1508d2f868cSEd Tanous  * @param[out] currentValue   Current value
1518d2f868cSEd Tanous  * @param[out] index          Index value
1528d2f868cSEd Tanous  *
1538d2f868cSEd Tanous  * @return bool true if the parsing is successful, false the parsing fails
1548d2f868cSEd Tanous  */
parsePostCode(std::string_view postCodeID,uint64_t & currentValue,uint16_t & index)1558d2f868cSEd Tanous inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue,
1568d2f868cSEd Tanous                           uint16_t& index)
1578d2f868cSEd Tanous {
1588d2f868cSEd Tanous     std::vector<std::string> split;
1598d2f868cSEd Tanous     bmcweb::split(split, postCodeID, '-');
1608d2f868cSEd Tanous     if (split.size() != 2)
1618d2f868cSEd Tanous     {
1628d2f868cSEd Tanous         return false;
1638d2f868cSEd Tanous     }
1648d2f868cSEd Tanous     std::string_view postCodeNumber = split[0];
1658d2f868cSEd Tanous     if (postCodeNumber.size() < 2)
1668d2f868cSEd Tanous     {
1678d2f868cSEd Tanous         return false;
1688d2f868cSEd Tanous     }
1698d2f868cSEd Tanous     if (postCodeNumber[0] != 'B')
1708d2f868cSEd Tanous     {
1718d2f868cSEd Tanous         return false;
1728d2f868cSEd Tanous     }
1738d2f868cSEd Tanous     postCodeNumber.remove_prefix(1);
1748d2f868cSEd Tanous     auto [ptrIndex, ecIndex] =
1758d2f868cSEd Tanous         std::from_chars(postCodeNumber.begin(), postCodeNumber.end(), index);
1768d2f868cSEd Tanous     if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc())
1778d2f868cSEd Tanous     {
1788d2f868cSEd Tanous         return false;
1798d2f868cSEd Tanous     }
1808d2f868cSEd Tanous 
1818d2f868cSEd Tanous     std::string_view postCodeIndex = split[1];
1828d2f868cSEd Tanous 
1838d2f868cSEd Tanous     auto [ptrValue, ecValue] = std::from_chars(
1848d2f868cSEd Tanous         postCodeIndex.begin(), postCodeIndex.end(), currentValue);
1858d2f868cSEd Tanous 
1868d2f868cSEd Tanous     return ptrValue == postCodeIndex.end() && ecValue == std::errc();
1878d2f868cSEd Tanous }
1888d2f868cSEd Tanous 
fillPostCodeEntry(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::container::flat_map<uint64_t,std::tuple<std::vector<uint8_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)1898d2f868cSEd Tanous static bool fillPostCodeEntry(
1908d2f868cSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1918d2f868cSEd Tanous     const boost::container::flat_map<
1926a42dc61SPotin Lai         uint64_t, std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>>&
1936a42dc61SPotin Lai         postcode,
1948d2f868cSEd Tanous     const uint16_t bootIndex, const uint64_t codeIndex = 0,
1958d2f868cSEd Tanous     const uint64_t skip = 0, const uint64_t top = 0)
1968d2f868cSEd Tanous {
1978d2f868cSEd Tanous     // Get the Message from the MessageRegistry
1988d2f868cSEd Tanous     const registries::Message* message =
1998d2f868cSEd Tanous         registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
2008d2f868cSEd Tanous     if (message == nullptr)
2018d2f868cSEd Tanous     {
2028d2f868cSEd Tanous         BMCWEB_LOG_ERROR("Couldn't find known message?");
2038d2f868cSEd Tanous         return false;
2048d2f868cSEd Tanous     }
2058d2f868cSEd Tanous     uint64_t currentCodeIndex = 0;
2068d2f868cSEd Tanous     uint64_t firstCodeTimeUs = 0;
2076a42dc61SPotin Lai     for (const std::pair<uint64_t, std::tuple<std::vector<uint8_t>,
2086a42dc61SPotin Lai                                               std::vector<uint8_t>>>& code :
2096a42dc61SPotin Lai          postcode)
2108d2f868cSEd Tanous     {
2118d2f868cSEd Tanous         currentCodeIndex++;
2128d2f868cSEd Tanous         std::string postcodeEntryID =
2138d2f868cSEd Tanous             "B" + std::to_string(bootIndex) + "-" +
2148d2f868cSEd Tanous             std::to_string(currentCodeIndex); // 1 based index in EntryID string
2158d2f868cSEd Tanous 
2168d2f868cSEd Tanous         uint64_t usecSinceEpoch = code.first;
2178d2f868cSEd Tanous         uint64_t usTimeOffset = 0;
2188d2f868cSEd Tanous 
2198d2f868cSEd Tanous         if (1 == currentCodeIndex)
2208d2f868cSEd Tanous         { // already incremented
2218d2f868cSEd Tanous             firstCodeTimeUs = code.first;
2228d2f868cSEd Tanous         }
2238d2f868cSEd Tanous         else
2248d2f868cSEd Tanous         {
2258d2f868cSEd Tanous             usTimeOffset = code.first - firstCodeTimeUs;
2268d2f868cSEd Tanous         }
2278d2f868cSEd Tanous 
2288d2f868cSEd Tanous         // skip if no specific codeIndex is specified and currentCodeIndex does
2298d2f868cSEd Tanous         // not fall between top and skip
2308d2f868cSEd Tanous         if ((codeIndex == 0) &&
2318d2f868cSEd Tanous             (currentCodeIndex <= skip || currentCodeIndex > top))
2328d2f868cSEd Tanous         {
2338d2f868cSEd Tanous             continue;
2348d2f868cSEd Tanous         }
2358d2f868cSEd Tanous 
2368d2f868cSEd Tanous         // skip if a specific codeIndex is specified and does not match the
2378d2f868cSEd Tanous         // currentIndex
2388d2f868cSEd Tanous         if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
2398d2f868cSEd Tanous         {
2408d2f868cSEd Tanous             // This is done for simplicity. 1st entry is needed to calculate
2418d2f868cSEd Tanous             // time offset. To improve efficiency, one can get to the entry
2428d2f868cSEd Tanous             // directly (possibly with flatmap's nth method)
2438d2f868cSEd Tanous             continue;
2448d2f868cSEd Tanous         }
2458d2f868cSEd Tanous 
2468d2f868cSEd Tanous         // currentCodeIndex is within top and skip or equal to specified code
2478d2f868cSEd Tanous         // index
2488d2f868cSEd Tanous 
2498d2f868cSEd Tanous         // Get the Created time from the timestamp
2508d2f868cSEd Tanous         std::string entryTimeStr;
2518d2f868cSEd Tanous         entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
2528d2f868cSEd Tanous 
2538d2f868cSEd Tanous         // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
2548d2f868cSEd Tanous         std::ostringstream timeOffsetStr;
2558d2f868cSEd Tanous         // Set Fixed -Point Notation
2568d2f868cSEd Tanous         timeOffsetStr << std::fixed;
2578d2f868cSEd Tanous         // Set precision to 4 digits
2588d2f868cSEd Tanous         timeOffsetStr << std::setprecision(4);
2598d2f868cSEd Tanous         // Add double to stream
2608d2f868cSEd Tanous         timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
2618d2f868cSEd Tanous 
2628d2f868cSEd Tanous         std::string bootIndexStr = std::to_string(bootIndex);
2638d2f868cSEd Tanous         std::string timeOffsetString = timeOffsetStr.str();
2646a42dc61SPotin Lai         std::string hexCodeStr =
2656a42dc61SPotin Lai             "0x" + bytesToHexString(std::get<0>(code.second));
2668d2f868cSEd Tanous 
2678d2f868cSEd Tanous         std::array<std::string_view, 3> messageArgs = {
2688d2f868cSEd Tanous             bootIndexStr, timeOffsetString, hexCodeStr};
2698d2f868cSEd Tanous 
2708d2f868cSEd Tanous         std::string msg =
2718d2f868cSEd Tanous             redfish::registries::fillMessageArgs(messageArgs, message->message);
2728d2f868cSEd Tanous         if (msg.empty())
2738d2f868cSEd Tanous         {
2748d2f868cSEd Tanous             messages::internalError(asyncResp->res);
2758d2f868cSEd Tanous             return false;
2768d2f868cSEd Tanous         }
2778d2f868cSEd Tanous 
2788d2f868cSEd Tanous         // Get Severity template from message registry
2798d2f868cSEd Tanous         std::string severity;
2808d2f868cSEd Tanous         if (message != nullptr)
2818d2f868cSEd Tanous         {
2828d2f868cSEd Tanous             severity = message->messageSeverity;
2838d2f868cSEd Tanous         }
2848d2f868cSEd Tanous 
2858d2f868cSEd Tanous         // Format entry
2868d2f868cSEd Tanous         nlohmann::json::object_t bmcLogEntry;
2878d2f868cSEd Tanous         bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
2888d2f868cSEd Tanous         bmcLogEntry["@odata.id"] = boost::urls::format(
2898d2f868cSEd Tanous             "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/{}",
2908d2f868cSEd Tanous             BMCWEB_REDFISH_SYSTEM_URI_NAME, postcodeEntryID);
2918d2f868cSEd Tanous         bmcLogEntry["Name"] = "POST Code Log Entry";
2928d2f868cSEd Tanous         bmcLogEntry["Id"] = postcodeEntryID;
2938d2f868cSEd Tanous         bmcLogEntry["Message"] = std::move(msg);
2948d2f868cSEd Tanous         bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
2958d2f868cSEd Tanous         bmcLogEntry["MessageArgs"] = messageArgs;
2968d2f868cSEd Tanous         bmcLogEntry["EntryType"] = "Event";
2978d2f868cSEd Tanous         bmcLogEntry["Severity"] = std::move(severity);
2988d2f868cSEd Tanous         bmcLogEntry["Created"] = entryTimeStr;
2996a42dc61SPotin Lai         if (!std::get<1>(code.second).empty())
3008d2f868cSEd Tanous         {
3018d2f868cSEd Tanous             bmcLogEntry["AdditionalDataURI"] =
3028d2f868cSEd Tanous                 std::format(
3038d2f868cSEd Tanous                     "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries/",
3048d2f868cSEd Tanous                     BMCWEB_REDFISH_SYSTEM_URI_NAME) +
3058d2f868cSEd Tanous                 postcodeEntryID + "/attachment";
3068d2f868cSEd Tanous         }
3078d2f868cSEd Tanous 
3088d2f868cSEd Tanous         // codeIndex is only specified when querying single entry, return only
3098d2f868cSEd Tanous         // that entry in this case
3108d2f868cSEd Tanous         if (codeIndex != 0)
3118d2f868cSEd Tanous         {
3128d2f868cSEd Tanous             asyncResp->res.jsonValue.update(bmcLogEntry);
3138d2f868cSEd Tanous             return true;
3148d2f868cSEd Tanous         }
3158d2f868cSEd Tanous 
3168d2f868cSEd Tanous         nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
3178d2f868cSEd Tanous         logEntryArray.emplace_back(std::move(bmcLogEntry));
3188d2f868cSEd Tanous     }
3198d2f868cSEd Tanous 
3208d2f868cSEd Tanous     // Return value is always false when querying multiple entries
3218d2f868cSEd Tanous     return false;
3228d2f868cSEd Tanous }
3238d2f868cSEd Tanous 
getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & entryId)324504af5a0SPatrick Williams inline void getPostCodeForEntry(
325504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3268d2f868cSEd Tanous     const std::string& entryId)
3278d2f868cSEd Tanous {
3288d2f868cSEd Tanous     uint16_t bootIndex = 0;
3298d2f868cSEd Tanous     uint64_t codeIndex = 0;
3308d2f868cSEd Tanous     if (!parsePostCode(entryId, codeIndex, bootIndex))
3318d2f868cSEd Tanous     {
3328d2f868cSEd Tanous         // Requested ID was not found
3338d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
3348d2f868cSEd Tanous         return;
3358d2f868cSEd Tanous     }
3368d2f868cSEd Tanous 
3378d2f868cSEd Tanous     if (bootIndex == 0 || codeIndex == 0)
3388d2f868cSEd Tanous     {
3398d2f868cSEd Tanous         // 0 is an invalid index
3408d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
3418d2f868cSEd Tanous         return;
3428d2f868cSEd Tanous     }
3438d2f868cSEd Tanous 
344*177612aaSEd Tanous     dbus::utility::async_method_call(
345*177612aaSEd Tanous         asyncResp,
3468d2f868cSEd Tanous         [asyncResp, entryId, bootIndex,
3478d2f868cSEd Tanous          codeIndex](const boost::system::error_code& ec,
3488d2f868cSEd Tanous                     const boost::container::flat_map<
3496a42dc61SPotin Lai                         uint64_t, std::tuple<std::vector<uint8_t>,
3506a42dc61SPotin Lai                                              std::vector<uint8_t>>>& 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             if (postcode.empty())
3598d2f868cSEd Tanous             {
3608d2f868cSEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
3618d2f868cSEd Tanous                 return;
3628d2f868cSEd Tanous             }
3638d2f868cSEd Tanous 
3648d2f868cSEd Tanous             if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
3658d2f868cSEd Tanous             {
3668d2f868cSEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
3678d2f868cSEd Tanous                 return;
3688d2f868cSEd Tanous             }
3698d2f868cSEd Tanous         },
3708d2f868cSEd Tanous         "xyz.openbmc_project.State.Boot.PostCode0",
3718d2f868cSEd Tanous         "/xyz/openbmc_project/State/Boot/PostCode0",
3728d2f868cSEd Tanous         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3738d2f868cSEd Tanous         bootIndex);
3748d2f868cSEd Tanous }
3758d2f868cSEd Tanous 
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)376504af5a0SPatrick Williams inline void getPostCodeForBoot(
377504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3788d2f868cSEd Tanous     const uint16_t bootIndex, const uint16_t bootCount,
3798d2f868cSEd Tanous     const uint64_t entryCount, size_t skip, size_t top)
3808d2f868cSEd Tanous {
381*177612aaSEd Tanous     dbus::utility::async_method_call(
382*177612aaSEd Tanous         asyncResp,
3838d2f868cSEd Tanous         [asyncResp, bootIndex, bootCount, entryCount, skip,
3848d2f868cSEd Tanous          top](const boost::system::error_code& ec,
3858d2f868cSEd Tanous               const boost::container::flat_map<
3866a42dc61SPotin Lai                   uint64_t, std::tuple<std::vector<uint8_t>,
3876a42dc61SPotin Lai                                        std::vector<uint8_t>>>& postcode) {
3888d2f868cSEd Tanous             if (ec)
3898d2f868cSEd Tanous             {
3908d2f868cSEd Tanous                 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
3918d2f868cSEd Tanous                 messages::internalError(asyncResp->res);
3928d2f868cSEd Tanous                 return;
3938d2f868cSEd Tanous             }
3948d2f868cSEd Tanous 
3958d2f868cSEd Tanous             uint64_t endCount = entryCount;
3968d2f868cSEd Tanous             if (!postcode.empty())
3978d2f868cSEd Tanous             {
3988d2f868cSEd Tanous                 endCount = entryCount + postcode.size();
3998d2f868cSEd Tanous                 if (skip < endCount && (top + skip) > entryCount)
4008d2f868cSEd Tanous                 {
4018d2f868cSEd Tanous                     uint64_t thisBootSkip =
4028d2f868cSEd Tanous                         std::max(static_cast<uint64_t>(skip), entryCount) -
4038d2f868cSEd Tanous                         entryCount;
4048d2f868cSEd Tanous                     uint64_t thisBootTop =
4058d2f868cSEd Tanous                         std::min(static_cast<uint64_t>(top + skip), endCount) -
4068d2f868cSEd Tanous                         entryCount;
4078d2f868cSEd Tanous 
4088d2f868cSEd Tanous                     fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
4098d2f868cSEd Tanous                                       thisBootSkip, thisBootTop);
4108d2f868cSEd Tanous                 }
4118d2f868cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] = endCount;
4128d2f868cSEd Tanous             }
4138d2f868cSEd Tanous 
4148d2f868cSEd Tanous             // continue to previous bootIndex
4158d2f868cSEd Tanous             if (bootIndex < bootCount)
4168d2f868cSEd Tanous             {
4178d2f868cSEd Tanous                 getPostCodeForBoot(asyncResp,
4188d2f868cSEd Tanous                                    static_cast<uint16_t>(bootIndex + 1),
4198d2f868cSEd Tanous                                    bootCount, endCount, skip, top);
4208d2f868cSEd Tanous             }
4218d2f868cSEd Tanous             else if (skip + top < endCount)
4228d2f868cSEd Tanous             {
4238d2f868cSEd Tanous                 asyncResp->res.jsonValue["Members@odata.nextLink"] =
4248d2f868cSEd Tanous                     std::format(
4258d2f868cSEd Tanous                         "/redfish/v1/Systems/{}/LogServices/PostCodes/Entries?$skip=",
4268d2f868cSEd Tanous                         BMCWEB_REDFISH_SYSTEM_URI_NAME) +
4278d2f868cSEd Tanous                     std::to_string(skip + top);
4288d2f868cSEd Tanous             }
4298d2f868cSEd Tanous         },
4308d2f868cSEd Tanous         "xyz.openbmc_project.State.Boot.PostCode0",
4318d2f868cSEd Tanous         "/xyz/openbmc_project/State/Boot/PostCode0",
4328d2f868cSEd Tanous         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4338d2f868cSEd Tanous         bootIndex);
4348d2f868cSEd Tanous }
4358d2f868cSEd Tanous 
getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,size_t skip,size_t top)436504af5a0SPatrick Williams inline void getCurrentBootNumber(
437504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, size_t skip,
438504af5a0SPatrick Williams     size_t top)
4398d2f868cSEd Tanous {
4408d2f868cSEd Tanous     uint64_t entryCount = 0;
441deae6a78SEd Tanous     dbus::utility::getProperty<uint16_t>(
4428d2f868cSEd Tanous         "xyz.openbmc_project.State.Boot.PostCode0",
4438d2f868cSEd Tanous         "/xyz/openbmc_project/State/Boot/PostCode0",
4448d2f868cSEd Tanous         "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
4458d2f868cSEd Tanous         [asyncResp, entryCount, skip,
4468d2f868cSEd Tanous          top](const boost::system::error_code& ec, const uint16_t bootCount) {
4478d2f868cSEd Tanous             if (ec)
4488d2f868cSEd Tanous             {
4498d2f868cSEd Tanous                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
4508d2f868cSEd Tanous                 messages::internalError(asyncResp->res);
4518d2f868cSEd Tanous                 return;
4528d2f868cSEd Tanous             }
4538d2f868cSEd Tanous             getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
4548d2f868cSEd Tanous         });
4558d2f868cSEd Tanous }
4568d2f868cSEd Tanous 
handleSystemsLogServicesPostCodesEntriesGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)45734fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesGet(
45834fe470aSEd Tanous     App& app, const crow::Request& req,
4598d2f868cSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
46034fe470aSEd Tanous     const std::string& systemName)
46134fe470aSEd Tanous {
4628d2f868cSEd Tanous     query_param::QueryCapabilities capabilities = {
4638d2f868cSEd Tanous         .canDelegateTop = true,
4648d2f868cSEd Tanous         .canDelegateSkip = true,
4658d2f868cSEd Tanous     };
4668d2f868cSEd Tanous     query_param::Query delegatedQuery;
46734fe470aSEd Tanous     if (!redfish::setUpRedfishRouteWithDelegation(app, req, asyncResp,
46834fe470aSEd Tanous                                                   delegatedQuery, capabilities))
4698d2f868cSEd Tanous     {
4708d2f868cSEd Tanous         return;
4718d2f868cSEd Tanous     }
4728d2f868cSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
4738d2f868cSEd Tanous     {
4748d2f868cSEd Tanous         // Option currently returns no systems.  TBD
4758d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4768d2f868cSEd Tanous                                    systemName);
4778d2f868cSEd Tanous         return;
4788d2f868cSEd Tanous     }
4798d2f868cSEd Tanous 
4808d2f868cSEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
4818d2f868cSEd Tanous     {
4828d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4838d2f868cSEd Tanous                                    systemName);
4848d2f868cSEd Tanous         return;
4858d2f868cSEd Tanous     }
4868d2f868cSEd Tanous     asyncResp->res.jsonValue["@odata.type"] =
4878d2f868cSEd Tanous         "#LogEntryCollection.LogEntryCollection";
48834fe470aSEd Tanous     asyncResp->res.jsonValue["@odata.id"] =
48934fe470aSEd Tanous         std::format("/redfish/v1/Systems/{}/LogServices/PostCodes/Entries",
4908d2f868cSEd Tanous                     BMCWEB_REDFISH_SYSTEM_URI_NAME);
4918d2f868cSEd Tanous     asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
4928d2f868cSEd Tanous     asyncResp->res.jsonValue["Description"] =
4938d2f868cSEd Tanous         "Collection of POST Code Log Entries";
4948d2f868cSEd Tanous     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
4958d2f868cSEd Tanous     asyncResp->res.jsonValue["Members@odata.count"] = 0;
4968d2f868cSEd Tanous     size_t skip = delegatedQuery.skip.value_or(0);
49734fe470aSEd Tanous     size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
4988d2f868cSEd Tanous     getCurrentBootNumber(asyncResp, skip, top);
4998d2f868cSEd Tanous }
5008d2f868cSEd Tanous 
handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & postCodeID)50134fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet(
50234fe470aSEd Tanous     App& app, const crow::Request& req,
5038d2f868cSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
50434fe470aSEd Tanous     const std::string& systemName, const std::string& postCodeID)
50534fe470aSEd Tanous {
5068d2f868cSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
5078d2f868cSEd Tanous     {
5088d2f868cSEd Tanous         return;
5098d2f868cSEd Tanous     }
5108d2f868cSEd Tanous     if (!http_helpers::isContentTypeAllowed(
5118d2f868cSEd Tanous             req.getHeaderValue("Accept"),
5128d2f868cSEd Tanous             http_helpers::ContentType::OctetStream, true))
5138d2f868cSEd Tanous     {
5148d2f868cSEd Tanous         asyncResp->res.result(boost::beast::http::status::bad_request);
5158d2f868cSEd Tanous         return;
5168d2f868cSEd Tanous     }
5178d2f868cSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
5188d2f868cSEd Tanous     {
5198d2f868cSEd Tanous         // Option currently returns no systems.  TBD
5208d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5218d2f868cSEd Tanous                                    systemName);
5228d2f868cSEd Tanous         return;
5238d2f868cSEd Tanous     }
5248d2f868cSEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
5258d2f868cSEd Tanous     {
5268d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
5278d2f868cSEd Tanous                                    systemName);
5288d2f868cSEd Tanous         return;
5298d2f868cSEd Tanous     }
5308d2f868cSEd Tanous 
5318d2f868cSEd Tanous     uint64_t currentValue = 0;
5328d2f868cSEd Tanous     uint16_t index = 0;
5338d2f868cSEd Tanous     if (!parsePostCode(postCodeID, currentValue, index))
5348d2f868cSEd Tanous     {
53534fe470aSEd Tanous         messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
5368d2f868cSEd Tanous         return;
5378d2f868cSEd Tanous     }
5388d2f868cSEd Tanous 
539*177612aaSEd Tanous     dbus::utility::async_method_call(
540*177612aaSEd Tanous         asyncResp,
5418d2f868cSEd Tanous         [asyncResp, postCodeID, currentValue](
5428d2f868cSEd Tanous             const boost::system::error_code& ec,
5436a42dc61SPotin Lai             const std::vector<std::tuple<std::vector<uint8_t>,
5446a42dc61SPotin Lai                                          std::vector<uint8_t>>>& postcodes) {
5458d2f868cSEd Tanous             if (ec.value() == EBADR)
5468d2f868cSEd Tanous             {
5478d2f868cSEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry",
5488d2f868cSEd Tanous                                            postCodeID);
5498d2f868cSEd Tanous                 return;
5508d2f868cSEd Tanous             }
5518d2f868cSEd Tanous             if (ec)
5528d2f868cSEd Tanous             {
5538d2f868cSEd Tanous                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
5548d2f868cSEd Tanous                 messages::internalError(asyncResp->res);
5558d2f868cSEd Tanous                 return;
5568d2f868cSEd Tanous             }
5578d2f868cSEd Tanous 
5588d2f868cSEd Tanous             size_t value = static_cast<size_t>(currentValue) - 1;
55934fe470aSEd Tanous             if (value == std::string::npos || postcodes.size() < currentValue)
5608d2f868cSEd Tanous             {
5618d2f868cSEd Tanous                 BMCWEB_LOG_WARNING("Wrong currentValue value");
5628d2f868cSEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry",
5638d2f868cSEd Tanous                                            postCodeID);
5648d2f868cSEd Tanous                 return;
5658d2f868cSEd Tanous             }
5668d2f868cSEd Tanous 
5678d2f868cSEd Tanous             const auto& [tID, c] = postcodes[value];
5688d2f868cSEd Tanous             if (c.empty())
5698d2f868cSEd Tanous             {
5708d2f868cSEd Tanous                 BMCWEB_LOG_WARNING("No found post code data");
5718d2f868cSEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry",
5728d2f868cSEd Tanous                                            postCodeID);
5738d2f868cSEd Tanous                 return;
5748d2f868cSEd Tanous             }
5758d2f868cSEd Tanous             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
5768d2f868cSEd Tanous             const char* d = reinterpret_cast<const char*>(c.data());
5778d2f868cSEd Tanous             std::string_view strData(d, c.size());
5788d2f868cSEd Tanous 
57934fe470aSEd Tanous             asyncResp->res.addHeader(boost::beast::http::field::content_type,
5808d2f868cSEd Tanous                                      "application/octet-stream");
5818d2f868cSEd Tanous             asyncResp->res.addHeader(
58234fe470aSEd Tanous                 boost::beast::http::field::content_transfer_encoding, "Base64");
5838d2f868cSEd Tanous             asyncResp->res.write(crow::utility::base64encode(strData));
5848d2f868cSEd Tanous         },
5858d2f868cSEd Tanous         "xyz.openbmc_project.State.Boot.PostCode0",
5868d2f868cSEd Tanous         "/xyz/openbmc_project/State/Boot/PostCode0",
58734fe470aSEd Tanous         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
5888d2f868cSEd Tanous }
5898d2f868cSEd Tanous 
handleSystemsLogServicesPostCodesEntriesEntryGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & targetID)59034fe470aSEd Tanous inline void handleSystemsLogServicesPostCodesEntriesEntryGet(
59134fe470aSEd Tanous     App& app, const crow::Request& req,
5928d2f868cSEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
59334fe470aSEd Tanous     const std::string& systemName, const std::string& targetID)
59434fe470aSEd Tanous {
5958d2f868cSEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
5968d2f868cSEd Tanous     {
5978d2f868cSEd Tanous         return;
5988d2f868cSEd Tanous     }
5998d2f868cSEd Tanous     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
6008d2f868cSEd Tanous     {
6018d2f868cSEd Tanous         // Option currently returns no systems.  TBD
6028d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6038d2f868cSEd Tanous                                    systemName);
6048d2f868cSEd Tanous         return;
6058d2f868cSEd Tanous     }
6068d2f868cSEd Tanous     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
6078d2f868cSEd Tanous     {
6088d2f868cSEd Tanous         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
6098d2f868cSEd Tanous                                    systemName);
6108d2f868cSEd Tanous         return;
6118d2f868cSEd Tanous     }
6128d2f868cSEd Tanous 
6138d2f868cSEd Tanous     getPostCodeForEntry(asyncResp, targetID);
6148d2f868cSEd Tanous }
6158d2f868cSEd Tanous 
requestRoutesSystemsLogServicesPostCode(App & app)6168d2f868cSEd Tanous inline void requestRoutesSystemsLogServicesPostCode(App& app)
6178d2f868cSEd Tanous {
61834fe470aSEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
61934fe470aSEd Tanous         .privileges(redfish::privileges::getLogService)
62034fe470aSEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
62134fe470aSEd Tanous             handleSystemsLogServicesPostCodesGet, std::ref(app)));
62234fe470aSEd Tanous 
62334fe470aSEd Tanous     BMCWEB_ROUTE(
62434fe470aSEd Tanous         app,
62534fe470aSEd Tanous         "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
6269d62d126SGunnar Mills         // The following privilege is correct; we need "SubordinateOverrides"
6279d62d126SGunnar Mills         // before we can automate it.
62834fe470aSEd Tanous         .privileges({{"ConfigureComponents"}})
62934fe470aSEd Tanous         .methods(boost::beast::http::verb::post)(std::bind_front(
63034fe470aSEd Tanous             handleSystemsLogServicesPostCodesPost, std::ref(app)));
63134fe470aSEd Tanous 
63234fe470aSEd Tanous     BMCWEB_ROUTE(app,
63334fe470aSEd Tanous                  "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
63434fe470aSEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
63534fe470aSEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
63634fe470aSEd Tanous             handleSystemsLogServicesPostCodesEntriesGet, std::ref(app)));
63734fe470aSEd Tanous 
63834fe470aSEd Tanous     BMCWEB_ROUTE(
63934fe470aSEd Tanous         app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
64034fe470aSEd Tanous         .privileges(redfish::privileges::getLogEntry)
64134fe470aSEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
64234fe470aSEd Tanous             handleSystemsLogServicesPostCodesEntriesEntryGet, std::ref(app)));
64334fe470aSEd Tanous 
64434fe470aSEd Tanous     BMCWEB_ROUTE(
64534fe470aSEd Tanous         app,
64634fe470aSEd Tanous         "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
64734fe470aSEd Tanous         .privileges(redfish::privileges::getLogEntry)
64834fe470aSEd Tanous         .methods(boost::beast::http::verb::get)(std::bind_front(
64934fe470aSEd Tanous             handleSystemsLogServicesPostCodesEntriesEntryAdditionalDataGet,
65034fe470aSEd Tanous             std::ref(app)));
6518d2f868cSEd Tanous }
6528d2f868cSEd Tanous } // namespace redfish
653