blob: 57363d86031a01fc85b8bf53cf3829fd3524a4fd [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
Tsu Chiang Chuangee520552011-02-25 18:38:53 -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
Tsu Chiang Chuangee520552011-02-25 18:38:53 -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
Colin Crossf8387882012-05-24 17:18:41 -070029#define _LARGEFILE64_SOURCE
30
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080031#include <stdio.h>
32#include <stdlib.h>
33#include <stdarg.h>
Colin Crossf8387882012-05-24 17:18:41 -070034#include <stdbool.h>
35#include <stdint.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080036#include <string.h>
37#include <errno.h>
38#include <fcntl.h>
39#include <unistd.h>
40#include <limits.h>
41#include <ctype.h>
Colin Cross8879f982012-05-22 17:53:34 -070042#include <getopt.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080043
44#include <sys/time.h>
Colin Crossf8387882012-05-24 17:18:41 -070045#include <sys/types.h>
46
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080047#include <bootimg.h>
Colin Crossf8387882012-05-24 17:18:41 -070048#include <sparse/sparse.h>
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080049#include <zipfile/zipfile.h>
50
51#include "fastboot.h"
52
Colin Crossf8387882012-05-24 17:18:41 -070053#ifndef O_BINARY
54#define O_BINARY 0
55#endif
56
Wink Savilleb98762f2011-04-04 17:54:59 -070057char cur_product[FB_RESPONSE_SZ + 1];
58
Brian Swetland2a63bb72009-04-28 16:05:07 -070059void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
60
61boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
62 void *ramdisk, unsigned ramdisk_size,
63 void *second, unsigned second_size,
64 unsigned page_size, unsigned base,
65 unsigned *bootimg_size);
66
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080067static usb_handle *usb = 0;
68static const char *serial = 0;
69static const char *product = 0;
70static const char *cmdline = 0;
71static int wipe_data = 0;
72static unsigned short vendor_id = 0;
Colin Crossf8387882012-05-24 17:18:41 -070073static int64_t sparse_limit = -1;
74static int64_t target_sparse_limit = -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080075
Brian Swetland2a63bb72009-04-28 16:05:07 -070076static unsigned base_addr = 0x10000000;
77
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080078void die(const char *fmt, ...)
79{
80 va_list ap;
81 va_start(ap, fmt);
82 fprintf(stderr,"error: ");
83 vfprintf(stderr, fmt, ap);
84 fprintf(stderr,"\n");
85 va_end(ap);
86 exit(1);
Tsu Chiang Chuangee520552011-02-25 18:38:53 -080087}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080088
89void get_my_path(char *path);
90
91char *find_item(const char *item, const char *product)
92{
93 char *dir;
94 char *fn;
95 char path[PATH_MAX + 128];
96
97 if(!strcmp(item,"boot")) {
98 fn = "boot.img";
99 } else if(!strcmp(item,"recovery")) {
100 fn = "recovery.img";
101 } else if(!strcmp(item,"system")) {
102 fn = "system.img";
103 } else if(!strcmp(item,"userdata")) {
104 fn = "userdata.img";
Jean-Baptiste Querud7608a42011-09-30 14:39:25 -0700105 } else if(!strcmp(item,"cache")) {
106 fn = "cache.img";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800107 } else if(!strcmp(item,"info")) {
108 fn = "android-info.txt";
109 } else {
110 fprintf(stderr,"unknown partition '%s'\n", item);
111 return 0;
112 }
113
114 if(product) {
115 get_my_path(path);
116 sprintf(path + strlen(path),
117 "../../../target/product/%s/%s", product, fn);
118 return strdup(path);
119 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800120
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800121 dir = getenv("ANDROID_PRODUCT_OUT");
122 if((dir == 0) || (dir[0] == 0)) {
123 die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
124 return 0;
125 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800126
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800127 sprintf(path, "%s/%s", dir, fn);
128 return strdup(path);
129}
130
131#ifdef _WIN32
132void *load_file(const char *fn, unsigned *_sz);
Colin Crossf8387882012-05-24 17:18:41 -0700133int64_t file_size(const char *fn);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800134#else
Colin Crossf8387882012-05-24 17:18:41 -0700135#if defined(__APPLE__) && defined(__MACH__)
136#define lseek64 lseek
137#define off64_t off_t
138#endif
139
140int64_t file_size(const char *fn)
141{
142 off64_t off;
143 int fd;
144
145 fd = open(fn, O_RDONLY);
146 if (fd < 0) return -1;
147
148 off = lseek64(fd, 0, SEEK_END);
149 close(fd);
150
151 return off;
152}
153
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800154void *load_file(const char *fn, unsigned *_sz)
155{
156 char *data;
157 int sz;
158 int fd;
159
160 data = 0;
161 fd = open(fn, O_RDONLY);
162 if(fd < 0) return 0;
163
164 sz = lseek(fd, 0, SEEK_END);
165 if(sz < 0) goto oops;
166
167 if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
168
169 data = (char*) malloc(sz);
170 if(data == 0) goto oops;
171
172 if(read(fd, data, sz) != sz) goto oops;
173 close(fd);
174
175 if(_sz) *_sz = sz;
176 return data;
177
178oops:
179 close(fd);
180 if(data != 0) free(data);
181 return 0;
182}
183#endif
184
185int match_fastboot(usb_ifc_info *info)
186{
187 if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
Mike Lockwood09070d92009-08-05 17:04:36 -0400188 (info->dev_vendor != 0x18d1) && // Google
Wu, Haof60e8632012-01-17 12:04:11 -0800189 (info->dev_vendor != 0x8087) && // Intel
The Android Open Source Projectf614d642009-03-18 17:39:49 -0700190 (info->dev_vendor != 0x0451) &&
Robert CH Choue25ff1c2009-09-21 09:51:35 +0800191 (info->dev_vendor != 0x0502) &&
Dima Zavin509f7392010-05-14 14:48:30 -0700192 (info->dev_vendor != 0x0fce) && // Sony Ericsson
193 (info->dev_vendor != 0x05c6) && // Qualcomm
Mike Lockwood09070d92009-08-05 17:04:36 -0400194 (info->dev_vendor != 0x22b8) && // Motorola
Erik Gilling37e9e902010-01-20 17:40:05 -0800195 (info->dev_vendor != 0x0955) && // Nvidia
Xavier Ducrohetaf82f212010-01-21 17:39:25 -0800196 (info->dev_vendor != 0x413c) && // DELL
Xavier Ducrohet746f3242012-01-13 16:03:37 -0800197 (info->dev_vendor != 0x2314) && // INQ Mobile
Ramanan Rajeswaran73c019b2012-02-24 13:00:34 -0800198 (info->dev_vendor != 0x0b05) && // Asus
Mike Lockwood09070d92009-08-05 17:04:36 -0400199 (info->dev_vendor != 0x0bb4)) // HTC
200 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800201 if(info->ifc_class != 0xff) return -1;
202 if(info->ifc_subclass != 0x42) return -1;
203 if(info->ifc_protocol != 0x03) return -1;
204 // require matching serial number if a serial number is specified
205 // at the command line with the -s option.
206 if (serial && strcmp(serial, info->serial_number) != 0) return -1;
207 return 0;
208}
209
210int list_devices_callback(usb_ifc_info *info)
211{
212 if (match_fastboot(info) == 0) {
213 char* serial = info->serial_number;
Elliott Hughesb4add9b2009-10-06 18:07:49 -0700214 if (!info->writable) {
215 serial = "no permissions"; // like "adb devices"
216 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800217 if (!serial[0]) {
218 serial = "????????????";
219 }
220 // output compatible with "adb devices"
221 printf("%s\tfastboot\n", serial);
222 }
223
224 return -1;
225}
226
227usb_handle *open_device(void)
228{
229 static usb_handle *usb = 0;
230 int announce = 1;
231
232 if(usb) return usb;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800233
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800234 for(;;) {
235 usb = usb_open(match_fastboot);
236 if(usb) return usb;
237 if(announce) {
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800238 announce = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800239 fprintf(stderr,"< waiting for device >\n");
240 }
241 sleep(1);
242 }
243}
244
245void list_devices(void) {
246 // We don't actually open a USB device here,
247 // just getting our callback called so we can
248 // list all the connected devices.
249 usb_open(list_devices_callback);
250}
251
252void usage(void)
253{
254 fprintf(stderr,
255/* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */
256 "usage: fastboot [ <option> ] <command>\n"
257 "\n"
258 "commands:\n"
259 " update <filename> reflash device from update.zip\n"
260 " flashall flash boot + recovery + system\n"
261 " flash <partition> [ <filename> ] write a file to a flash partition\n"
262 " erase <partition> erase a flash partition\n"
Anatol Pomazauc8ba5362011-12-15 17:50:18 -0800263 " format <partition> format a flash partition \n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800264 " getvar <variable> display a bootloader variable\n"
265 " boot <kernel> [ <ramdisk> ] download and boot kernel\n"
266 " flash:raw boot <kernel> [ <ramdisk> ] create bootimage and flash it\n"
267 " devices list all connected devices\n"
Bruce Beare24ce4bc2010-10-14 09:43:26 -0700268 " continue continue with autoboot\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800269 " reboot reboot device normally\n"
270 " reboot-bootloader reboot device into bootloader\n"
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800271 " help show this help message\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800272 "\n"
273 "options:\n"
274 " -w erase userdata and cache\n"
275 " -s <serial number> specify device serial number\n"
276 " -p <product> specify product name\n"
277 " -c <cmdline> override kernel commandline\n"
278 " -i <vendor id> specify a custom USB vendor id\n"
Dima Zavin95ec9832009-04-30 15:03:05 -0700279 " -b <base_addr> specify a custom kernel base address\n"
Dima Zavin931175a2010-02-12 20:26:33 -0800280 " -n <page size> specify the nand page size. default: 2048\n"
Colin Crossf8387882012-05-24 17:18:41 -0700281 " -S <size>[K|M|G] automatically sparse files greater than\n"
Colin Cross0bbfb392012-07-24 18:05:21 -0700282 " size. 0 to disable\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800283 );
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800284}
285
Dima Zavin931175a2010-02-12 20:26:33 -0800286void *load_bootable_image(unsigned page_size, const char *kernel, const char *ramdisk,
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800287 unsigned *sz, const char *cmdline)
288{
289 void *kdata = 0, *rdata = 0;
290 unsigned ksize = 0, rsize = 0;
291 void *bdata;
292 unsigned bsize;
293
294 if(kernel == 0) {
295 fprintf(stderr, "no image specified\n");
296 return 0;
297 }
298
299 kdata = load_file(kernel, &ksize);
300 if(kdata == 0) {
301 fprintf(stderr, "cannot load '%s'\n", kernel);
302 return 0;
303 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800304
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800305 /* is this actually a boot image? */
306 if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
307 if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800308
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800309 if(ramdisk) {
310 fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
311 return 0;
312 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800313
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800314 *sz = ksize;
315 return kdata;
316 }
317
318 if(ramdisk) {
319 rdata = load_file(ramdisk, &rsize);
320 if(rdata == 0) {
321 fprintf(stderr,"cannot load '%s'\n", ramdisk);
322 return 0;
323 }
324 }
325
326 fprintf(stderr,"creating boot image...\n");
Dima Zavin931175a2010-02-12 20:26:33 -0800327 bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, page_size, base_addr, &bsize);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800328 if(bdata == 0) {
329 fprintf(stderr,"failed to create boot.img\n");
330 return 0;
331 }
332 if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
333 fprintf(stderr,"creating boot image - %d bytes\n", bsize);
334 *sz = bsize;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800335
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800336 return bdata;
337}
338
339void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
340{
341 void *data;
342 zipentry_t entry;
343 unsigned datasz;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800344
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800345 entry = lookup_zipentry(zip, name);
346 if (entry == NULL) {
347 fprintf(stderr, "archive does not contain '%s'\n", name);
348 return 0;
349 }
350
351 *sz = get_zipentry_size(entry);
352
353 datasz = *sz * 1.001;
354 data = malloc(datasz);
355
356 if(data == 0) {
357 fprintf(stderr, "failed to allocate %d bytes\n", *sz);
358 return 0;
359 }
360
361 if (decompress_zipentry(entry, data, datasz)) {
362 fprintf(stderr, "failed to unzip '%s' from archive\n", name);
363 free(data);
364 return 0;
365 }
366
367 return data;
368}
369
370static char *strip(char *s)
371{
372 int n;
373 while(*s && isspace(*s)) s++;
374 n = strlen(s);
375 while(n-- > 0) {
376 if(!isspace(s[n])) break;
377 s[n] = 0;
378 }
379 return s;
380}
381
382#define MAX_OPTIONS 32
383static int setup_requirement_line(char *name)
384{
385 char *val[MAX_OPTIONS];
386 const char **out;
Wink Savilleb98762f2011-04-04 17:54:59 -0700387 char *prod = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800388 unsigned n, count;
389 char *x;
390 int invert = 0;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800391
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800392 if (!strncmp(name, "reject ", 7)) {
393 name += 7;
394 invert = 1;
395 } else if (!strncmp(name, "require ", 8)) {
396 name += 8;
397 invert = 0;
Wink Savilleb98762f2011-04-04 17:54:59 -0700398 } else if (!strncmp(name, "require-for-product:", 20)) {
399 // Get the product and point name past it
400 prod = name + 20;
401 name = strchr(name, ' ');
402 if (!name) return -1;
403 *name = 0;
404 name += 1;
405 invert = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800406 }
407
408 x = strchr(name, '=');
409 if (x == 0) return 0;
410 *x = 0;
411 val[0] = x + 1;
412
413 for(count = 1; count < MAX_OPTIONS; count++) {
414 x = strchr(val[count - 1],'|');
415 if (x == 0) break;
416 *x = 0;
417 val[count] = x + 1;
418 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800419
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800420 name = strip(name);
421 for(n = 0; n < count; n++) val[n] = strip(val[n]);
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800422
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800423 name = strip(name);
424 if (name == 0) return -1;
425
426 /* work around an unfortunate name mismatch */
427 if (!strcmp(name,"board")) name = "product";
428
429 out = malloc(sizeof(char*) * count);
430 if (out == 0) return -1;
431
432 for(n = 0; n < count; n++) {
433 out[n] = strdup(strip(val[n]));
434 if (out[n] == 0) return -1;
435 }
436
Wink Savilleb98762f2011-04-04 17:54:59 -0700437 fb_queue_require(prod, name, invert, n, out);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800438 return 0;
439}
440
441static void setup_requirements(char *data, unsigned sz)
442{
443 char *s;
444
445 s = data;
446 while (sz-- > 0) {
447 if(*s == '\n') {
448 *s++ = 0;
449 if (setup_requirement_line(data)) {
450 die("out of memory");
451 }
452 data = s;
453 } else {
454 s++;
455 }
456 }
457}
458
459void queue_info_dump(void)
460{
461 fb_queue_notice("--------------------------------------------");
462 fb_queue_display("version-bootloader", "Bootloader Version...");
463 fb_queue_display("version-baseband", "Baseband Version.....");
464 fb_queue_display("serialno", "Serial Number........");
465 fb_queue_notice("--------------------------------------------");
466}
467
Colin Crossf8387882012-05-24 17:18:41 -0700468
469struct sparse_file **load_sparse_files(const char *fname, int max_size)
470{
471 int fd;
472 struct sparse_file *s;
473 int files;
474 struct sparse_file **out_s;
475
476 fd = open(fname, O_RDONLY | O_BINARY);
477 if (fd < 0) {
478 die("cannot open '%s'\n", fname);
479 }
480
481 s = sparse_file_import_auto(fd, false);
482 if (!s) {
483 die("cannot sparse read file '%s'\n", fname);
484 }
485
486 files = sparse_file_resparse(s, max_size, NULL, 0);
487 if (files < 0) {
488 die("Failed to resparse '%s'\n", fname);
489 }
490
491 out_s = calloc(sizeof(struct sparse_file *), files + 1);
492 if (!out_s) {
493 die("Failed to allocate sparse file array\n");
494 }
495
496 files = sparse_file_resparse(s, max_size, out_s, files);
497 if (files < 0) {
498 die("Failed to resparse '%s'\n", fname);
499 }
500
501 return out_s;
502}
503
504static int64_t get_target_sparse_limit(struct usb_handle *usb)
505{
506 int64_t limit = 0;
507 char response[FB_RESPONSE_SZ + 1];
508 int status = fb_getvar(usb, response, "max-download-size");
509
510 if (!status) {
511 limit = strtoul(response, NULL, 0);
512 if (limit > 0) {
513 fprintf(stderr, "target reported max download size of %lld bytes\n",
514 limit);
515 }
516 }
517
518 return limit;
519}
520
521static int64_t get_sparse_limit(struct usb_handle *usb, int64_t size)
522{
523 int64_t limit;
524
525 if (sparse_limit == 0) {
526 return 0;
527 } else if (sparse_limit > 0) {
528 limit = sparse_limit;
529 } else {
530 if (target_sparse_limit == -1) {
531 target_sparse_limit = get_target_sparse_limit(usb);
532 }
533 if (target_sparse_limit > 0) {
534 limit = target_sparse_limit;
535 } else {
Colin Cross0bbfb392012-07-24 18:05:21 -0700536 return 0;
Colin Crossf8387882012-05-24 17:18:41 -0700537 }
538 }
539
540 if (size > limit) {
541 return limit;
542 }
543
544 return 0;
545}
546
547void do_flash(usb_handle *usb, const char *pname, const char *fname)
548{
549 int64_t sz64;
550 void *data;
551 int64_t limit;
552
553 sz64 = file_size(fname);
554 limit = get_sparse_limit(usb, sz64);
555 if (limit) {
556 struct sparse_file **s = load_sparse_files(fname, limit);
557 if (s == NULL) {
558 die("cannot sparse load '%s'\n", fname);
559 }
560 while (*s) {
561 sz64 = sparse_file_len(*s, true, false);
562 fb_queue_flash_sparse(pname, *s++, sz64);
563 }
564 } else {
565 unsigned int sz;
566 data = load_file(fname, &sz);
567 if (data == 0) die("cannot load '%s'\n", fname);
568 fb_queue_flash(pname, data, sz);
569 }
570}
571
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800572void do_update_signature(zipfile_t zip, char *fn)
573{
574 void *data;
575 unsigned sz;
576 data = unzip_file(zip, fn, &sz);
577 if (data == 0) return;
578 fb_queue_download("signature", data, sz);
579 fb_queue_command("signature", "installing signature");
580}
581
582void do_update(char *fn)
583{
584 void *zdata;
585 unsigned zsize;
586 void *data;
587 unsigned sz;
588 zipfile_t zip;
589
590 queue_info_dump();
591
Wink Savilleb98762f2011-04-04 17:54:59 -0700592 fb_queue_query_save("product", cur_product, sizeof(cur_product));
593
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800594 zdata = load_file(fn, &zsize);
595 if (zdata == 0) die("failed to load '%s'", fn);
596
597 zip = init_zipfile(zdata, zsize);
598 if(zip == 0) die("failed to access zipdata in '%s'");
599
600 data = unzip_file(zip, "android-info.txt", &sz);
601 if (data == 0) {
602 char *tmp;
603 /* fallback for older zipfiles */
604 data = unzip_file(zip, "android-product.txt", &sz);
605 if ((data == 0) || (sz < 1)) {
606 die("update package has no android-info.txt or android-product.txt");
607 }
608 tmp = malloc(sz + 128);
609 if (tmp == 0) die("out of memory");
610 sprintf(tmp,"board=%sversion-baseband=0.66.04.19\n",(char*)data);
611 data = tmp;
612 sz = strlen(tmp);
613 }
614
615 setup_requirements(data, sz);
616
617 data = unzip_file(zip, "boot.img", &sz);
618 if (data == 0) die("update package missing boot.img");
619 do_update_signature(zip, "boot.sig");
620 fb_queue_flash("boot", data, sz);
621
622 data = unzip_file(zip, "recovery.img", &sz);
623 if (data != 0) {
624 do_update_signature(zip, "recovery.sig");
625 fb_queue_flash("recovery", data, sz);
626 }
627
628 data = unzip_file(zip, "system.img", &sz);
629 if (data == 0) die("update package missing system.img");
630 do_update_signature(zip, "system.sig");
631 fb_queue_flash("system", data, sz);
632}
633
634void do_send_signature(char *fn)
635{
636 void *data;
637 unsigned sz;
638 char *xtn;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800639
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800640 xtn = strrchr(fn, '.');
641 if (!xtn) return;
642 if (strcmp(xtn, ".img")) return;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800643
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800644 strcpy(xtn,".sig");
645 data = load_file(fn, &sz);
646 strcpy(xtn,".img");
647 if (data == 0) return;
648 fb_queue_download("signature", data, sz);
649 fb_queue_command("signature", "installing signature");
650}
651
652void do_flashall(void)
653{
654 char *fname;
655 void *data;
656 unsigned sz;
657
658 queue_info_dump();
659
Wink Savilleb98762f2011-04-04 17:54:59 -0700660 fb_queue_query_save("product", cur_product, sizeof(cur_product));
661
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800662 fname = find_item("info", product);
663 if (fname == 0) die("cannot find android-info.txt");
664 data = load_file(fname, &sz);
665 if (data == 0) die("could not load android-info.txt");
666 setup_requirements(data, sz);
667
668 fname = find_item("boot", product);
669 data = load_file(fname, &sz);
670 if (data == 0) die("could not load boot.img");
671 do_send_signature(fname);
672 fb_queue_flash("boot", data, sz);
673
674 fname = find_item("recovery", product);
675 data = load_file(fname, &sz);
676 if (data != 0) {
677 do_send_signature(fname);
678 fb_queue_flash("recovery", data, sz);
679 }
680
681 fname = find_item("system", product);
682 data = load_file(fname, &sz);
683 if (data == 0) die("could not load system.img");
684 do_send_signature(fname);
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800685 fb_queue_flash("system", data, sz);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800686}
687
688#define skip(n) do { argc -= (n); argv += (n); } while (0)
JP Abgrall2d13d142011-03-01 23:35:07 -0800689#define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800690
691int do_oem_command(int argc, char **argv)
692{
693 int i;
694 char command[256];
695 if (argc <= 1) return 0;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800696
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800697 command[0] = 0;
698 while(1) {
699 strcat(command,*argv);
700 skip(1);
701 if(argc == 0) break;
702 strcat(command," ");
703 }
704
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800705 fb_queue_command(command,"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800706 return 0;
707}
708
Colin Crossf8387882012-05-24 17:18:41 -0700709static int64_t parse_num(const char *arg)
710{
711 char *endptr;
712 unsigned long long num;
713
714 num = strtoull(arg, &endptr, 0);
715 if (endptr == arg) {
716 return -1;
717 }
718
719 if (*endptr == 'k' || *endptr == 'K') {
720 if (num >= (-1ULL) / 1024) {
721 return -1;
722 }
723 num *= 1024LL;
724 endptr++;
725 } else if (*endptr == 'm' || *endptr == 'M') {
726 if (num >= (-1ULL) / (1024 * 1024)) {
727 return -1;
728 }
729 num *= 1024LL * 1024LL;
730 endptr++;
731 } else if (*endptr == 'g' || *endptr == 'G') {
732 if (num >= (-1ULL) / (1024 * 1024 * 1024)) {
733 return -1;
734 }
735 num *= 1024LL * 1024LL * 1024LL;
736 endptr++;
737 }
738
739 if (*endptr != '\0') {
740 return -1;
741 }
742
743 if (num > INT64_MAX) {
744 return -1;
745 }
746
747 return num;
748}
749
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800750int main(int argc, char **argv)
751{
752 int wants_wipe = 0;
753 int wants_reboot = 0;
754 int wants_reboot_bootloader = 0;
755 void *data;
756 unsigned sz;
Dima Zavin931175a2010-02-12 20:26:33 -0800757 unsigned page_size = 2048;
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700758 int status;
Colin Cross8879f982012-05-22 17:53:34 -0700759 int c;
Colin Crossf8387882012-05-24 17:18:41 -0700760 int r;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800761
Colin Crossf8387882012-05-24 17:18:41 -0700762 const struct option longopts = { 0, 0, 0, 0 };
Colin Cross8879f982012-05-22 17:53:34 -0700763
764 serial = getenv("ANDROID_SERIAL");
765
766 while (1) {
Colin Crossf8387882012-05-24 17:18:41 -0700767 c = getopt_long(argc, argv, "wb:n:s:S:p:c:i:m:h", &longopts, NULL);
Colin Cross8879f982012-05-22 17:53:34 -0700768 if (c < 0) {
769 break;
770 }
771
772 switch (c) {
773 case 'w':
774 wants_wipe = 1;
775 break;
776 case 'b':
777 base_addr = strtoul(optarg, 0, 16);
778 break;
779 case 'n':
780 page_size = (unsigned)strtoul(optarg, NULL, 0);
781 if (!page_size) die("invalid page size");
782 break;
783 case 's':
784 serial = optarg;
785 break;
Colin Crossf8387882012-05-24 17:18:41 -0700786 case 'S':
787 sparse_limit = parse_num(optarg);
788 if (sparse_limit < 0) {
789 die("invalid sparse limit");
790 }
791 break;
Colin Cross8879f982012-05-22 17:53:34 -0700792 case 'p':
793 product = optarg;
794 break;
795 case 'c':
796 cmdline = optarg;
797 break;
798 case 'i': {
799 char *endptr = NULL;
800 unsigned long val;
801
802 val = strtoul(optarg, &endptr, 0);
803 if (!endptr || *endptr != '\0' || (val & ~0xffff))
804 die("invalid vendor id '%s'", optarg);
805 vendor_id = (unsigned short)val;
806 break;
807 }
808 case 'h':
809 usage();
810 return 1;
811 case '?':
812 return 1;
813 default:
814 abort();
815 }
816 }
817
818 argc -= optind;
819 argv += optind;
820
821 if (argc == 0 && !wants_wipe) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800822 usage();
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700823 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800824 }
825
Colin Cross8fb6e062012-07-24 16:36:41 -0700826 if (argc > 0 && !strcmp(*argv, "devices")) {
Colin Cross8879f982012-05-22 17:53:34 -0700827 skip(1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800828 list_devices();
829 return 0;
830 }
831
Colin Cross8879f982012-05-22 17:53:34 -0700832 usb = open_device();
Elliott Hughes31dbed72009-10-07 15:38:53 -0700833
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800834 while (argc > 0) {
Colin Cross8879f982012-05-22 17:53:34 -0700835 if(!strcmp(*argv, "getvar")) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800836 require(2);
837 fb_queue_display(argv[1], argv[1]);
838 skip(2);
839 } else if(!strcmp(*argv, "erase")) {
840 require(2);
841 fb_queue_erase(argv[1]);
842 skip(2);
Anatol Pomazauc8ba5362011-12-15 17:50:18 -0800843 } else if(!strcmp(*argv, "format")) {
844 require(2);
JP Abgrall30ae5802012-05-07 20:25:24 -0700845 fb_queue_format(argv[1], 0);
Anatol Pomazauc8ba5362011-12-15 17:50:18 -0800846 skip(2);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800847 } else if(!strcmp(*argv, "signature")) {
848 require(2);
849 data = load_file(argv[1], &sz);
850 if (data == 0) die("could not load '%s'", argv[1]);
851 if (sz != 256) die("signature must be 256 bytes");
852 fb_queue_download("signature", data, sz);
853 fb_queue_command("signature", "installing signature");
854 skip(2);
855 } else if(!strcmp(*argv, "reboot")) {
856 wants_reboot = 1;
857 skip(1);
858 } else if(!strcmp(*argv, "reboot-bootloader")) {
859 wants_reboot_bootloader = 1;
860 skip(1);
861 } else if (!strcmp(*argv, "continue")) {
862 fb_queue_command("continue", "resuming boot");
863 skip(1);
864 } else if(!strcmp(*argv, "boot")) {
865 char *kname = 0;
866 char *rname = 0;
867 skip(1);
868 if (argc > 0) {
869 kname = argv[0];
870 skip(1);
871 }
872 if (argc > 0) {
873 rname = argv[0];
874 skip(1);
875 }
Dima Zavin931175a2010-02-12 20:26:33 -0800876 data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800877 if (data == 0) return 1;
878 fb_queue_download("boot.img", data, sz);
879 fb_queue_command("boot", "booting");
880 } else if(!strcmp(*argv, "flash")) {
881 char *pname = argv[1];
882 char *fname = 0;
883 require(2);
884 if (argc > 2) {
885 fname = argv[2];
886 skip(3);
887 } else {
888 fname = find_item(pname, product);
889 skip(2);
890 }
891 if (fname == 0) die("cannot determine image filename for '%s'", pname);
Colin Crossf8387882012-05-24 17:18:41 -0700892 do_flash(usb, pname, fname);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800893 } else if(!strcmp(*argv, "flash:raw")) {
894 char *pname = argv[1];
895 char *kname = argv[2];
896 char *rname = 0;
897 require(3);
898 if(argc > 3) {
899 rname = argv[3];
900 skip(4);
901 } else {
902 skip(3);
903 }
Dima Zavin931175a2010-02-12 20:26:33 -0800904 data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800905 if (data == 0) die("cannot load bootable image");
906 fb_queue_flash(pname, data, sz);
907 } else if(!strcmp(*argv, "flashall")) {
908 skip(1);
909 do_flashall();
910 wants_reboot = 1;
911 } else if(!strcmp(*argv, "update")) {
912 if (argc > 1) {
913 do_update(argv[1]);
914 skip(2);
915 } else {
916 do_update("update.zip");
917 skip(1);
918 }
919 wants_reboot = 1;
920 } else if(!strcmp(*argv, "oem")) {
921 argc = do_oem_command(argc, argv);
Colin Cross8879f982012-05-22 17:53:34 -0700922 } else if (!strcmp(*argv, "help")) {
923 usage();
924 return 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800925 } else {
926 usage();
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800927 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800928 }
929 }
930
931 if (wants_wipe) {
932 fb_queue_erase("userdata");
JP Abgrall30ae5802012-05-07 20:25:24 -0700933 fb_queue_format("userdata", 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800934 fb_queue_erase("cache");
JP Abgrall30ae5802012-05-07 20:25:24 -0700935 fb_queue_format("cache", 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800936 }
937 if (wants_reboot) {
938 fb_queue_reboot();
939 } else if (wants_reboot_bootloader) {
940 fb_queue_command("reboot-bootloader", "rebooting into bootloader");
941 }
942
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700943 status = fb_execute_queue(usb);
944 return (status) ? 1 : 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800945}