xref: /openbmc/phosphor-logging/extensions/openpower-pels/tools/peltool.cpp (revision fa2d962b5da807ac17bb7a355709ff05dd10d041)
1711d51d8SMatt Spinler /**
2711d51d8SMatt Spinler  * Copyright © 2019 IBM Corporation
3711d51d8SMatt Spinler  *
4711d51d8SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5711d51d8SMatt Spinler  * you may not use this file except in compliance with the License.
6711d51d8SMatt Spinler  * You may obtain a copy of the License at
7711d51d8SMatt Spinler  *
8711d51d8SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9711d51d8SMatt Spinler  *
10711d51d8SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11711d51d8SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12711d51d8SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13711d51d8SMatt Spinler  * See the License for the specific language governing permissions and
14711d51d8SMatt Spinler  * limitations under the License.
15711d51d8SMatt Spinler  */
167b291ec6SAatir #include "config.h"
177b291ec6SAatir 
182544b419SPatrick Williams #include "config_main.h"
192544b419SPatrick Williams 
207b291ec6SAatir #include "../bcd_time.hpp"
21d4002f39SHarisuddin Mohamed Isa #include "../json_utils.hpp"
220f717e10SHarisuddin Mohamed Isa #include "../paths.hpp"
23186ce8c9SAatir #include "../pel.hpp"
247b291ec6SAatir #include "../pel_types.hpp"
257b291ec6SAatir #include "../pel_values.hpp"
26186ce8c9SAatir 
27f67bafd0SHarisuddin Mohamed Isa #include <Python.h>
28f67bafd0SHarisuddin Mohamed Isa 
29186ce8c9SAatir #include <CLI/CLI.hpp>
30a561ff6aSMatt Spinler #include <phosphor-logging/log.hpp>
312544b419SPatrick Williams 
327b291ec6SAatir #include <bitset>
336f005199SHarisuddin Mohamed Isa #include <fstream>
34186ce8c9SAatir #include <iostream>
357b291ec6SAatir #include <regex>
36186ce8c9SAatir #include <string>
37186ce8c9SAatir 
387b291ec6SAatir namespace fs = std::filesystem;
39a561ff6aSMatt Spinler using namespace phosphor::logging;
40186ce8c9SAatir using namespace openpower::pels;
417b291ec6SAatir namespace message = openpower::pels::message;
427b291ec6SAatir namespace pv = openpower::pels::pel_values;
43186ce8c9SAatir 
44011ccae0SMiguel Gomez const uint8_t critSysTermSeverity = 0x51;
45011ccae0SMiguel Gomez 
46ed32c8daSHarisuddin Mohamed Isa using PELFunc = std::function<void(const PEL&, bool hexDump)>;
470d804ef5SMatt Spinler message::Registry registry(getPELReadOnlyDataPath() / message::registryFileName,
48d8e29000SMatt Spinler                            false);
4927de6f38SMatt Spinler namespace service
5027de6f38SMatt Spinler {
5127de6f38SMatt Spinler constexpr auto logging = "xyz.openbmc_project.Logging";
5227de6f38SMatt Spinler } // namespace service
5327de6f38SMatt Spinler 
5427de6f38SMatt Spinler namespace interface
5527de6f38SMatt Spinler {
5627de6f38SMatt Spinler constexpr auto deleteObj = "xyz.openbmc_project.Object.Delete";
5727de6f38SMatt Spinler constexpr auto deleteAll = "xyz.openbmc_project.Collection.DeleteAll";
5827de6f38SMatt Spinler } // namespace interface
5927de6f38SMatt Spinler 
6027de6f38SMatt Spinler namespace object_path
6127de6f38SMatt Spinler {
6227de6f38SMatt Spinler constexpr auto logEntry = "/xyz/openbmc_project/logging/entry/";
6327de6f38SMatt Spinler constexpr auto logging = "/xyz/openbmc_project/logging";
6427de6f38SMatt Spinler } // namespace object_path
6527de6f38SMatt Spinler 
pelLogDir()66b6b25575SWilliam A. Kennington III std::string pelLogDir()
67b6b25575SWilliam A. Kennington III {
68*fa2d962bSPatrick Williams     return std::string(phosphor::logging::paths::extension()) + "/pels/logs";
69b6b25575SWilliam A. Kennington III }
70b6b25575SWilliam A. Kennington III 
71e340c13fSAatir /**
7237822f68SAatir  * @brief helper function to get PEL commit timestamp from file name
73104c7967SSumit Kumar  * @retrun uint64_t - PEL commit timestamp
7437822f68SAatir  * @param[in] std::string - file name
7537822f68SAatir  */
fileNameToTimestamp(const std::string & fileName)76104c7967SSumit Kumar uint64_t fileNameToTimestamp(const std::string& fileName)
7737822f68SAatir {
7837822f68SAatir     std::string token = fileName.substr(0, fileName.find("_"));
79104c7967SSumit Kumar     uint64_t bcdTime = 0;
8037822f68SAatir     if (token.length() >= 14)
8137822f68SAatir     {
82be952d2eSMatt Spinler         int i = 0;
83be952d2eSMatt Spinler 
8437822f68SAatir         try
8537822f68SAatir         {
86104c7967SSumit Kumar             auto tmp = std::stoul(token.substr(i, 2), 0, 16);
87104c7967SSumit Kumar             bcdTime |= (static_cast<uint64_t>(tmp) << 56);
8837822f68SAatir         }
8966491c61SPatrick Williams         catch (const std::exception& err)
9037822f68SAatir         {
9137822f68SAatir             std::cout << "Conversion failure: " << err.what() << std::endl;
9237822f68SAatir         }
9337822f68SAatir         i += 2;
9437822f68SAatir         try
9537822f68SAatir         {
96104c7967SSumit Kumar             auto tmp = std::stoul(token.substr(i, 2), 0, 16);
97104c7967SSumit Kumar             bcdTime |= (static_cast<uint64_t>(tmp) << 48);
9837822f68SAatir         }
9966491c61SPatrick Williams         catch (const std::exception& err)
10037822f68SAatir         {
10137822f68SAatir             std::cout << "Conversion failure: " << err.what() << std::endl;
10237822f68SAatir         }
10337822f68SAatir         i += 2;
10437822f68SAatir         try
10537822f68SAatir         {
106104c7967SSumit Kumar             auto tmp = std::stoul(token.substr(i, 2), 0, 16);
107104c7967SSumit Kumar             bcdTime |= (static_cast<uint64_t>(tmp) << 40);
10837822f68SAatir         }
10966491c61SPatrick Williams         catch (const std::exception& err)
11037822f68SAatir         {
11137822f68SAatir             std::cout << "Conversion failure: " << err.what() << std::endl;
11237822f68SAatir         }
11337822f68SAatir         i += 2;
11437822f68SAatir         try
11537822f68SAatir         {
116104c7967SSumit Kumar             auto tmp = std::stoul(token.substr(i, 2), 0, 16);
117104c7967SSumit Kumar             bcdTime |= (static_cast<uint64_t>(tmp) << 32);
11837822f68SAatir         }
11966491c61SPatrick Williams         catch (const std::exception& err)
12037822f68SAatir         {
12137822f68SAatir             std::cout << "Conversion failure: " << err.what() << std::endl;
12237822f68SAatir         }
12337822f68SAatir         i += 2;
12437822f68SAatir         try
12537822f68SAatir         {
126104c7967SSumit Kumar             auto tmp = std::stoul(token.substr(i, 2), 0, 16);
127104c7967SSumit Kumar             bcdTime |= (tmp << 24);
12837822f68SAatir         }
12966491c61SPatrick Williams         catch (const std::exception& err)
13037822f68SAatir         {
13137822f68SAatir             std::cout << "Conversion failure: " << err.what() << std::endl;
13237822f68SAatir         }
13337822f68SAatir         i += 2;
13437822f68SAatir         try
13537822f68SAatir         {
136104c7967SSumit Kumar             auto tmp = std::stoul(token.substr(i, 2), 0, 16);
137104c7967SSumit Kumar             bcdTime |= (tmp << 16);
13837822f68SAatir         }
13966491c61SPatrick Williams         catch (const std::exception& err)
14037822f68SAatir         {
14137822f68SAatir             std::cout << "Conversion failure: " << err.what() << std::endl;
14237822f68SAatir         }
14337822f68SAatir         i += 2;
14437822f68SAatir         try
14537822f68SAatir         {
146104c7967SSumit Kumar             auto tmp = std::stoul(token.substr(i, 2), 0, 16);
147104c7967SSumit Kumar             bcdTime |= (tmp << 8);
14837822f68SAatir         }
14966491c61SPatrick Williams         catch (const std::exception& err)
15037822f68SAatir         {
15137822f68SAatir             std::cout << "Conversion failure: " << err.what() << std::endl;
15237822f68SAatir         }
15337822f68SAatir         i += 2;
15437822f68SAatir         try
15537822f68SAatir         {
156104c7967SSumit Kumar             auto tmp = std::stoul(token.substr(i, 2), 0, 16);
157104c7967SSumit Kumar             bcdTime |= tmp;
15837822f68SAatir         }
15966491c61SPatrick Williams         catch (const std::exception& err)
16037822f68SAatir         {
16137822f68SAatir             std::cout << "Conversion failure: " << err.what() << std::endl;
16237822f68SAatir         }
16337822f68SAatir     }
164104c7967SSumit Kumar     return bcdTime;
16537822f68SAatir }
16637822f68SAatir 
16737822f68SAatir /**
16837822f68SAatir  * @brief helper function to get PEL id from file name
16937822f68SAatir  * @retrun uint32_t - PEL id
17037822f68SAatir  * @param[in] std::string - file name
17137822f68SAatir  */
fileNameToPELId(const std::string & fileName)17237822f68SAatir uint32_t fileNameToPELId(const std::string& fileName)
17337822f68SAatir {
17437822f68SAatir     uint32_t num = 0;
17537822f68SAatir     try
17637822f68SAatir     {
177a1e4084aSSumit Kumar         num = std::stoul(fileName.substr(fileName.find("_") + 1), 0, 16);
17837822f68SAatir     }
17966491c61SPatrick Williams     catch (const std::exception& err)
18037822f68SAatir     {
18137822f68SAatir         std::cout << "Conversion failure: " << err.what() << std::endl;
18237822f68SAatir     }
18337822f68SAatir     return num;
18437822f68SAatir }
18537822f68SAatir 
18637822f68SAatir /**
18780129fe8SMatt Spinler  * @brief Check if the string ends with the PEL ID string passed in
18880129fe8SMatt Spinler  * @param[in] str - string to check for PEL ID
18980129fe8SMatt Spinler  * @param[in] pelID - PEL id string
19080129fe8SMatt Spinler  *
19180129fe8SMatt Spinler  * @return bool - true with suffix matches
192e340c13fSAatir  */
endsWithPelID(const std::string & str,const std::string & pelID)19380129fe8SMatt Spinler bool endsWithPelID(const std::string& str, const std::string& pelID)
194e340c13fSAatir {
19580129fe8SMatt Spinler     constexpr size_t pelIDSize = 8;
19680129fe8SMatt Spinler 
19780129fe8SMatt Spinler     if (pelID.size() != pelIDSize)
19880129fe8SMatt Spinler     {
19980129fe8SMatt Spinler         return false;
20080129fe8SMatt Spinler     }
20180129fe8SMatt Spinler 
20280129fe8SMatt Spinler     size_t slen = str.size(), elen = pelID.size();
203e340c13fSAatir     if (slen < elen)
204e340c13fSAatir         return false;
205e340c13fSAatir     while (elen)
206e340c13fSAatir     {
20780129fe8SMatt Spinler         if (str[--slen] != pelID[--elen])
208e340c13fSAatir             return false;
209e340c13fSAatir     }
210e340c13fSAatir     return true;
211e340c13fSAatir }
212e340c13fSAatir 
21337822f68SAatir /**
21437822f68SAatir  * @brief get data form raw PEL file.
21537822f68SAatir  * @param[in] std::string Name of file with raw PEL
21637822f68SAatir  * @return std::vector<uint8_t> char vector read from raw PEL file.
21737822f68SAatir  */
getFileData(const std::string & name)218bad5f8a2SAatir std::vector<uint8_t> getFileData(const std::string& name)
21937822f68SAatir {
22037822f68SAatir     std::ifstream file(name, std::ifstream::in);
22137822f68SAatir     if (file.good())
22237822f68SAatir     {
22337822f68SAatir         std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
22437822f68SAatir                                   std::istreambuf_iterator<char>()};
22537822f68SAatir         return data;
22637822f68SAatir     }
22737822f68SAatir     else
22837822f68SAatir     {
22937822f68SAatir         return {};
23037822f68SAatir     }
23137822f68SAatir }
23237822f68SAatir 
233a214ed30SHarisuddin Mohamed Isa /**
234f67bafd0SHarisuddin Mohamed Isa  * @brief Initialize Python interpreter and gather all UD parser modules under
235f67bafd0SHarisuddin Mohamed Isa  *        the paths found in Python sys.path and the current user directory.
236f67bafd0SHarisuddin Mohamed Isa  *        This is to prevent calling a non-existant module which causes Python
237f67bafd0SHarisuddin Mohamed Isa  *        to print an import error message and breaking JSON output.
238f67bafd0SHarisuddin Mohamed Isa  *
239f67bafd0SHarisuddin Mohamed Isa  * @return std::vector<std::string> Vector of plugins found in filesystem
240f67bafd0SHarisuddin Mohamed Isa  */
getPlugins()241f67bafd0SHarisuddin Mohamed Isa std::vector<std::string> getPlugins()
242f67bafd0SHarisuddin Mohamed Isa {
243f67bafd0SHarisuddin Mohamed Isa     Py_Initialize();
244f67bafd0SHarisuddin Mohamed Isa     std::vector<std::string> plugins;
245f67bafd0SHarisuddin Mohamed Isa     std::vector<std::string> siteDirs;
246c8d6cc61SHarisuddin Mohamed Isa     std::array<std::string, 2> parserDirs = {"udparsers", "srcparsers"};
247f67bafd0SHarisuddin Mohamed Isa     PyObject* pName = PyUnicode_FromString("sys");
248f67bafd0SHarisuddin Mohamed Isa     PyObject* pModule = PyImport_Import(pName);
249f67bafd0SHarisuddin Mohamed Isa     Py_XDECREF(pName);
250f67bafd0SHarisuddin Mohamed Isa     PyObject* pDict = PyModule_GetDict(pModule);
251f67bafd0SHarisuddin Mohamed Isa     Py_XDECREF(pModule);
252f67bafd0SHarisuddin Mohamed Isa     PyObject* pResult = PyDict_GetItemString(pDict, "path");
253f67bafd0SHarisuddin Mohamed Isa     PyObject* pValue = PyUnicode_FromString(".");
254f67bafd0SHarisuddin Mohamed Isa     PyList_Append(pResult, pValue);
255f67bafd0SHarisuddin Mohamed Isa     Py_XDECREF(pValue);
256f67bafd0SHarisuddin Mohamed Isa     auto list_size = PyList_Size(pResult);
257f67bafd0SHarisuddin Mohamed Isa     for (auto i = 0; i < list_size; i++)
258f67bafd0SHarisuddin Mohamed Isa     {
259f67bafd0SHarisuddin Mohamed Isa         PyObject* item = PyList_GetItem(pResult, i);
260f67bafd0SHarisuddin Mohamed Isa         PyObject* pBytes = PyUnicode_AsEncodedString(item, "utf-8", "~E~");
261f67bafd0SHarisuddin Mohamed Isa         const char* output = PyBytes_AS_STRING(pBytes);
262f67bafd0SHarisuddin Mohamed Isa         Py_XDECREF(pBytes);
263f67bafd0SHarisuddin Mohamed Isa         std::string tmpStr(output);
264f67bafd0SHarisuddin Mohamed Isa         siteDirs.push_back(tmpStr);
265f67bafd0SHarisuddin Mohamed Isa     }
266f67bafd0SHarisuddin Mohamed Isa     for (const auto& dir : siteDirs)
267f67bafd0SHarisuddin Mohamed Isa     {
268c8d6cc61SHarisuddin Mohamed Isa         for (const auto& parserDir : parserDirs)
269f67bafd0SHarisuddin Mohamed Isa         {
270c8d6cc61SHarisuddin Mohamed Isa             if (fs::exists(dir + "/" + parserDir))
271c8d6cc61SHarisuddin Mohamed Isa             {
272c8d6cc61SHarisuddin Mohamed Isa                 for (const auto& entry :
273c8d6cc61SHarisuddin Mohamed Isa                      fs::directory_iterator(dir + "/" + parserDir))
274f67bafd0SHarisuddin Mohamed Isa                 {
275f67bafd0SHarisuddin Mohamed Isa                     if (entry.is_directory() and
276f67bafd0SHarisuddin Mohamed Isa                         fs::exists(entry.path().string() + "/" +
277f67bafd0SHarisuddin Mohamed Isa                                    entry.path().stem().string() + ".py"))
278f67bafd0SHarisuddin Mohamed Isa                     {
279f67bafd0SHarisuddin Mohamed Isa                         plugins.push_back(entry.path().stem());
280f67bafd0SHarisuddin Mohamed Isa                     }
281f67bafd0SHarisuddin Mohamed Isa                 }
282f67bafd0SHarisuddin Mohamed Isa             }
283f67bafd0SHarisuddin Mohamed Isa         }
284c8d6cc61SHarisuddin Mohamed Isa     }
285f67bafd0SHarisuddin Mohamed Isa     return plugins;
286f67bafd0SHarisuddin Mohamed Isa }
287f67bafd0SHarisuddin Mohamed Isa 
288f67bafd0SHarisuddin Mohamed Isa /**
289a214ed30SHarisuddin Mohamed Isa  * @brief Creates JSON string of a PEL entry if fullPEL is false or prints to
290a214ed30SHarisuddin Mohamed Isa  *        stdout the full PEL in JSON if fullPEL is true
291a214ed30SHarisuddin Mohamed Isa  * @param[in] itr - std::map iterator of <uint32_t, BCDTime>
292a214ed30SHarisuddin Mohamed Isa  * @param[in] hidden - Boolean to include hidden PELs
2930c57a67bSHarisuddin Mohamed Isa  * @param[in] includeInfo - Boolean to include informational PELs
294011ccae0SMiguel Gomez  * @param[in] critSysTerm - Boolean to include critical error and system
295011ccae0SMiguel Gomez  * termination PELs
296a214ed30SHarisuddin Mohamed Isa  * @param[in] fullPEL - Boolean to print full JSON representation of PEL
297a214ed30SHarisuddin Mohamed Isa  * @param[in] foundPEL - Boolean to check if any PEL is present
2986f005199SHarisuddin Mohamed Isa  * @param[in] scrubRegex - SRC regex object
299f67bafd0SHarisuddin Mohamed Isa  * @param[in] plugins - Vector of strings of plugins found in filesystem
300ed32c8daSHarisuddin Mohamed Isa  * @param[in] hexDump - Boolean to print hexdump of PEL instead of JSON
301a214ed30SHarisuddin Mohamed Isa  * @return std::string - JSON string of PEL entry (empty if fullPEL is true)
302a214ed30SHarisuddin Mohamed Isa  */
3037b291ec6SAatir template <typename T>
genPELJSON(T itr,bool hidden,bool includeInfo,bool critSysTerm,bool fullPEL,bool & foundPEL,const std::optional<std::regex> & scrubRegex,const std::vector<std::string> & plugins,bool hexDump,bool archive)304075c7923SPatrick Williams std::string genPELJSON(
305075c7923SPatrick Williams     T itr, bool hidden, bool includeInfo, bool critSysTerm, bool fullPEL,
306075c7923SPatrick Williams     bool& foundPEL, const std::optional<std::regex>& scrubRegex,
307075c7923SPatrick Williams     const std::vector<std::string>& plugins, bool hexDump, bool archive)
3087b291ec6SAatir {
3097b291ec6SAatir     std::string val;
3107b291ec6SAatir     std::string listStr;
311b6b25575SWilliam A. Kennington III     char name[51];
312104c7967SSumit Kumar     sprintf(name, "/%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X_%.8X",
313104c7967SSumit Kumar             static_cast<uint8_t>((itr.second >> 56) & 0xFF),
314104c7967SSumit Kumar             static_cast<uint8_t>((itr.second >> 48) & 0xFF),
315104c7967SSumit Kumar             static_cast<uint8_t>((itr.second >> 40) & 0xFF),
316104c7967SSumit Kumar             static_cast<uint8_t>((itr.second >> 32) & 0xFF),
317104c7967SSumit Kumar             static_cast<uint8_t>((itr.second >> 24) & 0xFF),
318104c7967SSumit Kumar             static_cast<uint8_t>((itr.second >> 16) & 0xFF),
319104c7967SSumit Kumar             static_cast<uint8_t>((itr.second >> 8) & 0xFF),
320104c7967SSumit Kumar             static_cast<uint8_t>(itr.second & 0xFF), itr.first);
321104c7967SSumit Kumar 
3221d8835bbSSumit Kumar     auto fileName = (archive ? pelLogDir() + "/archive" : pelLogDir()) + name;
3237b291ec6SAatir     try
3247b291ec6SAatir     {
32537822f68SAatir         std::vector<uint8_t> data = getFileData(fileName);
326a214ed30SHarisuddin Mohamed Isa         if (data.empty())
32737822f68SAatir         {
328a561ff6aSMatt Spinler             log<level::ERR>("Empty PEL file",
329a561ff6aSMatt Spinler                             entry("FILENAME=%s", fileName.c_str()));
330a214ed30SHarisuddin Mohamed Isa             return listStr;
331a214ed30SHarisuddin Mohamed Isa         }
3327b291ec6SAatir         PEL pel{data};
3336f005199SHarisuddin Mohamed Isa         if (!pel.valid())
3347b291ec6SAatir         {
3356f005199SHarisuddin Mohamed Isa             return listStr;
3366f005199SHarisuddin Mohamed Isa         }
3370c57a67bSHarisuddin Mohamed Isa         if (!includeInfo && pel.userHeader().severity() == 0)
3380c57a67bSHarisuddin Mohamed Isa         {
3390c57a67bSHarisuddin Mohamed Isa             return listStr;
3400c57a67bSHarisuddin Mohamed Isa         }
341011ccae0SMiguel Gomez         if (critSysTerm && pel.userHeader().severity() != critSysTermSeverity)
342011ccae0SMiguel Gomez         {
343011ccae0SMiguel Gomez             return listStr;
344011ccae0SMiguel Gomez         }
3456f005199SHarisuddin Mohamed Isa         std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
3466f005199SHarisuddin Mohamed Isa         if (!hidden && actionFlags.test(hiddenFlagBit))
3476f005199SHarisuddin Mohamed Isa         {
3486f005199SHarisuddin Mohamed Isa             return listStr;
3496f005199SHarisuddin Mohamed Isa         }
3506f005199SHarisuddin Mohamed Isa         if (pel.primarySRC() && scrubRegex)
3516f005199SHarisuddin Mohamed Isa         {
3526f005199SHarisuddin Mohamed Isa             val = pel.primarySRC().value()->asciiString();
3536f005199SHarisuddin Mohamed Isa             if (std::regex_search(trimEnd(val), scrubRegex.value(),
3546f005199SHarisuddin Mohamed Isa                                   std::regex_constants::match_not_null))
3556f005199SHarisuddin Mohamed Isa             {
3566f005199SHarisuddin Mohamed Isa                 return listStr;
3576f005199SHarisuddin Mohamed Isa             }
3586f005199SHarisuddin Mohamed Isa         }
359ed32c8daSHarisuddin Mohamed Isa         if (hexDump)
360ed32c8daSHarisuddin Mohamed Isa         {
3618c8aaa06SArya K Padman             std::cout
3628c8aaa06SArya K Padman                 << dumpHex(std::data(pel.data()), pel.size(), 0, false).get()
363ed32c8daSHarisuddin Mohamed Isa                 << std::endl;
364ed32c8daSHarisuddin Mohamed Isa         }
365ed32c8daSHarisuddin Mohamed Isa         else if (fullPEL)
366a214ed30SHarisuddin Mohamed Isa         {
367a214ed30SHarisuddin Mohamed Isa             if (!foundPEL)
368a214ed30SHarisuddin Mohamed Isa             {
3696f005199SHarisuddin Mohamed Isa                 std::cout << "[\n";
370a214ed30SHarisuddin Mohamed Isa                 foundPEL = true;
371a214ed30SHarisuddin Mohamed Isa             }
372a214ed30SHarisuddin Mohamed Isa             else
373a214ed30SHarisuddin Mohamed Isa             {
3746f005199SHarisuddin Mohamed Isa                 std::cout << ",\n\n";
375a214ed30SHarisuddin Mohamed Isa             }
376f67bafd0SHarisuddin Mohamed Isa             pel.toJSON(registry, plugins);
377a214ed30SHarisuddin Mohamed Isa         }
378a214ed30SHarisuddin Mohamed Isa         else
379a214ed30SHarisuddin Mohamed Isa         {
3807b291ec6SAatir             // id
3813025d0b5SMatt Spinler             listStr += "    \"" +
3826f005199SHarisuddin Mohamed Isa                        getNumberString("0x%X", pel.privateHeader().id()) +
3836f005199SHarisuddin Mohamed Isa                        "\": {\n";
3847b291ec6SAatir             // ASCII
3850f717e10SHarisuddin Mohamed Isa             if (pel.primarySRC())
3860f717e10SHarisuddin Mohamed Isa             {
3870f717e10SHarisuddin Mohamed Isa                 val = pel.primarySRC().value()->asciiString();
3883025d0b5SMatt Spinler                 jsonInsert(listStr, "SRC", trimEnd(val), 2);
3893025d0b5SMatt Spinler 
3900f717e10SHarisuddin Mohamed Isa                 // Registry message
3910f717e10SHarisuddin Mohamed Isa                 auto regVal = pel.primarySRC().value()->getErrorDetails(
3920f717e10SHarisuddin Mohamed Isa                     registry, DetailLevel::message, true);
3930f717e10SHarisuddin Mohamed Isa                 if (regVal)
3940f717e10SHarisuddin Mohamed Isa                 {
3950f717e10SHarisuddin Mohamed Isa                     val = regVal.value();
3963025d0b5SMatt Spinler                     jsonInsert(listStr, "Message", val, 2);
3970f717e10SHarisuddin Mohamed Isa                 }
3980f717e10SHarisuddin Mohamed Isa             }
3990f717e10SHarisuddin Mohamed Isa             else
4000f717e10SHarisuddin Mohamed Isa             {
4013025d0b5SMatt Spinler                 jsonInsert(listStr, "SRC", "No SRC", 2);
4020f717e10SHarisuddin Mohamed Isa             }
4033025d0b5SMatt Spinler 
4047b291ec6SAatir             // platformid
4053025d0b5SMatt Spinler             jsonInsert(listStr, "PLID",
4063025d0b5SMatt Spinler                        getNumberString("0x%X", pel.privateHeader().plid()), 2);
4073025d0b5SMatt Spinler 
4087b291ec6SAatir             // creatorid
4096f005199SHarisuddin Mohamed Isa             std::string creatorID =
4106f005199SHarisuddin Mohamed Isa                 getNumberString("%c", pel.privateHeader().creatorID());
4116f005199SHarisuddin Mohamed Isa             val = pv::creatorIDs.count(creatorID) ? pv::creatorIDs.at(creatorID)
4127b291ec6SAatir                                                   : "Unknown Creator ID";
4133025d0b5SMatt Spinler             jsonInsert(listStr, "CreatorID", val, 2);
4143025d0b5SMatt Spinler 
4153025d0b5SMatt Spinler             // subsystem
4166f005199SHarisuddin Mohamed Isa             std::string subsystem = pv::getValue(pel.userHeader().subsystem(),
4176f005199SHarisuddin Mohamed Isa                                                  pel_values::subsystemValues);
4183025d0b5SMatt Spinler             jsonInsert(listStr, "Subsystem", subsystem, 2);
4193025d0b5SMatt Spinler 
4207b291ec6SAatir             // commit time
421be952d2eSMatt Spinler             char tmpValStr[50];
4227b291ec6SAatir             sprintf(tmpValStr, "%02X/%02X/%02X%02X %02X:%02X:%02X",
4237b291ec6SAatir                     pel.privateHeader().commitTimestamp().month,
4247b291ec6SAatir                     pel.privateHeader().commitTimestamp().day,
4257b291ec6SAatir                     pel.privateHeader().commitTimestamp().yearMSB,
4267b291ec6SAatir                     pel.privateHeader().commitTimestamp().yearLSB,
4277b291ec6SAatir                     pel.privateHeader().commitTimestamp().hour,
4287b291ec6SAatir                     pel.privateHeader().commitTimestamp().minutes,
4297b291ec6SAatir                     pel.privateHeader().commitTimestamp().seconds);
4303025d0b5SMatt Spinler             jsonInsert(listStr, "Commit Time", tmpValStr, 2);
4313025d0b5SMatt Spinler 
4327b291ec6SAatir             // severity
4337b291ec6SAatir             std::string severity = pv::getValue(pel.userHeader().severity(),
4347b291ec6SAatir                                                 pel_values::severityValues);
4353025d0b5SMatt Spinler             jsonInsert(listStr, "Sev", severity, 2);
4363025d0b5SMatt Spinler 
4377b291ec6SAatir             // compID
4389a808709SMatt Spinler             jsonInsert(
4399a808709SMatt Spinler                 listStr, "CompID",
4409a808709SMatt Spinler                 getComponentName(pel.privateHeader().header().componentID,
4419a808709SMatt Spinler                                  pel.privateHeader().creatorID()),
4423025d0b5SMatt Spinler                 2);
4433025d0b5SMatt Spinler 
444be952d2eSMatt Spinler             auto found = listStr.rfind(",");
4457b291ec6SAatir             if (found != std::string::npos)
4467b291ec6SAatir             {
4477b291ec6SAatir                 listStr.replace(found, 1, "");
4483025d0b5SMatt Spinler                 listStr += "    },\n";
4497b291ec6SAatir             }
4506f005199SHarisuddin Mohamed Isa             foundPEL = true;
4517b291ec6SAatir         }
45237822f68SAatir     }
45366491c61SPatrick Williams     catch (const std::exception& e)
4547b291ec6SAatir     {
455a561ff6aSMatt Spinler         log<level::ERR>("Hit exception while reading PEL File",
456a561ff6aSMatt Spinler                         entry("FILENAME=%s", fileName.c_str()),
457a561ff6aSMatt Spinler                         entry("ERROR=%s", e.what()));
4587b291ec6SAatir     }
4597b291ec6SAatir     return listStr;
4607b291ec6SAatir }
461a214ed30SHarisuddin Mohamed Isa 
4627b291ec6SAatir /**
463a214ed30SHarisuddin Mohamed Isa  * @brief Print a list of PELs or a JSON array of PELs
464a214ed30SHarisuddin Mohamed Isa  * @param[in] order - Boolean to print in reverse orser
465a214ed30SHarisuddin Mohamed Isa  * @param[in] hidden - Boolean to include hidden PELs
4660c57a67bSHarisuddin Mohamed Isa  * @param[in] includeInfo - Boolean to include informational PELs
467011ccae0SMiguel Gomez  * @param[in] critSysTerm - Boolean to include critical error and system
468011ccae0SMiguel Gomez  * termination PELs
469a214ed30SHarisuddin Mohamed Isa  * @param[in] fullPEL - Boolean to print full PEL into a JSON array
4706f005199SHarisuddin Mohamed Isa  * @param[in] scrubRegex - SRC regex object
471ed32c8daSHarisuddin Mohamed Isa  * @param[in] hexDump - Boolean to print hexdump of PEL instead of JSON
4727b291ec6SAatir  */
printPELs(bool order,bool hidden,bool includeInfo,bool critSysTerm,bool fullPEL,const std::optional<std::regex> & scrubRegex,bool hexDump,bool archive=false)473011ccae0SMiguel Gomez void printPELs(bool order, bool hidden, bool includeInfo, bool critSysTerm,
474011ccae0SMiguel Gomez                bool fullPEL, const std::optional<std::regex>& scrubRegex,
4751d8835bbSSumit Kumar                bool hexDump, bool archive = false)
4767b291ec6SAatir {
4777b291ec6SAatir     std::string listStr;
478104c7967SSumit Kumar     std::vector<std::pair<uint32_t, uint64_t>> PELs;
479f67bafd0SHarisuddin Mohamed Isa     std::vector<std::string> plugins;
4807b291ec6SAatir     listStr = "{\n";
4811d8835bbSSumit Kumar     for (auto it = (archive ? fs::directory_iterator(pelLogDir() + "/archive")
4821d8835bbSSumit Kumar                             : fs::directory_iterator(pelLogDir()));
4837b291ec6SAatir          it != fs::directory_iterator(); ++it)
4847b291ec6SAatir     {
4857b291ec6SAatir         if (!fs::is_regular_file((*it).path()))
4867b291ec6SAatir         {
4877b291ec6SAatir             continue;
4887b291ec6SAatir         }
48937822f68SAatir         else
4907b291ec6SAatir         {
491104c7967SSumit Kumar             PELs.emplace_back(fileNameToPELId((*it).path().filename()),
49237822f68SAatir                               fileNameToTimestamp((*it).path().filename()));
4937b291ec6SAatir         }
4947b291ec6SAatir     }
4951d8835bbSSumit Kumar 
496104c7967SSumit Kumar     // Sort the pairs based on second time parameter
497be952d2eSMatt Spinler     std::sort(PELs.begin(), PELs.end(),
498be952d2eSMatt Spinler               [](const auto& left, const auto& right) {
499104c7967SSumit Kumar                   return left.second < right.second;
500104c7967SSumit Kumar               });
501104c7967SSumit Kumar 
502a214ed30SHarisuddin Mohamed Isa     bool foundPEL = false;
503ed32c8daSHarisuddin Mohamed Isa 
504ed32c8daSHarisuddin Mohamed Isa     if (fullPEL && !hexDump)
505f67bafd0SHarisuddin Mohamed Isa     {
506f67bafd0SHarisuddin Mohamed Isa         plugins = getPlugins();
507f67bafd0SHarisuddin Mohamed Isa     }
508011ccae0SMiguel Gomez     auto buildJSON = [&listStr, &hidden, &includeInfo, &critSysTerm, &fullPEL,
5091d8835bbSSumit Kumar                       &foundPEL, &scrubRegex, &plugins, &hexDump,
5101d8835bbSSumit Kumar                       &archive](const auto& i) {
511011ccae0SMiguel Gomez         listStr += genPELJSON(i, hidden, includeInfo, critSysTerm, fullPEL,
5121d8835bbSSumit Kumar                               foundPEL, scrubRegex, plugins, hexDump, archive);
51337822f68SAatir     };
5147b291ec6SAatir     if (order)
5157b291ec6SAatir     {
5167b291ec6SAatir         std::for_each(PELs.rbegin(), PELs.rend(), buildJSON);
5177b291ec6SAatir     }
5187b291ec6SAatir     else
5197b291ec6SAatir     {
5207b291ec6SAatir         std::for_each(PELs.begin(), PELs.end(), buildJSON);
5217b291ec6SAatir     }
522ed32c8daSHarisuddin Mohamed Isa     if (hexDump)
523ed32c8daSHarisuddin Mohamed Isa     {
524ed32c8daSHarisuddin Mohamed Isa         return;
525ed32c8daSHarisuddin Mohamed Isa     }
5266f005199SHarisuddin Mohamed Isa     if (foundPEL)
5276f005199SHarisuddin Mohamed Isa     {
5286f005199SHarisuddin Mohamed Isa         if (fullPEL)
5296f005199SHarisuddin Mohamed Isa         {
5306f005199SHarisuddin Mohamed Isa             std::cout << "]" << std::endl;
5316f005199SHarisuddin Mohamed Isa         }
5326f005199SHarisuddin Mohamed Isa         else
533a214ed30SHarisuddin Mohamed Isa         {
534a214ed30SHarisuddin Mohamed Isa             std::size_t found;
5357b291ec6SAatir             found = listStr.rfind(",");
5367b291ec6SAatir             if (found != std::string::npos)
5377b291ec6SAatir             {
5387b291ec6SAatir                 listStr.replace(found, 1, "");
5396f005199SHarisuddin Mohamed Isa                 listStr += "}\n";
5407b291ec6SAatir                 printf("%s", listStr.c_str());
5417b291ec6SAatir             }
5427b291ec6SAatir         }
5436f005199SHarisuddin Mohamed Isa     }
5446f005199SHarisuddin Mohamed Isa     else
545a214ed30SHarisuddin Mohamed Isa     {
5466f005199SHarisuddin Mohamed Isa         std::string emptyJSON = fullPEL ? "[]" : "{}";
5476f005199SHarisuddin Mohamed Isa         std::cout << emptyJSON << std::endl;
548a214ed30SHarisuddin Mohamed Isa     }
549a214ed30SHarisuddin Mohamed Isa }
550186ce8c9SAatir 
55127de6f38SMatt Spinler /**
55227de6f38SMatt Spinler  * @brief Calls the function passed in on the PEL with the ID
55327de6f38SMatt Spinler  *        passed in.
55427de6f38SMatt Spinler  *
55558d3a988SHarisuddin Mohamed Isa  * @param[in] id - The string version of the PEL or BMC Log ID, either with or
55627de6f38SMatt Spinler  *                 without the 0x prefix.
557ed32c8daSHarisuddin Mohamed Isa  * @param[in] func - The std::function<void(const PEL&, bool hexDump)> function
558ed32c8daSHarisuddin Mohamed Isa  *                   to run.
55958d3a988SHarisuddin Mohamed Isa  * @param[in] useBMC - if true, search by BMC Log ID, else search by PEL ID
560ed32c8daSHarisuddin Mohamed Isa  * @param[in] hexDump - Boolean to print hexdump of PEL instead of JSON
56127de6f38SMatt Spinler  */
callFunctionOnPEL(const std::string & id,const PELFunc & func,bool useBMC=false,bool hexDump=false,bool archive=false)562ed32c8daSHarisuddin Mohamed Isa void callFunctionOnPEL(const std::string& id, const PELFunc& func,
5631d8835bbSSumit Kumar                        bool useBMC = false, bool hexDump = false,
5641d8835bbSSumit Kumar                        bool archive = false)
56527de6f38SMatt Spinler {
56627de6f38SMatt Spinler     std::string pelID{id};
56758d3a988SHarisuddin Mohamed Isa     if (!useBMC)
56858d3a988SHarisuddin Mohamed Isa     {
56927de6f38SMatt Spinler         std::transform(pelID.begin(), pelID.end(), pelID.begin(), toupper);
57027de6f38SMatt Spinler 
571be952d2eSMatt Spinler         if (pelID.starts_with("0X"))
57227de6f38SMatt Spinler         {
57327de6f38SMatt Spinler             pelID.erase(0, 2);
57427de6f38SMatt Spinler         }
57558d3a988SHarisuddin Mohamed Isa     }
57627de6f38SMatt Spinler 
57727de6f38SMatt Spinler     bool found = false;
57827de6f38SMatt Spinler 
5791d8835bbSSumit Kumar     for (auto it = (archive ? fs::directory_iterator(pelLogDir() + "/archive")
5801d8835bbSSumit Kumar                             : fs::directory_iterator(pelLogDir()));
58127de6f38SMatt Spinler          it != fs::directory_iterator(); ++it)
58227de6f38SMatt Spinler     {
58358d3a988SHarisuddin Mohamed Isa         // The PEL ID is part of the filename, so use that to find the PEL if
58458d3a988SHarisuddin Mohamed Isa         // "useBMC" is set to false, otherwise we have to search within the PEL
58527de6f38SMatt Spinler 
58627de6f38SMatt Spinler         if (!fs::is_regular_file((*it).path()))
58727de6f38SMatt Spinler         {
58827de6f38SMatt Spinler             continue;
58927de6f38SMatt Spinler         }
59027de6f38SMatt Spinler 
59180129fe8SMatt Spinler         if ((endsWithPelID((*it).path(), pelID) && !useBMC) || useBMC)
59227de6f38SMatt Spinler         {
59327de6f38SMatt Spinler             auto data = getFileData((*it).path());
59427de6f38SMatt Spinler             if (!data.empty())
59527de6f38SMatt Spinler             {
59627de6f38SMatt Spinler                 PEL pel{data};
59758d3a988SHarisuddin Mohamed Isa                 if (!useBMC ||
59858d3a988SHarisuddin Mohamed Isa                     (useBMC && pel.obmcLogID() == std::stoul(id, nullptr, 0)))
59958d3a988SHarisuddin Mohamed Isa                 {
60058d3a988SHarisuddin Mohamed Isa                     found = true;
60127de6f38SMatt Spinler                     try
60227de6f38SMatt Spinler                     {
603ed32c8daSHarisuddin Mohamed Isa                         func(pel, hexDump);
60458d3a988SHarisuddin Mohamed Isa                         break;
60527de6f38SMatt Spinler                     }
60666491c61SPatrick Williams                     catch (const std::exception& e)
60727de6f38SMatt Spinler                     {
60858d3a988SHarisuddin Mohamed Isa                         std::cerr << " Internal function threw an exception: "
60958d3a988SHarisuddin Mohamed Isa                                   << e.what() << "\n";
61027de6f38SMatt Spinler                         exit(1);
61127de6f38SMatt Spinler                     }
61227de6f38SMatt Spinler                 }
61358d3a988SHarisuddin Mohamed Isa             }
61427de6f38SMatt Spinler             else
61527de6f38SMatt Spinler             {
61627de6f38SMatt Spinler                 std::cerr << "Could not read PEL file\n";
61727de6f38SMatt Spinler                 exit(1);
61827de6f38SMatt Spinler             }
61927de6f38SMatt Spinler         }
62027de6f38SMatt Spinler     }
62127de6f38SMatt Spinler 
62227de6f38SMatt Spinler     if (!found)
62327de6f38SMatt Spinler     {
62427de6f38SMatt Spinler         std::cerr << "PEL not found\n";
62527de6f38SMatt Spinler         exit(1);
62627de6f38SMatt Spinler     }
62727de6f38SMatt Spinler }
62827de6f38SMatt Spinler 
62927de6f38SMatt Spinler /**
63025d986c1SMatt Spinler  * @brief Delete a PEL file.
63127de6f38SMatt Spinler  *
63225d986c1SMatt Spinler  * @param[in] id - The PEL ID to delete.
63327de6f38SMatt Spinler  */
deletePEL(const std::string & id)63425d986c1SMatt Spinler void deletePEL(const std::string& id)
63527de6f38SMatt Spinler {
63625d986c1SMatt Spinler     std::string pelID{id};
63727de6f38SMatt Spinler 
63825d986c1SMatt Spinler     std::transform(pelID.begin(), pelID.end(), pelID.begin(), toupper);
63925d986c1SMatt Spinler 
640be952d2eSMatt Spinler     if (pelID.starts_with("0X"))
64127de6f38SMatt Spinler     {
64225d986c1SMatt Spinler         pelID.erase(0, 2);
64327de6f38SMatt Spinler     }
64425d986c1SMatt Spinler 
645b6b25575SWilliam A. Kennington III     for (auto it = fs::directory_iterator(pelLogDir());
64625d986c1SMatt Spinler          it != fs::directory_iterator(); ++it)
64727de6f38SMatt Spinler     {
64880129fe8SMatt Spinler         if (endsWithPelID((*it).path(), pelID))
64925d986c1SMatt Spinler         {
65025d986c1SMatt Spinler             fs::remove((*it).path());
65125d986c1SMatt Spinler         }
65227de6f38SMatt Spinler     }
65327de6f38SMatt Spinler }
65427de6f38SMatt Spinler 
65527de6f38SMatt Spinler /**
65625d986c1SMatt Spinler  * @brief Delete all PEL files.
65727de6f38SMatt Spinler  */
deleteAllPELs()65827de6f38SMatt Spinler void deleteAllPELs()
65927de6f38SMatt Spinler {
660a561ff6aSMatt Spinler     log<level::INFO>("peltool deleting all event logs");
66127de6f38SMatt Spinler 
662b6b25575SWilliam A. Kennington III     for (const auto& entry : fs::directory_iterator(pelLogDir()))
66327de6f38SMatt Spinler     {
6641d8835bbSSumit Kumar         if (!fs::is_regular_file(entry.path()))
6651d8835bbSSumit Kumar         {
6661d8835bbSSumit Kumar             continue;
6671d8835bbSSumit Kumar         }
66825d986c1SMatt Spinler         fs::remove(entry.path());
66927de6f38SMatt Spinler     }
67027de6f38SMatt Spinler }
67127de6f38SMatt Spinler 
6721b420bcdSMatt Spinler /**
6731b420bcdSMatt Spinler  * @brief Display a single PEL
6741b420bcdSMatt Spinler  *
6751b420bcdSMatt Spinler  * @param[in] pel - the PEL to display
676ed32c8daSHarisuddin Mohamed Isa  * @param[in] hexDump - Boolean to print hexdump of PEL instead of JSON
6771b420bcdSMatt Spinler  */
displayPEL(const PEL & pel,bool hexDump)678ed32c8daSHarisuddin Mohamed Isa void displayPEL(const PEL& pel, bool hexDump)
6791b420bcdSMatt Spinler {
6801b420bcdSMatt Spinler     if (pel.valid())
6811b420bcdSMatt Spinler     {
682ed32c8daSHarisuddin Mohamed Isa         if (hexDump)
683ed32c8daSHarisuddin Mohamed Isa         {
6848c8aaa06SArya K Padman             std::string dstr =
6858c8aaa06SArya K Padman                 dumpHex(std::data(pel.data()), pel.size(), 0, false).get();
686ed32c8daSHarisuddin Mohamed Isa             std::cout << dstr << std::endl;
687ed32c8daSHarisuddin Mohamed Isa         }
688ed32c8daSHarisuddin Mohamed Isa         else
689ed32c8daSHarisuddin Mohamed Isa         {
690f67bafd0SHarisuddin Mohamed Isa             auto plugins = getPlugins();
691f67bafd0SHarisuddin Mohamed Isa             pel.toJSON(registry, plugins);
6921b420bcdSMatt Spinler         }
693ed32c8daSHarisuddin Mohamed Isa     }
6941b420bcdSMatt Spinler     else
6951b420bcdSMatt Spinler     {
6961b420bcdSMatt Spinler         std::cerr << "PEL was malformed\n";
6971b420bcdSMatt Spinler         exit(1);
6981b420bcdSMatt Spinler     }
6991b420bcdSMatt Spinler }
7001b420bcdSMatt Spinler 
701d4002f39SHarisuddin Mohamed Isa /**
702d4002f39SHarisuddin Mohamed Isa  * @brief Print number of PELs
703d4002f39SHarisuddin Mohamed Isa  * @param[in] hidden - Bool to include hidden logs
7040c57a67bSHarisuddin Mohamed Isa  * @param[in] includeInfo - Bool to include informational logs
705011ccae0SMiguel Gomez  * @param[in] critSysTerm - Bool to include CritSysTerm
7066f005199SHarisuddin Mohamed Isa  * @param[in] scrubRegex - SRC regex object
707d4002f39SHarisuddin Mohamed Isa  */
printPELCount(bool hidden,bool includeInfo,bool critSysTerm,const std::optional<std::regex> & scrubRegex)708011ccae0SMiguel Gomez void printPELCount(bool hidden, bool includeInfo, bool critSysTerm,
7090c57a67bSHarisuddin Mohamed Isa                    const std::optional<std::regex>& scrubRegex)
710d4002f39SHarisuddin Mohamed Isa {
711d4002f39SHarisuddin Mohamed Isa     std::size_t count = 0;
712b6b25575SWilliam A. Kennington III 
713b6b25575SWilliam A. Kennington III     for (auto it = fs::directory_iterator(pelLogDir());
714d4002f39SHarisuddin Mohamed Isa          it != fs::directory_iterator(); ++it)
715d4002f39SHarisuddin Mohamed Isa     {
716d4002f39SHarisuddin Mohamed Isa         if (!fs::is_regular_file((*it).path()))
717d4002f39SHarisuddin Mohamed Isa         {
718d4002f39SHarisuddin Mohamed Isa             continue;
719d4002f39SHarisuddin Mohamed Isa         }
720d4002f39SHarisuddin Mohamed Isa         std::vector<uint8_t> data = getFileData((*it).path());
7216f005199SHarisuddin Mohamed Isa         if (data.empty())
722d4002f39SHarisuddin Mohamed Isa         {
7236f005199SHarisuddin Mohamed Isa             continue;
7246f005199SHarisuddin Mohamed Isa         }
725d4002f39SHarisuddin Mohamed Isa         PEL pel{data};
7266f005199SHarisuddin Mohamed Isa         if (!pel.valid())
727d4002f39SHarisuddin Mohamed Isa         {
7286f005199SHarisuddin Mohamed Isa             continue;
7296f005199SHarisuddin Mohamed Isa         }
7300c57a67bSHarisuddin Mohamed Isa         if (!includeInfo && pel.userHeader().severity() == 0)
7310c57a67bSHarisuddin Mohamed Isa         {
7320c57a67bSHarisuddin Mohamed Isa             continue;
7330c57a67bSHarisuddin Mohamed Isa         }
734011ccae0SMiguel Gomez         if (critSysTerm && pel.userHeader().severity() != critSysTermSeverity)
735011ccae0SMiguel Gomez         {
736011ccae0SMiguel Gomez             continue;
737011ccae0SMiguel Gomez         }
7386f005199SHarisuddin Mohamed Isa         std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
7396f005199SHarisuddin Mohamed Isa         if (!hidden && actionFlags.test(hiddenFlagBit))
7406f005199SHarisuddin Mohamed Isa         {
7416f005199SHarisuddin Mohamed Isa             continue;
7426f005199SHarisuddin Mohamed Isa         }
7436f005199SHarisuddin Mohamed Isa         if (pel.primarySRC() && scrubRegex)
7446f005199SHarisuddin Mohamed Isa         {
7456f005199SHarisuddin Mohamed Isa             std::string val = pel.primarySRC().value()->asciiString();
7466f005199SHarisuddin Mohamed Isa             if (std::regex_search(trimEnd(val), scrubRegex.value(),
7476f005199SHarisuddin Mohamed Isa                                   std::regex_constants::match_not_null))
7486f005199SHarisuddin Mohamed Isa             {
7496f005199SHarisuddin Mohamed Isa                 continue;
7506f005199SHarisuddin Mohamed Isa             }
7516f005199SHarisuddin Mohamed Isa         }
752d4002f39SHarisuddin Mohamed Isa         count++;
753d4002f39SHarisuddin Mohamed Isa     }
754d4002f39SHarisuddin Mohamed Isa     std::cout << "{\n"
755d4002f39SHarisuddin Mohamed Isa               << "    \"Number of PELs found\": "
7566f005199SHarisuddin Mohamed Isa               << getNumberString("%d", count) << "\n}\n";
7576f005199SHarisuddin Mohamed Isa }
7586f005199SHarisuddin Mohamed Isa 
7596f005199SHarisuddin Mohamed Isa /**
7606f005199SHarisuddin Mohamed Isa  * @brief Generate regex pattern object from file contents
7616f005199SHarisuddin Mohamed Isa  * @param[in] scrubFile - File containing regex pattern
7626f005199SHarisuddin Mohamed Isa  * @return std::regex - SRC regex object
7636f005199SHarisuddin Mohamed Isa  */
genRegex(std::string & scrubFile)7646f005199SHarisuddin Mohamed Isa std::regex genRegex(std::string& scrubFile)
7656f005199SHarisuddin Mohamed Isa {
7666f005199SHarisuddin Mohamed Isa     std::string pattern;
7676f005199SHarisuddin Mohamed Isa     std::ifstream contents(scrubFile);
7686f005199SHarisuddin Mohamed Isa     if (contents.fail())
7696f005199SHarisuddin Mohamed Isa     {
7706f005199SHarisuddin Mohamed Isa         std::cerr << "Can't open \"" << scrubFile << "\"\n";
7716f005199SHarisuddin Mohamed Isa         exit(1);
7726f005199SHarisuddin Mohamed Isa     }
7736f005199SHarisuddin Mohamed Isa     std::string line;
7746f005199SHarisuddin Mohamed Isa     while (std::getline(contents, line))
7756f005199SHarisuddin Mohamed Isa     {
7766f005199SHarisuddin Mohamed Isa         if (!line.empty())
7776f005199SHarisuddin Mohamed Isa         {
7786f005199SHarisuddin Mohamed Isa             pattern.append(line + "|");
7796f005199SHarisuddin Mohamed Isa         }
7806f005199SHarisuddin Mohamed Isa     }
7816f005199SHarisuddin Mohamed Isa     try
7826f005199SHarisuddin Mohamed Isa     {
7836f005199SHarisuddin Mohamed Isa         std::regex scrubRegex(pattern, std::regex::icase);
7846f005199SHarisuddin Mohamed Isa         return scrubRegex;
7856f005199SHarisuddin Mohamed Isa     }
78666491c61SPatrick Williams     catch (const std::regex_error& e)
7876f005199SHarisuddin Mohamed Isa     {
7886f005199SHarisuddin Mohamed Isa         if (e.code() == std::regex_constants::error_collate)
7896f005199SHarisuddin Mohamed Isa             std::cerr << "Invalid collating element request\n";
7906f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_ctype)
7916f005199SHarisuddin Mohamed Isa             std::cerr << "Invalid character class\n";
7926f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_escape)
7936f005199SHarisuddin Mohamed Isa             std::cerr << "Invalid escape character or trailing escape\n";
7946f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_backref)
7956f005199SHarisuddin Mohamed Isa             std::cerr << "Invalid back reference\n";
7966f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_brack)
7976f005199SHarisuddin Mohamed Isa             std::cerr << "Mismatched bracket ([ or ])\n";
7986f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_paren)
7996f005199SHarisuddin Mohamed Isa         {
8006f005199SHarisuddin Mohamed Isa             // to catch return code error_badrepeat when error_paren is retured
8016f005199SHarisuddin Mohamed Isa             // instead
8026f005199SHarisuddin Mohamed Isa             size_t pos = pattern.find_first_of("*+?{");
8036f005199SHarisuddin Mohamed Isa             while (pos != std::string::npos)
8046f005199SHarisuddin Mohamed Isa             {
8056f005199SHarisuddin Mohamed Isa                 if (pos == 0 || pattern.substr(pos - 1, 1) == "|")
8066f005199SHarisuddin Mohamed Isa                 {
8076f005199SHarisuddin Mohamed Isa                     std::cerr
8086f005199SHarisuddin Mohamed Isa                         << "A repetition character (*, ?, +, or {) was not "
8096f005199SHarisuddin Mohamed Isa                            "preceded by a valid regular expression\n";
8106f005199SHarisuddin Mohamed Isa                     exit(1);
8116f005199SHarisuddin Mohamed Isa                 }
8126f005199SHarisuddin Mohamed Isa                 pos = pattern.find_first_of("*+?{", pos + 1);
8136f005199SHarisuddin Mohamed Isa             }
8146f005199SHarisuddin Mohamed Isa             std::cerr << "Mismatched parentheses (( or ))\n";
8156f005199SHarisuddin Mohamed Isa         }
8166f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_brace)
8176f005199SHarisuddin Mohamed Isa             std::cerr << "Mismatched brace ({ or })\n";
8186f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_badbrace)
8196f005199SHarisuddin Mohamed Isa             std::cerr << "Invalid range inside a { }\n";
8206f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_range)
8216f005199SHarisuddin Mohamed Isa             std::cerr << "Invalid character range (e.g., [z-a])\n";
8226f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_space)
8236f005199SHarisuddin Mohamed Isa             std::cerr << "Insufficient memory to handle regular expression\n";
8246f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_badrepeat)
8256f005199SHarisuddin Mohamed Isa             std::cerr << "A repetition character (*, ?, +, or {) was not "
8266f005199SHarisuddin Mohamed Isa                          "preceded by a valid regular expression\n";
8276f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_complexity)
8286f005199SHarisuddin Mohamed Isa             std::cerr << "The requested match is too complex\n";
8296f005199SHarisuddin Mohamed Isa         else if (e.code() == std::regex_constants::error_stack)
8306f005199SHarisuddin Mohamed Isa             std::cerr << "Insufficient memory to evaluate a match\n";
8316f005199SHarisuddin Mohamed Isa         exit(1);
8326f005199SHarisuddin Mohamed Isa     }
833d4002f39SHarisuddin Mohamed Isa }
834d4002f39SHarisuddin Mohamed Isa 
exitWithError(const std::string & help,const char * err)835186ce8c9SAatir static void exitWithError(const std::string& help, const char* err)
836186ce8c9SAatir {
837186ce8c9SAatir     std::cerr << "ERROR: " << err << std::endl << help << std::endl;
838186ce8c9SAatir     exit(-1);
839186ce8c9SAatir }
840186ce8c9SAatir 
main(int argc,char ** argv)841186ce8c9SAatir int main(int argc, char** argv)
842186ce8c9SAatir {
843186ce8c9SAatir     CLI::App app{"OpenBMC PEL Tool"};
844186ce8c9SAatir     std::string fileName;
845e340c13fSAatir     std::string idPEL;
84658d3a988SHarisuddin Mohamed Isa     std::string bmcId;
84727de6f38SMatt Spinler     std::string idToDelete;
8486f005199SHarisuddin Mohamed Isa     std::string scrubFile;
8496f005199SHarisuddin Mohamed Isa     std::optional<std::regex> scrubRegex;
850e340c13fSAatir     bool listPEL = false;
851e340c13fSAatir     bool listPELDescOrd = false;
852d4002f39SHarisuddin Mohamed Isa     bool hidden = false;
8530c57a67bSHarisuddin Mohamed Isa     bool includeInfo = false;
854011ccae0SMiguel Gomez     bool critSysTerm = false;
85527de6f38SMatt Spinler     bool deleteAll = false;
856d4002f39SHarisuddin Mohamed Isa     bool showPELCount = false;
857a214ed30SHarisuddin Mohamed Isa     bool fullPEL = false;
858ed32c8daSHarisuddin Mohamed Isa     bool hexDump = false;
8591d8835bbSSumit Kumar     bool archive = false;
86027de6f38SMatt Spinler 
861d4002f39SHarisuddin Mohamed Isa     app.set_help_flag("--help", "Print this help message and exit");
8620c57a67bSHarisuddin Mohamed Isa     app.add_option("--file", fileName, "Display a PEL using its Raw PEL file");
863e340c13fSAatir     app.add_option("-i, --id", idPEL, "Display a PEL based on its ID");
86458d3a988SHarisuddin Mohamed Isa     app.add_option("--bmc-id", bmcId,
86558d3a988SHarisuddin Mohamed Isa                    "Display a PEL based on its BMC Event ID");
866a214ed30SHarisuddin Mohamed Isa     app.add_flag("-a", fullPEL, "Display all PELs");
867bad5f8a2SAatir     app.add_flag("-l", listPEL, "List PELs");
868d4002f39SHarisuddin Mohamed Isa     app.add_flag("-n", showPELCount, "Show number of PELs");
8697b291ec6SAatir     app.add_flag("-r", listPELDescOrd, "Reverse order of output");
870d4002f39SHarisuddin Mohamed Isa     app.add_flag("-h", hidden, "Include hidden PELs");
8710c57a67bSHarisuddin Mohamed Isa     app.add_flag("-f,--info", includeInfo, "Include informational PELs");
872011ccae0SMiguel Gomez     app.add_flag("-t, --termination", critSysTerm,
873011ccae0SMiguel Gomez                  "List only critical system terminating PELs");
87427de6f38SMatt Spinler     app.add_option("-d, --delete", idToDelete, "Delete a PEL based on its ID");
87527de6f38SMatt Spinler     app.add_flag("-D, --delete-all", deleteAll, "Delete all PELs");
8766f005199SHarisuddin Mohamed Isa     app.add_option("-s, --scrub", scrubFile,
8776f005199SHarisuddin Mohamed Isa                    "File containing SRC regular expressions to ignore");
878ed32c8daSHarisuddin Mohamed Isa     app.add_flag("-x", hexDump, "Display PEL(s) in hexdump instead of JSON");
8791d8835bbSSumit Kumar     app.add_flag("--archive", archive, "List or display archived PELs");
88027de6f38SMatt Spinler 
881186ce8c9SAatir     CLI11_PARSE(app, argc, argv);
882186ce8c9SAatir 
883186ce8c9SAatir     if (!fileName.empty())
884186ce8c9SAatir     {
885186ce8c9SAatir         std::vector<uint8_t> data = getFileData(fileName);
886186ce8c9SAatir         if (!data.empty())
887186ce8c9SAatir         {
888186ce8c9SAatir             PEL pel{data};
889ed32c8daSHarisuddin Mohamed Isa             if (hexDump)
890ed32c8daSHarisuddin Mohamed Isa             {
8918c8aaa06SArya K Padman                 std::string dstr =
8928c8aaa06SArya K Padman                     dumpHex(std::data(pel.data()), pel.size(), 0, false).get();
893ed32c8daSHarisuddin Mohamed Isa                 std::cout << dstr << std::endl;
894ed32c8daSHarisuddin Mohamed Isa             }
895ed32c8daSHarisuddin Mohamed Isa             else
896ed32c8daSHarisuddin Mohamed Isa             {
897ed32c8daSHarisuddin Mohamed Isa                 auto plugins = getPlugins();
898f67bafd0SHarisuddin Mohamed Isa                 pel.toJSON(registry, plugins);
899186ce8c9SAatir             }
900ed32c8daSHarisuddin Mohamed Isa         }
901186ce8c9SAatir         else
902186ce8c9SAatir         {
903186ce8c9SAatir             exitWithError(app.help("", CLI::AppFormatMode::All),
904186ce8c9SAatir                           "Raw PEL file can't be read.");
905186ce8c9SAatir         }
906186ce8c9SAatir     }
907e340c13fSAatir     else if (!idPEL.empty())
908e340c13fSAatir     {
9091d8835bbSSumit Kumar         callFunctionOnPEL(idPEL, displayPEL, false, hexDump, archive);
91058d3a988SHarisuddin Mohamed Isa     }
91158d3a988SHarisuddin Mohamed Isa     else if (!bmcId.empty())
91258d3a988SHarisuddin Mohamed Isa     {
9131d8835bbSSumit Kumar         callFunctionOnPEL(bmcId, displayPEL, true, hexDump, archive);
914e340c13fSAatir     }
915a214ed30SHarisuddin Mohamed Isa     else if (fullPEL || listPEL)
9167b291ec6SAatir     {
9176f005199SHarisuddin Mohamed Isa         if (!scrubFile.empty())
9186f005199SHarisuddin Mohamed Isa         {
9196f005199SHarisuddin Mohamed Isa             scrubRegex = genRegex(scrubFile);
9206f005199SHarisuddin Mohamed Isa         }
921011ccae0SMiguel Gomez         printPELs(listPELDescOrd, hidden, includeInfo, critSysTerm, fullPEL,
9221d8835bbSSumit Kumar                   scrubRegex, hexDump, archive);
923d4002f39SHarisuddin Mohamed Isa     }
924d4002f39SHarisuddin Mohamed Isa     else if (showPELCount)
925d4002f39SHarisuddin Mohamed Isa     {
9266f005199SHarisuddin Mohamed Isa         if (!scrubFile.empty())
9276f005199SHarisuddin Mohamed Isa         {
9286f005199SHarisuddin Mohamed Isa             scrubRegex = genRegex(scrubFile);
9296f005199SHarisuddin Mohamed Isa         }
930011ccae0SMiguel Gomez         printPELCount(hidden, includeInfo, critSysTerm, scrubRegex);
9317b291ec6SAatir     }
93227de6f38SMatt Spinler     else if (!idToDelete.empty())
93327de6f38SMatt Spinler     {
93425d986c1SMatt Spinler         deletePEL(idToDelete);
93527de6f38SMatt Spinler     }
93627de6f38SMatt Spinler     else if (deleteAll)
93727de6f38SMatt Spinler     {
93827de6f38SMatt Spinler         deleteAllPELs();
93927de6f38SMatt Spinler     }
940186ce8c9SAatir     else
941186ce8c9SAatir     {
942a214ed30SHarisuddin Mohamed Isa         std::cout << app.help("", CLI::AppFormatMode::All) << std::endl;
943186ce8c9SAatir     }
944f67bafd0SHarisuddin Mohamed Isa     Py_Finalize();
945186ce8c9SAatir     return 0;
946186ce8c9SAatir }
947