189fa082aSMatt Spinler #include "repository.hpp" 289fa082aSMatt Spinler 389fa082aSMatt Spinler #include <fstream> 489fa082aSMatt Spinler #include <phosphor-logging/log.hpp> 589fa082aSMatt Spinler #include <xyz/openbmc_project/Common/File/error.hpp> 689fa082aSMatt Spinler 789fa082aSMatt Spinler namespace openpower 889fa082aSMatt Spinler { 989fa082aSMatt Spinler namespace pels 1089fa082aSMatt Spinler { 1189fa082aSMatt Spinler 1289fa082aSMatt Spinler namespace fs = std::filesystem; 1389fa082aSMatt Spinler using namespace phosphor::logging; 1489fa082aSMatt Spinler namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error; 1589fa082aSMatt Spinler 1689fa082aSMatt Spinler Repository::Repository(const std::filesystem::path& basePath) : 1789fa082aSMatt Spinler _logPath(basePath / "logs") 1889fa082aSMatt Spinler { 1989fa082aSMatt Spinler if (!fs::exists(_logPath)) 2089fa082aSMatt Spinler { 2189fa082aSMatt Spinler fs::create_directories(_logPath); 2289fa082aSMatt Spinler } 23475e574dSMatt Spinler 24475e574dSMatt Spinler restore(); 25475e574dSMatt Spinler } 26475e574dSMatt Spinler 27475e574dSMatt Spinler void Repository::restore() 28475e574dSMatt Spinler { 29475e574dSMatt Spinler for (auto& dirEntry : fs::directory_iterator(_logPath)) 30475e574dSMatt Spinler { 31475e574dSMatt Spinler try 32475e574dSMatt Spinler { 33475e574dSMatt Spinler if (!fs::is_regular_file(dirEntry.path())) 34475e574dSMatt Spinler { 35475e574dSMatt Spinler continue; 36475e574dSMatt Spinler } 37475e574dSMatt Spinler 38475e574dSMatt Spinler std::ifstream file{dirEntry.path()}; 39475e574dSMatt Spinler std::vector<uint8_t> data{std::istreambuf_iterator<char>(file), 40475e574dSMatt Spinler std::istreambuf_iterator<char>()}; 41475e574dSMatt Spinler file.close(); 42475e574dSMatt Spinler 43475e574dSMatt Spinler PEL pel(std::move(data)); 44475e574dSMatt Spinler if (pel.valid()) 45475e574dSMatt Spinler { 46475e574dSMatt Spinler using pelID = LogID::Pel; 47475e574dSMatt Spinler using obmcID = LogID::Obmc; 48475e574dSMatt Spinler _idsToPELs.emplace( 49475e574dSMatt Spinler LogID(pelID(pel.id()), obmcID(pel.obmcLogID())), 50475e574dSMatt Spinler dirEntry.path()); 51475e574dSMatt Spinler } 52475e574dSMatt Spinler else 53475e574dSMatt Spinler { 54475e574dSMatt Spinler log<level::ERR>( 55475e574dSMatt Spinler "Found invalid PEL file while restoring. Removing.", 56475e574dSMatt Spinler entry("FILENAME=%s", dirEntry.path().c_str())); 57475e574dSMatt Spinler fs::remove(dirEntry.path()); 58475e574dSMatt Spinler } 59475e574dSMatt Spinler } 60475e574dSMatt Spinler catch (std::exception& e) 61475e574dSMatt Spinler { 62475e574dSMatt Spinler log<level::ERR>("Hit exception while restoring PEL File", 63475e574dSMatt Spinler entry("FILENAME=%s", dirEntry.path().c_str()), 64475e574dSMatt Spinler entry("ERROR=%s", e.what())); 65475e574dSMatt Spinler } 66475e574dSMatt Spinler } 6789fa082aSMatt Spinler } 6889fa082aSMatt Spinler 6989fa082aSMatt Spinler std::string Repository::getPELFilename(uint32_t pelID, const BCDTime& time) 7089fa082aSMatt Spinler { 7189fa082aSMatt Spinler char name[50]; 7289fa082aSMatt Spinler sprintf(name, "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X_%.8X", time.yearMSB, 7389fa082aSMatt Spinler time.yearLSB, time.month, time.day, time.hour, time.minutes, 7489fa082aSMatt Spinler time.seconds, time.hundredths, pelID); 7589fa082aSMatt Spinler return std::string{name}; 7689fa082aSMatt Spinler } 7789fa082aSMatt Spinler 7889fa082aSMatt Spinler void Repository::add(std::unique_ptr<PEL>& pel) 7989fa082aSMatt Spinler { 8089fa082aSMatt Spinler auto path = _logPath / getPELFilename(pel->id(), pel->commitTime()); 8189fa082aSMatt Spinler std::ofstream file{path, std::ios::binary}; 8289fa082aSMatt Spinler 8389fa082aSMatt Spinler if (!file.good()) 8489fa082aSMatt Spinler { 8589fa082aSMatt Spinler // If this fails, the filesystem is probably full so it isn't like 8689fa082aSMatt Spinler // we could successfully create yet another error log here. 8789fa082aSMatt Spinler auto e = errno; 8889fa082aSMatt Spinler log<level::ERR>("Failed creating PEL file", 8989fa082aSMatt Spinler entry("FILE=%s", path.c_str())); 9089fa082aSMatt Spinler fs::remove(path); 9189fa082aSMatt Spinler log<level::ERR>("Unable to open PEL file for writing", 9289fa082aSMatt Spinler entry("ERRNO=%d", e), entry("PATH=%s", path.c_str())); 9389fa082aSMatt Spinler throw file_error::Open(); 9489fa082aSMatt Spinler } 9589fa082aSMatt Spinler 9689fa082aSMatt Spinler auto data = pel->data(); 9789fa082aSMatt Spinler file.write(reinterpret_cast<const char*>(data.data()), data.size()); 9889fa082aSMatt Spinler 9989fa082aSMatt Spinler if (file.fail()) 10089fa082aSMatt Spinler { 10189fa082aSMatt Spinler // Same note as above about not being able to create an error log 10289fa082aSMatt Spinler // for this case even if we wanted. 10389fa082aSMatt Spinler auto e = errno; 10489fa082aSMatt Spinler log<level::ERR>("Failed writing PEL file", 10589fa082aSMatt Spinler entry("FILE=%s", path.c_str())); 10689fa082aSMatt Spinler file.close(); 10789fa082aSMatt Spinler fs::remove(path); 10889fa082aSMatt Spinler log<level::ERR>("Unable to write PEL file", entry("ERRNO=%d", e), 10989fa082aSMatt Spinler entry("PATH=%s", path.c_str())); 11089fa082aSMatt Spinler throw file_error::Write(); 11189fa082aSMatt Spinler } 112475e574dSMatt Spinler 113475e574dSMatt Spinler using pelID = LogID::Pel; 114475e574dSMatt Spinler using obmcID = LogID::Obmc; 115475e574dSMatt Spinler _idsToPELs.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())), path); 116475e574dSMatt Spinler } 117475e574dSMatt Spinler 118475e574dSMatt Spinler void Repository::remove(const LogID& id) 119475e574dSMatt Spinler { 120475e574dSMatt Spinler auto pel = findPEL(id); 121475e574dSMatt Spinler if (pel != _idsToPELs.end()) 122475e574dSMatt Spinler { 123475e574dSMatt Spinler fs::remove(pel->second); 124475e574dSMatt Spinler _idsToPELs.erase(pel); 125475e574dSMatt Spinler } 12689fa082aSMatt Spinler } 12789fa082aSMatt Spinler 128*2813f36dSMatt Spinler std::optional<std::vector<uint8_t>> Repository::getPELData(const LogID& id) 129*2813f36dSMatt Spinler { 130*2813f36dSMatt Spinler auto pel = findPEL(id); 131*2813f36dSMatt Spinler if (pel != _idsToPELs.end()) 132*2813f36dSMatt Spinler { 133*2813f36dSMatt Spinler std::ifstream file{pel->second.c_str()}; 134*2813f36dSMatt Spinler if (!file.good()) 135*2813f36dSMatt Spinler { 136*2813f36dSMatt Spinler auto e = errno; 137*2813f36dSMatt Spinler log<level::ERR>("Unable to open PEL file", entry("ERRNO=%d", e), 138*2813f36dSMatt Spinler entry("PATH=%s", pel->second.c_str())); 139*2813f36dSMatt Spinler throw file_error::Open(); 140*2813f36dSMatt Spinler } 141*2813f36dSMatt Spinler 142*2813f36dSMatt Spinler std::vector<uint8_t> data{std::istreambuf_iterator<char>(file), 143*2813f36dSMatt Spinler std::istreambuf_iterator<char>()}; 144*2813f36dSMatt Spinler return data; 145*2813f36dSMatt Spinler } 146*2813f36dSMatt Spinler 147*2813f36dSMatt Spinler return std::nullopt; 148*2813f36dSMatt Spinler } 149*2813f36dSMatt Spinler 15089fa082aSMatt Spinler } // namespace pels 15189fa082aSMatt Spinler } // namespace openpower 152