tools: split out the update handler
Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I367ea961c98ec822d3200d101c4f5977d77e7402
diff --git a/tools/handler.cpp b/tools/handler.cpp
new file mode 100644
index 0000000..25bb48d
--- /dev/null
+++ b/tools/handler.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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 "handler.hpp"
+
+#include "helper.hpp"
+#include "status.hpp"
+#include "tool_errors.hpp"
+#include "util.hpp"
+
+#include <algorithm>
+#include <blobs-ipmid/blobs.hpp>
+#include <cstdint>
+#include <cstring>
+#include <ipmiblob/blob_errors.hpp>
+#include <string>
+#include <vector>
+
+namespace host_tool
+{
+
+bool UpdateHandler::checkAvailable(const std::string& goalFirmware)
+{
+ std::vector<std::string> blobs = blob->getBlobList();
+
+ auto blobInst = std::find_if(
+ blobs.begin(), blobs.end(), [&goalFirmware](const std::string& 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())
+ {
+ std::fprintf(stderr, "%s not found\n", goalFirmware.c_str());
+ return false;
+ }
+
+ /* Call stat on /flash/image (or /flash/tarball) and check if data interface
+ * is supported.
+ */
+ ipmiblob::StatResponse stat;
+
+ try
+ {
+ stat = blob->getStat(goalFirmware);
+ }
+ catch (const ipmiblob::BlobException& b)
+ {
+ std::fprintf(stderr, "Received exception '%s' on getStat\n", b.what());
+ return false;
+ }
+
+ auto supported = handler->supportedType();
+ if ((stat.blob_state & supported) == 0)
+ {
+ std::fprintf(stderr, "data interface selected not supported.\n");
+ return false;
+ }
+
+ return true;
+}
+
+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>(blobs::OpenFlags::write));
+ }
+ 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)
+{
+ std::uint16_t session;
+ bool success = false;
+
+ try
+ {
+ session = blob->openBlob(
+ target, static_cast<std::uint16_t>(blobs::OpenFlags::write));
+ }
+ 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)
+ {
+ throw ToolException("blob exception received: " +
+ std::string(b.what()));
+ }
+
+ 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);
+}
+
+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>(blobs::OpenFlags::write));
+ std::fprintf(stderr, "Committing to the cleanup blob\n");
+ blob->commit(session, {});
+ std::fprintf(stderr, "Closing cleanup blob\n");
+ blob->closeBlob(session);
+ }
+ catch (...)
+ {
+ }
+}
+
+} // namespace host_tool