1 #include "config.h"
2
3 #include "vpd_tool.hpp"
4
5 #include "tool_constants.hpp"
6 #include "tool_types.hpp"
7 #include "tool_utils.hpp"
8
9 #include <cstdlib>
10 #include <iostream>
11 #include <regex>
12 #include <tuple>
13 namespace vpd
14 {
readKeyword(const std::string & i_vpdPath,const std::string & i_recordName,const std::string & i_keywordName,const bool i_onHardware,const std::string & i_fileToSave)15 int VpdTool::readKeyword(
16 const std::string& i_vpdPath, const std::string& i_recordName,
17 const std::string& i_keywordName, const bool i_onHardware,
18 const std::string& i_fileToSave)
19 {
20 int l_rc = constants::FAILURE;
21 try
22 {
23 types::DbusVariantType l_keywordValue;
24 if (i_onHardware)
25 {
26 l_keywordValue = utils::readKeywordFromHardware(
27 i_vpdPath, std::make_tuple(i_recordName, i_keywordName));
28 }
29 else
30 {
31 std::string l_inventoryObjectPath(
32 constants::baseInventoryPath + i_vpdPath);
33
34 l_keywordValue = utils::readDbusProperty(
35 constants::inventoryManagerService, l_inventoryObjectPath,
36 constants::ipzVpdInfPrefix + i_recordName, i_keywordName);
37 }
38
39 if (const auto l_value =
40 std::get_if<types::BinaryVector>(&l_keywordValue);
41 l_value && !l_value->empty())
42 {
43 // ToDo: Print value in both ASCII and hex formats
44 const std::string& l_keywordStrValue =
45 utils::getPrintableValue(*l_value);
46
47 if (i_fileToSave.empty())
48 {
49 utils::displayOnConsole(i_vpdPath, i_keywordName,
50 l_keywordStrValue);
51 l_rc = constants::SUCCESS;
52 }
53 else
54 {
55 if (utils::saveToFile(i_fileToSave, l_keywordStrValue))
56 {
57 std::cout
58 << "Value read is saved on the file: " << i_fileToSave
59 << std::endl;
60 l_rc = constants::SUCCESS;
61 }
62 else
63 {
64 std::cerr
65 << "Error while saving the read value on the file: "
66 << i_fileToSave
67 << "\nDisplaying the read value on console"
68 << std::endl;
69 utils::displayOnConsole(i_vpdPath, i_keywordName,
70 l_keywordStrValue);
71 }
72 }
73 }
74 else
75 {
76 // TODO: Enable logging when verbose is enabled.
77 std::cout << "Invalid data type or empty data received."
78 << std::endl;
79 }
80 }
81 catch (const std::exception& l_ex)
82 {
83 // TODO: Enable logging when verbose is enabled.
84 std::cerr << "Read keyword's value failed for path: " << i_vpdPath
85 << ", Record: " << i_recordName << ", Keyword: "
86 << i_keywordName << ", error: " << l_ex.what() << std::endl;
87 }
88 return l_rc;
89 }
90
dumpObject(std::string i_fruPath) const91 int VpdTool::dumpObject(std::string i_fruPath) const noexcept
92 {
93 int l_rc{constants::FAILURE};
94 try
95 {
96 // ToDo: For PFuture system take only full path from the user.
97 i_fruPath = constants::baseInventoryPath + i_fruPath;
98
99 nlohmann::json l_resultJsonArray = nlohmann::json::array({});
100 const nlohmann::json l_fruJson = getFruProperties(i_fruPath);
101 if (!l_fruJson.empty())
102 {
103 l_resultJsonArray += l_fruJson;
104
105 utils::printJson(l_resultJsonArray);
106 }
107 else
108 {
109 std::cout << "FRU [" << i_fruPath
110 << "] is not present in the system" << std::endl;
111 }
112 l_rc = constants::SUCCESS;
113 }
114 catch (std::exception& l_ex)
115 {
116 // TODO: Enable logging when verbose is enabled.
117 std::cerr << "Dump Object failed for FRU [" << i_fruPath
118 << "], Error: " << l_ex.what() << std::endl;
119 }
120 return l_rc;
121 }
122
123 template <typename PropertyType>
populateInterfaceJson(const std::string & i_inventoryObjPath,const std::string & i_infName,const std::vector<std::string> & i_propList,nlohmann::json & io_fruJsonObject) const124 void VpdTool::populateInterfaceJson(const std::string& i_inventoryObjPath,
125 const std::string& i_infName,
126 const std::vector<std::string>& i_propList,
127 nlohmann::json& io_fruJsonObject) const
128 {
129 nlohmann::json l_interfaceJsonObj = nlohmann::json::object({});
130
131 auto l_readProperties = [i_inventoryObjPath, &l_interfaceJsonObj, i_infName,
132 this](const std::string& i_property) {
133 const nlohmann::json l_propertyJsonObj =
134 getInventoryPropertyJson<PropertyType>(i_inventoryObjPath,
135 i_infName, i_property);
136 l_interfaceJsonObj.insert(l_propertyJsonObj.cbegin(),
137 l_propertyJsonObj.cend());
138 };
139
140 std::for_each(i_propList.cbegin(), i_propList.cend(), l_readProperties);
141
142 if (!l_interfaceJsonObj.empty())
143 {
144 io_fruJsonObject.insert(l_interfaceJsonObj.cbegin(),
145 l_interfaceJsonObj.cend());
146 }
147 }
148
populateFruJson(const std::string & i_inventoryObjPath,nlohmann::json & io_fruJsonObject,const std::vector<std::string> & i_interfaceList) const149 void VpdTool::populateFruJson(
150 const std::string& i_inventoryObjPath, nlohmann::json& io_fruJsonObject,
151 const std::vector<std::string>& i_interfaceList) const
152 {
153 for (const auto& l_interface : i_interfaceList)
154 {
155 if (l_interface == constants::inventoryItemInf)
156 {
157 const std::vector<std::string> l_properties = {"PrettyName"};
158 populateInterfaceJson<std::string>(i_inventoryObjPath,
159 constants::inventoryItemInf,
160 l_properties, io_fruJsonObject);
161 continue;
162 }
163
164 if (l_interface == constants::locationCodeInf)
165 {
166 const std::vector<std::string> l_properties = {"LocationCode"};
167 populateInterfaceJson<std::string>(i_inventoryObjPath,
168 constants::locationCodeInf,
169 l_properties, io_fruJsonObject);
170 continue;
171 }
172
173 if (l_interface == constants::viniInf)
174 {
175 const std::vector<std::string> l_properties = {"SN", "PN", "CC",
176 "FN", "DR"};
177 populateInterfaceJson<vpd::types::BinaryVector>(
178 i_inventoryObjPath, constants::viniInf, l_properties,
179 io_fruJsonObject);
180 continue;
181 }
182
183 if (l_interface == constants::assetInf)
184 {
185 if (std::find(i_interfaceList.begin(), i_interfaceList.end(),
186 constants::viniInf) != i_interfaceList.end())
187 {
188 // The value will be filled from VINI interface. Don't
189 // process asset interface.
190 continue;
191 }
192
193 const std::vector<std::string> l_properties = {
194 "Model", "SerialNumber", "SubModel"};
195
196 populateInterfaceJson<std::string>(i_inventoryObjPath,
197 constants::assetInf,
198 l_properties, io_fruJsonObject);
199 continue;
200 }
201
202 if (l_interface == constants::networkInf)
203 {
204 const std::vector<std::string> l_properties = {"MACAddress"};
205 populateInterfaceJson<std::string>(i_inventoryObjPath,
206 constants::networkInf,
207 l_properties, io_fruJsonObject);
208 continue;
209 }
210
211 if (l_interface == constants::pcieSlotInf)
212 {
213 const std::vector<std::string> l_properties = {"SlotType"};
214 populateInterfaceJson<std::string>(i_inventoryObjPath,
215 constants::pcieSlotInf,
216 l_properties, io_fruJsonObject);
217 continue;
218 }
219
220 if (l_interface == constants::slotNumInf)
221 {
222 const std::vector<std::string> l_properties = {"SlotNumber"};
223 populateInterfaceJson<uint32_t>(i_inventoryObjPath,
224 constants::slotNumInf, l_properties,
225 io_fruJsonObject);
226 continue;
227 }
228
229 if (l_interface == constants::i2cDeviceInf)
230 {
231 const std::vector<std::string> l_properties = {"Address", "Bus"};
232 populateInterfaceJson<uint32_t>(i_inventoryObjPath,
233 constants::i2cDeviceInf,
234 l_properties, io_fruJsonObject);
235 continue;
236 }
237 }
238 }
239
getFruProperties(const std::string & i_objectPath) const240 nlohmann::json VpdTool::getFruProperties(const std::string& i_objectPath) const
241 {
242 // check if FRU is present in the system
243 if (!isFruPresent(i_objectPath))
244 {
245 return nlohmann::json::object_t();
246 }
247
248 nlohmann::json l_fruJson = nlohmann::json::object_t({});
249
250 // need to trim out the base inventory path in the FRU JSON.
251 const std::string l_displayObjectPath =
252 (i_objectPath.find(constants::baseInventoryPath) == std::string::npos)
253 ? i_objectPath
254 : i_objectPath.substr(strlen(constants::baseInventoryPath));
255
256 l_fruJson.emplace(l_displayObjectPath, nlohmann::json::object_t({}));
257
258 auto& l_fruObject = l_fruJson[l_displayObjectPath];
259
260 types::MapperGetObject l_mapperResp = utils::GetServiceInterfacesForObject(
261 i_objectPath, std::vector<std::string>{});
262
263 for (const auto& [l_service, l_interfaceList] : l_mapperResp)
264 {
265 if (l_service != constants::inventoryManagerService)
266 {
267 continue;
268 }
269 populateFruJson(i_objectPath, l_fruObject, l_interfaceList);
270 }
271
272 const auto l_typePropertyJson = getFruTypeProperty(i_objectPath);
273 if (!l_typePropertyJson.empty())
274 {
275 l_fruObject.insert(l_typePropertyJson.cbegin(),
276 l_typePropertyJson.cend());
277 }
278
279 // insert FRU "TYPE"
280 l_fruObject.emplace("TYPE", "FRU");
281
282 return l_fruJson;
283 }
284
285 template <typename PropertyType>
getInventoryPropertyJson(const std::string & i_objectPath,const std::string & i_interface,const std::string & i_propertyName) const286 nlohmann::json VpdTool::getInventoryPropertyJson(
287 const std::string& i_objectPath, const std::string& i_interface,
288 const std::string& i_propertyName) const noexcept
289 {
290 nlohmann::json l_resultInJson = nlohmann::json::object({});
291 try
292 {
293 types::DbusVariantType l_keyWordValue;
294
295 l_keyWordValue =
296 utils::readDbusProperty(constants::inventoryManagerService,
297 i_objectPath, i_interface, i_propertyName);
298
299 if (const auto l_value = std::get_if<PropertyType>(&l_keyWordValue))
300 {
301 if constexpr (std::is_same<PropertyType, std::string>::value)
302 {
303 l_resultInJson.emplace(i_propertyName, *l_value);
304 }
305 else if constexpr (std::is_same<PropertyType, bool>::value)
306 {
307 l_resultInJson.emplace(i_propertyName,
308 *l_value ? "true" : "false");
309 }
310 else if constexpr (std::is_same<PropertyType,
311 types::BinaryVector>::value)
312 {
313 const std::string& l_keywordStrValue =
314 vpd::utils::getPrintableValue(*l_value);
315
316 l_resultInJson.emplace(i_propertyName, l_keywordStrValue);
317 }
318 else if constexpr (std::is_same<PropertyType, uint32_t>::value)
319 {
320 l_resultInJson.emplace(i_propertyName,
321 std::to_string(*l_value));
322 }
323 }
324 else
325 {
326 // TODO: Enable logging when verbose is enabled.
327 std::cout << "Invalid data type received." << std::endl;
328 }
329 }
330 catch (const std::exception& l_ex)
331 {
332 // TODO: Enable logging when verbose is enabled.
333 std::cerr << "Read " << i_propertyName
334 << " value for FRU path: " << i_objectPath
335 << ", failed with exception: " << l_ex.what() << std::endl;
336 }
337 return l_resultInJson;
338 }
339
fixSystemVpd() const340 int VpdTool::fixSystemVpd() const noexcept
341 {
342 int l_rc = constants::FAILURE;
343
344 nlohmann::json l_backupRestoreCfgJsonObj = getBackupRestoreCfgJsonObj();
345 if (!fetchKeywordInfo(l_backupRestoreCfgJsonObj))
346 {
347 return l_rc;
348 }
349
350 printSystemVpd(l_backupRestoreCfgJsonObj);
351
352 do
353 {
354 printFixSystemVpdOption(types::UserOption::UseBackupDataForAll);
355 printFixSystemVpdOption(
356 types::UserOption::UseSystemBackplaneDataForAll);
357 printFixSystemVpdOption(types::UserOption::MoreOptions);
358 printFixSystemVpdOption(types::UserOption::Exit);
359
360 int l_userSelectedOption = types::UserOption::Exit;
361 std::cin >> l_userSelectedOption;
362
363 std::cout << std::endl << std::string(191, '=') << std::endl;
364
365 if (types::UserOption::UseBackupDataForAll == l_userSelectedOption)
366 {
367 l_rc = updateAllKeywords(l_backupRestoreCfgJsonObj, true);
368 break;
369 }
370 else if (types::UserOption::UseSystemBackplaneDataForAll ==
371 l_userSelectedOption)
372 {
373 l_rc = updateAllKeywords(l_backupRestoreCfgJsonObj, false);
374 break;
375 }
376 else if (types::UserOption::MoreOptions == l_userSelectedOption)
377 {
378 l_rc = handleMoreOption(l_backupRestoreCfgJsonObj);
379 break;
380 }
381 else if (types::UserOption::Exit == l_userSelectedOption)
382 {
383 std::cout << "Exit successfully" << std::endl;
384 break;
385 }
386 else
387 {
388 std::cout << "Provide a valid option. Retry." << std::endl;
389 }
390 } while (true);
391
392 return l_rc;
393 }
394
writeKeyword(std::string i_vpdPath,const std::string & i_recordName,const std::string & i_keywordName,const std::string & i_keywordValue,const bool i_onHardware)395 int VpdTool::writeKeyword(
396 std::string i_vpdPath, const std::string& i_recordName,
397 const std::string& i_keywordName, const std::string& i_keywordValue,
398 const bool i_onHardware) noexcept
399 {
400 int l_rc = constants::FAILURE;
401 try
402 {
403 if (i_vpdPath.empty() || i_recordName.empty() ||
404 i_keywordName.empty() || i_keywordValue.empty())
405 {
406 throw std::runtime_error("Received input is empty.");
407 }
408
409 auto l_paramsToWrite =
410 std::make_tuple(i_recordName, i_keywordName,
411 utils::convertToBinary(i_keywordValue));
412
413 if (i_onHardware)
414 {
415 l_rc = utils::writeKeywordOnHardware(i_vpdPath, l_paramsToWrite);
416 }
417 else
418 {
419 i_vpdPath = constants::baseInventoryPath + i_vpdPath;
420 l_rc = utils::writeKeyword(i_vpdPath, l_paramsToWrite);
421 }
422
423 if (l_rc > 0)
424 {
425 std::cout << "Data updated successfully " << std::endl;
426 l_rc = constants::SUCCESS;
427 }
428 }
429 catch (const std::exception& l_ex)
430 {
431 // TODO: Enable log when verbose is enabled.
432 std::cerr << "Write keyword's value for path: " << i_vpdPath
433 << ", Record: " << i_recordName
434 << ", Keyword: " << i_keywordName
435 << " is failed. Exception: " << l_ex.what() << std::endl;
436 }
437 return l_rc;
438 }
439
getBackupRestoreCfgJsonObj() const440 nlohmann::json VpdTool::getBackupRestoreCfgJsonObj() const noexcept
441 {
442 nlohmann::json l_parsedBackupRestoreJson{};
443 try
444 {
445 nlohmann::json l_parsedSystemJson =
446 utils::getParsedJson(INVENTORY_JSON_SYM_LINK);
447
448 // check for mandatory fields at this point itself.
449 if (!l_parsedSystemJson.contains("backupRestoreConfigPath"))
450 {
451 throw std::runtime_error(
452 "backupRestoreConfigPath tag is missing from system config JSON : " +
453 std::string(INVENTORY_JSON_SYM_LINK));
454 }
455
456 l_parsedBackupRestoreJson =
457 utils::getParsedJson(l_parsedSystemJson["backupRestoreConfigPath"]);
458 }
459 catch (const std::exception& l_ex)
460 {
461 // TODO: Enable logging when verbose is enabled.
462 std::cerr << l_ex.what() << std::endl;
463 }
464
465 return l_parsedBackupRestoreJson;
466 }
467
cleanSystemVpd(bool i_syncBiosAttributesRequired) const468 int VpdTool::cleanSystemVpd(bool i_syncBiosAttributesRequired) const noexcept
469 {
470 try
471 {
472 // In order to do syncBiosAttributes, we need BIOS Config Manager
473 // service up and running
474 if (i_syncBiosAttributesRequired &&
475 !utils::isServiceRunning(constants::biosConfigMgrService))
476 {
477 std::cerr
478 << "Cannot sync BIOS attributes as BIOS Config Manager service is not running."
479 << std::endl;
480 return constants::FAILURE;
481 }
482
483 // get the keyword map from backup_restore json
484 // iterate through the keyword map get default value of
485 // l_keywordName.
486 // use writeKeyword API to update default value on hardware,
487 // backup and D - Bus.
488 const nlohmann::json l_parsedBackupRestoreJson =
489 getBackupRestoreCfgJsonObj();
490
491 // check for mandatory tags
492 if (l_parsedBackupRestoreJson.contains("source") &&
493 l_parsedBackupRestoreJson.contains("backupMap") &&
494 l_parsedBackupRestoreJson["source"].contains("hardwarePath") &&
495 l_parsedBackupRestoreJson["backupMap"].is_array())
496 {
497 // get the source hardware path
498 const auto& l_hardwarePath =
499 l_parsedBackupRestoreJson["source"]["hardwarePath"];
500
501 // iterate through the backup map
502 for (const auto& l_aRecordKwInfo :
503 l_parsedBackupRestoreJson["backupMap"])
504 {
505 // check if Manufacturing Reset is required for this entry
506 const bool l_isMfgCleanRequired =
507 l_aRecordKwInfo.value("isManufactureResetRequired", false);
508
509 if (l_isMfgCleanRequired)
510 {
511 // get the Record name and Keyword name
512 const std::string& l_srcRecordName =
513 l_aRecordKwInfo.value("sourceRecord", "");
514 const std::string& l_srcKeywordName =
515 l_aRecordKwInfo.value("sourceKeyword", "");
516
517 // validate the Record name, Keyword name and the
518 // defaultValue
519 if (!l_srcRecordName.empty() && !l_srcKeywordName.empty() &&
520 l_aRecordKwInfo.contains("defaultValue") &&
521 l_aRecordKwInfo["defaultValue"].is_array())
522 {
523 // check if this keyword is used for backing up BIOS
524 // attribute
525 const bool l_isUsedForBiosAttributeBackup =
526 l_aRecordKwInfo.value("isBiosSyncRequired", false);
527
528 const types::BinaryVector l_keywordValueToUpdate =
529 (i_syncBiosAttributesRequired &&
530 l_isUsedForBiosAttributeBackup)
531 ? getVpdValueInBiosConfigManager(
532 l_srcRecordName, l_srcKeywordName)
533 : l_aRecordKwInfo["defaultValue"]
534 .get<types::BinaryVector>();
535
536 if (l_keywordValueToUpdate.empty())
537 {
538 std::cerr << "Failed to update " << l_srcRecordName
539 << ":" << l_srcKeywordName
540 << " . Keyword value to update is empty"
541 << std::endl;
542 continue;
543 }
544
545 // update the Keyword with default value, use D-Bus
546 // method UpdateKeyword exposed by vpd-manager.
547 // Note: writing to all paths (Primary EEPROM path,
548 // Secondary EEPROM path, D-Bus cache and Backup path)
549 // is the responsibility of vpd-manager's UpdateKeyword
550 // API
551 if (constants::FAILURE ==
552 utils::writeKeyword(
553 l_hardwarePath,
554 std::make_tuple(l_srcRecordName,
555 l_srcKeywordName,
556 l_keywordValueToUpdate)))
557 {
558 // TODO: Enable logging when verbose
559 // is enabled.
560 std::cerr << "Failed to update " << l_srcRecordName
561 << ":" << l_srcKeywordName << std::endl;
562 }
563 }
564 else
565 {
566 std::cerr
567 << "Unrecognized Entry Record [" << l_srcRecordName
568 << "] Keyword [" << l_srcKeywordName
569 << "] in Backup Restore JSON backup map"
570 << std::endl;
571 }
572 } // mfgClean required check
573 } // keyword list loop
574 }
575 else // backupRestoreJson is not valid
576 {
577 std::cerr << "Backup Restore JSON is not valid" << std::endl;
578 }
579
580 // success/failure message
581 std::cout << "The critical keywords from system backplane VPD has "
582 "been reset successfully."
583 << std::endl;
584
585 } // try block end
586 catch (const std::exception& l_ex)
587 {
588 // TODO: Enable logging when verbose is enabled.
589 std::cerr
590 << "Manufacturing reset on system vpd keywords is unsuccessful. Error : "
591 << l_ex.what() << std::endl;
592 }
593 return constants::SUCCESS;
594 }
595
fetchKeywordInfo(nlohmann::json & io_parsedJsonObj) const596 bool VpdTool::fetchKeywordInfo(nlohmann::json& io_parsedJsonObj) const noexcept
597 {
598 bool l_returnValue = false;
599 try
600 {
601 if (io_parsedJsonObj.empty() || !io_parsedJsonObj.contains("source") ||
602 !io_parsedJsonObj.contains("destination") ||
603 !io_parsedJsonObj.contains("backupMap"))
604 {
605 throw std::runtime_error("Invalid JSON");
606 }
607
608 std::string l_srcVpdPath;
609 std::string l_dstVpdPath;
610
611 bool l_isSourceOnHardware = false;
612 if (l_srcVpdPath = io_parsedJsonObj["source"].value("hardwarePath", "");
613 !l_srcVpdPath.empty())
614 {
615 l_isSourceOnHardware = true;
616 }
617 else if (l_srcVpdPath =
618 io_parsedJsonObj["source"].value("inventoryPath", "");
619 l_srcVpdPath.empty())
620 {
621 throw std::runtime_error("Source path is empty in JSON");
622 }
623
624 bool l_isDestinationOnHardware = false;
625 if (l_dstVpdPath =
626 io_parsedJsonObj["destination"].value("hardwarePath", "");
627 !l_dstVpdPath.empty())
628 {
629 l_isDestinationOnHardware = true;
630 }
631 else if (l_dstVpdPath =
632 io_parsedJsonObj["destination"].value("inventoryPath", "");
633 l_dstVpdPath.empty())
634 {
635 throw std::runtime_error("Destination path is empty in JSON");
636 }
637
638 for (auto& l_aRecordKwInfo : io_parsedJsonObj["backupMap"])
639 {
640 const std::string& l_srcRecordName =
641 l_aRecordKwInfo.value("sourceRecord", "");
642 const std::string& l_srcKeywordName =
643 l_aRecordKwInfo.value("sourceKeyword", "");
644 const std::string& l_dstRecordName =
645 l_aRecordKwInfo.value("destinationRecord", "");
646 const std::string& l_dstKeywordName =
647 l_aRecordKwInfo.value("destinationKeyword", "");
648
649 if (l_srcRecordName.empty() || l_dstRecordName.empty() ||
650 l_srcKeywordName.empty() || l_dstKeywordName.empty())
651 {
652 // TODO: Enable logging when verbose is enabled.
653 std::cout << "Record or keyword not found in the JSON."
654 << std::endl;
655 continue;
656 }
657
658 types::DbusVariantType l_srcKeywordVariant;
659 if (l_isSourceOnHardware)
660 {
661 l_srcKeywordVariant = utils::readKeywordFromHardware(
662 l_srcVpdPath,
663 std::make_tuple(l_srcRecordName, l_srcKeywordName));
664 }
665 else
666 {
667 l_srcKeywordVariant = utils::readDbusProperty(
668 constants::inventoryManagerService, l_srcVpdPath,
669 constants::ipzVpdInfPrefix + l_srcRecordName,
670 l_srcKeywordName);
671 }
672
673 if (auto l_srcKeywordValue =
674 std::get_if<types::BinaryVector>(&l_srcKeywordVariant);
675 l_srcKeywordValue && !l_srcKeywordValue->empty())
676 {
677 l_aRecordKwInfo["sourcekeywordValue"] = *l_srcKeywordValue;
678 }
679 else
680 {
681 // TODO: Enable logging when verbose is enabled.
682 std::cout
683 << "Invalid data type or empty data received, for source record: "
684 << l_srcRecordName << ", keyword: " << l_srcKeywordName
685 << std::endl;
686 continue;
687 }
688
689 types::DbusVariantType l_dstKeywordVariant;
690 if (l_isDestinationOnHardware)
691 {
692 l_dstKeywordVariant = utils::readKeywordFromHardware(
693 l_dstVpdPath,
694 std::make_tuple(l_dstRecordName, l_dstKeywordName));
695 }
696 else
697 {
698 l_dstKeywordVariant = utils::readDbusProperty(
699 constants::inventoryManagerService, l_dstVpdPath,
700 constants::ipzVpdInfPrefix + l_dstRecordName,
701 l_dstKeywordName);
702 }
703
704 if (auto l_dstKeywordValue =
705 std::get_if<types::BinaryVector>(&l_dstKeywordVariant);
706 l_dstKeywordValue && !l_dstKeywordValue->empty())
707 {
708 l_aRecordKwInfo["destinationkeywordValue"] = *l_dstKeywordValue;
709 }
710 else
711 {
712 // TODO: Enable logging when verbose is enabled.
713 std::cout
714 << "Invalid data type or empty data received, for destination record: "
715 << l_dstRecordName << ", keyword: " << l_dstKeywordName
716 << std::endl;
717 continue;
718 }
719 }
720
721 l_returnValue = true;
722 }
723 catch (const std::exception& l_ex)
724 {
725 // TODO: Enable logging when verbose is enabled.
726 std::cerr << l_ex.what() << std::endl;
727 }
728
729 return l_returnValue;
730 }
731
getFruTypeProperty(const std::string & i_objectPath) const732 nlohmann::json VpdTool::getFruTypeProperty(
733 const std::string& i_objectPath) const noexcept
734 {
735 nlohmann::json l_resultInJson = nlohmann::json::object({});
736 std::vector<std::string> l_pimInfList;
737
738 auto l_serviceInfMap = utils::GetServiceInterfacesForObject(
739 i_objectPath, std::vector<std::string>{constants::inventoryItemInf});
740 if (l_serviceInfMap.contains(constants::inventoryManagerService))
741 {
742 l_pimInfList = l_serviceInfMap[constants::inventoryManagerService];
743
744 // iterate through the list and find
745 // "xyz.openbmc_project.Inventory.Item.*"
746 for (const auto& l_interface : l_pimInfList)
747 {
748 if (l_interface.find(constants::inventoryItemInf) !=
749 std::string::npos &&
750 l_interface.length() >
751 std::string(constants::inventoryItemInf).length())
752 {
753 l_resultInJson.emplace("type", l_interface);
754 }
755 }
756 }
757 return l_resultInJson;
758 }
759
isFruPresent(const std::string & i_objectPath) const760 bool VpdTool::isFruPresent(const std::string& i_objectPath) const noexcept
761 {
762 bool l_returnValue{false};
763 try
764 {
765 types::DbusVariantType l_keyWordValue;
766
767 l_keyWordValue = utils::readDbusProperty(
768 constants::inventoryManagerService, i_objectPath,
769 constants::inventoryItemInf, "Present");
770
771 if (const auto l_value = std::get_if<bool>(&l_keyWordValue))
772 {
773 l_returnValue = *l_value;
774 }
775 }
776 catch (const std::runtime_error& l_ex)
777 {
778 // TODO: Enable logging when verbose is enabled.
779 // std::cerr << "Failed to check \"Present\" property for FRU "
780 // << i_objectPath << " Error: " << l_ex.what() <<
781 // std::endl;
782 }
783 return l_returnValue;
784 }
785
printFixSystemVpdOption(const types::UserOption & i_option) const786 void VpdTool::printFixSystemVpdOption(
787 const types::UserOption& i_option) const noexcept
788 {
789 switch (i_option)
790 {
791 case types::UserOption::Exit:
792 std::cout << "Enter 0 => To exit successfully : ";
793 break;
794 case types::UserOption::UseBackupDataForAll:
795 std::cout << "Enter 1 => If you choose the data on backup for all "
796 "mismatching record-keyword pairs"
797 << std::endl;
798 break;
799 case types::UserOption::UseSystemBackplaneDataForAll:
800 std::cout << "Enter 2 => If you choose the data on primary for all "
801 "mismatching record-keyword pairs"
802 << std::endl;
803 break;
804 case types::UserOption::MoreOptions:
805 std::cout << "Enter 3 => If you wish to explore more options"
806 << std::endl;
807 break;
808 case types::UserOption::UseBackupDataForCurrent:
809 std::cout << "Enter 4 => If you choose the data on backup as the "
810 "right value"
811 << std::endl;
812 break;
813 case types::UserOption::UseSystemBackplaneDataForCurrent:
814 std::cout << "Enter 5 => If you choose the data on primary as the "
815 "right value"
816 << std::endl;
817 break;
818 case types::UserOption::NewValueOnBoth:
819 std::cout
820 << "Enter 6 => If you wish to enter a new value to update "
821 "both on backup and primary"
822 << std::endl;
823 break;
824 case types::UserOption::SkipCurrent:
825 std::cout << "Enter 7 => If you wish to skip the above "
826 "record-keyword pair"
827 << std::endl;
828 break;
829 }
830 }
831
dumpInventory(bool i_dumpTable) const832 int VpdTool::dumpInventory(bool i_dumpTable) const noexcept
833 {
834 int l_rc{constants::FAILURE};
835
836 try
837 {
838 // get all object paths under PIM
839 const auto l_objectPaths = utils::GetSubTreePaths(
840 constants::baseInventoryPath, 0,
841 std::vector<std::string>{constants::inventoryItemInf});
842
843 if (!l_objectPaths.empty())
844 {
845 nlohmann::json l_resultInJson = nlohmann::json::array({});
846
847 std::for_each(l_objectPaths.begin(), l_objectPaths.end(),
848 [&](const auto& l_objectPath) {
849 const auto l_fruJson =
850 getFruProperties(l_objectPath);
851 if (!l_fruJson.empty())
852 {
853 if (l_resultInJson.empty())
854 {
855 l_resultInJson += l_fruJson;
856 }
857 else
858 {
859 l_resultInJson.at(0).insert(
860 l_fruJson.cbegin(), l_fruJson.cend());
861 }
862 }
863 });
864
865 if (i_dumpTable)
866 {
867 // create Table object
868 utils::Table l_inventoryTable{};
869
870 // columns to be populated in the Inventory table
871 const std::vector<types::TableColumnNameSizePair>
872 l_tableColumns = {
873 {"FRU", 100}, {"CC", 6}, {"DR", 20},
874 {"LocationCode", 32}, {"PN", 8}, {"PrettyName", 80},
875 {"SubModel", 10}, {"SN", 15}, {"type", 60}};
876
877 types::TableInputData l_tableData;
878
879 // First prepare the Table Columns
880 for (const auto& l_column : l_tableColumns)
881 {
882 if (constants::FAILURE ==
883 l_inventoryTable.AddColumn(l_column.first,
884 l_column.second))
885 {
886 // TODO: Enable logging when verbose is enabled.
887 std::cerr << "Failed to add column " << l_column.first
888 << " in Inventory Table." << std::endl;
889 }
890 }
891
892 // iterate through the json array
893 for (const auto& l_fruEntry : l_resultInJson[0].items())
894 {
895 // if object path ends in "unit([0-9][0-9]?)", skip adding
896 // the object path in the table
897 if (std::regex_search(l_fruEntry.key(),
898 std::regex("unit([0-9][0-9]?)")))
899 {
900 continue;
901 }
902
903 std::vector<std::string> l_row;
904 for (const auto& l_column : l_tableColumns)
905 {
906 const auto& l_fruJson = l_fruEntry.value();
907
908 if (l_column.first == "FRU")
909 {
910 l_row.push_back(l_fruEntry.key());
911 }
912 else
913 {
914 if (l_fruJson.contains(l_column.first))
915 {
916 l_row.push_back(l_fruJson[l_column.first]);
917 }
918 else
919 {
920 l_row.push_back("");
921 }
922 }
923 }
924
925 l_tableData.push_back(l_row);
926 }
927
928 l_rc = l_inventoryTable.Print(l_tableData);
929 }
930 else
931 {
932 // print JSON to console
933 utils::printJson(l_resultInJson);
934 l_rc = constants::SUCCESS;
935 }
936 }
937 }
938 catch (const std::exception& l_ex)
939 {
940 // TODO: Enable logging when verbose is enabled.
941 std::cerr << "Dump inventory failed. Error: " << l_ex.what()
942 << std::endl;
943 }
944 return l_rc;
945 }
946
printSystemVpd(const nlohmann::json & i_parsedJsonObj) const947 void VpdTool::printSystemVpd(
948 const nlohmann::json& i_parsedJsonObj) const noexcept
949 {
950 if (i_parsedJsonObj.empty() || !i_parsedJsonObj.contains("backupMap"))
951 {
952 // TODO: Enable logging when verbose is enabled.
953 std::cerr << "Invalid JSON to print system VPD" << std::endl;
954 }
955
956 std::string l_outline(191, '=');
957 std::cout << "\nRestorable record-keyword pairs and their data on backup & "
958 "primary.\n\n"
959 << l_outline << std::endl;
960
961 std::cout << std::left << std::setw(6) << "S.No" << std::left
962 << std::setw(8) << "Record" << std::left << std::setw(9)
963 << "Keyword" << std::left << std::setw(75) << "Data On Backup"
964 << std::left << std::setw(75) << "Data On Primary" << std::left
965 << std::setw(14) << "Data Mismatch\n"
966 << l_outline << std::endl;
967
968 uint8_t l_slNum = 0;
969
970 for (const auto& l_aRecordKwInfo : i_parsedJsonObj["backupMap"])
971 {
972 if (l_aRecordKwInfo.contains("sourceRecord") ||
973 l_aRecordKwInfo.contains("sourceKeyword") ||
974 l_aRecordKwInfo.contains("destinationkeywordValue") ||
975 l_aRecordKwInfo.contains("sourcekeywordValue"))
976 {
977 std::string l_mismatchFound{
978 (l_aRecordKwInfo["destinationkeywordValue"] !=
979 l_aRecordKwInfo["sourcekeywordValue"])
980 ? "YES"
981 : "NO"};
982
983 std::string l_splitLine(191, '-');
984
985 try
986 {
987 std::cout << std::left << std::setw(6)
988 << static_cast<int>(++l_slNum) << std::left
989 << std::setw(8)
990 << l_aRecordKwInfo.value("sourceRecord", "")
991 << std::left << std::setw(9)
992 << l_aRecordKwInfo.value("sourceKeyword", "")
993 << std::left << std::setw(75) << std::setfill(' ')
994 << utils::getPrintableValue(
995 l_aRecordKwInfo["destinationkeywordValue"])
996 << std::left << std::setw(75) << std::setfill(' ')
997 << utils::getPrintableValue(
998 l_aRecordKwInfo["sourcekeywordValue"])
999 << std::left << std::setw(14) << l_mismatchFound
1000 << '\n'
1001 << l_splitLine << std::endl;
1002 }
1003 catch (const std::exception& l_ex)
1004 {
1005 // TODO: Enable logging when verbose is enabled.
1006 std::cerr << l_ex.what() << std::endl;
1007 }
1008 }
1009 }
1010 }
1011
updateAllKeywords(const nlohmann::json & i_parsedJsonObj,bool i_useBackupData) const1012 int VpdTool::updateAllKeywords(const nlohmann::json& i_parsedJsonObj,
1013 bool i_useBackupData) const noexcept
1014 {
1015 int l_rc = constants::FAILURE;
1016
1017 if (i_parsedJsonObj.empty() || !i_parsedJsonObj.contains("source") ||
1018 !i_parsedJsonObj.contains("backupMap"))
1019 {
1020 // TODO: Enable logging when verbose is enabled.
1021 std::cerr << "Invalid JSON" << std::endl;
1022 return l_rc;
1023 }
1024
1025 std::string l_srcVpdPath;
1026 if (auto l_vpdPath = i_parsedJsonObj["source"].value("hardwarePath", "");
1027 !l_vpdPath.empty())
1028 {
1029 l_srcVpdPath = l_vpdPath;
1030 }
1031 else if (auto l_vpdPath =
1032 i_parsedJsonObj["source"].value("inventoryPath", "");
1033 !l_vpdPath.empty())
1034 {
1035 l_srcVpdPath = l_vpdPath;
1036 }
1037 else
1038 {
1039 // TODO: Enable logging when verbose is enabled.
1040 std::cerr << "source path information is missing in JSON" << std::endl;
1041 return l_rc;
1042 }
1043
1044 bool l_anyMismatchFound = false;
1045 for (const auto& l_aRecordKwInfo : i_parsedJsonObj["backupMap"])
1046 {
1047 if (!l_aRecordKwInfo.contains("sourceRecord") ||
1048 !l_aRecordKwInfo.contains("sourceKeyword") ||
1049 !l_aRecordKwInfo.contains("destinationkeywordValue") ||
1050 !l_aRecordKwInfo.contains("sourcekeywordValue"))
1051 {
1052 // TODO: Enable logging when verbose is enabled.
1053 std::cerr << "Missing required information in the JSON"
1054 << std::endl;
1055 continue;
1056 }
1057
1058 if (l_aRecordKwInfo["sourcekeywordValue"] !=
1059 l_aRecordKwInfo["destinationkeywordValue"])
1060 {
1061 l_anyMismatchFound = true;
1062
1063 auto l_keywordValue =
1064 i_useBackupData ? l_aRecordKwInfo["destinationkeywordValue"]
1065 : l_aRecordKwInfo["sourcekeywordValue"];
1066
1067 auto l_paramsToWrite = std::make_tuple(
1068 l_aRecordKwInfo["sourceRecord"],
1069 l_aRecordKwInfo["sourceKeyword"], l_keywordValue);
1070
1071 try
1072 {
1073 l_rc = utils::writeKeyword(l_srcVpdPath, l_paramsToWrite);
1074 if (l_rc > 0)
1075 {
1076 l_rc = constants::SUCCESS;
1077 }
1078 }
1079 catch (const std::exception& l_ex)
1080 {
1081 // TODO: Enable logging when verbose is enabled.
1082 std::cerr << "write keyword failed for record: "
1083 << l_aRecordKwInfo["sourceRecord"]
1084 << ", keyword: " << l_aRecordKwInfo["sourceKeyword"]
1085 << ", error: " << l_ex.what() << std::ends;
1086 }
1087 }
1088 }
1089
1090 std::string l_dataUsed =
1091 (i_useBackupData ? "data from backup" : "data from primary VPD");
1092 if (l_anyMismatchFound)
1093 {
1094 std::cout << "Data updated successfully for all mismatching "
1095 "record-keyword pairs by choosing their corresponding "
1096 << l_dataUsed << ". Exit successfully." << std::endl;
1097 }
1098 else
1099 {
1100 std::cout << "No mismatch found for any of the above mentioned "
1101 "record-keyword pair. Exit successfully."
1102 << std::endl;
1103 }
1104
1105 return l_rc;
1106 }
1107
handleMoreOption(const nlohmann::json & i_parsedJsonObj) const1108 int VpdTool::handleMoreOption(
1109 const nlohmann::json& i_parsedJsonObj) const noexcept
1110 {
1111 int l_rc = constants::FAILURE;
1112
1113 try
1114 {
1115 if (i_parsedJsonObj.empty() || !i_parsedJsonObj.contains("backupMap"))
1116 {
1117 throw std::runtime_error("Invalid JSON");
1118 }
1119
1120 std::string l_srcVpdPath;
1121
1122 if (auto l_vpdPath =
1123 i_parsedJsonObj["source"].value("hardwarePath", "");
1124 !l_vpdPath.empty())
1125 {
1126 l_srcVpdPath = l_vpdPath;
1127 }
1128 else if (auto l_vpdPath =
1129 i_parsedJsonObj["source"].value("inventoryPath", "");
1130 !l_vpdPath.empty())
1131 {
1132 l_srcVpdPath = l_vpdPath;
1133 }
1134 else
1135 {
1136 throw std::runtime_error(
1137 "source path information is missing in JSON");
1138 }
1139
1140 auto updateKeywordValue =
1141 [](std::string io_vpdPath, const std::string& i_recordName,
1142 const std::string& i_keywordName,
1143 const types::BinaryVector& i_keywordValue) -> int {
1144 int l_rc = constants::FAILURE;
1145
1146 try
1147 {
1148 auto l_paramsToWrite = std::make_tuple(
1149 i_recordName, i_keywordName, i_keywordValue);
1150 l_rc = utils::writeKeyword(io_vpdPath, l_paramsToWrite);
1151
1152 if (l_rc > 0)
1153 {
1154 std::cout << std::endl
1155 << "Data updated successfully." << std::endl;
1156 }
1157 }
1158 catch (const std::exception& l_ex)
1159 {
1160 // TODO: Enable log when verbose is enabled.
1161 std::cerr << l_ex.what() << std::endl;
1162 }
1163 return l_rc;
1164 };
1165
1166 do
1167 {
1168 int l_slNum = 0;
1169 bool l_exit = false;
1170
1171 for (const auto& l_aRecordKwInfo : i_parsedJsonObj["backupMap"])
1172 {
1173 if (!l_aRecordKwInfo.contains("sourceRecord") ||
1174 !l_aRecordKwInfo.contains("sourceKeyword") ||
1175 !l_aRecordKwInfo.contains("destinationkeywordValue") ||
1176 !l_aRecordKwInfo.contains("sourcekeywordValue"))
1177 {
1178 // TODO: Enable logging when verbose is enabled.
1179 std::cerr
1180 << "Source or destination information is missing in the JSON."
1181 << std::endl;
1182 continue;
1183 }
1184
1185 const std::string l_mismatchFound{
1186 (l_aRecordKwInfo["sourcekeywordValue"] !=
1187 l_aRecordKwInfo["destinationkeywordValue"])
1188 ? "YES"
1189 : "NO"};
1190
1191 std::cout << std::endl
1192 << std::left << std::setw(6) << "S.No" << std::left
1193 << std::setw(8) << "Record" << std::left
1194 << std::setw(9) << "Keyword" << std::left
1195 << std::setw(75) << std::setfill(' ') << "Backup Data"
1196 << std::left << std::setw(75) << std::setfill(' ')
1197 << "Primary Data" << std::left << std::setw(14)
1198 << "Data Mismatch" << std::endl;
1199
1200 std::cout << std::left << std::setw(6)
1201 << static_cast<int>(++l_slNum) << std::left
1202 << std::setw(8)
1203 << l_aRecordKwInfo.value("sourceRecord", "")
1204 << std::left << std::setw(9)
1205 << l_aRecordKwInfo.value("sourceKeyword", "")
1206 << std::left << std::setw(75) << std::setfill(' ')
1207 << utils::getPrintableValue(
1208 l_aRecordKwInfo["destinationkeywordValue"])
1209 << std::left << std::setw(75) << std::setfill(' ')
1210 << utils::getPrintableValue(
1211 l_aRecordKwInfo["sourcekeywordValue"])
1212 << std::left << std::setw(14) << l_mismatchFound
1213 << std::endl;
1214
1215 std::cout << std::string(191, '=') << std::endl;
1216
1217 if (constants::STR_CMP_SUCCESS ==
1218 l_mismatchFound.compare("YES"))
1219 {
1220 printFixSystemVpdOption(
1221 types::UserOption::UseBackupDataForCurrent);
1222 printFixSystemVpdOption(
1223 types::UserOption::UseSystemBackplaneDataForCurrent);
1224 printFixSystemVpdOption(types::UserOption::NewValueOnBoth);
1225 printFixSystemVpdOption(types::UserOption::SkipCurrent);
1226 printFixSystemVpdOption(types::UserOption::Exit);
1227 }
1228 else
1229 {
1230 std::cout << "No mismatch found." << std::endl << std::endl;
1231 printFixSystemVpdOption(types::UserOption::NewValueOnBoth);
1232 printFixSystemVpdOption(types::UserOption::SkipCurrent);
1233 printFixSystemVpdOption(types::UserOption::Exit);
1234 }
1235
1236 int l_userSelectedOption = types::UserOption::Exit;
1237 std::cin >> l_userSelectedOption;
1238
1239 if (types::UserOption::UseBackupDataForCurrent ==
1240 l_userSelectedOption)
1241 {
1242 l_rc = updateKeywordValue(
1243 l_srcVpdPath, l_aRecordKwInfo["sourceRecord"],
1244 l_aRecordKwInfo["sourceKeyword"],
1245 l_aRecordKwInfo["destinationkeywordValue"]);
1246 }
1247 else if (types::UserOption::UseSystemBackplaneDataForCurrent ==
1248 l_userSelectedOption)
1249 {
1250 l_rc = updateKeywordValue(
1251 l_srcVpdPath, l_aRecordKwInfo["sourceRecord"],
1252 l_aRecordKwInfo["sourceKeyword"],
1253 l_aRecordKwInfo["sourcekeywordValue"]);
1254 }
1255 else if (types::UserOption::NewValueOnBoth ==
1256 l_userSelectedOption)
1257 {
1258 std::string l_newValue;
1259 std::cout
1260 << std::endl
1261 << "Enter the new value to update on both "
1262 "primary & backup. Value should be in ASCII or "
1263 "in HEX(prefixed with 0x) : ";
1264 std::cin >> l_newValue;
1265 std::cout << std::endl
1266 << std::string(191, '=') << std::endl;
1267
1268 try
1269 {
1270 l_rc = updateKeywordValue(
1271 l_srcVpdPath, l_aRecordKwInfo["sourceRecord"],
1272 l_aRecordKwInfo["sourceKeyword"],
1273 utils::convertToBinary(l_newValue));
1274 }
1275 catch (const std::exception& l_ex)
1276 {
1277 // TODO: Enable logging when verbose is enabled.
1278 std::cerr << l_ex.what() << std::endl;
1279 }
1280 }
1281 else if (types::UserOption::SkipCurrent == l_userSelectedOption)
1282 {
1283 std::cout << std::endl
1284 << "Skipped the above record-keyword pair. "
1285 "Continue to the next available pair."
1286 << std::endl;
1287 }
1288 else if (types::UserOption::Exit == l_userSelectedOption)
1289 {
1290 std::cout << "Exit successfully" << std::endl;
1291 l_exit = true;
1292 break;
1293 }
1294 else
1295 {
1296 std::cout << "Provide a valid option. Retrying for the "
1297 "current record-keyword pair"
1298 << std::endl;
1299 }
1300 }
1301 if (l_exit)
1302 {
1303 l_rc = constants::SUCCESS;
1304 break;
1305 }
1306 } while (true);
1307 }
1308 catch (const std::exception& l_ex)
1309 {
1310 // TODO: Enable logging when verbose is enabled.
1311 std::cerr << l_ex.what() << std::endl;
1312 }
1313
1314 return l_rc;
1315 }
1316
resetVpdOnDbus()1317 int VpdTool::resetVpdOnDbus()
1318 {
1319 // ToDo: Limit this function to lab mode only.
1320
1321 int l_rc = constants::FAILURE;
1322 try
1323 {
1324 std::string l_vpdManagerStopCmd(
1325 "systemctl stop " + std::string(constants::vpdManagerProcessName));
1326
1327 std::cout << std::flush;
1328 if (auto l_rc = std::system(l_vpdManagerStopCmd.c_str()); l_rc != 0)
1329 {
1330 std::cerr << "Failed to stop " << constants::vpdManagerProcessName
1331 << " service. Return code [" << l_rc << "]. Exiting."
1332 << std::endl;
1333 return l_rc;
1334 }
1335
1336 std::string l_vpdServiceIsActiveCmd(
1337 "systemctl is-active --quiet " +
1338 std::string(constants::vpdManagerProcessName));
1339
1340 std::cout << std::flush;
1341 if (auto l_rc = std::system(l_vpdServiceIsActiveCmd.c_str()); l_rc == 0)
1342 {
1343 std::cerr
1344 << constants::vpdManagerProcessName
1345 << " service is still active, can't proceed further. Return code ["
1346 << l_rc << "]. Exiting." << std::endl;
1347 return l_rc;
1348 }
1349
1350 std::error_code l_ec;
1351 if (static_cast<std::uintmax_t>(-1) ==
1352 std::filesystem::remove_all(constants::pimPersistPath, l_ec))
1353 {
1354 std::cerr
1355 << "Error occured while removing the persisted VPD under path ["
1356 << constants::pimPersistPath << "]." << std::endl;
1357
1358 if (l_ec)
1359 {
1360 std::cerr << "Reason: " << l_ec.message() << std::endl;
1361 }
1362
1363 std::cerr << "Reboot BMC to recover the system." << std::endl;
1364 return l_rc;
1365 }
1366
1367 std::string l_pimServiceRestartCmd(
1368 "systemctl restart " +
1369 std::string(constants::inventoryManagerService));
1370
1371 std::cout << std::flush;
1372 if (auto l_rc = std::system(l_pimServiceRestartCmd.c_str()); l_rc != 0)
1373 {
1374 std::cerr << "Failed to restart "
1375 << constants::inventoryManagerService
1376 << " service. Return code [" << l_rc << "]. Exiting."
1377 << std::endl
1378 << "Reboot BMC to recover the system." << std::endl;
1379 return l_rc;
1380 }
1381
1382 std::string l_pimServiceIsActiveCmd(
1383 "systemctl is-active --quiet " +
1384 std::string(constants::inventoryManagerService));
1385
1386 std::cout << std::flush;
1387 if (auto l_rc = std::system(l_pimServiceIsActiveCmd.c_str()); l_rc != 0)
1388 {
1389 std::cerr << constants::inventoryManagerService
1390 << " service is not active. Return code [" << l_rc
1391 << "]. Exiting." << std::endl
1392 << "Reboot BMC to recover the system." << std::endl;
1393 return l_rc;
1394 }
1395
1396 std::string l_vpdManagerStartCmd(
1397 "systemctl start " + std::string(constants::vpdManagerProcessName));
1398
1399 std::cout << std::flush;
1400 if (auto l_rc = std::system(l_vpdManagerStartCmd.c_str()); l_rc != 0)
1401 {
1402 std::cerr << "Failed to start " << constants::vpdManagerProcessName
1403 << " service. Return code [" << l_rc << "]. Exiting."
1404 << std::endl
1405 << "Reboot BMC to recover the system." << std::endl;
1406 return l_rc;
1407 }
1408
1409 std::cout << std::flush;
1410 if (auto l_rc = std::system(l_vpdServiceIsActiveCmd.c_str()); l_rc != 0)
1411 {
1412 std::cerr << constants::vpdManagerProcessName
1413 << " service is not active. Return code [" << l_rc
1414 << "]. Exiting." << std::endl
1415 << "Reboot BMC to recover the system." << std::endl;
1416 return l_rc;
1417 }
1418
1419 l_rc = constants::SUCCESS;
1420 }
1421 catch (const std::exception& l_ex)
1422 {
1423 // TODO: Enable logging when verbose is enabled.
1424 std::cerr << l_ex.what() << std::endl;
1425 }
1426
1427 return l_rc;
1428 }
1429
getVpdValueInBiosConfigManager(const std::string & i_recordName,const std::string & i_keywordName) const1430 types::BinaryVector VpdTool::getVpdValueInBiosConfigManager(
1431 [[maybe_unused]] const std::string& i_recordName,
1432 [[maybe_unused]] const std::string& i_keywordName) const
1433 {
1434 types::BinaryVector l_result;
1435 // TODO: Use Record name, Keyword name to identify BIOS attribute.
1436 // Get BIOS attribute value from BIOS Config Manager.
1437 // Convert BIOS attribute value to VPD format value in binary.
1438 return l_result;
1439 }
1440 } // namespace vpd
1441