blob: b3697068ea8453cb2016ad0bd6570851093a0b87 [file] [log] [blame]
Matt Spinler89fa0822019-07-17 13:54:30 -05001#include "repository.hpp"
2
3#include <fstream>
4#include <phosphor-logging/log.hpp>
5#include <xyz/openbmc_project/Common/File/error.hpp>
6
7namespace openpower
8{
9namespace pels
10{
11
12namespace fs = std::filesystem;
13using namespace phosphor::logging;
14namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error;
15
16Repository::Repository(const std::filesystem::path& basePath) :
17 _logPath(basePath / "logs")
18{
19 if (!fs::exists(_logPath))
20 {
21 fs::create_directories(_logPath);
22 }
Matt Spinler475e5742019-07-18 16:09:49 -050023
24 restore();
25}
26
27void Repository::restore()
28{
29 for (auto& dirEntry : fs::directory_iterator(_logPath))
30 {
31 try
32 {
33 if (!fs::is_regular_file(dirEntry.path()))
34 {
35 continue;
36 }
37
38 std::ifstream file{dirEntry.path()};
39 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
40 std::istreambuf_iterator<char>()};
41 file.close();
42
Matt Spinler07eefc52019-09-26 11:18:26 -050043 PEL pel{data};
Matt Spinler475e5742019-07-18 16:09:49 -050044 if (pel.valid())
45 {
46 using pelID = LogID::Pel;
47 using obmcID = LogID::Obmc;
48 _idsToPELs.emplace(
49 LogID(pelID(pel.id()), obmcID(pel.obmcLogID())),
50 dirEntry.path());
51 }
52 else
53 {
54 log<level::ERR>(
55 "Found invalid PEL file while restoring. Removing.",
56 entry("FILENAME=%s", dirEntry.path().c_str()));
57 fs::remove(dirEntry.path());
58 }
59 }
60 catch (std::exception& e)
61 {
62 log<level::ERR>("Hit exception while restoring PEL File",
63 entry("FILENAME=%s", dirEntry.path().c_str()),
64 entry("ERROR=%s", e.what()));
65 }
66 }
Matt Spinler89fa0822019-07-17 13:54:30 -050067}
68
69std::string Repository::getPELFilename(uint32_t pelID, const BCDTime& time)
70{
71 char name[50];
72 sprintf(name, "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X_%.8X", time.yearMSB,
73 time.yearLSB, time.month, time.day, time.hour, time.minutes,
74 time.seconds, time.hundredths, pelID);
75 return std::string{name};
76}
77
78void Repository::add(std::unique_ptr<PEL>& pel)
79{
80 auto path = _logPath / getPELFilename(pel->id(), pel->commitTime());
81 std::ofstream file{path, std::ios::binary};
82
83 if (!file.good())
84 {
85 // If this fails, the filesystem is probably full so it isn't like
86 // we could successfully create yet another error log here.
87 auto e = errno;
88 log<level::ERR>("Failed creating PEL file",
89 entry("FILE=%s", path.c_str()));
90 fs::remove(path);
91 log<level::ERR>("Unable to open PEL file for writing",
92 entry("ERRNO=%d", e), entry("PATH=%s", path.c_str()));
93 throw file_error::Open();
94 }
95
96 auto data = pel->data();
97 file.write(reinterpret_cast<const char*>(data.data()), data.size());
98
99 if (file.fail())
100 {
101 // Same note as above about not being able to create an error log
102 // for this case even if we wanted.
103 auto e = errno;
104 log<level::ERR>("Failed writing PEL file",
105 entry("FILE=%s", path.c_str()));
106 file.close();
107 fs::remove(path);
108 log<level::ERR>("Unable to write PEL file", entry("ERRNO=%d", e),
109 entry("PATH=%s", path.c_str()));
110 throw file_error::Write();
111 }
Matt Spinler475e5742019-07-18 16:09:49 -0500112
113 using pelID = LogID::Pel;
114 using obmcID = LogID::Obmc;
115 _idsToPELs.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())), path);
116}
117
118void Repository::remove(const LogID& id)
119{
120 auto pel = findPEL(id);
121 if (pel != _idsToPELs.end())
122 {
123 fs::remove(pel->second);
124 _idsToPELs.erase(pel);
125 }
Matt Spinler89fa0822019-07-17 13:54:30 -0500126}
127
Matt Spinler2813f362019-07-19 12:45:28 -0500128std::optional<std::vector<uint8_t>> Repository::getPELData(const LogID& id)
129{
130 auto pel = findPEL(id);
131 if (pel != _idsToPELs.end())
132 {
133 std::ifstream file{pel->second.c_str()};
134 if (!file.good())
135 {
136 auto e = errno;
137 log<level::ERR>("Unable to open PEL file", entry("ERRNO=%d", e),
138 entry("PATH=%s", pel->second.c_str()));
139 throw file_error::Open();
140 }
141
142 std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
143 std::istreambuf_iterator<char>()};
144 return data;
145 }
146
147 return std::nullopt;
148}
149
Matt Spinler89fa0822019-07-17 13:54:30 -0500150} // namespace pels
151} // namespace openpower