| /* |
| * 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 "tool_errors.hpp" |
| |
| #include <algorithm> |
| #include <blobs-ipmid/blobs.hpp> |
| #include <cstring> |
| #include <ipmiblob/blob_errors.hpp> |
| #include <memory> |
| #include <string> |
| |
| namespace host_tool |
| { |
| |
| void updaterMain(ipmiblob::BlobInterface* blob, DataInterface* handler, |
| const std::string& imagePath, const std::string& signaturePath) |
| { |
| /* TODO(venture): Add optional parameter to specify the flash type, default |
| * to legacy for now. |
| */ |
| 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_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()) |
| { |
| throw ToolException(goalFirmware + " not found"); |
| } |
| |
| /* 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) |
| { |
| throw ToolException("blob exception received: " + |
| std::string(b.what())); |
| } |
| |
| auto supported = handler->supportedType(); |
| if ((stat.blob_state & supported) == 0) |
| { |
| throw ToolException("data interface selected not supported."); |
| } |
| |
| /* Yay, our data handler is supported. */ |
| std::uint16_t session; |
| try |
| { |
| session = blob->openBlob( |
| goalFirmware, |
| 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())); |
| } |
| |
| /* Send over the firmware image. */ |
| if (!handler->sendContents(imagePath, 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 " + imagePath); |
| } |
| |
| blob->closeBlob(session); |
| |
| /* Send over the hash contents. */ |
| /* Trigger the verification. */ |
| /* Check the verification. */ |
| |
| return; |
| } |
| |
| } // namespace host_tool |