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 "utils.hpp"
8 #include "xyz/openbmc_project/Common/error.hpp"
9 
10 #include <stdint.h>
11 #include <systemd/sd-bus.h>
12 #include <unistd.h>
13 
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 using namespace pldm::responder::utils;
23 using namespace pldm::utils;
24 
25 namespace pldm
26 {
27 namespace responder
28 {
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 MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
47     static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
48     static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
49     auto& bus = pldm::utils::DBusHandler::getBus();
50 
51     // Stores the current resource dump entry path
52     std::string curResDumpEntryPath{};
53 
54     try
55     {
56         std::vector<std::string> paths;
57         auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
58                                           MAPPER_INTERFACE, "GetSubTreePaths");
59         if (dumpType == PLDM_FILE_TYPE_DUMP)
60         {
61             method.append(dumpObjPath);
62             method.append(0);
63             method.append(std::vector<std::string>({systemDumpEntry}));
64         }
65         else if ((dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP) ||
66                  (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS))
67         {
68             method.append(resDumpObjPath);
69             method.append(0);
70             method.append(std::vector<std::string>({resDumpEntry}));
71         }
72 
73         auto reply = bus.call(method);
74         reply.read(paths);
75 
76         for (const auto& path : paths)
77         {
78             uint32_t dumpId = 0;
79             curResDumpEntryPath = path;
80             if (dumpType == PLDM_FILE_TYPE_DUMP)
81             {
82                 dumpId = pldm::utils::DBusHandler().getDbusProperty<uint32_t>(
83                     path.c_str(), "SourceDumpId", systemDumpEntry);
84             }
85             else if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP ||
86                      dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
87             {
88                 dumpId = pldm::utils::DBusHandler().getDbusProperty<uint32_t>(
89                     path.c_str(), "SourceDumpId", resDumpEntry);
90             }
91 
92             if (dumpId == fileHandle)
93             {
94                 curResDumpEntryPath = path;
95                 break;
96             }
97         }
98     }
99     catch (const std::exception& e)
100     {
101         std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
102                   << e.what() << "\n";
103     }
104 
105     return curResDumpEntryPath;
106 }
107 
108 int DumpHandler::newFileAvailable(uint64_t length)
109 {
110     static constexpr auto dumpInterface = "xyz.openbmc_project.Dump.NewDump";
111     auto& bus = pldm::utils::DBusHandler::getBus();
112 
113     auto notifyObjPath = dumpObjPath;
114     if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
115     {
116         // Setting the Notify path for resource dump
117         notifyObjPath = resDumpObjPath;
118 
119         uint32_t sourceDumpId = fileHandle;
120         auto path = findDumpObjPath(fileHandle);
121 
122         pldm::utils::PropertyValue propValue{sourceDumpId};
123 
124         DBusMapping dbusMapping{path, resDumpEntry, "SourceDumpId", "uint32_t"};
125         try
126         {
127             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, propValue);
128         }
129         catch (const std::exception& e)
130         {
131             std::cerr << "failed to make a d-bus call to DUMP manager to set "
132                          "resource dump SourceDumpId, ERROR="
133                       << e.what() << "\n";
134         }
135     }
136 
137     try
138     {
139         auto service =
140             pldm::utils::DBusHandler().getService(notifyObjPath, dumpInterface);
141         using namespace sdbusplus::xyz::openbmc_project::Dump::server;
142         auto method = bus.new_method_call(service.c_str(), notifyObjPath,
143                                           dumpInterface, "Notify");
144         method.append(fileHandle, length);
145         bus.call_noreply(method);
146     }
147     catch (const std::exception& e)
148     {
149         std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
150                   << e.what() << "\n";
151         return PLDM_ERROR;
152     }
153 
154     return PLDM_SUCCESS;
155 }
156 
157 std::string DumpHandler::getOffloadUri(uint32_t fileHandle)
158 {
159     auto path = findDumpObjPath(fileHandle);
160     if (path.empty())
161     {
162         return {};
163     }
164 
165     std::string socketInterface{};
166 
167     try
168     {
169         socketInterface =
170             pldm::utils::DBusHandler().getDbusProperty<std::string>(
171                 path.c_str(), "OffloadUri", dumpEntry);
172     }
173     catch (const std::exception& e)
174     {
175         std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
176                   << e.what() << "\n";
177     }
178 
179     return socketInterface;
180 }
181 
182 int DumpHandler::writeFromMemory(uint32_t, uint32_t length, uint64_t address,
183                                  oem_platform::Handler* /*oemPlatformHandler*/)
184 {
185     if (DumpHandler::fd == -1)
186     {
187         auto socketInterface = getOffloadUri(fileHandle);
188         int sock = setupUnixSocket(socketInterface);
189         if (sock < 0)
190         {
191             sock = -errno;
192             close(DumpHandler::fd);
193             std::cerr
194                 << "DumpHandler::writeFromMemory: setupUnixSocket() failed"
195                 << std::endl;
196             std::remove(socketInterface.c_str());
197             return PLDM_ERROR;
198         }
199 
200         DumpHandler::fd = sock;
201     }
202     return transferFileDataToSocket(DumpHandler::fd, length, address);
203 }
204 
205 int DumpHandler::write(const char* buffer, uint32_t, uint32_t& length,
206                        oem_platform::Handler* /*oemPlatformHandler*/)
207 {
208     int rc = writeToUnixSocket(DumpHandler::fd, buffer, length);
209     if (rc < 0)
210     {
211         rc = -errno;
212         close(DumpHandler::fd);
213         auto socketInterface = getOffloadUri(fileHandle);
214         std::remove(socketInterface.c_str());
215         std::cerr << "DumpHandler::write: writeToUnixSocket() failed"
216                   << std::endl;
217         return PLDM_ERROR;
218     }
219 
220     return PLDM_SUCCESS;
221 }
222 
223 int DumpHandler::fileAck(uint8_t fileStatus)
224 {
225     auto path = findDumpObjPath(fileHandle);
226     if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
227     {
228         if (fileStatus != PLDM_SUCCESS)
229         {
230             std::cerr << "Failue in resource dump file ack" << std::endl;
231             pldm::utils::reportError(
232                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
233 
234             PropertyValue value{
235                 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"};
236             DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress",
237                                     "Status", "string"};
238             try
239             {
240                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
241             }
242             catch (const std::exception& e)
243             {
244                 std::cerr << "failed to make a d-bus call to DUMP "
245                              "manager, ERROR="
246                           << e.what() << "\n";
247             }
248         }
249 
250         if (fs::exists(resDumpDirPath))
251         {
252             fs::remove_all(resDumpDirPath);
253         }
254         return PLDM_SUCCESS;
255     }
256 
257     if (DumpHandler::fd >= 0 && !path.empty())
258     {
259         if (dumpType == PLDM_FILE_TYPE_DUMP ||
260             dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
261         {
262             PropertyValue value{true};
263             DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"};
264             try
265             {
266                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
267             }
268             catch (const std::exception& e)
269             {
270                 std::cerr
271                     << "failed to make a d-bus call to DUMP manager, ERROR="
272                     << e.what() << "\n";
273             }
274 
275             close(DumpHandler::fd);
276             auto socketInterface = getOffloadUri(fileHandle);
277             std::remove(socketInterface.c_str());
278             DumpHandler::fd = -1;
279         }
280         return PLDM_SUCCESS;
281     }
282 
283     return PLDM_ERROR;
284 }
285 
286 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t& length,
287                                 uint64_t address,
288                                 oem_platform::Handler* /*oemPlatformHandler*/)
289 {
290     if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
291     {
292         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
293     }
294     return transferFileData(resDumpDirPath, true, offset, length, address);
295 }
296 
297 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response,
298                       oem_platform::Handler* /*oemPlatformHandler*/)
299 {
300     if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
301     {
302         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
303     }
304     return readFile(resDumpDirPath, offset, length, response);
305 }
306 
307 } // namespace responder
308 } // namespace pldm
309