blob: d01a28db3776286a0951fc660edce6c4cf795007 [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
33 while (!ss.eof())
34 {
35 ss >> setw(2) >> byteStr;
36 uint8_t byte = strtoul(byteStr.c_str(), nullptr, 16);
37
38 val.push_back(byte);
39 }
40 }
41
42 else
43 {
44 throw runtime_error("The value to be updated should be either in ascii "
45 "or in hex. Refer --help option");
46 }
47 return val;
48}
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053049
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -060050void VpdTool::printReturnCode(int returnCode)
51{
52 if (returnCode)
53 {
54 cout << "\n Command failed with the return code " << returnCode
55 << ". Continuing the execution. " << endl;
56 }
57}
58
PriyangaRamasamy887a42a2020-09-03 00:33:57 +053059string VpdTool::getPrintableValue(const vector<unsigned char>& vec)
60{
61 string str{};
62 bool printableChar = true;
63 for (auto i : vec)
64 {
65 if (!isprint(i))
66 {
67 printableChar = false;
68 break;
69 }
70 }
71
72 if (!printableChar)
73 {
74 stringstream ss;
75 string hexRep = "0x";
76 ss << hexRep;
77 str = ss.str();
78
79 // convert Decimal to Hex
80 for (auto& v : vec)
81 {
82 ss << setfill('0') << setw(2) << hex << (int)v;
83 str = ss.str();
84 }
85 }
86 else
87 {
88 str = string(vec.begin(), vec.end());
89 }
90 return str;
91}
92
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053093void VpdTool::eraseInventoryPath(string& fru)
94{
95 // Power supply frupath comes with INVENTORY_PATH appended in prefix.
96 // Stripping it off inorder to avoid INVENTORY_PATH duplication
97 // during getVINIProperties() execution.
98 fru.erase(0, sizeof(INVENTORY_PATH) - 1);
99}
100
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530101void VpdTool::debugger(json output)
102{
103 cout << output.dump(4) << '\n';
104}
105
106auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
107 const string& kw)
108{
109 auto bus = sdbusplus::bus::new_default();
110 auto properties =
111 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
112 "org.freedesktop.DBus.Properties", "Get");
113 properties.append(interface);
114 properties.append(kw);
115 auto result = bus.call(properties);
116
117 if (result.is_method_error())
118 {
119 throw runtime_error("Get api failed");
120 }
121 return result;
122}
123
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500124json VpdTool::getVINIProperties(string invPath)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530125{
126 variant<Binary> response;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530127 json kwVal = json::object({});
128
129 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
130 string interface = "com.ibm.ipzvpd.VINI";
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530131 string objectName = {};
132
133 if (invPath.find(INVENTORY_PATH) != string::npos)
134 {
135 objectName = invPath;
136 eraseInventoryPath(invPath);
137 }
138 else
139 {
140 objectName = INVENTORY_PATH + invPath;
141 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530142 for (string kw : keyword)
143 {
144 try
145 {
146 makeDBusCall(objectName, interface, kw).read(response);
147
148 if (auto vec = get_if<Binary>(&response))
149 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530150 string printableVal = getPrintableValue(*vec);
151 kwVal.emplace(kw, printableVal);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530152 }
153 }
Patrick Williams8be43342021-09-02 09:33:36 -0500154 catch (const sdbusplus::exception::exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530155 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500156 if (string(e.name()) ==
157 string("org.freedesktop.DBus.Error.UnknownObject"))
158 {
159 kwVal.emplace(invPath, json::object({}));
160 objFound = false;
161 break;
162 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530163 }
164 }
165
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500166 return kwVal;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530167}
168
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500169void VpdTool::getExtraInterfaceProperties(const string& invPath,
170 const string& extraInterface,
171 const json& prop, json& output)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530172{
173 variant<string> response;
174
175 string objectName = INVENTORY_PATH + invPath;
176
177 for (const auto& itProp : prop.items())
178 {
179 string kw = itProp.key();
180 try
181 {
182 makeDBusCall(objectName, extraInterface, kw).read(response);
183
184 if (auto str = get_if<string>(&response))
185 {
186 output.emplace(kw, *str);
187 }
188 }
Patrick Williams8be43342021-09-02 09:33:36 -0500189 catch (const sdbusplus::exception::exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530190 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500191 if (std::string(e.name()) ==
192 std::string("org.freedesktop.DBus.Error.UnknownObject"))
193 {
194 objFound = false;
195 break;
196 }
197 else if (std::string(e.name()) ==
198 std::string("org.freedesktop.DBus.Error.UnknownProperty"))
199 {
200 output.emplace(kw, "");
201 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530202 }
203 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530204}
205
206json VpdTool::interfaceDecider(json& itemEEPROM)
207{
208 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
209 {
210 throw runtime_error("Inventory Path not found");
211 }
212
213 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
214 {
215 throw runtime_error("Extra Interfaces not found");
216 }
217
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530218 json output = json::object({});
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500219 json subOutput = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500220 fruType = "FRU";
221
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500222 json j;
223 objFound = true;
224 string invPath = itemEEPROM.at("inventoryPath");
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530225
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500226 j = getVINIProperties(invPath);
227
228 if (objFound)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530229 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500230 subOutput.insert(j.begin(), j.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530231 json js;
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500232 if (itemEEPROM.find("type") != itemEEPROM.end())
233 {
234 fruType = itemEEPROM.at("type");
235 }
236 js.emplace("TYPE", fruType);
237
238 if (invPath.find("powersupply") != string::npos)
239 {
240 js.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
241 }
242 else if (invPath.find("fan") != string::npos)
243 {
244 js.emplace("type", FAN_INTERFACE);
245 }
246
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530247 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
248 {
249 if (!(ex.value().is_null()))
250 {
Priyanga Ramasamydacaa472021-10-07 12:22:41 -0500251 // TODO: Remove this if condition check once inventory json is
252 // updated with xyz location code interface.
253 if (ex.key() == "com.ibm.ipzvpd.Location")
254 {
255 getExtraInterfaceProperties(
256 invPath,
257 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
258 ex.value(), js);
259 }
260 else
261 {
262 getExtraInterfaceProperties(invPath, ex.key(), ex.value(),
263 js);
264 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530265 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500266 if ((ex.key().find("Item") != string::npos) &&
267 (ex.value().is_null()))
268 {
269 js.emplace("type", ex.key());
270 }
271 subOutput.insert(js.begin(), js.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530272 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530273 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500274 output.emplace(invPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530275 return output;
276}
277
278json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
279{
280 json output = json::object({});
281 bool validObject = false;
282
283 if (jsObject.find("frus") == jsObject.end())
284 {
285 throw runtime_error("Frus missing in Inventory json");
286 }
287 else
288 {
289 for (const auto& itemFRUS : jsObject["frus"].items())
290 {
291 for (auto itemEEPROM : itemFRUS.value())
292 {
293 try
294 {
295 if (flag == 'O')
296 {
297 if (itemEEPROM.find("inventoryPath") ==
298 itemEEPROM.end())
299 {
300 throw runtime_error("Inventory Path not found");
301 }
302
303 else if (itemEEPROM.at("inventoryPath") == fruPath)
304 {
305 validObject = true;
306 json j = interfaceDecider(itemEEPROM);
307 output.insert(j.begin(), j.end());
308 return output;
309 }
310 }
311 else
312 {
313 json j = interfaceDecider(itemEEPROM);
314 output.insert(j.begin(), j.end());
315 }
316 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500317 catch (const exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530318 {
319 cerr << e.what();
320 }
321 }
322 }
323 if ((flag == 'O') && (!validObject))
324 {
325 throw runtime_error(
326 "Invalid object path. Refer --dumpInventory/-i option.");
327 }
328 }
329 return output;
330}
331
332void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
333{
334 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530335 json output = json::array({});
336 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530337 debugger(output);
338}
339
340void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
341{
342 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530343 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530344 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530345 debugger(output);
346}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530347
348void VpdTool::readKeyword()
349{
350 string interface = "com.ibm.ipzvpd.";
351 variant<Binary> response;
352
353 try
354 {
355 json output = json::object({});
356 json kwVal = json::object({});
357 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
358 .read(response);
359
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530360 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530361 if (auto vec = get_if<Binary>(&response))
362 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530363 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530364 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530365 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530366
367 output.emplace(fruPath, kwVal);
368
369 debugger(output);
370 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500371 catch (const json::exception& e)
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530372 {
373 json output = json::object({});
374 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530375 }
376}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530377
378int VpdTool::updateKeyword()
379{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530380 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530381 auto bus = sdbusplus::bus::new_default();
382 auto properties =
383 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
384 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
385 properties.append(recordName);
386 properties.append(keyword);
387 properties.append(val);
388 auto result = bus.call(properties);
389
390 if (result.is_method_error())
391 {
392 throw runtime_error("Get api failed");
393 }
394 return 0;
395}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530396
397void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
398{
399 for (const auto& itemFRUS : jsObject["frus"].items())
400 {
401 for (const auto& itemEEPROM : itemFRUS.value().items())
402 {
403 string fru = itemEEPROM.value().at("inventoryPath");
404
405 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
406 fruCachePath += INVENTORY_PATH;
407 fruCachePath += fru;
408
409 try
410 {
411 for (const auto& it : fs::directory_iterator(fruCachePath))
412 {
413 if (fs::is_regular_file(it.status()))
414 {
415 fs::remove(it);
416 }
417 }
418 }
419 catch (const fs::filesystem_error& e)
420 {
421 }
422 }
423 }
424
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600425 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530426 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600427 int returnCode = system(udevRemove.c_str());
428 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530429
430 string invManagerRestart =
431 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600432 returnCode = system(invManagerRestart.c_str());
433 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530434
435 string sysVpdStop = "systemctl stop system-vpd.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600436 returnCode = system(sysVpdStop.c_str());
437 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530438
439 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600440 returnCode = system(udevAdd.c_str());
441 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530442}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530443
444int VpdTool::updateHardware()
445{
446 int rc = 0;
447 bool updCache = true;
448 const Binary& val = static_cast<const Binary&>(toBinary(value));
449 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
450 try
451 {
452 auto json = nlohmann::json::parse(inventoryJson);
453 EditorImpl edit(fruPath, json, recordName, keyword);
454 if (!((isPathInJson(fruPath)) &&
455 (isRecKwInDbusJson(recordName, keyword))))
456 {
457 updCache = false;
458 }
459 edit.updateKeyword(val, updCache);
460 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500461 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530462 {
463 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
464 }
465 return rc;
466}