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
fb_get_error()55 const std::string fb_get_error() {
56 return g_error;
57 }
58
check_response(Transport * transport,uint32_t size,char * response)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
_command_start(Transport * transport,const std::string & cmd,uint32_t size,char * response)116 static int64_t _command_start(Transport* transport, const std::string& cmd, uint32_t size,
117 char* response) {
118 if (cmd.size() > 64) {
119 g_error = android::base::StringPrintf("command too large (%zu)", cmd.size());
120 return -1;
121 }
122
123 if (response) {
124 response[0] = 0;
125 }
126
127 if (transport->Write(cmd.c_str(), cmd.size()) != static_cast<int>(cmd.size())) {
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
_command_write_data(Transport * transport,const void * data,uint32_t size)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
_command_read_data(Transport * transport,void * data,uint32_t size)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
_command_end(Transport * transport)166 static int64_t _command_end(Transport* transport) {
167 return check_response(transport, 0, 0) < 0 ? -1 : 0;
168 }
169
_command_send(Transport * transport,const std::string & cmd,const void * data,uint32_t size,char * response)170 static int64_t _command_send(Transport* transport, const std::string& cmd, const void* data,
171 uint32_t size, 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
_command_send_fd(Transport * transport,const std::string & cmd,int fd,uint32_t size,char * response)193 static int64_t _command_send_fd(Transport* transport, const std::string& 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
_command_send_no_data(Transport * transport,const std::string & cmd,char * response)226 static int _command_send_no_data(Transport* transport, const std::string& cmd, char* response) {
227 return _command_start(transport, cmd, 0, response);
228 }
229
fb_command(Transport * transport,const std::string & cmd)230 int fb_command(Transport* transport, const std::string& cmd) {
231 return _command_send_no_data(transport, cmd, 0);
232 }
233
fb_command_response(Transport * transport,const std::string & cmd,char * response)234 int fb_command_response(Transport* transport, const std::string& cmd, char* response) {
235 return _command_send_no_data(transport, cmd, response);
236 }
237
fb_download_data(Transport * transport,const void * data,uint32_t size)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
fb_download_data_fd(Transport * transport,int fd,uint32_t size)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
fb_upload_data(Transport * transport,const char * outfile)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
fb_download_data_sparse_write(void * priv,const void * data,int len)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
fb_download_data_sparse_flush(Transport * transport)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
fb_download_data_sparse(Transport * transport,struct sparse_file * s)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, 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