| /* |
| * 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) |
| { |
| blob->closeBlob(session); |
| 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)); |
| } |
| catch (...) |
| { |
| return; |
| } |
| |
| try |
| { |
| std::fprintf(stderr, "Committing to the cleanup blob\n"); |
| blob->commit(session, {}); |
| std::fprintf(stderr, "Closing cleanup blob\n"); |
| } |
| catch (...) |
| { |
| } |
| |
| blob->closeBlob(session); |
| } |
| |
| } // namespace host_tool |