blob: 06a6a133df135d120dd7905c6838a9bd9a80e21e [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;
Scott Anderson13081c62012-04-06 12:39:30 -070073static int long_listing = 0;
Colin Crossf8387882012-05-24 17:18:41 -070074static int64_t sparse_limit = -1;
75static int64_t target_sparse_limit = -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080076
Brian Swetland2a63bb72009-04-28 16:05:07 -070077static unsigned base_addr = 0x10000000;
78
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080079void die(const char *fmt, ...)
80{
81 va_list ap;
82 va_start(ap, fmt);
83 fprintf(stderr,"error: ");
84 vfprintf(stderr, fmt, ap);
85 fprintf(stderr,"\n");
86 va_end(ap);
87 exit(1);
Tsu Chiang Chuangee520552011-02-25 18:38:53 -080088}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080089
90void get_my_path(char *path);
91
92char *find_item(const char *item, const char *product)
93{
94 char *dir;
95 char *fn;
96 char path[PATH_MAX + 128];
97
98 if(!strcmp(item,"boot")) {
99 fn = "boot.img";
100 } else if(!strcmp(item,"recovery")) {
101 fn = "recovery.img";
102 } else if(!strcmp(item,"system")) {
103 fn = "system.img";
104 } else if(!strcmp(item,"userdata")) {
105 fn = "userdata.img";
Jean-Baptiste Querud7608a42011-09-30 14:39:25 -0700106 } else if(!strcmp(item,"cache")) {
107 fn = "cache.img";
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800108 } else if(!strcmp(item,"info")) {
109 fn = "android-info.txt";
110 } else {
111 fprintf(stderr,"unknown partition '%s'\n", item);
112 return 0;
113 }
114
115 if(product) {
116 get_my_path(path);
117 sprintf(path + strlen(path),
118 "../../../target/product/%s/%s", product, fn);
119 return strdup(path);
120 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800121
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800122 dir = getenv("ANDROID_PRODUCT_OUT");
123 if((dir == 0) || (dir[0] == 0)) {
124 die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
125 return 0;
126 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800127
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800128 sprintf(path, "%s/%s", dir, fn);
129 return strdup(path);
130}
131
132#ifdef _WIN32
133void *load_file(const char *fn, unsigned *_sz);
Colin Crossf8387882012-05-24 17:18:41 -0700134int64_t file_size(const char *fn);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800135#else
Colin Crossf8387882012-05-24 17:18:41 -0700136#if defined(__APPLE__) && defined(__MACH__)
137#define lseek64 lseek
138#define off64_t off_t
139#endif
140
141int64_t file_size(const char *fn)
142{
143 off64_t off;
144 int fd;
145
146 fd = open(fn, O_RDONLY);
147 if (fd < 0) return -1;
148
149 off = lseek64(fd, 0, SEEK_END);
150 close(fd);
151
152 return off;
153}
154
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800155void *load_file(const char *fn, unsigned *_sz)
156{
157 char *data;
158 int sz;
159 int fd;
Matt Gumbel64ba2582011-12-08 11:59:38 -0800160 int errno_tmp;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800161
162 data = 0;
163 fd = open(fn, O_RDONLY);
164 if(fd < 0) return 0;
165
166 sz = lseek(fd, 0, SEEK_END);
167 if(sz < 0) goto oops;
168
169 if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
170
171 data = (char*) malloc(sz);
172 if(data == 0) goto oops;
173
174 if(read(fd, data, sz) != sz) goto oops;
175 close(fd);
176
177 if(_sz) *_sz = sz;
178 return data;
179
180oops:
Matt Gumbel64ba2582011-12-08 11:59:38 -0800181 errno_tmp = errno;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800182 close(fd);
183 if(data != 0) free(data);
Matt Gumbel64ba2582011-12-08 11:59:38 -0800184 errno = errno_tmp;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800185 return 0;
186}
187#endif
188
189int match_fastboot(usb_ifc_info *info)
190{
JP Abgralla032ded2012-06-06 11:53:33 -0700191 return match_fastboot_with_serial(info, serial);
192}
193
194int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
195{
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800196 if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
Mike Lockwood09070d92009-08-05 17:04:36 -0400197 (info->dev_vendor != 0x18d1) && // Google
Wu, Haof60e8632012-01-17 12:04:11 -0800198 (info->dev_vendor != 0x8087) && // Intel
The Android Open Source Projectf614d642009-03-18 17:39:49 -0700199 (info->dev_vendor != 0x0451) &&
Robert CH Choue25ff1c2009-09-21 09:51:35 +0800200 (info->dev_vendor != 0x0502) &&
Dima Zavin509f7392010-05-14 14:48:30 -0700201 (info->dev_vendor != 0x0fce) && // Sony Ericsson
202 (info->dev_vendor != 0x05c6) && // Qualcomm
Mike Lockwood09070d92009-08-05 17:04:36 -0400203 (info->dev_vendor != 0x22b8) && // Motorola
Erik Gilling37e9e902010-01-20 17:40:05 -0800204 (info->dev_vendor != 0x0955) && // Nvidia
Xavier Ducrohetaf82f212010-01-21 17:39:25 -0800205 (info->dev_vendor != 0x413c) && // DELL
Xavier Ducrohet746f3242012-01-13 16:03:37 -0800206 (info->dev_vendor != 0x2314) && // INQ Mobile
Ramanan Rajeswaran73c019b2012-02-24 13:00:34 -0800207 (info->dev_vendor != 0x0b05) && // Asus
Mike Lockwood09070d92009-08-05 17:04:36 -0400208 (info->dev_vendor != 0x0bb4)) // HTC
209 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800210 if(info->ifc_class != 0xff) return -1;
211 if(info->ifc_subclass != 0x42) return -1;
212 if(info->ifc_protocol != 0x03) return -1;
Scott Anderson13081c62012-04-06 12:39:30 -0700213 // require matching serial number or device path if requested
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800214 // at the command line with the -s option.
JP Abgralla032ded2012-06-06 11:53:33 -0700215 if (local_serial && (strcmp(local_serial, info->serial_number) != 0 &&
216 strcmp(local_serial, info->device_path) != 0)) return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800217 return 0;
218}
219
220int list_devices_callback(usb_ifc_info *info)
221{
JP Abgralla032ded2012-06-06 11:53:33 -0700222 if (match_fastboot_with_serial(info, NULL) == 0) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800223 char* serial = info->serial_number;
Elliott Hughesb4add9b2009-10-06 18:07:49 -0700224 if (!info->writable) {
225 serial = "no permissions"; // like "adb devices"
226 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800227 if (!serial[0]) {
228 serial = "????????????";
229 }
Scott Anderson866b1bd2012-06-04 20:29:11 -0700230 // output compatible with "adb devices"
Scott Anderson13081c62012-04-06 12:39:30 -0700231 if (!long_listing) {
Scott Anderson13081c62012-04-06 12:39:30 -0700232 printf("%s\tfastboot\n", serial);
Scott Anderson866b1bd2012-06-04 20:29:11 -0700233 } else if (!info->device_path) {
234 printf("%-22s fastboot\n", serial);
Scott Anderson13081c62012-04-06 12:39:30 -0700235 } else {
Scott Anderson866b1bd2012-06-04 20:29:11 -0700236 printf("%-22s fastboot %s\n", serial, info->device_path);
Scott Anderson13081c62012-04-06 12:39:30 -0700237 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800238 }
239
240 return -1;
241}
242
243usb_handle *open_device(void)
244{
245 static usb_handle *usb = 0;
246 int announce = 1;
247
248 if(usb) return usb;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800249
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800250 for(;;) {
251 usb = usb_open(match_fastboot);
252 if(usb) return usb;
253 if(announce) {
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800254 announce = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800255 fprintf(stderr,"< waiting for device >\n");
256 }
257 sleep(1);
258 }
259}
260
261void list_devices(void) {
262 // We don't actually open a USB device here,
263 // just getting our callback called so we can
264 // list all the connected devices.
265 usb_open(list_devices_callback);
266}
267
268void usage(void)
269{
270 fprintf(stderr,
271/* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */
272 "usage: fastboot [ <option> ] <command>\n"
273 "\n"
274 "commands:\n"
275 " update <filename> reflash device from update.zip\n"
276 " flashall flash boot + recovery + system\n"
277 " flash <partition> [ <filename> ] write a file to a flash partition\n"
278 " erase <partition> erase a flash partition\n"
Anatol Pomazauc8ba5362011-12-15 17:50:18 -0800279 " format <partition> format a flash partition \n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800280 " getvar <variable> display a bootloader variable\n"
281 " boot <kernel> [ <ramdisk> ] download and boot kernel\n"
282 " flash:raw boot <kernel> [ <ramdisk> ] create bootimage and flash it\n"
283 " devices list all connected devices\n"
Bruce Beare24ce4bc2010-10-14 09:43:26 -0700284 " continue continue with autoboot\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800285 " reboot reboot device normally\n"
286 " reboot-bootloader reboot device into bootloader\n"
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800287 " help show this help message\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800288 "\n"
289 "options:\n"
290 " -w erase userdata and cache\n"
Scott Anderson13081c62012-04-06 12:39:30 -0700291 " -s <specific device> specify device serial number\n"
292 " or path to device port\n"
293 " -l with \"devices\", lists device paths\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800294 " -p <product> specify product name\n"
295 " -c <cmdline> override kernel commandline\n"
296 " -i <vendor id> specify a custom USB vendor id\n"
Dima Zavin95ec9832009-04-30 15:03:05 -0700297 " -b <base_addr> specify a custom kernel base address\n"
Dima Zavin931175a2010-02-12 20:26:33 -0800298 " -n <page size> specify the nand page size. default: 2048\n"
Colin Crossf8387882012-05-24 17:18:41 -0700299 " -S <size>[K|M|G] automatically sparse files greater than\n"
Colin Cross0bbfb392012-07-24 18:05:21 -0700300 " size. 0 to disable\n"
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800301 );
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800302}
303
Dima Zavin931175a2010-02-12 20:26:33 -0800304void *load_bootable_image(unsigned page_size, const char *kernel, const char *ramdisk,
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800305 unsigned *sz, const char *cmdline)
306{
307 void *kdata = 0, *rdata = 0;
308 unsigned ksize = 0, rsize = 0;
309 void *bdata;
310 unsigned bsize;
311
312 if(kernel == 0) {
313 fprintf(stderr, "no image specified\n");
314 return 0;
315 }
316
317 kdata = load_file(kernel, &ksize);
318 if(kdata == 0) {
Matt Gumbel64ba2582011-12-08 11:59:38 -0800319 fprintf(stderr, "cannot load '%s': %s\n", kernel, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800320 return 0;
321 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800322
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800323 /* is this actually a boot image? */
324 if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
325 if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800326
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800327 if(ramdisk) {
328 fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
329 return 0;
330 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800331
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800332 *sz = ksize;
333 return kdata;
334 }
335
336 if(ramdisk) {
337 rdata = load_file(ramdisk, &rsize);
338 if(rdata == 0) {
Matt Gumbel64ba2582011-12-08 11:59:38 -0800339 fprintf(stderr,"cannot load '%s': %s\n", ramdisk, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800340 return 0;
341 }
342 }
343
344 fprintf(stderr,"creating boot image...\n");
Dima Zavin931175a2010-02-12 20:26:33 -0800345 bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, page_size, base_addr, &bsize);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800346 if(bdata == 0) {
347 fprintf(stderr,"failed to create boot.img\n");
348 return 0;
349 }
350 if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
351 fprintf(stderr,"creating boot image - %d bytes\n", bsize);
352 *sz = bsize;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800353
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800354 return bdata;
355}
356
357void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
358{
359 void *data;
360 zipentry_t entry;
361 unsigned datasz;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800362
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800363 entry = lookup_zipentry(zip, name);
364 if (entry == NULL) {
365 fprintf(stderr, "archive does not contain '%s'\n", name);
366 return 0;
367 }
368
369 *sz = get_zipentry_size(entry);
370
371 datasz = *sz * 1.001;
372 data = malloc(datasz);
373
374 if(data == 0) {
375 fprintf(stderr, "failed to allocate %d bytes\n", *sz);
376 return 0;
377 }
378
379 if (decompress_zipentry(entry, data, datasz)) {
380 fprintf(stderr, "failed to unzip '%s' from archive\n", name);
381 free(data);
382 return 0;
383 }
384
385 return data;
386}
387
388static char *strip(char *s)
389{
390 int n;
391 while(*s && isspace(*s)) s++;
392 n = strlen(s);
393 while(n-- > 0) {
394 if(!isspace(s[n])) break;
395 s[n] = 0;
396 }
397 return s;
398}
399
400#define MAX_OPTIONS 32
401static int setup_requirement_line(char *name)
402{
403 char *val[MAX_OPTIONS];
404 const char **out;
Wink Savilleb98762f2011-04-04 17:54:59 -0700405 char *prod = NULL;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800406 unsigned n, count;
407 char *x;
408 int invert = 0;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800409
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800410 if (!strncmp(name, "reject ", 7)) {
411 name += 7;
412 invert = 1;
413 } else if (!strncmp(name, "require ", 8)) {
414 name += 8;
415 invert = 0;
Wink Savilleb98762f2011-04-04 17:54:59 -0700416 } else if (!strncmp(name, "require-for-product:", 20)) {
417 // Get the product and point name past it
418 prod = name + 20;
419 name = strchr(name, ' ');
420 if (!name) return -1;
421 *name = 0;
422 name += 1;
423 invert = 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800424 }
425
426 x = strchr(name, '=');
427 if (x == 0) return 0;
428 *x = 0;
429 val[0] = x + 1;
430
431 for(count = 1; count < MAX_OPTIONS; count++) {
432 x = strchr(val[count - 1],'|');
433 if (x == 0) break;
434 *x = 0;
435 val[count] = x + 1;
436 }
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800437
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800438 name = strip(name);
439 for(n = 0; n < count; n++) val[n] = strip(val[n]);
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800440
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800441 name = strip(name);
442 if (name == 0) return -1;
443
444 /* work around an unfortunate name mismatch */
445 if (!strcmp(name,"board")) name = "product";
446
447 out = malloc(sizeof(char*) * count);
448 if (out == 0) return -1;
449
450 for(n = 0; n < count; n++) {
451 out[n] = strdup(strip(val[n]));
452 if (out[n] == 0) return -1;
453 }
454
Wink Savilleb98762f2011-04-04 17:54:59 -0700455 fb_queue_require(prod, name, invert, n, out);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800456 return 0;
457}
458
459static void setup_requirements(char *data, unsigned sz)
460{
461 char *s;
462
463 s = data;
464 while (sz-- > 0) {
465 if(*s == '\n') {
466 *s++ = 0;
467 if (setup_requirement_line(data)) {
468 die("out of memory");
469 }
470 data = s;
471 } else {
472 s++;
473 }
474 }
475}
476
477void queue_info_dump(void)
478{
479 fb_queue_notice("--------------------------------------------");
480 fb_queue_display("version-bootloader", "Bootloader Version...");
481 fb_queue_display("version-baseband", "Baseband Version.....");
482 fb_queue_display("serialno", "Serial Number........");
483 fb_queue_notice("--------------------------------------------");
484}
485
Colin Crossf8387882012-05-24 17:18:41 -0700486
487struct sparse_file **load_sparse_files(const char *fname, int max_size)
488{
489 int fd;
490 struct sparse_file *s;
491 int files;
492 struct sparse_file **out_s;
493
494 fd = open(fname, O_RDONLY | O_BINARY);
495 if (fd < 0) {
496 die("cannot open '%s'\n", fname);
497 }
498
499 s = sparse_file_import_auto(fd, false);
500 if (!s) {
501 die("cannot sparse read file '%s'\n", fname);
502 }
503
504 files = sparse_file_resparse(s, max_size, NULL, 0);
505 if (files < 0) {
506 die("Failed to resparse '%s'\n", fname);
507 }
508
509 out_s = calloc(sizeof(struct sparse_file *), files + 1);
510 if (!out_s) {
511 die("Failed to allocate sparse file array\n");
512 }
513
514 files = sparse_file_resparse(s, max_size, out_s, files);
515 if (files < 0) {
516 die("Failed to resparse '%s'\n", fname);
517 }
518
519 return out_s;
520}
521
522static int64_t get_target_sparse_limit(struct usb_handle *usb)
523{
524 int64_t limit = 0;
525 char response[FB_RESPONSE_SZ + 1];
526 int status = fb_getvar(usb, response, "max-download-size");
527
528 if (!status) {
529 limit = strtoul(response, NULL, 0);
530 if (limit > 0) {
531 fprintf(stderr, "target reported max download size of %lld bytes\n",
532 limit);
533 }
534 }
535
536 return limit;
537}
538
539static int64_t get_sparse_limit(struct usb_handle *usb, int64_t size)
540{
541 int64_t limit;
542
543 if (sparse_limit == 0) {
544 return 0;
545 } else if (sparse_limit > 0) {
546 limit = sparse_limit;
547 } else {
548 if (target_sparse_limit == -1) {
549 target_sparse_limit = get_target_sparse_limit(usb);
550 }
551 if (target_sparse_limit > 0) {
552 limit = target_sparse_limit;
553 } else {
Colin Cross0bbfb392012-07-24 18:05:21 -0700554 return 0;
Colin Crossf8387882012-05-24 17:18:41 -0700555 }
556 }
557
558 if (size > limit) {
559 return limit;
560 }
561
562 return 0;
563}
564
565void do_flash(usb_handle *usb, const char *pname, const char *fname)
566{
567 int64_t sz64;
568 void *data;
569 int64_t limit;
570
571 sz64 = file_size(fname);
572 limit = get_sparse_limit(usb, sz64);
573 if (limit) {
574 struct sparse_file **s = load_sparse_files(fname, limit);
575 if (s == NULL) {
576 die("cannot sparse load '%s'\n", fname);
577 }
578 while (*s) {
579 sz64 = sparse_file_len(*s, true, false);
580 fb_queue_flash_sparse(pname, *s++, sz64);
581 }
582 } else {
583 unsigned int sz;
584 data = load_file(fname, &sz);
Matt Gumbel64ba2582011-12-08 11:59:38 -0800585 if (data == 0) die("cannot load '%s': %s\n", fname, strerror(errno));
Colin Crossf8387882012-05-24 17:18:41 -0700586 fb_queue_flash(pname, data, sz);
587 }
588}
589
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800590void do_update_signature(zipfile_t zip, char *fn)
591{
592 void *data;
593 unsigned sz;
594 data = unzip_file(zip, fn, &sz);
595 if (data == 0) return;
596 fb_queue_download("signature", data, sz);
597 fb_queue_command("signature", "installing signature");
598}
599
600void do_update(char *fn)
601{
602 void *zdata;
603 unsigned zsize;
604 void *data;
605 unsigned sz;
606 zipfile_t zip;
607
608 queue_info_dump();
609
Wink Savilleb98762f2011-04-04 17:54:59 -0700610 fb_queue_query_save("product", cur_product, sizeof(cur_product));
611
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800612 zdata = load_file(fn, &zsize);
Matt Gumbel64ba2582011-12-08 11:59:38 -0800613 if (zdata == 0) die("failed to load '%s': %s", fn, strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800614
615 zip = init_zipfile(zdata, zsize);
616 if(zip == 0) die("failed to access zipdata in '%s'");
617
618 data = unzip_file(zip, "android-info.txt", &sz);
619 if (data == 0) {
620 char *tmp;
621 /* fallback for older zipfiles */
622 data = unzip_file(zip, "android-product.txt", &sz);
623 if ((data == 0) || (sz < 1)) {
624 die("update package has no android-info.txt or android-product.txt");
625 }
626 tmp = malloc(sz + 128);
627 if (tmp == 0) die("out of memory");
628 sprintf(tmp,"board=%sversion-baseband=0.66.04.19\n",(char*)data);
629 data = tmp;
630 sz = strlen(tmp);
631 }
632
633 setup_requirements(data, sz);
634
635 data = unzip_file(zip, "boot.img", &sz);
636 if (data == 0) die("update package missing boot.img");
637 do_update_signature(zip, "boot.sig");
638 fb_queue_flash("boot", data, sz);
639
640 data = unzip_file(zip, "recovery.img", &sz);
641 if (data != 0) {
642 do_update_signature(zip, "recovery.sig");
643 fb_queue_flash("recovery", data, sz);
644 }
645
646 data = unzip_file(zip, "system.img", &sz);
647 if (data == 0) die("update package missing system.img");
648 do_update_signature(zip, "system.sig");
649 fb_queue_flash("system", data, sz);
650}
651
652void do_send_signature(char *fn)
653{
654 void *data;
655 unsigned sz;
656 char *xtn;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800657
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800658 xtn = strrchr(fn, '.');
659 if (!xtn) return;
660 if (strcmp(xtn, ".img")) return;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800661
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800662 strcpy(xtn,".sig");
663 data = load_file(fn, &sz);
664 strcpy(xtn,".img");
665 if (data == 0) return;
666 fb_queue_download("signature", data, sz);
667 fb_queue_command("signature", "installing signature");
668}
669
670void do_flashall(void)
671{
672 char *fname;
673 void *data;
674 unsigned sz;
675
676 queue_info_dump();
677
Wink Savilleb98762f2011-04-04 17:54:59 -0700678 fb_queue_query_save("product", cur_product, sizeof(cur_product));
679
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800680 fname = find_item("info", product);
681 if (fname == 0) die("cannot find android-info.txt");
682 data = load_file(fname, &sz);
Matt Gumbel64ba2582011-12-08 11:59:38 -0800683 if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800684 setup_requirements(data, sz);
685
686 fname = find_item("boot", product);
687 data = load_file(fname, &sz);
Matt Gumbel64ba2582011-12-08 11:59:38 -0800688 if (data == 0) die("could not load boot.img: %s", strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800689 do_send_signature(fname);
690 fb_queue_flash("boot", data, sz);
691
692 fname = find_item("recovery", product);
693 data = load_file(fname, &sz);
694 if (data != 0) {
695 do_send_signature(fname);
696 fb_queue_flash("recovery", data, sz);
697 }
698
699 fname = find_item("system", product);
700 data = load_file(fname, &sz);
Matt Gumbel64ba2582011-12-08 11:59:38 -0800701 if (data == 0) die("could not load system.img: %s", strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800702 do_send_signature(fname);
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800703 fb_queue_flash("system", data, sz);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800704}
705
706#define skip(n) do { argc -= (n); argv += (n); } while (0)
JP Abgrall2d13d142011-03-01 23:35:07 -0800707#define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800708
709int do_oem_command(int argc, char **argv)
710{
711 int i;
712 char command[256];
713 if (argc <= 1) return 0;
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800714
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800715 command[0] = 0;
716 while(1) {
717 strcat(command,*argv);
718 skip(1);
719 if(argc == 0) break;
720 strcat(command," ");
721 }
722
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800723 fb_queue_command(command,"");
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800724 return 0;
725}
726
Colin Crossf8387882012-05-24 17:18:41 -0700727static int64_t parse_num(const char *arg)
728{
729 char *endptr;
730 unsigned long long num;
731
732 num = strtoull(arg, &endptr, 0);
733 if (endptr == arg) {
734 return -1;
735 }
736
737 if (*endptr == 'k' || *endptr == 'K') {
738 if (num >= (-1ULL) / 1024) {
739 return -1;
740 }
741 num *= 1024LL;
742 endptr++;
743 } else if (*endptr == 'm' || *endptr == 'M') {
744 if (num >= (-1ULL) / (1024 * 1024)) {
745 return -1;
746 }
747 num *= 1024LL * 1024LL;
748 endptr++;
749 } else if (*endptr == 'g' || *endptr == 'G') {
750 if (num >= (-1ULL) / (1024 * 1024 * 1024)) {
751 return -1;
752 }
753 num *= 1024LL * 1024LL * 1024LL;
754 endptr++;
755 }
756
757 if (*endptr != '\0') {
758 return -1;
759 }
760
761 if (num > INT64_MAX) {
762 return -1;
763 }
764
765 return num;
766}
767
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800768int main(int argc, char **argv)
769{
770 int wants_wipe = 0;
771 int wants_reboot = 0;
772 int wants_reboot_bootloader = 0;
773 void *data;
774 unsigned sz;
Dima Zavin931175a2010-02-12 20:26:33 -0800775 unsigned page_size = 2048;
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700776 int status;
Colin Cross8879f982012-05-22 17:53:34 -0700777 int c;
Colin Crossf8387882012-05-24 17:18:41 -0700778 int r;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800779
Colin Crossf8387882012-05-24 17:18:41 -0700780 const struct option longopts = { 0, 0, 0, 0 };
Colin Cross8879f982012-05-22 17:53:34 -0700781
782 serial = getenv("ANDROID_SERIAL");
783
784 while (1) {
Colin Cross9a70e5c2012-07-17 23:35:21 -0700785 c = getopt_long(argc, argv, "wb:n:s:S:lp:c:i:m:h", &longopts, NULL);
Colin Cross8879f982012-05-22 17:53:34 -0700786 if (c < 0) {
787 break;
788 }
789
790 switch (c) {
791 case 'w':
792 wants_wipe = 1;
793 break;
794 case 'b':
795 base_addr = strtoul(optarg, 0, 16);
796 break;
797 case 'n':
798 page_size = (unsigned)strtoul(optarg, NULL, 0);
799 if (!page_size) die("invalid page size");
800 break;
801 case 's':
802 serial = optarg;
803 break;
Colin Crossf8387882012-05-24 17:18:41 -0700804 case 'S':
805 sparse_limit = parse_num(optarg);
806 if (sparse_limit < 0) {
807 die("invalid sparse limit");
808 }
809 break;
Colin Cross9a70e5c2012-07-17 23:35:21 -0700810 case 'l':
811 long_listing = 1;
812 break;
Colin Cross8879f982012-05-22 17:53:34 -0700813 case 'p':
814 product = optarg;
815 break;
816 case 'c':
817 cmdline = optarg;
818 break;
819 case 'i': {
820 char *endptr = NULL;
821 unsigned long val;
822
823 val = strtoul(optarg, &endptr, 0);
824 if (!endptr || *endptr != '\0' || (val & ~0xffff))
825 die("invalid vendor id '%s'", optarg);
826 vendor_id = (unsigned short)val;
827 break;
828 }
829 case 'h':
830 usage();
831 return 1;
832 case '?':
833 return 1;
834 default:
835 abort();
836 }
837 }
838
839 argc -= optind;
840 argv += optind;
841
842 if (argc == 0 && !wants_wipe) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800843 usage();
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700844 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800845 }
846
Colin Cross8fb6e062012-07-24 16:36:41 -0700847 if (argc > 0 && !strcmp(*argv, "devices")) {
Colin Cross8879f982012-05-22 17:53:34 -0700848 skip(1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800849 list_devices();
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800850 return 0;
851 }
852
Colin Crossc7b75dc2012-08-29 18:17:06 -0700853 if (argc > 0 && !strcmp(*argv, "help")) {
854 usage();
855 return 0;
856 }
857
Colin Cross8879f982012-05-22 17:53:34 -0700858 usb = open_device();
Elliott Hughes31dbed72009-10-07 15:38:53 -0700859
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800860 while (argc > 0) {
Colin Cross8879f982012-05-22 17:53:34 -0700861 if(!strcmp(*argv, "getvar")) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800862 require(2);
863 fb_queue_display(argv[1], argv[1]);
864 skip(2);
865 } else if(!strcmp(*argv, "erase")) {
866 require(2);
867 fb_queue_erase(argv[1]);
868 skip(2);
Anatol Pomazauc8ba5362011-12-15 17:50:18 -0800869 } else if(!strcmp(*argv, "format")) {
870 require(2);
JP Abgrall30ae5802012-05-07 20:25:24 -0700871 fb_queue_format(argv[1], 0);
Anatol Pomazauc8ba5362011-12-15 17:50:18 -0800872 skip(2);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800873 } else if(!strcmp(*argv, "signature")) {
874 require(2);
875 data = load_file(argv[1], &sz);
Matt Gumbel64ba2582011-12-08 11:59:38 -0800876 if (data == 0) die("could not load '%s': %s", argv[1], strerror(errno));
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800877 if (sz != 256) die("signature must be 256 bytes");
878 fb_queue_download("signature", data, sz);
879 fb_queue_command("signature", "installing signature");
880 skip(2);
881 } else if(!strcmp(*argv, "reboot")) {
882 wants_reboot = 1;
883 skip(1);
884 } else if(!strcmp(*argv, "reboot-bootloader")) {
885 wants_reboot_bootloader = 1;
886 skip(1);
887 } else if (!strcmp(*argv, "continue")) {
888 fb_queue_command("continue", "resuming boot");
889 skip(1);
890 } else if(!strcmp(*argv, "boot")) {
891 char *kname = 0;
892 char *rname = 0;
893 skip(1);
894 if (argc > 0) {
895 kname = argv[0];
896 skip(1);
897 }
898 if (argc > 0) {
899 rname = argv[0];
900 skip(1);
901 }
Dima Zavin931175a2010-02-12 20:26:33 -0800902 data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800903 if (data == 0) return 1;
904 fb_queue_download("boot.img", data, sz);
905 fb_queue_command("boot", "booting");
906 } else if(!strcmp(*argv, "flash")) {
907 char *pname = argv[1];
908 char *fname = 0;
909 require(2);
910 if (argc > 2) {
911 fname = argv[2];
912 skip(3);
913 } else {
914 fname = find_item(pname, product);
915 skip(2);
916 }
917 if (fname == 0) die("cannot determine image filename for '%s'", pname);
Colin Crossf8387882012-05-24 17:18:41 -0700918 do_flash(usb, pname, fname);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800919 } else if(!strcmp(*argv, "flash:raw")) {
920 char *pname = argv[1];
921 char *kname = argv[2];
922 char *rname = 0;
923 require(3);
924 if(argc > 3) {
925 rname = argv[3];
926 skip(4);
927 } else {
928 skip(3);
929 }
Dima Zavin931175a2010-02-12 20:26:33 -0800930 data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800931 if (data == 0) die("cannot load bootable image");
932 fb_queue_flash(pname, data, sz);
933 } else if(!strcmp(*argv, "flashall")) {
934 skip(1);
935 do_flashall();
936 wants_reboot = 1;
937 } else if(!strcmp(*argv, "update")) {
938 if (argc > 1) {
939 do_update(argv[1]);
940 skip(2);
941 } else {
942 do_update("update.zip");
943 skip(1);
944 }
945 wants_reboot = 1;
946 } else if(!strcmp(*argv, "oem")) {
947 argc = do_oem_command(argc, argv);
948 } else {
949 usage();
Tsu Chiang Chuangee520552011-02-25 18:38:53 -0800950 return 1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800951 }
952 }
953
954 if (wants_wipe) {
955 fb_queue_erase("userdata");
JP Abgrall30ae5802012-05-07 20:25:24 -0700956 fb_queue_format("userdata", 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800957 fb_queue_erase("cache");
JP Abgrall30ae5802012-05-07 20:25:24 -0700958 fb_queue_format("cache", 1);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800959 }
960 if (wants_reboot) {
961 fb_queue_reboot();
962 } else if (wants_reboot_bootloader) {
963 fb_queue_command("reboot-bootloader", "rebooting into bootloader");
964 }
965
Scott Anderson13081c62012-04-06 12:39:30 -0700966 if (fb_queue_is_empty())
967 return 0;
968
Brian Carlstromeb31c0b2010-04-23 12:38:51 -0700969 status = fb_execute_queue(usb);
970 return (status) ? 1 : 0;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800971}