blob: c590614f303bc161cde47ba3026a5f92158c5efa [file] [log] [blame]
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -05001#include "config.h"
2
3#include "dump_offload.hpp"
4
George Liu858fbb22021-07-01 12:25:44 +08005#include <fmt/core.h>
Ravi Tejaff9c4522020-11-13 05:14:51 -06006#include <sys/socket.h>
7#include <sys/types.h>
8#include <sys/un.h>
9#include <unistd.h>
10
11#include <dump_utils.hpp>
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -050012#include <phosphor-logging/elog-errors.hpp>
13#include <phosphor-logging/elog.hpp>
14#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 {
George Liu858fbb22021-07-01 12:25:44 +080058 log<level::ERR>(
59 fmt::format("writeOnUnixSocket: select() failed, errno({})",
60 errno)
61 .c_str());
Ravi Tejaff9c4522020-11-13 05:14:51 -060062 std::string msg = "select() failed " + std::string(strerror(errno));
63 throw std::runtime_error(msg);
64 }
65 if ((retVal > 0) && (FD_ISSET(socket, &writeFileDescriptor)))
66 {
67 numOfBytesWrote = write(socket, buf + i, blockSize - i);
68 if (numOfBytesWrote < 0)
69 {
70 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
71 {
72 numOfBytesWrote = 0;
73 continue;
74 }
George Liu858fbb22021-07-01 12:25:44 +080075 log<level::ERR>(
76 fmt::format("writeOnUnixSocket: write() failed, errno({})",
77 errno)
78 .c_str());
Patrick Williams78e88402023-05-10 07:50:48 -050079 std::string msg = "write() on socket failed " +
80 std::string(strerror(errno));
Ravi Tejaff9c4522020-11-13 05:14:51 -060081 throw std::runtime_error(msg);
82 }
83 }
84 }
85 return;
86}
87
88/**@brief API to setup unix socket.
89 *
90 * @param[in] sockPath - unix socket path
91 *
92 * @return returns returns socket fd on success
93 * and on error exception will be thrown
94 */
95int socketInit(const std::string& sockPath)
96{
97 int unixSocket;
98 struct sockaddr_un socketAddr;
99 memset(&socketAddr, 0, sizeof(socketAddr));
100 socketAddr.sun_family = AF_UNIX;
101 if (strnlen(sockPath.c_str(), sizeof(socketAddr.sun_path)) ==
102 sizeof(socketAddr.sun_path))
103 {
104 log<level::ERR>("UNIX socket path too long");
Patrick Williams78e88402023-05-10 07:50:48 -0500105 std::string msg = "UNIX socket path is too long " +
106 std::string(strerror(errno));
Ravi Tejaff9c4522020-11-13 05:14:51 -0600107 throw std::length_error(msg);
108 }
109 strncpy(socketAddr.sun_path, sockPath.c_str(),
110 sizeof(socketAddr.sun_path) - 1);
111 if ((unixSocket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
112 {
George Liu858fbb22021-07-01 12:25:44 +0800113 log<level::ERR>(
114 fmt::format("socketInit: socket() failed, errno({})", errno)
115 .c_str());
Ravi Tejaff9c4522020-11-13 05:14:51 -0600116 std::string msg = "socket() failed " + std::string(strerror(errno));
117 throw std::runtime_error(msg);
118 }
119 if (bind(unixSocket, (struct sockaddr*)&socketAddr, sizeof(socketAddr)) ==
120 -1)
121 {
George Liu858fbb22021-07-01 12:25:44 +0800122 log<level::ERR>(
123 fmt::format("socketInit: bind() failed, errno({})", errno).c_str());
Ravi Tejaff9c4522020-11-13 05:14:51 -0600124 close(unixSocket);
125 std::string msg = "socket bind failed " + std::string(strerror(errno));
126 throw std::runtime_error(msg);
127 }
128 if (listen(unixSocket, 1) == -1)
129 {
George Liu858fbb22021-07-01 12:25:44 +0800130 log<level::ERR>(
131 fmt::format("socketInit: listen() failed, errno({})", errno)
132 .c_str());
Ravi Tejaff9c4522020-11-13 05:14:51 -0600133 close(unixSocket);
134 std::string msg = "listen() failed " + std::string(strerror(errno));
135 throw std::runtime_error(msg);
136 }
137 return unixSocket;
138}
139
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500140void requestOffload(std::filesystem::path file, uint32_t dumpId,
141 std::string writePath)
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500142{
143 using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
144 using ErrnoOpen = xyz::openbmc_project::Common::File::Open::ERRNO;
145 using PathOpen = xyz::openbmc_project::Common::File::Open::PATH;
146 using ErrnoWrite = xyz::openbmc_project::Common::File::Write::ERRNO;
147 using PathWrite = xyz::openbmc_project::Common::File::Write::PATH;
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500148
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500149 try
150 {
Ravi Tejaff9c4522020-11-13 05:14:51 -0600151 CustomFd unixSocket = socketInit(writePath);
152
153 fd_set readFD;
154 struct timeval timeVal;
155 timeVal.tv_sec = 1;
156 timeVal.tv_usec = 0;
157
158 FD_ZERO(&readFD);
159 FD_SET(unixSocket(), &readFD);
160 int numOfFDs = unixSocket() + 1;
161
162 int retVal = select(numOfFDs, &readFD, NULL, NULL, &timeVal);
163 if (retVal <= 0)
164 {
George Liu858fbb22021-07-01 12:25:44 +0800165 log<level::ERR>(
166 fmt::format("select() failed, errno({}), DUMP_ID({})", errno,
167 dumpId)
168 .c_str());
Ravi Tejaff9c4522020-11-13 05:14:51 -0600169 std::string msg = "select() failed " + std::string(strerror(errno));
170 throw std::runtime_error(msg);
171 }
172 else if ((retVal > 0) && (FD_ISSET(unixSocket(), &readFD)))
173 {
174 CustomFd socketFD = accept(unixSocket(), NULL, NULL);
175 if (socketFD() < 0)
176 {
George Liu858fbb22021-07-01 12:25:44 +0800177 log<level::ERR>(
178 fmt::format("accept() failed, errno({}), DUMP_ID({})",
179 errno, dumpId)
180 .c_str());
Patrick Williams78e88402023-05-10 07:50:48 -0500181 std::string msg = "accept() failed " +
182 std::string(strerror(errno));
Ravi Tejaff9c4522020-11-13 05:14:51 -0600183 throw std::runtime_error(msg);
184 }
185
Dhruvaraj Subhashchandranee6f1ba2021-05-04 09:44:57 -0500186 std::ifstream infile{file, std::ios::in | std::ios::binary};
Ravi Tejaff9c4522020-11-13 05:14:51 -0600187 if (!infile.good())
188 {
189 // Unable to open the dump file
George Liu858fbb22021-07-01 12:25:44 +0800190 log<level::ERR>(
191 fmt::format("Failed to open the dump from file, errno({}), "
192 "DUMPFILE({}), DUMP_ID({})",
Dhruvaraj Subhashchandranee6f1ba2021-05-04 09:44:57 -0500193 errno, file.c_str(), dumpId)
George Liu858fbb22021-07-01 12:25:44 +0800194 .c_str());
Dhruvaraj Subhashchandranee6f1ba2021-05-04 09:44:57 -0500195 elog<Open>(ErrnoOpen(errno), PathOpen(file.c_str()));
Ravi Tejaff9c4522020-11-13 05:14:51 -0600196 }
197
198 infile.exceptions(std::ifstream::failbit | std::ifstream::badbit |
199 std::ifstream::eofbit);
200
George Liu858fbb22021-07-01 12:25:44 +0800201 log<level::INFO>(fmt::format("Opening File for RW, FILENAME({})",
202 file.filename().c_str())
203 .c_str());
Ravi Tejaff9c4522020-11-13 05:14:51 -0600204
205 std::filebuf* pbuf = infile.rdbuf();
206
207 // get file size using buffer's members
208 std::size_t size = pbuf->pubseekoff(0, infile.end, infile.in);
209 pbuf->pubseekpos(0, infile.in);
210
211 // allocate memory to contain file data
212 std::unique_ptr<char[]> buffer(new char[size]);
213 // get file data
214 pbuf->sgetn(buffer.get(), size);
215 infile.close();
216
217 writeOnUnixSocket(socketFD(), buffer.get(), size);
218 }
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500219 }
Patrick Williams9d2d7222021-10-06 12:44:44 -0500220 catch (const std::ifstream::failure& oe)
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500221 {
Ravi Tejaff9c4522020-11-13 05:14:51 -0600222 std::remove(writePath.c_str());
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500223 auto err = errno;
George Liu858fbb22021-07-01 12:25:44 +0800224 log<level::ERR>(
225 fmt::format(
226 "Failed to open, errormsg({}), OPENINTERFACE({}), DUMP_ID({})",
Dhruvaraj Subhashchandranee6f1ba2021-05-04 09:44:57 -0500227 oe.what(), file.c_str(), dumpId)
George Liu858fbb22021-07-01 12:25:44 +0800228 .c_str());
Dhruvaraj Subhashchandranee6f1ba2021-05-04 09:44:57 -0500229 elog<Open>(ErrnoOpen(err), PathOpen(file.c_str()));
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500230 }
231 catch (const std::exception& e)
232 {
Ravi Tejaff9c4522020-11-13 05:14:51 -0600233 std::remove(writePath.c_str());
234 auto err = errno;
George Liu858fbb22021-07-01 12:25:44 +0800235 log<level::ERR>(fmt::format("Failed to offload dump, errormsg({}), "
236 "DUMPFILE({}), DUMP_ID({})",
237 e.what(), writePath.c_str(), dumpId)
238 .c_str());
Ravi Tejaff9c4522020-11-13 05:14:51 -0600239 elog<Write>(ErrnoWrite(err), PathWrite(writePath.c_str()));
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500240 }
Ravi Tejaff9c4522020-11-13 05:14:51 -0600241 std::remove(writePath.c_str());
242 return;
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500243}
244
245} // namespace offload
246} // namespace dump
247} // namespace phosphor