| /* |
| * 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 "flash-ipmi.hpp" |
| |
| #include <cstdio> |
| #include <phosphor-logging/log.hpp> |
| |
| using namespace phosphor::logging; |
| |
| namespace |
| { |
| |
| /** |
| * Close a file pointer and set to null. |
| * |
| * @param[in] fd a pointer to your file handle. |
| */ |
| void closeFile(std::FILE** fd) |
| { |
| if (!fd) |
| { |
| return; |
| } |
| |
| if (*fd) |
| { |
| std::fclose(*fd); |
| (*fd) = nullptr; |
| } |
| } |
| } |
| |
| void FlashUpdate::closeEverything() |
| { |
| closeFile(&flashFd); |
| } |
| |
| FlashUpdate::~FlashUpdate() |
| { |
| /* Close without deleting. This object can only be destroyed if the ipmi |
| * daemon unloads it, by closing down. In this event, we want the verified |
| * file to live on. |
| */ |
| closeEverything(); |
| } |
| |
| void FlashUpdate::abortEverything() |
| { |
| closeEverything(); |
| |
| /* TODO: And now delete everything */ |
| return; |
| } |
| |
| bool FlashUpdate::openEverything() |
| { |
| flashFd = std::fopen(tmpPath.c_str(), "wb"); |
| if (flashFd == nullptr) |
| { |
| log<level::INFO>("Unable to open staging path", |
| entry("PATH=%s", tmpPath.c_str())); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* Prepare to receive a BMC image and then a signature. */ |
| bool FlashUpdate::start(uint32_t length) |
| { |
| /* Close out and delete everything. */ |
| abortEverything(); |
| |
| /* TODO: Validate request->length */ |
| flashLength = length; |
| |
| /* Start over! */ |
| return openEverything(); |
| } |
| |
| bool FlashUpdate::writeBlock(std::FILE* fd, uint32_t offset, |
| const std::vector<uint8_t>& bytes) |
| { |
| /* Seek into position, let's assume fseek won't call if offset matches |
| * position. |
| */ |
| if (std::fseek(fd, offset, SEEK_SET)) |
| { |
| log<level::ERR>("Unable to seek into file to write bytes."); |
| return false; |
| } |
| |
| /* Write the bytes. */ |
| auto written = std::fwrite(bytes.data(), 1, bytes.size(), fd); |
| |
| if (written != bytes.size()) |
| { |
| log<level::ERR>("Unable to write all the bytes requested."); |
| return false; |
| } |
| |
| (void)std::fflush(fd); |
| return true; |
| } |
| |
| bool FlashUpdate::flashData(uint32_t offset, const std::vector<uint8_t>& bytes) |
| { |
| if (flashFd) |
| { |
| return writeBlock(flashFd, offset, bytes); |
| } |
| |
| return false; |
| } |
| |
| bool FlashUpdate::flashFinish() |
| { |
| /* TODO: implement. */ |
| return false; |
| } |
| |
| bool FlashUpdate::startHash(uint32_t length) |
| { |
| /* TODO: implement. */ |
| return false; |
| } |
| |
| bool FlashUpdate::hashData(uint32_t offset, const std::vector<uint8_t>& bytes) |
| { |
| /* TODO: implement. */ |
| return false; |
| } |
| |
| bool FlashUpdate::hashFinish() |
| { |
| /* TODO: implement. */ |
| return false; |
| } |
| |
| bool FlashUpdate::startDataVerification() |
| { |
| /* TODO: implement. */ |
| return false; |
| } |
| |
| bool FlashUpdate::abortUpdate() |
| { |
| /* TODO: implement. */ |
| return false; |
| } |