blob: b30a99a244e29d5751387216e4141c42971b86eb [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
Patrick Williams1d73dcc2024-08-16 15:21:42 -0400116std::vector<uint8_t> SmbiosBlobHandler::read(
117 uint16_t /* session */, uint32_t /* offset */, uint32_t /* requestedSize */)
Jie Yangfbe1b682021-02-19 04:54:55 -0800118{
119 /* SMBIOS blob handler does not support read. */
120 return std::vector<uint8_t>();
121}
122
123bool SmbiosBlobHandler::write(uint16_t session, uint32_t offset,
124 const std::vector<uint8_t>& data)
125{
126 if (!blobPtr || blobPtr->sessionId != session)
127 {
128 return false;
129 }
130
131 if (!(blobPtr->state & blobs::StateFlags::open_write))
132 {
133 phosphor::logging::log<phosphor::logging::level::ERR>(
134 "No open blob to write");
135 return false;
136 }
137
138 /* Is the offset beyond the array? */
139 if (offset >= maxBufferSize)
140 {
141 return false;
142 }
143
144 /* Determine whether all their bytes will fit. */
145 uint32_t remain = maxBufferSize - offset;
146 if (data.size() > remain)
147 {
148 return false;
149 }
150
151 /* Resize the buffer if what we're writing will go over the size */
152 uint32_t newBufferSize = data.size() + offset;
153 if (newBufferSize > blobPtr->buffer.size())
154 {
155 blobPtr->buffer.resize(newBufferSize);
156 }
157
158 std::memcpy(blobPtr->buffer.data() + offset, data.data(), data.size());
159 return true;
160}
161
Jonathan Domanf2d8bb42023-07-26 10:13:34 -0700162bool SmbiosBlobHandler::writeMeta(uint16_t /* session */, uint32_t /* offset */,
163 const std::vector<uint8_t>& /* data */)
Jie Yangfbe1b682021-02-19 04:54:55 -0800164{
165 return false;
166}
167
168bool SmbiosBlobHandler::commit(uint16_t session,
169 const std::vector<uint8_t>& data)
170{
171 if (!data.empty())
172 {
173 phosphor::logging::log<phosphor::logging::level::ERR>(
174 "Unexpected data provided to commit call");
175 return false;
176 }
177
178 if (!blobPtr || blobPtr->sessionId != session)
179 {
180 return false;
181 }
182
Manojkiran Eda0fe13ab2024-06-17 14:55:10 +0530183 /* If a blob is committing or committed, return true directly. But if last
Jie Yangfbe1b682021-02-19 04:54:55 -0800184 * commit fails, may try to commit again.
185 */
186 if (blobPtr->state &
187 (blobs::StateFlags::committing | blobs::StateFlags::committed))
188 {
189 return true;
190 }
191
192 /* Clear the commit_error bit. */
193 blobPtr->state &= ~blobs::StateFlags::commit_error;
194
Josh Lehan027277a2023-09-11 05:28:19 -0700195 std::string defaultDir =
196 std::filesystem::path(mdrDefaultFile).parent_path();
197
Jie Yangfbe1b682021-02-19 04:54:55 -0800198 MDRSMBIOSHeader mdrHdr;
Josh Lehanf079e832023-09-19 15:52:52 -0700199 mdrHdr.dirVer = mdrDirVersion;
Jie Yangfbe1b682021-02-19 04:54:55 -0800200 mdrHdr.mdrType = mdrTypeII;
201 mdrHdr.timestamp = std::time(nullptr);
202 mdrHdr.dataSize = blobPtr->buffer.size();
Josh Lehan027277a2023-09-11 05:28:19 -0700203 if (access(defaultDir.c_str(), F_OK) == -1)
Jie Yangfbe1b682021-02-19 04:54:55 -0800204 {
Josh Lehan027277a2023-09-11 05:28:19 -0700205 int flag = mkdir(defaultDir.c_str(), S_IRWXU);
Jie Yangfbe1b682021-02-19 04:54:55 -0800206 if (flag != 0)
207 {
208 phosphor::logging::log<phosphor::logging::level::ERR>(
Josh Lehan027277a2023-09-11 05:28:19 -0700209 "create folder failed for writing smbios file");
Jie Yangfbe1b682021-02-19 04:54:55 -0800210 blobPtr->state |= blobs::StateFlags::commit_error;
211 return false;
212 }
213 }
214
Josh Lehan027277a2023-09-11 05:28:19 -0700215 std::ofstream smbiosFile(mdrDefaultFile,
Jie Yangfbe1b682021-02-19 04:54:55 -0800216 std::ios_base::binary | std::ios_base::trunc);
217 if (!smbiosFile.good())
218 {
219 phosphor::logging::log<phosphor::logging::level::ERR>(
220 "Write data from flash error - Open SMBIOS table file failure");
221 blobPtr->state |= blobs::StateFlags::commit_error;
222 return false;
223 }
224
225 smbiosFile.exceptions(std::ofstream::badbit | std::ofstream::failbit);
226 try
227 {
228 smbiosFile.write(reinterpret_cast<char*>(&mdrHdr),
229 sizeof(MDRSMBIOSHeader));
230 smbiosFile.write(reinterpret_cast<char*>(blobPtr->buffer.data()),
231 mdrHdr.dataSize);
Konstantin Aladyshev6106d542023-06-29 15:36:02 +0300232 smbiosFile.close();
Jie Yangfbe1b682021-02-19 04:54:55 -0800233 blobPtr->state |= blobs::StateFlags::committing;
234 }
Patrick Williams9ab8c8d2021-10-06 14:39:31 -0500235 catch (const std::ofstream::failure& e)
Jie Yangfbe1b682021-02-19 04:54:55 -0800236 {
237 phosphor::logging::log<phosphor::logging::level::ERR>(
238 "Write data from flash error - write data error",
239 phosphor::logging::entry("ERROR=%s", e.what()));
240 blobPtr->state |= blobs::StateFlags::commit_error;
241 return false;
242 }
243
244 if (!internal::syncSmbiosData())
245 {
246 blobPtr->state &= ~blobs::StateFlags::committing;
247 blobPtr->state |= blobs::StateFlags::commit_error;
248 return false;
249 }
250
251 // Unset committing state and set committed state
252 blobPtr->state &= ~blobs::StateFlags::committing;
253 blobPtr->state |= blobs::StateFlags::committed;
254
255 return true;
256}
257
258bool SmbiosBlobHandler::close(uint16_t session)
259{
260 if (!blobPtr || blobPtr->sessionId != session)
261 {
262 return false;
263 }
264
265 blobPtr = nullptr;
266 return true;
267}
268
269bool SmbiosBlobHandler::stat(uint16_t session, struct BlobMeta* meta)
270{
271 if (!blobPtr || blobPtr->sessionId != session)
272 {
273 return false;
274 }
275
276 meta->size = blobPtr->buffer.size();
277 meta->blobState = blobPtr->state;
278 return true;
279}
280
281bool SmbiosBlobHandler::expire(uint16_t session)
282{
283 return close(session);
284}
285
286} // namespace blobs