blob: bb647e5b2b91713363dd4020c760e10018cd6d4e [file] [log] [blame]
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -05001#include "config.h"
2
3#include "dump_offload.hpp"
4
Ravi Tejaff9c4522020-11-13 05:14:51 -06005#include <sys/socket.h>
6#include <sys/types.h>
7#include <sys/un.h>
8#include <unistd.h>
9
10#include <dump_utils.hpp>
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -050011#include <phosphor-logging/elog-errors.hpp>
12#include <phosphor-logging/elog.hpp>
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050013#include <phosphor-logging/lg2.hpp>
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -050014#include <xyz/openbmc_project/Common/File/error.hpp>
15#include <xyz/openbmc_project/Common/error.hpp>
16
Jayanth Othayoth0af74a52021-04-08 03:55:21 -050017#include <fstream>
18
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -050019namespace phosphor
20{
21namespace dump
22{
23namespace offload
24{
25
26using namespace sdbusplus::xyz::openbmc_project::Common::Error;
27using namespace phosphor::logging;
28
Ravi Tejaff9c4522020-11-13 05:14:51 -060029/** @brief API to write data on unix socket.
30 *
31 * @param[in] socket - unix socket
32 * @param[in] buf - buffer
33 * @param[in] blockSize - size of data
34 *
35 * @return void
36 */
37void writeOnUnixSocket(const int socket, const char* buf,
38 const uint64_t blockSize)
39{
40 int numOfBytesWrote = 0;
41
42 for (uint64_t i = 0; i < blockSize; i = i + numOfBytesWrote)
43 {
44 numOfBytesWrote = 0;
45 fd_set writeFileDescriptor;
46 struct timeval timeVal;
47 timeVal.tv_sec = 5;
48 timeVal.tv_usec = 0;
49
50 FD_ZERO(&writeFileDescriptor);
51 FD_SET(socket, &writeFileDescriptor);
52 int nextFileDescriptor = socket + 1;
53
54 int retVal = select(nextFileDescriptor, NULL, &writeFileDescriptor,
55 NULL, &timeVal);
56 if (retVal <= 0)
57 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050058 lg2::error("writeOnUnixSocket: select() failed, errno: {ERRNO}",
59 "ERRNO", errno);
Ravi Tejaff9c4522020-11-13 05:14:51 -060060 std::string msg = "select() failed " + std::string(strerror(errno));
61 throw std::runtime_error(msg);
62 }
63 if ((retVal > 0) && (FD_ISSET(socket, &writeFileDescriptor)))
64 {
65 numOfBytesWrote = write(socket, buf + i, blockSize - i);
66 if (numOfBytesWrote < 0)
67 {
68 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
69 {
70 numOfBytesWrote = 0;
71 continue;
72 }
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -050073 lg2::error("writeOnUnixSocket: write() failed, errno: {ERRNO}",
74 "ERRNO", errno);
Patrick Williams78e88402023-05-10 07:50:48 -050075 std::string msg = "write() on socket failed " +
76 std::string(strerror(errno));
Ravi Tejaff9c4522020-11-13 05:14:51 -060077 throw std::runtime_error(msg);
78 }
79 }
80 }
81 return;
82}
83
84/**@brief API to setup unix socket.
85 *
86 * @param[in] sockPath - unix socket path
87 *
88 * @return returns returns socket fd on success
89 * and on error exception will be thrown
90 */
91int socketInit(const std::string& sockPath)
92{
93 int unixSocket;
94 struct sockaddr_un socketAddr;
95 memset(&socketAddr, 0, sizeof(socketAddr));
96 socketAddr.sun_family = AF_UNIX;
97 if (strnlen(sockPath.c_str(), sizeof(socketAddr.sun_path)) ==
98 sizeof(socketAddr.sun_path))
99 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500100 lg2::error("UNIX socket path too long");
Patrick Williams78e88402023-05-10 07:50:48 -0500101 std::string msg = "UNIX socket path is too long " +
102 std::string(strerror(errno));
Ravi Tejaff9c4522020-11-13 05:14:51 -0600103 throw std::length_error(msg);
104 }
105 strncpy(socketAddr.sun_path, sockPath.c_str(),
106 sizeof(socketAddr.sun_path) - 1);
107 if ((unixSocket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
108 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500109 lg2::error("socketInit: socket() failed, errno: {ERRNO}", "ERRNO",
110 errno);
Ravi Tejaff9c4522020-11-13 05:14:51 -0600111 std::string msg = "socket() failed " + std::string(strerror(errno));
112 throw std::runtime_error(msg);
113 }
114 if (bind(unixSocket, (struct sockaddr*)&socketAddr, sizeof(socketAddr)) ==
115 -1)
116 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500117 lg2::error("socketInit: bind() failed, errno: {ERRNO}", "ERRNO", errno);
Ravi Tejaff9c4522020-11-13 05:14:51 -0600118 close(unixSocket);
119 std::string msg = "socket bind failed " + std::string(strerror(errno));
120 throw std::runtime_error(msg);
121 }
122 if (listen(unixSocket, 1) == -1)
123 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500124 lg2::error("socketInit: listen() failed, errno: {ERRNO}", "ERRNO",
125 errno);
Ravi Tejaff9c4522020-11-13 05:14:51 -0600126 close(unixSocket);
127 std::string msg = "listen() failed " + std::string(strerror(errno));
128 throw std::runtime_error(msg);
129 }
130 return unixSocket;
131}
132
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500133void requestOffload(std::filesystem::path file, uint32_t dumpId,
134 std::string writePath)
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500135{
136 using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
137 using ErrnoOpen = xyz::openbmc_project::Common::File::Open::ERRNO;
138 using PathOpen = xyz::openbmc_project::Common::File::Open::PATH;
139 using ErrnoWrite = xyz::openbmc_project::Common::File::Write::ERRNO;
140 using PathWrite = xyz::openbmc_project::Common::File::Write::PATH;
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500141
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500142 try
143 {
Ravi Tejaff9c4522020-11-13 05:14:51 -0600144 CustomFd unixSocket = socketInit(writePath);
145
146 fd_set readFD;
147 struct timeval timeVal;
148 timeVal.tv_sec = 1;
149 timeVal.tv_usec = 0;
150
151 FD_ZERO(&readFD);
152 FD_SET(unixSocket(), &readFD);
153 int numOfFDs = unixSocket() + 1;
154
155 int retVal = select(numOfFDs, &readFD, NULL, NULL, &timeVal);
156 if (retVal <= 0)
157 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500158 lg2::error("select() failed, errno: {ERRNO}, DUMP_ID: {DUMP_ID}",
159 "ERRNO", errno, "DUMP_ID", dumpId);
Ravi Tejaff9c4522020-11-13 05:14:51 -0600160 std::string msg = "select() failed " + std::string(strerror(errno));
161 throw std::runtime_error(msg);
162 }
163 else if ((retVal > 0) && (FD_ISSET(unixSocket(), &readFD)))
164 {
165 CustomFd socketFD = accept(unixSocket(), NULL, NULL);
166 if (socketFD() < 0)
167 {
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500168 lg2::error(
169 "accept() failed, errno: {ERRNO}, DUMP_ID: {DUMP_ID}",
170 "ERRNO", errno, "DUMP_ID", dumpId);
Patrick Williams78e88402023-05-10 07:50:48 -0500171 std::string msg = "accept() failed " +
172 std::string(strerror(errno));
Ravi Tejaff9c4522020-11-13 05:14:51 -0600173 throw std::runtime_error(msg);
174 }
175
Dhruvaraj Subhashchandranee6f1ba2021-05-04 09:44:57 -0500176 std::ifstream infile{file, std::ios::in | std::ios::binary};
Ravi Tejaff9c4522020-11-13 05:14:51 -0600177 if (!infile.good())
178 {
179 // Unable to open the dump file
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500180 lg2::error("Failed to open the dump from file, errno: {ERRNO}, "
181 "DUMPFILE: {DUMP_FILE}, DUMP_ID: {DUMP_ID}",
182 "ERRNO", errno, "DUMP_FILE", file, "DUMP_ID",
183 dumpId);
Dhruvaraj Subhashchandranee6f1ba2021-05-04 09:44:57 -0500184 elog<Open>(ErrnoOpen(errno), PathOpen(file.c_str()));
Ravi Tejaff9c4522020-11-13 05:14:51 -0600185 }
186
187 infile.exceptions(std::ifstream::failbit | std::ifstream::badbit |
188 std::ifstream::eofbit);
189
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500190 lg2::info("Opening File for RW, FILENAME: {FILENAME}", "FILENAME",
191 file.filename().c_str());
Ravi Tejaff9c4522020-11-13 05:14:51 -0600192
193 std::filebuf* pbuf = infile.rdbuf();
194
195 // get file size using buffer's members
196 std::size_t size = pbuf->pubseekoff(0, infile.end, infile.in);
197 pbuf->pubseekpos(0, infile.in);
198
199 // allocate memory to contain file data
200 std::unique_ptr<char[]> buffer(new char[size]);
201 // get file data
202 pbuf->sgetn(buffer.get(), size);
203 infile.close();
204
205 writeOnUnixSocket(socketFD(), buffer.get(), size);
206 }
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500207 }
Patrick Williams9d2d7222021-10-06 12:44:44 -0500208 catch (const std::ifstream::failure& oe)
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500209 {
Ravi Tejaff9c4522020-11-13 05:14:51 -0600210 std::remove(writePath.c_str());
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500211 auto err = errno;
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500212 lg2::error("Failed to open, errormsg: {ERROR}, "
213 "OPENINTERFACE: {OPEN_INTERFACE}, DUMP_ID: {DUMP_ID}",
214 "ERROR", oe, "OPEN_INTERFACE", file, "DUMP_ID", dumpId);
Dhruvaraj Subhashchandranee6f1ba2021-05-04 09:44:57 -0500215 elog<Open>(ErrnoOpen(err), PathOpen(file.c_str()));
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500216 }
217 catch (const std::exception& e)
218 {
Ravi Tejaff9c4522020-11-13 05:14:51 -0600219 std::remove(writePath.c_str());
220 auto err = errno;
Dhruvaraj Subhashchandrand1f670f2023-06-05 22:19:25 -0500221 lg2::error("Failed to offload dump, errormsg: {ERROR}, "
222 "DUMPFILE: {DUMP_FILE}, DUMP_ID: {DUMP_ID}",
223 "ERROR", e, "DUMP_FILE", writePath, "DUMP_ID", dumpId);
Ravi Tejaff9c4522020-11-13 05:14:51 -0600224 elog<Write>(ErrnoWrite(err), PathWrite(writePath.c_str()));
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500225 }
Ravi Tejaff9c4522020-11-13 05:14:51 -0600226 std::remove(writePath.c_str());
227 return;
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500228}
229
230} // namespace offload
231} // namespace dump
232} // namespace phosphor