1 #include "file_io_type_dump.hpp"
2 
3 #include "common/utils.hpp"
4 #include "utils.hpp"
5 #include "xyz/openbmc_project/Common/error.hpp"
6 
7 #include <libpldm/base.h>
8 #include <libpldm/oem/ibm/file_io.h>
9 #include <stdint.h>
10 #include <systemd/sd-bus.h>
11 #include <unistd.h>
12 
13 #include <phosphor-logging/lg2.hpp>
14 #include <sdbusplus/server.hpp>
15 #include <xyz/openbmc_project/Dump/NewDump/server.hpp>
16 
17 #include <exception>
18 #include <filesystem>
19 #include <type_traits>
20 
21 PHOSPHOR_LOG2_USING;
22 
23 using namespace pldm::responder::utils;
24 using namespace pldm::utils;
25 
26 namespace pldm
27 {
28 namespace responder
29 {
30 static constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
31 static constexpr auto dumpObjPath = "/xyz/openbmc_project/dump/system";
32 static constexpr auto systemDumpEntry = "xyz.openbmc_project.Dump.Entry.System";
33 static constexpr auto resDumpObjPath = "/xyz/openbmc_project/dump/resource";
34 static constexpr auto resDumpEntry = "com.ibm.Dump.Entry.Resource";
35 
36 // Resource dump file path to be deleted once hyperviosr validates the input
37 // parameters. Need to re-look in to this name when we support multiple
38 // resource dumps.
39 static constexpr auto resDumpDirPath = "/var/lib/pldm/resourcedump/1";
40 
41 int DumpHandler::fd = -1;
42 namespace fs = std::filesystem;
43 
44 std::string DumpHandler::findDumpObjPath(uint32_t fileHandle)
45 {
46     static constexpr auto DUMP_MANAGER_BUSNAME =
47         "xyz.openbmc_project.Dump.Manager";
48     static constexpr auto DUMP_MANAGER_PATH = "/xyz/openbmc_project/dump";
49     static constexpr auto OBJECT_MANAGER_INTERFACE =
50         "org.freedesktop.DBus.ObjectManager";
51     auto& bus = pldm::utils::DBusHandler::getBus();
52 
53     // Stores the current resource dump entry path
54     std::string curResDumpEntryPath{};
55 
56     dbus::ObjectValueTree objects;
57     // Select the dump entry interface for system dump or resource dump
58     DumpEntryInterface dumpEntryIntf = systemDumpEntry;
59     if ((dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) ||
60         (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS))
61     {
62         dumpEntryIntf = resDumpEntry;
63     }
64 
65     try
66     {
67         auto method =
68             bus.new_method_call(DUMP_MANAGER_BUSNAME, DUMP_MANAGER_PATH,
69                                 OBJECT_MANAGER_INTERFACE, "GetManagedObjects");
70 
71         auto reply = bus.call(method, dbusTimeout);
72         reply.read(objects);
73     }
74     catch (const sdbusplus::exception_t& e)
75     {
76         error(
77             "findDumpObjPath: Error {ERR_EXCEP} found with GetManagedObjects call in findDumpObjPath with objPath={OBJ_PATH} and intf={DUMP_INFT}",
78             "ERR_EXCEP", e.what(), "OBJ_PATH", DUMP_MANAGER_PATH, "DUMP_INFT",
79             dumpEntryIntf);
80         return curResDumpEntryPath;
81     }
82 
83     for (const auto& object : objects)
84     {
85         for (const auto& interface : object.second)
86         {
87             if (interface.first != dumpEntryIntf)
88             {
89                 continue;
90             }
91 
92             for (auto& propertyMap : interface.second)
93             {
94                 if (propertyMap.first == "SourceDumpId")
95                 {
96                     auto dumpIdPtr = std::get_if<uint32_t>(&propertyMap.second);
97                     if (dumpIdPtr != nullptr)
98                     {
99                         auto dumpId = *dumpIdPtr;
100                         if (fileHandle == dumpId)
101                         {
102                             curResDumpEntryPath = object.first.str;
103                             return curResDumpEntryPath;
104                         }
105                     }
106                     else
107                     {
108                         error(
109                             "Invalid SourceDumpId in curResDumpEntryPath {CUR_RES_DUMP_PATH} but continuing with next entry for a match...",
110                             "CUR_RES_DUMP_PATH", curResDumpEntryPath);
111                     }
112                 }
113             }
114         }
115     }
116     return curResDumpEntryPath;
117 }
118 
119 int DumpHandler::newFileAvailable(uint64_t length)
120 {
121     static constexpr auto dumpInterface = "xyz.openbmc_project.Dump.NewDump";
122     auto& bus = pldm::utils::DBusHandler::getBus();
123 
124     auto notifyObjPath = dumpObjPath;
125     if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
126     {
127         // Setting the Notify path for resource dump
128         notifyObjPath = resDumpObjPath;
129     }
130 
131     try
132     {
133         auto service = pldm::utils::DBusHandler().getService(notifyObjPath,
134                                                              dumpInterface);
135         using namespace sdbusplus::xyz::openbmc_project::Dump::server;
136         auto method = bus.new_method_call(service.c_str(), notifyObjPath,
137                                           dumpInterface, "Notify");
138         method.append(fileHandle, length);
139         bus.call_noreply(method, dbusTimeout);
140     }
141     catch (const std::exception& e)
142     {
143         error(
144             "newFileAvailable: Error {ERR_EXCEP} found while notifying new dump to dump manager with objPath={OBJ_PATH} and intf={DUMP_INTF}",
145             "ERR_EXCEP", e.what(), "OBJ_PATH", notifyObjPath, "DUMP_INTF",
146             dumpInterface);
147         return PLDM_ERROR;
148     }
149 
150     return PLDM_SUCCESS;
151 }
152 
153 std::string DumpHandler::getOffloadUri(uint32_t fileHandle)
154 {
155     auto path = findDumpObjPath(fileHandle);
156     if (path.empty())
157     {
158         return {};
159     }
160 
161     std::string socketInterface{};
162 
163     try
164     {
165         socketInterface =
166             pldm::utils::DBusHandler().getDbusProperty<std::string>(
167                 path.c_str(), "OffloadUri", dumpEntry);
168     }
169     catch (const std::exception& e)
170     {
171         error(
172             "getOffloadUri: Error {ERR_EXCEP} found while fetching the dump offload URI with objPath={OBJ_PATH} and intf={SOCKET_INTF}",
173             "ERR_EXCEP", e.what(), "OBJ_PATH", path.c_str(), "SOCKET_INTF",
174             socketInterface);
175     }
176 
177     return socketInterface;
178 }
179 
180 int DumpHandler::writeFromMemory(uint32_t, uint32_t length, uint64_t address,
181                                  oem_platform::Handler* /*oemPlatformHandler*/)
182 {
183     if (DumpHandler::fd == -1)
184     {
185         auto socketInterface = getOffloadUri(fileHandle);
186         int sock = setupUnixSocket(socketInterface);
187         if (sock < 0)
188         {
189             sock = -errno;
190             close(DumpHandler::fd);
191             error("DumpHandler::writeFromMemory: setupUnixSocket() failed");
192             std::remove(socketInterface.c_str());
193             return PLDM_ERROR;
194         }
195 
196         DumpHandler::fd = sock;
197     }
198     return transferFileDataToSocket(DumpHandler::fd, length, address);
199 }
200 
201 int DumpHandler::write(const char* buffer, uint32_t, uint32_t& length,
202                        oem_platform::Handler* /*oemPlatformHandler*/)
203 {
204     int rc = writeToUnixSocket(DumpHandler::fd, buffer, length);
205     if (rc < 0)
206     {
207         rc = -errno;
208         close(DumpHandler::fd);
209         auto socketInterface = getOffloadUri(fileHandle);
210         std::remove(socketInterface.c_str());
211         error("DumpHandler::write: writeToUnixSocket() failed");
212         return PLDM_ERROR;
213     }
214 
215     return PLDM_SUCCESS;
216 }
217 
218 int DumpHandler::fileAck(uint8_t fileStatus)
219 {
220     auto path = findDumpObjPath(fileHandle);
221     if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
222     {
223         if (fileStatus != PLDM_SUCCESS)
224         {
225             error("Failue in resource dump file ack");
226             pldm::utils::reportError(
227                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
228 
229             PropertyValue value{
230                 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"};
231             DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress",
232                                     "Status", "string"};
233             try
234             {
235                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
236             }
237             catch (const std::exception& e)
238             {
239                 error(
240                     "fileAck: Error {ERR_EXCEP} found while setting the dump progress status as Failed with objPath={OBJ_PATH} and intf=Common.Progress",
241                     "ERR_EXCEP", e.what(), "OBJ_PATH", path.c_str());
242             }
243         }
244 
245         if (fs::exists(resDumpDirPath))
246         {
247             fs::remove_all(resDumpDirPath);
248         }
249         return PLDM_SUCCESS;
250     }
251 
252     if (!path.empty())
253     {
254         if (fileStatus == PLDM_ERROR_FILE_DISCARDED)
255         {
256             uint32_t val = 0xFFFFFFFF;
257             PropertyValue value = static_cast<uint32_t>(val);
258             auto dumpIntf = resDumpEntry;
259 
260             if (dumpType == PLDM_FILE_TYPE_DUMP)
261             {
262                 dumpIntf = systemDumpEntry;
263             }
264 
265             DBusMapping dbusMapping{path.c_str(), dumpIntf, "SourceDumpId",
266                                     "uint32_t"};
267             try
268             {
269                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
270             }
271             catch (const std::exception& e)
272             {
273                 error(
274                     "fileAck: Failed to make a d-bus call to DUMP manager to reset source dump id of {FILE_PATH}, with ERROR={ERR_EXCEP}",
275                     "FILE_PATH", path.c_str(), "ERR_EXCEP", e.what());
276                 pldm::utils::reportError(
277                     "xyz.openbmc_project.bmc.PLDM.fileAck.SourceDumpIdResetFail");
278                 return PLDM_ERROR;
279             }
280 
281             auto& bus = pldm::utils::DBusHandler::getBus();
282             try
283             {
284                 auto method = bus.new_method_call(
285                     "xyz.openbmc_project.Dump.Manager", path.c_str(),
286                     "xyz.openbmc_project.Object.Delete", "Delete");
287                 bus.call(method, dbusTimeout);
288             }
289             catch (const std::exception& e)
290             {
291                 error(
292                     "fileAck: Failed to make a d-bus method to delete the dump entry {FILE_PATH}, with ERROR={ERR_EXCEP}",
293                     "FILE_PATH", path.c_str(), "ERR_EXCEP", e.what());
294                 pldm::utils::reportError(
295                     "xyz.openbmc_project.bmc.PLDM.fileAck.DumpEntryDeleteFail");
296                 return PLDM_ERROR;
297             }
298             return PLDM_SUCCESS;
299         }
300 
301         if (dumpType == PLDM_FILE_TYPE_DUMP ||
302             dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
303         {
304             PropertyValue value{true};
305             DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"};
306             try
307             {
308                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
309             }
310             catch (const std::exception& e)
311             {
312                 error(
313                     "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}",
314                     "FILE_PATH", path.c_str(), "ERR_EXCEP", e.what());
315             }
316 
317             auto socketInterface = getOffloadUri(fileHandle);
318             std::remove(socketInterface.c_str());
319             if (DumpHandler::fd >= 0)
320             {
321                 close(DumpHandler::fd);
322                 DumpHandler::fd = -1;
323             }
324         }
325         return PLDM_SUCCESS;
326     }
327 
328     return PLDM_ERROR;
329 }
330 
331 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t& length,
332                                 uint64_t address,
333                                 oem_platform::Handler* /*oemPlatformHandler*/)
334 {
335     if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
336     {
337         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
338     }
339     return transferFileData(resDumpDirPath, true, offset, length, address);
340 }
341 
342 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response,
343                       oem_platform::Handler* /*oemPlatformHandler*/)
344 {
345     if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
346     {
347         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
348     }
349     return readFile(resDumpDirPath, offset, length, response);
350 }
351 
352 } // namespace responder
353 } // namespace pldm
354