xref: /openbmc/ibm-logging/callout.cpp (revision 6a2b8956)
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 <phosphor-logging/log.hpp>
26 
27 #include <experimental/filesystem>
28 #include <fstream>
29 
30 CEREAL_CLASS_VERSION(ibm::logging::Callout, CALLOUT_CLASS_VERSION);
31 
32 namespace ibm
33 {
34 namespace logging
35 {
36 
37 using namespace phosphor::logging;
38 
39 /**
40  * Function required by Cereal for saving data
41  *
42  * @param[in] archive - the Cereal archive object
43  * @param[in] callout - the object to save
44  * @param[in] version - the version of the persisted data
45  */
46 template <class Archive>
save(Archive & archive,const Callout & callout,const std::uint32_t version)47 void save(Archive& archive, const Callout& callout, const std::uint32_t version)
48 {
49     archive(callout.id(), callout.ts(), callout.path(), callout.buildDate(),
50             callout.manufacturer(), callout.model(), callout.partNumber(),
51             callout.serialNumber());
52 }
53 
54 /**
55  * Function required by Cereal for restoring data into an object
56  *
57  * @param[in] archive - the Cereal archive object
58  * @param[in] callout - the callout object to restore
59  * @param[in] version - the version of the persisted data
60  */
61 template <class Archive>
load(Archive & archive,Callout & callout,const std::uint32_t version)62 void load(Archive& archive, Callout& callout, const std::uint32_t version)
63 {
64     size_t id;
65     uint64_t timestamp;
66     std::string inventoryPath;
67     std::string build;
68     std::string mfgr;
69     std::string model;
70     std::string pn;
71     std::string sn;
72 
73     archive(id, timestamp, inventoryPath, build, mfgr, model, pn, sn);
74 
75     callout.id(id);
76     callout.ts(timestamp);
77     callout.path(inventoryPath);
78     callout.buildDate(build);
79     callout.manufacturer(mfgr);
80     callout.model(model);
81     callout.partNumber(pn);
82     callout.serialNumber(sn);
83 }
84 
Callout(sdbusplus::bus_t & bus,const std::string & objectPath,size_t id,uint64_t timestamp)85 Callout::Callout(sdbusplus::bus_t& bus, const std::string& objectPath,
86                  size_t id, uint64_t timestamp) :
87     CalloutObject(bus, objectPath.c_str(), CalloutObject::action::defer_emit),
88     entryID(id), timestamp(timestamp)
89 {}
90 
Callout(sdbusplus::bus_t & bus,const std::string & objectPath,const std::string & inventoryPath,size_t id,uint64_t timestamp,const DbusPropertyMap & properties)91 Callout::Callout(sdbusplus::bus_t& 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(), CalloutObject::action::defer_emit),
95     entryID(id), timestamp(timestamp)
96 {
97     path(inventoryPath);
98 
99     auto it = properties.find("BuildDate");
100     if (it != properties.end())
101     {
102         buildDate(std::get<std::string>(it->second));
103     }
104 
105     it = properties.find("Manufacturer");
106     if (it != properties.end())
107     {
108         manufacturer(std::get<std::string>(it->second));
109     }
110 
111     it = properties.find("Model");
112     if (it != properties.end())
113     {
114         model(std::get<std::string>(it->second));
115     }
116 
117     it = properties.find("PartNumber");
118     if (it != properties.end())
119     {
120         partNumber(std::get<std::string>(it->second));
121     }
122 
123     it = properties.find("SerialNumber");
124     if (it != properties.end())
125     {
126         serialNumber(std::get<std::string>(it->second));
127     }
128 
129     emit_object_added();
130 }
131 
serialize(const fs::path & dir)132 void Callout::serialize(const fs::path& dir)
133 {
134     auto path = getFilePath(dir);
135     std::ofstream stream(path.c_str(), std::ios::binary);
136     cereal::BinaryOutputArchive oarchive(stream);
137 
138     oarchive(*this);
139 }
140 
deserialize(const fs::path & dir)141 bool Callout::deserialize(const fs::path& dir)
142 {
143     auto path = getFilePath(dir);
144 
145     if (!fs::exists(path))
146     {
147         return false;
148     }
149 
150     // Save the current ID and timestamp and then use them after
151     // deserialization to check that the data we are restoring
152     // is for the correct error log.
153 
154     auto originalID = entryID;
155     auto originalTS = timestamp;
156 
157     try
158     {
159         std::ifstream stream(path.c_str(), std::ios::binary);
160         cereal::BinaryInputArchive iarchive(stream);
161 
162         iarchive(*this);
163     }
164     catch (const std::exception& e)
165     {
166         log<level::ERR>(e.what());
167         log<level::ERR>("Failed trying to restore a Callout object",
168                         entry("PATH=%s", path.c_str()));
169         fs::remove(path);
170         return false;
171     }
172 
173     if ((entryID != originalID) || (timestamp != originalTS))
174     {
175         log<level::INFO>(
176             "Timestamp or ID mismatch in persisted Callout. Discarding",
177             entry("PATH=%s", path.c_str()), entry("PERSISTED_ID=%lu", entryID),
178             entry("EXPECTED_ID=%lu", originalID),
179             entry("PERSISTED_TS=%llu", timestamp),
180             entry("EXPECTED_TS=%llu", originalTS));
181         fs::remove(path);
182         return false;
183     }
184 
185     return true;
186 }
187 } // namespace logging
188 } // namespace ibm
189