blob: 25ae1406224508bf9d185d8dcc286505acc89459 [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#pragma once
2
3#include "config.h"
4
5#include "constants.hpp"
Souvik Roy815c6022025-02-20 00:54:24 -06006#include "event_logger.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05007#include "exceptions.hpp"
8#include "logger.hpp"
9#include "types.hpp"
10
11#include <nlohmann/json.hpp>
12#include <utility/common_utility.hpp>
13#include <utility/dbus_utility.hpp>
14
15#include <filesystem>
16#include <fstream>
17#include <regex>
Souvik Roy815c6022025-02-20 00:54:24 -060018#include <typeindex>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050019
20namespace vpd
21{
22namespace vpdSpecificUtility
23{
24/**
25 * @brief API to generate file name for bad VPD.
26 *
27 * For i2c eeproms - the pattern of the vpd-name will be
28 * i2c-<bus-number>-<eeprom-address>.
29 * For spi eeproms - the pattern of the vpd-name will be spi-<spi-number>.
30 *
Souvik Roy8fc12522025-02-19 01:28:38 -060031 * @param[in] i_vpdFilePath - file path of the vpd.
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050032 * @param[out] o_errCode - to set error code in case of error.
Souvik Roy8fc12522025-02-19 01:28:38 -060033 *
34 * @return On success, returns generated file name, otherwise returns empty
35 * string.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050036 */
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050037inline std::string generateBadVPDFileName(const std::string& i_vpdFilePath,
38 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050039{
Souvik Roy0f370432025-04-08 01:55:58 -050040 std::string l_badVpdFileName{constants::badVpdDir};
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050041
42 if (i_vpdFilePath.empty())
43 {
44 o_errCode = error_code::INVALID_INPUT_PARAMETER;
45 return l_badVpdFileName;
46 }
47
Souvik Roy8fc12522025-02-19 01:28:38 -060048 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050049 {
Souvik Roy8fc12522025-02-19 01:28:38 -060050 if (i_vpdFilePath.find("i2c") != std::string::npos)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050051 {
Souvik Roy8fc12522025-02-19 01:28:38 -060052 l_badVpdFileName += "i2c-";
53 std::regex l_i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
54 std::smatch l_match;
55 if (std::regex_search(i_vpdFilePath, l_match, l_i2cPattern))
56 {
57 l_badVpdFileName += l_match.str(2);
58 }
59 }
60 else if (i_vpdFilePath.find("spi") != std::string::npos)
61 {
62 std::regex l_spiPattern("((spi)[0-9]+)(.0)");
63 std::smatch l_match;
64 if (std::regex_search(i_vpdFilePath, l_match, l_spiPattern))
65 {
66 l_badVpdFileName += l_match.str(1);
67 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050068 }
69 }
Souvik Roy8fc12522025-02-19 01:28:38 -060070 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050071 {
Souvik Roy8fc12522025-02-19 01:28:38 -060072 l_badVpdFileName.clear();
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050073 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050074 }
Souvik Roy8fc12522025-02-19 01:28:38 -060075 return l_badVpdFileName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050076}
77
78/**
79 * @brief API which dumps the broken/bad vpd in a directory.
80 * When the vpd is bad, this API places the bad vpd file inside
Souvik Roy0f370432025-04-08 01:55:58 -050081 * "/var/lib/vpd/dumps" in BMC, in order to collect bad VPD data as a part of
82 * user initiated BMC dump.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050083 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050084 *
Souvik Roy8fc12522025-02-19 01:28:38 -060085 * @param[in] i_vpdFilePath - vpd file path
86 * @param[in] i_vpdVector - vpd vector
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050087 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy8fc12522025-02-19 01:28:38 -060088 *
89 * @return On success returns 0, otherwise returns -1.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050090 */
Souvik Roy8fc12522025-02-19 01:28:38 -060091inline int dumpBadVpd(const std::string& i_vpdFilePath,
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050092 const types::BinaryVector& i_vpdVector,
93 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050094{
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -050095 if (i_vpdFilePath.empty() || i_vpdVector.empty())
96 {
97 o_errCode = error_code::INVALID_INPUT_PARAMETER;
98 return constants::FAILURE;
99 }
100
Souvik Roy8fc12522025-02-19 01:28:38 -0600101 int l_rc{constants::FAILURE};
102 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500103 {
Souvik Roy0f370432025-04-08 01:55:58 -0500104 std::filesystem::create_directory(constants::badVpdDir);
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500105 auto l_badVpdPath = generateBadVPDFileName(i_vpdFilePath, o_errCode);
Souvik Roy8fc12522025-02-19 01:28:38 -0600106
107 if (l_badVpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500108 {
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500109 if (o_errCode)
110 {
111 logging::logMessage("Failed to create bad VPD file name : " +
112 commonUtility::getErrCodeMsg(o_errCode));
113 }
114
115 return constants::FAILURE;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500116 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500117
Souvik Roy8fc12522025-02-19 01:28:38 -0600118 if (std::filesystem::exists(l_badVpdPath))
119 {
120 std::error_code l_ec;
121 std::filesystem::remove(l_badVpdPath, l_ec);
122 if (l_ec) // error code
123 {
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500124 o_errCode = error_code::FILE_SYSTEM_ERROR;
125 return constants::FAILURE;
Souvik Roy8fc12522025-02-19 01:28:38 -0600126 }
127 }
128
129 std::ofstream l_badVpdFileStream(l_badVpdPath, std::ofstream::binary);
130 if (!l_badVpdFileStream.is_open())
131 {
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500132 o_errCode = error_code::FILE_ACCESS_ERROR;
133 return constants::FAILURE;
Souvik Roy8fc12522025-02-19 01:28:38 -0600134 }
135
136 l_badVpdFileStream.write(
137 reinterpret_cast<const char*>(i_vpdVector.data()),
138 i_vpdVector.size());
139
140 l_rc = constants::SUCCESS;
141 }
142 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500143 {
Rekha Aparna7f6cd4c2025-10-06 23:44:04 -0500144 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500145 }
Souvik Roy8fc12522025-02-19 01:28:38 -0600146 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500147}
148
149/**
150 * @brief An API to read value of a keyword.
151 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500152 *
Souvik Roya55fcca2025-02-19 01:33:58 -0600153 * @param[in] i_kwdValueMap - A map having Kwd value pair.
154 * @param[in] i_kwd - keyword name.
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500155 * @param[out] o_errCode - To set error code in case of error.
Souvik Roya55fcca2025-02-19 01:33:58 -0600156 *
157 * @return On success returns value of the keyword read from map, otherwise
158 * returns empty string.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500159 */
Souvik Roya55fcca2025-02-19 01:33:58 -0600160inline std::string getKwVal(const types::IPZKwdValueMap& i_kwdValueMap,
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500161 const std::string& i_kwd,
162 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500163{
Souvik Roya55fcca2025-02-19 01:33:58 -0600164 std::string l_kwdValue;
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500165 if (i_kwd.empty() || i_kwdValueMap.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500166 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500167 o_errCode = error_code::INVALID_INPUT_PARAMETER;
168 return l_kwdValue;
169 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500170
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500171 auto l_itrToKwd = i_kwdValueMap.find(i_kwd);
172 if (l_itrToKwd != i_kwdValueMap.end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500173 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500174 l_kwdValue = l_itrToKwd->second;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500175 }
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500176 else
177 {
178 o_errCode = error_code::KEYWORD_NOT_FOUND;
179 }
180
Souvik Roya55fcca2025-02-19 01:33:58 -0600181 return l_kwdValue;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500182}
183
184/**
185 * @brief An API to process encoding of a keyword.
186 *
Souvik Royf277d6a2025-02-20 00:08:43 -0600187 * @param[in] i_keyword - Keyword to be processed.
188 * @param[in] i_encoding - Type of encoding.
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500189 * @param[out] o_errCode - To set error code in case of error.
Souvik Royf277d6a2025-02-20 00:08:43 -0600190 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500191 * @return Value after being processed for encoded type.
192 */
Souvik Royf277d6a2025-02-20 00:08:43 -0600193inline std::string encodeKeyword(const std::string& i_keyword,
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500194 const std::string& i_encoding,
195 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500196{
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500197 if (i_keyword.empty())
198 {
199 o_errCode = error_code::INVALID_INPUT_PARAMETER;
200 return std::string{};
201 }
202
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500203 // Default value is keyword value
Souvik Royf277d6a2025-02-20 00:08:43 -0600204 std::string l_result(i_keyword.begin(), i_keyword.end());
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500205
206 if (i_encoding.empty())
207 {
208 return l_result;
209 }
210
Souvik Royf277d6a2025-02-20 00:08:43 -0600211 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500212 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600213 if (i_encoding == "MAC")
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500214 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600215 l_result.clear();
216 size_t l_firstByte = i_keyword[0];
Rekha Aparnabffecd92025-04-08 13:01:41 -0500217
218 auto l_hexValue = commonUtility::toHex(l_firstByte >> 4);
219
220 if (!l_hexValue)
221 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500222 o_errCode = error_code::OUT_OF_BOUND_EXCEPTION;
223 return std::string{};
Rekha Aparnabffecd92025-04-08 13:01:41 -0500224 }
225
226 l_result += l_hexValue;
227
228 l_hexValue = commonUtility::toHex(l_firstByte & 0x0f);
229
230 if (!l_hexValue)
231 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500232 o_errCode = error_code::OUT_OF_BOUND_EXCEPTION;
233 return std::string{};
Rekha Aparnabffecd92025-04-08 13:01:41 -0500234 }
235
236 l_result += l_hexValue;
237
Souvik Royf277d6a2025-02-20 00:08:43 -0600238 for (size_t i = 1; i < i_keyword.size(); ++i)
239 {
240 l_result += ":";
Rekha Aparnabffecd92025-04-08 13:01:41 -0500241
242 l_hexValue = commonUtility::toHex(i_keyword[i] >> 4);
243
244 if (!l_hexValue)
245 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500246 o_errCode = error_code::OUT_OF_BOUND_EXCEPTION;
247 return std::string{};
Rekha Aparnabffecd92025-04-08 13:01:41 -0500248 }
249
250 l_result += l_hexValue;
251
252 l_hexValue = commonUtility::toHex(i_keyword[i] & 0x0f);
253
254 if (!l_hexValue)
255 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500256 o_errCode = error_code::OUT_OF_BOUND_EXCEPTION;
257 return std::string{};
Rekha Aparnabffecd92025-04-08 13:01:41 -0500258 }
259
260 l_result += l_hexValue;
Souvik Royf277d6a2025-02-20 00:08:43 -0600261 }
262 }
263 else if (i_encoding == "DATE")
264 {
265 // Date, represent as
266 // <year>-<month>-<day> <hour>:<min>
267 l_result.clear();
268 static constexpr uint8_t skipPrefix = 3;
269
270 auto strItr = i_keyword.begin();
271 advance(strItr, skipPrefix);
272 for_each(strItr, i_keyword.end(),
273 [&l_result](size_t c) { l_result += c; });
274
275 l_result.insert(constants::BD_YEAR_END, 1, '-');
276 l_result.insert(constants::BD_MONTH_END, 1, '-');
277 l_result.insert(constants::BD_DAY_END, 1, ' ');
278 l_result.insert(constants::BD_HOUR_END, 1, ':');
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500279 }
280 }
Souvik Royf277d6a2025-02-20 00:08:43 -0600281 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500282 {
Souvik Royf277d6a2025-02-20 00:08:43 -0600283 l_result.clear();
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500284 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500285 }
286
Souvik Royf277d6a2025-02-20 00:08:43 -0600287 return l_result;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500288}
289
290/**
291 * @brief Helper function to insert or merge in map.
292 *
293 * This method checks in an interface if the given interface exists. If the
294 * interface key already exists, property map is inserted corresponding to it.
295 * If the key does'nt exist then given interface and property map pair is newly
296 * created. If the property present in propertymap already exist in the
297 * InterfaceMap, then the new property value is ignored.
298 *
Souvik Royfa47e6c2025-02-20 00:17:25 -0600299 * @param[in,out] io_map - Interface map.
300 * @param[in] i_interface - Interface to be processed.
301 * @param[in] i_propertyMap - new property map that needs to be emplaced.
Rekha Aparnad3662222025-10-14 10:33:17 -0500302 * @param[out] o_errCode - To set error code in case of error.
Souvik Royfa47e6c2025-02-20 00:17:25 -0600303 *
304 * @return On success returns 0, otherwise returns -1.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500305 */
Souvik Royfa47e6c2025-02-20 00:17:25 -0600306inline int insertOrMerge(types::InterfaceMap& io_map,
307 const std::string& i_interface,
Rekha Aparnad3662222025-10-14 10:33:17 -0500308 types::PropertyMap&& i_propertyMap,
309 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500310{
Souvik Royfa47e6c2025-02-20 00:17:25 -0600311 int l_rc{constants::FAILURE};
Rekha Aparnad3662222025-10-14 10:33:17 -0500312
Souvik Royfa47e6c2025-02-20 00:17:25 -0600313 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500314 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600315 if (io_map.find(i_interface) != io_map.end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500316 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600317 auto& l_prop = io_map.at(i_interface);
318 std::for_each(i_propertyMap.begin(), i_propertyMap.end(),
319 [&l_prop](auto l_keyValue) {
320 l_prop[l_keyValue.first] = l_keyValue.second;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500321 });
322 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600323 else
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500324 {
Souvik Royfa47e6c2025-02-20 00:17:25 -0600325 io_map.emplace(i_interface, i_propertyMap);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500326 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600327
328 l_rc = constants::SUCCESS;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500329 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600330 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500331 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500332 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500333 }
Souvik Royfa47e6c2025-02-20 00:17:25 -0600334 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500335}
336
337/**
338 * @brief API to expand unpanded location code.
339 *
340 * Note: The API handles all the exception internally, in case of any error
341 * unexpanded location code will be returned as it is.
342 *
343 * @param[in] unexpandedLocationCode - Unexpanded location code.
344 * @param[in] parsedVpdMap - Parsed VPD map.
Rekha Aparna6256db92025-10-17 09:58:49 -0500345 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500346 * @return Expanded location code. In case of any error, unexpanded is returned
347 * as it is.
348 */
Patrick Williams43fedab2025-02-03 14:28:05 -0500349inline std::string getExpandedLocationCode(
350 const std::string& unexpandedLocationCode,
Rekha Aparna6256db92025-10-17 09:58:49 -0500351 const types::VPDMapVariant& parsedVpdMap, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500352{
Rekha Aparna6256db92025-10-17 09:58:49 -0500353 if (unexpandedLocationCode.empty() ||
354 std::holds_alternative<std::monostate>(parsedVpdMap))
355 {
356 o_errCode = error_code::INVALID_INPUT_PARAMETER;
357 return unexpandedLocationCode;
358 }
359
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500360 auto expanded{unexpandedLocationCode};
361
362 try
363 {
364 // Expanded location code is formed by combining two keywords
365 // depending on type in unexpanded one. Second one is always "SE".
366 std::string kwd1, kwd2{constants::kwdSE};
367
368 // interface to search for required keywords;
369 std::string kwdInterface;
370
371 // record which holds the required keywords.
372 std::string recordName;
373
374 auto pos = unexpandedLocationCode.find("fcs");
375 if (pos != std::string::npos)
376 {
377 kwd1 = constants::kwdFC;
378 kwdInterface = constants::vcenInf;
379 recordName = constants::recVCEN;
380 }
381 else
382 {
383 pos = unexpandedLocationCode.find("mts");
384 if (pos != std::string::npos)
385 {
386 kwd1 = constants::kwdTM;
387 kwdInterface = constants::vsysInf;
388 recordName = constants::recVSYS;
389 }
390 else
391 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500392 o_errCode = error_code::FAILED_TO_DETECT_LOCATION_CODE_TYPE;
393 return expanded;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500394 }
395 }
396
397 std::string firstKwdValue, secondKwdValue;
398
399 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap);
400 ipzVpdMap && (*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
401 {
402 auto itrToVCEN = (*ipzVpdMap).find(recordName);
Rekha Aparna6256db92025-10-17 09:58:49 -0500403 firstKwdValue = getKwVal(itrToVCEN->second, kwd1, o_errCode);
Souvik Roya55fcca2025-02-19 01:33:58 -0600404 if (firstKwdValue.empty())
405 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500406 o_errCode = error_code::KEYWORD_NOT_FOUND;
407 return expanded;
Souvik Roya55fcca2025-02-19 01:33:58 -0600408 }
409
Rekha Aparna6256db92025-10-17 09:58:49 -0500410 secondKwdValue = getKwVal(itrToVCEN->second, kwd2, o_errCode);
Souvik Roya55fcca2025-02-19 01:33:58 -0600411 if (secondKwdValue.empty())
412 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500413 o_errCode = error_code::KEYWORD_NOT_FOUND;
414 return expanded;
Souvik Roya55fcca2025-02-19 01:33:58 -0600415 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500416 }
417 else
418 {
Anupama B R68a70432025-09-25 02:09:37 -0500419 std::vector<std::string> interfaceList = {kwdInterface};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500420
421 types::MapperGetObject mapperRetValue = dbusUtility::getObjectMap(
422 std::string(constants::systemVpdInvPath), interfaceList);
423
424 if (mapperRetValue.empty())
425 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500426 o_errCode = error_code::DBUS_FAILURE;
427 return expanded;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500428 }
429
430 const std::string& serviceName = std::get<0>(mapperRetValue.at(0));
431
432 auto retVal = dbusUtility::readDbusProperty(
433 serviceName, std::string(constants::systemVpdInvPath),
434 kwdInterface, kwd1);
435
436 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
437 {
438 firstKwdValue.assign(
439 reinterpret_cast<const char*>(kwdVal->data()),
440 kwdVal->size());
441 }
442 else
443 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500444 o_errCode = error_code::RECEIVED_INVALID_KWD_TYPE_FROM_DBUS;
445 return expanded;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500446 }
447
448 retVal = dbusUtility::readDbusProperty(
449 serviceName, std::string(constants::systemVpdInvPath),
450 kwdInterface, kwd2);
451
452 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
453 {
454 secondKwdValue.assign(
455 reinterpret_cast<const char*>(kwdVal->data()),
456 kwdVal->size());
457 }
458 else
459 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500460 o_errCode = error_code::RECEIVED_INVALID_KWD_TYPE_FROM_DBUS;
461 return expanded;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500462 }
463 }
464
465 if (unexpandedLocationCode.find("fcs") != std::string::npos)
466 {
467 // TODO: See if ND0 can be placed in the JSON
468 expanded.replace(
469 pos, 3, firstKwdValue.substr(0, 4) + ".ND0." + secondKwdValue);
470 }
471 else
472 {
473 replace(firstKwdValue.begin(), firstKwdValue.end(), '-', '.');
474 expanded.replace(pos, 3, firstKwdValue + "." + secondKwdValue);
475 }
476 }
477 catch (const std::exception& ex)
478 {
Rekha Aparna6256db92025-10-17 09:58:49 -0500479 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500480 }
481
482 return expanded;
483}
484
485/**
486 * @brief An API to get VPD in a vector.
487 *
488 * The vector is required by the respective parser to fill the VPD map.
489 * Note: API throws exception in case of failure. Caller needs to handle.
490 *
491 * @param[in] vpdFilePath - EEPROM path of the FRU.
492 * @param[out] vpdVector - VPD in vector form.
493 * @param[in] vpdStartOffset - Offset of VPD data in EEPROM.
Rekha Aparna769d6572025-10-22 09:50:35 -0500494 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500495 */
496inline void getVpdDataInVector(const std::string& vpdFilePath,
497 types::BinaryVector& vpdVector,
Rekha Aparna769d6572025-10-22 09:50:35 -0500498 size_t& vpdStartOffset, uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500499{
Rekha Aparna769d6572025-10-22 09:50:35 -0500500 if (vpdFilePath.empty())
501 {
502 o_errCode = error_code::INVALID_INPUT_PARAMETER;
503 return;
504 }
505
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500506 try
507 {
508 std::fstream vpdFileStream;
509 vpdFileStream.exceptions(
510 std::ifstream::badbit | std::ifstream::failbit);
511 vpdFileStream.open(vpdFilePath, std::ios::in | std::ios::binary);
512 auto vpdSizeToRead = std::min(std::filesystem::file_size(vpdFilePath),
513 static_cast<uintmax_t>(65504));
514 vpdVector.resize(vpdSizeToRead);
515
516 vpdFileStream.seekg(vpdStartOffset, std::ios_base::beg);
517 vpdFileStream.read(reinterpret_cast<char*>(&vpdVector[0]),
518 vpdSizeToRead);
519
520 vpdVector.resize(vpdFileStream.gcount());
521 vpdFileStream.clear(std::ios_base::eofbit);
522 }
523 catch (const std::ifstream::failure& fail)
524 {
Rekha Aparna769d6572025-10-22 09:50:35 -0500525 o_errCode = error_code::FILE_SYSTEM_ERROR;
526 return;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500527 }
528}
529
530/**
531 * @brief An API to get D-bus representation of given VPD keyword.
532 *
533 * @param[in] i_keywordName - VPD keyword name.
Rekha Aparna769d6572025-10-22 09:50:35 -0500534 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500535 *
536 * @return D-bus representation of given keyword.
537 */
Rekha Aparna769d6572025-10-22 09:50:35 -0500538inline std::string getDbusPropNameForGivenKw(const std::string& i_keywordName,
539 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500540{
Rekha Aparna769d6572025-10-22 09:50:35 -0500541 if (i_keywordName.empty())
542 {
543 o_errCode = error_code::INVALID_INPUT_PARAMETER;
544 return std::string{};
545 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500546 // Check for "#" prefixed VPD keyword.
547 if ((i_keywordName.size() == vpd::constants::TWO_BYTES) &&
548 (i_keywordName.at(0) == constants::POUND_KW))
549 {
550 // D-bus doesn't support "#". Replace "#" with "PD_" for those "#"
551 // prefixed keywords.
552 return (std::string(constants::POUND_KW_PREFIX) +
553 i_keywordName.substr(1));
554 }
555
556 // Return the keyword name back, if D-bus representation is same as the VPD
557 // keyword name.
558 return i_keywordName;
559}
560
561/**
562 * @brief API to find CCIN in parsed VPD map.
563 *
564 * Few FRUs need some special handling. To identify those FRUs CCIN are used.
565 * The API will check from parsed VPD map if the FRU is the one with desired
566 * CCIN.
567 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500568 * @param[in] i_JsonObject - Any JSON which contains CCIN tag to match.
569 * @param[in] i_parsedVpdMap - Parsed VPD map.
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500570 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy815c6022025-02-20 00:54:24 -0600571 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500572 * @return True if found, false otherwise.
573 */
574inline bool findCcinInVpd(const nlohmann::json& i_JsonObject,
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500575 const types::VPDMapVariant& i_parsedVpdMap,
576 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500577{
Souvik Roy815c6022025-02-20 00:54:24 -0600578 bool l_rc{false};
579 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500580 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500581 if (i_JsonObject.empty() ||
582 std::holds_alternative<std::monostate>(i_parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500583 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500584 o_errCode = error_code::INVALID_INPUT_PARAMETER;
585 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500586 }
587
Souvik Roy815c6022025-02-20 00:54:24 -0600588 if (auto l_ipzVPDMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500589 {
Souvik Roy815c6022025-02-20 00:54:24 -0600590 auto l_itrToRec = (*l_ipzVPDMap).find("VINI");
591 if (l_itrToRec == (*l_ipzVPDMap).end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500592 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500593 o_errCode = error_code::RECORD_NOT_FOUND;
594 return l_rc;
Souvik Roy815c6022025-02-20 00:54:24 -0600595 }
596
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500597 std::string l_ccinFromVpd{vpdSpecificUtility::getKwVal(
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500598 l_itrToRec->second, "CC", o_errCode)};
Souvik Roy815c6022025-02-20 00:54:24 -0600599 if (l_ccinFromVpd.empty())
600 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500601 o_errCode = error_code::KEYWORD_NOT_FOUND;
602 return l_rc;
Souvik Roy815c6022025-02-20 00:54:24 -0600603 }
604
605 transform(l_ccinFromVpd.begin(), l_ccinFromVpd.end(),
606 l_ccinFromVpd.begin(), ::toupper);
607
608 for (std::string l_ccinValue : i_JsonObject["ccin"])
609 {
610 transform(l_ccinValue.begin(), l_ccinValue.end(),
611 l_ccinValue.begin(), ::toupper);
612
613 if (l_ccinValue.compare(l_ccinFromVpd) ==
614 constants::STR_CMP_SUCCESS)
615 {
616 // CCIN found
617 l_rc = true;
618 }
619 }
620
621 if (!l_rc)
622 {
623 logging::logMessage("No match found for CCIN");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500624 }
625 }
Souvik Roy815c6022025-02-20 00:54:24 -0600626 else
627 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500628 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
Souvik Roy815c6022025-02-20 00:54:24 -0600629 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500630 }
Souvik Roy815c6022025-02-20 00:54:24 -0600631 catch (const std::exception& l_ex)
632 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500633 o_errCode = error_code::STANDARD_EXCEPTION;
Souvik Roy815c6022025-02-20 00:54:24 -0600634 }
635 return l_rc;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500636}
637
638/**
639 * @brief API to reset data of a FRU populated under PIM.
640 *
641 * This API resets the data for particular interfaces of a FRU under PIM.
642 *
643 * @param[in] i_objectPath - DBus object path of the FRU.
644 * @param[in] io_interfaceMap - Interface and its properties map.
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500645 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500646 */
647inline void resetDataUnderPIM(const std::string& i_objectPath,
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500648 types::InterfaceMap& io_interfaceMap,
649 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500650{
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500651 if (i_objectPath.empty())
652 {
653 o_errCode = error_code::INVALID_INPUT_PARAMETER;
654 return;
655 }
656
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500657 try
658 {
Anupama B R68a70432025-09-25 02:09:37 -0500659 std::vector<std::string> l_interfaces;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500660 const types::MapperGetObject& l_getObjectMap =
661 dbusUtility::getObjectMap(i_objectPath, l_interfaces);
662
663 const std::vector<std::string>& l_vpdRelatedInterfaces{
664 constants::operationalStatusInf, constants::inventoryItemInf,
Anupama B Rffa488f2025-05-22 07:34:00 -0500665 constants::assetInf, constants::vpdCollectionInterface};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500666
667 for (const auto& [l_service, l_interfaceList] : l_getObjectMap)
668 {
669 if (l_service.compare(constants::pimServiceName) !=
670 constants::STR_CMP_SUCCESS)
671 {
672 continue;
673 }
674
675 for (const auto& l_interface : l_interfaceList)
676 {
677 if ((l_interface.find(constants::ipzVpdInf) !=
678 std::string::npos) ||
679 ((std::find(l_vpdRelatedInterfaces.begin(),
680 l_vpdRelatedInterfaces.end(), l_interface)) !=
681 l_vpdRelatedInterfaces.end()))
682 {
683 const types::PropertyMap& l_propertyValueMap =
684 dbusUtility::getPropertyMap(l_service, i_objectPath,
685 l_interface);
686
687 types::PropertyMap l_propertyMap;
688
689 for (const auto& l_aProperty : l_propertyValueMap)
690 {
691 const std::string& l_propertyName = l_aProperty.first;
692 const auto& l_propertyValue = l_aProperty.second;
693
694 if (std::holds_alternative<types::BinaryVector>(
695 l_propertyValue))
696 {
697 l_propertyMap.emplace(l_propertyName,
698 types::BinaryVector{});
699 }
700 else if (std::holds_alternative<std::string>(
701 l_propertyValue))
702 {
Anupama B R5cd1b2d2025-08-05 04:57:40 -0500703 if (l_propertyName.compare("Status") ==
Anupama B Rffa488f2025-05-22 07:34:00 -0500704 constants::STR_CMP_SUCCESS)
705 {
706 l_propertyMap.emplace(
707 l_propertyName,
708 constants::vpdCollectionNotStarted);
Anupama B R4c65fcd2025-09-01 08:09:00 -0500709 l_propertyMap.emplace("StartTime", 0);
710 l_propertyMap.emplace("CompletedTime", 0);
Anupama B Rffa488f2025-05-22 07:34:00 -0500711 }
712 else
713 {
714 l_propertyMap.emplace(l_propertyName,
715 std::string{});
716 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500717 }
718 else if (std::holds_alternative<bool>(l_propertyValue))
719 {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500720 if (l_propertyName.compare("Present") ==
721 constants::STR_CMP_SUCCESS)
722 {
723 l_propertyMap.emplace(l_propertyName, false);
724 }
Rekha Aparna4f722062025-05-02 03:39:32 -0500725 else if (l_propertyName.compare("Functional") ==
726 constants::STR_CMP_SUCCESS)
727 {
728 // Since FRU is not present functional property
729 // is considered as true.
730 l_propertyMap.emplace(l_propertyName, true);
731 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500732 }
733 }
734 io_interfaceMap.emplace(l_interface,
735 std::move(l_propertyMap));
736 }
737 }
738 }
739 }
740 catch (const std::exception& l_ex)
741 {
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500742 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500743 }
744}
Sunny Srivastava78c91072025-02-05 14:09:50 +0530745
746/**
747 * @brief API to detect pass1 planar type.
748 *
749 * Based on HW version and IM keyword, This API detects is it is a pass1 planar
750 * or not.
Rekha Aparna715eaff2025-10-23 02:06:50 -0500751 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastava78c91072025-02-05 14:09:50 +0530752 *
753 * @return True if pass 1 planar, false otherwise.
754 */
Rekha Aparna715eaff2025-10-23 02:06:50 -0500755inline bool isPass1Planar(uint16_t& o_errCode) noexcept
Sunny Srivastava78c91072025-02-05 14:09:50 +0530756{
Souvik Roy094a7352025-02-20 01:31:45 -0600757 bool l_rc{false};
Rekha Aparna715eaff2025-10-23 02:06:50 -0500758 auto l_retVal = dbusUtility::readDbusProperty(
759 constants::pimServiceName, constants::systemVpdInvPath,
760 constants::viniInf, constants::kwdHW);
761
762 auto l_hwVer = std::get_if<types::BinaryVector>(&l_retVal);
763
764 l_retVal = dbusUtility::readDbusProperty(
765 constants::pimServiceName, constants::systemInvPath, constants::vsbpInf,
766 constants::kwdIM);
767
768 auto l_imValue = std::get_if<types::BinaryVector>(&l_retVal);
769
770 if (l_hwVer && l_imValue)
Sunny Srivastava78c91072025-02-05 14:09:50 +0530771 {
Rekha Aparna715eaff2025-10-23 02:06:50 -0500772 if (l_hwVer->size() != constants::VALUE_2)
Sunny Srivastava78c91072025-02-05 14:09:50 +0530773 {
Rekha Aparna715eaff2025-10-23 02:06:50 -0500774 o_errCode = error_code::INVALID_KEYWORD_LENGTH;
775 return l_rc;
776 }
Souvik Roy094a7352025-02-20 01:31:45 -0600777
Rekha Aparna715eaff2025-10-23 02:06:50 -0500778 if (l_imValue->size() != constants::VALUE_4)
779 {
780 o_errCode = error_code::INVALID_KEYWORD_LENGTH;
781 return l_rc;
782 }
Souvik Roy094a7352025-02-20 01:31:45 -0600783
Rekha Aparna715eaff2025-10-23 02:06:50 -0500784 const types::BinaryVector l_everest{80, 00, 48, 00};
785 const types::BinaryVector l_fuji{96, 00, 32, 00};
Souvik Roy094a7352025-02-20 01:31:45 -0600786
Rekha Aparna715eaff2025-10-23 02:06:50 -0500787 if (((*l_imValue) == l_everest) || ((*l_imValue) == l_fuji))
788 {
789 if ((*l_hwVer).at(1) < constants::VALUE_21)
Souvik Roy094a7352025-02-20 01:31:45 -0600790 {
791 l_rc = true;
Sunny Srivastava78c91072025-02-05 14:09:50 +0530792 }
793 }
Rekha Aparna715eaff2025-10-23 02:06:50 -0500794 else if ((*l_hwVer).at(1) < constants::VALUE_2)
795 {
796 l_rc = true;
797 }
Sunny Srivastava78c91072025-02-05 14:09:50 +0530798 }
799
Souvik Roy094a7352025-02-20 01:31:45 -0600800 return l_rc;
Sunny Srivastava78c91072025-02-05 14:09:50 +0530801}
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530802
803/**
804 * @brief API to detect if system configuration is that of PowerVS system.
805 *
806 * @param[in] i_imValue - IM value of the system.
Rekha Aparnaed09af82025-10-22 20:34:41 -0500807 * @param[out] o_errCode - To set error code in case of error.
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530808 * @return true if it is PowerVS configuration, false otherwise.
809 */
Rekha Aparnaed09af82025-10-22 20:34:41 -0500810inline bool isPowerVsConfiguration(const types::BinaryVector& i_imValue,
811 uint16_t& o_errCode)
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530812{
813 if (i_imValue.empty() || i_imValue.size() != constants::VALUE_4)
814 {
Rekha Aparnaed09af82025-10-22 20:34:41 -0500815 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavac6ef42d2025-02-19 19:17:10 +0530816 return false;
817 }
818
819 // Should be a 0x5000XX series system.
820 if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
821 i_imValue.at(1) == constants::HEX_VALUE_00)
822 {
823 std::string l_imagePrefix = dbusUtility::getImagePrefix();
824
825 // Check image for 0x500030XX series.
826 if ((i_imValue.at(2) == constants::HEX_VALUE_30) &&
827 ((l_imagePrefix == constants::powerVsImagePrefix_MY) ||
828 (l_imagePrefix == constants::powerVsImagePrefix_NY)))
829 {
830 logging::logMessage("PowerVS configuration");
831 return true;
832 }
833
834 // Check image for 0X500010XX series.
835 if ((i_imValue.at(2) == constants::HEX_VALUE_10) &&
836 ((l_imagePrefix == constants::powerVsImagePrefix_MZ) ||
837 (l_imagePrefix == constants::powerVsImagePrefix_NZ)))
838 {
839 logging::logMessage("PowerVS configuration");
840 return true;
841 }
842 }
843 return false;
844}
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530845
846/**
847 * @brief API to get CCIN for a given FRU from DBus.
848 *
849 * The API reads the CCIN for a FRU based on its inventory path.
850 *
851 * @param[in] i_invObjPath - Inventory path of the FRU.
Rekha Aparna80b674f2025-10-27 01:27:27 -0500852 * @param[out] o_errCode - To set error code in case of error.
853 *
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530854 * @return CCIN of the FRU on success, empty string otherwise.
855 */
Rekha Aparna80b674f2025-10-27 01:27:27 -0500856inline std::string getCcinFromDbus(const std::string& i_invObjPath,
857 uint16_t& o_errCode)
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530858{
859 try
860 {
861 if (i_invObjPath.empty())
862 {
Rekha Aparna80b674f2025-10-27 01:27:27 -0500863 o_errCode = error_code::INVALID_INPUT_PARAMETER;
864 return std::string{};
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530865 }
866
867 const auto& l_retValue = dbusUtility::readDbusProperty(
868 constants::pimServiceName, i_invObjPath, constants::viniInf,
869 constants::kwdCCIN);
870
871 auto l_ptrCcin = std::get_if<types::BinaryVector>(&l_retValue);
Rekha Aparna80b674f2025-10-27 01:27:27 -0500872
873 if (!l_ptrCcin)
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530874 {
Rekha Aparna80b674f2025-10-27 01:27:27 -0500875 o_errCode = error_code::RECEIVED_INVALID_KWD_TYPE_FROM_DBUS;
876 return std::string{};
877 }
878
879 if ((*l_ptrCcin).size() != constants::VALUE_4)
880 {
881 o_errCode = error_code::INVALID_VALUE_READ_FROM_DBUS;
882 return std::string{};
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530883 }
884
885 return std::string((*l_ptrCcin).begin(), (*l_ptrCcin).end());
886 }
887 catch (const std::exception& l_ex)
888 {
Rekha Aparna80b674f2025-10-27 01:27:27 -0500889 o_errCode = error_code::STANDARD_EXCEPTION;
Sunny Srivastavaf1dda762025-02-19 23:46:19 +0530890 return std::string{};
891 }
892}
Sunny Srivastavaecfaa212025-03-24 13:02:13 +0530893
894/**
895 * @brief API to check if the current running image is a powerVS image.
896 *
897 * @return true if it is PowerVS image, false otherwise.
898 */
899inline bool isPowerVsImage()
900{
901 std::string l_imagePrefix = dbusUtility::getImagePrefix();
902
903 if ((l_imagePrefix == constants::powerVsImagePrefix_MY) ||
904 (l_imagePrefix == constants::powerVsImagePrefix_NY) ||
905 (l_imagePrefix == constants::powerVsImagePrefix_MZ) ||
906 (l_imagePrefix == constants::powerVsImagePrefix_NZ))
907 {
908 return true;
909 }
910 return false;
911}
Souvik Roy2ee8a212025-04-24 02:37:59 -0500912
913/**
914 * @brief API to sync keyword update to inherited FRUs.
915 *
916 * For a given keyword update on a EEPROM path, this API syncs the keyword
917 * update to all inherited FRUs' respective interface, property on PIM.
918 *
919 * @param[in] i_fruPath - EEPROM path of FRU.
920 * @param[in] i_paramsToWriteData - Input details.
921 * @param[in] i_sysCfgJsonObj - System config JSON.
Rekha Aparna1324ed52025-10-27 03:26:33 -0500922 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy2ee8a212025-04-24 02:37:59 -0500923 *
924 */
925inline void updateKwdOnInheritedFrus(
926 const std::string& i_fruPath,
927 const types::WriteVpdParams& i_paramsToWriteData,
Rekha Aparna1324ed52025-10-27 03:26:33 -0500928 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) noexcept
Souvik Roy2ee8a212025-04-24 02:37:59 -0500929{
930 try
931 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500932 if (i_fruPath.empty() || i_sysCfgJsonObj.empty())
933 {
934 o_errCode = error_code::INVALID_INPUT_PARAMETER;
935 return;
936 }
937
Souvik Roy2ee8a212025-04-24 02:37:59 -0500938 if (!i_sysCfgJsonObj.contains("frus"))
939 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500940 o_errCode = error_code::INVALID_JSON;
941 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -0500942 }
943
944 if (!i_sysCfgJsonObj["frus"].contains(i_fruPath))
945 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500946 o_errCode = error_code::FRU_PATH_NOT_FOUND;
947 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -0500948 }
949
950 const types::IpzData* l_ipzData =
951 std::get_if<types::IpzData>(&i_paramsToWriteData);
952
953 if (!l_ipzData)
954 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500955 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
956 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -0500957 }
958 // iterate through all inventory paths for given EEPROM path,
959 // except the base FRU.
960 // if for an inventory path, "inherit" tag is true,
961 // update the inventory path's com.ibm.ipzvpd.<record>,keyword
962 // property
963
964 types::ObjectMap l_objectInterfaceMap;
965
966 auto l_populateInterfaceMap =
967 [&l_objectInterfaceMap,
968 &l_ipzData = std::as_const(l_ipzData)](const auto& l_Fru) {
969 // update inherited FRUs only
970 if (l_Fru.value("inherit", true))
971 {
972 l_objectInterfaceMap.emplace(
973 sdbusplus::message::object_path{l_Fru["inventoryPath"]},
974 types::InterfaceMap{
975 {std::string{constants::ipzVpdInf +
976 std::get<0>(*l_ipzData)},
977 types::PropertyMap{{std::get<1>(*l_ipzData),
978 std::get<2>(*l_ipzData)}}}});
979 }
980 };
981
982 // iterate through all FRUs except the base FRU
983 std::for_each(
984 i_sysCfgJsonObj["frus"][i_fruPath].begin() + constants::VALUE_1,
985 i_sysCfgJsonObj["frus"][i_fruPath].end(), l_populateInterfaceMap);
986
987 if (!l_objectInterfaceMap.empty())
988 {
989 // notify PIM
990 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
991 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500992 o_errCode = error_code::DBUS_FAILURE;
993 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -0500994 }
995 }
996 }
997 catch (const std::exception& l_ex)
998 {
Rekha Aparna1324ed52025-10-27 03:26:33 -0500999 o_errCode = error_code::STANDARD_EXCEPTION;
1000 return;
Souvik Roy2ee8a212025-04-24 02:37:59 -05001001 }
1002}
Souvik Roy96ebe962025-04-29 04:01:07 -05001003
1004/**
1005 * @brief API to get common interface(s) properties corresponding to given
1006 * record and keyword.
1007 *
1008 * For a given record and keyword, this API finds the corresponding common
1009 * interfaces(s) properties from the system config JSON and populates an
1010 * interface map with the respective properties and values.
1011 *
1012 * @param[in] i_paramsToWriteData - Input details.
1013 * @param[in] i_commonInterfaceJson - Common interface JSON object.
Rekha Aparna3fcad142025-10-24 08:16:44 -05001014 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy96ebe962025-04-29 04:01:07 -05001015 *
1016 * @return Returns a map of common interface(s) and properties corresponding to
1017 * the record and keyword. An empty map is returned if no such common
1018 * interface(s) and properties are found.
1019 */
1020inline types::InterfaceMap getCommonInterfaceProperties(
1021 const types::WriteVpdParams& i_paramsToWriteData,
Rekha Aparna3fcad142025-10-24 08:16:44 -05001022 const nlohmann::json& i_commonInterfaceJson, uint16_t& o_errCode) noexcept
Souvik Roy96ebe962025-04-29 04:01:07 -05001023{
1024 types::InterfaceMap l_interfaceMap;
1025 try
1026 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001027 if (i_commonInterfaceJson.empty())
1028 {
1029 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1030 return l_interfaceMap;
1031 }
1032
Souvik Roy96ebe962025-04-29 04:01:07 -05001033 const types::IpzData* l_ipzData =
1034 std::get_if<types::IpzData>(&i_paramsToWriteData);
1035
1036 if (!l_ipzData)
1037 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001038 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
1039 return l_interfaceMap;
Souvik Roy96ebe962025-04-29 04:01:07 -05001040 }
1041
1042 auto l_populateInterfaceMap = [&l_ipzData = std::as_const(l_ipzData),
Rekha Aparna3fcad142025-10-24 08:16:44 -05001043 &l_interfaceMap, &o_errCode](
Souvik Roy96ebe962025-04-29 04:01:07 -05001044 const auto& l_interfacesPropPair) {
Souvik Roy9654e032025-09-17 17:18:42 +00001045 if (l_interfacesPropPair.value().empty())
1046 {
1047 return;
1048 }
1049
Souvik Roy96ebe962025-04-29 04:01:07 -05001050 // find matching property value pair
1051 const auto l_matchPropValuePairIt = std::find_if(
1052 l_interfacesPropPair.value().items().begin(),
1053 l_interfacesPropPair.value().items().end(),
1054 [&l_ipzData](const auto& l_propValuePair) {
1055 return (l_propValuePair.value().value("recordName", "") ==
1056 std::get<0>(*l_ipzData) &&
1057 l_propValuePair.value().value("keywordName", "") ==
1058 std::get<1>(*l_ipzData));
1059 });
1060
1061 if (l_matchPropValuePairIt !=
1062 l_interfacesPropPair.value().items().end())
1063 {
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001064 std::string l_kwd = std::string(std::get<2>(*l_ipzData).begin(),
1065 std::get<2>(*l_ipzData).end());
1066
1067 std::string l_encodedValue = vpdSpecificUtility::encodeKeyword(
1068 l_kwd, l_matchPropValuePairIt.value().value("encoding", ""),
Rekha Aparna3fcad142025-10-24 08:16:44 -05001069 o_errCode);
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001070
Rekha Aparna3fcad142025-10-24 08:16:44 -05001071 if (l_encodedValue.empty() && o_errCode)
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001072 {
1073 logging::logMessage(
Rekha Aparna3fcad142025-10-24 08:16:44 -05001074 "Failed to get encoded value for keyword : " + l_kwd +
1075 ", error : " + commonUtility::getErrCodeMsg(o_errCode));
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001076 }
1077
Souvik Roy96ebe962025-04-29 04:01:07 -05001078 // add property map to interface map
1079 l_interfaceMap.emplace(
1080 l_interfacesPropPair.key(),
1081 types::PropertyMap{
Rekha Aparna17ddfb52025-10-09 20:45:53 -05001082 {l_matchPropValuePairIt.key(), l_encodedValue}});
Souvik Roy96ebe962025-04-29 04:01:07 -05001083 }
1084 };
1085
Sunny Srivastava89fbd2d2025-09-03 02:03:48 -05001086 if (!i_commonInterfaceJson.empty())
1087 {
1088 // iterate through all common interfaces and populate interface map
1089 std::for_each(i_commonInterfaceJson.items().begin(),
1090 i_commonInterfaceJson.items().end(),
1091 l_populateInterfaceMap);
1092 }
Souvik Roy96ebe962025-04-29 04:01:07 -05001093 }
1094 catch (const std::exception& l_ex)
1095 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001096 o_errCode = error_code::STANDARD_EXCEPTION;
Souvik Roy96ebe962025-04-29 04:01:07 -05001097 }
1098 return l_interfaceMap;
1099}
1100
1101/**
1102 * @brief API to update common interface(s) properties when keyword is updated.
1103 *
1104 * For a given keyword update on a EEPROM path, this API syncs the keyword
1105 * update to respective common interface(s) properties of the base FRU and all
1106 * inherited FRUs.
1107 *
1108 * @param[in] i_fruPath - EEPROM path of FRU.
1109 * @param[in] i_paramsToWriteData - Input details.
1110 * @param[in] i_sysCfgJsonObj - System config JSON.
Rekha Aparna3fcad142025-10-24 08:16:44 -05001111 * @param[out] o_errCode - To set error code in case of error.
Souvik Roy96ebe962025-04-29 04:01:07 -05001112 */
1113inline void updateCiPropertyOfInheritedFrus(
1114 const std::string& i_fruPath,
1115 const types::WriteVpdParams& i_paramsToWriteData,
Rekha Aparna3fcad142025-10-24 08:16:44 -05001116 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) noexcept
Souvik Roy96ebe962025-04-29 04:01:07 -05001117{
1118 try
1119 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001120 if (i_fruPath.empty() || i_sysCfgJsonObj.empty())
1121 {
1122 o_errCode = error_code::INVALID_INPUT_PARAMETER;
1123 return;
1124 }
1125
Souvik Roy96ebe962025-04-29 04:01:07 -05001126 if (!i_sysCfgJsonObj.contains("commonInterfaces"))
1127 {
1128 // no common interfaces in JSON, nothing to do
1129 return;
1130 }
1131
1132 if (!i_sysCfgJsonObj.contains("frus"))
1133 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001134 o_errCode = error_code::INVALID_JSON;
1135 return;
Souvik Roy96ebe962025-04-29 04:01:07 -05001136 }
1137
1138 if (!i_sysCfgJsonObj["frus"].contains(i_fruPath))
1139 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001140 o_errCode = error_code::FRU_PATH_NOT_FOUND;
1141 return;
Souvik Roy96ebe962025-04-29 04:01:07 -05001142 }
1143
1144 if (!std::get_if<types::IpzData>(&i_paramsToWriteData))
1145 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001146 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
1147 return;
Souvik Roy96ebe962025-04-29 04:01:07 -05001148 }
1149
1150 // iterate through all inventory paths for given EEPROM path,
1151 // if for an inventory path, "inherit" tag is true,
1152 // update the inventory path's com.ibm.ipzvpd.<record>,keyword
1153 // property
1154
1155 types::ObjectMap l_objectInterfaceMap;
1156
1157 const types::InterfaceMap l_interfaceMap = getCommonInterfaceProperties(
Rekha Aparna3fcad142025-10-24 08:16:44 -05001158 i_paramsToWriteData, i_sysCfgJsonObj["commonInterfaces"],
1159 o_errCode);
Souvik Roy96ebe962025-04-29 04:01:07 -05001160
1161 if (l_interfaceMap.empty())
1162 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001163 if (o_errCode)
1164 {
1165 logging::logMessage(
1166 "Failed to get common interface property list, error : " +
1167 commonUtility::getErrCodeMsg(o_errCode));
1168 }
Souvik Roy96ebe962025-04-29 04:01:07 -05001169 // nothing to do
1170 return;
1171 }
1172
1173 auto l_populateObjectInterfaceMap =
1174 [&l_objectInterfaceMap, &l_interfaceMap = std::as_const(
1175 l_interfaceMap)](const auto& l_Fru) {
1176 if (l_Fru.value("inherit", true) &&
1177 l_Fru.contains("inventoryPath"))
1178 {
1179 l_objectInterfaceMap.emplace(
1180 sdbusplus::message::object_path{l_Fru["inventoryPath"]},
1181 l_interfaceMap);
1182 }
1183 };
1184
1185 std::for_each(i_sysCfgJsonObj["frus"][i_fruPath].begin(),
1186 i_sysCfgJsonObj["frus"][i_fruPath].end(),
1187 l_populateObjectInterfaceMap);
1188
1189 if (!l_objectInterfaceMap.empty())
1190 {
1191 // notify PIM
1192 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
1193 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001194 o_errCode = error_code::DBUS_FAILURE;
1195 return;
Souvik Roy96ebe962025-04-29 04:01:07 -05001196 }
1197 }
1198 }
1199 catch (const std::exception& l_ex)
1200 {
Rekha Aparna3fcad142025-10-24 08:16:44 -05001201 o_errCode = error_code::STANDARD_EXCEPTION;
Souvik Roy96ebe962025-04-29 04:01:07 -05001202 }
1203}
Sunny Srivastava995e1c22025-08-28 03:13:00 -05001204
1205/**
Souvik Royd7c7cb52025-07-30 06:31:02 +00001206 * @brief API to convert write VPD parameters to a string.
1207 *
1208 * @param[in] i_paramsToWriteData - write VPD parameters.
1209 * @param[out] o_errCode - To set error code in case of error.
1210 *
1211 * @return On success returns string representation of write VPD parameters,
1212 * otherwise returns an empty string.
1213 */
1214inline const std::string convertWriteVpdParamsToString(
1215 const types::WriteVpdParams& i_paramsToWriteData,
1216 uint16_t& o_errCode) noexcept
1217{
1218 try
1219 {
1220 if (const types::IpzData* l_ipzDataPtr =
1221 std::get_if<types::IpzData>(&i_paramsToWriteData))
1222 {
1223 return std::string{
1224 "Record: " + std::get<0>(*l_ipzDataPtr) +
1225 " Keyword: " + std::get<1>(*l_ipzDataPtr) + " Value: " +
1226 commonUtility::convertByteVectorToHex(
1227 std::get<2>(*l_ipzDataPtr))};
1228 }
1229 else if (const types::KwData* l_kwDataPtr =
1230 std::get_if<types::KwData>(&i_paramsToWriteData))
1231 {
1232 return std::string{
1233 "Keyword: " + std::get<0>(*l_kwDataPtr) + " Value: " +
1234 commonUtility::convertByteVectorToHex(
1235 std::get<1>(*l_kwDataPtr))};
1236 }
1237 else
1238 {
1239 o_errCode = error_code::UNSUPPORTED_VPD_TYPE;
1240 }
1241 }
1242 catch (const std::exception& l_ex)
1243 {
1244 o_errCode = error_code::STANDARD_EXCEPTION;
1245 }
1246 return std::string{};
1247}
1248
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001249} // namespace vpdSpecificUtility
1250} // namespace vpd