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