xref: /openbmc/openpower-vpd-parser/vpd-tool/src/vpd_tool.cpp (revision 844f88f984ded76c3b68fab7356a48accb88fec3)
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