blob: fa8c3fc04d5afbdaa0b9204339c5ac00f82e8a85 [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#pragma once
2
3#include "config.h"
4
5#include "constants.hpp"
Rekha Aparnaa5be7222025-09-01 00:42:22 -05006#include "error_codes.hpp"
Souvik Roy815c6022025-02-20 00:54:24 -06007#include "event_logger.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05008#include "exceptions.hpp"
9#include "logger.hpp"
10#include "types.hpp"
11
12#include <nlohmann/json.hpp>
13#include <utility/common_utility.hpp>
14#include <utility/dbus_utility.hpp>
15
16#include <filesystem>
17#include <fstream>
18#include <regex>
Souvik Roy815c6022025-02-20 00:54:24 -060019#include <typeindex>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050020
21namespace vpd
22{
23namespace vpdSpecificUtility
24{
25/**
26 * @brief API to generate file name for bad VPD.
27 *
28 * For i2c eeproms - the pattern of the vpd-name will be
29 * i2c-<bus-number>-<eeprom-address>.
30 * For spi eeproms - the pattern of the vpd-name will be spi-<spi-number>.
31 *
Souvik Roy8fc12522025-02-19 01:28:38 -060032 * @param[in] i_vpdFilePath - file path of the vpd.
33 *
34 * @return On success, returns generated file name, otherwise returns empty
35 * string.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050036 */
Souvik Roy8fc12522025-02-19 01:28:38 -060037inline std::string generateBadVPDFileName(
38 const std::string& i_vpdFilePath) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050039{
Souvik Roy0f370432025-04-08 01:55:58 -050040 std::string l_badVpdFileName{constants::badVpdDir};
Souvik Roy8fc12522025-02-19 01:28:38 -060041 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050042 {
Souvik Roy8fc12522025-02-19 01:28:38 -060043 if (i_vpdFilePath.find("i2c") != std::string::npos)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050044 {
Souvik Roy8fc12522025-02-19 01:28:38 -060045 l_badVpdFileName += "i2c-";
46 std::regex l_i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
47 std::smatch l_match;
48 if (std::regex_search(i_vpdFilePath, l_match, l_i2cPattern))
49 {
50 l_badVpdFileName += l_match.str(2);
51 }
52 }
53 else if (i_vpdFilePath.find("spi") != std::string::npos)
54 {
55 std::regex l_spiPattern("((spi)[0-9]+)(.0)");
56 std::smatch l_match;
57 if (std::regex_search(i_vpdFilePath, l_match, l_spiPattern))
58 {
59 l_badVpdFileName += l_match.str(1);
60 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050061 }
62 }
Souvik Roy8fc12522025-02-19 01:28:38 -060063 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050064 {
Souvik Roy8fc12522025-02-19 01:28:38 -060065 l_badVpdFileName.clear();
66 logging::logMessage("Failed to generate bad VPD file name for [" +
67 i_vpdFilePath + "]. Error: " + l_ex.what());
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050068 }
Souvik Roy8fc12522025-02-19 01:28:38 -060069 return l_badVpdFileName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050070}
71
72/**
73 * @brief API which dumps the broken/bad vpd in a directory.
74 * When the vpd is bad, this API places the bad vpd file inside
Souvik Roy0f370432025-04-08 01:55:58 -050075 * "/var/lib/vpd/dumps" in BMC, in order to collect bad VPD data as a part of
76 * user initiated BMC dump.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050077 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050078 *
Souvik Roy8fc12522025-02-19 01:28:38 -060079 * @param[in] i_vpdFilePath - vpd file path
80 * @param[in] i_vpdVector - vpd vector
81 *
82 * @return On success returns 0, otherwise returns -1.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050083 */
Souvik Roy8fc12522025-02-19 01:28:38 -060084inline int dumpBadVpd(const std::string& i_vpdFilePath,
85 const types::BinaryVector& i_vpdVector) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050086{
Souvik Roy8fc12522025-02-19 01:28:38 -060087 int l_rc{constants::FAILURE};
88 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050089 {
Souvik Roy0f370432025-04-08 01:55:58 -050090 std::filesystem::create_directory(constants::badVpdDir);
Souvik Roy8fc12522025-02-19 01:28:38 -060091 auto l_badVpdPath = generateBadVPDFileName(i_vpdFilePath);
92
93 if (l_badVpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050094 {
Souvik Roy8fc12522025-02-19 01:28:38 -060095 throw std::runtime_error("Failed to generate bad VPD file name");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050096 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050097
Souvik Roy8fc12522025-02-19 01:28:38 -060098 if (std::filesystem::exists(l_badVpdPath))
99 {
100 std::error_code l_ec;
101 std::filesystem::remove(l_badVpdPath, l_ec);
102 if (l_ec) // error code
103 {
104 const std::string l_errorMsg{
105 "Error removing the existing broken vpd in " +
106 l_badVpdPath +
107 ". Error code : " + std::to_string(l_ec.value()) +
108 ". Error message : " + l_ec.message()};
109
110 throw std::runtime_error(l_errorMsg);
111 }
112 }
113
114 std::ofstream l_badVpdFileStream(l_badVpdPath, std::ofstream::binary);
115 if (!l_badVpdFileStream.is_open())
116 {
Souvik Roy0f370432025-04-08 01:55:58 -0500117 const std::string l_errorMsg{
118 "Failed to open bad vpd file path [" + l_badVpdPath +
119 "]. Unable to dump the broken/bad vpd file."};
120
121 throw std::runtime_error(l_errorMsg);
Souvik Roy8fc12522025-02-19 01:28:38 -0600122 }
123
124 l_badVpdFileStream.write(
125 reinterpret_cast<const char*>(i_vpdVector.data()),
126 i_vpdVector.size());
127
128 l_rc = constants::SUCCESS;
129 }
130 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500131 {
Souvik Roy8fc12522025-02-19 01:28:38 -0600132 logging::logMessage("Failed to dump bad VPD for [" + i_vpdFilePath +
133 "]. Error: " + l_ex.what());
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500134 }
Souvik Roy8fc12522025-02-19 01:28:38 -0600135 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500136}
137
138/**
139 * @brief An API to read value of a keyword.
140 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500141 *
Souvik Roya55fcca2025-02-19 01:33:58 -0600142 * @param[in] i_kwdValueMap - A map having Kwd value pair.
143 * @param[in] i_kwd - keyword name.
144 *
145 * @return On success returns value of the keyword read from map, otherwise
146 * returns empty string.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500147 */
Souvik Roya55fcca2025-02-19 01:33:58 -0600148inline std::string getKwVal(const types::IPZKwdValueMap& i_kwdValueMap,
149 const std::string& i_kwd) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500150{
Souvik Roya55fcca2025-02-19 01:33:58 -0600151 std::string l_kwdValue;
152 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500153 {
Souvik Roya55fcca2025-02-19 01:33:58 -0600154 if (i_kwd.empty())
155 {
156 throw std::runtime_error("Invalid parameters");
157 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500158
Souvik Roya55fcca2025-02-19 01:33:58 -0600159 auto l_itrToKwd = i_kwdValueMap.find(i_kwd);
160 if (l_itrToKwd != i_kwdValueMap.end())
161 {
162 l_kwdValue = l_itrToKwd->second;
163 }
164 else
165 {
166 throw std::runtime_error("Keyword not found");
167 }
168 }
169 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500170 {
Souvik Roya55fcca2025-02-19 01:33:58 -0600171 logging::logMessage("Failed to get value for keyword [" + i_kwd +
172 "]. Error : " + l_ex.what());
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500173 }
Souvik Roya55fcca2025-02-19 01:33:58 -0600174 return l_kwdValue;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500175}
176
177/**
178 * @brief An API to process encoding of a keyword.
179 *
Souvik Royf277d6a2025-02-20 00:08:43 -0600180 * @param[in] i_keyword - Keyword to be processed.
181 * @param[in] i_encoding - Type of encoding.
182 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500183 * @return Value after being processed for encoded type.
184 */
Souvik Royf277d6a2025-02-20 00:08:43 -0600185inline std::string encodeKeyword(const std::string& i_keyword,
186 const std::string& i_encoding) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500187{
188 // Default value is keyword value
Souvik Royf277d6a2025-02-20 00:08:43 -0600189 std::string l_result(i_keyword.begin(), i_keyword.end());
190 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500191 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600192 if (i_encoding == "MAC")
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500193 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600194 l_result.clear();
195 size_t l_firstByte = i_keyword[0];
Rekha Aparnabffecd92025-04-08 13:01:41 -0500196
197 auto l_hexValue = commonUtility::toHex(l_firstByte >> 4);
198
199 if (!l_hexValue)
200 {
201 throw std::runtime_error("Out of bound error");
202 }
203
204 l_result += l_hexValue;
205
206 l_hexValue = commonUtility::toHex(l_firstByte & 0x0f);
207
208 if (!l_hexValue)
209 {
210 throw std::runtime_error("Out of bound error");
211 }
212
213 l_result += l_hexValue;
214
Souvik Royf277d6a2025-02-20 00:08:43 -0600215 for (size_t i = 1; i < i_keyword.size(); ++i)
216 {
217 l_result += ":";
Rekha Aparnabffecd92025-04-08 13:01:41 -0500218
219 l_hexValue = commonUtility::toHex(i_keyword[i] >> 4);
220
221 if (!l_hexValue)
222 {
223 throw std::runtime_error("Out of bound error");
224 }
225
226 l_result += l_hexValue;
227
228 l_hexValue = commonUtility::toHex(i_keyword[i] & 0x0f);
229
230 if (!l_hexValue)
231 {
232 throw std::runtime_error("Out of bound error");
233 }
234
235 l_result += l_hexValue;
Souvik Royf277d6a2025-02-20 00:08:43 -0600236 }
237 }
238 else if (i_encoding == "DATE")
239 {
240 // Date, represent as
241 // <year>-<month>-<day> <hour>:<min>
242 l_result.clear();
243 static constexpr uint8_t skipPrefix = 3;
244
245 auto strItr = i_keyword.begin();
246 advance(strItr, skipPrefix);
247 for_each(strItr, i_keyword.end(),
248 [&l_result](size_t c) { l_result += c; });
249
250 l_result.insert(constants::BD_YEAR_END, 1, '-');
251 l_result.insert(constants::BD_MONTH_END, 1, '-');
252 l_result.insert(constants::BD_DAY_END, 1, ' ');
253 l_result.insert(constants::BD_HOUR_END, 1, ':');
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500254 }
255 }
Souvik Royf277d6a2025-02-20 00:08:43 -0600256 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500257 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600258 l_result.clear();
259 logging::logMessage("Failed to encode keyword [" + i_keyword +
260 "]. Error: " + l_ex.what());
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500261 }
262
Souvik Royf277d6a2025-02-20 00:08:43 -0600263 return l_result;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500264}
265
266/**
267 * @brief Helper function to insert or merge in map.
268 *
269 * This method checks in an interface if the given interface exists. If the
270 * interface key already exists, property map is inserted corresponding to it.
271 * If the key does'nt exist then given interface and property map pair is newly
272 * created. If the property present in propertymap already exist in the
273 * InterfaceMap, then the new property value is ignored.
274 *
Souvik Royfa47e6c2025-02-20 00:17:25 -0600275 * @param[in,out] io_map - Interface map.
276 * @param[in] i_interface - Interface to be processed.
277 * @param[in] i_propertyMap - new property map that needs to be emplaced.
278 *
279 * @return On success returns 0, otherwise returns -1.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500280 */
Souvik Royfa47e6c2025-02-20 00:17:25 -0600281inline int insertOrMerge(types::InterfaceMap& io_map,
282 const std::string& i_interface,
283 types::PropertyMap&& i_propertyMap) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500284{
Souvik Royfa47e6c2025-02-20 00:17:25 -0600285 int l_rc{constants::FAILURE};
286 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500287 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600288 if (io_map.find(i_interface) != io_map.end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500289 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600290 auto& l_prop = io_map.at(i_interface);
291 std::for_each(i_propertyMap.begin(), i_propertyMap.end(),
292 [&l_prop](auto l_keyValue) {
293 l_prop[l_keyValue.first] = l_keyValue.second;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500294 });
295 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600296 else
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500297 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600298 io_map.emplace(i_interface, i_propertyMap);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500299 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600300
301 l_rc = constants::SUCCESS;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500302 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600303 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500304 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600305 // ToDo:: Log PEL
306 logging::logMessage(
307 "Inserting properties into interface[" + i_interface +
308 "] map failed, reason: " + std::string(l_ex.what()));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500309 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600310 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500311}
312
313/**
314 * @brief API to expand unpanded location code.
315 *
316 * Note: The API handles all the exception internally, in case of any error
317 * unexpanded location code will be returned as it is.
318 *
319 * @param[in] unexpandedLocationCode - Unexpanded location code.
320 * @param[in] parsedVpdMap - Parsed VPD map.
321 * @return Expanded location code. In case of any error, unexpanded is returned
322 * as it is.
323 */
Patrick Williams43fedab2025-02-03 14:28:05 -0500324inline std::string getExpandedLocationCode(
325 const std::string& unexpandedLocationCode,
326 const types::VPDMapVariant& parsedVpdMap)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500327{
328 auto expanded{unexpandedLocationCode};
329
330 try
331 {
332 // Expanded location code is formed by combining two keywords
333 // depending on type in unexpanded one. Second one is always "SE".
334 std::string kwd1, kwd2{constants::kwdSE};
335
336 // interface to search for required keywords;
337 std::string kwdInterface;
338
339 // record which holds the required keywords.
340 std::string recordName;
341
342 auto pos = unexpandedLocationCode.find("fcs");
343 if (pos != std::string::npos)
344 {
345 kwd1 = constants::kwdFC;
346 kwdInterface = constants::vcenInf;
347 recordName = constants::recVCEN;
348 }
349 else
350 {
351 pos = unexpandedLocationCode.find("mts");
352 if (pos != std::string::npos)
353 {
354 kwd1 = constants::kwdTM;
355 kwdInterface = constants::vsysInf;
356 recordName = constants::recVSYS;
357 }
358 else
359 {
360 throw std::runtime_error(
361 "Error detecting type of unexpanded location code.");
362 }
363 }
364
365 std::string firstKwdValue, secondKwdValue;
366
367 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap);
368 ipzVpdMap && (*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
369 {
370 auto itrToVCEN = (*ipzVpdMap).find(recordName);
Souvik Roya55fcca2025-02-19 01:33:58 -0600371 firstKwdValue = getKwVal(itrToVCEN->second, kwd1);
372 if (firstKwdValue.empty())
373 {
374 throw std::runtime_error(
375 "Failed to get value for keyword [" + kwd1 + "]");
376 }
377
378 secondKwdValue = getKwVal(itrToVCEN->second, kwd2);
379 if (secondKwdValue.empty())
380 {
381 throw std::runtime_error(
382 "Failed to get value for keyword [" + kwd2 + "]");
383 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500384 }
385 else
386 {
387 std::array<const char*, 1> interfaceList = {kwdInterface.c_str()};
388
389 types::MapperGetObject mapperRetValue = dbusUtility::getObjectMap(
390 std::string(constants::systemVpdInvPath), interfaceList);
391
392 if (mapperRetValue.empty())
393 {
394 throw std::runtime_error("Mapper failed to get service");
395 }
396
397 const std::string& serviceName = std::get<0>(mapperRetValue.at(0));
398
399 auto retVal = dbusUtility::readDbusProperty(
400 serviceName, std::string(constants::systemVpdInvPath),
401 kwdInterface, kwd1);
402
403 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
404 {
405 firstKwdValue.assign(
406 reinterpret_cast<const char*>(kwdVal->data()),
407 kwdVal->size());
408 }
409 else
410 {
411 throw std::runtime_error(
412 "Failed to read value of " + kwd1 + " from Bus");
413 }
414
415 retVal = dbusUtility::readDbusProperty(
416 serviceName, std::string(constants::systemVpdInvPath),
417 kwdInterface, kwd2);
418
419 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
420 {
421 secondKwdValue.assign(
422 reinterpret_cast<const char*>(kwdVal->data()),
423 kwdVal->size());
424 }
425 else
426 {
427 throw std::runtime_error(
428 "Failed to read value of " + kwd2 + " from Bus");
429 }
430 }
431
432 if (unexpandedLocationCode.find("fcs") != std::string::npos)
433 {
434 // TODO: See if ND0 can be placed in the JSON
435 expanded.replace(
436 pos, 3, firstKwdValue.substr(0, 4) + ".ND0." + secondKwdValue);
437 }
438 else
439 {
440 replace(firstKwdValue.begin(), firstKwdValue.end(), '-', '.');
441 expanded.replace(pos, 3, firstKwdValue + "." + secondKwdValue);
442 }
443 }
444 catch (const std::exception& ex)
445 {
446 logging::logMessage("Failed to expand location code with exception: " +
447 std::string(ex.what()));
448 }
449
450 return expanded;
451}
452
453/**
454 * @brief An API to get VPD in a vector.
455 *
456 * The vector is required by the respective parser to fill the VPD map.
457 * Note: API throws exception in case of failure. Caller needs to handle.
458 *
459 * @param[in] vpdFilePath - EEPROM path of the FRU.
460 * @param[out] vpdVector - VPD in vector form.
461 * @param[in] vpdStartOffset - Offset of VPD data in EEPROM.
462 */
463inline void getVpdDataInVector(const std::string& vpdFilePath,
464 types::BinaryVector& vpdVector,
465 size_t& vpdStartOffset)
466{
467 try
468 {
469 std::fstream vpdFileStream;
470 vpdFileStream.exceptions(
471 std::ifstream::badbit | std::ifstream::failbit);
472 vpdFileStream.open(vpdFilePath, std::ios::in | std::ios::binary);
473 auto vpdSizeToRead = std::min(std::filesystem::file_size(vpdFilePath),
474 static_cast<uintmax_t>(65504));
475 vpdVector.resize(vpdSizeToRead);
476
477 vpdFileStream.seekg(vpdStartOffset, std::ios_base::beg);
478 vpdFileStream.read(reinterpret_cast<char*>(&vpdVector[0]),
479 vpdSizeToRead);
480
481 vpdVector.resize(vpdFileStream.gcount());
482 vpdFileStream.clear(std::ios_base::eofbit);
483 }
484 catch (const std::ifstream::failure& fail)
485 {
486 std::cerr << "Exception in file handling [" << vpdFilePath
487 << "] error : " << fail.what();
488 throw;
489 }
490}
491
492/**
493 * @brief An API to get D-bus representation of given VPD keyword.
494 *
495 * @param[in] i_keywordName - VPD keyword name.
496 *
497 * @return D-bus representation of given keyword.
498 */
499inline std::string getDbusPropNameForGivenKw(const std::string& i_keywordName)
500{
501 // Check for "#" prefixed VPD keyword.
502 if ((i_keywordName.size() == vpd::constants::TWO_BYTES) &&
503 (i_keywordName.at(0) == constants::POUND_KW))
504 {
505 // D-bus doesn't support "#". Replace "#" with "PD_" for those "#"
506 // prefixed keywords.
507 return (std::string(constants::POUND_KW_PREFIX) +
508 i_keywordName.substr(1));
509 }
510
511 // Return the keyword name back, if D-bus representation is same as the VPD
512 // keyword name.
513 return i_keywordName;
514}
515
516/**
517 * @brief API to find CCIN in parsed VPD map.
518 *
519 * Few FRUs need some special handling. To identify those FRUs CCIN are used.
520 * The API will check from parsed VPD map if the FRU is the one with desired
521 * CCIN.
522 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500523 * @param[in] i_JsonObject - Any JSON which contains CCIN tag to match.
524 * @param[in] i_parsedVpdMap - Parsed VPD map.
Souvik Roy815c6022025-02-20 00:54:24 -0600525 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500526 * @return True if found, false otherwise.
527 */
528inline bool findCcinInVpd(const nlohmann::json& i_JsonObject,
Souvik Roy815c6022025-02-20 00:54:24 -0600529 const types::VPDMapVariant& i_parsedVpdMap) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500530{
Souvik Roy815c6022025-02-20 00:54:24 -0600531 bool l_rc{false};
532 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500533 {
Souvik Roy815c6022025-02-20 00:54:24 -0600534 if (i_JsonObject.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500535 {
Souvik Roy815c6022025-02-20 00:54:24 -0600536 throw std::runtime_error("Json object is empty. Can't find CCIN");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500537 }
538
Souvik Roy815c6022025-02-20 00:54:24 -0600539 if (auto l_ipzVPDMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500540 {
Souvik Roy815c6022025-02-20 00:54:24 -0600541 auto l_itrToRec = (*l_ipzVPDMap).find("VINI");
542 if (l_itrToRec == (*l_ipzVPDMap).end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500543 {
Souvik Roy815c6022025-02-20 00:54:24 -0600544 throw DataException(
545 "VINI record not found in parsed VPD. Can't find CCIN");
546 }
547
Souvik Roya55fcca2025-02-19 01:33:58 -0600548 std::string l_ccinFromVpd{
549 vpdSpecificUtility::getKwVal(l_itrToRec->second, "CC")};
Souvik Roy815c6022025-02-20 00:54:24 -0600550 if (l_ccinFromVpd.empty())
551 {
552 throw DataException(
553 "Empty CCIN value in VPD map. Can't find CCIN");
554 }
555
556 transform(l_ccinFromVpd.begin(), l_ccinFromVpd.end(),
557 l_ccinFromVpd.begin(), ::toupper);
558
559 for (std::string l_ccinValue : i_JsonObject["ccin"])
560 {
561 transform(l_ccinValue.begin(), l_ccinValue.end(),
562 l_ccinValue.begin(), ::toupper);
563
564 if (l_ccinValue.compare(l_ccinFromVpd) ==
565 constants::STR_CMP_SUCCESS)
566 {
567 // CCIN found
568 l_rc = true;
569 }
570 }
571
572 if (!l_rc)
573 {
574 logging::logMessage("No match found for CCIN");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500575 }
576 }
Souvik Roy815c6022025-02-20 00:54:24 -0600577 else
578 {
579 logging::logMessage("VPD type not supported. Can't find CCIN");
580 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500581 }
Souvik Roy815c6022025-02-20 00:54:24 -0600582 catch (const std::exception& l_ex)
583 {
584 const std::string l_errMsg{
585 "Failed to find CCIN in VPD. Error : " + std::string(l_ex.what())};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500586
Souvik Roy815c6022025-02-20 00:54:24 -0600587 if (typeid(l_ex) == std::type_index(typeid(DataException)))
588 {
589 EventLogger::createSyncPel(
590 types::ErrorType::InvalidVpdMessage,
591 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
592 l_errMsg, std::nullopt, std::nullopt, std::nullopt,
593 std::nullopt);
594 }
595
596 logging::logMessage(l_errMsg);
597 }
598 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500599}
600
601/**
602 * @brief API to reset data of a FRU populated under PIM.
603 *
604 * This API resets the data for particular interfaces of a FRU under PIM.
605 *
606 * @param[in] i_objectPath - DBus object path of the FRU.
607 * @param[in] io_interfaceMap - Interface and its properties map.
608 */
609inline void resetDataUnderPIM(const std::string& i_objectPath,
610 types::InterfaceMap& io_interfaceMap)
611{
612 try
613 {
614 std::array<const char*, 0> l_interfaces;
615 const types::MapperGetObject& l_getObjectMap =
616 dbusUtility::getObjectMap(i_objectPath, l_interfaces);
617
618 const std::vector<std::string>& l_vpdRelatedInterfaces{
619 constants::operationalStatusInf, constants::inventoryItemInf,
Anupama B Rffa488f2025-05-22 07:34:00 -0500620 constants::assetInf, constants::vpdCollectionInterface};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500621
622 for (const auto& [l_service, l_interfaceList] : l_getObjectMap)
623 {
624 if (l_service.compare(constants::pimServiceName) !=
625 constants::STR_CMP_SUCCESS)
626 {
627 continue;
628 }
629
630 for (const auto& l_interface : l_interfaceList)
631 {
632 if ((l_interface.find(constants::ipzVpdInf) !=
633 std::string::npos) ||
634 ((std::find(l_vpdRelatedInterfaces.begin(),
635 l_vpdRelatedInterfaces.end(), l_interface)) !=
636 l_vpdRelatedInterfaces.end()))
637 {
638 const types::PropertyMap& l_propertyValueMap =
639 dbusUtility::getPropertyMap(l_service, i_objectPath,
640 l_interface);
641
642 types::PropertyMap l_propertyMap;
643
644 for (const auto& l_aProperty : l_propertyValueMap)
645 {
646 const std::string& l_propertyName = l_aProperty.first;
647 const auto& l_propertyValue = l_aProperty.second;
648
649 if (std::holds_alternative<types::BinaryVector>(
650 l_propertyValue))
651 {
652 l_propertyMap.emplace(l_propertyName,
653 types::BinaryVector{});
654 }
655 else if (std::holds_alternative<std::string>(
656 l_propertyValue))
657 {
Anupama B R5cd1b2d2025-08-05 04:57:40 -0500658 if (l_propertyName.compare("Status") ==
Anupama B Rffa488f2025-05-22 07:34:00 -0500659 constants::STR_CMP_SUCCESS)
660 {
661 l_propertyMap.emplace(
662 l_propertyName,
663 constants::vpdCollectionNotStarted);
Anupama B R4c65fcd2025-09-01 08:09:00 -0500664 l_propertyMap.emplace("StartTime", 0);
665 l_propertyMap.emplace("CompletedTime", 0);
Anupama B Rffa488f2025-05-22 07:34:00 -0500666 }
667 else
668 {
669 l_propertyMap.emplace(l_propertyName,
670 std::string{});
671 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500672 }
673 else if (std::holds_alternative<bool>(l_propertyValue))
674 {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500675 if (l_propertyName.compare("Present") ==
676 constants::STR_CMP_SUCCESS)
677 {
678 l_propertyMap.emplace(l_propertyName, false);
679 }
Rekha Aparna4f722062025-05-02 03:39:32 -0500680 else if (l_propertyName.compare("Functional") ==
681 constants::STR_CMP_SUCCESS)
682 {
683 // Since FRU is not present functional property
684 // is considered as true.
685 l_propertyMap.emplace(l_propertyName, true);
686 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500687 }
688 }
689 io_interfaceMap.emplace(l_interface,
690 std::move(l_propertyMap));
691 }
692 }
693 }
694 }
695 catch (const std::exception& l_ex)
696 {
697 logging::logMessage("Failed to remove VPD for FRU: " + i_objectPath +
698 " with error: " + std::string(l_ex.what()));
699 }
700}
Sunny Srivastava78c91072025-02-05 14:09:50 +0530701
702/**
703 * @brief API to detect pass1 planar type.
704 *
705 * Based on HW version and IM keyword, This API detects is it is a pass1 planar
706 * or not.
707 *
708 * @return True if pass 1 planar, false otherwise.
709 */
Souvik Roy094a7352025-02-20 01:31:45 -0600710inline bool isPass1Planar() noexcept
Sunny Srivastava78c91072025-02-05 14:09:50 +0530711{
Souvik Roy094a7352025-02-20 01:31:45 -0600712 bool l_rc{false};
713 try
Sunny Srivastava78c91072025-02-05 14:09:50 +0530714 {
Souvik Roy094a7352025-02-20 01:31:45 -0600715 auto l_retVal = dbusUtility::readDbusProperty(
716 constants::pimServiceName, constants::systemVpdInvPath,
717 constants::viniInf, constants::kwdHW);
Sunny Srivastava78c91072025-02-05 14:09:50 +0530718
Souvik Roy094a7352025-02-20 01:31:45 -0600719 auto l_hwVer = std::get_if<types::BinaryVector>(&l_retVal);
720
721 l_retVal = dbusUtility::readDbusProperty(
722 constants::pimServiceName, constants::systemInvPath,
723 constants::vsbpInf, constants::kwdIM);
724
725 auto l_imValue = std::get_if<types::BinaryVector>(&l_retVal);
726
727 if (l_hwVer && l_imValue)
Sunny Srivastava78c91072025-02-05 14:09:50 +0530728 {
Souvik Roy094a7352025-02-20 01:31:45 -0600729 if (l_hwVer->size() != constants::VALUE_2)
Sunny Srivastava78c91072025-02-05 14:09:50 +0530730 {
Souvik Roy094a7352025-02-20 01:31:45 -0600731 throw std::runtime_error("Invalid HW keyword length.");
732 }
733
734 if (l_imValue->size() != constants::VALUE_4)
735 {
736 throw std::runtime_error("Invalid IM keyword length.");
737 }
738
739 const types::BinaryVector l_everest{80, 00, 48, 00};
740 const types::BinaryVector l_fuji{96, 00, 32, 00};
741
742 if (((*l_imValue) == l_everest) || ((*l_imValue) == l_fuji))
743 {
744 if ((*l_hwVer).at(1) < constants::VALUE_21)
745 {
746 l_rc = true;
747 }
748 }
749 else if ((*l_hwVer).at(1) < constants::VALUE_2)
750 {
751 l_rc = true;
Sunny Srivastava78c91072025-02-05 14:09:50 +0530752 }
753 }
Souvik Roy094a7352025-02-20 01:31:45 -0600754 }
755 catch (const std::exception& l_ex)
756 {
757 logging::logMessage("Failed to check for pass 1 planar. Error: " +
758 std::string(l_ex.what()));
Sunny Srivastava78c91072025-02-05 14:09:50 +0530759 }
760
Souvik Roy094a7352025-02-20 01:31:45 -0600761 return l_rc;
Sunny Srivastava78c91072025-02-05 14:09:50 +0530762}
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530763
764/**
765 * @brief API to detect if system configuration is that of PowerVS system.
766 *
767 * @param[in] i_imValue - IM value of the system.
768 * @return true if it is PowerVS configuration, false otherwise.
769 */
770inline bool isPowerVsConfiguration(const types::BinaryVector& i_imValue)
771{
772 if (i_imValue.empty() || i_imValue.size() != constants::VALUE_4)
773 {
774 return false;
775 }
776
777 // Should be a 0x5000XX series system.
778 if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
779 i_imValue.at(1) == constants::HEX_VALUE_00)
780 {
781 std::string l_imagePrefix = dbusUtility::getImagePrefix();
782
783 // Check image for 0x500030XX series.
784 if ((i_imValue.at(2) == constants::HEX_VALUE_30) &&
785 ((l_imagePrefix == constants::powerVsImagePrefix_MY) ||
786 (l_imagePrefix == constants::powerVsImagePrefix_NY)))
787 {
788 logging::logMessage("PowerVS configuration");
789 return true;
790 }
791
792 // Check image for 0X500010XX series.
793 if ((i_imValue.at(2) == constants::HEX_VALUE_10) &&
794 ((l_imagePrefix == constants::powerVsImagePrefix_MZ) ||
795 (l_imagePrefix == constants::powerVsImagePrefix_NZ)))
796 {
797 logging::logMessage("PowerVS configuration");
798 return true;
799 }
800 }
801 return false;
802}
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530803
804/**
805 * @brief API to get CCIN for a given FRU from DBus.
806 *
807 * The API reads the CCIN for a FRU based on its inventory path.
808 *
809 * @param[in] i_invObjPath - Inventory path of the FRU.
810 * @return CCIN of the FRU on success, empty string otherwise.
811 */
812inline std::string getCcinFromDbus(const std::string& i_invObjPath)
813{
814 try
815 {
816 if (i_invObjPath.empty())
817 {
818 throw std::runtime_error("Empty EEPROM path, can't read CCIN");
819 }
820
821 const auto& l_retValue = dbusUtility::readDbusProperty(
822 constants::pimServiceName, i_invObjPath, constants::viniInf,
823 constants::kwdCCIN);
824
825 auto l_ptrCcin = std::get_if<types::BinaryVector>(&l_retValue);
826 if (!l_ptrCcin || (*l_ptrCcin).size() != constants::VALUE_4)
827 {
828 throw DbusException("Invalid CCIN read from Dbus");
829 }
830
831 return std::string((*l_ptrCcin).begin(), (*l_ptrCcin).end());
832 }
833 catch (const std::exception& l_ex)
834 {
835 logging::logMessage(l_ex.what());
836 return std::string{};
837 }
838}
Sunny Srivastavaecfaa212025-03-24 13:02:13 +0530839
840/**
841 * @brief API to check if the current running image is a powerVS image.
842 *
843 * @return true if it is PowerVS image, false otherwise.
844 */
845inline bool isPowerVsImage()
846{
847 std::string l_imagePrefix = dbusUtility::getImagePrefix();
848
849 if ((l_imagePrefix == constants::powerVsImagePrefix_MY) ||
850 (l_imagePrefix == constants::powerVsImagePrefix_NY) ||
851 (l_imagePrefix == constants::powerVsImagePrefix_MZ) ||
852 (l_imagePrefix == constants::powerVsImagePrefix_NZ))
853 {
854 return true;
855 }
856 return false;
857}
Souvik Roy2ee8a212025-04-24 02:37:59 -0500858
859/**
860 * @brief API to sync keyword update to inherited FRUs.
861 *
862 * For a given keyword update on a EEPROM path, this API syncs the keyword
863 * update to all inherited FRUs' respective interface, property on PIM.
864 *
865 * @param[in] i_fruPath - EEPROM path of FRU.
866 * @param[in] i_paramsToWriteData - Input details.
867 * @param[in] i_sysCfgJsonObj - System config JSON.
868 *
869 */
870inline void updateKwdOnInheritedFrus(
871 const std::string& i_fruPath,
872 const types::WriteVpdParams& i_paramsToWriteData,
873 const nlohmann::json& i_sysCfgJsonObj) noexcept
874{
875 try
876 {
877 if (!i_sysCfgJsonObj.contains("frus"))
878 {
879 throw std::runtime_error("Mandatory tag(s) missing from JSON");
880 }
881
882 if (!i_sysCfgJsonObj["frus"].contains(i_fruPath))
883 {
884 throw std::runtime_error(
885 "VPD path [" + i_fruPath + "] not found in system config JSON");
886 }
887
888 const types::IpzData* l_ipzData =
889 std::get_if<types::IpzData>(&i_paramsToWriteData);
890
891 if (!l_ipzData)
892 {
893 throw std::runtime_error("Unsupported VPD type");
894 }
895 // iterate through all inventory paths for given EEPROM path,
896 // except the base FRU.
897 // if for an inventory path, "inherit" tag is true,
898 // update the inventory path's com.ibm.ipzvpd.<record>,keyword
899 // property
900
901 types::ObjectMap l_objectInterfaceMap;
902
903 auto l_populateInterfaceMap =
904 [&l_objectInterfaceMap,
905 &l_ipzData = std::as_const(l_ipzData)](const auto& l_Fru) {
906 // update inherited FRUs only
907 if (l_Fru.value("inherit", true))
908 {
909 l_objectInterfaceMap.emplace(
910 sdbusplus::message::object_path{l_Fru["inventoryPath"]},
911 types::InterfaceMap{
912 {std::string{constants::ipzVpdInf +
913 std::get<0>(*l_ipzData)},
914 types::PropertyMap{{std::get<1>(*l_ipzData),
915 std::get<2>(*l_ipzData)}}}});
916 }
917 };
918
919 // iterate through all FRUs except the base FRU
920 std::for_each(
921 i_sysCfgJsonObj["frus"][i_fruPath].begin() + constants::VALUE_1,
922 i_sysCfgJsonObj["frus"][i_fruPath].end(), l_populateInterfaceMap);
923
924 if (!l_objectInterfaceMap.empty())
925 {
926 // notify PIM
927 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
928 {
929 throw std::runtime_error(
930 "Call to PIM failed for VPD file " + i_fruPath);
931 }
932 }
933 }
934 catch (const std::exception& l_ex)
935 {
936 logging::logMessage(
937 "Failed to sync keyword update to inherited FRUs of FRU [" +
938 i_fruPath + "]. Error: " + std::string(l_ex.what()));
939 }
940}
Souvik Roy96ebe962025-04-29 04:01:07 -0500941
942/**
943 * @brief API to get common interface(s) properties corresponding to given
944 * record and keyword.
945 *
946 * For a given record and keyword, this API finds the corresponding common
947 * interfaces(s) properties from the system config JSON and populates an
948 * interface map with the respective properties and values.
949 *
950 * @param[in] i_paramsToWriteData - Input details.
951 * @param[in] i_commonInterfaceJson - Common interface JSON object.
952 *
953 * @return Returns a map of common interface(s) and properties corresponding to
954 * the record and keyword. An empty map is returned if no such common
955 * interface(s) and properties are found.
956 */
957inline types::InterfaceMap getCommonInterfaceProperties(
958 const types::WriteVpdParams& i_paramsToWriteData,
959 const nlohmann::json& i_commonInterfaceJson) noexcept
960{
961 types::InterfaceMap l_interfaceMap;
962 try
963 {
964 const types::IpzData* l_ipzData =
965 std::get_if<types::IpzData>(&i_paramsToWriteData);
966
967 if (!l_ipzData)
968 {
969 throw std::runtime_error("Invalid VPD type");
970 }
971
972 auto l_populateInterfaceMap = [&l_ipzData = std::as_const(l_ipzData),
973 &l_interfaceMap](
974 const auto& l_interfacesPropPair) {
Souvik Roy9654e032025-09-17 17:18:42 +0000975 if (l_interfacesPropPair.value().empty())
976 {
977 return;
978 }
979
Souvik Roy96ebe962025-04-29 04:01:07 -0500980 // find matching property value pair
981 const auto l_matchPropValuePairIt = std::find_if(
982 l_interfacesPropPair.value().items().begin(),
983 l_interfacesPropPair.value().items().end(),
984 [&l_ipzData](const auto& l_propValuePair) {
985 return (l_propValuePair.value().value("recordName", "") ==
986 std::get<0>(*l_ipzData) &&
987 l_propValuePair.value().value("keywordName", "") ==
988 std::get<1>(*l_ipzData));
989 });
990
991 if (l_matchPropValuePairIt !=
992 l_interfacesPropPair.value().items().end())
993 {
994 // add property map to interface map
995 l_interfaceMap.emplace(
996 l_interfacesPropPair.key(),
997 types::PropertyMap{
998 {l_matchPropValuePairIt.key(),
999 vpdSpecificUtility::encodeKeyword(
1000 std::string(std::get<2>(*l_ipzData).begin(),
1001 std::get<2>(*l_ipzData).end()),
1002 l_matchPropValuePairIt.value().value("encoding",
1003 ""))}});
1004 }
1005 };
1006
Sunny Srivastava89fbd2d2025-09-03 02:03:48 -05001007 if (!i_commonInterfaceJson.empty())
1008 {
1009 // iterate through all common interfaces and populate interface map
1010 std::for_each(i_commonInterfaceJson.items().begin(),
1011 i_commonInterfaceJson.items().end(),
1012 l_populateInterfaceMap);
1013 }
Souvik Roy96ebe962025-04-29 04:01:07 -05001014 }
1015 catch (const std::exception& l_ex)
1016 {
1017 logging::logMessage(
1018 "Failed to find common interface properties. Error: " +
1019 std::string(l_ex.what()));
1020 }
1021 return l_interfaceMap;
1022}
1023
1024/**
1025 * @brief API to update common interface(s) properties when keyword is updated.
1026 *
1027 * For a given keyword update on a EEPROM path, this API syncs the keyword
1028 * update to respective common interface(s) properties of the base FRU and all
1029 * inherited FRUs.
1030 *
1031 * @param[in] i_fruPath - EEPROM path of FRU.
1032 * @param[in] i_paramsToWriteData - Input details.
1033 * @param[in] i_sysCfgJsonObj - System config JSON.
1034 *
1035 */
1036inline void updateCiPropertyOfInheritedFrus(
1037 const std::string& i_fruPath,
1038 const types::WriteVpdParams& i_paramsToWriteData,
1039 const nlohmann::json& i_sysCfgJsonObj) noexcept
1040{
1041 try
1042 {
1043 if (!i_sysCfgJsonObj.contains("commonInterfaces"))
1044 {
1045 // no common interfaces in JSON, nothing to do
1046 return;
1047 }
1048
1049 if (!i_sysCfgJsonObj.contains("frus"))
1050 {
1051 throw std::runtime_error("Mandatory tag(s) missing from JSON");
1052 }
1053
1054 if (!i_sysCfgJsonObj["frus"].contains(i_fruPath))
1055 {
1056 throw std::runtime_error(
1057 "VPD path [" + i_fruPath + "] not found in system config JSON");
1058 }
1059
1060 if (!std::get_if<types::IpzData>(&i_paramsToWriteData))
1061 {
1062 throw std::runtime_error("Unsupported VPD type");
1063 }
1064
1065 // iterate through all inventory paths for given EEPROM path,
1066 // if for an inventory path, "inherit" tag is true,
1067 // update the inventory path's com.ibm.ipzvpd.<record>,keyword
1068 // property
1069
1070 types::ObjectMap l_objectInterfaceMap;
1071
1072 const types::InterfaceMap l_interfaceMap = getCommonInterfaceProperties(
1073 i_paramsToWriteData, i_sysCfgJsonObj["commonInterfaces"]);
1074
1075 if (l_interfaceMap.empty())
1076 {
1077 // nothing to do
1078 return;
1079 }
1080
1081 auto l_populateObjectInterfaceMap =
1082 [&l_objectInterfaceMap, &l_interfaceMap = std::as_const(
1083 l_interfaceMap)](const auto& l_Fru) {
1084 if (l_Fru.value("inherit", true) &&
1085 l_Fru.contains("inventoryPath"))
1086 {
1087 l_objectInterfaceMap.emplace(
1088 sdbusplus::message::object_path{l_Fru["inventoryPath"]},
1089 l_interfaceMap);
1090 }
1091 };
1092
1093 std::for_each(i_sysCfgJsonObj["frus"][i_fruPath].begin(),
1094 i_sysCfgJsonObj["frus"][i_fruPath].end(),
1095 l_populateObjectInterfaceMap);
1096
1097 if (!l_objectInterfaceMap.empty())
1098 {
1099 // notify PIM
1100 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
1101 {
1102 throw std::runtime_error(
1103 "Call to PIM failed for VPD file " + i_fruPath);
1104 }
1105 }
1106 }
1107 catch (const std::exception& l_ex)
1108 {
1109 logging::logMessage(
1110 "Failed to update common interface properties of FRU [" +
1111 i_fruPath + "]. Error: " + std::string(l_ex.what()));
1112 }
1113}
Sunny Srivastava995e1c22025-08-28 03:13:00 -05001114
1115/**
Rekha Aparnaa5be7222025-09-01 00:42:22 -05001116 * @brief API to get error code message.
1117 *
1118 * @param[in] i_errCode - error code.
1119 *
1120 * @return Error message set for that error code. Otherwise empty
1121 * string.
1122 */
1123inline std::string getErrCodeMsg(const uint16_t& i_errCode)
1124{
Sunny Srivastavaad7e25e2025-09-04 09:43:21 -05001125 if (errorCodeMap.find(i_errCode) != errorCodeMap.end())
Rekha Aparnaa5be7222025-09-01 00:42:22 -05001126 {
Sunny Srivastavaad7e25e2025-09-04 09:43:21 -05001127 return errorCodeMap.at(i_errCode);
Rekha Aparnaa5be7222025-09-01 00:42:22 -05001128 }
1129
1130 return std::string{};
1131}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001132} // namespace vpdSpecificUtility
1133} // namespace vpd