blob: 5d1921a8fdf8f5fbc7f3cf331b0bb0527a2fe204 [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
77bool SmbiosBlobHandler::deleteBlob(const std::string& path)
78{
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
114std::vector<uint8_t> SmbiosBlobHandler::read(uint16_t session, uint32_t offset,
115 uint32_t requestedSize)
116{
117 /* SMBIOS blob handler does not support read. */
118 return std::vector<uint8_t>();
119}
120
121bool SmbiosBlobHandler::write(uint16_t session, uint32_t offset,
122 const std::vector<uint8_t>& data)
123{
124 if (!blobPtr || blobPtr->sessionId != session)
125 {
126 return false;
127 }
128
129 if (!(blobPtr->state & blobs::StateFlags::open_write))
130 {
131 phosphor::logging::log<phosphor::logging::level::ERR>(
132 "No open blob to write");
133 return false;
134 }
135
136 /* Is the offset beyond the array? */
137 if (offset >= maxBufferSize)
138 {
139 return false;
140 }
141
142 /* Determine whether all their bytes will fit. */
143 uint32_t remain = maxBufferSize - offset;
144 if (data.size() > remain)
145 {
146 return false;
147 }
148
149 /* Resize the buffer if what we're writing will go over the size */
150 uint32_t newBufferSize = data.size() + offset;
151 if (newBufferSize > blobPtr->buffer.size())
152 {
153 blobPtr->buffer.resize(newBufferSize);
154 }
155
156 std::memcpy(blobPtr->buffer.data() + offset, data.data(), data.size());
157 return true;
158}
159
160bool SmbiosBlobHandler::writeMeta(uint16_t session, uint32_t offset,
161 const std::vector<uint8_t>& data)
162{
163 return false;
164}
165
166bool SmbiosBlobHandler::commit(uint16_t session,
167 const std::vector<uint8_t>& data)
168{
169 if (!data.empty())
170 {
171 phosphor::logging::log<phosphor::logging::level::ERR>(
172 "Unexpected data provided to commit call");
173 return false;
174 }
175
176 if (!blobPtr || blobPtr->sessionId != session)
177 {
178 return false;
179 }
180
181 /* If a blob is committing or commited, return true directly. But if last
182 * commit fails, may try to commit again.
183 */
184 if (blobPtr->state &
185 (blobs::StateFlags::committing | blobs::StateFlags::committed))
186 {
187 return true;
188 }
189
190 /* Clear the commit_error bit. */
191 blobPtr->state &= ~blobs::StateFlags::commit_error;
192
193 MDRSMBIOSHeader mdrHdr;
194 mdrHdr.mdrType = mdrTypeII;
195 mdrHdr.timestamp = std::time(nullptr);
196 mdrHdr.dataSize = blobPtr->buffer.size();
197 if (access(smbiosPath, F_OK) == -1)
198 {
199 int flag = mkdir(smbiosPath, S_IRWXU);
200 if (flag != 0)
201 {
202 phosphor::logging::log<phosphor::logging::level::ERR>(
203 "create folder failed for writting smbios file");
204 blobPtr->state |= blobs::StateFlags::commit_error;
205 return false;
206 }
207 }
208
209 std::ofstream smbiosFile(mdrType2File,
210 std::ios_base::binary | std::ios_base::trunc);
211 if (!smbiosFile.good())
212 {
213 phosphor::logging::log<phosphor::logging::level::ERR>(
214 "Write data from flash error - Open SMBIOS table file failure");
215 blobPtr->state |= blobs::StateFlags::commit_error;
216 return false;
217 }
218
219 smbiosFile.exceptions(std::ofstream::badbit | std::ofstream::failbit);
220 try
221 {
222 smbiosFile.write(reinterpret_cast<char*>(&mdrHdr),
223 sizeof(MDRSMBIOSHeader));
224 smbiosFile.write(reinterpret_cast<char*>(blobPtr->buffer.data()),
225 mdrHdr.dataSize);
226 blobPtr->state |= blobs::StateFlags::committing;
227 }
Patrick Williams9ab8c8d2021-10-06 14:39:31 -0500228 catch (const std::ofstream::failure& e)
Jie Yangfbe1b682021-02-19 04:54:55 -0800229 {
230 phosphor::logging::log<phosphor::logging::level::ERR>(
231 "Write data from flash error - write data error",
232 phosphor::logging::entry("ERROR=%s", e.what()));
233 blobPtr->state |= blobs::StateFlags::commit_error;
234 return false;
235 }
236
237 if (!internal::syncSmbiosData())
238 {
239 blobPtr->state &= ~blobs::StateFlags::committing;
240 blobPtr->state |= blobs::StateFlags::commit_error;
241 return false;
242 }
243
244 // Unset committing state and set committed state
245 blobPtr->state &= ~blobs::StateFlags::committing;
246 blobPtr->state |= blobs::StateFlags::committed;
247
248 return true;
249}
250
251bool SmbiosBlobHandler::close(uint16_t session)
252{
253 if (!blobPtr || blobPtr->sessionId != session)
254 {
255 return false;
256 }
257
258 blobPtr = nullptr;
259 return true;
260}
261
262bool SmbiosBlobHandler::stat(uint16_t session, struct BlobMeta* meta)
263{
264 if (!blobPtr || blobPtr->sessionId != session)
265 {
266 return false;
267 }
268
269 meta->size = blobPtr->buffer.size();
270 meta->blobState = blobPtr->state;
271 return true;
272}
273
274bool SmbiosBlobHandler::expire(uint16_t session)
275{
276 return close(session);
277}
278
279} // namespace blobs