xref: /openbmc/bmcweb/features/redfish/lib/log_services.hpp (revision 002d39b4a7a5ed7166e2acad84e0943c3def9492)
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 {
66*002d39b4SEd Tanous     std::span<const MessageEntry>::iterator messageIt =
67*002d39b4SEd 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/" +
363*002d39b4SEd Tanous             std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
3645cb1dd27SAsmitha Karunanithi 
365*002d39b4SEd Tanous         std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) {
366*002d39b4SEd Tanous             return AlphanumLess<std::string>()(l.first.filename(),
367*002d39b4SEd 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             {
389*002d39b4SEd 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                         {
395*002d39b4SEd Tanous                             const auto* status =
396*002d39b4SEd 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                 }
406*002d39b4SEd 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";
459*002d39b4SEd 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         }
481*002d39b4SEd 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
48845ca1b86SEd Tanous     getDumpEntryById(crow::App& app, const crow::Request& req,
48945ca1b86SEd Tanous                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4908d1b46d7Szhanghch05                      const std::string& entryID, const std::string& dumpType)
4915cb1dd27SAsmitha Karunanithi {
49245ca1b86SEd Tanous     if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
49345ca1b86SEd Tanous     {
49445ca1b86SEd Tanous         return;
49545ca1b86SEd Tanous     }
4965cb1dd27SAsmitha Karunanithi     std::string dumpPath;
4975cb1dd27SAsmitha Karunanithi     if (dumpType == "BMC")
4985cb1dd27SAsmitha Karunanithi     {
4995cb1dd27SAsmitha Karunanithi         dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
5005cb1dd27SAsmitha Karunanithi     }
5015cb1dd27SAsmitha Karunanithi     else if (dumpType == "System")
5025cb1dd27SAsmitha Karunanithi     {
5035cb1dd27SAsmitha Karunanithi         dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
5045cb1dd27SAsmitha Karunanithi     }
5055cb1dd27SAsmitha Karunanithi     else
5065cb1dd27SAsmitha Karunanithi     {
5075cb1dd27SAsmitha Karunanithi         BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
5085cb1dd27SAsmitha Karunanithi         messages::internalError(asyncResp->res);
5095cb1dd27SAsmitha Karunanithi         return;
5105cb1dd27SAsmitha Karunanithi     }
5115cb1dd27SAsmitha Karunanithi 
5125cb1dd27SAsmitha Karunanithi     crow::connections::systemBus->async_method_call(
513711ac7a9SEd Tanous         [asyncResp, entryID, dumpPath,
514711ac7a9SEd Tanous          dumpType](const boost::system::error_code ec,
515711ac7a9SEd Tanous                    dbus::utility::ManagedObjectType& resp) {
5165cb1dd27SAsmitha Karunanithi         if (ec)
5175cb1dd27SAsmitha Karunanithi         {
5185cb1dd27SAsmitha Karunanithi             BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
5195cb1dd27SAsmitha Karunanithi             messages::internalError(asyncResp->res);
5205cb1dd27SAsmitha Karunanithi             return;
5215cb1dd27SAsmitha Karunanithi         }
5225cb1dd27SAsmitha Karunanithi 
523b47452b2SAsmitha Karunanithi         bool foundDumpEntry = false;
524b47452b2SAsmitha Karunanithi         std::string dumpEntryPath =
525b47452b2SAsmitha Karunanithi             "/xyz/openbmc_project/dump/" +
526*002d39b4SEd Tanous             std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
527b47452b2SAsmitha Karunanithi 
5289eb808c1SEd Tanous         for (const auto& objectPath : resp)
5295cb1dd27SAsmitha Karunanithi         {
530b47452b2SAsmitha Karunanithi             if (objectPath.first.str != dumpEntryPath + entryID)
5315cb1dd27SAsmitha Karunanithi             {
5325cb1dd27SAsmitha Karunanithi                 continue;
5335cb1dd27SAsmitha Karunanithi             }
5345cb1dd27SAsmitha Karunanithi 
5355cb1dd27SAsmitha Karunanithi             foundDumpEntry = true;
5361d8782e7SNan Zhou             uint64_t timestamp = 0;
5375cb1dd27SAsmitha Karunanithi             uint64_t size = 0;
53835440d18SAsmitha Karunanithi             std::string dumpStatus;
5395cb1dd27SAsmitha Karunanithi 
5409eb808c1SEd Tanous             for (const auto& interfaceMap : objectPath.second)
5415cb1dd27SAsmitha Karunanithi             {
542*002d39b4SEd Tanous                 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
54335440d18SAsmitha Karunanithi                 {
5449eb808c1SEd Tanous                     for (const auto& propertyMap : interfaceMap.second)
54535440d18SAsmitha Karunanithi                     {
54635440d18SAsmitha Karunanithi                         if (propertyMap.first == "Status")
54735440d18SAsmitha Karunanithi                         {
5489eb808c1SEd Tanous                             const std::string* status =
549*002d39b4SEd Tanous                                 std::get_if<std::string>(&propertyMap.second);
55035440d18SAsmitha Karunanithi                             if (status == nullptr)
55135440d18SAsmitha Karunanithi                             {
55235440d18SAsmitha Karunanithi                                 messages::internalError(asyncResp->res);
55335440d18SAsmitha Karunanithi                                 break;
55435440d18SAsmitha Karunanithi                             }
55535440d18SAsmitha Karunanithi                             dumpStatus = *status;
55635440d18SAsmitha Karunanithi                         }
55735440d18SAsmitha Karunanithi                     }
55835440d18SAsmitha Karunanithi                 }
559*002d39b4SEd Tanous                 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
5605cb1dd27SAsmitha Karunanithi                 {
5619eb808c1SEd Tanous                     for (const auto& propertyMap : interfaceMap.second)
5625cb1dd27SAsmitha Karunanithi                     {
5635cb1dd27SAsmitha Karunanithi                         if (propertyMap.first == "Size")
5645cb1dd27SAsmitha Karunanithi                         {
5659eb808c1SEd Tanous                             const uint64_t* sizePtr =
5665cb1dd27SAsmitha Karunanithi                                 std::get_if<uint64_t>(&propertyMap.second);
5675cb1dd27SAsmitha Karunanithi                             if (sizePtr == nullptr)
5685cb1dd27SAsmitha Karunanithi                             {
5695cb1dd27SAsmitha Karunanithi                                 messages::internalError(asyncResp->res);
5705cb1dd27SAsmitha Karunanithi                                 break;
5715cb1dd27SAsmitha Karunanithi                             }
5725cb1dd27SAsmitha Karunanithi                             size = *sizePtr;
5735cb1dd27SAsmitha Karunanithi                             break;
5745cb1dd27SAsmitha Karunanithi                         }
5755cb1dd27SAsmitha Karunanithi                     }
5765cb1dd27SAsmitha Karunanithi                 }
5775cb1dd27SAsmitha Karunanithi                 else if (interfaceMap.first ==
5785cb1dd27SAsmitha Karunanithi                          "xyz.openbmc_project.Time.EpochTime")
5795cb1dd27SAsmitha Karunanithi                 {
5809eb808c1SEd Tanous                     for (const auto& propertyMap : interfaceMap.second)
5815cb1dd27SAsmitha Karunanithi                     {
5825cb1dd27SAsmitha Karunanithi                         if (propertyMap.first == "Elapsed")
5835cb1dd27SAsmitha Karunanithi                         {
5845cb1dd27SAsmitha Karunanithi                             const uint64_t* usecsTimeStamp =
5855cb1dd27SAsmitha Karunanithi                                 std::get_if<uint64_t>(&propertyMap.second);
5865cb1dd27SAsmitha Karunanithi                             if (usecsTimeStamp == nullptr)
5875cb1dd27SAsmitha Karunanithi                             {
5885cb1dd27SAsmitha Karunanithi                                 messages::internalError(asyncResp->res);
5895cb1dd27SAsmitha Karunanithi                                 break;
5905cb1dd27SAsmitha Karunanithi                             }
5911d8782e7SNan Zhou                             timestamp = *usecsTimeStamp / 1000 / 1000;
5925cb1dd27SAsmitha Karunanithi                             break;
5935cb1dd27SAsmitha Karunanithi                         }
5945cb1dd27SAsmitha Karunanithi                     }
5955cb1dd27SAsmitha Karunanithi                 }
5965cb1dd27SAsmitha Karunanithi             }
5975cb1dd27SAsmitha Karunanithi 
5980fda0f12SGeorge Liu             if (dumpStatus !=
5990fda0f12SGeorge Liu                     "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
60035440d18SAsmitha Karunanithi                 !dumpStatus.empty())
60135440d18SAsmitha Karunanithi             {
60235440d18SAsmitha Karunanithi                 // Dump status is not Complete
60335440d18SAsmitha Karunanithi                 // return not found until status is changed to Completed
604*002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
605*002d39b4SEd Tanous                                            entryID);
60635440d18SAsmitha Karunanithi                 return;
60735440d18SAsmitha Karunanithi             }
60835440d18SAsmitha Karunanithi 
6095cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["@odata.type"] =
610647b3cdcSGeorge Liu                 "#LogEntry.v1_8_0.LogEntry";
6115cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["@odata.id"] = dumpPath + entryID;
6125cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["Id"] = entryID;
6135cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["EntryType"] = "Event";
6145cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["Created"] =
6151d8782e7SNan Zhou                 crow::utility::getDateTimeUint(timestamp);
6165cb1dd27SAsmitha Karunanithi             asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
6175cb1dd27SAsmitha Karunanithi 
618d337bb72SAsmitha Karunanithi             asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
6195cb1dd27SAsmitha Karunanithi 
6205cb1dd27SAsmitha Karunanithi             if (dumpType == "BMC")
6215cb1dd27SAsmitha Karunanithi             {
622d337bb72SAsmitha Karunanithi                 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
623d337bb72SAsmitha Karunanithi                 asyncResp->res.jsonValue["AdditionalDataURI"] =
624de8d94a3SAbhishek Patel                     "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
625de8d94a3SAbhishek Patel                     entryID + "/attachment";
6265cb1dd27SAsmitha Karunanithi             }
6275cb1dd27SAsmitha Karunanithi             else if (dumpType == "System")
6285cb1dd27SAsmitha Karunanithi             {
629d337bb72SAsmitha Karunanithi                 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
630*002d39b4SEd Tanous                 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
631d337bb72SAsmitha Karunanithi                 asyncResp->res.jsonValue["AdditionalDataURI"] =
632de8d94a3SAbhishek Patel                     "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
633de8d94a3SAbhishek Patel                     entryID + "/attachment";
6345cb1dd27SAsmitha Karunanithi             }
6355cb1dd27SAsmitha Karunanithi         }
636e05aec50SEd Tanous         if (!foundDumpEntry)
637b47452b2SAsmitha Karunanithi         {
638b47452b2SAsmitha Karunanithi             BMCWEB_LOG_ERROR << "Can't find Dump Entry";
639b47452b2SAsmitha Karunanithi             messages::internalError(asyncResp->res);
640b47452b2SAsmitha Karunanithi             return;
641b47452b2SAsmitha Karunanithi         }
6425cb1dd27SAsmitha Karunanithi         },
6435cb1dd27SAsmitha Karunanithi         "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
6445cb1dd27SAsmitha Karunanithi         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
6455cb1dd27SAsmitha Karunanithi }
6465cb1dd27SAsmitha Karunanithi 
6478d1b46d7Szhanghch05 inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6489878256fSStanley Chu                             const std::string& entryID,
649b47452b2SAsmitha Karunanithi                             const std::string& dumpType)
6505cb1dd27SAsmitha Karunanithi {
651*002d39b4SEd Tanous     auto respHandler =
652*002d39b4SEd Tanous         [asyncResp, entryID](const boost::system::error_code ec) {
6535cb1dd27SAsmitha Karunanithi         BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
6545cb1dd27SAsmitha Karunanithi         if (ec)
6555cb1dd27SAsmitha Karunanithi         {
6563de8d8baSGeorge Liu             if (ec.value() == EBADR)
6573de8d8baSGeorge Liu             {
6583de8d8baSGeorge Liu                 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
6593de8d8baSGeorge Liu                 return;
6603de8d8baSGeorge Liu             }
6615cb1dd27SAsmitha Karunanithi             BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
6625cb1dd27SAsmitha Karunanithi                              << ec;
6635cb1dd27SAsmitha Karunanithi             messages::internalError(asyncResp->res);
6645cb1dd27SAsmitha Karunanithi             return;
6655cb1dd27SAsmitha Karunanithi         }
6665cb1dd27SAsmitha Karunanithi     };
6675cb1dd27SAsmitha Karunanithi     crow::connections::systemBus->async_method_call(
6685cb1dd27SAsmitha Karunanithi         respHandler, "xyz.openbmc_project.Dump.Manager",
669b47452b2SAsmitha Karunanithi         "/xyz/openbmc_project/dump/" +
670b47452b2SAsmitha Karunanithi             std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
671b47452b2SAsmitha Karunanithi             entryID,
6725cb1dd27SAsmitha Karunanithi         "xyz.openbmc_project.Object.Delete", "Delete");
6735cb1dd27SAsmitha Karunanithi }
6745cb1dd27SAsmitha Karunanithi 
6758d1b46d7Szhanghch05 inline void
67698be3e39SEd Tanous     createDumpTaskCallback(task::Payload&& payload,
6778d1b46d7Szhanghch05                            const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6788d1b46d7Szhanghch05                            const uint32_t& dumpId, const std::string& dumpPath,
679a43be80fSAsmitha Karunanithi                            const std::string& dumpType)
680a43be80fSAsmitha Karunanithi {
681a43be80fSAsmitha Karunanithi     std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
6826145ed6fSAsmitha Karunanithi         [dumpId, dumpPath, dumpType](
683a43be80fSAsmitha Karunanithi             boost::system::error_code err, sdbusplus::message::message& m,
684a43be80fSAsmitha Karunanithi             const std::shared_ptr<task::TaskData>& taskData) {
685cb13a392SEd Tanous         if (err)
686cb13a392SEd Tanous         {
6876145ed6fSAsmitha Karunanithi             BMCWEB_LOG_ERROR << "Error in creating a dump";
6886145ed6fSAsmitha Karunanithi             taskData->state = "Cancelled";
6896145ed6fSAsmitha Karunanithi             return task::completed;
690cb13a392SEd Tanous         }
691b9d36b47SEd Tanous 
692b9d36b47SEd Tanous         dbus::utility::DBusInteracesMap interfacesList;
693a43be80fSAsmitha Karunanithi 
694a43be80fSAsmitha Karunanithi         sdbusplus::message::object_path objPath;
695a43be80fSAsmitha Karunanithi 
696a43be80fSAsmitha Karunanithi         m.read(objPath, interfacesList);
697a43be80fSAsmitha Karunanithi 
698b47452b2SAsmitha Karunanithi         if (objPath.str ==
699b47452b2SAsmitha Karunanithi             "/xyz/openbmc_project/dump/" +
700b47452b2SAsmitha Karunanithi                 std::string(boost::algorithm::to_lower_copy(dumpType)) +
701b47452b2SAsmitha Karunanithi                 "/entry/" + std::to_string(dumpId))
702a43be80fSAsmitha Karunanithi         {
703a43be80fSAsmitha Karunanithi             nlohmann::json retMessage = messages::success();
704a43be80fSAsmitha Karunanithi             taskData->messages.emplace_back(retMessage);
705a43be80fSAsmitha Karunanithi 
706a43be80fSAsmitha Karunanithi             std::string headerLoc =
707a43be80fSAsmitha Karunanithi                 "Location: " + dumpPath + std::to_string(dumpId);
708*002d39b4SEd Tanous             taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
709a43be80fSAsmitha Karunanithi 
710a43be80fSAsmitha Karunanithi             taskData->state = "Completed";
711b47452b2SAsmitha Karunanithi             return task::completed;
7126145ed6fSAsmitha Karunanithi         }
713a43be80fSAsmitha Karunanithi         return task::completed;
714a43be80fSAsmitha Karunanithi         },
7154978b63fSJason M. Bills         "type='signal',interface='org.freedesktop.DBus.ObjectManager',"
716a43be80fSAsmitha Karunanithi         "member='InterfacesAdded', "
717a43be80fSAsmitha Karunanithi         "path='/xyz/openbmc_project/dump'");
718a43be80fSAsmitha Karunanithi 
719a43be80fSAsmitha Karunanithi     task->startTimer(std::chrono::minutes(3));
720a43be80fSAsmitha Karunanithi     task->populateResp(asyncResp->res);
72198be3e39SEd Tanous     task->payload.emplace(std::move(payload));
722a43be80fSAsmitha Karunanithi }
723a43be80fSAsmitha Karunanithi 
7248d1b46d7Szhanghch05 inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7258d1b46d7Szhanghch05                        const crow::Request& req, const std::string& dumpType)
726a43be80fSAsmitha Karunanithi {
727a43be80fSAsmitha Karunanithi     std::string dumpPath;
728a43be80fSAsmitha Karunanithi     if (dumpType == "BMC")
729a43be80fSAsmitha Karunanithi     {
730a43be80fSAsmitha Karunanithi         dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
731a43be80fSAsmitha Karunanithi     }
732a43be80fSAsmitha Karunanithi     else if (dumpType == "System")
733a43be80fSAsmitha Karunanithi     {
734a43be80fSAsmitha Karunanithi         dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
735a43be80fSAsmitha Karunanithi     }
736a43be80fSAsmitha Karunanithi     else
737a43be80fSAsmitha Karunanithi     {
738a43be80fSAsmitha Karunanithi         BMCWEB_LOG_ERROR << "Invalid dump type: " << dumpType;
739a43be80fSAsmitha Karunanithi         messages::internalError(asyncResp->res);
740a43be80fSAsmitha Karunanithi         return;
741a43be80fSAsmitha Karunanithi     }
742a43be80fSAsmitha Karunanithi 
743a43be80fSAsmitha Karunanithi     std::optional<std::string> diagnosticDataType;
744a43be80fSAsmitha Karunanithi     std::optional<std::string> oemDiagnosticDataType;
745a43be80fSAsmitha Karunanithi 
74615ed6780SWilly Tu     if (!redfish::json_util::readJsonAction(
747a43be80fSAsmitha Karunanithi             req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
748a43be80fSAsmitha Karunanithi             "OEMDiagnosticDataType", oemDiagnosticDataType))
749a43be80fSAsmitha Karunanithi     {
750a43be80fSAsmitha Karunanithi         return;
751a43be80fSAsmitha Karunanithi     }
752a43be80fSAsmitha Karunanithi 
753a43be80fSAsmitha Karunanithi     if (dumpType == "System")
754a43be80fSAsmitha Karunanithi     {
755a43be80fSAsmitha Karunanithi         if (!oemDiagnosticDataType || !diagnosticDataType)
756a43be80fSAsmitha Karunanithi         {
7574978b63fSJason M. Bills             BMCWEB_LOG_ERROR
7584978b63fSJason M. Bills                 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
759a43be80fSAsmitha Karunanithi             messages::actionParameterMissing(
760a43be80fSAsmitha Karunanithi                 asyncResp->res, "CollectDiagnosticData",
761a43be80fSAsmitha Karunanithi                 "DiagnosticDataType & OEMDiagnosticDataType");
762a43be80fSAsmitha Karunanithi             return;
763a43be80fSAsmitha Karunanithi         }
7643174e4dfSEd Tanous         if ((*oemDiagnosticDataType != "System") ||
765a43be80fSAsmitha Karunanithi             (*diagnosticDataType != "OEM"))
766a43be80fSAsmitha Karunanithi         {
767a43be80fSAsmitha Karunanithi             BMCWEB_LOG_ERROR << "Wrong parameter values passed";
768ace85d60SEd Tanous             messages::internalError(asyncResp->res);
769a43be80fSAsmitha Karunanithi             return;
770a43be80fSAsmitha Karunanithi         }
771a43be80fSAsmitha Karunanithi     }
772a43be80fSAsmitha Karunanithi     else if (dumpType == "BMC")
773a43be80fSAsmitha Karunanithi     {
774a43be80fSAsmitha Karunanithi         if (!diagnosticDataType)
775a43be80fSAsmitha Karunanithi         {
7760fda0f12SGeorge Liu             BMCWEB_LOG_ERROR
7770fda0f12SGeorge Liu                 << "CreateDump action parameter 'DiagnosticDataType' not found!";
778a43be80fSAsmitha Karunanithi             messages::actionParameterMissing(
779a43be80fSAsmitha Karunanithi                 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
780a43be80fSAsmitha Karunanithi             return;
781a43be80fSAsmitha Karunanithi         }
7823174e4dfSEd Tanous         if (*diagnosticDataType != "Manager")
783a43be80fSAsmitha Karunanithi         {
784a43be80fSAsmitha Karunanithi             BMCWEB_LOG_ERROR
785a43be80fSAsmitha Karunanithi                 << "Wrong parameter value passed for 'DiagnosticDataType'";
786ace85d60SEd Tanous             messages::internalError(asyncResp->res);
787a43be80fSAsmitha Karunanithi             return;
788a43be80fSAsmitha Karunanithi         }
789a43be80fSAsmitha Karunanithi     }
790a43be80fSAsmitha Karunanithi 
791a43be80fSAsmitha Karunanithi     crow::connections::systemBus->async_method_call(
79298be3e39SEd Tanous         [asyncResp, payload(task::Payload(req)), dumpPath,
79398be3e39SEd Tanous          dumpType](const boost::system::error_code ec,
79498be3e39SEd Tanous                    const uint32_t& dumpId) mutable {
795a43be80fSAsmitha Karunanithi         if (ec)
796a43be80fSAsmitha Karunanithi         {
797a43be80fSAsmitha Karunanithi             BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
798a43be80fSAsmitha Karunanithi             messages::internalError(asyncResp->res);
799a43be80fSAsmitha Karunanithi             return;
800a43be80fSAsmitha Karunanithi         }
801a43be80fSAsmitha Karunanithi         BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
802a43be80fSAsmitha Karunanithi 
803*002d39b4SEd Tanous         createDumpTaskCallback(std::move(payload), asyncResp, dumpId, dumpPath,
804*002d39b4SEd Tanous                                dumpType);
805a43be80fSAsmitha Karunanithi         },
806b47452b2SAsmitha Karunanithi         "xyz.openbmc_project.Dump.Manager",
807b47452b2SAsmitha Karunanithi         "/xyz/openbmc_project/dump/" +
808b47452b2SAsmitha Karunanithi             std::string(boost::algorithm::to_lower_copy(dumpType)),
809a43be80fSAsmitha Karunanithi         "xyz.openbmc_project.Dump.Create", "CreateDump");
810a43be80fSAsmitha Karunanithi }
811a43be80fSAsmitha Karunanithi 
8128d1b46d7Szhanghch05 inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8138d1b46d7Szhanghch05                       const std::string& dumpType)
81480319af1SAsmitha Karunanithi {
815b47452b2SAsmitha Karunanithi     std::string dumpTypeLowerCopy =
816b47452b2SAsmitha Karunanithi         std::string(boost::algorithm::to_lower_copy(dumpType));
8178d1b46d7Szhanghch05 
81880319af1SAsmitha Karunanithi     crow::connections::systemBus->async_method_call(
819b9d36b47SEd Tanous         [asyncResp, dumpType](
820b9d36b47SEd Tanous             const boost::system::error_code ec,
821b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
82280319af1SAsmitha Karunanithi         if (ec)
82380319af1SAsmitha Karunanithi         {
82480319af1SAsmitha Karunanithi             BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
82580319af1SAsmitha Karunanithi             messages::internalError(asyncResp->res);
82680319af1SAsmitha Karunanithi             return;
82780319af1SAsmitha Karunanithi         }
82880319af1SAsmitha Karunanithi 
82980319af1SAsmitha Karunanithi         for (const std::string& path : subTreePaths)
83080319af1SAsmitha Karunanithi         {
8312dfd18efSEd Tanous             sdbusplus::message::object_path objPath(path);
8322dfd18efSEd Tanous             std::string logID = objPath.filename();
8332dfd18efSEd Tanous             if (logID.empty())
83480319af1SAsmitha Karunanithi             {
8352dfd18efSEd Tanous                 continue;
83680319af1SAsmitha Karunanithi             }
8372dfd18efSEd Tanous             deleteDumpEntry(asyncResp, logID, dumpType);
83880319af1SAsmitha Karunanithi         }
83980319af1SAsmitha Karunanithi         },
84080319af1SAsmitha Karunanithi         "xyz.openbmc_project.ObjectMapper",
84180319af1SAsmitha Karunanithi         "/xyz/openbmc_project/object_mapper",
84280319af1SAsmitha Karunanithi         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
843b47452b2SAsmitha Karunanithi         "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
844b47452b2SAsmitha Karunanithi         std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
845b47452b2SAsmitha Karunanithi                                    dumpType});
84680319af1SAsmitha Karunanithi }
84780319af1SAsmitha Karunanithi 
848b9d36b47SEd Tanous inline static void
849b9d36b47SEd Tanous     parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
850b9d36b47SEd Tanous                              std::string& filename, std::string& timestamp,
851b9d36b47SEd Tanous                              std::string& logfile)
852043a0536SJohnathan Mantey {
853043a0536SJohnathan Mantey     for (auto property : params)
854043a0536SJohnathan Mantey     {
855043a0536SJohnathan Mantey         if (property.first == "Timestamp")
856043a0536SJohnathan Mantey         {
857043a0536SJohnathan Mantey             const std::string* value =
8588d78b7a9SPatrick Williams                 std::get_if<std::string>(&property.second);
859043a0536SJohnathan Mantey             if (value != nullptr)
860043a0536SJohnathan Mantey             {
861043a0536SJohnathan Mantey                 timestamp = *value;
862043a0536SJohnathan Mantey             }
863043a0536SJohnathan Mantey         }
864043a0536SJohnathan Mantey         else if (property.first == "Filename")
865043a0536SJohnathan Mantey         {
866043a0536SJohnathan Mantey             const std::string* value =
8678d78b7a9SPatrick Williams                 std::get_if<std::string>(&property.second);
868043a0536SJohnathan Mantey             if (value != nullptr)
869043a0536SJohnathan Mantey             {
870043a0536SJohnathan Mantey                 filename = *value;
871043a0536SJohnathan Mantey             }
872043a0536SJohnathan Mantey         }
873043a0536SJohnathan Mantey         else if (property.first == "Log")
874043a0536SJohnathan Mantey         {
875043a0536SJohnathan Mantey             const std::string* value =
8768d78b7a9SPatrick Williams                 std::get_if<std::string>(&property.second);
877043a0536SJohnathan Mantey             if (value != nullptr)
878043a0536SJohnathan Mantey             {
879043a0536SJohnathan Mantey                 logfile = *value;
880043a0536SJohnathan Mantey             }
881043a0536SJohnathan Mantey         }
882043a0536SJohnathan Mantey     }
883043a0536SJohnathan Mantey }
884043a0536SJohnathan Mantey 
885a3316fc6SZhikuiRen constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
8867e860f15SJohn Edward Broadbent inline void requestRoutesSystemLogServiceCollection(App& app)
8871da66f75SEd Tanous {
888c4bf6374SJason M. Bills     /**
889c4bf6374SJason M. Bills      * Functions triggers appropriate requests on DBus
890c4bf6374SJason M. Bills      */
8917e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/")
892ed398213SEd Tanous         .privileges(redfish::privileges::getLogServiceCollection)
893*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
894*002d39b4SEd Tanous             [&app](const crow::Request& req,
895*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
89645ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
897c4bf6374SJason M. Bills         {
89845ca1b86SEd Tanous             return;
89945ca1b86SEd Tanous         }
9007e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
9017e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
902c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
903c4bf6374SJason M. Bills             "#LogServiceCollection.LogServiceCollection";
904c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.id"] =
905029573d4SEd Tanous             "/redfish/v1/Systems/system/LogServices";
90645ca1b86SEd Tanous         asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
907c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Description"] =
908c4bf6374SJason M. Bills             "Collection of LogServices for this Computer System";
909*002d39b4SEd Tanous         nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
910c4bf6374SJason M. Bills         logServiceArray = nlohmann::json::array();
9111476687dSEd Tanous         nlohmann::json::object_t eventLog;
9121476687dSEd Tanous         eventLog["@odata.id"] =
9131476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/EventLog";
9141476687dSEd Tanous         logServiceArray.push_back(std::move(eventLog));
9155cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
9161476687dSEd Tanous         nlohmann::json::object_t dumpLog;
917*002d39b4SEd Tanous         dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
9181476687dSEd Tanous         logServiceArray.push_back(std::move(dumpLog));
919c9bb6861Sraviteja-b #endif
920c9bb6861Sraviteja-b 
921d53dd41fSJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
9221476687dSEd Tanous         nlohmann::json::object_t crashdump;
9231476687dSEd Tanous         crashdump["@odata.id"] =
9241476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Crashdump";
9251476687dSEd Tanous         logServiceArray.push_back(std::move(crashdump));
926d53dd41fSJason M. Bills #endif
927b7028ebfSSpencer Ku 
928b7028ebfSSpencer Ku #ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
9291476687dSEd Tanous         nlohmann::json::object_t hostlogger;
9301476687dSEd Tanous         hostlogger["@odata.id"] =
9311476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/HostLogger";
9321476687dSEd Tanous         logServiceArray.push_back(std::move(hostlogger));
933b7028ebfSSpencer Ku #endif
934c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Members@odata.count"] =
935c4bf6374SJason M. Bills             logServiceArray.size();
936a3316fc6SZhikuiRen 
937a3316fc6SZhikuiRen         crow::connections::systemBus->async_method_call(
93845ca1b86SEd Tanous             [asyncResp](const boost::system::error_code ec,
939b9d36b47SEd Tanous                         const dbus::utility::MapperGetSubTreePathsResponse&
940b9d36b47SEd Tanous                             subtreePath) {
941a3316fc6SZhikuiRen             if (ec)
942a3316fc6SZhikuiRen             {
943a3316fc6SZhikuiRen                 BMCWEB_LOG_ERROR << ec;
944a3316fc6SZhikuiRen                 return;
945a3316fc6SZhikuiRen             }
946a3316fc6SZhikuiRen 
94755f79e6fSEd Tanous             for (const auto& pathStr : subtreePath)
948a3316fc6SZhikuiRen             {
949a3316fc6SZhikuiRen                 if (pathStr.find("PostCode") != std::string::npos)
950a3316fc6SZhikuiRen                 {
95123a21a1cSEd Tanous                     nlohmann::json& logServiceArrayLocal =
952a3316fc6SZhikuiRen                         asyncResp->res.jsonValue["Members"];
95323a21a1cSEd Tanous                     logServiceArrayLocal.push_back(
9540fda0f12SGeorge Liu                         {{"@odata.id",
9550fda0f12SGeorge Liu                           "/redfish/v1/Systems/system/LogServices/PostCodes"}});
95645ca1b86SEd Tanous                     asyncResp->res.jsonValue["Members@odata.count"] =
95723a21a1cSEd Tanous                         logServiceArrayLocal.size();
958a3316fc6SZhikuiRen                     return;
959a3316fc6SZhikuiRen                 }
960a3316fc6SZhikuiRen             }
961a3316fc6SZhikuiRen             },
962a3316fc6SZhikuiRen             "xyz.openbmc_project.ObjectMapper",
963a3316fc6SZhikuiRen             "/xyz/openbmc_project/object_mapper",
96445ca1b86SEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
96545ca1b86SEd Tanous             std::array<const char*, 1>{postCodeIface});
9667e860f15SJohn Edward Broadbent         });
967c4bf6374SJason M. Bills }
968c4bf6374SJason M. Bills 
9697e860f15SJohn Edward Broadbent inline void requestRoutesEventLogService(App& app)
970c4bf6374SJason M. Bills {
9717e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
972ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
973*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
974*002d39b4SEd Tanous             [&app](const crow::Request& req,
975*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
97645ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
97745ca1b86SEd Tanous         {
97845ca1b86SEd Tanous             return;
97945ca1b86SEd Tanous         }
980c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.id"] =
981029573d4SEd Tanous             "/redfish/v1/Systems/system/LogServices/EventLog";
982c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
983c4bf6374SJason M. Bills             "#LogService.v1_1_0.LogService";
984c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Name"] = "Event Log Service";
985*002d39b4SEd Tanous         asyncResp->res.jsonValue["Description"] = "System Event Log Service";
986c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Id"] = "EventLog";
987c4bf6374SJason M. Bills         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
9887c8c4058STejas Patil 
9897c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
9907c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
9917c8c4058STejas Patil 
9927c8c4058STejas Patil         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
9937c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
9947c8c4058STejas Patil             redfishDateTimeOffset.second;
9957c8c4058STejas Patil 
9961476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
9971476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
998e7d6c8b2SGunnar Mills         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
999e7d6c8b2SGunnar Mills 
10000fda0f12SGeorge Liu             {"target",
10010fda0f12SGeorge Liu              "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
10027e860f15SJohn Edward Broadbent         });
1003489640c6SJason M. Bills }
1004489640c6SJason M. Bills 
10057e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogClear(App& app)
1006489640c6SJason M. Bills {
10074978b63fSJason M. Bills     BMCWEB_ROUTE(
10084978b63fSJason M. Bills         app,
10094978b63fSJason M. Bills         "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
1010432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
10117e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
101245ca1b86SEd Tanous             [&app](const crow::Request& req,
10137e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
101445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
101545ca1b86SEd Tanous         {
101645ca1b86SEd Tanous             return;
101745ca1b86SEd Tanous         }
1018489640c6SJason M. Bills         // Clear the EventLog by deleting the log files
1019489640c6SJason M. Bills         std::vector<std::filesystem::path> redfishLogFiles;
1020489640c6SJason M. Bills         if (getRedfishLogFiles(redfishLogFiles))
1021489640c6SJason M. Bills         {
1022489640c6SJason M. Bills             for (const std::filesystem::path& file : redfishLogFiles)
1023489640c6SJason M. Bills             {
1024489640c6SJason M. Bills                 std::error_code ec;
1025489640c6SJason M. Bills                 std::filesystem::remove(file, ec);
1026489640c6SJason M. Bills             }
1027489640c6SJason M. Bills         }
1028489640c6SJason M. Bills 
1029489640c6SJason M. Bills         // Reload rsyslog so it knows to start new log files
1030489640c6SJason M. Bills         crow::connections::systemBus->async_method_call(
1031489640c6SJason M. Bills             [asyncResp](const boost::system::error_code ec) {
1032489640c6SJason M. Bills             if (ec)
1033489640c6SJason M. Bills             {
1034*002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1035489640c6SJason M. Bills                 messages::internalError(asyncResp->res);
1036489640c6SJason M. Bills                 return;
1037489640c6SJason M. Bills             }
1038489640c6SJason M. Bills 
1039489640c6SJason M. Bills             messages::success(asyncResp->res);
1040489640c6SJason M. Bills             },
1041489640c6SJason M. Bills             "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1042*002d39b4SEd Tanous             "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1043*002d39b4SEd Tanous             "replace");
10447e860f15SJohn Edward Broadbent         });
1045c4bf6374SJason M. Bills }
1046c4bf6374SJason M. Bills 
104795820184SJason M. Bills static int fillEventLogEntryJson(const std::string& logEntryID,
1048b5a76932SEd Tanous                                  const std::string& logEntry,
104995820184SJason M. Bills                                  nlohmann::json& logEntryJson)
1050c4bf6374SJason M. Bills {
105195820184SJason M. Bills     // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
1052cd225da8SJason M. Bills     // First get the Timestamp
1053f23b7296SEd Tanous     size_t space = logEntry.find_first_of(' ');
1054cd225da8SJason M. Bills     if (space == std::string::npos)
105595820184SJason M. Bills     {
105695820184SJason M. Bills         return 1;
105795820184SJason M. Bills     }
1058cd225da8SJason M. Bills     std::string timestamp = logEntry.substr(0, space);
1059cd225da8SJason M. Bills     // Then get the log contents
1060f23b7296SEd Tanous     size_t entryStart = logEntry.find_first_not_of(' ', space);
1061cd225da8SJason M. Bills     if (entryStart == std::string::npos)
1062cd225da8SJason M. Bills     {
1063cd225da8SJason M. Bills         return 1;
1064cd225da8SJason M. Bills     }
1065cd225da8SJason M. Bills     std::string_view entry(logEntry);
1066cd225da8SJason M. Bills     entry.remove_prefix(entryStart);
1067cd225da8SJason M. Bills     // Use split to separate the entry into its fields
1068cd225da8SJason M. Bills     std::vector<std::string> logEntryFields;
1069cd225da8SJason M. Bills     boost::split(logEntryFields, entry, boost::is_any_of(","),
1070cd225da8SJason M. Bills                  boost::token_compress_on);
1071cd225da8SJason M. Bills     // We need at least a MessageId to be valid
107226f6976fSEd Tanous     if (logEntryFields.empty())
1073cd225da8SJason M. Bills     {
1074cd225da8SJason M. Bills         return 1;
1075cd225da8SJason M. Bills     }
1076cd225da8SJason M. Bills     std::string& messageID = logEntryFields[0];
107795820184SJason M. Bills 
10784851d45dSJason M. Bills     // Get the Message from the MessageRegistry
1079fffb8c1fSEd Tanous     const registries::Message* message = registries::getMessage(messageID);
1080c4bf6374SJason M. Bills 
108154417b02SSui Chen     if (message == nullptr)
1082c4bf6374SJason M. Bills     {
108354417b02SSui Chen         BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
108454417b02SSui Chen         return 0;
1085c4bf6374SJason M. Bills     }
1086c4bf6374SJason M. Bills 
108754417b02SSui Chen     std::string msg = message->message;
108854417b02SSui Chen 
108915a86ff6SJason M. Bills     // Get the MessageArgs from the log if there are any
109026702d01SEd Tanous     std::span<std::string> messageArgs;
109115a86ff6SJason M. Bills     if (logEntryFields.size() > 1)
109215a86ff6SJason M. Bills     {
109315a86ff6SJason M. Bills         std::string& messageArgsStart = logEntryFields[1];
109415a86ff6SJason M. Bills         // If the first string is empty, assume there are no MessageArgs
109515a86ff6SJason M. Bills         std::size_t messageArgsSize = 0;
109615a86ff6SJason M. Bills         if (!messageArgsStart.empty())
109715a86ff6SJason M. Bills         {
109815a86ff6SJason M. Bills             messageArgsSize = logEntryFields.size() - 1;
109915a86ff6SJason M. Bills         }
110015a86ff6SJason M. Bills 
110123a21a1cSEd Tanous         messageArgs = {&messageArgsStart, messageArgsSize};
1102c4bf6374SJason M. Bills 
11034851d45dSJason M. Bills         // Fill the MessageArgs into the Message
110495820184SJason M. Bills         int i = 0;
110595820184SJason M. Bills         for (const std::string& messageArg : messageArgs)
11064851d45dSJason M. Bills         {
110795820184SJason M. Bills             std::string argStr = "%" + std::to_string(++i);
11084851d45dSJason M. Bills             size_t argPos = msg.find(argStr);
11094851d45dSJason M. Bills             if (argPos != std::string::npos)
11104851d45dSJason M. Bills             {
111195820184SJason M. Bills                 msg.replace(argPos, argStr.length(), messageArg);
11124851d45dSJason M. Bills             }
11134851d45dSJason M. Bills         }
111415a86ff6SJason M. Bills     }
11154851d45dSJason M. Bills 
111695820184SJason M. Bills     // Get the Created time from the timestamp. The log timestamp is in RFC3339
111795820184SJason M. Bills     // format which matches the Redfish format except for the fractional seconds
111895820184SJason M. Bills     // between the '.' and the '+', so just remove them.
1119f23b7296SEd Tanous     std::size_t dot = timestamp.find_first_of('.');
1120f23b7296SEd Tanous     std::size_t plus = timestamp.find_first_of('+');
112195820184SJason M. Bills     if (dot != std::string::npos && plus != std::string::npos)
1122c4bf6374SJason M. Bills     {
112395820184SJason M. Bills         timestamp.erase(dot, plus - dot);
1124c4bf6374SJason M. Bills     }
1125c4bf6374SJason M. Bills 
1126c4bf6374SJason M. Bills     // Fill in the log entry with the gathered data
112795820184SJason M. Bills     logEntryJson = {
1128647b3cdcSGeorge Liu         {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
1129029573d4SEd Tanous         {"@odata.id",
1130897967deSJason M. Bills          "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
113195820184SJason M. Bills              logEntryID},
1132c4bf6374SJason M. Bills         {"Name", "System Event Log Entry"},
113395820184SJason M. Bills         {"Id", logEntryID},
113495820184SJason M. Bills         {"Message", std::move(msg)},
113595820184SJason M. Bills         {"MessageId", std::move(messageID)},
1136f23b7296SEd Tanous         {"MessageArgs", messageArgs},
1137c4bf6374SJason M. Bills         {"EntryType", "Event"},
113854417b02SSui Chen         {"Severity", message->messageSeverity},
113995820184SJason M. Bills         {"Created", std::move(timestamp)}};
1140c4bf6374SJason M. Bills     return 0;
1141c4bf6374SJason M. Bills }
1142c4bf6374SJason M. Bills 
11437e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntryCollection(App& app)
1144c4bf6374SJason M. Bills {
11457e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
11467e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
11478b6a35f0SGunnar Mills         .privileges(redfish::privileges::getLogEntryCollection)
1148*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1149*002d39b4SEd Tanous             [&app](const crow::Request& req,
1150*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1151c937d2bfSEd Tanous         query_param::QueryCapabilities capabilities = {
1152c937d2bfSEd Tanous             .canDelegateTop = true,
1153c937d2bfSEd Tanous             .canDelegateSkip = true,
1154c937d2bfSEd Tanous         };
1155c937d2bfSEd Tanous         query_param::Query delegatedQuery;
1156c937d2bfSEd Tanous         if (!redfish::setUpRedfishRouteWithDelegation(
1157c937d2bfSEd Tanous                 app, req, asyncResp->res, delegatedQuery, capabilities))
1158c4bf6374SJason M. Bills         {
1159c4bf6374SJason M. Bills             return;
1160c4bf6374SJason M. Bills         }
11617e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
11627e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
1163c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
1164c4bf6374SJason M. Bills             "#LogEntryCollection.LogEntryCollection";
1165c4bf6374SJason M. Bills         asyncResp->res.jsonValue["@odata.id"] =
1166029573d4SEd Tanous             "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1167c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1168c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Description"] =
1169c4bf6374SJason M. Bills             "Collection of System Event Log Entries";
1170cb92c03bSAndrew Geissler 
11714978b63fSJason M. Bills         nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1172c4bf6374SJason M. Bills         logEntryArray = nlohmann::json::array();
11737e860f15SJohn Edward Broadbent         // Go through the log files and create a unique ID for each
11747e860f15SJohn Edward Broadbent         // entry
117595820184SJason M. Bills         std::vector<std::filesystem::path> redfishLogFiles;
117695820184SJason M. Bills         getRedfishLogFiles(redfishLogFiles);
1177b01bf299SEd Tanous         uint64_t entryCount = 0;
1178cd225da8SJason M. Bills         std::string logEntry;
117995820184SJason M. Bills 
11807e860f15SJohn Edward Broadbent         // Oldest logs are in the last file, so start there and loop
11817e860f15SJohn Edward Broadbent         // backwards
1182*002d39b4SEd Tanous         for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1183*002d39b4SEd Tanous              it++)
1184c4bf6374SJason M. Bills         {
1185cd225da8SJason M. Bills             std::ifstream logStream(*it);
118695820184SJason M. Bills             if (!logStream.is_open())
1187c4bf6374SJason M. Bills             {
1188c4bf6374SJason M. Bills                 continue;
1189c4bf6374SJason M. Bills             }
1190c4bf6374SJason M. Bills 
1191e85d6b16SJason M. Bills             // Reset the unique ID on the first entry
1192e85d6b16SJason M. Bills             bool firstEntry = true;
119395820184SJason M. Bills             while (std::getline(logStream, logEntry))
119495820184SJason M. Bills             {
1195c4bf6374SJason M. Bills                 entryCount++;
11967e860f15SJohn Edward Broadbent                 // Handle paging using skip (number of entries to skip
11977e860f15SJohn Edward Broadbent                 // from the start) and top (number of entries to
11987e860f15SJohn Edward Broadbent                 // display)
1199c937d2bfSEd Tanous                 if (entryCount <= delegatedQuery.skip ||
1200c937d2bfSEd Tanous                     entryCount > delegatedQuery.skip + delegatedQuery.top)
1201c4bf6374SJason M. Bills                 {
1202c4bf6374SJason M. Bills                     continue;
1203c4bf6374SJason M. Bills                 }
1204c4bf6374SJason M. Bills 
1205c4bf6374SJason M. Bills                 std::string idStr;
1206e85d6b16SJason M. Bills                 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1207c4bf6374SJason M. Bills                 {
1208c4bf6374SJason M. Bills                     continue;
1209c4bf6374SJason M. Bills                 }
1210c4bf6374SJason M. Bills 
1211e85d6b16SJason M. Bills                 if (firstEntry)
1212e85d6b16SJason M. Bills                 {
1213e85d6b16SJason M. Bills                     firstEntry = false;
1214e85d6b16SJason M. Bills                 }
1215e85d6b16SJason M. Bills 
1216c4bf6374SJason M. Bills                 logEntryArray.push_back({});
1217c4bf6374SJason M. Bills                 nlohmann::json& bmcLogEntry = logEntryArray.back();
1218*002d39b4SEd Tanous                 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) != 0)
1219c4bf6374SJason M. Bills                 {
1220c4bf6374SJason M. Bills                     messages::internalError(asyncResp->res);
1221c4bf6374SJason M. Bills                     return;
1222c4bf6374SJason M. Bills                 }
1223c4bf6374SJason M. Bills             }
122495820184SJason M. Bills         }
1225c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
1226c937d2bfSEd Tanous         if (delegatedQuery.skip + delegatedQuery.top < entryCount)
1227c4bf6374SJason M. Bills         {
1228c4bf6374SJason M. Bills             asyncResp->res.jsonValue["Members@odata.nextLink"] =
12294978b63fSJason M. Bills                 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
1230c937d2bfSEd Tanous                 std::to_string(delegatedQuery.skip + delegatedQuery.top);
1231c4bf6374SJason M. Bills         }
12327e860f15SJohn Edward Broadbent         });
1233897967deSJason M. Bills }
1234897967deSJason M. Bills 
12357e860f15SJohn Edward Broadbent inline void requestRoutesJournalEventLogEntry(App& app)
1236897967deSJason M. Bills {
12377e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
12387e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
1239ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
12407e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
124145ca1b86SEd Tanous             [&app](const crow::Request& req,
12427e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
12437e860f15SJohn Edward Broadbent                    const std::string& param) {
124445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
124545ca1b86SEd Tanous         {
124645ca1b86SEd Tanous             return;
124745ca1b86SEd Tanous         }
12487e860f15SJohn Edward Broadbent         const std::string& targetID = param;
12498d1b46d7Szhanghch05 
12507e860f15SJohn Edward Broadbent         // Go through the log files and check the unique ID for each
12517e860f15SJohn Edward Broadbent         // entry to find the target entry
1252897967deSJason M. Bills         std::vector<std::filesystem::path> redfishLogFiles;
1253897967deSJason M. Bills         getRedfishLogFiles(redfishLogFiles);
1254897967deSJason M. Bills         std::string logEntry;
1255897967deSJason M. Bills 
12567e860f15SJohn Edward Broadbent         // Oldest logs are in the last file, so start there and loop
12577e860f15SJohn Edward Broadbent         // backwards
1258*002d39b4SEd Tanous         for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1259*002d39b4SEd Tanous              it++)
1260897967deSJason M. Bills         {
1261897967deSJason M. Bills             std::ifstream logStream(*it);
1262897967deSJason M. Bills             if (!logStream.is_open())
1263897967deSJason M. Bills             {
1264897967deSJason M. Bills                 continue;
1265897967deSJason M. Bills             }
1266897967deSJason M. Bills 
1267897967deSJason M. Bills             // Reset the unique ID on the first entry
1268897967deSJason M. Bills             bool firstEntry = true;
1269897967deSJason M. Bills             while (std::getline(logStream, logEntry))
1270897967deSJason M. Bills             {
1271897967deSJason M. Bills                 std::string idStr;
1272897967deSJason M. Bills                 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1273897967deSJason M. Bills                 {
1274897967deSJason M. Bills                     continue;
1275897967deSJason M. Bills                 }
1276897967deSJason M. Bills 
1277897967deSJason M. Bills                 if (firstEntry)
1278897967deSJason M. Bills                 {
1279897967deSJason M. Bills                     firstEntry = false;
1280897967deSJason M. Bills                 }
1281897967deSJason M. Bills 
1282897967deSJason M. Bills                 if (idStr == targetID)
1283897967deSJason M. Bills                 {
1284*002d39b4SEd Tanous                     if (fillEventLogEntryJson(idStr, logEntry,
1285897967deSJason M. Bills                                               asyncResp->res.jsonValue) != 0)
1286897967deSJason M. Bills                     {
1287897967deSJason M. Bills                         messages::internalError(asyncResp->res);
1288897967deSJason M. Bills                         return;
1289897967deSJason M. Bills                     }
1290897967deSJason M. Bills                     return;
1291897967deSJason M. Bills                 }
1292897967deSJason M. Bills             }
1293897967deSJason M. Bills         }
1294897967deSJason M. Bills         // Requested ID was not found
1295*002d39b4SEd Tanous         messages::resourceMissingAtURI(asyncResp->res,
1296*002d39b4SEd Tanous                                        crow::utility::urlFromPieces(targetID));
12977e860f15SJohn Edward Broadbent         });
129808a4e4b5SAnthony Wilson }
129908a4e4b5SAnthony Wilson 
13007e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryCollection(App& app)
130108a4e4b5SAnthony Wilson {
13027e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
13037e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
1304ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
1305*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1306*002d39b4SEd Tanous             [&app](const crow::Request& req,
1307*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
130845ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
130945ca1b86SEd Tanous         {
131045ca1b86SEd Tanous             return;
131145ca1b86SEd Tanous         }
13127e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
13137e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
131408a4e4b5SAnthony Wilson         asyncResp->res.jsonValue["@odata.type"] =
131508a4e4b5SAnthony Wilson             "#LogEntryCollection.LogEntryCollection";
131608a4e4b5SAnthony Wilson         asyncResp->res.jsonValue["@odata.id"] =
131708a4e4b5SAnthony Wilson             "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
131808a4e4b5SAnthony Wilson         asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
131908a4e4b5SAnthony Wilson         asyncResp->res.jsonValue["Description"] =
132008a4e4b5SAnthony Wilson             "Collection of System Event Log Entries";
132108a4e4b5SAnthony Wilson 
1322cb92c03bSAndrew Geissler         // DBus implementation of EventLog/Entries
1323cb92c03bSAndrew Geissler         // Make call to Logging Service to find all log entry objects
1324cb92c03bSAndrew Geissler         crow::connections::systemBus->async_method_call(
1325cb92c03bSAndrew Geissler             [asyncResp](const boost::system::error_code ec,
1326914e2d5dSEd Tanous                         const dbus::utility::ManagedObjectType& resp) {
1327cb92c03bSAndrew Geissler             if (ec)
1328cb92c03bSAndrew Geissler             {
1329cb92c03bSAndrew Geissler                 // TODO Handle for specific error code
1330cb92c03bSAndrew Geissler                 BMCWEB_LOG_ERROR
1331*002d39b4SEd Tanous                     << "getLogEntriesIfaceData resp_handler got error " << ec;
1332cb92c03bSAndrew Geissler                 messages::internalError(asyncResp->res);
1333cb92c03bSAndrew Geissler                 return;
1334cb92c03bSAndrew Geissler             }
1335*002d39b4SEd Tanous             nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1336cb92c03bSAndrew Geissler             entriesArray = nlohmann::json::array();
13379eb808c1SEd Tanous             for (const auto& objectPath : resp)
1338cb92c03bSAndrew Geissler             {
1339914e2d5dSEd Tanous                 const uint32_t* id = nullptr;
1340c419c759SEd Tanous                 const uint64_t* timestamp = nullptr;
1341c419c759SEd Tanous                 const uint64_t* updateTimestamp = nullptr;
1342914e2d5dSEd Tanous                 const std::string* severity = nullptr;
1343914e2d5dSEd Tanous                 const std::string* message = nullptr;
1344914e2d5dSEd Tanous                 const std::string* filePath = nullptr;
134575710de2SXiaochao Ma                 bool resolved = false;
13469eb808c1SEd Tanous                 for (const auto& interfaceMap : objectPath.second)
1347f86bb901SAdriana Kobylak                 {
1348f86bb901SAdriana Kobylak                     if (interfaceMap.first ==
1349f86bb901SAdriana Kobylak                         "xyz.openbmc_project.Logging.Entry")
1350f86bb901SAdriana Kobylak                     {
1351*002d39b4SEd Tanous                         for (const auto& propertyMap : interfaceMap.second)
1352cb92c03bSAndrew Geissler                         {
1353cb92c03bSAndrew Geissler                             if (propertyMap.first == "Id")
1354cb92c03bSAndrew Geissler                             {
1355*002d39b4SEd Tanous                                 id = std::get_if<uint32_t>(&propertyMap.second);
1356cb92c03bSAndrew Geissler                             }
1357cb92c03bSAndrew Geissler                             else if (propertyMap.first == "Timestamp")
1358cb92c03bSAndrew Geissler                             {
1359*002d39b4SEd Tanous                                 timestamp =
1360*002d39b4SEd Tanous                                     std::get_if<uint64_t>(&propertyMap.second);
13617e860f15SJohn Edward Broadbent                             }
1362*002d39b4SEd Tanous                             else if (propertyMap.first == "UpdateTimestamp")
13637e860f15SJohn Edward Broadbent                             {
1364*002d39b4SEd Tanous                                 updateTimestamp =
1365*002d39b4SEd Tanous                                     std::get_if<uint64_t>(&propertyMap.second);
13667e860f15SJohn Edward Broadbent                             }
13677e860f15SJohn Edward Broadbent                             else if (propertyMap.first == "Severity")
13687e860f15SJohn Edward Broadbent                             {
13697e860f15SJohn Edward Broadbent                                 severity = std::get_if<std::string>(
13707e860f15SJohn Edward Broadbent                                     &propertyMap.second);
13717e860f15SJohn Edward Broadbent                             }
13727e860f15SJohn Edward Broadbent                             else if (propertyMap.first == "Message")
13737e860f15SJohn Edward Broadbent                             {
13747e860f15SJohn Edward Broadbent                                 message = std::get_if<std::string>(
13757e860f15SJohn Edward Broadbent                                     &propertyMap.second);
13767e860f15SJohn Edward Broadbent                             }
13777e860f15SJohn Edward Broadbent                             else if (propertyMap.first == "Resolved")
13787e860f15SJohn Edward Broadbent                             {
1379914e2d5dSEd Tanous                                 const bool* resolveptr =
1380*002d39b4SEd Tanous                                     std::get_if<bool>(&propertyMap.second);
13817e860f15SJohn Edward Broadbent                                 if (resolveptr == nullptr)
13827e860f15SJohn Edward Broadbent                                 {
1383*002d39b4SEd Tanous                                     messages::internalError(asyncResp->res);
13847e860f15SJohn Edward Broadbent                                     return;
13857e860f15SJohn Edward Broadbent                                 }
13867e860f15SJohn Edward Broadbent                                 resolved = *resolveptr;
13877e860f15SJohn Edward Broadbent                             }
13887e860f15SJohn Edward Broadbent                         }
13897e860f15SJohn Edward Broadbent                         if (id == nullptr || message == nullptr ||
13907e860f15SJohn Edward Broadbent                             severity == nullptr)
13917e860f15SJohn Edward Broadbent                         {
13927e860f15SJohn Edward Broadbent                             messages::internalError(asyncResp->res);
13937e860f15SJohn Edward Broadbent                             return;
13947e860f15SJohn Edward Broadbent                         }
13957e860f15SJohn Edward Broadbent                     }
13967e860f15SJohn Edward Broadbent                     else if (interfaceMap.first ==
13977e860f15SJohn Edward Broadbent                              "xyz.openbmc_project.Common.FilePath")
13987e860f15SJohn Edward Broadbent                     {
1399*002d39b4SEd Tanous                         for (const auto& propertyMap : interfaceMap.second)
14007e860f15SJohn Edward Broadbent                         {
14017e860f15SJohn Edward Broadbent                             if (propertyMap.first == "Path")
14027e860f15SJohn Edward Broadbent                             {
14037e860f15SJohn Edward Broadbent                                 filePath = std::get_if<std::string>(
14047e860f15SJohn Edward Broadbent                                     &propertyMap.second);
14057e860f15SJohn Edward Broadbent                             }
14067e860f15SJohn Edward Broadbent                         }
14077e860f15SJohn Edward Broadbent                     }
14087e860f15SJohn Edward Broadbent                 }
14097e860f15SJohn Edward Broadbent                 // Object path without the
14107e860f15SJohn Edward Broadbent                 // xyz.openbmc_project.Logging.Entry interface, ignore
14117e860f15SJohn Edward Broadbent                 // and continue.
14127e860f15SJohn Edward Broadbent                 if (id == nullptr || message == nullptr ||
1413c419c759SEd Tanous                     severity == nullptr || timestamp == nullptr ||
1414c419c759SEd Tanous                     updateTimestamp == nullptr)
14157e860f15SJohn Edward Broadbent                 {
14167e860f15SJohn Edward Broadbent                     continue;
14177e860f15SJohn Edward Broadbent                 }
14187e860f15SJohn Edward Broadbent                 entriesArray.push_back({});
14197e860f15SJohn Edward Broadbent                 nlohmann::json& thisEntry = entriesArray.back();
14207e860f15SJohn Edward Broadbent                 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
14217e860f15SJohn Edward Broadbent                 thisEntry["@odata.id"] =
14220fda0f12SGeorge Liu                     "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
14237e860f15SJohn Edward Broadbent                     std::to_string(*id);
14247e860f15SJohn Edward Broadbent                 thisEntry["Name"] = "System Event Log Entry";
14257e860f15SJohn Edward Broadbent                 thisEntry["Id"] = std::to_string(*id);
14267e860f15SJohn Edward Broadbent                 thisEntry["Message"] = *message;
14277e860f15SJohn Edward Broadbent                 thisEntry["Resolved"] = resolved;
14287e860f15SJohn Edward Broadbent                 thisEntry["EntryType"] = "Event";
14297e860f15SJohn Edward Broadbent                 thisEntry["Severity"] =
14307e860f15SJohn Edward Broadbent                     translateSeverityDbusToRedfish(*severity);
14317e860f15SJohn Edward Broadbent                 thisEntry["Created"] =
1432c419c759SEd Tanous                     crow::utility::getDateTimeUintMs(*timestamp);
14337e860f15SJohn Edward Broadbent                 thisEntry["Modified"] =
1434c419c759SEd Tanous                     crow::utility::getDateTimeUintMs(*updateTimestamp);
14357e860f15SJohn Edward Broadbent                 if (filePath != nullptr)
14367e860f15SJohn Edward Broadbent                 {
14377e860f15SJohn Edward Broadbent                     thisEntry["AdditionalDataURI"] =
14380fda0f12SGeorge Liu                         "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
14397e860f15SJohn Edward Broadbent                         std::to_string(*id) + "/attachment";
14407e860f15SJohn Edward Broadbent                 }
14417e860f15SJohn Edward Broadbent             }
1442*002d39b4SEd Tanous             std::sort(
1443*002d39b4SEd Tanous                 entriesArray.begin(), entriesArray.end(),
1444*002d39b4SEd Tanous                 [](const nlohmann::json& left, const nlohmann::json& right) {
14457e860f15SJohn Edward Broadbent                 return (left["Id"] <= right["Id"]);
14467e860f15SJohn Edward Broadbent                 });
14477e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["Members@odata.count"] =
14487e860f15SJohn Edward Broadbent                 entriesArray.size();
14497e860f15SJohn Edward Broadbent             },
14507e860f15SJohn Edward Broadbent             "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
14517e860f15SJohn Edward Broadbent             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
14527e860f15SJohn Edward Broadbent         });
14537e860f15SJohn Edward Broadbent }
14547e860f15SJohn Edward Broadbent 
14557e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntry(App& app)
14567e860f15SJohn Edward Broadbent {
14577e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
14587e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
1459ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
1460*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1461*002d39b4SEd Tanous             [&app](const crow::Request& req,
14627e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
146345ca1b86SEd Tanous                    const std::string& param) {
146445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
14657e860f15SJohn Edward Broadbent         {
146645ca1b86SEd Tanous             return;
146745ca1b86SEd Tanous         }
14687e860f15SJohn Edward Broadbent         std::string entryID = param;
14697e860f15SJohn Edward Broadbent         dbus::utility::escapePathForDbus(entryID);
14707e860f15SJohn Edward Broadbent 
14717e860f15SJohn Edward Broadbent         // DBus implementation of EventLog/Entries
14727e860f15SJohn Edward Broadbent         // Make call to Logging Service to find all log entry objects
14737e860f15SJohn Edward Broadbent         crow::connections::systemBus->async_method_call(
1474*002d39b4SEd Tanous             [asyncResp, entryID](const boost::system::error_code ec,
1475b9d36b47SEd Tanous                                  const dbus::utility::DBusPropertiesMap& resp) {
14767e860f15SJohn Edward Broadbent             if (ec.value() == EBADR)
14777e860f15SJohn Edward Broadbent             {
1478*002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1479*002d39b4SEd Tanous                                            entryID);
14807e860f15SJohn Edward Broadbent                 return;
14817e860f15SJohn Edward Broadbent             }
14827e860f15SJohn Edward Broadbent             if (ec)
14837e860f15SJohn Edward Broadbent             {
14840fda0f12SGeorge Liu                 BMCWEB_LOG_ERROR
1485*002d39b4SEd Tanous                     << "EventLogEntry (DBus) resp_handler got error " << ec;
14867e860f15SJohn Edward Broadbent                 messages::internalError(asyncResp->res);
14877e860f15SJohn Edward Broadbent                 return;
14887e860f15SJohn Edward Broadbent             }
1489914e2d5dSEd Tanous             const uint32_t* id = nullptr;
1490c419c759SEd Tanous             const uint64_t* timestamp = nullptr;
1491c419c759SEd Tanous             const uint64_t* updateTimestamp = nullptr;
1492914e2d5dSEd Tanous             const std::string* severity = nullptr;
1493914e2d5dSEd Tanous             const std::string* message = nullptr;
1494914e2d5dSEd Tanous             const std::string* filePath = nullptr;
14957e860f15SJohn Edward Broadbent             bool resolved = false;
14967e860f15SJohn Edward Broadbent 
14979eb808c1SEd Tanous             for (const auto& propertyMap : resp)
14987e860f15SJohn Edward Broadbent             {
14997e860f15SJohn Edward Broadbent                 if (propertyMap.first == "Id")
15007e860f15SJohn Edward Broadbent                 {
15017e860f15SJohn Edward Broadbent                     id = std::get_if<uint32_t>(&propertyMap.second);
15027e860f15SJohn Edward Broadbent                 }
15037e860f15SJohn Edward Broadbent                 else if (propertyMap.first == "Timestamp")
15047e860f15SJohn Edward Broadbent                 {
1505*002d39b4SEd Tanous                     timestamp = std::get_if<uint64_t>(&propertyMap.second);
1506ebd45906SGeorge Liu                 }
1507d139c236SGeorge Liu                 else if (propertyMap.first == "UpdateTimestamp")
1508d139c236SGeorge Liu                 {
1509ebd45906SGeorge Liu                     updateTimestamp =
1510c419c759SEd Tanous                         std::get_if<uint64_t>(&propertyMap.second);
1511ebd45906SGeorge Liu                 }
1512cb92c03bSAndrew Geissler                 else if (propertyMap.first == "Severity")
1513cb92c03bSAndrew Geissler                 {
1514*002d39b4SEd Tanous                     severity = std::get_if<std::string>(&propertyMap.second);
1515cb92c03bSAndrew Geissler                 }
1516cb92c03bSAndrew Geissler                 else if (propertyMap.first == "Message")
1517cb92c03bSAndrew Geissler                 {
1518*002d39b4SEd Tanous                     message = std::get_if<std::string>(&propertyMap.second);
1519ae34c8e8SAdriana Kobylak                 }
152075710de2SXiaochao Ma                 else if (propertyMap.first == "Resolved")
152175710de2SXiaochao Ma                 {
1522914e2d5dSEd Tanous                     const bool* resolveptr =
152375710de2SXiaochao Ma                         std::get_if<bool>(&propertyMap.second);
152475710de2SXiaochao Ma                     if (resolveptr == nullptr)
152575710de2SXiaochao Ma                     {
152675710de2SXiaochao Ma                         messages::internalError(asyncResp->res);
152775710de2SXiaochao Ma                         return;
152875710de2SXiaochao Ma                     }
152975710de2SXiaochao Ma                     resolved = *resolveptr;
153075710de2SXiaochao Ma                 }
15317e860f15SJohn Edward Broadbent                 else if (propertyMap.first == "Path")
1532f86bb901SAdriana Kobylak                 {
1533*002d39b4SEd Tanous                     filePath = std::get_if<std::string>(&propertyMap.second);
1534f86bb901SAdriana Kobylak                 }
1535f86bb901SAdriana Kobylak             }
1536*002d39b4SEd Tanous             if (id == nullptr || message == nullptr || severity == nullptr ||
1537*002d39b4SEd Tanous                 timestamp == nullptr || updateTimestamp == nullptr)
1538f86bb901SAdriana Kobylak             {
1539ae34c8e8SAdriana Kobylak                 messages::internalError(asyncResp->res);
1540271584abSEd Tanous                 return;
1541271584abSEd Tanous             }
1542f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["@odata.type"] =
1543f86bb901SAdriana Kobylak                 "#LogEntry.v1_8_0.LogEntry";
1544f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["@odata.id"] =
15450fda0f12SGeorge Liu                 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1546f86bb901SAdriana Kobylak                 std::to_string(*id);
154745ca1b86SEd Tanous             asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1548f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1549f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Message"] = *message;
1550f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Resolved"] = resolved;
1551f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["EntryType"] = "Event";
1552f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Severity"] =
1553f86bb901SAdriana Kobylak                 translateSeverityDbusToRedfish(*severity);
1554f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Created"] =
1555c419c759SEd Tanous                 crow::utility::getDateTimeUintMs(*timestamp);
1556f86bb901SAdriana Kobylak             asyncResp->res.jsonValue["Modified"] =
1557c419c759SEd Tanous                 crow::utility::getDateTimeUintMs(*updateTimestamp);
1558f86bb901SAdriana Kobylak             if (filePath != nullptr)
1559f86bb901SAdriana Kobylak             {
1560f86bb901SAdriana Kobylak                 asyncResp->res.jsonValue["AdditionalDataURI"] =
1561e7dbd530SPotin Lai                     "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1562e7dbd530SPotin Lai                     std::to_string(*id) + "/attachment";
1563f86bb901SAdriana Kobylak             }
1564cb92c03bSAndrew Geissler             },
1565cb92c03bSAndrew Geissler             "xyz.openbmc_project.Logging",
1566cb92c03bSAndrew Geissler             "/xyz/openbmc_project/logging/entry/" + entryID,
1567f86bb901SAdriana Kobylak             "org.freedesktop.DBus.Properties", "GetAll", "");
15687e860f15SJohn Edward Broadbent         });
1569336e96c6SChicago Duan 
15707e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
15717e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
1572ed398213SEd Tanous         .privileges(redfish::privileges::patchLogEntry)
15737e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
157445ca1b86SEd Tanous             [&app](const crow::Request& req,
15757e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
15767e860f15SJohn Edward Broadbent                    const std::string& entryId) {
157745ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
157845ca1b86SEd Tanous         {
157945ca1b86SEd Tanous             return;
158045ca1b86SEd Tanous         }
158175710de2SXiaochao Ma         std::optional<bool> resolved;
158275710de2SXiaochao Ma 
158315ed6780SWilly Tu         if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
15847e860f15SJohn Edward Broadbent                                       resolved))
158575710de2SXiaochao Ma         {
158675710de2SXiaochao Ma             return;
158775710de2SXiaochao Ma         }
158875710de2SXiaochao Ma         BMCWEB_LOG_DEBUG << "Set Resolved";
158975710de2SXiaochao Ma 
159075710de2SXiaochao Ma         crow::connections::systemBus->async_method_call(
15914f48d5f6SEd Tanous             [asyncResp, entryId](const boost::system::error_code ec) {
159275710de2SXiaochao Ma             if (ec)
159375710de2SXiaochao Ma             {
159475710de2SXiaochao Ma                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
159575710de2SXiaochao Ma                 messages::internalError(asyncResp->res);
159675710de2SXiaochao Ma                 return;
159775710de2SXiaochao Ma             }
159875710de2SXiaochao Ma             },
159975710de2SXiaochao Ma             "xyz.openbmc_project.Logging",
160075710de2SXiaochao Ma             "/xyz/openbmc_project/logging/entry/" + entryId,
160175710de2SXiaochao Ma             "org.freedesktop.DBus.Properties", "Set",
160275710de2SXiaochao Ma             "xyz.openbmc_project.Logging.Entry", "Resolved",
1603168e20c1SEd Tanous             dbus::utility::DbusVariantType(*resolved));
16047e860f15SJohn Edward Broadbent         });
160575710de2SXiaochao Ma 
16067e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
16077e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
1608ed398213SEd Tanous         .privileges(redfish::privileges::deleteLogEntry)
1609ed398213SEd Tanous 
1610*002d39b4SEd Tanous         .methods(boost::beast::http::verb::delete_)(
1611*002d39b4SEd Tanous             [&app](const crow::Request& req,
1612*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
161345ca1b86SEd Tanous                    const std::string& param) {
161445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1615336e96c6SChicago Duan         {
161645ca1b86SEd Tanous             return;
161745ca1b86SEd Tanous         }
1618336e96c6SChicago Duan         BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1619336e96c6SChicago Duan 
16207e860f15SJohn Edward Broadbent         std::string entryID = param;
1621336e96c6SChicago Duan 
1622336e96c6SChicago Duan         dbus::utility::escapePathForDbus(entryID);
1623336e96c6SChicago Duan 
1624336e96c6SChicago Duan         // Process response from Logging service.
1625*002d39b4SEd Tanous         auto respHandler =
1626*002d39b4SEd Tanous             [asyncResp, entryID](const boost::system::error_code ec) {
1627*002d39b4SEd Tanous             BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1628336e96c6SChicago Duan             if (ec)
1629336e96c6SChicago Duan             {
16303de8d8baSGeorge Liu                 if (ec.value() == EBADR)
16313de8d8baSGeorge Liu                 {
163245ca1b86SEd Tanous                     messages::resourceNotFound(asyncResp->res, "LogEntry",
163345ca1b86SEd Tanous                                                entryID);
16343de8d8baSGeorge Liu                     return;
16353de8d8baSGeorge Liu                 }
1636336e96c6SChicago Duan                 // TODO Handle for specific error code
16370fda0f12SGeorge Liu                 BMCWEB_LOG_ERROR
16380fda0f12SGeorge Liu                     << "EventLogEntry (DBus) doDelete respHandler got error "
1639336e96c6SChicago Duan                     << ec;
1640336e96c6SChicago Duan                 asyncResp->res.result(
1641336e96c6SChicago Duan                     boost::beast::http::status::internal_server_error);
1642336e96c6SChicago Duan                 return;
1643336e96c6SChicago Duan             }
1644336e96c6SChicago Duan 
1645336e96c6SChicago Duan             asyncResp->res.result(boost::beast::http::status::ok);
1646336e96c6SChicago Duan         };
1647336e96c6SChicago Duan 
1648336e96c6SChicago Duan         // Make call to Logging service to request Delete Log
1649336e96c6SChicago Duan         crow::connections::systemBus->async_method_call(
1650336e96c6SChicago Duan             respHandler, "xyz.openbmc_project.Logging",
1651336e96c6SChicago Duan             "/xyz/openbmc_project/logging/entry/" + entryID,
1652336e96c6SChicago Duan             "xyz.openbmc_project.Object.Delete", "Delete");
16537e860f15SJohn Edward Broadbent         });
1654400fd1fbSAdriana Kobylak }
1655400fd1fbSAdriana Kobylak 
16567e860f15SJohn Edward Broadbent inline void requestRoutesDBusEventLogEntryDownload(App& app)
1657400fd1fbSAdriana Kobylak {
16580fda0f12SGeorge Liu     BMCWEB_ROUTE(
16590fda0f12SGeorge Liu         app,
16600fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/attachment")
1661ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
16627e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
166345ca1b86SEd Tanous             [&app](const crow::Request& req,
16647e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
166545ca1b86SEd Tanous                    const std::string& param) {
166645ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
16677e860f15SJohn Edward Broadbent         {
166845ca1b86SEd Tanous             return;
166945ca1b86SEd Tanous         }
1670*002d39b4SEd Tanous         if (!http_helpers::isOctetAccepted(req.getHeaderValue("Accept")))
1671400fd1fbSAdriana Kobylak         {
1672*002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::bad_request);
1673400fd1fbSAdriana Kobylak             return;
1674400fd1fbSAdriana Kobylak         }
1675400fd1fbSAdriana Kobylak 
16767e860f15SJohn Edward Broadbent         std::string entryID = param;
1677400fd1fbSAdriana Kobylak         dbus::utility::escapePathForDbus(entryID);
1678400fd1fbSAdriana Kobylak 
1679400fd1fbSAdriana Kobylak         crow::connections::systemBus->async_method_call(
1680*002d39b4SEd Tanous             [asyncResp, entryID](const boost::system::error_code ec,
1681400fd1fbSAdriana Kobylak                                  const sdbusplus::message::unix_fd& unixfd) {
1682400fd1fbSAdriana Kobylak             if (ec.value() == EBADR)
1683400fd1fbSAdriana Kobylak             {
1684*002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1685*002d39b4SEd Tanous                                            entryID);
1686400fd1fbSAdriana Kobylak                 return;
1687400fd1fbSAdriana Kobylak             }
1688400fd1fbSAdriana Kobylak             if (ec)
1689400fd1fbSAdriana Kobylak             {
1690400fd1fbSAdriana Kobylak                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1691400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1692400fd1fbSAdriana Kobylak                 return;
1693400fd1fbSAdriana Kobylak             }
1694400fd1fbSAdriana Kobylak 
1695400fd1fbSAdriana Kobylak             int fd = -1;
1696400fd1fbSAdriana Kobylak             fd = dup(unixfd);
1697400fd1fbSAdriana Kobylak             if (fd == -1)
1698400fd1fbSAdriana Kobylak             {
1699400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1700400fd1fbSAdriana Kobylak                 return;
1701400fd1fbSAdriana Kobylak             }
1702400fd1fbSAdriana Kobylak 
1703400fd1fbSAdriana Kobylak             long long int size = lseek(fd, 0, SEEK_END);
1704400fd1fbSAdriana Kobylak             if (size == -1)
1705400fd1fbSAdriana Kobylak             {
1706400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1707400fd1fbSAdriana Kobylak                 return;
1708400fd1fbSAdriana Kobylak             }
1709400fd1fbSAdriana Kobylak 
1710400fd1fbSAdriana Kobylak             // Arbitrary max size of 64kb
1711400fd1fbSAdriana Kobylak             constexpr int maxFileSize = 65536;
1712400fd1fbSAdriana Kobylak             if (size > maxFileSize)
1713400fd1fbSAdriana Kobylak             {
1714*002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1715400fd1fbSAdriana Kobylak                                  << maxFileSize;
1716400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1717400fd1fbSAdriana Kobylak                 return;
1718400fd1fbSAdriana Kobylak             }
1719400fd1fbSAdriana Kobylak             std::vector<char> data(static_cast<size_t>(size));
1720400fd1fbSAdriana Kobylak             long long int rc = lseek(fd, 0, SEEK_SET);
1721400fd1fbSAdriana Kobylak             if (rc == -1)
1722400fd1fbSAdriana Kobylak             {
1723400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1724400fd1fbSAdriana Kobylak                 return;
1725400fd1fbSAdriana Kobylak             }
1726400fd1fbSAdriana Kobylak             rc = read(fd, data.data(), data.size());
1727400fd1fbSAdriana Kobylak             if ((rc == -1) || (rc != size))
1728400fd1fbSAdriana Kobylak             {
1729400fd1fbSAdriana Kobylak                 messages::internalError(asyncResp->res);
1730400fd1fbSAdriana Kobylak                 return;
1731400fd1fbSAdriana Kobylak             }
1732400fd1fbSAdriana Kobylak             close(fd);
1733400fd1fbSAdriana Kobylak 
1734400fd1fbSAdriana Kobylak             std::string_view strData(data.data(), data.size());
1735*002d39b4SEd Tanous             std::string output = crow::utility::base64encode(strData);
1736400fd1fbSAdriana Kobylak 
1737400fd1fbSAdriana Kobylak             asyncResp->res.addHeader("Content-Type",
1738400fd1fbSAdriana Kobylak                                      "application/octet-stream");
1739*002d39b4SEd Tanous             asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
1740400fd1fbSAdriana Kobylak             asyncResp->res.body() = std::move(output);
1741400fd1fbSAdriana Kobylak             },
1742400fd1fbSAdriana Kobylak             "xyz.openbmc_project.Logging",
1743400fd1fbSAdriana Kobylak             "/xyz/openbmc_project/logging/entry/" + entryID,
1744400fd1fbSAdriana Kobylak             "xyz.openbmc_project.Logging.Entry", "GetEntry");
17457e860f15SJohn Edward Broadbent         });
17461da66f75SEd Tanous }
17471da66f75SEd Tanous 
1748b7028ebfSSpencer Ku constexpr const char* hostLoggerFolderPath = "/var/log/console";
1749b7028ebfSSpencer Ku 
1750b7028ebfSSpencer Ku inline bool
1751b7028ebfSSpencer Ku     getHostLoggerFiles(const std::string& hostLoggerFilePath,
1752b7028ebfSSpencer Ku                        std::vector<std::filesystem::path>& hostLoggerFiles)
1753b7028ebfSSpencer Ku {
1754b7028ebfSSpencer Ku     std::error_code ec;
1755b7028ebfSSpencer Ku     std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1756b7028ebfSSpencer Ku     if (ec)
1757b7028ebfSSpencer Ku     {
1758b7028ebfSSpencer Ku         BMCWEB_LOG_ERROR << ec.message();
1759b7028ebfSSpencer Ku         return false;
1760b7028ebfSSpencer Ku     }
1761b7028ebfSSpencer Ku     for (const std::filesystem::directory_entry& it : logPath)
1762b7028ebfSSpencer Ku     {
1763b7028ebfSSpencer Ku         std::string filename = it.path().filename();
1764b7028ebfSSpencer Ku         // Prefix of each log files is "log". Find the file and save the
1765b7028ebfSSpencer Ku         // path
1766b7028ebfSSpencer Ku         if (boost::starts_with(filename, "log"))
1767b7028ebfSSpencer Ku         {
1768b7028ebfSSpencer Ku             hostLoggerFiles.emplace_back(it.path());
1769b7028ebfSSpencer Ku         }
1770b7028ebfSSpencer Ku     }
1771b7028ebfSSpencer Ku     // As the log files rotate, they are appended with a ".#" that is higher for
1772b7028ebfSSpencer Ku     // the older logs. Since we start from oldest logs, sort the name in
1773b7028ebfSSpencer Ku     // descending order.
1774b7028ebfSSpencer Ku     std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1775b7028ebfSSpencer Ku               AlphanumLess<std::string>());
1776b7028ebfSSpencer Ku 
1777b7028ebfSSpencer Ku     return true;
1778b7028ebfSSpencer Ku }
1779b7028ebfSSpencer Ku 
1780b7028ebfSSpencer Ku inline bool
1781b7028ebfSSpencer Ku     getHostLoggerEntries(std::vector<std::filesystem::path>& hostLoggerFiles,
1782c937d2bfSEd Tanous                          uint64_t skip, uint64_t top,
1783b7028ebfSSpencer Ku                          std::vector<std::string>& logEntries, size_t& logCount)
1784b7028ebfSSpencer Ku {
1785b7028ebfSSpencer Ku     GzFileReader logFile;
1786b7028ebfSSpencer Ku 
1787b7028ebfSSpencer Ku     // Go though all log files and expose host logs.
1788b7028ebfSSpencer Ku     for (const std::filesystem::path& it : hostLoggerFiles)
1789b7028ebfSSpencer Ku     {
1790b7028ebfSSpencer Ku         if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
1791b7028ebfSSpencer Ku         {
1792b7028ebfSSpencer Ku             BMCWEB_LOG_ERROR << "fail to expose host logs";
1793b7028ebfSSpencer Ku             return false;
1794b7028ebfSSpencer Ku         }
1795b7028ebfSSpencer Ku     }
1796b7028ebfSSpencer Ku     // Get lastMessage from constructor by getter
1797b7028ebfSSpencer Ku     std::string lastMessage = logFile.getLastMessage();
1798b7028ebfSSpencer Ku     if (!lastMessage.empty())
1799b7028ebfSSpencer Ku     {
1800b7028ebfSSpencer Ku         logCount++;
1801b7028ebfSSpencer Ku         if (logCount > skip && logCount <= (skip + top))
1802b7028ebfSSpencer Ku         {
1803b7028ebfSSpencer Ku             logEntries.push_back(lastMessage);
1804b7028ebfSSpencer Ku         }
1805b7028ebfSSpencer Ku     }
1806b7028ebfSSpencer Ku     return true;
1807b7028ebfSSpencer Ku }
1808b7028ebfSSpencer Ku 
1809b7028ebfSSpencer Ku inline void fillHostLoggerEntryJson(const std::string& logEntryID,
1810b7028ebfSSpencer Ku                                     const std::string& msg,
1811b7028ebfSSpencer Ku                                     nlohmann::json& logEntryJson)
1812b7028ebfSSpencer Ku {
1813b7028ebfSSpencer Ku     // Fill in the log entry with the gathered data.
1814b7028ebfSSpencer Ku     logEntryJson = {
1815b7028ebfSSpencer Ku         {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
1816b7028ebfSSpencer Ku         {"@odata.id",
1817b7028ebfSSpencer Ku          "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
1818b7028ebfSSpencer Ku              logEntryID},
1819b7028ebfSSpencer Ku         {"Name", "Host Logger Entry"},
1820b7028ebfSSpencer Ku         {"Id", logEntryID},
1821b7028ebfSSpencer Ku         {"Message", msg},
1822b7028ebfSSpencer Ku         {"EntryType", "Oem"},
1823b7028ebfSSpencer Ku         {"Severity", "OK"},
1824b7028ebfSSpencer Ku         {"OemRecordFormat", "Host Logger Entry"}};
1825b7028ebfSSpencer Ku }
1826b7028ebfSSpencer Ku 
1827b7028ebfSSpencer Ku inline void requestRoutesSystemHostLogger(App& app)
1828b7028ebfSSpencer Ku {
1829b7028ebfSSpencer Ku     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/HostLogger/")
1830b7028ebfSSpencer Ku         .privileges(redfish::privileges::getLogService)
18311476687dSEd Tanous         .methods(boost::beast::http::verb::get)(
18321476687dSEd Tanous             [&app](const crow::Request& req,
18331476687dSEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
183445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
183545ca1b86SEd Tanous         {
183645ca1b86SEd Tanous             return;
183745ca1b86SEd Tanous         }
1838b7028ebfSSpencer Ku         asyncResp->res.jsonValue["@odata.id"] =
1839b7028ebfSSpencer Ku             "/redfish/v1/Systems/system/LogServices/HostLogger";
1840b7028ebfSSpencer Ku         asyncResp->res.jsonValue["@odata.type"] =
1841b7028ebfSSpencer Ku             "#LogService.v1_1_0.LogService";
1842b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Name"] = "Host Logger Service";
1843b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Description"] = "Host Logger Service";
1844b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Id"] = "HostLogger";
18451476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
18461476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1847b7028ebfSSpencer Ku         });
1848b7028ebfSSpencer Ku }
1849b7028ebfSSpencer Ku 
1850b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerCollection(App& app)
1851b7028ebfSSpencer Ku {
1852b7028ebfSSpencer Ku     BMCWEB_ROUTE(app,
1853b7028ebfSSpencer Ku                  "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/")
1854b7028ebfSSpencer Ku         .privileges(redfish::privileges::getLogEntry)
1855*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
1856*002d39b4SEd Tanous             [&app](const crow::Request& req,
1857*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1858c937d2bfSEd Tanous         query_param::QueryCapabilities capabilities = {
1859c937d2bfSEd Tanous             .canDelegateTop = true,
1860c937d2bfSEd Tanous             .canDelegateSkip = true,
1861c937d2bfSEd Tanous         };
1862c937d2bfSEd Tanous         query_param::Query delegatedQuery;
1863c937d2bfSEd Tanous         if (!redfish::setUpRedfishRouteWithDelegation(
1864c937d2bfSEd Tanous                 app, req, asyncResp->res, delegatedQuery, capabilities))
1865b7028ebfSSpencer Ku         {
1866b7028ebfSSpencer Ku             return;
1867b7028ebfSSpencer Ku         }
1868b7028ebfSSpencer Ku         asyncResp->res.jsonValue["@odata.id"] =
1869b7028ebfSSpencer Ku             "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1870b7028ebfSSpencer Ku         asyncResp->res.jsonValue["@odata.type"] =
1871b7028ebfSSpencer Ku             "#LogEntryCollection.LogEntryCollection";
1872b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
1873b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Description"] =
1874b7028ebfSSpencer Ku             "Collection of HostLogger Entries";
18750fda0f12SGeorge Liu         nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1876b7028ebfSSpencer Ku         logEntryArray = nlohmann::json::array();
1877b7028ebfSSpencer Ku         asyncResp->res.jsonValue["Members@odata.count"] = 0;
1878b7028ebfSSpencer Ku 
1879b7028ebfSSpencer Ku         std::vector<std::filesystem::path> hostLoggerFiles;
1880b7028ebfSSpencer Ku         if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1881b7028ebfSSpencer Ku         {
1882b7028ebfSSpencer Ku             BMCWEB_LOG_ERROR << "fail to get host log file path";
1883b7028ebfSSpencer Ku             return;
1884b7028ebfSSpencer Ku         }
1885b7028ebfSSpencer Ku 
1886b7028ebfSSpencer Ku         size_t logCount = 0;
1887b7028ebfSSpencer Ku         // This vector only store the entries we want to expose that
1888b7028ebfSSpencer Ku         // control by skip and top.
1889b7028ebfSSpencer Ku         std::vector<std::string> logEntries;
1890c937d2bfSEd Tanous         if (!getHostLoggerEntries(hostLoggerFiles, delegatedQuery.skip,
1891c937d2bfSEd Tanous                                   delegatedQuery.top, logEntries, logCount))
1892b7028ebfSSpencer Ku         {
1893b7028ebfSSpencer Ku             messages::internalError(asyncResp->res);
1894b7028ebfSSpencer Ku             return;
1895b7028ebfSSpencer Ku         }
1896b7028ebfSSpencer Ku         // If vector is empty, that means skip value larger than total
1897b7028ebfSSpencer Ku         // log count
189826f6976fSEd Tanous         if (logEntries.empty())
1899b7028ebfSSpencer Ku         {
1900b7028ebfSSpencer Ku             asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1901b7028ebfSSpencer Ku             return;
1902b7028ebfSSpencer Ku         }
190326f6976fSEd Tanous         if (!logEntries.empty())
1904b7028ebfSSpencer Ku         {
1905b7028ebfSSpencer Ku             for (size_t i = 0; i < logEntries.size(); i++)
1906b7028ebfSSpencer Ku             {
1907b7028ebfSSpencer Ku                 logEntryArray.push_back({});
1908b7028ebfSSpencer Ku                 nlohmann::json& hostLogEntry = logEntryArray.back();
1909*002d39b4SEd Tanous                 fillHostLoggerEntryJson(std::to_string(delegatedQuery.skip + i),
1910*002d39b4SEd Tanous                                         logEntries[i], hostLogEntry);
1911b7028ebfSSpencer Ku             }
1912b7028ebfSSpencer Ku 
1913b7028ebfSSpencer Ku             asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1914c937d2bfSEd Tanous             if (delegatedQuery.skip + delegatedQuery.top < logCount)
1915b7028ebfSSpencer Ku             {
1916b7028ebfSSpencer Ku                 asyncResp->res.jsonValue["Members@odata.nextLink"] =
19170fda0f12SGeorge Liu                     "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
1918*002d39b4SEd Tanous                     std::to_string(delegatedQuery.skip + delegatedQuery.top);
1919b7028ebfSSpencer Ku             }
1920b7028ebfSSpencer Ku         }
1921b7028ebfSSpencer Ku         });
1922b7028ebfSSpencer Ku }
1923b7028ebfSSpencer Ku 
1924b7028ebfSSpencer Ku inline void requestRoutesSystemHostLoggerLogEntry(App& app)
1925b7028ebfSSpencer Ku {
1926b7028ebfSSpencer Ku     BMCWEB_ROUTE(
1927b7028ebfSSpencer Ku         app, "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/<str>/")
1928b7028ebfSSpencer Ku         .privileges(redfish::privileges::getLogEntry)
1929b7028ebfSSpencer Ku         .methods(boost::beast::http::verb::get)(
193045ca1b86SEd Tanous             [&app](const crow::Request& req,
1931b7028ebfSSpencer Ku                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1932b7028ebfSSpencer Ku                    const std::string& param) {
193345ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
193445ca1b86SEd Tanous         {
193545ca1b86SEd Tanous             return;
193645ca1b86SEd Tanous         }
1937b7028ebfSSpencer Ku         const std::string& targetID = param;
1938b7028ebfSSpencer Ku 
1939b7028ebfSSpencer Ku         uint64_t idInt = 0;
1940ca45aa3cSEd Tanous 
1941ca45aa3cSEd Tanous         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1942ca45aa3cSEd Tanous         const char* end = targetID.data() + targetID.size();
1943ca45aa3cSEd Tanous 
1944ca45aa3cSEd Tanous         auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
1945b7028ebfSSpencer Ku         if (ec == std::errc::invalid_argument)
1946b7028ebfSSpencer Ku         {
1947ace85d60SEd Tanous             messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1948b7028ebfSSpencer Ku             return;
1949b7028ebfSSpencer Ku         }
1950b7028ebfSSpencer Ku         if (ec == std::errc::result_out_of_range)
1951b7028ebfSSpencer Ku         {
1952ace85d60SEd Tanous             messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1953b7028ebfSSpencer Ku             return;
1954b7028ebfSSpencer Ku         }
1955b7028ebfSSpencer Ku 
1956b7028ebfSSpencer Ku         std::vector<std::filesystem::path> hostLoggerFiles;
1957b7028ebfSSpencer Ku         if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1958b7028ebfSSpencer Ku         {
1959b7028ebfSSpencer Ku             BMCWEB_LOG_ERROR << "fail to get host log file path";
1960b7028ebfSSpencer Ku             return;
1961b7028ebfSSpencer Ku         }
1962b7028ebfSSpencer Ku 
1963b7028ebfSSpencer Ku         size_t logCount = 0;
1964b7028ebfSSpencer Ku         uint64_t top = 1;
1965b7028ebfSSpencer Ku         std::vector<std::string> logEntries;
1966b7028ebfSSpencer Ku         // We can get specific entry by skip and top. For example, if we
1967b7028ebfSSpencer Ku         // want to get nth entry, we can set skip = n-1 and top = 1 to
1968b7028ebfSSpencer Ku         // get that entry
1969*002d39b4SEd Tanous         if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
1970*002d39b4SEd Tanous                                   logCount))
1971b7028ebfSSpencer Ku         {
1972b7028ebfSSpencer Ku             messages::internalError(asyncResp->res);
1973b7028ebfSSpencer Ku             return;
1974b7028ebfSSpencer Ku         }
1975b7028ebfSSpencer Ku 
1976b7028ebfSSpencer Ku         if (!logEntries.empty())
1977b7028ebfSSpencer Ku         {
1978b7028ebfSSpencer Ku             fillHostLoggerEntryJson(targetID, logEntries[0],
1979b7028ebfSSpencer Ku                                     asyncResp->res.jsonValue);
1980b7028ebfSSpencer Ku             return;
1981b7028ebfSSpencer Ku         }
1982b7028ebfSSpencer Ku 
1983b7028ebfSSpencer Ku         // Requested ID was not found
1984ace85d60SEd Tanous         messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1985b7028ebfSSpencer Ku         });
1986b7028ebfSSpencer Ku }
1987b7028ebfSSpencer Ku 
19887e860f15SJohn Edward Broadbent inline void requestRoutesBMCLogServiceCollection(App& app)
19891da66f75SEd Tanous {
19907e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
1991ad89dcf0SGunnar Mills         .privileges(redfish::privileges::getLogServiceCollection)
19927e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
199345ca1b86SEd Tanous             [&app](const crow::Request& req,
19947e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
199545ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
199645ca1b86SEd Tanous         {
199745ca1b86SEd Tanous             return;
199845ca1b86SEd Tanous         }
19997e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
20007e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
2001e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
20021da66f75SEd Tanous             "#LogServiceCollection.LogServiceCollection";
2003e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.id"] =
2004e1f26343SJason M. Bills             "/redfish/v1/Managers/bmc/LogServices";
2005*002d39b4SEd Tanous         asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2006e1f26343SJason M. Bills         asyncResp->res.jsonValue["Description"] =
20071da66f75SEd Tanous             "Collection of LogServices for this Manager";
2008*002d39b4SEd Tanous         nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2009c4bf6374SJason M. Bills         logServiceArray = nlohmann::json::array();
20105cb1dd27SAsmitha Karunanithi #ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
20115cb1dd27SAsmitha Karunanithi         logServiceArray.push_back(
2012*002d39b4SEd Tanous             {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Dump"}});
20135cb1dd27SAsmitha Karunanithi #endif
2014c4bf6374SJason M. Bills #ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
2015c4bf6374SJason M. Bills         logServiceArray.push_back(
2016*002d39b4SEd Tanous             {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal"}});
2017c4bf6374SJason M. Bills #endif
2018e1f26343SJason M. Bills         asyncResp->res.jsonValue["Members@odata.count"] =
2019c4bf6374SJason M. Bills             logServiceArray.size();
20207e860f15SJohn Edward Broadbent         });
2021e1f26343SJason M. Bills }
2022e1f26343SJason M. Bills 
20237e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogService(App& app)
2024e1f26343SJason M. Bills {
20257e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
2026ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
20277e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
202845ca1b86SEd Tanous             [&app](const crow::Request& req,
202945ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
203045ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
20317e860f15SJohn Edward Broadbent         {
203245ca1b86SEd Tanous             return;
203345ca1b86SEd Tanous         }
2034e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
2035e1f26343SJason M. Bills             "#LogService.v1_1_0.LogService";
20360f74e643SEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
20370f74e643SEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Journal";
2038*002d39b4SEd Tanous         asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2039*002d39b4SEd Tanous         asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2040c4bf6374SJason M. Bills         asyncResp->res.jsonValue["Id"] = "BMC Journal";
2041e1f26343SJason M. Bills         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
20427c8c4058STejas Patil 
20437c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
20447c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
2045*002d39b4SEd Tanous         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
20467c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
20477c8c4058STejas Patil             redfishDateTimeOffset.second;
20487c8c4058STejas Patil 
20491476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
20501476687dSEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
20517e860f15SJohn Edward Broadbent         });
2052e1f26343SJason M. Bills }
2053e1f26343SJason M. Bills 
2054c4bf6374SJason M. Bills static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2055e1f26343SJason M. Bills                                       sd_journal* journal,
2056c4bf6374SJason M. Bills                                       nlohmann::json& bmcJournalLogEntryJson)
2057e1f26343SJason M. Bills {
2058e1f26343SJason M. Bills     // Get the Log Entry contents
2059e1f26343SJason M. Bills     int ret = 0;
2060e1f26343SJason M. Bills 
2061a8fe54f0SJason M. Bills     std::string message;
2062a8fe54f0SJason M. Bills     std::string_view syslogID;
2063a8fe54f0SJason M. Bills     ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2064a8fe54f0SJason M. Bills     if (ret < 0)
2065a8fe54f0SJason M. Bills     {
2066a8fe54f0SJason M. Bills         BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2067a8fe54f0SJason M. Bills                          << strerror(-ret);
2068a8fe54f0SJason M. Bills     }
2069a8fe54f0SJason M. Bills     if (!syslogID.empty())
2070a8fe54f0SJason M. Bills     {
2071a8fe54f0SJason M. Bills         message += std::string(syslogID) + ": ";
2072a8fe54f0SJason M. Bills     }
2073a8fe54f0SJason M. Bills 
207439e77504SEd Tanous     std::string_view msg;
207516428a1aSJason M. Bills     ret = getJournalMetadata(journal, "MESSAGE", msg);
2076e1f26343SJason M. Bills     if (ret < 0)
2077e1f26343SJason M. Bills     {
2078e1f26343SJason M. Bills         BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2079e1f26343SJason M. Bills         return 1;
2080e1f26343SJason M. Bills     }
2081a8fe54f0SJason M. Bills     message += std::string(msg);
2082e1f26343SJason M. Bills 
2083e1f26343SJason M. Bills     // Get the severity from the PRIORITY field
2084271584abSEd Tanous     long int severity = 8; // Default to an invalid priority
208516428a1aSJason M. Bills     ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
2086e1f26343SJason M. Bills     if (ret < 0)
2087e1f26343SJason M. Bills     {
2088e1f26343SJason M. Bills         BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
2089e1f26343SJason M. Bills     }
2090e1f26343SJason M. Bills 
2091e1f26343SJason M. Bills     // Get the Created time from the timestamp
209216428a1aSJason M. Bills     std::string entryTimeStr;
209316428a1aSJason M. Bills     if (!getEntryTimestamp(journal, entryTimeStr))
2094e1f26343SJason M. Bills     {
209516428a1aSJason M. Bills         return 1;
2096e1f26343SJason M. Bills     }
2097e1f26343SJason M. Bills 
2098e1f26343SJason M. Bills     // Fill in the log entry with the gathered data
2099c4bf6374SJason M. Bills     bmcJournalLogEntryJson = {
2100647b3cdcSGeorge Liu         {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
2101c4bf6374SJason M. Bills         {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2102c4bf6374SJason M. Bills                           bmcJournalLogEntryID},
2103e1f26343SJason M. Bills         {"Name", "BMC Journal Entry"},
2104c4bf6374SJason M. Bills         {"Id", bmcJournalLogEntryID},
2105a8fe54f0SJason M. Bills         {"Message", std::move(message)},
2106e1f26343SJason M. Bills         {"EntryType", "Oem"},
2107738c1e61SPatrick Williams         {"Severity", severity <= 2   ? "Critical"
2108738c1e61SPatrick Williams                      : severity <= 4 ? "Warning"
2109738c1e61SPatrick Williams                                      : "OK"},
2110086be238SEd Tanous         {"OemRecordFormat", "BMC Journal Entry"},
2111e1f26343SJason M. Bills         {"Created", std::move(entryTimeStr)}};
2112e1f26343SJason M. Bills     return 0;
2113e1f26343SJason M. Bills }
2114e1f26343SJason M. Bills 
21157e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntryCollection(App& app)
2116e1f26343SJason M. Bills {
21177e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
2118ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
2119*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2120*002d39b4SEd Tanous             [&app](const crow::Request& req,
2121*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2122c937d2bfSEd Tanous         query_param::QueryCapabilities capabilities = {
2123c937d2bfSEd Tanous             .canDelegateTop = true,
2124c937d2bfSEd Tanous             .canDelegateSkip = true,
2125c937d2bfSEd Tanous         };
2126c937d2bfSEd Tanous         query_param::Query delegatedQuery;
2127c937d2bfSEd Tanous         if (!redfish::setUpRedfishRouteWithDelegation(
2128c937d2bfSEd Tanous                 app, req, asyncResp->res, delegatedQuery, capabilities))
2129193ad2faSJason M. Bills         {
2130193ad2faSJason M. Bills             return;
2131193ad2faSJason M. Bills         }
21327e860f15SJohn Edward Broadbent         // Collections don't include the static data added by SubRoute
21337e860f15SJohn Edward Broadbent         // because it has a duplicate entry for members
2134e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
2135e1f26343SJason M. Bills             "#LogEntryCollection.LogEntryCollection";
21360f74e643SEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
21370f74e643SEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2138e1f26343SJason M. Bills         asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2139e1f26343SJason M. Bills         asyncResp->res.jsonValue["Description"] =
2140e1f26343SJason M. Bills             "Collection of BMC Journal Entries";
21410fda0f12SGeorge Liu         nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2142e1f26343SJason M. Bills         logEntryArray = nlohmann::json::array();
2143e1f26343SJason M. Bills 
21447e860f15SJohn Edward Broadbent         // Go through the journal and use the timestamp to create a
21457e860f15SJohn Edward Broadbent         // unique ID for each entry
2146e1f26343SJason M. Bills         sd_journal* journalTmp = nullptr;
2147e1f26343SJason M. Bills         int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2148e1f26343SJason M. Bills         if (ret < 0)
2149e1f26343SJason M. Bills         {
2150*002d39b4SEd Tanous             BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2151f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2152e1f26343SJason M. Bills             return;
2153e1f26343SJason M. Bills         }
21540fda0f12SGeorge Liu         std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
21550fda0f12SGeorge Liu             journalTmp, sd_journal_close);
2156e1f26343SJason M. Bills         journalTmp = nullptr;
2157b01bf299SEd Tanous         uint64_t entryCount = 0;
2158e85d6b16SJason M. Bills         // Reset the unique ID on the first entry
2159e85d6b16SJason M. Bills         bool firstEntry = true;
2160e1f26343SJason M. Bills         SD_JOURNAL_FOREACH(journal.get())
2161e1f26343SJason M. Bills         {
2162193ad2faSJason M. Bills             entryCount++;
21637e860f15SJohn Edward Broadbent             // Handle paging using skip (number of entries to skip from
21647e860f15SJohn Edward Broadbent             // the start) and top (number of entries to display)
2165c937d2bfSEd Tanous             if (entryCount <= delegatedQuery.skip ||
2166c937d2bfSEd Tanous                 entryCount > delegatedQuery.skip + delegatedQuery.top)
2167193ad2faSJason M. Bills             {
2168193ad2faSJason M. Bills                 continue;
2169193ad2faSJason M. Bills             }
2170193ad2faSJason M. Bills 
217116428a1aSJason M. Bills             std::string idStr;
2172e85d6b16SJason M. Bills             if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2173e1f26343SJason M. Bills             {
2174e1f26343SJason M. Bills                 continue;
2175e1f26343SJason M. Bills             }
2176e1f26343SJason M. Bills 
2177e85d6b16SJason M. Bills             if (firstEntry)
2178e85d6b16SJason M. Bills             {
2179e85d6b16SJason M. Bills                 firstEntry = false;
2180e85d6b16SJason M. Bills             }
2181e85d6b16SJason M. Bills 
2182e1f26343SJason M. Bills             logEntryArray.push_back({});
2183c4bf6374SJason M. Bills             nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
2184c4bf6374SJason M. Bills             if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2185c4bf6374SJason M. Bills                                            bmcJournalLogEntry) != 0)
2186e1f26343SJason M. Bills             {
2187f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
2188e1f26343SJason M. Bills                 return;
2189e1f26343SJason M. Bills             }
2190e1f26343SJason M. Bills         }
2191193ad2faSJason M. Bills         asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
2192c937d2bfSEd Tanous         if (delegatedQuery.skip + delegatedQuery.top < entryCount)
2193193ad2faSJason M. Bills         {
2194193ad2faSJason M. Bills             asyncResp->res.jsonValue["Members@odata.nextLink"] =
21950fda0f12SGeorge Liu                 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
2196c937d2bfSEd Tanous                 std::to_string(delegatedQuery.skip + delegatedQuery.top);
2197193ad2faSJason M. Bills         }
21987e860f15SJohn Edward Broadbent         });
2199e1f26343SJason M. Bills }
2200e1f26343SJason M. Bills 
22017e860f15SJohn Edward Broadbent inline void requestRoutesBMCJournalLogEntry(App& app)
2202e1f26343SJason M. Bills {
22037e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
22047e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
2205ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
22067e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
220745ca1b86SEd Tanous             [&app](const crow::Request& req,
22087e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
22097e860f15SJohn Edward Broadbent                    const std::string& entryID) {
221045ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
221145ca1b86SEd Tanous         {
221245ca1b86SEd Tanous             return;
221345ca1b86SEd Tanous         }
2214e1f26343SJason M. Bills         // Convert the unique ID back to a timestamp to find the entry
2215e1f26343SJason M. Bills         uint64_t ts = 0;
2216271584abSEd Tanous         uint64_t index = 0;
22178d1b46d7Szhanghch05         if (!getTimestampFromID(asyncResp, entryID, ts, index))
2218e1f26343SJason M. Bills         {
221916428a1aSJason M. Bills             return;
2220e1f26343SJason M. Bills         }
2221e1f26343SJason M. Bills 
2222e1f26343SJason M. Bills         sd_journal* journalTmp = nullptr;
2223e1f26343SJason M. Bills         int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2224e1f26343SJason M. Bills         if (ret < 0)
2225e1f26343SJason M. Bills         {
2226*002d39b4SEd Tanous             BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2227f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2228e1f26343SJason M. Bills             return;
2229e1f26343SJason M. Bills         }
2230*002d39b4SEd Tanous         std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2231*002d39b4SEd Tanous             journalTmp, sd_journal_close);
2232e1f26343SJason M. Bills         journalTmp = nullptr;
22337e860f15SJohn Edward Broadbent         // Go to the timestamp in the log and move to the entry at the
22347e860f15SJohn Edward Broadbent         // index tracking the unique ID
2235af07e3f5SJason M. Bills         std::string idStr;
2236af07e3f5SJason M. Bills         bool firstEntry = true;
2237e1f26343SJason M. Bills         ret = sd_journal_seek_realtime_usec(journal.get(), ts);
22382056b6d1SManojkiran Eda         if (ret < 0)
22392056b6d1SManojkiran Eda         {
22402056b6d1SManojkiran Eda             BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
22412056b6d1SManojkiran Eda                              << strerror(-ret);
22422056b6d1SManojkiran Eda             messages::internalError(asyncResp->res);
22432056b6d1SManojkiran Eda             return;
22442056b6d1SManojkiran Eda         }
2245271584abSEd Tanous         for (uint64_t i = 0; i <= index; i++)
2246e1f26343SJason M. Bills         {
2247e1f26343SJason M. Bills             sd_journal_next(journal.get());
2248af07e3f5SJason M. Bills             if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2249af07e3f5SJason M. Bills             {
2250af07e3f5SJason M. Bills                 messages::internalError(asyncResp->res);
2251af07e3f5SJason M. Bills                 return;
2252af07e3f5SJason M. Bills             }
2253af07e3f5SJason M. Bills             if (firstEntry)
2254af07e3f5SJason M. Bills             {
2255af07e3f5SJason M. Bills                 firstEntry = false;
2256af07e3f5SJason M. Bills             }
2257e1f26343SJason M. Bills         }
2258c4bf6374SJason M. Bills         // Confirm that the entry ID matches what was requested
2259af07e3f5SJason M. Bills         if (idStr != entryID)
2260c4bf6374SJason M. Bills         {
2261ace85d60SEd Tanous             messages::resourceMissingAtURI(asyncResp->res, req.urlView);
2262c4bf6374SJason M. Bills             return;
2263c4bf6374SJason M. Bills         }
2264c4bf6374SJason M. Bills 
2265c4bf6374SJason M. Bills         if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2266e1f26343SJason M. Bills                                        asyncResp->res.jsonValue) != 0)
2267e1f26343SJason M. Bills         {
2268f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
2269e1f26343SJason M. Bills             return;
2270e1f26343SJason M. Bills         }
22717e860f15SJohn Edward Broadbent         });
2272c9bb6861Sraviteja-b }
2273c9bb6861Sraviteja-b 
22747e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpService(App& app)
2275c9bb6861Sraviteja-b {
22767e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
2277ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
2278*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2279*002d39b4SEd Tanous             [&app](const crow::Request& req,
2280*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
228145ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
228245ca1b86SEd Tanous         {
228345ca1b86SEd Tanous             return;
228445ca1b86SEd Tanous         }
2285c9bb6861Sraviteja-b         asyncResp->res.jsonValue["@odata.id"] =
22865cb1dd27SAsmitha Karunanithi             "/redfish/v1/Managers/bmc/LogServices/Dump";
2287c9bb6861Sraviteja-b         asyncResp->res.jsonValue["@odata.type"] =
2288d337bb72SAsmitha Karunanithi             "#LogService.v1_2_0.LogService";
2289c9bb6861Sraviteja-b         asyncResp->res.jsonValue["Name"] = "Dump LogService";
22905cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Description"] = "BMC Dump LogService";
22915cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Id"] = "Dump";
2292c9bb6861Sraviteja-b         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
22937c8c4058STejas Patil 
22947c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
22957c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
22960fda0f12SGeorge Liu         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
22977c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
22987c8c4058STejas Patil             redfishDateTimeOffset.second;
22997c8c4058STejas Patil 
23001476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
23011476687dSEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2302*002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
23031476687dSEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog";
2304*002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
23051476687dSEd Tanous                                 ["target"] =
23061476687dSEd Tanous             "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData";
23077e860f15SJohn Edward Broadbent         });
2308c9bb6861Sraviteja-b }
2309c9bb6861Sraviteja-b 
23107e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntryCollection(App& app)
23117e860f15SJohn Edward Broadbent {
23127e860f15SJohn Edward Broadbent 
2313c9bb6861Sraviteja-b     /**
2314c9bb6861Sraviteja-b      * Functions triggers appropriate requests on DBus
2315c9bb6861Sraviteja-b      */
23167e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
2317ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
23187e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
231945ca1b86SEd Tanous             [&app](const crow::Request& req,
23207e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
232145ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
232245ca1b86SEd Tanous         {
232345ca1b86SEd Tanous             return;
232445ca1b86SEd Tanous         }
2325c9bb6861Sraviteja-b         asyncResp->res.jsonValue["@odata.type"] =
2326c9bb6861Sraviteja-b             "#LogEntryCollection.LogEntryCollection";
2327c9bb6861Sraviteja-b         asyncResp->res.jsonValue["@odata.id"] =
23285cb1dd27SAsmitha Karunanithi             "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
23295cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Name"] = "BMC Dump Entries";
2330c9bb6861Sraviteja-b         asyncResp->res.jsonValue["Description"] =
23315cb1dd27SAsmitha Karunanithi             "Collection of BMC Dump Entries";
2332c9bb6861Sraviteja-b 
23335cb1dd27SAsmitha Karunanithi         getDumpEntryCollection(asyncResp, "BMC");
23347e860f15SJohn Edward Broadbent         });
2335c9bb6861Sraviteja-b }
2336c9bb6861Sraviteja-b 
23377e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpEntry(App& app)
2338c9bb6861Sraviteja-b {
23397e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
23407e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
2341ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
23427e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
234345ca1b86SEd Tanous             [&app](const crow::Request& req,
23447e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
23457e860f15SJohn Edward Broadbent                    const std::string& param) {
234645ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
234745ca1b86SEd Tanous         {
234845ca1b86SEd Tanous             return;
234945ca1b86SEd Tanous         }
235045ca1b86SEd Tanous 
235145ca1b86SEd Tanous         getDumpEntryById(app, req, asyncResp, param, "BMC");
23527e860f15SJohn Edward Broadbent         });
23537e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
23547e860f15SJohn Edward Broadbent                  "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
2355ed398213SEd Tanous         .privileges(redfish::privileges::deleteLogEntry)
23567e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
235745ca1b86SEd Tanous             [&app](const crow::Request& req,
23587e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
23597e860f15SJohn Edward Broadbent                    const std::string& param) {
236045ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
236145ca1b86SEd Tanous         {
236245ca1b86SEd Tanous             return;
236345ca1b86SEd Tanous         }
23647e860f15SJohn Edward Broadbent         deleteDumpEntry(asyncResp, param, "bmc");
23657e860f15SJohn Edward Broadbent         });
2366c9bb6861Sraviteja-b }
2367c9bb6861Sraviteja-b 
23687e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpCreate(App& app)
2369c9bb6861Sraviteja-b {
23700fda0f12SGeorge Liu     BMCWEB_ROUTE(
23710fda0f12SGeorge Liu         app,
23720fda0f12SGeorge Liu         "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
2373ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
23747e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
237545ca1b86SEd Tanous             [&app](const crow::Request& req,
23767e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
237745ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
237845ca1b86SEd Tanous         {
237945ca1b86SEd Tanous             return;
238045ca1b86SEd Tanous         }
23818d1b46d7Szhanghch05         createDump(asyncResp, req, "BMC");
23827e860f15SJohn Edward Broadbent         });
2383a43be80fSAsmitha Karunanithi }
2384a43be80fSAsmitha Karunanithi 
23857e860f15SJohn Edward Broadbent inline void requestRoutesBMCDumpClear(App& app)
238680319af1SAsmitha Karunanithi {
23870fda0f12SGeorge Liu     BMCWEB_ROUTE(
23880fda0f12SGeorge Liu         app,
23890fda0f12SGeorge Liu         "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
2390ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
23917e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
239245ca1b86SEd Tanous             [&app](const crow::Request& req,
23937e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
239445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
239545ca1b86SEd Tanous         {
239645ca1b86SEd Tanous             return;
239745ca1b86SEd Tanous         }
23988d1b46d7Szhanghch05         clearDump(asyncResp, "BMC");
23997e860f15SJohn Edward Broadbent         });
24005cb1dd27SAsmitha Karunanithi }
24015cb1dd27SAsmitha Karunanithi 
24027e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpService(App& app)
24035cb1dd27SAsmitha Karunanithi {
24047e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/")
2405ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
2406*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2407*002d39b4SEd Tanous             [&app](const crow::Request& req,
2408*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
240945ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
24107e860f15SJohn Edward Broadbent         {
241145ca1b86SEd Tanous             return;
241245ca1b86SEd Tanous         }
24135cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["@odata.id"] =
24145cb1dd27SAsmitha Karunanithi             "/redfish/v1/Systems/system/LogServices/Dump";
24155cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["@odata.type"] =
2416d337bb72SAsmitha Karunanithi             "#LogService.v1_2_0.LogService";
24175cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Name"] = "Dump LogService";
241845ca1b86SEd Tanous         asyncResp->res.jsonValue["Description"] = "System Dump LogService";
24195cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Id"] = "Dump";
24205cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
24217c8c4058STejas Patil 
24227c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
24237c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
242445ca1b86SEd Tanous         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
24257c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
24267c8c4058STejas Patil             redfishDateTimeOffset.second;
24277c8c4058STejas Patil 
24281476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
24291476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2430*002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
24311476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog";
24321476687dSEd Tanous 
2433*002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
24341476687dSEd Tanous                                 ["target"] =
24351476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData";
24367e860f15SJohn Edward Broadbent         });
24375cb1dd27SAsmitha Karunanithi }
24385cb1dd27SAsmitha Karunanithi 
24397e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntryCollection(App& app)
24407e860f15SJohn Edward Broadbent {
24417e860f15SJohn Edward Broadbent 
24425cb1dd27SAsmitha Karunanithi     /**
24435cb1dd27SAsmitha Karunanithi      * Functions triggers appropriate requests on DBus
24445cb1dd27SAsmitha Karunanithi      */
2445b2a3289dSAsmitha Karunanithi     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
2446ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
24477e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
244845ca1b86SEd Tanous             [&app](const crow::Request& req,
2449864d6a17SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
245045ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
245145ca1b86SEd Tanous         {
245245ca1b86SEd Tanous             return;
245345ca1b86SEd Tanous         }
24545cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["@odata.type"] =
24555cb1dd27SAsmitha Karunanithi             "#LogEntryCollection.LogEntryCollection";
24565cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["@odata.id"] =
24575cb1dd27SAsmitha Karunanithi             "/redfish/v1/Systems/system/LogServices/Dump/Entries";
24585cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Name"] = "System Dump Entries";
24595cb1dd27SAsmitha Karunanithi         asyncResp->res.jsonValue["Description"] =
24605cb1dd27SAsmitha Karunanithi             "Collection of System Dump Entries";
24615cb1dd27SAsmitha Karunanithi 
24625cb1dd27SAsmitha Karunanithi         getDumpEntryCollection(asyncResp, "System");
24637e860f15SJohn Edward Broadbent         });
24645cb1dd27SAsmitha Karunanithi }
24655cb1dd27SAsmitha Karunanithi 
24667e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpEntry(App& app)
24675cb1dd27SAsmitha Karunanithi {
24687e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2469864d6a17SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
2470ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
2471ed398213SEd Tanous 
24727e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
247345ca1b86SEd Tanous             [&app](const crow::Request& req,
24747e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24757e860f15SJohn Edward Broadbent                    const std::string& param) {
247645ca1b86SEd Tanous         getDumpEntryById(app, req, asyncResp, param, "System");
24777e860f15SJohn Edward Broadbent         });
24788d1b46d7Szhanghch05 
24797e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
2480864d6a17SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
2481ed398213SEd Tanous         .privileges(redfish::privileges::deleteLogEntry)
24827e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
248345ca1b86SEd Tanous             [&app](const crow::Request& req,
24847e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
24857e860f15SJohn Edward Broadbent                    const std::string& param) {
248645ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
248745ca1b86SEd Tanous         {
248845ca1b86SEd Tanous             return;
248945ca1b86SEd Tanous         }
24907e860f15SJohn Edward Broadbent         deleteDumpEntry(asyncResp, param, "system");
24917e860f15SJohn Edward Broadbent         });
24925cb1dd27SAsmitha Karunanithi }
2493c9bb6861Sraviteja-b 
24947e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpCreate(App& app)
2495c9bb6861Sraviteja-b {
24960fda0f12SGeorge Liu     BMCWEB_ROUTE(
24970fda0f12SGeorge Liu         app,
24980fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
2499ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
25007e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
250145ca1b86SEd Tanous             [&app](const crow::Request& req,
250245ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
250345ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
250445ca1b86SEd Tanous         {
250545ca1b86SEd Tanous             return;
250645ca1b86SEd Tanous         }
250745ca1b86SEd Tanous         createDump(asyncResp, req, "System");
250845ca1b86SEd Tanous         });
2509a43be80fSAsmitha Karunanithi }
2510a43be80fSAsmitha Karunanithi 
25117e860f15SJohn Edward Broadbent inline void requestRoutesSystemDumpClear(App& app)
2512a43be80fSAsmitha Karunanithi {
25130fda0f12SGeorge Liu     BMCWEB_ROUTE(
25140fda0f12SGeorge Liu         app,
25150fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog/")
2516ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
25177e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
251845ca1b86SEd Tanous             [&app](const crow::Request& req,
25197e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
25207e860f15SJohn Edward Broadbent 
252145ca1b86SEd Tanous             {
252245ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
252345ca1b86SEd Tanous         {
252445ca1b86SEd Tanous             return;
252545ca1b86SEd Tanous         }
252645ca1b86SEd Tanous         clearDump(asyncResp, "System");
252745ca1b86SEd Tanous         });
2528013487e5Sraviteja-b }
2529013487e5Sraviteja-b 
25307e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpService(App& app)
25311da66f75SEd Tanous {
25323946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
25333946028dSAppaRao Puli     // method for security reasons.
25341da66f75SEd Tanous     /**
25351da66f75SEd Tanous      * Functions triggers appropriate requests on DBus
25361da66f75SEd Tanous      */
25377e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
2538ed398213SEd Tanous         // This is incorrect, should be:
2539ed398213SEd Tanous         //.privileges(redfish::privileges::getLogService)
2540432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
2541*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2542*002d39b4SEd Tanous             [&app](const crow::Request& req,
2543*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
254445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
254545ca1b86SEd Tanous         {
254645ca1b86SEd Tanous             return;
254745ca1b86SEd Tanous         }
25487e860f15SJohn Edward Broadbent         // Copy over the static data to include the entries added by
25497e860f15SJohn Edward Broadbent         // SubRoute
25500f74e643SEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
2551424c4176SJason M. Bills             "/redfish/v1/Systems/system/LogServices/Crashdump";
2552e1f26343SJason M. Bills         asyncResp->res.jsonValue["@odata.type"] =
25538e6c099aSJason M. Bills             "#LogService.v1_2_0.LogService";
25544f50ae4bSGunnar Mills         asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
25554f50ae4bSGunnar Mills         asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
25564f50ae4bSGunnar Mills         asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2557e1f26343SJason M. Bills         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2558e1f26343SJason M. Bills         asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
25597c8c4058STejas Patil 
25607c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
25617c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
25627c8c4058STejas Patil         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
25637c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
25647c8c4058STejas Patil             redfishDateTimeOffset.second;
25657c8c4058STejas Patil 
25661476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
25671476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2568*002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
25691476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
2570*002d39b4SEd Tanous         asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
25711476687dSEd Tanous                                 ["target"] =
25721476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
25737e860f15SJohn Edward Broadbent         });
25741da66f75SEd Tanous }
25751da66f75SEd Tanous 
25767e860f15SJohn Edward Broadbent void inline requestRoutesCrashdumpClear(App& app)
25775b61b5e8SJason M. Bills {
25780fda0f12SGeorge Liu     BMCWEB_ROUTE(
25790fda0f12SGeorge Liu         app,
25800fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog/")
2581ed398213SEd Tanous         // This is incorrect, should be:
2582ed398213SEd Tanous         //.privileges(redfish::privileges::postLogService)
2583432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
25847e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
258545ca1b86SEd Tanous             [&app](const crow::Request& req,
25867e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
258745ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
258845ca1b86SEd Tanous         {
258945ca1b86SEd Tanous             return;
259045ca1b86SEd Tanous         }
25915b61b5e8SJason M. Bills         crow::connections::systemBus->async_method_call(
25925b61b5e8SJason M. Bills             [asyncResp](const boost::system::error_code ec,
2593cb13a392SEd Tanous                         const std::string&) {
25945b61b5e8SJason M. Bills             if (ec)
25955b61b5e8SJason M. Bills             {
25965b61b5e8SJason M. Bills                 messages::internalError(asyncResp->res);
25975b61b5e8SJason M. Bills                 return;
25985b61b5e8SJason M. Bills             }
25995b61b5e8SJason M. Bills             messages::success(asyncResp->res);
26005b61b5e8SJason M. Bills             },
2601*002d39b4SEd Tanous             crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
26027e860f15SJohn Edward Broadbent         });
26035b61b5e8SJason M. Bills }
26045b61b5e8SJason M. Bills 
26058d1b46d7Szhanghch05 static void
26068d1b46d7Szhanghch05     logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
26078d1b46d7Szhanghch05                       const std::string& logID, nlohmann::json& logEntryJson)
2608e855dd28SJason M. Bills {
2609043a0536SJohnathan Mantey     auto getStoredLogCallback =
2610b9d36b47SEd Tanous         [asyncResp, logID,
2611b9d36b47SEd Tanous          &logEntryJson](const boost::system::error_code ec,
2612b9d36b47SEd Tanous                         const dbus::utility::DBusPropertiesMap& params) {
2613e855dd28SJason M. Bills         if (ec)
2614e855dd28SJason M. Bills         {
2615e855dd28SJason M. Bills             BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
26161ddcf01aSJason M. Bills             if (ec.value() ==
26171ddcf01aSJason M. Bills                 boost::system::linux_error::bad_request_descriptor)
26181ddcf01aSJason M. Bills             {
2619*002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
26201ddcf01aSJason M. Bills             }
26211ddcf01aSJason M. Bills             else
26221ddcf01aSJason M. Bills             {
2623e855dd28SJason M. Bills                 messages::internalError(asyncResp->res);
26241ddcf01aSJason M. Bills             }
2625e855dd28SJason M. Bills             return;
2626e855dd28SJason M. Bills         }
2627043a0536SJohnathan Mantey 
2628043a0536SJohnathan Mantey         std::string timestamp{};
2629043a0536SJohnathan Mantey         std::string filename{};
2630043a0536SJohnathan Mantey         std::string logfile{};
26312c70f800SEd Tanous         parseCrashdumpParameters(params, filename, timestamp, logfile);
2632043a0536SJohnathan Mantey 
2633043a0536SJohnathan Mantey         if (filename.empty() || timestamp.empty())
2634e855dd28SJason M. Bills         {
2635*002d39b4SEd Tanous             messages::resourceMissingAtURI(asyncResp->res,
2636*002d39b4SEd Tanous                                            crow::utility::urlFromPieces(logID));
2637e855dd28SJason M. Bills             return;
2638e855dd28SJason M. Bills         }
2639e855dd28SJason M. Bills 
2640043a0536SJohnathan Mantey         std::string crashdumpURI =
2641e855dd28SJason M. Bills             "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2642043a0536SJohnathan Mantey             logID + "/" + filename;
26432b20ef6eSJason M. Bills         nlohmann::json logEntry = {
26444978b63fSJason M. Bills             {"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
26454978b63fSJason M. Bills             {"@odata.id",
26464978b63fSJason M. Bills              "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2647e855dd28SJason M. Bills                  logID},
2648e855dd28SJason M. Bills             {"Name", "CPU Crashdump"},
2649e855dd28SJason M. Bills             {"Id", logID},
2650e855dd28SJason M. Bills             {"EntryType", "Oem"},
26518e6c099aSJason M. Bills             {"AdditionalDataURI", std::move(crashdumpURI)},
26528e6c099aSJason M. Bills             {"DiagnosticDataType", "OEM"},
26538e6c099aSJason M. Bills             {"OEMDiagnosticDataType", "PECICrashdump"},
2654043a0536SJohnathan Mantey             {"Created", std::move(timestamp)}};
26552b20ef6eSJason M. Bills 
26562b20ef6eSJason M. Bills         // If logEntryJson references an array of LogEntry resources
26572b20ef6eSJason M. Bills         // ('Members' list), then push this as a new entry, otherwise set it
26582b20ef6eSJason M. Bills         // directly
26592b20ef6eSJason M. Bills         if (logEntryJson.is_array())
26602b20ef6eSJason M. Bills         {
26612b20ef6eSJason M. Bills             logEntryJson.push_back(logEntry);
26622b20ef6eSJason M. Bills             asyncResp->res.jsonValue["Members@odata.count"] =
26632b20ef6eSJason M. Bills                 logEntryJson.size();
26642b20ef6eSJason M. Bills         }
26652b20ef6eSJason M. Bills         else
26662b20ef6eSJason M. Bills         {
26672b20ef6eSJason M. Bills             logEntryJson = logEntry;
26682b20ef6eSJason M. Bills         }
2669e855dd28SJason M. Bills     };
2670e855dd28SJason M. Bills     crow::connections::systemBus->async_method_call(
26715b61b5e8SJason M. Bills         std::move(getStoredLogCallback), crashdumpObject,
26725b61b5e8SJason M. Bills         crashdumpPath + std::string("/") + logID,
2673043a0536SJohnathan Mantey         "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
2674e855dd28SJason M. Bills }
2675e855dd28SJason M. Bills 
26767e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntryCollection(App& app)
26771da66f75SEd Tanous {
26783946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
26793946028dSAppaRao Puli     // method for security reasons.
26801da66f75SEd Tanous     /**
26811da66f75SEd Tanous      * Functions triggers appropriate requests on DBus
26821da66f75SEd Tanous      */
26837e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
26847e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
2685ed398213SEd Tanous         // This is incorrect, should be.
2686ed398213SEd Tanous         //.privileges(redfish::privileges::postLogEntryCollection)
2687432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
2688*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
2689*002d39b4SEd Tanous             [&app](const crow::Request& req,
2690*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
269145ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
269245ca1b86SEd Tanous         {
269345ca1b86SEd Tanous             return;
269445ca1b86SEd Tanous         }
26952b20ef6eSJason M. Bills         crow::connections::systemBus->async_method_call(
26962b20ef6eSJason M. Bills             [asyncResp](const boost::system::error_code ec,
26972b20ef6eSJason M. Bills                         const std::vector<std::string>& resp) {
26981da66f75SEd Tanous             if (ec)
26991da66f75SEd Tanous             {
27001da66f75SEd Tanous                 if (ec.value() !=
27011da66f75SEd Tanous                     boost::system::errc::no_such_file_or_directory)
27021da66f75SEd Tanous                 {
27031da66f75SEd Tanous                     BMCWEB_LOG_DEBUG << "failed to get entries ec: "
27041da66f75SEd Tanous                                      << ec.message();
2705f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
27061da66f75SEd Tanous                     return;
27071da66f75SEd Tanous                 }
27081da66f75SEd Tanous             }
2709e1f26343SJason M. Bills             asyncResp->res.jsonValue["@odata.type"] =
27101da66f75SEd Tanous                 "#LogEntryCollection.LogEntryCollection";
27110f74e643SEd Tanous             asyncResp->res.jsonValue["@odata.id"] =
2712424c4176SJason M. Bills                 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2713*002d39b4SEd Tanous             asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
2714e1f26343SJason M. Bills             asyncResp->res.jsonValue["Description"] =
2715424c4176SJason M. Bills                 "Collection of Crashdump Entries";
2716*002d39b4SEd Tanous             asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
2717a2dd60a6SBrandon Kim             asyncResp->res.jsonValue["Members@odata.count"] = 0;
27182b20ef6eSJason M. Bills 
27192b20ef6eSJason M. Bills             for (const std::string& path : resp)
27201da66f75SEd Tanous             {
27212b20ef6eSJason M. Bills                 const sdbusplus::message::object_path objPath(path);
2722e855dd28SJason M. Bills                 // Get the log ID
27232b20ef6eSJason M. Bills                 std::string logID = objPath.filename();
27242b20ef6eSJason M. Bills                 if (logID.empty())
27251da66f75SEd Tanous                 {
2726e855dd28SJason M. Bills                     continue;
27271da66f75SEd Tanous                 }
2728e855dd28SJason M. Bills                 // Add the log entry to the array
27292b20ef6eSJason M. Bills                 logCrashdumpEntry(asyncResp, logID,
27302b20ef6eSJason M. Bills                                   asyncResp->res.jsonValue["Members"]);
27311da66f75SEd Tanous             }
27322b20ef6eSJason M. Bills             },
27331da66f75SEd Tanous             "xyz.openbmc_project.ObjectMapper",
27341da66f75SEd Tanous             "/xyz/openbmc_project/object_mapper",
27351da66f75SEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
27365b61b5e8SJason M. Bills             std::array<const char*, 1>{crashdumpInterface});
27377e860f15SJohn Edward Broadbent         });
27381da66f75SEd Tanous }
27391da66f75SEd Tanous 
27407e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpEntry(App& app)
27411da66f75SEd Tanous {
27423946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
27433946028dSAppaRao Puli     // method for security reasons.
27441da66f75SEd Tanous 
27457e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
27467e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/")
2747ed398213SEd Tanous         // this is incorrect, should be
2748ed398213SEd Tanous         // .privileges(redfish::privileges::getLogEntry)
2749432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
27507e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
275145ca1b86SEd Tanous             [&app](const crow::Request& req,
27527e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
27537e860f15SJohn Edward Broadbent                    const std::string& param) {
275445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
275545ca1b86SEd Tanous         {
275645ca1b86SEd Tanous             return;
275745ca1b86SEd Tanous         }
27587e860f15SJohn Edward Broadbent         const std::string& logID = param;
2759e855dd28SJason M. Bills         logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
27607e860f15SJohn Edward Broadbent         });
2761e855dd28SJason M. Bills }
2762e855dd28SJason M. Bills 
27637e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpFile(App& app)
2764e855dd28SJason M. Bills {
27653946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
27663946028dSAppaRao Puli     // method for security reasons.
27677e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
27687e860f15SJohn Edward Broadbent         app,
27697e860f15SJohn Edward Broadbent         "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/<str>/")
2770ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
27717e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
277245ca1b86SEd Tanous             [&app](const crow::Request& req,
27737e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
27747e860f15SJohn Edward Broadbent                    const std::string& logID, const std::string& fileName) {
277545ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
277645ca1b86SEd Tanous         {
277745ca1b86SEd Tanous             return;
277845ca1b86SEd Tanous         }
2779043a0536SJohnathan Mantey         auto getStoredLogCallback =
2780*002d39b4SEd Tanous             [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
2781abf2add6SEd Tanous                 const boost::system::error_code ec,
2782*002d39b4SEd Tanous                 const std::vector<
2783*002d39b4SEd Tanous                     std::pair<std::string, dbus::utility::DbusVariantType>>&
27847e860f15SJohn Edward Broadbent                     resp) {
27851da66f75SEd Tanous             if (ec)
27861da66f75SEd Tanous             {
2787*002d39b4SEd Tanous                 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2788f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
27891da66f75SEd Tanous                 return;
27901da66f75SEd Tanous             }
2791e855dd28SJason M. Bills 
2792043a0536SJohnathan Mantey             std::string dbusFilename{};
2793043a0536SJohnathan Mantey             std::string dbusTimestamp{};
2794043a0536SJohnathan Mantey             std::string dbusFilepath{};
2795043a0536SJohnathan Mantey 
2796*002d39b4SEd Tanous             parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
2797*002d39b4SEd Tanous                                      dbusFilepath);
2798043a0536SJohnathan Mantey 
2799043a0536SJohnathan Mantey             if (dbusFilename.empty() || dbusTimestamp.empty() ||
2800043a0536SJohnathan Mantey                 dbusFilepath.empty())
28011da66f75SEd Tanous             {
2802ace85d60SEd Tanous                 messages::resourceMissingAtURI(asyncResp->res, url);
28031da66f75SEd Tanous                 return;
28041da66f75SEd Tanous             }
2805e855dd28SJason M. Bills 
2806043a0536SJohnathan Mantey             // Verify the file name parameter is correct
2807043a0536SJohnathan Mantey             if (fileName != dbusFilename)
2808043a0536SJohnathan Mantey             {
2809ace85d60SEd Tanous                 messages::resourceMissingAtURI(asyncResp->res, url);
2810043a0536SJohnathan Mantey                 return;
2811043a0536SJohnathan Mantey             }
2812043a0536SJohnathan Mantey 
2813043a0536SJohnathan Mantey             if (!std::filesystem::exists(dbusFilepath))
2814043a0536SJohnathan Mantey             {
2815ace85d60SEd Tanous                 messages::resourceMissingAtURI(asyncResp->res, url);
2816043a0536SJohnathan Mantey                 return;
2817043a0536SJohnathan Mantey             }
2818*002d39b4SEd Tanous             std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
2819*002d39b4SEd Tanous             asyncResp->res.body() =
2820*002d39b4SEd Tanous                 std::string(std::istreambuf_iterator<char>{ifs}, {});
2821043a0536SJohnathan Mantey 
28227e860f15SJohn Edward Broadbent             // Configure this to be a file download when accessed
28237e860f15SJohn Edward Broadbent             // from a browser
2824*002d39b4SEd Tanous             asyncResp->res.addHeader("Content-Disposition", "attachment");
28251da66f75SEd Tanous         };
28261da66f75SEd Tanous         crow::connections::systemBus->async_method_call(
28275b61b5e8SJason M. Bills             std::move(getStoredLogCallback), crashdumpObject,
28285b61b5e8SJason M. Bills             crashdumpPath + std::string("/") + logID,
2829*002d39b4SEd Tanous             "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
28307e860f15SJohn Edward Broadbent         });
28311da66f75SEd Tanous }
28321da66f75SEd Tanous 
2833c5a4c82aSJason M. Bills enum class OEMDiagnosticType
2834c5a4c82aSJason M. Bills {
2835c5a4c82aSJason M. Bills     onDemand,
2836c5a4c82aSJason M. Bills     telemetry,
2837c5a4c82aSJason M. Bills     invalid,
2838c5a4c82aSJason M. Bills };
2839c5a4c82aSJason M. Bills 
2840f7725d79SEd Tanous inline OEMDiagnosticType
2841f7725d79SEd Tanous     getOEMDiagnosticType(const std::string_view& oemDiagStr)
2842c5a4c82aSJason M. Bills {
2843c5a4c82aSJason M. Bills     if (oemDiagStr == "OnDemand")
2844c5a4c82aSJason M. Bills     {
2845c5a4c82aSJason M. Bills         return OEMDiagnosticType::onDemand;
2846c5a4c82aSJason M. Bills     }
2847c5a4c82aSJason M. Bills     if (oemDiagStr == "Telemetry")
2848c5a4c82aSJason M. Bills     {
2849c5a4c82aSJason M. Bills         return OEMDiagnosticType::telemetry;
2850c5a4c82aSJason M. Bills     }
2851c5a4c82aSJason M. Bills 
2852c5a4c82aSJason M. Bills     return OEMDiagnosticType::invalid;
2853c5a4c82aSJason M. Bills }
2854c5a4c82aSJason M. Bills 
28557e860f15SJohn Edward Broadbent inline void requestRoutesCrashdumpCollect(App& app)
28561da66f75SEd Tanous {
28573946028dSAppaRao Puli     // Note: Deviated from redfish privilege registry for GET & HEAD
28583946028dSAppaRao Puli     // method for security reasons.
28590fda0f12SGeorge Liu     BMCWEB_ROUTE(
28600fda0f12SGeorge Liu         app,
28610fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
2862ed398213SEd Tanous         // The below is incorrect;  Should be ConfigureManager
2863ed398213SEd Tanous         //.privileges(redfish::privileges::postLogService)
2864432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
2865*002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
2866*002d39b4SEd Tanous             [&app](const crow::Request& req,
28677e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
286845ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
286945ca1b86SEd Tanous         {
287045ca1b86SEd Tanous             return;
287145ca1b86SEd Tanous         }
28728e6c099aSJason M. Bills         std::string diagnosticDataType;
28738e6c099aSJason M. Bills         std::string oemDiagnosticDataType;
287415ed6780SWilly Tu         if (!redfish::json_util::readJsonAction(
2875*002d39b4SEd Tanous                 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
2876*002d39b4SEd Tanous                 "OEMDiagnosticDataType", oemDiagnosticDataType))
28778e6c099aSJason M. Bills         {
28788e6c099aSJason M. Bills             return;
28798e6c099aSJason M. Bills         }
28808e6c099aSJason M. Bills 
28818e6c099aSJason M. Bills         if (diagnosticDataType != "OEM")
28828e6c099aSJason M. Bills         {
28838e6c099aSJason M. Bills             BMCWEB_LOG_ERROR
28848e6c099aSJason M. Bills                 << "Only OEM DiagnosticDataType supported for Crashdump";
28858e6c099aSJason M. Bills             messages::actionParameterValueFormatError(
28868e6c099aSJason M. Bills                 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
28878e6c099aSJason M. Bills                 "CollectDiagnosticData");
28888e6c099aSJason M. Bills             return;
28898e6c099aSJason M. Bills         }
28908e6c099aSJason M. Bills 
2891c5a4c82aSJason M. Bills         OEMDiagnosticType oemDiagType =
2892c5a4c82aSJason M. Bills             getOEMDiagnosticType(oemDiagnosticDataType);
2893c5a4c82aSJason M. Bills 
2894c5a4c82aSJason M. Bills         std::string iface;
2895c5a4c82aSJason M. Bills         std::string method;
2896c5a4c82aSJason M. Bills         std::string taskMatchStr;
2897c5a4c82aSJason M. Bills         if (oemDiagType == OEMDiagnosticType::onDemand)
2898c5a4c82aSJason M. Bills         {
2899c5a4c82aSJason M. Bills             iface = crashdumpOnDemandInterface;
2900c5a4c82aSJason M. Bills             method = "GenerateOnDemandLog";
2901c5a4c82aSJason M. Bills             taskMatchStr = "type='signal',"
2902c5a4c82aSJason M. Bills                            "interface='org.freedesktop.DBus.Properties',"
2903c5a4c82aSJason M. Bills                            "member='PropertiesChanged',"
2904c5a4c82aSJason M. Bills                            "arg0namespace='com.intel.crashdump'";
2905c5a4c82aSJason M. Bills         }
2906c5a4c82aSJason M. Bills         else if (oemDiagType == OEMDiagnosticType::telemetry)
2907c5a4c82aSJason M. Bills         {
2908c5a4c82aSJason M. Bills             iface = crashdumpTelemetryInterface;
2909c5a4c82aSJason M. Bills             method = "GenerateTelemetryLog";
2910c5a4c82aSJason M. Bills             taskMatchStr = "type='signal',"
2911c5a4c82aSJason M. Bills                            "interface='org.freedesktop.DBus.Properties',"
2912c5a4c82aSJason M. Bills                            "member='PropertiesChanged',"
2913c5a4c82aSJason M. Bills                            "arg0namespace='com.intel.crashdump'";
2914c5a4c82aSJason M. Bills         }
2915c5a4c82aSJason M. Bills         else
2916c5a4c82aSJason M. Bills         {
2917c5a4c82aSJason M. Bills             BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
2918c5a4c82aSJason M. Bills                              << oemDiagnosticDataType;
2919c5a4c82aSJason M. Bills             messages::actionParameterValueFormatError(
2920*002d39b4SEd Tanous                 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
2921*002d39b4SEd Tanous                 "CollectDiagnosticData");
2922c5a4c82aSJason M. Bills             return;
2923c5a4c82aSJason M. Bills         }
2924c5a4c82aSJason M. Bills 
2925c5a4c82aSJason M. Bills         auto collectCrashdumpCallback =
2926c5a4c82aSJason M. Bills             [asyncResp, payload(task::Payload(req)),
2927c5a4c82aSJason M. Bills              taskMatchStr](const boost::system::error_code ec,
292898be3e39SEd Tanous                            const std::string&) mutable {
29291da66f75SEd Tanous             if (ec)
29301da66f75SEd Tanous             {
2931*002d39b4SEd Tanous                 if (ec.value() == boost::system::errc::operation_not_supported)
29321da66f75SEd Tanous                 {
2933f12894f8SJason M. Bills                     messages::resourceInStandby(asyncResp->res);
29341da66f75SEd Tanous                 }
29354363d3b2SJason M. Bills                 else if (ec.value() ==
29364363d3b2SJason M. Bills                          boost::system::errc::device_or_resource_busy)
29374363d3b2SJason M. Bills                 {
2938*002d39b4SEd Tanous                     messages::serviceTemporarilyUnavailable(asyncResp->res,
2939*002d39b4SEd Tanous                                                             "60");
29404363d3b2SJason M. Bills                 }
29411da66f75SEd Tanous                 else
29421da66f75SEd Tanous                 {
2943f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
29441da66f75SEd Tanous                 }
29451da66f75SEd Tanous                 return;
29461da66f75SEd Tanous             }
2947*002d39b4SEd Tanous             std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
2948*002d39b4SEd Tanous                 [](boost::system::error_code err, sdbusplus::message::message&,
2949*002d39b4SEd Tanous                    const std::shared_ptr<task::TaskData>& taskData) {
295066afe4faSJames Feist                 if (!err)
295166afe4faSJames Feist                 {
2952*002d39b4SEd Tanous                     taskData->messages.emplace_back(messages::taskCompletedOK(
2953e5d5006bSJames Feist                         std::to_string(taskData->index)));
2954831d6b09SJames Feist                     taskData->state = "Completed";
295566afe4faSJames Feist                 }
295632898ceaSJames Feist                 return task::completed;
295766afe4faSJames Feist                 },
2958c5a4c82aSJason M. Bills                 taskMatchStr);
2959c5a4c82aSJason M. Bills 
296046229577SJames Feist             task->startTimer(std::chrono::minutes(5));
296146229577SJames Feist             task->populateResp(asyncResp->res);
296298be3e39SEd Tanous             task->payload.emplace(std::move(payload));
29631da66f75SEd Tanous         };
29648e6c099aSJason M. Bills 
29651da66f75SEd Tanous         crow::connections::systemBus->async_method_call(
2966*002d39b4SEd Tanous             std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
2967*002d39b4SEd Tanous             iface, method);
29687e860f15SJohn Edward Broadbent         });
29696eda7685SKenny L. Ku }
29706eda7685SKenny L. Ku 
2971cb92c03bSAndrew Geissler /**
2972cb92c03bSAndrew Geissler  * DBusLogServiceActionsClear class supports POST method for ClearLog action.
2973cb92c03bSAndrew Geissler  */
29747e860f15SJohn Edward Broadbent inline void requestRoutesDBusLogServiceActionsClear(App& app)
2975cb92c03bSAndrew Geissler {
2976cb92c03bSAndrew Geissler     /**
2977cb92c03bSAndrew Geissler      * Function handles POST method request.
2978cb92c03bSAndrew Geissler      * The Clear Log actions does not require any parameter.The action deletes
2979cb92c03bSAndrew Geissler      * all entries found in the Entries collection for this Log Service.
2980cb92c03bSAndrew Geissler      */
29817e860f15SJohn Edward Broadbent 
29820fda0f12SGeorge Liu     BMCWEB_ROUTE(
29830fda0f12SGeorge Liu         app,
29840fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
2985ed398213SEd Tanous         .privileges(redfish::privileges::postLogService)
29867e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
298745ca1b86SEd Tanous             [&app](const crow::Request& req,
29887e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
298945ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
299045ca1b86SEd Tanous         {
299145ca1b86SEd Tanous             return;
299245ca1b86SEd Tanous         }
2993cb92c03bSAndrew Geissler         BMCWEB_LOG_DEBUG << "Do delete all entries.";
2994cb92c03bSAndrew Geissler 
2995cb92c03bSAndrew Geissler         // Process response from Logging service.
2996*002d39b4SEd Tanous         auto respHandler = [asyncResp](const boost::system::error_code ec) {
2997*002d39b4SEd Tanous             BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
2998cb92c03bSAndrew Geissler             if (ec)
2999cb92c03bSAndrew Geissler             {
3000cb92c03bSAndrew Geissler                 // TODO Handle for specific error code
3001*002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3002cb92c03bSAndrew Geissler                 asyncResp->res.result(
3003cb92c03bSAndrew Geissler                     boost::beast::http::status::internal_server_error);
3004cb92c03bSAndrew Geissler                 return;
3005cb92c03bSAndrew Geissler             }
3006cb92c03bSAndrew Geissler 
3007*002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::no_content);
3008cb92c03bSAndrew Geissler         };
3009cb92c03bSAndrew Geissler 
3010cb92c03bSAndrew Geissler         // Make call to Logging service to request Clear Log
3011cb92c03bSAndrew Geissler         crow::connections::systemBus->async_method_call(
30122c70f800SEd Tanous             respHandler, "xyz.openbmc_project.Logging",
3013cb92c03bSAndrew Geissler             "/xyz/openbmc_project/logging",
3014cb92c03bSAndrew Geissler             "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
30157e860f15SJohn Edward Broadbent         });
3016cb92c03bSAndrew Geissler }
3017a3316fc6SZhikuiRen 
3018a3316fc6SZhikuiRen /****************************************************
3019a3316fc6SZhikuiRen  * Redfish PostCode interfaces
3020a3316fc6SZhikuiRen  * using DBUS interface: getPostCodesTS
3021a3316fc6SZhikuiRen  ******************************************************/
30227e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesLogService(App& app)
3023a3316fc6SZhikuiRen {
30247e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
3025ed398213SEd Tanous         .privileges(redfish::privileges::getLogService)
3026*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
3027*002d39b4SEd Tanous             [&app](const crow::Request& req,
3028*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
302945ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
303045ca1b86SEd Tanous         {
303145ca1b86SEd Tanous             return;
303245ca1b86SEd Tanous         }
30331476687dSEd Tanous 
30341476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
30351476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/PostCodes";
30361476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
30371476687dSEd Tanous             "#LogService.v1_1_0.LogService";
30381476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
30391476687dSEd Tanous         asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
30401476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
30411476687dSEd Tanous         asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
30421476687dSEd Tanous         asyncResp->res.jsonValue["Entries"]["@odata.id"] =
30431476687dSEd Tanous             "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
30447c8c4058STejas Patil 
30457c8c4058STejas Patil         std::pair<std::string, std::string> redfishDateTimeOffset =
30467c8c4058STejas Patil             crow::utility::getDateTimeOffsetNow();
30470fda0f12SGeorge Liu         asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
30487c8c4058STejas Patil         asyncResp->res.jsonValue["DateTimeLocalOffset"] =
30497c8c4058STejas Patil             redfishDateTimeOffset.second;
30507c8c4058STejas Patil 
3051a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
30527e860f15SJohn Edward Broadbent             {"target",
30530fda0f12SGeorge Liu              "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
30547e860f15SJohn Edward Broadbent         });
3055a3316fc6SZhikuiRen }
3056a3316fc6SZhikuiRen 
30577e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesClear(App& app)
3058a3316fc6SZhikuiRen {
30590fda0f12SGeorge Liu     BMCWEB_ROUTE(
30600fda0f12SGeorge Liu         app,
30610fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog/")
3062ed398213SEd Tanous         // The following privilege is incorrect;  It should be ConfigureManager
3063ed398213SEd Tanous         //.privileges(redfish::privileges::postLogService)
3064432a890cSEd Tanous         .privileges({{"ConfigureComponents"}})
30657e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
306645ca1b86SEd Tanous             [&app](const crow::Request& req,
30677e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
306845ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
306945ca1b86SEd Tanous         {
307045ca1b86SEd Tanous             return;
307145ca1b86SEd Tanous         }
3072a3316fc6SZhikuiRen         BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
3073a3316fc6SZhikuiRen 
3074a3316fc6SZhikuiRen         // Make call to post-code service to request clear all
3075a3316fc6SZhikuiRen         crow::connections::systemBus->async_method_call(
3076a3316fc6SZhikuiRen             [asyncResp](const boost::system::error_code ec) {
3077a3316fc6SZhikuiRen             if (ec)
3078a3316fc6SZhikuiRen             {
3079a3316fc6SZhikuiRen                 // TODO Handle for specific error code
3080*002d39b4SEd Tanous                 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
30817e860f15SJohn Edward Broadbent                                  << ec;
3082*002d39b4SEd Tanous                 asyncResp->res.result(
3083*002d39b4SEd Tanous                     boost::beast::http::status::internal_server_error);
3084a3316fc6SZhikuiRen                 messages::internalError(asyncResp->res);
3085a3316fc6SZhikuiRen                 return;
3086a3316fc6SZhikuiRen             }
3087a3316fc6SZhikuiRen             },
308815124765SJonathan Doman             "xyz.openbmc_project.State.Boot.PostCode0",
308915124765SJonathan Doman             "/xyz/openbmc_project/State/Boot/PostCode0",
3090a3316fc6SZhikuiRen             "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
30917e860f15SJohn Edward Broadbent         });
3092a3316fc6SZhikuiRen }
3093a3316fc6SZhikuiRen 
3094a3316fc6SZhikuiRen static void fillPostCodeEntry(
30958d1b46d7Szhanghch05     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
30966c9a279eSManojkiran Eda     const boost::container::flat_map<
30976c9a279eSManojkiran Eda         uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
3098a3316fc6SZhikuiRen     const uint16_t bootIndex, const uint64_t codeIndex = 0,
3099a3316fc6SZhikuiRen     const uint64_t skip = 0, const uint64_t top = 0)
3100a3316fc6SZhikuiRen {
3101a3316fc6SZhikuiRen     // Get the Message from the MessageRegistry
3102fffb8c1fSEd Tanous     const registries::Message* message =
3103fffb8c1fSEd Tanous         registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
3104a3316fc6SZhikuiRen 
3105a3316fc6SZhikuiRen     uint64_t currentCodeIndex = 0;
3106a3316fc6SZhikuiRen     nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
3107a3316fc6SZhikuiRen 
3108a3316fc6SZhikuiRen     uint64_t firstCodeTimeUs = 0;
31096c9a279eSManojkiran Eda     for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
31106c9a279eSManojkiran Eda              code : postcode)
3111a3316fc6SZhikuiRen     {
3112a3316fc6SZhikuiRen         currentCodeIndex++;
3113a3316fc6SZhikuiRen         std::string postcodeEntryID =
3114a3316fc6SZhikuiRen             "B" + std::to_string(bootIndex) + "-" +
3115a3316fc6SZhikuiRen             std::to_string(currentCodeIndex); // 1 based index in EntryID string
3116a3316fc6SZhikuiRen 
3117a3316fc6SZhikuiRen         uint64_t usecSinceEpoch = code.first;
3118a3316fc6SZhikuiRen         uint64_t usTimeOffset = 0;
3119a3316fc6SZhikuiRen 
3120a3316fc6SZhikuiRen         if (1 == currentCodeIndex)
3121a3316fc6SZhikuiRen         { // already incremented
3122a3316fc6SZhikuiRen             firstCodeTimeUs = code.first;
3123a3316fc6SZhikuiRen         }
3124a3316fc6SZhikuiRen         else
3125a3316fc6SZhikuiRen         {
3126a3316fc6SZhikuiRen             usTimeOffset = code.first - firstCodeTimeUs;
3127a3316fc6SZhikuiRen         }
3128a3316fc6SZhikuiRen 
3129a3316fc6SZhikuiRen         // skip if no specific codeIndex is specified and currentCodeIndex does
3130a3316fc6SZhikuiRen         // not fall between top and skip
3131a3316fc6SZhikuiRen         if ((codeIndex == 0) &&
3132a3316fc6SZhikuiRen             (currentCodeIndex <= skip || currentCodeIndex > top))
3133a3316fc6SZhikuiRen         {
3134a3316fc6SZhikuiRen             continue;
3135a3316fc6SZhikuiRen         }
3136a3316fc6SZhikuiRen 
31374e0453b1SGunnar Mills         // skip if a specific codeIndex is specified and does not match the
3138a3316fc6SZhikuiRen         // currentIndex
3139a3316fc6SZhikuiRen         if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3140a3316fc6SZhikuiRen         {
3141a3316fc6SZhikuiRen             // This is done for simplicity. 1st entry is needed to calculate
3142a3316fc6SZhikuiRen             // time offset. To improve efficiency, one can get to the entry
3143a3316fc6SZhikuiRen             // directly (possibly with flatmap's nth method)
3144a3316fc6SZhikuiRen             continue;
3145a3316fc6SZhikuiRen         }
3146a3316fc6SZhikuiRen 
3147a3316fc6SZhikuiRen         // currentCodeIndex is within top and skip or equal to specified code
3148a3316fc6SZhikuiRen         // index
3149a3316fc6SZhikuiRen 
3150a3316fc6SZhikuiRen         // Get the Created time from the timestamp
3151a3316fc6SZhikuiRen         std::string entryTimeStr;
31521d8782e7SNan Zhou         entryTimeStr =
31531d8782e7SNan Zhou             crow::utility::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
3154a3316fc6SZhikuiRen 
3155a3316fc6SZhikuiRen         // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3156a3316fc6SZhikuiRen         std::ostringstream hexCode;
3157a3316fc6SZhikuiRen         hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
31586c9a279eSManojkiran Eda                 << std::get<0>(code.second);
3159a3316fc6SZhikuiRen         std::ostringstream timeOffsetStr;
3160a3316fc6SZhikuiRen         // Set Fixed -Point Notation
3161a3316fc6SZhikuiRen         timeOffsetStr << std::fixed;
3162a3316fc6SZhikuiRen         // Set precision to 4 digits
3163a3316fc6SZhikuiRen         timeOffsetStr << std::setprecision(4);
3164a3316fc6SZhikuiRen         // Add double to stream
3165a3316fc6SZhikuiRen         timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3166a3316fc6SZhikuiRen         std::vector<std::string> messageArgs = {
3167a3316fc6SZhikuiRen             std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3168a3316fc6SZhikuiRen 
3169a3316fc6SZhikuiRen         // Get MessageArgs template from message registry
3170a3316fc6SZhikuiRen         std::string msg;
3171a3316fc6SZhikuiRen         if (message != nullptr)
3172a3316fc6SZhikuiRen         {
3173a3316fc6SZhikuiRen             msg = message->message;
3174a3316fc6SZhikuiRen 
3175a3316fc6SZhikuiRen             // fill in this post code value
3176a3316fc6SZhikuiRen             int i = 0;
3177a3316fc6SZhikuiRen             for (const std::string& messageArg : messageArgs)
3178a3316fc6SZhikuiRen             {
3179a3316fc6SZhikuiRen                 std::string argStr = "%" + std::to_string(++i);
3180a3316fc6SZhikuiRen                 size_t argPos = msg.find(argStr);
3181a3316fc6SZhikuiRen                 if (argPos != std::string::npos)
3182a3316fc6SZhikuiRen                 {
3183a3316fc6SZhikuiRen                     msg.replace(argPos, argStr.length(), messageArg);
3184a3316fc6SZhikuiRen                 }
3185a3316fc6SZhikuiRen             }
3186a3316fc6SZhikuiRen         }
3187a3316fc6SZhikuiRen 
3188d4342a92STim Lee         // Get Severity template from message registry
3189d4342a92STim Lee         std::string severity;
3190d4342a92STim Lee         if (message != nullptr)
3191d4342a92STim Lee         {
31925f2b84eeSEd Tanous             severity = message->messageSeverity;
3193d4342a92STim Lee         }
3194d4342a92STim Lee 
3195a3316fc6SZhikuiRen         // add to AsyncResp
3196a3316fc6SZhikuiRen         logEntryArray.push_back({});
3197a3316fc6SZhikuiRen         nlohmann::json& bmcLogEntry = logEntryArray.back();
31980fda0f12SGeorge Liu         bmcLogEntry = {
31990fda0f12SGeorge Liu             {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
32000fda0f12SGeorge Liu             {"@odata.id",
32010fda0f12SGeorge Liu              "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3202a3316fc6SZhikuiRen                  postcodeEntryID},
3203a3316fc6SZhikuiRen             {"Name", "POST Code Log Entry"},
3204a3316fc6SZhikuiRen             {"Id", postcodeEntryID},
3205a3316fc6SZhikuiRen             {"Message", std::move(msg)},
32064a0bf539SManojkiran Eda             {"MessageId", "OpenBMC.0.2.BIOSPOSTCode"},
3207a3316fc6SZhikuiRen             {"MessageArgs", std::move(messageArgs)},
3208a3316fc6SZhikuiRen             {"EntryType", "Event"},
3209a3316fc6SZhikuiRen             {"Severity", std::move(severity)},
32109c620e21SAsmitha Karunanithi             {"Created", entryTimeStr}};
3211647b3cdcSGeorge Liu         if (!std::get<std::vector<uint8_t>>(code.second).empty())
3212647b3cdcSGeorge Liu         {
3213647b3cdcSGeorge Liu             bmcLogEntry["AdditionalDataURI"] =
3214647b3cdcSGeorge Liu                 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3215647b3cdcSGeorge Liu                 postcodeEntryID + "/attachment";
3216647b3cdcSGeorge Liu         }
3217a3316fc6SZhikuiRen     }
3218a3316fc6SZhikuiRen }
3219a3316fc6SZhikuiRen 
32208d1b46d7Szhanghch05 static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3221a3316fc6SZhikuiRen                                 const uint16_t bootIndex,
3222a3316fc6SZhikuiRen                                 const uint64_t codeIndex)
3223a3316fc6SZhikuiRen {
3224a3316fc6SZhikuiRen     crow::connections::systemBus->async_method_call(
32256c9a279eSManojkiran Eda         [aResp, bootIndex,
32266c9a279eSManojkiran Eda          codeIndex](const boost::system::error_code ec,
32276c9a279eSManojkiran Eda                     const boost::container::flat_map<
32286c9a279eSManojkiran Eda                         uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
32296c9a279eSManojkiran Eda                         postcode) {
3230a3316fc6SZhikuiRen         if (ec)
3231a3316fc6SZhikuiRen         {
3232a3316fc6SZhikuiRen             BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3233a3316fc6SZhikuiRen             messages::internalError(aResp->res);
3234a3316fc6SZhikuiRen             return;
3235a3316fc6SZhikuiRen         }
3236a3316fc6SZhikuiRen 
3237a3316fc6SZhikuiRen         // skip the empty postcode boots
3238a3316fc6SZhikuiRen         if (postcode.empty())
3239a3316fc6SZhikuiRen         {
3240a3316fc6SZhikuiRen             return;
3241a3316fc6SZhikuiRen         }
3242a3316fc6SZhikuiRen 
3243a3316fc6SZhikuiRen         fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
3244a3316fc6SZhikuiRen 
3245a3316fc6SZhikuiRen         aResp->res.jsonValue["Members@odata.count"] =
3246a3316fc6SZhikuiRen             aResp->res.jsonValue["Members"].size();
3247a3316fc6SZhikuiRen         },
324815124765SJonathan Doman         "xyz.openbmc_project.State.Boot.PostCode0",
324915124765SJonathan Doman         "/xyz/openbmc_project/State/Boot/PostCode0",
3250a3316fc6SZhikuiRen         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3251a3316fc6SZhikuiRen         bootIndex);
3252a3316fc6SZhikuiRen }
3253a3316fc6SZhikuiRen 
32548d1b46d7Szhanghch05 static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3255a3316fc6SZhikuiRen                                const uint16_t bootIndex,
3256a3316fc6SZhikuiRen                                const uint16_t bootCount,
3257a3316fc6SZhikuiRen                                const uint64_t entryCount, const uint64_t skip,
3258a3316fc6SZhikuiRen                                const uint64_t top)
3259a3316fc6SZhikuiRen {
3260a3316fc6SZhikuiRen     crow::connections::systemBus->async_method_call(
3261a3316fc6SZhikuiRen         [aResp, bootIndex, bootCount, entryCount, skip,
3262a3316fc6SZhikuiRen          top](const boost::system::error_code ec,
32636c9a279eSManojkiran Eda               const boost::container::flat_map<
32646c9a279eSManojkiran Eda                   uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
32656c9a279eSManojkiran Eda                   postcode) {
3266a3316fc6SZhikuiRen         if (ec)
3267a3316fc6SZhikuiRen         {
3268a3316fc6SZhikuiRen             BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3269a3316fc6SZhikuiRen             messages::internalError(aResp->res);
3270a3316fc6SZhikuiRen             return;
3271a3316fc6SZhikuiRen         }
3272a3316fc6SZhikuiRen 
3273a3316fc6SZhikuiRen         uint64_t endCount = entryCount;
3274a3316fc6SZhikuiRen         if (!postcode.empty())
3275a3316fc6SZhikuiRen         {
3276a3316fc6SZhikuiRen             endCount = entryCount + postcode.size();
3277a3316fc6SZhikuiRen 
3278a3316fc6SZhikuiRen             if ((skip < endCount) && ((top + skip) > entryCount))
3279a3316fc6SZhikuiRen             {
3280*002d39b4SEd Tanous                 uint64_t thisBootSkip = std::max(skip, entryCount) - entryCount;
3281a3316fc6SZhikuiRen                 uint64_t thisBootTop =
3282a3316fc6SZhikuiRen                     std::min(top + skip, endCount) - entryCount;
3283a3316fc6SZhikuiRen 
3284*002d39b4SEd Tanous                 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3285*002d39b4SEd Tanous                                   thisBootTop);
3286a3316fc6SZhikuiRen             }
3287a3316fc6SZhikuiRen             aResp->res.jsonValue["Members@odata.count"] = endCount;
3288a3316fc6SZhikuiRen         }
3289a3316fc6SZhikuiRen 
3290a3316fc6SZhikuiRen         // continue to previous bootIndex
3291a3316fc6SZhikuiRen         if (bootIndex < bootCount)
3292a3316fc6SZhikuiRen         {
3293a3316fc6SZhikuiRen             getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3294a3316fc6SZhikuiRen                                bootCount, endCount, skip, top);
3295a3316fc6SZhikuiRen         }
3296a3316fc6SZhikuiRen         else
3297a3316fc6SZhikuiRen         {
3298a3316fc6SZhikuiRen             aResp->res.jsonValue["Members@odata.nextLink"] =
32990fda0f12SGeorge Liu                 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3300a3316fc6SZhikuiRen                 std::to_string(skip + top);
3301a3316fc6SZhikuiRen         }
3302a3316fc6SZhikuiRen         },
330315124765SJonathan Doman         "xyz.openbmc_project.State.Boot.PostCode0",
330415124765SJonathan Doman         "/xyz/openbmc_project/State/Boot/PostCode0",
3305a3316fc6SZhikuiRen         "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3306a3316fc6SZhikuiRen         bootIndex);
3307a3316fc6SZhikuiRen }
3308a3316fc6SZhikuiRen 
33098d1b46d7Szhanghch05 static void
33108d1b46d7Szhanghch05     getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3311a3316fc6SZhikuiRen                          const uint64_t skip, const uint64_t top)
3312a3316fc6SZhikuiRen {
3313a3316fc6SZhikuiRen     uint64_t entryCount = 0;
33141e1e598dSJonathan Doman     sdbusplus::asio::getProperty<uint16_t>(
33151e1e598dSJonathan Doman         *crow::connections::systemBus,
33161e1e598dSJonathan Doman         "xyz.openbmc_project.State.Boot.PostCode0",
33171e1e598dSJonathan Doman         "/xyz/openbmc_project/State/Boot/PostCode0",
33181e1e598dSJonathan Doman         "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
33191e1e598dSJonathan Doman         [aResp, entryCount, skip, top](const boost::system::error_code ec,
33201e1e598dSJonathan Doman                                        const uint16_t bootCount) {
3321a3316fc6SZhikuiRen         if (ec)
3322a3316fc6SZhikuiRen         {
3323a3316fc6SZhikuiRen             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3324a3316fc6SZhikuiRen             messages::internalError(aResp->res);
3325a3316fc6SZhikuiRen             return;
3326a3316fc6SZhikuiRen         }
33271e1e598dSJonathan Doman         getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
33281e1e598dSJonathan Doman         });
3329a3316fc6SZhikuiRen }
3330a3316fc6SZhikuiRen 
33317e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntryCollection(App& app)
3332a3316fc6SZhikuiRen {
33337e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app,
33347e860f15SJohn Edward Broadbent                  "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
3335ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntryCollection)
33367e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
333745ca1b86SEd Tanous             [&app](const crow::Request& req,
33387e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3339c937d2bfSEd Tanous         query_param::QueryCapabilities capabilities = {
3340c937d2bfSEd Tanous             .canDelegateTop = true,
3341c937d2bfSEd Tanous             .canDelegateSkip = true,
3342c937d2bfSEd Tanous         };
3343c937d2bfSEd Tanous         query_param::Query delegatedQuery;
3344c937d2bfSEd Tanous         if (!redfish::setUpRedfishRouteWithDelegation(
3345c937d2bfSEd Tanous                 app, req, asyncResp->res, delegatedQuery, capabilities))
334645ca1b86SEd Tanous         {
334745ca1b86SEd Tanous             return;
334845ca1b86SEd Tanous         }
3349a3316fc6SZhikuiRen         asyncResp->res.jsonValue["@odata.type"] =
3350a3316fc6SZhikuiRen             "#LogEntryCollection.LogEntryCollection";
3351a3316fc6SZhikuiRen         asyncResp->res.jsonValue["@odata.id"] =
3352a3316fc6SZhikuiRen             "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3353a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3354a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Description"] =
3355a3316fc6SZhikuiRen             "Collection of POST Code Log Entries";
3356a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3357a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Members@odata.count"] = 0;
3358a3316fc6SZhikuiRen 
3359c937d2bfSEd Tanous         getCurrentBootNumber(asyncResp, delegatedQuery.skip,
3360c937d2bfSEd Tanous                              delegatedQuery.top);
33617e860f15SJohn Edward Broadbent         });
3362a3316fc6SZhikuiRen }
3363a3316fc6SZhikuiRen 
3364647b3cdcSGeorge Liu /**
3365647b3cdcSGeorge Liu  * @brief Parse post code ID and get the current value and index value
3366647b3cdcSGeorge Liu  *        eg: postCodeID=B1-2, currentValue=1, index=2
3367647b3cdcSGeorge Liu  *
3368647b3cdcSGeorge Liu  * @param[in]  postCodeID     Post Code ID
3369647b3cdcSGeorge Liu  * @param[out] currentValue   Current value
3370647b3cdcSGeorge Liu  * @param[out] index          Index value
3371647b3cdcSGeorge Liu  *
3372647b3cdcSGeorge Liu  * @return bool true if the parsing is successful, false the parsing fails
3373647b3cdcSGeorge Liu  */
3374647b3cdcSGeorge Liu inline static bool parsePostCode(const std::string& postCodeID,
3375647b3cdcSGeorge Liu                                  uint64_t& currentValue, uint16_t& index)
3376647b3cdcSGeorge Liu {
3377647b3cdcSGeorge Liu     std::vector<std::string> split;
3378647b3cdcSGeorge Liu     boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3379647b3cdcSGeorge Liu     if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3380647b3cdcSGeorge Liu     {
3381647b3cdcSGeorge Liu         return false;
3382647b3cdcSGeorge Liu     }
3383647b3cdcSGeorge Liu 
3384ca45aa3cSEd Tanous     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3385647b3cdcSGeorge Liu     const char* start = split[0].data() + 1;
3386ca45aa3cSEd Tanous     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3387647b3cdcSGeorge Liu     const char* end = split[0].data() + split[0].size();
3388647b3cdcSGeorge Liu     auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3389647b3cdcSGeorge Liu 
3390647b3cdcSGeorge Liu     if (ptrIndex != end || ecIndex != std::errc())
3391647b3cdcSGeorge Liu     {
3392647b3cdcSGeorge Liu         return false;
3393647b3cdcSGeorge Liu     }
3394647b3cdcSGeorge Liu 
3395647b3cdcSGeorge Liu     start = split[1].data();
3396ca45aa3cSEd Tanous 
3397ca45aa3cSEd Tanous     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3398647b3cdcSGeorge Liu     end = split[1].data() + split[1].size();
3399647b3cdcSGeorge Liu     auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
3400647b3cdcSGeorge Liu 
3401dcf2ebc0SEd Tanous     return ptrValue == end && ecValue != std::errc();
3402647b3cdcSGeorge Liu }
3403647b3cdcSGeorge Liu 
3404647b3cdcSGeorge Liu inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3405647b3cdcSGeorge Liu {
34060fda0f12SGeorge Liu     BMCWEB_ROUTE(
34070fda0f12SGeorge Liu         app,
34080fda0f12SGeorge Liu         "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/attachment/")
3409647b3cdcSGeorge Liu         .privileges(redfish::privileges::getLogEntry)
3410647b3cdcSGeorge Liu         .methods(boost::beast::http::verb::get)(
341145ca1b86SEd Tanous             [&app](const crow::Request& req,
3412647b3cdcSGeorge Liu                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3413647b3cdcSGeorge Liu                    const std::string& postCodeID) {
341445ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
341545ca1b86SEd Tanous         {
341645ca1b86SEd Tanous             return;
341745ca1b86SEd Tanous         }
3418*002d39b4SEd Tanous         if (!http_helpers::isOctetAccepted(req.getHeaderValue("Accept")))
3419647b3cdcSGeorge Liu         {
3420*002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::bad_request);
3421647b3cdcSGeorge Liu             return;
3422647b3cdcSGeorge Liu         }
3423647b3cdcSGeorge Liu 
3424647b3cdcSGeorge Liu         uint64_t currentValue = 0;
3425647b3cdcSGeorge Liu         uint16_t index = 0;
3426647b3cdcSGeorge Liu         if (!parsePostCode(postCodeID, currentValue, index))
3427647b3cdcSGeorge Liu         {
3428*002d39b4SEd Tanous             messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3429647b3cdcSGeorge Liu             return;
3430647b3cdcSGeorge Liu         }
3431647b3cdcSGeorge Liu 
3432647b3cdcSGeorge Liu         crow::connections::systemBus->async_method_call(
3433647b3cdcSGeorge Liu             [asyncResp, postCodeID, currentValue](
3434647b3cdcSGeorge Liu                 const boost::system::error_code ec,
3435*002d39b4SEd Tanous                 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3436*002d39b4SEd Tanous                     postcodes) {
3437647b3cdcSGeorge Liu             if (ec.value() == EBADR)
3438647b3cdcSGeorge Liu             {
3439*002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry",
3440*002d39b4SEd Tanous                                            postCodeID);
3441647b3cdcSGeorge Liu                 return;
3442647b3cdcSGeorge Liu             }
3443647b3cdcSGeorge Liu             if (ec)
3444647b3cdcSGeorge Liu             {
3445647b3cdcSGeorge Liu                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3446647b3cdcSGeorge Liu                 messages::internalError(asyncResp->res);
3447647b3cdcSGeorge Liu                 return;
3448647b3cdcSGeorge Liu             }
3449647b3cdcSGeorge Liu 
3450647b3cdcSGeorge Liu             size_t value = static_cast<size_t>(currentValue) - 1;
3451*002d39b4SEd Tanous             if (value == std::string::npos || postcodes.size() < currentValue)
3452647b3cdcSGeorge Liu             {
3453647b3cdcSGeorge Liu                 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3454*002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry",
3455*002d39b4SEd Tanous                                            postCodeID);
3456647b3cdcSGeorge Liu                 return;
3457647b3cdcSGeorge Liu             }
3458647b3cdcSGeorge Liu 
34599eb808c1SEd Tanous             const auto& [tID, c] = postcodes[value];
346046ff87baSEd Tanous             if (c.empty())
3461647b3cdcSGeorge Liu             {
3462647b3cdcSGeorge Liu                 BMCWEB_LOG_INFO << "No found post code data";
3463*002d39b4SEd Tanous                 messages::resourceNotFound(asyncResp->res, "LogEntry",
3464*002d39b4SEd Tanous                                            postCodeID);
3465647b3cdcSGeorge Liu                 return;
3466647b3cdcSGeorge Liu             }
346746ff87baSEd Tanous             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
346846ff87baSEd Tanous             const char* d = reinterpret_cast<const char*>(c.data());
346946ff87baSEd Tanous             std::string_view strData(d, c.size());
3470647b3cdcSGeorge Liu 
3471647b3cdcSGeorge Liu             asyncResp->res.addHeader("Content-Type",
3472647b3cdcSGeorge Liu                                      "application/octet-stream");
3473*002d39b4SEd Tanous             asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
3474*002d39b4SEd Tanous             asyncResp->res.body() = crow::utility::base64encode(strData);
3475647b3cdcSGeorge Liu             },
3476647b3cdcSGeorge Liu             "xyz.openbmc_project.State.Boot.PostCode0",
3477647b3cdcSGeorge Liu             "/xyz/openbmc_project/State/Boot/PostCode0",
3478*002d39b4SEd Tanous             "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
3479647b3cdcSGeorge Liu         });
3480647b3cdcSGeorge Liu }
3481647b3cdcSGeorge Liu 
34827e860f15SJohn Edward Broadbent inline void requestRoutesPostCodesEntry(App& app)
3483a3316fc6SZhikuiRen {
34847e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
34857e860f15SJohn Edward Broadbent         app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/")
3486ed398213SEd Tanous         .privileges(redfish::privileges::getLogEntry)
34877e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
348845ca1b86SEd Tanous             [&app](const crow::Request& req,
34897e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
34907e860f15SJohn Edward Broadbent                    const std::string& targetID) {
349145ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
349245ca1b86SEd Tanous         {
349345ca1b86SEd Tanous             return;
349445ca1b86SEd Tanous         }
3495647b3cdcSGeorge Liu         uint16_t bootIndex = 0;
3496647b3cdcSGeorge Liu         uint64_t codeIndex = 0;
3497647b3cdcSGeorge Liu         if (!parsePostCode(targetID, codeIndex, bootIndex))
3498a3316fc6SZhikuiRen         {
3499a3316fc6SZhikuiRen             // Requested ID was not found
3500ace85d60SEd Tanous             messages::resourceMissingAtURI(asyncResp->res, req.urlView);
3501a3316fc6SZhikuiRen             return;
3502a3316fc6SZhikuiRen         }
3503a3316fc6SZhikuiRen         if (bootIndex == 0 || codeIndex == 0)
3504a3316fc6SZhikuiRen         {
3505a3316fc6SZhikuiRen             BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
35067e860f15SJohn Edward Broadbent                              << targetID;
3507a3316fc6SZhikuiRen         }
3508a3316fc6SZhikuiRen 
3509*002d39b4SEd Tanous         asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_4_0.LogEntry";
3510a3316fc6SZhikuiRen         asyncResp->res.jsonValue["@odata.id"] =
35110fda0f12SGeorge Liu             "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3512a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3513a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Description"] =
3514a3316fc6SZhikuiRen             "Collection of POST Code Log Entries";
3515a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3516a3316fc6SZhikuiRen         asyncResp->res.jsonValue["Members@odata.count"] = 0;
3517a3316fc6SZhikuiRen 
3518a3316fc6SZhikuiRen         getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
35197e860f15SJohn Edward Broadbent         });
3520a3316fc6SZhikuiRen }
3521a3316fc6SZhikuiRen 
35221da66f75SEd Tanous } // namespace redfish
3523