#include "file_io_type_dump.hpp" #include "common/utils.hpp" #include "utils.hpp" #include "xyz/openbmc_project/Common/error.hpp" #include #include #include #include #include #include #include #include #include #include #include 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(&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( 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.PLDM.Error.fileAck.ResourceDumpFileAckFail", pldm::PelSeverity::Informational); 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(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.PLDM.Error.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.PLDM.Error.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