xref: /openbmc/ibm-logging/callout.cpp (revision f5866e704d9429a7195a20aaf52c778591531d88)
1 /** Copyright © 2018 IBM Corporation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "config.h"
16 
17 #include "callout.hpp"
18 
19 #include "dbus.hpp"
20 
21 #include <cereal/archives/binary.hpp>
22 #include <cereal/types/string.hpp>
23 #include <cereal/types/tuple.hpp>
24 #include <cereal/types/vector.hpp>
25 #include <experimental/filesystem>
26 #include <fstream>
27 #include <phosphor-logging/log.hpp>
28 
29 CEREAL_CLASS_VERSION(ibm::logging::Callout, CALLOUT_CLASS_VERSION);
30 
31 namespace ibm
32 {
33 namespace logging
34 {
35 
36 using namespace phosphor::logging;
37 
38 /**
39  * Function required by Cereal for saving data
40  *
41  * @param[in] archive - the Cereal archive object
42  * @param[in] callout - the object to save
43  * @param[in] version - the version of the persisted data
44  */
45 template <class Archive>
46 void save(Archive& archive, const Callout& callout, const std::uint32_t version)
47 {
48     archive(callout.id(), callout.ts(), callout.path(), callout.buildDate(),
49             callout.manufacturer(), callout.model(), callout.partNumber(),
50             callout.serialNumber());
51 }
52 
53 /**
54  * Function required by Cereal for restoring data into an object
55  *
56  * @param[in] archive - the Cereal archive object
57  * @param[in] callout - the callout object to restore
58  * @param[in] version - the version of the persisted data
59  */
60 template <class Archive>
61 void load(Archive& archive, Callout& callout, const std::uint32_t version)
62 {
63     size_t id;
64     uint64_t timestamp;
65     std::string inventoryPath;
66     std::string build;
67     std::string mfgr;
68     std::string model;
69     std::string pn;
70     std::string sn;
71 
72     archive(id, timestamp, inventoryPath, build, mfgr, model, pn, sn);
73 
74     callout.id(id);
75     callout.ts(timestamp);
76     callout.path(inventoryPath);
77     callout.buildDate(build);
78     callout.manufacturer(mfgr);
79     callout.model(model);
80     callout.partNumber(pn);
81     callout.serialNumber(sn);
82 }
83 
84 Callout::Callout(sdbusplus::bus::bus& bus, const std::string& objectPath,
85                  size_t id, uint64_t timestamp) :
86     CalloutObject(bus, objectPath.c_str(), true),
87     entryID(id), timestamp(timestamp)
88 {
89 }
90 
91 Callout::Callout(sdbusplus::bus::bus& bus, const std::string& objectPath,
92                  const std::string& inventoryPath, size_t id,
93                  uint64_t timestamp, const DbusPropertyMap& properties) :
94     CalloutObject(bus, objectPath.c_str(), true),
95     entryID(id), timestamp(timestamp)
96 {
97     path(inventoryPath);
98 
99     auto it = properties.find("BuildDate");
100     if (it != properties.end())
101     {
102         buildDate(sdbusplus::message::variant_ns::get<std::string>(it->second));
103     }
104 
105     it = properties.find("Manufacturer");
106     if (it != properties.end())
107     {
108         manufacturer(
109             sdbusplus::message::variant_ns::get<std::string>(it->second));
110     }
111 
112     it = properties.find("Model");
113     if (it != properties.end())
114     {
115         model(sdbusplus::message::variant_ns::get<std::string>(it->second));
116     }
117 
118     it = properties.find("PartNumber");
119     if (it != properties.end())
120     {
121         partNumber(
122             sdbusplus::message::variant_ns::get<std::string>(it->second));
123     }
124 
125     it = properties.find("SerialNumber");
126     if (it != properties.end())
127     {
128         serialNumber(
129             sdbusplus::message::variant_ns::get<std::string>(it->second));
130     }
131 
132     emit_object_added();
133 }
134 
135 void Callout::serialize(const fs::path& dir)
136 {
137     auto path = getFilePath(dir);
138     std::ofstream stream(path.c_str(), std::ios::binary);
139     cereal::BinaryOutputArchive oarchive(stream);
140 
141     oarchive(*this);
142 }
143 
144 bool Callout::deserialize(const fs::path& dir)
145 {
146     auto path = getFilePath(dir);
147 
148     if (!fs::exists(path))
149     {
150         return false;
151     }
152 
153     // Save the current ID and timestamp and then use them after
154     // deserialization to check that the data we are restoring
155     // is for the correct error log.
156 
157     auto originalID = entryID;
158     auto originalTS = timestamp;
159 
160     try
161     {
162         std::ifstream stream(path.c_str(), std::ios::binary);
163         cereal::BinaryInputArchive iarchive(stream);
164 
165         iarchive(*this);
166     }
167     catch (std::exception& e)
168     {
169         log<level::ERR>(e.what());
170         log<level::ERR>("Failed trying to restore a Callout object",
171                         entry("PATH=%s", path.c_str()));
172         fs::remove(path);
173         return false;
174     }
175 
176     if ((entryID != originalID) || (timestamp != originalTS))
177     {
178         log<level::INFO>(
179             "Timestamp or ID mismatch in persisted Callout. Discarding",
180             entry("PATH=%s", path.c_str()), entry("PERSISTED_ID=%lu", entryID),
181             entry("EXPECTED_ID=%lu", originalID),
182             entry("PERSISTED_TS=%llu", timestamp),
183             entry("EXPECTED_TS=%llu", originalTS));
184         fs::remove(path);
185         return false;
186     }
187 
188     return true;
189 }
190 } // namespace logging
191 } // namespace ibm
192