blob: ba8a9d49267fcfb4ead8b2f86803442b670e3c7d [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#include "parser.hpp"
2
3#include "constants.hpp"
4#include "event_logger.hpp"
5
6#include <utility/dbus_utility.hpp>
7#include <utility/json_utility.hpp>
8#include <utility/vpd_specific_utility.hpp>
9
10#include <fstream>
11
12namespace vpd
13{
14Parser::Parser(const std::string& vpdFilePath, nlohmann::json parsedJson) :
15 m_vpdFilePath(vpdFilePath), m_parsedJson(parsedJson)
16{
17 std::error_code l_errCode;
18
19 // ToDo: Add minimum file size check in all the concert praser classes,
20 // depends on their VPD type.
21 if (!std::filesystem::exists(m_vpdFilePath, l_errCode))
22 {
23 std::string l_message{"Parser object creation failed, file [" +
24 m_vpdFilePath + "] doesn't exists."};
25
26 if (l_errCode)
27 {
28 l_message += " Error message: " + l_errCode.message();
29 }
30
31 throw std::runtime_error(l_message);
32 }
33
34 // Read VPD offset if applicable.
35 if (!m_parsedJson.empty())
36 {
Rekha Aparna017567a2025-08-13 02:07:06 -050037 uint16_t l_errorCode = 0;
38
39 m_vpdStartOffset =
40 jsonUtility::getVPDOffset(m_parsedJson, vpdFilePath, l_errorCode);
41
42 if (l_errorCode)
43 {
44 logging::logMessage(
45 "Failed to get vpd offset for path [" + m_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +053046 "], error: " + commonUtility::getErrCodeMsg(l_errorCode));
Rekha Aparna017567a2025-08-13 02:07:06 -050047 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050048 }
49}
50
51std::shared_ptr<vpd::ParserInterface> Parser::getVpdParserInstance()
52{
53 // Read the VPD data into a vector.
Rekha Aparna769d6572025-10-22 09:50:35 -050054 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050055 vpdSpecificUtility::getVpdDataInVector(m_vpdFilePath, m_vpdVector,
Rekha Aparna769d6572025-10-22 09:50:35 -050056 m_vpdStartOffset, l_errCode);
57
58 if (l_errCode)
59 {
60 logging::logMessage("Failed to get VPD in vector, error : " +
61 commonUtility::getErrCodeMsg(l_errCode));
62 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050063
64 // This will detect the type of parser required.
65 std::shared_ptr<vpd::ParserInterface> l_parser =
66 ParserFactory::getParser(m_vpdVector, m_vpdFilePath, m_vpdStartOffset);
67
68 return l_parser;
69}
70
71types::VPDMapVariant Parser::parse()
72{
73 std::shared_ptr<vpd::ParserInterface> l_parser = getVpdParserInstance();
74 return l_parser->parse();
75}
76
Souvik Roy9b0b0fd2025-08-08 05:20:23 +000077int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData,
78 types::DbusVariantType& o_updatedValue)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050079{
80 int l_bytesUpdatedOnHardware = constants::FAILURE;
81
82 // A lambda to extract Record : Keyword string from i_paramsToWriteData
83 auto l_keyWordIdentifier =
84 [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
85 std::string l_keywordString{};
86 if (const types::IpzData* l_ipzData =
87 std::get_if<types::IpzData>(&i_paramsToWriteData))
88 {
89 l_keywordString =
90 std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
91 }
92 else if (const types::KwData* l_kwData =
93 std::get_if<types::KwData>(&i_paramsToWriteData))
94 {
95 l_keywordString = std::get<0>(*l_kwData);
96 }
97 return l_keywordString;
98 };
99
100 try
101 {
102 // Enable Reboot Guard
103 if (constants::FAILURE == dbusUtility::EnableRebootGuard())
104 {
105 EventLogger::createAsyncPel(
106 types::ErrorType::DbusFailure,
107 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
108 std::string(
109 "Failed to enable BMC Reboot Guard while updating " +
110 l_keyWordIdentifier(i_paramsToWriteData)),
111 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
112
113 return constants::FAILURE;
114 }
115
116 // Update keyword's value on hardware
117 try
118 {
119 std::shared_ptr<ParserInterface> l_vpdParserInstance =
120 getVpdParserInstance();
121 l_bytesUpdatedOnHardware =
122 l_vpdParserInstance->writeKeywordOnHardware(
123 i_paramsToWriteData);
124 }
125 catch (const std::exception& l_exception)
126 {
127 std::string l_errMsg(
128 "Error while updating keyword's value on hardware path " +
129 m_vpdFilePath + ", error: " + std::string(l_exception.what()));
130
131 // TODO : Log PEL
132
133 throw std::runtime_error(l_errMsg);
134 }
135
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500136 uint16_t l_errCode = 0;
137
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500138 auto [l_fruPath, l_inventoryObjPath, l_redundantFruPath] =
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500139 jsonUtility::getAllPathsToUpdateKeyword(m_parsedJson, m_vpdFilePath,
140 l_errCode);
141
142 if (l_errCode == error_code::INVALID_INPUT_PARAMETER ||
143 l_errCode == error_code::INVALID_JSON)
144 {
145 throw std::runtime_error(
146 "Failed to get paths to update keyword. Error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530147 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500148 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500149
150 // If inventory D-bus object path is present, update keyword's value on
151 // DBus
152 if (!l_inventoryObjPath.empty())
153 {
154 types::Record l_recordName;
155 std::string l_interfaceName;
156 std::string l_propertyName;
157 types::DbusVariantType l_keywordValue;
158
159 if (const types::IpzData* l_ipzData =
160 std::get_if<types::IpzData>(&i_paramsToWriteData))
161 {
162 l_recordName = std::get<0>(*l_ipzData);
163 l_interfaceName = constants::ipzVpdInf + l_recordName;
164 l_propertyName = std::get<1>(*l_ipzData);
165
166 try
167 {
168 // Read keyword's value from hardware to write the same on
169 // D-bus.
170 std::shared_ptr<ParserInterface> l_vpdParserInstance =
171 getVpdParserInstance();
172
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500173 l_keywordValue =
174 l_vpdParserInstance->readKeywordFromHardware(
175 types::ReadVpdParams(
176 std::make_tuple(l_recordName, l_propertyName)));
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000177
178 // return the actual value updated on hardware
179 o_updatedValue = l_keywordValue;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500180 }
181 catch (const std::exception& l_exception)
182 {
183 // Unable to read keyword's value from hardware.
184 std::string l_errMsg(
185 "Error while reading keyword's value from hadware path " +
186 m_vpdFilePath +
187 ", error: " + std::string(l_exception.what()));
188
189 // TODO: Log PEL
190
191 throw std::runtime_error(l_errMsg);
192 }
193 }
194 else
195 {
196 // Input parameter type provided isn't compatible to perform
197 // update.
198 std::string l_errMsg(
199 "Input parameter type isn't compatible to update keyword's value on DBus for object path: " +
200 l_inventoryObjPath);
201 throw std::runtime_error(l_errMsg);
202 }
203
204 // Get D-bus name for the given keyword
Rekha Aparna769d6572025-10-22 09:50:35 -0500205 l_propertyName = vpdSpecificUtility::getDbusPropNameForGivenKw(
206 l_propertyName, l_errCode);
207
208 if (l_errCode)
209 {
210 logging::logMessage(
211 "Failed to get Dbus property name for given keyword, error : " +
212 commonUtility::getErrCodeMsg(l_errCode));
213 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500214
215 // Create D-bus object map
216 types::ObjectMap l_dbusObjMap = {std::make_pair(
217 l_inventoryObjPath,
218 types::InterfaceMap{std::make_pair(
219 l_interfaceName, types::PropertyMap{std::make_pair(
220 l_propertyName, l_keywordValue)})})};
221
222 // Call PIM's Notify method to perform update
223 if (!dbusUtility::callPIM(std::move(l_dbusObjMap)))
224 {
225 // Call to PIM's Notify method failed.
226 std::string l_errMsg("Notify PIM is failed for object path: " +
227 l_inventoryObjPath);
228 throw std::runtime_error(l_errMsg);
229 }
230 }
231
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500232 if (l_errCode == error_code::ERROR_GETTING_REDUNDANT_PATH)
233 {
Rekha Aparnac6159a22025-10-09 12:20:20 +0530234 logging::logMessage(commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500235 }
236
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500237 // Update keyword's value on redundant hardware if present
238 if (!l_redundantFruPath.empty())
239 {
240 if (updateVpdKeywordOnRedundantPath(l_redundantFruPath,
241 i_paramsToWriteData) < 0)
242 {
243 std::string l_errMsg(
244 "Error while updating keyword's value on redundant path " +
245 l_redundantFruPath);
246 throw std::runtime_error(l_errMsg);
247 }
248 }
249
250 // TODO: Check if revert is required when any of the writes fails.
251 // TODO: Handle error logging
252 }
253 catch (const std::exception& l_ex)
254 {
255 logging::logMessage("Update VPD Keyword failed for : " +
256 l_keyWordIdentifier(i_paramsToWriteData) +
257 " failed due to error: " + l_ex.what());
258
259 // update failed, set return value to failure
260 l_bytesUpdatedOnHardware = constants::FAILURE;
261 }
262
263 // Disable Reboot Guard
264 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
265 {
266 EventLogger::createAsyncPel(
267 types::ErrorType::DbusFailure, types::SeverityType::Critical,
268 __FILE__, __FUNCTION__, 0,
269 std::string("Failed to disable BMC Reboot Guard while updating " +
270 l_keyWordIdentifier(i_paramsToWriteData)),
271 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
272 }
273
274 return l_bytesUpdatedOnHardware;
275}
276
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000277int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData)
278{
279 types::DbusVariantType o_updatedValue;
280 return updateVpdKeyword(i_paramsToWriteData, o_updatedValue);
281}
282
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500283int Parser::updateVpdKeywordOnRedundantPath(
284 const std::string& i_fruPath,
285 const types::WriteVpdParams& i_paramsToWriteData)
286{
287 try
288 {
289 std::shared_ptr<Parser> l_parserObj =
290 std::make_shared<Parser>(i_fruPath, m_parsedJson);
291
292 std::shared_ptr<ParserInterface> l_vpdParserInstance =
293 l_parserObj->getVpdParserInstance();
294
295 return l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
296 }
297 catch (const std::exception& l_exception)
298 {
299 EventLogger::createSyncPel(
300 types::ErrorType::InvalidVpdMessage,
301 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
302 "Error while updating keyword's value on redundant path " +
303 i_fruPath + ", error: " + std::string(l_exception.what()),
304 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
305 return -1;
306 }
307}
308
309int Parser::updateVpdKeywordOnHardware(
310 const types::WriteVpdParams& i_paramsToWriteData)
311{
312 int l_bytesUpdatedOnHardware = constants::FAILURE;
313
314 // A lambda to extract Record : Keyword string from i_paramsToWriteData
315 auto l_keyWordIdentifier =
316 [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
317 std::string l_keywordString{};
318 if (const types::IpzData* l_ipzData =
319 std::get_if<types::IpzData>(&i_paramsToWriteData))
320 {
321 l_keywordString =
322 std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
323 }
324 else if (const types::KwData* l_kwData =
325 std::get_if<types::KwData>(&i_paramsToWriteData))
326 {
327 l_keywordString = std::get<0>(*l_kwData);
328 }
329 return l_keywordString;
330 };
331
332 try
333 {
334 // Enable Reboot Guard
335 if (constants::FAILURE == dbusUtility::EnableRebootGuard())
336 {
337 EventLogger::createAsyncPel(
338 types::ErrorType::DbusFailure,
339 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
340 std::string(
341 "Failed to enable BMC Reboot Guard while updating " +
342 l_keyWordIdentifier(i_paramsToWriteData)),
343 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
344
345 return constants::FAILURE;
346 }
347
348 std::shared_ptr<ParserInterface> l_vpdParserInstance =
349 getVpdParserInstance();
350 l_bytesUpdatedOnHardware =
351 l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
352 }
353 catch (const std::exception& l_exception)
354 {
355 types::ErrorType l_errorType;
356
357 if (typeid(l_exception) == typeid(EccException))
358 {
359 l_errorType = types::ErrorType::EccCheckFailed;
360 }
361 else
362 {
363 l_errorType = types::ErrorType::InvalidVpdMessage;
364 }
365
366 EventLogger::createAsyncPel(
367 l_errorType, types::SeverityType::Informational, __FILE__,
368 __FUNCTION__, 0,
369 "Error while updating keyword's value on hardware path [" +
370 m_vpdFilePath + "], error: " + std::string(l_exception.what()),
371 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
372 }
373
374 // Disable Reboot Guard
375 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
376 {
377 EventLogger::createAsyncPel(
378 types::ErrorType::DbusFailure, types::SeverityType::Critical,
379 __FILE__, __FUNCTION__, 0,
380 std::string("Failed to disable BMC Reboot Guard while updating " +
381 l_keyWordIdentifier(i_paramsToWriteData)),
382 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
383 }
384
385 return l_bytesUpdatedOnHardware;
386}
387
388} // namespace vpd