blob: b7fa3a04db0885b68539fb6d4ae43daf33d73568 [file] [log] [blame]
#include "dump_entry.hpp"
#include "dump_manager.hpp"
#include <fcntl.h>
#include <nlohmann/json.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdeventplus/event.hpp>
#include <sdeventplus/source/event.hpp>
#include <xyz/openbmc_project/Common/File/error.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
#include <cstring>
namespace phosphor
{
namespace dump
{
using namespace phosphor::logging;
void Entry::delete_()
{
// Remove Dump entry D-bus object
parent.erase(id);
}
sdbusplus::message::unix_fd Entry::getFileHandle()
{
using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
using metadata = xyz::openbmc_project::Common::File::Open;
if (file.empty())
{
lg2::error("Failed to get file handle: File path is empty.");
elog<sdbusplus::xyz::openbmc_project::Common::Error::Unavailable>();
}
if (fdCloseEventSource)
{
// Return the existing file descriptor
return fdCloseEventSource->first;
}
int fd = open(file.c_str(), O_RDONLY | O_NONBLOCK);
if (fd == -1)
{
auto err = errno;
lg2::error("Failed to open dump file: id: {ID} error: {ERRNO}", "ID",
id, "ERRNO", std::strerror(errno));
elog<Open>(metadata::ERRNO(err), metadata::PATH(file.c_str()));
}
// Create a new Defer event source for closing this fd
sdeventplus::Event event = sdeventplus::Event::get_default();
auto eventSource = std::make_unique<sdeventplus::source::Defer>(
event, [this](auto& /*source*/) { closeFD(); });
// Store the file descriptor and event source in the optional pair
fdCloseEventSource = std::make_pair(fd, std::move(eventSource));
return fd;
}
void Entry::serialize()
{
// Folder for serialized entry
std::filesystem::path dir = file.parent_path() / PRESERVE;
// Serialized entry file
std::filesystem::path serializePath = dir / SERIAL_FILE;
try
{
if (!std::filesystem::exists(dir))
{
std::filesystem::create_directories(dir);
}
std::ofstream os(serializePath, std::ios::binary);
if (!os.is_open())
{
lg2::error("Failed to open file for serialization: {PATH} ", "PATH",
serializePath);
return;
}
nlohmann::json j;
j["version"] = CLASS_SERIALIZATION_VERSION;
j["dumpId"] = id;
j["originatorId"] = originatorId();
j["originatorType"] = originatorType();
j["startTime"] = startTime();
os << j.dump();
}
catch (const std::exception& e)
{
lg2::error("Serialization error: {PATH} {ERROR} ", "PATH",
serializePath, "ERROR", e);
// Remove the serialization folder if that got created
// Ignore the error since folder may not be created
std::error_code ec;
std::filesystem::remove_all(dir, ec);
}
}
void Entry::deserialize(const std::filesystem::path& dumpPath)
{
try
{
// .preserve folder
std::filesystem::path dir = dumpPath / PRESERVE;
if (!std::filesystem::exists(dir))
{
lg2::info("Serialization directory: {SERIAL_DIR} doesnt exist, "
"skip deserialization",
"SERIAL_DIR", dir);
return;
}
// Serialized entry
std::filesystem::path serializePath = dir / SERIAL_FILE;
std::ifstream is(serializePath, std::ios::binary);
if (!is.is_open())
{
lg2::error("Failed to open file for deserialization: {PATH}",
"PATH", serializePath);
return;
}
nlohmann::json j;
is >> j;
uint32_t version;
j.at("version").get_to(version);
if (version == CLASS_SERIALIZATION_VERSION)
{
uint32_t storedId;
j.at("dumpId").get_to(storedId);
if (storedId == id)
{
originatorId(j["originatorId"].get<std::string>());
originatorType(j["originatorType"].get<originatorTypes>());
startTime(j["startTime"].get<uint64_t>());
}
else
{
lg2::error("The id ({ID_IN_FILE}) is not matching the dump id "
"({DUMPID}); skipping deserialization.",
"ID_IN_FILE", storedId, "DUMPID", id);
// Id is not matching, this could be due to file corruption
// deleting the .preserve folder.
// Attempt to delete the folder and ignore any error.
std::error_code ec;
std::filesystem::remove_all(dir, ec);
}
}
else
{
lg2::error("The serialized file version and current class version"
"doesnt match, skip deserialization {VERSION}",
"VERSION", version);
}
}
catch (const std::exception& e)
{
lg2::error("Deserialization error: {PATH}, {ERROR}", "PATH", dumpPath,
"ERROR", e);
}
}
} // namespace dump
} // namespace phosphor