blob: 374a65700dca3b1c47c2dfe16db3a8f54aad3e00 [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>
13#include <xyz/openbmc_project/Common/File/error.hpp>
14#include <xyz/openbmc_project/Common/error.hpp>
15
Jayanth Othayoth0af74a52021-04-08 03:55:21 -050016#include <fstream>
17
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -050018namespace phosphor
19{
20namespace dump
21{
22namespace offload
23{
24
25using namespace sdbusplus::xyz::openbmc_project::Common::Error;
26using namespace phosphor::logging;
27
Ravi Tejaff9c4522020-11-13 05:14:51 -060028/** @brief API to write data on unix socket.
29 *
30 * @param[in] socket - unix socket
31 * @param[in] buf - buffer
32 * @param[in] blockSize - size of data
33 *
34 * @return void
35 */
36void writeOnUnixSocket(const int socket, const char* buf,
37 const uint64_t blockSize)
38{
39 int numOfBytesWrote = 0;
40
41 for (uint64_t i = 0; i < blockSize; i = i + numOfBytesWrote)
42 {
43 numOfBytesWrote = 0;
44 fd_set writeFileDescriptor;
45 struct timeval timeVal;
46 timeVal.tv_sec = 5;
47 timeVal.tv_usec = 0;
48
49 FD_ZERO(&writeFileDescriptor);
50 FD_SET(socket, &writeFileDescriptor);
51 int nextFileDescriptor = socket + 1;
52
53 int retVal = select(nextFileDescriptor, NULL, &writeFileDescriptor,
54 NULL, &timeVal);
55 if (retVal <= 0)
56 {
57 log<level::ERR>("writeOnUnixSocket: select() failed",
58 entry("ERRNO=%d", errno));
59 std::string msg = "select() failed " + std::string(strerror(errno));
60 throw std::runtime_error(msg);
61 }
62 if ((retVal > 0) && (FD_ISSET(socket, &writeFileDescriptor)))
63 {
64 numOfBytesWrote = write(socket, buf + i, blockSize - i);
65 if (numOfBytesWrote < 0)
66 {
67 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
68 {
69 numOfBytesWrote = 0;
70 continue;
71 }
72 log<level::ERR>("writeOnUnixSocket: write() failed",
73 entry("ERRNO=%d", errno));
74 std::string msg =
75 "write() on socket failed " + std::string(strerror(errno));
76 throw std::runtime_error(msg);
77 }
78 }
79 }
80 return;
81}
82
83/**@brief API to setup unix socket.
84 *
85 * @param[in] sockPath - unix socket path
86 *
87 * @return returns returns socket fd on success
88 * and on error exception will be thrown
89 */
90int socketInit(const std::string& sockPath)
91{
92 int unixSocket;
93 struct sockaddr_un socketAddr;
94 memset(&socketAddr, 0, sizeof(socketAddr));
95 socketAddr.sun_family = AF_UNIX;
96 if (strnlen(sockPath.c_str(), sizeof(socketAddr.sun_path)) ==
97 sizeof(socketAddr.sun_path))
98 {
99 log<level::ERR>("UNIX socket path too long");
100 std::string msg =
101 "UNIX socket path is too long " + std::string(strerror(errno));
102 throw std::length_error(msg);
103 }
104 strncpy(socketAddr.sun_path, sockPath.c_str(),
105 sizeof(socketAddr.sun_path) - 1);
106 if ((unixSocket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
107 {
108 log<level::ERR>("socketInit: socket() failed",
109 entry("ERRNO=%d", errno));
110 std::string msg = "socket() failed " + std::string(strerror(errno));
111 throw std::runtime_error(msg);
112 }
113 if (bind(unixSocket, (struct sockaddr*)&socketAddr, sizeof(socketAddr)) ==
114 -1)
115 {
116 log<level::ERR>("socketInit: bind() failed", entry("ERRNO=%d", errno));
117 close(unixSocket);
118 std::string msg = "socket bind failed " + std::string(strerror(errno));
119 throw std::runtime_error(msg);
120 }
121 if (listen(unixSocket, 1) == -1)
122 {
123 log<level::ERR>("socketInit: listen() failed",
124 entry("ERRNO=%d", errno));
125 close(unixSocket);
126 std::string msg = "listen() failed " + std::string(strerror(errno));
127 throw std::runtime_error(msg);
128 }
129 return unixSocket;
130}
131
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500132void requestOffload(std::filesystem::path file, uint32_t dumpId,
133 std::string writePath)
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500134{
135 using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
136 using ErrnoOpen = xyz::openbmc_project::Common::File::Open::ERRNO;
137 using PathOpen = xyz::openbmc_project::Common::File::Open::PATH;
138 using ErrnoWrite = xyz::openbmc_project::Common::File::Write::ERRNO;
139 using PathWrite = xyz::openbmc_project::Common::File::Write::PATH;
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500140 // open a dump file for a transfer.
Jayanth Othayoth3fc6df42021-04-08 03:45:24 -0500141 std::filesystem::path dumpPath(BMC_DUMP_PATH);
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500142 dumpPath /= std::to_string(dumpId);
143 dumpPath /= file.filename();
144
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500145 try
146 {
Ravi Tejaff9c4522020-11-13 05:14:51 -0600147
148 CustomFd unixSocket = socketInit(writePath);
149
150 fd_set readFD;
151 struct timeval timeVal;
152 timeVal.tv_sec = 1;
153 timeVal.tv_usec = 0;
154
155 FD_ZERO(&readFD);
156 FD_SET(unixSocket(), &readFD);
157 int numOfFDs = unixSocket() + 1;
158
159 int retVal = select(numOfFDs, &readFD, NULL, NULL, &timeVal);
160 if (retVal <= 0)
161 {
162 log<level::ERR>("select() failed", entry("ERRNO=%d", errno),
163 entry("DUMP ID=%d", dumpId));
164 std::string msg = "select() failed " + std::string(strerror(errno));
165 throw std::runtime_error(msg);
166 }
167 else if ((retVal > 0) && (FD_ISSET(unixSocket(), &readFD)))
168 {
169 CustomFd socketFD = accept(unixSocket(), NULL, NULL);
170 if (socketFD() < 0)
171 {
172 log<level::ERR>("accept() failed", entry("ERRNO=%d", errno),
173 entry("DUMP ID=%d", dumpId));
174 std::string msg =
175 "accept() failed " + std::string(strerror(errno));
176 throw std::runtime_error(msg);
177 }
178
179 std::ifstream infile{dumpPath, std::ios::in | std::ios::binary};
180 if (!infile.good())
181 {
182 // Unable to open the dump file
183 log<level::ERR>("Failed to open the dump from file ",
184 entry("ERR=%d", errno),
185 entry("DUMPFILE=%s", dumpPath.c_str()),
186 entry("DUMP ID=%d", dumpId));
187 elog<Open>(ErrnoOpen(errno), PathOpen(dumpPath.c_str()));
188 }
189
190 infile.exceptions(std::ifstream::failbit | std::ifstream::badbit |
191 std::ifstream::eofbit);
192
193 log<level::INFO>("Opening File for RW ",
194 entry("FILENAME=%s", file.filename().c_str()));
195
196 std::filebuf* pbuf = infile.rdbuf();
197
198 // get file size using buffer's members
199 std::size_t size = pbuf->pubseekoff(0, infile.end, infile.in);
200 pbuf->pubseekpos(0, infile.in);
201
202 // allocate memory to contain file data
203 std::unique_ptr<char[]> buffer(new char[size]);
204 // get file data
205 pbuf->sgetn(buffer.get(), size);
206 infile.close();
207
208 writeOnUnixSocket(socketFD(), buffer.get(), size);
209 }
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500210 }
Ravi Tejaff9c4522020-11-13 05:14:51 -0600211 catch (std::ifstream::failure& oe)
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500212 {
Ravi Tejaff9c4522020-11-13 05:14:51 -0600213 std::remove(writePath.c_str());
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500214 auto err = errno;
Ravi Tejaff9c4522020-11-13 05:14:51 -0600215 log<level::ERR>("Failed to open", entry("ERR=%s", oe.what()),
216 entry("OPENINTERFACE=%s", dumpPath.c_str()),
217 entry("DUMP ID=%d", dumpId));
218 elog<Open>(ErrnoOpen(err), PathOpen(dumpPath.c_str()));
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500219 }
220 catch (const std::exception& e)
221 {
Ravi Tejaff9c4522020-11-13 05:14:51 -0600222 std::remove(writePath.c_str());
223 auto err = errno;
224 log<level::ERR>("Failed to offload dump", entry("ERR=%s", e.what()),
225 entry("DUMPFILE=%s", writePath.c_str()),
226 entry("DUMP ID=%d", dumpId));
227 elog<Write>(ErrnoWrite(err), PathWrite(writePath.c_str()));
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500228 }
Ravi Tejaff9c4522020-11-13 05:14:51 -0600229 std::remove(writePath.c_str());
230 return;
Dhruvaraj Subhashchandran580d91d2020-04-22 12:29:18 -0500231}
232
233} // namespace offload
234} // namespace dump
235} // namespace phosphor