xref: /openbmc/phosphor-logging/extensions/openpower-pels/repository.cpp (revision 2813f36ded0fce084df9620c972469dc8e096179)
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