blob: a0e990a85e95dc50b00ebdcc3031fd912c2081d2 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
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
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080012 * the documentation and/or other materials provided with the
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080013 * 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
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080022 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080023 * 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
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080029#include "fastboot.h"
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070030#include "fs.h"
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080031
Colin Cross81c632e2013-01-23 19:13:43 -080032#include <errno.h>
Elliott Hughes3ab8b852015-08-25 19:34:13 -070033#include <stdarg.h>
Mark Salyzyn5957c1f2014-04-30 14:05:28 -070034#include <stdio.h>
35#include <stdlib.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036#include <string.h>
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080037#include <sys/stat.h>
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080038#include <sys/types.h>
39#include <unistd.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080040
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080041#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080042
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043#define OP_DOWNLOAD 1
44#define OP_COMMAND 2
45#define OP_QUERY 3
46#define OP_NOTICE 4
Dmitry Grinberge6f3e9b2014-03-11 18:28:15 -070047#define OP_DOWNLOAD_SPARSE 5
48#define OP_WAIT_FOR_DISCONNECT 6
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080049
50typedef struct Action Action;
51
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080052#define CMD_SIZE 64
53
Elliott Hughesfc797672015-04-07 20:12:50 -070054struct Action {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080055 unsigned op;
Elliott Hughesfc797672015-04-07 20:12:50 -070056 Action* next;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080057
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080058 char cmd[CMD_SIZE];
Elliott Hughesfc797672015-04-07 20:12:50 -070059 const char* prod;
60 void* data;
61
62 // The protocol only supports 32-bit sizes, so you'll have to break
63 // anything larger into chunks.
64 uint32_t size;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080065
66 const char *msg;
Elliott Hughesb3748de2015-06-23 20:27:58 -070067 int (*func)(Action* a, int status, const char* resp);
Daniel Sandlercb6e22b2010-02-25 14:05:33 -050068
69 double start;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080070};
71
72static Action *action_list = 0;
73static Action *action_last = 0;
74
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080075
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080076
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080077
Colin Cross80f2d032012-05-24 18:24:53 -070078int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...)
79{
80 char cmd[CMD_SIZE] = "getvar:";
81 int getvar_len = strlen(cmd);
82 va_list args;
83
84 response[FB_RESPONSE_SZ] = '\0';
85 va_start(args, fmt);
86 vsnprintf(cmd + getvar_len, sizeof(cmd) - getvar_len, fmt, args);
87 va_end(args);
88 cmd[CMD_SIZE - 1] = '\0';
89 return fb_command_response(usb, cmd, response);
90}
91
Anatol Pomazauc8ba5362011-12-15 17:50:18 -080092
Ken Sumrall5ee5d382012-09-29 14:46:25 -070093/* Return true if this partition is supported by the fastboot format command.
94 * It is also used to determine if we should first erase a partition before
95 * flashing it with an ext4 filesystem. See needs_erase()
96 *
97 * Not all devices report the filesystem type, so don't report any errors,
98 * just return false.
99 */
JP Abgrall7e859742014-05-06 15:14:15 -0700100int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override)
Ken Sumrall5ee5d382012-09-29 14:46:25 -0700101{
JP Abgrall7e859742014-05-06 15:14:15 -0700102 char fs_type[FB_RESPONSE_SZ + 1] = {0,};
Ken Sumrall5ee5d382012-09-29 14:46:25 -0700103 int status;
Ken Sumrall5ee5d382012-09-29 14:46:25 -0700104
JP Abgrall7e859742014-05-06 15:14:15 -0700105 if (type_override) {
106 return !!fs_get_generator(type_override);
107 }
108 status = fb_getvar(usb, fs_type, "partition-type:%s", partition);
Ken Sumrall5ee5d382012-09-29 14:46:25 -0700109 if (status) {
110 return 0;
111 }
JP Abgrall7e859742014-05-06 15:14:15 -0700112 return !!fs_get_generator(fs_type);
Ken Sumrall5ee5d382012-09-29 14:46:25 -0700113}
114
Elliott Hughesb3748de2015-06-23 20:27:58 -0700115static int cb_default(Action* a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800116 if (status) {
117 fprintf(stderr,"FAILED (%s)\n", resp);
118 } else {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500119 double split = now();
120 fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
121 a->start = split;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800122 }
123 return status;
124}
125
126static Action *queue_action(unsigned op, const char *fmt, ...)
127{
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800128 va_list ap;
Bruce Beare50b39952010-07-15 08:52:01 -0700129 size_t cmdsize;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800130
Elliott Hughesb3748de2015-06-23 20:27:58 -0700131 Action* a = reinterpret_cast<Action*>(calloc(1, sizeof(Action)));
132 if (a == nullptr) die("out of memory");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800133
134 va_start(ap, fmt);
Bruce Beare50b39952010-07-15 08:52:01 -0700135 cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800136 va_end(ap);
137
Bruce Beare50b39952010-07-15 08:52:01 -0700138 if (cmdsize >= sizeof(a->cmd)) {
139 free(a);
140 die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd));
141 }
142
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800143 if (action_last) {
144 action_last->next = a;
145 } else {
146 action_list = a;
147 }
148 action_last = a;
149 a->op = op;
150 a->func = cb_default;
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500151
152 a->start = -1;
153
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800154 return a;
155}
156
157void fb_queue_erase(const char *ptn)
158{
159 Action *a;
160 a = queue_action(OP_COMMAND, "erase:%s", ptn);
161 a->msg = mkmsg("erasing '%s'", ptn);
162}
163
Alexander Levitskiy8d7ddb32014-05-07 23:31:59 +0000164void fb_queue_flash(const char *ptn, void *data, unsigned sz)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800165{
166 Action *a;
167
168 a = queue_action(OP_DOWNLOAD, "");
169 a->data = data;
170 a->size = sz;
171 a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
172
173 a = queue_action(OP_COMMAND, "flash:%s", ptn);
174 a->msg = mkmsg("writing '%s'", ptn);
175}
176
Alexander Levitskiy8d7ddb32014-05-07 23:31:59 +0000177void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz)
Colin Crossf8387882012-05-24 17:18:41 -0700178{
179 Action *a;
180
181 a = queue_action(OP_DOWNLOAD_SPARSE, "");
182 a->data = s;
183 a->size = 0;
184 a->msg = mkmsg("sending sparse '%s' (%d KB)", ptn, sz / 1024);
185
186 a = queue_action(OP_COMMAND, "flash:%s", ptn);
187 a->msg = mkmsg("writing '%s'", ptn);
188}
189
Elliott Hughesb3748de2015-06-23 20:27:58 -0700190static int match(const char* str, const char** value, unsigned count) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800191 unsigned n;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800192
193 for (n = 0; n < count; n++) {
194 const char *val = value[n];
195 int len = strlen(val);
196 int match;
197
198 if ((len > 1) && (val[len-1] == '*')) {
199 len--;
200 match = !strncmp(val, str, len);
201 } else {
202 match = !strcmp(val, str);
203 }
204
205 if (match) return 1;
206 }
207
208 return 0;
209}
210
211
212
Elliott Hughesb3748de2015-06-23 20:27:58 -0700213static int cb_check(Action* a, int status, const char* resp, int invert)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800214{
Elliott Hughesb3748de2015-06-23 20:27:58 -0700215 const char** value = reinterpret_cast<const char**>(a->data);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800216 unsigned count = a->size;
217 unsigned n;
218 int yes;
219
220 if (status) {
221 fprintf(stderr,"FAILED (%s)\n", resp);
222 return status;
223 }
224
Wink Savilleb98762f2011-04-04 17:54:59 -0700225 if (a->prod) {
226 if (strcmp(a->prod, cur_product) != 0) {
227 double split = now();
228 fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n",
229 cur_product, a->prod, (split - a->start));
230 a->start = split;
231 return 0;
232 }
233 }
234
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800235 yes = match(resp, value, count);
236 if (invert) yes = !yes;
237
238 if (yes) {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500239 double split = now();
240 fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
241 a->start = split;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800242 return 0;
243 }
244
245 fprintf(stderr,"FAILED\n\n");
246 fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
247 fprintf(stderr,"Update %s '%s'",
248 invert ? "rejects" : "requires", value[0]);
249 for (n = 1; n < count; n++) {
250 fprintf(stderr," or '%s'", value[n]);
251 }
252 fprintf(stderr,".\n\n");
253 return -1;
254}
255
Elliott Hughesb3748de2015-06-23 20:27:58 -0700256static int cb_require(Action*a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800257 return cb_check(a, status, resp, 0);
258}
259
Elliott Hughesb3748de2015-06-23 20:27:58 -0700260static int cb_reject(Action* a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800261 return cb_check(a, status, resp, 1);
262}
263
Wink Savilleb98762f2011-04-04 17:54:59 -0700264void fb_queue_require(const char *prod, const char *var,
Elliott Hughesfc797672015-04-07 20:12:50 -0700265 bool invert, size_t nvalues, const char **value)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800266{
267 Action *a;
268 a = queue_action(OP_QUERY, "getvar:%s", var);
Wink Savilleb98762f2011-04-04 17:54:59 -0700269 a->prod = prod;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800270 a->data = value;
271 a->size = nvalues;
272 a->msg = mkmsg("checking %s", var);
273 a->func = invert ? cb_reject : cb_require;
Elliott Hughesb3748de2015-06-23 20:27:58 -0700274 if (a->data == nullptr) die("out of memory");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800275}
276
Elliott Hughesb3748de2015-06-23 20:27:58 -0700277static int cb_display(Action* a, int status, const char* resp) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800278 if (status) {
279 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
280 return status;
281 }
282 fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
283 return 0;
284}
285
286void fb_queue_display(const char *var, const char *prettyname)
287{
288 Action *a;
289 a = queue_action(OP_QUERY, "getvar:%s", var);
290 a->data = strdup(prettyname);
Elliott Hughesb3748de2015-06-23 20:27:58 -0700291 if (a->data == nullptr) die("out of memory");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800292 a->func = cb_display;
293}
294
Elliott Hughesb3748de2015-06-23 20:27:58 -0700295static int cb_save(Action* a, int status, const char* resp) {
Wink Savilleb98762f2011-04-04 17:54:59 -0700296 if (status) {
297 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
298 return status;
299 }
Elliott Hughesb3748de2015-06-23 20:27:58 -0700300 strncpy(reinterpret_cast<char*>(a->data), resp, a->size);
Wink Savilleb98762f2011-04-04 17:54:59 -0700301 return 0;
302}
303
304void fb_queue_query_save(const char *var, char *dest, unsigned dest_size)
305{
306 Action *a;
307 a = queue_action(OP_QUERY, "getvar:%s", var);
308 a->data = (void *)dest;
309 a->size = dest_size;
310 a->func = cb_save;
311}
312
Elliott Hughesb3748de2015-06-23 20:27:58 -0700313static int cb_do_nothing(Action*, int , const char*) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800314 fprintf(stderr,"\n");
315 return 0;
316}
317
318void fb_queue_reboot(void)
319{
320 Action *a = queue_action(OP_COMMAND, "reboot");
321 a->func = cb_do_nothing;
322 a->msg = "rebooting";
323}
324
325void fb_queue_command(const char *cmd, const char *msg)
326{
327 Action *a = queue_action(OP_COMMAND, cmd);
328 a->msg = msg;
329}
330
331void fb_queue_download(const char *name, void *data, unsigned size)
332{
333 Action *a = queue_action(OP_DOWNLOAD, "");
334 a->data = data;
335 a->size = size;
336 a->msg = mkmsg("downloading '%s'", name);
337}
338
339void fb_queue_notice(const char *notice)
340{
341 Action *a = queue_action(OP_NOTICE, "");
342 a->data = (void*) notice;
343}
344
Mark Wachsler157b0012013-10-02 09:35:38 -0400345void fb_queue_wait_for_disconnect(void)
346{
347 queue_action(OP_WAIT_FOR_DISCONNECT, "");
348}
349
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700350int fb_execute_queue(usb_handle *usb)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800351{
352 Action *a;
353 char resp[FB_RESPONSE_SZ+1];
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700354 int status = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800355
356 a = action_list;
Scott Anderson13081c62012-04-06 12:39:30 -0700357 if (!a)
358 return status;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800359 resp[FB_RESPONSE_SZ] = 0;
360
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500361 double start = -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800362 for (a = action_list; a; a = a->next) {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500363 a->start = now();
364 if (start < 0) start = a->start;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800365 if (a->msg) {
Brian Swetland63e52052010-06-28 11:14:26 -0700366 // fprintf(stderr,"%30s... ",a->msg);
367 fprintf(stderr,"%s...\n",a->msg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800368 }
369 if (a->op == OP_DOWNLOAD) {
370 status = fb_download_data(usb, a->data, a->size);
371 status = a->func(a, status, status ? fb_get_error() : "");
372 if (status) break;
373 } else if (a->op == OP_COMMAND) {
374 status = fb_command(usb, a->cmd);
375 status = a->func(a, status, status ? fb_get_error() : "");
376 if (status) break;
377 } else if (a->op == OP_QUERY) {
378 status = fb_command_response(usb, a->cmd, resp);
379 status = a->func(a, status, status ? fb_get_error() : resp);
380 if (status) break;
381 } else if (a->op == OP_NOTICE) {
382 fprintf(stderr,"%s\n",(char*)a->data);
Colin Crossf8387882012-05-24 17:18:41 -0700383 } else if (a->op == OP_DOWNLOAD_SPARSE) {
Elliott Hughesb3748de2015-06-23 20:27:58 -0700384 status = fb_download_data_sparse(usb, reinterpret_cast<sparse_file*>(a->data));
Colin Crossf8387882012-05-24 17:18:41 -0700385 status = a->func(a, status, status ? fb_get_error() : "");
386 if (status) break;
Mark Wachsler157b0012013-10-02 09:35:38 -0400387 } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
388 usb_wait_for_disconnect(usb);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800389 } else {
390 die("bogus action");
391 }
392 }
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500393
394 fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700395 return status;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800396}
Scott Anderson13081c62012-04-06 12:39:30 -0700397
398int fb_queue_is_empty(void)
399{
Elliott Hughesb3748de2015-06-23 20:27:58 -0700400 return (action_list == nullptr);
Scott Anderson13081c62012-04-06 12:39:30 -0700401}