blob: d241b9fc391163a5e1bc548b0719740fa72170f9 [file] [log] [blame]
Patrick Venture01123b22019-06-20 13:49:06 -07001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "handler.hpp"
18
Patrick Venture84778b82019-06-26 20:11:09 -070019#include "flags.hpp"
Patrick Venture01123b22019-06-20 13:49:06 -070020#include "helper.hpp"
21#include "status.hpp"
22#include "tool_errors.hpp"
23#include "util.hpp"
24
Patrick Venture9b37b092020-05-28 20:58:57 -070025#include <ipmiblob/blob_errors.hpp>
William A. Kennington III43eeeb32021-10-14 01:49:34 -070026#include <stdplus/handle/managed.hpp>
Patrick Venture9b37b092020-05-28 20:58:57 -070027
Patrick Venture01123b22019-06-20 13:49:06 -070028#include <algorithm>
Patrick Venture01123b22019-06-20 13:49:06 -070029#include <cstdint>
30#include <cstring>
Patrick Venture01123b22019-06-20 13:49:06 -070031#include <string>
32#include <vector>
33
34namespace host_tool
35{
36
William A. Kennington III43eeeb32021-10-14 01:49:34 -070037static void closeBlob(uint16_t&& session, ipmiblob::BlobInterface*& blob)
38{
39 blob->closeBlob(session);
40}
41
42using BlobHandle =
43 stdplus::Managed<uint16_t, ipmiblob::BlobInterface*>::Handle<closeBlob>;
44
45template <typename... Args>
46inline BlobHandle openBlob(ipmiblob::BlobInterface* blob, Args&&... args)
47{
48 return BlobHandle(blob->openBlob(std::forward<Args>(args)...), blob);
49}
50
Patrick Venture01123b22019-06-20 13:49:06 -070051bool UpdateHandler::checkAvailable(const std::string& goalFirmware)
52{
53 std::vector<std::string> blobs = blob->getBlobList();
54
Patrick Williams10388362023-05-10 07:51:09 -050055 auto blobInst = std::find_if(blobs.begin(), blobs.end(),
56 [&goalFirmware](const std::string& iter) {
57 /* Running into weird scenarios where the string comparison doesn't
58 * work. TODO: revisit.
59 */
60 return (0 == std::memcmp(goalFirmware.c_str(), iter.c_str(),
61 goalFirmware.length()));
62 // return (goalFirmware.compare(iter));
63 });
Patrick Venture01123b22019-06-20 13:49:06 -070064 if (blobInst == blobs.end())
65 {
66 std::fprintf(stderr, "%s not found\n", goalFirmware.c_str());
67 return false;
68 }
69
Patrick Venture01123b22019-06-20 13:49:06 -070070 return true;
71}
72
Willy Tu1b23b772023-03-15 01:33:03 -070073void UpdateHandler::retrySendFile(const std::string& target,
74 const std::string& path)
Patrick Venture01123b22019-06-20 13:49:06 -070075{
Patrick Venture01123b22019-06-20 13:49:06 -070076 auto supported = handler->supportedType();
Willy Tu1b23b772023-03-15 01:33:03 -070077 auto session =
78 openBlob(blob, target,
79 static_cast<std::uint16_t>(supported) |
80 static_cast<std::uint16_t>(
81 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
Patrick Venture01123b22019-06-20 13:49:06 -070082
Willy Tu1b23b772023-03-15 01:33:03 -070083 if (!handler->sendContents(path, *session))
Patrick Venture01123b22019-06-20 13:49:06 -070084 {
Willy Tu1b23b772023-03-15 01:33:03 -070085 throw ToolException("Failed to send contents of " + path);
Patrick Venture01123b22019-06-20 13:49:06 -070086 }
Willy Tu1b23b772023-03-15 01:33:03 -070087}
88
89void UpdateHandler::sendFile(const std::string& target, const std::string& path)
90{
91 const uint8_t retryCount = 3;
92 uint8_t i = 1;
93 while (true)
Patrick Venture01123b22019-06-20 13:49:06 -070094 {
Willy Tu1b23b772023-03-15 01:33:03 -070095 try
96 {
97 retrySendFile(target, path);
98 return;
99 }
100 catch (const ipmiblob::BlobException& b)
101 {
102 throw ToolException("blob exception received: " +
103 std::string(b.what()));
104 }
105 catch (const ToolException& t)
106 {
107 uint8_t remains = retryCount - i;
108 std::fprintf(
109 stderr,
110 "tool exception received: %s: Retrying it %u more times\n",
111 t.what(), remains);
112 if (remains == 0)
113 throw;
114 }
115 ++i;
Patrick Venture01123b22019-06-20 13:49:06 -0700116 }
Patrick Venture01123b22019-06-20 13:49:06 -0700117}
118
Brandon Kim6749ba12019-09-19 13:31:37 -0700119bool UpdateHandler::verifyFile(const std::string& target, bool ignoreStatus)
Patrick Venture01123b22019-06-20 13:49:06 -0700120{
Patrick Venture01123b22019-06-20 13:49:06 -0700121 try
122 {
William A. Kennington III43eeeb32021-10-14 01:49:34 -0700123 auto session =
124 openBlob(blob, target,
125 static_cast<std::uint16_t>(
126 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
127
128 std::fprintf(stderr, "Committing to %s to trigger service\n",
129 target.c_str());
130 blob->commit(*session, {});
131
132 if (ignoreStatus)
133 {
134 // Skip checking the blob for status if ignoreStatus is enabled
135 return true;
136 }
137
138 std::fprintf(stderr, "Calling stat on %s session to check status\n",
139 target.c_str());
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700140 pollStatus(*session, blob);
141 return true;
Patrick Venture01123b22019-06-20 13:49:06 -0700142 }
143 catch (const ipmiblob::BlobException& b)
144 {
145 throw ToolException("blob exception received: " +
146 std::string(b.what()));
147 }
Patrick Venture01123b22019-06-20 13:49:06 -0700148}
149
Jie Yang328f5202021-03-16 00:52:07 -0700150std::vector<uint8_t> UpdateHandler::readVersion(const std::string& versionBlob)
151{
Jie Yang328f5202021-03-16 00:52:07 -0700152 try
153 {
William A. Kennington III43eeeb32021-10-14 01:49:34 -0700154 auto session =
155 openBlob(blob, versionBlob,
156 static_cast<std::uint16_t>(
157 ipmi_flash::FirmwareFlags::UpdateFlags::openRead));
158
159 std::fprintf(stderr, "Calling stat on %s session to check status\n",
160 versionBlob.c_str());
161
162 /* TODO: call readBytes multiple times in case IPMI message length
163 * exceeds IPMI_MAX_MSG_LENGTH.
164 */
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700165 auto size = pollReadReady(*session, blob);
166 if (size > 0)
William A. Kennington III43eeeb32021-10-14 01:49:34 -0700167 {
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700168 return blob->readBytes(*session, 0, size);
William A. Kennington III43eeeb32021-10-14 01:49:34 -0700169 }
170 return {};
Jie Yang328f5202021-03-16 00:52:07 -0700171 }
172 catch (const ipmiblob::BlobException& b)
173 {
174 throw ToolException("blob exception received: " +
175 std::string(b.what()));
176 }
Jie Yang328f5202021-03-16 00:52:07 -0700177}
178
Patrick Venture01123b22019-06-20 13:49:06 -0700179void UpdateHandler::cleanArtifacts()
180{
Patrick Venture01123b22019-06-20 13:49:06 -0700181 /* Errors aren't important for this call. */
182 try
183 {
William A. Kennington III4b0c2ec2021-10-14 02:04:14 -0700184 std::fprintf(stderr, "Executing cleanup blob\n");
William A. Kennington III43eeeb32021-10-14 01:49:34 -0700185 auto session =
186 openBlob(blob, ipmi_flash::cleanupBlobId,
187 static_cast<std::uint16_t>(
188 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
William A. Kennington III43eeeb32021-10-14 01:49:34 -0700189 blob->commit(*session, {});
Patrick Venture01123b22019-06-20 13:49:06 -0700190 }
William A. Kennington III4b0c2ec2021-10-14 02:04:14 -0700191 catch (const std::exception& e)
192 {
193 std::fprintf(stderr, "Cleanup failed: %s\n", e.what());
194 }
Patrick Venture01123b22019-06-20 13:49:06 -0700195}
196
197} // namespace host_tool