blob: 4d9f1a31fff92f1bed7c24846ac78b7512706213 [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;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053013using namespace openpower::vpd;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053014using namespace inventory;
15using namespace openpower::vpd::manager::editor;
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053016namespace fs = std::filesystem;
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053017using json = nlohmann::json;
18using namespace openpower::vpd::exceptions;
19
20Binary VpdTool::toBinary(const std::string& value)
21{
22 Binary val{};
23 if (value.find("0x") == string::npos)
24 {
25 val.assign(value.begin(), value.end());
26 }
27 else if (value.find("0x") != string::npos)
28 {
29 stringstream ss;
30 ss.str(value.substr(2));
31 string byteStr{};
32
Priyanga Ramasamyec912e62021-12-15 22:47:51 -060033 if (value.length() % 2 != 0)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053034 {
Priyanga Ramasamyec912e62021-12-15 22:47:51 -060035 throw runtime_error(
36 "VPD-TOOL write option accepts 2 digit hex numbers. (Eg. 0x1 "
37 "should be given as 0x01). Aborting the write operation.");
38 }
39
40 if (value.find_first_not_of("0123456789abcdefABCDEF", 2) !=
41 std::string::npos)
42 {
43 throw runtime_error("Provide a valid hexadecimal input.");
44 }
45
46 while (ss >> setw(2) >> byteStr)
47 {
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +053048 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
49
50 val.push_back(byte);
51 }
52 }
53
54 else
55 {
56 throw runtime_error("The value to be updated should be either in ascii "
57 "or in hex. Refer --help option");
58 }
59 return val;
60}
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053061
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -060062void VpdTool::printReturnCode(int returnCode)
63{
64 if (returnCode)
65 {
66 cout << "\n Command failed with the return code " << returnCode
67 << ". Continuing the execution. " << endl;
68 }
69}
70
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053071void VpdTool::eraseInventoryPath(string& fru)
72{
73 // Power supply frupath comes with INVENTORY_PATH appended in prefix.
74 // Stripping it off inorder to avoid INVENTORY_PATH duplication
75 // during getVINIProperties() execution.
76 fru.erase(0, sizeof(INVENTORY_PATH) - 1);
77}
78
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053079void VpdTool::debugger(json output)
80{
81 cout << output.dump(4) << '\n';
82}
83
84auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
85 const string& kw)
86{
87 auto bus = sdbusplus::bus::new_default();
88 auto properties =
89 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
90 "org.freedesktop.DBus.Properties", "Get");
91 properties.append(interface);
92 properties.append(kw);
93 auto result = bus.call(properties);
94
95 if (result.is_method_error())
96 {
97 throw runtime_error("Get api failed");
98 }
99 return result;
100}
101
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500102json VpdTool::getVINIProperties(string invPath)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530103{
104 variant<Binary> response;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530105 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 for (string kw : keyword)
121 {
122 try
123 {
124 makeDBusCall(objectName, interface, kw).read(response);
125
126 if (auto vec = get_if<Binary>(&response))
127 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530128 string printableVal = getPrintableValue(*vec);
129 kwVal.emplace(kw, printableVal);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530130 }
131 }
Patrick Williams8be43342021-09-02 09:33:36 -0500132 catch (const sdbusplus::exception::exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530133 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500134 if (string(e.name()) ==
135 string("org.freedesktop.DBus.Error.UnknownObject"))
136 {
137 kwVal.emplace(invPath, json::object({}));
138 objFound = false;
139 break;
140 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530141 }
142 }
143
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500144 return kwVal;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530145}
146
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500147void VpdTool::getExtraInterfaceProperties(const string& invPath,
148 const string& extraInterface,
149 const json& prop, json& output)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530150{
151 variant<string> response;
152
153 string objectName = INVENTORY_PATH + invPath;
154
155 for (const auto& itProp : prop.items())
156 {
157 string kw = itProp.key();
158 try
159 {
160 makeDBusCall(objectName, extraInterface, kw).read(response);
161
162 if (auto str = get_if<string>(&response))
163 {
164 output.emplace(kw, *str);
165 }
166 }
Patrick Williams8be43342021-09-02 09:33:36 -0500167 catch (const sdbusplus::exception::exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530168 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500169 if (std::string(e.name()) ==
170 std::string("org.freedesktop.DBus.Error.UnknownObject"))
171 {
172 objFound = false;
173 break;
174 }
175 else if (std::string(e.name()) ==
176 std::string("org.freedesktop.DBus.Error.UnknownProperty"))
177 {
178 output.emplace(kw, "");
179 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530180 }
181 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530182}
183
184json VpdTool::interfaceDecider(json& itemEEPROM)
185{
186 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
187 {
188 throw runtime_error("Inventory Path not found");
189 }
190
191 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
192 {
193 throw runtime_error("Extra Interfaces not found");
194 }
195
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500196 json subOutput = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500197 fruType = "FRU";
198
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500199 json j;
200 objFound = true;
201 string invPath = itemEEPROM.at("inventoryPath");
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530202
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500203 j = getVINIProperties(invPath);
204
205 if (objFound)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530206 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500207 subOutput.insert(j.begin(), j.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530208 json js;
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500209 if (itemEEPROM.find("type") != itemEEPROM.end())
210 {
211 fruType = itemEEPROM.at("type");
212 }
213 js.emplace("TYPE", fruType);
214
215 if (invPath.find("powersupply") != string::npos)
216 {
217 js.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
218 }
219 else if (invPath.find("fan") != string::npos)
220 {
221 js.emplace("type", FAN_INTERFACE);
222 }
223
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530224 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
225 {
226 if (!(ex.value().is_null()))
227 {
Priyanga Ramasamydacaa472021-10-07 12:22:41 -0500228 // TODO: Remove this if condition check once inventory json is
229 // updated with xyz location code interface.
230 if (ex.key() == "com.ibm.ipzvpd.Location")
231 {
232 getExtraInterfaceProperties(
233 invPath,
234 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
235 ex.value(), js);
236 }
237 else
238 {
239 getExtraInterfaceProperties(invPath, ex.key(), ex.value(),
240 js);
241 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530242 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500243 if ((ex.key().find("Item") != string::npos) &&
244 (ex.value().is_null()))
245 {
246 js.emplace("type", ex.key());
247 }
248 subOutput.insert(js.begin(), js.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530249 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530250 }
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500251 return subOutput;
252}
253
254json VpdTool::getPresentPropJson(const std::string& invPath,
255 std::string& parentPresence)
256{
257 std::variant<bool> response;
258 makeDBusCall(invPath, "xyz.openbmc_project.Inventory.Item", "Present")
259 .read(response);
260
261 std::string presence{};
262
263 if (auto pVal = get_if<bool>(&response))
264 {
265 presence = *pVal ? "true" : "false";
266 if (parentPresence.empty())
267 {
268 parentPresence = presence;
269 }
270 }
271 else
272 {
273 presence = parentPresence;
274 }
275
276 json js;
277 js.emplace("Present", presence);
278 return js;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530279}
280
281json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
282{
283 json output = json::object({});
284 bool validObject = false;
285
286 if (jsObject.find("frus") == jsObject.end())
287 {
288 throw runtime_error("Frus missing in Inventory json");
289 }
290 else
291 {
292 for (const auto& itemFRUS : jsObject["frus"].items())
293 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500294 string parentPresence{};
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530295 for (auto itemEEPROM : itemFRUS.value())
296 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500297 json subOutput = json::object({});
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530298 try
299 {
300 if (flag == 'O')
301 {
302 if (itemEEPROM.find("inventoryPath") ==
303 itemEEPROM.end())
304 {
305 throw runtime_error("Inventory Path not found");
306 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530307 else if (itemEEPROM.at("inventoryPath") == fruPath)
308 {
309 validObject = true;
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500310 subOutput = interfaceDecider(itemEEPROM);
311 json presentJs = getPresentPropJson(
312 "/xyz/openbmc_project/inventory" + fruPath,
313 parentPresence);
314 subOutput.insert(presentJs.begin(),
315 presentJs.end());
316 output.emplace(fruPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530317 return output;
318 }
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500319 else // this else is to keep track of parent present
320 // property.
321 {
322 json presentJs = getPresentPropJson(
323 "/xyz/openbmc_project/inventory" +
324 string(itemEEPROM.at("inventoryPath")),
325 parentPresence);
326 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530327 }
328 else
329 {
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500330 subOutput = interfaceDecider(itemEEPROM);
331 json presentJs = getPresentPropJson(
332 "/xyz/openbmc_project/inventory" +
333 string(itemEEPROM.at("inventoryPath")),
334 parentPresence);
335 subOutput.insert(presentJs.begin(), presentJs.end());
336 output.emplace(string(itemEEPROM.at("inventoryPath")),
337 subOutput);
338 }
339 }
340 catch (const sdbusplus::exception::SdBusError& e)
341 {
342 // if any of frupath doesn't have Present property of its
343 // own, emplace its parent's present property value.
344 if (e.name() == std::string("org.freedesktop.DBus.Error."
345 "UnknownProperty") &&
346 (((flag == 'O') && validObject) || flag == 'I'))
347 {
348 json presentJs;
349 presentJs.emplace("Present", parentPresence);
350 subOutput.insert(presentJs.begin(), presentJs.end());
351 output.emplace(string(itemEEPROM.at("inventoryPath")),
352 subOutput);
353 }
354
355 // for the user given child frupath which doesn't have
356 // Present prop (vpd-tool -o).
357 if ((flag == 'O') && validObject)
358 {
359 return output;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530360 }
361 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500362 catch (const exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530363 {
364 cerr << e.what();
365 }
366 }
367 }
368 if ((flag == 'O') && (!validObject))
369 {
370 throw runtime_error(
371 "Invalid object path. Refer --dumpInventory/-i option.");
372 }
373 }
374 return output;
375}
376
377void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
378{
379 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530380 json output = json::array({});
381 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530382 debugger(output);
383}
384
385void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
386{
387 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530388 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530389 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530390 debugger(output);
391}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530392
393void VpdTool::readKeyword()
394{
395 string interface = "com.ibm.ipzvpd.";
396 variant<Binary> response;
397
398 try
399 {
400 json output = json::object({});
401 json kwVal = json::object({});
402 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
403 .read(response);
404
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530405 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530406 if (auto vec = get_if<Binary>(&response))
407 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530408 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530409 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530410 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530411
412 output.emplace(fruPath, kwVal);
413
414 debugger(output);
415 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500416 catch (const json::exception& e)
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530417 {
418 json output = json::object({});
419 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530420 }
421}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530422
423int VpdTool::updateKeyword()
424{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530425 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530426 auto bus = sdbusplus::bus::new_default();
427 auto properties =
428 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
429 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
430 properties.append(recordName);
431 properties.append(keyword);
432 properties.append(val);
433 auto result = bus.call(properties);
434
435 if (result.is_method_error())
436 {
437 throw runtime_error("Get api failed");
438 }
439 return 0;
440}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530441
442void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
443{
444 for (const auto& itemFRUS : jsObject["frus"].items())
445 {
446 for (const auto& itemEEPROM : itemFRUS.value().items())
447 {
448 string fru = itemEEPROM.value().at("inventoryPath");
449
450 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
451 fruCachePath += INVENTORY_PATH;
452 fruCachePath += fru;
453
454 try
455 {
456 for (const auto& it : fs::directory_iterator(fruCachePath))
457 {
458 if (fs::is_regular_file(it.status()))
459 {
460 fs::remove(it);
461 }
462 }
463 }
464 catch (const fs::filesystem_error& e)
465 {
466 }
467 }
468 }
469
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600470 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530471 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600472 int returnCode = system(udevRemove.c_str());
473 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530474
475 string invManagerRestart =
476 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600477 returnCode = system(invManagerRestart.c_str());
478 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530479
480 string sysVpdStop = "systemctl stop system-vpd.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600481 returnCode = system(sysVpdStop.c_str());
482 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530483
484 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600485 returnCode = system(udevAdd.c_str());
486 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530487}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530488
489int VpdTool::updateHardware()
490{
491 int rc = 0;
492 bool updCache = true;
493 const Binary& val = static_cast<const Binary&>(toBinary(value));
494 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
495 try
496 {
497 auto json = nlohmann::json::parse(inventoryJson);
498 EditorImpl edit(fruPath, json, recordName, keyword);
499 if (!((isPathInJson(fruPath)) &&
500 (isRecKwInDbusJson(recordName, keyword))))
501 {
502 updCache = false;
503 }
504 edit.updateKeyword(val, updCache);
505 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500506 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530507 {
508 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
509 }
510 return rc;
Priyanga Ramasamy0086dd12021-09-28 10:31:50 -0500511}