blob: 9a0d296a6e73365b53cfc0caae0f7b7d251c7222 [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 Williams10388362023-05-10 07:51:09 -050039 auto data = std::make_shared<std::optional<std::vector<uint8_t>>>();
40 do
41 {
42 if (tai.status() != ActionStatus::success)
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000043 {
Patrick Williams10388362023-05-10 07:51:09 -050044 fprintf(stderr,
45 "LogBlobHandler: Log file unit failed for %s\n",
46 infoP->blobId.c_str());
47 continue;
48 }
49 if (!infoP->handler->open("", std::ios::in))
50 {
51 fprintf(stderr,
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000052 "LogBlobHandler: Opening log file failed for %s\n",
53 infoP->blobId.c_str());
Patrick Williams10388362023-05-10 07:51:09 -050054 continue;
55 }
56 auto d = infoP->handler->read(
57 0, std::numeric_limits<uint32_t>::max());
58 infoP->handler->close();
59 if (!d)
60 {
61 fprintf(stderr,
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000062 "LogBlobHandler: Reading log file failed for %s\n",
63 infoP->blobId.c_str());
Patrick Williams10388362023-05-10 07:51:09 -050064 continue;
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000065 }
Patrick Williams10388362023-05-10 07:51:09 -050066 *data = std::move(d);
67 } while (false);
68 for (auto sessionP : infoP->sessionsToUpdate)
69 {
70 sessionP->data = data;
71 }
72 infoP->sessionsToUpdate.clear();
73 });
Gaurav Gandhia49a3f72021-10-26 20:43:25 +000074 if (!blobInfoMap.try_emplace(info->blobId, std::move(info)).second)
75 {
76 fprintf(stderr,
77 "LogBlobHandler: Ignoring duplicate config for %s\n",
78 info->blobId.c_str());
79 }
80 }
81}
82
83bool LogBlobHandler::canHandleBlob(const std::string& path)
84{
85 return blobInfoMap.find(path) != blobInfoMap.end();
86}
87
88std::vector<std::string> LogBlobHandler::getBlobIds()
89{
90 std::vector<std::string> ret;
91 for (const auto& [key, _] : blobInfoMap)
92 {
93 ret.emplace_back(key);
94 }
95 return ret;
96}
97
98/**
99 * deleteBlob - does nothing, always fails
100 */
101bool LogBlobHandler::deleteBlob(const std::string& path)
102{
103 for (const auto& [sessionId, sessionInfo] : sessionInfoMap)
104 {
105 if (sessionInfo->blob->blobId == path)
106 {
107 fprintf(stderr,
108 "LogBlobHandler: delete %s fail: there is an open session "
109 "for this blob\n",
110 path.c_str());
111 return false;
112 }
113 }
114
115 auto* blob = blobInfoMap.at(path).get();
116 if (!blob->actions->onDelete->trigger())
117 {
118 fprintf(stderr,
119 "LogBlobHandler: delete %s fail: onDelete trigger failed\n",
120 path.c_str());
121 return false;
122 }
123 return true;
124}
125
126bool LogBlobHandler::stat(const std::string&, blobs::BlobMeta*)
127{
128 return false;
129}
130
131bool LogBlobHandler::open(uint16_t session, uint16_t flags,
132 const std::string& path)
133{
134 /* only reads are supported, check if blob is handled and make sure
135 * the blob isn't already opened
136 */
137 if (flags != blobs::read)
138 {
139 fprintf(stderr,
140 "LogBlobHandler: open %s fail: unsupported flags(0x%04X.)\n",
141 path.c_str(), flags);
142 return false;
143 }
144
145 auto info = std::make_unique<SessionInfo>();
146 info->blob = blobInfoMap.at(path).get();
147 info->blob->sessionsToUpdate.emplace(info.get());
148 if (info->blob->sessionsToUpdate.size() == 1 &&
149 !info->blob->actions->onOpen->trigger())
150 {
151 fprintf(stderr, "LogBlobHandler: open %s fail: onOpen trigger failed\n",
152 path.c_str());
153 info->blob->sessionsToUpdate.erase(info.get());
154 return false;
155 }
156
157 sessionInfoMap[session] = std::move(info);
158 return true;
159}
160
161std::vector<uint8_t> LogBlobHandler::read(uint16_t session, uint32_t offset,
162 uint32_t requestedSize)
163{
164 auto& data = sessionInfoMap.at(session)->data;
165 if (data == nullptr || !*data)
166 {
167 throw std::runtime_error("LogBlobHandler: Log data not ready for read");
168 }
169 if ((*data)->size() < offset)
170 {
171 return {};
172 }
173 std::vector<uint8_t> ret(
174 std::min<size_t>(requestedSize, (*data)->size() - offset));
175 std::memcpy(&ret[0], &(**data)[offset], ret.size());
176 return ret;
177}
178
179bool LogBlobHandler::close(uint16_t session)
180{
181 auto it = sessionInfoMap.find(session);
182 if (it == sessionInfoMap.end())
183 {
184 return false;
185 }
186 auto& info = *it->second;
187 info.blob->sessionsToUpdate.erase(&info);
188 if (info.blob->sessionsToUpdate.empty())
189 {
190 info.blob->actions->onOpen->abort();
191 }
192 sessionInfoMap.erase(it);
193 return true;
194}
195
196bool LogBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
197{
198 const auto& data = sessionInfoMap.at(session)->data;
199 if (data == nullptr)
200 {
201 meta->blobState = blobs::StateFlags::committing;
202 meta->size = 0;
203 }
204 else if (!*data)
205 {
206 meta->blobState = blobs::StateFlags::commit_error;
207 meta->size = 0;
208 }
209 else
210 {
Patrick Williams10388362023-05-10 07:51:09 -0500211 meta->blobState = blobs::StateFlags::committed |
212 blobs::StateFlags::open_read;
Gaurav Gandhia49a3f72021-10-26 20:43:25 +0000213 meta->size = (*data)->size();
214 }
215 return true;
216}
217
218bool LogBlobHandler::expire(uint16_t session)
219{
220 close(session);
221 return true;
222}
223
224} // namespace ipmi_flash