blob: 20c6bd296fcc2eb8be1a331a94495ba93e034713 [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_errCode = 0;
206 l_propertyName = vpdSpecificUtility::getDbusPropNameForGivenKw(
207 l_propertyName, l_errCode);
208
209 if (l_errCode)
210 {
211 logging::logMessage(
212 "Failed to get Dbus property name for given keyword, error : " +
213 commonUtility::getErrCodeMsg(l_errCode));
214 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500215
216 // Create D-bus object map
217 types::ObjectMap l_dbusObjMap = {std::make_pair(
218 l_inventoryObjPath,
219 types::InterfaceMap{std::make_pair(
220 l_interfaceName, types::PropertyMap{std::make_pair(
221 l_propertyName, l_keywordValue)})})};
222
223 // Call PIM's Notify method to perform update
224 if (!dbusUtility::callPIM(std::move(l_dbusObjMap)))
225 {
226 // Call to PIM's Notify method failed.
227 std::string l_errMsg("Notify PIM is failed for object path: " +
228 l_inventoryObjPath);
229 throw std::runtime_error(l_errMsg);
230 }
231 }
232
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500233 if (l_errCode == error_code::ERROR_GETTING_REDUNDANT_PATH)
234 {
Rekha Aparnac6159a22025-10-09 12:20:20 +0530235 logging::logMessage(commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna2d6f0712025-09-02 03:52:57 -0500236 }
237
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500238 // Update keyword's value on redundant hardware if present
239 if (!l_redundantFruPath.empty())
240 {
241 if (updateVpdKeywordOnRedundantPath(l_redundantFruPath,
242 i_paramsToWriteData) < 0)
243 {
244 std::string l_errMsg(
245 "Error while updating keyword's value on redundant path " +
246 l_redundantFruPath);
247 throw std::runtime_error(l_errMsg);
248 }
249 }
250
251 // TODO: Check if revert is required when any of the writes fails.
252 // TODO: Handle error logging
253 }
254 catch (const std::exception& l_ex)
255 {
256 logging::logMessage("Update VPD Keyword failed for : " +
257 l_keyWordIdentifier(i_paramsToWriteData) +
258 " failed due to error: " + l_ex.what());
259
260 // update failed, set return value to failure
261 l_bytesUpdatedOnHardware = constants::FAILURE;
262 }
263
264 // Disable Reboot Guard
265 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
266 {
267 EventLogger::createAsyncPel(
268 types::ErrorType::DbusFailure, types::SeverityType::Critical,
269 __FILE__, __FUNCTION__, 0,
270 std::string("Failed to disable BMC Reboot Guard while updating " +
271 l_keyWordIdentifier(i_paramsToWriteData)),
272 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
273 }
274
275 return l_bytesUpdatedOnHardware;
276}
277
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000278int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData)
279{
280 types::DbusVariantType o_updatedValue;
281 return updateVpdKeyword(i_paramsToWriteData, o_updatedValue);
282}
283
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500284int Parser::updateVpdKeywordOnRedundantPath(
285 const std::string& i_fruPath,
286 const types::WriteVpdParams& i_paramsToWriteData)
287{
288 try
289 {
290 std::shared_ptr<Parser> l_parserObj =
291 std::make_shared<Parser>(i_fruPath, m_parsedJson);
292
293 std::shared_ptr<ParserInterface> l_vpdParserInstance =
294 l_parserObj->getVpdParserInstance();
295
296 return l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
297 }
298 catch (const std::exception& l_exception)
299 {
300 EventLogger::createSyncPel(
301 types::ErrorType::InvalidVpdMessage,
302 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
303 "Error while updating keyword's value on redundant path " +
304 i_fruPath + ", error: " + std::string(l_exception.what()),
305 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
306 return -1;
307 }
308}
309
310int Parser::updateVpdKeywordOnHardware(
311 const types::WriteVpdParams& i_paramsToWriteData)
312{
313 int l_bytesUpdatedOnHardware = constants::FAILURE;
314
315 // A lambda to extract Record : Keyword string from i_paramsToWriteData
316 auto l_keyWordIdentifier =
317 [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
318 std::string l_keywordString{};
319 if (const types::IpzData* l_ipzData =
320 std::get_if<types::IpzData>(&i_paramsToWriteData))
321 {
322 l_keywordString =
323 std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
324 }
325 else if (const types::KwData* l_kwData =
326 std::get_if<types::KwData>(&i_paramsToWriteData))
327 {
328 l_keywordString = std::get<0>(*l_kwData);
329 }
330 return l_keywordString;
331 };
332
333 try
334 {
335 // Enable Reboot Guard
336 if (constants::FAILURE == dbusUtility::EnableRebootGuard())
337 {
338 EventLogger::createAsyncPel(
339 types::ErrorType::DbusFailure,
340 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
341 std::string(
342 "Failed to enable BMC Reboot Guard while updating " +
343 l_keyWordIdentifier(i_paramsToWriteData)),
344 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
345
346 return constants::FAILURE;
347 }
348
349 std::shared_ptr<ParserInterface> l_vpdParserInstance =
350 getVpdParserInstance();
351 l_bytesUpdatedOnHardware =
352 l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
353 }
354 catch (const std::exception& l_exception)
355 {
356 types::ErrorType l_errorType;
357
358 if (typeid(l_exception) == typeid(EccException))
359 {
360 l_errorType = types::ErrorType::EccCheckFailed;
361 }
362 else
363 {
364 l_errorType = types::ErrorType::InvalidVpdMessage;
365 }
366
367 EventLogger::createAsyncPel(
368 l_errorType, types::SeverityType::Informational, __FILE__,
369 __FUNCTION__, 0,
370 "Error while updating keyword's value on hardware path [" +
371 m_vpdFilePath + "], error: " + std::string(l_exception.what()),
372 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
373 }
374
375 // Disable Reboot Guard
376 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
377 {
378 EventLogger::createAsyncPel(
379 types::ErrorType::DbusFailure, types::SeverityType::Critical,
380 __FILE__, __FUNCTION__, 0,
381 std::string("Failed to disable BMC Reboot Guard while updating " +
382 l_keyWordIdentifier(i_paramsToWriteData)),
383 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
384 }
385
386 return l_bytesUpdatedOnHardware;
387}
388
389} // namespace vpd