xref: /openbmc/phosphor-ipmi-flash/bmc/version-handler/version_handler.cpp (revision 42a44c281cce08be0ca6251955f4fb73d30c8ced)
1c78bfc82SJason Ling #include "version_handler.hpp"
2c78bfc82SJason Ling 
3cc7f385bSWilliam A. Kennington III #include <algorithm>
4cc7f385bSWilliam A. Kennington III #include <cstring>
5cc7f385bSWilliam A. Kennington III #include <ios>
6cc7f385bSWilliam A. Kennington III #include <limits>
7cc7f385bSWilliam A. Kennington III #include <memory>
8cc7f385bSWilliam A. Kennington III #include <optional>
9abf17354SWilliam A. Kennington III #include <utility>
10abf17354SWilliam A. Kennington III #include <vector>
11abf17354SWilliam A. Kennington III 
12c78bfc82SJason Ling namespace ipmi_flash
13c78bfc82SJason Ling {
14abf17354SWilliam A. Kennington III 
VersionBlobHandler(std::vector<HandlerConfig<ActionPack>> && configs)15abf17354SWilliam A. Kennington III VersionBlobHandler::VersionBlobHandler(
16abf17354SWilliam A. Kennington III     std::vector<HandlerConfig<ActionPack>>&& configs)
17c78bfc82SJason Ling {
18abf17354SWilliam A. Kennington III     for (auto& config : configs)
19c78bfc82SJason Ling     {
20b45eb5eeSWilliam A. Kennington III         auto info = std::make_unique<BlobInfo>();
21b45eb5eeSWilliam A. Kennington III         info->blobId = std::move(config.blobId);
22b45eb5eeSWilliam A. Kennington III         info->actions = std::move(config.actions);
23b45eb5eeSWilliam A. Kennington III         info->handler = std::move(config.handler);
249936c456SWilliam A. Kennington III         info->actions->onOpen->setCallback(
259936c456SWilliam A. Kennington III             [infoP = info.get()](TriggerableActionInterface& tai) {
26*42a44c28SPatrick Williams                 auto data =
27*42a44c28SPatrick Williams                     std::make_shared<std::optional<std::vector<uint8_t>>>();
289936c456SWilliam A. Kennington III                 do
299936c456SWilliam A. Kennington III                 {
309936c456SWilliam A. Kennington III                     if (tai.status() != ActionStatus::success)
319936c456SWilliam A. Kennington III                     {
329936c456SWilliam A. Kennington III                         fprintf(stderr, "Version file unit failed for %s\n",
339936c456SWilliam A. Kennington III                                 infoP->blobId.c_str());
349936c456SWilliam A. Kennington III                         continue;
359936c456SWilliam A. Kennington III                     }
369936c456SWilliam A. Kennington III                     if (!infoP->handler->open("", std::ios::in))
379936c456SWilliam A. Kennington III                     {
389936c456SWilliam A. Kennington III                         fprintf(stderr, "Opening version file failed for %s\n",
399936c456SWilliam A. Kennington III                                 infoP->blobId.c_str());
409936c456SWilliam A. Kennington III                         continue;
419936c456SWilliam A. Kennington III                     }
429936c456SWilliam A. Kennington III                     auto d = infoP->handler->read(
439936c456SWilliam A. Kennington III                         0, std::numeric_limits<uint32_t>::max());
449936c456SWilliam A. Kennington III                     infoP->handler->close();
459936c456SWilliam A. Kennington III                     if (!d)
469936c456SWilliam A. Kennington III                     {
479936c456SWilliam A. Kennington III                         fprintf(stderr, "Reading version file failed for %s\n",
489936c456SWilliam A. Kennington III                                 infoP->blobId.c_str());
499936c456SWilliam A. Kennington III                         continue;
509936c456SWilliam A. Kennington III                     }
519936c456SWilliam A. Kennington III                     *data = std::move(d);
529936c456SWilliam A. Kennington III                 } while (false);
539936c456SWilliam A. Kennington III                 for (auto sessionP : infoP->sessionsToUpdate)
549936c456SWilliam A. Kennington III                 {
559936c456SWilliam A. Kennington III                     sessionP->data = data;
569936c456SWilliam A. Kennington III                 }
579936c456SWilliam A. Kennington III                 infoP->sessionsToUpdate.clear();
589936c456SWilliam A. Kennington III             });
59b45eb5eeSWilliam A. Kennington III         if (!blobInfoMap.try_emplace(info->blobId, std::move(info)).second)
60abf17354SWilliam A. Kennington III         {
61abf17354SWilliam A. Kennington III             fprintf(stderr, "Ignoring duplicate config for %s\n",
62b45eb5eeSWilliam A. Kennington III                     info->blobId.c_str());
63c78bfc82SJason Ling         }
64abf17354SWilliam A. Kennington III     }
65c78bfc82SJason Ling }
66c78bfc82SJason Ling 
canHandleBlob(const std::string & path)67c78bfc82SJason Ling bool VersionBlobHandler::canHandleBlob(const std::string& path)
68c78bfc82SJason Ling {
69abf17354SWilliam A. Kennington III     return blobInfoMap.find(path) != blobInfoMap.end();
70c78bfc82SJason Ling }
71c78bfc82SJason Ling 
getBlobIds()72c78bfc82SJason Ling std::vector<std::string> VersionBlobHandler::getBlobIds()
73c78bfc82SJason Ling {
74abf17354SWilliam A. Kennington III     std::vector<std::string> ret;
75abf17354SWilliam A. Kennington III     for (const auto& [key, _] : blobInfoMap)
76abf17354SWilliam A. Kennington III     {
77b45eb5eeSWilliam A. Kennington III         ret.emplace_back(key);
78abf17354SWilliam A. Kennington III     }
79abf17354SWilliam A. Kennington III     return ret;
80c78bfc82SJason Ling }
81c78bfc82SJason Ling 
82c78bfc82SJason Ling /**
83c78bfc82SJason Ling  * deleteBlob - does nothing, always fails
84c78bfc82SJason Ling  */
deleteBlob(const std::string &)85b487eb47SWilly Tu bool VersionBlobHandler::deleteBlob(const std::string&)
86c78bfc82SJason Ling {
87c78bfc82SJason Ling     return false;
88c78bfc82SJason Ling }
89c78bfc82SJason Ling 
stat(const std::string &,blobs::BlobMeta *)90b487eb47SWilly Tu bool VersionBlobHandler::stat(const std::string&, blobs::BlobMeta*)
91c78bfc82SJason Ling {
92eba0c34aSWilliam A. Kennington III     return false;
93c78bfc82SJason Ling }
94c78bfc82SJason Ling 
open(uint16_t session,uint16_t flags,const std::string & path)95c78bfc82SJason Ling bool VersionBlobHandler::open(uint16_t session, uint16_t flags,
96c78bfc82SJason Ling                               const std::string& path)
97c78bfc82SJason Ling {
98c78bfc82SJason Ling     /* only reads are supported, check if blob is handled and make sure
99c78bfc82SJason Ling      * the blob isn't already opened
100c78bfc82SJason Ling      */
101c78bfc82SJason Ling     if (flags != blobs::read)
102c78bfc82SJason Ling     {
103c78bfc82SJason Ling         fprintf(stderr, "open %s fail: unsupported flags(0x%04X.)\n",
104c78bfc82SJason Ling                 path.c_str(), flags);
105c78bfc82SJason Ling         return false;
106c78bfc82SJason Ling     }
107c78bfc82SJason Ling 
1089936c456SWilliam A. Kennington III     auto info = std::make_unique<SessionInfo>();
1099936c456SWilliam A. Kennington III     info->blob = blobInfoMap.at(path).get();
1109936c456SWilliam A. Kennington III     info->blob->sessionsToUpdate.emplace(info.get());
1119936c456SWilliam A. Kennington III     if (info->blob->sessionsToUpdate.size() == 1 &&
1129936c456SWilliam A. Kennington III         !info->blob->actions->onOpen->trigger())
113c78bfc82SJason Ling     {
114b45eb5eeSWilliam A. Kennington III         fprintf(stderr, "open %s fail: onOpen trigger failed\n", path.c_str());
1159936c456SWilliam A. Kennington III         info->blob->sessionsToUpdate.erase(info.get());
116c78bfc82SJason Ling         return false;
117c78bfc82SJason Ling     }
118007c0166SWilliam A. Kennington III 
1199936c456SWilliam A. Kennington III     sessionInfoMap[session] = std::move(info);
120c78bfc82SJason Ling     return true;
121c78bfc82SJason Ling }
122c78bfc82SJason Ling 
read(uint16_t session,uint32_t offset,uint32_t requestedSize)123c78bfc82SJason Ling std::vector<uint8_t> VersionBlobHandler::read(uint16_t session, uint32_t offset,
124c78bfc82SJason Ling                                               uint32_t requestedSize)
125c78bfc82SJason Ling {
1269936c456SWilliam A. Kennington III     auto& data = sessionInfoMap.at(session)->data;
1270674a6d7SWilliam A. Kennington III     if (data == nullptr || !*data)
1280674a6d7SWilliam A. Kennington III     {
1290674a6d7SWilliam A. Kennington III         throw std::runtime_error("Version data not ready for read");
1300674a6d7SWilliam A. Kennington III     }
1310674a6d7SWilliam A. Kennington III     if ((*data)->size() < offset)
132c78bfc82SJason Ling     {
133c78bfc82SJason Ling         return {};
134c78bfc82SJason Ling     }
1359936c456SWilliam A. Kennington III     std::vector<uint8_t> ret(
1369936c456SWilliam A. Kennington III         std::min<size_t>(requestedSize, (*data)->size() - offset));
1379936c456SWilliam A. Kennington III     std::memcpy(&ret[0], &(**data)[offset], ret.size());
1389936c456SWilliam A. Kennington III     return ret;
139c78bfc82SJason Ling }
140c78bfc82SJason Ling 
close(uint16_t session)141c78bfc82SJason Ling bool VersionBlobHandler::close(uint16_t session)
142c78bfc82SJason Ling {
1439936c456SWilliam A. Kennington III     auto it = sessionInfoMap.find(session);
1449936c456SWilliam A. Kennington III     if (it == sessionInfoMap.end())
145c78bfc82SJason Ling     {
146c78bfc82SJason Ling         return false;
147c78bfc82SJason Ling     }
1489936c456SWilliam A. Kennington III     auto& info = *it->second;
1499936c456SWilliam A. Kennington III     info.blob->sessionsToUpdate.erase(&info);
1509936c456SWilliam A. Kennington III     if (info.blob->sessionsToUpdate.empty())
1519936c456SWilliam A. Kennington III     {
1529936c456SWilliam A. Kennington III         info.blob->actions->onOpen->abort();
1539936c456SWilliam A. Kennington III     }
1549936c456SWilliam A. Kennington III     sessionInfoMap.erase(it);
1559936c456SWilliam A. Kennington III     return true;
156c78bfc82SJason Ling }
157c5b901d8SWilliam A. Kennington III 
stat(uint16_t session,blobs::BlobMeta * meta)158c5b901d8SWilliam A. Kennington III bool VersionBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
159c5b901d8SWilliam A. Kennington III {
160eba0c34aSWilliam A. Kennington III     const auto& data = sessionInfoMap.at(session)->data;
161eba0c34aSWilliam A. Kennington III     if (data == nullptr)
162eba0c34aSWilliam A. Kennington III     {
163eba0c34aSWilliam A. Kennington III         meta->blobState = blobs::StateFlags::committing;
164eba0c34aSWilliam A. Kennington III         meta->size = 0;
165eba0c34aSWilliam A. Kennington III     }
166eba0c34aSWilliam A. Kennington III     else if (!*data)
167eba0c34aSWilliam A. Kennington III     {
168eba0c34aSWilliam A. Kennington III         meta->blobState = blobs::StateFlags::commit_error;
169eba0c34aSWilliam A. Kennington III         meta->size = 0;
170eba0c34aSWilliam A. Kennington III     }
171eba0c34aSWilliam A. Kennington III     else
172eba0c34aSWilliam A. Kennington III     {
1731038836cSPatrick Williams         meta->blobState = blobs::StateFlags::committed |
1741038836cSPatrick Williams                           blobs::StateFlags::open_read;
175eba0c34aSWilliam A. Kennington III         meta->size = (*data)->size();
176eba0c34aSWilliam A. Kennington III     }
177eba0c34aSWilliam A. Kennington III     return true;
178c5b901d8SWilliam A. Kennington III }
179c5b901d8SWilliam A. Kennington III 
expire(uint16_t session)180c5b901d8SWilliam A. Kennington III bool VersionBlobHandler::expire(uint16_t session)
181c5b901d8SWilliam A. Kennington III {
182c5b901d8SWilliam A. Kennington III     close(session);
183c5b901d8SWilliam A. Kennington III     return true;
184c5b901d8SWilliam A. Kennington III }
185c5b901d8SWilliam A. Kennington III 
186c78bfc82SJason Ling } // namespace ipmi_flash
187