blob: 5b285f88e517a69f6d77b0d4b2be7fc2ec400413 [file] [log] [blame]
Jason Lingc78bfc82020-11-05 18:58:16 -08001#include "version_handler.hpp"
2
William A. Kennington IIIcc7f3852021-01-21 19:01:56 -08003#include <algorithm>
4#include <cstring>
5#include <ios>
6#include <limits>
7#include <memory>
8#include <optional>
William A. Kennington IIIabf17352020-12-22 21:07:11 -08009#include <utility>
10#include <vector>
11
Jason Lingc78bfc82020-11-05 18:58:16 -080012namespace ipmi_flash
13{
William A. Kennington IIIabf17352020-12-22 21:07:11 -080014
15VersionBlobHandler::VersionBlobHandler(
16 std::vector<HandlerConfig<ActionPack>>&& configs)
Jason Lingc78bfc82020-11-05 18:58:16 -080017{
William A. Kennington IIIabf17352020-12-22 21:07:11 -080018 for (auto& config : configs)
Jason Lingc78bfc82020-11-05 18:58:16 -080019 {
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -080020 auto info = std::make_unique<BlobInfo>();
21 info->blobId = std::move(config.blobId);
22 info->actions = std::move(config.actions);
23 info->handler = std::move(config.handler);
William A. Kennington III9936c452020-12-23 23:31:23 -080024 info->actions->onOpen->setCallback(
25 [infoP = info.get()](TriggerableActionInterface& tai) {
Patrick Williams42a44c22024-08-16 15:21:32 -040026 auto data =
27 std::make_shared<std::optional<std::vector<uint8_t>>>();
28 do
William A. Kennington III9936c452020-12-23 23:31:23 -080029 {
Patrick Williams42a44c22024-08-16 15:21:32 -040030 if (tai.status() != ActionStatus::success)
31 {
32 fprintf(stderr, "Version file unit failed for %s\n",
33 infoP->blobId.c_str());
34 continue;
35 }
36 if (!infoP->handler->open("", std::ios::in))
37 {
38 fprintf(stderr, "Opening version file failed for %s\n",
39 infoP->blobId.c_str());
40 continue;
41 }
42 auto d = infoP->handler->read(
43 0, std::numeric_limits<uint32_t>::max());
44 infoP->handler->close();
45 if (!d)
46 {
47 fprintf(stderr, "Reading version file failed for %s\n",
48 infoP->blobId.c_str());
49 continue;
50 }
51 *data = std::move(d);
52 } while (false);
53 for (auto sessionP : infoP->sessionsToUpdate)
Patrick Williams10388362023-05-10 07:51:09 -050054 {
Patrick Williams42a44c22024-08-16 15:21:32 -040055 sessionP->data = data;
Patrick Williams10388362023-05-10 07:51:09 -050056 }
Patrick Williams42a44c22024-08-16 15:21:32 -040057 infoP->sessionsToUpdate.clear();
58 });
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -080059 if (!blobInfoMap.try_emplace(info->blobId, std::move(info)).second)
William A. Kennington IIIabf17352020-12-22 21:07:11 -080060 {
61 fprintf(stderr, "Ignoring duplicate config for %s\n",
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -080062 info->blobId.c_str());
William A. Kennington IIIabf17352020-12-22 21:07:11 -080063 }
Jason Lingc78bfc82020-11-05 18:58:16 -080064 }
Jason Lingc78bfc82020-11-05 18:58:16 -080065}
66
67bool VersionBlobHandler::canHandleBlob(const std::string& path)
68{
William A. Kennington IIIabf17352020-12-22 21:07:11 -080069 return blobInfoMap.find(path) != blobInfoMap.end();
Jason Lingc78bfc82020-11-05 18:58:16 -080070}
71
72std::vector<std::string> VersionBlobHandler::getBlobIds()
73{
William A. Kennington IIIabf17352020-12-22 21:07:11 -080074 std::vector<std::string> ret;
75 for (const auto& [key, _] : blobInfoMap)
76 {
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -080077 ret.emplace_back(key);
William A. Kennington IIIabf17352020-12-22 21:07:11 -080078 }
79 return ret;
Jason Lingc78bfc82020-11-05 18:58:16 -080080}
81
82/**
83 * deleteBlob - does nothing, always fails
84 */
Willy Tub487eb42021-09-16 21:44:43 -070085bool VersionBlobHandler::deleteBlob(const std::string&)
Jason Lingc78bfc82020-11-05 18:58:16 -080086{
87 return false;
88}
89
Willy Tub487eb42021-09-16 21:44:43 -070090bool VersionBlobHandler::stat(const std::string&, blobs::BlobMeta*)
Jason Lingc78bfc82020-11-05 18:58:16 -080091{
William A. Kennington IIIeba0c342021-01-12 14:23:01 -080092 return false;
Jason Lingc78bfc82020-11-05 18:58:16 -080093}
94
95bool VersionBlobHandler::open(uint16_t session, uint16_t flags,
96 const std::string& path)
97{
Jason Lingc78bfc82020-11-05 18:58:16 -080098 /* only reads are supported, check if blob is handled and make sure
99 * the blob isn't already opened
100 */
101 if (flags != blobs::read)
102 {
103 fprintf(stderr, "open %s fail: unsupported flags(0x%04X.)\n",
104 path.c_str(), flags);
Jason Lingc78bfc82020-11-05 18:58:16 -0800105 return false;
106 }
Jason Lingc78bfc82020-11-05 18:58:16 -0800107
William A. Kennington III9936c452020-12-23 23:31:23 -0800108 auto info = std::make_unique<SessionInfo>();
109 info->blob = blobInfoMap.at(path).get();
110 info->blob->sessionsToUpdate.emplace(info.get());
111 if (info->blob->sessionsToUpdate.size() == 1 &&
112 !info->blob->actions->onOpen->trigger())
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -0800113 {
114 fprintf(stderr, "open %s fail: onOpen trigger failed\n", path.c_str());
William A. Kennington III9936c452020-12-23 23:31:23 -0800115 info->blob->sessionsToUpdate.erase(info.get());
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -0800116 return false;
117 }
William A. Kennington III007c0162020-12-23 16:36:22 -0800118
William A. Kennington III9936c452020-12-23 23:31:23 -0800119 sessionInfoMap[session] = std::move(info);
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -0800120 return true;
Jason Lingc78bfc82020-11-05 18:58:16 -0800121}
122
123std::vector<uint8_t> VersionBlobHandler::read(uint16_t session, uint32_t offset,
124 uint32_t requestedSize)
125{
William A. Kennington III9936c452020-12-23 23:31:23 -0800126 auto& data = sessionInfoMap.at(session)->data;
William A. Kennington III0674a6d2021-01-12 14:25:41 -0800127 if (data == nullptr || !*data)
128 {
129 throw std::runtime_error("Version data not ready for read");
130 }
131 if ((*data)->size() < offset)
Jason Lingc78bfc82020-11-05 18:58:16 -0800132 {
Jason Lingc78bfc82020-11-05 18:58:16 -0800133 return {};
134 }
William A. Kennington III9936c452020-12-23 23:31:23 -0800135 std::vector<uint8_t> ret(
136 std::min<size_t>(requestedSize, (*data)->size() - offset));
137 std::memcpy(&ret[0], &(**data)[offset], ret.size());
138 return ret;
Jason Lingc78bfc82020-11-05 18:58:16 -0800139}
140
141bool VersionBlobHandler::close(uint16_t session)
142{
William A. Kennington III9936c452020-12-23 23:31:23 -0800143 auto it = sessionInfoMap.find(session);
144 if (it == sessionInfoMap.end())
Jason Lingc78bfc82020-11-05 18:58:16 -0800145 {
146 return false;
147 }
William A. Kennington III9936c452020-12-23 23:31:23 -0800148 auto& info = *it->second;
149 info.blob->sessionsToUpdate.erase(&info);
150 if (info.blob->sessionsToUpdate.empty())
151 {
152 info.blob->actions->onOpen->abort();
153 }
154 sessionInfoMap.erase(it);
155 return true;
Jason Lingc78bfc82020-11-05 18:58:16 -0800156}
William A. Kennington IIIc5b901d2020-12-23 17:07:20 -0800157
158bool VersionBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
159{
William A. Kennington IIIeba0c342021-01-12 14:23:01 -0800160 const auto& data = sessionInfoMap.at(session)->data;
161 if (data == nullptr)
162 {
163 meta->blobState = blobs::StateFlags::committing;
164 meta->size = 0;
165 }
166 else if (!*data)
167 {
168 meta->blobState = blobs::StateFlags::commit_error;
169 meta->size = 0;
170 }
171 else
172 {
Patrick Williams10388362023-05-10 07:51:09 -0500173 meta->blobState = blobs::StateFlags::committed |
174 blobs::StateFlags::open_read;
William A. Kennington IIIeba0c342021-01-12 14:23:01 -0800175 meta->size = (*data)->size();
176 }
177 return true;
William A. Kennington IIIc5b901d2020-12-23 17:07:20 -0800178}
179
180bool VersionBlobHandler::expire(uint16_t session)
181{
182 close(session);
183 return true;
184}
185
Jason Lingc78bfc82020-11-05 18:58:16 -0800186} // namespace ipmi_flash