blob: e40db2bad83d404066282b9d85f8dab3ccc7653c [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
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
Anatol Pomazau049dff52011-12-15 17:50:18 -080029#include "fastboot.h"
30#include "make_ext4fs.h"
31#include "ext4_utils.h"
32
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080033#include <stdio.h>
34#include <stdlib.h>
35#include <stdarg.h>
Anatol Pomazau049dff52011-12-15 17:50:18 -080036#include <stdbool.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080037#include <string.h>
Anatol Pomazau049dff52011-12-15 17:50:18 -080038#include <sys/mman.h>
39#include <sys/stat.h>
Daniel Sandlercb6e22b2010-02-25 14:05:33 -050040#include <sys/time.h>
Anatol Pomazau049dff52011-12-15 17:50:18 -080041#include <sys/types.h>
42#include <unistd.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043
Anatol Pomazau049dff52011-12-15 17:50:18 -080044extern struct fs_info info;
45
46#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080047
Daniel Sandlercb6e22b2010-02-25 14:05:33 -050048double now()
49{
50 struct timeval tv;
51 gettimeofday(&tv, NULL);
52 return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
53}
54
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080055char *mkmsg(const char *fmt, ...)
56{
57 char buf[256];
58 char *s;
59 va_list ap;
60
61 va_start(ap, fmt);
62 vsprintf(buf, fmt, ap);
63 va_end(ap);
64
65 s = strdup(buf);
66 if (s == 0) die("out of memory");
67 return s;
68}
69
70#define OP_DOWNLOAD 1
71#define OP_COMMAND 2
72#define OP_QUERY 3
73#define OP_NOTICE 4
Anatol Pomazau049dff52011-12-15 17:50:18 -080074#define OP_FORMAT 5
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080075
76typedef struct Action Action;
77
Anatol Pomazau049dff52011-12-15 17:50:18 -080078#define CMD_SIZE 64
79
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080080struct Action
81{
82 unsigned op;
83 Action *next;
84
Anatol Pomazau049dff52011-12-15 17:50:18 -080085 char cmd[CMD_SIZE];
Wink Savilleb98762f2011-04-04 17:54:59 -070086 const char *prod;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080087 void *data;
88 unsigned size;
89
90 const char *msg;
91 int (*func)(Action *a, int status, char *resp);
Daniel Sandlercb6e22b2010-02-25 14:05:33 -050092
93 double start;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080094};
95
96static Action *action_list = 0;
97static Action *action_last = 0;
98
Anatol Pomazau049dff52011-12-15 17:50:18 -080099
100struct image_data {
101 long long partition_size;
102 long long image_size; // real size of image file
103 void *buffer;
104};
105
106void generate_ext4_image(struct image_data *image);
107void munmap_image(struct image_data *image);
108
109struct generator {
110 char *fs_type;
111
112 /* generate image and return it as image->buffer.
113 * size of the buffer returned as image->image_size.
114 *
115 * image->partition_size specifies what is the size of the
116 * file partition we generate image for.
117 */
118 void (*generate)(struct image_data *image);
119
120 /* it cleans the buffer allocated during image creation.
121 * this function probably does free() or munmap().
122 */
123 void (*cleanup)(struct image_data *image);
124} generators[] = {
125 { "ext4", generate_ext4_image, munmap_image }
126};
127
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800128static int cb_default(Action *a, int status, char *resp)
129{
130 if (status) {
131 fprintf(stderr,"FAILED (%s)\n", resp);
132 } else {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500133 double split = now();
134 fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
135 a->start = split;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800136 }
137 return status;
138}
139
140static Action *queue_action(unsigned op, const char *fmt, ...)
141{
142 Action *a;
143 va_list ap;
Bruce Beare50b39952010-07-15 08:52:01 -0700144 size_t cmdsize;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800145
146 a = calloc(1, sizeof(Action));
147 if (a == 0) die("out of memory");
148
149 va_start(ap, fmt);
Bruce Beare50b39952010-07-15 08:52:01 -0700150 cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800151 va_end(ap);
152
Bruce Beare50b39952010-07-15 08:52:01 -0700153 if (cmdsize >= sizeof(a->cmd)) {
154 free(a);
155 die("Command length (%d) exceeds maximum size (%d)", cmdsize, sizeof(a->cmd));
156 }
157
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800158 if (action_last) {
159 action_last->next = a;
160 } else {
161 action_list = a;
162 }
163 action_last = a;
164 a->op = op;
165 a->func = cb_default;
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500166
167 a->start = -1;
168
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800169 return a;
170}
171
172void fb_queue_erase(const char *ptn)
173{
174 Action *a;
175 a = queue_action(OP_COMMAND, "erase:%s", ptn);
176 a->msg = mkmsg("erasing '%s'", ptn);
177}
178
Anatol Pomazau049dff52011-12-15 17:50:18 -0800179void munmap_image(struct image_data *image)
180{
181 munmap(image->buffer, image->image_size);
182}
183
184void generate_ext4_image(struct image_data *image)
185{
186 int fd;
187 struct stat st;
188
189 fd = fileno(tmpfile());
190 info.len = image->partition_size;
191 make_ext4fs_internal(fd, NULL, NULL, 0, 0, 1, 0, 0, 0);
192
193 fstat(fd, &st);
194 image->image_size = st.st_size;
195
196 image->buffer = mmap(NULL, image->image_size, PROT_READ, MAP_PRIVATE, fd, 0);
197 if (image->buffer == MAP_FAILED) {
198 perror("mmap");
199 image->buffer = NULL;
200 }
201
202 close(fd);
203}
204
205int fb_format(Action *a, usb_handle *usb)
206{
207 const char *partition = a->cmd;
208 char query[256];
209 char response[FB_RESPONSE_SZ+1];
210 int status = 0;
211 struct image_data image;
212 struct generator *generator = NULL;
213 int fd;
214 unsigned i;
215 char cmd[CMD_SIZE];
216
217 response[FB_RESPONSE_SZ] = '\0';
218 snprintf(query, sizeof(query), "getvar:partition-type:%s", partition);
219 status = fb_command_response(usb, query, response);
220 if (status) {
221 fprintf(stderr,"FAILED (%s)\n", fb_get_error());
222 return status;
223 }
224
225 for (i = 0; i < ARRAY_SIZE(generators); i++) {
226 if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) {
227 generator = &generators[i];
228 break;
229 }
230 }
231 if (!generator) {
232 fprintf(stderr,"Formatting is not supported for filesystem with type '%s'.\n",
233 response);
234 return -1;
235 }
236
237 response[FB_RESPONSE_SZ] = '\0';
238 snprintf(query, sizeof(query), "getvar:partition-size:%s", partition);
239 status = fb_command_response(usb, query, response);
240 if (status) {
241 fprintf(stderr,"FAILED (%s)\n", fb_get_error());
242 return status;
243 }
244 image.partition_size = strtoll(response, (char **)NULL, 16);
245
246 generator->generate(&image);
247 if (!image.buffer) {
248 fprintf(stderr,"Cannot generate image.\n");
249 return -1;
250 }
251
252 // Following piece of code is similar to fb_queue_flash() but executes
253 // actions directly without queuing
254 fprintf(stderr, "sending '%s' (%lli KB)...\n", partition, image.image_size/1024);
255 status = fb_download_data(usb, image.buffer, image.image_size);
256 if (status) goto cleanup;
257
258 fprintf(stderr, "writing '%s'...\n", partition);
259 snprintf(cmd, CMD_SIZE, "flash:%s", partition);
260 status = fb_command(usb, cmd);
261 if (status) goto cleanup;
262
263cleanup:
264 generator->cleanup(&image);
265
266 return status;
267}
268
269void fb_queue_format(const char *partition)
270{
271 Action *a;
272
273 a = queue_action(OP_FORMAT, partition);
274 a->msg = mkmsg("formatting '%s' partition", partition);
275}
276
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800277void fb_queue_flash(const char *ptn, void *data, unsigned sz)
278{
279 Action *a;
280
281 a = queue_action(OP_DOWNLOAD, "");
282 a->data = data;
283 a->size = sz;
284 a->msg = mkmsg("sending '%s' (%d KB)", ptn, sz / 1024);
285
286 a = queue_action(OP_COMMAND, "flash:%s", ptn);
287 a->msg = mkmsg("writing '%s'", ptn);
288}
289
290static int match(char *str, const char **value, unsigned count)
291{
292 const char *val;
293 unsigned n;
294 int len;
295
296 for (n = 0; n < count; n++) {
297 const char *val = value[n];
298 int len = strlen(val);
299 int match;
300
301 if ((len > 1) && (val[len-1] == '*')) {
302 len--;
303 match = !strncmp(val, str, len);
304 } else {
305 match = !strcmp(val, str);
306 }
307
308 if (match) return 1;
309 }
310
311 return 0;
312}
313
314
315
316static int cb_check(Action *a, int status, char *resp, int invert)
317{
318 const char **value = a->data;
319 unsigned count = a->size;
320 unsigned n;
321 int yes;
322
323 if (status) {
324 fprintf(stderr,"FAILED (%s)\n", resp);
325 return status;
326 }
327
Wink Savilleb98762f2011-04-04 17:54:59 -0700328 if (a->prod) {
329 if (strcmp(a->prod, cur_product) != 0) {
330 double split = now();
331 fprintf(stderr,"IGNORE, product is %s required only for %s [%7.3fs]\n",
332 cur_product, a->prod, (split - a->start));
333 a->start = split;
334 return 0;
335 }
336 }
337
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800338 yes = match(resp, value, count);
339 if (invert) yes = !yes;
340
341 if (yes) {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500342 double split = now();
343 fprintf(stderr,"OKAY [%7.3fs]\n", (split - a->start));
344 a->start = split;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800345 return 0;
346 }
347
348 fprintf(stderr,"FAILED\n\n");
349 fprintf(stderr,"Device %s is '%s'.\n", a->cmd + 7, resp);
350 fprintf(stderr,"Update %s '%s'",
351 invert ? "rejects" : "requires", value[0]);
352 for (n = 1; n < count; n++) {
353 fprintf(stderr," or '%s'", value[n]);
354 }
355 fprintf(stderr,".\n\n");
356 return -1;
357}
358
359static int cb_require(Action *a, int status, char *resp)
360{
361 return cb_check(a, status, resp, 0);
362}
363
364static int cb_reject(Action *a, int status, char *resp)
365{
366 return cb_check(a, status, resp, 1);
367}
368
Wink Savilleb98762f2011-04-04 17:54:59 -0700369void fb_queue_require(const char *prod, const char *var,
370 int invert, unsigned nvalues, const char **value)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800371{
372 Action *a;
373 a = queue_action(OP_QUERY, "getvar:%s", var);
Wink Savilleb98762f2011-04-04 17:54:59 -0700374 a->prod = prod;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800375 a->data = value;
376 a->size = nvalues;
377 a->msg = mkmsg("checking %s", var);
378 a->func = invert ? cb_reject : cb_require;
379 if (a->data == 0) die("out of memory");
380}
381
382static int cb_display(Action *a, int status, char *resp)
383{
384 if (status) {
385 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
386 return status;
387 }
388 fprintf(stderr, "%s: %s\n", (char*) a->data, resp);
389 return 0;
390}
391
392void fb_queue_display(const char *var, const char *prettyname)
393{
394 Action *a;
395 a = queue_action(OP_QUERY, "getvar:%s", var);
396 a->data = strdup(prettyname);
397 if (a->data == 0) die("out of memory");
398 a->func = cb_display;
399}
400
Wink Savilleb98762f2011-04-04 17:54:59 -0700401static int cb_save(Action *a, int status, char *resp)
402{
403 if (status) {
404 fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
405 return status;
406 }
407 strncpy(a->data, resp, a->size);
408 return 0;
409}
410
411void fb_queue_query_save(const char *var, char *dest, unsigned dest_size)
412{
413 Action *a;
414 a = queue_action(OP_QUERY, "getvar:%s", var);
415 a->data = (void *)dest;
416 a->size = dest_size;
417 a->func = cb_save;
418}
419
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800420static int cb_do_nothing(Action *a, int status, char *resp)
421{
422 fprintf(stderr,"\n");
423 return 0;
424}
425
426void fb_queue_reboot(void)
427{
428 Action *a = queue_action(OP_COMMAND, "reboot");
429 a->func = cb_do_nothing;
430 a->msg = "rebooting";
431}
432
433void fb_queue_command(const char *cmd, const char *msg)
434{
435 Action *a = queue_action(OP_COMMAND, cmd);
436 a->msg = msg;
437}
438
439void fb_queue_download(const char *name, void *data, unsigned size)
440{
441 Action *a = queue_action(OP_DOWNLOAD, "");
442 a->data = data;
443 a->size = size;
444 a->msg = mkmsg("downloading '%s'", name);
445}
446
447void fb_queue_notice(const char *notice)
448{
449 Action *a = queue_action(OP_NOTICE, "");
450 a->data = (void*) notice;
451}
452
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700453int fb_execute_queue(usb_handle *usb)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800454{
455 Action *a;
456 char resp[FB_RESPONSE_SZ+1];
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700457 int status = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800458
459 a = action_list;
460 resp[FB_RESPONSE_SZ] = 0;
461
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500462 double start = -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800463 for (a = action_list; a; a = a->next) {
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500464 a->start = now();
465 if (start < 0) start = a->start;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800466 if (a->msg) {
Brian Swetland63e52052010-06-28 11:14:26 -0700467 // fprintf(stderr,"%30s... ",a->msg);
468 fprintf(stderr,"%s...\n",a->msg);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800469 }
470 if (a->op == OP_DOWNLOAD) {
471 status = fb_download_data(usb, a->data, a->size);
472 status = a->func(a, status, status ? fb_get_error() : "");
473 if (status) break;
474 } else if (a->op == OP_COMMAND) {
475 status = fb_command(usb, a->cmd);
476 status = a->func(a, status, status ? fb_get_error() : "");
477 if (status) break;
478 } else if (a->op == OP_QUERY) {
479 status = fb_command_response(usb, a->cmd, resp);
480 status = a->func(a, status, status ? fb_get_error() : resp);
481 if (status) break;
482 } else if (a->op == OP_NOTICE) {
483 fprintf(stderr,"%s\n",(char*)a->data);
Anatol Pomazau049dff52011-12-15 17:50:18 -0800484 } else if (a->op == OP_FORMAT) {
485 status = fb_format(a, usb);
486 status = a->func(a, status, status ? fb_get_error() : "");
487 if (status) break;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800488 } else {
489 die("bogus action");
490 }
491 }
Daniel Sandlercb6e22b2010-02-25 14:05:33 -0500492
493 fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700494 return status;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800495}