blob: de91ae4da319e63191fb57e07dba95557948313d [file] [log] [blame]
Gaurav Gandhia49a3f72021-10-26 20:43:25 +00001// Copyright 2021 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "log_handler.hpp"
16
17#include <algorithm>
18#include <cstring>
19#include <ios>
20#include <limits>
21#include <memory>
22#include <optional>
23#include <utility>
24#include <vector>
25
26namespace ipmi_flash
27{
28
29LogBlobHandler::LogBlobHandler(std::vector<HandlerConfig<ActionPack>>&& configs)
30{
31 for (auto& config : configs)
32 {
33 auto info = std::make_unique<BlobInfo>();
34 info->blobId = std::move(config.blobId);
35 info->actions = std::move(config.actions);
36 info->handler = std::move(config.handler);
37 info->actions->onOpen->setCallback(
38 [infoP = info.get()](TriggerableActionInterface& tai) {
Patrick Williams42a44c22024-08-16 15:21:32 -040039 auto data =
40 std::make_shared<std::optional<std::vector<uint8_t>>>();
41 do
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000042 {
Patrick Williams42a44c22024-08-16 15:21:32 -040043 if (tai.status() != ActionStatus::success)
44 {
45 fprintf(stderr,
46 "LogBlobHandler: Log file unit failed for %s\n",
47 infoP->blobId.c_str());
48 continue;
49 }
50 if (!infoP->handler->open("", std::ios::in))
51 {
52 fprintf(
53 stderr,
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000054 "LogBlobHandler: Opening log file failed for %s\n",
55 infoP->blobId.c_str());
Patrick Williams42a44c22024-08-16 15:21:32 -040056 continue;
57 }
58 auto d = infoP->handler->read(
59 0, std::numeric_limits<uint32_t>::max());
60 infoP->handler->close();
61 if (!d)
62 {
63 fprintf(
64 stderr,
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000065 "LogBlobHandler: Reading log file failed for %s\n",
66 infoP->blobId.c_str());
Patrick Williams42a44c22024-08-16 15:21:32 -040067 continue;
68 }
69 *data = std::move(d);
70 } while (false);
71 for (auto sessionP : infoP->sessionsToUpdate)
72 {
73 sessionP->data = data;
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000074 }
Patrick Williams42a44c22024-08-16 15:21:32 -040075 infoP->sessionsToUpdate.clear();
76 });
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000077 if (!blobInfoMap.try_emplace(info->blobId, std::move(info)).second)
78 {
79 fprintf(stderr,
80 "LogBlobHandler: Ignoring duplicate config for %s\n",
81 info->blobId.c_str());
82 }
83 }
84}
85
86bool LogBlobHandler::canHandleBlob(const std::string& path)
87{
88 return blobInfoMap.find(path) != blobInfoMap.end();
89}
90
91std::vector<std::string> LogBlobHandler::getBlobIds()
92{
93 std::vector<std::string> ret;
94 for (const auto& [key, _] : blobInfoMap)
95 {
96 ret.emplace_back(key);
97 }
98 return ret;
99}
100
101/**
102 * deleteBlob - does nothing, always fails
103 */
104bool LogBlobHandler::deleteBlob(const std::string& path)
105{
106 for (const auto& [sessionId, sessionInfo] : sessionInfoMap)
107 {
108 if (sessionInfo->blob->blobId == path)
109 {
110 fprintf(stderr,
111 "LogBlobHandler: delete %s fail: there is an open session "
112 "for this blob\n",
113 path.c_str());
114 return false;
115 }
116 }
117
118 auto* blob = blobInfoMap.at(path).get();
119 if (!blob->actions->onDelete->trigger())
120 {
121 fprintf(stderr,
122 "LogBlobHandler: delete %s fail: onDelete trigger failed\n",
123 path.c_str());
124 return false;
125 }
126 return true;
127}
128
129bool LogBlobHandler::stat(const std::string&, blobs::BlobMeta*)
130{
131 return false;
132}
133
134bool LogBlobHandler::open(uint16_t session, uint16_t flags,
135 const std::string& path)
136{
137 /* only reads are supported, check if blob is handled and make sure
138 * the blob isn't already opened
139 */
140 if (flags != blobs::read)
141 {
142 fprintf(stderr,
143 "LogBlobHandler: open %s fail: unsupported flags(0x%04X.)\n",
144 path.c_str(), flags);
145 return false;
146 }
147
148 auto info = std::make_unique<SessionInfo>();
149 info->blob = blobInfoMap.at(path).get();
150 info->blob->sessionsToUpdate.emplace(info.get());
151 if (info->blob->sessionsToUpdate.size() == 1 &&
152 !info->blob->actions->onOpen->trigger())
153 {
154 fprintf(stderr, "LogBlobHandler: open %s fail: onOpen trigger failed\n",
155 path.c_str());
156 info->blob->sessionsToUpdate.erase(info.get());
157 return false;
158 }
159
160 sessionInfoMap[session] = std::move(info);
161 return true;
162}
163
164std::vector<uint8_t> LogBlobHandler::read(uint16_t session, uint32_t offset,
165 uint32_t requestedSize)
166{
167 auto& data = sessionInfoMap.at(session)->data;
168 if (data == nullptr || !*data)
169 {
170 throw std::runtime_error("LogBlobHandler: Log data not ready for read");
171 }
172 if ((*data)->size() < offset)
173 {
174 return {};
175 }
176 std::vector<uint8_t> ret(
177 std::min<size_t>(requestedSize, (*data)->size() - offset));
178 std::memcpy(&ret[0], &(**data)[offset], ret.size());
179 return ret;
180}
181
182bool LogBlobHandler::close(uint16_t session)
183{
184 auto it = sessionInfoMap.find(session);
185 if (it == sessionInfoMap.end())
186 {
187 return false;
188 }
189 auto& info = *it->second;
190 info.blob->sessionsToUpdate.erase(&info);
191 if (info.blob->sessionsToUpdate.empty())
192 {
193 info.blob->actions->onOpen->abort();
194 }
195 sessionInfoMap.erase(it);
196 return true;
197}
198
199bool LogBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
200{
201 const auto& data = sessionInfoMap.at(session)->data;
202 if (data == nullptr)
203 {
204 meta->blobState = blobs::StateFlags::committing;
205 meta->size = 0;
206 }
207 else if (!*data)
208 {
209 meta->blobState = blobs::StateFlags::commit_error;
210 meta->size = 0;
211 }
212 else
213 {
Patrick Williams10388362023-05-10 07:51:09 -0500214 meta->blobState = blobs::StateFlags::committed |
215 blobs::StateFlags::open_read;
Gaurav Gandhia49a3f72021-10-26 20:43:25 +0000216 meta->size = (*data)->size();
217 }
218 return true;
219}
220
221bool LogBlobHandler::expire(uint16_t session)
222{
223 close(session);
224 return true;
225}
226
227} // namespace ipmi_flash