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 27 #include <algorithm> 28 #include <cstdint> 29 #include <cstring> 30 #include <string> 31 #include <vector> 32 33 namespace host_tool 34 { 35 36 bool UpdateHandler::checkAvailable(const std::string& goalFirmware) 37 { 38 std::vector<std::string> blobs = blob->getBlobList(); 39 40 auto blobInst = std::find_if( 41 blobs.begin(), blobs.end(), [&goalFirmware](const std::string& iter) { 42 /* Running into weird scenarios where the string comparison doesn't 43 * work. TODO: revisit. 44 */ 45 return (0 == std::memcmp(goalFirmware.c_str(), iter.c_str(), 46 goalFirmware.length())); 47 // return (goalFirmware.compare(iter)); 48 }); 49 if (blobInst == blobs.end()) 50 { 51 std::fprintf(stderr, "%s not found\n", goalFirmware.c_str()); 52 return false; 53 } 54 55 return true; 56 } 57 58 void UpdateHandler::sendFile(const std::string& target, const std::string& path) 59 { 60 std::uint16_t session; 61 auto supported = handler->supportedType(); 62 63 try 64 { 65 session = blob->openBlob( 66 target, static_cast<std::uint16_t>(supported) | 67 static_cast<std::uint16_t>( 68 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite)); 69 } 70 catch (const ipmiblob::BlobException& b) 71 { 72 throw ToolException("blob exception received: " + 73 std::string(b.what())); 74 } 75 76 if (!handler->sendContents(path, session)) 77 { 78 /* Need to close the session on failure, or it's stuck open (until the 79 * blob handler timeout is implemented, and even then, why make it wait. 80 */ 81 blob->closeBlob(session); 82 throw ToolException("Failed to send contents of " + path); 83 } 84 85 blob->closeBlob(session); 86 } 87 88 bool UpdateHandler::verifyFile(const std::string& target, bool ignoreStatus) 89 { 90 std::uint16_t session; 91 bool success = false; 92 93 try 94 { 95 session = blob->openBlob( 96 target, static_cast<std::uint16_t>( 97 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite)); 98 } 99 catch (const ipmiblob::BlobException& b) 100 { 101 throw ToolException("blob exception received: " + 102 std::string(b.what())); 103 } 104 105 std::fprintf(stderr, "Committing to %s to trigger service\n", 106 target.c_str()); 107 108 try 109 { 110 blob->commit(session, {}); 111 } 112 catch (const ipmiblob::BlobException& b) 113 { 114 blob->closeBlob(session); 115 throw ToolException("blob exception received: " + 116 std::string(b.what())); 117 } 118 119 if (ignoreStatus) 120 { 121 // Skip checking the blob for status if ignoreStatus is enabled 122 blob->closeBlob(session); 123 return true; 124 } 125 126 std::fprintf(stderr, "Calling stat on %s session to check status\n", 127 target.c_str()); 128 129 if (pollStatus(session, blob)) 130 { 131 std::fprintf(stderr, "Returned success\n"); 132 success = true; 133 } 134 else 135 { 136 std::fprintf(stderr, "Returned non-success (could still " 137 "be running (unlikely))\n"); 138 } 139 140 blob->closeBlob(session); 141 return (success == true); 142 } 143 144 std::vector<uint8_t> UpdateHandler::readVersion(const std::string& versionBlob) 145 { 146 std::uint16_t session; 147 148 try 149 { 150 session = blob->openBlob( 151 versionBlob, static_cast<std::uint16_t>( 152 ipmi_flash::FirmwareFlags::UpdateFlags::openRead)); 153 } 154 catch (const ipmiblob::BlobException& b) 155 { 156 throw ToolException("blob exception received: " + 157 std::string(b.what())); 158 } 159 160 std::fprintf(stderr, "Calling stat on %s session to check status\n", 161 versionBlob.c_str()); 162 std::vector<uint8_t> data; 163 164 /* TODO: call readBytes multiple times in case IPMI message length exceeds 165 * IPMI_MAX_MSG_LENGTH. 166 */ 167 auto pollResp = pollReadReady(session, blob); 168 if (pollResp.first) 169 { 170 std::fprintf(stderr, "Returned success\n"); 171 if (pollResp.second > 0) 172 { 173 try 174 { 175 data = blob->readBytes(session, 0, pollResp.second); 176 } 177 catch (const ipmiblob::BlobException& b) 178 { 179 blob->closeBlob(session); 180 throw ToolException("blob exception received: " + 181 std::string(b.what())); 182 } 183 } 184 } 185 else 186 { 187 std::fprintf(stderr, "Returned non-success (could still " 188 "be running (unlikely))\n"); 189 } 190 191 blob->closeBlob(session); 192 return data; 193 } 194 195 void UpdateHandler::cleanArtifacts() 196 { 197 /* open(), commit(), close() */ 198 std::uint16_t session; 199 200 /* Errors aren't important for this call. */ 201 try 202 { 203 std::fprintf(stderr, "Opening the cleanup blob\n"); 204 session = blob->openBlob( 205 ipmi_flash::cleanupBlobId, 206 static_cast<std::uint16_t>( 207 ipmi_flash::FirmwareFlags::UpdateFlags::openWrite)); 208 } 209 catch (...) 210 { 211 return; 212 } 213 214 try 215 { 216 std::fprintf(stderr, "Committing to the cleanup blob\n"); 217 blob->commit(session, {}); 218 std::fprintf(stderr, "Closing cleanup blob\n"); 219 } 220 catch (...) 221 {} 222 223 blob->closeBlob(session); 224 } 225 226 } // namespace host_tool 227