1 #pragma once 2 3 #include "config.h" 4 5 #include "constants.hpp" 6 #include "event_logger.hpp" 7 #include "exceptions.hpp" 8 #include "logger.hpp" 9 #include "types.hpp" 10 11 #include <nlohmann/json.hpp> 12 #include <utility/common_utility.hpp> 13 #include <utility/dbus_utility.hpp> 14 15 #include <filesystem> 16 #include <fstream> 17 #include <regex> 18 #include <typeindex> 19 20 namespace vpd 21 { 22 namespace vpdSpecificUtility 23 { 24 /** 25 * @brief API to generate file name for bad VPD. 26 * 27 * For i2c eeproms - the pattern of the vpd-name will be 28 * i2c-<bus-number>-<eeprom-address>. 29 * For spi eeproms - the pattern of the vpd-name will be spi-<spi-number>. 30 * 31 * @param[in] i_vpdFilePath - file path of the vpd. 32 * 33 * @return On success, returns generated file name, otherwise returns empty 34 * string. 35 */ 36 inline std::string generateBadVPDFileName( 37 const std::string& i_vpdFilePath) noexcept 38 { 39 std::string l_badVpdFileName{BAD_VPD_DIR}; 40 try 41 { 42 if (i_vpdFilePath.find("i2c") != std::string::npos) 43 { 44 l_badVpdFileName += "i2c-"; 45 std::regex l_i2cPattern("(at24/)([0-9]+-[0-9]+)\\/"); 46 std::smatch l_match; 47 if (std::regex_search(i_vpdFilePath, l_match, l_i2cPattern)) 48 { 49 l_badVpdFileName += l_match.str(2); 50 } 51 } 52 else if (i_vpdFilePath.find("spi") != std::string::npos) 53 { 54 std::regex l_spiPattern("((spi)[0-9]+)(.0)"); 55 std::smatch l_match; 56 if (std::regex_search(i_vpdFilePath, l_match, l_spiPattern)) 57 { 58 l_badVpdFileName += l_match.str(1); 59 } 60 } 61 } 62 catch (const std::exception& l_ex) 63 { 64 l_badVpdFileName.clear(); 65 logging::logMessage("Failed to generate bad VPD file name for [" + 66 i_vpdFilePath + "]. Error: " + l_ex.what()); 67 } 68 return l_badVpdFileName; 69 } 70 71 /** 72 * @brief API which dumps the broken/bad vpd in a directory. 73 * When the vpd is bad, this API places the bad vpd file inside 74 * "/tmp/bad-vpd" in BMC, in order to collect bad VPD data as a part of user 75 * initiated BMC dump. 76 * 77 * 78 * @param[in] i_vpdFilePath - vpd file path 79 * @param[in] i_vpdVector - vpd vector 80 * 81 * @return On success returns 0, otherwise returns -1. 82 */ 83 inline int dumpBadVpd(const std::string& i_vpdFilePath, 84 const types::BinaryVector& i_vpdVector) noexcept 85 { 86 int l_rc{constants::FAILURE}; 87 try 88 { 89 std::filesystem::create_directory(BAD_VPD_DIR); 90 auto l_badVpdPath = generateBadVPDFileName(i_vpdFilePath); 91 92 if (l_badVpdPath.empty()) 93 { 94 throw std::runtime_error("Failed to generate bad VPD file name"); 95 } 96 97 if (std::filesystem::exists(l_badVpdPath)) 98 { 99 std::error_code l_ec; 100 std::filesystem::remove(l_badVpdPath, l_ec); 101 if (l_ec) // error code 102 { 103 const std::string l_errorMsg{ 104 "Error removing the existing broken vpd in " + 105 l_badVpdPath + 106 ". Error code : " + std::to_string(l_ec.value()) + 107 ". Error message : " + l_ec.message()}; 108 109 throw std::runtime_error(l_errorMsg); 110 } 111 } 112 113 std::ofstream l_badVpdFileStream(l_badVpdPath, std::ofstream::binary); 114 if (!l_badVpdFileStream.is_open()) 115 { 116 throw std::runtime_error( 117 "Failed to open bad vpd file path in /tmp/bad-vpd. " 118 "Unable to dump the broken/bad vpd file."); 119 } 120 121 l_badVpdFileStream.write( 122 reinterpret_cast<const char*>(i_vpdVector.data()), 123 i_vpdVector.size()); 124 125 l_rc = constants::SUCCESS; 126 } 127 catch (const std::exception& l_ex) 128 { 129 logging::logMessage("Failed to dump bad VPD for [" + i_vpdFilePath + 130 "]. Error: " + l_ex.what()); 131 } 132 return l_rc; 133 } 134 135 /** 136 * @brief An API to read value of a keyword. 137 * 138 * 139 * @param[in] i_kwdValueMap - A map having Kwd value pair. 140 * @param[in] i_kwd - keyword name. 141 * 142 * @return On success returns value of the keyword read from map, otherwise 143 * returns empty string. 144 */ 145 inline std::string getKwVal(const types::IPZKwdValueMap& i_kwdValueMap, 146 const std::string& i_kwd) noexcept 147 { 148 std::string l_kwdValue; 149 try 150 { 151 if (i_kwd.empty()) 152 { 153 throw std::runtime_error("Invalid parameters"); 154 } 155 156 auto l_itrToKwd = i_kwdValueMap.find(i_kwd); 157 if (l_itrToKwd != i_kwdValueMap.end()) 158 { 159 l_kwdValue = l_itrToKwd->second; 160 } 161 else 162 { 163 throw std::runtime_error("Keyword not found"); 164 } 165 } 166 catch (const std::exception& l_ex) 167 { 168 logging::logMessage("Failed to get value for keyword [" + i_kwd + 169 "]. Error : " + l_ex.what()); 170 } 171 return l_kwdValue; 172 } 173 174 /** 175 * @brief An API to process encoding of a keyword. 176 * 177 * @param[in] i_keyword - Keyword to be processed. 178 * @param[in] i_encoding - Type of encoding. 179 * 180 * @return Value after being processed for encoded type. 181 */ 182 inline std::string encodeKeyword(const std::string& i_keyword, 183 const std::string& i_encoding) noexcept 184 { 185 // Default value is keyword value 186 std::string l_result(i_keyword.begin(), i_keyword.end()); 187 try 188 { 189 if (i_encoding == "MAC") 190 { 191 l_result.clear(); 192 size_t l_firstByte = i_keyword[0]; 193 l_result += commonUtility::toHex(l_firstByte >> 4); 194 l_result += commonUtility::toHex(l_firstByte & 0x0f); 195 for (size_t i = 1; i < i_keyword.size(); ++i) 196 { 197 l_result += ":"; 198 l_result += commonUtility::toHex(i_keyword[i] >> 4); 199 l_result += commonUtility::toHex(i_keyword[i] & 0x0f); 200 } 201 } 202 else if (i_encoding == "DATE") 203 { 204 // Date, represent as 205 // <year>-<month>-<day> <hour>:<min> 206 l_result.clear(); 207 static constexpr uint8_t skipPrefix = 3; 208 209 auto strItr = i_keyword.begin(); 210 advance(strItr, skipPrefix); 211 for_each(strItr, i_keyword.end(), 212 [&l_result](size_t c) { l_result += c; }); 213 214 l_result.insert(constants::BD_YEAR_END, 1, '-'); 215 l_result.insert(constants::BD_MONTH_END, 1, '-'); 216 l_result.insert(constants::BD_DAY_END, 1, ' '); 217 l_result.insert(constants::BD_HOUR_END, 1, ':'); 218 } 219 } 220 catch (const std::exception& l_ex) 221 { 222 l_result.clear(); 223 logging::logMessage("Failed to encode keyword [" + i_keyword + 224 "]. Error: " + l_ex.what()); 225 } 226 227 return l_result; 228 } 229 230 /** 231 * @brief Helper function to insert or merge in map. 232 * 233 * This method checks in an interface if the given interface exists. If the 234 * interface key already exists, property map is inserted corresponding to it. 235 * If the key does'nt exist then given interface and property map pair is newly 236 * created. If the property present in propertymap already exist in the 237 * InterfaceMap, then the new property value is ignored. 238 * 239 * @param[in,out] io_map - Interface map. 240 * @param[in] i_interface - Interface to be processed. 241 * @param[in] i_propertyMap - new property map that needs to be emplaced. 242 * 243 * @return On success returns 0, otherwise returns -1. 244 */ 245 inline int insertOrMerge(types::InterfaceMap& io_map, 246 const std::string& i_interface, 247 types::PropertyMap&& i_propertyMap) noexcept 248 { 249 int l_rc{constants::FAILURE}; 250 try 251 { 252 if (io_map.find(i_interface) != io_map.end()) 253 { 254 auto& l_prop = io_map.at(i_interface); 255 std::for_each(i_propertyMap.begin(), i_propertyMap.end(), 256 [&l_prop](auto l_keyValue) { 257 l_prop[l_keyValue.first] = l_keyValue.second; 258 }); 259 } 260 else 261 { 262 io_map.emplace(i_interface, i_propertyMap); 263 } 264 265 l_rc = constants::SUCCESS; 266 } 267 catch (const std::exception& l_ex) 268 { 269 // ToDo:: Log PEL 270 logging::logMessage( 271 "Inserting properties into interface[" + i_interface + 272 "] map failed, reason: " + std::string(l_ex.what())); 273 } 274 return l_rc; 275 } 276 277 /** 278 * @brief API to expand unpanded location code. 279 * 280 * Note: The API handles all the exception internally, in case of any error 281 * unexpanded location code will be returned as it is. 282 * 283 * @param[in] unexpandedLocationCode - Unexpanded location code. 284 * @param[in] parsedVpdMap - Parsed VPD map. 285 * @return Expanded location code. In case of any error, unexpanded is returned 286 * as it is. 287 */ 288 inline std::string getExpandedLocationCode( 289 const std::string& unexpandedLocationCode, 290 const types::VPDMapVariant& parsedVpdMap) 291 { 292 auto expanded{unexpandedLocationCode}; 293 294 try 295 { 296 // Expanded location code is formed by combining two keywords 297 // depending on type in unexpanded one. Second one is always "SE". 298 std::string kwd1, kwd2{constants::kwdSE}; 299 300 // interface to search for required keywords; 301 std::string kwdInterface; 302 303 // record which holds the required keywords. 304 std::string recordName; 305 306 auto pos = unexpandedLocationCode.find("fcs"); 307 if (pos != std::string::npos) 308 { 309 kwd1 = constants::kwdFC; 310 kwdInterface = constants::vcenInf; 311 recordName = constants::recVCEN; 312 } 313 else 314 { 315 pos = unexpandedLocationCode.find("mts"); 316 if (pos != std::string::npos) 317 { 318 kwd1 = constants::kwdTM; 319 kwdInterface = constants::vsysInf; 320 recordName = constants::recVSYS; 321 } 322 else 323 { 324 throw std::runtime_error( 325 "Error detecting type of unexpanded location code."); 326 } 327 } 328 329 std::string firstKwdValue, secondKwdValue; 330 331 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap); 332 ipzVpdMap && (*ipzVpdMap).find(recordName) != (*ipzVpdMap).end()) 333 { 334 auto itrToVCEN = (*ipzVpdMap).find(recordName); 335 firstKwdValue = getKwVal(itrToVCEN->second, kwd1); 336 if (firstKwdValue.empty()) 337 { 338 throw std::runtime_error( 339 "Failed to get value for keyword [" + kwd1 + "]"); 340 } 341 342 secondKwdValue = getKwVal(itrToVCEN->second, kwd2); 343 if (secondKwdValue.empty()) 344 { 345 throw std::runtime_error( 346 "Failed to get value for keyword [" + kwd2 + "]"); 347 } 348 } 349 else 350 { 351 std::array<const char*, 1> interfaceList = {kwdInterface.c_str()}; 352 353 types::MapperGetObject mapperRetValue = dbusUtility::getObjectMap( 354 std::string(constants::systemVpdInvPath), interfaceList); 355 356 if (mapperRetValue.empty()) 357 { 358 throw std::runtime_error("Mapper failed to get service"); 359 } 360 361 const std::string& serviceName = std::get<0>(mapperRetValue.at(0)); 362 363 auto retVal = dbusUtility::readDbusProperty( 364 serviceName, std::string(constants::systemVpdInvPath), 365 kwdInterface, kwd1); 366 367 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal)) 368 { 369 firstKwdValue.assign( 370 reinterpret_cast<const char*>(kwdVal->data()), 371 kwdVal->size()); 372 } 373 else 374 { 375 throw std::runtime_error( 376 "Failed to read value of " + kwd1 + " from Bus"); 377 } 378 379 retVal = dbusUtility::readDbusProperty( 380 serviceName, std::string(constants::systemVpdInvPath), 381 kwdInterface, kwd2); 382 383 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal)) 384 { 385 secondKwdValue.assign( 386 reinterpret_cast<const char*>(kwdVal->data()), 387 kwdVal->size()); 388 } 389 else 390 { 391 throw std::runtime_error( 392 "Failed to read value of " + kwd2 + " from Bus"); 393 } 394 } 395 396 if (unexpandedLocationCode.find("fcs") != std::string::npos) 397 { 398 // TODO: See if ND0 can be placed in the JSON 399 expanded.replace( 400 pos, 3, firstKwdValue.substr(0, 4) + ".ND0." + secondKwdValue); 401 } 402 else 403 { 404 replace(firstKwdValue.begin(), firstKwdValue.end(), '-', '.'); 405 expanded.replace(pos, 3, firstKwdValue + "." + secondKwdValue); 406 } 407 } 408 catch (const std::exception& ex) 409 { 410 logging::logMessage("Failed to expand location code with exception: " + 411 std::string(ex.what())); 412 } 413 414 return expanded; 415 } 416 417 /** 418 * @brief An API to get VPD in a vector. 419 * 420 * The vector is required by the respective parser to fill the VPD map. 421 * Note: API throws exception in case of failure. Caller needs to handle. 422 * 423 * @param[in] vpdFilePath - EEPROM path of the FRU. 424 * @param[out] vpdVector - VPD in vector form. 425 * @param[in] vpdStartOffset - Offset of VPD data in EEPROM. 426 */ 427 inline void getVpdDataInVector(const std::string& vpdFilePath, 428 types::BinaryVector& vpdVector, 429 size_t& vpdStartOffset) 430 { 431 try 432 { 433 std::fstream vpdFileStream; 434 vpdFileStream.exceptions( 435 std::ifstream::badbit | std::ifstream::failbit); 436 vpdFileStream.open(vpdFilePath, std::ios::in | std::ios::binary); 437 auto vpdSizeToRead = std::min(std::filesystem::file_size(vpdFilePath), 438 static_cast<uintmax_t>(65504)); 439 vpdVector.resize(vpdSizeToRead); 440 441 vpdFileStream.seekg(vpdStartOffset, std::ios_base::beg); 442 vpdFileStream.read(reinterpret_cast<char*>(&vpdVector[0]), 443 vpdSizeToRead); 444 445 vpdVector.resize(vpdFileStream.gcount()); 446 vpdFileStream.clear(std::ios_base::eofbit); 447 } 448 catch (const std::ifstream::failure& fail) 449 { 450 std::cerr << "Exception in file handling [" << vpdFilePath 451 << "] error : " << fail.what(); 452 throw; 453 } 454 } 455 456 /** 457 * @brief An API to get D-bus representation of given VPD keyword. 458 * 459 * @param[in] i_keywordName - VPD keyword name. 460 * 461 * @return D-bus representation of given keyword. 462 */ 463 inline std::string getDbusPropNameForGivenKw(const std::string& i_keywordName) 464 { 465 // Check for "#" prefixed VPD keyword. 466 if ((i_keywordName.size() == vpd::constants::TWO_BYTES) && 467 (i_keywordName.at(0) == constants::POUND_KW)) 468 { 469 // D-bus doesn't support "#". Replace "#" with "PD_" for those "#" 470 // prefixed keywords. 471 return (std::string(constants::POUND_KW_PREFIX) + 472 i_keywordName.substr(1)); 473 } 474 475 // Return the keyword name back, if D-bus representation is same as the VPD 476 // keyword name. 477 return i_keywordName; 478 } 479 480 /** 481 * @brief API to find CCIN in parsed VPD map. 482 * 483 * Few FRUs need some special handling. To identify those FRUs CCIN are used. 484 * The API will check from parsed VPD map if the FRU is the one with desired 485 * CCIN. 486 * 487 * @param[in] i_JsonObject - Any JSON which contains CCIN tag to match. 488 * @param[in] i_parsedVpdMap - Parsed VPD map. 489 * 490 * @return True if found, false otherwise. 491 */ 492 inline bool findCcinInVpd(const nlohmann::json& i_JsonObject, 493 const types::VPDMapVariant& i_parsedVpdMap) noexcept 494 { 495 bool l_rc{false}; 496 try 497 { 498 if (i_JsonObject.empty()) 499 { 500 throw std::runtime_error("Json object is empty. Can't find CCIN"); 501 } 502 503 if (auto l_ipzVPDMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap)) 504 { 505 auto l_itrToRec = (*l_ipzVPDMap).find("VINI"); 506 if (l_itrToRec == (*l_ipzVPDMap).end()) 507 { 508 throw DataException( 509 "VINI record not found in parsed VPD. Can't find CCIN"); 510 } 511 512 std::string l_ccinFromVpd{ 513 vpdSpecificUtility::getKwVal(l_itrToRec->second, "CC")}; 514 if (l_ccinFromVpd.empty()) 515 { 516 throw DataException( 517 "Empty CCIN value in VPD map. Can't find CCIN"); 518 } 519 520 transform(l_ccinFromVpd.begin(), l_ccinFromVpd.end(), 521 l_ccinFromVpd.begin(), ::toupper); 522 523 for (std::string l_ccinValue : i_JsonObject["ccin"]) 524 { 525 transform(l_ccinValue.begin(), l_ccinValue.end(), 526 l_ccinValue.begin(), ::toupper); 527 528 if (l_ccinValue.compare(l_ccinFromVpd) == 529 constants::STR_CMP_SUCCESS) 530 { 531 // CCIN found 532 l_rc = true; 533 } 534 } 535 536 if (!l_rc) 537 { 538 logging::logMessage("No match found for CCIN"); 539 } 540 } 541 else 542 { 543 logging::logMessage("VPD type not supported. Can't find CCIN"); 544 } 545 } 546 catch (const std::exception& l_ex) 547 { 548 const std::string l_errMsg{ 549 "Failed to find CCIN in VPD. Error : " + std::string(l_ex.what())}; 550 551 if (typeid(l_ex) == std::type_index(typeid(DataException))) 552 { 553 EventLogger::createSyncPel( 554 types::ErrorType::InvalidVpdMessage, 555 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0, 556 l_errMsg, std::nullopt, std::nullopt, std::nullopt, 557 std::nullopt); 558 } 559 560 logging::logMessage(l_errMsg); 561 } 562 return l_rc; 563 } 564 565 /** 566 * @brief API to reset data of a FRU populated under PIM. 567 * 568 * This API resets the data for particular interfaces of a FRU under PIM. 569 * 570 * @param[in] i_objectPath - DBus object path of the FRU. 571 * @param[in] io_interfaceMap - Interface and its properties map. 572 */ 573 inline void resetDataUnderPIM(const std::string& i_objectPath, 574 types::InterfaceMap& io_interfaceMap) 575 { 576 try 577 { 578 std::array<const char*, 0> l_interfaces; 579 const types::MapperGetObject& l_getObjectMap = 580 dbusUtility::getObjectMap(i_objectPath, l_interfaces); 581 582 const std::vector<std::string>& l_vpdRelatedInterfaces{ 583 constants::operationalStatusInf, constants::inventoryItemInf, 584 constants::assetInf}; 585 586 for (const auto& [l_service, l_interfaceList] : l_getObjectMap) 587 { 588 if (l_service.compare(constants::pimServiceName) != 589 constants::STR_CMP_SUCCESS) 590 { 591 continue; 592 } 593 594 for (const auto& l_interface : l_interfaceList) 595 { 596 if ((l_interface.find(constants::ipzVpdInf) != 597 std::string::npos) || 598 ((std::find(l_vpdRelatedInterfaces.begin(), 599 l_vpdRelatedInterfaces.end(), l_interface)) != 600 l_vpdRelatedInterfaces.end())) 601 { 602 const types::PropertyMap& l_propertyValueMap = 603 dbusUtility::getPropertyMap(l_service, i_objectPath, 604 l_interface); 605 606 types::PropertyMap l_propertyMap; 607 608 for (const auto& l_aProperty : l_propertyValueMap) 609 { 610 const std::string& l_propertyName = l_aProperty.first; 611 const auto& l_propertyValue = l_aProperty.second; 612 613 if (std::holds_alternative<types::BinaryVector>( 614 l_propertyValue)) 615 { 616 l_propertyMap.emplace(l_propertyName, 617 types::BinaryVector{}); 618 } 619 else if (std::holds_alternative<std::string>( 620 l_propertyValue)) 621 { 622 l_propertyMap.emplace(l_propertyName, 623 std::string{}); 624 } 625 else if (std::holds_alternative<bool>(l_propertyValue)) 626 { 627 // ToDo -- Update the functional status property 628 // to true. 629 if (l_propertyName.compare("Present") == 630 constants::STR_CMP_SUCCESS) 631 { 632 l_propertyMap.emplace(l_propertyName, false); 633 } 634 } 635 } 636 io_interfaceMap.emplace(l_interface, 637 std::move(l_propertyMap)); 638 } 639 } 640 } 641 } 642 catch (const std::exception& l_ex) 643 { 644 logging::logMessage("Failed to remove VPD for FRU: " + i_objectPath + 645 " with error: " + std::string(l_ex.what())); 646 } 647 } 648 649 /** 650 * @brief API to detect pass1 planar type. 651 * 652 * Based on HW version and IM keyword, This API detects is it is a pass1 planar 653 * or not. 654 * 655 * @return True if pass 1 planar, false otherwise. 656 */ 657 inline bool isPass1Planar() noexcept 658 { 659 bool l_rc{false}; 660 try 661 { 662 auto l_retVal = dbusUtility::readDbusProperty( 663 constants::pimServiceName, constants::systemVpdInvPath, 664 constants::viniInf, constants::kwdHW); 665 666 auto l_hwVer = std::get_if<types::BinaryVector>(&l_retVal); 667 668 l_retVal = dbusUtility::readDbusProperty( 669 constants::pimServiceName, constants::systemInvPath, 670 constants::vsbpInf, constants::kwdIM); 671 672 auto l_imValue = std::get_if<types::BinaryVector>(&l_retVal); 673 674 if (l_hwVer && l_imValue) 675 { 676 if (l_hwVer->size() != constants::VALUE_2) 677 { 678 throw std::runtime_error("Invalid HW keyword length."); 679 } 680 681 if (l_imValue->size() != constants::VALUE_4) 682 { 683 throw std::runtime_error("Invalid IM keyword length."); 684 } 685 686 const types::BinaryVector l_everest{80, 00, 48, 00}; 687 const types::BinaryVector l_fuji{96, 00, 32, 00}; 688 689 if (((*l_imValue) == l_everest) || ((*l_imValue) == l_fuji)) 690 { 691 if ((*l_hwVer).at(1) < constants::VALUE_21) 692 { 693 l_rc = true; 694 } 695 } 696 else if ((*l_hwVer).at(1) < constants::VALUE_2) 697 { 698 l_rc = true; 699 } 700 } 701 } 702 catch (const std::exception& l_ex) 703 { 704 logging::logMessage("Failed to check for pass 1 planar. Error: " + 705 std::string(l_ex.what())); 706 } 707 708 return l_rc; 709 } 710 711 /** 712 * @brief API to detect if system configuration is that of PowerVS system. 713 * 714 * @param[in] i_imValue - IM value of the system. 715 * @return true if it is PowerVS configuration, false otherwise. 716 */ 717 inline bool isPowerVsConfiguration(const types::BinaryVector& i_imValue) 718 { 719 if (i_imValue.empty() || i_imValue.size() != constants::VALUE_4) 720 { 721 return false; 722 } 723 724 // Should be a 0x5000XX series system. 725 if (i_imValue.at(0) == constants::HEX_VALUE_50 && 726 i_imValue.at(1) == constants::HEX_VALUE_00) 727 { 728 std::string l_imagePrefix = dbusUtility::getImagePrefix(); 729 730 // Check image for 0x500030XX series. 731 if ((i_imValue.at(2) == constants::HEX_VALUE_30) && 732 ((l_imagePrefix == constants::powerVsImagePrefix_MY) || 733 (l_imagePrefix == constants::powerVsImagePrefix_NY))) 734 { 735 logging::logMessage("PowerVS configuration"); 736 return true; 737 } 738 739 // Check image for 0X500010XX series. 740 if ((i_imValue.at(2) == constants::HEX_VALUE_10) && 741 ((l_imagePrefix == constants::powerVsImagePrefix_MZ) || 742 (l_imagePrefix == constants::powerVsImagePrefix_NZ))) 743 { 744 logging::logMessage("PowerVS configuration"); 745 return true; 746 } 747 } 748 return false; 749 } 750 751 /** 752 * @brief API to get CCIN for a given FRU from DBus. 753 * 754 * The API reads the CCIN for a FRU based on its inventory path. 755 * 756 * @param[in] i_invObjPath - Inventory path of the FRU. 757 * @return CCIN of the FRU on success, empty string otherwise. 758 */ 759 inline std::string getCcinFromDbus(const std::string& i_invObjPath) 760 { 761 try 762 { 763 if (i_invObjPath.empty()) 764 { 765 throw std::runtime_error("Empty EEPROM path, can't read CCIN"); 766 } 767 768 const auto& l_retValue = dbusUtility::readDbusProperty( 769 constants::pimServiceName, i_invObjPath, constants::viniInf, 770 constants::kwdCCIN); 771 772 auto l_ptrCcin = std::get_if<types::BinaryVector>(&l_retValue); 773 if (!l_ptrCcin || (*l_ptrCcin).size() != constants::VALUE_4) 774 { 775 throw DbusException("Invalid CCIN read from Dbus"); 776 } 777 778 return std::string((*l_ptrCcin).begin(), (*l_ptrCcin).end()); 779 } 780 catch (const std::exception& l_ex) 781 { 782 logging::logMessage(l_ex.what()); 783 return std::string{}; 784 } 785 } 786 } // namespace vpdSpecificUtility 787 } // namespace vpd 788