blob: 5d35f030c1821a6fd6b00059f8479d63396869c9 [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 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500251 getExtraInterfaceProperties(invPath, ex.key(), ex.value(), js);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530252 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500253 if ((ex.key().find("Item") != string::npos) &&
254 (ex.value().is_null()))
255 {
256 js.emplace("type", ex.key());
257 }
258 subOutput.insert(js.begin(), js.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530259 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530260 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500261 output.emplace(invPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530262 return output;
263}
264
265json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
266{
267 json output = json::object({});
268 bool validObject = false;
269
270 if (jsObject.find("frus") == jsObject.end())
271 {
272 throw runtime_error("Frus missing in Inventory json");
273 }
274 else
275 {
276 for (const auto& itemFRUS : jsObject["frus"].items())
277 {
278 for (auto itemEEPROM : itemFRUS.value())
279 {
280 try
281 {
282 if (flag == 'O')
283 {
284 if (itemEEPROM.find("inventoryPath") ==
285 itemEEPROM.end())
286 {
287 throw runtime_error("Inventory Path not found");
288 }
289
290 else if (itemEEPROM.at("inventoryPath") == fruPath)
291 {
292 validObject = true;
293 json j = interfaceDecider(itemEEPROM);
294 output.insert(j.begin(), j.end());
295 return output;
296 }
297 }
298 else
299 {
300 json j = interfaceDecider(itemEEPROM);
301 output.insert(j.begin(), j.end());
302 }
303 }
304 catch (exception& e)
305 {
306 cerr << e.what();
307 }
308 }
309 }
310 if ((flag == 'O') && (!validObject))
311 {
312 throw runtime_error(
313 "Invalid object path. Refer --dumpInventory/-i option.");
314 }
315 }
316 return output;
317}
318
319void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
320{
321 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530322 json output = json::array({});
323 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530324 debugger(output);
325}
326
327void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
328{
329 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530330 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530331 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530332 debugger(output);
333}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530334
335void VpdTool::readKeyword()
336{
337 string interface = "com.ibm.ipzvpd.";
338 variant<Binary> response;
339
340 try
341 {
342 json output = json::object({});
343 json kwVal = json::object({});
344 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
345 .read(response);
346
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530347 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530348 if (auto vec = get_if<Binary>(&response))
349 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530350 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530351 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530352 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530353
354 output.emplace(fruPath, kwVal);
355
356 debugger(output);
357 }
358 catch (json::exception& e)
359 {
360 json output = json::object({});
361 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530362 }
363}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530364
365int VpdTool::updateKeyword()
366{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530367 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530368 auto bus = sdbusplus::bus::new_default();
369 auto properties =
370 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
371 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
372 properties.append(recordName);
373 properties.append(keyword);
374 properties.append(val);
375 auto result = bus.call(properties);
376
377 if (result.is_method_error())
378 {
379 throw runtime_error("Get api failed");
380 }
381 return 0;
382}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530383
384void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
385{
386 for (const auto& itemFRUS : jsObject["frus"].items())
387 {
388 for (const auto& itemEEPROM : itemFRUS.value().items())
389 {
390 string fru = itemEEPROM.value().at("inventoryPath");
391
392 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
393 fruCachePath += INVENTORY_PATH;
394 fruCachePath += fru;
395
396 try
397 {
398 for (const auto& it : fs::directory_iterator(fruCachePath))
399 {
400 if (fs::is_regular_file(it.status()))
401 {
402 fs::remove(it);
403 }
404 }
405 }
406 catch (const fs::filesystem_error& e)
407 {
408 }
409 }
410 }
411
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600412 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530413 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600414 int returnCode = system(udevRemove.c_str());
415 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530416
417 string invManagerRestart =
418 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600419 returnCode = system(invManagerRestart.c_str());
420 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530421
422 string sysVpdStop = "systemctl stop system-vpd.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600423 returnCode = system(sysVpdStop.c_str());
424 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530425
426 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600427 returnCode = system(udevAdd.c_str());
428 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530429}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530430
431int VpdTool::updateHardware()
432{
433 int rc = 0;
434 bool updCache = true;
435 const Binary& val = static_cast<const Binary&>(toBinary(value));
436 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
437 try
438 {
439 auto json = nlohmann::json::parse(inventoryJson);
440 EditorImpl edit(fruPath, json, recordName, keyword);
441 if (!((isPathInJson(fruPath)) &&
442 (isRecKwInDbusJson(recordName, keyword))))
443 {
444 updCache = false;
445 }
446 edit.updateKeyword(val, updCache);
447 }
448 catch (json::parse_error& ex)
449 {
450 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
451 }
452 return rc;
453}