blob: 5ffb041ce868ce6fb0f038c0592f967c56e20af5 [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
PriyangaRamasamy887a42a2020-09-03 00:33:57 +053026string VpdTool::getPrintableValue(const vector<unsigned char>& vec)
27{
28 string str{};
29 bool printableChar = true;
30 for (auto i : vec)
31 {
32 if (!isprint(i))
33 {
34 printableChar = false;
35 break;
36 }
37 }
38
39 if (!printableChar)
40 {
41 stringstream ss;
42 string hexRep = "0x";
43 ss << hexRep;
44 str = ss.str();
45
46 // convert Decimal to Hex
47 for (auto& v : vec)
48 {
49 ss << setfill('0') << setw(2) << hex << (int)v;
50 str = ss.str();
51 }
52 }
53 else
54 {
55 str = string(vec.begin(), vec.end());
56 }
57 return str;
58}
59
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053060void VpdTool::eraseInventoryPath(string& fru)
61{
62 // Power supply frupath comes with INVENTORY_PATH appended in prefix.
63 // Stripping it off inorder to avoid INVENTORY_PATH duplication
64 // during getVINIProperties() execution.
65 fru.erase(0, sizeof(INVENTORY_PATH) - 1);
66}
67
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053068void VpdTool::debugger(json output)
69{
70 cout << output.dump(4) << '\n';
71}
72
73auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
74 const string& kw)
75{
76 auto bus = sdbusplus::bus::new_default();
77 auto properties =
78 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
79 "org.freedesktop.DBus.Properties", "Get");
80 properties.append(interface);
81 properties.append(kw);
82 auto result = bus.call(properties);
83
84 if (result.is_method_error())
85 {
86 throw runtime_error("Get api failed");
87 }
88 return result;
89}
90
91void VpdTool::addFruTypeAndLocation(json exIntf, const string& object,
92 json& kwVal)
93{
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053094 if (object.find("powersupply") != string::npos)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053095 {
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053096 kwVal.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
97 }
98
99 // add else if statement for fan fru
100
101 else
102 {
103 for (const auto& intf : exIntf.items())
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530104 {
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530105 if ((intf.key().find("Item") != string::npos) &&
106 (intf.value().is_null()))
107 {
108 kwVal.emplace("type", intf.key());
109 break;
110 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530111 }
112 }
113
114 // Add location code.
115 constexpr auto LOCATION_CODE_IF = "com.ibm.ipzvpd.Location";
116 constexpr auto LOCATION_CODE_PROP = "LocationCode";
117
118 try
119 {
120 variant<string> response;
121 makeDBusCall(object, LOCATION_CODE_IF, LOCATION_CODE_PROP)
122 .read(response);
123
124 if (auto prop = get_if<string>(&response))
125 {
126 kwVal.emplace(LOCATION_CODE_PROP, *prop);
127 }
128 }
129 catch (const SdBusError& e)
130 {
131 kwVal.emplace(LOCATION_CODE_PROP, "");
132 }
133}
134
135json VpdTool::getVINIProperties(string invPath, json exIntf)
136{
137 variant<Binary> response;
138 json output = json::object({});
139 json kwVal = json::object({});
140
141 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
142 string interface = "com.ibm.ipzvpd.VINI";
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530143 string objectName = {};
144
145 if (invPath.find(INVENTORY_PATH) != string::npos)
146 {
147 objectName = invPath;
148 eraseInventoryPath(invPath);
149 }
150 else
151 {
152 objectName = INVENTORY_PATH + invPath;
153 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530154
155 for (string kw : keyword)
156 {
157 try
158 {
159 makeDBusCall(objectName, interface, kw).read(response);
160
161 if (auto vec = get_if<Binary>(&response))
162 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530163 string printableVal = getPrintableValue(*vec);
164 kwVal.emplace(kw, printableVal);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530165 }
166 }
167 catch (const SdBusError& e)
168 {
169 output.emplace(invPath, json::object({}));
170 }
171 }
172
173 addFruTypeAndLocation(exIntf, objectName, kwVal);
Alpana Kumarib6965f12020-06-01 00:32:21 -0500174 kwVal.emplace("TYPE", fruType);
175
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530176 output.emplace(invPath, kwVal);
177 return output;
178}
179
180void VpdTool::getExtraInterfaceProperties(string invPath, string extraInterface,
181 json prop, json exIntf, json& output)
182{
183 variant<string> response;
184
185 string objectName = INVENTORY_PATH + invPath;
186
187 for (const auto& itProp : prop.items())
188 {
189 string kw = itProp.key();
190 try
191 {
192 makeDBusCall(objectName, extraInterface, kw).read(response);
193
194 if (auto str = get_if<string>(&response))
195 {
196 output.emplace(kw, *str);
197 }
198 }
199 catch (const SdBusError& e)
200 {
201 output.emplace(invPath, json::object({}));
202 }
203 }
204 addFruTypeAndLocation(exIntf, objectName, output);
205}
206
207json VpdTool::interfaceDecider(json& itemEEPROM)
208{
209 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
210 {
211 throw runtime_error("Inventory Path not found");
212 }
213
214 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
215 {
216 throw runtime_error("Extra Interfaces not found");
217 }
218
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530219 json output = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500220 fruType = "FRU";
221
222 // check type and add FRU Type in object
223 if (itemEEPROM.find("type") != itemEEPROM.end())
224 {
225 fruType = itemEEPROM.at("type");
226 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530227
228 if (itemEEPROM.value("inherit", true))
229 {
230 json j = getVINIProperties(itemEEPROM.at("inventoryPath"),
231 itemEEPROM["extraInterfaces"]);
232 output.insert(j.begin(), j.end());
233 }
234 else
235 {
236 json js;
237 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
238 {
239 if (!(ex.value().is_null()))
240 {
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530241 getExtraInterfaceProperties(itemEEPROM.at("inventoryPath"),
242 ex.key(), ex.value(),
243 itemEEPROM["extraInterfaces"], js);
244 }
245 }
246 output.emplace(itemEEPROM.at("inventoryPath"), js);
247 }
Alpana Kumarib6965f12020-06-01 00:32:21 -0500248
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530249 return output;
250}
251
252json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
253{
254 json output = json::object({});
255 bool validObject = false;
256
257 if (jsObject.find("frus") == jsObject.end())
258 {
259 throw runtime_error("Frus missing in Inventory json");
260 }
261 else
262 {
263 for (const auto& itemFRUS : jsObject["frus"].items())
264 {
265 for (auto itemEEPROM : itemFRUS.value())
266 {
267 try
268 {
269 if (flag == 'O')
270 {
271 if (itemEEPROM.find("inventoryPath") ==
272 itemEEPROM.end())
273 {
274 throw runtime_error("Inventory Path not found");
275 }
276
277 else if (itemEEPROM.at("inventoryPath") == fruPath)
278 {
279 validObject = true;
280 json j = interfaceDecider(itemEEPROM);
281 output.insert(j.begin(), j.end());
282 return output;
283 }
284 }
285 else
286 {
287 json j = interfaceDecider(itemEEPROM);
288 output.insert(j.begin(), j.end());
289 }
290 }
291 catch (exception& e)
292 {
293 cerr << e.what();
294 }
295 }
296 }
297 if ((flag == 'O') && (!validObject))
298 {
299 throw runtime_error(
300 "Invalid object path. Refer --dumpInventory/-i option.");
301 }
302 }
303 return output;
304}
305
306void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
307{
308 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530309 json output = json::array({});
310 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530311 debugger(output);
312}
313
314void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
315{
316 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530317 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530318 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530319 debugger(output);
320}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530321
322void VpdTool::readKeyword()
323{
324 string interface = "com.ibm.ipzvpd.";
325 variant<Binary> response;
326
327 try
328 {
329 json output = json::object({});
330 json kwVal = json::object({});
331 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
332 .read(response);
333
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530334 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530335 if (auto vec = get_if<Binary>(&response))
336 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530337 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530338 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530339 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530340
341 output.emplace(fruPath, kwVal);
342
343 debugger(output);
344 }
345 catch (json::exception& e)
346 {
347 json output = json::object({});
348 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530349 }
350}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530351
352int VpdTool::updateKeyword()
353{
354 Binary val;
355
356 if (value.find("0x") == string::npos)
357 {
358 val.assign(value.begin(), value.end());
359 }
360 else if (value.find("0x") != string::npos)
361 {
362 stringstream ss;
363 ss.str(value.substr(2));
364 string byteStr{};
365
366 while (!ss.eof())
367 {
368 ss >> setw(2) >> byteStr;
369 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
370
371 val.push_back(byte);
372 }
373 }
374
375 else
376 {
377 throw runtime_error("The value to be updated should be either in ascii "
378 "or in hex. Refer --help option");
379 }
380
381 // writeKeyword(fruPath, recordName, keyword, val);
382
383 auto bus = sdbusplus::bus::new_default();
384 auto properties =
385 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
386 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
387 properties.append(recordName);
388 properties.append(keyword);
389 properties.append(val);
390 auto result = bus.call(properties);
391
392 if (result.is_method_error())
393 {
394 throw runtime_error("Get api failed");
395 }
396 return 0;
397}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530398
399void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
400{
401 for (const auto& itemFRUS : jsObject["frus"].items())
402 {
403 for (const auto& itemEEPROM : itemFRUS.value().items())
404 {
405 string fru = itemEEPROM.value().at("inventoryPath");
406
407 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
408 fruCachePath += INVENTORY_PATH;
409 fruCachePath += fru;
410
411 try
412 {
413 for (const auto& it : fs::directory_iterator(fruCachePath))
414 {
415 if (fs::is_regular_file(it.status()))
416 {
417 fs::remove(it);
418 }
419 }
420 }
421 catch (const fs::filesystem_error& e)
422 {
423 }
424 }
425 }
426
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600427 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530428 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600429 int returnCode = system(udevRemove.c_str());
430 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530431
432 string invManagerRestart =
433 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600434 returnCode = system(invManagerRestart.c_str());
435 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530436
437 string sysVpdStop = "systemctl stop system-vpd.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600438 returnCode = system(sysVpdStop.c_str());
439 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530440
441 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600442 returnCode = system(udevAdd.c_str());
443 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530444}