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