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 
120     try
121     {
122         auto service =
123             pldm::utils::DBusHandler().getService(notifyObjPath, dumpInterface);
124         using namespace sdbusplus::xyz::openbmc_project::Dump::server;
125         auto method = bus.new_method_call(service.c_str(), notifyObjPath,
126                                           dumpInterface, "Notify");
127         method.append(fileHandle, length);
128         bus.call_noreply(method);
129     }
130     catch (const std::exception& e)
131     {
132         std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
133                   << e.what() << "\n";
134         return PLDM_ERROR;
135     }
136 
137     return PLDM_SUCCESS;
138 }
139 
140 std::string DumpHandler::getOffloadUri(uint32_t fileHandle)
141 {
142     auto path = findDumpObjPath(fileHandle);
143     if (path.empty())
144     {
145         return {};
146     }
147 
148     std::string socketInterface{};
149 
150     try
151     {
152         socketInterface =
153             pldm::utils::DBusHandler().getDbusProperty<std::string>(
154                 path.c_str(), "OffloadUri", dumpEntry);
155     }
156     catch (const std::exception& e)
157     {
158         std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
159                   << e.what() << "\n";
160     }
161 
162     return socketInterface;
163 }
164 
165 int DumpHandler::writeFromMemory(uint32_t, uint32_t length, uint64_t address,
166                                  oem_platform::Handler* /*oemPlatformHandler*/)
167 {
168     if (DumpHandler::fd == -1)
169     {
170         auto socketInterface = getOffloadUri(fileHandle);
171         int sock = setupUnixSocket(socketInterface);
172         if (sock < 0)
173         {
174             sock = -errno;
175             close(DumpHandler::fd);
176             std::cerr
177                 << "DumpHandler::writeFromMemory: setupUnixSocket() failed"
178                 << std::endl;
179             std::remove(socketInterface.c_str());
180             return PLDM_ERROR;
181         }
182 
183         DumpHandler::fd = sock;
184     }
185     return transferFileDataToSocket(DumpHandler::fd, length, address);
186 }
187 
188 int DumpHandler::write(const char* buffer, uint32_t, uint32_t& length,
189                        oem_platform::Handler* /*oemPlatformHandler*/)
190 {
191     int rc = writeToUnixSocket(DumpHandler::fd, buffer, length);
192     if (rc < 0)
193     {
194         rc = -errno;
195         close(DumpHandler::fd);
196         auto socketInterface = getOffloadUri(fileHandle);
197         std::remove(socketInterface.c_str());
198         std::cerr << "DumpHandler::write: writeToUnixSocket() failed"
199                   << std::endl;
200         return PLDM_ERROR;
201     }
202 
203     return PLDM_SUCCESS;
204 }
205 
206 int DumpHandler::fileAck(uint8_t fileStatus)
207 {
208     auto path = findDumpObjPath(fileHandle);
209     if (dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
210     {
211         if (fileStatus != PLDM_SUCCESS)
212         {
213             std::cerr << "Failue in resource dump file ack" << std::endl;
214             pldm::utils::reportError(
215                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
216 
217             PropertyValue value{
218                 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"};
219             DBusMapping dbusMapping{path, "xyz.openbmc_project.Common.Progress",
220                                     "Status", "string"};
221             try
222             {
223                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
224             }
225             catch (const std::exception& e)
226             {
227                 std::cerr << "failed to make a d-bus call to DUMP "
228                              "manager, ERROR="
229                           << e.what() << "\n";
230             }
231         }
232 
233         if (fs::exists(resDumpDirPath))
234         {
235             fs::remove_all(resDumpDirPath);
236         }
237         return PLDM_SUCCESS;
238     }
239 
240     if (DumpHandler::fd >= 0 && !path.empty())
241     {
242         if (dumpType == PLDM_FILE_TYPE_DUMP ||
243             dumpType == PLDM_FILE_TYPE_RESOURCE_DUMP)
244         {
245             PropertyValue value{true};
246             DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"};
247             try
248             {
249                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
250             }
251             catch (const std::exception& e)
252             {
253                 std::cerr
254                     << "failed to make a d-bus call to DUMP manager, ERROR="
255                     << e.what() << "\n";
256             }
257 
258             close(DumpHandler::fd);
259             auto socketInterface = getOffloadUri(fileHandle);
260             std::remove(socketInterface.c_str());
261             DumpHandler::fd = -1;
262         }
263         return PLDM_SUCCESS;
264     }
265 
266     return PLDM_ERROR;
267 }
268 
269 int DumpHandler::readIntoMemory(uint32_t offset, uint32_t& length,
270                                 uint64_t address,
271                                 oem_platform::Handler* /*oemPlatformHandler*/)
272 {
273     if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
274     {
275         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
276     }
277     return transferFileData(resDumpDirPath, true, offset, length, address);
278 }
279 
280 int DumpHandler::read(uint32_t offset, uint32_t& length, Response& response,
281                       oem_platform::Handler* /*oemPlatformHandler*/)
282 {
283     if (dumpType != PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS)
284     {
285         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
286     }
287     return readFile(resDumpDirPath, offset, length, response);
288 }
289 
290 } // namespace responder
291 } // namespace pldm
292