blob: 8572259a3bb5d69b3bc2f2f81d2e95de301970d2 [file] [log] [blame]
#include "file_io_type_dump.hpp"
#include "utils.hpp"
#include "xyz/openbmc_project/Common/error.hpp"
#include <stdint.h>
#include <systemd/sd-bus.h>
#include <unistd.h>
#include <exception>
#include <filesystem>
#include <iostream>
#include <sdbusplus/server.hpp>
#include <xyz/openbmc_project/Dump/NewDump/server.hpp>
#include "libpldm/base.h"
#include "oem/ibm/libpldm/file_io.h"
using namespace pldm::utils;
namespace pldm
{
namespace responder
{
static constexpr auto nbdInterfaceDefault = "/dev/nbd1";
static constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
static constexpr auto dumpObjPath = "/xyz/openbmc_project/dump";
int DumpHandler::fd = -1;
static std::string findDumpObjPath(uint32_t fileHandle)
{
static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
static constexpr auto systemDumpEntry =
"xyz.openbmc_project.Dump.Entry.System";
auto& bus = pldm::utils::DBusHandler::getBus();
try
{
std::vector<std::string> paths;
auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
MAPPER_INTERFACE, "GetSubTreePaths");
method.append(dumpObjPath);
method.append(0);
method.append(std::vector<std::string>({systemDumpEntry}));
auto reply = bus.call(method);
reply.read(paths);
for (const auto& path : paths)
{
auto dumpId = pldm::utils::DBusHandler().getDbusProperty<uint32_t>(
path.c_str(), "SourceDumpId", systemDumpEntry);
if (dumpId == fileHandle)
{
return path;
}
}
}
catch (const std::exception& e)
{
std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
<< e.what() << "\n";
}
std::cerr << "failed to find dump object for dump id " << fileHandle
<< "\n";
return {};
}
int DumpHandler::newFileAvailable(uint64_t length)
{
static constexpr auto dumpInterface = "xyz.openbmc_project.Dump.NewDump";
auto& bus = pldm::utils::DBusHandler::getBus();
try
{
auto service =
pldm::utils::DBusHandler().getService(dumpObjPath, dumpInterface);
using namespace sdbusplus::xyz::openbmc_project::Dump::server;
auto method = bus.new_method_call(service.c_str(), dumpObjPath,
dumpInterface, "Notify");
method.append(
sdbusplus::xyz::openbmc_project::Dump::server::convertForMessage(
NewDump::DumpType::System),
fileHandle, length);
bus.call_noreply(method);
}
catch (const std::exception& e)
{
std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
<< e.what() << "\n";
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}
static std::string getOffloadUri(uint32_t fileHandle)
{
auto path = findDumpObjPath(fileHandle);
if (path.empty())
{
return {};
}
std::string nbdInterface{};
try
{
nbdInterface = pldm::utils::DBusHandler().getDbusProperty<std::string>(
path.c_str(), "OffloadUri", dumpEntry);
}
catch (const std::exception& e)
{
std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
<< e.what() << "\n";
}
if (nbdInterface == "")
{
nbdInterface = nbdInterfaceDefault;
}
return nbdInterface;
}
int DumpHandler::writeFromMemory(uint32_t offset, uint32_t length,
uint64_t address)
{
auto nbdInterface = getOffloadUri(fileHandle);
if (nbdInterface.empty())
{
return PLDM_ERROR;
}
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE;
if (DumpHandler::fd == -1)
{
DumpHandler::fd = open(nbdInterface.c_str(), flags);
if (DumpHandler::fd == -1)
{
std::cerr << "NBD file does not exist at " << nbdInterface
<< " ERROR=" << errno << "\n";
return PLDM_ERROR;
}
}
return transferFileData(DumpHandler::fd, false, offset, length, address);
}
int DumpHandler::write(const char* buffer, uint32_t offset, uint32_t& length)
{
auto nbdInterface = getOffloadUri(fileHandle);
if (nbdInterface.empty())
{
return PLDM_ERROR;
}
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE;
if (DumpHandler::fd == -1)
{
DumpHandler::fd = open(nbdInterface.c_str(), flags);
if (DumpHandler::fd == -1)
{
std::cerr << "NBD file does not exist at " << nbdInterface
<< " ERROR=" << errno << "\n";
return PLDM_ERROR;
}
}
int rc = lseek(DumpHandler::fd, offset, SEEK_SET);
if (rc == -1)
{
std::cerr << "lseek failed, ERROR=" << errno << ", OFFSET=" << offset
<< "\n";
return PLDM_ERROR;
}
rc = ::write(DumpHandler::fd, buffer, length);
if (rc == -1)
{
std::cerr << "file write failed, ERROR=" << errno
<< ", LENGTH=" << length << ", OFFSET=" << offset << "\n";
return PLDM_ERROR;
}
length = rc;
return PLDM_SUCCESS;
}
int DumpHandler::fileAck(uint8_t /*fileStatus*/)
{
if (DumpHandler::fd >= 0)
{
auto path = findDumpObjPath(fileHandle);
if (!path.empty())
{
PropertyValue value{true};
DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"};
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
std::cerr
<< "failed to make a d-bus call to DUMP manager, ERROR="
<< e.what() << "\n";
}
close(DumpHandler::fd);
DumpHandler::fd = -1;
return PLDM_SUCCESS;
}
}
return PLDM_ERROR;
}
} // namespace responder
} // namespace pldm