blob: e0e173bf686a0c370494fae6a0349bd3fffb5ff2 [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 +
46 "], error: " + vpdSpecificUtility::getErrCodeMsg(l_errorCode));
47 }
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.
54 vpdSpecificUtility::getVpdDataInVector(m_vpdFilePath, m_vpdVector,
55 m_vpdStartOffset);
56
57 // This will detect the type of parser required.
58 std::shared_ptr<vpd::ParserInterface> l_parser =
59 ParserFactory::getParser(m_vpdVector, m_vpdFilePath, m_vpdStartOffset);
60
61 return l_parser;
62}
63
64types::VPDMapVariant Parser::parse()
65{
66 std::shared_ptr<vpd::ParserInterface> l_parser = getVpdParserInstance();
67 return l_parser->parse();
68}
69
Souvik Roy9b0b0fd2025-08-08 05:20:23 +000070int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData,
71 types::DbusVariantType& o_updatedValue)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050072{
73 int l_bytesUpdatedOnHardware = constants::FAILURE;
74
75 // A lambda to extract Record : Keyword string from i_paramsToWriteData
76 auto l_keyWordIdentifier =
77 [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
78 std::string l_keywordString{};
79 if (const types::IpzData* l_ipzData =
80 std::get_if<types::IpzData>(&i_paramsToWriteData))
81 {
82 l_keywordString =
83 std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
84 }
85 else if (const types::KwData* l_kwData =
86 std::get_if<types::KwData>(&i_paramsToWriteData))
87 {
88 l_keywordString = std::get<0>(*l_kwData);
89 }
90 return l_keywordString;
91 };
92
93 try
94 {
95 // Enable Reboot Guard
96 if (constants::FAILURE == dbusUtility::EnableRebootGuard())
97 {
98 EventLogger::createAsyncPel(
99 types::ErrorType::DbusFailure,
100 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
101 std::string(
102 "Failed to enable BMC Reboot Guard while updating " +
103 l_keyWordIdentifier(i_paramsToWriteData)),
104 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
105
106 return constants::FAILURE;
107 }
108
109 // Update keyword's value on hardware
110 try
111 {
112 std::shared_ptr<ParserInterface> l_vpdParserInstance =
113 getVpdParserInstance();
114 l_bytesUpdatedOnHardware =
115 l_vpdParserInstance->writeKeywordOnHardware(
116 i_paramsToWriteData);
117 }
118 catch (const std::exception& l_exception)
119 {
120 std::string l_errMsg(
121 "Error while updating keyword's value on hardware path " +
122 m_vpdFilePath + ", error: " + std::string(l_exception.what()));
123
124 // TODO : Log PEL
125
126 throw std::runtime_error(l_errMsg);
127 }
128
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500129 uint16_t l_errCode = 0;
130
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500131 auto [l_fruPath, l_inventoryObjPath, l_redundantFruPath] =
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500132 jsonUtility::getAllPathsToUpdateKeyword(m_parsedJson, m_vpdFilePath,
133 l_errCode);
134
135 if (l_errCode == error_code::INVALID_INPUT_PARAMETER ||
136 l_errCode == error_code::INVALID_JSON)
137 {
138 throw std::runtime_error(
139 "Failed to get paths to update keyword. Error : " +
140 vpdSpecificUtility::getErrCodeMsg(l_errCode));
141 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500142
143 // If inventory D-bus object path is present, update keyword's value on
144 // DBus
145 if (!l_inventoryObjPath.empty())
146 {
147 types::Record l_recordName;
148 std::string l_interfaceName;
149 std::string l_propertyName;
150 types::DbusVariantType l_keywordValue;
151
152 if (const types::IpzData* l_ipzData =
153 std::get_if<types::IpzData>(&i_paramsToWriteData))
154 {
155 l_recordName = std::get<0>(*l_ipzData);
156 l_interfaceName = constants::ipzVpdInf + l_recordName;
157 l_propertyName = std::get<1>(*l_ipzData);
158
159 try
160 {
161 // Read keyword's value from hardware to write the same on
162 // D-bus.
163 std::shared_ptr<ParserInterface> l_vpdParserInstance =
164 getVpdParserInstance();
165
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500166 l_keywordValue =
167 l_vpdParserInstance->readKeywordFromHardware(
168 types::ReadVpdParams(
169 std::make_tuple(l_recordName, l_propertyName)));
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000170
171 // return the actual value updated on hardware
172 o_updatedValue = l_keywordValue;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500173 }
174 catch (const std::exception& l_exception)
175 {
176 // Unable to read keyword's value from hardware.
177 std::string l_errMsg(
178 "Error while reading keyword's value from hadware path " +
179 m_vpdFilePath +
180 ", error: " + std::string(l_exception.what()));
181
182 // TODO: Log PEL
183
184 throw std::runtime_error(l_errMsg);
185 }
186 }
187 else
188 {
189 // Input parameter type provided isn't compatible to perform
190 // update.
191 std::string l_errMsg(
192 "Input parameter type isn't compatible to update keyword's value on DBus for object path: " +
193 l_inventoryObjPath);
194 throw std::runtime_error(l_errMsg);
195 }
196
197 // Get D-bus name for the given keyword
198 l_propertyName =
199 vpdSpecificUtility::getDbusPropNameForGivenKw(l_propertyName);
200
201 // Create D-bus object map
202 types::ObjectMap l_dbusObjMap = {std::make_pair(
203 l_inventoryObjPath,
204 types::InterfaceMap{std::make_pair(
205 l_interfaceName, types::PropertyMap{std::make_pair(
206 l_propertyName, l_keywordValue)})})};
207
208 // Call PIM's Notify method to perform update
209 if (!dbusUtility::callPIM(std::move(l_dbusObjMap)))
210 {
211 // Call to PIM's Notify method failed.
212 std::string l_errMsg("Notify PIM is failed for object path: " +
213 l_inventoryObjPath);
214 throw std::runtime_error(l_errMsg);
215 }
216 }
217
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500218 if (l_errCode == error_code::ERROR_GETTING_REDUNDANT_PATH)
219 {
220 logging::logMessage(vpdSpecificUtility::getErrCodeMsg(l_errCode));
221 }
222
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500223 // Update keyword's value on redundant hardware if present
224 if (!l_redundantFruPath.empty())
225 {
226 if (updateVpdKeywordOnRedundantPath(l_redundantFruPath,
227 i_paramsToWriteData) < 0)
228 {
229 std::string l_errMsg(
230 "Error while updating keyword's value on redundant path " +
231 l_redundantFruPath);
232 throw std::runtime_error(l_errMsg);
233 }
234 }
235
236 // TODO: Check if revert is required when any of the writes fails.
237 // TODO: Handle error logging
238 }
239 catch (const std::exception& l_ex)
240 {
241 logging::logMessage("Update VPD Keyword failed for : " +
242 l_keyWordIdentifier(i_paramsToWriteData) +
243 " failed due to error: " + l_ex.what());
244
245 // update failed, set return value to failure
246 l_bytesUpdatedOnHardware = constants::FAILURE;
247 }
248
249 // Disable Reboot Guard
250 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
251 {
252 EventLogger::createAsyncPel(
253 types::ErrorType::DbusFailure, types::SeverityType::Critical,
254 __FILE__, __FUNCTION__, 0,
255 std::string("Failed to disable BMC Reboot Guard while updating " +
256 l_keyWordIdentifier(i_paramsToWriteData)),
257 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
258 }
259
260 return l_bytesUpdatedOnHardware;
261}
262
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000263int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData)
264{
265 types::DbusVariantType o_updatedValue;
266 return updateVpdKeyword(i_paramsToWriteData, o_updatedValue);
267}
268
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500269int Parser::updateVpdKeywordOnRedundantPath(
270 const std::string& i_fruPath,
271 const types::WriteVpdParams& i_paramsToWriteData)
272{
273 try
274 {
275 std::shared_ptr<Parser> l_parserObj =
276 std::make_shared<Parser>(i_fruPath, m_parsedJson);
277
278 std::shared_ptr<ParserInterface> l_vpdParserInstance =
279 l_parserObj->getVpdParserInstance();
280
281 return l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
282 }
283 catch (const std::exception& l_exception)
284 {
285 EventLogger::createSyncPel(
286 types::ErrorType::InvalidVpdMessage,
287 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
288 "Error while updating keyword's value on redundant path " +
289 i_fruPath + ", error: " + std::string(l_exception.what()),
290 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
291 return -1;
292 }
293}
294
295int Parser::updateVpdKeywordOnHardware(
296 const types::WriteVpdParams& i_paramsToWriteData)
297{
298 int l_bytesUpdatedOnHardware = constants::FAILURE;
299
300 // A lambda to extract Record : Keyword string from i_paramsToWriteData
301 auto l_keyWordIdentifier =
302 [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
303 std::string l_keywordString{};
304 if (const types::IpzData* l_ipzData =
305 std::get_if<types::IpzData>(&i_paramsToWriteData))
306 {
307 l_keywordString =
308 std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
309 }
310 else if (const types::KwData* l_kwData =
311 std::get_if<types::KwData>(&i_paramsToWriteData))
312 {
313 l_keywordString = std::get<0>(*l_kwData);
314 }
315 return l_keywordString;
316 };
317
318 try
319 {
320 // Enable Reboot Guard
321 if (constants::FAILURE == dbusUtility::EnableRebootGuard())
322 {
323 EventLogger::createAsyncPel(
324 types::ErrorType::DbusFailure,
325 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
326 std::string(
327 "Failed to enable BMC Reboot Guard while updating " +
328 l_keyWordIdentifier(i_paramsToWriteData)),
329 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
330
331 return constants::FAILURE;
332 }
333
334 std::shared_ptr<ParserInterface> l_vpdParserInstance =
335 getVpdParserInstance();
336 l_bytesUpdatedOnHardware =
337 l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
338 }
339 catch (const std::exception& l_exception)
340 {
341 types::ErrorType l_errorType;
342
343 if (typeid(l_exception) == typeid(EccException))
344 {
345 l_errorType = types::ErrorType::EccCheckFailed;
346 }
347 else
348 {
349 l_errorType = types::ErrorType::InvalidVpdMessage;
350 }
351
352 EventLogger::createAsyncPel(
353 l_errorType, types::SeverityType::Informational, __FILE__,
354 __FUNCTION__, 0,
355 "Error while updating keyword's value on hardware path [" +
356 m_vpdFilePath + "], error: " + std::string(l_exception.what()),
357 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
358 }
359
360 // Disable Reboot Guard
361 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
362 {
363 EventLogger::createAsyncPel(
364 types::ErrorType::DbusFailure, types::SeverityType::Critical,
365 __FILE__, __FUNCTION__, 0,
366 std::string("Failed to disable BMC Reboot Guard while updating " +
367 l_keyWordIdentifier(i_paramsToWriteData)),
368 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
369 }
370
371 return l_bytesUpdatedOnHardware;
372}
373
374} // namespace vpd