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