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