blob: f26884b334908c924b820c2a5498b92a4fa14a49 [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 Williams10388362023-05-10 07:51:09 -050026 auto data = std::make_shared<std::optional<std::vector<uint8_t>>>();
27 do
28 {
29 if (tai.status() != ActionStatus::success)
William A. Kennington III9936c452020-12-23 23:31:23 -080030 {
Patrick Williams10388362023-05-10 07:51:09 -050031 fprintf(stderr, "Version file unit failed for %s\n",
32 infoP->blobId.c_str());
33 continue;
William A. Kennington III9936c452020-12-23 23:31:23 -080034 }
Patrick Williams10388362023-05-10 07:51:09 -050035 if (!infoP->handler->open("", std::ios::in))
36 {
37 fprintf(stderr, "Opening version file failed for %s\n",
38 infoP->blobId.c_str());
39 continue;
40 }
41 auto d = infoP->handler->read(
42 0, std::numeric_limits<uint32_t>::max());
43 infoP->handler->close();
44 if (!d)
45 {
46 fprintf(stderr, "Reading version file failed for %s\n",
47 infoP->blobId.c_str());
48 continue;
49 }
50 *data = std::move(d);
51 } while (false);
52 for (auto sessionP : infoP->sessionsToUpdate)
53 {
54 sessionP->data = data;
55 }
56 infoP->sessionsToUpdate.clear();
57 });
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -080058 if (!blobInfoMap.try_emplace(info->blobId, std::move(info)).second)
William A. Kennington IIIabf17352020-12-22 21:07:11 -080059 {
60 fprintf(stderr, "Ignoring duplicate config for %s\n",
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -080061 info->blobId.c_str());
William A. Kennington IIIabf17352020-12-22 21:07:11 -080062 }
Jason Lingc78bfc82020-11-05 18:58:16 -080063 }
Jason Lingc78bfc82020-11-05 18:58:16 -080064}
65
66bool VersionBlobHandler::canHandleBlob(const std::string& path)
67{
William A. Kennington IIIabf17352020-12-22 21:07:11 -080068 return blobInfoMap.find(path) != blobInfoMap.end();
Jason Lingc78bfc82020-11-05 18:58:16 -080069}
70
71std::vector<std::string> VersionBlobHandler::getBlobIds()
72{
William A. Kennington IIIabf17352020-12-22 21:07:11 -080073 std::vector<std::string> ret;
74 for (const auto& [key, _] : blobInfoMap)
75 {
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -080076 ret.emplace_back(key);
William A. Kennington IIIabf17352020-12-22 21:07:11 -080077 }
78 return ret;
Jason Lingc78bfc82020-11-05 18:58:16 -080079}
80
81/**
82 * deleteBlob - does nothing, always fails
83 */
Willy Tub487eb42021-09-16 21:44:43 -070084bool VersionBlobHandler::deleteBlob(const std::string&)
Jason Lingc78bfc82020-11-05 18:58:16 -080085{
86 return false;
87}
88
Willy Tub487eb42021-09-16 21:44:43 -070089bool VersionBlobHandler::stat(const std::string&, blobs::BlobMeta*)
Jason Lingc78bfc82020-11-05 18:58:16 -080090{
William A. Kennington IIIeba0c342021-01-12 14:23:01 -080091 return false;
Jason Lingc78bfc82020-11-05 18:58:16 -080092}
93
94bool VersionBlobHandler::open(uint16_t session, uint16_t flags,
95 const std::string& path)
96{
Jason Lingc78bfc82020-11-05 18:58:16 -080097 /* only reads are supported, check if blob is handled and make sure
98 * the blob isn't already opened
99 */
100 if (flags != blobs::read)
101 {
102 fprintf(stderr, "open %s fail: unsupported flags(0x%04X.)\n",
103 path.c_str(), flags);
Jason Lingc78bfc82020-11-05 18:58:16 -0800104 return false;
105 }
Jason Lingc78bfc82020-11-05 18:58:16 -0800106
William A. Kennington III9936c452020-12-23 23:31:23 -0800107 auto info = std::make_unique<SessionInfo>();
108 info->blob = blobInfoMap.at(path).get();
109 info->blob->sessionsToUpdate.emplace(info.get());
110 if (info->blob->sessionsToUpdate.size() == 1 &&
111 !info->blob->actions->onOpen->trigger())
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -0800112 {
113 fprintf(stderr, "open %s fail: onOpen trigger failed\n", path.c_str());
William A. Kennington III9936c452020-12-23 23:31:23 -0800114 info->blob->sessionsToUpdate.erase(info.get());
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -0800115 return false;
116 }
William A. Kennington III007c0162020-12-23 16:36:22 -0800117
William A. Kennington III9936c452020-12-23 23:31:23 -0800118 sessionInfoMap[session] = std::move(info);
William A. Kennington IIIb45eb5e2020-12-23 11:47:05 -0800119 return true;
Jason Lingc78bfc82020-11-05 18:58:16 -0800120}
121
122std::vector<uint8_t> VersionBlobHandler::read(uint16_t session, uint32_t offset,
123 uint32_t requestedSize)
124{
William A. Kennington III9936c452020-12-23 23:31:23 -0800125 auto& data = sessionInfoMap.at(session)->data;
William A. Kennington III0674a6d2021-01-12 14:25:41 -0800126 if (data == nullptr || !*data)
127 {
128 throw std::runtime_error("Version data not ready for read");
129 }
130 if ((*data)->size() < offset)
Jason Lingc78bfc82020-11-05 18:58:16 -0800131 {
Jason Lingc78bfc82020-11-05 18:58:16 -0800132 return {};
133 }
William A. Kennington III9936c452020-12-23 23:31:23 -0800134 std::vector<uint8_t> ret(
135 std::min<size_t>(requestedSize, (*data)->size() - offset));
136 std::memcpy(&ret[0], &(**data)[offset], ret.size());
137 return ret;
Jason Lingc78bfc82020-11-05 18:58:16 -0800138}
139
140bool VersionBlobHandler::close(uint16_t session)
141{
William A. Kennington III9936c452020-12-23 23:31:23 -0800142 auto it = sessionInfoMap.find(session);
143 if (it == sessionInfoMap.end())
Jason Lingc78bfc82020-11-05 18:58:16 -0800144 {
145 return false;
146 }
William A. Kennington III9936c452020-12-23 23:31:23 -0800147 auto& info = *it->second;
148 info.blob->sessionsToUpdate.erase(&info);
149 if (info.blob->sessionsToUpdate.empty())
150 {
151 info.blob->actions->onOpen->abort();
152 }
153 sessionInfoMap.erase(it);
154 return true;
Jason Lingc78bfc82020-11-05 18:58:16 -0800155}
William A. Kennington IIIc5b901d2020-12-23 17:07:20 -0800156
157bool VersionBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
158{
William A. Kennington IIIeba0c342021-01-12 14:23:01 -0800159 const auto& data = sessionInfoMap.at(session)->data;
160 if (data == nullptr)
161 {
162 meta->blobState = blobs::StateFlags::committing;
163 meta->size = 0;
164 }
165 else if (!*data)
166 {
167 meta->blobState = blobs::StateFlags::commit_error;
168 meta->size = 0;
169 }
170 else
171 {
Patrick Williams10388362023-05-10 07:51:09 -0500172 meta->blobState = blobs::StateFlags::committed |
173 blobs::StateFlags::open_read;
William A. Kennington IIIeba0c342021-01-12 14:23:01 -0800174 meta->size = (*data)->size();
175 }
176 return true;
William A. Kennington IIIc5b901d2020-12-23 17:07:20 -0800177}
178
179bool VersionBlobHandler::expire(uint16_t session)
180{
181 close(session);
182 return true;
183}
184
Jason Lingc78bfc82020-11-05 18:58:16 -0800185} // namespace ipmi_flash