blob: cd5be8f1b660f97f5c6df6ac25540bc7068d1a0a [file] [log] [blame]
#include "config.h"
#include "defines.hpp"
#include "parser.hpp"
#include "utils.hpp"
#include <CLI/CLI.hpp>
#include <exception>
#include <fstream>
#include <iostream>
#include <iterator>
#include <nlohmann/json.hpp>
using namespace std;
using namespace openpower::vpd;
/** @brief Encodes a keyword for D-Bus.
*/
static string encodeKeyword(const string& rec, const string& kw,
const string& encoding, const Parsed& vpdMap)
{
if (encoding == "MAC")
{
string res{};
const auto& val = vpdMap.at(rec).at(kw);
size_t first = val[0];
res += toHex(first >> 4);
res += toHex(first & 0x0f);
for (size_t i = 1; i < val.size(); ++i)
{
res += ":";
res += toHex(val[i] >> 4);
res += toHex(val[i] & 0x0f);
}
return res;
}
else // default to string encoding
{
return string(vpdMap.at(rec).at(kw).begin(),
vpdMap.at(rec).at(kw).end());
}
}
static void populateInterfaces(const nlohmann::json& js,
inventory::InterfaceMap& interfaces,
const Parsed& vpdMap)
{
for (const auto& ifs : js.items())
{
const string& inf = ifs.key();
inventory::PropertyMap props;
for (const auto& itr : ifs.value().items())
{
const string& rec = itr.value().value("recordName", "");
const string& kw = itr.value().value("keywordName", "");
const string& encoding = itr.value().value("encoding", "");
if (!rec.empty() && !kw.empty() && vpdMap.count(rec) &&
vpdMap.at(rec).count(kw))
{
auto encoded = encodeKeyword(rec, kw, encoding, vpdMap);
props.emplace(itr.key(), encoded);
}
}
interfaces.emplace(inf, move(props));
}
}
static void populateDbus(Store& vpdStore, nlohmann::json& js,
const string& filePath)
{
inventory::InterfaceMap interfaces;
inventory::ObjectMap objects;
const auto& vpdMap = vpdStore.getVpdMap();
string preIntrStr = "com.ibm.ipzvpd.";
for (const auto& item : js["frus"][filePath])
{
const auto& objectPath = item["inventoryPath"];
sdbusplus::message::object_path object(objectPath);
// Populate the VPD keywords and the common interfaces only if we
// are asked to inherit that data from the VPD, else only add the
// extraInterfaces.
if (item.value("inherit", true))
{
// Each record in the VPD becomes an interface and all keywords
// within the record are properties under that interface.
for (const auto& record : vpdMap)
{
inventory::PropertyMap prop;
for (auto kwVal : record.second)
{
std::vector<uint8_t> vec(kwVal.second.begin(),
kwVal.second.end());
std::string kw = kwVal.first;
if (kw[0] == '#')
{
kw = std::string("PD_") + kw[1];
}
prop.emplace(move(kw), move(vec));
}
interfaces.emplace(preIntrStr + record.first, move(prop));
}
// Populate interfaces and properties that are common to every FRU
// and additional interface that might be defined on a per-FRU
// basis.
if (js.find("commonInterfaces") != js.end())
{
populateInterfaces(js["commonInterfaces"], interfaces, vpdMap);
}
}
if (item.find("extraInterfaces") != item.end())
{
populateInterfaces(item["extraInterfaces"], interfaces, vpdMap);
}
objects.emplace(move(object), move(interfaces));
}
// Notify PIM
inventory::callPIM(move(objects));
}
int main(int argc, char** argv)
{
int rc = 0;
try
{
using namespace CLI;
using json = nlohmann::json;
App app{"ibm-read-vpd - App to read IPZ format VPD, parse it and store "
"in DBUS"};
string file{};
app.add_option("-f, --file", file, "File containing VPD in IPZ format")
->required()
->check(ExistingFile);
CLI11_PARSE(app, argc, argv);
// Make sure that the file path we get is for a supported EEPROM
ifstream inventoryJson(INVENTORY_JSON);
auto js = json::parse(inventoryJson);
if ((js.find("frus") == js.end()) ||
(js["frus"].find(file) == js["frus"].end()))
{
throw std::runtime_error("Device path missing in inventory JSON");
}
ifstream vpdFile(file, ios::binary);
Binary vpd((istreambuf_iterator<char>(vpdFile)),
istreambuf_iterator<char>());
// Use ipz vpd Parser
auto vpdStore = parse(move(vpd));
// Write it to the inventory
populateDbus(vpdStore, js, file);
}
catch (exception& e)
{
cerr << e.what() << "\n";
rc = -1;
}
return rc;
}