30ae5806e9
If the bootloader doesn't support formatting of those partitions (either because it doesn't support the getvar commands needed or the partition type is not supported), the errors are printed but doesn't halt processing of subsequent commands. Change-Id: I816ac2e5e7593846fcb4fd39c793a8dbdd996f6f Signed-off-by: Mike J. Chen <mjchen@google.com>
744 lines
21 KiB
C
744 lines
21 KiB
C
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include <ctype.h>
|
|
|
|
#include <sys/time.h>
|
|
#include <bootimg.h>
|
|
#include <zipfile/zipfile.h>
|
|
|
|
#include "fastboot.h"
|
|
|
|
char cur_product[FB_RESPONSE_SZ + 1];
|
|
|
|
void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
|
|
|
|
boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
|
|
void *ramdisk, unsigned ramdisk_size,
|
|
void *second, unsigned second_size,
|
|
unsigned page_size, unsigned base,
|
|
unsigned *bootimg_size);
|
|
|
|
static usb_handle *usb = 0;
|
|
static const char *serial = 0;
|
|
static const char *product = 0;
|
|
static const char *cmdline = 0;
|
|
static int wipe_data = 0;
|
|
static unsigned short vendor_id = 0;
|
|
|
|
static unsigned base_addr = 0x10000000;
|
|
|
|
void die(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
fprintf(stderr,"error: ");
|
|
vfprintf(stderr, fmt, ap);
|
|
fprintf(stderr,"\n");
|
|
va_end(ap);
|
|
exit(1);
|
|
}
|
|
|
|
void get_my_path(char *path);
|
|
|
|
char *find_item(const char *item, const char *product)
|
|
{
|
|
char *dir;
|
|
char *fn;
|
|
char path[PATH_MAX + 128];
|
|
|
|
if(!strcmp(item,"boot")) {
|
|
fn = "boot.img";
|
|
} else if(!strcmp(item,"recovery")) {
|
|
fn = "recovery.img";
|
|
} else if(!strcmp(item,"system")) {
|
|
fn = "system.img";
|
|
} else if(!strcmp(item,"userdata")) {
|
|
fn = "userdata.img";
|
|
} else if(!strcmp(item,"cache")) {
|
|
fn = "cache.img";
|
|
} else if(!strcmp(item,"info")) {
|
|
fn = "android-info.txt";
|
|
} else {
|
|
fprintf(stderr,"unknown partition '%s'\n", item);
|
|
return 0;
|
|
}
|
|
|
|
if(product) {
|
|
get_my_path(path);
|
|
sprintf(path + strlen(path),
|
|
"../../../target/product/%s/%s", product, fn);
|
|
return strdup(path);
|
|
}
|
|
|
|
dir = getenv("ANDROID_PRODUCT_OUT");
|
|
if((dir == 0) || (dir[0] == 0)) {
|
|
die("neither -p product specified nor ANDROID_PRODUCT_OUT set");
|
|
return 0;
|
|
}
|
|
|
|
sprintf(path, "%s/%s", dir, fn);
|
|
return strdup(path);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
void *load_file(const char *fn, unsigned *_sz);
|
|
#else
|
|
void *load_file(const char *fn, unsigned *_sz)
|
|
{
|
|
char *data;
|
|
int sz;
|
|
int fd;
|
|
|
|
data = 0;
|
|
fd = open(fn, O_RDONLY);
|
|
if(fd < 0) return 0;
|
|
|
|
sz = lseek(fd, 0, SEEK_END);
|
|
if(sz < 0) goto oops;
|
|
|
|
if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
|
|
|
|
data = (char*) malloc(sz);
|
|
if(data == 0) goto oops;
|
|
|
|
if(read(fd, data, sz) != sz) goto oops;
|
|
close(fd);
|
|
|
|
if(_sz) *_sz = sz;
|
|
return data;
|
|
|
|
oops:
|
|
close(fd);
|
|
if(data != 0) free(data);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int match_fastboot(usb_ifc_info *info)
|
|
{
|
|
if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
|
|
(info->dev_vendor != 0x18d1) && // Google
|
|
(info->dev_vendor != 0x8087) && // Intel
|
|
(info->dev_vendor != 0x0451) &&
|
|
(info->dev_vendor != 0x0502) &&
|
|
(info->dev_vendor != 0x0fce) && // Sony Ericsson
|
|
(info->dev_vendor != 0x05c6) && // Qualcomm
|
|
(info->dev_vendor != 0x22b8) && // Motorola
|
|
(info->dev_vendor != 0x0955) && // Nvidia
|
|
(info->dev_vendor != 0x413c) && // DELL
|
|
(info->dev_vendor != 0x2314) && // INQ Mobile
|
|
(info->dev_vendor != 0x0b05) && // Asus
|
|
(info->dev_vendor != 0x0bb4)) // HTC
|
|
return -1;
|
|
if(info->ifc_class != 0xff) return -1;
|
|
if(info->ifc_subclass != 0x42) return -1;
|
|
if(info->ifc_protocol != 0x03) return -1;
|
|
// require matching serial number if a serial number is specified
|
|
// at the command line with the -s option.
|
|
if (serial && strcmp(serial, info->serial_number) != 0) return -1;
|
|
return 0;
|
|
}
|
|
|
|
int list_devices_callback(usb_ifc_info *info)
|
|
{
|
|
if (match_fastboot(info) == 0) {
|
|
char* serial = info->serial_number;
|
|
if (!info->writable) {
|
|
serial = "no permissions"; // like "adb devices"
|
|
}
|
|
if (!serial[0]) {
|
|
serial = "????????????";
|
|
}
|
|
// output compatible with "adb devices"
|
|
printf("%s\tfastboot\n", serial);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
usb_handle *open_device(void)
|
|
{
|
|
static usb_handle *usb = 0;
|
|
int announce = 1;
|
|
|
|
if(usb) return usb;
|
|
|
|
for(;;) {
|
|
usb = usb_open(match_fastboot);
|
|
if(usb) return usb;
|
|
if(announce) {
|
|
announce = 0;
|
|
fprintf(stderr,"< waiting for device >\n");
|
|
}
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
void list_devices(void) {
|
|
// We don't actually open a USB device here,
|
|
// just getting our callback called so we can
|
|
// list all the connected devices.
|
|
usb_open(list_devices_callback);
|
|
}
|
|
|
|
void usage(void)
|
|
{
|
|
fprintf(stderr,
|
|
/* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */
|
|
"usage: fastboot [ <option> ] <command>\n"
|
|
"\n"
|
|
"commands:\n"
|
|
" update <filename> reflash device from update.zip\n"
|
|
" flashall flash boot + recovery + system\n"
|
|
" flash <partition> [ <filename> ] write a file to a flash partition\n"
|
|
" erase <partition> erase a flash partition\n"
|
|
" format <partition> format a flash partition \n"
|
|
" getvar <variable> display a bootloader variable\n"
|
|
" boot <kernel> [ <ramdisk> ] download and boot kernel\n"
|
|
" flash:raw boot <kernel> [ <ramdisk> ] create bootimage and flash it\n"
|
|
" devices list all connected devices\n"
|
|
" continue continue with autoboot\n"
|
|
" reboot reboot device normally\n"
|
|
" reboot-bootloader reboot device into bootloader\n"
|
|
" help show this help message\n"
|
|
"\n"
|
|
"options:\n"
|
|
" -w erase userdata and cache\n"
|
|
" -s <serial number> specify device serial number\n"
|
|
" -p <product> specify product name\n"
|
|
" -c <cmdline> override kernel commandline\n"
|
|
" -i <vendor id> specify a custom USB vendor id\n"
|
|
" -b <base_addr> specify a custom kernel base address\n"
|
|
" -n <page size> specify the nand page size. default: 2048\n"
|
|
);
|
|
}
|
|
|
|
void *load_bootable_image(unsigned page_size, const char *kernel, const char *ramdisk,
|
|
unsigned *sz, const char *cmdline)
|
|
{
|
|
void *kdata = 0, *rdata = 0;
|
|
unsigned ksize = 0, rsize = 0;
|
|
void *bdata;
|
|
unsigned bsize;
|
|
|
|
if(kernel == 0) {
|
|
fprintf(stderr, "no image specified\n");
|
|
return 0;
|
|
}
|
|
|
|
kdata = load_file(kernel, &ksize);
|
|
if(kdata == 0) {
|
|
fprintf(stderr, "cannot load '%s'\n", kernel);
|
|
return 0;
|
|
}
|
|
|
|
/* is this actually a boot image? */
|
|
if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
|
|
if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
|
|
|
|
if(ramdisk) {
|
|
fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
|
|
return 0;
|
|
}
|
|
|
|
*sz = ksize;
|
|
return kdata;
|
|
}
|
|
|
|
if(ramdisk) {
|
|
rdata = load_file(ramdisk, &rsize);
|
|
if(rdata == 0) {
|
|
fprintf(stderr,"cannot load '%s'\n", ramdisk);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
fprintf(stderr,"creating boot image...\n");
|
|
bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, page_size, base_addr, &bsize);
|
|
if(bdata == 0) {
|
|
fprintf(stderr,"failed to create boot.img\n");
|
|
return 0;
|
|
}
|
|
if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
|
|
fprintf(stderr,"creating boot image - %d bytes\n", bsize);
|
|
*sz = bsize;
|
|
|
|
return bdata;
|
|
}
|
|
|
|
void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
|
|
{
|
|
void *data;
|
|
zipentry_t entry;
|
|
unsigned datasz;
|
|
|
|
entry = lookup_zipentry(zip, name);
|
|
if (entry == NULL) {
|
|
fprintf(stderr, "archive does not contain '%s'\n", name);
|
|
return 0;
|
|
}
|
|
|
|
*sz = get_zipentry_size(entry);
|
|
|
|
datasz = *sz * 1.001;
|
|
data = malloc(datasz);
|
|
|
|
if(data == 0) {
|
|
fprintf(stderr, "failed to allocate %d bytes\n", *sz);
|
|
return 0;
|
|
}
|
|
|
|
if (decompress_zipentry(entry, data, datasz)) {
|
|
fprintf(stderr, "failed to unzip '%s' from archive\n", name);
|
|
free(data);
|
|
return 0;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
static char *strip(char *s)
|
|
{
|
|
int n;
|
|
while(*s && isspace(*s)) s++;
|
|
n = strlen(s);
|
|
while(n-- > 0) {
|
|
if(!isspace(s[n])) break;
|
|
s[n] = 0;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
#define MAX_OPTIONS 32
|
|
static int setup_requirement_line(char *name)
|
|
{
|
|
char *val[MAX_OPTIONS];
|
|
const char **out;
|
|
char *prod = NULL;
|
|
unsigned n, count;
|
|
char *x;
|
|
int invert = 0;
|
|
|
|
if (!strncmp(name, "reject ", 7)) {
|
|
name += 7;
|
|
invert = 1;
|
|
} else if (!strncmp(name, "require ", 8)) {
|
|
name += 8;
|
|
invert = 0;
|
|
} else if (!strncmp(name, "require-for-product:", 20)) {
|
|
// Get the product and point name past it
|
|
prod = name + 20;
|
|
name = strchr(name, ' ');
|
|
if (!name) return -1;
|
|
*name = 0;
|
|
name += 1;
|
|
invert = 0;
|
|
}
|
|
|
|
x = strchr(name, '=');
|
|
if (x == 0) return 0;
|
|
*x = 0;
|
|
val[0] = x + 1;
|
|
|
|
for(count = 1; count < MAX_OPTIONS; count++) {
|
|
x = strchr(val[count - 1],'|');
|
|
if (x == 0) break;
|
|
*x = 0;
|
|
val[count] = x + 1;
|
|
}
|
|
|
|
name = strip(name);
|
|
for(n = 0; n < count; n++) val[n] = strip(val[n]);
|
|
|
|
name = strip(name);
|
|
if (name == 0) return -1;
|
|
|
|
/* work around an unfortunate name mismatch */
|
|
if (!strcmp(name,"board")) name = "product";
|
|
|
|
out = malloc(sizeof(char*) * count);
|
|
if (out == 0) return -1;
|
|
|
|
for(n = 0; n < count; n++) {
|
|
out[n] = strdup(strip(val[n]));
|
|
if (out[n] == 0) return -1;
|
|
}
|
|
|
|
fb_queue_require(prod, name, invert, n, out);
|
|
return 0;
|
|
}
|
|
|
|
static void setup_requirements(char *data, unsigned sz)
|
|
{
|
|
char *s;
|
|
|
|
s = data;
|
|
while (sz-- > 0) {
|
|
if(*s == '\n') {
|
|
*s++ = 0;
|
|
if (setup_requirement_line(data)) {
|
|
die("out of memory");
|
|
}
|
|
data = s;
|
|
} else {
|
|
s++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void queue_info_dump(void)
|
|
{
|
|
fb_queue_notice("--------------------------------------------");
|
|
fb_queue_display("version-bootloader", "Bootloader Version...");
|
|
fb_queue_display("version-baseband", "Baseband Version.....");
|
|
fb_queue_display("serialno", "Serial Number........");
|
|
fb_queue_notice("--------------------------------------------");
|
|
}
|
|
|
|
void do_update_signature(zipfile_t zip, char *fn)
|
|
{
|
|
void *data;
|
|
unsigned sz;
|
|
data = unzip_file(zip, fn, &sz);
|
|
if (data == 0) return;
|
|
fb_queue_download("signature", data, sz);
|
|
fb_queue_command("signature", "installing signature");
|
|
}
|
|
|
|
void do_update(char *fn)
|
|
{
|
|
void *zdata;
|
|
unsigned zsize;
|
|
void *data;
|
|
unsigned sz;
|
|
zipfile_t zip;
|
|
|
|
queue_info_dump();
|
|
|
|
fb_queue_query_save("product", cur_product, sizeof(cur_product));
|
|
|
|
zdata = load_file(fn, &zsize);
|
|
if (zdata == 0) die("failed to load '%s'", fn);
|
|
|
|
zip = init_zipfile(zdata, zsize);
|
|
if(zip == 0) die("failed to access zipdata in '%s'");
|
|
|
|
data = unzip_file(zip, "android-info.txt", &sz);
|
|
if (data == 0) {
|
|
char *tmp;
|
|
/* fallback for older zipfiles */
|
|
data = unzip_file(zip, "android-product.txt", &sz);
|
|
if ((data == 0) || (sz < 1)) {
|
|
die("update package has no android-info.txt or android-product.txt");
|
|
}
|
|
tmp = malloc(sz + 128);
|
|
if (tmp == 0) die("out of memory");
|
|
sprintf(tmp,"board=%sversion-baseband=0.66.04.19\n",(char*)data);
|
|
data = tmp;
|
|
sz = strlen(tmp);
|
|
}
|
|
|
|
setup_requirements(data, sz);
|
|
|
|
data = unzip_file(zip, "boot.img", &sz);
|
|
if (data == 0) die("update package missing boot.img");
|
|
do_update_signature(zip, "boot.sig");
|
|
fb_queue_flash("boot", data, sz);
|
|
|
|
data = unzip_file(zip, "recovery.img", &sz);
|
|
if (data != 0) {
|
|
do_update_signature(zip, "recovery.sig");
|
|
fb_queue_flash("recovery", data, sz);
|
|
}
|
|
|
|
data = unzip_file(zip, "system.img", &sz);
|
|
if (data == 0) die("update package missing system.img");
|
|
do_update_signature(zip, "system.sig");
|
|
fb_queue_flash("system", data, sz);
|
|
}
|
|
|
|
void do_send_signature(char *fn)
|
|
{
|
|
void *data;
|
|
unsigned sz;
|
|
char *xtn;
|
|
|
|
xtn = strrchr(fn, '.');
|
|
if (!xtn) return;
|
|
if (strcmp(xtn, ".img")) return;
|
|
|
|
strcpy(xtn,".sig");
|
|
data = load_file(fn, &sz);
|
|
strcpy(xtn,".img");
|
|
if (data == 0) return;
|
|
fb_queue_download("signature", data, sz);
|
|
fb_queue_command("signature", "installing signature");
|
|
}
|
|
|
|
void do_flashall(void)
|
|
{
|
|
char *fname;
|
|
void *data;
|
|
unsigned sz;
|
|
|
|
queue_info_dump();
|
|
|
|
fb_queue_query_save("product", cur_product, sizeof(cur_product));
|
|
|
|
fname = find_item("info", product);
|
|
if (fname == 0) die("cannot find android-info.txt");
|
|
data = load_file(fname, &sz);
|
|
if (data == 0) die("could not load android-info.txt");
|
|
setup_requirements(data, sz);
|
|
|
|
fname = find_item("boot", product);
|
|
data = load_file(fname, &sz);
|
|
if (data == 0) die("could not load boot.img");
|
|
do_send_signature(fname);
|
|
fb_queue_flash("boot", data, sz);
|
|
|
|
fname = find_item("recovery", product);
|
|
data = load_file(fname, &sz);
|
|
if (data != 0) {
|
|
do_send_signature(fname);
|
|
fb_queue_flash("recovery", data, sz);
|
|
}
|
|
|
|
fname = find_item("system", product);
|
|
data = load_file(fname, &sz);
|
|
if (data == 0) die("could not load system.img");
|
|
do_send_signature(fname);
|
|
fb_queue_flash("system", data, sz);
|
|
}
|
|
|
|
#define skip(n) do { argc -= (n); argv += (n); } while (0)
|
|
#define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0)
|
|
|
|
int do_oem_command(int argc, char **argv)
|
|
{
|
|
int i;
|
|
char command[256];
|
|
if (argc <= 1) return 0;
|
|
|
|
command[0] = 0;
|
|
while(1) {
|
|
strcat(command,*argv);
|
|
skip(1);
|
|
if(argc == 0) break;
|
|
strcat(command," ");
|
|
}
|
|
|
|
fb_queue_command(command,"");
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int wants_wipe = 0;
|
|
int wants_reboot = 0;
|
|
int wants_reboot_bootloader = 0;
|
|
void *data;
|
|
unsigned sz;
|
|
unsigned page_size = 2048;
|
|
int status;
|
|
|
|
skip(1);
|
|
if (argc == 0) {
|
|
usage();
|
|
return 1;
|
|
}
|
|
|
|
if (!strcmp(*argv, "devices")) {
|
|
list_devices();
|
|
return 0;
|
|
}
|
|
|
|
if (!strcmp(*argv, "help")) {
|
|
usage();
|
|
return 0;
|
|
}
|
|
|
|
|
|
serial = getenv("ANDROID_SERIAL");
|
|
|
|
while (argc > 0) {
|
|
if(!strcmp(*argv, "-w")) {
|
|
wants_wipe = 1;
|
|
skip(1);
|
|
} else if(!strcmp(*argv, "-b")) {
|
|
require(2);
|
|
base_addr = strtoul(argv[1], 0, 16);
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "-n")) {
|
|
require(2);
|
|
page_size = (unsigned)strtoul(argv[1], NULL, 0);
|
|
if (!page_size) die("invalid page size");
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "-s")) {
|
|
require(2);
|
|
serial = argv[1];
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "-p")) {
|
|
require(2);
|
|
product = argv[1];
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "-c")) {
|
|
require(2);
|
|
cmdline = argv[1];
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "-i")) {
|
|
char *endptr = NULL;
|
|
unsigned long val;
|
|
|
|
require(2);
|
|
val = strtoul(argv[1], &endptr, 0);
|
|
if (!endptr || *endptr != '\0' || (val & ~0xffff))
|
|
die("invalid vendor id '%s'", argv[1]);
|
|
vendor_id = (unsigned short)val;
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "getvar")) {
|
|
require(2);
|
|
fb_queue_display(argv[1], argv[1]);
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "erase")) {
|
|
require(2);
|
|
fb_queue_erase(argv[1]);
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "format")) {
|
|
require(2);
|
|
fb_queue_format(argv[1], 0);
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "signature")) {
|
|
require(2);
|
|
data = load_file(argv[1], &sz);
|
|
if (data == 0) die("could not load '%s'", argv[1]);
|
|
if (sz != 256) die("signature must be 256 bytes");
|
|
fb_queue_download("signature", data, sz);
|
|
fb_queue_command("signature", "installing signature");
|
|
skip(2);
|
|
} else if(!strcmp(*argv, "reboot")) {
|
|
wants_reboot = 1;
|
|
skip(1);
|
|
} else if(!strcmp(*argv, "reboot-bootloader")) {
|
|
wants_reboot_bootloader = 1;
|
|
skip(1);
|
|
} else if (!strcmp(*argv, "continue")) {
|
|
fb_queue_command("continue", "resuming boot");
|
|
skip(1);
|
|
} else if(!strcmp(*argv, "boot")) {
|
|
char *kname = 0;
|
|
char *rname = 0;
|
|
skip(1);
|
|
if (argc > 0) {
|
|
kname = argv[0];
|
|
skip(1);
|
|
}
|
|
if (argc > 0) {
|
|
rname = argv[0];
|
|
skip(1);
|
|
}
|
|
data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
|
|
if (data == 0) return 1;
|
|
fb_queue_download("boot.img", data, sz);
|
|
fb_queue_command("boot", "booting");
|
|
} else if(!strcmp(*argv, "flash")) {
|
|
char *pname = argv[1];
|
|
char *fname = 0;
|
|
require(2);
|
|
if (argc > 2) {
|
|
fname = argv[2];
|
|
skip(3);
|
|
} else {
|
|
fname = find_item(pname, product);
|
|
skip(2);
|
|
}
|
|
if (fname == 0) die("cannot determine image filename for '%s'", pname);
|
|
data = load_file(fname, &sz);
|
|
if (data == 0) die("cannot load '%s'\n", fname);
|
|
fb_queue_flash(pname, data, sz);
|
|
} else if(!strcmp(*argv, "flash:raw")) {
|
|
char *pname = argv[1];
|
|
char *kname = argv[2];
|
|
char *rname = 0;
|
|
require(3);
|
|
if(argc > 3) {
|
|
rname = argv[3];
|
|
skip(4);
|
|
} else {
|
|
skip(3);
|
|
}
|
|
data = load_bootable_image(page_size, kname, rname, &sz, cmdline);
|
|
if (data == 0) die("cannot load bootable image");
|
|
fb_queue_flash(pname, data, sz);
|
|
} else if(!strcmp(*argv, "flashall")) {
|
|
skip(1);
|
|
do_flashall();
|
|
wants_reboot = 1;
|
|
} else if(!strcmp(*argv, "update")) {
|
|
if (argc > 1) {
|
|
do_update(argv[1]);
|
|
skip(2);
|
|
} else {
|
|
do_update("update.zip");
|
|
skip(1);
|
|
}
|
|
wants_reboot = 1;
|
|
} else if(!strcmp(*argv, "oem")) {
|
|
argc = do_oem_command(argc, argv);
|
|
} else {
|
|
usage();
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (wants_wipe) {
|
|
fb_queue_erase("userdata");
|
|
fb_queue_format("userdata", 1);
|
|
fb_queue_erase("cache");
|
|
fb_queue_format("cache", 1);
|
|
}
|
|
if (wants_reboot) {
|
|
fb_queue_reboot();
|
|
} else if (wants_reboot_bootloader) {
|
|
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
|
|
}
|
|
|
|
usb = open_device();
|
|
|
|
status = fb_execute_queue(usb);
|
|
return (status) ? 1 : 0;
|
|
}
|