blob: 51d9d95ea9950641cce37627d7531d48924bd58c [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;
35 sdbusplus::bus::bus bus =
36 sdbusplus::bus::bus(ipmid_get_sd_bus_connection());
37 sdbusplus::message::message method =
38 bus.new_method_call(mdrV2Service, phosphor::smbios::mdrV2Path,
39 mdrV2Interface, "AgentSynchronizeData");
40
41 try
42 {
43 sdbusplus::message::message reply = bus.call(method);
44 reply.read(status);
45 }
46 catch (sdbusplus::exception_t& e)
47 {
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),
52 phosphor::logging::entry("PATH=%s", phosphor::smbios::mdrV2Path));
53 return false;
54 }
55
56 if (!status)
57 {
58 phosphor::logging::log<phosphor::logging::level::ERR>(
59 "Sync data with service failure");
60 return false;
61 }
62
63 return true;
64}
65
66} // namespace internal
67
68bool SmbiosBlobHandler::canHandleBlob(const std::string& path)
69{
70 return path == blobId;
71}
72
73std::vector<std::string> SmbiosBlobHandler::getBlobIds()
74{
75 return std::vector<std::string>(1, blobId);
76}
77
78bool SmbiosBlobHandler::deleteBlob(const std::string& path)
79{
80 return false;
81}
82
83bool SmbiosBlobHandler::stat(const std::string& path, struct BlobMeta* meta)
84{
85 if (!blobPtr || blobPtr->blobId != path)
86 {
87 return false;
88 }
89
90 meta->size = blobPtr->buffer.size();
91 meta->blobState = blobPtr->state;
92 return true;
93}
94
95bool SmbiosBlobHandler::open(uint16_t session, uint16_t flags,
96 const std::string& path)
97{
98 if (flags & blobs::OpenFlags::read)
99 {
100 /* Disable the read operation. */
101 return false;
102 }
103
104 /* The handler only allows one session. If an open blob exists, return
105 * false directly.
106 */
107 if (blobPtr)
108 {
109 return false;
110 }
111 blobPtr = std::make_unique<SmbiosBlob>(session, path, flags);
112 return true;
113}
114
115std::vector<uint8_t> SmbiosBlobHandler::read(uint16_t session, uint32_t offset,
116 uint32_t requestedSize)
117{
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
161bool SmbiosBlobHandler::writeMeta(uint16_t session, uint32_t offset,
162 const std::vector<uint8_t>& data)
163{
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);
227 blobPtr->state |= blobs::StateFlags::committing;
228 }
229 catch (std::ofstream::failure& e)
230 {
231 phosphor::logging::log<phosphor::logging::level::ERR>(
232 "Write data from flash error - write data error",
233 phosphor::logging::entry("ERROR=%s", e.what()));
234 blobPtr->state |= blobs::StateFlags::commit_error;
235 return false;
236 }
237
238 if (!internal::syncSmbiosData())
239 {
240 blobPtr->state &= ~blobs::StateFlags::committing;
241 blobPtr->state |= blobs::StateFlags::commit_error;
242 return false;
243 }
244
245 // Unset committing state and set committed state
246 blobPtr->state &= ~blobs::StateFlags::committing;
247 blobPtr->state |= blobs::StateFlags::committed;
248
249 return true;
250}
251
252bool SmbiosBlobHandler::close(uint16_t session)
253{
254 if (!blobPtr || blobPtr->sessionId != session)
255 {
256 return false;
257 }
258
259 blobPtr = nullptr;
260 return true;
261}
262
263bool SmbiosBlobHandler::stat(uint16_t session, struct BlobMeta* meta)
264{
265 if (!blobPtr || blobPtr->sessionId != session)
266 {
267 return false;
268 }
269
270 meta->size = blobPtr->buffer.size();
271 meta->blobState = blobPtr->state;
272 return true;
273}
274
275bool SmbiosBlobHandler::expire(uint16_t session)
276{
277 return close(session);
278}
279
280} // namespace blobs