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