blob: c9b0bb72b6f2f265b2ddb368c01d3c648866f597 [file] [log] [blame]
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +05301#include "vpd_tool_impl.hpp"
2
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +05303#include "vpd_exceptions.hpp"
4
PriyangaRamasamycdf943c2020-03-18 02:25:30 +05305#include <cstdlib>
6#include <filesystem>
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +05307#include <iostream>
8#include <sdbusplus/bus.hpp>
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +05309#include <variant>
10#include <vector>
11
12using namespace std;
13using sdbusplus::exception::SdBusError;
14using namespace openpower::vpd;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053015using namespace inventory;
16using namespace openpower::vpd::manager::editor;
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053017namespace fs = std::filesystem;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053018using json = nlohmann::json;
19using namespace openpower::vpd::exceptions;
20
21Binary VpdTool::toBinary(const std::string& value)
22{
23 Binary val{};
24 if (value.find("0x") == string::npos)
25 {
26 val.assign(value.begin(), value.end());
27 }
28 else if (value.find("0x") != string::npos)
29 {
30 stringstream ss;
31 ss.str(value.substr(2));
32 string byteStr{};
33
34 while (!ss.eof())
35 {
36 ss >> setw(2) >> byteStr;
37 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
38
39 val.push_back(byte);
40 }
41 }
42
43 else
44 {
45 throw runtime_error("The value to be updated should be either in ascii "
46 "or in hex. Refer --help option");
47 }
48 return val;
49}
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053050
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -060051void VpdTool::printReturnCode(int returnCode)
52{
53 if (returnCode)
54 {
55 cout << "\n Command failed with the return code " << returnCode
56 << ". Continuing the execution. " << endl;
57 }
58}
59
PriyangaRamasamy887a42a2020-09-03 00:33:57 +053060string VpdTool::getPrintableValue(const vector<unsigned char>& vec)
61{
62 string str{};
63 bool printableChar = true;
64 for (auto i : vec)
65 {
66 if (!isprint(i))
67 {
68 printableChar = false;
69 break;
70 }
71 }
72
73 if (!printableChar)
74 {
75 stringstream ss;
76 string hexRep = "0x";
77 ss << hexRep;
78 str = ss.str();
79
80 // convert Decimal to Hex
81 for (auto& v : vec)
82 {
83 ss << setfill('0') << setw(2) << hex << (int)v;
84 str = ss.str();
85 }
86 }
87 else
88 {
89 str = string(vec.begin(), vec.end());
90 }
91 return str;
92}
93
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053094void VpdTool::eraseInventoryPath(string& fru)
95{
96 // Power supply frupath comes with INVENTORY_PATH appended in prefix.
97 // Stripping it off inorder to avoid INVENTORY_PATH duplication
98 // during getVINIProperties() execution.
99 fru.erase(0, sizeof(INVENTORY_PATH) - 1);
100}
101
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530102void VpdTool::debugger(json output)
103{
104 cout << output.dump(4) << '\n';
105}
106
107auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
108 const string& kw)
109{
110 auto bus = sdbusplus::bus::new_default();
111 auto properties =
112 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
113 "org.freedesktop.DBus.Properties", "Get");
114 properties.append(interface);
115 properties.append(kw);
116 auto result = bus.call(properties);
117
118 if (result.is_method_error())
119 {
120 throw runtime_error("Get api failed");
121 }
122 return result;
123}
124
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500125json VpdTool::getVINIProperties(string invPath)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530126{
127 variant<Binary> response;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530128 json kwVal = json::object({});
129
130 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
131 string interface = "com.ibm.ipzvpd.VINI";
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530132 string objectName = {};
133
134 if (invPath.find(INVENTORY_PATH) != string::npos)
135 {
136 objectName = invPath;
137 eraseInventoryPath(invPath);
138 }
139 else
140 {
141 objectName = INVENTORY_PATH + invPath;
142 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530143 for (string kw : keyword)
144 {
145 try
146 {
147 makeDBusCall(objectName, interface, kw).read(response);
148
149 if (auto vec = get_if<Binary>(&response))
150 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530151 string printableVal = getPrintableValue(*vec);
152 kwVal.emplace(kw, printableVal);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530153 }
154 }
155 catch (const SdBusError& e)
156 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500157 if (string(e.name()) ==
158 string("org.freedesktop.DBus.Error.UnknownObject"))
159 {
160 kwVal.emplace(invPath, json::object({}));
161 objFound = false;
162 break;
163 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530164 }
165 }
166
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500167 return kwVal;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530168}
169
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500170void VpdTool::getExtraInterfaceProperties(const string& invPath,
171 const string& extraInterface,
172 const json& prop, json& output)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530173{
174 variant<string> response;
175
176 string objectName = INVENTORY_PATH + invPath;
177
178 for (const auto& itProp : prop.items())
179 {
180 string kw = itProp.key();
181 try
182 {
183 makeDBusCall(objectName, extraInterface, kw).read(response);
184
185 if (auto str = get_if<string>(&response))
186 {
187 output.emplace(kw, *str);
188 }
189 }
190 catch (const SdBusError& e)
191 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500192 if (std::string(e.name()) ==
193 std::string("org.freedesktop.DBus.Error.UnknownObject"))
194 {
195 objFound = false;
196 break;
197 }
198 else if (std::string(e.name()) ==
199 std::string("org.freedesktop.DBus.Error.UnknownProperty"))
200 {
201 output.emplace(kw, "");
202 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530203 }
204 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530205}
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({});
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500220 json subOutput = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500221 fruType = "FRU";
222
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500223 json j;
224 objFound = true;
225 string invPath = itemEEPROM.at("inventoryPath");
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530226
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500227 j = getVINIProperties(invPath);
228
229 if (objFound)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530230 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500231 subOutput.insert(j.begin(), j.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530232 json js;
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500233 if (itemEEPROM.find("type") != itemEEPROM.end())
234 {
235 fruType = itemEEPROM.at("type");
236 }
237 js.emplace("TYPE", fruType);
238
239 if (invPath.find("powersupply") != string::npos)
240 {
241 js.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
242 }
243 else if (invPath.find("fan") != string::npos)
244 {
245 js.emplace("type", FAN_INTERFACE);
246 }
247
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530248 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
249 {
250 if (!(ex.value().is_null()))
251 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500252 getExtraInterfaceProperties(invPath, ex.key(), ex.value(), js);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530253 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500254 if ((ex.key().find("Item") != string::npos) &&
255 (ex.value().is_null()))
256 {
257 js.emplace("type", ex.key());
258 }
259 subOutput.insert(js.begin(), js.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530260 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530261 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500262 output.emplace(invPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530263 return output;
264}
265
266json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
267{
268 json output = json::object({});
269 bool validObject = false;
270
271 if (jsObject.find("frus") == jsObject.end())
272 {
273 throw runtime_error("Frus missing in Inventory json");
274 }
275 else
276 {
277 for (const auto& itemFRUS : jsObject["frus"].items())
278 {
279 for (auto itemEEPROM : itemFRUS.value())
280 {
281 try
282 {
283 if (flag == 'O')
284 {
285 if (itemEEPROM.find("inventoryPath") ==
286 itemEEPROM.end())
287 {
288 throw runtime_error("Inventory Path not found");
289 }
290
291 else if (itemEEPROM.at("inventoryPath") == fruPath)
292 {
293 validObject = true;
294 json j = interfaceDecider(itemEEPROM);
295 output.insert(j.begin(), j.end());
296 return output;
297 }
298 }
299 else
300 {
301 json j = interfaceDecider(itemEEPROM);
302 output.insert(j.begin(), j.end());
303 }
304 }
305 catch (exception& e)
306 {
307 cerr << e.what();
308 }
309 }
310 }
311 if ((flag == 'O') && (!validObject))
312 {
313 throw runtime_error(
314 "Invalid object path. Refer --dumpInventory/-i option.");
315 }
316 }
317 return output;
318}
319
320void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
321{
322 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530323 json output = json::array({});
324 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530325 debugger(output);
326}
327
328void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
329{
330 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530331 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530332 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530333 debugger(output);
334}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530335
336void VpdTool::readKeyword()
337{
338 string interface = "com.ibm.ipzvpd.";
339 variant<Binary> response;
340
341 try
342 {
343 json output = json::object({});
344 json kwVal = json::object({});
345 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
346 .read(response);
347
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530348 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530349 if (auto vec = get_if<Binary>(&response))
350 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530351 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530352 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530353 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530354
355 output.emplace(fruPath, kwVal);
356
357 debugger(output);
358 }
359 catch (json::exception& e)
360 {
361 json output = json::object({});
362 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530363 }
364}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530365
366int VpdTool::updateKeyword()
367{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530368 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530369 auto bus = sdbusplus::bus::new_default();
370 auto properties =
371 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
372 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
373 properties.append(recordName);
374 properties.append(keyword);
375 properties.append(val);
376 auto result = bus.call(properties);
377
378 if (result.is_method_error())
379 {
380 throw runtime_error("Get api failed");
381 }
382 return 0;
383}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530384
385void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
386{
387 for (const auto& itemFRUS : jsObject["frus"].items())
388 {
389 for (const auto& itemEEPROM : itemFRUS.value().items())
390 {
391 string fru = itemEEPROM.value().at("inventoryPath");
392
393 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
394 fruCachePath += INVENTORY_PATH;
395 fruCachePath += fru;
396
397 try
398 {
399 for (const auto& it : fs::directory_iterator(fruCachePath))
400 {
401 if (fs::is_regular_file(it.status()))
402 {
403 fs::remove(it);
404 }
405 }
406 }
407 catch (const fs::filesystem_error& e)
408 {
409 }
410 }
411 }
412
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600413 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530414 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600415 int returnCode = system(udevRemove.c_str());
416 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530417
418 string invManagerRestart =
419 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600420 returnCode = system(invManagerRestart.c_str());
421 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530422
423 string sysVpdStop = "systemctl stop system-vpd.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600424 returnCode = system(sysVpdStop.c_str());
425 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530426
427 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600428 returnCode = system(udevAdd.c_str());
429 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530430}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530431
432int VpdTool::updateHardware()
433{
434 int rc = 0;
435 bool updCache = true;
436 const Binary& val = static_cast<const Binary&>(toBinary(value));
437 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
438 try
439 {
440 auto json = nlohmann::json::parse(inventoryJson);
441 EditorImpl edit(fruPath, json, recordName, keyword);
442 if (!((isPathInJson(fruPath)) &&
443 (isRecKwInDbusJson(recordName, keyword))))
444 {
445 updCache = false;
446 }
447 edit.updateKeyword(val, updCache);
448 }
449 catch (json::parse_error& ex)
450 {
451 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
452 }
453 return rc;
454}