1 #include "config.h" 2 3 #include "vpd_tool.hpp" 4 5 #include "tool_constants.hpp" 6 #include "tool_types.hpp" 7 #include "tool_utils.hpp" 8 9 #include <cstdlib> 10 #include <iostream> 11 #include <regex> 12 #include <tuple> 13 namespace vpd 14 { 15 int VpdTool::readKeyword( 16 const std::string& i_vpdPath, const std::string& i_recordName, 17 const std::string& i_keywordName, const bool i_onHardware, 18 const std::string& i_fileToSave) 19 { 20 int l_rc = constants::FAILURE; 21 try 22 { 23 types::DbusVariantType l_keywordValue; 24 if (i_onHardware) 25 { 26 l_keywordValue = utils::readKeywordFromHardware( 27 i_vpdPath, std::make_tuple(i_recordName, i_keywordName)); 28 } 29 else 30 { 31 std::string l_inventoryObjectPath( 32 constants::baseInventoryPath + i_vpdPath); 33 34 l_keywordValue = utils::readDbusProperty( 35 constants::inventoryManagerService, l_inventoryObjectPath, 36 constants::ipzVpdInfPrefix + i_recordName, i_keywordName); 37 } 38 39 if (const auto l_value = 40 std::get_if<types::BinaryVector>(&l_keywordValue); 41 l_value && !l_value->empty()) 42 { 43 // ToDo: Print value in both ASCII and hex formats 44 const std::string& l_keywordStrValue = 45 utils::getPrintableValue(*l_value); 46 47 if (i_fileToSave.empty()) 48 { 49 utils::displayOnConsole(i_vpdPath, i_keywordName, 50 l_keywordStrValue); 51 l_rc = constants::SUCCESS; 52 } 53 else 54 { 55 if (utils::saveToFile(i_fileToSave, l_keywordStrValue)) 56 { 57 std::cout 58 << "Value read is saved on the file: " << i_fileToSave 59 << std::endl; 60 l_rc = constants::SUCCESS; 61 } 62 else 63 { 64 std::cerr 65 << "Error while saving the read value on the file: " 66 << i_fileToSave 67 << "\nDisplaying the read value on console" 68 << std::endl; 69 utils::displayOnConsole(i_vpdPath, i_keywordName, 70 l_keywordStrValue); 71 } 72 } 73 } 74 else 75 { 76 // TODO: Enable logging when verbose is enabled. 77 std::cout << "Invalid data type or empty data received." 78 << std::endl; 79 } 80 } 81 catch (const std::exception& l_ex) 82 { 83 // TODO: Enable logging when verbose is enabled. 84 std::cerr << "Read keyword's value failed for path: " << i_vpdPath 85 << ", Record: " << i_recordName << ", Keyword: " 86 << i_keywordName << ", error: " << l_ex.what() << std::endl; 87 } 88 return l_rc; 89 } 90 91 int VpdTool::dumpObject(std::string i_fruPath) const noexcept 92 { 93 int l_rc{constants::FAILURE}; 94 try 95 { 96 // ToDo: For PFuture system take only full path from the user. 97 i_fruPath = constants::baseInventoryPath + i_fruPath; 98 99 nlohmann::json l_resultJsonArray = nlohmann::json::array({}); 100 const nlohmann::json l_fruJson = getFruProperties(i_fruPath); 101 if (!l_fruJson.empty()) 102 { 103 l_resultJsonArray += l_fruJson; 104 105 utils::printJson(l_resultJsonArray); 106 } 107 else 108 { 109 std::cout << "FRU [" << i_fruPath 110 << "] is not present in the system" << std::endl; 111 } 112 l_rc = constants::SUCCESS; 113 } 114 catch (std::exception& l_ex) 115 { 116 // TODO: Enable logging when verbose is enabled. 117 std::cerr << "Dump Object failed for FRU [" << i_fruPath 118 << "], Error: " << l_ex.what() << std::endl; 119 } 120 return l_rc; 121 } 122 123 template <typename PropertyType> 124 void VpdTool::populateInterfaceJson(const std::string& i_inventoryObjPath, 125 const std::string& i_infName, 126 const std::vector<std::string>& i_propList, 127 nlohmann::json& io_fruJsonObject) const 128 { 129 nlohmann::json l_interfaceJsonObj = nlohmann::json::object({}); 130 131 auto l_readProperties = [i_inventoryObjPath, &l_interfaceJsonObj, i_infName, 132 this](const std::string& i_property) { 133 const nlohmann::json l_propertyJsonObj = 134 getInventoryPropertyJson<PropertyType>(i_inventoryObjPath, 135 i_infName, i_property); 136 l_interfaceJsonObj.insert(l_propertyJsonObj.cbegin(), 137 l_propertyJsonObj.cend()); 138 }; 139 140 std::for_each(i_propList.cbegin(), i_propList.cend(), l_readProperties); 141 142 if (!l_interfaceJsonObj.empty()) 143 { 144 io_fruJsonObject.insert(l_interfaceJsonObj.cbegin(), 145 l_interfaceJsonObj.cend()); 146 } 147 } 148 149 void VpdTool::populateFruJson( 150 const std::string& i_inventoryObjPath, nlohmann::json& io_fruJsonObject, 151 const std::vector<std::string>& i_interfaceList) const 152 { 153 for (const auto& l_interface : i_interfaceList) 154 { 155 if (l_interface == constants::inventoryItemInf) 156 { 157 const std::vector<std::string> l_properties = {"PrettyName"}; 158 populateInterfaceJson<std::string>(i_inventoryObjPath, 159 constants::inventoryItemInf, 160 l_properties, io_fruJsonObject); 161 continue; 162 } 163 164 if (l_interface == constants::locationCodeInf) 165 { 166 const std::vector<std::string> l_properties = {"LocationCode"}; 167 populateInterfaceJson<std::string>(i_inventoryObjPath, 168 constants::locationCodeInf, 169 l_properties, io_fruJsonObject); 170 continue; 171 } 172 173 if (l_interface == constants::viniInf) 174 { 175 const std::vector<std::string> l_properties = {"SN", "PN", "CC", 176 "FN", "DR"}; 177 populateInterfaceJson<vpd::types::BinaryVector>( 178 i_inventoryObjPath, constants::viniInf, l_properties, 179 io_fruJsonObject); 180 continue; 181 } 182 183 if (l_interface == constants::assetInf) 184 { 185 if (std::find(i_interfaceList.begin(), i_interfaceList.end(), 186 constants::viniInf) != i_interfaceList.end()) 187 { 188 // The value will be filled from VINI interface. Don't 189 // process asset interface. 190 continue; 191 } 192 193 const std::vector<std::string> l_properties = { 194 "Model", "SerialNumber", "SubModel"}; 195 196 populateInterfaceJson<std::string>(i_inventoryObjPath, 197 constants::assetInf, 198 l_properties, io_fruJsonObject); 199 continue; 200 } 201 202 if (l_interface == constants::networkInf) 203 { 204 const std::vector<std::string> l_properties = {"MACAddress"}; 205 populateInterfaceJson<std::string>(i_inventoryObjPath, 206 constants::networkInf, 207 l_properties, io_fruJsonObject); 208 continue; 209 } 210 211 if (l_interface == constants::pcieSlotInf) 212 { 213 const std::vector<std::string> l_properties = {"SlotType"}; 214 populateInterfaceJson<std::string>(i_inventoryObjPath, 215 constants::pcieSlotInf, 216 l_properties, io_fruJsonObject); 217 continue; 218 } 219 220 if (l_interface == constants::slotNumInf) 221 { 222 const std::vector<std::string> l_properties = {"SlotNumber"}; 223 populateInterfaceJson<uint32_t>(i_inventoryObjPath, 224 constants::slotNumInf, l_properties, 225 io_fruJsonObject); 226 continue; 227 } 228 229 if (l_interface == constants::i2cDeviceInf) 230 { 231 const std::vector<std::string> l_properties = {"Address", "Bus"}; 232 populateInterfaceJson<uint32_t>(i_inventoryObjPath, 233 constants::i2cDeviceInf, 234 l_properties, io_fruJsonObject); 235 continue; 236 } 237 } 238 } 239 240 nlohmann::json VpdTool::getFruProperties(const std::string& i_objectPath) const 241 { 242 // check if FRU is present in the system 243 if (!isFruPresent(i_objectPath)) 244 { 245 return nlohmann::json::object_t(); 246 } 247 248 nlohmann::json l_fruJson = nlohmann::json::object_t({}); 249 250 // need to trim out the base inventory path in the FRU JSON. 251 const std::string l_displayObjectPath = 252 (i_objectPath.find(constants::baseInventoryPath) == std::string::npos) 253 ? i_objectPath 254 : i_objectPath.substr(strlen(constants::baseInventoryPath)); 255 256 l_fruJson.emplace(l_displayObjectPath, nlohmann::json::object_t({})); 257 258 auto& l_fruObject = l_fruJson[l_displayObjectPath]; 259 260 types::MapperGetObject l_mapperResp = utils::GetServiceInterfacesForObject( 261 i_objectPath, std::vector<std::string>{}); 262 263 for (const auto& [l_service, l_interfaceList] : l_mapperResp) 264 { 265 if (l_service != constants::inventoryManagerService) 266 { 267 continue; 268 } 269 populateFruJson(i_objectPath, l_fruObject, l_interfaceList); 270 } 271 272 const auto l_typePropertyJson = getFruTypeProperty(i_objectPath); 273 if (!l_typePropertyJson.empty()) 274 { 275 l_fruObject.insert(l_typePropertyJson.cbegin(), 276 l_typePropertyJson.cend()); 277 } 278 279 // insert FRU "TYPE" 280 l_fruObject.emplace("TYPE", "FRU"); 281 282 return l_fruJson; 283 } 284 285 template <typename PropertyType> 286 nlohmann::json VpdTool::getInventoryPropertyJson( 287 const std::string& i_objectPath, const std::string& i_interface, 288 const std::string& i_propertyName) const noexcept 289 { 290 nlohmann::json l_resultInJson = nlohmann::json::object({}); 291 try 292 { 293 types::DbusVariantType l_keyWordValue; 294 295 l_keyWordValue = 296 utils::readDbusProperty(constants::inventoryManagerService, 297 i_objectPath, i_interface, i_propertyName); 298 299 if (const auto l_value = std::get_if<PropertyType>(&l_keyWordValue)) 300 { 301 if constexpr (std::is_same<PropertyType, std::string>::value) 302 { 303 l_resultInJson.emplace(i_propertyName, *l_value); 304 } 305 else if constexpr (std::is_same<PropertyType, bool>::value) 306 { 307 l_resultInJson.emplace(i_propertyName, 308 *l_value ? "true" : "false"); 309 } 310 else if constexpr (std::is_same<PropertyType, 311 types::BinaryVector>::value) 312 { 313 const std::string& l_keywordStrValue = 314 vpd::utils::getPrintableValue(*l_value); 315 316 l_resultInJson.emplace(i_propertyName, l_keywordStrValue); 317 } 318 else if constexpr (std::is_same<PropertyType, uint32_t>::value) 319 { 320 l_resultInJson.emplace(i_propertyName, 321 std::to_string(*l_value)); 322 } 323 } 324 else 325 { 326 // TODO: Enable logging when verbose is enabled. 327 std::cout << "Invalid data type received." << std::endl; 328 } 329 } 330 catch (const std::exception& l_ex) 331 { 332 // TODO: Enable logging when verbose is enabled. 333 std::cerr << "Read " << i_propertyName 334 << " value for FRU path: " << i_objectPath 335 << ", failed with exception: " << l_ex.what() << std::endl; 336 } 337 return l_resultInJson; 338 } 339 340 int VpdTool::fixSystemVpd() const noexcept 341 { 342 int l_rc = constants::FAILURE; 343 344 nlohmann::json l_backupRestoreCfgJsonObj = getBackupRestoreCfgJsonObj(); 345 if (!fetchKeywordInfo(l_backupRestoreCfgJsonObj)) 346 { 347 return l_rc; 348 } 349 350 printSystemVpd(l_backupRestoreCfgJsonObj); 351 352 do 353 { 354 printFixSystemVpdOption(types::UserOption::UseBackupDataForAll); 355 printFixSystemVpdOption( 356 types::UserOption::UseSystemBackplaneDataForAll); 357 printFixSystemVpdOption(types::UserOption::MoreOptions); 358 printFixSystemVpdOption(types::UserOption::Exit); 359 360 int l_userSelectedOption = types::UserOption::Exit; 361 std::cin >> l_userSelectedOption; 362 363 std::cout << std::endl << std::string(191, '=') << std::endl; 364 365 if (types::UserOption::UseBackupDataForAll == l_userSelectedOption) 366 { 367 l_rc = updateAllKeywords(l_backupRestoreCfgJsonObj, true); 368 break; 369 } 370 else if (types::UserOption::UseSystemBackplaneDataForAll == 371 l_userSelectedOption) 372 { 373 l_rc = updateAllKeywords(l_backupRestoreCfgJsonObj, false); 374 break; 375 } 376 else if (types::UserOption::MoreOptions == l_userSelectedOption) 377 { 378 l_rc = handleMoreOption(l_backupRestoreCfgJsonObj); 379 break; 380 } 381 else if (types::UserOption::Exit == l_userSelectedOption) 382 { 383 std::cout << "Exit successfully" << std::endl; 384 break; 385 } 386 else 387 { 388 std::cout << "Provide a valid option. Retry." << std::endl; 389 } 390 } while (true); 391 392 return l_rc; 393 } 394 395 int VpdTool::writeKeyword( 396 std::string i_vpdPath, const std::string& i_recordName, 397 const std::string& i_keywordName, const std::string& i_keywordValue, 398 const bool i_onHardware) noexcept 399 { 400 int l_rc = constants::FAILURE; 401 try 402 { 403 if (i_vpdPath.empty() || i_recordName.empty() || 404 i_keywordName.empty() || i_keywordValue.empty()) 405 { 406 throw std::runtime_error("Received input is empty."); 407 } 408 409 auto l_paramsToWrite = 410 std::make_tuple(i_recordName, i_keywordName, 411 utils::convertToBinary(i_keywordValue)); 412 413 if (i_onHardware) 414 { 415 l_rc = utils::writeKeywordOnHardware(i_vpdPath, l_paramsToWrite); 416 } 417 else 418 { 419 i_vpdPath = constants::baseInventoryPath + i_vpdPath; 420 l_rc = utils::writeKeyword(i_vpdPath, l_paramsToWrite); 421 } 422 423 if (l_rc > 0) 424 { 425 std::cout << "Data updated successfully " << std::endl; 426 l_rc = constants::SUCCESS; 427 } 428 } 429 catch (const std::exception& l_ex) 430 { 431 // TODO: Enable log when verbose is enabled. 432 std::cerr << "Write keyword's value for path: " << i_vpdPath 433 << ", Record: " << i_recordName 434 << ", Keyword: " << i_keywordName 435 << " is failed. Exception: " << l_ex.what() << std::endl; 436 } 437 return l_rc; 438 } 439 440 nlohmann::json VpdTool::getBackupRestoreCfgJsonObj() const noexcept 441 { 442 nlohmann::json l_parsedBackupRestoreJson{}; 443 try 444 { 445 nlohmann::json l_parsedSystemJson = 446 utils::getParsedJson(INVENTORY_JSON_SYM_LINK); 447 448 // check for mandatory fields at this point itself. 449 if (!l_parsedSystemJson.contains("backupRestoreConfigPath")) 450 { 451 throw std::runtime_error( 452 "backupRestoreConfigPath tag is missing from system config JSON : " + 453 std::string(INVENTORY_JSON_SYM_LINK)); 454 } 455 456 l_parsedBackupRestoreJson = 457 utils::getParsedJson(l_parsedSystemJson["backupRestoreConfigPath"]); 458 } 459 catch (const std::exception& l_ex) 460 { 461 // TODO: Enable logging when verbose is enabled. 462 std::cerr << l_ex.what() << std::endl; 463 } 464 465 return l_parsedBackupRestoreJson; 466 } 467 468 int VpdTool::cleanSystemVpd(bool i_syncBiosAttributesRequired) const noexcept 469 { 470 try 471 { 472 // In order to do syncBiosAttributes, we need BIOS Config Manager 473 // service up and running 474 if (i_syncBiosAttributesRequired && 475 !utils::isServiceRunning(constants::biosConfigMgrService)) 476 { 477 std::cerr 478 << "Cannot sync BIOS attributes as BIOS Config Manager service is not running." 479 << std::endl; 480 return constants::FAILURE; 481 } 482 483 // get the keyword map from backup_restore json 484 // iterate through the keyword map get default value of 485 // l_keywordName. 486 // use writeKeyword API to update default value on hardware, 487 // backup and D - Bus. 488 const nlohmann::json l_parsedBackupRestoreJson = 489 getBackupRestoreCfgJsonObj(); 490 491 // check for mandatory tags 492 if (l_parsedBackupRestoreJson.contains("source") && 493 l_parsedBackupRestoreJson.contains("backupMap") && 494 l_parsedBackupRestoreJson["source"].contains("hardwarePath") && 495 l_parsedBackupRestoreJson["backupMap"].is_array()) 496 { 497 // get the source hardware path 498 const auto& l_hardwarePath = 499 l_parsedBackupRestoreJson["source"]["hardwarePath"]; 500 501 // iterate through the backup map 502 for (const auto& l_aRecordKwInfo : 503 l_parsedBackupRestoreJson["backupMap"]) 504 { 505 // check if Manufacturing Reset is required for this entry 506 const bool l_isMfgCleanRequired = 507 l_aRecordKwInfo.value("isManufactureResetRequired", false); 508 509 if (l_isMfgCleanRequired) 510 { 511 // get the Record name and Keyword name 512 const std::string& l_srcRecordName = 513 l_aRecordKwInfo.value("sourceRecord", ""); 514 const std::string& l_srcKeywordName = 515 l_aRecordKwInfo.value("sourceKeyword", ""); 516 517 // validate the Record name, Keyword name and the 518 // defaultValue 519 if (!l_srcRecordName.empty() && !l_srcKeywordName.empty() && 520 l_aRecordKwInfo.contains("defaultValue") && 521 l_aRecordKwInfo["defaultValue"].is_array()) 522 { 523 // check if this keyword is used for backing up BIOS 524 // attribute 525 const bool l_isUsedForBiosAttributeBackup = 526 l_aRecordKwInfo.value("isBiosSyncRequired", false); 527 528 const types::BinaryVector l_keywordValueToUpdate = 529 (i_syncBiosAttributesRequired && 530 l_isUsedForBiosAttributeBackup) 531 ? getVpdValueInBiosConfigManager( 532 l_srcRecordName, l_srcKeywordName) 533 : l_aRecordKwInfo["defaultValue"] 534 .get<types::BinaryVector>(); 535 536 if (l_keywordValueToUpdate.empty()) 537 { 538 std::cerr << "Failed to update " << l_srcRecordName 539 << ":" << l_srcKeywordName 540 << " . Keyword value to update is empty" 541 << std::endl; 542 continue; 543 } 544 545 // update the Keyword with default value, use D-Bus 546 // method UpdateKeyword exposed by vpd-manager. 547 // Note: writing to all paths (Primary EEPROM path, 548 // Secondary EEPROM path, D-Bus cache and Backup path) 549 // is the responsibility of vpd-manager's UpdateKeyword 550 // API 551 if (constants::FAILURE == 552 utils::writeKeyword( 553 l_hardwarePath, 554 std::make_tuple(l_srcRecordName, 555 l_srcKeywordName, 556 l_keywordValueToUpdate))) 557 { 558 // TODO: Enable logging when verbose 559 // is enabled. 560 std::cerr << "Failed to update " << l_srcRecordName 561 << ":" << l_srcKeywordName << std::endl; 562 } 563 } 564 else 565 { 566 std::cerr 567 << "Unrecognized Entry Record [" << l_srcRecordName 568 << "] Keyword [" << l_srcKeywordName 569 << "] in Backup Restore JSON backup map" 570 << std::endl; 571 } 572 } // mfgClean required check 573 } // keyword list loop 574 } 575 else // backupRestoreJson is not valid 576 { 577 std::cerr << "Backup Restore JSON is not valid" << std::endl; 578 } 579 580 // success/failure message 581 std::cout << "The critical keywords from system backplane VPD has " 582 "been reset successfully." 583 << std::endl; 584 585 } // try block end 586 catch (const std::exception& l_ex) 587 { 588 // TODO: Enable logging when verbose is enabled. 589 std::cerr 590 << "Manufacturing reset on system vpd keywords is unsuccessful. Error : " 591 << l_ex.what() << std::endl; 592 } 593 return constants::SUCCESS; 594 } 595 596 bool VpdTool::fetchKeywordInfo(nlohmann::json& io_parsedJsonObj) const noexcept 597 { 598 bool l_returnValue = false; 599 try 600 { 601 if (io_parsedJsonObj.empty() || !io_parsedJsonObj.contains("source") || 602 !io_parsedJsonObj.contains("destination") || 603 !io_parsedJsonObj.contains("backupMap")) 604 { 605 throw std::runtime_error("Invalid JSON"); 606 } 607 608 std::string l_srcVpdPath; 609 std::string l_dstVpdPath; 610 611 bool l_isSourceOnHardware = false; 612 if (l_srcVpdPath = io_parsedJsonObj["source"].value("hardwarePath", ""); 613 !l_srcVpdPath.empty()) 614 { 615 l_isSourceOnHardware = true; 616 } 617 else if (l_srcVpdPath = 618 io_parsedJsonObj["source"].value("inventoryPath", ""); 619 l_srcVpdPath.empty()) 620 { 621 throw std::runtime_error("Source path is empty in JSON"); 622 } 623 624 bool l_isDestinationOnHardware = false; 625 if (l_dstVpdPath = 626 io_parsedJsonObj["destination"].value("hardwarePath", ""); 627 !l_dstVpdPath.empty()) 628 { 629 l_isDestinationOnHardware = true; 630 } 631 else if (l_dstVpdPath = 632 io_parsedJsonObj["destination"].value("inventoryPath", ""); 633 l_dstVpdPath.empty()) 634 { 635 throw std::runtime_error("Destination path is empty in JSON"); 636 } 637 638 for (auto& l_aRecordKwInfo : io_parsedJsonObj["backupMap"]) 639 { 640 const std::string& l_srcRecordName = 641 l_aRecordKwInfo.value("sourceRecord", ""); 642 const std::string& l_srcKeywordName = 643 l_aRecordKwInfo.value("sourceKeyword", ""); 644 const std::string& l_dstRecordName = 645 l_aRecordKwInfo.value("destinationRecord", ""); 646 const std::string& l_dstKeywordName = 647 l_aRecordKwInfo.value("destinationKeyword", ""); 648 649 if (l_srcRecordName.empty() || l_dstRecordName.empty() || 650 l_srcKeywordName.empty() || l_dstKeywordName.empty()) 651 { 652 // TODO: Enable logging when verbose is enabled. 653 std::cout << "Record or keyword not found in the JSON." 654 << std::endl; 655 continue; 656 } 657 658 types::DbusVariantType l_srcKeywordVariant; 659 if (l_isSourceOnHardware) 660 { 661 l_srcKeywordVariant = utils::readKeywordFromHardware( 662 l_srcVpdPath, 663 std::make_tuple(l_srcRecordName, l_srcKeywordName)); 664 } 665 else 666 { 667 l_srcKeywordVariant = utils::readDbusProperty( 668 constants::inventoryManagerService, l_srcVpdPath, 669 constants::ipzVpdInfPrefix + l_srcRecordName, 670 l_srcKeywordName); 671 } 672 673 if (auto l_srcKeywordValue = 674 std::get_if<types::BinaryVector>(&l_srcKeywordVariant); 675 l_srcKeywordValue && !l_srcKeywordValue->empty()) 676 { 677 l_aRecordKwInfo["sourcekeywordValue"] = *l_srcKeywordValue; 678 } 679 else 680 { 681 // TODO: Enable logging when verbose is enabled. 682 std::cout 683 << "Invalid data type or empty data received, for source record: " 684 << l_srcRecordName << ", keyword: " << l_srcKeywordName 685 << std::endl; 686 continue; 687 } 688 689 types::DbusVariantType l_dstKeywordVariant; 690 if (l_isDestinationOnHardware) 691 { 692 l_dstKeywordVariant = utils::readKeywordFromHardware( 693 l_dstVpdPath, 694 std::make_tuple(l_dstRecordName, l_dstKeywordName)); 695 } 696 else 697 { 698 l_dstKeywordVariant = utils::readDbusProperty( 699 constants::inventoryManagerService, l_dstVpdPath, 700 constants::ipzVpdInfPrefix + l_dstRecordName, 701 l_dstKeywordName); 702 } 703 704 if (auto l_dstKeywordValue = 705 std::get_if<types::BinaryVector>(&l_dstKeywordVariant); 706 l_dstKeywordValue && !l_dstKeywordValue->empty()) 707 { 708 l_aRecordKwInfo["destinationkeywordValue"] = *l_dstKeywordValue; 709 } 710 else 711 { 712 // TODO: Enable logging when verbose is enabled. 713 std::cout 714 << "Invalid data type or empty data received, for destination record: " 715 << l_dstRecordName << ", keyword: " << l_dstKeywordName 716 << std::endl; 717 continue; 718 } 719 } 720 721 l_returnValue = true; 722 } 723 catch (const std::exception& l_ex) 724 { 725 // TODO: Enable logging when verbose is enabled. 726 std::cerr << l_ex.what() << std::endl; 727 } 728 729 return l_returnValue; 730 } 731 732 nlohmann::json VpdTool::getFruTypeProperty( 733 const std::string& i_objectPath) const noexcept 734 { 735 nlohmann::json l_resultInJson = nlohmann::json::object({}); 736 std::vector<std::string> l_pimInfList; 737 738 auto l_serviceInfMap = utils::GetServiceInterfacesForObject( 739 i_objectPath, std::vector<std::string>{constants::inventoryItemInf}); 740 if (l_serviceInfMap.contains(constants::inventoryManagerService)) 741 { 742 l_pimInfList = l_serviceInfMap[constants::inventoryManagerService]; 743 744 // iterate through the list and find 745 // "xyz.openbmc_project.Inventory.Item.*" 746 for (const auto& l_interface : l_pimInfList) 747 { 748 if (l_interface.find(constants::inventoryItemInf) != 749 std::string::npos && 750 l_interface.length() > 751 std::string(constants::inventoryItemInf).length()) 752 { 753 l_resultInJson.emplace("type", l_interface); 754 } 755 } 756 } 757 return l_resultInJson; 758 } 759 760 bool VpdTool::isFruPresent(const std::string& i_objectPath) const noexcept 761 { 762 bool l_returnValue{false}; 763 try 764 { 765 types::DbusVariantType l_keyWordValue; 766 767 l_keyWordValue = utils::readDbusProperty( 768 constants::inventoryManagerService, i_objectPath, 769 constants::inventoryItemInf, "Present"); 770 771 if (const auto l_value = std::get_if<bool>(&l_keyWordValue)) 772 { 773 l_returnValue = *l_value; 774 } 775 } 776 catch (const std::runtime_error& l_ex) 777 { 778 // TODO: Enable logging when verbose is enabled. 779 // std::cerr << "Failed to check \"Present\" property for FRU " 780 // << i_objectPath << " Error: " << l_ex.what() << 781 // std::endl; 782 } 783 return l_returnValue; 784 } 785 786 void VpdTool::printFixSystemVpdOption( 787 const types::UserOption& i_option) const noexcept 788 { 789 switch (i_option) 790 { 791 case types::UserOption::Exit: 792 std::cout << "Enter 0 => To exit successfully : "; 793 break; 794 case types::UserOption::UseBackupDataForAll: 795 std::cout << "Enter 1 => If you choose the data on backup for all " 796 "mismatching record-keyword pairs" 797 << std::endl; 798 break; 799 case types::UserOption::UseSystemBackplaneDataForAll: 800 std::cout << "Enter 2 => If you choose the data on primary for all " 801 "mismatching record-keyword pairs" 802 << std::endl; 803 break; 804 case types::UserOption::MoreOptions: 805 std::cout << "Enter 3 => If you wish to explore more options" 806 << std::endl; 807 break; 808 case types::UserOption::UseBackupDataForCurrent: 809 std::cout << "Enter 4 => If you choose the data on backup as the " 810 "right value" 811 << std::endl; 812 break; 813 case types::UserOption::UseSystemBackplaneDataForCurrent: 814 std::cout << "Enter 5 => If you choose the data on primary as the " 815 "right value" 816 << std::endl; 817 break; 818 case types::UserOption::NewValueOnBoth: 819 std::cout 820 << "Enter 6 => If you wish to enter a new value to update " 821 "both on backup and primary" 822 << std::endl; 823 break; 824 case types::UserOption::SkipCurrent: 825 std::cout << "Enter 7 => If you wish to skip the above " 826 "record-keyword pair" 827 << std::endl; 828 break; 829 } 830 } 831 832 int VpdTool::dumpInventory(bool i_dumpTable) const noexcept 833 { 834 int l_rc{constants::FAILURE}; 835 836 try 837 { 838 // get all object paths under PIM 839 const auto l_objectPaths = utils::GetSubTreePaths( 840 constants::baseInventoryPath, 0, 841 std::vector<std::string>{constants::inventoryItemInf}); 842 843 if (!l_objectPaths.empty()) 844 { 845 nlohmann::json l_resultInJson = nlohmann::json::array({}); 846 847 std::for_each(l_objectPaths.begin(), l_objectPaths.end(), 848 [&](const auto& l_objectPath) { 849 const auto l_fruJson = 850 getFruProperties(l_objectPath); 851 if (!l_fruJson.empty()) 852 { 853 if (l_resultInJson.empty()) 854 { 855 l_resultInJson += l_fruJson; 856 } 857 else 858 { 859 l_resultInJson.at(0).insert( 860 l_fruJson.cbegin(), l_fruJson.cend()); 861 } 862 } 863 }); 864 865 if (i_dumpTable) 866 { 867 // create Table object 868 utils::Table l_inventoryTable{}; 869 870 // columns to be populated in the Inventory table 871 const std::vector<types::TableColumnNameSizePair> 872 l_tableColumns = { 873 {"FRU", 100}, {"CC", 6}, {"DR", 20}, 874 {"LocationCode", 32}, {"PN", 8}, {"PrettyName", 80}, 875 {"SubModel", 10}, {"SN", 15}, {"type", 60}}; 876 877 types::TableInputData l_tableData; 878 879 // First prepare the Table Columns 880 for (const auto& l_column : l_tableColumns) 881 { 882 if (constants::FAILURE == 883 l_inventoryTable.AddColumn(l_column.first, 884 l_column.second)) 885 { 886 // TODO: Enable logging when verbose is enabled. 887 std::cerr << "Failed to add column " << l_column.first 888 << " in Inventory Table." << std::endl; 889 } 890 } 891 892 // iterate through the json array 893 for (const auto& l_fruEntry : l_resultInJson[0].items()) 894 { 895 // if object path ends in "unit([0-9][0-9]?)", skip adding 896 // the object path in the table 897 if (std::regex_search(l_fruEntry.key(), 898 std::regex("unit([0-9][0-9]?)"))) 899 { 900 continue; 901 } 902 903 std::vector<std::string> l_row; 904 for (const auto& l_column : l_tableColumns) 905 { 906 const auto& l_fruJson = l_fruEntry.value(); 907 908 if (l_column.first == "FRU") 909 { 910 l_row.push_back(l_fruEntry.key()); 911 } 912 else 913 { 914 if (l_fruJson.contains(l_column.first)) 915 { 916 l_row.push_back(l_fruJson[l_column.first]); 917 } 918 else 919 { 920 l_row.push_back(""); 921 } 922 } 923 } 924 925 l_tableData.push_back(l_row); 926 } 927 928 l_rc = l_inventoryTable.Print(l_tableData); 929 } 930 else 931 { 932 // print JSON to console 933 utils::printJson(l_resultInJson); 934 l_rc = constants::SUCCESS; 935 } 936 } 937 } 938 catch (const std::exception& l_ex) 939 { 940 // TODO: Enable logging when verbose is enabled. 941 std::cerr << "Dump inventory failed. Error: " << l_ex.what() 942 << std::endl; 943 } 944 return l_rc; 945 } 946 947 void VpdTool::printSystemVpd( 948 const nlohmann::json& i_parsedJsonObj) const noexcept 949 { 950 if (i_parsedJsonObj.empty() || !i_parsedJsonObj.contains("backupMap")) 951 { 952 // TODO: Enable logging when verbose is enabled. 953 std::cerr << "Invalid JSON to print system VPD" << std::endl; 954 } 955 956 std::string l_outline(191, '='); 957 std::cout << "\nRestorable record-keyword pairs and their data on backup & " 958 "primary.\n\n" 959 << l_outline << std::endl; 960 961 std::cout << std::left << std::setw(6) << "S.No" << std::left 962 << std::setw(8) << "Record" << std::left << std::setw(9) 963 << "Keyword" << std::left << std::setw(75) << "Data On Backup" 964 << std::left << std::setw(75) << "Data On Primary" << std::left 965 << std::setw(14) << "Data Mismatch\n" 966 << l_outline << std::endl; 967 968 uint8_t l_slNum = 0; 969 970 for (const auto& l_aRecordKwInfo : i_parsedJsonObj["backupMap"]) 971 { 972 if (l_aRecordKwInfo.contains("sourceRecord") || 973 l_aRecordKwInfo.contains("sourceKeyword") || 974 l_aRecordKwInfo.contains("destinationkeywordValue") || 975 l_aRecordKwInfo.contains("sourcekeywordValue")) 976 { 977 std::string l_mismatchFound{ 978 (l_aRecordKwInfo["destinationkeywordValue"] != 979 l_aRecordKwInfo["sourcekeywordValue"]) 980 ? "YES" 981 : "NO"}; 982 983 std::string l_splitLine(191, '-'); 984 985 try 986 { 987 std::cout << std::left << std::setw(6) 988 << static_cast<int>(++l_slNum) << std::left 989 << std::setw(8) 990 << l_aRecordKwInfo.value("sourceRecord", "") 991 << std::left << std::setw(9) 992 << l_aRecordKwInfo.value("sourceKeyword", "") 993 << std::left << std::setw(75) << std::setfill(' ') 994 << utils::getPrintableValue( 995 l_aRecordKwInfo["destinationkeywordValue"]) 996 << std::left << std::setw(75) << std::setfill(' ') 997 << utils::getPrintableValue( 998 l_aRecordKwInfo["sourcekeywordValue"]) 999 << std::left << std::setw(14) << l_mismatchFound 1000 << '\n' 1001 << l_splitLine << std::endl; 1002 } 1003 catch (const std::exception& l_ex) 1004 { 1005 // TODO: Enable logging when verbose is enabled. 1006 std::cerr << l_ex.what() << std::endl; 1007 } 1008 } 1009 } 1010 } 1011 1012 int VpdTool::updateAllKeywords(const nlohmann::json& i_parsedJsonObj, 1013 bool i_useBackupData) const noexcept 1014 { 1015 int l_rc = constants::FAILURE; 1016 1017 if (i_parsedJsonObj.empty() || !i_parsedJsonObj.contains("source") || 1018 !i_parsedJsonObj.contains("backupMap")) 1019 { 1020 // TODO: Enable logging when verbose is enabled. 1021 std::cerr << "Invalid JSON" << std::endl; 1022 return l_rc; 1023 } 1024 1025 std::string l_srcVpdPath; 1026 if (auto l_vpdPath = i_parsedJsonObj["source"].value("hardwarePath", ""); 1027 !l_vpdPath.empty()) 1028 { 1029 l_srcVpdPath = l_vpdPath; 1030 } 1031 else if (auto l_vpdPath = 1032 i_parsedJsonObj["source"].value("inventoryPath", ""); 1033 !l_vpdPath.empty()) 1034 { 1035 l_srcVpdPath = l_vpdPath; 1036 } 1037 else 1038 { 1039 // TODO: Enable logging when verbose is enabled. 1040 std::cerr << "source path information is missing in JSON" << std::endl; 1041 return l_rc; 1042 } 1043 1044 bool l_anyMismatchFound = false; 1045 for (const auto& l_aRecordKwInfo : i_parsedJsonObj["backupMap"]) 1046 { 1047 if (!l_aRecordKwInfo.contains("sourceRecord") || 1048 !l_aRecordKwInfo.contains("sourceKeyword") || 1049 !l_aRecordKwInfo.contains("destinationkeywordValue") || 1050 !l_aRecordKwInfo.contains("sourcekeywordValue")) 1051 { 1052 // TODO: Enable logging when verbose is enabled. 1053 std::cerr << "Missing required information in the JSON" 1054 << std::endl; 1055 continue; 1056 } 1057 1058 if (l_aRecordKwInfo["sourcekeywordValue"] != 1059 l_aRecordKwInfo["destinationkeywordValue"]) 1060 { 1061 l_anyMismatchFound = true; 1062 1063 auto l_keywordValue = 1064 i_useBackupData ? l_aRecordKwInfo["destinationkeywordValue"] 1065 : l_aRecordKwInfo["sourcekeywordValue"]; 1066 1067 auto l_paramsToWrite = std::make_tuple( 1068 l_aRecordKwInfo["sourceRecord"], 1069 l_aRecordKwInfo["sourceKeyword"], l_keywordValue); 1070 1071 try 1072 { 1073 l_rc = utils::writeKeyword(l_srcVpdPath, l_paramsToWrite); 1074 if (l_rc > 0) 1075 { 1076 l_rc = constants::SUCCESS; 1077 } 1078 } 1079 catch (const std::exception& l_ex) 1080 { 1081 // TODO: Enable logging when verbose is enabled. 1082 std::cerr << "write keyword failed for record: " 1083 << l_aRecordKwInfo["sourceRecord"] 1084 << ", keyword: " << l_aRecordKwInfo["sourceKeyword"] 1085 << ", error: " << l_ex.what() << std::ends; 1086 } 1087 } 1088 } 1089 1090 std::string l_dataUsed = 1091 (i_useBackupData ? "data from backup" : "data from primary VPD"); 1092 if (l_anyMismatchFound) 1093 { 1094 std::cout << "Data updated successfully for all mismatching " 1095 "record-keyword pairs by choosing their corresponding " 1096 << l_dataUsed << ". Exit successfully." << std::endl; 1097 } 1098 else 1099 { 1100 std::cout << "No mismatch found for any of the above mentioned " 1101 "record-keyword pair. Exit successfully." 1102 << std::endl; 1103 } 1104 1105 return l_rc; 1106 } 1107 1108 int VpdTool::handleMoreOption( 1109 const nlohmann::json& i_parsedJsonObj) const noexcept 1110 { 1111 int l_rc = constants::FAILURE; 1112 1113 try 1114 { 1115 if (i_parsedJsonObj.empty() || !i_parsedJsonObj.contains("backupMap")) 1116 { 1117 throw std::runtime_error("Invalid JSON"); 1118 } 1119 1120 std::string l_srcVpdPath; 1121 1122 if (auto l_vpdPath = 1123 i_parsedJsonObj["source"].value("hardwarePath", ""); 1124 !l_vpdPath.empty()) 1125 { 1126 l_srcVpdPath = l_vpdPath; 1127 } 1128 else if (auto l_vpdPath = 1129 i_parsedJsonObj["source"].value("inventoryPath", ""); 1130 !l_vpdPath.empty()) 1131 { 1132 l_srcVpdPath = l_vpdPath; 1133 } 1134 else 1135 { 1136 throw std::runtime_error( 1137 "source path information is missing in JSON"); 1138 } 1139 1140 auto updateKeywordValue = 1141 [](std::string io_vpdPath, const std::string& i_recordName, 1142 const std::string& i_keywordName, 1143 const types::BinaryVector& i_keywordValue) -> int { 1144 int l_rc = constants::FAILURE; 1145 1146 try 1147 { 1148 auto l_paramsToWrite = std::make_tuple( 1149 i_recordName, i_keywordName, i_keywordValue); 1150 l_rc = utils::writeKeyword(io_vpdPath, l_paramsToWrite); 1151 1152 if (l_rc > 0) 1153 { 1154 std::cout << std::endl 1155 << "Data updated successfully." << std::endl; 1156 } 1157 } 1158 catch (const std::exception& l_ex) 1159 { 1160 // TODO: Enable log when verbose is enabled. 1161 std::cerr << l_ex.what() << std::endl; 1162 } 1163 return l_rc; 1164 }; 1165 1166 do 1167 { 1168 int l_slNum = 0; 1169 bool l_exit = false; 1170 1171 for (const auto& l_aRecordKwInfo : i_parsedJsonObj["backupMap"]) 1172 { 1173 if (!l_aRecordKwInfo.contains("sourceRecord") || 1174 !l_aRecordKwInfo.contains("sourceKeyword") || 1175 !l_aRecordKwInfo.contains("destinationkeywordValue") || 1176 !l_aRecordKwInfo.contains("sourcekeywordValue")) 1177 { 1178 // TODO: Enable logging when verbose is enabled. 1179 std::cerr 1180 << "Source or destination information is missing in the JSON." 1181 << std::endl; 1182 continue; 1183 } 1184 1185 const std::string l_mismatchFound{ 1186 (l_aRecordKwInfo["sourcekeywordValue"] != 1187 l_aRecordKwInfo["destinationkeywordValue"]) 1188 ? "YES" 1189 : "NO"}; 1190 1191 std::cout << std::endl 1192 << std::left << std::setw(6) << "S.No" << std::left 1193 << std::setw(8) << "Record" << std::left 1194 << std::setw(9) << "Keyword" << std::left 1195 << std::setw(75) << std::setfill(' ') << "Backup Data" 1196 << std::left << std::setw(75) << std::setfill(' ') 1197 << "Primary Data" << std::left << std::setw(14) 1198 << "Data Mismatch" << std::endl; 1199 1200 std::cout << std::left << std::setw(6) 1201 << static_cast<int>(++l_slNum) << std::left 1202 << std::setw(8) 1203 << l_aRecordKwInfo.value("sourceRecord", "") 1204 << std::left << std::setw(9) 1205 << l_aRecordKwInfo.value("sourceKeyword", "") 1206 << std::left << std::setw(75) << std::setfill(' ') 1207 << utils::getPrintableValue( 1208 l_aRecordKwInfo["destinationkeywordValue"]) 1209 << std::left << std::setw(75) << std::setfill(' ') 1210 << utils::getPrintableValue( 1211 l_aRecordKwInfo["sourcekeywordValue"]) 1212 << std::left << std::setw(14) << l_mismatchFound 1213 << std::endl; 1214 1215 std::cout << std::string(191, '=') << std::endl; 1216 1217 if (constants::STR_CMP_SUCCESS == 1218 l_mismatchFound.compare("YES")) 1219 { 1220 printFixSystemVpdOption( 1221 types::UserOption::UseBackupDataForCurrent); 1222 printFixSystemVpdOption( 1223 types::UserOption::UseSystemBackplaneDataForCurrent); 1224 printFixSystemVpdOption(types::UserOption::NewValueOnBoth); 1225 printFixSystemVpdOption(types::UserOption::SkipCurrent); 1226 printFixSystemVpdOption(types::UserOption::Exit); 1227 } 1228 else 1229 { 1230 std::cout << "No mismatch found." << std::endl << std::endl; 1231 printFixSystemVpdOption(types::UserOption::NewValueOnBoth); 1232 printFixSystemVpdOption(types::UserOption::SkipCurrent); 1233 printFixSystemVpdOption(types::UserOption::Exit); 1234 } 1235 1236 int l_userSelectedOption = types::UserOption::Exit; 1237 std::cin >> l_userSelectedOption; 1238 1239 if (types::UserOption::UseBackupDataForCurrent == 1240 l_userSelectedOption) 1241 { 1242 l_rc = updateKeywordValue( 1243 l_srcVpdPath, l_aRecordKwInfo["sourceRecord"], 1244 l_aRecordKwInfo["sourceKeyword"], 1245 l_aRecordKwInfo["destinationkeywordValue"]); 1246 } 1247 else if (types::UserOption::UseSystemBackplaneDataForCurrent == 1248 l_userSelectedOption) 1249 { 1250 l_rc = updateKeywordValue( 1251 l_srcVpdPath, l_aRecordKwInfo["sourceRecord"], 1252 l_aRecordKwInfo["sourceKeyword"], 1253 l_aRecordKwInfo["sourcekeywordValue"]); 1254 } 1255 else if (types::UserOption::NewValueOnBoth == 1256 l_userSelectedOption) 1257 { 1258 std::string l_newValue; 1259 std::cout 1260 << std::endl 1261 << "Enter the new value to update on both " 1262 "primary & backup. Value should be in ASCII or " 1263 "in HEX(prefixed with 0x) : "; 1264 std::cin >> l_newValue; 1265 std::cout << std::endl 1266 << std::string(191, '=') << std::endl; 1267 1268 try 1269 { 1270 l_rc = updateKeywordValue( 1271 l_srcVpdPath, l_aRecordKwInfo["sourceRecord"], 1272 l_aRecordKwInfo["sourceKeyword"], 1273 utils::convertToBinary(l_newValue)); 1274 } 1275 catch (const std::exception& l_ex) 1276 { 1277 // TODO: Enable logging when verbose is enabled. 1278 std::cerr << l_ex.what() << std::endl; 1279 } 1280 } 1281 else if (types::UserOption::SkipCurrent == l_userSelectedOption) 1282 { 1283 std::cout << std::endl 1284 << "Skipped the above record-keyword pair. " 1285 "Continue to the next available pair." 1286 << std::endl; 1287 } 1288 else if (types::UserOption::Exit == l_userSelectedOption) 1289 { 1290 std::cout << "Exit successfully" << std::endl; 1291 l_exit = true; 1292 break; 1293 } 1294 else 1295 { 1296 std::cout << "Provide a valid option. Retrying for the " 1297 "current record-keyword pair" 1298 << std::endl; 1299 } 1300 } 1301 if (l_exit) 1302 { 1303 l_rc = constants::SUCCESS; 1304 break; 1305 } 1306 } while (true); 1307 } 1308 catch (const std::exception& l_ex) 1309 { 1310 // TODO: Enable logging when verbose is enabled. 1311 std::cerr << l_ex.what() << std::endl; 1312 } 1313 1314 return l_rc; 1315 } 1316 1317 int VpdTool::resetVpdOnDbus() 1318 { 1319 // ToDo: Limit this function to lab mode only. 1320 1321 int l_rc = constants::FAILURE; 1322 try 1323 { 1324 std::string l_vpdManagerStopCmd( 1325 "systemctl stop " + std::string(constants::vpdManagerProcessName)); 1326 1327 std::cout << std::flush; 1328 if (auto l_rc = std::system(l_vpdManagerStopCmd.c_str()); l_rc != 0) 1329 { 1330 std::cerr << "Failed to stop " << constants::vpdManagerProcessName 1331 << " service. Return code [" << l_rc << "]. Exiting." 1332 << std::endl; 1333 return l_rc; 1334 } 1335 1336 std::string l_vpdServiceIsActiveCmd( 1337 "systemctl is-active --quiet " + 1338 std::string(constants::vpdManagerProcessName)); 1339 1340 std::cout << std::flush; 1341 if (auto l_rc = std::system(l_vpdServiceIsActiveCmd.c_str()); l_rc == 0) 1342 { 1343 std::cerr 1344 << constants::vpdManagerProcessName 1345 << " service is still active, can't proceed further. Return code [" 1346 << l_rc << "]. Exiting." << std::endl; 1347 return l_rc; 1348 } 1349 1350 std::error_code l_ec; 1351 if (static_cast<std::uintmax_t>(-1) == 1352 std::filesystem::remove_all(constants::pimPersistPath, l_ec)) 1353 { 1354 std::cerr 1355 << "Error occured while removing the persisted VPD under path [" 1356 << constants::pimPersistPath << "]." << std::endl; 1357 1358 if (l_ec) 1359 { 1360 std::cerr << "Reason: " << l_ec.message() << std::endl; 1361 } 1362 1363 std::cerr << "Reboot BMC to recover the system." << std::endl; 1364 return l_rc; 1365 } 1366 1367 std::string l_pimServiceRestartCmd( 1368 "systemctl restart " + 1369 std::string(constants::inventoryManagerService)); 1370 1371 std::cout << std::flush; 1372 if (auto l_rc = std::system(l_pimServiceRestartCmd.c_str()); l_rc != 0) 1373 { 1374 std::cerr << "Failed to restart " 1375 << constants::inventoryManagerService 1376 << " service. Return code [" << l_rc << "]. Exiting." 1377 << std::endl 1378 << "Reboot BMC to recover the system." << std::endl; 1379 return l_rc; 1380 } 1381 1382 std::string l_pimServiceIsActiveCmd( 1383 "systemctl is-active --quiet " + 1384 std::string(constants::inventoryManagerService)); 1385 1386 std::cout << std::flush; 1387 if (auto l_rc = std::system(l_pimServiceIsActiveCmd.c_str()); l_rc != 0) 1388 { 1389 std::cerr << constants::inventoryManagerService 1390 << " service is not active. Return code [" << l_rc 1391 << "]. Exiting." << std::endl 1392 << "Reboot BMC to recover the system." << std::endl; 1393 return l_rc; 1394 } 1395 1396 std::string l_vpdManagerStartCmd( 1397 "systemctl start " + std::string(constants::vpdManagerProcessName)); 1398 1399 std::cout << std::flush; 1400 if (auto l_rc = std::system(l_vpdManagerStartCmd.c_str()); l_rc != 0) 1401 { 1402 std::cerr << "Failed to start " << constants::vpdManagerProcessName 1403 << " service. Return code [" << l_rc << "]. Exiting." 1404 << std::endl 1405 << "Reboot BMC to recover the system." << std::endl; 1406 return l_rc; 1407 } 1408 1409 std::cout << std::flush; 1410 if (auto l_rc = std::system(l_vpdServiceIsActiveCmd.c_str()); l_rc != 0) 1411 { 1412 std::cerr << constants::vpdManagerProcessName 1413 << " service is not active. Return code [" << l_rc 1414 << "]. Exiting." << std::endl 1415 << "Reboot BMC to recover the system." << std::endl; 1416 return l_rc; 1417 } 1418 1419 l_rc = constants::SUCCESS; 1420 } 1421 catch (const std::exception& l_ex) 1422 { 1423 // TODO: Enable logging when verbose is enabled. 1424 std::cerr << l_ex.what() << std::endl; 1425 } 1426 1427 return l_rc; 1428 } 1429 1430 types::BinaryVector VpdTool::getVpdValueInBiosConfigManager( 1431 [[maybe_unused]] const std::string& i_recordName, 1432 [[maybe_unused]] const std::string& i_keywordName) const 1433 { 1434 types::BinaryVector l_result; 1435 // TODO: Use Record name, Keyword name to identify BIOS attribute. 1436 // Get BIOS attribute value from BIOS Config Manager. 1437 // Convert BIOS attribute value to VPD format value in binary. 1438 return l_result; 1439 } 1440 } // namespace vpd 1441