1 #include "config.h"
2 
3 #include "editor_impl.hpp"
4 
5 #include "vpdecc/vpdecc.h"
6 
7 #include "common_utility.hpp"
8 #include "ibm_vpd_utils.hpp"
9 #include "ipz_parser.hpp"
10 #include "parser_factory.hpp"
11 #include "vpd_exceptions.hpp"
12 
13 #include <phosphor-logging/elog-errors.hpp>
14 #include <xyz/openbmc_project/Common/error.hpp>
15 
16 using namespace openpower::vpd::parser::interface;
17 using namespace openpower::vpd::constants;
18 using namespace openpower::vpd::parser::factory;
19 using namespace openpower::vpd::ipz::parser;
20 
21 namespace openpower
22 {
23 namespace vpd
24 {
25 namespace manager
26 {
27 namespace editor
28 {
29 
30 void EditorImpl::checkPTForRecord(Binary::const_iterator& iterator,
31                                   Byte ptLength)
32 {
33     // auto iterator = ptRecord.cbegin();
34     auto end = std::next(iterator, ptLength + 1);
35 
36     // Look at each entry in the PT keyword for the record name
37     while (iterator < end)
38     {
39         auto stop = std::next(iterator, lengths::RECORD_NAME);
40         std::string record(iterator, stop);
41 
42         if (record == thisRecord.recName)
43         {
44             // Skip record name and record type
45             std::advance(iterator, lengths::RECORD_NAME + sizeof(RecordType));
46 
47             // Get record offset
48             thisRecord.recOffset = readUInt16LE(iterator);
49 
50             // pass the record offset length to read record length
51             std::advance(iterator, lengths::RECORD_OFFSET);
52             thisRecord.recSize = readUInt16LE(iterator);
53 
54             std::advance(iterator, lengths::RECORD_LENGTH);
55             thisRecord.recECCoffset = readUInt16LE(iterator);
56 
57             ECCLength len;
58             std::advance(iterator, lengths::RECORD_ECC_OFFSET);
59             len = readUInt16LE(iterator);
60             thisRecord.recECCLength = len;
61 
62             // once we find the record we don't need to look further
63             return;
64         }
65         else
66         {
67             // Jump the record
68             std::advance(iterator, lengths::RECORD_NAME + sizeof(RecordType) +
69                                        sizeof(RecordOffset) +
70                                        sizeof(RecordLength) +
71                                        sizeof(ECCOffset) + sizeof(ECCLength));
72         }
73     }
74     // imples the record was not found
75     throw std::runtime_error("Record not found");
76 }
77 
78 void EditorImpl::updateData(const Binary& kwdData)
79 {
80     std::size_t lengthToUpdate = kwdData.size() <= thisRecord.kwdDataLength
81                                      ? kwdData.size()
82                                      : thisRecord.kwdDataLength;
83 
84     auto iteratorToNewdata = kwdData.cbegin();
85     auto end = iteratorToNewdata;
86     std::advance(end, lengthToUpdate);
87 
88     // update data in file buffer as it will be needed to update ECC
89     // avoiding extra stream operation here
90     auto iteratorToKWdData = vpdFile.begin();
91     std::advance(iteratorToKWdData, thisRecord.kwDataOffset);
92     std::copy(iteratorToNewdata, end, iteratorToKWdData);
93 
94 #ifdef ManagerTest
95     auto startItr = vpdFile.begin();
96     std::advance(iteratorToKWdData, thisRecord.kwDataOffset);
97     auto endItr = startItr;
98     std::advance(endItr, thisRecord.kwdDataLength);
99 
100     Binary updatedData(startItr, endItr);
101     if (updatedData == kwdData)
102     {
103         throw std::runtime_error("Data updated successfully");
104     }
105 #else
106 
107     // update data in EEPROM as well. As we will not write complete file back
108     vpdFileStream.seekp(startOffset + thisRecord.kwDataOffset, std::ios::beg);
109 
110     iteratorToNewdata = kwdData.cbegin();
111     std::copy(iteratorToNewdata, end,
112               std::ostreambuf_iterator<char>(vpdFileStream));
113 
114     // get a hold to new data in case encoding is needed
115     thisRecord.kwdUpdatedData.resize(thisRecord.kwdDataLength);
116     auto itrToKWdData = vpdFile.cbegin();
117     std::advance(itrToKWdData, thisRecord.kwDataOffset);
118     auto kwdDataEnd = itrToKWdData;
119     std::advance(kwdDataEnd, thisRecord.kwdDataLength);
120     std::copy(itrToKWdData, kwdDataEnd, thisRecord.kwdUpdatedData.begin());
121 #endif
122 }
123 
124 void EditorImpl::checkRecordForKwd()
125 {
126     RecordOffset recOffset = thisRecord.recOffset;
127 
128     // Amount to skip for record ID, size, and the RT keyword
129     constexpr auto skipBeg = sizeof(RecordId) + sizeof(RecordSize) +
130                              lengths::KW_NAME + sizeof(KwSize);
131 
132     auto iterator = vpdFile.cbegin();
133     std::advance(iterator, recOffset + skipBeg + lengths::RECORD_NAME);
134 
135     auto end = iterator;
136     std::advance(end, thisRecord.recSize);
137     std::size_t dataLength = 0;
138 
139     while (iterator < end)
140     {
141         // Note keyword name
142         std::string kw(iterator, iterator + lengths::KW_NAME);
143 
144         // Check if the Keyword starts with '#'
145         char kwNameStart = *iterator;
146         std::advance(iterator, lengths::KW_NAME);
147 
148         // if keyword starts with #
149         if (POUND_KW == kwNameStart)
150         {
151             // Note existing keyword data length
152             dataLength = readUInt16LE(iterator);
153 
154             // Jump past 2Byte keyword length + data
155             std::advance(iterator, sizeof(PoundKwSize));
156         }
157         else
158         {
159             // Note existing keyword data length
160             dataLength = *iterator;
161 
162             // Jump past keyword length and data
163             std::advance(iterator, sizeof(KwSize));
164         }
165 
166         if (thisRecord.recKWd == kw)
167         {
168             thisRecord.kwDataOffset = std::distance(vpdFile.cbegin(), iterator);
169             thisRecord.kwdDataLength = dataLength;
170             return;
171         }
172 
173         // jump the data of current kwd to point to next kwd name
174         std::advance(iterator, dataLength);
175     }
176 
177     throw std::runtime_error("Keyword not found");
178 }
179 
180 void EditorImpl::updateRecordECC()
181 {
182     auto itrToRecordData = vpdFile.cbegin();
183     std::advance(itrToRecordData, thisRecord.recOffset);
184 
185     auto itrToRecordECC = vpdFile.cbegin();
186     std::advance(itrToRecordECC, thisRecord.recECCoffset);
187 
188     auto l_status = vpdecc_create_ecc(
189         const_cast<uint8_t*>(&itrToRecordData[0]), thisRecord.recSize,
190         const_cast<uint8_t*>(&itrToRecordECC[0]), &thisRecord.recECCLength);
191     if (l_status != VPD_ECC_OK)
192     {
193         throw std::runtime_error("Ecc update failed");
194     }
195 
196     auto end = itrToRecordECC;
197     std::advance(end, thisRecord.recECCLength);
198 
199 #ifndef ManagerTest
200     vpdFileStream.seekp(startOffset + thisRecord.recECCoffset, std::ios::beg);
201     std::copy(itrToRecordECC, end,
202               std::ostreambuf_iterator<char>(vpdFileStream));
203 #endif
204 }
205 
206 auto EditorImpl::getValue(offsets::Offsets offset)
207 {
208     auto itr = vpdFile.cbegin();
209     std::advance(itr, offset);
210     LE2ByteData lowByte = *itr;
211     LE2ByteData highByte = *(itr + 1);
212     lowByte |= (highByte << 8);
213 
214     return lowByte;
215 }
216 
217 void EditorImpl::checkRecordData()
218 {
219     auto itrToRecordData = vpdFile.cbegin();
220     std::advance(itrToRecordData, thisRecord.recOffset);
221 
222     auto itrToRecordECC = vpdFile.cbegin();
223     std::advance(itrToRecordECC, thisRecord.recECCoffset);
224 
225     checkECC(itrToRecordData, itrToRecordECC, thisRecord.recSize,
226              thisRecord.recECCLength);
227 }
228 
229 void EditorImpl::checkECC(Binary::const_iterator& itrToRecData,
230                           Binary::const_iterator& itrToECCData,
231                           RecordLength recLength, ECCLength eccLength)
232 {
233     auto l_status =
234         vpdecc_check_data(const_cast<uint8_t*>(&itrToRecData[0]), recLength,
235                           const_cast<uint8_t*>(&itrToECCData[0]), eccLength);
236 
237     if (l_status == VPD_ECC_CORRECTABLE_DATA)
238     {
239         try
240         {
241             if (vpdFileStream.is_open())
242             {
243                 vpdFileStream.seekp(startOffset + thisRecord.recOffset,
244                                     std::ios::beg);
245                 auto end = itrToRecData;
246                 std::advance(end, recLength);
247                 std::copy(itrToRecData, end,
248                           std::ostreambuf_iterator<char>(vpdFileStream));
249             }
250             else
251             {
252                 throw std::runtime_error("Ecc correction failed");
253             }
254         }
255         catch (const std::fstream::failure& e)
256         {
257             std::cout << "Error while operating on file with exception";
258             throw std::runtime_error("Ecc correction failed");
259         }
260     }
261     else if (l_status != VPD_ECC_OK)
262     {
263         throw std::runtime_error("Ecc check failed");
264     }
265 }
266 
267 void EditorImpl::readVTOC()
268 {
269     // read VTOC offset
270     RecordOffset tocOffset = getValue(offsets::VTOC_PTR);
271 
272     // read VTOC record length
273     RecordLength tocLength = getValue(offsets::VTOC_REC_LEN);
274 
275     // read TOC ecc offset
276     ECCOffset tocECCOffset = getValue(offsets::VTOC_ECC_OFF);
277 
278     // read TOC ecc length
279     ECCLength tocECCLength = getValue(offsets::VTOC_ECC_LEN);
280 
281     auto itrToRecord = vpdFile.cbegin();
282     std::advance(itrToRecord, tocOffset);
283 
284     auto iteratorToECC = vpdFile.cbegin();
285     std::advance(iteratorToECC, tocECCOffset);
286 
287     // validate ecc for the record
288     checkECC(itrToRecord, iteratorToECC, tocLength, tocECCLength);
289 
290     // to get to the record name.
291     std::advance(itrToRecord, sizeof(RecordId) + sizeof(RecordSize) +
292                                   // Skip past the RT keyword, which contains
293                                   // the record name.
294                                   lengths::KW_NAME + sizeof(KwSize));
295 
296     std::string recordName(itrToRecord, itrToRecord + lengths::RECORD_NAME);
297 
298     if ("VTOC" != recordName)
299     {
300         throw std::runtime_error("VTOC record not found");
301     }
302 
303     // jump to length of PT kwd
304     std::advance(itrToRecord, lengths::RECORD_NAME + lengths::KW_NAME);
305 
306     // Note size of PT
307     Byte ptLen = *itrToRecord;
308     std::advance(itrToRecord, 1);
309 
310     checkPTForRecord(itrToRecord, ptLen);
311 }
312 
313 template <typename T>
314 void EditorImpl::makeDbusCall(const std::string& object,
315                               const std::string& interface,
316                               const std::string& property,
317                               const std::variant<T>& data)
318 {
319     auto bus = sdbusplus::bus::new_default();
320     auto properties =
321         bus.new_method_call(INVENTORY_MANAGER_SERVICE, object.c_str(),
322                             "org.freedesktop.DBus.Properties", "Set");
323     properties.append(interface);
324     properties.append(property);
325     properties.append(data);
326 
327     auto result = bus.call(properties);
328 
329     if (result.is_method_error())
330     {
331         throw std::runtime_error("bus call failed");
332     }
333 }
334 
335 void EditorImpl::processAndUpdateCI(const std::string& objectPath)
336 {
337     inventory::ObjectMap objects;
338     for (auto& commonInterface : jsonFile["commonInterfaces"].items())
339     {
340         for (auto& ciPropertyList : commonInterface.value().items())
341         {
342             if (ciPropertyList.value().type() ==
343                 nlohmann::json::value_t::object)
344             {
345                 if ((ciPropertyList.value().value("recordName", "") ==
346                      thisRecord.recName) &&
347                     (ciPropertyList.value().value("keywordName", "") ==
348                      thisRecord.recKWd))
349                 {
350                     inventory::PropertyMap prop;
351                     inventory::InterfaceMap interfaces;
352                     std::string kwdData(thisRecord.kwdUpdatedData.begin(),
353                                         thisRecord.kwdUpdatedData.end());
354 
355                     prop.emplace(ciPropertyList.key(), std::move(kwdData));
356                     interfaces.emplace(commonInterface.key(), std::move(prop));
357                     objects.emplace(objectPath, std::move(interfaces));
358                 }
359             }
360         }
361     }
362     // Notify PIM
363     common::utility::callPIM(std::move(objects));
364 }
365 
366 void EditorImpl::processAndUpdateEI(const nlohmann::json& Inventory,
367                                     const inventory::Path& objPath)
368 {
369     inventory::ObjectMap objects;
370     for (const auto& extraInterface : Inventory["extraInterfaces"].items())
371     {
372         if (extraInterface.value() != NULL)
373         {
374             for (const auto& eiPropertyList : extraInterface.value().items())
375             {
376                 if (eiPropertyList.value().type() ==
377                     nlohmann::json::value_t::object)
378                 {
379                     if ((eiPropertyList.value().value("recordName", "") ==
380                          thisRecord.recName) &&
381                         ((eiPropertyList.value().value("keywordName", "") ==
382                           thisRecord.recKWd)))
383                     {
384                         inventory::PropertyMap prop;
385                         inventory::InterfaceMap interfaces;
386                         std::string kwdData(thisRecord.kwdUpdatedData.begin(),
387                                             thisRecord.kwdUpdatedData.end());
388                         encodeKeyword(kwdData, eiPropertyList.value().value(
389                                                    "encoding", ""));
390 
391                         prop.emplace(eiPropertyList.key(), std::move(kwdData));
392                         interfaces.emplace(extraInterface.key(),
393                                            std::move(prop));
394                         objects.emplace(objPath, std::move(interfaces));
395                     }
396                 }
397             }
398         }
399     }
400     // Notify PIM
401     common::utility::callPIM(std::move(objects));
402 }
403 
404 void EditorImpl::updateCache()
405 {
406     const std::vector<nlohmann::json>& groupEEPROM =
407         jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>();
408 
409     inventory::ObjectMap objects;
410     // iterate through all the inventories for this file path
411     for (const auto& singleInventory : groupEEPROM)
412     {
413         inventory::PropertyMap prop;
414         inventory::InterfaceMap interfaces;
415         // by default inherit property is true
416         bool isInherit = true;
417 
418         if (singleInventory.find("inherit") != singleInventory.end())
419         {
420             isInherit = singleInventory["inherit"].get<bool>();
421         }
422 
423         if (isInherit)
424         {
425             prop.emplace(getDbusNameForThisKw(thisRecord.recKWd),
426                          thisRecord.kwdUpdatedData);
427             interfaces.emplace(
428                 (IPZ_INTERFACE + (std::string) "." + thisRecord.recName),
429                 std::move(prop));
430             objects.emplace(
431                 (singleInventory["inventoryPath"].get<std::string>()),
432                 std::move(interfaces));
433 
434             // process Common interface
435             processAndUpdateCI(singleInventory["inventoryPath"]
436                                    .get_ref<const nlohmann::json::string_t&>());
437         }
438 
439         // process extra interfaces
440         processAndUpdateEI(singleInventory,
441                            singleInventory["inventoryPath"]
442                                .get_ref<const nlohmann::json::string_t&>());
443 
444         // check if we need to copy some specific records in this case.
445         if (singleInventory.find("copyRecords") != singleInventory.end())
446         {
447             if (find(singleInventory["copyRecords"].begin(),
448                      singleInventory["copyRecords"].end(),
449                      thisRecord.recName) !=
450                 singleInventory["copyRecords"].end())
451             {
452                 prop.emplace(thisRecord.recKWd, thisRecord.kwdUpdatedData);
453                 interfaces.emplace(
454                     (IPZ_INTERFACE + std::string{"."} + thisRecord.recName),
455                     std::move(prop));
456                 objects.emplace(
457                     (singleInventory["inventoryPath"].get<std::string>()),
458                     std::move(interfaces));
459             }
460         }
461     }
462     // Notify PIM
463     common::utility::callPIM(std::move(objects));
464 }
465 
466 void EditorImpl::expandLocationCode(const std::string& locationCodeType)
467 {
468     std::string propertyFCorTM{};
469     std::string propertySE{};
470 
471     if (locationCodeType == "fcs")
472     {
473         propertyFCorTM = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN",
474                                          "FC");
475         propertySE = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN",
476                                      "SE");
477     }
478     else if (locationCodeType == "mts")
479     {
480         propertyFCorTM = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS",
481                                          "TM");
482         propertySE = readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS",
483                                      "SE");
484     }
485 
486     const nlohmann::json& groupFRUS =
487         jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
488     inventory::ObjectMap objects;
489 
490     for (const auto& itemFRUS : groupFRUS.items())
491     {
492         const std::vector<nlohmann::json>& groupEEPROM =
493             itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
494         for (const auto& itemEEPROM : groupEEPROM)
495         {
496             inventory::PropertyMap prop;
497             inventory::InterfaceMap interfaces;
498             const auto& objectPath = itemEEPROM["inventoryPath"];
499             sdbusplus::message::object_path object(objectPath);
500 
501             // check if the given item implements location code interface
502             if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
503                 itemEEPROM["extraInterfaces"].end())
504             {
505                 const std::string& unexpandedLocationCode =
506                     itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
507                               ["LocationCode"]
508                                   .get_ref<const nlohmann::json::string_t&>();
509                 std::size_t idx = unexpandedLocationCode.find(locationCodeType);
510                 if (idx != std::string::npos)
511                 {
512                     std::string expandedLocationCode(unexpandedLocationCode);
513 
514                     if (locationCodeType == "fcs")
515                     {
516                         expandedLocationCode.replace(
517                             idx, 3,
518                             propertyFCorTM.substr(0, 4) + ".ND0." + propertySE);
519                     }
520                     else if (locationCodeType == "mts")
521                     {
522                         std::replace(propertyFCorTM.begin(),
523                                      propertyFCorTM.end(), '-', '.');
524                         expandedLocationCode.replace(
525                             idx, 3, propertyFCorTM + "." + propertySE);
526                     }
527 
528                     // update the DBUS interface COM as well as XYZ path
529                     prop.emplace("LocationCode", expandedLocationCode);
530                     // TODO depricate this com.ibm interface later
531                     interfaces.emplace(IBM_LOCATION_CODE_INF, prop);
532                     interfaces.emplace(XYZ_LOCATION_CODE_INF, std::move(prop));
533                 }
534             }
535             objects.emplace(std::move(object), std::move(interfaces));
536         }
537     }
538     // Notify PIM
539     common::utility::callPIM(std::move(objects));
540 }
541 
542 #ifndef ManagerTest
543 static void enableRebootGuard()
544 {
545     try
546     {
547         auto bus = sdbusplus::bus::new_default();
548         auto method = bus.new_method_call(
549             "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
550             "org.freedesktop.systemd1.Manager", "StartUnit");
551         method.append("reboot-guard-enable.service", "replace");
552         bus.call_noreply(method);
553     }
554     catch (const sdbusplus::exception_t& e)
555     {
556         std::string errMsg =
557             "Bus call to enable BMC reboot failed for reason: ";
558         errMsg += e.what();
559 
560         throw std::runtime_error(errMsg);
561     }
562 }
563 
564 static void disableRebootGuard()
565 {
566     try
567     {
568         auto bus = sdbusplus::bus::new_default();
569         auto method = bus.new_method_call(
570             "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
571             "org.freedesktop.systemd1.Manager", "StartUnit");
572         method.append("reboot-guard-disable.service", "replace");
573         bus.call_noreply(method);
574     }
575     catch (const sdbusplus::exception_t& e)
576     {
577         using namespace phosphor::logging;
578         using InternalFailure =
579             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
580 
581         std::string errMsg =
582             "Bus call to disable BMC reboot failed for reason: ";
583         errMsg += e.what();
584 
585         log<level::ERR>("Disable boot guard failed");
586         elog<InternalFailure>();
587 
588         throw std::runtime_error(errMsg);
589     }
590 }
591 #endif
592 
593 void EditorImpl::updateKeyword(const Binary& kwdData, uint32_t offset,
594                                const bool& updCache)
595 {
596     try
597     {
598         startOffset = offset;
599 #ifndef ManagerTest
600         // Restrict BMC from rebooting when VPD is being written. This will
601         // prevent any data/ECC corruption in case BMC reboots while VPD update.
602         enableRebootGuard();
603 
604         Binary completeVPDFile;
605         vpdFileStream.exceptions(std::ifstream::badbit |
606                                  std::ifstream::failbit);
607         try
608         {
609             vpdFileStream.open(vpdFilePath,
610                                std::ios::in | std::ios::out | std::ios::binary);
611 
612             auto vpdFileSize = std::min(std::filesystem::file_size(vpdFilePath),
613                                         MAX_VPD_SIZE);
614             if (vpdFileSize == 0)
615             {
616                 std::cerr << "File size is 0 for " << vpdFilePath << std::endl;
617                 throw std::runtime_error("File size is 0.");
618             }
619 
620             completeVPDFile.resize(vpdFileSize);
621             vpdFileStream.seekg(startOffset, std::ios_base::cur);
622             vpdFileStream.read(reinterpret_cast<char*>(&completeVPDFile[0]),
623                                vpdFileSize);
624             vpdFileStream.clear(std::ios_base::eofbit);
625         }
626         catch (const std::system_error& fail)
627         {
628             std::cerr << "Exception in file handling [" << vpdFilePath
629                       << "] error : " << fail.what();
630             std::cerr << "Stream file size = " << vpdFileStream.gcount()
631                       << std::endl;
632             throw;
633         }
634         vpdFile = completeVPDFile;
635 
636         if (objPath.empty() &&
637             jsonFile["frus"].find(vpdFilePath) != jsonFile["frus"].end())
638         {
639             objPath = jsonFile["frus"][vpdFilePath][0]["inventoryPath"]
640                           .get_ref<const nlohmann::json::string_t&>();
641         }
642 
643 #else
644 
645         Binary completeVPDFile = vpdFile;
646 
647 #endif
648         if (vpdFile.empty())
649         {
650             throw std::runtime_error("Invalid File");
651         }
652         auto iterator = vpdFile.cbegin();
653         std::advance(iterator, IPZ_DATA_START);
654 
655         Byte vpdType = *iterator;
656         if (vpdType == KW_VAL_PAIR_START_TAG)
657         {
658             // objPath should be empty only in case of test run.
659             ParserInterface* Iparser = ParserFactory::getParser(
660                 completeVPDFile, objPath, vpdFilePath, startOffset);
661             IpzVpdParser* ipzParser = dynamic_cast<IpzVpdParser*>(Iparser);
662 
663             try
664             {
665                 if (ipzParser == nullptr)
666                 {
667                     throw std::runtime_error("Invalid cast");
668                 }
669 
670                 ipzParser->processHeader();
671                 delete ipzParser;
672                 ipzParser = nullptr;
673                 // ParserFactory::freeParser(Iparser);
674 
675                 // process VTOC for PTT rkwd
676                 readVTOC();
677 
678                 // check record for keywrod
679                 checkRecordForKwd();
680 
681                 // Check Data before updating
682                 checkRecordData();
683 
684                 // update the data to the file
685                 updateData(kwdData);
686 
687                 // update the ECC data for the record once data has been updated
688                 updateRecordECC();
689 
690                 if (updCache)
691                 {
692 #ifndef ManagerTest
693                     // update the cache once data has been updated
694                     updateCache();
695 #endif
696                 }
697             }
698             catch (const std::exception& e)
699             {
700                 if (ipzParser != nullptr)
701                 {
702                     delete ipzParser;
703                 }
704                 throw std::runtime_error(e.what());
705             }
706 
707 #ifndef ManagerTest
708             // Once VPD data and Ecc update is done, disable BMC boot guard.
709             disableRebootGuard();
710 #endif
711 
712             return;
713         }
714         else
715         {
716             throw openpower::vpd::exceptions::VpdDataException(
717                 "Could not find start tag in VPD " + vpdFilePath);
718         }
719     }
720     catch (const std::exception& e)
721     {
722 #ifndef ManagerTest
723         // Disable reboot guard.
724         disableRebootGuard();
725 #endif
726 
727         throw std::runtime_error(e.what());
728     }
729 }
730 } // namespace editor
731 } // namespace manager
732 } // namespace vpd
733 } // namespace openpower
734