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