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