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, 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
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(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
processAndUpdateCI(const std::string & objectPath)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
processAndUpdateEI(const nlohmann::json & Inventory,const inventory::Path & objPath)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
updateCache()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
expandLocationCode(const std::string & locationCodeType)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 deprecate 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
enableRebootGuard()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
disableRebootGuard()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
updateKeyword(const Binary & kwdData,uint32_t offset,const bool & updCache)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