blob: 83343b7d36026d536efe66f2e79f8d7bab7e3480 [file] [log] [blame]
#include "file_io_type_dump.hpp"
#include "common/utils.hpp"
#include "utils.hpp"
#include "xyz/openbmc_project/Common/error.hpp"
#include <libpldm/base.h>
#include <libpldm/oem/ibm/file_io.h>
#include <stdint.h>
#include <systemd/sd-bus.h>
#include <unistd.h>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/server.hpp>
#include <xyz/openbmc_project/Dump/NewDump/server.hpp>
#include <exception>
#include <filesystem>
#include <type_traits>
PHOSPHOR_LOG2_USING;
using namespace pldm::responder::utils;
using namespace pldm::utils;
namespace pldm
{
namespace responder
{
static constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
static constexpr auto dumpObjPath = "/xyz/openbmc_project/dump/system";
static constexpr auto systemDumpEntry = "xyz.openbmc_project.Dump.Entry.System";
static constexpr auto resDumpObjPath = "/xyz/openbmc_project/dump/resource";
static constexpr auto resDumpEntry = "com.ibm.Dump.Entry.Resource";
// Resource dump file path to be deleted once hyperviosr validates the input
// parameters. Need to re-look in to this name when we support multiple
// resource dumps.
static constexpr auto resDumpDirPath = "/var/lib/pldm/resourcedump/1";
int DumpHandler::fd = -1;
namespace fs = std::filesystem;
std::string DumpHandler::findDumpObjPath(uint32_t fileHandle)
{
static constexpr auto DUMP_MANAGER_BUSNAME =
"xyz.openbmc_project.Dump.Manager";
static constexpr auto DUMP_MANAGER_PATH = "/xyz/openbmc_project/dump";
// Stores the current resource dump entry path
std::string curResDumpEntryPath{};
ObjectValueTree objects;
// Select the dump entry interface for system dump or resource dump
DumpEntryInterface dumpEntryIntf = systemDumpEntry;
if ((dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) ||
(dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS))
{
dumpEntryIntf = resDumpEntry;
}
try
{
objects = pldm::utils::DBusHandler::getManagedObj(DUMP_MANAGER_BUSNAME,
DUMP_MANAGER_PATH);
}
catch (const sdbusplus::exception_t& e)
{
error(
"findDumpObjPath: Error {ERR_EXCEP} found with GetManagedObjects call in findDumpObjPath with objPath={OBJ_PATH} and intf={DUMP_INFT}",
"ERR_EXCEP", e.what(), "OBJ_PATH", DUMP_MANAGER_PATH, "DUMP_INFT",
dumpEntryIntf);
return curResDumpEntryPath;
}
for (const auto& object : objects)
{
for (const auto& interface : object.second)
{
if (interface.first != dumpEntryIntf)
{
continue;
}
for (auto& propertyMap : interface.second)
{
if (propertyMap.first == "SourceDumpId")
{
auto dumpIdPtr = std::get_if<uint32_t>(&propertyMap.second);
if (dumpIdPtr != nullptr)
{
auto dumpId = *dumpIdPtr;
if (fileHandle == dumpId)
{
curResDumpEntryPath = object.first.str;
return curResDumpEntryPath;
}
}
else
{
error(
"Invalid SourceDumpId in curResDumpEntryPath {CUR_RES_DUMP_PATH} but continuing with next entry for a match...",
"CUR_RES_DUMP_PATH", curResDumpEntryPath);
}
}
}
}
}
return curResDumpEntryPath;
}
int DumpHandler::newFileAvailable(uint64_t length)
{
static constexpr auto dumpInterface = "xyz.openbmc_project.Dump.NewDump";
auto& bus = pldm::utils::DBusHandler::getBus();
auto notifyObjPath = dumpObjPath;
if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
{
// Setting the Notify path for resource dump
notifyObjPath = resDumpObjPath;
}
try
{
auto service = pldm::utils::DBusHandler().getService(notifyObjPath,
dumpInterface);
using namespace sdbusplus::xyz::openbmc_project::Dump::server;
auto method = bus.new_method_call(service.c_str(), notifyObjPath,
dumpInterface, "Notify");
method.append(fileHandle, length);
bus.call_noreply(method, dbusTimeout);
}
catch (const std::exception& e)
{
error(
"newFileAvailable: Error {ERR_EXCEP} found while notifying new dump to dump manager with objPath={OBJ_PATH} and intf={DUMP_INTF}",
"ERR_EXCEP", e.what(), "OBJ_PATH", notifyObjPath, "DUMP_INTF",
dumpInterface);
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}
std::string DumpHandler::getOffloadUri(uint32_t fileHandle)
{
auto path = findDumpObjPath(fileHandle);
if (path.empty())
{
return {};
}
std::string socketInterface{};
try
{
socketInterface =
pldm::utils::DBusHandler().getDbusProperty<std::string>(
path.c_str(), "OffloadUri", dumpEntry);
}
catch (const std::exception& e)
{
error(
"getOffloadUri: Error {ERR_EXCEP} found while fetching the dump offload URI with objPath={OBJ_PATH} and intf={SOCKET_INTF}",
"ERR_EXCEP", e.what(), "OBJ_PATH", path.c_str(), "SOCKET_INTF",
socketInterface);
}
return socketInterface;
}
int DumpHandler::writeFromMemory(uint32_t, uint32_t length, uint64_t address,
oem_platform::Handler* /*oemPlatformHandler*/)
{
if (DumpHandler::fd == -1)
{
auto socketInterface = getOffloadUri(fileHandle);
int sock = setupUnixSocket(socketInterface);
if (sock < 0)
{
sock = -errno;
close(DumpHandler::fd);
error(
"DumpHandler::writeFromMemory: setupUnixSocket() failed ERR={ERR_NO}",
"ERR_NO", sock);
std::remove(socketInterface.c_str());
return PLDM_ERROR;
}
DumpHandler::fd = sock;
}
return transferFileDataToSocket(DumpHandler::fd, length, address);
}
int DumpHandler::write(const char* buffer, uint32_t, uint32_t& length,
oem_platform::Handler* /*oemPlatformHandler*/)
{
int rc = writeToUnixSocket(DumpHandler::fd, buffer, length);
if (rc < 0)
{
rc = -errno;
close(DumpHandler::fd);
auto socketInterface = getOffloadUri(fileHandle);
std::remove(socketInterface.c_str());
error("DumpHandler::write: writeToUnixSocket() failed ERR={RC_VAL}",
"RC_VAL", rc);
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}
int DumpHandler::fileAck(uint8_t fileStatus)
{
auto path = findDumpObjPath(fileHandle);
if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
{
if (fileStatus != PLDM_SUCCESS)
{
error("Failue in resource dump file ack");
pldm::utils::reportError(
"xyz.openbmc_project.bmc.pldm.InternalFailure");
PropertyValue value{
"xyz.openbmc_project.Common.Progress.OperationStatus.Failed"};
DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress",
"Status", "string"};
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
error(
"fileAck: Error {ERR_EXCEP} found while setting the dump progress status as Failed with objPath={OBJ_PATH} and intf=Common.Progress",
"ERR_EXCEP", e.what(), "OBJ_PATH", path.c_str());
}
}
if (fs::exists(resDumpDirPath))
{
fs::remove_all(resDumpDirPath);
}
return PLDM_SUCCESS;
}
if (!path.empty())
{
if (fileStatus == PLDM_ERROR_FILE_DISCARDED)
{
uint32_t val = 0xFFFFFFFF;
PropertyValue value = static_cast<uint32_t>(val);
auto dumpIntf = resDumpEntry;
if (dumpType == PLDM_FILE_TYPE_DUMP)
{
dumpIntf = systemDumpEntry;
}
DBusMapping dbusMapping{path.c_str(), dumpIntf, "SourceDumpId",
"uint32_t"};
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
error(
"fileAck: Failed to make a d-bus call to DUMP manager to reset source dump id of {FILE_PATH}, with ERROR={ERR_EXCEP}",
"FILE_PATH", path.c_str(), "ERR_EXCEP", e.what());
pldm::utils::reportError(
"xyz.openbmc_project.bmc.PLDM.fileAck.SourceDumpIdResetFail");
return PLDM_ERROR;
}
auto& bus = pldm::utils::DBusHandler::getBus();
try
{
auto method = bus.new_method_call(
"xyz.openbmc_project.Dump.Manager", path.c_str(),
"xyz.openbmc_project.Object.Delete", "Delete");
bus.call(method, dbusTimeout);
}
catch (const std::exception& e)
{
error(
"fileAck: Failed to make a d-bus method to delete the dump entry {FILE_PATH}, with ERROR={ERR_EXCEP}",
"FILE_PATH", path.c_str(), "ERR_EXCEP", e.what());
pldm::utils::reportError(
"xyz.openbmc_project.bmc.PLDM.fileAck.DumpEntryDeleteFail");
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}
if (dumpType == PLDM_FILE_TYPE_DUMP ||
dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
{
PropertyValue value{true};
DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"};
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
error(
"fileAck: Failed to make a d-bus method to set the dump offloaded property to true with path={FILE_PATH} and with ERROR={ERR_EXCEP}",
"FILE_PATH", path.c_str(), "ERR_EXCEP", e.what());
}
auto socketInterface = getOffloadUri(fileHandle);
std::remove(socketInterface.c_str());
if (DumpHandler::fd >= 0)
{
close(DumpHandler::fd);
DumpHandler::fd = -1;
}
}
return PLDM_SUCCESS;
}
return PLDM_ERROR;
}
int DumpHandler::readIntoMemory(uint32_t offset, uint32_t& length,
uint64_t address,
oem_platform::Handler* /*oemPlatformHandler*/)
{
if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
{
return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
}
return transferFileData(resDumpDirPath, true, offset, length, address);
}
int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response,
oem_platform::Handler* /*oemPlatformHandler*/)
{
if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
{
return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
}
return readFile(resDumpDirPath, offset, length, response);
}
} // namespace responder
} // namespace pldm