1 #include "dump_entry.hpp" 2 3 #include "dump_manager.hpp" 4 5 #include <fcntl.h> 6 7 #include <nlohmann/json.hpp> 8 #include <phosphor-logging/elog-errors.hpp> 9 #include <phosphor-logging/elog.hpp> 10 #include <phosphor-logging/lg2.hpp> 11 #include <sdeventplus/event.hpp> 12 #include <sdeventplus/source/event.hpp> 13 #include <xyz/openbmc_project/Common/File/error.hpp> 14 #include <xyz/openbmc_project/Common/error.hpp> 15 16 #include <cstring> 17 18 namespace phosphor 19 { 20 namespace dump 21 { 22 23 using namespace phosphor::logging; 24 25 void Entry::delete_() 26 { 27 // Remove Dump entry D-bus object 28 parent.erase(id); 29 } 30 31 sdbusplus::message::unix_fd Entry::getFileHandle() 32 { 33 using namespace sdbusplus::xyz::openbmc_project::Common::File::Error; 34 using metadata = xyz::openbmc_project::Common::File::Open; 35 if (file.empty()) 36 { 37 lg2::error("Failed to get file handle: File path is empty."); 38 elog<sdbusplus::xyz::openbmc_project::Common::Error::Unavailable>(); 39 } 40 41 if (fdCloseEventSource) 42 { 43 // Return the existing file descriptor 44 return fdCloseEventSource->first; 45 } 46 47 int fd = open(file.c_str(), O_RDONLY | O_NONBLOCK); 48 if (fd == -1) 49 { 50 auto err = errno; 51 lg2::error("Failed to open dump file: id: {ID} error: {ERRNO}", "ID", 52 id, "ERRNO", std::strerror(errno)); 53 elog<Open>(metadata::ERRNO(err), metadata::PATH(file.c_str())); 54 } 55 56 // Create a new Defer event source for closing this fd 57 sdeventplus::Event event = sdeventplus::Event::get_default(); 58 auto eventSource = std::make_unique<sdeventplus::source::Defer>( 59 event, [this](auto& /*source*/) { closeFD(); }); 60 61 // Store the file descriptor and event source in the optional pair 62 fdCloseEventSource = std::make_pair(fd, std::move(eventSource)); 63 64 return fd; 65 } 66 67 void Entry::serialize() 68 { 69 // Folder for serialized entry 70 std::filesystem::path dir = file.parent_path() / PRESERVE; 71 72 // Serialized entry file 73 std::filesystem::path serializePath = dir / SERIAL_FILE; 74 try 75 { 76 if (!std::filesystem::exists(dir)) 77 { 78 std::filesystem::create_directories(dir); 79 } 80 81 std::ofstream os(serializePath, std::ios::binary); 82 if (!os.is_open()) 83 { 84 lg2::error("Failed to open file for serialization: {PATH} ", "PATH", 85 serializePath); 86 return; 87 } 88 nlohmann::json j; 89 j["version"] = CLASS_SERIALIZATION_VERSION; 90 j["dumpId"] = id; 91 j["originatorId"] = originatorId(); 92 j["originatorType"] = originatorType(); 93 j["startTime"] = startTime(); 94 95 os << j.dump(); 96 } 97 catch (const std::exception& e) 98 { 99 lg2::error("Serialization error: {PATH} {ERROR} ", "PATH", 100 serializePath, "ERROR", e); 101 102 // Remove the serialization folder if that got created 103 // Ignore the error since folder may not be created 104 std::error_code ec; 105 std::filesystem::remove_all(dir, ec); 106 } 107 } 108 109 void Entry::deserialize(const std::filesystem::path& dumpPath) 110 { 111 try 112 { 113 // .preserve folder 114 std::filesystem::path dir = dumpPath / PRESERVE; 115 if (!std::filesystem::exists(dir)) 116 { 117 lg2::info("Serialization directory: {SERIAL_DIR} doesnt exist, " 118 "skip deserialization", 119 "SERIAL_DIR", dir); 120 return; 121 } 122 123 // Serialized entry 124 std::filesystem::path serializePath = dir / SERIAL_FILE; 125 std::ifstream is(serializePath, std::ios::binary); 126 if (!is.is_open()) 127 { 128 lg2::error("Failed to open file for deserialization: {PATH}", 129 "PATH", serializePath); 130 return; 131 } 132 nlohmann::json j; 133 is >> j; 134 135 uint32_t version; 136 j.at("version").get_to(version); 137 if (version == CLASS_SERIALIZATION_VERSION) 138 { 139 uint32_t storedId; 140 j.at("dumpId").get_to(storedId); 141 if (storedId == id) 142 { 143 originatorId(j["originatorId"].get<std::string>()); 144 originatorType(j["originatorType"].get<originatorTypes>()); 145 startTime(j["startTime"].get<uint64_t>()); 146 } 147 else 148 { 149 lg2::error("The id ({ID_IN_FILE}) is not matching the dump id " 150 "({DUMPID}); skipping deserialization.", 151 "ID_IN_FILE", storedId, "DUMPID", id); 152 153 // Id is not matching, this could be due to file corruption 154 // deleting the .preserve folder. 155 // Attempt to delete the folder and ignore any error. 156 std::error_code ec; 157 std::filesystem::remove_all(dir, ec); 158 } 159 } 160 else 161 { 162 lg2::error("The serialized file version and current class version" 163 "doesnt match, skip deserialization {VERSION}", 164 "VERSION", version); 165 } 166 } 167 catch (const std::exception& e) 168 { 169 lg2::error("Deserialization error: {PATH}, {ERROR}", "PATH", dumpPath, 170 "ERROR", e); 171 } 172 } 173 174 } // namespace dump 175 } // namespace phosphor 176