/* * 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 "flags.hpp" #include "handler.hpp" #include "status.hpp" #include "tool_errors.hpp" #include "util.hpp" #include #include #include #include #include #include #include #include namespace host_tool { void updaterMain(UpdateHandlerInterface* updater, ipmiblob::BlobInterface* blob, const std::string& imagePath, const std::string& signaturePath, const std::string& layoutType, bool ignoreUpdate) { /* TODO: validate the layoutType isn't a special value such as: 'update', * 'verify', or 'hash' */ std::string layout = "/flash/" + layoutType; bool goalSupported = updater->checkAvailable(layout); if (!goalSupported) { throw ToolException("Goal firmware not supported"); } // Clean all active blobs to support multiple stages // Check for any active blobs and delete the first one found to reset the // BMC's phosphor-ipmi-flash state machine then clean any leftover artifacts const auto blobList = blob->getBlobList(); for (const auto& activeBlob : blobList) { // Prefix is /flash/active/ if (activeBlob.find("/flash/active/", 0) == 0) { std::fprintf(stderr, "Found an active blob, deleting %s\n", activeBlob.c_str()); blob->deleteBlob(activeBlob); updater->cleanArtifacts(); break; } } /* Yay, our layout type is supported. */ try { /* Send over the firmware image. */ std::fprintf(stderr, "Sending over the firmware image.\n"); updater->sendFile(layout, imagePath); /* Send over the hash contents. */ std::fprintf(stderr, "Sending over the hash file.\n"); updater->sendFile(ipmi_flash::hashBlobId, signaturePath); /* Trigger the verification by opening and committing the verify file. */ std::fprintf(stderr, "Opening the verification file\n"); if (updater->verifyFile(ipmi_flash::verifyBlobId, false)) { std::fprintf(stderr, "succeeded\n"); } else { std::fprintf(stderr, "failed\n"); throw ToolException("Verification failed"); } /* Trigger the update by opening and committing the update file. */ std::fprintf(stderr, "Opening the update file\n"); if (updater->verifyFile(ipmi_flash::updateBlobId, ignoreUpdate)) { std::fprintf(stderr, "succeeded\n"); } else { /* Depending on the update mechanism used, this may be * uninteresting. For instance, for the static layout, we use the * reboot update mechanism. Which doesn't always lead to a * successful return before the BMC starts shutting down services. */ std::fprintf(stderr, "failed\n"); throw ToolException("Update failed"); } } catch (...) { updater->cleanArtifacts(); throw; } } } // namespace host_tool