tools: Add handle for automatically closing blobs
This makes it harder to accidentally leak blob handles and cleans up the
code a little bit.
Change-Id: I49a1606a3360e6439a8c3d426de7006a138d330c
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/tools/handler.cpp b/tools/handler.cpp
index 8cd7a99..293c4e6 100644
--- a/tools/handler.cpp
+++ b/tools/handler.cpp
@@ -23,6 +23,7 @@
#include "util.hpp"
#include <ipmiblob/blob_errors.hpp>
+#include <stdplus/handle/managed.hpp>
#include <algorithm>
#include <cstdint>
@@ -33,6 +34,20 @@
namespace host_tool
{
+static void closeBlob(uint16_t&& session, ipmiblob::BlobInterface*& blob)
+{
+ blob->closeBlob(session);
+}
+
+using BlobHandle =
+ stdplus::Managed<uint16_t, ipmiblob::BlobInterface*>::Handle<closeBlob>;
+
+template <typename... Args>
+inline BlobHandle openBlob(ipmiblob::BlobInterface* blob, Args&&... args)
+{
+ return BlobHandle(blob->openBlob(std::forward<Args>(args)...), blob);
+}
+
bool UpdateHandler::checkAvailable(const std::string& goalFirmware)
{
std::vector<std::string> blobs = blob->getBlobList();
@@ -57,170 +72,104 @@
void UpdateHandler::sendFile(const std::string& target, const std::string& path)
{
- std::uint16_t session;
auto supported = handler->supportedType();
try
{
- session = blob->openBlob(
- target, static_cast<std::uint16_t>(supported) |
- static_cast<std::uint16_t>(
- ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
+ auto session = openBlob(
+ blob, target,
+ static_cast<std::uint16_t>(supported) |
+ static_cast<std::uint16_t>(
+ ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
+
+ if (!handler->sendContents(path, *session))
+ {
+ throw ToolException("Failed to send contents of " + path);
+ }
}
catch (const ipmiblob::BlobException& b)
{
throw ToolException("blob exception received: " +
std::string(b.what()));
}
-
- if (!handler->sendContents(path, session))
- {
- /* Need to close the session on failure, or it's stuck open (until the
- * blob handler timeout is implemented, and even then, why make it wait.
- */
- blob->closeBlob(session);
- throw ToolException("Failed to send contents of " + path);
- }
-
- blob->closeBlob(session);
}
bool UpdateHandler::verifyFile(const std::string& target, bool ignoreStatus)
{
- std::uint16_t session;
- bool success = false;
-
try
{
- session = blob->openBlob(
- target, static_cast<std::uint16_t>(
- ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
+ auto session =
+ openBlob(blob, target,
+ static_cast<std::uint16_t>(
+ ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
+
+ std::fprintf(stderr, "Committing to %s to trigger service\n",
+ target.c_str());
+ blob->commit(*session, {});
+
+ if (ignoreStatus)
+ {
+ // Skip checking the blob for status if ignoreStatus is enabled
+ return true;
+ }
+
+ std::fprintf(stderr, "Calling stat on %s session to check status\n",
+ target.c_str());
+ return pollStatus(*session, blob);
}
catch (const ipmiblob::BlobException& b)
{
throw ToolException("blob exception received: " +
std::string(b.what()));
}
-
- std::fprintf(stderr, "Committing to %s to trigger service\n",
- target.c_str());
-
- try
- {
- blob->commit(session, {});
- }
- catch (const ipmiblob::BlobException& b)
- {
- blob->closeBlob(session);
- throw ToolException("blob exception received: " +
- std::string(b.what()));
- }
-
- if (ignoreStatus)
- {
- // Skip checking the blob for status if ignoreStatus is enabled
- blob->closeBlob(session);
- return true;
- }
-
- std::fprintf(stderr, "Calling stat on %s session to check status\n",
- target.c_str());
-
- if (pollStatus(session, blob))
- {
- std::fprintf(stderr, "Returned success\n");
- success = true;
- }
- else
- {
- std::fprintf(stderr, "Returned non-success (could still "
- "be running (unlikely))\n");
- }
-
- blob->closeBlob(session);
- return (success == true);
}
std::vector<uint8_t> UpdateHandler::readVersion(const std::string& versionBlob)
{
- std::uint16_t session;
-
try
{
- session = blob->openBlob(
- versionBlob, static_cast<std::uint16_t>(
- ipmi_flash::FirmwareFlags::UpdateFlags::openRead));
+ auto session =
+ openBlob(blob, versionBlob,
+ static_cast<std::uint16_t>(
+ ipmi_flash::FirmwareFlags::UpdateFlags::openRead));
+
+ std::fprintf(stderr, "Calling stat on %s session to check status\n",
+ versionBlob.c_str());
+
+ /* TODO: call readBytes multiple times in case IPMI message length
+ * exceeds IPMI_MAX_MSG_LENGTH.
+ */
+ auto pollResp = pollReadReady(*session, blob);
+ if (pollResp.first && pollResp.second > 0)
+ {
+ return blob->readBytes(*session, 0, pollResp.second);
+ }
+ return {};
}
catch (const ipmiblob::BlobException& b)
{
throw ToolException("blob exception received: " +
std::string(b.what()));
}
-
- std::fprintf(stderr, "Calling stat on %s session to check status\n",
- versionBlob.c_str());
- std::vector<uint8_t> data;
-
- /* TODO: call readBytes multiple times in case IPMI message length exceeds
- * IPMI_MAX_MSG_LENGTH.
- */
- auto pollResp = pollReadReady(session, blob);
- if (pollResp.first)
- {
- std::fprintf(stderr, "Returned success\n");
- if (pollResp.second > 0)
- {
- try
- {
- data = blob->readBytes(session, 0, pollResp.second);
- }
- catch (const ipmiblob::BlobException& b)
- {
- blob->closeBlob(session);
- throw ToolException("blob exception received: " +
- std::string(b.what()));
- }
- }
- }
- else
- {
- std::fprintf(stderr, "Returned non-success (could still "
- "be running (unlikely))\n");
- }
-
- blob->closeBlob(session);
- return data;
}
void UpdateHandler::cleanArtifacts()
{
- /* open(), commit(), close() */
- std::uint16_t session;
-
/* Errors aren't important for this call. */
try
{
std::fprintf(stderr, "Opening the cleanup blob\n");
- session = blob->openBlob(
- ipmi_flash::cleanupBlobId,
- static_cast<std::uint16_t>(
- ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
- }
- catch (...)
- {
- return;
- }
+ auto session =
+ openBlob(blob, ipmi_flash::cleanupBlobId,
+ static_cast<std::uint16_t>(
+ ipmi_flash::FirmwareFlags::UpdateFlags::openWrite));
- try
- {
std::fprintf(stderr, "Committing to the cleanup blob\n");
- blob->commit(session, {});
+ blob->commit(*session, {});
std::fprintf(stderr, "Closing cleanup blob\n");
}
catch (...)
{}
-
- blob->closeBlob(session);
}
} // namespace host_tool