blob: 44977e0e8990c03f0a7ef06371a7b112d18b984f [file] [log] [blame]
PriyangaRamasamyabb87ed2019-11-19 17:25:35 +05301#include "config.h"
2
3#include "defines.hpp"
4#include "ibm_vpd_type_check.hpp"
5#include "keyword_vpd_parser.hpp"
6#include "parser.hpp"
7#include "utils.hpp"
8
9#include <CLI/CLI.hpp>
10#include <exception>
11#include <fstream>
12#include <iostream>
13#include <iterator>
14#include <nlohmann/json.hpp>
15
16using namespace std;
17using namespace openpower::vpd;
18using namespace CLI;
19using namespace vpd::keyword::parser;
20using namespace vpdFormat;
21
22/** @brief Encodes a keyword for D-Bus.
23 */
24static string encodeKeyword(const string& kw, const string& encoding)
25{
26 if (encoding == "MAC")
27 {
28 string res{};
29 size_t first = kw[0];
30 res += toHex(first >> 4);
31 res += toHex(first & 0x0f);
32 for (size_t i = 1; i < kw.size(); ++i)
33 {
34 res += ":";
35 res += toHex(kw[i] >> 4);
36 res += toHex(kw[i] & 0x0f);
37 }
38 return res;
39 }
40 else // default to string encoding
41 {
42 return string(kw.begin(), kw.end());
43 }
44}
45
46/**
47 * @brief Populate FRU specific interfaces.
48 *
49 * This is a common method which handles both
50 * ipz and keyword specific interfaces thus,
51 * reducing the code redundancy.
52 * @param[in] map - Reference to the innermost keyword-value map.
53 * @param[in] preIntrStr - Reference to the interface string.
54 * @param[out] interfaces - Reference to interface map.
55 */
56template <typename T>
57static void populateFruSpecificInterfaces(const T& map,
58 const string& preIntrStr,
59 inventory::InterfaceMap& interfaces)
60{
61 inventory::PropertyMap prop;
62
63 for (const auto& kwVal : map)
64 {
65 std::vector<uint8_t> vec(kwVal.second.begin(), kwVal.second.end());
66
67 auto kw = kwVal.first;
68
69 if (kw[0] == '#')
70 {
71 kw = std::string("PD_") + kw[1];
72 }
73 prop.emplace(move(kw), move(vec));
74 }
75
76 interfaces.emplace(preIntrStr, move(prop));
77}
78
79/**
80 * @brief Populate Interfaces.
81 *
82 * This method populates common and extra interfaces to dbus.
83 * @param[in] js - json object
84 * @param[out] interfaces - Reference to interface map
85 * @param[in] vpdMap - Reference to the parsed vpd map.
86 */
87template <typename T>
88static void populateInterfaces(const nlohmann::json& js,
89 inventory::InterfaceMap& interfaces,
90 const T& vpdMap)
91{
92 for (const auto& ifs : js.items())
93 {
94 const string& inf = ifs.key();
95 inventory::PropertyMap props;
96
97 for (const auto& itr : ifs.value().items())
98 {
99 const string& rec = itr.value().value("recordName", "");
100 const string& kw = itr.value().value("keywordName", "");
101 const string& encoding = itr.value().value("encoding", "");
102
103 if constexpr (std::is_same<T, Parsed>::value)
104 {
105 if (!rec.empty() && !kw.empty() && vpdMap.at(rec).count(kw) &&
106 vpdMap.count(rec))
107 {
108 auto encoded =
109 encodeKeyword(vpdMap.at(rec).at(kw), encoding);
110 props.emplace(itr.key(), encoded);
111 }
112 }
113 else if constexpr (std::is_same<T, KeywordVpdMap>::value)
114 {
115 if (!kw.empty() && vpdMap.count(kw))
116 {
117 auto prop =
118 string(vpdMap.at(kw).begin(), vpdMap.at(kw).end());
119 auto encoded = encodeKeyword(prop, encoding);
120 props.emplace(itr.key(), encoded);
121 }
122 }
123 }
124 interfaces.emplace(inf, move(props));
125 }
126}
127
128/**
129 * @brief Populate Dbus.
130 *
131 * This method invokes all the populateInterface functions
132 * and notifies PIM about dbus object.
133 * @param[in] vpdMap - Either IPZ vpd map or Keyword vpd map based on the input.
134 * @param[in] js - Inventory json object
135 * @param[in] filePath - Path of the vpd file
136 * @param[in] preIntrStr - Interface string
137 */
138template <typename T>
139static void populateDbus(const T& vpdMap, nlohmann::json& js,
140 const string& filePath, const string& preIntrStr)
141{
142 inventory::InterfaceMap interfaces;
143 inventory::ObjectMap objects;
144 inventory::PropertyMap prop;
145
146 for (const auto& item : js["frus"][filePath])
147 {
148 const auto& objectPath = item["inventoryPath"];
149 sdbusplus::message::object_path object(objectPath);
150 // Populate the VPD keywords and the common interfaces only if we
151 // are asked to inherit that data from the VPD, else only add the
152 // extraInterfaces.
153 if (item.value("inherit", true))
154 {
155 if constexpr (std::is_same<T, Parsed>::value)
156 {
157 // Each record in the VPD becomes an interface and all keyword
158 // within the record are properties under that interface.
159 for (const auto& record : vpdMap)
160 {
161 populateFruSpecificInterfaces(
162 record.second, preIntrStr + record.first, interfaces);
163 }
164 }
165 else if constexpr (std::is_same<T, KeywordVpdMap>::value)
166 {
167 populateFruSpecificInterfaces(vpdMap, preIntrStr, interfaces);
168 }
169 }
170
171 // Populate interfaces and properties that are common to every FRU
172 // and additional interface that might be defined on a per-FRU basis.
173
174 if (item.find("commonInterfaces") != item.end())
175 {
176 populateInterfaces(item["commonInterfaces"], interfaces, vpdMap);
177 }
178 if (item.find("extraInterfaces") != item.end())
179 {
180 populateInterfaces(item["extraInterfaces"], interfaces, vpdMap);
181 }
182 objects.emplace(move(object), move(interfaces));
183 }
184
185 // Notify PIM
186 inventory::callPIM(move(objects));
187}
188
189int main(int argc, char** argv)
190{
191 int rc = 0;
192
193 try
194 {
195 using json = nlohmann::json;
196
197 App app{"ibm-read-vpd - App to read IPZ format VPD, parse it and store "
198 "in DBUS"};
199 string file{};
200
201 app.add_option("-f, --file", file, "File containing VPD (IPZ/KEYWORD)")
202 ->required()
203 ->check(ExistingFile);
204
205 CLI11_PARSE(app, argc, argv);
206
207 // Make sure that the file path we get is for a supported EEPROM
208 ifstream inventoryJson(INVENTORY_JSON);
209 auto js = json::parse(inventoryJson);
210
211 if ((js.find("frus") == js.end()) ||
212 (js["frus"].find(file) == js["frus"].end()))
213 {
214 throw std::runtime_error("Device path missing in inventory JSON");
215 }
216
217 // Open the file in binary mode
218 ifstream vpdFile(file, ios::binary);
219 // Read the content of the binary file into a vector
220 Binary vpdVector((istreambuf_iterator<char>(vpdFile)),
221 istreambuf_iterator<char>());
222
223 vpdType type = vpdTypeCheck(vpdVector);
224
225 switch (type)
226 {
227 case IPZ_VPD:
228 {
229 // Invoking IPZ Vpd Parser
230 auto vpdStore = parse(move(vpdVector));
231 const Parsed& vpdMap = vpdStore.getVpdMap();
232 string preIntrStr = "com.ibm.ipzvpd.";
233 // Write it to the inventory
234 populateDbus(vpdMap, js, file, preIntrStr);
235 }
236 break;
237
238 case KEYWORD_VPD:
239 {
240 // Creating Keyword Vpd Parser Object
241 KeywordVpdParser parserObj(move(vpdVector));
242 // Invoking KW Vpd Parser
243 const auto& kwValMap = parserObj.parseKwVpd();
244 string preIntrStr = "com.ibm.kwvpd.KWVPD";
245 populateDbus(kwValMap, js, file, preIntrStr);
246 }
247 break;
248 default:
249 throw std::runtime_error("Invalid VPD format");
250 }
251 }
252 catch (exception& e)
253 {
254 cerr << e.what() << "\n";
255 rc = -1;
256 }
257
258 return rc;
259}