tools: blob: add exceptions
Add exceptions on failures where it's a clean failure path.
Change-Id: Iaa8b6c7a0914367866092a7e31899453183fd7b2
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/test/tools_updater_unittest.cpp b/test/tools_updater_unittest.cpp
index d36304b..bc7417c 100644
--- a/test/tools_updater_unittest.cpp
+++ b/test/tools_updater_unittest.cpp
@@ -17,8 +17,9 @@
BlobInterfaceMock blobMock;
std::string firmwareImage = "image.bin";
std::string signatureFile = "image.sig";
+ std::string expectedBlob = "/flash/image";
- std::vector<std::string> blobList = {"/flash/image"};
+ std::vector<std::string> blobList = {expectedBlob};
StatResponse statObj;
statObj.blob_state = blobs::FirmwareBlobHandler::UpdateFlags::ipmi |
blobs::FirmwareBlobHandler::UpdateFlags::lpc;
@@ -29,12 +30,11 @@
EXPECT_CALL(blobMock, getBlobList()).WillOnce(Return(blobList));
- EXPECT_CALL(blobMock, getStat(StrEq(blobList[0].c_str())))
- .WillOnce(Return(statObj));
+ EXPECT_CALL(blobMock, getStat(Eq(expectedBlob))).WillOnce(Return(statObj));
EXPECT_CALL(handlerMock, supportedType()).WillOnce(Return(supported));
- EXPECT_CALL(blobMock, openBlob(StrEq(blobList[0].c_str()), Eq(supported)))
+ EXPECT_CALL(blobMock, openBlob(StrEq(expectedBlob.c_str()), Eq(supported)))
.WillOnce(Return(session));
EXPECT_CALL(handlerMock,
diff --git a/tools/blob_handler.cpp b/tools/blob_handler.cpp
index 43fc891..62bbb4d 100644
--- a/tools/blob_handler.cpp
+++ b/tools/blob_handler.cpp
@@ -56,8 +56,7 @@
}
catch (const IpmiException& e)
{
- std::fprintf(stderr, "Received exception: %s\n", e.what());
- return {};
+ throw BlobException(e.what());
}
/* IPMI_CC was OK, and it returned no bytes, so let's be happy with that for
@@ -75,16 +74,14 @@
*/
if (reply.size() < headerSize)
{
- std::fprintf(stderr, "Invalid response length\n");
- return {};
+ throw BlobException("Invalid response length");
}
/* Verify the OEN. */
if (std::memcmp(ipmiPhosphorOen.data(), reply.data(),
ipmiPhosphorOen.size()) != 0)
{
- std::fprintf(stderr, "Invalid OEN received\n");
- return {};
+ throw BlobException("Invalid OEN received");
}
/* Validate CRC. */
@@ -106,7 +103,7 @@
{
std::fprintf(stderr, "Invalid CRC, received: 0x%x, computed: 0x%x\n",
crc, computed);
- return {};
+ throw BlobException("Invalid CRC on received data.");
}
return bytes;
@@ -115,14 +112,23 @@
int BlobHandler::getBlobCount()
{
std::uint32_t count;
- auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobGetCount, {});
- if (resp.size() != sizeof(count))
+ try
+ {
+ auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobGetCount, {});
+ if (resp.size() != sizeof(count))
+ {
+ return 0;
+ }
+
+ /* LE to LE (need to make this portable as some point. */
+ std::memcpy(&count, resp.data(), sizeof(count));
+ }
+ catch (const BlobException& b)
{
return 0;
}
- /* LE to LE (need to make this portable as some point. */
- std::memcpy(&count, resp.data(), sizeof(count));
+ std::fprintf(stderr, "BLOB Count: %d\n", count);
return count;
}
@@ -130,11 +136,19 @@
{
std::vector<std::uint8_t> payload;
std::uint8_t* data = reinterpret_cast<std::uint8_t*>(&index);
+
std::copy(data, data + sizeof(std::uint32_t), std::back_inserter(payload));
- auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobEnumerate, payload);
- return (resp.size() > 0) ? std::string(&resp[0], &resp[resp.size() - 1])
- : "";
+ try
+ {
+ auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobEnumerate, payload);
+ return (resp.size() > 0) ? std::string(&resp[0], &resp[resp.size() - 1])
+ : "";
+ }
+ catch (const BlobException& b)
+ {
+ return "";
+ }
}
std::vector<std::string> BlobHandler::getBlobList()
@@ -158,11 +172,20 @@
StatResponse BlobHandler::getStat(const std::string& id)
{
StatResponse meta;
- std::vector<std::uint8_t> name;
+ std::vector<std::uint8_t> name, resp;
+
std::copy(id.begin(), id.end(), std::back_inserter(name));
name.push_back(0x00); /* need to add nul-terminator. */
- auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobStat, name);
+ try
+ {
+ resp = sendIpmiPayload(BlobOEMCommands::bmcBlobStat, name);
+ }
+ catch (const BlobException& b)
+ {
+ throw;
+ }
+
std::memcpy(&meta.blob_state, &resp[0], sizeof(meta.blob_state));
std::memcpy(&meta.size, &resp[sizeof(meta.blob_state)], sizeof(meta.size));
int offset = sizeof(meta.blob_state) + sizeof(meta.size);
@@ -181,16 +204,25 @@
blobs::FirmwareBlobHandler::UpdateFlags handlerFlags)
{
std::uint16_t session;
- std::vector<std::uint8_t> request;
+ std::vector<std::uint8_t> request, resp;
std::uint16_t flags =
blobs::FirmwareBlobHandler::UpdateFlags::openWrite | handlerFlags;
auto addrFlags = reinterpret_cast<std::uint8_t*>(&flags);
+
std::copy(addrFlags, addrFlags + sizeof(flags),
std::back_inserter(request));
std::copy(id.begin(), id.end(), std::back_inserter(request));
request.push_back(0x00); /* need to add nul-terminator. */
- auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobOpen, request);
+ try
+ {
+ resp = sendIpmiPayload(BlobOEMCommands::bmcBlobOpen, request);
+ }
+ catch (const BlobException& b)
+ {
+ throw;
+ }
+
if (resp.size() != sizeof(session))
{
throw BlobException("Did not receive session.");
diff --git a/tools/blob_handler.hpp b/tools/blob_handler.hpp
index bcac0a8..73f0d94 100644
--- a/tools/blob_handler.hpp
+++ b/tools/blob_handler.hpp
@@ -30,6 +30,7 @@
* @param[in] command - the blob command.
* @param[in] payload - the payload bytes.
* @return the bytes returned from the ipmi interface.
+ * @throws BlobException.
*/
std::vector<std::uint8_t>
sendIpmiPayload(BlobOEMCommands command,
@@ -51,7 +52,15 @@
std::string enumerateBlob(std::uint32_t index);
std::vector<std::string> getBlobList() override;
+
+ /**
+ * @throws BlobException.
+ */
StatResponse getStat(const std::string& id) override;
+
+ /**
+ * @throws BlobException.
+ */
std::uint16_t
openBlob(const std::string& id,
blobs::FirmwareBlobHandler::UpdateFlags handlerFlags) override;
diff --git a/tools/updater.cpp b/tools/updater.cpp
index b9574d8..b7ea191 100644
--- a/tools/updater.cpp
+++ b/tools/updater.cpp
@@ -20,6 +20,7 @@
#include "tool_errors.hpp"
#include <algorithm>
+#include <cstring>
#include <memory>
void updaterMain(BlobInterface* blob, DataInterface* handler,
@@ -36,7 +37,15 @@
* available and use it.
*/
std::vector<std::string> blobs = blob->getBlobList();
- auto blobInst = std::find(blobs.begin(), blobs.end(), goalFirmware);
+ auto blobInst = std::find_if(
+ blobs.begin(), blobs.end(), [&goalFirmware](const auto& iter) {
+ /* Running into weird scenarios where the string comparison doesn't
+ * work. TODO: revisit.
+ */
+ return (0 == std::memcmp(goalFirmware.c_str(), iter.c_str(),
+ goalFirmware.length()));
+ // return (goalFirmware.compare(iter));
+ });
if (blobInst == blobs.end())
{
throw ToolException(goalFirmware + " not found");
@@ -45,7 +54,17 @@
/* Call stat on /flash/image (or /flash/tarball) and check if data interface
* is supported.
*/
- auto stat = blob->getStat(goalFirmware);
+ StatResponse stat;
+ try
+ {
+ stat = blob->getStat(goalFirmware);
+ }
+ catch (const BlobException& b)
+ {
+ throw ToolException("blob exception received: " +
+ std::string(b.what()));
+ }
+
auto supported = handler->supportedType();
if ((stat.blob_state & supported) == 0)
{
@@ -64,8 +83,6 @@
std::string(b.what()));
}
- std::fprintf(stderr, "using session: %d\n", session);
-
/* Send over the firmware image. */
if (!handler->sendContents(imagePath, session))
{