blob: b8bb01b91fbe99a59fca808709e8147a1d80e0c6 [file] [log] [blame]
#include "fru_parser.hpp"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <nlohmann/json.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
namespace pldm
{
namespace responder
{
namespace fru_parser
{
using Json = nlohmann::json;
using InternalFailure =
sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
const Json emptyJson{};
const std::vector<Json> emptyJsonList{};
const std::vector<std::string> emptyStringVec{};
constexpr auto fruMasterJson = "FRU_Master.json";
FruParser::FruParser(const std::string& dirPath)
{
fs::path dir(dirPath);
if (!fs::exists(dir) || fs::is_empty(dir))
{
std::cerr << "FRU config directory does not exist or empty, DIR="
<< dirPath;
throw InternalFailure();
}
fs::path masterFilePath = dir / fruMasterJson;
if (!fs::exists(masterFilePath))
{
std::cerr << "FRU D-Bus lookup JSON does not exist, PATH="
<< masterFilePath;
throw InternalFailure();
}
setupDBusLookup(masterFilePath);
setupFruRecordMap(dirPath);
}
void FruParser::setupDBusLookup(const fs::path& filePath)
{
std::ifstream jsonFile(filePath);
auto data = Json::parse(jsonFile, nullptr, false);
if (data.is_discarded())
{
std::cerr << "Parsing FRU master config file failed, FILE=" << filePath;
throw InternalFailure();
}
Service service = data.value("service", "");
RootPath rootPath = data.value("root_path", "");
Interfaces interfaces = data.value("interfaces", emptyStringVec);
lookupInfo.emplace(std::make_tuple(std::move(service), std::move(rootPath),
std::move(interfaces)));
}
void FruParser::setupFruRecordMap(const std::string& dirPath)
{
for (auto& file : fs::directory_iterator(dirPath))
{
auto fileName = file.path().filename().string();
if (fruMasterJson == fileName)
{
continue;
}
std::ifstream jsonFile(file.path());
auto data = Json::parse(jsonFile, nullptr, false);
if (data.is_discarded())
{
std::cerr << "Parsing FRU master config file failed, FILE="
<< file.path();
throw InternalFailure();
}
auto record = data.value("record_details", emptyJson);
auto recordType =
static_cast<uint8_t>(record.value("fru_record_type", 0));
auto encType =
static_cast<uint8_t>(record.value("fru_encoding_type", 0));
auto dbusIntfName = record.value("dbus_interface_name", "");
auto entries = data.value("fru_fields", emptyJsonList);
std::vector<FieldInfo> fieldInfo;
for (const auto& entry : entries)
{
auto fieldType =
static_cast<uint8_t>(entry.value("fru_field_type", 0));
auto dbus = entry.value("dbus", emptyJson);
auto interface = dbus.value("interface", "");
auto property = dbus.value("property_name", "");
auto propType = dbus.value("property_type", "");
fieldInfo.emplace_back(
std::make_tuple(std::move(interface), std::move(property),
std::move(propType), std::move(fieldType)));
}
FruRecordInfo fruInfo;
fruInfo = std::make_tuple(recordType, encType, std::move(fieldInfo));
auto search = recordMap.find(dbusIntfName);
// PLDM FRU can have multiple records for the same FRU like General FRU
// record and multiple OEM FRU records. If the FRU item interface name
// is already in the map, that indicates a record info is already added
// for the FRU, so append the new record info to the same data.
if (search != recordMap.end())
{
search->second.emplace_back(std::move(fruInfo));
}
else
{
FruRecordInfos recordInfos{fruInfo};
recordMap.emplace(dbusIntfName, recordInfos);
}
}
}
} // namespace fru_parser
} // namespace responder
} // namespace pldm