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 
checkPTForRecord(Binary::const_iterator & iterator,Byte ptLength)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,
69                          lengths::RECORD_NAME + sizeof(RecordType) +
70                              sizeof(RecordOffset) + 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 
updateData(const Binary & kwdData)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 
checkRecordForKwd()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 
updateRecordECC()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 
getValue(offsets::Offsets offset)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 
checkRecordData()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 
checkECC(Binary::const_iterator & itrToRecData,Binary::const_iterator & itrToECCData,RecordLength recLength,ECCLength eccLength)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 
readVTOC()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>
makeDbusCall(const std::string & object,const std::string & interface,const std::string & property,const std::variant<T> & data)314 void EditorImpl::makeDbusCall(
315     const std::string& object, const std::string& interface,
316     const std::string& property, const std::variant<T>& data)
317 {
318     auto bus = sdbusplus::bus::new_default();
319     auto properties =
320         bus.new_method_call(INVENTORY_MANAGER_SERVICE, object.c_str(),
321                             "org.freedesktop.DBus.Properties", "Set");
322     properties.append(interface);
323     properties.append(property);
324     properties.append(data);
325 
326     auto result = bus.call(properties);
327 
328     if (result.is_method_error())
329     {
330         throw std::runtime_error("bus call failed");
331     }
332 }
333 
processAndUpdateCI(const std::string & objectPath)334 void EditorImpl::processAndUpdateCI(const std::string& objectPath)
335 {
336     inventory::ObjectMap objects;
337     for (auto& commonInterface : jsonFile["commonInterfaces"].items())
338     {
339         for (auto& ciPropertyList : commonInterface.value().items())
340         {
341             if (ciPropertyList.value().type() ==
342                 nlohmann::json::value_t::object)
343             {
344                 if ((ciPropertyList.value().value("recordName", "") ==
345                      thisRecord.recName) &&
346                     (ciPropertyList.value().value("keywordName", "") ==
347                      thisRecord.recKWd))
348                 {
349                     inventory::PropertyMap prop;
350                     inventory::InterfaceMap interfaces;
351                     std::string kwdData(thisRecord.kwdUpdatedData.begin(),
352                                         thisRecord.kwdUpdatedData.end());
353 
354                     prop.emplace(ciPropertyList.key(), std::move(kwdData));
355                     interfaces.emplace(commonInterface.key(), std::move(prop));
356                     objects.emplace(objectPath, std::move(interfaces));
357                 }
358             }
359         }
360     }
361     // Notify PIM
362     common::utility::callPIM(std::move(objects));
363 }
364 
processAndUpdateEI(const nlohmann::json & Inventory,const inventory::Path & objPath)365 void EditorImpl::processAndUpdateEI(const nlohmann::json& Inventory,
366                                     const inventory::Path& objPath)
367 {
368     inventory::ObjectMap objects;
369     for (const auto& extraInterface : Inventory["extraInterfaces"].items())
370     {
371         if (extraInterface.value() != NULL)
372         {
373             for (const auto& eiPropertyList : extraInterface.value().items())
374             {
375                 if (eiPropertyList.value().type() ==
376                     nlohmann::json::value_t::object)
377                 {
378                     if ((eiPropertyList.value().value("recordName", "") ==
379                          thisRecord.recName) &&
380                         ((eiPropertyList.value().value("keywordName", "") ==
381                           thisRecord.recKWd)))
382                     {
383                         inventory::PropertyMap prop;
384                         inventory::InterfaceMap interfaces;
385                         std::string kwdData(thisRecord.kwdUpdatedData.begin(),
386                                             thisRecord.kwdUpdatedData.end());
387                         encodeKeyword(kwdData, eiPropertyList.value().value(
388                                                    "encoding", ""));
389 
390                         prop.emplace(eiPropertyList.key(), std::move(kwdData));
391                         interfaces.emplace(extraInterface.key(),
392                                            std::move(prop));
393                         objects.emplace(objPath, std::move(interfaces));
394                     }
395                 }
396             }
397         }
398     }
399     // Notify PIM
400     common::utility::callPIM(std::move(objects));
401 }
402 
updateCache()403 void EditorImpl::updateCache()
404 {
405     const std::vector<nlohmann::json>& groupEEPROM =
406         jsonFile["frus"][vpdFilePath].get_ref<const nlohmann::json::array_t&>();
407 
408     inventory::ObjectMap objects;
409     // iterate through all the inventories for this file path
410     for (const auto& singleInventory : groupEEPROM)
411     {
412         inventory::PropertyMap prop;
413         inventory::InterfaceMap interfaces;
414         // by default inherit property is true
415         bool isInherit = true;
416 
417         if (singleInventory.find("inherit") != singleInventory.end())
418         {
419             isInherit = singleInventory["inherit"].get<bool>();
420         }
421 
422         if (isInherit)
423         {
424             prop.emplace(getDbusNameForThisKw(thisRecord.recKWd),
425                          thisRecord.kwdUpdatedData);
426             interfaces.emplace(
427                 (IPZ_INTERFACE + (std::string) "." + thisRecord.recName),
428                 std::move(prop));
429             objects.emplace(
430                 (singleInventory["inventoryPath"].get<std::string>()),
431                 std::move(interfaces));
432 
433             // process Common interface
434             processAndUpdateCI(singleInventory["inventoryPath"]
435                                    .get_ref<const nlohmann::json::string_t&>());
436         }
437 
438         // process extra interfaces
439         processAndUpdateEI(singleInventory,
440                            singleInventory["inventoryPath"]
441                                .get_ref<const nlohmann::json::string_t&>());
442 
443         // check if we need to copy some specific records in this case.
444         if (singleInventory.find("copyRecords") != singleInventory.end())
445         {
446             if (find(singleInventory["copyRecords"].begin(),
447                      singleInventory["copyRecords"].end(),
448                      thisRecord.recName) !=
449                 singleInventory["copyRecords"].end())
450             {
451                 prop.emplace(thisRecord.recKWd, thisRecord.kwdUpdatedData);
452                 interfaces.emplace(
453                     (IPZ_INTERFACE + std::string{"."} + thisRecord.recName),
454                     std::move(prop));
455                 objects.emplace(
456                     (singleInventory["inventoryPath"].get<std::string>()),
457                     std::move(interfaces));
458             }
459         }
460     }
461     // Notify PIM
462     common::utility::callPIM(std::move(objects));
463 }
464 
expandLocationCode(const std::string & locationCodeType)465 void EditorImpl::expandLocationCode(const std::string& locationCodeType)
466 {
467     std::string propertyFCorTM{};
468     std::string propertySE{};
469 
470     if (locationCodeType == "fcs")
471     {
472         propertyFCorTM =
473             readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "FC");
474         propertySE =
475             readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "SE");
476     }
477     else if (locationCodeType == "mts")
478     {
479         propertyFCorTM =
480             readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "TM");
481         propertySE =
482             readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "SE");
483     }
484 
485     const nlohmann::json& groupFRUS =
486         jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
487     inventory::ObjectMap objects;
488 
489     for (const auto& itemFRUS : groupFRUS.items())
490     {
491         const std::vector<nlohmann::json>& groupEEPROM =
492             itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
493         for (const auto& itemEEPROM : groupEEPROM)
494         {
495             inventory::PropertyMap prop;
496             inventory::InterfaceMap interfaces;
497             const auto& objectPath = itemEEPROM["inventoryPath"];
498             sdbusplus::message::object_path object(objectPath);
499 
500             // check if the given item implements location code interface
501             if (itemEEPROM["extraInterfaces"].find(IBM_LOCATION_CODE_INF) !=
502                 itemEEPROM["extraInterfaces"].end())
503             {
504                 const std::string& unexpandedLocationCode =
505                     itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
506                               ["LocationCode"]
507                                   .get_ref<const nlohmann::json::string_t&>();
508                 std::size_t idx = unexpandedLocationCode.find(locationCodeType);
509                 if (idx != std::string::npos)
510                 {
511                     std::string expandedLocationCode(unexpandedLocationCode);
512 
513                     if (locationCodeType == "fcs")
514                     {
515                         expandedLocationCode.replace(
516                             idx, 3,
517                             propertyFCorTM.substr(0, 4) + ".ND0." + propertySE);
518                     }
519                     else if (locationCodeType == "mts")
520                     {
521                         std::replace(propertyFCorTM.begin(),
522                                      propertyFCorTM.end(), '-', '.');
523                         expandedLocationCode.replace(
524                             idx, 3, propertyFCorTM + "." + propertySE);
525                     }
526 
527                     // update the DBUS interface COM as well as XYZ path
528                     prop.emplace("LocationCode", expandedLocationCode);
529                     // TODO deprecate this com.ibm interface later
530                     interfaces.emplace(IBM_LOCATION_CODE_INF, prop);
531                     interfaces.emplace(XYZ_LOCATION_CODE_INF, std::move(prop));
532                 }
533             }
534             objects.emplace(std::move(object), std::move(interfaces));
535         }
536     }
537     // Notify PIM
538     common::utility::callPIM(std::move(objects));
539 }
540 
541 #ifndef ManagerTest
enableRebootGuard()542 static void enableRebootGuard()
543 {
544     try
545     {
546         auto bus = sdbusplus::bus::new_default();
547         auto method = bus.new_method_call(
548             "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
549             "org.freedesktop.systemd1.Manager", "StartUnit");
550         method.append("reboot-guard-enable.service", "replace");
551         bus.call_noreply(method);
552     }
553     catch (const sdbusplus::exception_t& e)
554     {
555         std::string errMsg =
556             "Bus call to enable BMC reboot failed for reason: ";
557         errMsg += e.what();
558 
559         throw std::runtime_error(errMsg);
560     }
561 }
562 
disableRebootGuard()563 static void disableRebootGuard()
564 {
565     try
566     {
567         auto bus = sdbusplus::bus::new_default();
568         auto method = bus.new_method_call(
569             "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
570             "org.freedesktop.systemd1.Manager", "StartUnit");
571         method.append("reboot-guard-disable.service", "replace");
572         bus.call_noreply(method);
573     }
574     catch (const sdbusplus::exception_t& e)
575     {
576         using namespace phosphor::logging;
577         using InternalFailure =
578             sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
579 
580         std::string errMsg =
581             "Bus call to disable BMC reboot failed for reason: ";
582         errMsg += e.what();
583 
584         log<level::ERR>("Disable boot guard failed");
585         elog<InternalFailure>();
586 
587         throw std::runtime_error(errMsg);
588     }
589 }
590 #endif
591 
updateKeyword(const Binary & kwdData,uint32_t offset,const bool & updCache)592 void EditorImpl::updateKeyword(const Binary& kwdData, uint32_t offset,
593                                const bool& updCache)
594 {
595     try
596     {
597         startOffset = offset;
598 #ifndef ManagerTest
599         // Restrict BMC from rebooting when VPD is being written. This will
600         // prevent any data/ECC corruption in case BMC reboots while VPD update.
601         enableRebootGuard();
602 
603         Binary completeVPDFile;
604         vpdFileStream.exceptions(
605             std::ifstream::badbit | std::ifstream::failbit);
606         try
607         {
608             vpdFileStream.open(vpdFilePath,
609                                std::ios::in | std::ios::out | std::ios::binary);
610 
611             auto vpdFileSize =
612                 std::min(std::filesystem::file_size(vpdFilePath), MAX_VPD_SIZE);
613             if (vpdFileSize == 0)
614             {
615                 std::cerr << "File size is 0 for " << vpdFilePath << std::endl;
616                 throw std::runtime_error("File size is 0.");
617             }
618 
619             completeVPDFile.resize(vpdFileSize);
620             vpdFileStream.seekg(startOffset, std::ios_base::cur);
621             vpdFileStream.read(reinterpret_cast<char*>(&completeVPDFile[0]),
622                                vpdFileSize);
623             vpdFileStream.clear(std::ios_base::eofbit);
624         }
625         catch (const std::system_error& fail)
626         {
627             std::cerr << "Exception in file handling [" << vpdFilePath
628                       << "] error : " << fail.what();
629             std::cerr << "Stream file size = " << vpdFileStream.gcount()
630                       << std::endl;
631             throw;
632         }
633         vpdFile = completeVPDFile;
634 
635         if (objPath.empty() &&
636             jsonFile["frus"].find(vpdFilePath) != jsonFile["frus"].end())
637         {
638             objPath = jsonFile["frus"][vpdFilePath][0]["inventoryPath"]
639                           .get_ref<const nlohmann::json::string_t&>();
640         }
641 
642 #else
643 
644         Binary completeVPDFile = vpdFile;
645 
646 #endif
647         if (vpdFile.empty())
648         {
649             throw std::runtime_error("Invalid File");
650         }
651         auto iterator = vpdFile.cbegin();
652         std::advance(iterator, IPZ_DATA_START);
653 
654         Byte vpdType = *iterator;
655         if (vpdType == KW_VAL_PAIR_START_TAG)
656         {
657             // objPath should be empty only in case of test run.
658             ParserInterface* Iparser = ParserFactory::getParser(
659                 completeVPDFile, objPath, vpdFilePath, startOffset);
660             IpzVpdParser* ipzParser = dynamic_cast<IpzVpdParser*>(Iparser);
661 
662             try
663             {
664                 if (ipzParser == nullptr)
665                 {
666                     throw std::runtime_error("Invalid cast");
667                 }
668 
669                 ipzParser->processHeader();
670                 delete ipzParser;
671                 ipzParser = nullptr;
672                 // ParserFactory::freeParser(Iparser);
673 
674                 // process VTOC for PTT rkwd
675                 readVTOC();
676 
677                 // check record for keywrod
678                 checkRecordForKwd();
679 
680                 // Check Data before updating
681                 checkRecordData();
682 
683                 // update the data to the file
684                 updateData(kwdData);
685 
686                 // update the ECC data for the record once data has been updated
687                 updateRecordECC();
688 
689                 if (updCache)
690                 {
691 #ifndef ManagerTest
692                     // update the cache once data has been updated
693                     updateCache();
694 #endif
695                 }
696             }
697             catch (const std::exception& e)
698             {
699                 if (ipzParser != nullptr)
700                 {
701                     delete ipzParser;
702                 }
703                 throw std::runtime_error(e.what());
704             }
705 
706 #ifndef ManagerTest
707             // Once VPD data and Ecc update is done, disable BMC boot guard.
708             disableRebootGuard();
709 #endif
710 
711             return;
712         }
713         else
714         {
715             throw openpower::vpd::exceptions::VpdDataException(
716                 "Could not find start tag in VPD " + vpdFilePath);
717         }
718     }
719     catch (const std::exception& e)
720     {
721 #ifndef ManagerTest
722         // Disable reboot guard.
723         disableRebootGuard();
724 #endif
725 
726         throw std::runtime_error(e.what());
727     }
728 }
729 } // namespace editor
730 } // namespace manager
731 } // namespace vpd
732 } // namespace openpower
733