blob: 4b1841ff635fc919920579dbaa36cea678e2849f [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;
195 mdrHdr.mdrType = mdrTypeII;
196 mdrHdr.timestamp = std::time(nullptr);
197 mdrHdr.dataSize = blobPtr->buffer.size();
198 if (access(smbiosPath, F_OK) == -1)
199 {
200 int flag = mkdir(smbiosPath, S_IRWXU);
201 if (flag != 0)
202 {
203 phosphor::logging::log<phosphor::logging::level::ERR>(
204 "create folder failed for writting smbios file");
205 blobPtr->state |= blobs::StateFlags::commit_error;
206 return false;
207 }
208 }
209
210 std::ofstream smbiosFile(mdrType2File,
211 std::ios_base::binary | std::ios_base::trunc);
212 if (!smbiosFile.good())
213 {
214 phosphor::logging::log<phosphor::logging::level::ERR>(
215 "Write data from flash error - Open SMBIOS table file failure");
216 blobPtr->state |= blobs::StateFlags::commit_error;
217 return false;
218 }
219
220 smbiosFile.exceptions(std::ofstream::badbit | std::ofstream::failbit);
221 try
222 {
223 smbiosFile.write(reinterpret_cast<char*>(&mdrHdr),
224 sizeof(MDRSMBIOSHeader));
225 smbiosFile.write(reinterpret_cast<char*>(blobPtr->buffer.data()),
226 mdrHdr.dataSize);
Konstantin Aladyshev6106d542023-06-29 15:36:02 +0300227 smbiosFile.close();
Jie Yangfbe1b682021-02-19 04:54:55 -0800228 blobPtr->state |= blobs::StateFlags::committing;
229 }
Patrick Williams9ab8c8d2021-10-06 14:39:31 -0500230 catch (const std::ofstream::failure& e)
Jie Yangfbe1b682021-02-19 04:54:55 -0800231 {
232 phosphor::logging::log<phosphor::logging::level::ERR>(
233 "Write data from flash error - write data error",
234 phosphor::logging::entry("ERROR=%s", e.what()));
235 blobPtr->state |= blobs::StateFlags::commit_error;
236 return false;
237 }
238
239 if (!internal::syncSmbiosData())
240 {
241 blobPtr->state &= ~blobs::StateFlags::committing;
242 blobPtr->state |= blobs::StateFlags::commit_error;
243 return false;
244 }
245
246 // Unset committing state and set committed state
247 blobPtr->state &= ~blobs::StateFlags::committing;
248 blobPtr->state |= blobs::StateFlags::committed;
249
250 return true;
251}
252
253bool SmbiosBlobHandler::close(uint16_t session)
254{
255 if (!blobPtr || blobPtr->sessionId != session)
256 {
257 return false;
258 }
259
260 blobPtr = nullptr;
261 return true;
262}
263
264bool SmbiosBlobHandler::stat(uint16_t session, struct BlobMeta* meta)
265{
266 if (!blobPtr || blobPtr->sessionId != session)
267 {
268 return false;
269 }
270
271 meta->size = blobPtr->buffer.size();
272 meta->blobState = blobPtr->state;
273 return true;
274}
275
276bool SmbiosBlobHandler::expire(uint16_t session)
277{
278 return close(session);
279}
280
281} // namespace blobs