#include "vpd_tool_impl.hpp" #include "impl.hpp" #include "parser_factory.hpp" #include "vpd_exceptions.hpp" #include #include #include #include #include #include using namespace std; using namespace openpower::vpd; using namespace inventory; using namespace openpower::vpd::manager::editor; namespace fs = std::filesystem; using json = nlohmann::json; using namespace openpower::vpd::exceptions; using namespace openpower::vpd::parser; using namespace openpower::vpd::parser::factory; using namespace openpower::vpd::parser::interface; bool VpdTool::fileToVector(Binary& data) { try { std::ifstream file(value, std::ifstream::in); if (file) { std::string line; while (std::getline(file, line)) { std::istringstream iss(line); std::string byteStr; while (iss >> std::setw(2) >> std::hex >> byteStr) { uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16); data.emplace(data.end(), byte); } } return true; } else { std::cerr << "Unable to open the given file " << value << std::endl; } } catch (std::exception& e) { std::cerr << e.what(); } return false; } bool VpdTool::copyStringToFile(const std::string& input) { try { std::ofstream outFile(value, std::ofstream::out); if (outFile.is_open()) { std::string hexString = input; if (input.substr(0, 2) == "0x") { // truncating prefix 0x hexString = input.substr(2); } outFile.write(hexString.c_str(), hexString.length()); } else { std::cerr << "Error opening output file " << value << std::endl; return false; } outFile.close(); } catch (std::exception& e) { std::cerr << e.what(); return false; } return true; } static void getVPDInMap(const std::string& vpdPath, std::unordered_map& vpdMap, json& js, const std::string& invPath) { auto jsonToParse = INVENTORY_JSON_DEFAULT; if (fs::exists(INVENTORY_JSON_SYM_LINK)) { jsonToParse = INVENTORY_JSON_SYM_LINK; } std::ifstream inventoryJson(jsonToParse); if (!inventoryJson) { throw std::runtime_error("VPD JSON file not found"); } try { js = json::parse(inventoryJson); } catch (const json::parse_error& ex) { throw std::runtime_error("VPD JSON parsing failed"); } Binary vpdVector{}; uint32_t vpdStartOffset = 0; vpdVector = getVpdDataInVector(js, vpdPath); ParserInterface* parser = ParserFactory::getParser(vpdVector, invPath, vpdPath, vpdStartOffset); auto parseResult = parser->parse(); ParserFactory::freeParser(parser); if (auto pVal = std::get_if(&parseResult)) { vpdMap = pVal->getVpdMap(); } else { std::string err = vpdPath + " is not of type IPZ VPD. Unable to parse the VPD."; throw std::runtime_error(err); } } Binary VpdTool::toBinary(const std::string& value) { Binary val{}; if (value.find("0x") == string::npos) { val.assign(value.begin(), value.end()); } else if (value.find("0x") != string::npos) { stringstream ss; ss.str(value.substr(2)); string byteStr{}; if (value.length() % 2 != 0) { throw runtime_error( "VPD-TOOL write option accepts 2 digit hex numbers. (Eg. 0x1 " "should be given as 0x01). Aborting the write operation."); } if (value.find_first_not_of("0123456789abcdefABCDEF", 2) != std::string::npos) { throw runtime_error("Provide a valid hexadecimal input."); } while (ss >> setw(2) >> byteStr) { uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16); val.push_back(byte); } } else { throw runtime_error("The value to be updated should be either in ascii " "or in hex. Refer --help option"); } return val; } void VpdTool::printReturnCode(int returnCode) { if (returnCode) { cout << "\n Command failed with the return code " << returnCode << ". Continuing the execution. " << endl; } } void VpdTool::eraseInventoryPath(string& fru) { // Power supply frupath comes with INVENTORY_PATH appended in prefix. // Stripping it off inorder to avoid INVENTORY_PATH duplication // during getVINIProperties() execution. fru.erase(0, sizeof(INVENTORY_PATH) - 1); } void VpdTool::debugger(json output) { cout << output.dump(4) << '\n'; } auto VpdTool::makeDBusCall(const string& objectName, const string& interface, const string& kw) { auto bus = sdbusplus::bus::new_default(); auto properties = bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(), "org.freedesktop.DBus.Properties", "Get"); properties.append(interface); properties.append(kw); auto result = bus.call(properties); if (result.is_method_error()) { throw runtime_error("Get api failed"); } return result; } json VpdTool::getVINIProperties(string invPath) { variant response; json kwVal = json::object({}); vector keyword{"CC", "SN", "PN", "FN", "DR"}; string interface = "com.ibm.ipzvpd.VINI"; string objectName = {}; if (invPath.find(INVENTORY_PATH) != string::npos) { objectName = invPath; eraseInventoryPath(invPath); } else { objectName = INVENTORY_PATH + invPath; } for (string kw : keyword) { try { makeDBusCall(objectName, interface, kw).read(response); if (auto vec = get_if(&response)) { string printableVal = getPrintableValue(*vec); kwVal.emplace(kw, printableVal); } } catch (const sdbusplus::exception_t& e) { if (string(e.name()) == string("org.freedesktop.DBus.Error.UnknownObject")) { kwVal.emplace(invPath, json::object({})); objFound = false; break; } } } return kwVal; } void VpdTool::getExtraInterfaceProperties(const string& invPath, const string& extraInterface, const json& prop, json& output) { variant response; string objectName = INVENTORY_PATH + invPath; for (const auto& itProp : prop.items()) { string kw = itProp.key(); try { makeDBusCall(objectName, extraInterface, kw).read(response); if (auto str = get_if(&response)) { output.emplace(kw, *str); } } catch (const sdbusplus::exception_t& e) { if (std::string(e.name()) == std::string("org.freedesktop.DBus.Error.UnknownObject")) { objFound = false; break; } else if (std::string(e.name()) == std::string("org.freedesktop.DBus.Error.UnknownProperty")) { output.emplace(kw, ""); } } } } json VpdTool::interfaceDecider(json& itemEEPROM) { if (itemEEPROM.find("inventoryPath") == itemEEPROM.end()) { throw runtime_error("Inventory Path not found"); } if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end()) { throw runtime_error("Extra Interfaces not found"); } json subOutput = json::object({}); fruType = "FRU"; json j; objFound = true; string invPath = itemEEPROM.at("inventoryPath"); j = getVINIProperties(invPath); if (objFound) { subOutput.insert(j.begin(), j.end()); json js; if (itemEEPROM.find("type") != itemEEPROM.end()) { fruType = itemEEPROM.at("type"); } js.emplace("TYPE", fruType); if (invPath.find("powersupply") != string::npos) { js.emplace("type", POWER_SUPPLY_TYPE_INTERFACE); } else if (invPath.find("fan") != string::npos) { js.emplace("type", FAN_INTERFACE); } for (const auto& ex : itemEEPROM["extraInterfaces"].items()) { // Properties under Decorator.Asset interface are derived from VINI // keywords. Displaying VINI keywords and skipping Decorator.Asset // interface's properties will avoid duplicate entries in vpd-tool // output. if (ex.key() == "xyz.openbmc_project.Inventory.Decorator.Asset" && itemEEPROM["extraInterfaces"].find(constants::kwdVpdInf) != itemEEPROM["extraInterfaces"].end()) { continue; } if (!(ex.value().is_null())) { // TODO: Remove this if condition check once inventory json is // updated with xyz location code interface. if (ex.key() == "com.ibm.ipzvpd.Location") { getExtraInterfaceProperties( invPath, "xyz.openbmc_project.Inventory.Decorator.LocationCode", ex.value(), js); } else { getExtraInterfaceProperties(invPath, ex.key(), ex.value(), js); } } if ((ex.key().find("Item") != string::npos) && (ex.value().is_null())) { js.emplace("type", ex.key()); } subOutput.insert(js.begin(), js.end()); } } return subOutput; } json VpdTool::getPresentPropJson(const std::string& invPath) { std::variant response; std::string presence = "Unknown"; try { makeDBusCall(invPath, "xyz.openbmc_project.Inventory.Item", "Present") .read(response); if (auto pVal = get_if(&response)) { presence = *pVal ? "true" : "false"; } } catch (const sdbusplus::exception::SdBusError& e) { presence = "Unknown"; } json js; js.emplace("Present", presence); return js; } json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath) { json output = json::object({}); bool validObject = false; if (jsObject.find("frus") == jsObject.end()) { throw runtime_error("Frus missing in Inventory json"); } else { for (const auto& itemFRUS : jsObject["frus"].items()) { for (auto itemEEPROM : itemFRUS.value()) { json subOutput = json::object({}); try { if (flag == 'O') { if (itemEEPROM.find("inventoryPath") == itemEEPROM.end()) { throw runtime_error("Inventory Path not found"); } else if (itemEEPROM.at("inventoryPath") == fruPath) { validObject = true; subOutput = interfaceDecider(itemEEPROM); json presentJs = getPresentPropJson( "/xyz/openbmc_project/inventory" + fruPath); subOutput.insert(presentJs.begin(), presentJs.end()); output.emplace(fruPath, subOutput); return output; } } else { subOutput = interfaceDecider(itemEEPROM); json presentJs = getPresentPropJson( "/xyz/openbmc_project/inventory" + string(itemEEPROM.at("inventoryPath"))); subOutput.insert(presentJs.begin(), presentJs.end()); output.emplace(string(itemEEPROM.at("inventoryPath")), subOutput); } } catch (const exception& e) { cerr << e.what(); } } } if ((flag == 'O') && (!validObject)) { throw runtime_error( "Invalid object path. Refer --dumpInventory/-i option."); } } return output; } void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject) { char flag = 'I'; json output = json::array({}); output.emplace_back(parseInvJson(jsObject, flag, "")); debugger(output); } void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject) { char flag = 'O'; json output = json::array({}); output.emplace_back(parseInvJson(jsObject, flag, fruPath)); debugger(output); } void VpdTool::readKeyword() { const std::string& kw = getDbusNameForThisKw(keyword); string interface = "com.ibm.ipzvpd."; variant response; try { makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, kw) .read(response); string printableVal{}; if (auto vec = get_if(&response)) { printableVal = getPrintableValue(*vec); } if (!value.empty()) { if (copyStringToFile(printableVal)) { std::cout << "Value read is saved in the file " << value << std::endl; return; } else { std::cerr << "Error while saving the read value in file. " "Displaying the read value on console" << std::endl; } } json output = json::object({}); json kwVal = json::object({}); kwVal.emplace(keyword, printableVal); output.emplace(fruPath, kwVal); debugger(output); } catch (const json::exception& e) { std::cout << "Keyword Value: " << keyword << std::endl; std::cout << e.what() << std::endl; } } int VpdTool::updateKeyword() { Binary val; if (std::filesystem::exists(value)) { if (!fileToVector(val)) { std::cout << "Keyword " << keyword << " update failed." << std::endl; return 1; } } else { val = toBinary(value); } auto bus = sdbusplus::bus::new_default(); auto properties = bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword"); properties.append(static_cast(fruPath)); properties.append(recordName); properties.append(keyword); properties.append(val); // When there is a request to write 10K bytes, there occurs a delay in dbus // call which leads to dbus timeout exception. To avoid such exceptions // increase the timeout period from default 25 seconds to 60 seconds. auto timeoutInMicroSeconds = 60 * 1000000L; auto result = bus.call(properties, timeoutInMicroSeconds); if (result.is_method_error()) { throw runtime_error("Get api failed"); } std::cout << "Data updated successfully " << std::endl; return 0; } void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject) { for (const auto& itemFRUS : jsObject["frus"].items()) { for (const auto& itemEEPROM : itemFRUS.value().items()) { string fru = itemEEPROM.value().at("inventoryPath"); fs::path fruCachePath = INVENTORY_MANAGER_CACHE; fruCachePath += INVENTORY_PATH; fruCachePath += fru; try { for (const auto& it : fs::directory_iterator(fruCachePath)) { if (fs::is_regular_file(it.status())) { fs::remove(it); } } } catch (const fs::filesystem_error& e) {} } } cout.flush(); string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v"; int returnCode = system(udevRemove.c_str()); printReturnCode(returnCode); string invManagerRestart = "systemctl restart xyz.openbmc_project.Inventory.Manager.service"; returnCode = system(invManagerRestart.c_str()); printReturnCode(returnCode); string sysVpdRestart = "systemctl restart system-vpd.service"; returnCode = system(sysVpdRestart.c_str()); printReturnCode(returnCode); string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v"; returnCode = system(udevAdd.c_str()); printReturnCode(returnCode); } int VpdTool::updateHardware(const uint32_t offset) { int rc = 0; Binary val; if (std::filesystem::exists(value)) { if (!fileToVector(val)) { std::cout << "Keyword " << keyword << " update failed." << std::endl; return 1; } } else { val = toBinary(value); } ifstream inventoryJson(INVENTORY_JSON_SYM_LINK); try { auto json = nlohmann::json::parse(inventoryJson); EditorImpl edit(fruPath, json, recordName, keyword); edit.updateKeyword(val, offset, false); } catch (const json::parse_error& ex) { throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK)); } std::cout << "Data updated successfully " << std::endl; return rc; } void VpdTool::readKwFromHw(const uint32_t& startOffset) { ifstream inventoryJson(INVENTORY_JSON_SYM_LINK); auto jsonFile = nlohmann::json::parse(inventoryJson); std::string inventoryPath; if (jsonFile["frus"].contains(fruPath)) { uint32_t vpdStartOffset = 0; for (const auto& item : jsonFile["frus"][fruPath]) { if (item.find("offset") != item.end()) { vpdStartOffset = item["offset"]; break; } } if ((startOffset != vpdStartOffset)) { std::cerr << "Invalid offset, please correct the offset" << endl; std::cerr << "Recommended Offset is: " << vpdStartOffset << endl; return; } inventoryPath = jsonFile["frus"][fruPath][0]["inventoryPath"]; } Binary completeVPDFile; fstream vpdFileStream; vpdFileStream.exceptions(std::ifstream::badbit | std::ifstream::failbit); try { vpdFileStream.open(fruPath, std::ios::in | std::ios::out | std::ios::binary); auto vpdFileSize = std::min(std::filesystem::file_size(fruPath), constants::MAX_VPD_SIZE); if (vpdFileSize == 0) { std::cerr << "File size is 0 for " << fruPath << std::endl; throw std::runtime_error("File size is 0."); } completeVPDFile.resize(vpdFileSize); vpdFileStream.seekg(startOffset, ios_base::cur); vpdFileStream.read(reinterpret_cast(&completeVPDFile[0]), vpdFileSize); vpdFileStream.clear(std::ios_base::eofbit); } catch (const std::system_error& fail) { std::cerr << "Exception in file handling [" << fruPath << "] error : " << fail.what(); std::cerr << "Stream file size = " << vpdFileStream.gcount() << std::endl; throw; } if (completeVPDFile.empty()) { throw std::runtime_error("Invalid File"); } Impl obj(completeVPDFile, (constants::pimPath + inventoryPath), fruPath, startOffset); std::string keywordVal = obj.readKwFromHw(recordName, keyword); keywordVal = getPrintableValue(keywordVal); if (keywordVal.empty()) { std::cerr << "The given keyword " << keyword << " or record " << recordName << " or both are not present in the given FRU path " << fruPath << std::endl; return; } if (!value.empty()) { if (copyStringToFile(keywordVal)) { std::cout << "Value read is saved in the file " << value << std::endl; return; } else { std::cerr << "Error while saving the read value in file. Displaying " "the read value on console" << std::endl; } } json output = json::object({}); json kwVal = json::object({}); kwVal.emplace(keyword, keywordVal); output.emplace(fruPath, kwVal); debugger(output); } void VpdTool::printFixSystemVPDOption(UserOption option) { switch (option) { case VpdTool::EXIT: cout << "\nEnter 0 => To exit successfully : "; break; case VpdTool::BACKUP_DATA_FOR_ALL: cout << "\n\nEnter 1 => If you choose the data on backup for all " "mismatching record-keyword pairs"; break; case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL: cout << "\nEnter 2 => If you choose the data on primary for all " "mismatching record-keyword pairs"; break; case VpdTool::MORE_OPTIONS: cout << "\nEnter 3 => If you wish to explore more options"; break; case VpdTool::BACKUP_DATA_FOR_CURRENT: cout << "\nEnter 4 => If you choose the data on backup as the " "right value"; break; case VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT: cout << "\nEnter 5 => If you choose the data on primary as the " "right value"; break; case VpdTool::NEW_VALUE_ON_BOTH: cout << "\nEnter 6 => If you wish to enter a new value to update " "both on backup and primary"; break; case VpdTool::SKIP_CURRENT: cout << "\nEnter 7 => If you wish to skip the above " "record-keyword pair"; break; } } void VpdTool::getSystemDataFromCache(IntfPropMap& svpdBusData) { const auto vsys = getAllDBusProperty( constants::pimIntf, "/xyz/openbmc_project/inventory/system/chassis/motherboard", "com.ibm.ipzvpd.VSYS"); svpdBusData.emplace("VSYS", vsys); const auto vcen = getAllDBusProperty( constants::pimIntf, "/xyz/openbmc_project/inventory/system/chassis/motherboard", "com.ibm.ipzvpd.VCEN"); svpdBusData.emplace("VCEN", vcen); const auto lxr0 = getAllDBusProperty( constants::pimIntf, "/xyz/openbmc_project/inventory/system/chassis/motherboard", "com.ibm.ipzvpd.LXR0"); svpdBusData.emplace("LXR0", lxr0); const auto util = getAllDBusProperty( constants::pimIntf, "/xyz/openbmc_project/inventory/system/chassis/motherboard", "com.ibm.ipzvpd.UTIL"); svpdBusData.emplace("UTIL", util); } int VpdTool::fixSystemVPD() { std::string outline(191, '='); cout << "\nRestorable record-keyword pairs and their data on backup & " "primary.\n\n" << outline << std::endl; cout << left << setw(6) << "S.No" << left << setw(8) << "Record" << left << setw(9) << "Keyword" << left << setw(75) << "Data On Backup" << left << setw(75) << "Data On Primary" << left << setw(14) << "Data Mismatch\n" << outline << std::endl; uint8_t num = 0; // Get system VPD data in map unordered_map vpdMap; json js; getVPDInMap(constants::systemVpdFilePath, vpdMap, js, constants::pimPath + static_cast(constants::SYSTEM_OBJECT)); // Get system VPD D-Bus Data in a map IntfPropMap svpdBusData; getSystemDataFromCache(svpdBusData); for (const auto& recordKw : svpdKwdMap) { string record = recordKw.first; // Extract specific record data from the svpdBusData map. const auto& rec = svpdBusData.find(record); if (rec == svpdBusData.end()) { std::cerr << record << " not a part of critical system VPD records." << std::endl; continue; } const auto& recData = svpdBusData.find(record)->second; string busStr{}, hwValStr{}; for (const auto& keywordInfo : recordKw.second) { const auto& keyword = get<0>(keywordInfo); string mismatch = "NO"; // no mismatch string hardwareValue{}; auto recItr = vpdMap.find(record); if (recItr != vpdMap.end()) { DbusPropertyMap& kwValMap = recItr->second; auto kwItr = kwValMap.find(keyword); if (kwItr != kwValMap.end()) { hardwareValue = kwItr->second; } } inventory::Value kwValue; for (auto& kwData : recData) { if (kwData.first == keyword) { kwValue = kwData.second; break; } } if (keyword != "SE") // SE to display in Hex string only { ostringstream hwValStream; hwValStream << "0x"; hwValStr = hwValStream.str(); for (uint16_t byte : hardwareValue) { hwValStream << setfill('0') << setw(2) << hex << byte; hwValStr = hwValStream.str(); } if (const auto value = get_if(&kwValue)) { busStr = hexString(*value); } if (busStr != hwValStr) { mismatch = "YES"; } } else { if (const auto value = get_if(&kwValue)) { busStr = getPrintableValue(*value); } if (busStr != hardwareValue) { mismatch = "YES"; } hwValStr = hardwareValue; } recKwData.push_back( make_tuple(++num, record, keyword, busStr, hwValStr, mismatch)); std::string splitLine(191, '-'); cout << left << setw(6) << static_cast(num) << left << setw(8) << record << left << setw(9) << keyword << left << setw(75) << setfill(' ') << busStr << left << setw(75) << setfill(' ') << hwValStr << left << setw(14) << mismatch << '\n' << splitLine << endl; } } parseSVPDOptions(js, std::string()); return 0; } void VpdTool::parseSVPDOptions(const nlohmann::json& json, const std::string& backupEEPROMPath) { do { printFixSystemVPDOption(VpdTool::BACKUP_DATA_FOR_ALL); printFixSystemVPDOption(VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL); printFixSystemVPDOption(VpdTool::MORE_OPTIONS); printFixSystemVPDOption(VpdTool::EXIT); int option = 0; cin >> option; std::string outline(191, '='); cout << '\n' << outline << endl; if (json.find("frus") == json.end()) { throw runtime_error("Frus not found in json"); } bool mismatchFound = false; if (option == VpdTool::BACKUP_DATA_FOR_ALL) { for (const auto& data : recKwData) { if (get<5>(data) == "YES") { EditorImpl edit(constants::systemVpdFilePath, json, get<1>(data), get<2>(data)); edit.updateKeyword(toBinary(get<3>(data)), 0, true); mismatchFound = true; } } if (mismatchFound) { cout << "\nData updated successfully for all mismatching " "record-keyword pairs by choosing their corresponding " "data from backup. Exit successfully.\n" << endl; } else { cout << "\nNo mismatch found for any of the above mentioned " "record-keyword pair. Exit successfully.\n"; } exit(0); } else if (option == VpdTool::SYSTEM_BACKPLANE_DATA_FOR_ALL) { std::string hardwarePath = constants::systemVpdFilePath; if (!backupEEPROMPath.empty()) { hardwarePath = backupEEPROMPath; } for (const auto& data : recKwData) { if (get<5>(data) == "YES") { std::string record = get<1>(data), keyword = get<2>(data); if (!backupEEPROMPath.empty()) { getBackupRecordKeyword(record, keyword); } EditorImpl edit(hardwarePath, json, record, keyword); edit.updateKeyword(toBinary(get<4>(data)), 0, true); mismatchFound = true; } } if (mismatchFound) { cout << "\nData updated successfully for all mismatching " "record-keyword pairs by choosing their corresponding " "data from primary VPD.\n" << endl; } else { cout << "\nNo mismatch found for any of the above mentioned " "record-keyword pair. Exit successfully.\n"; } exit(0); } else if (option == VpdTool::MORE_OPTIONS) { cout << "\nIterate through all restorable record-keyword pairs\n"; for (const auto& data : recKwData) { do { cout << '\n' << outline << endl; cout << left << setw(6) << "S.No" << left << setw(8) << "Record" << left << setw(9) << "Keyword" << left << setw(75) << setfill(' ') << "Backup Data" << left << setw(75) << setfill(' ') << "Primary Data" << left << setw(14) << "Data Mismatch" << endl; cout << left << setw(6) << static_cast(get<0>(data)) << left << setw(8) << get<1>(data) << left << setw(9) << get<2>(data) << left << setw(75) << setfill(' ') << get<3>(data) << left << setw(75) << setfill(' ') << get<4>(data) << left << setw(14) << get<5>(data); cout << '\n' << outline << endl; if (get<5>(data) == "NO") { cout << "\nNo mismatch found.\n"; printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH); printFixSystemVPDOption(VpdTool::SKIP_CURRENT); printFixSystemVPDOption(VpdTool::EXIT); } else { printFixSystemVPDOption( VpdTool::BACKUP_DATA_FOR_CURRENT); printFixSystemVPDOption( VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT); printFixSystemVPDOption(VpdTool::NEW_VALUE_ON_BOTH); printFixSystemVPDOption(VpdTool::SKIP_CURRENT); printFixSystemVPDOption(VpdTool::EXIT); } cin >> option; cout << '\n' << outline << endl; if (option == VpdTool::BACKUP_DATA_FOR_CURRENT) { EditorImpl edit(constants::systemVpdFilePath, json, get<1>(data), get<2>(data)); edit.updateKeyword(toBinary(get<3>(data)), 0, true); cout << "\nData updated successfully.\n"; break; } else if (option == VpdTool::SYSTEM_BACKPLANE_DATA_FOR_CURRENT) { std::string hardwarePath = constants::systemVpdFilePath; std::string record = get<1>(data); std::string keyword = get<2>(data); if (!backupEEPROMPath.empty()) { hardwarePath = backupEEPROMPath; getBackupRecordKeyword(record, keyword); } EditorImpl edit(hardwarePath, json, record, keyword); edit.updateKeyword(toBinary(get<4>(data)), 0, true); cout << "\nData updated successfully.\n"; break; } else if (option == VpdTool::NEW_VALUE_ON_BOTH) { string value; cout << "\nEnter the new value to update on both " "primary & backup. Value should be in ASCII or " "in HEX(prefixed with 0x) : "; cin >> value; cout << '\n' << outline << endl; EditorImpl edit(constants::systemVpdFilePath, json, get<1>(data), get<2>(data)); edit.updateKeyword(toBinary(value), 0, true); if (!backupEEPROMPath.empty()) { std::string record = get<1>(data); std::string keyword = get<2>(data); getBackupRecordKeyword(record, keyword); EditorImpl edit(backupEEPROMPath, json, record, keyword); edit.updateKeyword(toBinary(value), 0, true); } cout << "\nData updated successfully.\n"; break; } else if (option == VpdTool::SKIP_CURRENT) { cout << "\nSkipped the above record-keyword pair. " "Continue to the next available pair.\n"; break; } else if (option == VpdTool::EXIT) { cout << "\nExit successfully\n"; exit(0); } else { cout << "\nProvide a valid option. Retrying for the " "current record-keyword pair\n"; } } while (1); } exit(0); } else if (option == VpdTool::EXIT) { cout << "\nExit successfully"; exit(0); } else { cout << "\nProvide a valid option. Retry."; continue; } } while (true); } int VpdTool::cleanSystemVPD() { try { // Get system VPD hardware data in map unordered_map vpdMap; json js; getVPDInMap(constants::systemVpdFilePath, vpdMap, js, constants::pimPath + static_cast(constants::SYSTEM_OBJECT)); RecKwValMap kwdsToBeUpdated; for (auto recordMap : svpdKwdMap) { const auto& record = recordMap.first; std::unordered_map kwDefault; for (auto keywordMap : recordMap.second) { // Skip those keywords which cannot be reset at manufacturing if (!std::get<3>(keywordMap)) { continue; } const auto& keyword = std::get<0>(keywordMap); // Get hardware value for this keyword from vpdMap Binary hardwareValue; auto recItr = vpdMap.find(record); if (recItr != vpdMap.end()) { DbusPropertyMap& kwValMap = recItr->second; auto kwItr = kwValMap.find(keyword); if (kwItr != kwValMap.end()) { hardwareValue = toBinary(kwItr->second); } } // compare hardware value with the keyword's default value auto defaultValue = std::get<1>(keywordMap); if (hardwareValue != defaultValue) { EditorImpl edit(constants::systemVpdFilePath, js, record, keyword); edit.updateKeyword(defaultValue, 0, true); } } } std::cout << "\n The critical keywords from system backplane VPD has " "been reset successfully." << std::endl; } catch (const std::exception& e) { std::cerr << e.what(); std::cerr << "\nManufacturing reset on system vpd keywords is unsuccessful"; } return 0; } int VpdTool::fixSystemBackupVPD(const std::string& backupEepromPath, const std::string& backupInvPath) { std::string outline(191, '='); cout << "\nRestorable record-keyword pairs and their data on backup & " "primary.\n\n" << outline << std::endl; cout << left << setw(6) << "S.No" << left << setw(8) << "Record" << left << setw(9) << "Keyword" << left << setw(75) << "Data On Backup" << left << setw(75) << "Data On Primary" << left << setw(14) << "Data Mismatch\n" << outline << std::endl; uint8_t num = 0; // Get system VPD data in map unordered_map systemVPDMap; json js; getVPDInMap(constants::systemVpdFilePath, systemVPDMap, js, constants::pimPath + static_cast(constants::SYSTEM_OBJECT)); // Get backup VPD data in map unordered_map backupVPDMap; getVPDInMap(backupEepromPath, backupVPDMap, js, constants::pimPath + backupInvPath); for (const auto& recordKw : svpdKwdMap) { const std::string& primaryRecord = recordKw.first; std::string primaryValStr{}, backupValStr{}; for (const auto& keywordInfo : recordKw.second) { const auto& primaryKeyword = get<0>(keywordInfo); const auto& bkRecord = get<4>(keywordInfo); const auto& bkKeyword = get<5>(keywordInfo); string mismatch = "NO"; string primaryValue{}; string backupValue{}; // Find keyword value for system VPD (primary VPD) auto primaryRecItr = systemVPDMap.find(primaryRecord); if (primaryRecItr != systemVPDMap.end()) { DbusPropertyMap& primaryKwValMap = primaryRecItr->second; auto kwItr = primaryKwValMap.find(primaryKeyword); if (kwItr != primaryKwValMap.end()) { primaryValue = kwItr->second; } } // Find keyword value for backup VPD auto bkRecItr = backupVPDMap.find(bkRecord); if (bkRecItr != backupVPDMap.end()) { DbusPropertyMap& bkKwValMap = bkRecItr->second; auto kwItr = bkKwValMap.find(bkKeyword); if (kwItr != bkKwValMap.end()) { backupValue = kwItr->second; } } // SE to display in hex string only if (primaryKeyword != "SE") { ostringstream hwValStream; hwValStream << "0x"; primaryValStr = hwValStream.str(); for (uint16_t byte : primaryValue) { hwValStream << setfill('0') << setw(2) << hex << byte; primaryValStr = hwValStream.str(); } hwValStream.str(std::string()); hwValStream << "0x"; backupValStr = hwValStream.str(); for (uint16_t byte : backupValue) { hwValStream << setfill('0') << setw(2) << hex << byte; backupValStr = hwValStream.str(); } if (primaryValStr != backupValStr) { mismatch = "YES"; } } else { if (primaryValue != backupValue) { mismatch = "YES"; } primaryValStr = primaryValue; backupValStr = backupValue; } recKwData.push_back(make_tuple(++num, primaryRecord, primaryKeyword, backupValStr, primaryValStr, mismatch)); std::string splitLine(191, '-'); cout << left << setw(6) << static_cast(num) << left << setw(8) << primaryRecord << left << setw(9) << primaryKeyword << left << setw(75) << setfill(' ') << backupValStr << left << setw(75) << setfill(' ') << primaryValStr << left << setw(14) << mismatch << '\n' << splitLine << endl; } } parseSVPDOptions(js, backupEepromPath); return 0; }