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