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(it->second.get<std::string>()); 103 } 104 105 it = properties.find("Manufacturer"); 106 if (it != properties.end()) 107 { 108 manufacturer(it->second.get<std::string>()); 109 } 110 111 it = properties.find("Model"); 112 if (it != properties.end()) 113 { 114 model(it->second.get<std::string>()); 115 } 116 117 it = properties.find("PartNumber"); 118 if (it != properties.end()) 119 { 120 partNumber(it->second.get<std::string>()); 121 } 122 123 it = properties.find("SerialNumber"); 124 if (it != properties.end()) 125 { 126 serialNumber(it->second.get<std::string>()); 127 } 128 129 emit_object_added(); 130 } 131 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 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 (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