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