1 #include "config.h"
2
3 #include "elog_serialize.hpp"
4
5 #include "util.hpp"
6
7 #include <cereal/archives/binary.hpp>
8 #include <cereal/types/map.hpp>
9 #include <cereal/types/string.hpp>
10 #include <cereal/types/tuple.hpp>
11 #include <cereal/types/vector.hpp>
12 #include <phosphor-logging/lg2.hpp>
13
14 #include <fstream>
15
16 // Register class version
17 // From cereal documentation;
18 // "This macro should be placed at global scope"
19 CEREAL_CLASS_VERSION(phosphor::logging::Entry, CLASS_VERSION)
20
21 namespace phosphor
22 {
23 namespace logging
24 {
25
26 /** @brief Function required by Cereal to perform serialization.
27 * @tparam Archive - Cereal archive type (binary in our case).
28 * @param[in] a - reference to Cereal archive.
29 * @param[in] e - const reference to error entry.
30 * @param[in] version - Class version that enables handling
31 * a serialized data across code levels
32 */
33 template <class Archive>
save(Archive & a,const Entry & e,const std::uint32_t)34 void save(Archive& a, const Entry& e, const std::uint32_t /*version*/)
35 {
36 a(e.id(), e.severity(), e.timestamp(), e.message(),
37 util::additional_data::combine(e.additionalData()), e.associations(),
38 e.resolved(), e.version(), e.updateTimestamp(), e.eventId(),
39 e.resolution());
40 }
41
42 /** @brief Function required by Cereal to perform deserialization.
43 * @tparam Archive - Cereal archive type (binary in our case).
44 * @param[in] a - reference to Cereal archive.
45 * @param[in] e - reference to error entry.
46 * @param[in] version - Class version that enables handling
47 * a serialized data across code levels
48 */
49 template <class Archive>
load(Archive & a,Entry & e,const std::uint32_t version)50 void load(Archive& a, Entry& e, const std::uint32_t version)
51 {
52 using namespace sdbusplus::server::xyz::openbmc_project::logging;
53
54 uint32_t id{};
55 Entry::Level severity{};
56 uint64_t timestamp{};
57 std::string message{};
58 std::map<std::string, std::string> additionalData{};
59 bool resolved{};
60 AssociationList associations{};
61 std::string fwVersion{};
62 uint64_t updateTimestamp{};
63 std::string eventId{};
64 std::string resolution{};
65
66 if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_FWLEVEL))
67 {
68 std::vector<std::string> additionalData_old{};
69 a(id, severity, timestamp, message, additionalData_old, associations,
70 resolved);
71 updateTimestamp = timestamp;
72 additionalData = util::additional_data::parse(additionalData_old);
73 }
74 else if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_UPDATE_TS))
75 {
76 std::vector<std::string> additionalData_old{};
77 a(id, severity, timestamp, message, additionalData_old, associations,
78 resolved, fwVersion);
79 updateTimestamp = timestamp;
80 additionalData = util::additional_data::parse(additionalData_old);
81 }
82 else if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_EVENTID))
83 {
84 std::vector<std::string> additionalData_old{};
85 a(id, severity, timestamp, message, additionalData_old, associations,
86 resolved, fwVersion, updateTimestamp);
87 additionalData = util::additional_data::parse(additionalData_old);
88 }
89 else if (version < std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_RESOLUTION))
90 {
91 std::vector<std::string> additionalData_old{};
92 a(id, severity, timestamp, message, additionalData_old, associations,
93 resolved, fwVersion, updateTimestamp, eventId);
94 additionalData = util::additional_data::parse(additionalData_old);
95 }
96 else if (version <
97 std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_METADATA_DICT))
98 {
99 std::vector<std::string> additionalData_old{};
100 a(id, severity, timestamp, message, additionalData_old, associations,
101 resolved, fwVersion, updateTimestamp, eventId, resolution);
102 additionalData = util::additional_data::parse(additionalData_old);
103 }
104 else if (version ==
105 std::stoul(FIRST_CEREAL_CLASS_VERSION_WITH_METADATA_DICT))
106 {
107 a(id, severity, timestamp, message, additionalData, associations,
108 resolved, fwVersion, updateTimestamp, eventId, resolution);
109 }
110 else
111 {
112 // Go back to reading a vector for additionalData
113 std::vector<std::string> additionalData_old{};
114 a(id, severity, timestamp, message, additionalData_old, associations,
115 resolved, fwVersion, updateTimestamp, eventId, resolution);
116 additionalData = util::additional_data::parse(additionalData_old);
117 }
118
119 e.id(id, true);
120 e.severity(severity, true);
121 e.timestamp(timestamp, true);
122 e.message(message, true);
123 e.additionalData(additionalData, true);
124 e.sdbusplus::server::xyz::openbmc_project::logging::Entry::resolved(
125 resolved, true);
126 e.associations(associations, true);
127 e.version(fwVersion, true);
128 e.purpose(sdbusplus::server::xyz::openbmc_project::software::Version::
129 VersionPurpose::BMC,
130 true);
131 e.updateTimestamp(updateTimestamp, true);
132 e.eventId(eventId, true);
133 e.resolution(resolution, true);
134 }
135
getEntrySerializePath(uint32_t id,const fs::path & dir)136 fs::path getEntrySerializePath(uint32_t id, const fs::path& dir)
137 {
138 return dir / std::to_string(id);
139 }
140
serialize(const Entry & e,const fs::path & dir)141 fs::path serialize(const Entry& e, const fs::path& dir)
142 {
143 auto path = getEntrySerializePath(e.id(), dir);
144 std::ofstream os(path.c_str(), std::ios::binary);
145 cereal::BinaryOutputArchive oarchive(os);
146 oarchive(e);
147 return path;
148 }
149
deserialize(const fs::path & path,Entry & e)150 bool deserialize(const fs::path& path, Entry& e)
151 {
152 try
153 {
154 if (fs::exists(path))
155 {
156 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
157 cereal::BinaryInputArchive iarchive(is);
158 iarchive(e);
159 return true;
160 }
161 return false;
162 }
163 catch (const std::exception& ex)
164 {
165 lg2::error("Failed restoring {PATH}: {EXCEPTION}", "PATH", path,
166 "EXCEPTION", ex);
167 // Save it for later debug. Just write over any previous ones.
168 auto saveDir = paths::error().parent_path();
169 fs::rename(path, saveDir / "corrupt_error");
170 return false;
171 }
172 }
173
174 } // namespace logging
175 } // namespace phosphor
176