1 #include "fru_parser.hpp" 2 3 #include <filesystem> 4 #include <fstream> 5 #include <iostream> 6 #include <nlohmann/json.hpp> 7 #include <xyz/openbmc_project/Common/error.hpp> 8 9 namespace pldm 10 { 11 12 namespace responder 13 { 14 15 namespace fru_parser 16 { 17 18 using Json = nlohmann::json; 19 using InternalFailure = 20 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 21 22 const Json emptyJson{}; 23 const std::vector<Json> emptyJsonList{}; 24 const std::vector<std::string> emptyStringVec{}; 25 26 constexpr auto fruMasterJson = "FRU_Master.json"; 27 28 FruParser::FruParser(const std::string& dirPath) 29 { 30 fs::path dir(dirPath); 31 if (!fs::exists(dir) || fs::is_empty(dir)) 32 { 33 std::cerr << "FRU config directory does not exist or empty, DIR=" 34 << dirPath << "\n"; 35 return; 36 } 37 38 fs::path masterFilePath = dir / fruMasterJson; 39 if (!fs::exists(masterFilePath)) 40 { 41 std::cerr << "FRU D-Bus lookup JSON does not exist, PATH=" 42 << masterFilePath << "\n"; 43 throw InternalFailure(); 44 } 45 46 setupDBusLookup(masterFilePath); 47 setupFruRecordMap(dirPath); 48 } 49 50 void FruParser::setupDBusLookup(const fs::path& filePath) 51 { 52 std::ifstream jsonFile(filePath); 53 54 auto data = Json::parse(jsonFile, nullptr, false); 55 if (data.is_discarded()) 56 { 57 std::cerr << "Parsing FRU master config file failed, FILE=" << filePath; 58 throw InternalFailure(); 59 } 60 61 Service service = data.value("service", ""); 62 RootPath rootPath = data.value("root_path", ""); 63 auto entities = data.value("entities", emptyJsonList); 64 Interfaces interfaces{}; 65 EntityType entityType{}; 66 for (auto& entity : entities) 67 { 68 auto intf = entity.value("interface", ""); 69 intfToEntityType[intf] = 70 std::move(entity.value("entity_type", entityType)); 71 interfaces.emplace(std::move(intf)); 72 } 73 lookupInfo.emplace(std::make_tuple(std::move(service), std::move(rootPath), 74 std::move(interfaces))); 75 } 76 77 void FruParser::setupFruRecordMap(const std::string& dirPath) 78 { 79 for (auto& file : fs::directory_iterator(dirPath)) 80 { 81 auto fileName = file.path().filename().string(); 82 if (fruMasterJson == fileName) 83 { 84 continue; 85 } 86 87 std::ifstream jsonFile(file.path()); 88 auto data = Json::parse(jsonFile, nullptr, false); 89 if (data.is_discarded()) 90 { 91 92 std::cerr << "Parsing FRU master config file failed, FILE=" 93 << file.path(); 94 throw InternalFailure(); 95 } 96 97 auto record = data.value("record_details", emptyJson); 98 auto recordType = 99 static_cast<uint8_t>(record.value("fru_record_type", 0)); 100 auto encType = 101 static_cast<uint8_t>(record.value("fru_encoding_type", 0)); 102 auto dbusIntfName = record.value("dbus_interface_name", ""); 103 auto entries = data.value("fru_fields", emptyJsonList); 104 std::vector<FieldInfo> fieldInfo; 105 106 for (const auto& entry : entries) 107 { 108 auto fieldType = 109 static_cast<uint8_t>(entry.value("fru_field_type", 0)); 110 auto dbus = entry.value("dbus", emptyJson); 111 auto interface = dbus.value("interface", ""); 112 auto property = dbus.value("property_name", ""); 113 auto propType = dbus.value("property_type", ""); 114 fieldInfo.emplace_back( 115 std::make_tuple(std::move(interface), std::move(property), 116 std::move(propType), std::move(fieldType))); 117 } 118 119 FruRecordInfo fruInfo; 120 fruInfo = std::make_tuple(recordType, encType, std::move(fieldInfo)); 121 122 auto search = recordMap.find(dbusIntfName); 123 124 // PLDM FRU can have multiple records for the same FRU like General FRU 125 // record and multiple OEM FRU records. If the FRU item interface name 126 // is already in the map, that indicates a record info is already added 127 // for the FRU, so append the new record info to the same data. 128 if (search != recordMap.end()) 129 { 130 search->second.emplace_back(std::move(fruInfo)); 131 } 132 else 133 { 134 FruRecordInfos recordInfos{fruInfo}; 135 recordMap.emplace(dbusIntfName, recordInfos); 136 } 137 } 138 } 139 140 } // namespace fru_parser 141 142 } // namespace responder 143 144 } // namespace pldm 145