1711d51d8SMatt Spinler /** 2711d51d8SMatt Spinler * Copyright © 2019 IBM Corporation 3711d51d8SMatt Spinler * 4711d51d8SMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License"); 5711d51d8SMatt Spinler * you may not use this file except in compliance with the License. 6711d51d8SMatt Spinler * You may obtain a copy of the License at 7711d51d8SMatt Spinler * 8711d51d8SMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0 9711d51d8SMatt Spinler * 10711d51d8SMatt Spinler * Unless required by applicable law or agreed to in writing, software 11711d51d8SMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS, 12711d51d8SMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13711d51d8SMatt Spinler * See the License for the specific language governing permissions and 14711d51d8SMatt Spinler * limitations under the License. 15711d51d8SMatt Spinler */ 1689fa082aSMatt Spinler #include "repository.hpp" 1789fa082aSMatt Spinler 18*dd325c32SMatt Spinler #include <sys/stat.h> 19*dd325c32SMatt Spinler 2089fa082aSMatt Spinler #include <fstream> 2189fa082aSMatt Spinler #include <phosphor-logging/log.hpp> 2289fa082aSMatt Spinler #include <xyz/openbmc_project/Common/File/error.hpp> 2389fa082aSMatt Spinler 2489fa082aSMatt Spinler namespace openpower 2589fa082aSMatt Spinler { 2689fa082aSMatt Spinler namespace pels 2789fa082aSMatt Spinler { 2889fa082aSMatt Spinler 2989fa082aSMatt Spinler namespace fs = std::filesystem; 3089fa082aSMatt Spinler using namespace phosphor::logging; 3189fa082aSMatt Spinler namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error; 3289fa082aSMatt Spinler 33*dd325c32SMatt Spinler /** 34*dd325c32SMatt Spinler * @brief Returns the amount of space the file uses on disk. 35*dd325c32SMatt Spinler * 36*dd325c32SMatt Spinler * This is different than just the regular size of the file. 37*dd325c32SMatt Spinler * 38*dd325c32SMatt Spinler * @param[in] file - The file to get the size of 39*dd325c32SMatt Spinler * 40*dd325c32SMatt Spinler * @return size_t The disk space the file uses 41*dd325c32SMatt Spinler */ 42*dd325c32SMatt Spinler size_t getFileDiskSize(const std::filesystem::path& file) 43*dd325c32SMatt Spinler { 44*dd325c32SMatt Spinler constexpr size_t statBlockSize = 512; 45*dd325c32SMatt Spinler struct stat statData; 46*dd325c32SMatt Spinler auto rc = stat(file.c_str(), &statData); 47*dd325c32SMatt Spinler if (rc != 0) 48*dd325c32SMatt Spinler { 49*dd325c32SMatt Spinler auto e = errno; 50*dd325c32SMatt Spinler std::string msg = "call to stat() failed on " + file.native() + 51*dd325c32SMatt Spinler " with errno " + std::to_string(e); 52*dd325c32SMatt Spinler log<level::ERR>(msg.c_str()); 53*dd325c32SMatt Spinler abort(); 54*dd325c32SMatt Spinler } 55*dd325c32SMatt Spinler 56*dd325c32SMatt Spinler return statData.st_blocks * statBlockSize; 57*dd325c32SMatt Spinler } 58*dd325c32SMatt Spinler 598d5f3a2bSMatt Spinler Repository::Repository(const std::filesystem::path& basePath, size_t repoSize, 608d5f3a2bSMatt Spinler size_t maxNumPELs) : 618d5f3a2bSMatt Spinler _logPath(basePath / "logs"), 628d5f3a2bSMatt Spinler _maxRepoSize(repoSize), _maxNumPELs(maxNumPELs) 6389fa082aSMatt Spinler { 6489fa082aSMatt Spinler if (!fs::exists(_logPath)) 6589fa082aSMatt Spinler { 6689fa082aSMatt Spinler fs::create_directories(_logPath); 6789fa082aSMatt Spinler } 68475e574dSMatt Spinler 69475e574dSMatt Spinler restore(); 70475e574dSMatt Spinler } 71475e574dSMatt Spinler 72475e574dSMatt Spinler void Repository::restore() 73475e574dSMatt Spinler { 74475e574dSMatt Spinler for (auto& dirEntry : fs::directory_iterator(_logPath)) 75475e574dSMatt Spinler { 76475e574dSMatt Spinler try 77475e574dSMatt Spinler { 78475e574dSMatt Spinler if (!fs::is_regular_file(dirEntry.path())) 79475e574dSMatt Spinler { 80475e574dSMatt Spinler continue; 81475e574dSMatt Spinler } 82475e574dSMatt Spinler 83475e574dSMatt Spinler std::ifstream file{dirEntry.path()}; 84475e574dSMatt Spinler std::vector<uint8_t> data{std::istreambuf_iterator<char>(file), 85475e574dSMatt Spinler std::istreambuf_iterator<char>()}; 86475e574dSMatt Spinler file.close(); 87475e574dSMatt Spinler 8807eefc54SMatt Spinler PEL pel{data}; 89475e574dSMatt Spinler if (pel.valid()) 90475e574dSMatt Spinler { 91a3c12a48SMatt Spinler // If the host hasn't acked it, reset the host state so 92a3c12a48SMatt Spinler // it will get sent up again. 93a3c12a48SMatt Spinler if (pel.hostTransmissionState() == TransmissionState::sent) 94a3c12a48SMatt Spinler { 95a3c12a48SMatt Spinler pel.setHostTransmissionState(TransmissionState::newPEL); 96a3c12a48SMatt Spinler try 97a3c12a48SMatt Spinler { 98a3c12a48SMatt Spinler write(pel, dirEntry.path()); 99a3c12a48SMatt Spinler } 100a3c12a48SMatt Spinler catch (std::exception& e) 101a3c12a48SMatt Spinler { 102a3c12a48SMatt Spinler log<level::ERR>( 103a3c12a48SMatt Spinler "Failed to save PEL after updating host state", 104a3c12a48SMatt Spinler entry("PELID=0x%X", pel.id())); 105a3c12a48SMatt Spinler } 106a3c12a48SMatt Spinler } 107a3c12a48SMatt Spinler 108*dd325c32SMatt Spinler PELAttributes attributes{dirEntry.path(), 109*dd325c32SMatt Spinler getFileDiskSize(dirEntry.path()), 110*dd325c32SMatt Spinler pel.privateHeader().creatorID(), 111*dd325c32SMatt Spinler pel.userHeader().severity(), 112*dd325c32SMatt Spinler pel.userHeader().actionFlags(), 113*dd325c32SMatt Spinler pel.hostTransmissionState(), 114*dd325c32SMatt Spinler pel.hmcTransmissionState()}; 1150ff00485SMatt Spinler 116475e574dSMatt Spinler using pelID = LogID::Pel; 117475e574dSMatt Spinler using obmcID = LogID::Obmc; 1180ff00485SMatt Spinler _pelAttributes.emplace( 119475e574dSMatt Spinler LogID(pelID(pel.id()), obmcID(pel.obmcLogID())), 1200ff00485SMatt Spinler attributes); 121475e574dSMatt Spinler } 122475e574dSMatt Spinler else 123475e574dSMatt Spinler { 124475e574dSMatt Spinler log<level::ERR>( 125475e574dSMatt Spinler "Found invalid PEL file while restoring. Removing.", 126475e574dSMatt Spinler entry("FILENAME=%s", dirEntry.path().c_str())); 127475e574dSMatt Spinler fs::remove(dirEntry.path()); 128475e574dSMatt Spinler } 129475e574dSMatt Spinler } 130475e574dSMatt Spinler catch (std::exception& e) 131475e574dSMatt Spinler { 132475e574dSMatt Spinler log<level::ERR>("Hit exception while restoring PEL File", 133475e574dSMatt Spinler entry("FILENAME=%s", dirEntry.path().c_str()), 134475e574dSMatt Spinler entry("ERROR=%s", e.what())); 135475e574dSMatt Spinler } 136475e574dSMatt Spinler } 13789fa082aSMatt Spinler } 13889fa082aSMatt Spinler 13989fa082aSMatt Spinler std::string Repository::getPELFilename(uint32_t pelID, const BCDTime& time) 14089fa082aSMatt Spinler { 14189fa082aSMatt Spinler char name[50]; 14289fa082aSMatt Spinler sprintf(name, "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X_%.8X", time.yearMSB, 14389fa082aSMatt Spinler time.yearLSB, time.month, time.day, time.hour, time.minutes, 14489fa082aSMatt Spinler time.seconds, time.hundredths, pelID); 14589fa082aSMatt Spinler return std::string{name}; 14689fa082aSMatt Spinler } 14789fa082aSMatt Spinler 14889fa082aSMatt Spinler void Repository::add(std::unique_ptr<PEL>& pel) 14989fa082aSMatt Spinler { 150df43a305SMatt Spinler pel->setHostTransmissionState(TransmissionState::newPEL); 151df43a305SMatt Spinler pel->setHMCTransmissionState(TransmissionState::newPEL); 152df43a305SMatt Spinler 15389fa082aSMatt Spinler auto path = _logPath / getPELFilename(pel->id(), pel->commitTime()); 154ab1b97feSMatt Spinler 155ab1b97feSMatt Spinler write(*(pel.get()), path); 156ab1b97feSMatt Spinler 157*dd325c32SMatt Spinler PELAttributes attributes{path, 158*dd325c32SMatt Spinler getFileDiskSize(path), 159*dd325c32SMatt Spinler pel->privateHeader().creatorID(), 160*dd325c32SMatt Spinler pel->userHeader().severity(), 161*dd325c32SMatt Spinler pel->userHeader().actionFlags(), 162346f99a1SMatt Spinler pel->hostTransmissionState(), 163346f99a1SMatt Spinler pel->hmcTransmissionState()}; 164ab1b97feSMatt Spinler 165ab1b97feSMatt Spinler using pelID = LogID::Pel; 166ab1b97feSMatt Spinler using obmcID = LogID::Obmc; 167ab1b97feSMatt Spinler _pelAttributes.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())), 168ab1b97feSMatt Spinler attributes); 169ab1b97feSMatt Spinler 170ab1b97feSMatt Spinler processAddCallbacks(*pel); 171ab1b97feSMatt Spinler } 172ab1b97feSMatt Spinler 173ab1b97feSMatt Spinler void Repository::write(const PEL& pel, const fs::path& path) 174ab1b97feSMatt Spinler { 17589fa082aSMatt Spinler std::ofstream file{path, std::ios::binary}; 17689fa082aSMatt Spinler 17789fa082aSMatt Spinler if (!file.good()) 17889fa082aSMatt Spinler { 17989fa082aSMatt Spinler // If this fails, the filesystem is probably full so it isn't like 18089fa082aSMatt Spinler // we could successfully create yet another error log here. 18189fa082aSMatt Spinler auto e = errno; 18289fa082aSMatt Spinler fs::remove(path); 18389fa082aSMatt Spinler log<level::ERR>("Unable to open PEL file for writing", 18489fa082aSMatt Spinler entry("ERRNO=%d", e), entry("PATH=%s", path.c_str())); 18589fa082aSMatt Spinler throw file_error::Open(); 18689fa082aSMatt Spinler } 18789fa082aSMatt Spinler 188ab1b97feSMatt Spinler auto data = pel.data(); 18989fa082aSMatt Spinler file.write(reinterpret_cast<const char*>(data.data()), data.size()); 19089fa082aSMatt Spinler 19189fa082aSMatt Spinler if (file.fail()) 19289fa082aSMatt Spinler { 19389fa082aSMatt Spinler // Same note as above about not being able to create an error log 19489fa082aSMatt Spinler // for this case even if we wanted. 19589fa082aSMatt Spinler auto e = errno; 19689fa082aSMatt Spinler file.close(); 19789fa082aSMatt Spinler fs::remove(path); 19889fa082aSMatt Spinler log<level::ERR>("Unable to write PEL file", entry("ERRNO=%d", e), 19989fa082aSMatt Spinler entry("PATH=%s", path.c_str())); 20089fa082aSMatt Spinler throw file_error::Write(); 20189fa082aSMatt Spinler } 202475e574dSMatt Spinler } 203475e574dSMatt Spinler 204475e574dSMatt Spinler void Repository::remove(const LogID& id) 205475e574dSMatt Spinler { 206475e574dSMatt Spinler auto pel = findPEL(id); 2070ff00485SMatt Spinler if (pel != _pelAttributes.end()) 208475e574dSMatt Spinler { 2095f5352e5SMatt Spinler log<level::DEBUG>("Removing PEL from repository", 2105f5352e5SMatt Spinler entry("PEL_ID=0x%X", pel->first.pelID.id), 2115f5352e5SMatt Spinler entry("OBMC_LOG_ID=%d", pel->first.obmcID.id)); 2120ff00485SMatt Spinler fs::remove(pel->second.path); 2130ff00485SMatt Spinler _pelAttributes.erase(pel); 214421f6531SMatt Spinler 2155f5352e5SMatt Spinler processDeleteCallbacks(pel->first.pelID.id); 2165f5352e5SMatt Spinler } 2175f5352e5SMatt Spinler else 2185f5352e5SMatt Spinler { 2195f5352e5SMatt Spinler log<level::DEBUG>("Could not find PEL to remove", 2205f5352e5SMatt Spinler entry("PEL_ID=0x%X", id.pelID.id), 2215f5352e5SMatt Spinler entry("OBMC_LOG_ID=%d", id.obmcID.id)); 222475e574dSMatt Spinler } 22389fa082aSMatt Spinler } 22489fa082aSMatt Spinler 2252813f36dSMatt Spinler std::optional<std::vector<uint8_t>> Repository::getPELData(const LogID& id) 2262813f36dSMatt Spinler { 2272813f36dSMatt Spinler auto pel = findPEL(id); 2280ff00485SMatt Spinler if (pel != _pelAttributes.end()) 2292813f36dSMatt Spinler { 2300ff00485SMatt Spinler std::ifstream file{pel->second.path.c_str()}; 2312813f36dSMatt Spinler if (!file.good()) 2322813f36dSMatt Spinler { 2332813f36dSMatt Spinler auto e = errno; 2342813f36dSMatt Spinler log<level::ERR>("Unable to open PEL file", entry("ERRNO=%d", e), 2350ff00485SMatt Spinler entry("PATH=%s", pel->second.path.c_str())); 2362813f36dSMatt Spinler throw file_error::Open(); 2372813f36dSMatt Spinler } 2382813f36dSMatt Spinler 2392813f36dSMatt Spinler std::vector<uint8_t> data{std::istreambuf_iterator<char>(file), 2402813f36dSMatt Spinler std::istreambuf_iterator<char>()}; 2412813f36dSMatt Spinler return data; 2422813f36dSMatt Spinler } 2432813f36dSMatt Spinler 2442813f36dSMatt Spinler return std::nullopt; 2452813f36dSMatt Spinler } 2462813f36dSMatt Spinler 2476d51224bSMatt Spinler std::optional<sdbusplus::message::unix_fd> Repository::getPELFD(const LogID& id) 2486d51224bSMatt Spinler { 2496d51224bSMatt Spinler auto pel = findPEL(id); 2506d51224bSMatt Spinler if (pel != _pelAttributes.end()) 2516d51224bSMatt Spinler { 2526d51224bSMatt Spinler FILE* fp = fopen(pel->second.path.c_str(), "rb"); 2536d51224bSMatt Spinler 2546d51224bSMatt Spinler if (fp == nullptr) 2556d51224bSMatt Spinler { 2566d51224bSMatt Spinler auto e = errno; 2576d51224bSMatt Spinler log<level::ERR>("Unable to open PEL File", entry("ERRNO=%d", e), 2586d51224bSMatt Spinler entry("PATH=%s", pel->second.path.c_str())); 2596d51224bSMatt Spinler throw file_error::Open(); 2606d51224bSMatt Spinler } 2616d51224bSMatt Spinler 2626d51224bSMatt Spinler // Must leave the file open here. It will be closed by sdbusplus 2636d51224bSMatt Spinler // when it sends it back over D-Bus. 2646d51224bSMatt Spinler 2656d51224bSMatt Spinler return fileno(fp); 2666d51224bSMatt Spinler } 2676d51224bSMatt Spinler return std::nullopt; 2686d51224bSMatt Spinler } 2696d51224bSMatt Spinler 2701ea78801SMatt Spinler void Repository::for_each(ForEachFunc func) const 2711ea78801SMatt Spinler { 2720ff00485SMatt Spinler for (const auto& [id, attributes] : _pelAttributes) 2731ea78801SMatt Spinler { 2740ff00485SMatt Spinler std::ifstream file{attributes.path}; 2751ea78801SMatt Spinler 2761ea78801SMatt Spinler if (!file.good()) 2771ea78801SMatt Spinler { 2781ea78801SMatt Spinler auto e = errno; 2791ea78801SMatt Spinler log<level::ERR>("Repository::for_each: Unable to open PEL file", 2801ea78801SMatt Spinler entry("ERRNO=%d", e), 2810ff00485SMatt Spinler entry("PATH=%s", attributes.path.c_str())); 2821ea78801SMatt Spinler continue; 2831ea78801SMatt Spinler } 2841ea78801SMatt Spinler 2851ea78801SMatt Spinler std::vector<uint8_t> data{std::istreambuf_iterator<char>(file), 2861ea78801SMatt Spinler std::istreambuf_iterator<char>()}; 2871ea78801SMatt Spinler file.close(); 2881ea78801SMatt Spinler 2891ea78801SMatt Spinler PEL pel{data}; 2901ea78801SMatt Spinler 2911ea78801SMatt Spinler try 2921ea78801SMatt Spinler { 2931ea78801SMatt Spinler if (func(pel)) 2941ea78801SMatt Spinler { 2951ea78801SMatt Spinler break; 2961ea78801SMatt Spinler } 2971ea78801SMatt Spinler } 2981ea78801SMatt Spinler catch (std::exception& e) 2991ea78801SMatt Spinler { 3001ea78801SMatt Spinler log<level::ERR>("Repository::for_each function exception", 3011ea78801SMatt Spinler entry("ERROR=%s", e.what())); 3021ea78801SMatt Spinler } 3031ea78801SMatt Spinler } 3041ea78801SMatt Spinler } 3051ea78801SMatt Spinler 306421f6531SMatt Spinler void Repository::processAddCallbacks(const PEL& pel) const 307421f6531SMatt Spinler { 308421f6531SMatt Spinler for (auto& [name, func] : _addSubscriptions) 309421f6531SMatt Spinler { 310421f6531SMatt Spinler try 311421f6531SMatt Spinler { 312421f6531SMatt Spinler func(pel); 313421f6531SMatt Spinler } 314421f6531SMatt Spinler catch (std::exception& e) 315421f6531SMatt Spinler { 316421f6531SMatt Spinler log<level::ERR>("PEL Repository add callback exception", 317421f6531SMatt Spinler entry("NAME=%s", name.c_str()), 318421f6531SMatt Spinler entry("ERROR=%s", e.what())); 319421f6531SMatt Spinler } 320421f6531SMatt Spinler } 321421f6531SMatt Spinler } 322421f6531SMatt Spinler 323421f6531SMatt Spinler void Repository::processDeleteCallbacks(uint32_t id) const 324421f6531SMatt Spinler { 325421f6531SMatt Spinler for (auto& [name, func] : _deleteSubscriptions) 326421f6531SMatt Spinler { 327421f6531SMatt Spinler try 328421f6531SMatt Spinler { 329421f6531SMatt Spinler func(id); 330421f6531SMatt Spinler } 331421f6531SMatt Spinler catch (std::exception& e) 332421f6531SMatt Spinler { 333421f6531SMatt Spinler log<level::ERR>("PEL Repository delete callback exception", 334421f6531SMatt Spinler entry("NAME=%s", name.c_str()), 335421f6531SMatt Spinler entry("ERROR=%s", e.what())); 336421f6531SMatt Spinler } 337421f6531SMatt Spinler } 338421f6531SMatt Spinler } 339421f6531SMatt Spinler 3400ff00485SMatt Spinler std::optional<std::reference_wrapper<const Repository::PELAttributes>> 3410ff00485SMatt Spinler Repository::getPELAttributes(const LogID& id) const 3420ff00485SMatt Spinler { 3430ff00485SMatt Spinler auto pel = findPEL(id); 3440ff00485SMatt Spinler if (pel != _pelAttributes.end()) 3450ff00485SMatt Spinler { 3460ff00485SMatt Spinler return pel->second; 3470ff00485SMatt Spinler } 3480ff00485SMatt Spinler 3490ff00485SMatt Spinler return std::nullopt; 3500ff00485SMatt Spinler } 3510ff00485SMatt Spinler 35229d18c11SMatt Spinler void Repository::setPELHostTransState(uint32_t pelID, TransmissionState state) 35329d18c11SMatt Spinler { 35429d18c11SMatt Spinler LogID id{LogID::Pel{pelID}}; 35529d18c11SMatt Spinler auto attr = std::find_if(_pelAttributes.begin(), _pelAttributes.end(), 35629d18c11SMatt Spinler [&id](const auto& a) { return a.first == id; }); 35729d18c11SMatt Spinler 35829d18c11SMatt Spinler if ((attr != _pelAttributes.end()) && (attr->second.hostState != state)) 35929d18c11SMatt Spinler { 36029d18c11SMatt Spinler PELUpdateFunc func = [state](PEL& pel) { 36129d18c11SMatt Spinler pel.setHostTransmissionState(state); 36229d18c11SMatt Spinler }; 36329d18c11SMatt Spinler 36429d18c11SMatt Spinler try 36529d18c11SMatt Spinler { 36629d18c11SMatt Spinler updatePEL(attr->second.path, func); 36729d18c11SMatt Spinler 36829d18c11SMatt Spinler attr->second.hostState = state; 36929d18c11SMatt Spinler } 37029d18c11SMatt Spinler catch (std::exception& e) 37129d18c11SMatt Spinler { 37229d18c11SMatt Spinler log<level::ERR>("Unable to update PEL host transmission state", 37329d18c11SMatt Spinler entry("PATH=%s", attr->second.path.c_str()), 37429d18c11SMatt Spinler entry("ERROR=%s", e.what())); 37529d18c11SMatt Spinler } 37629d18c11SMatt Spinler } 37729d18c11SMatt Spinler } 37829d18c11SMatt Spinler 37929d18c11SMatt Spinler void Repository::setPELHMCTransState(uint32_t pelID, TransmissionState state) 38029d18c11SMatt Spinler { 38129d18c11SMatt Spinler LogID id{LogID::Pel{pelID}}; 38229d18c11SMatt Spinler auto attr = std::find_if(_pelAttributes.begin(), _pelAttributes.end(), 38329d18c11SMatt Spinler [&id](const auto& a) { return a.first == id; }); 38429d18c11SMatt Spinler 38529d18c11SMatt Spinler if ((attr != _pelAttributes.end()) && (attr->second.hmcState != state)) 38629d18c11SMatt Spinler { 38729d18c11SMatt Spinler PELUpdateFunc func = [state](PEL& pel) { 38829d18c11SMatt Spinler pel.setHMCTransmissionState(state); 38929d18c11SMatt Spinler }; 39029d18c11SMatt Spinler 39129d18c11SMatt Spinler try 39229d18c11SMatt Spinler { 39329d18c11SMatt Spinler updatePEL(attr->second.path, func); 39429d18c11SMatt Spinler 39529d18c11SMatt Spinler attr->second.hmcState = state; 39629d18c11SMatt Spinler } 39729d18c11SMatt Spinler catch (std::exception& e) 39829d18c11SMatt Spinler { 39929d18c11SMatt Spinler log<level::ERR>("Unable to update PEL HMC transmission state", 40029d18c11SMatt Spinler entry("PATH=%s", attr->second.path.c_str()), 40129d18c11SMatt Spinler entry("ERROR=%s", e.what())); 40229d18c11SMatt Spinler } 40329d18c11SMatt Spinler } 40429d18c11SMatt Spinler } 40529d18c11SMatt Spinler 40629d18c11SMatt Spinler void Repository::updatePEL(const fs::path& path, PELUpdateFunc updateFunc) 40729d18c11SMatt Spinler { 40829d18c11SMatt Spinler std::ifstream file{path}; 40929d18c11SMatt Spinler std::vector<uint8_t> data{std::istreambuf_iterator<char>(file), 41029d18c11SMatt Spinler std::istreambuf_iterator<char>()}; 41129d18c11SMatt Spinler file.close(); 41229d18c11SMatt Spinler 41329d18c11SMatt Spinler PEL pel{data}; 41429d18c11SMatt Spinler 41529d18c11SMatt Spinler if (pel.valid()) 41629d18c11SMatt Spinler { 41729d18c11SMatt Spinler updateFunc(pel); 41829d18c11SMatt Spinler 41929d18c11SMatt Spinler write(pel, path); 42029d18c11SMatt Spinler } 42129d18c11SMatt Spinler else 42229d18c11SMatt Spinler { 42329d18c11SMatt Spinler throw std::runtime_error( 42429d18c11SMatt Spinler "Unable to read a valid PEL when trying to update it"); 42529d18c11SMatt Spinler } 42629d18c11SMatt Spinler } 42729d18c11SMatt Spinler 42889fa082aSMatt Spinler } // namespace pels 42989fa082aSMatt Spinler } // namespace openpower 430