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 m_vpdStartOffset = jsonUtility::getVPDOffset(m_parsedJson, vpdFilePath); 38 } 39 } 40 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 54 types::VPDMapVariant Parser::parse() 55 { 56 std::shared_ptr<vpd::ParserInterface> l_parser = getVpdParserInstance(); 57 return l_parser->parse(); 58 } 59 60 int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData, 61 types::DbusVariantType& o_updatedValue) 62 { 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 146 l_keywordValue = 147 l_vpdParserInstance->readKeywordFromHardware( 148 types::ReadVpdParams( 149 std::make_tuple(l_recordName, l_propertyName))); 150 151 // return the actual value updated on hardware 152 o_updatedValue = l_keywordValue; 153 } 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 238 int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData) 239 { 240 types::DbusVariantType o_updatedValue; 241 return updateVpdKeyword(i_paramsToWriteData, o_updatedValue); 242 } 243 244 int 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 270 int 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 350