blob: 041449e82526f6c27fa6a40fa00e9b10f6f224ce [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM 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 */
Aatir7b291ec2019-11-19 10:37:37 -060016#include "config.h"
17
18#include "../bcd_time.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050019#include "../pel.hpp"
Aatir7b291ec2019-11-19 10:37:37 -060020#include "../pel_types.hpp"
21#include "../pel_values.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050022
23#include <CLI/CLI.hpp>
Aatir7b291ec2019-11-19 10:37:37 -060024#include <bitset>
Aatir186ce8c2019-10-20 15:13:39 -050025#include <iostream>
Aatir7b291ec2019-11-19 10:37:37 -060026#include <phosphor-logging/log.hpp>
27#include <regex>
Aatir186ce8c2019-10-20 15:13:39 -050028#include <string>
Aatir7b291ec2019-11-19 10:37:37 -060029#include <xyz/openbmc_project/Common/File/error.hpp>
Aatir186ce8c2019-10-20 15:13:39 -050030
Aatir7b291ec2019-11-19 10:37:37 -060031namespace fs = std::filesystem;
Aatir186ce8c2019-10-20 15:13:39 -050032using namespace phosphor::logging;
33using namespace openpower::pels;
Aatir7b291ec2019-11-19 10:37:37 -060034namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error;
35namespace message = openpower::pels::message;
36namespace pv = openpower::pels::pel_values;
Aatir186ce8c2019-10-20 15:13:39 -050037
Aatir7b291ec2019-11-19 10:37:37 -060038std::string ltrim(const std::string& s)
39{
40 return std::regex_replace(s, std::regex("^\\s+"), std::string(""));
41}
42
43std::string rtrim(const std::string& s)
44{
45 return std::regex_replace(s, std::regex("\\s+$"), std::string(""));
46}
47
48std::string trim(const std::string& s)
49{
50 return ltrim(rtrim(s));
51}
52
53template <typename T>
54std::string genPELJSON(T itr)
55{
56 std::size_t found;
57 std::string val;
58 char tmpValStr[50];
59 std::string listStr;
60 char name[50];
61 sprintf(name, "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X_%.8X", itr.second.yearMSB,
62 itr.second.yearLSB, itr.second.month, itr.second.day,
63 itr.second.hour, itr.second.minutes, itr.second.seconds,
64 itr.second.hundredths, itr.first);
65 std::string fileName(name);
66 fileName = EXTENSION_PERSIST_DIR "/pels/logs/" + fileName;
67 try
68 {
69 std::ifstream stream(fileName, std::ios::in | std::ios::binary);
70 std::vector<uint8_t> data((std::istreambuf_iterator<char>(stream)),
71 std::istreambuf_iterator<char>());
72 stream.close();
73 PEL pel{data};
74 if (pel.valid())
75 {
76 // id
77 sprintf(tmpValStr, "0x%X", pel.privateHeader().id());
78 val = std::string(tmpValStr);
79 listStr += "\t\"" + val + "\": {\n";
80 // ASCII
81 val = pel.primarySRC() ? pel.primarySRC().value()->asciiString()
82 : "No SRC";
83 listStr += "\t\t\"SRC\": \"" + trim(val) + "\",\n";
84 // platformid
85 sprintf(tmpValStr, "0x%X", pel.privateHeader().plid());
86 val = std::string(tmpValStr);
87 listStr += "\t\t\"PLID\": \"" + val + "\",\n";
88 // creatorid
89 sprintf(tmpValStr, "%c", pel.privateHeader().creatorID());
90 std::string creatorID(tmpValStr);
91 val = pv::creatorIDs.count(creatorID) ? pv::creatorIDs.at(creatorID)
92 : "Unknown Creator ID";
93 listStr += "\t\t\"CreatorID\": \"" + val + "\",\n";
94 // subsytem
95 std::string subsystem = pv::getValue(pel.userHeader().subsystem(),
96 pel_values::subsystemValues);
97 listStr += "\t\t\"Subsystem\": \"" + subsystem + "\",\n";
98 // commit time
99 sprintf(tmpValStr, "%02X/%02X/%02X%02X %02X:%02X:%02X",
100 pel.privateHeader().commitTimestamp().month,
101 pel.privateHeader().commitTimestamp().day,
102 pel.privateHeader().commitTimestamp().yearMSB,
103 pel.privateHeader().commitTimestamp().yearLSB,
104 pel.privateHeader().commitTimestamp().hour,
105 pel.privateHeader().commitTimestamp().minutes,
106 pel.privateHeader().commitTimestamp().seconds);
107 val = std::string(tmpValStr);
108 listStr += "\t\t\"Commit Time\": \"" + val + "\",\n";
109 // severity
110 std::string severity = pv::getValue(pel.userHeader().severity(),
111 pel_values::severityValues);
112 listStr += "\t\t\"Sev\": \"" + severity + "\",\n ";
113 // compID
114 sprintf(tmpValStr, "0x%X",
115 pel.privateHeader().header().componentID);
116 val = std::string(tmpValStr);
117 listStr += "\t\t\"CompID\": \"" + val + "\",\n ";
118
119 found = listStr.rfind(",");
120 if (found != std::string::npos)
121 {
122 listStr.replace(found, 1, "");
123 listStr += "\t}, \n";
124 }
125 }
126 }
127 catch (std::exception& e)
128 {
129 log<level::ERR>("Hit exception while reading PEL File",
130 entry("FILENAME=%s", fileName.c_str()),
131 entry("ERROR=%s", e.what()));
132 }
133 return listStr;
134}
135/**
136 * @brief Print a list of PELs
137 */
138void printList(bool order, bool hidden)
139{
140 std::string listStr;
141 std::map<uint32_t, BCDTime> PELs;
142 std::size_t found;
143 listStr = "{\n";
144 for (auto it = fs::directory_iterator(EXTENSION_PERSIST_DIR "/pels/logs");
145 it != fs::directory_iterator(); ++it)
146 {
147 if (!fs::is_regular_file((*it).path()))
148 {
149 continue;
150 }
151 try
152 {
153 std::ifstream stream((*it).path(), std::ios::in | std::ios::binary);
154 std::vector<uint8_t> data((std::istreambuf_iterator<char>(stream)),
155 std::istreambuf_iterator<char>());
156 stream.close();
157 PEL pel{data};
158 if (pel.valid())
159 {
160
161 std::bitset<16> actionFlags{pel.userHeader().actionFlags()};
162 if (hidden || !actionFlags.test(hiddenFlagBit))
163 {
164 PELs.emplace(pel.id(),
165 pel.privateHeader().commitTimestamp());
166 }
167 }
168 }
169 catch (std::exception& e)
170 {
171 log<level::ERR>("Hit exception while reading PEL File",
172 entry("FILENAME=%s", (*it).path().c_str()),
173 entry("ERROR=%s", e.what()));
174 }
175 }
176 std::string val;
177 auto buildJSON = [&listStr](const auto& i) { listStr += genPELJSON(i); };
178 if (order)
179 {
180 std::for_each(PELs.rbegin(), PELs.rend(), buildJSON);
181 }
182 else
183 {
184 std::for_each(PELs.begin(), PELs.end(), buildJSON);
185 }
186
187 found = listStr.rfind(",");
188 if (found != std::string::npos)
189 {
190 listStr.replace(found, 1, "");
191 listStr += "\n}\n";
192 printf("%s", listStr.c_str());
193 }
194}
Aatir186ce8c2019-10-20 15:13:39 -0500195/**
196 * @brief get data form raw PEL file.
197 * @param[in] std::string Name of file with raw PEL
198 * @return std::vector<uint8_t> char vector read from raw PEL file.
199 */
200std::vector<uint8_t> getFileData(std::string name)
201{
202 std::ifstream file(name, std::ifstream::in);
203 if (file.good())
204 {
205 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
206 std::istreambuf_iterator<char>()};
207 return data;
208 }
209 else
210 {
211 printf("Can't open raw PEL file");
212 return {};
213 }
214}
215
216static void exitWithError(const std::string& help, const char* err)
217{
218 std::cerr << "ERROR: " << err << std::endl << help << std::endl;
219 exit(-1);
220}
221
222int main(int argc, char** argv)
223{
224 CLI::App app{"OpenBMC PEL Tool"};
225 std::string fileName;
Aatir7b291ec2019-11-19 10:37:37 -0600226 bool listPEL;
227 bool listPELDescOrd;
228 bool listPELShowHidden;
229 listPELDescOrd = false;
230 listPELShowHidden = false;
231 app.add_option("-f,--file", fileName, "Raw PEL file");
232 app.add_flag("-l", listPEL, "List PELS");
233 app.add_flag("-r", listPELDescOrd, "Reverse order of output");
234 app.add_flag("-s", listPELShowHidden, "Show hidden PELs");
Aatir186ce8c2019-10-20 15:13:39 -0500235 CLI11_PARSE(app, argc, argv);
236
237 if (!fileName.empty())
238 {
239 std::vector<uint8_t> data = getFileData(fileName);
240 if (!data.empty())
241 {
242 PEL pel{data};
243 pel.toJSON();
244 }
245 else
246 {
247 exitWithError(app.help("", CLI::AppFormatMode::All),
248 "Raw PEL file can't be read.");
249 }
250 }
Aatir7b291ec2019-11-19 10:37:37 -0600251
252 else if (listPEL)
253 {
254
255 printList(listPELDescOrd, listPELShowHidden);
256 }
Aatir186ce8c2019-10-20 15:13:39 -0500257 else
258 {
259 exitWithError(app.help("", CLI::AppFormatMode::All),
260 "Raw PEL file path not specified.");
261 }
262 return 0;
263}