tools: blob: implement get blob stat command

The firmware update process requires implementing the stat command, so
that one can verify the firmware mechanism requested is available.

Change-Id: I582f344124767975ee305c420657f991d2223889
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/tools/blob_handler.cpp b/tools/blob_handler.cpp
index e05da90..a30eb9e 100644
--- a/tools/blob_handler.cpp
+++ b/tools/blob_handler.cpp
@@ -149,3 +149,23 @@
 
     return list;
 }
+
+StatResponse BlobHandler::getStat(const std::string& id)
+{
+    StatResponse meta;
+    std::vector<std::uint8_t> name;
+    std::copy(id.begin(), id.end(), std::back_inserter(name));
+
+    auto resp = sendIpmiPayload(BlobOEMCommands::bmcBlobStat, name);
+    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);
+    std::uint8_t len = resp[offset];
+    if (len > 0)
+    {
+        std::copy(&resp[offset + 1], &resp[resp.size()],
+                  std::back_inserter(meta.metadata));
+    }
+
+    return meta;
+}
diff --git a/tools/blob_handler.hpp b/tools/blob_handler.hpp
index fb2dcb5..fbc6fcb 100644
--- a/tools/blob_handler.hpp
+++ b/tools/blob_handler.hpp
@@ -51,6 +51,7 @@
     std::string enumerateBlob(std::uint32_t index);
 
     std::vector<std::string> getBlobList() override;
+    StatResponse getStat(const std::string& id) override;
 
   private:
     IpmiInterface* ipmi;
diff --git a/tools/blob_interface.hpp b/tools/blob_interface.hpp
index ce2b2d7..9b0ff7d 100644
--- a/tools/blob_interface.hpp
+++ b/tools/blob_interface.hpp
@@ -3,9 +3,15 @@
 #include <string>
 #include <vector>
 
+struct StatResponse
+{
+    std::uint16_t blob_state;
+    std::uint32_t size;
+    std::vector<std::uint8_t> metadata;
+};
+
 class BlobInterface
 {
-
   public:
     virtual ~BlobInterface() = default;
 
@@ -15,4 +21,12 @@
      * @return list of strings, each representing a blob_id returned.
      */
     virtual std::vector<std::string> getBlobList() = 0;
+
+    /**
+     * Get the stat() on the blob_id.
+     *
+     * @param[in] id - the blob_id.
+     * @return metadata structure.
+     */
+    virtual StatResponse getStat(const std::string& id) = 0;
 };
diff --git a/tools/updater.cpp b/tools/updater.cpp
index 817b6f1..7b5ec0f 100644
--- a/tools/updater.cpp
+++ b/tools/updater.cpp
@@ -27,8 +27,12 @@
      */
     std::string goalFirmware = "/flash/image";
 
+    /* Get list of blob_ids, check for /flash/image, or /flash/tarball.
+     * TODO(venture) the mechanism doesn't care, but the caller of burn_my_bmc
+     * will have in mind which they're sending and we need to verify it's
+     * available and use it.
+     */
     std::vector<std::string> blobs = blob->getBlobList();
-
     auto blobInst = std::find(blobs.begin(), blobs.end(), goalFirmware);
     if (blobInst == blobs.end())
     {
@@ -36,15 +40,10 @@
         return -1; /* throw custom exception. */
     }
 
-    /* Get list of blob_ids, check for /flash/image, or /flash/tarball.
-     * TODO(venture) the mechanism doesn't care, but the caller of burn_my_bmc
-     * will have in mind which they're sending and we need to verify it's
-     * available and use it.
-     */
-
     /* Call stat on /flash/image (or /flash/tarball) and check if data interface
      * is supported.
      */
+    auto stat = blob->getStat(goalFirmware);
 
     return 0;
 }