blob: 8c5a92ee0823c351bab47da3096875388fbe0ceb [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
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530196 json output = json::object({});
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500197 json subOutput = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500198 fruType = "FRU";
199
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500200 json j;
201 objFound = true;
202 string invPath = itemEEPROM.at("inventoryPath");
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530203
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500204 j = getVINIProperties(invPath);
205
206 if (objFound)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530207 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500208 subOutput.insert(j.begin(), j.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530209 json js;
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500210 if (itemEEPROM.find("type") != itemEEPROM.end())
211 {
212 fruType = itemEEPROM.at("type");
213 }
214 js.emplace("TYPE", fruType);
215
216 if (invPath.find("powersupply") != string::npos)
217 {
218 js.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
219 }
220 else if (invPath.find("fan") != string::npos)
221 {
222 js.emplace("type", FAN_INTERFACE);
223 }
224
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530225 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
226 {
227 if (!(ex.value().is_null()))
228 {
Priyanga Ramasamydacaa472021-10-07 12:22:41 -0500229 // TODO: Remove this if condition check once inventory json is
230 // updated with xyz location code interface.
231 if (ex.key() == "com.ibm.ipzvpd.Location")
232 {
233 getExtraInterfaceProperties(
234 invPath,
235 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
236 ex.value(), js);
237 }
238 else
239 {
240 getExtraInterfaceProperties(invPath, ex.key(), ex.value(),
241 js);
242 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530243 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500244 if ((ex.key().find("Item") != string::npos) &&
245 (ex.value().is_null()))
246 {
247 js.emplace("type", ex.key());
248 }
249 subOutput.insert(js.begin(), js.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530250 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530251 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500252 output.emplace(invPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530253 return output;
254}
255
256json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
257{
258 json output = json::object({});
259 bool validObject = false;
260
261 if (jsObject.find("frus") == jsObject.end())
262 {
263 throw runtime_error("Frus missing in Inventory json");
264 }
265 else
266 {
267 for (const auto& itemFRUS : jsObject["frus"].items())
268 {
269 for (auto itemEEPROM : itemFRUS.value())
270 {
271 try
272 {
273 if (flag == 'O')
274 {
275 if (itemEEPROM.find("inventoryPath") ==
276 itemEEPROM.end())
277 {
278 throw runtime_error("Inventory Path not found");
279 }
280
281 else if (itemEEPROM.at("inventoryPath") == fruPath)
282 {
283 validObject = true;
284 json j = interfaceDecider(itemEEPROM);
285 output.insert(j.begin(), j.end());
286 return output;
287 }
288 }
289 else
290 {
291 json j = interfaceDecider(itemEEPROM);
292 output.insert(j.begin(), j.end());
293 }
294 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500295 catch (const exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530296 {
297 cerr << e.what();
298 }
299 }
300 }
301 if ((flag == 'O') && (!validObject))
302 {
303 throw runtime_error(
304 "Invalid object path. Refer --dumpInventory/-i option.");
305 }
306 }
307 return output;
308}
309
310void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
311{
312 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530313 json output = json::array({});
314 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530315 debugger(output);
316}
317
318void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
319{
320 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530321 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530322 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530323 debugger(output);
324}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530325
326void VpdTool::readKeyword()
327{
328 string interface = "com.ibm.ipzvpd.";
329 variant<Binary> response;
330
331 try
332 {
333 json output = json::object({});
334 json kwVal = json::object({});
335 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
336 .read(response);
337
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530338 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530339 if (auto vec = get_if<Binary>(&response))
340 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530341 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530342 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530343 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530344
345 output.emplace(fruPath, kwVal);
346
347 debugger(output);
348 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500349 catch (const json::exception& e)
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530350 {
351 json output = json::object({});
352 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530353 }
354}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530355
356int VpdTool::updateKeyword()
357{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530358 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530359 auto bus = sdbusplus::bus::new_default();
360 auto properties =
361 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
362 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
363 properties.append(recordName);
364 properties.append(keyword);
365 properties.append(val);
366 auto result = bus.call(properties);
367
368 if (result.is_method_error())
369 {
370 throw runtime_error("Get api failed");
371 }
372 return 0;
373}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530374
375void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
376{
377 for (const auto& itemFRUS : jsObject["frus"].items())
378 {
379 for (const auto& itemEEPROM : itemFRUS.value().items())
380 {
381 string fru = itemEEPROM.value().at("inventoryPath");
382
383 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
384 fruCachePath += INVENTORY_PATH;
385 fruCachePath += fru;
386
387 try
388 {
389 for (const auto& it : fs::directory_iterator(fruCachePath))
390 {
391 if (fs::is_regular_file(it.status()))
392 {
393 fs::remove(it);
394 }
395 }
396 }
397 catch (const fs::filesystem_error& e)
398 {
399 }
400 }
401 }
402
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600403 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530404 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600405 int returnCode = system(udevRemove.c_str());
406 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530407
408 string invManagerRestart =
409 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600410 returnCode = system(invManagerRestart.c_str());
411 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530412
413 string sysVpdStop = "systemctl stop system-vpd.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600414 returnCode = system(sysVpdStop.c_str());
415 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530416
417 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600418 returnCode = system(udevAdd.c_str());
419 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530420}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530421
422int VpdTool::updateHardware()
423{
424 int rc = 0;
425 bool updCache = true;
426 const Binary& val = static_cast<const Binary&>(toBinary(value));
427 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
428 try
429 {
430 auto json = nlohmann::json::parse(inventoryJson);
431 EditorImpl edit(fruPath, json, recordName, keyword);
432 if (!((isPathInJson(fruPath)) &&
433 (isRecKwInDbusJson(recordName, keyword))))
434 {
435 updCache = false;
436 }
437 edit.updateKeyword(val, updCache);
438 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500439 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530440 {
441 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
442 }
443 return rc;
444}