blob: 931bba1ebdc3e3164bcdb0b5d745c0521ac2064c [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
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053059void VpdTool::eraseInventoryPath(string& fru)
60{
61 // Power supply frupath comes with INVENTORY_PATH appended in prefix.
62 // Stripping it off inorder to avoid INVENTORY_PATH duplication
63 // during getVINIProperties() execution.
64 fru.erase(0, sizeof(INVENTORY_PATH) - 1);
65}
66
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053067void VpdTool::debugger(json output)
68{
69 cout << output.dump(4) << '\n';
70}
71
72auto VpdTool::makeDBusCall(const string& objectName, const string& interface,
73 const string& kw)
74{
75 auto bus = sdbusplus::bus::new_default();
76 auto properties =
77 bus.new_method_call(INVENTORY_MANAGER_SERVICE, objectName.c_str(),
78 "org.freedesktop.DBus.Properties", "Get");
79 properties.append(interface);
80 properties.append(kw);
81 auto result = bus.call(properties);
82
83 if (result.is_method_error())
84 {
85 throw runtime_error("Get api failed");
86 }
87 return result;
88}
89
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -050090json VpdTool::getVINIProperties(string invPath)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053091{
92 variant<Binary> response;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +053093 json kwVal = json::object({});
94
95 vector<string> keyword{"CC", "SN", "PN", "FN", "DR"};
96 string interface = "com.ibm.ipzvpd.VINI";
PriyangaRamasamycdf943c2020-03-18 02:25:30 +053097 string objectName = {};
98
99 if (invPath.find(INVENTORY_PATH) != string::npos)
100 {
101 objectName = invPath;
102 eraseInventoryPath(invPath);
103 }
104 else
105 {
106 objectName = INVENTORY_PATH + invPath;
107 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530108 for (string kw : keyword)
109 {
110 try
111 {
112 makeDBusCall(objectName, interface, kw).read(response);
113
114 if (auto vec = get_if<Binary>(&response))
115 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530116 string printableVal = getPrintableValue(*vec);
117 kwVal.emplace(kw, printableVal);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530118 }
119 }
Patrick Williams8be43342021-09-02 09:33:36 -0500120 catch (const sdbusplus::exception::exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530121 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500122 if (string(e.name()) ==
123 string("org.freedesktop.DBus.Error.UnknownObject"))
124 {
125 kwVal.emplace(invPath, json::object({}));
126 objFound = false;
127 break;
128 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530129 }
130 }
131
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500132 return kwVal;
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530133}
134
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500135void VpdTool::getExtraInterfaceProperties(const string& invPath,
136 const string& extraInterface,
137 const json& prop, json& output)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530138{
139 variant<string> response;
140
141 string objectName = INVENTORY_PATH + invPath;
142
143 for (const auto& itProp : prop.items())
144 {
145 string kw = itProp.key();
146 try
147 {
148 makeDBusCall(objectName, extraInterface, kw).read(response);
149
150 if (auto str = get_if<string>(&response))
151 {
152 output.emplace(kw, *str);
153 }
154 }
Patrick Williams8be43342021-09-02 09:33:36 -0500155 catch (const sdbusplus::exception::exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530156 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500157 if (std::string(e.name()) ==
158 std::string("org.freedesktop.DBus.Error.UnknownObject"))
159 {
160 objFound = false;
161 break;
162 }
163 else if (std::string(e.name()) ==
164 std::string("org.freedesktop.DBus.Error.UnknownProperty"))
165 {
166 output.emplace(kw, "");
167 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530168 }
169 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530170}
171
172json VpdTool::interfaceDecider(json& itemEEPROM)
173{
174 if (itemEEPROM.find("inventoryPath") == itemEEPROM.end())
175 {
176 throw runtime_error("Inventory Path not found");
177 }
178
179 if (itemEEPROM.find("extraInterfaces") == itemEEPROM.end())
180 {
181 throw runtime_error("Extra Interfaces not found");
182 }
183
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530184 json output = json::object({});
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500185 json subOutput = json::object({});
Alpana Kumarib6965f12020-06-01 00:32:21 -0500186 fruType = "FRU";
187
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500188 json j;
189 objFound = true;
190 string invPath = itemEEPROM.at("inventoryPath");
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530191
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500192 j = getVINIProperties(invPath);
193
194 if (objFound)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530195 {
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500196 subOutput.insert(j.begin(), j.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530197 json js;
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500198 if (itemEEPROM.find("type") != itemEEPROM.end())
199 {
200 fruType = itemEEPROM.at("type");
201 }
202 js.emplace("TYPE", fruType);
203
204 if (invPath.find("powersupply") != string::npos)
205 {
206 js.emplace("type", POWER_SUPPLY_TYPE_INTERFACE);
207 }
208 else if (invPath.find("fan") != string::npos)
209 {
210 js.emplace("type", FAN_INTERFACE);
211 }
212
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530213 for (const auto& ex : itemEEPROM["extraInterfaces"].items())
214 {
215 if (!(ex.value().is_null()))
216 {
Priyanga Ramasamydacaa472021-10-07 12:22:41 -0500217 // TODO: Remove this if condition check once inventory json is
218 // updated with xyz location code interface.
219 if (ex.key() == "com.ibm.ipzvpd.Location")
220 {
221 getExtraInterfaceProperties(
222 invPath,
223 "xyz.openbmc_project.Inventory.Decorator.LocationCode",
224 ex.value(), js);
225 }
226 else
227 {
228 getExtraInterfaceProperties(invPath, ex.key(), ex.value(),
229 js);
230 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530231 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500232 if ((ex.key().find("Item") != string::npos) &&
233 (ex.value().is_null()))
234 {
235 js.emplace("type", ex.key());
236 }
237 subOutput.insert(js.begin(), js.end());
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530238 }
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530239 }
PriyangaRamasamy8cc5b152021-06-03 13:05:17 -0500240 output.emplace(invPath, subOutput);
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530241 return output;
242}
243
244json VpdTool::parseInvJson(const json& jsObject, char flag, string fruPath)
245{
246 json output = json::object({});
247 bool validObject = false;
248
249 if (jsObject.find("frus") == jsObject.end())
250 {
251 throw runtime_error("Frus missing in Inventory json");
252 }
253 else
254 {
255 for (const auto& itemFRUS : jsObject["frus"].items())
256 {
257 for (auto itemEEPROM : itemFRUS.value())
258 {
259 try
260 {
261 if (flag == 'O')
262 {
263 if (itemEEPROM.find("inventoryPath") ==
264 itemEEPROM.end())
265 {
266 throw runtime_error("Inventory Path not found");
267 }
268
269 else if (itemEEPROM.at("inventoryPath") == fruPath)
270 {
271 validObject = true;
272 json j = interfaceDecider(itemEEPROM);
273 output.insert(j.begin(), j.end());
274 return output;
275 }
276 }
277 else
278 {
279 json j = interfaceDecider(itemEEPROM);
280 output.insert(j.begin(), j.end());
281 }
282 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500283 catch (const exception& e)
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530284 {
285 cerr << e.what();
286 }
287 }
288 }
289 if ((flag == 'O') && (!validObject))
290 {
291 throw runtime_error(
292 "Invalid object path. Refer --dumpInventory/-i option.");
293 }
294 }
295 return output;
296}
297
298void VpdTool::dumpInventory(const nlohmann::basic_json<>& jsObject)
299{
300 char flag = 'I';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530301 json output = json::array({});
302 output.emplace_back(parseInvJson(jsObject, flag, ""));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530303 debugger(output);
304}
305
306void VpdTool::dumpObject(const nlohmann::basic_json<>& jsObject)
307{
308 char flag = 'O';
PriyangaRamasamycdf943c2020-03-18 02:25:30 +0530309 json output = json::array({});
Santosh Puranikd5d52bb2020-07-28 15:08:10 +0530310 output.emplace_back(parseInvJson(jsObject, flag, fruPath));
PriyangaRamasamy1f0b1e62020-02-20 20:48:25 +0530311 debugger(output);
312}
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530313
314void VpdTool::readKeyword()
315{
316 string interface = "com.ibm.ipzvpd.";
317 variant<Binary> response;
318
319 try
320 {
321 json output = json::object({});
322 json kwVal = json::object({});
323 makeDBusCall(INVENTORY_PATH + fruPath, interface + recordName, keyword)
324 .read(response);
325
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530326 string printableVal{};
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530327 if (auto vec = get_if<Binary>(&response))
328 {
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530329 printableVal = getPrintableValue(*vec);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530330 }
PriyangaRamasamy887a42a2020-09-03 00:33:57 +0530331 kwVal.emplace(keyword, printableVal);
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530332
333 output.emplace(fruPath, kwVal);
334
335 debugger(output);
336 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500337 catch (const json::exception& e)
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530338 {
339 json output = json::object({});
340 json kwVal = json::object({});
PriyangaRamasamy02d4d4e2020-02-24 14:54:45 +0530341 }
342}
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530343
344int VpdTool::updateKeyword()
345{
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530346 Binary val = toBinary(value);
PriyangaRamasamyd09d2ec2020-03-12 14:11:50 +0530347 auto bus = sdbusplus::bus::new_default();
348 auto properties =
349 bus.new_method_call(BUSNAME, OBJPATH, IFACE, "WriteKeyword");
350 properties.append(static_cast<sdbusplus::message::object_path>(fruPath));
351 properties.append(recordName);
352 properties.append(keyword);
353 properties.append(val);
354 auto result = bus.call(properties);
355
356 if (result.is_method_error())
357 {
358 throw runtime_error("Get api failed");
359 }
360 return 0;
361}
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530362
363void VpdTool::forceReset(const nlohmann::basic_json<>& jsObject)
364{
365 for (const auto& itemFRUS : jsObject["frus"].items())
366 {
367 for (const auto& itemEEPROM : itemFRUS.value().items())
368 {
369 string fru = itemEEPROM.value().at("inventoryPath");
370
371 fs::path fruCachePath = INVENTORY_MANAGER_CACHE;
372 fruCachePath += INVENTORY_PATH;
373 fruCachePath += fru;
374
375 try
376 {
377 for (const auto& it : fs::directory_iterator(fruCachePath))
378 {
379 if (fs::is_regular_file(it.status()))
380 {
381 fs::remove(it);
382 }
383 }
384 }
385 catch (const fs::filesystem_error& e)
386 {
387 }
388 }
389 }
390
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600391 cout.flush();
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530392 string udevRemove = "udevadm trigger -c remove -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600393 int returnCode = system(udevRemove.c_str());
394 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530395
396 string invManagerRestart =
397 "systemctl restart xyz.openbmc_project.Inventory.Manager.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600398 returnCode = system(invManagerRestart.c_str());
399 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530400
401 string sysVpdStop = "systemctl stop system-vpd.service";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600402 returnCode = system(sysVpdStop.c_str());
403 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530404
405 string udevAdd = "udevadm trigger -c add -s \"*nvmem*\" -v";
PriyangaRamasamy6ee637a2021-02-12 04:49:02 -0600406 returnCode = system(udevAdd.c_str());
407 printReturnCode(returnCode);
PriyangaRamasamy0407b172020-03-31 13:57:18 +0530408}
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530409
410int VpdTool::updateHardware()
411{
412 int rc = 0;
413 bool updCache = true;
414 const Binary& val = static_cast<const Binary&>(toBinary(value));
415 ifstream inventoryJson(INVENTORY_JSON_SYM_LINK);
416 try
417 {
418 auto json = nlohmann::json::parse(inventoryJson);
419 EditorImpl edit(fruPath, json, recordName, keyword);
420 if (!((isPathInJson(fruPath)) &&
421 (isRecKwInDbusJson(recordName, keyword))))
422 {
423 updCache = false;
424 }
425 edit.updateKeyword(val, updCache);
426 }
Patrick Williams8e15b932021-10-06 13:04:22 -0500427 catch (const json::parse_error& ex)
PriyangaRamasamyc0a534f2020-08-24 21:29:18 +0530428 {
429 throw(VpdJsonException("Json Parsing failed", INVENTORY_JSON_SYM_LINK));
430 }
431 return rc;
432}