xref: /openbmc/bmcweb/features/redfish/lib/log_services.hpp (revision 3ba0007367777144f474fdf99439ae8c03633486)
11da66f75SEd Tanous /*
21da66f75SEd Tanous // Copyright (c) 2018 Intel Corporation
31da66f75SEd Tanous //
41da66f75SEd Tanous // Licensed under the Apache License, Version 2.0 (the "License");
51da66f75SEd Tanous // you may not use this file except in compliance with the License.
61da66f75SEd Tanous // You may obtain a copy of the License at
71da66f75SEd Tanous //
81da66f75SEd Tanous //      http://www.apache.org/licenses/LICENSE-2.0
91da66f75SEd Tanous //
101da66f75SEd Tanous // Unless required by applicable law or agreed to in writing, software
111da66f75SEd Tanous // distributed under the License is distributed on an "AS IS" BASIS,
121da66f75SEd Tanous // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131da66f75SEd Tanous // See the License for the specific language governing permissions and
141da66f75SEd Tanous // limitations under the License.
151da66f75SEd Tanous */
161da66f75SEd Tanous #pragma once
171da66f75SEd Tanous 
18b7028ebfSSpencer Ku #include "gzfile.hpp"
19647b3cdcSGeorge Liu #include "http_utility.hpp"
20b7028ebfSSpencer Ku #include "human_sort.hpp"
214851d45dSJason M. Bills #include "registries.hpp"
224851d45dSJason M. Bills #include "registries/base_message_registry.hpp"
234851d45dSJason M. Bills #include "registries/openbmc_message_registry.hpp"
2446229577SJames Feist #include "task.hpp"
251da66f75SEd Tanous 
26e1f26343SJason M. Bills #include <systemd/sd-journal.h>
27400fd1fbSAdriana Kobylak #include <unistd.h>
28e1f26343SJason M. Bills 
297e860f15SJohn Edward Broadbent #include <app.hpp>
30400fd1fbSAdriana Kobylak #include <boost/algorithm/string/replace.hpp>
314851d45dSJason M. Bills #include <boost/algorithm/string/split.hpp>
32400fd1fbSAdriana Kobylak #include <boost/beast/http.hpp>
331da66f75SEd Tanous #include <boost/container/flat_map.hpp>
341ddcf01aSJason M. Bills #include <boost/system/linux_error.hpp>
35168e20c1SEd Tanous #include <dbus_utility.hpp>
36cb92c03bSAndrew Geissler #include <error_messages.hpp>
3745ca1b86SEd Tanous #include <query.hpp>
38ed398213SEd Tanous #include <registries/privilege_registry.hpp>
391214b7e7SGunnar Mills 
40647b3cdcSGeorge Liu #include <charconv>
414418c7f0SJames Feist #include <filesystem>
4275710de2SXiaochao Ma #include <optional>
4326702d01SEd Tanous #include <span>
44cd225da8SJason M. Bills #include <string_view>
45abf2add6SEd Tanous #include <variant>
461da66f75SEd Tanous 
471da66f75SEd Tanous namespace redfish
481da66f75SEd Tanous {
491da66f75SEd Tanous 
505b61b5e8SJason M. Bills constexpr char const* crashdumpObject = "com.intel.crashdump";
515b61b5e8SJason M. Bills constexpr char const* crashdumpPath = "/com/intel/crashdump";
525b61b5e8SJason M. Bills constexpr char const* crashdumpInterface = "com.intel.crashdump";
535b61b5e8SJason M. Bills constexpr char const* deleteAllInterface =
545b61b5e8SJason M. Bills     "xyz.openbmc_project.Collection.DeleteAll";
555b61b5e8SJason M. Bills constexpr char const* crashdumpOnDemandInterface =
56424c4176SJason M. Bills     "com.intel.crashdump.OnDemand";
576eda7685SKenny L. Ku constexpr char const* crashdumpTelemetryInterface =
586eda7685SKenny L. Ku     "com.intel.crashdump.Telemetry";
591da66f75SEd Tanous 
60fffb8c1fSEd Tanous namespace registries
614851d45dSJason M. Bills {
6226702d01SEd Tanous static const Message*
6326702d01SEd Tanous     getMessageFromRegistry(const std::string& messageKey,
6426702d01SEd Tanous                            const std::span<const MessageEntry> registry)
654851d45dSJason M. Bills {
66002d39b4SEd Tanous     std::span<const MessageEntry>::iterator messageIt =
67002d39b4SEd Tanous         std::find_if(registry.begin(), registry.end(),
684851d45dSJason M. Bills                      [&messageKey](const MessageEntry& messageEntry) {
69e662eae8SEd Tanous         return std::strcmp(messageEntry.first, messageKey.c_str()) == 0;
704851d45dSJason M. Bills         });
7126702d01SEd Tanous     if (messageIt != registry.end())
724851d45dSJason M. Bills     {
734851d45dSJason M. Bills         return &messageIt->second;
744851d45dSJason M. Bills     }
754851d45dSJason M. Bills 
764851d45dSJason M. Bills     return nullptr;
774851d45dSJason M. Bills }
784851d45dSJason M. Bills 
794851d45dSJason M. Bills static const Message* getMessage(const std::string_view& messageID)
804851d45dSJason M. Bills {
814851d45dSJason M. Bills     // Redfish MessageIds are in the form
824851d45dSJason M. Bills     // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
834851d45dSJason M. Bills     // the right Message
844851d45dSJason M. Bills     std::vector<std::string> fields;
854851d45dSJason M. Bills     fields.reserve(4);
864851d45dSJason M. Bills     boost::split(fields, messageID, boost::is_any_of("."));
874851d45dSJason M. Bills     std::string& registryName = fields[0];
884851d45dSJason M. Bills     std::string& messageKey = fields[3];
894851d45dSJason M. Bills 
904851d45dSJason M. Bills     // Find the right registry and check it for the MessageKey
914851d45dSJason M. Bills     if (std::string(base::header.registryPrefix) == registryName)
924851d45dSJason M. Bills     {
934851d45dSJason M. Bills         return getMessageFromRegistry(
9426702d01SEd Tanous             messageKey, std::span<const MessageEntry>(base::registry));
954851d45dSJason M. Bills     }
964851d45dSJason M. Bills     if (std::string(openbmc::header.registryPrefix) == registryName)
974851d45dSJason M. Bills     {
984851d45dSJason M. Bills         return getMessageFromRegistry(
9926702d01SEd Tanous             messageKey, std::span<const MessageEntry>(openbmc::registry));
1004851d45dSJason M. Bills     }
1014851d45dSJason M. Bills     return nullptr;
1024851d45dSJason M. Bills }
103fffb8c1fSEd Tanous } // namespace registries
1044851d45dSJason M. Bills 
105f6150403SJames Feist namespace fs = std::filesystem;
1061da66f75SEd Tanous 
107cb92c03bSAndrew Geissler inline std::string translateSeverityDbusToRedfish(const std::string& s)
108cb92c03bSAndrew Geissler {
109d4d25793SEd Tanous     if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
110d4d25793SEd Tanous         (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
111d4d25793SEd Tanous         (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
112d4d25793SEd Tanous         (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
113cb92c03bSAndrew Geissler     {
114cb92c03bSAndrew Geissler         return "Critical";
115cb92c03bSAndrew Geissler     }
1163174e4dfSEd Tanous     if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
117d4d25793SEd Tanous         (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
118d4d25793SEd Tanous         (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
119cb92c03bSAndrew Geissler     {
120cb92c03bSAndrew Geissler         return "OK";
121cb92c03bSAndrew Geissler     }
1223174e4dfSEd Tanous     if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
123cb92c03bSAndrew Geissler     {
124cb92c03bSAndrew Geissler         return "Warning";
125cb92c03bSAndrew Geissler     }
126cb92c03bSAndrew Geissler     return "";
127cb92c03bSAndrew Geissler }
128cb92c03bSAndrew Geissler 
1297e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal,
13039e77504SEd Tanous                                      const std::string_view& field,
13139e77504SEd Tanous                                      std::string_view& contents)
13216428a1aSJason M. Bills {
13316428a1aSJason M. Bills     const char* data = nullptr;
13416428a1aSJason M. Bills     size_t length = 0;
13516428a1aSJason M. Bills     int ret = 0;
13616428a1aSJason M. Bills     // Get the metadata from the requested field of the journal entry
13746ff87baSEd Tanous     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
13846ff87baSEd Tanous     const void** dataVoid = reinterpret_cast<const void**>(&data);
13946ff87baSEd Tanous 
14046ff87baSEd Tanous     ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
14116428a1aSJason M. Bills     if (ret < 0)
14216428a1aSJason M. Bills     {
14316428a1aSJason M. Bills         return ret;
14416428a1aSJason M. Bills     }
14539e77504SEd Tanous     contents = std::string_view(data, length);
14616428a1aSJason M. Bills     // Only use the content after the "=" character.
14781ce609eSEd Tanous     contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
14816428a1aSJason M. Bills     return ret;
14916428a1aSJason M. Bills }
15016428a1aSJason M. Bills 
1517e860f15SJohn Edward Broadbent inline static int getJournalMetadata(sd_journal* journal,
1527e860f15SJohn Edward Broadbent                                      const std::string_view& field,
1537e860f15SJohn Edward Broadbent                                      const int& base, long int& contents)
15416428a1aSJason M. Bills {
15516428a1aSJason M. Bills     int ret = 0;
15639e77504SEd Tanous     std::string_view metadata;
15716428a1aSJason M. Bills     // Get the metadata from the requested field of the journal entry
15816428a1aSJason M. Bills     ret = getJournalMetadata(journal, field, metadata);
15916428a1aSJason M. Bills     if (ret < 0)
16016428a1aSJason M. Bills     {
16116428a1aSJason M. Bills         return ret;
16216428a1aSJason M. Bills     }
163b01bf299SEd Tanous     contents = strtol(metadata.data(), nullptr, base);
16416428a1aSJason M. Bills     return ret;
16516428a1aSJason M. Bills }
16616428a1aSJason M. Bills 
1677e860f15SJohn Edward Broadbent inline static bool getEntryTimestamp(sd_journal* journal,
1687e860f15SJohn Edward Broadbent                                      std::string& entryTimestamp)
169a3316fc6SZhikuiRen {
170a3316fc6SZhikuiRen     int ret = 0;
171a3316fc6SZhikuiRen     uint64_t timestamp = 0;
172a3316fc6SZhikuiRen     ret = sd_journal_get_realtime_usec(journal, &timestamp);
173a3316fc6SZhikuiRen     if (ret < 0)
174a3316fc6SZhikuiRen     {
175a3316fc6SZhikuiRen         BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
176a3316fc6SZhikuiRen                          << strerror(-ret);
177a3316fc6SZhikuiRen         return false;
178a3316fc6SZhikuiRen     }
1791d8782e7SNan Zhou     entryTimestamp = crow::utility::getDateTimeUint(timestamp / 1000 / 1000);
1809c620e21SAsmitha Karunanithi     return true;
181a3316fc6SZhikuiRen }
18250b8a43aSEd Tanous 
1837e860f15SJohn Edward Broadbent inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
184e85d6b16SJason M. Bills                                     const bool firstEntry = true)
18516428a1aSJason M. Bills {
18616428a1aSJason M. Bills     int ret = 0;
18716428a1aSJason M. Bills     static uint64_t prevTs = 0;
18816428a1aSJason M. Bills     static int index = 0;
189e85d6b16SJason M. Bills     if (firstEntry)
190e85d6b16SJason M. Bills     {
191e85d6b16SJason M. Bills         prevTs = 0;
192e85d6b16SJason M. Bills     }
193e85d6b16SJason M. Bills 
19416428a1aSJason M. Bills     // Get the entry timestamp
19516428a1aSJason M. Bills     uint64_t curTs = 0;
19616428a1aSJason M. Bills     ret = sd_journal_get_realtime_usec(journal, &curTs);
19716428a1aSJason M. Bills     if (ret < 0)
19816428a1aSJason M. Bills     {
19916428a1aSJason M. Bills         BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
20016428a1aSJason M. Bills                          << strerror(-ret);
20116428a1aSJason M. Bills         return false;
20216428a1aSJason M. Bills     }
20316428a1aSJason M. Bills     // If the timestamp isn't unique, increment the index
20416428a1aSJason M. Bills     if (curTs == prevTs)
20516428a1aSJason M. Bills     {
20616428a1aSJason M. Bills         index++;
20716428a1aSJason M. Bills     }
20816428a1aSJason M. Bills     else
20916428a1aSJason M. Bills     {
21016428a1aSJason M. Bills         // Otherwise, reset it
21116428a1aSJason M. Bills         index = 0;
21216428a1aSJason M. Bills     }
21316428a1aSJason M. Bills     // Save the timestamp
21416428a1aSJason M. Bills     prevTs = curTs;
21516428a1aSJason M. Bills 
21616428a1aSJason M. Bills     entryID = std::to_string(curTs);
21716428a1aSJason M. Bills     if (index > 0)
21816428a1aSJason M. Bills     {
21916428a1aSJason M. Bills         entryID += "_" + std::to_string(index);
22016428a1aSJason M. Bills     }
22116428a1aSJason M. Bills     return true;
22216428a1aSJason M. Bills }
22316428a1aSJason M. Bills 
224e85d6b16SJason M. Bills static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
225e85d6b16SJason M. Bills                              const bool firstEntry = true)
22695820184SJason M. Bills {
227271584abSEd Tanous     static time_t prevTs = 0;
22895820184SJason M. Bills     static int index = 0;
229e85d6b16SJason M. Bills     if (firstEntry)
230e85d6b16SJason M. Bills     {
231e85d6b16SJason M. Bills         prevTs = 0;
232e85d6b16SJason M. Bills     }
233e85d6b16SJason M. Bills 
23495820184SJason M. Bills     // Get the entry timestamp
235271584abSEd Tanous     std::time_t curTs = 0;
23695820184SJason M. Bills     std::tm timeStruct = {};
23795820184SJason M. Bills     std::istringstream entryStream(logEntry);
23895820184SJason M. Bills     if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
23995820184SJason M. Bills     {
24095820184SJason M. Bills         curTs = std::mktime(&timeStruct);
24195820184SJason M. Bills     }
24295820184SJason M. Bills     // If the timestamp isn't unique, increment the index
24395820184SJason M. Bills     if (curTs == prevTs)
24495820184SJason M. Bills     {
24595820184SJason M. Bills         index++;
24695820184SJason M. Bills     }
24795820184SJason M. Bills     else
24895820184SJason M. Bills     {
24995820184SJason M. Bills         // Otherwise, reset it
25095820184SJason M. Bills         index = 0;
25195820184SJason M. Bills     }
25295820184SJason M. Bills     // Save the timestamp
25395820184SJason M. Bills     prevTs = curTs;
25495820184SJason M. Bills 
25595820184SJason M. Bills     entryID = std::to_string(curTs);
25695820184SJason M. Bills     if (index > 0)
25795820184SJason M. Bills     {
25895820184SJason M. Bills         entryID += "_" + std::to_string(index);
25995820184SJason M. Bills     }
26095820184SJason M. Bills     return true;
26195820184SJason M. Bills }
26295820184SJason M. Bills 
2637e860f15SJohn Edward Broadbent inline static bool
2648d1b46d7Szhanghch05     getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2658d1b46d7Szhanghch05                        const std::string& entryID, uint64_t& timestamp,
2668d1b46d7Szhanghch05                        uint64_t& index)
26716428a1aSJason M. Bills {
26816428a1aSJason M. Bills     if (entryID.empty())
26916428a1aSJason M. Bills     {
27016428a1aSJason M. Bills         return false;
27116428a1aSJason M. Bills     }
27216428a1aSJason M. Bills     // Convert the unique ID back to a timestamp to find the entry
27339e77504SEd Tanous     std::string_view tsStr(entryID);
27416428a1aSJason M. Bills 
27581ce609eSEd Tanous     auto underscorePos = tsStr.find('_');
27671d5d8dbSEd Tanous     if (underscorePos != std::string_view::npos)
27716428a1aSJason M. Bills     {
27816428a1aSJason M. Bills         // Timestamp has an index
27916428a1aSJason M. Bills         tsStr.remove_suffix(tsStr.size() - underscorePos);
28039e77504SEd Tanous         std::string_view indexStr(entryID);
28116428a1aSJason M. Bills         indexStr.remove_prefix(underscorePos + 1);
282c0bd5e4bSEd Tanous         auto [ptr, ec] = std::from_chars(
283c0bd5e4bSEd Tanous             indexStr.data(), indexStr.data() + indexStr.size(), index);
284c0bd5e4bSEd Tanous         if (ec != std::errc())
28516428a1aSJason M. Bills         {
286ace85d60SEd Tanous             messages::resourceMissingAtURI(
287ace85d60SEd Tanous                 asyncResp->res, crow::utility::urlFromPieces(entryID));
28816428a1aSJason M. Bills             return false;
28916428a1aSJason M. Bills         }
29016428a1aSJason M. Bills     }
29116428a1aSJason M. Bills     // Timestamp has no index
292c0bd5e4bSEd Tanous     auto [ptr, ec] =
293c0bd5e4bSEd Tanous         std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp);
294c0bd5e4bSEd Tanous     if (ec != std::errc())
29516428a1aSJason M. Bills     {
296ace85d60SEd Tanous         messages::resourceMissingAtURI(asyncResp->res,
297ace85d60SEd Tanous                                        crow::utility::urlFromPieces(entryID));
29816428a1aSJason M. Bills         return false;
29916428a1aSJason M. Bills     }
30016428a1aSJason M. Bills     return true;
30116428a1aSJason M. Bills }
30216428a1aSJason M. Bills 
30395820184SJason M. Bills static bool
30495820184SJason M. Bills     getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
30595820184SJason M. Bills {
30695820184SJason M. Bills     static const std::filesystem::path redfishLogDir = "/var/log";
30795820184SJason M. Bills     static const std::string redfishLogFilename = "redfish";
30895820184SJason M. Bills 
30995820184SJason M. Bills     // Loop through the directory looking for redfish log files
31095820184SJason M. Bills     for (const std::filesystem::directory_entry& dirEnt :
31195820184SJason M. Bills          std::filesystem::directory_iterator(redfishLogDir))
31295820184SJason M. Bills     {
31395820184SJason M. Bills         // If we find a redfish log file, save the path
31495820184SJason M. Bills         std::string filename = dirEnt.path().filename();
31595820184SJason M. Bills         if (boost::starts_with(filename, redfishLogFilename))
31695820184SJason M. Bills         {
31795820184SJason M. Bills             redfishLogFiles.emplace_back(redfishLogDir / filename);
31895820184SJason M. Bills         }
31995820184SJason M. Bills     }
32095820184SJason M. Bills     // As the log files rotate, they are appended with a ".#" that is higher for
32195820184SJason M. Bills     // the older logs. Since we don't expect more than 10 log files, we
32295820184SJason M. Bills     // can just sort the list to get them in order from newest to oldest
32395820184SJason M. Bills     std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
32495820184SJason M. Bills 
32595820184SJason M. Bills     return !redfishLogFiles.empty();
32695820184SJason M. Bills }
32795820184SJason M. Bills 
3288d1b46d7Szhanghch05 inline void
3298d1b46d7Szhanghch05     getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3305cb1dd27SAsmitha Karunanithi                            const std::string& dumpType)
3315cb1dd27SAsmitha Karunanithi {
3325cb1dd27SAsmitha Karunanithi     std::string dumpPath;
3335cb1dd27SAsmitha Karunanithi     if (dumpType == "BMC")
3345cb1dd27SAsmitha Karunanithi     {
3355cb1dd27SAsmitha Karunanithi         dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
3365cb1dd27SAsmitha Karunanithi     }
3375cb1dd27SAsmitha Karunanithi     else if (dumpType == "System")
3385cb1dd27SAsmitha Karunanithi     {
3395cb1dd27SAsmitha Karunanithi         dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
3405cb1dd27SAsmitha Karunanithi     }
3415cb1dd27SAsmitha Karunanithi     else
3425cb1dd27SAsmitha Karunanithi     {
3435cb1dd27SAsmitha Karunanithi         BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
3445cb1dd27SAsmitha Karunanithi         messages::internalError(asyncResp->res);
3455cb1dd27SAsmitha Karunanithi         return;
3465cb1dd27SAsmitha Karunanithi     }
3475cb1dd27SAsmitha Karunanithi 
3485cb1dd27SAsmitha Karunanithi     crow::connections::systemBus->async_method_call(
349711ac7a9SEd Tanous         [asyncResp, dumpPath,
350711ac7a9SEd Tanous          dumpType](const boost::system::error_code ec,
351711ac7a9SEd Tanous                    dbus::utility::ManagedObjectType& resp) {
3525cb1dd27SAsmitha Karunanithi         if (ec)
3535cb1dd27SAsmitha Karunanithi         {
3545cb1dd27SAsmitha Karunanithi             BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
3555cb1dd27SAsmitha Karunanithi             messages::internalError(asyncResp->res);
3565cb1dd27SAsmitha Karunanithi             return;
3575cb1dd27SAsmitha Karunanithi         }
3585cb1dd27SAsmitha Karunanithi 
3595cb1dd27SAsmitha Karunanithi         nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
3605cb1dd27SAsmitha Karunanithi         entriesArray = nlohmann::json::array();
361b47452b2SAsmitha Karunanithi         std::string dumpEntryPath =
362b47452b2SAsmitha Karunanithi             "/xyz/openbmc_project/dump/" +
363002d39b4SEd Tanous             std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
3645cb1dd27SAsmitha Karunanithi 
365002d39b4SEd Tanous         std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) {
366002d39b4SEd Tanous             return AlphanumLess<std::string>()(l.first.filename(),
367002d39b4SEd Tanous                                                r.first.filename());
368565dfb6fSClaire Weinan         });
369565dfb6fSClaire Weinan 
3705cb1dd27SAsmitha Karunanithi         for (auto& object : resp)
3715cb1dd27SAsmitha Karunanithi         {
372b47452b2SAsmitha Karunanithi             if (object.first.str.find(dumpEntryPath) == std::string::npos)
3735cb1dd27SAsmitha Karunanithi             {
3745cb1dd27SAsmitha Karunanithi                 continue;
3755cb1dd27SAsmitha Karunanithi             }
3761d8782e7SNan Zhou             uint64_t timestamp = 0;
3775cb1dd27SAsmitha Karunanithi             uint64_t size = 0;
37835440d18SAsmitha Karunanithi             std::string dumpStatus;
37935440d18SAsmitha Karunanithi             nlohmann::json thisEntry;
3802dfd18efSEd Tanous 
3812dfd18efSEd Tanous             std::string entryID = object.first.filename();
3822dfd18efSEd Tanous             if (entryID.empty())
3835cb1dd27SAsmitha Karunanithi             {
3845cb1dd27SAsmitha Karunanithi                 continue;
3855cb1dd27SAsmitha Karunanithi             }
3865cb1dd27SAsmitha Karunanithi 
3875cb1dd27SAsmitha Karunanithi             for (auto& interfaceMap : object.second)
3885cb1dd27SAsmitha Karunanithi             {
389002d39b4SEd Tanous                 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
39035440d18SAsmitha Karunanithi                 {
3919eb808c1SEd Tanous                     for (const auto& propertyMap : interfaceMap.second)
39235440d18SAsmitha Karunanithi                     {
39335440d18SAsmitha Karunanithi                         if (propertyMap.first == "Status")
39435440d18SAsmitha Karunanithi                         {
395002d39b4SEd Tanous                             const auto* status =
396002d39b4SEd Tanous                                 std::get_if<std::string>(&propertyMap.second);
39735440d18SAsmitha Karunanithi                             if (status == nullptr)
39835440d18SAsmitha Karunanithi                             {
39935440d18SAsmitha Karunanithi                                 messages::internalError(asyncResp->res);
40035440d18SAsmitha Karunanithi                                 break;
40135440d18SAsmitha Karunanithi                             }
40235440d18SAsmitha Karunanithi                             dumpStatus = *status;
40335440d18SAsmitha Karunanithi                         }
40435440d18SAsmitha Karunanithi                     }
40535440d18SAsmitha Karunanithi                 }
406002d39b4SEd Tanous                 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
4075cb1dd27SAsmitha Karunanithi                 {
4085cb1dd27SAsmitha Karunanithi 
4095cb1dd27SAsmitha Karunanithi                     for (auto& propertyMap : interfaceMap.second)
4105cb1dd27SAsmitha Karunanithi                     {
4115cb1dd27SAsmitha Karunanithi                         if (propertyMap.first == "Size")
4125cb1dd27SAsmitha Karunanithi                         {
41355f79e6fSEd Tanous                             const auto* sizePtr =
4145cb1dd27SAsmitha Karunanithi                                 std::get_if<uint64_t>(&propertyMap.second);
4155cb1dd27SAsmitha Karunanithi                             if (sizePtr == nullptr)
4165cb1dd27SAsmitha Karunanithi                             {
4175cb1dd27SAsmitha Karunanithi                                 messages::internalError(asyncResp->res);
4185cb1dd27SAsmitha Karunanithi                                 break;
4195cb1dd27SAsmitha Karunanithi                             }
4205cb1dd27SAsmitha Karunanithi                             size = *sizePtr;
4215cb1dd27SAsmitha Karunanithi                             break;
4225cb1dd27SAsmitha Karunanithi                         }
4235cb1dd27SAsmitha Karunanithi                     }
4245cb1dd27SAsmitha Karunanithi                 }
4255cb1dd27SAsmitha Karunanithi                 else if (interfaceMap.first ==
4265cb1dd27SAsmitha Karunanithi                          "xyz.openbmc_project.Time.EpochTime")
4275cb1dd27SAsmitha Karunanithi                 {
4285cb1dd27SAsmitha Karunanithi 
4299eb808c1SEd Tanous                     for (const auto& propertyMap : interfaceMap.second)
4305cb1dd27SAsmitha Karunanithi                     {
4315cb1dd27SAsmitha Karunanithi                         if (propertyMap.first == "Elapsed")
4325cb1dd27SAsmitha Karunanithi                         {
4335cb1dd27SAsmitha Karunanithi                             const uint64_t* usecsTimeStamp =
4345cb1dd27SAsmitha Karunanithi                                 std::get_if<uint64_t>(&propertyMap.second);
4355cb1dd27SAsmitha Karunanithi                             if (usecsTimeStamp == nullptr)
4365cb1dd27SAsmitha Karunanithi                             {
4375cb1dd27SAsmitha Karunanithi                                 messages::internalError(asyncResp->res);
4385cb1dd27SAsmitha Karunanithi                                 break;
4395cb1dd27SAsmitha Karunanithi                             }
4401d8782e7SNan Zhou                             timestamp = (*usecsTimeStamp / 1000 / 1000);
4415cb1dd27SAsmitha Karunanithi                             break;
4425cb1dd27SAsmitha Karunanithi                         }
4435cb1dd27SAsmitha Karunanithi                     }
4445cb1dd27SAsmitha Karunanithi                 }
4455cb1dd27SAsmitha Karunanithi             }
4465cb1dd27SAsmitha Karunanithi 
4470fda0f12SGeorge Liu             if (dumpStatus !=
4480fda0f12SGeorge Liu                     "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
44935440d18SAsmitha Karunanithi                 !dumpStatus.empty())
45035440d18SAsmitha Karunanithi             {
45135440d18SAsmitha Karunanithi                 // Dump status is not Complete, no need to enumerate
45235440d18SAsmitha Karunanithi                 continue;
45335440d18SAsmitha Karunanithi             }
45435440d18SAsmitha Karunanithi 
455647b3cdcSGeorge Liu             thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
4565cb1dd27SAsmitha Karunanithi             thisEntry["@odata.id"] = dumpPath + entryID;
4575cb1dd27SAsmitha Karunanithi             thisEntry["Id"] = entryID;
4585cb1dd27SAsmitha Karunanithi             thisEntry["EntryType"] = "Event";
459002d39b4SEd Tanous             thisEntry["Created"] = crow::utility::getDateTimeUint(timestamp);
4605cb1dd27SAsmitha Karunanithi             thisEntry["Name"] = dumpType + " Dump Entry";
4615cb1dd27SAsmitha Karunanithi 
462d337bb72SAsmitha Karunanithi             thisEntry["AdditionalDataSizeBytes"] = size;
4635cb1dd27SAsmitha Karunanithi 
4645cb1dd27SAsmitha Karunanithi             if (dumpType == "BMC")
4655cb1dd27SAsmitha Karunanithi             {
466d337bb72SAsmitha Karunanithi                 thisEntry["DiagnosticDataType"] = "Manager";
467d337bb72SAsmitha Karunanithi                 thisEntry["AdditionalDataURI"] =
468de8d94a3SAbhishek Patel                     "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
469de8d94a3SAbhishek Patel                     entryID + "/attachment";
4705cb1dd27SAsmitha Karunanithi             }
4715cb1dd27SAsmitha Karunanithi             else if (dumpType == "System")
4725cb1dd27SAsmitha Karunanithi             {
473d337bb72SAsmitha Karunanithi                 thisEntry["DiagnosticDataType"] = "OEM";
474d337bb72SAsmitha Karunanithi                 thisEntry["OEMDiagnosticDataType"] = "System";
475d337bb72SAsmitha Karunanithi                 thisEntry["AdditionalDataURI"] =
476de8d94a3SAbhishek Patel                     "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
477de8d94a3SAbhishek Patel                     entryID + "/attachment";
4785cb1dd27SAsmitha Karunanithi             }
47935440d18SAsmitha Karunanithi             entriesArray.push_back(std::move(thisEntry));
4805cb1dd27SAsmitha Karunanithi         }
481002d39b4SEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
4825cb1dd27SAsmitha Karunanithi         },
4835cb1dd27SAsmitha Karunanithi         "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
4845cb1dd27SAsmitha Karunanithi         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
4855cb1dd27SAsmitha Karunanithi }
4865cb1dd27SAsmitha Karunanithi 
4878d1b46d7Szhanghch05 inline void
488c7a6d660SClaire Weinan     getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4898d1b46d7Szhanghch05                      const std::string& entryID, const std::string& dumpType)
4905cb1dd27SAsmitha Karunanithi {
4915cb1dd27SAsmitha Karunanithi     std::string dumpPath;
4925cb1dd27SAsmitha Karunanithi     if (dumpType == "BMC")
4935cb1dd27SAsmitha Karunanithi     {
4945cb1dd27SAsmitha Karunanithi         dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
4955cb1dd27SAsmitha Karunanithi     }
4965cb1dd27SAsmitha Karunanithi     else if (dumpType == "System")
4975cb1dd27SAsmitha Karunanithi     {
4985cb1dd27SAsmitha Karunanithi         dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
4995cb1dd27SAsmitha Karunanithi     }
5005cb1dd27SAsmitha Karunanithi     else
5015cb1dd27SAsmitha Karunanithi     {
5025cb1dd27SAsmitha Karunanithi         BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
5035cb1dd27SAsmitha Karunanithi         messages::internalError(asyncResp->res);
5045cb1dd27SAsmitha Karunanithi         return;
5055cb1dd27SAsmitha Karunanithi     }
5065cb1dd27SAsmitha Karunanithi 
5075cb1dd27SAsmitha Karunanithi     crow::connections::systemBus->async_method_call(
508711ac7a9SEd Tanous         [asyncResp, entryID, dumpPath,
509711ac7a9SEd Tanous          dumpType](const boost::system::error_code ec,
510711ac7a9SEd Tanous                    dbus::utility::ManagedObjectType& resp) {
5115cb1dd27SAsmitha Karunanithi         if (ec)
5125cb1dd27SAsmitha Karunanithi         {
5135cb1dd27SAsmitha Karunanithi             BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
5145cb1dd27SAsmitha Karunanithi             messages::internalError(asyncResp->res);
5155cb1dd27SAsmitha Karunanithi             return;
5165cb1dd27SAsmitha Karunanithi         }
5175cb1dd27SAsmitha Karunanithi 
518b47452b2SAsmitha Karunanithi         bool foundDumpEntry = false;
519b47452b2SAsmitha Karunanithi         std::string dumpEntryPath =
520b47452b2SAsmitha Karunanithi             "/xyz/openbmc_project/dump/" +
521002d39b4SEd Tanous             std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
522b47452b2SAsmitha Karunanithi 
5239eb808c1SEd Tanous         for (const auto& objectPath : resp)
5245cb1dd27SAsmitha Karunanithi         {
525b47452b2SAsmitha Karunanithi             if (objectPath.first.str != dumpEntryPath + entryID)
5265cb1dd27SAsmitha Karunanithi             {
5275cb1dd27SAsmitha Karunanithi                 continue;
5285cb1dd27SAsmitha Karunanithi             }
5295cb1dd27SAsmitha Karunanithi 
5305cb1dd27SAsmitha Karunanithi             foundDumpEntry = true;
5311d8782e7SNan Zhou             uint64_t timestamp = 0;
5325cb1dd27SAsmitha Karunanithi             uint64_t size = 0;
53335440d18SAsmitha Karunanithi             std::string dumpStatus;
5345cb1dd27SAsmitha Karunanithi 
5359eb808c1SEd Tanous             for (const auto& interfaceMap : objectPath.second)
5365cb1dd27SAsmitha Karunanithi             {
537002d39b4SEd Tanous                 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
53835440d18SAsmitha Karunanithi                 {
5399eb808c1SEd Tanous                     for (const auto& propertyMap : interfaceMap.second)
54035440d18SAsmitha Karunanithi                     {
54135440d18SAsmitha Karunanithi                         if (propertyMap.first == "Status")
54235440d18SAsmitha Karunanithi                         {
5439eb808c1SEd Tanous                             const std::string* status =
544002d39b4SEd Tanous                                 std::get_if<std::string>(&propertyMap.second);
54535440d18SAsmitha Karunanithi                             if (status == nullptr)
54635440d18SAsmitha Karunanithi                             {
54735440d18SAsmitha Karunanithi                                 messages::internalError(asyncResp->res);
54835440d18SAsmitha Karunanithi                                 break;
54935440d18SAsmitha Karunanithi                             }
55035440d18SAsmitha Karunanithi                             dumpStatus = *status;
55135440d18SAsmitha Karunanithi                         }
55235440d18SAsmitha Karunanithi                     }
55335440d18SAsmitha Karunanithi                 }
554002d39b4SEd Tanous                 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
5555cb1dd27SAsmitha Karunanithi                 {
5569eb808c1SEd Tanous                     for (const auto& propertyMap : interfaceMap.second)
5575cb1dd27SAsmitha Karunanithi                     {
5585cb1dd27SAsmitha Karunanithi                         if (propertyMap.first == "Size")
5595cb1dd27SAsmitha Karunanithi                         {
5609eb808c1SEd Tanous                             const uint64_t* sizePtr =
5615cb1dd27SAsmitha Karunanithi                                 std::get_if<uint64_t>(&propertyMap.second);
5625cb1dd27SAsmitha Karunanithi                             if (sizePtr == nullptr)
5635cb1dd27SAsmitha Karunanithi                             {
5645cb1dd27SAsmitha Karunanithi                                 messages::internalError(asyncResp->res);
5655cb1dd27SAsmitha Karunanithi                                 break;
5665cb1dd27SAsmitha Karunanithi                             }
5675cb1dd27SAsmitha Karunanithi                             size = *sizePtr;
5685cb1dd27SAsmitha Karunanithi                             break;
5695cb1dd27SAsmitha Karunanithi                         }
5705cb1dd27SAsmitha Karunanithi                     }
5715cb1dd27SAsmitha Karunanithi                 }
5725cb1dd27SAsmitha Karunanithi                 else if (interfaceMap.first ==
5735cb1dd27SAsmitha Karunanithi                          "xyz.openbmc_project.Time.EpochTime")
5745cb1dd27SAsmitha Karunanithi                 {
5759eb808c1SEd Tanous                     for (const auto& propertyMap : interfaceMap.second)
5765cb1dd27SAsmitha Karunanithi                     {
5775cb1dd27SAsmitha Karunanithi                         if (propertyMap.first == "Elapsed")
5785cb1dd27SAsmitha Karunanithi                         {
5795cb1dd27SAsmitha Karunanithi                             const uint64_t* usecsTimeStamp =
5805cb1dd27SAsmitha Karunanithi                                 std::get_if<uint64_t>(&propertyMap.second);
5815cb1dd27SAsmitha Karunanithi                             if (usecsTimeStamp == nullptr)
5825cb1dd27SAsmitha Karunanithi                             {
5835cb1dd27SAsmitha Karunanithi                                 messages::internalError(asyncResp->res);
5845cb1dd27SAsmitha Karunanithi                                 break;
5855cb1dd27SAsmitha Karunanithi                             }
5861d8782e7SNan Zhou                             timestamp = *usecsTimeStamp / 1000 / 1000;
5875cb1dd27SAsmitha Karunanithi                             break;
5885cb1dd27SAsmitha Karunanithi                         }
5895cb1dd27SAsmitha Karunanithi                     }
5905cb1dd27SAsmitha Karunanithi                 }
5915cb1dd27SAsmitha Karunanithi             }
5925cb1dd27SAsmitha Karunanithi 
5930fda0f12SGeorge Liu             if (dumpStatus !=
5940fda0f12SGeorge Liu                     "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
59535440d18SAsmitha Karunanithi                 !dumpStatus.empty())
59635440d18SAsmitha Karunanithi             {
59735440d18SAsmitha Karunanithi                 // Dump status is not Complete
59835440d18SAsmitha Karunanithi                 // return not found until status is changed to Completed
599002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
600002d39b4SEd Tanous                                            entryID);
60135440d18SAsmitha Karunanithi                 return;
60235440d18SAsmitha Karunanithi             }
60335440d18SAsmitha Karunanithi 
6045cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["@odata.type"] =
605647b3cdcSGeorge Liu                 "#LogEntry.v1_8_0.LogEntry";
6065cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["@odata.id"] = dumpPath + entryID;
6075cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["Id"] = entryID;
6085cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["EntryType"] = "Event";
6095cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["Created"] =
6101d8782e7SNan Zhou                 crow::utility::getDateTimeUint(timestamp);
6115cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
6125cb1dd27SAsmitha Karunanithi 
613d337bb72SAsmitha Karunanithi             asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
6145cb1dd27SAsmitha Karunanithi 
6155cb1dd27SAsmitha Karunanithi             if (dumpType == "BMC")
6165cb1dd27SAsmitha Karunanithi             {
617d337bb72SAsmitha Karunanithi                 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
618d337bb72SAsmitha Karunanithi                 asyncResp->res.jsonValue["AdditionalDataURI"] =
619de8d94a3SAbhishek Patel                     "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
620de8d94a3SAbhishek Patel                     entryID + "/attachment";
6215cb1dd27SAsmitha Karunanithi             }
6225cb1dd27SAsmitha Karunanithi             else if (dumpType == "System")
6235cb1dd27SAsmitha Karunanithi             {
624d337bb72SAsmitha Karunanithi                 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
625002d39b4SEd Tanous                 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
626d337bb72SAsmitha Karunanithi                 asyncResp->res.jsonValue["AdditionalDataURI"] =
627de8d94a3SAbhishek Patel                     "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
628de8d94a3SAbhishek Patel                     entryID + "/attachment";
6295cb1dd27SAsmitha Karunanithi             }
6305cb1dd27SAsmitha Karunanithi         }
631e05aec50SEd Tanous         if (!foundDumpEntry)
632b47452b2SAsmitha Karunanithi         {
633b47452b2SAsmitha Karunanithi             BMCWEB_LOG_ERROR << "Can't find Dump Entry";
634b47452b2SAsmitha Karunanithi             messages::internalError(asyncResp->res);
635b47452b2SAsmitha Karunanithi             return;
636b47452b2SAsmitha Karunanithi         }
6375cb1dd27SAsmitha Karunanithi         },
6385cb1dd27SAsmitha Karunanithi         "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
6395cb1dd27SAsmitha Karunanithi         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
6405cb1dd27SAsmitha Karunanithi }
6415cb1dd27SAsmitha Karunanithi 
6428d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6439878256fSStanley Chu                             const std::string& entryID,
644b47452b2SAsmitha Karunanithi                             const std::string& dumpType)
6455cb1dd27SAsmitha Karunanithi {
646002d39b4SEd Tanous     auto respHandler =
647002d39b4SEd Tanous         [asyncResp, entryID](const boost::system::error_code ec) {
6485cb1dd27SAsmitha Karunanithi         BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
6495cb1dd27SAsmitha Karunanithi         if (ec)
6505cb1dd27SAsmitha Karunanithi         {
6513de8d8baSGeorge Liu             if (ec.value() == EBADR)
6523de8d8baSGeorge Liu             {
6533de8d8baSGeorge Liu                 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
6543de8d8baSGeorge Liu                 return;
6553de8d8baSGeorge Liu             }
6565cb1dd27SAsmitha Karunanithi             BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
6575cb1dd27SAsmitha Karunanithi                              << ec;
6585cb1dd27SAsmitha Karunanithi             messages::internalError(asyncResp->res);
6595cb1dd27SAsmitha Karunanithi             return;
6605cb1dd27SAsmitha Karunanithi         }
6615cb1dd27SAsmitha Karunanithi     };
6625cb1dd27SAsmitha Karunanithi     crow::connections::systemBus->async_method_call(
6635cb1dd27SAsmitha Karunanithi         respHandler, "xyz.openbmc_project.Dump.Manager",
664b47452b2SAsmitha Karunanithi         "/xyz/openbmc_project/dump/" +
665b47452b2SAsmitha Karunanithi             std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
666b47452b2SAsmitha Karunanithi             entryID,
6675cb1dd27SAsmitha Karunanithi         "xyz.openbmc_project.Object.Delete", "Delete");
6685cb1dd27SAsmitha Karunanithi }
6695cb1dd27SAsmitha Karunanithi 
6708d1b46d7Szhanghch05 inline void
67198be3e39SEd Tanous     createDumpTaskCallback(task::Payload&& payload,
6728d1b46d7Szhanghch05                            const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6738d1b46d7Szhanghch05                            const uint32_t& dumpId, const std::string& dumpPath,
674a43be80fSAsmitha Karunanithi                            const std::string& dumpType)
675a43be80fSAsmitha Karunanithi {
676a43be80fSAsmitha Karunanithi     std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
6776145ed6fSAsmitha Karunanithi         [dumpId, dumpPath, dumpType](
678a43be80fSAsmitha Karunanithi             boost::system::error_code err, sdbusplus::message::message& m,
679a43be80fSAsmitha Karunanithi             const std::shared_ptr<task::TaskData>& taskData) {
680cb13a392SEd Tanous         if (err)
681cb13a392SEd Tanous         {
6826145ed6fSAsmitha Karunanithi             BMCWEB_LOG_ERROR << "Error in creating a dump";
6836145ed6fSAsmitha Karunanithi             taskData->state = "Cancelled";
6846145ed6fSAsmitha Karunanithi             return task::completed;
685cb13a392SEd Tanous         }
686b9d36b47SEd Tanous 
687b9d36b47SEd Tanous         dbus::utility::DBusInteracesMap interfacesList;
688a43be80fSAsmitha Karunanithi 
689a43be80fSAsmitha Karunanithi         sdbusplus::message::object_path objPath;
690a43be80fSAsmitha Karunanithi 
691a43be80fSAsmitha Karunanithi         m.read(objPath, interfacesList);
692a43be80fSAsmitha Karunanithi 
693b47452b2SAsmitha Karunanithi         if (objPath.str ==
694b47452b2SAsmitha Karunanithi             "/xyz/openbmc_project/dump/" +
695b47452b2SAsmitha Karunanithi                 std::string(boost::algorithm::to_lower_copy(dumpType)) +
696b47452b2SAsmitha Karunanithi                 "/entry/" + std::to_string(dumpId))
697a43be80fSAsmitha Karunanithi         {
698a43be80fSAsmitha Karunanithi             nlohmann::json retMessage = messages::success();
699a43be80fSAsmitha Karunanithi             taskData->messages.emplace_back(retMessage);
700a43be80fSAsmitha Karunanithi 
701a43be80fSAsmitha Karunanithi             std::string headerLoc =
702a43be80fSAsmitha Karunanithi                 "Location: " + dumpPath + std::to_string(dumpId);
703002d39b4SEd Tanous             taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
704a43be80fSAsmitha Karunanithi 
705a43be80fSAsmitha Karunanithi             taskData->state = "Completed";
706b47452b2SAsmitha Karunanithi             return task::completed;
7076145ed6fSAsmitha Karunanithi         }
708a43be80fSAsmitha Karunanithi         return task::completed;
709a43be80fSAsmitha Karunanithi         },
7104978b63fSJason M. Bills         "type='signal',interface='org.freedesktop.DBus.ObjectManager',"
711a43be80fSAsmitha Karunanithi         "member='InterfacesAdded', "
712a43be80fSAsmitha Karunanithi         "path='/xyz/openbmc_project/dump'");
713a43be80fSAsmitha Karunanithi 
714a43be80fSAsmitha Karunanithi     task->startTimer(std::chrono::minutes(3));
715a43be80fSAsmitha Karunanithi     task->populateResp(asyncResp->res);
71698be3e39SEd Tanous     task->payload.emplace(std::move(payload));
717a43be80fSAsmitha Karunanithi }
718a43be80fSAsmitha Karunanithi 
7198d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7208d1b46d7Szhanghch05                        const crow::Request& req, const std::string& dumpType)
721a43be80fSAsmitha Karunanithi {
722a43be80fSAsmitha Karunanithi     std::string dumpPath;
723a43be80fSAsmitha Karunanithi     if (dumpType == "BMC")
724a43be80fSAsmitha Karunanithi     {
725a43be80fSAsmitha Karunanithi         dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
726a43be80fSAsmitha Karunanithi     }
727a43be80fSAsmitha Karunanithi     else if (dumpType == "System")
728a43be80fSAsmitha Karunanithi     {
729a43be80fSAsmitha Karunanithi         dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
730a43be80fSAsmitha Karunanithi     }
731a43be80fSAsmitha Karunanithi     else
732a43be80fSAsmitha Karunanithi     {
733a43be80fSAsmitha Karunanithi         BMCWEB_LOG_ERROR << "Invalid dump type: " << dumpType;
734a43be80fSAsmitha Karunanithi         messages::internalError(asyncResp->res);
735a43be80fSAsmitha Karunanithi         return;
736a43be80fSAsmitha Karunanithi     }
737a43be80fSAsmitha Karunanithi 
738a43be80fSAsmitha Karunanithi     std::optional<std::string> diagnosticDataType;
739a43be80fSAsmitha Karunanithi     std::optional<std::string> oemDiagnosticDataType;
740a43be80fSAsmitha Karunanithi 
74115ed6780SWilly Tu     if (!redfish::json_util::readJsonAction(
742a43be80fSAsmitha Karunanithi             req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
743a43be80fSAsmitha Karunanithi             "OEMDiagnosticDataType", oemDiagnosticDataType))
744a43be80fSAsmitha Karunanithi     {
745a43be80fSAsmitha Karunanithi         return;
746a43be80fSAsmitha Karunanithi     }
747a43be80fSAsmitha Karunanithi 
748a43be80fSAsmitha Karunanithi     if (dumpType == "System")
749a43be80fSAsmitha Karunanithi     {
750a43be80fSAsmitha Karunanithi         if (!oemDiagnosticDataType || !diagnosticDataType)
751a43be80fSAsmitha Karunanithi         {
7524978b63fSJason M. Bills             BMCWEB_LOG_ERROR
7534978b63fSJason M. Bills                 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
754a43be80fSAsmitha Karunanithi             messages::actionParameterMissing(
755a43be80fSAsmitha Karunanithi                 asyncResp->res, "CollectDiagnosticData",
756a43be80fSAsmitha Karunanithi                 "DiagnosticDataType & OEMDiagnosticDataType");
757a43be80fSAsmitha Karunanithi             return;
758a43be80fSAsmitha Karunanithi         }
7593174e4dfSEd Tanous         if ((*oemDiagnosticDataType != "System") ||
760a43be80fSAsmitha Karunanithi             (*diagnosticDataType != "OEM"))
761a43be80fSAsmitha Karunanithi         {
762a43be80fSAsmitha Karunanithi             BMCWEB_LOG_ERROR << "Wrong parameter values passed";
763ace85d60SEd Tanous             messages::internalError(asyncResp->res);
764a43be80fSAsmitha Karunanithi             return;
765a43be80fSAsmitha Karunanithi         }
766a43be80fSAsmitha Karunanithi     }
767a43be80fSAsmitha Karunanithi     else if (dumpType == "BMC")
768a43be80fSAsmitha Karunanithi     {
769a43be80fSAsmitha Karunanithi         if (!diagnosticDataType)
770a43be80fSAsmitha Karunanithi         {
7710fda0f12SGeorge Liu             BMCWEB_LOG_ERROR
7720fda0f12SGeorge Liu                 << "CreateDump action parameter 'DiagnosticDataType' not found!";
773a43be80fSAsmitha Karunanithi             messages::actionParameterMissing(
774a43be80fSAsmitha Karunanithi                 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
775a43be80fSAsmitha Karunanithi             return;
776a43be80fSAsmitha Karunanithi         }
7773174e4dfSEd Tanous         if (*diagnosticDataType != "Manager")
778a43be80fSAsmitha Karunanithi         {
779a43be80fSAsmitha Karunanithi             BMCWEB_LOG_ERROR
780a43be80fSAsmitha Karunanithi                 << "Wrong parameter value passed for 'DiagnosticDataType'";
781ace85d60SEd Tanous             messages::internalError(asyncResp->res);
782a43be80fSAsmitha Karunanithi             return;
783a43be80fSAsmitha Karunanithi         }
784a43be80fSAsmitha Karunanithi     }
785a43be80fSAsmitha Karunanithi 
786a43be80fSAsmitha Karunanithi     crow::connections::systemBus->async_method_call(
78798be3e39SEd Tanous         [asyncResp, payload(task::Payload(req)), dumpPath,
78898be3e39SEd Tanous          dumpType](const boost::system::error_code ec,
78998be3e39SEd Tanous                    const uint32_t& dumpId) mutable {
790a43be80fSAsmitha Karunanithi         if (ec)
791a43be80fSAsmitha Karunanithi         {
792a43be80fSAsmitha Karunanithi             BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
793a43be80fSAsmitha Karunanithi             messages::internalError(asyncResp->res);
794a43be80fSAsmitha Karunanithi             return;
795a43be80fSAsmitha Karunanithi         }
796a43be80fSAsmitha Karunanithi         BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
797a43be80fSAsmitha Karunanithi 
798002d39b4SEd Tanous         createDumpTaskCallback(std::move(payload), asyncResp, dumpId, dumpPath,
799002d39b4SEd Tanous                                dumpType);
800a43be80fSAsmitha Karunanithi         },
801b47452b2SAsmitha Karunanithi         "xyz.openbmc_project.Dump.Manager",
802b47452b2SAsmitha Karunanithi         "/xyz/openbmc_project/dump/" +
803b47452b2SAsmitha Karunanithi             std::string(boost::algorithm::to_lower_copy(dumpType)),
804a43be80fSAsmitha Karunanithi         "xyz.openbmc_project.Dump.Create", "CreateDump");
805a43be80fSAsmitha Karunanithi }
806a43be80fSAsmitha Karunanithi 
8078d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8088d1b46d7Szhanghch05                       const std::string& dumpType)
80980319af1SAsmitha Karunanithi {
810b47452b2SAsmitha Karunanithi     std::string dumpTypeLowerCopy =
811b47452b2SAsmitha Karunanithi         std::string(boost::algorithm::to_lower_copy(dumpType));
8128d1b46d7Szhanghch05 
81380319af1SAsmitha Karunanithi     crow::connections::systemBus->async_method_call(
814b9d36b47SEd Tanous         [asyncResp, dumpType](
815b9d36b47SEd Tanous             const boost::system::error_code ec,
816b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
81780319af1SAsmitha Karunanithi         if (ec)
81880319af1SAsmitha Karunanithi         {
81980319af1SAsmitha Karunanithi             BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
82080319af1SAsmitha Karunanithi             messages::internalError(asyncResp->res);
82180319af1SAsmitha Karunanithi             return;
82280319af1SAsmitha Karunanithi         }
82380319af1SAsmitha Karunanithi 
82480319af1SAsmitha Karunanithi         for (const std::string& path : subTreePaths)
82580319af1SAsmitha Karunanithi         {
8262dfd18efSEd Tanous             sdbusplus::message::object_path objPath(path);
8272dfd18efSEd Tanous             std::string logID = objPath.filename();
8282dfd18efSEd Tanous             if (logID.empty())
82980319af1SAsmitha Karunanithi             {
8302dfd18efSEd Tanous                 continue;
83180319af1SAsmitha Karunanithi             }
8322dfd18efSEd Tanous             deleteDumpEntry(asyncResp, logID, dumpType);
83380319af1SAsmitha Karunanithi         }
83480319af1SAsmitha Karunanithi         },
83580319af1SAsmitha Karunanithi         "xyz.openbmc_project.ObjectMapper",
83680319af1SAsmitha Karunanithi         "/xyz/openbmc_project/object_mapper",
83780319af1SAsmitha Karunanithi         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
838b47452b2SAsmitha Karunanithi         "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
839b47452b2SAsmitha Karunanithi         std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
840b47452b2SAsmitha Karunanithi                                    dumpType});
84180319af1SAsmitha Karunanithi }
84280319af1SAsmitha Karunanithi 
843b9d36b47SEd Tanous inline static void
844b9d36b47SEd Tanous     parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
845b9d36b47SEd Tanous                              std::string& filename, std::string& timestamp,
846b9d36b47SEd Tanous                              std::string& logfile)
847043a0536SJohnathan Mantey {
848043a0536SJohnathan Mantey     for (auto property : params)
849043a0536SJohnathan Mantey     {
850043a0536SJohnathan Mantey         if (property.first == "Timestamp")
851043a0536SJohnathan Mantey         {
852043a0536SJohnathan Mantey             const std::string* value =
8538d78b7a9SPatrick Williams                 std::get_if<std::string>(&property.second);
854043a0536SJohnathan Mantey             if (value != nullptr)
855043a0536SJohnathan Mantey             {
856043a0536SJohnathan Mantey                 timestamp = *value;
857043a0536SJohnathan Mantey             }
858043a0536SJohnathan Mantey         }
859043a0536SJohnathan Mantey         else if (property.first == "Filename")
860043a0536SJohnathan Mantey         {
861043a0536SJohnathan Mantey             const std::string* value =
8628d78b7a9SPatrick Williams                 std::get_if<std::string>(&property.second);
863043a0536SJohnathan Mantey             if (value != nullptr)
864043a0536SJohnathan Mantey             {
865043a0536SJohnathan Mantey                 filename = *value;
866043a0536SJohnathan Mantey             }
867043a0536SJohnathan Mantey         }
868043a0536SJohnathan Mantey         else if (property.first == "Log")
869043a0536SJohnathan Mantey         {
870043a0536SJohnathan Mantey             const std::string* value =
8718d78b7a9SPatrick Williams                 std::get_if<std::string>(&property.second);
872043a0536SJohnathan Mantey             if (value != nullptr)
873043a0536SJohnathan Mantey             {
874043a0536SJohnathan Mantey                 logfile = *value;
875043a0536SJohnathan Mantey             }
876043a0536SJohnathan Mantey         }
877043a0536SJohnathan Mantey     }
878043a0536SJohnathan Mantey }
879043a0536SJohnathan Mantey 
880a3316fc6SZhikuiRen constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
8817e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app)
8821da66f75SEd Tanous {
883c4bf6374SJason M. Bills     /**
884c4bf6374SJason M. Bills      * Functions triggers appropriate requests on DBus
885c4bf6374SJason M. Bills      */
8867e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/")
887ed398213SEd Tanous         .privileges(redfish::privileges::getLogServiceCollection)
888002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
889002d39b4SEd Tanous             [&app](const crow::Request& req,
890002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
891*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
892c4bf6374SJason M. Bills         {
89345ca1b86SEd Tanous             return;
89445ca1b86SEd Tanous         }
8957e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
8967e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
897c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
898c4bf6374SJason M. Bills             "#LogServiceCollection.LogServiceCollection";
899c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.id"] =
900029573d4SEd Tanous             "/redfish/v1/Systems/system/LogServices";
90145ca1b86SEd Tanous         asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
902c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Description"] =
903c4bf6374SJason M. Bills             "Collection of LogServices for this Computer System";
904002d39b4SEd Tanous         nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
905c4bf6374SJason M. Bills         logServiceArray = nlohmann::json::array();
9061476687dSEd Tanous         nlohmann::json::object_t eventLog;
9071476687dSEd Tanous         eventLog["@odata.id"] =
9081476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/EventLog";
9091476687dSEd Tanous         logServiceArray.push_back(std::move(eventLog));
9105cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
9111476687dSEd Tanous         nlohmann::json::object_t dumpLog;
912002d39b4SEd Tanous         dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
9131476687dSEd Tanous         logServiceArray.push_back(std::move(dumpLog));
914c9bb6861Sraviteja-b #endif
915c9bb6861Sraviteja-b 
916d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
9171476687dSEd Tanous         nlohmann::json::object_t crashdump;
9181476687dSEd Tanous         crashdump["@odata.id"] =
9191476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Crashdump";
9201476687dSEd Tanous         logServiceArray.push_back(std::move(crashdump));
921d53dd41fSJason M. Bills #endif
922b7028ebfSSpencer Ku 
923b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
9241476687dSEd Tanous         nlohmann::json::object_t hostlogger;
9251476687dSEd Tanous         hostlogger["@odata.id"] =
9261476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/HostLogger";
9271476687dSEd Tanous         logServiceArray.push_back(std::move(hostlogger));
928b7028ebfSSpencer Ku #endif
929c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Members@odata.count"] =
930c4bf6374SJason M. Bills             logServiceArray.size();
931a3316fc6SZhikuiRen 
932a3316fc6SZhikuiRen         crow::connections::systemBus->async_method_call(
93345ca1b86SEd Tanous             [asyncResp](const boost::system::error_code ec,
934b9d36b47SEd Tanous                         const dbus::utility::MapperGetSubTreePathsResponse&
935b9d36b47SEd Tanous                             subtreePath) {
936a3316fc6SZhikuiRen             if (ec)
937a3316fc6SZhikuiRen             {
938a3316fc6SZhikuiRen                 BMCWEB_LOG_ERROR << ec;
939a3316fc6SZhikuiRen                 return;
940a3316fc6SZhikuiRen             }
941a3316fc6SZhikuiRen 
94255f79e6fSEd Tanous             for (const auto& pathStr : subtreePath)
943a3316fc6SZhikuiRen             {
944a3316fc6SZhikuiRen                 if (pathStr.find("PostCode") != std::string::npos)
945a3316fc6SZhikuiRen                 {
94623a21a1cSEd Tanous                     nlohmann::json& logServiceArrayLocal =
947a3316fc6SZhikuiRen                         asyncResp->res.jsonValue["Members"];
94823a21a1cSEd Tanous                     logServiceArrayLocal.push_back(
9490fda0f12SGeorge Liu                         {{"@odata.id",
9500fda0f12SGeorge Liu                           "/redfish/v1/Systems/system/LogServices/PostCodes"}});
95145ca1b86SEd Tanous                     asyncResp->res.jsonValue["Members@odata.count"] =
95223a21a1cSEd Tanous                         logServiceArrayLocal.size();
953a3316fc6SZhikuiRen                     return;
954a3316fc6SZhikuiRen                 }
955a3316fc6SZhikuiRen             }
956a3316fc6SZhikuiRen             },
957a3316fc6SZhikuiRen             "xyz.openbmc_project.ObjectMapper",
958a3316fc6SZhikuiRen             "/xyz/openbmc_project/object_mapper",
95945ca1b86SEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
96045ca1b86SEd Tanous             std::array<const char*, 1>{postCodeIface});
9617e860f15SJohn Edward Broadbent         });
962c4bf6374SJason M. Bills }
963c4bf6374SJason M. Bills 
9647e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app)
965c4bf6374SJason M. Bills {
9667e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
967ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
968002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
969002d39b4SEd Tanous             [&app](const crow::Request& req,
970002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
971*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
97245ca1b86SEd Tanous         {
97345ca1b86SEd Tanous             return;
97445ca1b86SEd Tanous         }
975c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.id"] =
976029573d4SEd Tanous             "/redfish/v1/Systems/system/LogServices/EventLog";
977c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
978c4bf6374SJason M. Bills             "#LogService.v1_1_0.LogService";
979c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Name"] = "Event Log Service";
980002d39b4SEd Tanous         asyncResp->res.jsonValue["Description"] = "System Event Log Service";
981c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Id"] = "EventLog";
982c4bf6374SJason M. Bills         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
9837c8c4058STejas Patil 
9847c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
9857c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
9867c8c4058STejas Patil 
9877c8c4058STejas Patil         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
9887c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
9897c8c4058STejas Patil             redfishDateTimeOffset.second;
9907c8c4058STejas Patil 
9911476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
9921476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
993e7d6c8b2SGunnar Mills         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
994e7d6c8b2SGunnar Mills 
9950fda0f12SGeorge Liu             {"target",
9960fda0f12SGeorge Liu              "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
9977e860f15SJohn Edward Broadbent         });
998489640c6SJason M. Bills }
999489640c6SJason M. Bills 
10007e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app)
1001489640c6SJason M. Bills {
10024978b63fSJason M. Bills     BMCWEB_ROUTE(
10034978b63fSJason M. Bills         app,
10044978b63fSJason M. Bills         "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
1005432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
10067e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
100745ca1b86SEd Tanous             [&app](const crow::Request& req,
10087e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1009*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
101045ca1b86SEd Tanous         {
101145ca1b86SEd Tanous             return;
101245ca1b86SEd Tanous         }
1013489640c6SJason M. Bills         // Clear the EventLog by deleting the log files
1014489640c6SJason M. Bills         std::vector<std::filesystem::path> redfishLogFiles;
1015489640c6SJason M. Bills         if (getRedfishLogFiles(redfishLogFiles))
1016489640c6SJason M. Bills         {
1017489640c6SJason M. Bills             for (const std::filesystem::path& file : redfishLogFiles)
1018489640c6SJason M. Bills             {
1019489640c6SJason M. Bills                 std::error_code ec;
1020489640c6SJason M. Bills                 std::filesystem::remove(file, ec);
1021489640c6SJason M. Bills             }
1022489640c6SJason M. Bills         }
1023489640c6SJason M. Bills 
1024489640c6SJason M. Bills         // Reload rsyslog so it knows to start new log files
1025489640c6SJason M. Bills         crow::connections::systemBus->async_method_call(
1026489640c6SJason M. Bills             [asyncResp](const boost::system::error_code ec) {
1027489640c6SJason M. Bills             if (ec)
1028489640c6SJason M. Bills             {
1029002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1030489640c6SJason M. Bills                 messages::internalError(asyncResp->res);
1031489640c6SJason M. Bills                 return;
1032489640c6SJason M. Bills             }
1033489640c6SJason M. Bills 
1034489640c6SJason M. Bills             messages::success(asyncResp->res);
1035489640c6SJason M. Bills             },
1036489640c6SJason M. Bills             "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1037002d39b4SEd Tanous             "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1038002d39b4SEd Tanous             "replace");
10397e860f15SJohn Edward Broadbent         });
1040c4bf6374SJason M. Bills }
1041c4bf6374SJason M. Bills 
104295820184SJason M. Bills static int fillEventLogEntryJson(const std::string& logEntryID,
1043b5a76932SEd Tanous                                  const std::string& logEntry,
104495820184SJason M. Bills                                  nlohmann::json& logEntryJson)
1045c4bf6374SJason M. Bills {
104695820184SJason M. Bills     // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
1047cd225da8SJason M. Bills     // First get the Timestamp
1048f23b7296SEd Tanous     size_t space = logEntry.find_first_of(' ');
1049cd225da8SJason M. Bills     if (space == std::string::npos)
105095820184SJason M. Bills     {
105195820184SJason M. Bills         return 1;
105295820184SJason M. Bills     }
1053cd225da8SJason M. Bills     std::string timestamp = logEntry.substr(0, space);
1054cd225da8SJason M. Bills     // Then get the log contents
1055f23b7296SEd Tanous     size_t entryStart = logEntry.find_first_not_of(' ', space);
1056cd225da8SJason M. Bills     if (entryStart == std::string::npos)
1057cd225da8SJason M. Bills     {
1058cd225da8SJason M. Bills         return 1;
1059cd225da8SJason M. Bills     }
1060cd225da8SJason M. Bills     std::string_view entry(logEntry);
1061cd225da8SJason M. Bills     entry.remove_prefix(entryStart);
1062cd225da8SJason M. Bills     // Use split to separate the entry into its fields
1063cd225da8SJason M. Bills     std::vector<std::string> logEntryFields;
1064cd225da8SJason M. Bills     boost::split(logEntryFields, entry, boost::is_any_of(","),
1065cd225da8SJason M. Bills                  boost::token_compress_on);
1066cd225da8SJason M. Bills     // We need at least a MessageId to be valid
106726f6976fSEd Tanous     if (logEntryFields.empty())
1068cd225da8SJason M. Bills     {
1069cd225da8SJason M. Bills         return 1;
1070cd225da8SJason M. Bills     }
1071cd225da8SJason M. Bills     std::string& messageID = logEntryFields[0];
107295820184SJason M. Bills 
10734851d45dSJason M. Bills     // Get the Message from the MessageRegistry
1074fffb8c1fSEd Tanous     const registries::Message* message = registries::getMessage(messageID);
1075c4bf6374SJason M. Bills 
107654417b02SSui Chen     if (message == nullptr)
1077c4bf6374SJason M. Bills     {
107854417b02SSui Chen         BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
107954417b02SSui Chen         return 0;
1080c4bf6374SJason M. Bills     }
1081c4bf6374SJason M. Bills 
108254417b02SSui Chen     std::string msg = message->message;
108354417b02SSui Chen 
108415a86ff6SJason M. Bills     // Get the MessageArgs from the log if there are any
108526702d01SEd Tanous     std::span<std::string> messageArgs;
108615a86ff6SJason M. Bills     if (logEntryFields.size() > 1)
108715a86ff6SJason M. Bills     {
108815a86ff6SJason M. Bills         std::string& messageArgsStart = logEntryFields[1];
108915a86ff6SJason M. Bills         // If the first string is empty, assume there are no MessageArgs
109015a86ff6SJason M. Bills         std::size_t messageArgsSize = 0;
109115a86ff6SJason M. Bills         if (!messageArgsStart.empty())
109215a86ff6SJason M. Bills         {
109315a86ff6SJason M. Bills             messageArgsSize = logEntryFields.size() - 1;
109415a86ff6SJason M. Bills         }
109515a86ff6SJason M. Bills 
109623a21a1cSEd Tanous         messageArgs = {&messageArgsStart, messageArgsSize};
1097c4bf6374SJason M. Bills 
10984851d45dSJason M. Bills         // Fill the MessageArgs into the Message
109995820184SJason M. Bills         int i = 0;
110095820184SJason M. Bills         for (const std::string& messageArg : messageArgs)
11014851d45dSJason M. Bills         {
110295820184SJason M. Bills             std::string argStr = "%" + std::to_string(++i);
11034851d45dSJason M. Bills             size_t argPos = msg.find(argStr);
11044851d45dSJason M. Bills             if (argPos != std::string::npos)
11054851d45dSJason M. Bills             {
110695820184SJason M. Bills                 msg.replace(argPos, argStr.length(), messageArg);
11074851d45dSJason M. Bills             }
11084851d45dSJason M. Bills         }
110915a86ff6SJason M. Bills     }
11104851d45dSJason M. Bills 
111195820184SJason M. Bills     // Get the Created time from the timestamp. The log timestamp is in RFC3339
111295820184SJason M. Bills     // format which matches the Redfish format except for the fractional seconds
111395820184SJason M. Bills     // between the '.' and the '+', so just remove them.
1114f23b7296SEd Tanous     std::size_t dot = timestamp.find_first_of('.');
1115f23b7296SEd Tanous     std::size_t plus = timestamp.find_first_of('+');
111695820184SJason M. Bills     if (dot != std::string::npos && plus != std::string::npos)
1117c4bf6374SJason M. Bills     {
111895820184SJason M. Bills         timestamp.erase(dot, plus - dot);
1119c4bf6374SJason M. Bills     }
1120c4bf6374SJason M. Bills 
1121c4bf6374SJason M. Bills     // Fill in the log entry with the gathered data
112295820184SJason M. Bills     logEntryJson = {
1123647b3cdcSGeorge Liu         {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
1124029573d4SEd Tanous         {"@odata.id",
1125897967deSJason M. Bills          "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
112695820184SJason M. Bills              logEntryID},
1127c4bf6374SJason M. Bills         {"Name", "System Event Log Entry"},
112895820184SJason M. Bills         {"Id", logEntryID},
112995820184SJason M. Bills         {"Message", std::move(msg)},
113095820184SJason M. Bills         {"MessageId", std::move(messageID)},
1131f23b7296SEd Tanous         {"MessageArgs", messageArgs},
1132c4bf6374SJason M. Bills         {"EntryType", "Event"},
113354417b02SSui Chen         {"Severity", message->messageSeverity},
113495820184SJason M. Bills         {"Created", std::move(timestamp)}};
1135c4bf6374SJason M. Bills     return 0;
1136c4bf6374SJason M. Bills }
1137c4bf6374SJason M. Bills 
11387e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app)
1139c4bf6374SJason M. Bills {
11407e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
11417e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
11428b6a35f0SGunnar Mills         .privileges(redfish::privileges::getLogEntryCollection)
1143002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1144002d39b4SEd Tanous             [&app](const crow::Request& req,
1145002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1146c937d2bfSEd Tanous         query_param::QueryCapabilities capabilities = {
1147c937d2bfSEd Tanous             .canDelegateTop = true,
1148c937d2bfSEd Tanous             .canDelegateSkip = true,
1149c937d2bfSEd Tanous         };
1150c937d2bfSEd Tanous         query_param::Query delegatedQuery;
1151c937d2bfSEd Tanous         if (!redfish::setUpRedfishRouteWithDelegation(
1152*3ba00073SCarson Labrado                 app, req, asyncResp, delegatedQuery, capabilities))
1153c4bf6374SJason M. Bills         {
1154c4bf6374SJason M. Bills             return;
1155c4bf6374SJason M. Bills         }
11567e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
11577e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
1158c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
1159c4bf6374SJason M. Bills             "#LogEntryCollection.LogEntryCollection";
1160c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.id"] =
1161029573d4SEd Tanous             "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1162c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1163c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Description"] =
1164c4bf6374SJason M. Bills             "Collection of System Event Log Entries";
1165cb92c03bSAndrew Geissler 
11664978b63fSJason M. Bills         nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1167c4bf6374SJason M. Bills         logEntryArray = nlohmann::json::array();
11687e860f15SJohn Edward Broadbent         // Go through the log files and create a unique ID for each
11697e860f15SJohn Edward Broadbent         // entry
117095820184SJason M. Bills         std::vector<std::filesystem::path> redfishLogFiles;
117195820184SJason M. Bills         getRedfishLogFiles(redfishLogFiles);
1172b01bf299SEd Tanous         uint64_t entryCount = 0;
1173cd225da8SJason M. Bills         std::string logEntry;
117495820184SJason M. Bills 
11757e860f15SJohn Edward Broadbent         // Oldest logs are in the last file, so start there and loop
11767e860f15SJohn Edward Broadbent         // backwards
1177002d39b4SEd Tanous         for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1178002d39b4SEd Tanous              it++)
1179c4bf6374SJason M. Bills         {
1180cd225da8SJason M. Bills             std::ifstream logStream(*it);
118195820184SJason M. Bills             if (!logStream.is_open())
1182c4bf6374SJason M. Bills             {
1183c4bf6374SJason M. Bills                 continue;
1184c4bf6374SJason M. Bills             }
1185c4bf6374SJason M. Bills 
1186e85d6b16SJason M. Bills             // Reset the unique ID on the first entry
1187e85d6b16SJason M. Bills             bool firstEntry = true;
118895820184SJason M. Bills             while (std::getline(logStream, logEntry))
118995820184SJason M. Bills             {
1190c4bf6374SJason M. Bills                 entryCount++;
11917e860f15SJohn Edward Broadbent                 // Handle paging using skip (number of entries to skip
11927e860f15SJohn Edward Broadbent                 // from the start) and top (number of entries to
11937e860f15SJohn Edward Broadbent                 // display)
1194c937d2bfSEd Tanous                 if (entryCount <= delegatedQuery.skip ||
1195c937d2bfSEd Tanous                     entryCount > delegatedQuery.skip + delegatedQuery.top)
1196c4bf6374SJason M. Bills                 {
1197c4bf6374SJason M. Bills                     continue;
1198c4bf6374SJason M. Bills                 }
1199c4bf6374SJason M. Bills 
1200c4bf6374SJason M. Bills                 std::string idStr;
1201e85d6b16SJason M. Bills                 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1202c4bf6374SJason M. Bills                 {
1203c4bf6374SJason M. Bills                     continue;
1204c4bf6374SJason M. Bills                 }
1205c4bf6374SJason M. Bills 
1206e85d6b16SJason M. Bills                 if (firstEntry)
1207e85d6b16SJason M. Bills                 {
1208e85d6b16SJason M. Bills                     firstEntry = false;
1209e85d6b16SJason M. Bills                 }
1210e85d6b16SJason M. Bills 
1211c4bf6374SJason M. Bills                 logEntryArray.push_back({});
1212c4bf6374SJason M. Bills                 nlohmann::json& bmcLogEntry = logEntryArray.back();
1213002d39b4SEd Tanous                 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) != 0)
1214c4bf6374SJason M. Bills                 {
1215c4bf6374SJason M. Bills                     messages::internalError(asyncResp->res);
1216c4bf6374SJason M. Bills                     return;
1217c4bf6374SJason M. Bills                 }
1218c4bf6374SJason M. Bills             }
121995820184SJason M. Bills         }
1220c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
1221c937d2bfSEd Tanous         if (delegatedQuery.skip + delegatedQuery.top < entryCount)
1222c4bf6374SJason M. Bills         {
1223c4bf6374SJason M. Bills             asyncResp->res.jsonValue["Members@odata.nextLink"] =
12244978b63fSJason M. Bills                 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
1225c937d2bfSEd Tanous                 std::to_string(delegatedQuery.skip + delegatedQuery.top);
1226c4bf6374SJason M. Bills         }
12277e860f15SJohn Edward Broadbent         });
1228897967deSJason M. Bills }
1229897967deSJason M. Bills 
12307e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app)
1231897967deSJason M. Bills {
12327e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
12337e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
1234ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
12357e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
123645ca1b86SEd Tanous             [&app](const crow::Request& req,
12377e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12387e860f15SJohn Edward Broadbent                    const std::string& param) {
1239*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
124045ca1b86SEd Tanous         {
124145ca1b86SEd Tanous             return;
124245ca1b86SEd Tanous         }
12437e860f15SJohn Edward Broadbent         const std::string& targetID = param;
12448d1b46d7Szhanghch05 
12457e860f15SJohn Edward Broadbent         // Go through the log files and check the unique ID for each
12467e860f15SJohn Edward Broadbent         // entry to find the target entry
1247897967deSJason M. Bills         std::vector<std::filesystem::path> redfishLogFiles;
1248897967deSJason M. Bills         getRedfishLogFiles(redfishLogFiles);
1249897967deSJason M. Bills         std::string logEntry;
1250897967deSJason M. Bills 
12517e860f15SJohn Edward Broadbent         // Oldest logs are in the last file, so start there and loop
12527e860f15SJohn Edward Broadbent         // backwards
1253002d39b4SEd Tanous         for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1254002d39b4SEd Tanous              it++)
1255897967deSJason M. Bills         {
1256897967deSJason M. Bills             std::ifstream logStream(*it);
1257897967deSJason M. Bills             if (!logStream.is_open())
1258897967deSJason M. Bills             {
1259897967deSJason M. Bills                 continue;
1260897967deSJason M. Bills             }
1261897967deSJason M. Bills 
1262897967deSJason M. Bills             // Reset the unique ID on the first entry
1263897967deSJason M. Bills             bool firstEntry = true;
1264897967deSJason M. Bills             while (std::getline(logStream, logEntry))
1265897967deSJason M. Bills             {
1266897967deSJason M. Bills                 std::string idStr;
1267897967deSJason M. Bills                 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1268897967deSJason M. Bills                 {
1269897967deSJason M. Bills                     continue;
1270897967deSJason M. Bills                 }
1271897967deSJason M. Bills 
1272897967deSJason M. Bills                 if (firstEntry)
1273897967deSJason M. Bills                 {
1274897967deSJason M. Bills                     firstEntry = false;
1275897967deSJason M. Bills                 }
1276897967deSJason M. Bills 
1277897967deSJason M. Bills                 if (idStr == targetID)
1278897967deSJason M. Bills                 {
1279002d39b4SEd Tanous                     if (fillEventLogEntryJson(idStr, logEntry,
1280897967deSJason M. Bills                                               asyncResp->res.jsonValue) != 0)
1281897967deSJason M. Bills                     {
1282897967deSJason M. Bills                         messages::internalError(asyncResp->res);
1283897967deSJason M. Bills                         return;
1284897967deSJason M. Bills                     }
1285897967deSJason M. Bills                     return;
1286897967deSJason M. Bills                 }
1287897967deSJason M. Bills             }
1288897967deSJason M. Bills         }
1289897967deSJason M. Bills         // Requested ID was not found
1290002d39b4SEd Tanous         messages::resourceMissingAtURI(asyncResp->res,
1291002d39b4SEd Tanous                                        crow::utility::urlFromPieces(targetID));
12927e860f15SJohn Edward Broadbent         });
129308a4e4b5SAnthony Wilson }
129408a4e4b5SAnthony Wilson 
12957e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app)
129608a4e4b5SAnthony Wilson {
12977e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
12987e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
1299ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
1300002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1301002d39b4SEd Tanous             [&app](const crow::Request& req,
1302002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1303*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
130445ca1b86SEd Tanous         {
130545ca1b86SEd Tanous             return;
130645ca1b86SEd Tanous         }
13077e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
13087e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
130908a4e4b5SAnthony Wilson         asyncResp->res.jsonValue["@odata.type"] =
131008a4e4b5SAnthony Wilson             "#LogEntryCollection.LogEntryCollection";
131108a4e4b5SAnthony Wilson         asyncResp->res.jsonValue["@odata.id"] =
131208a4e4b5SAnthony Wilson             "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
131308a4e4b5SAnthony Wilson         asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
131408a4e4b5SAnthony Wilson         asyncResp->res.jsonValue["Description"] =
131508a4e4b5SAnthony Wilson             "Collection of System Event Log Entries";
131608a4e4b5SAnthony Wilson 
1317cb92c03bSAndrew Geissler         // DBus implementation of EventLog/Entries
1318cb92c03bSAndrew Geissler         // Make call to Logging Service to find all log entry objects
1319cb92c03bSAndrew Geissler         crow::connections::systemBus->async_method_call(
1320cb92c03bSAndrew Geissler             [asyncResp](const boost::system::error_code ec,
1321914e2d5dSEd Tanous                         const dbus::utility::ManagedObjectType& resp) {
1322cb92c03bSAndrew Geissler             if (ec)
1323cb92c03bSAndrew Geissler             {
1324cb92c03bSAndrew Geissler                 // TODO Handle for specific error code
1325cb92c03bSAndrew Geissler                 BMCWEB_LOG_ERROR
1326002d39b4SEd Tanous                     << "getLogEntriesIfaceData resp_handler got error " << ec;
1327cb92c03bSAndrew Geissler                 messages::internalError(asyncResp->res);
1328cb92c03bSAndrew Geissler                 return;
1329cb92c03bSAndrew Geissler             }
1330002d39b4SEd Tanous             nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1331cb92c03bSAndrew Geissler             entriesArray = nlohmann::json::array();
13329eb808c1SEd Tanous             for (const auto& objectPath : resp)
1333cb92c03bSAndrew Geissler             {
1334914e2d5dSEd Tanous                 const uint32_t* id = nullptr;
1335c419c759SEd Tanous                 const uint64_t* timestamp = nullptr;
1336c419c759SEd Tanous                 const uint64_t* updateTimestamp = nullptr;
1337914e2d5dSEd Tanous                 const std::string* severity = nullptr;
1338914e2d5dSEd Tanous                 const std::string* message = nullptr;
1339914e2d5dSEd Tanous                 const std::string* filePath = nullptr;
134075710de2SXiaochao Ma                 bool resolved = false;
13419eb808c1SEd Tanous                 for (const auto& interfaceMap : objectPath.second)
1342f86bb901SAdriana Kobylak                 {
1343f86bb901SAdriana Kobylak                     if (interfaceMap.first ==
1344f86bb901SAdriana Kobylak                         "xyz.openbmc_project.Logging.Entry")
1345f86bb901SAdriana Kobylak                     {
1346002d39b4SEd Tanous                         for (const auto& propertyMap : interfaceMap.second)
1347cb92c03bSAndrew Geissler                         {
1348cb92c03bSAndrew Geissler                             if (propertyMap.first == "Id")
1349cb92c03bSAndrew Geissler                             {
1350002d39b4SEd Tanous                                 id = std::get_if<uint32_t>(&propertyMap.second);
1351cb92c03bSAndrew Geissler                             }
1352cb92c03bSAndrew Geissler                             else if (propertyMap.first == "Timestamp")
1353cb92c03bSAndrew Geissler                             {
1354002d39b4SEd Tanous                                 timestamp =
1355002d39b4SEd Tanous                                     std::get_if<uint64_t>(&propertyMap.second);
13567e860f15SJohn Edward Broadbent                             }
1357002d39b4SEd Tanous                             else if (propertyMap.first == "UpdateTimestamp")
13587e860f15SJohn Edward Broadbent                             {
1359002d39b4SEd Tanous                                 updateTimestamp =
1360002d39b4SEd Tanous                                     std::get_if<uint64_t>(&propertyMap.second);
13617e860f15SJohn Edward Broadbent                             }
13627e860f15SJohn Edward Broadbent                             else if (propertyMap.first == "Severity")
13637e860f15SJohn Edward Broadbent                             {
13647e860f15SJohn Edward Broadbent                                 severity = std::get_if<std::string>(
13657e860f15SJohn Edward Broadbent                                     &propertyMap.second);
13667e860f15SJohn Edward Broadbent                             }
13677e860f15SJohn Edward Broadbent                             else if (propertyMap.first == "Message")
13687e860f15SJohn Edward Broadbent                             {
13697e860f15SJohn Edward Broadbent                                 message = std::get_if<std::string>(
13707e860f15SJohn Edward Broadbent                                     &propertyMap.second);
13717e860f15SJohn Edward Broadbent                             }
13727e860f15SJohn Edward Broadbent                             else if (propertyMap.first == "Resolved")
13737e860f15SJohn Edward Broadbent                             {
1374914e2d5dSEd Tanous                                 const bool* resolveptr =
1375002d39b4SEd Tanous                                     std::get_if<bool>(&propertyMap.second);
13767e860f15SJohn Edward Broadbent                                 if (resolveptr == nullptr)
13777e860f15SJohn Edward Broadbent                                 {
1378002d39b4SEd Tanous                                     messages::internalError(asyncResp->res);
13797e860f15SJohn Edward Broadbent                                     return;
13807e860f15SJohn Edward Broadbent                                 }
13817e860f15SJohn Edward Broadbent                                 resolved = *resolveptr;
13827e860f15SJohn Edward Broadbent                             }
13837e860f15SJohn Edward Broadbent                         }
13847e860f15SJohn Edward Broadbent                         if (id == nullptr || message == nullptr ||
13857e860f15SJohn Edward Broadbent                             severity == nullptr)
13867e860f15SJohn Edward Broadbent                         {
13877e860f15SJohn Edward Broadbent                             messages::internalError(asyncResp->res);
13887e860f15SJohn Edward Broadbent                             return;
13897e860f15SJohn Edward Broadbent                         }
13907e860f15SJohn Edward Broadbent                     }
13917e860f15SJohn Edward Broadbent                     else if (interfaceMap.first ==
13927e860f15SJohn Edward Broadbent                              "xyz.openbmc_project.Common.FilePath")
13937e860f15SJohn Edward Broadbent                     {
1394002d39b4SEd Tanous                         for (const auto& propertyMap : interfaceMap.second)
13957e860f15SJohn Edward Broadbent                         {
13967e860f15SJohn Edward Broadbent                             if (propertyMap.first == "Path")
13977e860f15SJohn Edward Broadbent                             {
13987e860f15SJohn Edward Broadbent                                 filePath = std::get_if<std::string>(
13997e860f15SJohn Edward Broadbent                                     &propertyMap.second);
14007e860f15SJohn Edward Broadbent                             }
14017e860f15SJohn Edward Broadbent                         }
14027e860f15SJohn Edward Broadbent                     }
14037e860f15SJohn Edward Broadbent                 }
14047e860f15SJohn Edward Broadbent                 // Object path without the
14057e860f15SJohn Edward Broadbent                 // xyz.openbmc_project.Logging.Entry interface, ignore
14067e860f15SJohn Edward Broadbent                 // and continue.
14077e860f15SJohn Edward Broadbent                 if (id == nullptr || message == nullptr ||
1408c419c759SEd Tanous                     severity == nullptr || timestamp == nullptr ||
1409c419c759SEd Tanous                     updateTimestamp == nullptr)
14107e860f15SJohn Edward Broadbent                 {
14117e860f15SJohn Edward Broadbent                     continue;
14127e860f15SJohn Edward Broadbent                 }
14137e860f15SJohn Edward Broadbent                 entriesArray.push_back({});
14147e860f15SJohn Edward Broadbent                 nlohmann::json& thisEntry = entriesArray.back();
14157e860f15SJohn Edward Broadbent                 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
14167e860f15SJohn Edward Broadbent                 thisEntry["@odata.id"] =
14170fda0f12SGeorge Liu                     "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
14187e860f15SJohn Edward Broadbent                     std::to_string(*id);
14197e860f15SJohn Edward Broadbent                 thisEntry["Name"] = "System Event Log Entry";
14207e860f15SJohn Edward Broadbent                 thisEntry["Id"] = std::to_string(*id);
14217e860f15SJohn Edward Broadbent                 thisEntry["Message"] = *message;
14227e860f15SJohn Edward Broadbent                 thisEntry["Resolved"] = resolved;
14237e860f15SJohn Edward Broadbent                 thisEntry["EntryType"] = "Event";
14247e860f15SJohn Edward Broadbent                 thisEntry["Severity"] =
14257e860f15SJohn Edward Broadbent                     translateSeverityDbusToRedfish(*severity);
14267e860f15SJohn Edward Broadbent                 thisEntry["Created"] =
1427c419c759SEd Tanous                     crow::utility::getDateTimeUintMs(*timestamp);
14287e860f15SJohn Edward Broadbent                 thisEntry["Modified"] =
1429c419c759SEd Tanous                     crow::utility::getDateTimeUintMs(*updateTimestamp);
14307e860f15SJohn Edward Broadbent                 if (filePath != nullptr)
14317e860f15SJohn Edward Broadbent                 {
14327e860f15SJohn Edward Broadbent                     thisEntry["AdditionalDataURI"] =
14330fda0f12SGeorge Liu                         "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
14347e860f15SJohn Edward Broadbent                         std::to_string(*id) + "/attachment";
14357e860f15SJohn Edward Broadbent                 }
14367e860f15SJohn Edward Broadbent             }
1437002d39b4SEd Tanous             std::sort(
1438002d39b4SEd Tanous                 entriesArray.begin(), entriesArray.end(),
1439002d39b4SEd Tanous                 [](const nlohmann::json& left, const nlohmann::json& right) {
14407e860f15SJohn Edward Broadbent                 return (left["Id"] <= right["Id"]);
14417e860f15SJohn Edward Broadbent                 });
14427e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["Members@odata.count"] =
14437e860f15SJohn Edward Broadbent                 entriesArray.size();
14447e860f15SJohn Edward Broadbent             },
14457e860f15SJohn Edward Broadbent             "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
14467e860f15SJohn Edward Broadbent             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
14477e860f15SJohn Edward Broadbent         });
14487e860f15SJohn Edward Broadbent }
14497e860f15SJohn Edward Broadbent 
14507e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app)
14517e860f15SJohn Edward Broadbent {
14527e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
14537e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
1454ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
1455002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1456002d39b4SEd Tanous             [&app](const crow::Request& req,
14577e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
145845ca1b86SEd Tanous                    const std::string& param) {
1459*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
14607e860f15SJohn Edward Broadbent         {
146145ca1b86SEd Tanous             return;
146245ca1b86SEd Tanous         }
14637e860f15SJohn Edward Broadbent         std::string entryID = param;
14647e860f15SJohn Edward Broadbent         dbus::utility::escapePathForDbus(entryID);
14657e860f15SJohn Edward Broadbent 
14667e860f15SJohn Edward Broadbent         // DBus implementation of EventLog/Entries
14677e860f15SJohn Edward Broadbent         // Make call to Logging Service to find all log entry objects
14687e860f15SJohn Edward Broadbent         crow::connections::systemBus->async_method_call(
1469002d39b4SEd Tanous             [asyncResp, entryID](const boost::system::error_code ec,
1470b9d36b47SEd Tanous                                  const dbus::utility::DBusPropertiesMap& resp) {
14717e860f15SJohn Edward Broadbent             if (ec.value() == EBADR)
14727e860f15SJohn Edward Broadbent             {
1473002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1474002d39b4SEd Tanous                                            entryID);
14757e860f15SJohn Edward Broadbent                 return;
14767e860f15SJohn Edward Broadbent             }
14777e860f15SJohn Edward Broadbent             if (ec)
14787e860f15SJohn Edward Broadbent             {
14790fda0f12SGeorge Liu                 BMCWEB_LOG_ERROR
1480002d39b4SEd Tanous                     << "EventLogEntry (DBus) resp_handler got error " << ec;
14817e860f15SJohn Edward Broadbent                 messages::internalError(asyncResp->res);
14827e860f15SJohn Edward Broadbent                 return;
14837e860f15SJohn Edward Broadbent             }
1484914e2d5dSEd Tanous             const uint32_t* id = nullptr;
1485c419c759SEd Tanous             const uint64_t* timestamp = nullptr;
1486c419c759SEd Tanous             const uint64_t* updateTimestamp = nullptr;
1487914e2d5dSEd Tanous             const std::string* severity = nullptr;
1488914e2d5dSEd Tanous             const std::string* message = nullptr;
1489914e2d5dSEd Tanous             const std::string* filePath = nullptr;
14907e860f15SJohn Edward Broadbent             bool resolved = false;
14917e860f15SJohn Edward Broadbent 
14929eb808c1SEd Tanous             for (const auto& propertyMap : resp)
14937e860f15SJohn Edward Broadbent             {
14947e860f15SJohn Edward Broadbent                 if (propertyMap.first == "Id")
14957e860f15SJohn Edward Broadbent                 {
14967e860f15SJohn Edward Broadbent                     id = std::get_if<uint32_t>(&propertyMap.second);
14977e860f15SJohn Edward Broadbent                 }
14987e860f15SJohn Edward Broadbent                 else if (propertyMap.first == "Timestamp")
14997e860f15SJohn Edward Broadbent                 {
1500002d39b4SEd Tanous                     timestamp = std::get_if<uint64_t>(&propertyMap.second);
1501ebd45906SGeorge Liu                 }
1502d139c236SGeorge Liu                 else if (propertyMap.first == "UpdateTimestamp")
1503d139c236SGeorge Liu                 {
1504ebd45906SGeorge Liu                     updateTimestamp =
1505c419c759SEd Tanous                         std::get_if<uint64_t>(&propertyMap.second);
1506ebd45906SGeorge Liu                 }
1507cb92c03bSAndrew Geissler                 else if (propertyMap.first == "Severity")
1508cb92c03bSAndrew Geissler                 {
1509002d39b4SEd Tanous                     severity = std::get_if<std::string>(&propertyMap.second);
1510cb92c03bSAndrew Geissler                 }
1511cb92c03bSAndrew Geissler                 else if (propertyMap.first == "Message")
1512cb92c03bSAndrew Geissler                 {
1513002d39b4SEd Tanous                     message = std::get_if<std::string>(&propertyMap.second);
1514ae34c8e8SAdriana Kobylak                 }
151575710de2SXiaochao Ma                 else if (propertyMap.first == "Resolved")
151675710de2SXiaochao Ma                 {
1517914e2d5dSEd Tanous                     const bool* resolveptr =
151875710de2SXiaochao Ma                         std::get_if<bool>(&propertyMap.second);
151975710de2SXiaochao Ma                     if (resolveptr == nullptr)
152075710de2SXiaochao Ma                     {
152175710de2SXiaochao Ma                         messages::internalError(asyncResp->res);
152275710de2SXiaochao Ma                         return;
152375710de2SXiaochao Ma                     }
152475710de2SXiaochao Ma                     resolved = *resolveptr;
152575710de2SXiaochao Ma                 }
15267e860f15SJohn Edward Broadbent                 else if (propertyMap.first == "Path")
1527f86bb901SAdriana Kobylak                 {
1528002d39b4SEd Tanous                     filePath = std::get_if<std::string>(&propertyMap.second);
1529f86bb901SAdriana Kobylak                 }
1530f86bb901SAdriana Kobylak             }
1531002d39b4SEd Tanous             if (id == nullptr || message == nullptr || severity == nullptr ||
1532002d39b4SEd Tanous                 timestamp == nullptr || updateTimestamp == nullptr)
1533f86bb901SAdriana Kobylak             {
1534ae34c8e8SAdriana Kobylak                 messages::internalError(asyncResp->res);
1535271584abSEd Tanous                 return;
1536271584abSEd Tanous             }
1537f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["@odata.type"] =
1538f86bb901SAdriana Kobylak                 "#LogEntry.v1_8_0.LogEntry";
1539f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["@odata.id"] =
15400fda0f12SGeorge Liu                 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1541f86bb901SAdriana Kobylak                 std::to_string(*id);
154245ca1b86SEd Tanous             asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1543f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1544f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Message"] = *message;
1545f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Resolved"] = resolved;
1546f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["EntryType"] = "Event";
1547f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Severity"] =
1548f86bb901SAdriana Kobylak                 translateSeverityDbusToRedfish(*severity);
1549f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Created"] =
1550c419c759SEd Tanous                 crow::utility::getDateTimeUintMs(*timestamp);
1551f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Modified"] =
1552c419c759SEd Tanous                 crow::utility::getDateTimeUintMs(*updateTimestamp);
1553f86bb901SAdriana Kobylak             if (filePath != nullptr)
1554f86bb901SAdriana Kobylak             {
1555f86bb901SAdriana Kobylak                 asyncResp->res.jsonValue["AdditionalDataURI"] =
1556e7dbd530SPotin Lai                     "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1557e7dbd530SPotin Lai                     std::to_string(*id) + "/attachment";
1558f86bb901SAdriana Kobylak             }
1559cb92c03bSAndrew Geissler             },
1560cb92c03bSAndrew Geissler             "xyz.openbmc_project.Logging",
1561cb92c03bSAndrew Geissler             "/xyz/openbmc_project/logging/entry/" + entryID,
1562f86bb901SAdriana Kobylak             "org.freedesktop.DBus.Properties", "GetAll", "");
15637e860f15SJohn Edward Broadbent         });
1564336e96c6SChicago Duan 
15657e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
15667e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
1567ed398213SEd Tanous         .privileges(redfish::privileges::patchLogEntry)
15687e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
156945ca1b86SEd Tanous             [&app](const crow::Request& req,
15707e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15717e860f15SJohn Edward Broadbent                    const std::string& entryId) {
1572*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
157345ca1b86SEd Tanous         {
157445ca1b86SEd Tanous             return;
157545ca1b86SEd Tanous         }
157675710de2SXiaochao Ma         std::optional<bool> resolved;
157775710de2SXiaochao Ma 
157815ed6780SWilly Tu         if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
15797e860f15SJohn Edward Broadbent                                       resolved))
158075710de2SXiaochao Ma         {
158175710de2SXiaochao Ma             return;
158275710de2SXiaochao Ma         }
158375710de2SXiaochao Ma         BMCWEB_LOG_DEBUG << "Set Resolved";
158475710de2SXiaochao Ma 
158575710de2SXiaochao Ma         crow::connections::systemBus->async_method_call(
15864f48d5f6SEd Tanous             [asyncResp, entryId](const boost::system::error_code ec) {
158775710de2SXiaochao Ma             if (ec)
158875710de2SXiaochao Ma             {
158975710de2SXiaochao Ma                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
159075710de2SXiaochao Ma                 messages::internalError(asyncResp->res);
159175710de2SXiaochao Ma                 return;
159275710de2SXiaochao Ma             }
159375710de2SXiaochao Ma             },
159475710de2SXiaochao Ma             "xyz.openbmc_project.Logging",
159575710de2SXiaochao Ma             "/xyz/openbmc_project/logging/entry/" + entryId,
159675710de2SXiaochao Ma             "org.freedesktop.DBus.Properties", "Set",
159775710de2SXiaochao Ma             "xyz.openbmc_project.Logging.Entry", "Resolved",
1598168e20c1SEd Tanous             dbus::utility::DbusVariantType(*resolved));
15997e860f15SJohn Edward Broadbent         });
160075710de2SXiaochao Ma 
16017e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
16027e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
1603ed398213SEd Tanous         .privileges(redfish::privileges::deleteLogEntry)
1604ed398213SEd Tanous 
1605002d39b4SEd Tanous         .methods(boost::beast::http::verb::delete_)(
1606002d39b4SEd Tanous             [&app](const crow::Request& req,
1607002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
160845ca1b86SEd Tanous                    const std::string& param) {
1609*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1610336e96c6SChicago Duan         {
161145ca1b86SEd Tanous             return;
161245ca1b86SEd Tanous         }
1613336e96c6SChicago Duan         BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1614336e96c6SChicago Duan 
16157e860f15SJohn Edward Broadbent         std::string entryID = param;
1616336e96c6SChicago Duan 
1617336e96c6SChicago Duan         dbus::utility::escapePathForDbus(entryID);
1618336e96c6SChicago Duan 
1619336e96c6SChicago Duan         // Process response from Logging service.
1620002d39b4SEd Tanous         auto respHandler =
1621002d39b4SEd Tanous             [asyncResp, entryID](const boost::system::error_code ec) {
1622002d39b4SEd Tanous             BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1623336e96c6SChicago Duan             if (ec)
1624336e96c6SChicago Duan             {
16253de8d8baSGeorge Liu                 if (ec.value() == EBADR)
16263de8d8baSGeorge Liu                 {
162745ca1b86SEd Tanous                     messages::resourceNotFound(asyncResp->res, "LogEntry",
162845ca1b86SEd Tanous                                                entryID);
16293de8d8baSGeorge Liu                     return;
16303de8d8baSGeorge Liu                 }
1631336e96c6SChicago Duan                 // TODO Handle for specific error code
16320fda0f12SGeorge Liu                 BMCWEB_LOG_ERROR
16330fda0f12SGeorge Liu                     << "EventLogEntry (DBus) doDelete respHandler got error "
1634336e96c6SChicago Duan                     << ec;
1635336e96c6SChicago Duan                 asyncResp->res.result(
1636336e96c6SChicago Duan                     boost::beast::http::status::internal_server_error);
1637336e96c6SChicago Duan                 return;
1638336e96c6SChicago Duan             }
1639336e96c6SChicago Duan 
1640336e96c6SChicago Duan             asyncResp->res.result(boost::beast::http::status::ok);
1641336e96c6SChicago Duan         };
1642336e96c6SChicago Duan 
1643336e96c6SChicago Duan         // Make call to Logging service to request Delete Log
1644336e96c6SChicago Duan         crow::connections::systemBus->async_method_call(
1645336e96c6SChicago Duan             respHandler, "xyz.openbmc_project.Logging",
1646336e96c6SChicago Duan             "/xyz/openbmc_project/logging/entry/" + entryID,
1647336e96c6SChicago Duan             "xyz.openbmc_project.Object.Delete", "Delete");
16487e860f15SJohn Edward Broadbent         });
1649400fd1fbSAdriana Kobylak }
1650400fd1fbSAdriana Kobylak 
16517e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app)
1652400fd1fbSAdriana Kobylak {
16530fda0f12SGeorge Liu     BMCWEB_ROUTE(
16540fda0f12SGeorge Liu         app,
16550fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/attachment")
1656ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
16577e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
165845ca1b86SEd Tanous             [&app](const crow::Request& req,
16597e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
166045ca1b86SEd Tanous                    const std::string& param) {
1661*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
16627e860f15SJohn Edward Broadbent         {
166345ca1b86SEd Tanous             return;
166445ca1b86SEd Tanous         }
1665002d39b4SEd Tanous         if (!http_helpers::isOctetAccepted(req.getHeaderValue("Accept")))
1666400fd1fbSAdriana Kobylak         {
1667002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::bad_request);
1668400fd1fbSAdriana Kobylak             return;
1669400fd1fbSAdriana Kobylak         }
1670400fd1fbSAdriana Kobylak 
16717e860f15SJohn Edward Broadbent         std::string entryID = param;
1672400fd1fbSAdriana Kobylak         dbus::utility::escapePathForDbus(entryID);
1673400fd1fbSAdriana Kobylak 
1674400fd1fbSAdriana Kobylak         crow::connections::systemBus->async_method_call(
1675002d39b4SEd Tanous             [asyncResp, entryID](const boost::system::error_code ec,
1676400fd1fbSAdriana Kobylak                                  const sdbusplus::message::unix_fd& unixfd) {
1677400fd1fbSAdriana Kobylak             if (ec.value() == EBADR)
1678400fd1fbSAdriana Kobylak             {
1679002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1680002d39b4SEd Tanous                                            entryID);
1681400fd1fbSAdriana Kobylak                 return;
1682400fd1fbSAdriana Kobylak             }
1683400fd1fbSAdriana Kobylak             if (ec)
1684400fd1fbSAdriana Kobylak             {
1685400fd1fbSAdriana Kobylak                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1686400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1687400fd1fbSAdriana Kobylak                 return;
1688400fd1fbSAdriana Kobylak             }
1689400fd1fbSAdriana Kobylak 
1690400fd1fbSAdriana Kobylak             int fd = -1;
1691400fd1fbSAdriana Kobylak             fd = dup(unixfd);
1692400fd1fbSAdriana Kobylak             if (fd == -1)
1693400fd1fbSAdriana Kobylak             {
1694400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1695400fd1fbSAdriana Kobylak                 return;
1696400fd1fbSAdriana Kobylak             }
1697400fd1fbSAdriana Kobylak 
1698400fd1fbSAdriana Kobylak             long long int size = lseek(fd, 0, SEEK_END);
1699400fd1fbSAdriana Kobylak             if (size == -1)
1700400fd1fbSAdriana Kobylak             {
1701400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1702400fd1fbSAdriana Kobylak                 return;
1703400fd1fbSAdriana Kobylak             }
1704400fd1fbSAdriana Kobylak 
1705400fd1fbSAdriana Kobylak             // Arbitrary max size of 64kb
1706400fd1fbSAdriana Kobylak             constexpr int maxFileSize = 65536;
1707400fd1fbSAdriana Kobylak             if (size > maxFileSize)
1708400fd1fbSAdriana Kobylak             {
1709002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1710400fd1fbSAdriana Kobylak                                  << maxFileSize;
1711400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1712400fd1fbSAdriana Kobylak                 return;
1713400fd1fbSAdriana Kobylak             }
1714400fd1fbSAdriana Kobylak             std::vector<char> data(static_cast<size_t>(size));
1715400fd1fbSAdriana Kobylak             long long int rc = lseek(fd, 0, SEEK_SET);
1716400fd1fbSAdriana Kobylak             if (rc == -1)
1717400fd1fbSAdriana Kobylak             {
1718400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1719400fd1fbSAdriana Kobylak                 return;
1720400fd1fbSAdriana Kobylak             }
1721400fd1fbSAdriana Kobylak             rc = read(fd, data.data(), data.size());
1722400fd1fbSAdriana Kobylak             if ((rc == -1) || (rc != size))
1723400fd1fbSAdriana Kobylak             {
1724400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1725400fd1fbSAdriana Kobylak                 return;
1726400fd1fbSAdriana Kobylak             }
1727400fd1fbSAdriana Kobylak             close(fd);
1728400fd1fbSAdriana Kobylak 
1729400fd1fbSAdriana Kobylak             std::string_view strData(data.data(), data.size());
1730002d39b4SEd Tanous             std::string output = crow::utility::base64encode(strData);
1731400fd1fbSAdriana Kobylak 
1732400fd1fbSAdriana Kobylak             asyncResp->res.addHeader("Content-Type",
1733400fd1fbSAdriana Kobylak                                      "application/octet-stream");
1734002d39b4SEd Tanous             asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
1735400fd1fbSAdriana Kobylak             asyncResp->res.body() = std::move(output);
1736400fd1fbSAdriana Kobylak             },
1737400fd1fbSAdriana Kobylak             "xyz.openbmc_project.Logging",
1738400fd1fbSAdriana Kobylak             "/xyz/openbmc_project/logging/entry/" + entryID,
1739400fd1fbSAdriana Kobylak             "xyz.openbmc_project.Logging.Entry", "GetEntry");
17407e860f15SJohn Edward Broadbent         });
17411da66f75SEd Tanous }
17421da66f75SEd Tanous 
1743b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console";
1744b7028ebfSSpencer Ku 
1745b7028ebfSSpencer Ku inline bool
1746b7028ebfSSpencer Ku     getHostLoggerFiles(const std::string& hostLoggerFilePath,
1747b7028ebfSSpencer Ku                        std::vector<std::filesystem::path>& hostLoggerFiles)
1748b7028ebfSSpencer Ku {
1749b7028ebfSSpencer Ku     std::error_code ec;
1750b7028ebfSSpencer Ku     std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1751b7028ebfSSpencer Ku     if (ec)
1752b7028ebfSSpencer Ku     {
1753b7028ebfSSpencer Ku         BMCWEB_LOG_ERROR << ec.message();
1754b7028ebfSSpencer Ku         return false;
1755b7028ebfSSpencer Ku     }
1756b7028ebfSSpencer Ku     for (const std::filesystem::directory_entry& it : logPath)
1757b7028ebfSSpencer Ku     {
1758b7028ebfSSpencer Ku         std::string filename = it.path().filename();
1759b7028ebfSSpencer Ku         // Prefix of each log files is "log". Find the file and save the
1760b7028ebfSSpencer Ku         // path
1761b7028ebfSSpencer Ku         if (boost::starts_with(filename, "log"))
1762b7028ebfSSpencer Ku         {
1763b7028ebfSSpencer Ku             hostLoggerFiles.emplace_back(it.path());
1764b7028ebfSSpencer Ku         }
1765b7028ebfSSpencer Ku     }
1766b7028ebfSSpencer Ku     // As the log files rotate, they are appended with a ".#" that is higher for
1767b7028ebfSSpencer Ku     // the older logs. Since we start from oldest logs, sort the name in
1768b7028ebfSSpencer Ku     // descending order.
1769b7028ebfSSpencer Ku     std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1770b7028ebfSSpencer Ku               AlphanumLess<std::string>());
1771b7028ebfSSpencer Ku 
1772b7028ebfSSpencer Ku     return true;
1773b7028ebfSSpencer Ku }
1774b7028ebfSSpencer Ku 
1775b7028ebfSSpencer Ku inline bool
1776b7028ebfSSpencer Ku     getHostLoggerEntries(std::vector<std::filesystem::path>& hostLoggerFiles,
1777c937d2bfSEd Tanous                          uint64_t skip, uint64_t top,
1778b7028ebfSSpencer Ku                          std::vector<std::string>& logEntries, size_t& logCount)
1779b7028ebfSSpencer Ku {
1780b7028ebfSSpencer Ku     GzFileReader logFile;
1781b7028ebfSSpencer Ku 
1782b7028ebfSSpencer Ku     // Go though all log files and expose host logs.
1783b7028ebfSSpencer Ku     for (const std::filesystem::path& it : hostLoggerFiles)
1784b7028ebfSSpencer Ku     {
1785b7028ebfSSpencer Ku         if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
1786b7028ebfSSpencer Ku         {
1787b7028ebfSSpencer Ku             BMCWEB_LOG_ERROR << "fail to expose host logs";
1788b7028ebfSSpencer Ku             return false;
1789b7028ebfSSpencer Ku         }
1790b7028ebfSSpencer Ku     }
1791b7028ebfSSpencer Ku     // Get lastMessage from constructor by getter
1792b7028ebfSSpencer Ku     std::string lastMessage = logFile.getLastMessage();
1793b7028ebfSSpencer Ku     if (!lastMessage.empty())
1794b7028ebfSSpencer Ku     {
1795b7028ebfSSpencer Ku         logCount++;
1796b7028ebfSSpencer Ku         if (logCount > skip && logCount <= (skip + top))
1797b7028ebfSSpencer Ku         {
1798b7028ebfSSpencer Ku             logEntries.push_back(lastMessage);
1799b7028ebfSSpencer Ku         }
1800b7028ebfSSpencer Ku     }
1801b7028ebfSSpencer Ku     return true;
1802b7028ebfSSpencer Ku }
1803b7028ebfSSpencer Ku 
1804b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID,
1805b7028ebfSSpencer Ku                                     const std::string& msg,
1806b7028ebfSSpencer Ku                                     nlohmann::json& logEntryJson)
1807b7028ebfSSpencer Ku {
1808b7028ebfSSpencer Ku     // Fill in the log entry with the gathered data.
1809b7028ebfSSpencer Ku     logEntryJson = {
1810b7028ebfSSpencer Ku         {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
1811b7028ebfSSpencer Ku         {"@odata.id",
1812b7028ebfSSpencer Ku          "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
1813b7028ebfSSpencer Ku              logEntryID},
1814b7028ebfSSpencer Ku         {"Name", "Host Logger Entry"},
1815b7028ebfSSpencer Ku         {"Id", logEntryID},
1816b7028ebfSSpencer Ku         {"Message", msg},
1817b7028ebfSSpencer Ku         {"EntryType", "Oem"},
1818b7028ebfSSpencer Ku         {"Severity", "OK"},
1819b7028ebfSSpencer Ku         {"OemRecordFormat", "Host Logger Entry"}};
1820b7028ebfSSpencer Ku }
1821b7028ebfSSpencer Ku 
1822b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app)
1823b7028ebfSSpencer Ku {
1824b7028ebfSSpencer Ku     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/HostLogger/")
1825b7028ebfSSpencer Ku         .privileges(redfish::privileges::getLogService)
18261476687dSEd Tanous         .methods(boost::beast::http::verb::get)(
18271476687dSEd Tanous             [&app](const crow::Request& req,
18281476687dSEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1829*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
183045ca1b86SEd Tanous         {
183145ca1b86SEd Tanous             return;
183245ca1b86SEd Tanous         }
1833b7028ebfSSpencer Ku         asyncResp->res.jsonValue["@odata.id"] =
1834b7028ebfSSpencer Ku             "/redfish/v1/Systems/system/LogServices/HostLogger";
1835b7028ebfSSpencer Ku         asyncResp->res.jsonValue["@odata.type"] =
1836b7028ebfSSpencer Ku             "#LogService.v1_1_0.LogService";
1837b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Name"] = "Host Logger Service";
1838b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Description"] = "Host Logger Service";
1839b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Id"] = "HostLogger";
18401476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
18411476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1842b7028ebfSSpencer Ku         });
1843b7028ebfSSpencer Ku }
1844b7028ebfSSpencer Ku 
1845b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app)
1846b7028ebfSSpencer Ku {
1847b7028ebfSSpencer Ku     BMCWEB_ROUTE(app,
1848b7028ebfSSpencer Ku                  "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/")
1849b7028ebfSSpencer Ku         .privileges(redfish::privileges::getLogEntry)
1850002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1851002d39b4SEd Tanous             [&app](const crow::Request& req,
1852002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1853c937d2bfSEd Tanous         query_param::QueryCapabilities capabilities = {
1854c937d2bfSEd Tanous             .canDelegateTop = true,
1855c937d2bfSEd Tanous             .canDelegateSkip = true,
1856c937d2bfSEd Tanous         };
1857c937d2bfSEd Tanous         query_param::Query delegatedQuery;
1858c937d2bfSEd Tanous         if (!redfish::setUpRedfishRouteWithDelegation(
1859*3ba00073SCarson Labrado                 app, req, asyncResp, delegatedQuery, capabilities))
1860b7028ebfSSpencer Ku         {
1861b7028ebfSSpencer Ku             return;
1862b7028ebfSSpencer Ku         }
1863b7028ebfSSpencer Ku         asyncResp->res.jsonValue["@odata.id"] =
1864b7028ebfSSpencer Ku             "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1865b7028ebfSSpencer Ku         asyncResp->res.jsonValue["@odata.type"] =
1866b7028ebfSSpencer Ku             "#LogEntryCollection.LogEntryCollection";
1867b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
1868b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Description"] =
1869b7028ebfSSpencer Ku             "Collection of HostLogger Entries";
18700fda0f12SGeorge Liu         nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1871b7028ebfSSpencer Ku         logEntryArray = nlohmann::json::array();
1872b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Members@odata.count"] = 0;
1873b7028ebfSSpencer Ku 
1874b7028ebfSSpencer Ku         std::vector<std::filesystem::path> hostLoggerFiles;
1875b7028ebfSSpencer Ku         if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1876b7028ebfSSpencer Ku         {
1877b7028ebfSSpencer Ku             BMCWEB_LOG_ERROR << "fail to get host log file path";
1878b7028ebfSSpencer Ku             return;
1879b7028ebfSSpencer Ku         }
1880b7028ebfSSpencer Ku 
1881b7028ebfSSpencer Ku         size_t logCount = 0;
1882b7028ebfSSpencer Ku         // This vector only store the entries we want to expose that
1883b7028ebfSSpencer Ku         // control by skip and top.
1884b7028ebfSSpencer Ku         std::vector<std::string> logEntries;
1885c937d2bfSEd Tanous         if (!getHostLoggerEntries(hostLoggerFiles, delegatedQuery.skip,
1886c937d2bfSEd Tanous                                   delegatedQuery.top, logEntries, logCount))
1887b7028ebfSSpencer Ku         {
1888b7028ebfSSpencer Ku             messages::internalError(asyncResp->res);
1889b7028ebfSSpencer Ku             return;
1890b7028ebfSSpencer Ku         }
1891b7028ebfSSpencer Ku         // If vector is empty, that means skip value larger than total
1892b7028ebfSSpencer Ku         // log count
189326f6976fSEd Tanous         if (logEntries.empty())
1894b7028ebfSSpencer Ku         {
1895b7028ebfSSpencer Ku             asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1896b7028ebfSSpencer Ku             return;
1897b7028ebfSSpencer Ku         }
189826f6976fSEd Tanous         if (!logEntries.empty())
1899b7028ebfSSpencer Ku         {
1900b7028ebfSSpencer Ku             for (size_t i = 0; i < logEntries.size(); i++)
1901b7028ebfSSpencer Ku             {
1902b7028ebfSSpencer Ku                 logEntryArray.push_back({});
1903b7028ebfSSpencer Ku                 nlohmann::json& hostLogEntry = logEntryArray.back();
1904002d39b4SEd Tanous                 fillHostLoggerEntryJson(std::to_string(delegatedQuery.skip + i),
1905002d39b4SEd Tanous                                         logEntries[i], hostLogEntry);
1906b7028ebfSSpencer Ku             }
1907b7028ebfSSpencer Ku 
1908b7028ebfSSpencer Ku             asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1909c937d2bfSEd Tanous             if (delegatedQuery.skip + delegatedQuery.top < logCount)
1910b7028ebfSSpencer Ku             {
1911b7028ebfSSpencer Ku                 asyncResp->res.jsonValue["Members@odata.nextLink"] =
19120fda0f12SGeorge Liu                     "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
1913002d39b4SEd Tanous                     std::to_string(delegatedQuery.skip + delegatedQuery.top);
1914b7028ebfSSpencer Ku             }
1915b7028ebfSSpencer Ku         }
1916b7028ebfSSpencer Ku         });
1917b7028ebfSSpencer Ku }
1918b7028ebfSSpencer Ku 
1919b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app)
1920b7028ebfSSpencer Ku {
1921b7028ebfSSpencer Ku     BMCWEB_ROUTE(
1922b7028ebfSSpencer Ku         app, "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/<str>/")
1923b7028ebfSSpencer Ku         .privileges(redfish::privileges::getLogEntry)
1924b7028ebfSSpencer Ku         .methods(boost::beast::http::verb::get)(
192545ca1b86SEd Tanous             [&app](const crow::Request& req,
1926b7028ebfSSpencer Ku                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1927b7028ebfSSpencer Ku                    const std::string& param) {
1928*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
192945ca1b86SEd Tanous         {
193045ca1b86SEd Tanous             return;
193145ca1b86SEd Tanous         }
1932b7028ebfSSpencer Ku         const std::string& targetID = param;
1933b7028ebfSSpencer Ku 
1934b7028ebfSSpencer Ku         uint64_t idInt = 0;
1935ca45aa3cSEd Tanous 
1936ca45aa3cSEd Tanous         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1937ca45aa3cSEd Tanous         const char* end = targetID.data() + targetID.size();
1938ca45aa3cSEd Tanous 
1939ca45aa3cSEd Tanous         auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
1940b7028ebfSSpencer Ku         if (ec == std::errc::invalid_argument)
1941b7028ebfSSpencer Ku         {
1942ace85d60SEd Tanous             messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1943b7028ebfSSpencer Ku             return;
1944b7028ebfSSpencer Ku         }
1945b7028ebfSSpencer Ku         if (ec == std::errc::result_out_of_range)
1946b7028ebfSSpencer Ku         {
1947ace85d60SEd Tanous             messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1948b7028ebfSSpencer Ku             return;
1949b7028ebfSSpencer Ku         }
1950b7028ebfSSpencer Ku 
1951b7028ebfSSpencer Ku         std::vector<std::filesystem::path> hostLoggerFiles;
1952b7028ebfSSpencer Ku         if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1953b7028ebfSSpencer Ku         {
1954b7028ebfSSpencer Ku             BMCWEB_LOG_ERROR << "fail to get host log file path";
1955b7028ebfSSpencer Ku             return;
1956b7028ebfSSpencer Ku         }
1957b7028ebfSSpencer Ku 
1958b7028ebfSSpencer Ku         size_t logCount = 0;
1959b7028ebfSSpencer Ku         uint64_t top = 1;
1960b7028ebfSSpencer Ku         std::vector<std::string> logEntries;
1961b7028ebfSSpencer Ku         // We can get specific entry by skip and top. For example, if we
1962b7028ebfSSpencer Ku         // want to get nth entry, we can set skip = n-1 and top = 1 to
1963b7028ebfSSpencer Ku         // get that entry
1964002d39b4SEd Tanous         if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
1965002d39b4SEd Tanous                                   logCount))
1966b7028ebfSSpencer Ku         {
1967b7028ebfSSpencer Ku             messages::internalError(asyncResp->res);
1968b7028ebfSSpencer Ku             return;
1969b7028ebfSSpencer Ku         }
1970b7028ebfSSpencer Ku 
1971b7028ebfSSpencer Ku         if (!logEntries.empty())
1972b7028ebfSSpencer Ku         {
1973b7028ebfSSpencer Ku             fillHostLoggerEntryJson(targetID, logEntries[0],
1974b7028ebfSSpencer Ku                                     asyncResp->res.jsonValue);
1975b7028ebfSSpencer Ku             return;
1976b7028ebfSSpencer Ku         }
1977b7028ebfSSpencer Ku 
1978b7028ebfSSpencer Ku         // Requested ID was not found
1979ace85d60SEd Tanous         messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1980b7028ebfSSpencer Ku         });
1981b7028ebfSSpencer Ku }
1982b7028ebfSSpencer Ku 
19837e860f15SJohn Edward Broadbent inline void requestRoutesBMCLogServiceCollection(App& app)
19841da66f75SEd Tanous {
19857e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
1986ad89dcf0SGunnar Mills         .privileges(redfish::privileges::getLogServiceCollection)
19877e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
198845ca1b86SEd Tanous             [&app](const crow::Request& req,
19897e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1990*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
199145ca1b86SEd Tanous         {
199245ca1b86SEd Tanous             return;
199345ca1b86SEd Tanous         }
19947e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
19957e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
1996e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
19971da66f75SEd Tanous             "#LogServiceCollection.LogServiceCollection";
1998e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.id"] =
1999e1f26343SJason M. Bills             "/redfish/v1/Managers/bmc/LogServices";
2000002d39b4SEd Tanous         asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2001e1f26343SJason M. Bills         asyncResp->res.jsonValue["Description"] =
20021da66f75SEd Tanous             "Collection of LogServices for this Manager";
2003002d39b4SEd Tanous         nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2004c4bf6374SJason M. Bills         logServiceArray = nlohmann::json::array();
20055cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
20065cb1dd27SAsmitha Karunanithi         logServiceArray.push_back(
2007002d39b4SEd Tanous             {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Dump"}});
20085cb1dd27SAsmitha Karunanithi #endif
2009c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
2010c4bf6374SJason M. Bills         logServiceArray.push_back(
2011002d39b4SEd Tanous             {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal"}});
2012c4bf6374SJason M. Bills #endif
2013e1f26343SJason M. Bills         asyncResp->res.jsonValue["Members@odata.count"] =
2014c4bf6374SJason M. Bills             logServiceArray.size();
20157e860f15SJohn Edward Broadbent         });
2016e1f26343SJason M. Bills }
2017e1f26343SJason M. Bills 
20187e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app)
2019e1f26343SJason M. Bills {
20207e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
2021ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
20227e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
202345ca1b86SEd Tanous             [&app](const crow::Request& req,
202445ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2025*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
20267e860f15SJohn Edward Broadbent         {
202745ca1b86SEd Tanous             return;
202845ca1b86SEd Tanous         }
2029e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
2030e1f26343SJason M. Bills             "#LogService.v1_1_0.LogService";
20310f74e643SEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
20320f74e643SEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Journal";
2033002d39b4SEd Tanous         asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2034002d39b4SEd Tanous         asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2035c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Id"] = "BMC Journal";
2036e1f26343SJason M. Bills         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
20377c8c4058STejas Patil 
20387c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
20397c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
2040002d39b4SEd Tanous         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
20417c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
20427c8c4058STejas Patil             redfishDateTimeOffset.second;
20437c8c4058STejas Patil 
20441476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
20451476687dSEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
20467e860f15SJohn Edward Broadbent         });
2047e1f26343SJason M. Bills }
2048e1f26343SJason M. Bills 
2049c4bf6374SJason M. Bills static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2050e1f26343SJason M. Bills                                       sd_journal* journal,
2051c4bf6374SJason M. Bills                                       nlohmann::json& bmcJournalLogEntryJson)
2052e1f26343SJason M. Bills {
2053e1f26343SJason M. Bills     // Get the Log Entry contents
2054e1f26343SJason M. Bills     int ret = 0;
2055e1f26343SJason M. Bills 
2056a8fe54f0SJason M. Bills     std::string message;
2057a8fe54f0SJason M. Bills     std::string_view syslogID;
2058a8fe54f0SJason M. Bills     ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2059a8fe54f0SJason M. Bills     if (ret < 0)
2060a8fe54f0SJason M. Bills     {
2061a8fe54f0SJason M. Bills         BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2062a8fe54f0SJason M. Bills                          << strerror(-ret);
2063a8fe54f0SJason M. Bills     }
2064a8fe54f0SJason M. Bills     if (!syslogID.empty())
2065a8fe54f0SJason M. Bills     {
2066a8fe54f0SJason M. Bills         message += std::string(syslogID) + ": ";
2067a8fe54f0SJason M. Bills     }
2068a8fe54f0SJason M. Bills 
206939e77504SEd Tanous     std::string_view msg;
207016428a1aSJason M. Bills     ret = getJournalMetadata(journal, "MESSAGE", msg);
2071e1f26343SJason M. Bills     if (ret < 0)
2072e1f26343SJason M. Bills     {
2073e1f26343SJason M. Bills         BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2074e1f26343SJason M. Bills         return 1;
2075e1f26343SJason M. Bills     }
2076a8fe54f0SJason M. Bills     message += std::string(msg);
2077e1f26343SJason M. Bills 
2078e1f26343SJason M. Bills     // Get the severity from the PRIORITY field
2079271584abSEd Tanous     long int severity = 8; // Default to an invalid priority
208016428a1aSJason M. Bills     ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
2081e1f26343SJason M. Bills     if (ret < 0)
2082e1f26343SJason M. Bills     {
2083e1f26343SJason M. Bills         BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
2084e1f26343SJason M. Bills     }
2085e1f26343SJason M. Bills 
2086e1f26343SJason M. Bills     // Get the Created time from the timestamp
208716428a1aSJason M. Bills     std::string entryTimeStr;
208816428a1aSJason M. Bills     if (!getEntryTimestamp(journal, entryTimeStr))
2089e1f26343SJason M. Bills     {
209016428a1aSJason M. Bills         return 1;
2091e1f26343SJason M. Bills     }
2092e1f26343SJason M. Bills 
2093e1f26343SJason M. Bills     // Fill in the log entry with the gathered data
2094c4bf6374SJason M. Bills     bmcJournalLogEntryJson = {
2095647b3cdcSGeorge Liu         {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
2096c4bf6374SJason M. Bills         {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2097c4bf6374SJason M. Bills                           bmcJournalLogEntryID},
2098e1f26343SJason M. Bills         {"Name", "BMC Journal Entry"},
2099c4bf6374SJason M. Bills         {"Id", bmcJournalLogEntryID},
2100a8fe54f0SJason M. Bills         {"Message", std::move(message)},
2101e1f26343SJason M. Bills         {"EntryType", "Oem"},
2102738c1e61SPatrick Williams         {"Severity", severity <= 2   ? "Critical"
2103738c1e61SPatrick Williams                      : severity <= 4 ? "Warning"
2104738c1e61SPatrick Williams                                      : "OK"},
2105086be238SEd Tanous         {"OemRecordFormat", "BMC Journal Entry"},
2106e1f26343SJason M. Bills         {"Created", std::move(entryTimeStr)}};
2107e1f26343SJason M. Bills     return 0;
2108e1f26343SJason M. Bills }
2109e1f26343SJason M. Bills 
21107e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app)
2111e1f26343SJason M. Bills {
21127e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
2113ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
2114002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2115002d39b4SEd Tanous             [&app](const crow::Request& req,
2116002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2117c937d2bfSEd Tanous         query_param::QueryCapabilities capabilities = {
2118c937d2bfSEd Tanous             .canDelegateTop = true,
2119c937d2bfSEd Tanous             .canDelegateSkip = true,
2120c937d2bfSEd Tanous         };
2121c937d2bfSEd Tanous         query_param::Query delegatedQuery;
2122c937d2bfSEd Tanous         if (!redfish::setUpRedfishRouteWithDelegation(
2123*3ba00073SCarson Labrado                 app, req, asyncResp, delegatedQuery, capabilities))
2124193ad2faSJason M. Bills         {
2125193ad2faSJason M. Bills             return;
2126193ad2faSJason M. Bills         }
21277e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
21287e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
2129e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
2130e1f26343SJason M. Bills             "#LogEntryCollection.LogEntryCollection";
21310f74e643SEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
21320f74e643SEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2133e1f26343SJason M. Bills         asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2134e1f26343SJason M. Bills         asyncResp->res.jsonValue["Description"] =
2135e1f26343SJason M. Bills             "Collection of BMC Journal Entries";
21360fda0f12SGeorge Liu         nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2137e1f26343SJason M. Bills         logEntryArray = nlohmann::json::array();
2138e1f26343SJason M. Bills 
21397e860f15SJohn Edward Broadbent         // Go through the journal and use the timestamp to create a
21407e860f15SJohn Edward Broadbent         // unique ID for each entry
2141e1f26343SJason M. Bills         sd_journal* journalTmp = nullptr;
2142e1f26343SJason M. Bills         int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2143e1f26343SJason M. Bills         if (ret < 0)
2144e1f26343SJason M. Bills         {
2145002d39b4SEd Tanous             BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2146f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2147e1f26343SJason M. Bills             return;
2148e1f26343SJason M. Bills         }
21490fda0f12SGeorge Liu         std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
21500fda0f12SGeorge Liu             journalTmp, sd_journal_close);
2151e1f26343SJason M. Bills         journalTmp = nullptr;
2152b01bf299SEd Tanous         uint64_t entryCount = 0;
2153e85d6b16SJason M. Bills         // Reset the unique ID on the first entry
2154e85d6b16SJason M. Bills         bool firstEntry = true;
2155e1f26343SJason M. Bills         SD_JOURNAL_FOREACH(journal.get())
2156e1f26343SJason M. Bills         {
2157193ad2faSJason M. Bills             entryCount++;
21587e860f15SJohn Edward Broadbent             // Handle paging using skip (number of entries to skip from
21597e860f15SJohn Edward Broadbent             // the start) and top (number of entries to display)
2160c937d2bfSEd Tanous             if (entryCount <= delegatedQuery.skip ||
2161c937d2bfSEd Tanous                 entryCount > delegatedQuery.skip + delegatedQuery.top)
2162193ad2faSJason M. Bills             {
2163193ad2faSJason M. Bills                 continue;
2164193ad2faSJason M. Bills             }
2165193ad2faSJason M. Bills 
216616428a1aSJason M. Bills             std::string idStr;
2167e85d6b16SJason M. Bills             if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2168e1f26343SJason M. Bills             {
2169e1f26343SJason M. Bills                 continue;
2170e1f26343SJason M. Bills             }
2171e1f26343SJason M. Bills 
2172e85d6b16SJason M. Bills             if (firstEntry)
2173e85d6b16SJason M. Bills             {
2174e85d6b16SJason M. Bills                 firstEntry = false;
2175e85d6b16SJason M. Bills             }
2176e85d6b16SJason M. Bills 
2177e1f26343SJason M. Bills             logEntryArray.push_back({});
2178c4bf6374SJason M. Bills             nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
2179c4bf6374SJason M. Bills             if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2180c4bf6374SJason M. Bills                                            bmcJournalLogEntry) != 0)
2181e1f26343SJason M. Bills             {
2182f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
2183e1f26343SJason M. Bills                 return;
2184e1f26343SJason M. Bills             }
2185e1f26343SJason M. Bills         }
2186193ad2faSJason M. Bills         asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
2187c937d2bfSEd Tanous         if (delegatedQuery.skip + delegatedQuery.top < entryCount)
2188193ad2faSJason M. Bills         {
2189193ad2faSJason M. Bills             asyncResp->res.jsonValue["Members@odata.nextLink"] =
21900fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
2191c937d2bfSEd Tanous                 std::to_string(delegatedQuery.skip + delegatedQuery.top);
2192193ad2faSJason M. Bills         }
21937e860f15SJohn Edward Broadbent         });
2194e1f26343SJason M. Bills }
2195e1f26343SJason M. Bills 
21967e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app)
2197e1f26343SJason M. Bills {
21987e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
21997e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
2200ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
22017e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
220245ca1b86SEd Tanous             [&app](const crow::Request& req,
22037e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
22047e860f15SJohn Edward Broadbent                    const std::string& entryID) {
2205*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
220645ca1b86SEd Tanous         {
220745ca1b86SEd Tanous             return;
220845ca1b86SEd Tanous         }
2209e1f26343SJason M. Bills         // Convert the unique ID back to a timestamp to find the entry
2210e1f26343SJason M. Bills         uint64_t ts = 0;
2211271584abSEd Tanous         uint64_t index = 0;
22128d1b46d7Szhanghch05         if (!getTimestampFromID(asyncResp, entryID, ts, index))
2213e1f26343SJason M. Bills         {
221416428a1aSJason M. Bills             return;
2215e1f26343SJason M. Bills         }
2216e1f26343SJason M. Bills 
2217e1f26343SJason M. Bills         sd_journal* journalTmp = nullptr;
2218e1f26343SJason M. Bills         int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2219e1f26343SJason M. Bills         if (ret < 0)
2220e1f26343SJason M. Bills         {
2221002d39b4SEd Tanous             BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2222f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2223e1f26343SJason M. Bills             return;
2224e1f26343SJason M. Bills         }
2225002d39b4SEd Tanous         std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2226002d39b4SEd Tanous             journalTmp, sd_journal_close);
2227e1f26343SJason M. Bills         journalTmp = nullptr;
22287e860f15SJohn Edward Broadbent         // Go to the timestamp in the log and move to the entry at the
22297e860f15SJohn Edward Broadbent         // index tracking the unique ID
2230af07e3f5SJason M. Bills         std::string idStr;
2231af07e3f5SJason M. Bills         bool firstEntry = true;
2232e1f26343SJason M. Bills         ret = sd_journal_seek_realtime_usec(journal.get(), ts);
22332056b6d1SManojkiran Eda         if (ret < 0)
22342056b6d1SManojkiran Eda         {
22352056b6d1SManojkiran Eda             BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
22362056b6d1SManojkiran Eda                              << strerror(-ret);
22372056b6d1SManojkiran Eda             messages::internalError(asyncResp->res);
22382056b6d1SManojkiran Eda             return;
22392056b6d1SManojkiran Eda         }
2240271584abSEd Tanous         for (uint64_t i = 0; i <= index; i++)
2241e1f26343SJason M. Bills         {
2242e1f26343SJason M. Bills             sd_journal_next(journal.get());
2243af07e3f5SJason M. Bills             if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2244af07e3f5SJason M. Bills             {
2245af07e3f5SJason M. Bills                 messages::internalError(asyncResp->res);
2246af07e3f5SJason M. Bills                 return;
2247af07e3f5SJason M. Bills             }
2248af07e3f5SJason M. Bills             if (firstEntry)
2249af07e3f5SJason M. Bills             {
2250af07e3f5SJason M. Bills                 firstEntry = false;
2251af07e3f5SJason M. Bills             }
2252e1f26343SJason M. Bills         }
2253c4bf6374SJason M. Bills         // Confirm that the entry ID matches what was requested
2254af07e3f5SJason M. Bills         if (idStr != entryID)
2255c4bf6374SJason M. Bills         {
2256ace85d60SEd Tanous             messages::resourceMissingAtURI(asyncResp->res, req.urlView);
2257c4bf6374SJason M. Bills             return;
2258c4bf6374SJason M. Bills         }
2259c4bf6374SJason M. Bills 
2260c4bf6374SJason M. Bills         if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2261e1f26343SJason M. Bills                                        asyncResp->res.jsonValue) != 0)
2262e1f26343SJason M. Bills         {
2263f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2264e1f26343SJason M. Bills             return;
2265e1f26343SJason M. Bills         }
22667e860f15SJohn Edward Broadbent         });
2267c9bb6861Sraviteja-b }
2268c9bb6861Sraviteja-b 
22697e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpService(App& app)
2270c9bb6861Sraviteja-b {
22717e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
2272ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
2273002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2274002d39b4SEd Tanous             [&app](const crow::Request& req,
2275002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2276*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
227745ca1b86SEd Tanous         {
227845ca1b86SEd Tanous             return;
227945ca1b86SEd Tanous         }
2280c9bb6861Sraviteja-b         asyncResp->res.jsonValue["@odata.id"] =
22815cb1dd27SAsmitha Karunanithi             "/redfish/v1/Managers/bmc/LogServices/Dump";
2282c9bb6861Sraviteja-b         asyncResp->res.jsonValue["@odata.type"] =
2283d337bb72SAsmitha Karunanithi             "#LogService.v1_2_0.LogService";
2284c9bb6861Sraviteja-b         asyncResp->res.jsonValue["Name"] = "Dump LogService";
22855cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Description"] = "BMC Dump LogService";
22865cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Id"] = "Dump";
2287c9bb6861Sraviteja-b         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
22887c8c4058STejas Patil 
22897c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
22907c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
22910fda0f12SGeorge Liu         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
22927c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
22937c8c4058STejas Patil             redfishDateTimeOffset.second;
22947c8c4058STejas Patil 
22951476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
22961476687dSEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2297002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
22981476687dSEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog";
2299002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
23001476687dSEd Tanous                                 ["target"] =
23011476687dSEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData";
23027e860f15SJohn Edward Broadbent         });
2303c9bb6861Sraviteja-b }
2304c9bb6861Sraviteja-b 
23057e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntryCollection(App& app)
23067e860f15SJohn Edward Broadbent {
23077e860f15SJohn Edward Broadbent 
2308c9bb6861Sraviteja-b     /**
2309c9bb6861Sraviteja-b      * Functions triggers appropriate requests on DBus
2310c9bb6861Sraviteja-b      */
23117e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
2312ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
23137e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
231445ca1b86SEd Tanous             [&app](const crow::Request& req,
23157e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2316*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
231745ca1b86SEd Tanous         {
231845ca1b86SEd Tanous             return;
231945ca1b86SEd Tanous         }
2320c9bb6861Sraviteja-b         asyncResp->res.jsonValue["@odata.type"] =
2321c9bb6861Sraviteja-b             "#LogEntryCollection.LogEntryCollection";
2322c9bb6861Sraviteja-b         asyncResp->res.jsonValue["@odata.id"] =
23235cb1dd27SAsmitha Karunanithi             "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
23245cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Name"] = "BMC Dump Entries";
2325c9bb6861Sraviteja-b         asyncResp->res.jsonValue["Description"] =
23265cb1dd27SAsmitha Karunanithi             "Collection of BMC Dump Entries";
2327c9bb6861Sraviteja-b 
23285cb1dd27SAsmitha Karunanithi         getDumpEntryCollection(asyncResp, "BMC");
23297e860f15SJohn Edward Broadbent         });
2330c9bb6861Sraviteja-b }
2331c9bb6861Sraviteja-b 
23327e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app)
2333c9bb6861Sraviteja-b {
23347e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
23357e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
2336ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
23377e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
233845ca1b86SEd Tanous             [&app](const crow::Request& req,
23397e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
23407e860f15SJohn Edward Broadbent                    const std::string& param) {
2341*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
234245ca1b86SEd Tanous         {
234345ca1b86SEd Tanous             return;
234445ca1b86SEd Tanous         }
2345c7a6d660SClaire Weinan         getDumpEntryById(asyncResp, param, "BMC");
23467e860f15SJohn Edward Broadbent         });
23477e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
23487e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
2349ed398213SEd Tanous         .privileges(redfish::privileges::deleteLogEntry)
23507e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
235145ca1b86SEd Tanous             [&app](const crow::Request& req,
23527e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
23537e860f15SJohn Edward Broadbent                    const std::string& param) {
2354*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
235545ca1b86SEd Tanous         {
235645ca1b86SEd Tanous             return;
235745ca1b86SEd Tanous         }
23587e860f15SJohn Edward Broadbent         deleteDumpEntry(asyncResp, param, "bmc");
23597e860f15SJohn Edward Broadbent         });
2360c9bb6861Sraviteja-b }
2361c9bb6861Sraviteja-b 
23627e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app)
2363c9bb6861Sraviteja-b {
23640fda0f12SGeorge Liu     BMCWEB_ROUTE(
23650fda0f12SGeorge Liu         app,
23660fda0f12SGeorge Liu         "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
2367ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
23687e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
236945ca1b86SEd Tanous             [&app](const crow::Request& req,
23707e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2371*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
237245ca1b86SEd Tanous         {
237345ca1b86SEd Tanous             return;
237445ca1b86SEd Tanous         }
23758d1b46d7Szhanghch05         createDump(asyncResp, req, "BMC");
23767e860f15SJohn Edward Broadbent         });
2377a43be80fSAsmitha Karunanithi }
2378a43be80fSAsmitha Karunanithi 
23797e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app)
238080319af1SAsmitha Karunanithi {
23810fda0f12SGeorge Liu     BMCWEB_ROUTE(
23820fda0f12SGeorge Liu         app,
23830fda0f12SGeorge Liu         "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
2384ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
23857e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
238645ca1b86SEd Tanous             [&app](const crow::Request& req,
23877e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2388*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
238945ca1b86SEd Tanous         {
239045ca1b86SEd Tanous             return;
239145ca1b86SEd Tanous         }
23928d1b46d7Szhanghch05         clearDump(asyncResp, "BMC");
23937e860f15SJohn Edward Broadbent         });
23945cb1dd27SAsmitha Karunanithi }
23955cb1dd27SAsmitha Karunanithi 
23967e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app)
23975cb1dd27SAsmitha Karunanithi {
23987e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/")
2399ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
2400002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2401002d39b4SEd Tanous             [&app](const crow::Request& req,
2402002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2403*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
24047e860f15SJohn Edward Broadbent         {
240545ca1b86SEd Tanous             return;
240645ca1b86SEd Tanous         }
24075cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["@odata.id"] =
24085cb1dd27SAsmitha Karunanithi             "/redfish/v1/Systems/system/LogServices/Dump";
24095cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["@odata.type"] =
2410d337bb72SAsmitha Karunanithi             "#LogService.v1_2_0.LogService";
24115cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Name"] = "Dump LogService";
241245ca1b86SEd Tanous         asyncResp->res.jsonValue["Description"] = "System Dump LogService";
24135cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Id"] = "Dump";
24145cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
24157c8c4058STejas Patil 
24167c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
24177c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
241845ca1b86SEd Tanous         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
24197c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
24207c8c4058STejas Patil             redfishDateTimeOffset.second;
24217c8c4058STejas Patil 
24221476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
24231476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2424002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
24251476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog";
24261476687dSEd Tanous 
2427002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
24281476687dSEd Tanous                                 ["target"] =
24291476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData";
24307e860f15SJohn Edward Broadbent         });
24315cb1dd27SAsmitha Karunanithi }
24325cb1dd27SAsmitha Karunanithi 
24337e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app)
24347e860f15SJohn Edward Broadbent {
24357e860f15SJohn Edward Broadbent 
24365cb1dd27SAsmitha Karunanithi     /**
24375cb1dd27SAsmitha Karunanithi      * Functions triggers appropriate requests on DBus
24385cb1dd27SAsmitha Karunanithi      */
2439b2a3289dSAsmitha Karunanithi     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
2440ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
24417e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
244245ca1b86SEd Tanous             [&app](const crow::Request& req,
2443864d6a17SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2444*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
244545ca1b86SEd Tanous         {
244645ca1b86SEd Tanous             return;
244745ca1b86SEd Tanous         }
24485cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["@odata.type"] =
24495cb1dd27SAsmitha Karunanithi             "#LogEntryCollection.LogEntryCollection";
24505cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["@odata.id"] =
24515cb1dd27SAsmitha Karunanithi             "/redfish/v1/Systems/system/LogServices/Dump/Entries";
24525cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Name"] = "System Dump Entries";
24535cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Description"] =
24545cb1dd27SAsmitha Karunanithi             "Collection of System Dump Entries";
24555cb1dd27SAsmitha Karunanithi 
24565cb1dd27SAsmitha Karunanithi         getDumpEntryCollection(asyncResp, "System");
24577e860f15SJohn Edward Broadbent         });
24585cb1dd27SAsmitha Karunanithi }
24595cb1dd27SAsmitha Karunanithi 
24607e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app)
24615cb1dd27SAsmitha Karunanithi {
24627e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2463864d6a17SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
2464ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
2465ed398213SEd Tanous 
24667e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
246745ca1b86SEd Tanous             [&app](const crow::Request& req,
24687e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24697e860f15SJohn Edward Broadbent                    const std::string& param) {
2470*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2471c7a6d660SClaire Weinan         {
2472c7a6d660SClaire Weinan             return;
2473c7a6d660SClaire Weinan         }
2474c7a6d660SClaire Weinan         getDumpEntryById(asyncResp, param, "System");
24757e860f15SJohn Edward Broadbent         });
24768d1b46d7Szhanghch05 
24777e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2478864d6a17SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
2479ed398213SEd Tanous         .privileges(redfish::privileges::deleteLogEntry)
24807e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
248145ca1b86SEd Tanous             [&app](const crow::Request& req,
24827e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24837e860f15SJohn Edward Broadbent                    const std::string& param) {
2484*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
248545ca1b86SEd Tanous         {
248645ca1b86SEd Tanous             return;
248745ca1b86SEd Tanous         }
24887e860f15SJohn Edward Broadbent         deleteDumpEntry(asyncResp, param, "system");
24897e860f15SJohn Edward Broadbent         });
24905cb1dd27SAsmitha Karunanithi }
2491c9bb6861Sraviteja-b 
24927e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app)
2493c9bb6861Sraviteja-b {
24940fda0f12SGeorge Liu     BMCWEB_ROUTE(
24950fda0f12SGeorge Liu         app,
24960fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
2497ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
24987e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
249945ca1b86SEd Tanous             [&app](const crow::Request& req,
250045ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2501*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
250245ca1b86SEd Tanous         {
250345ca1b86SEd Tanous             return;
250445ca1b86SEd Tanous         }
250545ca1b86SEd Tanous         createDump(asyncResp, req, "System");
250645ca1b86SEd Tanous         });
2507a43be80fSAsmitha Karunanithi }
2508a43be80fSAsmitha Karunanithi 
25097e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app)
2510a43be80fSAsmitha Karunanithi {
25110fda0f12SGeorge Liu     BMCWEB_ROUTE(
25120fda0f12SGeorge Liu         app,
25130fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog/")
2514ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
25157e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
251645ca1b86SEd Tanous             [&app](const crow::Request& req,
25177e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
25187e860f15SJohn Edward Broadbent 
251945ca1b86SEd Tanous             {
2520*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
252145ca1b86SEd Tanous         {
252245ca1b86SEd Tanous             return;
252345ca1b86SEd Tanous         }
252445ca1b86SEd Tanous         clearDump(asyncResp, "System");
252545ca1b86SEd Tanous         });
2526013487e5Sraviteja-b }
2527013487e5Sraviteja-b 
25287e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app)
25291da66f75SEd Tanous {
25303946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
25313946028dSAppaRao Puli     // method for security reasons.
25321da66f75SEd Tanous     /**
25331da66f75SEd Tanous      * Functions triggers appropriate requests on DBus
25341da66f75SEd Tanous      */
25357e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
2536ed398213SEd Tanous         // This is incorrect, should be:
2537ed398213SEd Tanous         //.privileges(redfish::privileges::getLogService)
2538432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
2539002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2540002d39b4SEd Tanous             [&app](const crow::Request& req,
2541002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2542*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
254345ca1b86SEd Tanous         {
254445ca1b86SEd Tanous             return;
254545ca1b86SEd Tanous         }
25467e860f15SJohn Edward Broadbent         // Copy over the static data to include the entries added by
25477e860f15SJohn Edward Broadbent         // SubRoute
25480f74e643SEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
2549424c4176SJason M. Bills             "/redfish/v1/Systems/system/LogServices/Crashdump";
2550e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
25518e6c099aSJason M. Bills             "#LogService.v1_2_0.LogService";
25524f50ae4bSGunnar Mills         asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
25534f50ae4bSGunnar Mills         asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
25544f50ae4bSGunnar Mills         asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2555e1f26343SJason M. Bills         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2556e1f26343SJason M. Bills         asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
25577c8c4058STejas Patil 
25587c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
25597c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
25607c8c4058STejas Patil         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
25617c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
25627c8c4058STejas Patil             redfishDateTimeOffset.second;
25637c8c4058STejas Patil 
25641476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
25651476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2566002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
25671476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
2568002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
25691476687dSEd Tanous                                 ["target"] =
25701476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
25717e860f15SJohn Edward Broadbent         });
25721da66f75SEd Tanous }
25731da66f75SEd Tanous 
25747e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app)
25755b61b5e8SJason M. Bills {
25760fda0f12SGeorge Liu     BMCWEB_ROUTE(
25770fda0f12SGeorge Liu         app,
25780fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog/")
2579ed398213SEd Tanous         // This is incorrect, should be:
2580ed398213SEd Tanous         //.privileges(redfish::privileges::postLogService)
2581432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
25827e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
258345ca1b86SEd Tanous             [&app](const crow::Request& req,
25847e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2585*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
258645ca1b86SEd Tanous         {
258745ca1b86SEd Tanous             return;
258845ca1b86SEd Tanous         }
25895b61b5e8SJason M. Bills         crow::connections::systemBus->async_method_call(
25905b61b5e8SJason M. Bills             [asyncResp](const boost::system::error_code ec,
2591cb13a392SEd Tanous                         const std::string&) {
25925b61b5e8SJason M. Bills             if (ec)
25935b61b5e8SJason M. Bills             {
25945b61b5e8SJason M. Bills                 messages::internalError(asyncResp->res);
25955b61b5e8SJason M. Bills                 return;
25965b61b5e8SJason M. Bills             }
25975b61b5e8SJason M. Bills             messages::success(asyncResp->res);
25985b61b5e8SJason M. Bills             },
2599002d39b4SEd Tanous             crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
26007e860f15SJohn Edward Broadbent         });
26015b61b5e8SJason M. Bills }
26025b61b5e8SJason M. Bills 
26038d1b46d7Szhanghch05 static void
26048d1b46d7Szhanghch05     logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
26058d1b46d7Szhanghch05                       const std::string& logID, nlohmann::json& logEntryJson)
2606e855dd28SJason M. Bills {
2607043a0536SJohnathan Mantey     auto getStoredLogCallback =
2608b9d36b47SEd Tanous         [asyncResp, logID,
2609b9d36b47SEd Tanous          &logEntryJson](const boost::system::error_code ec,
2610b9d36b47SEd Tanous                         const dbus::utility::DBusPropertiesMap& params) {
2611e855dd28SJason M. Bills         if (ec)
2612e855dd28SJason M. Bills         {
2613e855dd28SJason M. Bills             BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
26141ddcf01aSJason M. Bills             if (ec.value() ==
26151ddcf01aSJason M. Bills                 boost::system::linux_error::bad_request_descriptor)
26161ddcf01aSJason M. Bills             {
2617002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
26181ddcf01aSJason M. Bills             }
26191ddcf01aSJason M. Bills             else
26201ddcf01aSJason M. Bills             {
2621e855dd28SJason M. Bills                 messages::internalError(asyncResp->res);
26221ddcf01aSJason M. Bills             }
2623e855dd28SJason M. Bills             return;
2624e855dd28SJason M. Bills         }
2625043a0536SJohnathan Mantey 
2626043a0536SJohnathan Mantey         std::string timestamp{};
2627043a0536SJohnathan Mantey         std::string filename{};
2628043a0536SJohnathan Mantey         std::string logfile{};
26292c70f800SEd Tanous         parseCrashdumpParameters(params, filename, timestamp, logfile);
2630043a0536SJohnathan Mantey 
2631043a0536SJohnathan Mantey         if (filename.empty() || timestamp.empty())
2632e855dd28SJason M. Bills         {
2633002d39b4SEd Tanous             messages::resourceMissingAtURI(asyncResp->res,
2634002d39b4SEd Tanous                                            crow::utility::urlFromPieces(logID));
2635e855dd28SJason M. Bills             return;
2636e855dd28SJason M. Bills         }
2637e855dd28SJason M. Bills 
2638043a0536SJohnathan Mantey         std::string crashdumpURI =
2639e855dd28SJason M. Bills             "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2640043a0536SJohnathan Mantey             logID + "/" + filename;
26412b20ef6eSJason M. Bills         nlohmann::json logEntry = {
26424978b63fSJason M. Bills             {"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
26434978b63fSJason M. Bills             {"@odata.id",
26444978b63fSJason M. Bills              "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2645e855dd28SJason M. Bills                  logID},
2646e855dd28SJason M. Bills             {"Name", "CPU Crashdump"},
2647e855dd28SJason M. Bills             {"Id", logID},
2648e855dd28SJason M. Bills             {"EntryType", "Oem"},
26498e6c099aSJason M. Bills             {"AdditionalDataURI", std::move(crashdumpURI)},
26508e6c099aSJason M. Bills             {"DiagnosticDataType", "OEM"},
26518e6c099aSJason M. Bills             {"OEMDiagnosticDataType", "PECICrashdump"},
2652043a0536SJohnathan Mantey             {"Created", std::move(timestamp)}};
26532b20ef6eSJason M. Bills 
26542b20ef6eSJason M. Bills         // If logEntryJson references an array of LogEntry resources
26552b20ef6eSJason M. Bills         // ('Members' list), then push this as a new entry, otherwise set it
26562b20ef6eSJason M. Bills         // directly
26572b20ef6eSJason M. Bills         if (logEntryJson.is_array())
26582b20ef6eSJason M. Bills         {
26592b20ef6eSJason M. Bills             logEntryJson.push_back(logEntry);
26602b20ef6eSJason M. Bills             asyncResp->res.jsonValue["Members@odata.count"] =
26612b20ef6eSJason M. Bills                 logEntryJson.size();
26622b20ef6eSJason M. Bills         }
26632b20ef6eSJason M. Bills         else
26642b20ef6eSJason M. Bills         {
26652b20ef6eSJason M. Bills             logEntryJson = logEntry;
26662b20ef6eSJason M. Bills         }
2667e855dd28SJason M. Bills     };
2668e855dd28SJason M. Bills     crow::connections::systemBus->async_method_call(
26695b61b5e8SJason M. Bills         std::move(getStoredLogCallback), crashdumpObject,
26705b61b5e8SJason M. Bills         crashdumpPath + std::string("/") + logID,
2671043a0536SJohnathan Mantey         "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
2672e855dd28SJason M. Bills }
2673e855dd28SJason M. Bills 
26747e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app)
26751da66f75SEd Tanous {
26763946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
26773946028dSAppaRao Puli     // method for security reasons.
26781da66f75SEd Tanous     /**
26791da66f75SEd Tanous      * Functions triggers appropriate requests on DBus
26801da66f75SEd Tanous      */
26817e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
26827e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
2683ed398213SEd Tanous         // This is incorrect, should be.
2684ed398213SEd Tanous         //.privileges(redfish::privileges::postLogEntryCollection)
2685432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
2686002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2687002d39b4SEd Tanous             [&app](const crow::Request& req,
2688002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2689*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
269045ca1b86SEd Tanous         {
269145ca1b86SEd Tanous             return;
269245ca1b86SEd Tanous         }
26932b20ef6eSJason M. Bills         crow::connections::systemBus->async_method_call(
26942b20ef6eSJason M. Bills             [asyncResp](const boost::system::error_code ec,
26952b20ef6eSJason M. Bills                         const std::vector<std::string>& resp) {
26961da66f75SEd Tanous             if (ec)
26971da66f75SEd Tanous             {
26981da66f75SEd Tanous                 if (ec.value() !=
26991da66f75SEd Tanous                     boost::system::errc::no_such_file_or_directory)
27001da66f75SEd Tanous                 {
27011da66f75SEd Tanous                     BMCWEB_LOG_DEBUG << "failed to get entries ec: "
27021da66f75SEd Tanous                                      << ec.message();
2703f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
27041da66f75SEd Tanous                     return;
27051da66f75SEd Tanous                 }
27061da66f75SEd Tanous             }
2707e1f26343SJason M. Bills             asyncResp->res.jsonValue["@odata.type"] =
27081da66f75SEd Tanous                 "#LogEntryCollection.LogEntryCollection";
27090f74e643SEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
2710424c4176SJason M. Bills                 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2711002d39b4SEd Tanous             asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
2712e1f26343SJason M. Bills             asyncResp->res.jsonValue["Description"] =
2713424c4176SJason M. Bills                 "Collection of Crashdump Entries";
2714002d39b4SEd Tanous             asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
2715a2dd60a6SBrandon Kim             asyncResp->res.jsonValue["Members@odata.count"] = 0;
27162b20ef6eSJason M. Bills 
27172b20ef6eSJason M. Bills             for (const std::string& path : resp)
27181da66f75SEd Tanous             {
27192b20ef6eSJason M. Bills                 const sdbusplus::message::object_path objPath(path);
2720e855dd28SJason M. Bills                 // Get the log ID
27212b20ef6eSJason M. Bills                 std::string logID = objPath.filename();
27222b20ef6eSJason M. Bills                 if (logID.empty())
27231da66f75SEd Tanous                 {
2724e855dd28SJason M. Bills                     continue;
27251da66f75SEd Tanous                 }
2726e855dd28SJason M. Bills                 // Add the log entry to the array
27272b20ef6eSJason M. Bills                 logCrashdumpEntry(asyncResp, logID,
27282b20ef6eSJason M. Bills                                   asyncResp->res.jsonValue["Members"]);
27291da66f75SEd Tanous             }
27302b20ef6eSJason M. Bills             },
27311da66f75SEd Tanous             "xyz.openbmc_project.ObjectMapper",
27321da66f75SEd Tanous             "/xyz/openbmc_project/object_mapper",
27331da66f75SEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
27345b61b5e8SJason M. Bills             std::array<const char*, 1>{crashdumpInterface});
27357e860f15SJohn Edward Broadbent         });
27361da66f75SEd Tanous }
27371da66f75SEd Tanous 
27387e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app)
27391da66f75SEd Tanous {
27403946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
27413946028dSAppaRao Puli     // method for security reasons.
27421da66f75SEd Tanous 
27437e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
27447e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/")
2745ed398213SEd Tanous         // this is incorrect, should be
2746ed398213SEd Tanous         // .privileges(redfish::privileges::getLogEntry)
2747432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
27487e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
274945ca1b86SEd Tanous             [&app](const crow::Request& req,
27507e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
27517e860f15SJohn Edward Broadbent                    const std::string& param) {
2752*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
275345ca1b86SEd Tanous         {
275445ca1b86SEd Tanous             return;
275545ca1b86SEd Tanous         }
27567e860f15SJohn Edward Broadbent         const std::string& logID = param;
2757e855dd28SJason M. Bills         logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
27587e860f15SJohn Edward Broadbent         });
2759e855dd28SJason M. Bills }
2760e855dd28SJason M. Bills 
27617e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app)
2762e855dd28SJason M. Bills {
27633946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
27643946028dSAppaRao Puli     // method for security reasons.
27657e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
27667e860f15SJohn Edward Broadbent         app,
27677e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/<str>/")
2768ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
27697e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
277045ca1b86SEd Tanous             [&app](const crow::Request& req,
27717e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
27727e860f15SJohn Edward Broadbent                    const std::string& logID, const std::string& fileName) {
2773*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
277445ca1b86SEd Tanous         {
277545ca1b86SEd Tanous             return;
277645ca1b86SEd Tanous         }
2777043a0536SJohnathan Mantey         auto getStoredLogCallback =
2778002d39b4SEd Tanous             [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
2779abf2add6SEd Tanous                 const boost::system::error_code ec,
2780002d39b4SEd Tanous                 const std::vector<
2781002d39b4SEd Tanous                     std::pair<std::string, dbus::utility::DbusVariantType>>&
27827e860f15SJohn Edward Broadbent                     resp) {
27831da66f75SEd Tanous             if (ec)
27841da66f75SEd Tanous             {
2785002d39b4SEd Tanous                 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2786f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
27871da66f75SEd Tanous                 return;
27881da66f75SEd Tanous             }
2789e855dd28SJason M. Bills 
2790043a0536SJohnathan Mantey             std::string dbusFilename{};
2791043a0536SJohnathan Mantey             std::string dbusTimestamp{};
2792043a0536SJohnathan Mantey             std::string dbusFilepath{};
2793043a0536SJohnathan Mantey 
2794002d39b4SEd Tanous             parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
2795002d39b4SEd Tanous                                      dbusFilepath);
2796043a0536SJohnathan Mantey 
2797043a0536SJohnathan Mantey             if (dbusFilename.empty() || dbusTimestamp.empty() ||
2798043a0536SJohnathan Mantey                 dbusFilepath.empty())
27991da66f75SEd Tanous             {
2800ace85d60SEd Tanous                 messages::resourceMissingAtURI(asyncResp->res, url);
28011da66f75SEd Tanous                 return;
28021da66f75SEd Tanous             }
2803e855dd28SJason M. Bills 
2804043a0536SJohnathan Mantey             // Verify the file name parameter is correct
2805043a0536SJohnathan Mantey             if (fileName != dbusFilename)
2806043a0536SJohnathan Mantey             {
2807ace85d60SEd Tanous                 messages::resourceMissingAtURI(asyncResp->res, url);
2808043a0536SJohnathan Mantey                 return;
2809043a0536SJohnathan Mantey             }
2810043a0536SJohnathan Mantey 
2811043a0536SJohnathan Mantey             if (!std::filesystem::exists(dbusFilepath))
2812043a0536SJohnathan Mantey             {
2813ace85d60SEd Tanous                 messages::resourceMissingAtURI(asyncResp->res, url);
2814043a0536SJohnathan Mantey                 return;
2815043a0536SJohnathan Mantey             }
2816002d39b4SEd Tanous             std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
2817002d39b4SEd Tanous             asyncResp->res.body() =
2818002d39b4SEd Tanous                 std::string(std::istreambuf_iterator<char>{ifs}, {});
2819043a0536SJohnathan Mantey 
28207e860f15SJohn Edward Broadbent             // Configure this to be a file download when accessed
28217e860f15SJohn Edward Broadbent             // from a browser
2822002d39b4SEd Tanous             asyncResp->res.addHeader("Content-Disposition", "attachment");
28231da66f75SEd Tanous         };
28241da66f75SEd Tanous         crow::connections::systemBus->async_method_call(
28255b61b5e8SJason M. Bills             std::move(getStoredLogCallback), crashdumpObject,
28265b61b5e8SJason M. Bills             crashdumpPath + std::string("/") + logID,
2827002d39b4SEd Tanous             "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
28287e860f15SJohn Edward Broadbent         });
28291da66f75SEd Tanous }
28301da66f75SEd Tanous 
2831c5a4c82aSJason M. Bills enum class OEMDiagnosticType
2832c5a4c82aSJason M. Bills {
2833c5a4c82aSJason M. Bills     onDemand,
2834c5a4c82aSJason M. Bills     telemetry,
2835c5a4c82aSJason M. Bills     invalid,
2836c5a4c82aSJason M. Bills };
2837c5a4c82aSJason M. Bills 
2838f7725d79SEd Tanous inline OEMDiagnosticType
2839f7725d79SEd Tanous     getOEMDiagnosticType(const std::string_view& oemDiagStr)
2840c5a4c82aSJason M. Bills {
2841c5a4c82aSJason M. Bills     if (oemDiagStr == "OnDemand")
2842c5a4c82aSJason M. Bills     {
2843c5a4c82aSJason M. Bills         return OEMDiagnosticType::onDemand;
2844c5a4c82aSJason M. Bills     }
2845c5a4c82aSJason M. Bills     if (oemDiagStr == "Telemetry")
2846c5a4c82aSJason M. Bills     {
2847c5a4c82aSJason M. Bills         return OEMDiagnosticType::telemetry;
2848c5a4c82aSJason M. Bills     }
2849c5a4c82aSJason M. Bills 
2850c5a4c82aSJason M. Bills     return OEMDiagnosticType::invalid;
2851c5a4c82aSJason M. Bills }
2852c5a4c82aSJason M. Bills 
28537e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app)
28541da66f75SEd Tanous {
28553946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
28563946028dSAppaRao Puli     // method for security reasons.
28570fda0f12SGeorge Liu     BMCWEB_ROUTE(
28580fda0f12SGeorge Liu         app,
28590fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
2860ed398213SEd Tanous         // The below is incorrect;  Should be ConfigureManager
2861ed398213SEd Tanous         //.privileges(redfish::privileges::postLogService)
2862432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
2863002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
2864002d39b4SEd Tanous             [&app](const crow::Request& req,
28657e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2866*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
286745ca1b86SEd Tanous         {
286845ca1b86SEd Tanous             return;
286945ca1b86SEd Tanous         }
28708e6c099aSJason M. Bills         std::string diagnosticDataType;
28718e6c099aSJason M. Bills         std::string oemDiagnosticDataType;
287215ed6780SWilly Tu         if (!redfish::json_util::readJsonAction(
2873002d39b4SEd Tanous                 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
2874002d39b4SEd Tanous                 "OEMDiagnosticDataType", oemDiagnosticDataType))
28758e6c099aSJason M. Bills         {
28768e6c099aSJason M. Bills             return;
28778e6c099aSJason M. Bills         }
28788e6c099aSJason M. Bills 
28798e6c099aSJason M. Bills         if (diagnosticDataType != "OEM")
28808e6c099aSJason M. Bills         {
28818e6c099aSJason M. Bills             BMCWEB_LOG_ERROR
28828e6c099aSJason M. Bills                 << "Only OEM DiagnosticDataType supported for Crashdump";
28838e6c099aSJason M. Bills             messages::actionParameterValueFormatError(
28848e6c099aSJason M. Bills                 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
28858e6c099aSJason M. Bills                 "CollectDiagnosticData");
28868e6c099aSJason M. Bills             return;
28878e6c099aSJason M. Bills         }
28888e6c099aSJason M. Bills 
2889c5a4c82aSJason M. Bills         OEMDiagnosticType oemDiagType =
2890c5a4c82aSJason M. Bills             getOEMDiagnosticType(oemDiagnosticDataType);
2891c5a4c82aSJason M. Bills 
2892c5a4c82aSJason M. Bills         std::string iface;
2893c5a4c82aSJason M. Bills         std::string method;
2894c5a4c82aSJason M. Bills         std::string taskMatchStr;
2895c5a4c82aSJason M. Bills         if (oemDiagType == OEMDiagnosticType::onDemand)
2896c5a4c82aSJason M. Bills         {
2897c5a4c82aSJason M. Bills             iface = crashdumpOnDemandInterface;
2898c5a4c82aSJason M. Bills             method = "GenerateOnDemandLog";
2899c5a4c82aSJason M. Bills             taskMatchStr = "type='signal',"
2900c5a4c82aSJason M. Bills                            "interface='org.freedesktop.DBus.Properties',"
2901c5a4c82aSJason M. Bills                            "member='PropertiesChanged',"
2902c5a4c82aSJason M. Bills                            "arg0namespace='com.intel.crashdump'";
2903c5a4c82aSJason M. Bills         }
2904c5a4c82aSJason M. Bills         else if (oemDiagType == OEMDiagnosticType::telemetry)
2905c5a4c82aSJason M. Bills         {
2906c5a4c82aSJason M. Bills             iface = crashdumpTelemetryInterface;
2907c5a4c82aSJason M. Bills             method = "GenerateTelemetryLog";
2908c5a4c82aSJason M. Bills             taskMatchStr = "type='signal',"
2909c5a4c82aSJason M. Bills                            "interface='org.freedesktop.DBus.Properties',"
2910c5a4c82aSJason M. Bills                            "member='PropertiesChanged',"
2911c5a4c82aSJason M. Bills                            "arg0namespace='com.intel.crashdump'";
2912c5a4c82aSJason M. Bills         }
2913c5a4c82aSJason M. Bills         else
2914c5a4c82aSJason M. Bills         {
2915c5a4c82aSJason M. Bills             BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
2916c5a4c82aSJason M. Bills                              << oemDiagnosticDataType;
2917c5a4c82aSJason M. Bills             messages::actionParameterValueFormatError(
2918002d39b4SEd Tanous                 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
2919002d39b4SEd Tanous                 "CollectDiagnosticData");
2920c5a4c82aSJason M. Bills             return;
2921c5a4c82aSJason M. Bills         }
2922c5a4c82aSJason M. Bills 
2923c5a4c82aSJason M. Bills         auto collectCrashdumpCallback =
2924c5a4c82aSJason M. Bills             [asyncResp, payload(task::Payload(req)),
2925c5a4c82aSJason M. Bills              taskMatchStr](const boost::system::error_code ec,
292698be3e39SEd Tanous                            const std::string&) mutable {
29271da66f75SEd Tanous             if (ec)
29281da66f75SEd Tanous             {
2929002d39b4SEd Tanous                 if (ec.value() == boost::system::errc::operation_not_supported)
29301da66f75SEd Tanous                 {
2931f12894f8SJason M. Bills                     messages::resourceInStandby(asyncResp->res);
29321da66f75SEd Tanous                 }
29334363d3b2SJason M. Bills                 else if (ec.value() ==
29344363d3b2SJason M. Bills                          boost::system::errc::device_or_resource_busy)
29354363d3b2SJason M. Bills                 {
2936002d39b4SEd Tanous                     messages::serviceTemporarilyUnavailable(asyncResp->res,
2937002d39b4SEd Tanous                                                             "60");
29384363d3b2SJason M. Bills                 }
29391da66f75SEd Tanous                 else
29401da66f75SEd Tanous                 {
2941f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
29421da66f75SEd Tanous                 }
29431da66f75SEd Tanous                 return;
29441da66f75SEd Tanous             }
2945002d39b4SEd Tanous             std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
2946002d39b4SEd Tanous                 [](boost::system::error_code err, sdbusplus::message::message&,
2947002d39b4SEd Tanous                    const std::shared_ptr<task::TaskData>& taskData) {
294866afe4faSJames Feist                 if (!err)
294966afe4faSJames Feist                 {
2950002d39b4SEd Tanous                     taskData->messages.emplace_back(messages::taskCompletedOK(
2951e5d5006bSJames Feist                         std::to_string(taskData->index)));
2952831d6b09SJames Feist                     taskData->state = "Completed";
295366afe4faSJames Feist                 }
295432898ceaSJames Feist                 return task::completed;
295566afe4faSJames Feist                 },
2956c5a4c82aSJason M. Bills                 taskMatchStr);
2957c5a4c82aSJason M. Bills 
295846229577SJames Feist             task->startTimer(std::chrono::minutes(5));
295946229577SJames Feist             task->populateResp(asyncResp->res);
296098be3e39SEd Tanous             task->payload.emplace(std::move(payload));
29611da66f75SEd Tanous         };
29628e6c099aSJason M. Bills 
29631da66f75SEd Tanous         crow::connections::systemBus->async_method_call(
2964002d39b4SEd Tanous             std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
2965002d39b4SEd Tanous             iface, method);
29667e860f15SJohn Edward Broadbent         });
29676eda7685SKenny L. Ku }
29686eda7685SKenny L. Ku 
2969cb92c03bSAndrew Geissler /**
2970cb92c03bSAndrew Geissler  * DBusLogServiceActionsClear class supports POST method for ClearLog action.
2971cb92c03bSAndrew Geissler  */
29727e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app)
2973cb92c03bSAndrew Geissler {
2974cb92c03bSAndrew Geissler     /**
2975cb92c03bSAndrew Geissler      * Function handles POST method request.
2976cb92c03bSAndrew Geissler      * The Clear Log actions does not require any parameter.The action deletes
2977cb92c03bSAndrew Geissler      * all entries found in the Entries collection for this Log Service.
2978cb92c03bSAndrew Geissler      */
29797e860f15SJohn Edward Broadbent 
29800fda0f12SGeorge Liu     BMCWEB_ROUTE(
29810fda0f12SGeorge Liu         app,
29820fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
2983ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
29847e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
298545ca1b86SEd Tanous             [&app](const crow::Request& req,
29867e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2987*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
298845ca1b86SEd Tanous         {
298945ca1b86SEd Tanous             return;
299045ca1b86SEd Tanous         }
2991cb92c03bSAndrew Geissler         BMCWEB_LOG_DEBUG << "Do delete all entries.";
2992cb92c03bSAndrew Geissler 
2993cb92c03bSAndrew Geissler         // Process response from Logging service.
2994002d39b4SEd Tanous         auto respHandler = [asyncResp](const boost::system::error_code ec) {
2995002d39b4SEd Tanous             BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
2996cb92c03bSAndrew Geissler             if (ec)
2997cb92c03bSAndrew Geissler             {
2998cb92c03bSAndrew Geissler                 // TODO Handle for specific error code
2999002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3000cb92c03bSAndrew Geissler                 asyncResp->res.result(
3001cb92c03bSAndrew Geissler                     boost::beast::http::status::internal_server_error);
3002cb92c03bSAndrew Geissler                 return;
3003cb92c03bSAndrew Geissler             }
3004cb92c03bSAndrew Geissler 
3005002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::no_content);
3006cb92c03bSAndrew Geissler         };
3007cb92c03bSAndrew Geissler 
3008cb92c03bSAndrew Geissler         // Make call to Logging service to request Clear Log
3009cb92c03bSAndrew Geissler         crow::connections::systemBus->async_method_call(
30102c70f800SEd Tanous             respHandler, "xyz.openbmc_project.Logging",
3011cb92c03bSAndrew Geissler             "/xyz/openbmc_project/logging",
3012cb92c03bSAndrew Geissler             "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
30137e860f15SJohn Edward Broadbent         });
3014cb92c03bSAndrew Geissler }
3015a3316fc6SZhikuiRen 
3016a3316fc6SZhikuiRen /****************************************************
3017a3316fc6SZhikuiRen  * Redfish PostCode interfaces
3018a3316fc6SZhikuiRen  * using DBUS interface: getPostCodesTS
3019a3316fc6SZhikuiRen  ******************************************************/
30207e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app)
3021a3316fc6SZhikuiRen {
30227e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
3023ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
3024002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
3025002d39b4SEd Tanous             [&app](const crow::Request& req,
3026002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3027*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
302845ca1b86SEd Tanous         {
302945ca1b86SEd Tanous             return;
303045ca1b86SEd Tanous         }
30311476687dSEd Tanous 
30321476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
30331476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/PostCodes";
30341476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
30351476687dSEd Tanous             "#LogService.v1_1_0.LogService";
30361476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
30371476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
30381476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
30391476687dSEd Tanous         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
30401476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
30411476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
30427c8c4058STejas Patil 
30437c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
30447c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
30450fda0f12SGeorge Liu         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
30467c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
30477c8c4058STejas Patil             redfishDateTimeOffset.second;
30487c8c4058STejas Patil 
3049a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
30507e860f15SJohn Edward Broadbent             {"target",
30510fda0f12SGeorge Liu              "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
30527e860f15SJohn Edward Broadbent         });
3053a3316fc6SZhikuiRen }
3054a3316fc6SZhikuiRen 
30557e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app)
3056a3316fc6SZhikuiRen {
30570fda0f12SGeorge Liu     BMCWEB_ROUTE(
30580fda0f12SGeorge Liu         app,
30590fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog/")
3060ed398213SEd Tanous         // The following privilege is incorrect;  It should be ConfigureManager
3061ed398213SEd Tanous         //.privileges(redfish::privileges::postLogService)
3062432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
30637e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
306445ca1b86SEd Tanous             [&app](const crow::Request& req,
30657e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3066*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
306745ca1b86SEd Tanous         {
306845ca1b86SEd Tanous             return;
306945ca1b86SEd Tanous         }
3070a3316fc6SZhikuiRen         BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
3071a3316fc6SZhikuiRen 
3072a3316fc6SZhikuiRen         // Make call to post-code service to request clear all
3073a3316fc6SZhikuiRen         crow::connections::systemBus->async_method_call(
3074a3316fc6SZhikuiRen             [asyncResp](const boost::system::error_code ec) {
3075a3316fc6SZhikuiRen             if (ec)
3076a3316fc6SZhikuiRen             {
3077a3316fc6SZhikuiRen                 // TODO Handle for specific error code
3078002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
30797e860f15SJohn Edward Broadbent                                  << ec;
3080002d39b4SEd Tanous                 asyncResp->res.result(
3081002d39b4SEd Tanous                     boost::beast::http::status::internal_server_error);
3082a3316fc6SZhikuiRen                 messages::internalError(asyncResp->res);
3083a3316fc6SZhikuiRen                 return;
3084a3316fc6SZhikuiRen             }
3085a3316fc6SZhikuiRen             },
308615124765SJonathan Doman             "xyz.openbmc_project.State.Boot.PostCode0",
308715124765SJonathan Doman             "/xyz/openbmc_project/State/Boot/PostCode0",
3088a3316fc6SZhikuiRen             "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
30897e860f15SJohn Edward Broadbent         });
3090a3316fc6SZhikuiRen }
3091a3316fc6SZhikuiRen 
3092a3316fc6SZhikuiRen static void fillPostCodeEntry(
30938d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
30946c9a279eSManojkiran Eda     const boost::container::flat_map<
30956c9a279eSManojkiran Eda         uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
3096a3316fc6SZhikuiRen     const uint16_t bootIndex, const uint64_t codeIndex = 0,
3097a3316fc6SZhikuiRen     const uint64_t skip = 0, const uint64_t top = 0)
3098a3316fc6SZhikuiRen {
3099a3316fc6SZhikuiRen     // Get the Message from the MessageRegistry
3100fffb8c1fSEd Tanous     const registries::Message* message =
3101fffb8c1fSEd Tanous         registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
3102a3316fc6SZhikuiRen 
3103a3316fc6SZhikuiRen     uint64_t currentCodeIndex = 0;
3104a3316fc6SZhikuiRen     nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
3105a3316fc6SZhikuiRen 
3106a3316fc6SZhikuiRen     uint64_t firstCodeTimeUs = 0;
31076c9a279eSManojkiran Eda     for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
31086c9a279eSManojkiran Eda              code : postcode)
3109a3316fc6SZhikuiRen     {
3110a3316fc6SZhikuiRen         currentCodeIndex++;
3111a3316fc6SZhikuiRen         std::string postcodeEntryID =
3112a3316fc6SZhikuiRen             "B" + std::to_string(bootIndex) + "-" +
3113a3316fc6SZhikuiRen             std::to_string(currentCodeIndex); // 1 based index in EntryID string
3114a3316fc6SZhikuiRen 
3115a3316fc6SZhikuiRen         uint64_t usecSinceEpoch = code.first;
3116a3316fc6SZhikuiRen         uint64_t usTimeOffset = 0;
3117a3316fc6SZhikuiRen 
3118a3316fc6SZhikuiRen         if (1 == currentCodeIndex)
3119a3316fc6SZhikuiRen         { // already incremented
3120a3316fc6SZhikuiRen             firstCodeTimeUs = code.first;
3121a3316fc6SZhikuiRen         }
3122a3316fc6SZhikuiRen         else
3123a3316fc6SZhikuiRen         {
3124a3316fc6SZhikuiRen             usTimeOffset = code.first - firstCodeTimeUs;
3125a3316fc6SZhikuiRen         }
3126a3316fc6SZhikuiRen 
3127a3316fc6SZhikuiRen         // skip if no specific codeIndex is specified and currentCodeIndex does
3128a3316fc6SZhikuiRen         // not fall between top and skip
3129a3316fc6SZhikuiRen         if ((codeIndex == 0) &&
3130a3316fc6SZhikuiRen             (currentCodeIndex <= skip || currentCodeIndex > top))
3131a3316fc6SZhikuiRen         {
3132a3316fc6SZhikuiRen             continue;
3133a3316fc6SZhikuiRen         }
3134a3316fc6SZhikuiRen 
31354e0453b1SGunnar Mills         // skip if a specific codeIndex is specified and does not match the
3136a3316fc6SZhikuiRen         // currentIndex
3137a3316fc6SZhikuiRen         if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3138a3316fc6SZhikuiRen         {
3139a3316fc6SZhikuiRen             // This is done for simplicity. 1st entry is needed to calculate
3140a3316fc6SZhikuiRen             // time offset. To improve efficiency, one can get to the entry
3141a3316fc6SZhikuiRen             // directly (possibly with flatmap's nth method)
3142a3316fc6SZhikuiRen             continue;
3143a3316fc6SZhikuiRen         }
3144a3316fc6SZhikuiRen 
3145a3316fc6SZhikuiRen         // currentCodeIndex is within top and skip or equal to specified code
3146a3316fc6SZhikuiRen         // index
3147a3316fc6SZhikuiRen 
3148a3316fc6SZhikuiRen         // Get the Created time from the timestamp
3149a3316fc6SZhikuiRen         std::string entryTimeStr;
31501d8782e7SNan Zhou         entryTimeStr =
31511d8782e7SNan Zhou             crow::utility::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
3152a3316fc6SZhikuiRen 
3153a3316fc6SZhikuiRen         // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3154a3316fc6SZhikuiRen         std::ostringstream hexCode;
3155a3316fc6SZhikuiRen         hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
31566c9a279eSManojkiran Eda                 << std::get<0>(code.second);
3157a3316fc6SZhikuiRen         std::ostringstream timeOffsetStr;
3158a3316fc6SZhikuiRen         // Set Fixed -Point Notation
3159a3316fc6SZhikuiRen         timeOffsetStr << std::fixed;
3160a3316fc6SZhikuiRen         // Set precision to 4 digits
3161a3316fc6SZhikuiRen         timeOffsetStr << std::setprecision(4);
3162a3316fc6SZhikuiRen         // Add double to stream
3163a3316fc6SZhikuiRen         timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3164a3316fc6SZhikuiRen         std::vector<std::string> messageArgs = {
3165a3316fc6SZhikuiRen             std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3166a3316fc6SZhikuiRen 
3167a3316fc6SZhikuiRen         // Get MessageArgs template from message registry
3168a3316fc6SZhikuiRen         std::string msg;
3169a3316fc6SZhikuiRen         if (message != nullptr)
3170a3316fc6SZhikuiRen         {
3171a3316fc6SZhikuiRen             msg = message->message;
3172a3316fc6SZhikuiRen 
3173a3316fc6SZhikuiRen             // fill in this post code value
3174a3316fc6SZhikuiRen             int i = 0;
3175a3316fc6SZhikuiRen             for (const std::string& messageArg : messageArgs)
3176a3316fc6SZhikuiRen             {
3177a3316fc6SZhikuiRen                 std::string argStr = "%" + std::to_string(++i);
3178a3316fc6SZhikuiRen                 size_t argPos = msg.find(argStr);
3179a3316fc6SZhikuiRen                 if (argPos != std::string::npos)
3180a3316fc6SZhikuiRen                 {
3181a3316fc6SZhikuiRen                     msg.replace(argPos, argStr.length(), messageArg);
3182a3316fc6SZhikuiRen                 }
3183a3316fc6SZhikuiRen             }
3184a3316fc6SZhikuiRen         }
3185a3316fc6SZhikuiRen 
3186d4342a92STim Lee         // Get Severity template from message registry
3187d4342a92STim Lee         std::string severity;
3188d4342a92STim Lee         if (message != nullptr)
3189d4342a92STim Lee         {
31905f2b84eeSEd Tanous             severity = message->messageSeverity;
3191d4342a92STim Lee         }
3192d4342a92STim Lee 
3193a3316fc6SZhikuiRen         // add to AsyncResp
3194a3316fc6SZhikuiRen         logEntryArray.push_back({});
3195a3316fc6SZhikuiRen         nlohmann::json& bmcLogEntry = logEntryArray.back();
31960fda0f12SGeorge Liu         bmcLogEntry = {
31970fda0f12SGeorge Liu             {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
31980fda0f12SGeorge Liu             {"@odata.id",
31990fda0f12SGeorge Liu              "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3200a3316fc6SZhikuiRen                  postcodeEntryID},
3201a3316fc6SZhikuiRen             {"Name", "POST Code Log Entry"},
3202a3316fc6SZhikuiRen             {"Id", postcodeEntryID},
3203a3316fc6SZhikuiRen             {"Message", std::move(msg)},
32044a0bf539SManojkiran Eda             {"MessageId", "OpenBMC.0.2.BIOSPOSTCode"},
3205a3316fc6SZhikuiRen             {"MessageArgs", std::move(messageArgs)},
3206a3316fc6SZhikuiRen             {"EntryType", "Event"},
3207a3316fc6SZhikuiRen             {"Severity", std::move(severity)},
32089c620e21SAsmitha Karunanithi             {"Created", entryTimeStr}};
3209647b3cdcSGeorge Liu         if (!std::get<std::vector<uint8_t>>(code.second).empty())
3210647b3cdcSGeorge Liu         {
3211647b3cdcSGeorge Liu             bmcLogEntry["AdditionalDataURI"] =
3212647b3cdcSGeorge Liu                 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3213647b3cdcSGeorge Liu                 postcodeEntryID + "/attachment";
3214647b3cdcSGeorge Liu         }
3215a3316fc6SZhikuiRen     }
3216a3316fc6SZhikuiRen }
3217a3316fc6SZhikuiRen 
32188d1b46d7Szhanghch05 static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3219a3316fc6SZhikuiRen                                 const uint16_t bootIndex,
3220a3316fc6SZhikuiRen                                 const uint64_t codeIndex)
3221a3316fc6SZhikuiRen {
3222a3316fc6SZhikuiRen     crow::connections::systemBus->async_method_call(
32236c9a279eSManojkiran Eda         [aResp, bootIndex,
32246c9a279eSManojkiran Eda          codeIndex](const boost::system::error_code ec,
32256c9a279eSManojkiran Eda                     const boost::container::flat_map<
32266c9a279eSManojkiran Eda                         uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
32276c9a279eSManojkiran Eda                         postcode) {
3228a3316fc6SZhikuiRen         if (ec)
3229a3316fc6SZhikuiRen         {
3230a3316fc6SZhikuiRen             BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3231a3316fc6SZhikuiRen             messages::internalError(aResp->res);
3232a3316fc6SZhikuiRen             return;
3233a3316fc6SZhikuiRen         }
3234a3316fc6SZhikuiRen 
3235a3316fc6SZhikuiRen         // skip the empty postcode boots
3236a3316fc6SZhikuiRen         if (postcode.empty())
3237a3316fc6SZhikuiRen         {
3238a3316fc6SZhikuiRen             return;
3239a3316fc6SZhikuiRen         }
3240a3316fc6SZhikuiRen 
3241a3316fc6SZhikuiRen         fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
3242a3316fc6SZhikuiRen 
3243a3316fc6SZhikuiRen         aResp->res.jsonValue["Members@odata.count"] =
3244a3316fc6SZhikuiRen             aResp->res.jsonValue["Members"].size();
3245a3316fc6SZhikuiRen         },
324615124765SJonathan Doman         "xyz.openbmc_project.State.Boot.PostCode0",
324715124765SJonathan Doman         "/xyz/openbmc_project/State/Boot/PostCode0",
3248a3316fc6SZhikuiRen         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3249a3316fc6SZhikuiRen         bootIndex);
3250a3316fc6SZhikuiRen }
3251a3316fc6SZhikuiRen 
32528d1b46d7Szhanghch05 static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3253a3316fc6SZhikuiRen                                const uint16_t bootIndex,
3254a3316fc6SZhikuiRen                                const uint16_t bootCount,
3255a3316fc6SZhikuiRen                                const uint64_t entryCount, const uint64_t skip,
3256a3316fc6SZhikuiRen                                const uint64_t top)
3257a3316fc6SZhikuiRen {
3258a3316fc6SZhikuiRen     crow::connections::systemBus->async_method_call(
3259a3316fc6SZhikuiRen         [aResp, bootIndex, bootCount, entryCount, skip,
3260a3316fc6SZhikuiRen          top](const boost::system::error_code ec,
32616c9a279eSManojkiran Eda               const boost::container::flat_map<
32626c9a279eSManojkiran Eda                   uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
32636c9a279eSManojkiran Eda                   postcode) {
3264a3316fc6SZhikuiRen         if (ec)
3265a3316fc6SZhikuiRen         {
3266a3316fc6SZhikuiRen             BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3267a3316fc6SZhikuiRen             messages::internalError(aResp->res);
3268a3316fc6SZhikuiRen             return;
3269a3316fc6SZhikuiRen         }
3270a3316fc6SZhikuiRen 
3271a3316fc6SZhikuiRen         uint64_t endCount = entryCount;
3272a3316fc6SZhikuiRen         if (!postcode.empty())
3273a3316fc6SZhikuiRen         {
3274a3316fc6SZhikuiRen             endCount = entryCount + postcode.size();
3275a3316fc6SZhikuiRen 
3276a3316fc6SZhikuiRen             if ((skip < endCount) && ((top + skip) > entryCount))
3277a3316fc6SZhikuiRen             {
3278002d39b4SEd Tanous                 uint64_t thisBootSkip = std::max(skip, entryCount) - entryCount;
3279a3316fc6SZhikuiRen                 uint64_t thisBootTop =
3280a3316fc6SZhikuiRen                     std::min(top + skip, endCount) - entryCount;
3281a3316fc6SZhikuiRen 
3282002d39b4SEd Tanous                 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3283002d39b4SEd Tanous                                   thisBootTop);
3284a3316fc6SZhikuiRen             }
3285a3316fc6SZhikuiRen             aResp->res.jsonValue["Members@odata.count"] = endCount;
3286a3316fc6SZhikuiRen         }
3287a3316fc6SZhikuiRen 
3288a3316fc6SZhikuiRen         // continue to previous bootIndex
3289a3316fc6SZhikuiRen         if (bootIndex < bootCount)
3290a3316fc6SZhikuiRen         {
3291a3316fc6SZhikuiRen             getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3292a3316fc6SZhikuiRen                                bootCount, endCount, skip, top);
3293a3316fc6SZhikuiRen         }
3294a3316fc6SZhikuiRen         else
3295a3316fc6SZhikuiRen         {
3296a3316fc6SZhikuiRen             aResp->res.jsonValue["Members@odata.nextLink"] =
32970fda0f12SGeorge Liu                 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3298a3316fc6SZhikuiRen                 std::to_string(skip + top);
3299a3316fc6SZhikuiRen         }
3300a3316fc6SZhikuiRen         },
330115124765SJonathan Doman         "xyz.openbmc_project.State.Boot.PostCode0",
330215124765SJonathan Doman         "/xyz/openbmc_project/State/Boot/PostCode0",
3303a3316fc6SZhikuiRen         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3304a3316fc6SZhikuiRen         bootIndex);
3305a3316fc6SZhikuiRen }
3306a3316fc6SZhikuiRen 
33078d1b46d7Szhanghch05 static void
33088d1b46d7Szhanghch05     getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3309a3316fc6SZhikuiRen                          const uint64_t skip, const uint64_t top)
3310a3316fc6SZhikuiRen {
3311a3316fc6SZhikuiRen     uint64_t entryCount = 0;
33121e1e598dSJonathan Doman     sdbusplus::asio::getProperty<uint16_t>(
33131e1e598dSJonathan Doman         *crow::connections::systemBus,
33141e1e598dSJonathan Doman         "xyz.openbmc_project.State.Boot.PostCode0",
33151e1e598dSJonathan Doman         "/xyz/openbmc_project/State/Boot/PostCode0",
33161e1e598dSJonathan Doman         "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
33171e1e598dSJonathan Doman         [aResp, entryCount, skip, top](const boost::system::error_code ec,
33181e1e598dSJonathan Doman                                        const uint16_t bootCount) {
3319a3316fc6SZhikuiRen         if (ec)
3320a3316fc6SZhikuiRen         {
3321a3316fc6SZhikuiRen             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3322a3316fc6SZhikuiRen             messages::internalError(aResp->res);
3323a3316fc6SZhikuiRen             return;
3324a3316fc6SZhikuiRen         }
33251e1e598dSJonathan Doman         getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
33261e1e598dSJonathan Doman         });
3327a3316fc6SZhikuiRen }
3328a3316fc6SZhikuiRen 
33297e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app)
3330a3316fc6SZhikuiRen {
33317e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
33327e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
3333ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
33347e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
333545ca1b86SEd Tanous             [&app](const crow::Request& req,
33367e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3337c937d2bfSEd Tanous         query_param::QueryCapabilities capabilities = {
3338c937d2bfSEd Tanous             .canDelegateTop = true,
3339c937d2bfSEd Tanous             .canDelegateSkip = true,
3340c937d2bfSEd Tanous         };
3341c937d2bfSEd Tanous         query_param::Query delegatedQuery;
3342c937d2bfSEd Tanous         if (!redfish::setUpRedfishRouteWithDelegation(
3343*3ba00073SCarson Labrado                 app, req, asyncResp, delegatedQuery, capabilities))
334445ca1b86SEd Tanous         {
334545ca1b86SEd Tanous             return;
334645ca1b86SEd Tanous         }
3347a3316fc6SZhikuiRen         asyncResp->res.jsonValue["@odata.type"] =
3348a3316fc6SZhikuiRen             "#LogEntryCollection.LogEntryCollection";
3349a3316fc6SZhikuiRen         asyncResp->res.jsonValue["@odata.id"] =
3350a3316fc6SZhikuiRen             "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3351a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3352a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Description"] =
3353a3316fc6SZhikuiRen             "Collection of POST Code Log Entries";
3354a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3355a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Members@odata.count"] = 0;
3356a3316fc6SZhikuiRen 
3357c937d2bfSEd Tanous         getCurrentBootNumber(asyncResp, delegatedQuery.skip,
3358c937d2bfSEd Tanous                              delegatedQuery.top);
33597e860f15SJohn Edward Broadbent         });
3360a3316fc6SZhikuiRen }
3361a3316fc6SZhikuiRen 
3362647b3cdcSGeorge Liu /**
3363647b3cdcSGeorge Liu  * @brief Parse post code ID and get the current value and index value
3364647b3cdcSGeorge Liu  *        eg: postCodeID=B1-2, currentValue=1, index=2
3365647b3cdcSGeorge Liu  *
3366647b3cdcSGeorge Liu  * @param[in]  postCodeID     Post Code ID
3367647b3cdcSGeorge Liu  * @param[out] currentValue   Current value
3368647b3cdcSGeorge Liu  * @param[out] index          Index value
3369647b3cdcSGeorge Liu  *
3370647b3cdcSGeorge Liu  * @return bool true if the parsing is successful, false the parsing fails
3371647b3cdcSGeorge Liu  */
3372647b3cdcSGeorge Liu inline static bool parsePostCode(const std::string& postCodeID,
3373647b3cdcSGeorge Liu                                  uint64_t& currentValue, uint16_t& index)
3374647b3cdcSGeorge Liu {
3375647b3cdcSGeorge Liu     std::vector<std::string> split;
3376647b3cdcSGeorge Liu     boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3377647b3cdcSGeorge Liu     if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3378647b3cdcSGeorge Liu     {
3379647b3cdcSGeorge Liu         return false;
3380647b3cdcSGeorge Liu     }
3381647b3cdcSGeorge Liu 
3382ca45aa3cSEd Tanous     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3383647b3cdcSGeorge Liu     const char* start = split[0].data() + 1;
3384ca45aa3cSEd Tanous     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3385647b3cdcSGeorge Liu     const char* end = split[0].data() + split[0].size();
3386647b3cdcSGeorge Liu     auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3387647b3cdcSGeorge Liu 
3388647b3cdcSGeorge Liu     if (ptrIndex != end || ecIndex != std::errc())
3389647b3cdcSGeorge Liu     {
3390647b3cdcSGeorge Liu         return false;
3391647b3cdcSGeorge Liu     }
3392647b3cdcSGeorge Liu 
3393647b3cdcSGeorge Liu     start = split[1].data();
3394ca45aa3cSEd Tanous 
3395ca45aa3cSEd Tanous     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3396647b3cdcSGeorge Liu     end = split[1].data() + split[1].size();
3397647b3cdcSGeorge Liu     auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
3398647b3cdcSGeorge Liu 
3399dcf2ebc0SEd Tanous     return ptrValue == end && ecValue != std::errc();
3400647b3cdcSGeorge Liu }
3401647b3cdcSGeorge Liu 
3402647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3403647b3cdcSGeorge Liu {
34040fda0f12SGeorge Liu     BMCWEB_ROUTE(
34050fda0f12SGeorge Liu         app,
34060fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/attachment/")
3407647b3cdcSGeorge Liu         .privileges(redfish::privileges::getLogEntry)
3408647b3cdcSGeorge Liu         .methods(boost::beast::http::verb::get)(
340945ca1b86SEd Tanous             [&app](const crow::Request& req,
3410647b3cdcSGeorge Liu                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3411647b3cdcSGeorge Liu                    const std::string& postCodeID) {
3412*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
341345ca1b86SEd Tanous         {
341445ca1b86SEd Tanous             return;
341545ca1b86SEd Tanous         }
3416002d39b4SEd Tanous         if (!http_helpers::isOctetAccepted(req.getHeaderValue("Accept")))
3417647b3cdcSGeorge Liu         {
3418002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::bad_request);
3419647b3cdcSGeorge Liu             return;
3420647b3cdcSGeorge Liu         }
3421647b3cdcSGeorge Liu 
3422647b3cdcSGeorge Liu         uint64_t currentValue = 0;
3423647b3cdcSGeorge Liu         uint16_t index = 0;
3424647b3cdcSGeorge Liu         if (!parsePostCode(postCodeID, currentValue, index))
3425647b3cdcSGeorge Liu         {
3426002d39b4SEd Tanous             messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3427647b3cdcSGeorge Liu             return;
3428647b3cdcSGeorge Liu         }
3429647b3cdcSGeorge Liu 
3430647b3cdcSGeorge Liu         crow::connections::systemBus->async_method_call(
3431647b3cdcSGeorge Liu             [asyncResp, postCodeID, currentValue](
3432647b3cdcSGeorge Liu                 const boost::system::error_code ec,
3433002d39b4SEd Tanous                 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3434002d39b4SEd Tanous                     postcodes) {
3435647b3cdcSGeorge Liu             if (ec.value() == EBADR)
3436647b3cdcSGeorge Liu             {
3437002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry",
3438002d39b4SEd Tanous                                            postCodeID);
3439647b3cdcSGeorge Liu                 return;
3440647b3cdcSGeorge Liu             }
3441647b3cdcSGeorge Liu             if (ec)
3442647b3cdcSGeorge Liu             {
3443647b3cdcSGeorge Liu                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3444647b3cdcSGeorge Liu                 messages::internalError(asyncResp->res);
3445647b3cdcSGeorge Liu                 return;
3446647b3cdcSGeorge Liu             }
3447647b3cdcSGeorge Liu 
3448647b3cdcSGeorge Liu             size_t value = static_cast<size_t>(currentValue) - 1;
3449002d39b4SEd Tanous             if (value == std::string::npos || postcodes.size() < currentValue)
3450647b3cdcSGeorge Liu             {
3451647b3cdcSGeorge Liu                 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3452002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry",
3453002d39b4SEd Tanous                                            postCodeID);
3454647b3cdcSGeorge Liu                 return;
3455647b3cdcSGeorge Liu             }
3456647b3cdcSGeorge Liu 
34579eb808c1SEd Tanous             const auto& [tID, c] = postcodes[value];
345846ff87baSEd Tanous             if (c.empty())
3459647b3cdcSGeorge Liu             {
3460647b3cdcSGeorge Liu                 BMCWEB_LOG_INFO << "No found post code data";
3461002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry",
3462002d39b4SEd Tanous                                            postCodeID);
3463647b3cdcSGeorge Liu                 return;
3464647b3cdcSGeorge Liu             }
346546ff87baSEd Tanous             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
346646ff87baSEd Tanous             const char* d = reinterpret_cast<const char*>(c.data());
346746ff87baSEd Tanous             std::string_view strData(d, c.size());
3468647b3cdcSGeorge Liu 
3469647b3cdcSGeorge Liu             asyncResp->res.addHeader("Content-Type",
3470647b3cdcSGeorge Liu                                      "application/octet-stream");
3471002d39b4SEd Tanous             asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
3472002d39b4SEd Tanous             asyncResp->res.body() = crow::utility::base64encode(strData);
3473647b3cdcSGeorge Liu             },
3474647b3cdcSGeorge Liu             "xyz.openbmc_project.State.Boot.PostCode0",
3475647b3cdcSGeorge Liu             "/xyz/openbmc_project/State/Boot/PostCode0",
3476002d39b4SEd Tanous             "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
3477647b3cdcSGeorge Liu         });
3478647b3cdcSGeorge Liu }
3479647b3cdcSGeorge Liu 
34807e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app)
3481a3316fc6SZhikuiRen {
34827e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
34837e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/")
3484ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
34857e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
348645ca1b86SEd Tanous             [&app](const crow::Request& req,
34877e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
34887e860f15SJohn Edward Broadbent                    const std::string& targetID) {
3489*3ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
349045ca1b86SEd Tanous         {
349145ca1b86SEd Tanous             return;
349245ca1b86SEd Tanous         }
3493647b3cdcSGeorge Liu         uint16_t bootIndex = 0;
3494647b3cdcSGeorge Liu         uint64_t codeIndex = 0;
3495647b3cdcSGeorge Liu         if (!parsePostCode(targetID, codeIndex, bootIndex))
3496a3316fc6SZhikuiRen         {
3497a3316fc6SZhikuiRen             // Requested ID was not found
3498ace85d60SEd Tanous             messages::resourceMissingAtURI(asyncResp->res, req.urlView);
3499a3316fc6SZhikuiRen             return;
3500a3316fc6SZhikuiRen         }
3501a3316fc6SZhikuiRen         if (bootIndex == 0 || codeIndex == 0)
3502a3316fc6SZhikuiRen         {
3503a3316fc6SZhikuiRen             BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
35047e860f15SJohn Edward Broadbent                              << targetID;
3505a3316fc6SZhikuiRen         }
3506a3316fc6SZhikuiRen 
3507002d39b4SEd Tanous         asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_4_0.LogEntry";
3508a3316fc6SZhikuiRen         asyncResp->res.jsonValue["@odata.id"] =
35090fda0f12SGeorge Liu             "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3510a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3511a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Description"] =
3512a3316fc6SZhikuiRen             "Collection of POST Code Log Entries";
3513a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3514a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Members@odata.count"] = 0;
3515a3316fc6SZhikuiRen 
3516a3316fc6SZhikuiRen         getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
35177e860f15SJohn Edward Broadbent         });
3518a3316fc6SZhikuiRen }
3519a3316fc6SZhikuiRen 
35201da66f75SEd Tanous } // namespace redfish
3521