1 #include "file_io_type_dump.hpp" 2 3 #include "libpldm/base.h" 4 #include "oem/ibm/libpldm/file_io.h" 5 6 #include "common/utils.hpp" 7 #include "xyz/openbmc_project/Common/error.hpp" 8 9 #include <stdint.h> 10 #include <systemd/sd-bus.h> 11 #include <unistd.h> 12 13 #include <sdbusplus/server.hpp> 14 #include <xyz/openbmc_project/Dump/NewDump/server.hpp> 15 16 #include <exception> 17 #include <filesystem> 18 #include <iostream> 19 20 using namespace pldm::utils; 21 22 namespace pldm 23 { 24 namespace responder 25 { 26 27 static constexpr auto nbdInterfaceDefault = "/dev/nbd1"; 28 static constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry"; 29 static constexpr auto dumpObjPath = "/xyz/openbmc_project/dump"; 30 31 int DumpHandler::fd = -1; 32 33 static std::string findDumpObjPath(uint32_t fileHandle) 34 { 35 static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; 36 static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; 37 static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; 38 static constexpr auto systemDumpEntry = 39 "xyz.openbmc_project.Dump.Entry.System"; 40 auto& bus = pldm::utils::DBusHandler::getBus(); 41 42 try 43 { 44 std::vector<std::string> paths; 45 auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 46 MAPPER_INTERFACE, "GetSubTreePaths"); 47 method.append(dumpObjPath); 48 method.append(0); 49 method.append(std::vector<std::string>({systemDumpEntry})); 50 auto reply = bus.call(method); 51 reply.read(paths); 52 for (const auto& path : paths) 53 { 54 auto dumpId = pldm::utils::DBusHandler().getDbusProperty<uint32_t>( 55 path.c_str(), "SourceDumpId", systemDumpEntry); 56 if (dumpId == fileHandle) 57 { 58 return path; 59 } 60 } 61 } 62 catch (const std::exception& e) 63 { 64 std::cerr << "failed to make a d-bus call to DUMP manager, ERROR=" 65 << e.what() << "\n"; 66 } 67 68 std::cerr << "failed to find dump object for dump id " << fileHandle 69 << "\n"; 70 return {}; 71 } 72 73 int DumpHandler::newFileAvailable(uint64_t length) 74 { 75 static constexpr auto dumpInterface = "xyz.openbmc_project.Dump.NewDump"; 76 auto& bus = pldm::utils::DBusHandler::getBus(); 77 78 try 79 { 80 auto service = 81 pldm::utils::DBusHandler().getService(dumpObjPath, dumpInterface); 82 using namespace sdbusplus::xyz::openbmc_project::Dump::server; 83 auto method = bus.new_method_call(service.c_str(), dumpObjPath, 84 dumpInterface, "Notify"); 85 method.append( 86 sdbusplus::xyz::openbmc_project::Dump::server::convertForMessage( 87 NewDump::DumpType::System), 88 fileHandle, length); 89 bus.call_noreply(method); 90 } 91 catch (const std::exception& e) 92 { 93 std::cerr << "failed to make a d-bus call to DUMP manager, ERROR=" 94 << e.what() << "\n"; 95 return PLDM_ERROR; 96 } 97 98 return PLDM_SUCCESS; 99 } 100 101 static std::string getOffloadUri(uint32_t fileHandle) 102 { 103 auto path = findDumpObjPath(fileHandle); 104 if (path.empty()) 105 { 106 return {}; 107 } 108 109 std::string nbdInterface{}; 110 try 111 { 112 nbdInterface = pldm::utils::DBusHandler().getDbusProperty<std::string>( 113 path.c_str(), "OffloadUri", dumpEntry); 114 } 115 catch (const std::exception& e) 116 { 117 std::cerr << "failed to make a d-bus call to DUMP manager, ERROR=" 118 << e.what() << "\n"; 119 } 120 121 if (nbdInterface == "") 122 { 123 nbdInterface = nbdInterfaceDefault; 124 } 125 126 return nbdInterface; 127 } 128 129 int DumpHandler::writeFromMemory(uint32_t offset, uint32_t length, 130 uint64_t address) 131 { 132 auto nbdInterface = getOffloadUri(fileHandle); 133 if (nbdInterface.empty()) 134 { 135 return PLDM_ERROR; 136 } 137 138 int flags = O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE; 139 if (DumpHandler::fd == -1) 140 { 141 DumpHandler::fd = open(nbdInterface.c_str(), flags); 142 if (DumpHandler::fd == -1) 143 { 144 std::cerr << "NBD file does not exist at " << nbdInterface 145 << " ERROR=" << errno << "\n"; 146 return PLDM_ERROR; 147 } 148 } 149 150 return transferFileData(DumpHandler::fd, false, offset, length, address); 151 } 152 153 int DumpHandler::write(const char* buffer, uint32_t offset, uint32_t& length) 154 { 155 auto nbdInterface = getOffloadUri(fileHandle); 156 if (nbdInterface.empty()) 157 { 158 return PLDM_ERROR; 159 } 160 161 int flags = O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE; 162 if (DumpHandler::fd == -1) 163 { 164 DumpHandler::fd = open(nbdInterface.c_str(), flags); 165 if (DumpHandler::fd == -1) 166 { 167 std::cerr << "NBD file does not exist at " << nbdInterface 168 << " ERROR=" << errno << "\n"; 169 return PLDM_ERROR; 170 } 171 } 172 173 int rc = lseek(DumpHandler::fd, offset, SEEK_SET); 174 if (rc == -1) 175 { 176 std::cerr << "lseek failed, ERROR=" << errno << ", OFFSET=" << offset 177 << "\n"; 178 return PLDM_ERROR; 179 } 180 rc = ::write(DumpHandler::fd, buffer, length); 181 if (rc == -1) 182 { 183 std::cerr << "file write failed, ERROR=" << errno 184 << ", LENGTH=" << length << ", OFFSET=" << offset << "\n"; 185 return PLDM_ERROR; 186 } 187 length = rc; 188 189 return PLDM_SUCCESS; 190 } 191 192 int DumpHandler::fileAck(uint8_t /*fileStatus*/) 193 { 194 if (DumpHandler::fd >= 0) 195 { 196 auto path = findDumpObjPath(fileHandle); 197 if (!path.empty()) 198 { 199 PropertyValue value{true}; 200 DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"}; 201 try 202 { 203 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 204 } 205 catch (const std::exception& e) 206 { 207 std::cerr 208 << "failed to make a d-bus call to DUMP manager, ERROR=" 209 << e.what() << "\n"; 210 } 211 close(DumpHandler::fd); 212 DumpHandler::fd = -1; 213 return PLDM_SUCCESS; 214 } 215 } 216 217 return PLDM_ERROR; 218 } 219 220 } // namespace responder 221 } // namespace pldm 222