blob: 1ee7b2b29d7eaeca63e3c27100df676db3a01538 [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);
Alpana Kumarib6965f12020-06-01 00:32:21 -0500130 kwVal.emplace("TYPE", fruType);
131
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530132 output.emplace(invPath, kwVal);
133 return output;
134}
135
136void VpdTool::getExtraInterfaceProperties(string invPath, string extraInterface,
137 json prop, json exIntf, json& output)
138{
139 variant<string> response;
140
141 string objectName = INVENTORY_PATH + invPath;
142
143 for (const auto& itProp : prop.items())
144 {
145 string kw = itProp.key();
146 try
147 {
148 makeDBusCall(objectName, extraInterface, kw).read(response);
149
150 if (auto str = get_if<string>(&response))
151 {
152 output.emplace(kw, *str);
153 }
154 }
155 catch (const SdBusError& e)
156 {
157 output.emplace(invPath, json::object({}));
158 }
159 }
160 addFruTypeAndLocation(exIntf, objectName, output);
161}
162
163json VpdTool::interfaceDecider(json& itemEEPROM)
164{
165 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
166 {
167 throw runtime_error("Inventory Path not found");
168 }
169
170 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
171 {
172 throw runtime_error("Extra Interfaces not found");
173 }
174
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530175 json output = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500176 fruType = "FRU";
177
178 // check type and add FRU Type in object
179 if (itemEEPROM.find("type") != itemEEPROM.end())
180 {
181 fruType = itemEEPROM.at("type");
182 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530183
184 if (itemEEPROM.value("inherit", true))
185 {
186 json j = getVINIProperties(itemEEPROM.at("inventoryPath"),
187 itemEEPROM["extraInterfaces"]);
188 output.insert(j.begin(), j.end());
189 }
190 else
191 {
192 json js;
193 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
194 {
195 if (!(ex.value().is_null()))
196 {
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530197 getExtraInterfaceProperties(itemEEPROM.at("inventoryPath"),
198 ex.key(), ex.value(),
199 itemEEPROM["extraInterfaces"], js);
200 }
201 }
202 output.emplace(itemEEPROM.at("inventoryPath"), js);
203 }
Alpana Kumarib6965f12020-06-01 00:32:21 -0500204
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530205 return output;
206}
207
208json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
209{
210 json output = json::object({});
211 bool validObject = false;
212
213 if (jsObject.find("frus") == jsObject.end())
214 {
215 throw runtime_error("Frus missing in Inventory json");
216 }
217 else
218 {
219 for (const auto& itemFRUS : jsObject["frus"].items())
220 {
221 for (auto itemEEPROM : itemFRUS.value())
222 {
223 try
224 {
225 if (flag == 'O')
226 {
227 if (itemEEPROM.find("inventoryPath") ==
228 itemEEPROM.end())
229 {
230 throw runtime_error("Inventory Path not found");
231 }
232
233 else if (itemEEPROM.at("inventoryPath") == fruPath)
234 {
235 validObject = true;
236 json j = interfaceDecider(itemEEPROM);
237 output.insert(j.begin(), j.end());
238 return output;
239 }
240 }
241 else
242 {
243 json j = interfaceDecider(itemEEPROM);
244 output.insert(j.begin(), j.end());
245 }
246 }
247 catch (exception& e)
248 {
249 cerr << e.what();
250 }
251 }
252 }
253 if ((flag == 'O') && (!validObject))
254 {
255 throw runtime_error(
256 "Invalid object path. Refer --dumpInventory/-i option.");
257 }
258 }
259 return output;
260}
261
262void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
263{
264 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530265 json output = json::array({});
266 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530267 debugger(output);
268}
269
270void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
271{
272 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530273 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530274 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530275 debugger(output);
276}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530277
278void VpdTool::readKeyword()
279{
280 string interface = "com.ibm.ipzvpd.";
281 variant<Binary> response;
282
283 try
284 {
285 json output = json::object({});
286 json kwVal = json::object({});
287 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
288 .read(response);
289
290 if (auto vec = get_if<Binary>(&response))
291 {
292 kwVal.emplace(keyword, string(vec->begin(), vec->end()));
293 }
294
295 output.emplace(fruPath, kwVal);
296
297 debugger(output);
298 }
299 catch (json::exception& e)
300 {
301 json output = json::object({});
302 json kwVal = json::object({});
303
304 if (e.id == 316) // invalid UTF-8 byte exception
305 {
306 stringstream ss;
307 string hexByte;
308 string hexRep = "0x";
309 ss << hexRep;
310 hexByte = ss.str();
311
312 // convert Decimal to Hex
313 if (auto resp = get_if<Binary>(&response))
314 {
315 for (auto& vec : *resp)
316 {
317 if ((int)vec == 0)
318 {
319 ss << hex << (int)vec;
320 hexByte = ss.str();
321 }
322 ss << hex << (int)vec;
323 hexByte = ss.str();
324 }
325 }
326
327 kwVal.emplace(keyword, hexByte);
328 output.emplace(fruPath, kwVal);
329
330 debugger(output);
331 }
332 }
333}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530334
335int VpdTool::updateKeyword()
336{
337 Binary val;
338
339 if (value.find("0x") == string::npos)
340 {
341 val.assign(value.begin(), value.end());
342 }
343 else if (value.find("0x") != string::npos)
344 {
345 stringstream ss;
346 ss.str(value.substr(2));
347 string byteStr{};
348
349 while (!ss.eof())
350 {
351 ss >> setw(2) >> byteStr;
352 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
353
354 val.push_back(byte);
355 }
356 }
357
358 else
359 {
360 throw runtime_error("The value to be updated should be either in ascii "
361 "or in hex. Refer --help option");
362 }
363
364 // writeKeyword(fruPath, recordName, keyword, val);
365
366 auto bus = sdbusplus::bus::new_default();
367 auto properties =
368 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
369 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
370 properties.append(recordName);
371 properties.append(keyword);
372 properties.append(val);
373 auto result = bus.call(properties);
374
375 if (result.is_method_error())
376 {
377 throw runtime_error("Get api failed");
378 }
379 return 0;
380}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530381
382void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
383{
384 for (const auto& itemFRUS : jsObject["frus"].items())
385 {
386 for (const auto& itemEEPROM : itemFRUS.value().items())
387 {
388 string fru = itemEEPROM.value().at("inventoryPath");
389
390 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
391 fruCachePath += INVENTORY_PATH;
392 fruCachePath += fru;
393
394 try
395 {
396 for (const auto& it : fs::directory_iterator(fruCachePath))
397 {
398 if (fs::is_regular_file(it.status()))
399 {
400 fs::remove(it);
401 }
402 }
403 }
404 catch (const fs::filesystem_error& e)
405 {
406 }
407 }
408 }
409
410 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
411 system(udevRemove.c_str());
412
413 string invManagerRestart =
414 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
415 system(invManagerRestart.c_str());
416
417 string sysVpdStop = "systemctl stop system-vpd.service";
418 system(sysVpdStop.c_str());
419
420 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
421 system(udevAdd.c_str());
422}