blob: 893109ccf1b53e1172c2d23c73afc3e554ef1cef [file] [log] [blame]
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +05301#include "vpd_tool_impl.hpp"
2
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +05303#include <iomanip>
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +05304#include <iostream>
5#include <sdbusplus/bus.hpp>
6#include <sstream>
7#include <variant>
8#include <vector>
9
10using namespace std;
11using sdbusplus::exception::SdBusError;
12using namespace openpower::vpd;
13
14void VpdTool::debugger(json output)
15{
16 cout << output.dump(4) << '\n';
17}
18
19auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
20 const string& kw)
21{
22 auto bus = sdbusplus::bus::new_default();
23 auto properties =
24 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
25 "org.freedesktop.DBus.Properties", "Get");
26 properties.append(interface);
27 properties.append(kw);
28 auto result = bus.call(properties);
29
30 if (result.is_method_error())
31 {
32 throw runtime_error("Get api failed");
33 }
34 return result;
35}
36
37void VpdTool::addFruTypeAndLocation(json exIntf, const string& object,
38 json& kwVal)
39{
40 for (const auto& intf : exIntf.items())
41 {
42 if ((intf.key().find("Item") != string::npos) &&
43 (intf.value().is_null()))
44 {
45 kwVal.emplace("type", intf.key());
46 break;
47 }
48 }
49
50 // Add location code.
51 constexpr auto LOCATION_CODE_IF = "com.ibm.ipzvpd.Location";
52 constexpr auto LOCATION_CODE_PROP = "LocationCode";
53
54 try
55 {
56 variant<string> response;
57 makeDBusCall(object, LOCATION_CODE_IF, LOCATION_CODE_PROP)
58 .read(response);
59
60 if (auto prop = get_if<string>(&response))
61 {
62 kwVal.emplace(LOCATION_CODE_PROP, *prop);
63 }
64 }
65 catch (const SdBusError& e)
66 {
67 kwVal.emplace(LOCATION_CODE_PROP, "");
68 }
69}
70
71json VpdTool::getVINIProperties(string invPath, json exIntf)
72{
73 variant<Binary> response;
74 json output = json::object({});
75 json kwVal = json::object({});
76
77 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
78 string interface = "com.ibm.ipzvpd.VINI";
79 string objectName = INVENTORY_PATH + invPath;
80
81 for (string kw : keyword)
82 {
83 try
84 {
85 makeDBusCall(objectName, interface, kw).read(response);
86
87 if (auto vec = get_if<Binary>(&response))
88 {
89 kwVal.emplace(kw, string(vec->begin(), vec->end()));
90 }
91 }
92 catch (const SdBusError& e)
93 {
94 output.emplace(invPath, json::object({}));
95 }
96 }
97
98 addFruTypeAndLocation(exIntf, objectName, kwVal);
99 output.emplace(invPath, kwVal);
100 return output;
101}
102
103void VpdTool::getExtraInterfaceProperties(string invPath, string extraInterface,
104 json prop, json exIntf, json& output)
105{
106 variant<string> response;
107
108 string objectName = INVENTORY_PATH + invPath;
109
110 for (const auto& itProp : prop.items())
111 {
112 string kw = itProp.key();
113 try
114 {
115 makeDBusCall(objectName, extraInterface, kw).read(response);
116
117 if (auto str = get_if<string>(&response))
118 {
119 output.emplace(kw, *str);
120 }
121 }
122 catch (const SdBusError& e)
123 {
124 output.emplace(invPath, json::object({}));
125 }
126 }
127 addFruTypeAndLocation(exIntf, objectName, output);
128}
129
130json VpdTool::interfaceDecider(json& itemEEPROM)
131{
132 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
133 {
134 throw runtime_error("Inventory Path not found");
135 }
136
137 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
138 {
139 throw runtime_error("Extra Interfaces not found");
140 }
141
142 bool exIntfCheck = false;
143 json output = json::object({});
144
145 if (itemEEPROM.value("inherit", true))
146 {
147 json j = getVINIProperties(itemEEPROM.at("inventoryPath"),
148 itemEEPROM["extraInterfaces"]);
149 output.insert(j.begin(), j.end());
150 }
151 else
152 {
153 json js;
154 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
155 {
156 if (!(ex.value().is_null()))
157 {
158 exIntfCheck = true;
159 getExtraInterfaceProperties(itemEEPROM.at("inventoryPath"),
160 ex.key(), ex.value(),
161 itemEEPROM["extraInterfaces"], js);
162 }
163 }
164 output.emplace(itemEEPROM.at("inventoryPath"), js);
165 }
166 return output;
167}
168
169json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
170{
171 json output = json::object({});
172 bool validObject = false;
173
174 if (jsObject.find("frus") == jsObject.end())
175 {
176 throw runtime_error("Frus missing in Inventory json");
177 }
178 else
179 {
180 for (const auto& itemFRUS : jsObject["frus"].items())
181 {
182 for (auto itemEEPROM : itemFRUS.value())
183 {
184 try
185 {
186 if (flag == 'O')
187 {
188 if (itemEEPROM.find("inventoryPath") ==
189 itemEEPROM.end())
190 {
191 throw runtime_error("Inventory Path not found");
192 }
193
194 else if (itemEEPROM.at("inventoryPath") == fruPath)
195 {
196 validObject = true;
197 json j = interfaceDecider(itemEEPROM);
198 output.insert(j.begin(), j.end());
199 return output;
200 }
201 }
202 else
203 {
204 json j = interfaceDecider(itemEEPROM);
205 output.insert(j.begin(), j.end());
206 }
207 }
208 catch (exception& e)
209 {
210 cerr << e.what();
211 }
212 }
213 }
214 if ((flag == 'O') && (!validObject))
215 {
216 throw runtime_error(
217 "Invalid object path. Refer --dumpInventory/-i option.");
218 }
219 }
220 return output;
221}
222
223void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
224{
225 char flag = 'I';
226 json output = parseInvJson(jsObject, flag, "");
227 debugger(output);
228}
229
230void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
231{
232 char flag = 'O';
233 json output = parseInvJson(jsObject, flag, fruPath);
234 debugger(output);
235}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530236
237void VpdTool::readKeyword()
238{
239 string interface = "com.ibm.ipzvpd.";
240 variant<Binary> response;
241
242 try
243 {
244 json output = json::object({});
245 json kwVal = json::object({});
246 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
247 .read(response);
248
249 if (auto vec = get_if<Binary>(&response))
250 {
251 kwVal.emplace(keyword, string(vec->begin(), vec->end()));
252 }
253
254 output.emplace(fruPath, kwVal);
255
256 debugger(output);
257 }
258 catch (json::exception& e)
259 {
260 json output = json::object({});
261 json kwVal = json::object({});
262
263 if (e.id == 316) // invalid UTF-8 byte exception
264 {
265 stringstream ss;
266 string hexByte;
267 string hexRep = "0x";
268 ss << hexRep;
269 hexByte = ss.str();
270
271 // convert Decimal to Hex
272 if (auto resp = get_if<Binary>(&response))
273 {
274 for (auto& vec : *resp)
275 {
276 if ((int)vec == 0)
277 {
278 ss << hex << (int)vec;
279 hexByte = ss.str();
280 }
281 ss << hex << (int)vec;
282 hexByte = ss.str();
283 }
284 }
285
286 kwVal.emplace(keyword, hexByte);
287 output.emplace(fruPath, kwVal);
288
289 debugger(output);
290 }
291 }
292}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530293
294int VpdTool::updateKeyword()
295{
296 Binary val;
297
298 if (value.find("0x") == string::npos)
299 {
300 val.assign(value.begin(), value.end());
301 }
302 else if (value.find("0x") != string::npos)
303 {
304 stringstream ss;
305 ss.str(value.substr(2));
306 string byteStr{};
307
308 while (!ss.eof())
309 {
310 ss >> setw(2) >> byteStr;
311 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
312
313 val.push_back(byte);
314 }
315 }
316
317 else
318 {
319 throw runtime_error("The value to be updated should be either in ascii "
320 "or in hex. Refer --help option");
321 }
322
323 // writeKeyword(fruPath, recordName, keyword, val);
324
325 auto bus = sdbusplus::bus::new_default();
326 auto properties =
327 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
328 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
329 properties.append(recordName);
330 properties.append(keyword);
331 properties.append(val);
332 auto result = bus.call(properties);
333
334 if (result.is_method_error())
335 {
336 throw runtime_error("Get api failed");
337 }
338 return 0;
339}