blob: fa1f57e99cbc7f12aff0d3e1c8b945c6e235b099 [file] [log] [blame]
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +05301#include "vpd_tool_impl.hpp"
2
PriyangaRamasamycdf943c2020-03-18 02:25:30 +05303#include <cstdlib>
4#include <filesystem>
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +05305#include <iomanip>
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +05306#include <iostream>
7#include <sdbusplus/bus.hpp>
8#include <sstream>
9#include <variant>
10#include <vector>
11
12using namespace std;
13using sdbusplus::exception::SdBusError;
14using namespace openpower::vpd;
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053015namespace fs = std::filesystem;
16
17void VpdTool::eraseInventoryPath(string& fru)
18{
19 // Power supply frupath comes with INVENTORY_PATH appended in prefix.
20 // Stripping it off inorder to avoid INVENTORY_PATH duplication
21 // during getVINIProperties() execution.
22 fru.erase(0, sizeof(INVENTORY_PATH) - 1);
23}
24
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053025void VpdTool::debugger(json output)
26{
27 cout << output.dump(4) << '\n';
28}
29
30auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
31 const string& kw)
32{
33 auto bus = sdbusplus::bus::new_default();
34 auto properties =
35 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
36 "org.freedesktop.DBus.Properties", "Get");
37 properties.append(interface);
38 properties.append(kw);
39 auto result = bus.call(properties);
40
41 if (result.is_method_error())
42 {
43 throw runtime_error("Get api failed");
44 }
45 return result;
46}
47
48void VpdTool::addFruTypeAndLocation(json exIntf, const string& object,
49 json& kwVal)
50{
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053051 if (object.find("powersupply") != string::npos)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053052 {
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053053 kwVal.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
54 }
55
56 // add else if statement for fan fru
57
58 else
59 {
60 for (const auto& intf : exIntf.items())
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053061 {
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053062 if ((intf.key().find("Item") != string::npos) &&
63 (intf.value().is_null()))
64 {
65 kwVal.emplace("type", intf.key());
66 break;
67 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053068 }
69 }
70
71 // Add location code.
72 constexpr auto LOCATION_CODE_IF = "com.ibm.ipzvpd.Location";
73 constexpr auto LOCATION_CODE_PROP = "LocationCode";
74
75 try
76 {
77 variant<string> response;
78 makeDBusCall(object, LOCATION_CODE_IF, LOCATION_CODE_PROP)
79 .read(response);
80
81 if (auto prop = get_if<string>(&response))
82 {
83 kwVal.emplace(LOCATION_CODE_PROP, *prop);
84 }
85 }
86 catch (const SdBusError& e)
87 {
88 kwVal.emplace(LOCATION_CODE_PROP, "");
89 }
90}
91
92json VpdTool::getVINIProperties(string invPath, json exIntf)
93{
94 variant<Binary> response;
95 json output = json::object({});
96 json kwVal = json::object({});
97
98 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
99 string interface = "com.ibm.ipzvpd.VINI";
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530100 string objectName = {};
101
102 if (invPath.find(INVENTORY_PATH) != string::npos)
103 {
104 objectName = invPath;
105 eraseInventoryPath(invPath);
106 }
107 else
108 {
109 objectName = INVENTORY_PATH + invPath;
110 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530111
112 for (string kw : keyword)
113 {
114 try
115 {
116 makeDBusCall(objectName, interface, kw).read(response);
117
118 if (auto vec = get_if<Binary>(&response))
119 {
120 kwVal.emplace(kw, string(vec->begin(), vec->end()));
121 }
122 }
123 catch (const SdBusError& e)
124 {
125 output.emplace(invPath, json::object({}));
126 }
127 }
128
129 addFruTypeAndLocation(exIntf, objectName, kwVal);
130 output.emplace(invPath, kwVal);
131 return output;
132}
133
134void VpdTool::getExtraInterfaceProperties(string invPath, string extraInterface,
135 json prop, json exIntf, json& output)
136{
137 variant<string> response;
138
139 string objectName = INVENTORY_PATH + invPath;
140
141 for (const auto& itProp : prop.items())
142 {
143 string kw = itProp.key();
144 try
145 {
146 makeDBusCall(objectName, extraInterface, kw).read(response);
147
148 if (auto str = get_if<string>(&response))
149 {
150 output.emplace(kw, *str);
151 }
152 }
153 catch (const SdBusError& e)
154 {
155 output.emplace(invPath, json::object({}));
156 }
157 }
158 addFruTypeAndLocation(exIntf, objectName, output);
159}
160
161json VpdTool::interfaceDecider(json& itemEEPROM)
162{
163 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
164 {
165 throw runtime_error("Inventory Path not found");
166 }
167
168 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
169 {
170 throw runtime_error("Extra Interfaces not found");
171 }
172
173 bool exIntfCheck = false;
174 json output = json::object({});
175
176 if (itemEEPROM.value("inherit", true))
177 {
178 json j = getVINIProperties(itemEEPROM.at("inventoryPath"),
179 itemEEPROM["extraInterfaces"]);
180 output.insert(j.begin(), j.end());
181 }
182 else
183 {
184 json js;
185 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
186 {
187 if (!(ex.value().is_null()))
188 {
189 exIntfCheck = true;
190 getExtraInterfaceProperties(itemEEPROM.at("inventoryPath"),
191 ex.key(), ex.value(),
192 itemEEPROM["extraInterfaces"], js);
193 }
194 }
195 output.emplace(itemEEPROM.at("inventoryPath"), js);
196 }
197 return output;
198}
199
200json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
201{
202 json output = json::object({});
203 bool validObject = false;
204
205 if (jsObject.find("frus") == jsObject.end())
206 {
207 throw runtime_error("Frus missing in Inventory json");
208 }
209 else
210 {
211 for (const auto& itemFRUS : jsObject["frus"].items())
212 {
213 for (auto itemEEPROM : itemFRUS.value())
214 {
215 try
216 {
217 if (flag == 'O')
218 {
219 if (itemEEPROM.find("inventoryPath") ==
220 itemEEPROM.end())
221 {
222 throw runtime_error("Inventory Path not found");
223 }
224
225 else if (itemEEPROM.at("inventoryPath") == fruPath)
226 {
227 validObject = true;
228 json j = interfaceDecider(itemEEPROM);
229 output.insert(j.begin(), j.end());
230 return output;
231 }
232 }
233 else
234 {
235 json j = interfaceDecider(itemEEPROM);
236 output.insert(j.begin(), j.end());
237 }
238 }
239 catch (exception& e)
240 {
241 cerr << e.what();
242 }
243 }
244 }
245 if ((flag == 'O') && (!validObject))
246 {
247 throw runtime_error(
248 "Invalid object path. Refer --dumpInventory/-i option.");
249 }
250 }
251 return output;
252}
253
254void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
255{
256 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530257 json output = json::array({});
258 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530259 debugger(output);
260}
261
262void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
263{
264 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530265 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530266 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530267 debugger(output);
268}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530269
270void VpdTool::readKeyword()
271{
272 string interface = "com.ibm.ipzvpd.";
273 variant<Binary> response;
274
275 try
276 {
277 json output = json::object({});
278 json kwVal = json::object({});
279 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
280 .read(response);
281
282 if (auto vec = get_if<Binary>(&response))
283 {
284 kwVal.emplace(keyword, string(vec->begin(), vec->end()));
285 }
286
287 output.emplace(fruPath, kwVal);
288
289 debugger(output);
290 }
291 catch (json::exception& e)
292 {
293 json output = json::object({});
294 json kwVal = json::object({});
295
296 if (e.id == 316) // invalid UTF-8 byte exception
297 {
298 stringstream ss;
299 string hexByte;
300 string hexRep = "0x";
301 ss << hexRep;
302 hexByte = ss.str();
303
304 // convert Decimal to Hex
305 if (auto resp = get_if<Binary>(&response))
306 {
307 for (auto& vec : *resp)
308 {
309 if ((int)vec == 0)
310 {
311 ss << hex << (int)vec;
312 hexByte = ss.str();
313 }
314 ss << hex << (int)vec;
315 hexByte = ss.str();
316 }
317 }
318
319 kwVal.emplace(keyword, hexByte);
320 output.emplace(fruPath, kwVal);
321
322 debugger(output);
323 }
324 }
325}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530326
327int VpdTool::updateKeyword()
328{
329 Binary val;
330
331 if (value.find("0x") == string::npos)
332 {
333 val.assign(value.begin(), value.end());
334 }
335 else if (value.find("0x") != string::npos)
336 {
337 stringstream ss;
338 ss.str(value.substr(2));
339 string byteStr{};
340
341 while (!ss.eof())
342 {
343 ss >> setw(2) >> byteStr;
344 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
345
346 val.push_back(byte);
347 }
348 }
349
350 else
351 {
352 throw runtime_error("The value to be updated should be either in ascii "
353 "or in hex. Refer --help option");
354 }
355
356 // writeKeyword(fruPath, recordName, keyword, val);
357
358 auto bus = sdbusplus::bus::new_default();
359 auto properties =
360 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
361 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
362 properties.append(recordName);
363 properties.append(keyword);
364 properties.append(val);
365 auto result = bus.call(properties);
366
367 if (result.is_method_error())
368 {
369 throw runtime_error("Get api failed");
370 }
371 return 0;
372}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530373
374void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
375{
376 for (const auto& itemFRUS : jsObject["frus"].items())
377 {
378 for (const auto& itemEEPROM : itemFRUS.value().items())
379 {
380 string fru = itemEEPROM.value().at("inventoryPath");
381
382 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
383 fruCachePath += INVENTORY_PATH;
384 fruCachePath += fru;
385
386 try
387 {
388 for (const auto& it : fs::directory_iterator(fruCachePath))
389 {
390 if (fs::is_regular_file(it.status()))
391 {
392 fs::remove(it);
393 }
394 }
395 }
396 catch (const fs::filesystem_error& e)
397 {
398 }
399 }
400 }
401
402 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
403 system(udevRemove.c_str());
404
405 string invManagerRestart =
406 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
407 system(invManagerRestart.c_str());
408
409 string sysVpdStop = "systemctl stop system-vpd.service";
410 system(sysVpdStop.c_str());
411
412 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
413 system(udevAdd.c_str());
414}