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