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 { 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 } 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 70 int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData, 71 types::DbusVariantType& o_updatedValue) 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 156 l_keywordValue = 157 l_vpdParserInstance->readKeywordFromHardware( 158 types::ReadVpdParams( 159 std::make_tuple(l_recordName, l_propertyName))); 160 161 // return the actual value updated on hardware 162 o_updatedValue = l_keywordValue; 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 248 int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData) 249 { 250 types::DbusVariantType o_updatedValue; 251 return updateVpdKeyword(i_paramsToWriteData, o_updatedValue); 252 } 253 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 360