tools: starting burn_my_bmc host utility

burn_my_bmc is a host-run utility that in cooperation with the
phosphor-ipmi-flash library, attempts to send a BMC firmware image and
signature file to the BMC and trigger verification of said image.

The program's current design and use were tailored towards the legacy
OpenBMC image and not UBI.  Therefore, changes to support the UBI
process will get addressed as it all takes shape.

The overall process is:
1) Attempts to send firmware image over an interface.
2) Attempts to send signature file contents over an interface*.
3) Triggers a verification step.
4) Reboots the BMC**.

* The only interface in the initial version here is the blocktransfer
interface.  It's technically also possibly KCS.  It's sending the data
over the same communications channel as the normal IPMI packets.  A
later patchset will enable sending the data bytes over an LPC memory
region or the PCI P2A region.

** The 4th step is done by a separate call to the 'reboot' command.
The 'reboot' and 'ping' commands will come in a later patchset.

Change-Id: I62d725274e56c55ca414fa6c2a3eab6c500066ed
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/tools/updater.cpp b/tools/updater.cpp
new file mode 100644
index 0000000..c012c76
--- /dev/null
+++ b/tools/updater.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "updater.hpp"
+
+#include "bt.hpp"
+#include "raw.hpp"
+#include "updatehelper.hpp"
+
+#include <experimental/filesystem>
+#include <fstream>
+#include <memory>
+#include <set>
+#include <stdexcept>
+
+extern "C" {
+#include "ipmitoolintf.h"
+} // extern "C"
+
+std::unique_ptr<UploadManager> UploadManager::BuildUploadMgr(
+    const std::string& image, const std::string& hash,
+    UpdateHelperInterface* helper, DataInterface* dintf)
+{
+    std::ifstream imageStream, hashStream;
+
+    imageStream.open(image);
+    hashStream.open(hash);
+    if (imageStream.bad() || hashStream.bad())
+    {
+        return nullptr;
+    }
+
+    int32_t imageSize = std::experimental::filesystem::file_size(image);
+    int32_t hashSize = std::experimental::filesystem::file_size(hash);
+
+    return std::make_unique<UploadManager>(std::move(imageStream),
+                                           std::move(hashStream), imageSize,
+                                           hashSize, helper, dintf);
+}
+
+void UploadManager::UpdateBMC()
+{
+    /* Let's build the raw command input.
+     *
+     * The sequence is:
+     * FLASH_START_TRANSFER,
+     * FLASH_DATA_BLOCK x times. (or FLASH_EXTERNAL_DATA_BLOCK)
+     * FLASH_DATA_FINISH
+     * FLASH_START_HASH
+     * FLASH_HASH_DATA x times. (or FLASH_EXTERNAL_HASH_BLOCK)
+     * FLASH_HASH_FINISH
+     * FLASH_DATA_VERIFY
+     * FLASH_VERIFY_CHECK x times.
+     */
+
+    /* TODO: implement this. */
+
+    /* UploadImage() */
+    /* UploadHash() */
+
+    /*
+     * FLASH_DATA_VERIFY - The verify command will trigger verification of the
+     * image against the signature file sent down.
+     */
+    //  ret = helper_->SendEmptyCommand(FLASH_DATA_VERIFY, nullptr);
+    //  if (!ret.ok()) return ret;
+
+    return;
+}
+
+void UpdaterMain(const std::string& interface, const std::string& image,
+                 const std::string& signature)
+{
+    static const std::set<std::string> supportedInterfaces = {"ipmibt"};
+
+    /* Check if interface is supported. */
+    if (!supportedInterfaces.count(interface))
+    {
+        throw std::runtime_error("Unsupported interface");
+    }
+
+    /* NOTE: Presently, the hash signature being separate is optional on the BMC
+     * but isn't here, for now.
+     */
+
+    /* There are three key components to the process.  There's the data handler,
+     * which deals with sending the data, and it uses a convenience method to
+     * package the specific IPMI firmware update commands, and those commands
+     * are then routed through a convenience layer that will handle calling into
+     * the C-library.
+     */
+    IpmiRaw raw;
+    IpmiUpdateHelper ipmih(&raw);
+    std::unique_ptr<DataInterface> handler;
+
+    if (interface == "ipmibt")
+    {
+        handler = std::make_unique<BtDataHandler>(&ipmih);
+    }
+
+    if (handler == nullptr)
+    {
+        throw std::runtime_error("Unable to build interface handler.");
+    }
+
+    auto updater =
+        UploadManager::BuildUploadMgr(image, signature, &ipmih, handler.get());
+
+    if (updater == nullptr)
+    {
+        throw std::runtime_error("Unable to build update manager.");
+    }
+
+    updater->UpdateBMC();
+
+    return;
+}