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 "xyz/openbmc_project/Common/error.hpp"
8 
9 #include <stdint.h>
10 #include <systemd/sd-bus.h>
11 #include <unistd.h>
12 
13 #include <sdbusplus/server.hpp>
14 #include <xyz/openbmc_project/Dump/NewDump/server.hpp>
15 
16 #include <exception>
17 #include <filesystem>
18 #include <iostream>
19 
20 using namespace pldm::utils;
21 
22 namespace pldm
23 {
24 namespace responder
25 {
26 
27 static constexpr auto nbdInterfaceDefault = "/dev/nbd1";
28 static constexpr auto dumpEntry = "xyz.openbmc_project.Dump.Entry";
29 static constexpr auto dumpObjPath = "/xyz/openbmc_project/dump";
30 
31 int DumpHandler::fd = -1;
32 
33 static std::string findDumpObjPath(uint32_t fileHandle)
34 {
35     static constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
36     static constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
37     static constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
38     static constexpr auto systemDumpEntry =
39         "xyz.openbmc_project.Dump.Entry.System";
40     auto& bus = pldm::utils::DBusHandler::getBus();
41 
42     try
43     {
44         std::vector<std::string> paths;
45         auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
46                                           MAPPER_INTERFACE, "GetSubTreePaths");
47         method.append(dumpObjPath);
48         method.append(0);
49         method.append(std::vector<std::string>({systemDumpEntry}));
50         auto reply = bus.call(method);
51         reply.read(paths);
52         for (const auto& path : paths)
53         {
54             auto dumpId = pldm::utils::DBusHandler().getDbusProperty<uint32_t>(
55                 path.c_str(), "SourceDumpId", systemDumpEntry);
56             if (dumpId == fileHandle)
57             {
58                 return path;
59             }
60         }
61     }
62     catch (const std::exception& e)
63     {
64         std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
65                   << e.what() << "\n";
66     }
67 
68     std::cerr << "failed to find dump object for dump id " << fileHandle
69               << "\n";
70     return {};
71 }
72 
73 int DumpHandler::newFileAvailable(uint64_t length)
74 {
75     static constexpr auto dumpInterface = "xyz.openbmc_project.Dump.NewDump";
76     auto& bus = pldm::utils::DBusHandler::getBus();
77 
78     try
79     {
80         auto service =
81             pldm::utils::DBusHandler().getService(dumpObjPath, dumpInterface);
82         using namespace sdbusplus::xyz::openbmc_project::Dump::server;
83         auto method = bus.new_method_call(service.c_str(), dumpObjPath,
84                                           dumpInterface, "Notify");
85         method.append(
86             sdbusplus::xyz::openbmc_project::Dump::server::convertForMessage(
87                 NewDump::DumpType::System),
88             fileHandle, length);
89         bus.call_noreply(method);
90     }
91     catch (const std::exception& e)
92     {
93         std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
94                   << e.what() << "\n";
95         return PLDM_ERROR;
96     }
97 
98     return PLDM_SUCCESS;
99 }
100 
101 static std::string getOffloadUri(uint32_t fileHandle)
102 {
103     auto path = findDumpObjPath(fileHandle);
104     if (path.empty())
105     {
106         return {};
107     }
108 
109     std::string nbdInterface{};
110     try
111     {
112         nbdInterface = pldm::utils::DBusHandler().getDbusProperty<std::string>(
113             path.c_str(), "OffloadUri", dumpEntry);
114     }
115     catch (const std::exception& e)
116     {
117         std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
118                   << e.what() << "\n";
119     }
120 
121     if (nbdInterface == "")
122     {
123         nbdInterface = nbdInterfaceDefault;
124     }
125 
126     return nbdInterface;
127 }
128 
129 int DumpHandler::writeFromMemory(uint32_t offset, uint32_t length,
130                                  uint64_t address)
131 {
132     auto nbdInterface = getOffloadUri(fileHandle);
133     if (nbdInterface.empty())
134     {
135         return PLDM_ERROR;
136     }
137 
138     int flags = O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE;
139     if (DumpHandler::fd == -1)
140     {
141         DumpHandler::fd = open(nbdInterface.c_str(), flags);
142         if (DumpHandler::fd == -1)
143         {
144             std::cerr << "NBD file does not exist at " << nbdInterface
145                       << " ERROR=" << errno << "\n";
146             return PLDM_ERROR;
147         }
148     }
149 
150     return transferFileData(DumpHandler::fd, false, offset, length, address);
151 }
152 
153 int DumpHandler::write(const char* buffer, uint32_t offset, uint32_t& length)
154 {
155     auto nbdInterface = getOffloadUri(fileHandle);
156     if (nbdInterface.empty())
157     {
158         return PLDM_ERROR;
159     }
160 
161     int flags = O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE;
162     if (DumpHandler::fd == -1)
163     {
164         DumpHandler::fd = open(nbdInterface.c_str(), flags);
165         if (DumpHandler::fd == -1)
166         {
167             std::cerr << "NBD file does not exist at " << nbdInterface
168                       << " ERROR=" << errno << "\n";
169             return PLDM_ERROR;
170         }
171     }
172 
173     int rc = lseek(DumpHandler::fd, offset, SEEK_SET);
174     if (rc == -1)
175     {
176         std::cerr << "lseek failed, ERROR=" << errno << ", OFFSET=" << offset
177                   << "\n";
178         return PLDM_ERROR;
179     }
180     rc = ::write(DumpHandler::fd, buffer, length);
181     if (rc == -1)
182     {
183         std::cerr << "file write failed, ERROR=" << errno
184                   << ", LENGTH=" << length << ", OFFSET=" << offset << "\n";
185         return PLDM_ERROR;
186     }
187     length = rc;
188 
189     return PLDM_SUCCESS;
190 }
191 
192 int DumpHandler::fileAck(uint8_t /*fileStatus*/)
193 {
194     if (DumpHandler::fd >= 0)
195     {
196         auto path = findDumpObjPath(fileHandle);
197         if (!path.empty())
198         {
199             PropertyValue value{true};
200             DBusMapping dbusMapping{path, dumpEntry, "Offloaded", "bool"};
201             try
202             {
203                 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
204             }
205             catch (const std::exception& e)
206             {
207                 std::cerr
208                     << "failed to make a d-bus call to DUMP manager, ERROR="
209                     << e.what() << "\n";
210             }
211             close(DumpHandler::fd);
212             DumpHandler::fd = -1;
213             return PLDM_SUCCESS;
214         }
215     }
216 
217     return PLDM_ERROR;
218 }
219 
220 } // namespace responder
221 } // namespace pldm
222