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