1 #include "dbus_to_file_handler.hpp"
2 
3 #include "libpldm/requester/pldm.h"
4 #include "oem/ibm/libpldm/file_io.h"
5 
6 #include "common/utils.hpp"
7 
8 namespace pldm
9 {
10 namespace requester
11 {
12 namespace oem_ibm
13 {
14 
15 using namespace pldm::utils;
16 using namespace sdbusplus::bus::match::rules;
17 
18 static constexpr auto resDumpObjPath =
19     "/xyz/openbmc_project/dump/resource/entry";
20 static constexpr auto resDumpEntry = "com.ibm.Dump.Entry.Resource";
21 static constexpr auto resDumpProgressIntf =
22     "xyz.openbmc_project.Common.Progress";
23 static constexpr auto resDumpStatus =
24     "xyz.openbmc_project.Common.Progress.OperationStatus.Failed";
25 
26 DbusToFileHandler::DbusToFileHandler(
27     int mctp_fd, uint8_t mctp_eid, dbus_api::Requester* requester,
28     sdbusplus::message::object_path resDumpCurrentObjPath) :
29     mctp_fd(mctp_fd),
30     mctp_eid(mctp_eid), requester(requester),
31     resDumpCurrentObjPath(resDumpCurrentObjPath)
32 {}
33 
34 void DbusToFileHandler::sendNewFileAvailableCmd(uint64_t fileSize)
35 {
36     if (requester == NULL)
37     {
38         std::cerr << "Failed to send resource dump parameters as requester is "
39                      "not set";
40         pldm::utils::reportError(
41             "xyz.openbmc_project.bmc.pldm.InternalFailure");
42         return;
43     }
44     auto instanceId = requester->getInstanceId(mctp_eid);
45     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
46                                     PLDM_NEW_FILE_REQ_BYTES + fileSize);
47     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
48     // Need to revisit this logic at the time of multiple resource dump support
49     uint32_t fileHandle = 1;
50 
51     auto rc =
52         encode_new_file_req(instanceId, PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS,
53                             fileHandle, fileSize, request);
54     if (rc != PLDM_SUCCESS)
55     {
56         requester->markFree(mctp_eid, instanceId);
57         std::cerr << "Failed to encode_new_file_req, rc = " << rc << std::endl;
58         return;
59     }
60 
61     uint8_t* responseMsg = nullptr;
62     size_t responseMsgSize{};
63 
64     auto requesterRc =
65         pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
66                        &responseMsg, &responseMsgSize);
67 
68     std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
69                                                                   std::free};
70 
71     requester->markFree(mctp_eid, instanceId);
72     bool isDecodeNewFileRespFailed = false;
73     if (requesterRc != PLDM_REQUESTER_SUCCESS)
74     {
75         std::cerr << "Failed to send resource dump parameters, rc = "
76                   << requesterRc << std::endl;
77     }
78     else
79     {
80         uint8_t completionCode{};
81         auto responsePtr =
82             reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
83 
84         rc = decode_new_file_resp(responsePtr, PLDM_NEW_FILE_RESP_BYTES,
85                                   &completionCode);
86 
87         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
88         {
89             std::cerr << "Failed to decode_new_file_resp: "
90                       << "rc=" << rc
91                       << ", cc=" << static_cast<unsigned>(completionCode)
92                       << std::endl;
93             isDecodeNewFileRespFailed = true;
94         }
95     }
96 
97     if ((requesterRc != PLDM_REQUESTER_SUCCESS) || (isDecodeNewFileRespFailed))
98     {
99         pldm::utils::reportError(
100             "xyz.openbmc_project.bmc.pldm.InternalFailure");
101 
102         PropertyValue value{resDumpStatus};
103         DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
104                                 "Status", "string"};
105         try
106         {
107             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
108         }
109         catch (const std::exception& e)
110         {
111             std::cerr << "failed to set resource dump operation status, "
112                          "ERROR="
113                       << e.what() << "\n";
114         }
115     }
116 }
117 
118 void DbusToFileHandler::processNewResourceDump(
119     const std::string& vspString, const std::string& resDumpReqPass)
120 {
121     // This needs special handling in later point of time. Resource dump without
122     // the vsp string is supposed to be a non-disruptive system dump.
123     if (vspString.empty())
124     {
125         std::cerr << "Empty vsp string"
126                   << "\n";
127         PropertyValue value{resDumpStatus};
128         DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
129                                 "Status", "string"};
130         try
131         {
132             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
133         }
134         catch (const std::exception& e)
135         {
136             std::cerr << "failed to set resource dump operation status, "
137                          "ERROR="
138                       << e.what() << "\n";
139         }
140         return;
141     }
142 
143     namespace fs = std::filesystem;
144     const fs::path resDumpDirPath = "/var/lib/pldm/resourcedump";
145 
146     if (!fs::exists(resDumpDirPath))
147     {
148         fs::create_directories(resDumpDirPath);
149     }
150 
151     // Need to reconsider this logic to set the value as "1" when we have the
152     // support to handle multiple resource dumps
153     fs::path resDumpFilePath = resDumpDirPath / "1";
154 
155     std::ofstream fileHandle;
156     fileHandle.open(resDumpFilePath, std::ios::out | std::ofstream::binary);
157 
158     if (!fileHandle)
159     {
160         std::cerr << "resource dump file open error: " << resDumpFilePath
161                   << "\n";
162         PropertyValue value{resDumpStatus};
163         DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
164                                 "Status", "string"};
165         try
166         {
167             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
168         }
169         catch (const std::exception& e)
170         {
171             std::cerr << "failed to set resource dump operation status, "
172                          "ERROR="
173                       << e.what() << "\n";
174         }
175         return;
176     }
177 
178     // Fill up the file with resource dump parameters and respective sizes
179     auto fileFunc = [&fileHandle](auto& paramBuf) {
180         uint32_t paramSize = paramBuf.size();
181         fileHandle.write((char*)&paramSize, sizeof(paramSize));
182         fileHandle << paramBuf;
183     };
184     fileFunc(vspString);
185     fileFunc(resDumpReqPass);
186 
187     fileHandle.close();
188     size_t fileSize = fs::file_size(resDumpFilePath);
189 
190     sendNewFileAvailableCmd(fileSize);
191 }
192 
193 } // namespace oem_ibm
194 } // namespace requester
195 } // namespace pldm
196