blob: 647bf503456584c2cb3130f127708e5e2dc882a3 [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
125void VpdTool::addFruTypeAndLocation(json exIntf, const string& object,
126 json& kwVal)
127{
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530128 if (object.find("powersupply") != string::npos)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530129 {
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530130 kwVal.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
131 }
132
133 // add else if statement for fan fru
134
135 else
136 {
137 for (const auto& intf : exIntf.items())
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530138 {
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530139 if ((intf.key().find("Item") != string::npos) &&
140 (intf.value().is_null()))
141 {
142 kwVal.emplace("type", intf.key());
143 break;
144 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530145 }
146 }
147
148 // Add location code.
149 constexpr auto LOCATION_CODE_IF = "com.ibm.ipzvpd.Location";
150 constexpr auto LOCATION_CODE_PROP = "LocationCode";
151
152 try
153 {
154 variant<string> response;
155 makeDBusCall(object, LOCATION_CODE_IF, LOCATION_CODE_PROP)
156 .read(response);
157
158 if (auto prop = get_if<string>(&response))
159 {
160 kwVal.emplace(LOCATION_CODE_PROP, *prop);
161 }
162 }
163 catch (const SdBusError& e)
164 {
165 kwVal.emplace(LOCATION_CODE_PROP, "");
166 }
167}
168
169json VpdTool::getVINIProperties(string invPath, json exIntf)
170{
171 variant<Binary> response;
172 json output = json::object({});
173 json kwVal = json::object({});
174
175 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
176 string interface = "com.ibm.ipzvpd.VINI";
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530177 string objectName = {};
178
179 if (invPath.find(INVENTORY_PATH) != string::npos)
180 {
181 objectName = invPath;
182 eraseInventoryPath(invPath);
183 }
184 else
185 {
186 objectName = INVENTORY_PATH + invPath;
187 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530188
189 for (string kw : keyword)
190 {
191 try
192 {
193 makeDBusCall(objectName, interface, kw).read(response);
194
195 if (auto vec = get_if<Binary>(&response))
196 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530197 string printableVal = getPrintableValue(*vec);
198 kwVal.emplace(kw, printableVal);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530199 }
200 }
201 catch (const SdBusError& e)
202 {
203 output.emplace(invPath, json::object({}));
204 }
205 }
206
207 addFruTypeAndLocation(exIntf, objectName, kwVal);
Alpana Kumarib6965f12020-06-01 00:32:21 -0500208 kwVal.emplace("TYPE", fruType);
209
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530210 output.emplace(invPath, kwVal);
211 return output;
212}
213
214void VpdTool::getExtraInterfaceProperties(string invPath, string extraInterface,
215 json prop, json exIntf, json& output)
216{
217 variant<string> response;
218
219 string objectName = INVENTORY_PATH + invPath;
220
221 for (const auto& itProp : prop.items())
222 {
223 string kw = itProp.key();
224 try
225 {
226 makeDBusCall(objectName, extraInterface, kw).read(response);
227
228 if (auto str = get_if<string>(&response))
229 {
230 output.emplace(kw, *str);
231 }
232 }
233 catch (const SdBusError& e)
234 {
235 output.emplace(invPath, json::object({}));
236 }
237 }
238 addFruTypeAndLocation(exIntf, objectName, output);
239}
240
241json VpdTool::interfaceDecider(json& itemEEPROM)
242{
243 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
244 {
245 throw runtime_error("Inventory Path not found");
246 }
247
248 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
249 {
250 throw runtime_error("Extra Interfaces not found");
251 }
252
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530253 json output = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500254 fruType = "FRU";
255
256 // check type and add FRU Type in object
257 if (itemEEPROM.find("type") != itemEEPROM.end())
258 {
259 fruType = itemEEPROM.at("type");
260 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530261
262 if (itemEEPROM.value("inherit", true))
263 {
264 json j = getVINIProperties(itemEEPROM.at("inventoryPath"),
265 itemEEPROM["extraInterfaces"]);
266 output.insert(j.begin(), j.end());
267 }
268 else
269 {
270 json js;
271 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
272 {
273 if (!(ex.value().is_null()))
274 {
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530275 getExtraInterfaceProperties(itemEEPROM.at("inventoryPath"),
276 ex.key(), ex.value(),
277 itemEEPROM["extraInterfaces"], js);
278 }
279 }
280 output.emplace(itemEEPROM.at("inventoryPath"), js);
281 }
Alpana Kumarib6965f12020-06-01 00:32:21 -0500282
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530283 return output;
284}
285
286json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
287{
288 json output = json::object({});
289 bool validObject = false;
290
291 if (jsObject.find("frus") == jsObject.end())
292 {
293 throw runtime_error("Frus missing in Inventory json");
294 }
295 else
296 {
297 for (const auto& itemFRUS : jsObject["frus"].items())
298 {
299 for (auto itemEEPROM : itemFRUS.value())
300 {
301 try
302 {
303 if (flag == 'O')
304 {
305 if (itemEEPROM.find("inventoryPath") ==
306 itemEEPROM.end())
307 {
308 throw runtime_error("Inventory Path not found");
309 }
310
311 else if (itemEEPROM.at("inventoryPath") == fruPath)
312 {
313 validObject = true;
314 json j = interfaceDecider(itemEEPROM);
315 output.insert(j.begin(), j.end());
316 return output;
317 }
318 }
319 else
320 {
321 json j = interfaceDecider(itemEEPROM);
322 output.insert(j.begin(), j.end());
323 }
324 }
325 catch (exception& e)
326 {
327 cerr << e.what();
328 }
329 }
330 }
331 if ((flag == 'O') && (!validObject))
332 {
333 throw runtime_error(
334 "Invalid object path. Refer --dumpInventory/-i option.");
335 }
336 }
337 return output;
338}
339
340void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
341{
342 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530343 json output = json::array({});
344 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530345 debugger(output);
346}
347
348void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
349{
350 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530351 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530352 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530353 debugger(output);
354}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530355
356void VpdTool::readKeyword()
357{
358 string interface = "com.ibm.ipzvpd.";
359 variant<Binary> response;
360
361 try
362 {
363 json output = json::object({});
364 json kwVal = json::object({});
365 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
366 .read(response);
367
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530368 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530369 if (auto vec = get_if<Binary>(&response))
370 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530371 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530372 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530373 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530374
375 output.emplace(fruPath, kwVal);
376
377 debugger(output);
378 }
379 catch (json::exception& e)
380 {
381 json output = json::object({});
382 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530383 }
384}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530385
386int VpdTool::updateKeyword()
387{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530388 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530389 auto bus = sdbusplus::bus::new_default();
390 auto properties =
391 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
392 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
393 properties.append(recordName);
394 properties.append(keyword);
395 properties.append(val);
396 auto result = bus.call(properties);
397
398 if (result.is_method_error())
399 {
400 throw runtime_error("Get api failed");
401 }
402 return 0;
403}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530404
405void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
406{
407 for (const auto& itemFRUS : jsObject["frus"].items())
408 {
409 for (const auto& itemEEPROM : itemFRUS.value().items())
410 {
411 string fru = itemEEPROM.value().at("inventoryPath");
412
413 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
414 fruCachePath += INVENTORY_PATH;
415 fruCachePath += fru;
416
417 try
418 {
419 for (const auto& it : fs::directory_iterator(fruCachePath))
420 {
421 if (fs::is_regular_file(it.status()))
422 {
423 fs::remove(it);
424 }
425 }
426 }
427 catch (const fs::filesystem_error& e)
428 {
429 }
430 }
431 }
432
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600433 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530434 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600435 int returnCode = system(udevRemove.c_str());
436 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530437
438 string invManagerRestart =
439 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600440 returnCode = system(invManagerRestart.c_str());
441 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530442
443 string sysVpdStop = "systemctl stop system-vpd.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600444 returnCode = system(sysVpdStop.c_str());
445 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530446
447 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600448 returnCode = system(udevAdd.c_str());
449 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530450}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530451
452int VpdTool::updateHardware()
453{
454 int rc = 0;
455 bool updCache = true;
456 const Binary& val = static_cast<const Binary&>(toBinary(value));
457 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
458 try
459 {
460 auto json = nlohmann::json::parse(inventoryJson);
461 EditorImpl edit(fruPath, json, recordName, keyword);
462 if (!((isPathInJson(fruPath)) &&
463 (isRecKwInDbusJson(recordName, keyword))))
464 {
465 updCache = false;
466 }
467 edit.updateKeyword(val, updCache);
468 }
469 catch (json::parse_error& ex)
470 {
471 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
472 }
473 return rc;
474}