blob: d31602cd546be37fd62601d1c9a5307d5e62b80b [file] [log] [blame]
Ed Tanous1da66f72018-07-27 16:13:37 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Spencer Kub7028eb2021-10-26 15:27:35 +080018#include "gzfile.hpp"
George Liu647b3cd2021-07-05 12:43:56 +080019#include "http_utility.hpp"
Spencer Kub7028eb2021-10-26 15:27:35 +080020#include "human_sort.hpp"
Jason M. Bills4851d452019-03-28 11:27:48 -070021#include "registries.hpp"
22#include "registries/base_message_registry.hpp"
23#include "registries/openbmc_message_registry.hpp"
James Feist46229572020-02-19 15:11:58 -080024#include "task.hpp"
Ed Tanous1da66f72018-07-27 16:13:37 -070025
Jason M. Billse1f26342018-07-18 12:12:00 -070026#include <systemd/sd-journal.h>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060027#include <unistd.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070028
John Edward Broadbent7e860f12021-04-08 15:57:16 -070029#include <app.hpp>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060030#include <boost/algorithm/string/replace.hpp>
Jason M. Bills4851d452019-03-28 11:27:48 -070031#include <boost/algorithm/string/split.hpp>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060032#include <boost/beast/http.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070033#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080034#include <boost/system/linux_error.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080035#include <dbus_utility.hpp>
Andrew Geisslercb92c032018-08-17 07:56:14 -070036#include <error_messages.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070037#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070038#include <registries/privilege_registry.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050039
George Liu647b3cd2021-07-05 12:43:56 +080040#include <charconv>
James Feist4418c7f2019-04-15 11:09:15 -070041#include <filesystem>
Xiaochao Ma75710de2021-01-21 17:56:02 +080042#include <optional>
Ed Tanous26702d02021-11-03 15:02:33 -070043#include <span>
Jason M. Billscd225da2019-05-08 15:31:57 -070044#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080045#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070046
47namespace redfish
48{
49
Gunnar Mills1214b7e2020-06-04 10:11:30 -050050constexpr char const* crashdumpObject = "com.intel.crashdump";
51constexpr char const* crashdumpPath = "/com/intel/crashdump";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050052constexpr char const* crashdumpInterface = "com.intel.crashdump";
53constexpr char const* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070054 "xyz.openbmc_project.Collection.DeleteAll";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050055constexpr char const* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070056 "com.intel.crashdump.OnDemand";
Kenny L. Ku6eda7682020-06-19 09:48:36 -070057constexpr char const* crashdumpTelemetryInterface =
58 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070059
Ed Tanousfffb8c12022-02-07 23:53:03 -080060namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -070061{
Ed Tanous26702d02021-11-03 15:02:33 -070062static const Message*
63 getMessageFromRegistry(const std::string& messageKey,
64 const std::span<const MessageEntry> registry)
Jason M. Bills4851d452019-03-28 11:27:48 -070065{
Ed Tanous26702d02021-11-03 15:02:33 -070066 std::span<const MessageEntry>::iterator messageIt = std::find_if(
67 registry.begin(), registry.end(),
68 [&messageKey](const MessageEntry& messageEntry) {
Ed Tanouse662eae2022-01-25 10:39:19 -080069 return std::strcmp(messageEntry.first, messageKey.c_str()) == 0;
Ed Tanous26702d02021-11-03 15:02:33 -070070 });
71 if (messageIt != registry.end())
Jason M. Bills4851d452019-03-28 11:27:48 -070072 {
73 return &messageIt->second;
74 }
75
76 return nullptr;
77}
78
Gunnar Mills1214b7e2020-06-04 10:11:30 -050079static const Message* getMessage(const std::string_view& messageID)
Jason M. Bills4851d452019-03-28 11:27:48 -070080{
81 // Redfish MessageIds are in the form
82 // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
83 // the right Message
84 std::vector<std::string> fields;
85 fields.reserve(4);
86 boost::split(fields, messageID, boost::is_any_of("."));
Gunnar Mills1214b7e2020-06-04 10:11:30 -050087 std::string& registryName = fields[0];
88 std::string& messageKey = fields[3];
Jason M. Bills4851d452019-03-28 11:27:48 -070089
90 // Find the right registry and check it for the MessageKey
91 if (std::string(base::header.registryPrefix) == registryName)
92 {
93 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -070094 messageKey, std::span<const MessageEntry>(base::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -070095 }
96 if (std::string(openbmc::header.registryPrefix) == registryName)
97 {
98 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -070099 messageKey, std::span<const MessageEntry>(openbmc::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -0700100 }
101 return nullptr;
102}
Ed Tanousfffb8c12022-02-07 23:53:03 -0800103} // namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -0700104
James Feistf6150402019-01-08 10:36:20 -0800105namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -0700106
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500107inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700108{
Ed Tanousd4d25792020-09-29 15:15:03 -0700109 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
110 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
111 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
112 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700113 {
114 return "Critical";
115 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700116 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
117 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
118 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700119 {
120 return "OK";
121 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700122 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -0700123 {
124 return "Warning";
125 }
126 return "";
127}
128
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700129inline static int getJournalMetadata(sd_journal* journal,
130 const std::string_view& field,
131 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700132{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500133 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700134 size_t length = 0;
135 int ret = 0;
136 // Get the metadata from the requested field of the journal entry
Ed Tanous46ff87b2022-01-07 09:25:51 -0800137 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
138 const void** dataVoid = reinterpret_cast<const void**>(&data);
139
140 ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700141 if (ret < 0)
142 {
143 return ret;
144 }
Ed Tanous39e77502019-03-04 17:35:53 -0800145 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700146 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000147 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700148 return ret;
149}
150
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700151inline static int getJournalMetadata(sd_journal* journal,
152 const std::string_view& field,
153 const int& base, long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700154{
155 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800156 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700157 // Get the metadata from the requested field of the journal entry
158 ret = getJournalMetadata(journal, field, metadata);
159 if (ret < 0)
160 {
161 return ret;
162 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000163 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700164 return ret;
165}
166
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700167inline static bool getEntryTimestamp(sd_journal* journal,
168 std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800169{
170 int ret = 0;
171 uint64_t timestamp = 0;
172 ret = sd_journal_get_realtime_usec(journal, &timestamp);
173 if (ret < 0)
174 {
175 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
176 << strerror(-ret);
177 return false;
178 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800179 entryTimestamp = crow::utility::getDateTimeUint(timestamp / 1000 / 1000);
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500180 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800181}
Ed Tanous50b8a432022-02-03 16:29:50 -0800182
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700183inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
184 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700185{
186 int ret = 0;
187 static uint64_t prevTs = 0;
188 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700189 if (firstEntry)
190 {
191 prevTs = 0;
192 }
193
Jason M. Bills16428a12018-11-02 12:42:29 -0700194 // Get the entry timestamp
195 uint64_t curTs = 0;
196 ret = sd_journal_get_realtime_usec(journal, &curTs);
197 if (ret < 0)
198 {
199 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
200 << strerror(-ret);
201 return false;
202 }
203 // If the timestamp isn't unique, increment the index
204 if (curTs == prevTs)
205 {
206 index++;
207 }
208 else
209 {
210 // Otherwise, reset it
211 index = 0;
212 }
213 // Save the timestamp
214 prevTs = curTs;
215
216 entryID = std::to_string(curTs);
217 if (index > 0)
218 {
219 entryID += "_" + std::to_string(index);
220 }
221 return true;
222}
223
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500224static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700225 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700226{
Ed Tanous271584a2019-07-09 16:24:22 -0700227 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700228 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700229 if (firstEntry)
230 {
231 prevTs = 0;
232 }
233
Jason M. Bills95820182019-04-22 16:25:34 -0700234 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700235 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700236 std::tm timeStruct = {};
237 std::istringstream entryStream(logEntry);
238 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
239 {
240 curTs = std::mktime(&timeStruct);
241 }
242 // If the timestamp isn't unique, increment the index
243 if (curTs == prevTs)
244 {
245 index++;
246 }
247 else
248 {
249 // Otherwise, reset it
250 index = 0;
251 }
252 // Save the timestamp
253 prevTs = curTs;
254
255 entryID = std::to_string(curTs);
256 if (index > 0)
257 {
258 entryID += "_" + std::to_string(index);
259 }
260 return true;
261}
262
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700263inline static bool
zhanghch058d1b46d2021-04-01 11:18:24 +0800264 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
265 const std::string& entryID, uint64_t& timestamp,
266 uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700267{
268 if (entryID.empty())
269 {
270 return false;
271 }
272 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800273 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700274
Ed Tanous81ce6092020-12-17 16:54:55 +0000275 auto underscorePos = tsStr.find('_');
Ed Tanous71d5d8d2022-01-25 11:04:33 -0800276 if (underscorePos != std::string_view::npos)
Jason M. Bills16428a12018-11-02 12:42:29 -0700277 {
278 // Timestamp has an index
279 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800280 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700281 indexStr.remove_prefix(underscorePos + 1);
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700282 auto [ptr, ec] = std::from_chars(
283 indexStr.data(), indexStr.data() + indexStr.size(), index);
284 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700285 {
Ed Tanousace85d62021-10-26 12:45:59 -0700286 messages::resourceMissingAtURI(
287 asyncResp->res, crow::utility::urlFromPieces(entryID));
Jason M. Bills16428a12018-11-02 12:42:29 -0700288 return false;
289 }
290 }
291 // Timestamp has no index
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700292 auto [ptr, ec] =
293 std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp);
294 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700295 {
Ed Tanousace85d62021-10-26 12:45:59 -0700296 messages::resourceMissingAtURI(asyncResp->res,
297 crow::utility::urlFromPieces(entryID));
Jason M. Bills16428a12018-11-02 12:42:29 -0700298 return false;
299 }
300 return true;
301}
302
Jason M. Bills95820182019-04-22 16:25:34 -0700303static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500304 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700305{
306 static const std::filesystem::path redfishLogDir = "/var/log";
307 static const std::string redfishLogFilename = "redfish";
308
309 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500310 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700311 std::filesystem::directory_iterator(redfishLogDir))
312 {
313 // If we find a redfish log file, save the path
314 std::string filename = dirEnt.path().filename();
315 if (boost::starts_with(filename, redfishLogFilename))
316 {
317 redfishLogFiles.emplace_back(redfishLogDir / filename);
318 }
319 }
320 // As the log files rotate, they are appended with a ".#" that is higher for
321 // the older logs. Since we don't expect more than 10 log files, we
322 // can just sort the list to get them in order from newest to oldest
323 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
324
325 return !redfishLogFiles.empty();
326}
327
zhanghch058d1b46d2021-04-01 11:18:24 +0800328inline void
329 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
330 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500331{
332 std::string dumpPath;
333 if (dumpType == "BMC")
334 {
335 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
336 }
337 else if (dumpType == "System")
338 {
339 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
340 }
341 else
342 {
343 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
344 messages::internalError(asyncResp->res);
345 return;
346 }
347
348 crow::connections::systemBus->async_method_call(
Ed Tanous711ac7a2021-12-20 09:34:41 -0800349 [asyncResp, dumpPath,
350 dumpType](const boost::system::error_code ec,
351 dbus::utility::ManagedObjectType& resp) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500352 if (ec)
353 {
354 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
355 messages::internalError(asyncResp->res);
356 return;
357 }
358
359 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
360 entriesArray = nlohmann::json::array();
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500361 std::string dumpEntryPath =
362 "/xyz/openbmc_project/dump/" +
363 std::string(boost::algorithm::to_lower_copy(dumpType)) +
364 "/entry/";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500365
366 for (auto& object : resp)
367 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500368 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500369 {
370 continue;
371 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800372 uint64_t timestamp = 0;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500373 uint64_t size = 0;
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500374 std::string dumpStatus;
375 nlohmann::json thisEntry;
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000376
377 std::string entryID = object.first.filename();
378 if (entryID.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500379 {
380 continue;
381 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500382
383 for (auto& interfaceMap : object.second)
384 {
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500385 if (interfaceMap.first ==
386 "xyz.openbmc_project.Common.Progress")
387 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800388 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500389 {
390 if (propertyMap.first == "Status")
391 {
Ed Tanous55f79e62022-01-25 11:26:16 -0800392 const auto* status = std::get_if<std::string>(
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500393 &propertyMap.second);
394 if (status == nullptr)
395 {
396 messages::internalError(asyncResp->res);
397 break;
398 }
399 dumpStatus = *status;
400 }
401 }
402 }
403 else if (interfaceMap.first ==
404 "xyz.openbmc_project.Dump.Entry")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500405 {
406
407 for (auto& propertyMap : interfaceMap.second)
408 {
409 if (propertyMap.first == "Size")
410 {
Ed Tanous55f79e62022-01-25 11:26:16 -0800411 const auto* sizePtr =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500412 std::get_if<uint64_t>(&propertyMap.second);
413 if (sizePtr == nullptr)
414 {
415 messages::internalError(asyncResp->res);
416 break;
417 }
418 size = *sizePtr;
419 break;
420 }
421 }
422 }
423 else if (interfaceMap.first ==
424 "xyz.openbmc_project.Time.EpochTime")
425 {
426
Ed Tanous9eb808c2022-01-25 10:19:23 -0800427 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500428 {
429 if (propertyMap.first == "Elapsed")
430 {
431 const uint64_t* usecsTimeStamp =
432 std::get_if<uint64_t>(&propertyMap.second);
433 if (usecsTimeStamp == nullptr)
434 {
435 messages::internalError(asyncResp->res);
436 break;
437 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800438 timestamp = (*usecsTimeStamp / 1000 / 1000);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500439 break;
440 }
441 }
442 }
443 }
444
George Liu0fda0f12021-11-16 10:06:17 +0800445 if (dumpStatus !=
446 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500447 !dumpStatus.empty())
448 {
449 // Dump status is not Complete, no need to enumerate
450 continue;
451 }
452
George Liu647b3cd2021-07-05 12:43:56 +0800453 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500454 thisEntry["@odata.id"] = dumpPath + entryID;
455 thisEntry["Id"] = entryID;
456 thisEntry["EntryType"] = "Event";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800457 thisEntry["Created"] =
458 crow::utility::getDateTimeUint(timestamp);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500459 thisEntry["Name"] = dumpType + " Dump Entry";
460
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500461 thisEntry["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500462
463 if (dumpType == "BMC")
464 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500465 thisEntry["DiagnosticDataType"] = "Manager";
466 thisEntry["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500467 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
468 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500469 }
470 else if (dumpType == "System")
471 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500472 thisEntry["DiagnosticDataType"] = "OEM";
473 thisEntry["OEMDiagnosticDataType"] = "System";
474 thisEntry["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500475 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
476 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500477 }
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500478 entriesArray.push_back(std::move(thisEntry));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500479 }
480 asyncResp->res.jsonValue["Members@odata.count"] =
481 entriesArray.size();
482 },
483 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
484 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
485}
486
zhanghch058d1b46d2021-04-01 11:18:24 +0800487inline void
Ed Tanous45ca1b82022-03-25 13:07:27 -0700488 getDumpEntryById(crow::App& app, const crow::Request& req,
489 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800490 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500491{
Ed Tanous45ca1b82022-03-25 13:07:27 -0700492 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
493 {
494 return;
495 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500496 std::string dumpPath;
497 if (dumpType == "BMC")
498 {
499 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
500 }
501 else if (dumpType == "System")
502 {
503 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
504 }
505 else
506 {
507 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
508 messages::internalError(asyncResp->res);
509 return;
510 }
511
512 crow::connections::systemBus->async_method_call(
Ed Tanous711ac7a2021-12-20 09:34:41 -0800513 [asyncResp, entryID, dumpPath,
514 dumpType](const boost::system::error_code ec,
515 dbus::utility::ManagedObjectType& resp) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500516 if (ec)
517 {
518 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
519 messages::internalError(asyncResp->res);
520 return;
521 }
522
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500523 bool foundDumpEntry = false;
524 std::string dumpEntryPath =
525 "/xyz/openbmc_project/dump/" +
526 std::string(boost::algorithm::to_lower_copy(dumpType)) +
527 "/entry/";
528
Ed Tanous9eb808c2022-01-25 10:19:23 -0800529 for (const auto& objectPath : resp)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500530 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500531 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500532 {
533 continue;
534 }
535
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500536 foundDumpEntry = true;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800537 uint64_t timestamp = 0;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500538 uint64_t size = 0;
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500539 std::string dumpStatus;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500540
Ed Tanous9eb808c2022-01-25 10:19:23 -0800541 for (const auto& interfaceMap : objectPath.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500542 {
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500543 if (interfaceMap.first ==
544 "xyz.openbmc_project.Common.Progress")
545 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800546 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500547 {
548 if (propertyMap.first == "Status")
549 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800550 const std::string* status =
551 std::get_if<std::string>(
552 &propertyMap.second);
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500553 if (status == nullptr)
554 {
555 messages::internalError(asyncResp->res);
556 break;
557 }
558 dumpStatus = *status;
559 }
560 }
561 }
562 else if (interfaceMap.first ==
563 "xyz.openbmc_project.Dump.Entry")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500564 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800565 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500566 {
567 if (propertyMap.first == "Size")
568 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800569 const uint64_t* sizePtr =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500570 std::get_if<uint64_t>(&propertyMap.second);
571 if (sizePtr == nullptr)
572 {
573 messages::internalError(asyncResp->res);
574 break;
575 }
576 size = *sizePtr;
577 break;
578 }
579 }
580 }
581 else if (interfaceMap.first ==
582 "xyz.openbmc_project.Time.EpochTime")
583 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800584 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500585 {
586 if (propertyMap.first == "Elapsed")
587 {
588 const uint64_t* usecsTimeStamp =
589 std::get_if<uint64_t>(&propertyMap.second);
590 if (usecsTimeStamp == nullptr)
591 {
592 messages::internalError(asyncResp->res);
593 break;
594 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800595 timestamp = *usecsTimeStamp / 1000 / 1000;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500596 break;
597 }
598 }
599 }
600 }
601
George Liu0fda0f12021-11-16 10:06:17 +0800602 if (dumpStatus !=
603 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500604 !dumpStatus.empty())
605 {
606 // Dump status is not Complete
607 // return not found until status is changed to Completed
608 messages::resourceNotFound(asyncResp->res,
609 dumpType + " dump", entryID);
610 return;
611 }
612
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500613 asyncResp->res.jsonValue["@odata.type"] =
George Liu647b3cd2021-07-05 12:43:56 +0800614 "#LogEntry.v1_8_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500615 asyncResp->res.jsonValue["@odata.id"] = dumpPath + entryID;
616 asyncResp->res.jsonValue["Id"] = entryID;
617 asyncResp->res.jsonValue["EntryType"] = "Event";
618 asyncResp->res.jsonValue["Created"] =
Nan Zhou1d8782e2021-11-29 22:23:18 -0800619 crow::utility::getDateTimeUint(timestamp);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500620 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
621
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500622 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500623
624 if (dumpType == "BMC")
625 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500626 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
627 asyncResp->res.jsonValue["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500628 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
629 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500630 }
631 else if (dumpType == "System")
632 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500633 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
634 asyncResp->res.jsonValue["OEMDiagnosticDataType"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500635 "System";
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500636 asyncResp->res.jsonValue["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500637 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
638 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500639 }
640 }
Ed Tanouse05aec52022-01-25 10:28:56 -0800641 if (!foundDumpEntry)
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500642 {
643 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
644 messages::internalError(asyncResp->res);
645 return;
646 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500647 },
648 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
649 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
650}
651
zhanghch058d1b46d2021-04-01 11:18:24 +0800652inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800653 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500654 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500655{
George Liu3de8d8b2021-03-22 17:49:39 +0800656 auto respHandler = [asyncResp,
657 entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500658 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
659 if (ec)
660 {
George Liu3de8d8b2021-03-22 17:49:39 +0800661 if (ec.value() == EBADR)
662 {
663 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
664 return;
665 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500666 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
667 << ec;
668 messages::internalError(asyncResp->res);
669 return;
670 }
671 };
672 crow::connections::systemBus->async_method_call(
673 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500674 "/xyz/openbmc_project/dump/" +
675 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
676 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500677 "xyz.openbmc_project.Object.Delete", "Delete");
678}
679
zhanghch058d1b46d2021-04-01 11:18:24 +0800680inline void
Ed Tanous98be3e32021-09-16 15:05:36 -0700681 createDumpTaskCallback(task::Payload&& payload,
zhanghch058d1b46d2021-04-01 11:18:24 +0800682 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
683 const uint32_t& dumpId, const std::string& dumpPath,
684 const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500685{
686 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500687 [dumpId, dumpPath, dumpType](
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500688 boost::system::error_code err, sdbusplus::message::message& m,
689 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanouscb13a392020-07-25 19:02:03 +0000690 if (err)
691 {
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500692 BMCWEB_LOG_ERROR << "Error in creating a dump";
693 taskData->state = "Cancelled";
694 return task::completed;
Ed Tanouscb13a392020-07-25 19:02:03 +0000695 }
Ed Tanousb9d36b42022-02-26 21:42:46 -0800696
697 dbus::utility::DBusInteracesMap interfacesList;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500698
699 sdbusplus::message::object_path objPath;
700
701 m.read(objPath, interfacesList);
702
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500703 if (objPath.str ==
704 "/xyz/openbmc_project/dump/" +
705 std::string(boost::algorithm::to_lower_copy(dumpType)) +
706 "/entry/" + std::to_string(dumpId))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500707 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500708 nlohmann::json retMessage = messages::success();
709 taskData->messages.emplace_back(retMessage);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500710
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500711 std::string headerLoc =
712 "Location: " + dumpPath + std::to_string(dumpId);
713 taskData->payload->httpHeaders.emplace_back(
714 std::move(headerLoc));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500715
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500716 taskData->state = "Completed";
717 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500718 }
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500719 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500720 },
Jason M. Bills4978b632022-02-22 14:17:43 -0800721 "type='signal',interface='org.freedesktop.DBus.ObjectManager',"
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500722 "member='InterfacesAdded', "
723 "path='/xyz/openbmc_project/dump'");
724
725 task->startTimer(std::chrono::minutes(3));
726 task->populateResp(asyncResp->res);
Ed Tanous98be3e32021-09-16 15:05:36 -0700727 task->payload.emplace(std::move(payload));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500728}
729
zhanghch058d1b46d2021-04-01 11:18:24 +0800730inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
731 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500732{
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500733 std::string dumpPath;
734 if (dumpType == "BMC")
735 {
736 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
737 }
738 else if (dumpType == "System")
739 {
740 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
741 }
742 else
743 {
744 BMCWEB_LOG_ERROR << "Invalid dump type: " << dumpType;
745 messages::internalError(asyncResp->res);
746 return;
747 }
748
749 std::optional<std::string> diagnosticDataType;
750 std::optional<std::string> oemDiagnosticDataType;
751
Willy Tu15ed6782021-12-14 11:03:16 -0800752 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500753 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
754 "OEMDiagnosticDataType", oemDiagnosticDataType))
755 {
756 return;
757 }
758
759 if (dumpType == "System")
760 {
761 if (!oemDiagnosticDataType || !diagnosticDataType)
762 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800763 BMCWEB_LOG_ERROR
764 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500765 messages::actionParameterMissing(
766 asyncResp->res, "CollectDiagnosticData",
767 "DiagnosticDataType & OEMDiagnosticDataType");
768 return;
769 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700770 if ((*oemDiagnosticDataType != "System") ||
771 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500772 {
773 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700774 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500775 return;
776 }
777 }
778 else if (dumpType == "BMC")
779 {
780 if (!diagnosticDataType)
781 {
George Liu0fda0f12021-11-16 10:06:17 +0800782 BMCWEB_LOG_ERROR
783 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500784 messages::actionParameterMissing(
785 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
786 return;
787 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700788 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500789 {
790 BMCWEB_LOG_ERROR
791 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700792 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500793 return;
794 }
795 }
796
797 crow::connections::systemBus->async_method_call(
Ed Tanous98be3e32021-09-16 15:05:36 -0700798 [asyncResp, payload(task::Payload(req)), dumpPath,
799 dumpType](const boost::system::error_code ec,
800 const uint32_t& dumpId) mutable {
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500801 if (ec)
802 {
803 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
804 messages::internalError(asyncResp->res);
805 return;
806 }
807 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
808
Ed Tanous98be3e32021-09-16 15:05:36 -0700809 createDumpTaskCallback(std::move(payload), asyncResp, dumpId,
810 dumpPath, dumpType);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500811 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500812 "xyz.openbmc_project.Dump.Manager",
813 "/xyz/openbmc_project/dump/" +
814 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500815 "xyz.openbmc_project.Dump.Create", "CreateDump");
816}
817
zhanghch058d1b46d2021-04-01 11:18:24 +0800818inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
819 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500820{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500821 std::string dumpTypeLowerCopy =
822 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800823
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500824 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800825 [asyncResp, dumpType](
826 const boost::system::error_code ec,
827 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500828 if (ec)
829 {
830 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
831 messages::internalError(asyncResp->res);
832 return;
833 }
834
835 for (const std::string& path : subTreePaths)
836 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000837 sdbusplus::message::object_path objPath(path);
838 std::string logID = objPath.filename();
839 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500840 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000841 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500842 }
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000843 deleteDumpEntry(asyncResp, logID, dumpType);
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500844 }
845 },
846 "xyz.openbmc_project.ObjectMapper",
847 "/xyz/openbmc_project/object_mapper",
848 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500849 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
850 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
851 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500852}
853
Ed Tanousb9d36b42022-02-26 21:42:46 -0800854inline static void
855 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
856 std::string& filename, std::string& timestamp,
857 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700858{
859 for (auto property : params)
860 {
861 if (property.first == "Timestamp")
862 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500863 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500864 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700865 if (value != nullptr)
866 {
867 timestamp = *value;
868 }
869 }
870 else if (property.first == "Filename")
871 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500872 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500873 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700874 if (value != nullptr)
875 {
876 filename = *value;
877 }
878 }
879 else if (property.first == "Log")
880 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500881 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500882 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700883 if (value != nullptr)
884 {
885 logfile = *value;
886 }
887 }
888 }
889}
890
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500891constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700892inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -0700893{
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800894 /**
895 * Functions triggers appropriate requests on DBus
896 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700897 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -0700898 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700899 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
900 const std::shared_ptr<
901 bmcweb::AsyncResp>&
902 asyncResp) {
903 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700904 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700905 return;
906 }
907 // Collections don't include the static data added by SubRoute
908 // because it has a duplicate entry for members
909 asyncResp->res.jsonValue["@odata.type"] =
910 "#LogServiceCollection.LogServiceCollection";
911 asyncResp->res.jsonValue["@odata.id"] =
912 "/redfish/v1/Systems/system/LogServices";
913 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
914 asyncResp->res.jsonValue["Description"] =
915 "Collection of LogServices for this Computer System";
916 nlohmann::json& logServiceArray =
917 asyncResp->res.jsonValue["Members"];
918 logServiceArray = nlohmann::json::array();
Ed Tanous14766872022-03-15 10:44:42 -0700919 nlohmann::json::object_t eventLog;
920 eventLog["@odata.id"] =
921 "/redfish/v1/Systems/system/LogServices/EventLog";
922 logServiceArray.push_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500923#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous14766872022-03-15 10:44:42 -0700924 nlohmann::json::object_t dumpLog;
925 eventLog["@odata.id"] =
926 "/redfish/v1/Systems/system/LogServices/Dump";
927 logServiceArray.push_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -0600928#endif
929
Jason M. Billsd53dd412019-02-12 17:16:22 -0800930#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous14766872022-03-15 10:44:42 -0700931 nlohmann::json::object_t crashdump;
932 crashdump["@odata.id"] =
933 "/redfish/v1/Systems/system/LogServices/Crashdump";
934 logServiceArray.push_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -0800935#endif
Spencer Kub7028eb2021-10-26 15:27:35 +0800936
937#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous14766872022-03-15 10:44:42 -0700938 nlohmann::json::object_t hostlogger;
939 hostlogger["@odata.id"] =
940 "/redfish/v1/Systems/system/LogServices/HostLogger";
941 logServiceArray.push_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +0800942#endif
Ed Tanous45ca1b82022-03-25 13:07:27 -0700943 asyncResp->res.jsonValue["Members@odata.count"] =
944 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800945
Ed Tanous45ca1b82022-03-25 13:07:27 -0700946 crow::connections::systemBus->async_method_call(
947 [asyncResp](const boost::system::error_code ec,
948 const dbus::utility::MapperGetSubTreePathsResponse&
949 subtreePath) {
950 if (ec)
951 {
952 BMCWEB_LOG_ERROR << ec;
953 return;
954 }
955
956 for (const auto& pathStr : subtreePath)
957 {
958 if (pathStr.find("PostCode") != std::string::npos)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700959 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700960 nlohmann::json& logServiceArrayLocal =
961 asyncResp->res.jsonValue["Members"];
962 logServiceArrayLocal.push_back(
963 {{"@odata.id",
964 "/redfish/v1/Systems/system/LogServices/PostCodes"}});
965 asyncResp->res.jsonValue["Members@odata.count"] =
966 logServiceArrayLocal.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700967 return;
968 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700969 }
970 },
971 "xyz.openbmc_project.ObjectMapper",
972 "/xyz/openbmc_project/object_mapper",
973 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
974 std::array<const char*, 1>{postCodeIface});
975 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700976}
977
978inline void requestRoutesEventLogService(App& app)
979{
980 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -0700981 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700982 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
983 const std::shared_ptr<
984 bmcweb::AsyncResp>&
985 asyncResp) {
986 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
987 {
988 return;
989 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700990 asyncResp->res.jsonValue["@odata.id"] =
991 "/redfish/v1/Systems/system/LogServices/EventLog";
992 asyncResp->res.jsonValue["@odata.type"] =
993 "#LogService.v1_1_0.LogService";
994 asyncResp->res.jsonValue["Name"] = "Event Log Service";
995 asyncResp->res.jsonValue["Description"] =
996 "System Event Log Service";
997 asyncResp->res.jsonValue["Id"] = "EventLog";
998 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +0530999
1000 std::pair<std::string, std::string> redfishDateTimeOffset =
1001 crow::utility::getDateTimeOffsetNow();
1002
1003 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1004 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1005 redfishDateTimeOffset.second;
1006
Ed Tanous14766872022-03-15 10:44:42 -07001007 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1008 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001009 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
1010
George Liu0fda0f12021-11-16 10:06:17 +08001011 {"target",
1012 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001013 });
1014}
1015
1016inline void requestRoutesJournalEventLogClear(App& app)
1017{
Jason M. Bills4978b632022-02-22 14:17:43 -08001018 BMCWEB_ROUTE(
1019 app,
1020 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001021 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001022 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001023 [&app](const crow::Request& req,
1024 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1025 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1026 {
1027 return;
1028 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001029 // Clear the EventLog by deleting the log files
1030 std::vector<std::filesystem::path> redfishLogFiles;
1031 if (getRedfishLogFiles(redfishLogFiles))
ZhikuiRena3316fc2020-01-29 14:58:08 -08001032 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001033 for (const std::filesystem::path& file : redfishLogFiles)
ZhikuiRena3316fc2020-01-29 14:58:08 -08001034 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001035 std::error_code ec;
1036 std::filesystem::remove(file, ec);
ZhikuiRena3316fc2020-01-29 14:58:08 -08001037 }
1038 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001039
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001040 // Reload rsyslog so it knows to start new log files
1041 crow::connections::systemBus->async_method_call(
1042 [asyncResp](const boost::system::error_code ec) {
1043 if (ec)
1044 {
1045 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: "
1046 << ec;
1047 messages::internalError(asyncResp->res);
1048 return;
1049 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001050
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001051 messages::success(asyncResp->res);
1052 },
1053 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1054 "org.freedesktop.systemd1.Manager", "ReloadUnit",
1055 "rsyslog.service", "replace");
1056 });
1057}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001058
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001059static int fillEventLogEntryJson(const std::string& logEntryID,
Ed Tanousb5a76932020-09-29 16:16:58 -07001060 const std::string& logEntry,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001061 nlohmann::json& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001062{
Jason M. Bills95820182019-04-22 16:25:34 -07001063 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001064 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001065 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001066 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001067 {
1068 return 1;
1069 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001070 std::string timestamp = logEntry.substr(0, space);
1071 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001072 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001073 if (entryStart == std::string::npos)
1074 {
1075 return 1;
1076 }
1077 std::string_view entry(logEntry);
1078 entry.remove_prefix(entryStart);
1079 // Use split to separate the entry into its fields
1080 std::vector<std::string> logEntryFields;
1081 boost::split(logEntryFields, entry, boost::is_any_of(","),
1082 boost::token_compress_on);
1083 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001084 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001085 {
1086 return 1;
1087 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001088 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001089
Jason M. Bills4851d452019-03-28 11:27:48 -07001090 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001091 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001092
Sui Chen54417b02022-03-24 14:59:52 -07001093 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001094 {
Sui Chen54417b02022-03-24 14:59:52 -07001095 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
1096 return 0;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001097 }
1098
Sui Chen54417b02022-03-24 14:59:52 -07001099 std::string msg = message->message;
1100
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001101 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001102 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001103 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001104 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001105 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001106 // If the first string is empty, assume there are no MessageArgs
1107 std::size_t messageArgsSize = 0;
1108 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001109 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001110 messageArgsSize = logEntryFields.size() - 1;
1111 }
1112
Ed Tanous23a21a12020-07-25 04:45:05 +00001113 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001114
1115 // Fill the MessageArgs into the Message
1116 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001117 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001118 {
1119 std::string argStr = "%" + std::to_string(++i);
1120 size_t argPos = msg.find(argStr);
1121 if (argPos != std::string::npos)
1122 {
1123 msg.replace(argPos, argStr.length(), messageArg);
1124 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001125 }
1126 }
1127
Jason M. Bills95820182019-04-22 16:25:34 -07001128 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1129 // format which matches the Redfish format except for the fractional seconds
1130 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001131 std::size_t dot = timestamp.find_first_of('.');
1132 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001133 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001134 {
Jason M. Bills95820182019-04-22 16:25:34 -07001135 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001136 }
1137
1138 // Fill in the log entry with the gathered data
Jason M. Bills95820182019-04-22 16:25:34 -07001139 logEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08001140 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Ed Tanous029573d2019-02-01 10:57:49 -08001141 {"@odata.id",
Jason M. Bills897967d2019-07-29 17:05:30 -07001142 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
Jason M. Bills95820182019-04-22 16:25:34 -07001143 logEntryID},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001144 {"Name", "System Event Log Entry"},
Jason M. Bills95820182019-04-22 16:25:34 -07001145 {"Id", logEntryID},
1146 {"Message", std::move(msg)},
1147 {"MessageId", std::move(messageID)},
Ed Tanousf23b7292020-10-15 09:41:17 -07001148 {"MessageArgs", messageArgs},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001149 {"EntryType", "Event"},
Sui Chen54417b02022-03-24 14:59:52 -07001150 {"Severity", message->messageSeverity},
Jason M. Bills95820182019-04-22 16:25:34 -07001151 {"Created", std::move(timestamp)}};
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001152 return 0;
1153}
1154
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001155inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001156{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001157 BMCWEB_ROUTE(app,
1158 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001159 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001160 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1161 const std::shared_ptr<
1162 bmcweb::AsyncResp>&
1163 asyncResp) {
Ed Tanousc937d2b2022-04-05 09:58:00 -07001164 query_param::QueryCapabilities capabilities = {
1165 .canDelegateTop = true,
1166 .canDelegateSkip = true,
1167 };
1168 query_param::Query delegatedQuery;
1169 if (!redfish::setUpRedfishRouteWithDelegation(
1170 app, req, asyncResp->res, delegatedQuery, capabilities))
Jason M. Bills4978b632022-02-22 14:17:43 -08001171 {
1172 return;
1173 }
1174 // Collections don't include the static data added by SubRoute
1175 // because it has a duplicate entry for members
1176 asyncResp->res.jsonValue["@odata.type"] =
1177 "#LogEntryCollection.LogEntryCollection";
1178 asyncResp->res.jsonValue["@odata.id"] =
1179 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1180 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1181 asyncResp->res.jsonValue["Description"] =
1182 "Collection of System Event Log Entries";
Jason M. Bills897967d2019-07-29 17:05:30 -07001183
Jason M. Bills4978b632022-02-22 14:17:43 -08001184 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1185 logEntryArray = nlohmann::json::array();
1186 // Go through the log files and create a unique ID for each
1187 // entry
1188 std::vector<std::filesystem::path> redfishLogFiles;
1189 getRedfishLogFiles(redfishLogFiles);
1190 uint64_t entryCount = 0;
1191 std::string logEntry;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001192
Jason M. Bills4978b632022-02-22 14:17:43 -08001193 // Oldest logs are in the last file, so start there and loop
1194 // backwards
1195 for (auto it = redfishLogFiles.rbegin();
1196 it < redfishLogFiles.rend(); it++)
1197 {
1198 std::ifstream logStream(*it);
1199 if (!logStream.is_open())
Andrew Geisslercb92c032018-08-17 07:56:14 -07001200 {
Jason M. Bills4978b632022-02-22 14:17:43 -08001201 continue;
1202 }
1203
1204 // Reset the unique ID on the first entry
1205 bool firstEntry = true;
1206 while (std::getline(logStream, logEntry))
1207 {
1208 entryCount++;
1209 // Handle paging using skip (number of entries to skip
1210 // from the start) and top (number of entries to
1211 // display)
Ed Tanousc937d2b2022-04-05 09:58:00 -07001212 if (entryCount <= delegatedQuery.skip ||
1213 entryCount > delegatedQuery.skip + delegatedQuery.top)
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001214 {
1215 continue;
1216 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001217
Jason M. Bills4978b632022-02-22 14:17:43 -08001218 std::string idStr;
1219 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001220 {
Jason M. Bills4978b632022-02-22 14:17:43 -08001221 continue;
1222 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001223
Jason M. Bills4978b632022-02-22 14:17:43 -08001224 if (firstEntry)
1225 {
1226 firstEntry = false;
1227 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001228
Jason M. Bills4978b632022-02-22 14:17:43 -08001229 logEntryArray.push_back({});
1230 nlohmann::json& bmcLogEntry = logEntryArray.back();
1231 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) !=
1232 0)
1233 {
1234 messages::internalError(asyncResp->res);
1235 return;
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001236 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001237 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001238 }
1239 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanousc937d2b2022-04-05 09:58:00 -07001240 if (delegatedQuery.skip + delegatedQuery.top < entryCount)
Jason M. Bills4978b632022-02-22 14:17:43 -08001241 {
1242 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1243 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanousc937d2b2022-04-05 09:58:00 -07001244 std::to_string(delegatedQuery.skip + delegatedQuery.top);
Jason M. Bills4978b632022-02-22 14:17:43 -08001245 }
1246 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001247}
Chicago Duan336e96c2019-07-15 14:22:08 +08001248
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001249inline void requestRoutesJournalEventLogEntry(App& app)
1250{
1251 BMCWEB_ROUTE(
1252 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001253 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001254 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001255 [&app](const crow::Request& req,
1256 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1257 const std::string& param) {
1258 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1259 {
1260 return;
1261 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001262 const std::string& targetID = param;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001263
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001264 // Go through the log files and check the unique ID for each
1265 // entry to find the target entry
1266 std::vector<std::filesystem::path> redfishLogFiles;
1267 getRedfishLogFiles(redfishLogFiles);
1268 std::string logEntry;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001269
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001270 // Oldest logs are in the last file, so start there and loop
1271 // backwards
1272 for (auto it = redfishLogFiles.rbegin();
1273 it < redfishLogFiles.rend(); it++)
1274 {
1275 std::ifstream logStream(*it);
1276 if (!logStream.is_open())
1277 {
1278 continue;
1279 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001280
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001281 // Reset the unique ID on the first entry
1282 bool firstEntry = true;
1283 while (std::getline(logStream, logEntry))
1284 {
1285 std::string idStr;
1286 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1287 {
1288 continue;
1289 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001290
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001291 if (firstEntry)
1292 {
1293 firstEntry = false;
1294 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001295
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001296 if (idStr == targetID)
1297 {
1298 if (fillEventLogEntryJson(
1299 idStr, logEntry,
1300 asyncResp->res.jsonValue) != 0)
1301 {
1302 messages::internalError(asyncResp->res);
1303 return;
1304 }
1305 return;
1306 }
1307 }
1308 }
1309 // Requested ID was not found
Ed Tanousace85d62021-10-26 12:45:59 -07001310 messages::resourceMissingAtURI(
1311 asyncResp->res, crow::utility::urlFromPieces(targetID));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001312 });
1313}
1314
1315inline void requestRoutesDBusEventLogEntryCollection(App& app)
1316{
1317 BMCWEB_ROUTE(app,
1318 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001319 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001320 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1321 const std::shared_ptr<
1322 bmcweb::AsyncResp>&
1323 asyncResp) {
1324 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1325 {
1326 return;
1327 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001328 // Collections don't include the static data added by SubRoute
1329 // because it has a duplicate entry for members
1330 asyncResp->res.jsonValue["@odata.type"] =
1331 "#LogEntryCollection.LogEntryCollection";
1332 asyncResp->res.jsonValue["@odata.id"] =
1333 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1334 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1335 asyncResp->res.jsonValue["Description"] =
1336 "Collection of System Event Log Entries";
1337
1338 // DBus implementation of EventLog/Entries
1339 // Make call to Logging Service to find all log entry objects
Xiaochao Ma75710de2021-01-21 17:56:02 +08001340 crow::connections::systemBus->async_method_call(
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001341 [asyncResp](const boost::system::error_code ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001342 const dbus::utility::ManagedObjectType& resp) {
Xiaochao Ma75710de2021-01-21 17:56:02 +08001343 if (ec)
1344 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001345 // TODO Handle for specific error code
1346 BMCWEB_LOG_ERROR
1347 << "getLogEntriesIfaceData resp_handler got error "
1348 << ec;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001349 messages::internalError(asyncResp->res);
1350 return;
1351 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001352 nlohmann::json& entriesArray =
1353 asyncResp->res.jsonValue["Members"];
1354 entriesArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001355 for (const auto& objectPath : resp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001356 {
Ed Tanous914e2d52022-01-07 11:38:34 -08001357 const uint32_t* id = nullptr;
Ed Tanousc419c752022-01-26 12:19:54 -08001358 const uint64_t* timestamp = nullptr;
1359 const uint64_t* updateTimestamp = nullptr;
Ed Tanous914e2d52022-01-07 11:38:34 -08001360 const std::string* severity = nullptr;
1361 const std::string* message = nullptr;
1362 const std::string* filePath = nullptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001363 bool resolved = false;
Ed Tanous9eb808c2022-01-25 10:19:23 -08001364 for (const auto& interfaceMap : objectPath.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001365 {
1366 if (interfaceMap.first ==
1367 "xyz.openbmc_project.Logging.Entry")
1368 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001369 for (const auto& propertyMap :
1370 interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001371 {
1372 if (propertyMap.first == "Id")
1373 {
1374 id = std::get_if<uint32_t>(
1375 &propertyMap.second);
1376 }
1377 else if (propertyMap.first == "Timestamp")
1378 {
Ed Tanousc419c752022-01-26 12:19:54 -08001379 timestamp = std::get_if<uint64_t>(
1380 &propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001381 }
1382 else if (propertyMap.first ==
1383 "UpdateTimestamp")
1384 {
Ed Tanousc419c752022-01-26 12:19:54 -08001385 updateTimestamp = std::get_if<uint64_t>(
1386 &propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001387 }
1388 else if (propertyMap.first == "Severity")
1389 {
1390 severity = std::get_if<std::string>(
1391 &propertyMap.second);
1392 }
1393 else if (propertyMap.first == "Message")
1394 {
1395 message = std::get_if<std::string>(
1396 &propertyMap.second);
1397 }
1398 else if (propertyMap.first == "Resolved")
1399 {
Ed Tanous914e2d52022-01-07 11:38:34 -08001400 const bool* resolveptr =
1401 std::get_if<bool>(
1402 &propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001403 if (resolveptr == nullptr)
1404 {
1405 messages::internalError(
1406 asyncResp->res);
1407 return;
1408 }
1409 resolved = *resolveptr;
1410 }
1411 }
1412 if (id == nullptr || message == nullptr ||
1413 severity == nullptr)
1414 {
1415 messages::internalError(asyncResp->res);
1416 return;
1417 }
1418 }
1419 else if (interfaceMap.first ==
1420 "xyz.openbmc_project.Common.FilePath")
1421 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001422 for (const auto& propertyMap :
1423 interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001424 {
1425 if (propertyMap.first == "Path")
1426 {
1427 filePath = std::get_if<std::string>(
1428 &propertyMap.second);
1429 }
1430 }
1431 }
1432 }
1433 // Object path without the
1434 // xyz.openbmc_project.Logging.Entry interface, ignore
1435 // and continue.
1436 if (id == nullptr || message == nullptr ||
Ed Tanousc419c752022-01-26 12:19:54 -08001437 severity == nullptr || timestamp == nullptr ||
1438 updateTimestamp == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001439 {
1440 continue;
1441 }
1442 entriesArray.push_back({});
1443 nlohmann::json& thisEntry = entriesArray.back();
1444 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
1445 thisEntry["@odata.id"] =
George Liu0fda0f12021-11-16 10:06:17 +08001446 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001447 std::to_string(*id);
1448 thisEntry["Name"] = "System Event Log Entry";
1449 thisEntry["Id"] = std::to_string(*id);
1450 thisEntry["Message"] = *message;
1451 thisEntry["Resolved"] = resolved;
1452 thisEntry["EntryType"] = "Event";
1453 thisEntry["Severity"] =
1454 translateSeverityDbusToRedfish(*severity);
1455 thisEntry["Created"] =
Ed Tanousc419c752022-01-26 12:19:54 -08001456 crow::utility::getDateTimeUintMs(*timestamp);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001457 thisEntry["Modified"] =
Ed Tanousc419c752022-01-26 12:19:54 -08001458 crow::utility::getDateTimeUintMs(*updateTimestamp);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001459 if (filePath != nullptr)
1460 {
1461 thisEntry["AdditionalDataURI"] =
George Liu0fda0f12021-11-16 10:06:17 +08001462 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001463 std::to_string(*id) + "/attachment";
1464 }
1465 }
1466 std::sort(entriesArray.begin(), entriesArray.end(),
1467 [](const nlohmann::json& left,
1468 const nlohmann::json& right) {
1469 return (left["Id"] <= right["Id"]);
1470 });
1471 asyncResp->res.jsonValue["Members@odata.count"] =
1472 entriesArray.size();
Xiaochao Ma75710de2021-01-21 17:56:02 +08001473 },
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001474 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1475 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1476 });
1477}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001478
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001479inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001480{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001481 BMCWEB_ROUTE(
1482 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001483 .privileges(redfish::privileges::getLogEntry)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001484 .methods(
1485 boost::beast::http::verb::
1486 get)([&app](const crow::Request& req,
1487 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1488 const std::string& param) {
1489 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001490 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001491 return;
1492 }
1493 std::string entryID = param;
1494 dbus::utility::escapePathForDbus(entryID);
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001495
Ed Tanous45ca1b82022-03-25 13:07:27 -07001496 // DBus implementation of EventLog/Entries
1497 // Make call to Logging Service to find all log entry objects
1498 crow::connections::systemBus->async_method_call(
1499 [asyncResp,
1500 entryID](const boost::system::error_code ec,
1501 const dbus::utility::DBusPropertiesMap& resp) {
1502 if (ec.value() == EBADR)
1503 {
1504 messages::resourceNotFound(asyncResp->res,
1505 "EventLogEntry", entryID);
1506 return;
1507 }
1508 if (ec)
1509 {
1510 BMCWEB_LOG_ERROR
1511 << "EventLogEntry (DBus) resp_handler got error "
1512 << ec;
1513 messages::internalError(asyncResp->res);
1514 return;
1515 }
1516 const uint32_t* id = nullptr;
1517 const uint64_t* timestamp = nullptr;
1518 const uint64_t* updateTimestamp = nullptr;
1519 const std::string* severity = nullptr;
1520 const std::string* message = nullptr;
1521 const std::string* filePath = nullptr;
1522 bool resolved = false;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001523
Ed Tanous45ca1b82022-03-25 13:07:27 -07001524 for (const auto& propertyMap : resp)
1525 {
1526 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001527 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001528 id = std::get_if<uint32_t>(&propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001529 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001530 else if (propertyMap.first == "Timestamp")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001531 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001532 timestamp =
1533 std::get_if<uint64_t>(&propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001534 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001535 else if (propertyMap.first == "UpdateTimestamp")
1536 {
1537 updateTimestamp =
1538 std::get_if<uint64_t>(&propertyMap.second);
1539 }
1540 else if (propertyMap.first == "Severity")
1541 {
1542 severity =
1543 std::get_if<std::string>(&propertyMap.second);
1544 }
1545 else if (propertyMap.first == "Message")
1546 {
1547 message =
1548 std::get_if<std::string>(&propertyMap.second);
1549 }
1550 else if (propertyMap.first == "Resolved")
1551 {
1552 const bool* resolveptr =
1553 std::get_if<bool>(&propertyMap.second);
1554 if (resolveptr == nullptr)
1555 {
1556 messages::internalError(asyncResp->res);
1557 return;
1558 }
1559 resolved = *resolveptr;
1560 }
1561 else if (propertyMap.first == "Path")
1562 {
1563 filePath =
1564 std::get_if<std::string>(&propertyMap.second);
1565 }
1566 }
1567 if (id == nullptr || message == nullptr ||
1568 severity == nullptr || timestamp == nullptr ||
1569 updateTimestamp == nullptr)
1570 {
1571 messages::internalError(asyncResp->res);
1572 return;
1573 }
1574 asyncResp->res.jsonValue["@odata.type"] =
1575 "#LogEntry.v1_8_0.LogEntry";
1576 asyncResp->res.jsonValue["@odata.id"] =
1577 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1578 std::to_string(*id);
1579 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1580 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1581 asyncResp->res.jsonValue["Message"] = *message;
1582 asyncResp->res.jsonValue["Resolved"] = resolved;
1583 asyncResp->res.jsonValue["EntryType"] = "Event";
1584 asyncResp->res.jsonValue["Severity"] =
1585 translateSeverityDbusToRedfish(*severity);
1586 asyncResp->res.jsonValue["Created"] =
1587 crow::utility::getDateTimeUintMs(*timestamp);
1588 asyncResp->res.jsonValue["Modified"] =
1589 crow::utility::getDateTimeUintMs(*updateTimestamp);
1590 if (filePath != nullptr)
1591 {
1592 asyncResp->res.jsonValue["AdditionalDataURI"] =
1593 "/redfish/v1/Systems/system/LogServices/EventLog/attachment/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001594 std::to_string(*id);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001595 }
1596 },
1597 "xyz.openbmc_project.Logging",
1598 "/xyz/openbmc_project/logging/entry/" + entryID,
1599 "org.freedesktop.DBus.Properties", "GetAll", "");
1600 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001601
1602 BMCWEB_ROUTE(
1603 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001604 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001605 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001606 [&app](const crow::Request& req,
1607 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1608 const std::string& entryId) {
1609 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1610 {
1611 return;
1612 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001613 std::optional<bool> resolved;
1614
Willy Tu15ed6782021-12-14 11:03:16 -08001615 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1616 resolved))
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001617 {
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001618 return;
1619 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001620 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001621
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001622 crow::connections::systemBus->async_method_call(
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001623 [asyncResp, entryId](const boost::system::error_code ec) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001624 if (ec)
1625 {
1626 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1627 messages::internalError(asyncResp->res);
1628 return;
1629 }
1630 },
1631 "xyz.openbmc_project.Logging",
1632 "/xyz/openbmc_project/logging/entry/" + entryId,
1633 "org.freedesktop.DBus.Properties", "Set",
1634 "xyz.openbmc_project.Logging.Entry", "Resolved",
Ed Tanous168e20c2021-12-13 14:39:53 -08001635 dbus::utility::DbusVariantType(*resolved));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001636 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001637
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001638 BMCWEB_ROUTE(
1639 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001640 .privileges(redfish::privileges::deleteLogEntry)
1641
Ed Tanous45ca1b82022-03-25 13:07:27 -07001642 .methods(boost::beast::http::verb::
1643 delete_)([&app](const crow::Request& req,
1644 const std::shared_ptr<bmcweb::AsyncResp>&
1645 asyncResp,
1646 const std::string& param) {
1647 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001648 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001649 return;
1650 }
1651 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001652
Ed Tanous45ca1b82022-03-25 13:07:27 -07001653 std::string entryID = param;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001654
Ed Tanous45ca1b82022-03-25 13:07:27 -07001655 dbus::utility::escapePathForDbus(entryID);
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001656
Ed Tanous45ca1b82022-03-25 13:07:27 -07001657 // Process response from Logging service.
1658 auto respHandler = [asyncResp,
1659 entryID](const boost::system::error_code ec) {
1660 BMCWEB_LOG_DEBUG
1661 << "EventLogEntry (DBus) doDelete callback: Done";
1662 if (ec)
1663 {
1664 if (ec.value() == EBADR)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001665 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001666 messages::resourceNotFound(asyncResp->res, "LogEntry",
1667 entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001668 return;
1669 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001670 // TODO Handle for specific error code
1671 BMCWEB_LOG_ERROR
1672 << "EventLogEntry (DBus) doDelete respHandler got error "
1673 << ec;
1674 asyncResp->res.result(
1675 boost::beast::http::status::internal_server_error);
1676 return;
1677 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001678
Ed Tanous45ca1b82022-03-25 13:07:27 -07001679 asyncResp->res.result(boost::beast::http::status::ok);
1680 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001681
Ed Tanous45ca1b82022-03-25 13:07:27 -07001682 // Make call to Logging service to request Delete Log
1683 crow::connections::systemBus->async_method_call(
1684 respHandler, "xyz.openbmc_project.Logging",
1685 "/xyz/openbmc_project/logging/entry/" + entryID,
1686 "xyz.openbmc_project.Object.Delete", "Delete");
1687 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001688}
1689
1690inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001691{
George Liu0fda0f12021-11-16 10:06:17 +08001692 BMCWEB_ROUTE(
1693 app,
1694 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001695 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001696 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001697 [&app](const crow::Request& req,
1698 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1699 const std::string& param) {
1700 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1701 {
1702 return;
1703 }
George Liu647b3cd2021-07-05 12:43:56 +08001704 if (!http_helpers::isOctetAccepted(
1705 req.getHeaderValue("Accept")))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001706 {
1707 asyncResp->res.result(
1708 boost::beast::http::status::bad_request);
1709 return;
1710 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001711
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001712 std::string entryID = param;
1713 dbus::utility::escapePathForDbus(entryID);
1714
1715 crow::connections::systemBus->async_method_call(
1716 [asyncResp,
1717 entryID](const boost::system::error_code ec,
1718 const sdbusplus::message::unix_fd& unixfd) {
1719 if (ec.value() == EBADR)
1720 {
1721 messages::resourceNotFound(
1722 asyncResp->res, "EventLogAttachment", entryID);
1723 return;
1724 }
1725 if (ec)
1726 {
1727 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1728 messages::internalError(asyncResp->res);
1729 return;
1730 }
1731
1732 int fd = -1;
1733 fd = dup(unixfd);
1734 if (fd == -1)
1735 {
1736 messages::internalError(asyncResp->res);
1737 return;
1738 }
1739
1740 long long int size = lseek(fd, 0, SEEK_END);
1741 if (size == -1)
1742 {
1743 messages::internalError(asyncResp->res);
1744 return;
1745 }
1746
1747 // Arbitrary max size of 64kb
1748 constexpr int maxFileSize = 65536;
1749 if (size > maxFileSize)
1750 {
1751 BMCWEB_LOG_ERROR
1752 << "File size exceeds maximum allowed size of "
1753 << maxFileSize;
1754 messages::internalError(asyncResp->res);
1755 return;
1756 }
1757 std::vector<char> data(static_cast<size_t>(size));
1758 long long int rc = lseek(fd, 0, SEEK_SET);
1759 if (rc == -1)
1760 {
1761 messages::internalError(asyncResp->res);
1762 return;
1763 }
1764 rc = read(fd, data.data(), data.size());
1765 if ((rc == -1) || (rc != size))
1766 {
1767 messages::internalError(asyncResp->res);
1768 return;
1769 }
1770 close(fd);
1771
1772 std::string_view strData(data.data(), data.size());
1773 std::string output =
1774 crow::utility::base64encode(strData);
1775
1776 asyncResp->res.addHeader("Content-Type",
1777 "application/octet-stream");
1778 asyncResp->res.addHeader("Content-Transfer-Encoding",
1779 "Base64");
1780 asyncResp->res.body() = std::move(output);
1781 },
1782 "xyz.openbmc_project.Logging",
1783 "/xyz/openbmc_project/logging/entry/" + entryID,
1784 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1785 });
1786}
1787
Spencer Kub7028eb2021-10-26 15:27:35 +08001788constexpr const char* hostLoggerFolderPath = "/var/log/console";
1789
1790inline bool
1791 getHostLoggerFiles(const std::string& hostLoggerFilePath,
1792 std::vector<std::filesystem::path>& hostLoggerFiles)
1793{
1794 std::error_code ec;
1795 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1796 if (ec)
1797 {
1798 BMCWEB_LOG_ERROR << ec.message();
1799 return false;
1800 }
1801 for (const std::filesystem::directory_entry& it : logPath)
1802 {
1803 std::string filename = it.path().filename();
1804 // Prefix of each log files is "log". Find the file and save the
1805 // path
1806 if (boost::starts_with(filename, "log"))
1807 {
1808 hostLoggerFiles.emplace_back(it.path());
1809 }
1810 }
1811 // As the log files rotate, they are appended with a ".#" that is higher for
1812 // the older logs. Since we start from oldest logs, sort the name in
1813 // descending order.
1814 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1815 AlphanumLess<std::string>());
1816
1817 return true;
1818}
1819
1820inline bool
1821 getHostLoggerEntries(std::vector<std::filesystem::path>& hostLoggerFiles,
Ed Tanousc937d2b2022-04-05 09:58:00 -07001822 uint64_t skip, uint64_t top,
Spencer Kub7028eb2021-10-26 15:27:35 +08001823 std::vector<std::string>& logEntries, size_t& logCount)
1824{
1825 GzFileReader logFile;
1826
1827 // Go though all log files and expose host logs.
1828 for (const std::filesystem::path& it : hostLoggerFiles)
1829 {
1830 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
1831 {
1832 BMCWEB_LOG_ERROR << "fail to expose host logs";
1833 return false;
1834 }
1835 }
1836 // Get lastMessage from constructor by getter
1837 std::string lastMessage = logFile.getLastMessage();
1838 if (!lastMessage.empty())
1839 {
1840 logCount++;
1841 if (logCount > skip && logCount <= (skip + top))
1842 {
1843 logEntries.push_back(lastMessage);
1844 }
1845 }
1846 return true;
1847}
1848
1849inline void fillHostLoggerEntryJson(const std::string& logEntryID,
1850 const std::string& msg,
1851 nlohmann::json& logEntryJson)
1852{
1853 // Fill in the log entry with the gathered data.
1854 logEntryJson = {
1855 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
1856 {"@odata.id",
1857 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
1858 logEntryID},
1859 {"Name", "Host Logger Entry"},
1860 {"Id", logEntryID},
1861 {"Message", msg},
1862 {"EntryType", "Oem"},
1863 {"Severity", "OK"},
1864 {"OemRecordFormat", "Host Logger Entry"}};
1865}
1866
1867inline void requestRoutesSystemHostLogger(App& app)
1868{
1869 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/HostLogger/")
1870 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07001871 .methods(boost::beast::http::verb::get)(
1872 [&app](const crow::Request& req,
1873 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1874 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1875 {
1876 return;
1877 }
1878 asyncResp->res.jsonValue["@odata.id"] =
1879 "/redfish/v1/Systems/system/LogServices/HostLogger";
1880 asyncResp->res.jsonValue["@odata.type"] =
1881 "#LogService.v1_1_0.LogService";
1882 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
1883 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
1884 asyncResp->res.jsonValue["Id"] = "HostLogger";
1885 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1886 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1887 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001888}
1889
1890inline void requestRoutesSystemHostLoggerCollection(App& app)
1891{
1892 BMCWEB_ROUTE(app,
1893 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/")
1894 .privileges(redfish::privileges::getLogEntry)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001895 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1896 const std::shared_ptr<
1897 bmcweb::AsyncResp>&
1898 asyncResp) {
Ed Tanousc937d2b2022-04-05 09:58:00 -07001899 query_param::QueryCapabilities capabilities = {
1900 .canDelegateTop = true,
1901 .canDelegateSkip = true,
1902 };
1903 query_param::Query delegatedQuery;
1904 if (!redfish::setUpRedfishRouteWithDelegation(
1905 app, req, asyncResp->res, delegatedQuery, capabilities))
George Liu0fda0f12021-11-16 10:06:17 +08001906 {
1907 return;
1908 }
1909 asyncResp->res.jsonValue["@odata.id"] =
1910 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1911 asyncResp->res.jsonValue["@odata.type"] =
1912 "#LogEntryCollection.LogEntryCollection";
1913 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
1914 asyncResp->res.jsonValue["Description"] =
1915 "Collection of HostLogger Entries";
1916 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1917 logEntryArray = nlohmann::json::array();
1918 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08001919
George Liu0fda0f12021-11-16 10:06:17 +08001920 std::vector<std::filesystem::path> hostLoggerFiles;
1921 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1922 {
1923 BMCWEB_LOG_ERROR << "fail to get host log file path";
1924 return;
1925 }
1926
1927 size_t logCount = 0;
1928 // This vector only store the entries we want to expose that
1929 // control by skip and top.
1930 std::vector<std::string> logEntries;
Ed Tanousc937d2b2022-04-05 09:58:00 -07001931 if (!getHostLoggerEntries(hostLoggerFiles, delegatedQuery.skip,
1932 delegatedQuery.top, logEntries, logCount))
George Liu0fda0f12021-11-16 10:06:17 +08001933 {
1934 messages::internalError(asyncResp->res);
1935 return;
1936 }
1937 // If vector is empty, that means skip value larger than total
1938 // log count
Ed Tanous26f69762022-01-25 09:49:11 -08001939 if (logEntries.empty())
George Liu0fda0f12021-11-16 10:06:17 +08001940 {
1941 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1942 return;
1943 }
Ed Tanous26f69762022-01-25 09:49:11 -08001944 if (!logEntries.empty())
George Liu0fda0f12021-11-16 10:06:17 +08001945 {
1946 for (size_t i = 0; i < logEntries.size(); i++)
Spencer Kub7028eb2021-10-26 15:27:35 +08001947 {
George Liu0fda0f12021-11-16 10:06:17 +08001948 logEntryArray.push_back({});
1949 nlohmann::json& hostLogEntry = logEntryArray.back();
Ed Tanousc937d2b2022-04-05 09:58:00 -07001950 fillHostLoggerEntryJson(
1951 std::to_string(delegatedQuery.skip + i), logEntries[i],
1952 hostLogEntry);
Spencer Kub7028eb2021-10-26 15:27:35 +08001953 }
1954
George Liu0fda0f12021-11-16 10:06:17 +08001955 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanousc937d2b2022-04-05 09:58:00 -07001956 if (delegatedQuery.skip + delegatedQuery.top < logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08001957 {
George Liu0fda0f12021-11-16 10:06:17 +08001958 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1959 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanousc937d2b2022-04-05 09:58:00 -07001960 std::to_string(delegatedQuery.skip +
1961 delegatedQuery.top);
Spencer Kub7028eb2021-10-26 15:27:35 +08001962 }
George Liu0fda0f12021-11-16 10:06:17 +08001963 }
1964 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001965}
1966
1967inline void requestRoutesSystemHostLoggerLogEntry(App& app)
1968{
1969 BMCWEB_ROUTE(
1970 app, "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/<str>/")
1971 .privileges(redfish::privileges::getLogEntry)
1972 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001973 [&app](const crow::Request& req,
1974 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1975 const std::string& param) {
1976 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1977 {
1978 return;
1979 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001980 const std::string& targetID = param;
1981
1982 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08001983
1984 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1985 const char* end = targetID.data() + targetID.size();
1986
1987 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
Spencer Kub7028eb2021-10-26 15:27:35 +08001988 if (ec == std::errc::invalid_argument)
1989 {
Ed Tanousace85d62021-10-26 12:45:59 -07001990 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
Spencer Kub7028eb2021-10-26 15:27:35 +08001991 return;
1992 }
1993 if (ec == std::errc::result_out_of_range)
1994 {
Ed Tanousace85d62021-10-26 12:45:59 -07001995 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
Spencer Kub7028eb2021-10-26 15:27:35 +08001996 return;
1997 }
1998
1999 std::vector<std::filesystem::path> hostLoggerFiles;
2000 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2001 {
2002 BMCWEB_LOG_ERROR << "fail to get host log file path";
2003 return;
2004 }
2005
2006 size_t logCount = 0;
2007 uint64_t top = 1;
2008 std::vector<std::string> logEntries;
2009 // We can get specific entry by skip and top. For example, if we
2010 // want to get nth entry, we can set skip = n-1 and top = 1 to
2011 // get that entry
2012 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top,
2013 logEntries, logCount))
2014 {
2015 messages::internalError(asyncResp->res);
2016 return;
2017 }
2018
2019 if (!logEntries.empty())
2020 {
2021 fillHostLoggerEntryJson(targetID, logEntries[0],
2022 asyncResp->res.jsonValue);
2023 return;
2024 }
2025
2026 // Requested ID was not found
Ed Tanousace85d62021-10-26 12:45:59 -07002027 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
Spencer Kub7028eb2021-10-26 15:27:35 +08002028 });
2029}
2030
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002031inline void requestRoutesBMCLogServiceCollection(App& app)
2032{
2033 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002034 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002035 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002036 [&app](const crow::Request& req,
2037 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2038 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2039 {
2040 return;
2041 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002042 // Collections don't include the static data added by SubRoute
2043 // because it has a duplicate entry for members
2044 asyncResp->res.jsonValue["@odata.type"] =
2045 "#LogServiceCollection.LogServiceCollection";
2046 asyncResp->res.jsonValue["@odata.id"] =
2047 "/redfish/v1/Managers/bmc/LogServices";
2048 asyncResp->res.jsonValue["Name"] =
2049 "Open BMC Log Services Collection";
2050 asyncResp->res.jsonValue["Description"] =
2051 "Collection of LogServices for this Manager";
2052 nlohmann::json& logServiceArray =
2053 asyncResp->res.jsonValue["Members"];
2054 logServiceArray = nlohmann::json::array();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002055#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002056 logServiceArray.push_back(
2057 {{"@odata.id",
2058 "/redfish/v1/Managers/bmc/LogServices/Dump"}});
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002059#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002060#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002061 logServiceArray.push_back(
2062 {{"@odata.id",
2063 "/redfish/v1/Managers/bmc/LogServices/Journal"}});
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002064#endif
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002065 asyncResp->res.jsonValue["Members@odata.count"] =
2066 logServiceArray.size();
2067 });
2068}
Ed Tanous1da66f72018-07-27 16:13:37 -07002069
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002070inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002071{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002072 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002073 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002074 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002075 [&app](const crow::Request& req,
2076 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2077 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2078 {
2079 return;
2080 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002081 asyncResp->res.jsonValue["@odata.type"] =
2082 "#LogService.v1_1_0.LogService";
2083 asyncResp->res.jsonValue["@odata.id"] =
2084 "/redfish/v1/Managers/bmc/LogServices/Journal";
2085 asyncResp->res.jsonValue["Name"] =
2086 "Open BMC Journal Log Service";
2087 asyncResp->res.jsonValue["Description"] =
2088 "BMC Journal Log Service";
2089 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2090 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302091
2092 std::pair<std::string, std::string> redfishDateTimeOffset =
2093 crow::utility::getDateTimeOffsetNow();
2094 asyncResp->res.jsonValue["DateTime"] =
2095 redfishDateTimeOffset.first;
2096 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2097 redfishDateTimeOffset.second;
2098
Ed Tanous14766872022-03-15 10:44:42 -07002099 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2100 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002101 });
2102}
Jason M. Billse1f26342018-07-18 12:12:00 -07002103
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002104static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2105 sd_journal* journal,
2106 nlohmann::json& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002107{
2108 // Get the Log Entry contents
2109 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002110
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002111 std::string message;
2112 std::string_view syslogID;
2113 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2114 if (ret < 0)
2115 {
2116 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2117 << strerror(-ret);
2118 }
2119 if (!syslogID.empty())
2120 {
2121 message += std::string(syslogID) + ": ";
2122 }
2123
Ed Tanous39e77502019-03-04 17:35:53 -08002124 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002125 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002126 if (ret < 0)
2127 {
2128 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2129 return 1;
2130 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002131 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002132
2133 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002134 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002135 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002136 if (ret < 0)
2137 {
2138 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002139 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002140
2141 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002142 std::string entryTimeStr;
2143 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002144 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002145 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002146 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002147
2148 // Fill in the log entry with the gathered data
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002149 bmcJournalLogEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08002150 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002151 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2152 bmcJournalLogEntryID},
Jason M. Billse1f26342018-07-18 12:12:00 -07002153 {"Name", "BMC Journal Entry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002154 {"Id", bmcJournalLogEntryID},
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002155 {"Message", std::move(message)},
Jason M. Billse1f26342018-07-18 12:12:00 -07002156 {"EntryType", "Oem"},
Patrick Williams738c1e62021-02-22 17:14:25 -06002157 {"Severity", severity <= 2 ? "Critical"
2158 : severity <= 4 ? "Warning"
2159 : "OK"},
Ed Tanous086be232019-05-23 11:47:09 -07002160 {"OemRecordFormat", "BMC Journal Entry"},
Jason M. Billse1f26342018-07-18 12:12:00 -07002161 {"Created", std::move(entryTimeStr)}};
2162 return 0;
2163}
2164
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002165inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002166{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002167 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002168 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002169 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2170 const std::shared_ptr<
2171 bmcweb::AsyncResp>&
2172 asyncResp) {
Ed Tanousc937d2b2022-04-05 09:58:00 -07002173 query_param::QueryCapabilities capabilities = {
2174 .canDelegateTop = true,
2175 .canDelegateSkip = true,
2176 };
2177 query_param::Query delegatedQuery;
2178 if (!redfish::setUpRedfishRouteWithDelegation(
2179 app, req, asyncResp->res, delegatedQuery, capabilities))
George Liu0fda0f12021-11-16 10:06:17 +08002180 {
2181 return;
2182 }
2183 // Collections don't include the static data added by SubRoute
2184 // because it has a duplicate entry for members
2185 asyncResp->res.jsonValue["@odata.type"] =
2186 "#LogEntryCollection.LogEntryCollection";
2187 asyncResp->res.jsonValue["@odata.id"] =
2188 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2189 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2190 asyncResp->res.jsonValue["Description"] =
2191 "Collection of BMC Journal Entries";
2192 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2193 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002194
George Liu0fda0f12021-11-16 10:06:17 +08002195 // Go through the journal and use the timestamp to create a
2196 // unique ID for each entry
2197 sd_journal* journalTmp = nullptr;
2198 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2199 if (ret < 0)
2200 {
2201 BMCWEB_LOG_ERROR << "failed to open journal: "
2202 << strerror(-ret);
2203 messages::internalError(asyncResp->res);
2204 return;
2205 }
2206 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2207 journalTmp, sd_journal_close);
2208 journalTmp = nullptr;
2209 uint64_t entryCount = 0;
2210 // Reset the unique ID on the first entry
2211 bool firstEntry = true;
2212 SD_JOURNAL_FOREACH(journal.get())
2213 {
2214 entryCount++;
2215 // Handle paging using skip (number of entries to skip from
2216 // the start) and top (number of entries to display)
Ed Tanousc937d2b2022-04-05 09:58:00 -07002217 if (entryCount <= delegatedQuery.skip ||
2218 entryCount > delegatedQuery.skip + delegatedQuery.top)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002219 {
George Liu0fda0f12021-11-16 10:06:17 +08002220 continue;
2221 }
2222
2223 std::string idStr;
2224 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2225 {
2226 continue;
2227 }
2228
2229 if (firstEntry)
2230 {
2231 firstEntry = false;
2232 }
2233
2234 logEntryArray.push_back({});
2235 nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
2236 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2237 bmcJournalLogEntry) != 0)
2238 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002239 messages::internalError(asyncResp->res);
2240 return;
2241 }
George Liu0fda0f12021-11-16 10:06:17 +08002242 }
2243 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanousc937d2b2022-04-05 09:58:00 -07002244 if (delegatedQuery.skip + delegatedQuery.top < entryCount)
George Liu0fda0f12021-11-16 10:06:17 +08002245 {
2246 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2247 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanousc937d2b2022-04-05 09:58:00 -07002248 std::to_string(delegatedQuery.skip + delegatedQuery.top);
George Liu0fda0f12021-11-16 10:06:17 +08002249 }
2250 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002251}
Jason M. Billse1f26342018-07-18 12:12:00 -07002252
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002253inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002254{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002255 BMCWEB_ROUTE(app,
2256 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002257 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002258 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002259 [&app](const crow::Request& req,
2260 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2261 const std::string& entryID) {
2262 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2263 {
2264 return;
2265 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002266 // Convert the unique ID back to a timestamp to find the entry
2267 uint64_t ts = 0;
2268 uint64_t index = 0;
2269 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2270 {
2271 return;
2272 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002273
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002274 sd_journal* journalTmp = nullptr;
2275 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2276 if (ret < 0)
2277 {
2278 BMCWEB_LOG_ERROR << "failed to open journal: "
2279 << strerror(-ret);
2280 messages::internalError(asyncResp->res);
2281 return;
2282 }
2283 std::unique_ptr<sd_journal, decltype(&sd_journal_close)>
2284 journal(journalTmp, sd_journal_close);
2285 journalTmp = nullptr;
2286 // Go to the timestamp in the log and move to the entry at the
2287 // index tracking the unique ID
2288 std::string idStr;
2289 bool firstEntry = true;
2290 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2291 if (ret < 0)
2292 {
2293 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2294 << strerror(-ret);
2295 messages::internalError(asyncResp->res);
2296 return;
2297 }
2298 for (uint64_t i = 0; i <= index; i++)
2299 {
2300 sd_journal_next(journal.get());
2301 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2302 {
2303 messages::internalError(asyncResp->res);
2304 return;
2305 }
2306 if (firstEntry)
2307 {
2308 firstEntry = false;
2309 }
2310 }
2311 // Confirm that the entry ID matches what was requested
2312 if (idStr != entryID)
2313 {
Ed Tanousace85d62021-10-26 12:45:59 -07002314 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002315 return;
2316 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002317
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002318 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2319 asyncResp->res.jsonValue) != 0)
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002320 {
2321 messages::internalError(asyncResp->res);
2322 return;
2323 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002324 });
2325}
2326
2327inline void requestRoutesBMCDumpService(App& app)
2328{
2329 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002330 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002331 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2332 const std::shared_ptr<
2333 bmcweb::AsyncResp>&
2334 asyncResp) {
2335 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2336 {
2337 return;
2338 }
George Liu0fda0f12021-11-16 10:06:17 +08002339 asyncResp->res.jsonValue["@odata.id"] =
2340 "/redfish/v1/Managers/bmc/LogServices/Dump";
2341 asyncResp->res.jsonValue["@odata.type"] =
2342 "#LogService.v1_2_0.LogService";
2343 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2344 asyncResp->res.jsonValue["Description"] = "BMC Dump LogService";
2345 asyncResp->res.jsonValue["Id"] = "Dump";
2346 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302347
George Liu0fda0f12021-11-16 10:06:17 +08002348 std::pair<std::string, std::string> redfishDateTimeOffset =
2349 crow::utility::getDateTimeOffsetNow();
2350 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2351 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2352 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302353
Ed Tanous14766872022-03-15 10:44:42 -07002354 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2355 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2356 asyncResp->res
2357 .jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2358 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog";
2359 asyncResp->res
2360 .jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2361 ["target"] =
2362 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData";
George Liu0fda0f12021-11-16 10:06:17 +08002363 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002364}
2365
2366inline void requestRoutesBMCDumpEntryCollection(App& app)
2367{
2368
2369 /**
2370 * Functions triggers appropriate requests on DBus
2371 */
2372 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002373 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002374 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002375 [&app](const crow::Request& req,
2376 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2377 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2378 {
2379 return;
2380 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002381 asyncResp->res.jsonValue["@odata.type"] =
2382 "#LogEntryCollection.LogEntryCollection";
2383 asyncResp->res.jsonValue["@odata.id"] =
2384 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2385 asyncResp->res.jsonValue["Name"] = "BMC Dump Entries";
2386 asyncResp->res.jsonValue["Description"] =
2387 "Collection of BMC Dump Entries";
2388
2389 getDumpEntryCollection(asyncResp, "BMC");
2390 });
2391}
2392
2393inline void requestRoutesBMCDumpEntry(App& app)
2394{
2395 BMCWEB_ROUTE(app,
2396 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002397 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002398 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002399 [&app](const crow::Request& req,
2400 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2401 const std::string& param) {
2402 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2403 {
2404 return;
2405 }
2406
2407 getDumpEntryById(app, req, asyncResp, param, "BMC");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002408 });
2409 BMCWEB_ROUTE(app,
2410 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002411 .privileges(redfish::privileges::deleteLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002412 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002413 [&app](const crow::Request& req,
2414 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2415 const std::string& param) {
2416 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2417 {
2418 return;
2419 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002420 deleteDumpEntry(asyncResp, param, "bmc");
2421 });
2422}
2423
2424inline void requestRoutesBMCDumpCreate(App& app)
2425{
George Liu0fda0f12021-11-16 10:06:17 +08002426 BMCWEB_ROUTE(
2427 app,
2428 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002429 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002430 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002431 [&app](const crow::Request& req,
2432 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2433 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2434 {
2435 return;
2436 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002437 createDump(asyncResp, req, "BMC");
2438 });
2439}
2440
2441inline void requestRoutesBMCDumpClear(App& app)
2442{
George Liu0fda0f12021-11-16 10:06:17 +08002443 BMCWEB_ROUTE(
2444 app,
2445 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002446 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002447 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002448 [&app](const crow::Request& req,
2449 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2450 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2451 {
2452 return;
2453 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002454 clearDump(asyncResp, "BMC");
2455 });
2456}
2457
2458inline void requestRoutesSystemDumpService(App& app)
2459{
2460 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002461 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002462 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2463 const std::shared_ptr<
2464 bmcweb::AsyncResp>&
2465 asyncResp) {
2466 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002467 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07002468 return;
2469 }
2470 asyncResp->res.jsonValue["@odata.id"] =
2471 "/redfish/v1/Systems/system/LogServices/Dump";
2472 asyncResp->res.jsonValue["@odata.type"] =
2473 "#LogService.v1_2_0.LogService";
2474 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2475 asyncResp->res.jsonValue["Description"] = "System Dump LogService";
2476 asyncResp->res.jsonValue["Id"] = "Dump";
2477 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302478
Ed Tanous45ca1b82022-03-25 13:07:27 -07002479 std::pair<std::string, std::string> redfishDateTimeOffset =
2480 crow::utility::getDateTimeOffsetNow();
2481 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2482 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2483 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302484
Ed Tanous14766872022-03-15 10:44:42 -07002485 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2486 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2487 asyncResp->res
2488 .jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2489 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog";
2490
2491 asyncResp->res
2492 .jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2493 ["target"] =
2494 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData";
Ed Tanous45ca1b82022-03-25 13:07:27 -07002495 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002496}
2497
2498inline void requestRoutesSystemDumpEntryCollection(App& app)
2499{
2500
2501 /**
2502 * Functions triggers appropriate requests on DBus
2503 */
Asmitha Karunanithib2a32892021-07-13 11:56:15 -05002504 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002505 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002506 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002507 [&app](const crow::Request& req,
2508 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2509 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2510 {
2511 return;
2512 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002513 asyncResp->res.jsonValue["@odata.type"] =
2514 "#LogEntryCollection.LogEntryCollection";
2515 asyncResp->res.jsonValue["@odata.id"] =
2516 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2517 asyncResp->res.jsonValue["Name"] = "System Dump Entries";
2518 asyncResp->res.jsonValue["Description"] =
2519 "Collection of System Dump Entries";
2520
2521 getDumpEntryCollection(asyncResp, "System");
2522 });
2523}
2524
2525inline void requestRoutesSystemDumpEntry(App& app)
2526{
2527 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002528 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002529 .privileges(redfish::privileges::getLogEntry)
2530
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002531 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002532 [&app](const crow::Request& req,
2533 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2534 const std::string& param) {
2535 getDumpEntryById(app, req, asyncResp, param, "System");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002536 });
2537
2538 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002539 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002540 .privileges(redfish::privileges::deleteLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002541 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002542 [&app](const crow::Request& req,
2543 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2544 const std::string& param) {
2545 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2546 {
2547 return;
2548 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002549 deleteDumpEntry(asyncResp, param, "system");
2550 });
2551}
2552
2553inline void requestRoutesSystemDumpCreate(App& app)
2554{
George Liu0fda0f12021-11-16 10:06:17 +08002555 BMCWEB_ROUTE(
2556 app,
2557 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002558 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002559 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002560 [&app](const crow::Request& req,
2561 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2562 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2563 {
2564 return;
2565 }
2566 createDump(asyncResp, req, "System");
2567 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002568}
2569
2570inline void requestRoutesSystemDumpClear(App& app)
2571{
George Liu0fda0f12021-11-16 10:06:17 +08002572 BMCWEB_ROUTE(
2573 app,
2574 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002575 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002576 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002577 [&app](const crow::Request& req,
2578 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002579
Ed Tanous45ca1b82022-03-25 13:07:27 -07002580 {
2581 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2582 {
2583 return;
2584 }
2585 clearDump(asyncResp, "System");
2586 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002587}
2588
2589inline void requestRoutesCrashdumpService(App& app)
2590{
2591 // Note: Deviated from redfish privilege registry for GET & HEAD
2592 // method for security reasons.
2593 /**
2594 * Functions triggers appropriate requests on DBus
2595 */
2596 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002597 // This is incorrect, should be:
2598 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002599 .privileges({{"ConfigureManager"}})
Ed Tanous45ca1b82022-03-25 13:07:27 -07002600 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2601 const std::shared_ptr<
2602 bmcweb::AsyncResp>&
2603 asyncResp) {
2604 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2605 {
2606 return;
2607 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002608 // Copy over the static data to include the entries added by
2609 // SubRoute
2610 asyncResp->res.jsonValue["@odata.id"] =
2611 "/redfish/v1/Systems/system/LogServices/Crashdump";
2612 asyncResp->res.jsonValue["@odata.type"] =
2613 "#LogService.v1_2_0.LogService";
2614 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2615 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2616 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2617 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2618 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302619
2620 std::pair<std::string, std::string> redfishDateTimeOffset =
2621 crow::utility::getDateTimeOffsetNow();
2622 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2623 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2624 redfishDateTimeOffset.second;
2625
Ed Tanous14766872022-03-15 10:44:42 -07002626 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2627 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2628 asyncResp->res
2629 .jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2630 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
2631 asyncResp->res
2632 .jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2633 ["target"] =
2634 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002635 });
2636}
2637
2638void inline requestRoutesCrashdumpClear(App& app)
2639{
George Liu0fda0f12021-11-16 10:06:17 +08002640 BMCWEB_ROUTE(
2641 app,
2642 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002643 // This is incorrect, should be:
2644 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002645 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002646 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002647 [&app](const crow::Request& req,
2648 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2649 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2650 {
2651 return;
2652 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002653 crow::connections::systemBus->async_method_call(
2654 [asyncResp](const boost::system::error_code ec,
2655 const std::string&) {
2656 if (ec)
2657 {
2658 messages::internalError(asyncResp->res);
2659 return;
2660 }
2661 messages::success(asyncResp->res);
2662 },
2663 crashdumpObject, crashdumpPath, deleteAllInterface,
2664 "DeleteAll");
2665 });
2666}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002667
zhanghch058d1b46d2021-04-01 11:18:24 +08002668static void
2669 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2670 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002671{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002672 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08002673 [asyncResp, logID,
2674 &logEntryJson](const boost::system::error_code ec,
2675 const dbus::utility::DBusPropertiesMap& params) {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002676 if (ec)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002677 {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002678 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2679 if (ec.value() ==
2680 boost::system::linux_error::bad_request_descriptor)
2681 {
2682 messages::resourceNotFound(asyncResp->res, "LogEntry",
2683 logID);
2684 }
2685 else
2686 {
2687 messages::internalError(asyncResp->res);
2688 }
2689 return;
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002690 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002691
Johnathan Mantey043a0532020-03-10 17:15:28 -07002692 std::string timestamp{};
2693 std::string filename{};
2694 std::string logfile{};
Ed Tanous2c70f802020-09-28 14:29:23 -07002695 parseCrashdumpParameters(params, filename, timestamp, logfile);
Johnathan Mantey043a0532020-03-10 17:15:28 -07002696
2697 if (filename.empty() || timestamp.empty())
2698 {
Ed Tanousace85d62021-10-26 12:45:59 -07002699 messages::resourceMissingAtURI(
2700 asyncResp->res, crow::utility::urlFromPieces(logID));
Johnathan Mantey043a0532020-03-10 17:15:28 -07002701 return;
2702 }
2703
2704 std::string crashdumpURI =
2705 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2706 logID + "/" + filename;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002707 nlohmann::json logEntry = {
Jason M. Bills4978b632022-02-22 14:17:43 -08002708 {"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
2709 {"@odata.id",
2710 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2711 logID},
2712 {"Name", "CPU Crashdump"},
2713 {"Id", logID},
2714 {"EntryType", "Oem"},
2715 {"AdditionalDataURI", std::move(crashdumpURI)},
2716 {"DiagnosticDataType", "OEM"},
2717 {"OEMDiagnosticDataType", "PECICrashdump"},
2718 {"Created", std::move(timestamp)}};
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002719
2720 // If logEntryJson references an array of LogEntry resources
2721 // ('Members' list), then push this as a new entry, otherwise set it
2722 // directly
2723 if (logEntryJson.is_array())
2724 {
2725 logEntryJson.push_back(logEntry);
2726 asyncResp->res.jsonValue["Members@odata.count"] =
2727 logEntryJson.size();
2728 }
2729 else
2730 {
2731 logEntryJson = logEntry;
2732 }
Johnathan Mantey043a0532020-03-10 17:15:28 -07002733 };
Jason M. Billse855dd22019-10-08 11:37:48 -07002734 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002735 std::move(getStoredLogCallback), crashdumpObject,
2736 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002737 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Jason M. Billse855dd22019-10-08 11:37:48 -07002738}
2739
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002740inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002741{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002742 // Note: Deviated from redfish privilege registry for GET & HEAD
2743 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002744 /**
2745 * Functions triggers appropriate requests on DBus
2746 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002747 BMCWEB_ROUTE(app,
2748 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002749 // This is incorrect, should be.
2750 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07002751 .privileges({{"ConfigureComponents"}})
Ed Tanous45ca1b82022-03-25 13:07:27 -07002752 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2753 const std::shared_ptr<
2754 bmcweb::AsyncResp>&
2755 asyncResp) {
2756 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2757 {
2758 return;
2759 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002760 crow::connections::systemBus->async_method_call(
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002761 [asyncResp](const boost::system::error_code ec,
2762 const std::vector<std::string>& resp) {
2763 if (ec)
2764 {
2765 if (ec.value() !=
2766 boost::system::errc::no_such_file_or_directory)
2767 {
2768 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
2769 << ec.message();
2770 messages::internalError(asyncResp->res);
2771 return;
2772 }
2773 }
2774 asyncResp->res.jsonValue["@odata.type"] =
2775 "#LogEntryCollection.LogEntryCollection";
2776 asyncResp->res.jsonValue["@odata.id"] =
2777 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2778 asyncResp->res.jsonValue["Name"] =
2779 "Open BMC Crashdump Entries";
2780 asyncResp->res.jsonValue["Description"] =
2781 "Collection of Crashdump Entries";
2782 asyncResp->res.jsonValue["Members"] =
2783 nlohmann::json::array();
Brandon Kima2dd60a2022-03-14 11:42:34 -07002784 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002785
2786 for (const std::string& path : resp)
2787 {
2788 const sdbusplus::message::object_path objPath(path);
2789 // Get the log ID
2790 std::string logID = objPath.filename();
2791 if (logID.empty())
2792 {
2793 continue;
2794 }
2795 // Add the log entry to the array
2796 logCrashdumpEntry(asyncResp, logID,
2797 asyncResp->res.jsonValue["Members"]);
2798 }
2799 },
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002800 "xyz.openbmc_project.ObjectMapper",
2801 "/xyz/openbmc_project/object_mapper",
2802 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
2803 std::array<const char*, 1>{crashdumpInterface});
2804 });
2805}
Ed Tanous1da66f72018-07-27 16:13:37 -07002806
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002807inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002808{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002809 // Note: Deviated from redfish privilege registry for GET & HEAD
2810 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002811
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002812 BMCWEB_ROUTE(
2813 app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002814 // this is incorrect, should be
2815 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07002816 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002817 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002818 [&app](const crow::Request& req,
2819 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2820 const std::string& param) {
2821 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2822 {
2823 return;
2824 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002825 const std::string& logID = param;
2826 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
2827 });
2828}
Ed Tanous1da66f72018-07-27 16:13:37 -07002829
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002830inline void requestRoutesCrashdumpFile(App& app)
2831{
2832 // Note: Deviated from redfish privilege registry for GET & HEAD
2833 // method for security reasons.
2834 BMCWEB_ROUTE(
2835 app,
2836 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002837 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002838 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002839 [&app](const crow::Request& req,
2840 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2841 const std::string& logID, const std::string& fileName) {
2842 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2843 {
2844 return;
2845 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002846 auto getStoredLogCallback =
Ed Tanousace85d62021-10-26 12:45:59 -07002847 [asyncResp, logID, fileName,
2848 url(boost::urls::url(req.urlView))](
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002849 const boost::system::error_code ec,
Ed Tanous168e20c2021-12-13 14:39:53 -08002850 const std::vector<std::pair<
2851 std::string, dbus::utility::DbusVariantType>>&
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002852 resp) {
2853 if (ec)
2854 {
2855 BMCWEB_LOG_DEBUG << "failed to get log ec: "
2856 << ec.message();
2857 messages::internalError(asyncResp->res);
2858 return;
2859 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002860
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002861 std::string dbusFilename{};
2862 std::string dbusTimestamp{};
2863 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002864
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002865 parseCrashdumpParameters(resp, dbusFilename,
2866 dbusTimestamp, dbusFilepath);
2867
2868 if (dbusFilename.empty() || dbusTimestamp.empty() ||
2869 dbusFilepath.empty())
2870 {
Ed Tanousace85d62021-10-26 12:45:59 -07002871 messages::resourceMissingAtURI(asyncResp->res, url);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002872 return;
2873 }
2874
2875 // Verify the file name parameter is correct
2876 if (fileName != dbusFilename)
2877 {
Ed Tanousace85d62021-10-26 12:45:59 -07002878 messages::resourceMissingAtURI(asyncResp->res, url);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002879 return;
2880 }
2881
2882 if (!std::filesystem::exists(dbusFilepath))
2883 {
Ed Tanousace85d62021-10-26 12:45:59 -07002884 messages::resourceMissingAtURI(asyncResp->res, url);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002885 return;
2886 }
Jason M. Bills2d314912022-01-12 13:59:01 -08002887 std::ifstream ifs(dbusFilepath,
2888 std::ios::in | std::ios::binary);
2889 asyncResp->res.body() = std::string(
2890 std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002891
2892 // Configure this to be a file download when accessed
2893 // from a browser
2894 asyncResp->res.addHeader("Content-Disposition",
2895 "attachment");
2896 };
2897 crow::connections::systemBus->async_method_call(
2898 std::move(getStoredLogCallback), crashdumpObject,
2899 crashdumpPath + std::string("/") + logID,
2900 "org.freedesktop.DBus.Properties", "GetAll",
2901 crashdumpInterface);
2902 });
2903}
2904
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002905enum class OEMDiagnosticType
2906{
2907 onDemand,
2908 telemetry,
2909 invalid,
2910};
2911
Ed Tanousf7725d72022-03-07 12:46:00 -08002912inline OEMDiagnosticType
2913 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002914{
2915 if (oemDiagStr == "OnDemand")
2916 {
2917 return OEMDiagnosticType::onDemand;
2918 }
2919 if (oemDiagStr == "Telemetry")
2920 {
2921 return OEMDiagnosticType::telemetry;
2922 }
2923
2924 return OEMDiagnosticType::invalid;
2925}
2926
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002927inline void requestRoutesCrashdumpCollect(App& app)
2928{
2929 // Note: Deviated from redfish privilege registry for GET & HEAD
2930 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08002931 BMCWEB_ROUTE(
2932 app,
2933 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002934 // The below is incorrect; Should be ConfigureManager
2935 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002936 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002937 .methods(
2938 boost::beast::http::verb::
Ed Tanous45ca1b82022-03-25 13:07:27 -07002939 post)([&app](
2940 const crow::Request& req,
2941 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2942 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2943 {
2944 return;
2945 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002946 std::string diagnosticDataType;
2947 std::string oemDiagnosticDataType;
Willy Tu15ed6782021-12-14 11:03:16 -08002948 if (!redfish::json_util::readJsonAction(
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002949 req, asyncResp->res, "DiagnosticDataType",
2950 diagnosticDataType, "OEMDiagnosticDataType",
2951 oemDiagnosticDataType))
James Feist46229572020-02-19 15:11:58 -08002952 {
James Feist46229572020-02-19 15:11:58 -08002953 return;
2954 }
Ed Tanous1da66f72018-07-27 16:13:37 -07002955
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002956 if (diagnosticDataType != "OEM")
2957 {
2958 BMCWEB_LOG_ERROR
2959 << "Only OEM DiagnosticDataType supported for Crashdump";
2960 messages::actionParameterValueFormatError(
2961 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
2962 "CollectDiagnosticData");
2963 return;
2964 }
2965
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002966 OEMDiagnosticType oemDiagType =
2967 getOEMDiagnosticType(oemDiagnosticDataType);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002968
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002969 std::string iface;
2970 std::string method;
2971 std::string taskMatchStr;
2972 if (oemDiagType == OEMDiagnosticType::onDemand)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002973 {
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002974 iface = crashdumpOnDemandInterface;
2975 method = "GenerateOnDemandLog";
2976 taskMatchStr = "type='signal',"
2977 "interface='org.freedesktop.DBus.Properties',"
2978 "member='PropertiesChanged',"
2979 "arg0namespace='com.intel.crashdump'";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002980 }
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002981 else if (oemDiagType == OEMDiagnosticType::telemetry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002982 {
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002983 iface = crashdumpTelemetryInterface;
2984 method = "GenerateTelemetryLog";
2985 taskMatchStr = "type='signal',"
2986 "interface='org.freedesktop.DBus.Properties',"
2987 "member='PropertiesChanged',"
2988 "arg0namespace='com.intel.crashdump'";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002989 }
2990 else
2991 {
2992 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
2993 << oemDiagnosticDataType;
2994 messages::actionParameterValueFormatError(
2995 asyncResp->res, oemDiagnosticDataType,
2996 "OEMDiagnosticDataType", "CollectDiagnosticData");
2997 return;
2998 }
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002999
3000 auto collectCrashdumpCallback =
3001 [asyncResp, payload(task::Payload(req)),
3002 taskMatchStr](const boost::system::error_code ec,
3003 const std::string&) mutable {
3004 if (ec)
3005 {
3006 if (ec.value() ==
3007 boost::system::errc::operation_not_supported)
3008 {
3009 messages::resourceInStandby(asyncResp->res);
3010 }
3011 else if (ec.value() ==
3012 boost::system::errc::device_or_resource_busy)
3013 {
3014 messages::serviceTemporarilyUnavailable(
3015 asyncResp->res, "60");
3016 }
3017 else
3018 {
3019 messages::internalError(asyncResp->res);
3020 }
3021 return;
3022 }
3023 std::shared_ptr<task::TaskData> task =
3024 task::TaskData::createTask(
3025 [](boost::system::error_code err,
3026 sdbusplus::message::message&,
3027 const std::shared_ptr<task::TaskData>&
3028 taskData) {
3029 if (!err)
3030 {
3031 taskData->messages.emplace_back(
3032 messages::taskCompletedOK(
3033 std::to_string(taskData->index)));
3034 taskData->state = "Completed";
3035 }
3036 return task::completed;
3037 },
3038 taskMatchStr);
3039
3040 task->startTimer(std::chrono::minutes(5));
3041 task->populateResp(asyncResp->res);
3042 task->payload.emplace(std::move(payload));
3043 };
3044
3045 crow::connections::systemBus->async_method_call(
3046 std::move(collectCrashdumpCallback), crashdumpObject,
3047 crashdumpPath, iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003048 });
3049}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003050
Andrew Geisslercb92c032018-08-17 07:56:14 -07003051/**
3052 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3053 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003054inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003055{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003056 /**
3057 * Function handles POST method request.
3058 * The Clear Log actions does not require any parameter.The action deletes
3059 * all entries found in the Entries collection for this Log Service.
3060 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003061
George Liu0fda0f12021-11-16 10:06:17 +08003062 BMCWEB_ROUTE(
3063 app,
3064 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003065 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003066 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003067 [&app](const crow::Request& req,
3068 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3069 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3070 {
3071 return;
3072 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003073 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003074
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003075 // Process response from Logging service.
3076 auto respHandler = [asyncResp](
3077 const boost::system::error_code ec) {
3078 BMCWEB_LOG_DEBUG
3079 << "doClearLog resp_handler callback: Done";
3080 if (ec)
3081 {
3082 // TODO Handle for specific error code
3083 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error "
3084 << ec;
3085 asyncResp->res.result(
3086 boost::beast::http::status::internal_server_error);
3087 return;
3088 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003089
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003090 asyncResp->res.result(
3091 boost::beast::http::status::no_content);
3092 };
3093
3094 // Make call to Logging service to request Clear Log
3095 crow::connections::systemBus->async_method_call(
3096 respHandler, "xyz.openbmc_project.Logging",
3097 "/xyz/openbmc_project/logging",
3098 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3099 });
3100}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003101
3102/****************************************************
3103 * Redfish PostCode interfaces
3104 * using DBUS interface: getPostCodesTS
3105 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003106inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003107{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003108 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003109 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003110 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
3111 const std::shared_ptr<
3112 bmcweb::AsyncResp>&
3113 asyncResp) {
3114 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3115 {
3116 return;
3117 }
Ed Tanous14766872022-03-15 10:44:42 -07003118
3119 asyncResp->res.jsonValue["@odata.id"] =
3120 "/redfish/v1/Systems/system/LogServices/PostCodes";
3121 asyncResp->res.jsonValue["@odata.type"] =
3122 "#LogService.v1_1_0.LogService";
3123 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3124 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
3125 asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
3126 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3127 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3128 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303129
George Liu0fda0f12021-11-16 10:06:17 +08003130 std::pair<std::string, std::string> redfishDateTimeOffset =
3131 crow::utility::getDateTimeOffsetNow();
3132 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3133 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3134 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303135
George Liu0fda0f12021-11-16 10:06:17 +08003136 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3137 {"target",
3138 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
3139 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003140}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003141
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003142inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003143{
George Liu0fda0f12021-11-16 10:06:17 +08003144 BMCWEB_ROUTE(
3145 app,
3146 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003147 // The following privilege is incorrect; It should be ConfigureManager
3148 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003149 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003150 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003151 [&app](const crow::Request& req,
3152 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3153 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3154 {
3155 return;
3156 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003157 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003158
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003159 // Make call to post-code service to request clear all
3160 crow::connections::systemBus->async_method_call(
3161 [asyncResp](const boost::system::error_code ec) {
3162 if (ec)
3163 {
3164 // TODO Handle for specific error code
3165 BMCWEB_LOG_ERROR
3166 << "doClearPostCodes resp_handler got error "
3167 << ec;
3168 asyncResp->res.result(boost::beast::http::status::
3169 internal_server_error);
3170 messages::internalError(asyncResp->res);
3171 return;
3172 }
3173 },
3174 "xyz.openbmc_project.State.Boot.PostCode0",
3175 "/xyz/openbmc_project/State/Boot/PostCode0",
3176 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3177 });
3178}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003179
3180static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003181 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303182 const boost::container::flat_map<
3183 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003184 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3185 const uint64_t skip = 0, const uint64_t top = 0)
3186{
3187 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003188 const registries::Message* message =
3189 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003190
3191 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003192 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003193
3194 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303195 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3196 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003197 {
3198 currentCodeIndex++;
3199 std::string postcodeEntryID =
3200 "B" + std::to_string(bootIndex) + "-" +
3201 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3202
3203 uint64_t usecSinceEpoch = code.first;
3204 uint64_t usTimeOffset = 0;
3205
3206 if (1 == currentCodeIndex)
3207 { // already incremented
3208 firstCodeTimeUs = code.first;
3209 }
3210 else
3211 {
3212 usTimeOffset = code.first - firstCodeTimeUs;
3213 }
3214
3215 // skip if no specific codeIndex is specified and currentCodeIndex does
3216 // not fall between top and skip
3217 if ((codeIndex == 0) &&
3218 (currentCodeIndex <= skip || currentCodeIndex > top))
3219 {
3220 continue;
3221 }
3222
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003223 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003224 // currentIndex
3225 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3226 {
3227 // This is done for simplicity. 1st entry is needed to calculate
3228 // time offset. To improve efficiency, one can get to the entry
3229 // directly (possibly with flatmap's nth method)
3230 continue;
3231 }
3232
3233 // currentCodeIndex is within top and skip or equal to specified code
3234 // index
3235
3236 // Get the Created time from the timestamp
3237 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003238 entryTimeStr =
3239 crow::utility::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003240
3241 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3242 std::ostringstream hexCode;
3243 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303244 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003245 std::ostringstream timeOffsetStr;
3246 // Set Fixed -Point Notation
3247 timeOffsetStr << std::fixed;
3248 // Set precision to 4 digits
3249 timeOffsetStr << std::setprecision(4);
3250 // Add double to stream
3251 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3252 std::vector<std::string> messageArgs = {
3253 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3254
3255 // Get MessageArgs template from message registry
3256 std::string msg;
3257 if (message != nullptr)
3258 {
3259 msg = message->message;
3260
3261 // fill in this post code value
3262 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003263 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003264 {
3265 std::string argStr = "%" + std::to_string(++i);
3266 size_t argPos = msg.find(argStr);
3267 if (argPos != std::string::npos)
3268 {
3269 msg.replace(argPos, argStr.length(), messageArg);
3270 }
3271 }
3272 }
3273
Tim Leed4342a92020-04-27 11:47:58 +08003274 // Get Severity template from message registry
3275 std::string severity;
3276 if (message != nullptr)
3277 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003278 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003279 }
3280
ZhikuiRena3316fc2020-01-29 14:58:08 -08003281 // add to AsyncResp
3282 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003283 nlohmann::json& bmcLogEntry = logEntryArray.back();
George Liu0fda0f12021-11-16 10:06:17 +08003284 bmcLogEntry = {
3285 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
3286 {"@odata.id",
3287 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3288 postcodeEntryID},
3289 {"Name", "POST Code Log Entry"},
3290 {"Id", postcodeEntryID},
3291 {"Message", std::move(msg)},
3292 {"MessageId", "OpenBMC.0.2.BIOSPOSTCode"},
3293 {"MessageArgs", std::move(messageArgs)},
3294 {"EntryType", "Event"},
3295 {"Severity", std::move(severity)},
3296 {"Created", entryTimeStr}};
George Liu647b3cd2021-07-05 12:43:56 +08003297 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3298 {
3299 bmcLogEntry["AdditionalDataURI"] =
3300 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3301 postcodeEntryID + "/attachment";
3302 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003303 }
3304}
3305
zhanghch058d1b46d2021-04-01 11:18:24 +08003306static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003307 const uint16_t bootIndex,
3308 const uint64_t codeIndex)
3309{
3310 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303311 [aResp, bootIndex,
3312 codeIndex](const boost::system::error_code ec,
3313 const boost::container::flat_map<
3314 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3315 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003316 if (ec)
3317 {
3318 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3319 messages::internalError(aResp->res);
3320 return;
3321 }
3322
3323 // skip the empty postcode boots
3324 if (postcode.empty())
3325 {
3326 return;
3327 }
3328
3329 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
3330
3331 aResp->res.jsonValue["Members@odata.count"] =
3332 aResp->res.jsonValue["Members"].size();
3333 },
Jonathan Doman15124762021-01-07 17:54:17 -08003334 "xyz.openbmc_project.State.Boot.PostCode0",
3335 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003336 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3337 bootIndex);
3338}
3339
zhanghch058d1b46d2021-04-01 11:18:24 +08003340static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003341 const uint16_t bootIndex,
3342 const uint16_t bootCount,
3343 const uint64_t entryCount, const uint64_t skip,
3344 const uint64_t top)
3345{
3346 crow::connections::systemBus->async_method_call(
3347 [aResp, bootIndex, bootCount, entryCount, skip,
3348 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303349 const boost::container::flat_map<
3350 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3351 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003352 if (ec)
3353 {
3354 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3355 messages::internalError(aResp->res);
3356 return;
3357 }
3358
3359 uint64_t endCount = entryCount;
3360 if (!postcode.empty())
3361 {
3362 endCount = entryCount + postcode.size();
3363
3364 if ((skip < endCount) && ((top + skip) > entryCount))
3365 {
3366 uint64_t thisBootSkip =
3367 std::max(skip, entryCount) - entryCount;
3368 uint64_t thisBootTop =
3369 std::min(top + skip, endCount) - entryCount;
3370
3371 fillPostCodeEntry(aResp, postcode, bootIndex, 0,
3372 thisBootSkip, thisBootTop);
3373 }
3374 aResp->res.jsonValue["Members@odata.count"] = endCount;
3375 }
3376
3377 // continue to previous bootIndex
3378 if (bootIndex < bootCount)
3379 {
3380 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3381 bootCount, endCount, skip, top);
3382 }
3383 else
3384 {
3385 aResp->res.jsonValue["Members@odata.nextLink"] =
George Liu0fda0f12021-11-16 10:06:17 +08003386 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
ZhikuiRena3316fc2020-01-29 14:58:08 -08003387 std::to_string(skip + top);
3388 }
3389 },
Jonathan Doman15124762021-01-07 17:54:17 -08003390 "xyz.openbmc_project.State.Boot.PostCode0",
3391 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003392 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3393 bootIndex);
3394}
3395
zhanghch058d1b46d2021-04-01 11:18:24 +08003396static void
3397 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3398 const uint64_t skip, const uint64_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003399{
3400 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003401 sdbusplus::asio::getProperty<uint16_t>(
3402 *crow::connections::systemBus,
3403 "xyz.openbmc_project.State.Boot.PostCode0",
3404 "/xyz/openbmc_project/State/Boot/PostCode0",
3405 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3406 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3407 const uint16_t bootCount) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003408 if (ec)
3409 {
3410 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3411 messages::internalError(aResp->res);
3412 return;
3413 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003414 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
3415 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003416}
3417
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003418inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003419{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003420 BMCWEB_ROUTE(app,
3421 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003422 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003423 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003424 [&app](const crow::Request& req,
3425 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanousc937d2b2022-04-05 09:58:00 -07003426 query_param::QueryCapabilities capabilities = {
3427 .canDelegateTop = true,
3428 .canDelegateSkip = true,
3429 };
3430 query_param::Query delegatedQuery;
3431 if (!redfish::setUpRedfishRouteWithDelegation(
3432 app, req, asyncResp->res, delegatedQuery, capabilities))
Ed Tanous45ca1b82022-03-25 13:07:27 -07003433 {
3434 return;
3435 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003436 asyncResp->res.jsonValue["@odata.type"] =
3437 "#LogEntryCollection.LogEntryCollection";
3438 asyncResp->res.jsonValue["@odata.id"] =
3439 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3440 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3441 asyncResp->res.jsonValue["Description"] =
3442 "Collection of POST Code Log Entries";
3443 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3444 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003445
Ed Tanousc937d2b2022-04-05 09:58:00 -07003446 getCurrentBootNumber(asyncResp, delegatedQuery.skip,
3447 delegatedQuery.top);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003448 });
3449}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003450
George Liu647b3cd2021-07-05 12:43:56 +08003451/**
3452 * @brief Parse post code ID and get the current value and index value
3453 * eg: postCodeID=B1-2, currentValue=1, index=2
3454 *
3455 * @param[in] postCodeID Post Code ID
3456 * @param[out] currentValue Current value
3457 * @param[out] index Index value
3458 *
3459 * @return bool true if the parsing is successful, false the parsing fails
3460 */
3461inline static bool parsePostCode(const std::string& postCodeID,
3462 uint64_t& currentValue, uint16_t& index)
3463{
3464 std::vector<std::string> split;
3465 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3466 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3467 {
3468 return false;
3469 }
3470
Ed Tanousca45aa32022-01-07 09:28:45 -08003471 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003472 const char* start = split[0].data() + 1;
Ed Tanousca45aa32022-01-07 09:28:45 -08003473 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003474 const char* end = split[0].data() + split[0].size();
3475 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3476
3477 if (ptrIndex != end || ecIndex != std::errc())
3478 {
3479 return false;
3480 }
3481
3482 start = split[1].data();
Ed Tanousca45aa32022-01-07 09:28:45 -08003483
3484 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003485 end = split[1].data() + split[1].size();
3486 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
George Liu647b3cd2021-07-05 12:43:56 +08003487
Ed Tanousdcf2ebc2022-01-25 10:07:45 -08003488 return ptrValue == end && ecValue != std::errc();
George Liu647b3cd2021-07-05 12:43:56 +08003489}
3490
3491inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3492{
George Liu0fda0f12021-11-16 10:06:17 +08003493 BMCWEB_ROUTE(
3494 app,
3495 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003496 .privileges(redfish::privileges::getLogEntry)
3497 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003498 [&app](const crow::Request& req,
3499 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3500 const std::string& postCodeID) {
3501 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3502 {
3503 return;
3504 }
George Liu647b3cd2021-07-05 12:43:56 +08003505 if (!http_helpers::isOctetAccepted(
3506 req.getHeaderValue("Accept")))
3507 {
3508 asyncResp->res.result(
3509 boost::beast::http::status::bad_request);
3510 return;
3511 }
3512
3513 uint64_t currentValue = 0;
3514 uint16_t index = 0;
3515 if (!parsePostCode(postCodeID, currentValue, index))
3516 {
3517 messages::resourceNotFound(asyncResp->res, "LogEntry",
3518 postCodeID);
3519 return;
3520 }
3521
3522 crow::connections::systemBus->async_method_call(
3523 [asyncResp, postCodeID, currentValue](
3524 const boost::system::error_code ec,
3525 const std::vector<std::tuple<
3526 uint64_t, std::vector<uint8_t>>>& postcodes) {
3527 if (ec.value() == EBADR)
3528 {
3529 messages::resourceNotFound(asyncResp->res,
3530 "LogEntry", postCodeID);
3531 return;
3532 }
3533 if (ec)
3534 {
3535 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3536 messages::internalError(asyncResp->res);
3537 return;
3538 }
3539
3540 size_t value = static_cast<size_t>(currentValue) - 1;
3541 if (value == std::string::npos ||
3542 postcodes.size() < currentValue)
3543 {
3544 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3545 messages::resourceNotFound(asyncResp->res,
3546 "LogEntry", postCodeID);
3547 return;
3548 }
3549
Ed Tanous9eb808c2022-01-25 10:19:23 -08003550 const auto& [tID, c] = postcodes[value];
Ed Tanous46ff87b2022-01-07 09:25:51 -08003551 if (c.empty())
George Liu647b3cd2021-07-05 12:43:56 +08003552 {
3553 BMCWEB_LOG_INFO << "No found post code data";
3554 messages::resourceNotFound(asyncResp->res,
3555 "LogEntry", postCodeID);
3556 return;
3557 }
Ed Tanous46ff87b2022-01-07 09:25:51 -08003558 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
3559 const char* d = reinterpret_cast<const char*>(c.data());
3560 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08003561
3562 asyncResp->res.addHeader("Content-Type",
3563 "application/octet-stream");
3564 asyncResp->res.addHeader("Content-Transfer-Encoding",
3565 "Base64");
3566 asyncResp->res.body() =
3567 crow::utility::base64encode(strData);
3568 },
3569 "xyz.openbmc_project.State.Boot.PostCode0",
3570 "/xyz/openbmc_project/State/Boot/PostCode0",
3571 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes",
3572 index);
3573 });
3574}
3575
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003576inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003577{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003578 BMCWEB_ROUTE(
3579 app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003580 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003581 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003582 [&app](const crow::Request& req,
3583 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3584 const std::string& targetID) {
3585 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3586 {
3587 return;
3588 }
George Liu647b3cd2021-07-05 12:43:56 +08003589 uint16_t bootIndex = 0;
3590 uint64_t codeIndex = 0;
3591 if (!parsePostCode(targetID, codeIndex, bootIndex))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003592 {
3593 // Requested ID was not found
Ed Tanousace85d62021-10-26 12:45:59 -07003594 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003595 return;
3596 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003597 if (bootIndex == 0 || codeIndex == 0)
3598 {
3599 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3600 << targetID;
3601 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003602
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003603 asyncResp->res.jsonValue["@odata.type"] =
3604 "#LogEntry.v1_4_0.LogEntry";
3605 asyncResp->res.jsonValue["@odata.id"] =
George Liu0fda0f12021-11-16 10:06:17 +08003606 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003607 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3608 asyncResp->res.jsonValue["Description"] =
3609 "Collection of POST Code Log Entries";
3610 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3611 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003612
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003613 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3614 });
3615}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003616
Ed Tanous1da66f72018-07-27 16:13:37 -07003617} // namespace redfish