xref: /openbmc/pldm/oem/ibm/libpldmresponder/file_io_type_dump.cpp (revision dde014625c1aac2b423cc7dbcf3a189ff58dc233)
1 #include "file_io_type_dump.hpp"
2 
3 #include "com/ibm/Dump/Notify/server.hpp"
4 #include "common/utils.hpp"
5 #include "utils.hpp"
6 #include "xyz/openbmc_project/Common/error.hpp"
7 
8 #include <libpldm/base.h>
9 #include <libpldm/oem/ibm/file_io.h>
10 #include <systemd/sd-bus.h>
11 #include <unistd.h>
12 
13 #include <com/ibm/Dump/Notify/server.hpp>
14 #include <phosphor-logging/lg2.hpp>
15 #include <sdbusplus/server.hpp>
16 
17 #include <cstdint>
18 #include <exception>
19 #include <filesystem>
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 
findDumpObjPath(uint32_t fileHandle)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 
51     // Stores the current resource dump entry path
52     std::string curResDumpEntryPath{};
53 
54     ObjectValueTree objects;
55     // Select the dump entry interface for system dump or resource dump
56     DumpEntryInterface dumpEntryIntf = systemDumpEntry;
57     if ((dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) ||
58         (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS))
59     {
60         dumpEntryIntf = resDumpEntry;
61     }
62 
63     try
64     {
65         objects = pldm::utils::DBusHandler::getManagedObj(DUMP_MANAGER_BUSNAME,
66                                                           DUMP_MANAGER_PATH);
67     }
68     catch (const sdbusplus::exception_t& e)
69     {
70         error(
71             "Failed to retrieve dump object using GetManagedObjects call for path '{PATH}' and interface '{INTERFACE}', error - {ERROR}",
72             "PATH", DUMP_MANAGER_PATH, "INTERFACE", dumpEntryIntf, "ERROR", e);
73         return curResDumpEntryPath;
74     }
75 
76     for (const auto& object : objects)
77     {
78         for (const auto& interface : object.second)
79         {
80             if (interface.first != dumpEntryIntf)
81             {
82                 continue;
83             }
84 
85             for (auto& propertyMap : interface.second)
86             {
87                 if (propertyMap.first == "SourceDumpId")
88                 {
89                     auto dumpIdPtr = std::get_if<uint32_t>(&propertyMap.second);
90                     if (dumpIdPtr != nullptr)
91                     {
92                         auto dumpId = *dumpIdPtr;
93                         if (fileHandle == dumpId)
94                         {
95                             curResDumpEntryPath = object.first.str;
96                             return curResDumpEntryPath;
97                         }
98                     }
99                     else
100                     {
101                         error(
102                             "Invalid SourceDumpId in curResDumpEntryPath '{PATH}' but continuing with next entry for a match...",
103                             "PATH", object.first.str);
104                     }
105                 }
106             }
107         }
108     }
109     return curResDumpEntryPath;
110 }
111 
newFileAvailable(uint64_t length)112 int DumpHandler::newFileAvailable(uint64_t length)
113 {
114     static constexpr auto dumpInterface = "com.ibm.Dump.Notify";
115     auto& bus = pldm::utils::DBusHandler::getBus();
116 
117     auto notifyObjPath = dumpObjPath;
118     auto notifyDumpType =
119         sdbusplus::common::com::ibm::dump::Notify::DumpType::System;
120 
121     if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
122     {
123         // Setting the Notify path for resource dump
124         notifyObjPath = resDumpObjPath;
125         notifyDumpType =
126             sdbusplus::common::com::ibm::dump::Notify::DumpType::Resource;
127     }
128 
129     try
130     {
131         auto service =
132             pldm::utils::DBusHandler().getService(notifyObjPath, dumpInterface);
133         auto method = bus.new_method_call(service.c_str(), notifyObjPath,
134                                           dumpInterface, "NotifyDump");
135         method.append(fileHandle, length, notifyDumpType, 0);
136         bus.call_noreply(method, dbusTimeout);
137     }
138     catch (const std::exception& e)
139     {
140         error(
141             "Error '{ERROR}' found for new file available while notifying new dump to dump manager with object path {PATH} and interface {INTERFACE}",
142             "ERROR", e, "PATH", notifyObjPath, "INTERFACE", dumpInterface);
143         return PLDM_ERROR;
144     }
145 
146     return PLDM_SUCCESS;
147 }
148 
getOffloadUri(uint32_t fileHandle)149 std::string DumpHandler::getOffloadUri(uint32_t fileHandle)
150 {
151     auto path = findDumpObjPath(fileHandle);
152     if (path.empty())
153     {
154         return {};
155     }
156 
157     std::string socketInterface{};
158 
159     try
160     {
161         socketInterface =
162             pldm::utils::DBusHandler().getDbusProperty<std::string>(
163                 path.c_str(), "OffloadUri", dumpEntry);
164     }
165     catch (const std::exception& e)
166     {
167         error(
168             "Error '{ERROR}' found while fetching the dump offload URI with object path '{PATH}' and interface '{INTERFACE}'",
169             "ERROR", e, "PATH", path, "INTERFACE", socketInterface);
170     }
171 
172     return socketInterface;
173 }
174 
writeFromMemory(uint32_t,uint32_t length,uint64_t address,oem_platform::Handler *)175 int DumpHandler::writeFromMemory(uint32_t, uint32_t length, uint64_t address,
176                                  oem_platform::Handler* /*oemPlatformHandler*/)
177 {
178     if (DumpHandler::fd == -1)
179     {
180         auto socketInterface = getOffloadUri(fileHandle);
181         int sock = setupUnixSocket(socketInterface);
182         if (sock < 0)
183         {
184             sock = -errno;
185             close(DumpHandler::fd);
186             error(
187                 "Failed to setup Unix socket while write from memory for interface '{INTERFACE}', response code '{SOCKET_RC}'",
188                 "INTERFACE", socketInterface, "SOCKET_RC", sock);
189             std::remove(socketInterface.c_str());
190             return PLDM_ERROR;
191         }
192 
193         DumpHandler::fd = sock;
194     }
195     return transferFileDataToSocket(DumpHandler::fd, length, address);
196 }
197 
write(const char * buffer,uint32_t,uint32_t & length,oem_platform::Handler *)198 int DumpHandler::write(const char* buffer, uint32_t, uint32_t& length,
199                        oem_platform::Handler* /*oemPlatformHandler*/)
200 {
201     int rc = writeToUnixSocket(DumpHandler::fd, buffer, length);
202     if (rc < 0)
203     {
204         rc = -errno;
205         close(DumpHandler::fd);
206         auto socketInterface = getOffloadUri(fileHandle);
207         std::remove(socketInterface.c_str());
208         error(
209             "Failed to do dump write to Unix socket for interface '{INTERFACE}', response code '{RC}'",
210             "INTERFACE", socketInterface, "RC", rc);
211         return PLDM_ERROR;
212     }
213 
214     return PLDM_SUCCESS;
215 }
216 
fileAck(uint8_t fileStatus)217 int DumpHandler::fileAck(uint8_t fileStatus)
218 {
219     auto path = findDumpObjPath(fileHandle);
220     if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
221     {
222         if (fileStatus != PLDM_SUCCESS)
223         {
224             error("Failure in resource dump file ack");
225             pldm::utils::reportError(
226                 "xyz.openbmc_project.PLDM.Error.fileAck.ResourceDumpFileAckFail");
227 
228             PropertyValue value{
229                 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"};
230             DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress",
231                                     "Status", "string"};
232             try
233             {
234                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
235             }
236             catch (const std::exception& e)
237             {
238                 error(
239                     "Error '{ERROR}' found for file ack while setting the dump progress status as 'Failed' with object path '{PATH}' and interface 'xyz.openbmc_project.Common.Progress'",
240                     "ERROR", e, "PATH", path);
241             }
242         }
243 
244         if (fs::exists(resDumpDirPath))
245         {
246             fs::remove_all(resDumpDirPath);
247         }
248         return PLDM_SUCCESS;
249     }
250 
251     if (!path.empty())
252     {
253         if (fileStatus == PLDM_ERROR_FILE_DISCARDED)
254         {
255             uint32_t val = 0xFFFFFFFF;
256             PropertyValue value = static_cast<uint32_t>(val);
257             auto dumpIntf = resDumpEntry;
258 
259             if (dumpType == PLDM_FILE_TYPE_DUMP)
260             {
261                 dumpIntf = systemDumpEntry;
262             }
263 
264             DBusMapping dbusMapping{path.c_str(), dumpIntf, "SourceDumpId",
265                                     "uint32_t"};
266             try
267             {
268                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
269             }
270             catch (const std::exception& e)
271             {
272                 error(
273                     "Failed to make a D-bus call to DUMP manager for resetting source dump file '{PATH}' on interface '{INTERFACE}', error - {ERROR}",
274                     "PATH", path, "INTERFACE", dumpIntf, "ERROR", e);
275                 pldm::utils::reportError(
276                     "xyz.openbmc_project.bmc.PLDM.fileAck.SourceDumpIdResetFail");
277                 return PLDM_ERROR;
278             }
279 
280             auto& bus = pldm::utils::DBusHandler::getBus();
281             try
282             {
283                 auto method = bus.new_method_call(
284                     "xyz.openbmc_project.Dump.Manager", path.c_str(),
285                     "xyz.openbmc_project.Object.Delete", "Delete");
286                 bus.call(method, dbusTimeout);
287             }
288             catch (const std::exception& e)
289             {
290                 error(
291                     "Failed to make a D-bus call to DUMP manager for delete dump file '{PATH}', error - {ERROR}",
292                     "PATH", path, "ERROR", e);
293                 pldm::utils::reportError(
294                     "xyz.openbmc_project.bmc.PLDM.fileAck.DumpEntryDeleteFail");
295                 return PLDM_ERROR;
296             }
297             return PLDM_SUCCESS;
298         }
299 
300         if (dumpType == PLDM_FILE_TYPE_DUMP ||
301             dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
302         {
303             PropertyValue value{true};
304             DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"};
305             try
306             {
307                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
308             }
309             catch (const std::exception& e)
310             {
311                 error(
312                     "Failed to make a D-bus call to DUMP manager to set the dump offloaded property 'true' for dump file '{PATH}', error - {ERROR}",
313                     "PATH", path, "ERROR", e);
314             }
315 
316             auto socketInterface = getOffloadUri(fileHandle);
317             std::remove(socketInterface.c_str());
318             if (DumpHandler::fd >= 0)
319             {
320                 close(DumpHandler::fd);
321                 DumpHandler::fd = -1;
322             }
323         }
324         return PLDM_SUCCESS;
325     }
326 
327     return PLDM_ERROR;
328 }
329 
readIntoMemory(uint32_t offset,uint32_t length,uint64_t address,oem_platform::Handler *)330 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t length,
331                                 uint64_t address,
332                                 oem_platform::Handler* /*oemPlatformHandler*/)
333 {
334     if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
335     {
336         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
337     }
338     return transferFileData(resDumpDirPath, true, offset, length, address);
339 }
340 
read(uint32_t offset,uint32_t & length,Response & response,oem_platform::Handler *)341 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response,
342                       oem_platform::Handler* /*oemPlatformHandler*/)
343 {
344     if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
345     {
346         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
347     }
348     return readFile(resDumpDirPath, offset, length, response);
349 }
350 
newFileAvailableWithMetaData(uint64_t length,uint32_t metaDataValue1,uint32_t,uint32_t,uint32_t)351 int DumpHandler::newFileAvailableWithMetaData(
352     uint64_t length, uint32_t metaDataValue1, uint32_t /*metaDataValue2*/,
353     uint32_t /*metaDataValue3*/, uint32_t /*metaDataValue4*/)
354 {
355     static constexpr auto dumpInterface = "com.ibm.Dump.Notify";
356     auto& bus = pldm::utils::DBusHandler::getBus();
357 
358     auto notifyObjPath = dumpObjPath;
359     auto notifyDumpType =
360         sdbusplus::common::com::ibm::dump::Notify::DumpType::System;
361     if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
362     {
363         notifyDumpType =
364             sdbusplus::common::com::ibm::dump::Notify::DumpType::Resource;
365     }
366 
367     try
368     {
369         auto service =
370             pldm::utils::DBusHandler().getService(notifyObjPath, dumpInterface);
371         auto method = bus.new_method_call(service.c_str(), notifyObjPath,
372                                           dumpInterface, "NotifyDump");
373         method.append(fileHandle, length, notifyDumpType, metaDataValue1);
374         bus.call(method, dbusTimeout);
375     }
376     catch (const sdbusplus::exception_t& e)
377     {
378         error(
379             "failed to make a d-bus call to notify a new dump request using newFileAvailableWithMetaData, error - {ERROR}",
380             "ERROR", e);
381         pldm::utils::reportError(
382             "xyz.openbmc_project.PLDM.Error.newFileAvailableWithMetaData.NewDumpNotifyFail");
383         return PLDM_ERROR;
384     }
385 
386     return PLDM_SUCCESS;
387 }
388 
389 } // namespace responder
390 } // namespace pldm
391