#include "dbus_to_file_handler.hpp" #include "common/utils.hpp" #include #include PHOSPHOR_LOG2_USING; namespace pldm { namespace requester { namespace oem_ibm { using namespace pldm::utils; using namespace sdbusplus::bus::match::rules; static constexpr auto resDumpProgressIntf = "xyz.openbmc_project.Common.Progress"; static constexpr auto resDumpStatus = "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"; DbusToFileHandler::DbusToFileHandler( int mctp_fd, uint8_t mctp_eid, pldm::InstanceIdDb* instanceIdDb, sdbusplus::message::object_path resDumpCurrentObjPath, pldm::requester::Handler* handler) : mctp_fd(mctp_fd), mctp_eid(mctp_eid), instanceIdDb(instanceIdDb), resDumpCurrentObjPath(resDumpCurrentObjPath), handler(handler) {} void DbusToFileHandler::sendNewFileAvailableCmd(uint64_t fileSize) { if (instanceIdDb == NULL) { error( "Failed to send resource dump parameters as instance ID DB is not set"); pldm::utils::reportError( "xyz.openbmc_project.bmc.pldm.InternalFailure"); return; } auto instanceId = instanceIdDb->next(mctp_eid); std::vector requestMsg(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_REQ_BYTES); auto request = reinterpret_cast(requestMsg.data()); // Need to revisit this logic at the time of multiple resource dump support uint32_t fileHandle = 1; auto rc = encode_new_file_req(instanceId, PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS, fileHandle, fileSize, request); if (rc != PLDM_SUCCESS) { instanceIdDb->free(mctp_eid, instanceId); error("Failed to encode_new_file_req, rc = {RC}", "RC", rc); return; } auto newFileAvailableRespHandler = [this](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { if (response == nullptr || !respMsgLen) { error("Failed to receive response for NewFileAvailable command"); return; } uint8_t completionCode{}; auto rc = decode_new_file_resp(response, respMsgLen, &completionCode); if (rc || completionCode) { error( "Failed to decode_new_file_resp or Host returned error for new_file_available rc={RC}, cc = {CC}", "RC", rc, "CC", static_cast(completionCode)); reportResourceDumpFailure(); } }; rc = handler->registerRequest( mctp_eid, instanceId, PLDM_OEM, PLDM_NEW_FILE_AVAILABLE, std::move(requestMsg), std::move(newFileAvailableRespHandler)); if (rc) { error("Failed to send NewFileAvailable Request to Host"); reportResourceDumpFailure(); } } void DbusToFileHandler::reportResourceDumpFailure() { pldm::utils::reportError("xyz.openbmc_project.bmc.pldm.InternalFailure"); PropertyValue value{resDumpStatus}; DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf, "Status", "string"}; try { pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); } catch (const std::exception& e) { error("failed to set resource dump operation status, ERROR={ERR_EXCEP}", "ERR_EXCEP", e.what()); } } void DbusToFileHandler::processNewResourceDump( const std::string& vspString, const std::string& resDumpReqPass) { try { std::string objPath = resDumpCurrentObjPath; auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant( objPath.c_str(), "Status", resDumpProgressIntf); const auto& curResDumpStatus = std::get(propVal); if (curResDumpStatus != "xyz.openbmc_project.Common.Progress.OperationStatus.InProgress") { return; } } catch (const sdbusplus::exception_t& e) { error( "Error {ERR_EXCEP} found in getting current resource dump status while initiating a new resource dump with objPath={DUMP_OBJ_PATH} and intf={DUMP_PROG_INTF}", "ERR_EXCEP", e.what(), "DUMP_OBJ_PATH", resDumpCurrentObjPath.str.c_str(), "DUMP_PROG_INTF", resDumpProgressIntf); } namespace fs = std::filesystem; const fs::path resDumpDirPath = "/var/lib/pldm/resourcedump"; if (!fs::exists(resDumpDirPath)) { fs::create_directories(resDumpDirPath); } // Need to reconsider this logic to set the value as "1" when we have the // support to handle multiple resource dumps fs::path resDumpFilePath = resDumpDirPath / "1"; std::ofstream fileHandle; fileHandle.open(resDumpFilePath, std::ios::out | std::ofstream::binary); if (!fileHandle) { error("resource dump file open error:{RES_DUMP_PATH}", "RES_DUMP_PATH", resDumpFilePath); PropertyValue value{resDumpStatus}; DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf, "Status", "string"}; try { pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); } catch (const std::exception& e) { error( "failed to set resource dump operation status, ERROR={ERR_EXCEP}", "ERR_EXCEP", e.what()); } return; } // Fill up the file with resource dump parameters and respective sizes auto fileFunc = [&fileHandle](auto& paramBuf) { uint32_t paramSize = paramBuf.size(); fileHandle.write((char*)¶mSize, sizeof(paramSize)); fileHandle << paramBuf; }; fileFunc(vspString); fileFunc(resDumpReqPass); std::string str; if (!resDumpReqPass.empty()) { str = getAcfFileContent(); } fileFunc(str); fileHandle.close(); size_t fileSize = fs::file_size(resDumpFilePath); sendNewFileAvailableCmd(fileSize); } std::string DbusToFileHandler::getAcfFileContent() { std::string str; static constexpr auto acfDirPath = "/etc/acf/service.acf"; if (fs::exists(acfDirPath)) { std::ifstream file; file.open(acfDirPath); std::stringstream acfBuf; acfBuf << file.rdbuf(); str = acfBuf.str(); file.close(); } return str; } void DbusToFileHandler::newCsrFileAvailable(const std::string& csr, const std::string fileHandle) { namespace fs = std::filesystem; std::string dirPath = "/var/lib/ibm/bmcweb"; const fs::path certDirPath = dirPath; if (!fs::exists(certDirPath)) { fs::create_directories(certDirPath); fs::permissions(certDirPath, fs::perms::others_read | fs::perms::owner_write); } fs::path certFilePath = certDirPath / ("CSR_" + fileHandle); std::ofstream certFile; certFile.open(certFilePath, std::ios::out | std::ofstream::binary); if (!certFile) { error("cert file open error: {CERT_PATH}", "CERT_PATH", certFilePath.c_str()); return; } // Add csr to file certFile << csr << std::endl; certFile.close(); uint32_t fileSize = fs::file_size(certFilePath); newFileAvailableSendToHost(fileSize, (uint32_t)stoi(fileHandle), PLDM_FILE_TYPE_CERT_SIGNING_REQUEST); } void DbusToFileHandler::newFileAvailableSendToHost(const uint32_t fileSize, const uint32_t fileHandle, const uint16_t type) { if (instanceIdDb == NULL) { error("Failed to send csr to host."); pldm::utils::reportError( "xyz.openbmc_project.bmc.pldm.InternalFailure"); return; } auto instanceId = instanceIdDb->next(mctp_eid); std::vector requestMsg(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_REQ_BYTES); auto request = reinterpret_cast(requestMsg.data()); auto rc = encode_new_file_req(instanceId, type, fileHandle, fileSize, request); if (rc != PLDM_SUCCESS) { instanceIdDb->free(mctp_eid, instanceId); error("Failed to encode_new_file_req, rc = {RC}", "RC", rc); return; } auto newFileAvailableRespHandler = [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { if (response == nullptr || !respMsgLen) { error( "Failed to receive response for NewFileAvailable command for vmi"); return; } uint8_t completionCode{}; auto rc = decode_new_file_resp(response, respMsgLen, &completionCode); if (rc || completionCode) { error( "Failed to decode_new_file_resp for vmi, or Host returned error for new_file_available rc = {RC}, cc = {CC}", "RC", rc, "CC", static_cast(completionCode)); pldm::utils::reportError( "xyz.openbmc_project.bmc.pldm.InternalFailure"); } }; rc = handler->registerRequest( mctp_eid, instanceId, PLDM_OEM, PLDM_NEW_FILE_AVAILABLE, std::move(requestMsg), std::move(newFileAvailableRespHandler)); if (rc) { error("Failed to send NewFileAvailable Request to Host for vmi"); pldm::utils::reportError( "xyz.openbmc_project.bmc.pldm.InternalFailure"); } } } // namespace oem_ibm } // namespace requester } // namespace pldm