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