blob: 3763762e628de5909c9dcf6f981352d010e87538 [file] [log] [blame]
Jie Yangfbe1b682021-02-19 04:54:55 -08001#include "handler.hpp"
2
3#include "mdrv2.hpp"
4#include "smbios_mdrv2.hpp"
5
6#include <sys/stat.h>
7#include <unistd.h>
8
9#include <ipmid/api.hpp>
10#include <phosphor-logging/log.hpp>
11#include <sdbusplus/bus.hpp>
12#include <sdbusplus/exception.hpp>
13#include <sdbusplus/message.hpp>
14
15#include <algorithm>
16#include <cstdint>
17#include <ctime>
18#include <fstream>
19#include <memory>
20#include <string>
21#include <vector>
22
23namespace blobs
24{
25
26namespace internal
27{
28
29constexpr const char* mdrV2Service = "xyz.openbmc_project.Smbios.MDR_V2";
30constexpr const char* mdrV2Interface = "xyz.openbmc_project.Smbios.MDR_V2";
31
32bool syncSmbiosData()
33{
34 bool status = false;
Patrick Williams77b9c472022-07-22 19:26:57 -050035 sdbusplus::bus_t bus = sdbusplus::bus_t(ipmid_get_sd_bus_connection());
36 sdbusplus::message_t method =
Jie Yangfbe1b682021-02-19 04:54:55 -080037 bus.new_method_call(mdrV2Service, phosphor::smbios::mdrV2Path,
38 mdrV2Interface, "AgentSynchronizeData");
39
40 try
41 {
Patrick Williams77b9c472022-07-22 19:26:57 -050042 sdbusplus::message_t reply = bus.call(method);
Jie Yangfbe1b682021-02-19 04:54:55 -080043 reply.read(status);
44 }
Patrick Williams9ab8c8d2021-10-06 14:39:31 -050045 catch (const sdbusplus::exception_t& e)
Jie Yangfbe1b682021-02-19 04:54:55 -080046 {
47 phosphor::logging::log<phosphor::logging::level::ERR>(
48 "Error Sync data with service",
49 phosphor::logging::entry("ERROR=%s", e.what()),
50 phosphor::logging::entry("SERVICE=%s", mdrV2Service),
51 phosphor::logging::entry("PATH=%s", phosphor::smbios::mdrV2Path));
52 return false;
53 }
54
55 if (!status)
56 {
57 phosphor::logging::log<phosphor::logging::level::ERR>(
58 "Sync data with service failure");
59 return false;
60 }
61
62 return true;
63}
64
65} // namespace internal
66
67bool SmbiosBlobHandler::canHandleBlob(const std::string& path)
68{
69 return path == blobId;
70}
71
72std::vector<std::string> SmbiosBlobHandler::getBlobIds()
73{
74 return std::vector<std::string>(1, blobId);
75}
76
Jonathan Domanf2d8bb42023-07-26 10:13:34 -070077bool SmbiosBlobHandler::deleteBlob(const std::string& /* path */)
Jie Yangfbe1b682021-02-19 04:54:55 -080078{
79 return false;
80}
81
82bool SmbiosBlobHandler::stat(const std::string& path, struct BlobMeta* meta)
83{
84 if (!blobPtr || blobPtr->blobId != path)
85 {
86 return false;
87 }
88
89 meta->size = blobPtr->buffer.size();
90 meta->blobState = blobPtr->state;
91 return true;
92}
93
94bool SmbiosBlobHandler::open(uint16_t session, uint16_t flags,
95 const std::string& path)
96{
97 if (flags & blobs::OpenFlags::read)
98 {
99 /* Disable the read operation. */
100 return false;
101 }
102
103 /* The handler only allows one session. If an open blob exists, return
104 * false directly.
105 */
106 if (blobPtr)
107 {
108 return false;
109 }
110 blobPtr = std::make_unique<SmbiosBlob>(session, path, flags);
111 return true;
112}
113
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700114std::vector<uint8_t> SmbiosBlobHandler::read(uint16_t /* session */,
115 uint32_t /* offset */,
116 uint32_t /* requestedSize */)
Jie Yangfbe1b682021-02-19 04:54:55 -0800117{
118 /* SMBIOS blob handler does not support read. */
119 return std::vector<uint8_t>();
120}
121
122bool SmbiosBlobHandler::write(uint16_t session, uint32_t offset,
123 const std::vector<uint8_t>& data)
124{
125 if (!blobPtr || blobPtr->sessionId != session)
126 {
127 return false;
128 }
129
130 if (!(blobPtr->state & blobs::StateFlags::open_write))
131 {
132 phosphor::logging::log<phosphor::logging::level::ERR>(
133 "No open blob to write");
134 return false;
135 }
136
137 /* Is the offset beyond the array? */
138 if (offset >= maxBufferSize)
139 {
140 return false;
141 }
142
143 /* Determine whether all their bytes will fit. */
144 uint32_t remain = maxBufferSize - offset;
145 if (data.size() > remain)
146 {
147 return false;
148 }
149
150 /* Resize the buffer if what we're writing will go over the size */
151 uint32_t newBufferSize = data.size() + offset;
152 if (newBufferSize > blobPtr->buffer.size())
153 {
154 blobPtr->buffer.resize(newBufferSize);
155 }
156
157 std::memcpy(blobPtr->buffer.data() + offset, data.data(), data.size());
158 return true;
159}
160
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700161bool SmbiosBlobHandler::writeMeta(uint16_t /* session */, uint32_t /* offset */,
162 const std::vector<uint8_t>& /* data */)
Jie Yangfbe1b682021-02-19 04:54:55 -0800163{
164 return false;
165}
166
167bool SmbiosBlobHandler::commit(uint16_t session,
168 const std::vector<uint8_t>& data)
169{
170 if (!data.empty())
171 {
172 phosphor::logging::log<phosphor::logging::level::ERR>(
173 "Unexpected data provided to commit call");
174 return false;
175 }
176
177 if (!blobPtr || blobPtr->sessionId != session)
178 {
179 return false;
180 }
181
182 /* If a blob is committing or commited, return true directly. But if last
183 * commit fails, may try to commit again.
184 */
185 if (blobPtr->state &
186 (blobs::StateFlags::committing | blobs::StateFlags::committed))
187 {
188 return true;
189 }
190
191 /* Clear the commit_error bit. */
192 blobPtr->state &= ~blobs::StateFlags::commit_error;
193
194 MDRSMBIOSHeader mdrHdr;
Josh Lehanf079e832023-09-19 15:52:52 -0700195 mdrHdr.dirVer = mdrDirVersion;
Jie Yangfbe1b682021-02-19 04:54:55 -0800196 mdrHdr.mdrType = mdrTypeII;
197 mdrHdr.timestamp = std::time(nullptr);
198 mdrHdr.dataSize = blobPtr->buffer.size();
199 if (access(smbiosPath, F_OK) == -1)
200 {
201 int flag = mkdir(smbiosPath, S_IRWXU);
202 if (flag != 0)
203 {
204 phosphor::logging::log<phosphor::logging::level::ERR>(
205 "create folder failed for writting smbios file");
206 blobPtr->state |= blobs::StateFlags::commit_error;
207 return false;
208 }
209 }
210
211 std::ofstream smbiosFile(mdrType2File,
212 std::ios_base::binary | std::ios_base::trunc);
213 if (!smbiosFile.good())
214 {
215 phosphor::logging::log<phosphor::logging::level::ERR>(
216 "Write data from flash error - Open SMBIOS table file failure");
217 blobPtr->state |= blobs::StateFlags::commit_error;
218 return false;
219 }
220
221 smbiosFile.exceptions(std::ofstream::badbit | std::ofstream::failbit);
222 try
223 {
224 smbiosFile.write(reinterpret_cast<char*>(&mdrHdr),
225 sizeof(MDRSMBIOSHeader));
226 smbiosFile.write(reinterpret_cast<char*>(blobPtr->buffer.data()),
227 mdrHdr.dataSize);
Konstantin Aladyshev6106d542023-06-29 15:36:02 +0300228 smbiosFile.close();
Jie Yangfbe1b682021-02-19 04:54:55 -0800229 blobPtr->state |= blobs::StateFlags::committing;
230 }
Patrick Williams9ab8c8d2021-10-06 14:39:31 -0500231 catch (const std::ofstream::failure& e)
Jie Yangfbe1b682021-02-19 04:54:55 -0800232 {
233 phosphor::logging::log<phosphor::logging::level::ERR>(
234 "Write data from flash error - write data error",
235 phosphor::logging::entry("ERROR=%s", e.what()));
236 blobPtr->state |= blobs::StateFlags::commit_error;
237 return false;
238 }
239
240 if (!internal::syncSmbiosData())
241 {
242 blobPtr->state &= ~blobs::StateFlags::committing;
243 blobPtr->state |= blobs::StateFlags::commit_error;
244 return false;
245 }
246
247 // Unset committing state and set committed state
248 blobPtr->state &= ~blobs::StateFlags::committing;
249 blobPtr->state |= blobs::StateFlags::committed;
250
251 return true;
252}
253
254bool SmbiosBlobHandler::close(uint16_t session)
255{
256 if (!blobPtr || blobPtr->sessionId != session)
257 {
258 return false;
259 }
260
261 blobPtr = nullptr;
262 return true;
263}
264
265bool SmbiosBlobHandler::stat(uint16_t session, struct BlobMeta* meta)
266{
267 if (!blobPtr || blobPtr->sessionId != session)
268 {
269 return false;
270 }
271
272 meta->size = blobPtr->buffer.size();
273 meta->blobState = blobPtr->state;
274 return true;
275}
276
277bool SmbiosBlobHandler::expire(uint16_t session)
278{
279 return close(session);
280}
281
282} // namespace blobs