/** * Copyright © 2019 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "repository.hpp" #include #include #include namespace openpower { namespace pels { namespace fs = std::filesystem; using namespace phosphor::logging; namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error; Repository::Repository(const std::filesystem::path& basePath) : _logPath(basePath / "logs") { if (!fs::exists(_logPath)) { fs::create_directories(_logPath); } restore(); } void Repository::restore() { for (auto& dirEntry : fs::directory_iterator(_logPath)) { try { if (!fs::is_regular_file(dirEntry.path())) { continue; } std::ifstream file{dirEntry.path()}; std::vector data{std::istreambuf_iterator(file), std::istreambuf_iterator()}; file.close(); PEL pel{data}; if (pel.valid()) { using pelID = LogID::Pel; using obmcID = LogID::Obmc; _idsToPELs.emplace( LogID(pelID(pel.id()), obmcID(pel.obmcLogID())), dirEntry.path()); } else { log( "Found invalid PEL file while restoring. Removing.", entry("FILENAME=%s", dirEntry.path().c_str())); fs::remove(dirEntry.path()); } } catch (std::exception& e) { log("Hit exception while restoring PEL File", entry("FILENAME=%s", dirEntry.path().c_str()), entry("ERROR=%s", e.what())); } } } std::string Repository::getPELFilename(uint32_t pelID, const BCDTime& time) { char name[50]; sprintf(name, "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X_%.8X", time.yearMSB, time.yearLSB, time.month, time.day, time.hour, time.minutes, time.seconds, time.hundredths, pelID); return std::string{name}; } void Repository::add(std::unique_ptr& pel) { auto path = _logPath / getPELFilename(pel->id(), pel->commitTime()); std::ofstream file{path, std::ios::binary}; if (!file.good()) { // If this fails, the filesystem is probably full so it isn't like // we could successfully create yet another error log here. auto e = errno; log("Failed creating PEL file", entry("FILE=%s", path.c_str())); fs::remove(path); log("Unable to open PEL file for writing", entry("ERRNO=%d", e), entry("PATH=%s", path.c_str())); throw file_error::Open(); } auto data = pel->data(); file.write(reinterpret_cast(data.data()), data.size()); if (file.fail()) { // Same note as above about not being able to create an error log // for this case even if we wanted. auto e = errno; log("Failed writing PEL file", entry("FILE=%s", path.c_str())); file.close(); fs::remove(path); log("Unable to write PEL file", entry("ERRNO=%d", e), entry("PATH=%s", path.c_str())); throw file_error::Write(); } using pelID = LogID::Pel; using obmcID = LogID::Obmc; _idsToPELs.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())), path); } void Repository::remove(const LogID& id) { auto pel = findPEL(id); if (pel != _idsToPELs.end()) { fs::remove(pel->second); _idsToPELs.erase(pel); } } std::optional> Repository::getPELData(const LogID& id) { auto pel = findPEL(id); if (pel != _idsToPELs.end()) { std::ifstream file{pel->second.c_str()}; if (!file.good()) { auto e = errno; log("Unable to open PEL file", entry("ERRNO=%d", e), entry("PATH=%s", pel->second.c_str())); throw file_error::Open(); } std::vector data{std::istreambuf_iterator(file), std::istreambuf_iterator()}; return data; } return std::nullopt; } } // namespace pels } // namespace openpower