1 /* 2 * Copyright 2018 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "handler.hpp" 18 19 #include "flags.hpp" 20 #include "helper.hpp" 21 #include "status.hpp" 22 #include "tool_errors.hpp" 23 #include "util.hpp" 24 25 #include <ipmiblob/blob_errors.hpp> 26 #include <stdplus/handle/managed.hpp> 27 28 #include <algorithm> 29 #include <cstdint> 30 #include <cstring> 31 #include <string> 32 #include <vector> 33 34 namespace host_tool 35 { 36 37 static void closeBlob(uint16_t&& session, ipmiblob::BlobInterface*& blob) 38 { 39 blob->closeBlob(session); 40 } 41 42 using BlobHandle = 43 stdplus::Managed<uint16_t, ipmiblob::BlobInterface*>::Handle<closeBlob>; 44 45 template <typename... Args> 46 inline BlobHandle openBlob(ipmiblob::BlobInterface* blob, Args&&... args) 47 { 48 return BlobHandle(blob->openBlob(std::forward<Args>(args)...), blob); 49 } 50 51 bool UpdateHandler::checkAvailable(const std::string& goalFirmware) 52 { 53 std::vector<std::string> blobs = blob->getBlobList(); 54 55 auto blobInst = std::find_if( 56 blobs.begin(), blobs.end(), [&goalFirmware](const std::string& iter) { 57 /* Running into weird scenarios where the string comparison doesn't 58 * work. TODO: revisit. 59 */ 60 return (0 == std::memcmp(goalFirmware.c_str(), iter.c_str(), 61 goalFirmware.length())); 62 // return (goalFirmware.compare(iter)); 63 }); 64 if (blobInst == blobs.end()) 65 { 66 std::fprintf(stderr, "%s not found\n", goalFirmware.c_str()); 67 return false; 68 } 69 70 return true; 71 } 72 73 void UpdateHandler::sendFile(const std::string& target, const std::string& path) 74 { 75 auto supported = handler->supportedType(); 76 77 try 78 { 79 auto session = openBlob( 80 blob, target, 81 static_cast<std::uint16_t>(supported) | 82 static_cast<std::uint16_t>( 83 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite)); 84 85 if (!handler->sendContents(path, *session)) 86 { 87 throw ToolException("Failed to send contents of " + path); 88 } 89 } 90 catch (const ipmiblob::BlobException& b) 91 { 92 throw ToolException("blob exception received: " + 93 std::string(b.what())); 94 } 95 } 96 97 bool UpdateHandler::verifyFile(const std::string& target, bool ignoreStatus) 98 { 99 try 100 { 101 auto session = 102 openBlob(blob, target, 103 static_cast<std::uint16_t>( 104 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite)); 105 106 std::fprintf(stderr, "Committing to %s to trigger service\n", 107 target.c_str()); 108 blob->commit(*session, {}); 109 110 if (ignoreStatus) 111 { 112 // Skip checking the blob for status if ignoreStatus is enabled 113 return true; 114 } 115 116 std::fprintf(stderr, "Calling stat on %s session to check status\n", 117 target.c_str()); 118 pollStatus(*session, blob); 119 return true; 120 } 121 catch (const ipmiblob::BlobException& b) 122 { 123 throw ToolException("blob exception received: " + 124 std::string(b.what())); 125 } 126 } 127 128 std::vector<uint8_t> UpdateHandler::readVersion(const std::string& versionBlob) 129 { 130 try 131 { 132 auto session = 133 openBlob(blob, versionBlob, 134 static_cast<std::uint16_t>( 135 ipmi_flash::FirmwareFlags::UpdateFlags::openRead)); 136 137 std::fprintf(stderr, "Calling stat on %s session to check status\n", 138 versionBlob.c_str()); 139 140 /* TODO: call readBytes multiple times in case IPMI message length 141 * exceeds IPMI_MAX_MSG_LENGTH. 142 */ 143 auto size = pollReadReady(*session, blob); 144 if (size > 0) 145 { 146 return blob->readBytes(*session, 0, size); 147 } 148 return {}; 149 } 150 catch (const ipmiblob::BlobException& b) 151 { 152 throw ToolException("blob exception received: " + 153 std::string(b.what())); 154 } 155 } 156 157 void UpdateHandler::cleanArtifacts() 158 { 159 /* Errors aren't important for this call. */ 160 try 161 { 162 std::fprintf(stderr, "Executing cleanup blob\n"); 163 auto session = 164 openBlob(blob, ipmi_flash::cleanupBlobId, 165 static_cast<std::uint16_t>( 166 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite)); 167 blob->commit(*session, {}); 168 } 169 catch (const std::exception& e) 170 { 171 std::fprintf(stderr, "Cleanup failed: %s\n", e.what()); 172 } 173 } 174 175 } // namespace host_tool 176