blob: a32d155b9311e7ba1e8fbdd955eb5c1f0e5bd1ee [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
129 auto [l_fruPath, l_inventoryObjPath, l_redundantFruPath] =
130 jsonUtility::getAllPathsToUpdateKeyword(m_parsedJson,
131 m_vpdFilePath);
132
133 // If inventory D-bus object path is present, update keyword's value on
134 // DBus
135 if (!l_inventoryObjPath.empty())
136 {
137 types::Record l_recordName;
138 std::string l_interfaceName;
139 std::string l_propertyName;
140 types::DbusVariantType l_keywordValue;
141
142 if (const types::IpzData* l_ipzData =
143 std::get_if<types::IpzData>(&i_paramsToWriteData))
144 {
145 l_recordName = std::get<0>(*l_ipzData);
146 l_interfaceName = constants::ipzVpdInf + l_recordName;
147 l_propertyName = std::get<1>(*l_ipzData);
148
149 try
150 {
151 // Read keyword's value from hardware to write the same on
152 // D-bus.
153 std::shared_ptr<ParserInterface> l_vpdParserInstance =
154 getVpdParserInstance();
155
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500156 l_keywordValue =
157 l_vpdParserInstance->readKeywordFromHardware(
158 types::ReadVpdParams(
159 std::make_tuple(l_recordName, l_propertyName)));
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000160
161 // return the actual value updated on hardware
162 o_updatedValue = l_keywordValue;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500163 }
164 catch (const std::exception& l_exception)
165 {
166 // Unable to read keyword's value from hardware.
167 std::string l_errMsg(
168 "Error while reading keyword's value from hadware path " +
169 m_vpdFilePath +
170 ", error: " + std::string(l_exception.what()));
171
172 // TODO: Log PEL
173
174 throw std::runtime_error(l_errMsg);
175 }
176 }
177 else
178 {
179 // Input parameter type provided isn't compatible to perform
180 // update.
181 std::string l_errMsg(
182 "Input parameter type isn't compatible to update keyword's value on DBus for object path: " +
183 l_inventoryObjPath);
184 throw std::runtime_error(l_errMsg);
185 }
186
187 // Get D-bus name for the given keyword
188 l_propertyName =
189 vpdSpecificUtility::getDbusPropNameForGivenKw(l_propertyName);
190
191 // Create D-bus object map
192 types::ObjectMap l_dbusObjMap = {std::make_pair(
193 l_inventoryObjPath,
194 types::InterfaceMap{std::make_pair(
195 l_interfaceName, types::PropertyMap{std::make_pair(
196 l_propertyName, l_keywordValue)})})};
197
198 // Call PIM's Notify method to perform update
199 if (!dbusUtility::callPIM(std::move(l_dbusObjMap)))
200 {
201 // Call to PIM's Notify method failed.
202 std::string l_errMsg("Notify PIM is failed for object path: " +
203 l_inventoryObjPath);
204 throw std::runtime_error(l_errMsg);
205 }
206 }
207
208 // Update keyword's value on redundant hardware if present
209 if (!l_redundantFruPath.empty())
210 {
211 if (updateVpdKeywordOnRedundantPath(l_redundantFruPath,
212 i_paramsToWriteData) < 0)
213 {
214 std::string l_errMsg(
215 "Error while updating keyword's value on redundant path " +
216 l_redundantFruPath);
217 throw std::runtime_error(l_errMsg);
218 }
219 }
220
221 // TODO: Check if revert is required when any of the writes fails.
222 // TODO: Handle error logging
223 }
224 catch (const std::exception& l_ex)
225 {
226 logging::logMessage("Update VPD Keyword failed for : " +
227 l_keyWordIdentifier(i_paramsToWriteData) +
228 " failed due to error: " + l_ex.what());
229
230 // update failed, set return value to failure
231 l_bytesUpdatedOnHardware = constants::FAILURE;
232 }
233
234 // Disable Reboot Guard
235 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
236 {
237 EventLogger::createAsyncPel(
238 types::ErrorType::DbusFailure, types::SeverityType::Critical,
239 __FILE__, __FUNCTION__, 0,
240 std::string("Failed to disable BMC Reboot Guard while updating " +
241 l_keyWordIdentifier(i_paramsToWriteData)),
242 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
243 }
244
245 return l_bytesUpdatedOnHardware;
246}
247
Souvik Roy9b0b0fd2025-08-08 05:20:23 +0000248int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData)
249{
250 types::DbusVariantType o_updatedValue;
251 return updateVpdKeyword(i_paramsToWriteData, o_updatedValue);
252}
253
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500254int Parser::updateVpdKeywordOnRedundantPath(
255 const std::string& i_fruPath,
256 const types::WriteVpdParams& i_paramsToWriteData)
257{
258 try
259 {
260 std::shared_ptr<Parser> l_parserObj =
261 std::make_shared<Parser>(i_fruPath, m_parsedJson);
262
263 std::shared_ptr<ParserInterface> l_vpdParserInstance =
264 l_parserObj->getVpdParserInstance();
265
266 return l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
267 }
268 catch (const std::exception& l_exception)
269 {
270 EventLogger::createSyncPel(
271 types::ErrorType::InvalidVpdMessage,
272 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
273 "Error while updating keyword's value on redundant path " +
274 i_fruPath + ", error: " + std::string(l_exception.what()),
275 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
276 return -1;
277 }
278}
279
280int Parser::updateVpdKeywordOnHardware(
281 const types::WriteVpdParams& i_paramsToWriteData)
282{
283 int l_bytesUpdatedOnHardware = constants::FAILURE;
284
285 // A lambda to extract Record : Keyword string from i_paramsToWriteData
286 auto l_keyWordIdentifier =
287 [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
288 std::string l_keywordString{};
289 if (const types::IpzData* l_ipzData =
290 std::get_if<types::IpzData>(&i_paramsToWriteData))
291 {
292 l_keywordString =
293 std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
294 }
295 else if (const types::KwData* l_kwData =
296 std::get_if<types::KwData>(&i_paramsToWriteData))
297 {
298 l_keywordString = std::get<0>(*l_kwData);
299 }
300 return l_keywordString;
301 };
302
303 try
304 {
305 // Enable Reboot Guard
306 if (constants::FAILURE == dbusUtility::EnableRebootGuard())
307 {
308 EventLogger::createAsyncPel(
309 types::ErrorType::DbusFailure,
310 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
311 std::string(
312 "Failed to enable BMC Reboot Guard while updating " +
313 l_keyWordIdentifier(i_paramsToWriteData)),
314 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
315
316 return constants::FAILURE;
317 }
318
319 std::shared_ptr<ParserInterface> l_vpdParserInstance =
320 getVpdParserInstance();
321 l_bytesUpdatedOnHardware =
322 l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
323 }
324 catch (const std::exception& l_exception)
325 {
326 types::ErrorType l_errorType;
327
328 if (typeid(l_exception) == typeid(EccException))
329 {
330 l_errorType = types::ErrorType::EccCheckFailed;
331 }
332 else
333 {
334 l_errorType = types::ErrorType::InvalidVpdMessage;
335 }
336
337 EventLogger::createAsyncPel(
338 l_errorType, types::SeverityType::Informational, __FILE__,
339 __FUNCTION__, 0,
340 "Error while updating keyword's value on hardware path [" +
341 m_vpdFilePath + "], error: " + std::string(l_exception.what()),
342 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
343 }
344
345 // Disable Reboot Guard
346 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
347 {
348 EventLogger::createAsyncPel(
349 types::ErrorType::DbusFailure, types::SeverityType::Critical,
350 __FILE__, __FUNCTION__, 0,
351 std::string("Failed to disable BMC Reboot Guard while updating " +
352 l_keyWordIdentifier(i_paramsToWriteData)),
353 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
354 }
355
356 return l_bytesUpdatedOnHardware;
357}
358
359} // namespace vpd