xref: /openbmc/phosphor-logging/extensions/openpower-pels/repository.cpp (revision 475e574da95a75af6001fdc2198c1892c1bfc041)
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     }
23*475e574dSMatt Spinler 
24*475e574dSMatt Spinler     restore();
25*475e574dSMatt Spinler }
26*475e574dSMatt Spinler 
27*475e574dSMatt Spinler void Repository::restore()
28*475e574dSMatt Spinler {
29*475e574dSMatt Spinler     for (auto& dirEntry : fs::directory_iterator(_logPath))
30*475e574dSMatt Spinler     {
31*475e574dSMatt Spinler         try
32*475e574dSMatt Spinler         {
33*475e574dSMatt Spinler             if (!fs::is_regular_file(dirEntry.path()))
34*475e574dSMatt Spinler             {
35*475e574dSMatt Spinler                 continue;
36*475e574dSMatt Spinler             }
37*475e574dSMatt Spinler 
38*475e574dSMatt Spinler             std::ifstream file{dirEntry.path()};
39*475e574dSMatt Spinler             std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
40*475e574dSMatt Spinler                                       std::istreambuf_iterator<char>()};
41*475e574dSMatt Spinler             file.close();
42*475e574dSMatt Spinler 
43*475e574dSMatt Spinler             PEL pel(std::move(data));
44*475e574dSMatt Spinler             if (pel.valid())
45*475e574dSMatt Spinler             {
46*475e574dSMatt Spinler                 using pelID = LogID::Pel;
47*475e574dSMatt Spinler                 using obmcID = LogID::Obmc;
48*475e574dSMatt Spinler                 _idsToPELs.emplace(
49*475e574dSMatt Spinler                     LogID(pelID(pel.id()), obmcID(pel.obmcLogID())),
50*475e574dSMatt Spinler                     dirEntry.path());
51*475e574dSMatt Spinler             }
52*475e574dSMatt Spinler             else
53*475e574dSMatt Spinler             {
54*475e574dSMatt Spinler                 log<level::ERR>(
55*475e574dSMatt Spinler                     "Found invalid PEL file while restoring.  Removing.",
56*475e574dSMatt Spinler                     entry("FILENAME=%s", dirEntry.path().c_str()));
57*475e574dSMatt Spinler                 fs::remove(dirEntry.path());
58*475e574dSMatt Spinler             }
59*475e574dSMatt Spinler         }
60*475e574dSMatt Spinler         catch (std::exception& e)
61*475e574dSMatt Spinler         {
62*475e574dSMatt Spinler             log<level::ERR>("Hit exception while restoring PEL File",
63*475e574dSMatt Spinler                             entry("FILENAME=%s", dirEntry.path().c_str()),
64*475e574dSMatt Spinler                             entry("ERROR=%s", e.what()));
65*475e574dSMatt Spinler         }
66*475e574dSMatt 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     }
112*475e574dSMatt Spinler 
113*475e574dSMatt Spinler     using pelID = LogID::Pel;
114*475e574dSMatt Spinler     using obmcID = LogID::Obmc;
115*475e574dSMatt Spinler     _idsToPELs.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())), path);
116*475e574dSMatt Spinler }
117*475e574dSMatt Spinler 
118*475e574dSMatt Spinler void Repository::remove(const LogID& id)
119*475e574dSMatt Spinler {
120*475e574dSMatt Spinler     auto pel = findPEL(id);
121*475e574dSMatt Spinler     if (pel != _idsToPELs.end())
122*475e574dSMatt Spinler     {
123*475e574dSMatt Spinler         fs::remove(pel->second);
124*475e574dSMatt Spinler         _idsToPELs.erase(pel);
125*475e574dSMatt Spinler     }
12689fa082aSMatt Spinler }
12789fa082aSMatt Spinler 
12889fa082aSMatt Spinler } // namespace pels
12989fa082aSMatt Spinler } // namespace openpower
130