| Sunny Srivastava | fa5e4d3 | 2023-03-12 11:59:49 -0500 | [diff] [blame] | 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 | { | 
|  | 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 | { | 
| Rekha Aparna | 017567a | 2025-08-13 02:07:06 -0500 | [diff] [blame] | 37 | 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 Srivastava | fa5e4d3 | 2023-03-12 11:59:49 -0500 | [diff] [blame] | 48 | } | 
|  | 49 | } | 
|  | 50 |  | 
|  | 51 | std::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 |  | 
|  | 64 | types::VPDMapVariant Parser::parse() | 
|  | 65 | { | 
|  | 66 | std::shared_ptr<vpd::ParserInterface> l_parser = getVpdParserInstance(); | 
|  | 67 | return l_parser->parse(); | 
|  | 68 | } | 
|  | 69 |  | 
| Souvik Roy | 9b0b0fd | 2025-08-08 05:20:23 +0000 | [diff] [blame] | 70 | int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData, | 
|  | 71 | types::DbusVariantType& o_updatedValue) | 
| Sunny Srivastava | fa5e4d3 | 2023-03-12 11:59:49 -0500 | [diff] [blame] | 72 | { | 
|  | 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 Srivastava | fa5e4d3 | 2023-03-12 11:59:49 -0500 | [diff] [blame] | 156 | l_keywordValue = | 
|  | 157 | l_vpdParserInstance->readKeywordFromHardware( | 
|  | 158 | types::ReadVpdParams( | 
|  | 159 | std::make_tuple(l_recordName, l_propertyName))); | 
| Souvik Roy | 9b0b0fd | 2025-08-08 05:20:23 +0000 | [diff] [blame] | 160 |  | 
|  | 161 | // return the actual value updated on hardware | 
|  | 162 | o_updatedValue = l_keywordValue; | 
| Sunny Srivastava | fa5e4d3 | 2023-03-12 11:59:49 -0500 | [diff] [blame] | 163 | } | 
|  | 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 Roy | 9b0b0fd | 2025-08-08 05:20:23 +0000 | [diff] [blame] | 248 | int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData) | 
|  | 249 | { | 
|  | 250 | types::DbusVariantType o_updatedValue; | 
|  | 251 | return updateVpdKeyword(i_paramsToWriteData, o_updatedValue); | 
|  | 252 | } | 
|  | 253 |  | 
| Sunny Srivastava | fa5e4d3 | 2023-03-12 11:59:49 -0500 | [diff] [blame] | 254 | int 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 |  | 
|  | 280 | int 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 |