blob: cd5be8f1b660f97f5c6df6ac25540bc7068d1a0a [file] [log] [blame]
Alpana Kumari26a74af2019-09-10 23:53:58 -05001#include "config.h"
2
3#include "defines.hpp"
4#include "parser.hpp"
5#include "utils.hpp"
6
7#include <CLI/CLI.hpp>
8#include <exception>
9#include <fstream>
10#include <iostream>
11#include <iterator>
12#include <nlohmann/json.hpp>
13
14using namespace std;
15using namespace openpower::vpd;
16
Santosh Puranikbd011b22020-01-23 04:05:25 -060017/** @brief Encodes a keyword for D-Bus.
18 */
19static string encodeKeyword(const string& rec, const string& kw,
20 const string& encoding, const Parsed& vpdMap)
21{
22 if (encoding == "MAC")
23 {
24 string res{};
25 const auto& val = vpdMap.at(rec).at(kw);
26 size_t first = val[0];
27 res += toHex(first >> 4);
28 res += toHex(first & 0x0f);
29 for (size_t i = 1; i < val.size(); ++i)
30 {
31 res += ":";
32 res += toHex(val[i] >> 4);
33 res += toHex(val[i] & 0x0f);
34 }
35 return res;
36 }
37 else // default to string encoding
38 {
39 return string(vpdMap.at(rec).at(kw).begin(),
40 vpdMap.at(rec).at(kw).end());
41 }
42}
43
Alpana Kumari26a74af2019-09-10 23:53:58 -050044static void populateInterfaces(const nlohmann::json& js,
45 inventory::InterfaceMap& interfaces,
46 const Parsed& vpdMap)
47{
48 for (const auto& ifs : js.items())
49 {
50 const string& inf = ifs.key();
51 inventory::PropertyMap props;
52
53 for (const auto& itr : ifs.value().items())
54 {
55 const string& rec = itr.value().value("recordName", "");
56 const string& kw = itr.value().value("keywordName", "");
Santosh Puranikbd011b22020-01-23 04:05:25 -060057 const string& encoding = itr.value().value("encoding", "");
Alpana Kumari26a74af2019-09-10 23:53:58 -050058
59 if (!rec.empty() && !kw.empty() && vpdMap.count(rec) &&
60 vpdMap.at(rec).count(kw))
61 {
Santosh Puranikbd011b22020-01-23 04:05:25 -060062 auto encoded = encodeKeyword(rec, kw, encoding, vpdMap);
63 props.emplace(itr.key(), encoded);
Alpana Kumari26a74af2019-09-10 23:53:58 -050064 }
65 }
66 interfaces.emplace(inf, move(props));
67 }
68}
69
70static void populateDbus(Store& vpdStore, nlohmann::json& js,
Santosh Puranikbd011b22020-01-23 04:05:25 -060071 const string& filePath)
Alpana Kumari26a74af2019-09-10 23:53:58 -050072{
73 inventory::InterfaceMap interfaces;
74 inventory::ObjectMap objects;
Alpana Kumari26a74af2019-09-10 23:53:58 -050075 const auto& vpdMap = vpdStore.getVpdMap();
76 string preIntrStr = "com.ibm.ipzvpd.";
77
Santosh Puranikbd011b22020-01-23 04:05:25 -060078 for (const auto& item : js["frus"][filePath])
Alpana Kumari26a74af2019-09-10 23:53:58 -050079 {
Santosh Puranikbd011b22020-01-23 04:05:25 -060080 const auto& objectPath = item["inventoryPath"];
81 sdbusplus::message::object_path object(objectPath);
82
83 // Populate the VPD keywords and the common interfaces only if we
84 // are asked to inherit that data from the VPD, else only add the
85 // extraInterfaces.
86 if (item.value("inherit", true))
Alpana Kumari26a74af2019-09-10 23:53:58 -050087 {
Santosh Puranikbd011b22020-01-23 04:05:25 -060088 // Each record in the VPD becomes an interface and all keywords
89 // within the record are properties under that interface.
90 for (const auto& record : vpdMap)
Alpana Kumari26a74af2019-09-10 23:53:58 -050091 {
Santosh Puranikbd011b22020-01-23 04:05:25 -060092 inventory::PropertyMap prop;
93 for (auto kwVal : record.second)
94 {
95 std::vector<uint8_t> vec(kwVal.second.begin(),
96 kwVal.second.end());
97 std::string kw = kwVal.first;
98 if (kw[0] == '#')
99 {
100 kw = std::string("PD_") + kw[1];
101 }
102 prop.emplace(move(kw), move(vec));
103 }
104 interfaces.emplace(preIntrStr + record.first, move(prop));
Alpana Kumari26a74af2019-09-10 23:53:58 -0500105 }
Santosh Puranikbd011b22020-01-23 04:05:25 -0600106
107 // Populate interfaces and properties that are common to every FRU
108 // and additional interface that might be defined on a per-FRU
109 // basis.
110 if (js.find("commonInterfaces") != js.end())
111 {
112 populateInterfaces(js["commonInterfaces"], interfaces, vpdMap);
113 }
Alpana Kumari26a74af2019-09-10 23:53:58 -0500114 }
Santosh Puranikbd011b22020-01-23 04:05:25 -0600115 if (item.find("extraInterfaces") != item.end())
116 {
117 populateInterfaces(item["extraInterfaces"], interfaces, vpdMap);
118 }
119 objects.emplace(move(object), move(interfaces));
Alpana Kumari26a74af2019-09-10 23:53:58 -0500120 }
121
Alpana Kumari26a74af2019-09-10 23:53:58 -0500122 // Notify PIM
123 inventory::callPIM(move(objects));
124}
125
126int main(int argc, char** argv)
127{
128 int rc = 0;
129
130 try
131 {
132 using namespace CLI;
133 using json = nlohmann::json;
134
135 App app{"ibm-read-vpd - App to read IPZ format VPD, parse it and store "
136 "in DBUS"};
137 string file{};
138
139 app.add_option("-f, --file", file, "File containing VPD in IPZ format")
140 ->required()
141 ->check(ExistingFile);
142
143 CLI11_PARSE(app, argc, argv);
144
145 // Make sure that the file path we get is for a supported EEPROM
146 ifstream inventoryJson(INVENTORY_JSON);
147 auto js = json::parse(inventoryJson);
148
149 if ((js.find("frus") == js.end()) ||
150 (js["frus"].find(file) == js["frus"].end()))
151 {
152 throw std::runtime_error("Device path missing in inventory JSON");
153 }
154
Alpana Kumari26a74af2019-09-10 23:53:58 -0500155 ifstream vpdFile(file, ios::binary);
156 Binary vpd((istreambuf_iterator<char>(vpdFile)),
157 istreambuf_iterator<char>());
158
159 // Use ipz vpd Parser
160 auto vpdStore = parse(move(vpd));
161
162 // Write it to the inventory
Santosh Puranikbd011b22020-01-23 04:05:25 -0600163 populateDbus(vpdStore, js, file);
Alpana Kumari26a74af2019-09-10 23:53:58 -0500164 }
165 catch (exception& e)
166 {
167 cerr << e.what() << "\n";
168 rc = -1;
169 }
170
171 return rc;
172}