1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #define round_down(a, b) \ 30 ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) 31 32 #include <fcntl.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <errno.h> 37 38 #include <algorithm> 39 #include <vector> 40 41 #include <android-base/file.h> 42 #include <android-base/stringprintf.h> 43 #include <android-base/unique_fd.h> 44 #include <sparse/sparse.h> 45 #include <utils/FileMap.h> 46 47 #include "fastboot.h" 48 #include "transport.h" 49 50 static std::string g_error; 51 52 using android::base::unique_fd; 53 using android::base::WriteStringToFile; 54 55 const std::string fb_get_error() { 56 return g_error; 57 } 58 59 static int64_t check_response(Transport* transport, uint32_t size, char* response) { 60 char status[65]; 61 62 while (true) { 63 int r = transport->Read(status, 64); 64 if (r < 0) { 65 g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno)); 66 transport->Close(); 67 return -1; 68 } 69 status[r] = 0; 70 71 if (r < 4) { 72 g_error = android::base::StringPrintf("status malformed (%d bytes)", r); 73 transport->Close(); 74 return -1; 75 } 76 77 if (!memcmp(status, "INFO", 4)) { 78 fprintf(stderr,"(bootloader) %s\n", status + 4); 79 continue; 80 } 81 82 if (!memcmp(status, "OKAY", 4)) { 83 if (response) { 84 strcpy(response, (char*) status + 4); 85 } 86 return 0; 87 } 88 89 if (!memcmp(status, "FAIL", 4)) { 90 if (r > 4) { 91 g_error = android::base::StringPrintf("remote: %s", status + 4); 92 } else { 93 g_error = "remote failure"; 94 } 95 return -1; 96 } 97 98 if (!memcmp(status, "DATA", 4) && size > 0){ 99 uint32_t dsize = strtol(status + 4, 0, 16); 100 if (dsize > size) { 101 g_error = android::base::StringPrintf("data size too large (%d)", dsize); 102 transport->Close(); 103 return -1; 104 } 105 return dsize; 106 } 107 108 g_error = "unknown status code"; 109 transport->Close(); 110 break; 111 } 112 113 return -1; 114 } 115 116 static int64_t _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) { 117 size_t cmdsize = strlen(cmd); 118 if (cmdsize > 64) { 119 g_error = android::base::StringPrintf("command too large (%zu)", cmdsize); 120 return -1; 121 } 122 123 if (response) { 124 response[0] = 0; 125 } 126 127 if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) { 128 g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno)); 129 transport->Close(); 130 return -1; 131 } 132 133 return check_response(transport, size, response); 134 } 135 136 static int64_t _command_write_data(Transport* transport, const void* data, uint32_t size) { 137 int64_t r = transport->Write(data, size); 138 if (r < 0) { 139 g_error = android::base::StringPrintf("data write failure (%s)", strerror(errno)); 140 transport->Close(); 141 return -1; 142 } 143 if (r != static_cast<int64_t>(size)) { 144 g_error = "data write failure (short transfer)"; 145 transport->Close(); 146 return -1; 147 } 148 return r; 149 } 150 151 static int64_t _command_read_data(Transport* transport, void* data, uint32_t size) { 152 int64_t r = transport->Read(data, size); 153 if (r < 0) { 154 g_error = android::base::StringPrintf("data read failure (%s)", strerror(errno)); 155 transport->Close(); 156 return -1; 157 } 158 if (r != (static_cast<int64_t>(size))) { 159 g_error = "data read failure (short transfer)"; 160 transport->Close(); 161 return -1; 162 } 163 return r; 164 } 165 166 static int64_t _command_end(Transport* transport) { 167 return check_response(transport, 0, 0) < 0 ? -1 : 0; 168 } 169 170 static int64_t _command_send(Transport* transport, const char* cmd, const void* data, uint32_t size, 171 char* response) { 172 if (size == 0) { 173 return -1; 174 } 175 176 int64_t r = _command_start(transport, cmd, size, response); 177 if (r < 0) { 178 return -1; 179 } 180 r = _command_write_data(transport, data, size); 181 if (r < 0) { 182 return -1; 183 } 184 185 r = _command_end(transport); 186 if (r < 0) { 187 return -1; 188 } 189 190 return size; 191 } 192 193 static int64_t _command_send_fd(Transport* transport, const char* cmd, int fd, uint32_t size, 194 char* response) { 195 static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024; 196 off64_t offset = 0; 197 uint32_t remaining = size; 198 199 if (_command_start(transport, cmd, size, response) < 0) { 200 return -1; 201 } 202 203 while (remaining) { 204 android::FileMap filemap; 205 size_t len = std::min(remaining, MAX_MAP_SIZE); 206 207 if (!filemap.create(NULL, fd, offset, len, true)) { 208 return -1; 209 } 210 211 if (_command_write_data(transport, filemap.getDataPtr(), len) < 0) { 212 return -1; 213 } 214 215 remaining -= len; 216 offset += len; 217 } 218 219 if (_command_end(transport) < 0) { 220 return -1; 221 } 222 223 return size; 224 } 225 226 static int _command_send_no_data(Transport* transport, const char* cmd, char* response) { 227 return _command_start(transport, cmd, 0, response); 228 } 229 230 int fb_command(Transport* transport, const char* cmd) { 231 return _command_send_no_data(transport, cmd, 0); 232 } 233 234 int fb_command_response(Transport* transport, const char* cmd, char* response) { 235 return _command_send_no_data(transport, cmd, response); 236 } 237 238 int64_t fb_download_data(Transport* transport, const void* data, uint32_t size) { 239 std::string cmd(android::base::StringPrintf("download:%08x", size)); 240 return _command_send(transport, cmd.c_str(), data, size, 0) < 0 ? -1 : 0; 241 } 242 243 int64_t fb_download_data_fd(Transport* transport, int fd, uint32_t size) { 244 std::string cmd(android::base::StringPrintf("download:%08x", size)); 245 return _command_send_fd(transport, cmd.c_str(), fd, size, 0) < 0 ? -1 : 0; 246 } 247 248 int64_t fb_upload_data(Transport* transport, const char* outfile) { 249 // positive return value is the upload size sent by the device 250 int64_t r = _command_start(transport, "upload", std::numeric_limits<int32_t>::max(), nullptr); 251 if (r <= 0) { 252 g_error = android::base::StringPrintf("command start failed (%s)", strerror(errno)); 253 return r; 254 } 255 256 std::string data; 257 data.resize(r); 258 if ((r = _command_read_data(transport, &data[0], data.size())) == -1) { 259 return r; 260 } 261 262 if (!WriteStringToFile(data, outfile, true)) { 263 g_error = android::base::StringPrintf("write to '%s' failed", outfile); 264 return -1; 265 } 266 267 return _command_end(transport); 268 } 269 270 #define TRANSPORT_BUF_SIZE 1024 271 static char transport_buf[TRANSPORT_BUF_SIZE]; 272 static int transport_buf_len; 273 274 static int fb_download_data_sparse_write(void *priv, const void *data, int len) 275 { 276 int r; 277 Transport* transport = reinterpret_cast<Transport*>(priv); 278 int to_write; 279 const char* ptr = reinterpret_cast<const char*>(data); 280 281 if (transport_buf_len) { 282 to_write = std::min(TRANSPORT_BUF_SIZE - transport_buf_len, len); 283 284 memcpy(transport_buf + transport_buf_len, ptr, to_write); 285 transport_buf_len += to_write; 286 ptr += to_write; 287 len -= to_write; 288 } 289 290 if (transport_buf_len == TRANSPORT_BUF_SIZE) { 291 r = _command_write_data(transport, transport_buf, TRANSPORT_BUF_SIZE); 292 if (r != TRANSPORT_BUF_SIZE) { 293 return -1; 294 } 295 transport_buf_len = 0; 296 } 297 298 if (len > TRANSPORT_BUF_SIZE) { 299 if (transport_buf_len > 0) { 300 g_error = "internal error: transport_buf not empty"; 301 return -1; 302 } 303 to_write = round_down(len, TRANSPORT_BUF_SIZE); 304 r = _command_write_data(transport, ptr, to_write); 305 if (r != to_write) { 306 return -1; 307 } 308 ptr += to_write; 309 len -= to_write; 310 } 311 312 if (len > 0) { 313 if (len > TRANSPORT_BUF_SIZE) { 314 g_error = "internal error: too much left for transport_buf"; 315 return -1; 316 } 317 memcpy(transport_buf, ptr, len); 318 transport_buf_len = len; 319 } 320 321 return 0; 322 } 323 324 static int fb_download_data_sparse_flush(Transport* transport) { 325 if (transport_buf_len > 0) { 326 int64_t r = _command_write_data(transport, transport_buf, transport_buf_len); 327 if (r != static_cast<int64_t>(transport_buf_len)) { 328 return -1; 329 } 330 transport_buf_len = 0; 331 } 332 return 0; 333 } 334 335 int fb_download_data_sparse(Transport* transport, struct sparse_file* s) { 336 int size = sparse_file_len(s, true, false); 337 if (size <= 0) { 338 return -1; 339 } 340 341 std::string cmd(android::base::StringPrintf("download:%08x", size)); 342 int r = _command_start(transport, cmd.c_str(), size, 0); 343 if (r < 0) { 344 return -1; 345 } 346 347 r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, transport); 348 if (r < 0) { 349 return -1; 350 } 351 352 r = fb_download_data_sparse_flush(transport); 353 if (r < 0) { 354 return -1; 355 } 356 357 return _command_end(transport); 358 } 359