1 #pragma once
2
3 #include "config.h"
4
5 #include "constants.hpp"
6 #include "event_logger.hpp"
7 #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>
18 #include <typeindex>
19
20 namespace vpd
21 {
22 namespace 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 *
31 * @param[in] i_vpdFilePath - file path of the vpd.
32 *
33 * @return On success, returns generated file name, otherwise returns empty
34 * string.
35 */
generateBadVPDFileName(const std::string & i_vpdFilePath)36 inline std::string generateBadVPDFileName(
37 const std::string& i_vpdFilePath) noexcept
38 {
39 std::string l_badVpdFileName{BAD_VPD_DIR};
40 try
41 {
42 if (i_vpdFilePath.find("i2c") != std::string::npos)
43 {
44 l_badVpdFileName += "i2c-";
45 std::regex l_i2cPattern("(at24/)([0-9]+-[0-9]+)\\/");
46 std::smatch l_match;
47 if (std::regex_search(i_vpdFilePath, l_match, l_i2cPattern))
48 {
49 l_badVpdFileName += l_match.str(2);
50 }
51 }
52 else if (i_vpdFilePath.find("spi") != std::string::npos)
53 {
54 std::regex l_spiPattern("((spi)[0-9]+)(.0)");
55 std::smatch l_match;
56 if (std::regex_search(i_vpdFilePath, l_match, l_spiPattern))
57 {
58 l_badVpdFileName += l_match.str(1);
59 }
60 }
61 }
62 catch (const std::exception& l_ex)
63 {
64 l_badVpdFileName.clear();
65 logging::logMessage("Failed to generate bad VPD file name for [" +
66 i_vpdFilePath + "]. Error: " + l_ex.what());
67 }
68 return l_badVpdFileName;
69 }
70
71 /**
72 * @brief API which dumps the broken/bad vpd in a directory.
73 * When the vpd is bad, this API places the bad vpd file inside
74 * "/tmp/bad-vpd" in BMC, in order to collect bad VPD data as a part of user
75 * initiated BMC dump.
76 *
77 *
78 * @param[in] i_vpdFilePath - vpd file path
79 * @param[in] i_vpdVector - vpd vector
80 *
81 * @return On success returns 0, otherwise returns -1.
82 */
dumpBadVpd(const std::string & i_vpdFilePath,const types::BinaryVector & i_vpdVector)83 inline int dumpBadVpd(const std::string& i_vpdFilePath,
84 const types::BinaryVector& i_vpdVector) noexcept
85 {
86 int l_rc{constants::FAILURE};
87 try
88 {
89 std::filesystem::create_directory(BAD_VPD_DIR);
90 auto l_badVpdPath = generateBadVPDFileName(i_vpdFilePath);
91
92 if (l_badVpdPath.empty())
93 {
94 throw std::runtime_error("Failed to generate bad VPD file name");
95 }
96
97 if (std::filesystem::exists(l_badVpdPath))
98 {
99 std::error_code l_ec;
100 std::filesystem::remove(l_badVpdPath, l_ec);
101 if (l_ec) // error code
102 {
103 const std::string l_errorMsg{
104 "Error removing the existing broken vpd in " +
105 l_badVpdPath +
106 ". Error code : " + std::to_string(l_ec.value()) +
107 ". Error message : " + l_ec.message()};
108
109 throw std::runtime_error(l_errorMsg);
110 }
111 }
112
113 std::ofstream l_badVpdFileStream(l_badVpdPath, std::ofstream::binary);
114 if (!l_badVpdFileStream.is_open())
115 {
116 throw std::runtime_error(
117 "Failed to open bad vpd file path in /tmp/bad-vpd. "
118 "Unable to dump the broken/bad vpd file.");
119 }
120
121 l_badVpdFileStream.write(
122 reinterpret_cast<const char*>(i_vpdVector.data()),
123 i_vpdVector.size());
124
125 l_rc = constants::SUCCESS;
126 }
127 catch (const std::exception& l_ex)
128 {
129 logging::logMessage("Failed to dump bad VPD for [" + i_vpdFilePath +
130 "]. Error: " + l_ex.what());
131 }
132 return l_rc;
133 }
134
135 /**
136 * @brief An API to read value of a keyword.
137 *
138 *
139 * @param[in] i_kwdValueMap - A map having Kwd value pair.
140 * @param[in] i_kwd - keyword name.
141 *
142 * @return On success returns value of the keyword read from map, otherwise
143 * returns empty string.
144 */
getKwVal(const types::IPZKwdValueMap & i_kwdValueMap,const std::string & i_kwd)145 inline std::string getKwVal(const types::IPZKwdValueMap& i_kwdValueMap,
146 const std::string& i_kwd) noexcept
147 {
148 std::string l_kwdValue;
149 try
150 {
151 if (i_kwd.empty())
152 {
153 throw std::runtime_error("Invalid parameters");
154 }
155
156 auto l_itrToKwd = i_kwdValueMap.find(i_kwd);
157 if (l_itrToKwd != i_kwdValueMap.end())
158 {
159 l_kwdValue = l_itrToKwd->second;
160 }
161 else
162 {
163 throw std::runtime_error("Keyword not found");
164 }
165 }
166 catch (const std::exception& l_ex)
167 {
168 logging::logMessage("Failed to get value for keyword [" + i_kwd +
169 "]. Error : " + l_ex.what());
170 }
171 return l_kwdValue;
172 }
173
174 /**
175 * @brief An API to process encoding of a keyword.
176 *
177 * @param[in] i_keyword - Keyword to be processed.
178 * @param[in] i_encoding - Type of encoding.
179 *
180 * @return Value after being processed for encoded type.
181 */
encodeKeyword(const std::string & i_keyword,const std::string & i_encoding)182 inline std::string encodeKeyword(const std::string& i_keyword,
183 const std::string& i_encoding) noexcept
184 {
185 // Default value is keyword value
186 std::string l_result(i_keyword.begin(), i_keyword.end());
187 try
188 {
189 if (i_encoding == "MAC")
190 {
191 l_result.clear();
192 size_t l_firstByte = i_keyword[0];
193 l_result += commonUtility::toHex(l_firstByte >> 4);
194 l_result += commonUtility::toHex(l_firstByte & 0x0f);
195 for (size_t i = 1; i < i_keyword.size(); ++i)
196 {
197 l_result += ":";
198 l_result += commonUtility::toHex(i_keyword[i] >> 4);
199 l_result += commonUtility::toHex(i_keyword[i] & 0x0f);
200 }
201 }
202 else if (i_encoding == "DATE")
203 {
204 // Date, represent as
205 // <year>-<month>-<day> <hour>:<min>
206 l_result.clear();
207 static constexpr uint8_t skipPrefix = 3;
208
209 auto strItr = i_keyword.begin();
210 advance(strItr, skipPrefix);
211 for_each(strItr, i_keyword.end(),
212 [&l_result](size_t c) { l_result += c; });
213
214 l_result.insert(constants::BD_YEAR_END, 1, '-');
215 l_result.insert(constants::BD_MONTH_END, 1, '-');
216 l_result.insert(constants::BD_DAY_END, 1, ' ');
217 l_result.insert(constants::BD_HOUR_END, 1, ':');
218 }
219 }
220 catch (const std::exception& l_ex)
221 {
222 l_result.clear();
223 logging::logMessage("Failed to encode keyword [" + i_keyword +
224 "]. Error: " + l_ex.what());
225 }
226
227 return l_result;
228 }
229
230 /**
231 * @brief Helper function to insert or merge in map.
232 *
233 * This method checks in an interface if the given interface exists. If the
234 * interface key already exists, property map is inserted corresponding to it.
235 * If the key does'nt exist then given interface and property map pair is newly
236 * created. If the property present in propertymap already exist in the
237 * InterfaceMap, then the new property value is ignored.
238 *
239 * @param[in,out] io_map - Interface map.
240 * @param[in] i_interface - Interface to be processed.
241 * @param[in] i_propertyMap - new property map that needs to be emplaced.
242 *
243 * @return On success returns 0, otherwise returns -1.
244 */
insertOrMerge(types::InterfaceMap & io_map,const std::string & i_interface,types::PropertyMap && i_propertyMap)245 inline int insertOrMerge(types::InterfaceMap& io_map,
246 const std::string& i_interface,
247 types::PropertyMap&& i_propertyMap) noexcept
248 {
249 int l_rc{constants::FAILURE};
250 try
251 {
252 if (io_map.find(i_interface) != io_map.end())
253 {
254 auto& l_prop = io_map.at(i_interface);
255 std::for_each(i_propertyMap.begin(), i_propertyMap.end(),
256 [&l_prop](auto l_keyValue) {
257 l_prop[l_keyValue.first] = l_keyValue.second;
258 });
259 }
260 else
261 {
262 io_map.emplace(i_interface, i_propertyMap);
263 }
264
265 l_rc = constants::SUCCESS;
266 }
267 catch (const std::exception& l_ex)
268 {
269 // ToDo:: Log PEL
270 logging::logMessage(
271 "Inserting properties into interface[" + i_interface +
272 "] map failed, reason: " + std::string(l_ex.what()));
273 }
274 return l_rc;
275 }
276
277 /**
278 * @brief API to expand unpanded location code.
279 *
280 * Note: The API handles all the exception internally, in case of any error
281 * unexpanded location code will be returned as it is.
282 *
283 * @param[in] unexpandedLocationCode - Unexpanded location code.
284 * @param[in] parsedVpdMap - Parsed VPD map.
285 * @return Expanded location code. In case of any error, unexpanded is returned
286 * as it is.
287 */
getExpandedLocationCode(const std::string & unexpandedLocationCode,const types::VPDMapVariant & parsedVpdMap)288 inline std::string getExpandedLocationCode(
289 const std::string& unexpandedLocationCode,
290 const types::VPDMapVariant& parsedVpdMap)
291 {
292 auto expanded{unexpandedLocationCode};
293
294 try
295 {
296 // Expanded location code is formed by combining two keywords
297 // depending on type in unexpanded one. Second one is always "SE".
298 std::string kwd1, kwd2{constants::kwdSE};
299
300 // interface to search for required keywords;
301 std::string kwdInterface;
302
303 // record which holds the required keywords.
304 std::string recordName;
305
306 auto pos = unexpandedLocationCode.find("fcs");
307 if (pos != std::string::npos)
308 {
309 kwd1 = constants::kwdFC;
310 kwdInterface = constants::vcenInf;
311 recordName = constants::recVCEN;
312 }
313 else
314 {
315 pos = unexpandedLocationCode.find("mts");
316 if (pos != std::string::npos)
317 {
318 kwd1 = constants::kwdTM;
319 kwdInterface = constants::vsysInf;
320 recordName = constants::recVSYS;
321 }
322 else
323 {
324 throw std::runtime_error(
325 "Error detecting type of unexpanded location code.");
326 }
327 }
328
329 std::string firstKwdValue, secondKwdValue;
330
331 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap);
332 ipzVpdMap && (*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
333 {
334 auto itrToVCEN = (*ipzVpdMap).find(recordName);
335 firstKwdValue = getKwVal(itrToVCEN->second, kwd1);
336 if (firstKwdValue.empty())
337 {
338 throw std::runtime_error(
339 "Failed to get value for keyword [" + kwd1 + "]");
340 }
341
342 secondKwdValue = getKwVal(itrToVCEN->second, kwd2);
343 if (secondKwdValue.empty())
344 {
345 throw std::runtime_error(
346 "Failed to get value for keyword [" + kwd2 + "]");
347 }
348 }
349 else
350 {
351 std::array<const char*, 1> interfaceList = {kwdInterface.c_str()};
352
353 types::MapperGetObject mapperRetValue = dbusUtility::getObjectMap(
354 std::string(constants::systemVpdInvPath), interfaceList);
355
356 if (mapperRetValue.empty())
357 {
358 throw std::runtime_error("Mapper failed to get service");
359 }
360
361 const std::string& serviceName = std::get<0>(mapperRetValue.at(0));
362
363 auto retVal = dbusUtility::readDbusProperty(
364 serviceName, std::string(constants::systemVpdInvPath),
365 kwdInterface, kwd1);
366
367 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
368 {
369 firstKwdValue.assign(
370 reinterpret_cast<const char*>(kwdVal->data()),
371 kwdVal->size());
372 }
373 else
374 {
375 throw std::runtime_error(
376 "Failed to read value of " + kwd1 + " from Bus");
377 }
378
379 retVal = dbusUtility::readDbusProperty(
380 serviceName, std::string(constants::systemVpdInvPath),
381 kwdInterface, kwd2);
382
383 if (auto kwdVal = std::get_if<types::BinaryVector>(&retVal))
384 {
385 secondKwdValue.assign(
386 reinterpret_cast<const char*>(kwdVal->data()),
387 kwdVal->size());
388 }
389 else
390 {
391 throw std::runtime_error(
392 "Failed to read value of " + kwd2 + " from Bus");
393 }
394 }
395
396 if (unexpandedLocationCode.find("fcs") != std::string::npos)
397 {
398 // TODO: See if ND0 can be placed in the JSON
399 expanded.replace(
400 pos, 3, firstKwdValue.substr(0, 4) + ".ND0." + secondKwdValue);
401 }
402 else
403 {
404 replace(firstKwdValue.begin(), firstKwdValue.end(), '-', '.');
405 expanded.replace(pos, 3, firstKwdValue + "." + secondKwdValue);
406 }
407 }
408 catch (const std::exception& ex)
409 {
410 logging::logMessage("Failed to expand location code with exception: " +
411 std::string(ex.what()));
412 }
413
414 return expanded;
415 }
416
417 /**
418 * @brief An API to get VPD in a vector.
419 *
420 * The vector is required by the respective parser to fill the VPD map.
421 * Note: API throws exception in case of failure. Caller needs to handle.
422 *
423 * @param[in] vpdFilePath - EEPROM path of the FRU.
424 * @param[out] vpdVector - VPD in vector form.
425 * @param[in] vpdStartOffset - Offset of VPD data in EEPROM.
426 */
getVpdDataInVector(const std::string & vpdFilePath,types::BinaryVector & vpdVector,size_t & vpdStartOffset)427 inline void getVpdDataInVector(const std::string& vpdFilePath,
428 types::BinaryVector& vpdVector,
429 size_t& vpdStartOffset)
430 {
431 try
432 {
433 std::fstream vpdFileStream;
434 vpdFileStream.exceptions(
435 std::ifstream::badbit | std::ifstream::failbit);
436 vpdFileStream.open(vpdFilePath, std::ios::in | std::ios::binary);
437 auto vpdSizeToRead = std::min(std::filesystem::file_size(vpdFilePath),
438 static_cast<uintmax_t>(65504));
439 vpdVector.resize(vpdSizeToRead);
440
441 vpdFileStream.seekg(vpdStartOffset, std::ios_base::beg);
442 vpdFileStream.read(reinterpret_cast<char*>(&vpdVector[0]),
443 vpdSizeToRead);
444
445 vpdVector.resize(vpdFileStream.gcount());
446 vpdFileStream.clear(std::ios_base::eofbit);
447 }
448 catch (const std::ifstream::failure& fail)
449 {
450 std::cerr << "Exception in file handling [" << vpdFilePath
451 << "] error : " << fail.what();
452 throw;
453 }
454 }
455
456 /**
457 * @brief An API to get D-bus representation of given VPD keyword.
458 *
459 * @param[in] i_keywordName - VPD keyword name.
460 *
461 * @return D-bus representation of given keyword.
462 */
getDbusPropNameForGivenKw(const std::string & i_keywordName)463 inline std::string getDbusPropNameForGivenKw(const std::string& i_keywordName)
464 {
465 // Check for "#" prefixed VPD keyword.
466 if ((i_keywordName.size() == vpd::constants::TWO_BYTES) &&
467 (i_keywordName.at(0) == constants::POUND_KW))
468 {
469 // D-bus doesn't support "#". Replace "#" with "PD_" for those "#"
470 // prefixed keywords.
471 return (std::string(constants::POUND_KW_PREFIX) +
472 i_keywordName.substr(1));
473 }
474
475 // Return the keyword name back, if D-bus representation is same as the VPD
476 // keyword name.
477 return i_keywordName;
478 }
479
480 /**
481 * @brief API to find CCIN in parsed VPD map.
482 *
483 * Few FRUs need some special handling. To identify those FRUs CCIN are used.
484 * The API will check from parsed VPD map if the FRU is the one with desired
485 * CCIN.
486 *
487 * @param[in] i_JsonObject - Any JSON which contains CCIN tag to match.
488 * @param[in] i_parsedVpdMap - Parsed VPD map.
489 *
490 * @return True if found, false otherwise.
491 */
findCcinInVpd(const nlohmann::json & i_JsonObject,const types::VPDMapVariant & i_parsedVpdMap)492 inline bool findCcinInVpd(const nlohmann::json& i_JsonObject,
493 const types::VPDMapVariant& i_parsedVpdMap) noexcept
494 {
495 bool l_rc{false};
496 try
497 {
498 if (i_JsonObject.empty())
499 {
500 throw std::runtime_error("Json object is empty. Can't find CCIN");
501 }
502
503 if (auto l_ipzVPDMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
504 {
505 auto l_itrToRec = (*l_ipzVPDMap).find("VINI");
506 if (l_itrToRec == (*l_ipzVPDMap).end())
507 {
508 throw DataException(
509 "VINI record not found in parsed VPD. Can't find CCIN");
510 }
511
512 std::string l_ccinFromVpd{
513 vpdSpecificUtility::getKwVal(l_itrToRec->second, "CC")};
514 if (l_ccinFromVpd.empty())
515 {
516 throw DataException(
517 "Empty CCIN value in VPD map. Can't find CCIN");
518 }
519
520 transform(l_ccinFromVpd.begin(), l_ccinFromVpd.end(),
521 l_ccinFromVpd.begin(), ::toupper);
522
523 for (std::string l_ccinValue : i_JsonObject["ccin"])
524 {
525 transform(l_ccinValue.begin(), l_ccinValue.end(),
526 l_ccinValue.begin(), ::toupper);
527
528 if (l_ccinValue.compare(l_ccinFromVpd) ==
529 constants::STR_CMP_SUCCESS)
530 {
531 // CCIN found
532 l_rc = true;
533 }
534 }
535
536 if (!l_rc)
537 {
538 logging::logMessage("No match found for CCIN");
539 }
540 }
541 else
542 {
543 logging::logMessage("VPD type not supported. Can't find CCIN");
544 }
545 }
546 catch (const std::exception& l_ex)
547 {
548 const std::string l_errMsg{
549 "Failed to find CCIN in VPD. Error : " + std::string(l_ex.what())};
550
551 if (typeid(l_ex) == std::type_index(typeid(DataException)))
552 {
553 EventLogger::createSyncPel(
554 types::ErrorType::InvalidVpdMessage,
555 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
556 l_errMsg, std::nullopt, std::nullopt, std::nullopt,
557 std::nullopt);
558 }
559
560 logging::logMessage(l_errMsg);
561 }
562 return l_rc;
563 }
564
565 /**
566 * @brief API to reset data of a FRU populated under PIM.
567 *
568 * This API resets the data for particular interfaces of a FRU under PIM.
569 *
570 * @param[in] i_objectPath - DBus object path of the FRU.
571 * @param[in] io_interfaceMap - Interface and its properties map.
572 */
resetDataUnderPIM(const std::string & i_objectPath,types::InterfaceMap & io_interfaceMap)573 inline void resetDataUnderPIM(const std::string& i_objectPath,
574 types::InterfaceMap& io_interfaceMap)
575 {
576 try
577 {
578 std::array<const char*, 0> l_interfaces;
579 const types::MapperGetObject& l_getObjectMap =
580 dbusUtility::getObjectMap(i_objectPath, l_interfaces);
581
582 const std::vector<std::string>& l_vpdRelatedInterfaces{
583 constants::operationalStatusInf, constants::inventoryItemInf,
584 constants::assetInf};
585
586 for (const auto& [l_service, l_interfaceList] : l_getObjectMap)
587 {
588 if (l_service.compare(constants::pimServiceName) !=
589 constants::STR_CMP_SUCCESS)
590 {
591 continue;
592 }
593
594 for (const auto& l_interface : l_interfaceList)
595 {
596 if ((l_interface.find(constants::ipzVpdInf) !=
597 std::string::npos) ||
598 ((std::find(l_vpdRelatedInterfaces.begin(),
599 l_vpdRelatedInterfaces.end(), l_interface)) !=
600 l_vpdRelatedInterfaces.end()))
601 {
602 const types::PropertyMap& l_propertyValueMap =
603 dbusUtility::getPropertyMap(l_service, i_objectPath,
604 l_interface);
605
606 types::PropertyMap l_propertyMap;
607
608 for (const auto& l_aProperty : l_propertyValueMap)
609 {
610 const std::string& l_propertyName = l_aProperty.first;
611 const auto& l_propertyValue = l_aProperty.second;
612
613 if (std::holds_alternative<types::BinaryVector>(
614 l_propertyValue))
615 {
616 l_propertyMap.emplace(l_propertyName,
617 types::BinaryVector{});
618 }
619 else if (std::holds_alternative<std::string>(
620 l_propertyValue))
621 {
622 l_propertyMap.emplace(l_propertyName,
623 std::string{});
624 }
625 else if (std::holds_alternative<bool>(l_propertyValue))
626 {
627 // ToDo -- Update the functional status property
628 // to true.
629 if (l_propertyName.compare("Present") ==
630 constants::STR_CMP_SUCCESS)
631 {
632 l_propertyMap.emplace(l_propertyName, false);
633 }
634 }
635 }
636 io_interfaceMap.emplace(l_interface,
637 std::move(l_propertyMap));
638 }
639 }
640 }
641 }
642 catch (const std::exception& l_ex)
643 {
644 logging::logMessage("Failed to remove VPD for FRU: " + i_objectPath +
645 " with error: " + std::string(l_ex.what()));
646 }
647 }
648
649 /**
650 * @brief API to detect pass1 planar type.
651 *
652 * Based on HW version and IM keyword, This API detects is it is a pass1 planar
653 * or not.
654 *
655 * @return True if pass 1 planar, false otherwise.
656 */
isPass1Planar()657 inline bool isPass1Planar() noexcept
658 {
659 bool l_rc{false};
660 try
661 {
662 auto l_retVal = dbusUtility::readDbusProperty(
663 constants::pimServiceName, constants::systemVpdInvPath,
664 constants::viniInf, constants::kwdHW);
665
666 auto l_hwVer = std::get_if<types::BinaryVector>(&l_retVal);
667
668 l_retVal = dbusUtility::readDbusProperty(
669 constants::pimServiceName, constants::systemInvPath,
670 constants::vsbpInf, constants::kwdIM);
671
672 auto l_imValue = std::get_if<types::BinaryVector>(&l_retVal);
673
674 if (l_hwVer && l_imValue)
675 {
676 if (l_hwVer->size() != constants::VALUE_2)
677 {
678 throw std::runtime_error("Invalid HW keyword length.");
679 }
680
681 if (l_imValue->size() != constants::VALUE_4)
682 {
683 throw std::runtime_error("Invalid IM keyword length.");
684 }
685
686 const types::BinaryVector l_everest{80, 00, 48, 00};
687 const types::BinaryVector l_fuji{96, 00, 32, 00};
688
689 if (((*l_imValue) == l_everest) || ((*l_imValue) == l_fuji))
690 {
691 if ((*l_hwVer).at(1) < constants::VALUE_21)
692 {
693 l_rc = true;
694 }
695 }
696 else if ((*l_hwVer).at(1) < constants::VALUE_2)
697 {
698 l_rc = true;
699 }
700 }
701 }
702 catch (const std::exception& l_ex)
703 {
704 logging::logMessage("Failed to check for pass 1 planar. Error: " +
705 std::string(l_ex.what()));
706 }
707
708 return l_rc;
709 }
710
711 /**
712 * @brief API to detect if system configuration is that of PowerVS system.
713 *
714 * @param[in] i_imValue - IM value of the system.
715 * @return true if it is PowerVS configuration, false otherwise.
716 */
isPowerVsConfiguration(const types::BinaryVector & i_imValue)717 inline bool isPowerVsConfiguration(const types::BinaryVector& i_imValue)
718 {
719 if (i_imValue.empty() || i_imValue.size() != constants::VALUE_4)
720 {
721 return false;
722 }
723
724 // Should be a 0x5000XX series system.
725 if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
726 i_imValue.at(1) == constants::HEX_VALUE_00)
727 {
728 std::string l_imagePrefix = dbusUtility::getImagePrefix();
729
730 // Check image for 0x500030XX series.
731 if ((i_imValue.at(2) == constants::HEX_VALUE_30) &&
732 ((l_imagePrefix == constants::powerVsImagePrefix_MY) ||
733 (l_imagePrefix == constants::powerVsImagePrefix_NY)))
734 {
735 logging::logMessage("PowerVS configuration");
736 return true;
737 }
738
739 // Check image for 0X500010XX series.
740 if ((i_imValue.at(2) == constants::HEX_VALUE_10) &&
741 ((l_imagePrefix == constants::powerVsImagePrefix_MZ) ||
742 (l_imagePrefix == constants::powerVsImagePrefix_NZ)))
743 {
744 logging::logMessage("PowerVS configuration");
745 return true;
746 }
747 }
748 return false;
749 }
750
751 /**
752 * @brief API to get CCIN for a given FRU from DBus.
753 *
754 * The API reads the CCIN for a FRU based on its inventory path.
755 *
756 * @param[in] i_invObjPath - Inventory path of the FRU.
757 * @return CCIN of the FRU on success, empty string otherwise.
758 */
getCcinFromDbus(const std::string & i_invObjPath)759 inline std::string getCcinFromDbus(const std::string& i_invObjPath)
760 {
761 try
762 {
763 if (i_invObjPath.empty())
764 {
765 throw std::runtime_error("Empty EEPROM path, can't read CCIN");
766 }
767
768 const auto& l_retValue = dbusUtility::readDbusProperty(
769 constants::pimServiceName, i_invObjPath, constants::viniInf,
770 constants::kwdCCIN);
771
772 auto l_ptrCcin = std::get_if<types::BinaryVector>(&l_retValue);
773 if (!l_ptrCcin || (*l_ptrCcin).size() != constants::VALUE_4)
774 {
775 throw DbusException("Invalid CCIN read from Dbus");
776 }
777
778 return std::string((*l_ptrCcin).begin(), (*l_ptrCcin).end());
779 }
780 catch (const std::exception& l_ex)
781 {
782 logging::logMessage(l_ex.what());
783 return std::string{};
784 }
785 }
786 } // namespace vpdSpecificUtility
787 } // namespace vpd
788