blob: fb8111a868f3f80981a02b2fe0e375d7a14a1f1d [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>
Josh Lehan027277a2023-09-11 05:28:19 -070018#include <filesystem>
Jie Yangfbe1b682021-02-19 04:54:55 -080019#include <fstream>
20#include <memory>
21#include <string>
22#include <vector>
23
24namespace blobs
25{
26
27namespace internal
28{
29
30constexpr const char* mdrV2Service = "xyz.openbmc_project.Smbios.MDR_V2";
31constexpr const char* mdrV2Interface = "xyz.openbmc_project.Smbios.MDR_V2";
32
33bool syncSmbiosData()
34{
35 bool status = false;
Patrick Williams77b9c472022-07-22 19:26:57 -050036 sdbusplus::bus_t bus = sdbusplus::bus_t(ipmid_get_sd_bus_connection());
37 sdbusplus::message_t method =
Josh Lehan027277a2023-09-11 05:28:19 -070038 bus.new_method_call(mdrV2Service, phosphor::smbios::defaultObjectPath,
Jie Yangfbe1b682021-02-19 04:54:55 -080039 mdrV2Interface, "AgentSynchronizeData");
40
41 try
42 {
Patrick Williams77b9c472022-07-22 19:26:57 -050043 sdbusplus::message_t reply = bus.call(method);
Jie Yangfbe1b682021-02-19 04:54:55 -080044 reply.read(status);
45 }
Patrick Williams9ab8c8d2021-10-06 14:39:31 -050046 catch (const sdbusplus::exception_t& e)
Jie Yangfbe1b682021-02-19 04:54:55 -080047 {
48 phosphor::logging::log<phosphor::logging::level::ERR>(
49 "Error Sync data with service",
50 phosphor::logging::entry("ERROR=%s", e.what()),
51 phosphor::logging::entry("SERVICE=%s", mdrV2Service),
Josh Lehan027277a2023-09-11 05:28:19 -070052 phosphor::logging::entry("PATH=%s",
53 phosphor::smbios::defaultObjectPath));
Jie Yangfbe1b682021-02-19 04:54:55 -080054 return false;
55 }
56
57 if (!status)
58 {
59 phosphor::logging::log<phosphor::logging::level::ERR>(
60 "Sync data with service failure");
61 return false;
62 }
63
64 return true;
65}
66
67} // namespace internal
68
69bool SmbiosBlobHandler::canHandleBlob(const std::string& path)
70{
71 return path == blobId;
72}
73
74std::vector<std::string> SmbiosBlobHandler::getBlobIds()
75{
76 return std::vector<std::string>(1, blobId);
77}
78
Jonathan Domanf2d8bb42023-07-26 10:13:34 -070079bool SmbiosBlobHandler::deleteBlob(const std::string& /* path */)
Jie Yangfbe1b682021-02-19 04:54:55 -080080{
81 return false;
82}
83
84bool SmbiosBlobHandler::stat(const std::string& path, struct BlobMeta* meta)
85{
86 if (!blobPtr || blobPtr->blobId != path)
87 {
88 return false;
89 }
90
91 meta->size = blobPtr->buffer.size();
92 meta->blobState = blobPtr->state;
93 return true;
94}
95
96bool SmbiosBlobHandler::open(uint16_t session, uint16_t flags,
97 const std::string& path)
98{
99 if (flags & blobs::OpenFlags::read)
100 {
101 /* Disable the read operation. */
102 return false;
103 }
104
105 /* The handler only allows one session. If an open blob exists, return
106 * false directly.
107 */
108 if (blobPtr)
109 {
110 return false;
111 }
112 blobPtr = std::make_unique<SmbiosBlob>(session, path, flags);
113 return true;
114}
115
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700116std::vector<uint8_t> SmbiosBlobHandler::read(uint16_t /* session */,
117 uint32_t /* offset */,
118 uint32_t /* requestedSize */)
Jie Yangfbe1b682021-02-19 04:54:55 -0800119{
120 /* SMBIOS blob handler does not support read. */
121 return std::vector<uint8_t>();
122}
123
124bool SmbiosBlobHandler::write(uint16_t session, uint32_t offset,
125 const std::vector<uint8_t>& data)
126{
127 if (!blobPtr || blobPtr->sessionId != session)
128 {
129 return false;
130 }
131
132 if (!(blobPtr->state & blobs::StateFlags::open_write))
133 {
134 phosphor::logging::log<phosphor::logging::level::ERR>(
135 "No open blob to write");
136 return false;
137 }
138
139 /* Is the offset beyond the array? */
140 if (offset >= maxBufferSize)
141 {
142 return false;
143 }
144
145 /* Determine whether all their bytes will fit. */
146 uint32_t remain = maxBufferSize - offset;
147 if (data.size() > remain)
148 {
149 return false;
150 }
151
152 /* Resize the buffer if what we're writing will go over the size */
153 uint32_t newBufferSize = data.size() + offset;
154 if (newBufferSize > blobPtr->buffer.size())
155 {
156 blobPtr->buffer.resize(newBufferSize);
157 }
158
159 std::memcpy(blobPtr->buffer.data() + offset, data.data(), data.size());
160 return true;
161}
162
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700163bool SmbiosBlobHandler::writeMeta(uint16_t /* session */, uint32_t /* offset */,
164 const std::vector<uint8_t>& /* data */)
Jie Yangfbe1b682021-02-19 04:54:55 -0800165{
166 return false;
167}
168
169bool SmbiosBlobHandler::commit(uint16_t session,
170 const std::vector<uint8_t>& data)
171{
172 if (!data.empty())
173 {
174 phosphor::logging::log<phosphor::logging::level::ERR>(
175 "Unexpected data provided to commit call");
176 return false;
177 }
178
179 if (!blobPtr || blobPtr->sessionId != session)
180 {
181 return false;
182 }
183
184 /* If a blob is committing or commited, return true directly. But if last
185 * commit fails, may try to commit again.
186 */
187 if (blobPtr->state &
188 (blobs::StateFlags::committing | blobs::StateFlags::committed))
189 {
190 return true;
191 }
192
193 /* Clear the commit_error bit. */
194 blobPtr->state &= ~blobs::StateFlags::commit_error;
195
Josh Lehan027277a2023-09-11 05:28:19 -0700196 std::string defaultDir =
197 std::filesystem::path(mdrDefaultFile).parent_path();
198
Jie Yangfbe1b682021-02-19 04:54:55 -0800199 MDRSMBIOSHeader mdrHdr;
Josh Lehanf079e832023-09-19 15:52:52 -0700200 mdrHdr.dirVer = mdrDirVersion;
Jie Yangfbe1b682021-02-19 04:54:55 -0800201 mdrHdr.mdrType = mdrTypeII;
202 mdrHdr.timestamp = std::time(nullptr);
203 mdrHdr.dataSize = blobPtr->buffer.size();
Josh Lehan027277a2023-09-11 05:28:19 -0700204 if (access(defaultDir.c_str(), F_OK) == -1)
Jie Yangfbe1b682021-02-19 04:54:55 -0800205 {
Josh Lehan027277a2023-09-11 05:28:19 -0700206 int flag = mkdir(defaultDir.c_str(), S_IRWXU);
Jie Yangfbe1b682021-02-19 04:54:55 -0800207 if (flag != 0)
208 {
209 phosphor::logging::log<phosphor::logging::level::ERR>(
Josh Lehan027277a2023-09-11 05:28:19 -0700210 "create folder failed for writing smbios file");
Jie Yangfbe1b682021-02-19 04:54:55 -0800211 blobPtr->state |= blobs::StateFlags::commit_error;
212 return false;
213 }
214 }
215
Josh Lehan027277a2023-09-11 05:28:19 -0700216 std::ofstream smbiosFile(mdrDefaultFile,
Jie Yangfbe1b682021-02-19 04:54:55 -0800217 std::ios_base::binary | std::ios_base::trunc);
218 if (!smbiosFile.good())
219 {
220 phosphor::logging::log<phosphor::logging::level::ERR>(
221 "Write data from flash error - Open SMBIOS table file failure");
222 blobPtr->state |= blobs::StateFlags::commit_error;
223 return false;
224 }
225
226 smbiosFile.exceptions(std::ofstream::badbit | std::ofstream::failbit);
227 try
228 {
229 smbiosFile.write(reinterpret_cast<char*>(&mdrHdr),
230 sizeof(MDRSMBIOSHeader));
231 smbiosFile.write(reinterpret_cast<char*>(blobPtr->buffer.data()),
232 mdrHdr.dataSize);
Konstantin Aladyshev6106d542023-06-29 15:36:02 +0300233 smbiosFile.close();
Jie Yangfbe1b682021-02-19 04:54:55 -0800234 blobPtr->state |= blobs::StateFlags::committing;
235 }
Patrick Williams9ab8c8d2021-10-06 14:39:31 -0500236 catch (const std::ofstream::failure& e)
Jie Yangfbe1b682021-02-19 04:54:55 -0800237 {
238 phosphor::logging::log<phosphor::logging::level::ERR>(
239 "Write data from flash error - write data error",
240 phosphor::logging::entry("ERROR=%s", e.what()));
241 blobPtr->state |= blobs::StateFlags::commit_error;
242 return false;
243 }
244
245 if (!internal::syncSmbiosData())
246 {
247 blobPtr->state &= ~blobs::StateFlags::committing;
248 blobPtr->state |= blobs::StateFlags::commit_error;
249 return false;
250 }
251
252 // Unset committing state and set committed state
253 blobPtr->state &= ~blobs::StateFlags::committing;
254 blobPtr->state |= blobs::StateFlags::committed;
255
256 return true;
257}
258
259bool SmbiosBlobHandler::close(uint16_t session)
260{
261 if (!blobPtr || blobPtr->sessionId != session)
262 {
263 return false;
264 }
265
266 blobPtr = nullptr;
267 return true;
268}
269
270bool SmbiosBlobHandler::stat(uint16_t session, struct BlobMeta* meta)
271{
272 if (!blobPtr || blobPtr->sessionId != session)
273 {
274 return false;
275 }
276
277 meta->size = blobPtr->buffer.size();
278 meta->blobState = blobPtr->state;
279 return true;
280}
281
282bool SmbiosBlobHandler::expire(uint16_t session)
283{
284 return close(session);
285}
286
287} // namespace blobs