void do_update(char *fn, int erase_first) { 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': %s", fn, strerror(errno)); 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"); if (erase_first && needs_erase("boot")) { fb_queue_erase("boot"); } fb_queue_flash("boot", data, sz); data = unzip_file(zip, "recovery.img", &sz); if (data != 0) { do_update_signature(zip, "recovery.sig"); if (erase_first && needs_erase("recovery")) { fb_queue_erase("recovery"); } 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"); if (erase_first && needs_erase("system")) { fb_queue_erase("system"); } fb_queue_flash("system", data, sz); }
void do_flashall(usb_handle *usb, int erase_first) { queue_info_dump(); fb_queue_query_save("product", cur_product, sizeof(cur_product)); char* fname = find_item("info", product); if (fname == 0) die("cannot find android-info.txt"); unsigned sz; void* data = load_file(fname, &sz); if (data == 0) die("could not load android-info.txt: %s", strerror(errno)); setup_requirements(reinterpret_cast<char*>(data), sz); for (size_t i = 0; i < ARRAY_SIZE(images); i++) { fname = find_item(images[i].part_name, product); fastboot_buffer buf; if (load_buf(usb, fname, &buf)) { if (images[i].is_optional) continue; die("could not load %s\n", images[i].img_name); } do_send_signature(fname); if (erase_first && needs_erase(usb, images[i].part_name)) { fb_queue_erase(images[i].part_name); } flash_buf(images[i].part_name, &buf); } }
void do_update(usb_handle *usb, char *fn, int erase_first) { void *zdata; unsigned zsize; void *data; unsigned sz; zipfile_t zip; int fd; int rc; struct fastboot_buffer buf; size_t i; 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': %s", fn, strerror(errno)); 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); for (i = 0; i < ARRAY_SIZE(images); i++) { fd = unzip_to_file(zip, images[i].img_name); if (fd < 0) { if (images[i].is_optional) continue; die("update package missing %s", images[i].img_name); } rc = load_buf_fd(usb, fd, &buf); if (rc) die("cannot load %s from flash", images[i].img_name); do_update_signature(zip, images[i].sig_name); if (erase_first && needs_erase(images[i].part_name)) { fb_queue_erase(images[i].part_name); } flash_buf(images[i].part_name, &buf); /* not closing the fd here since the sparse code keeps the fd around * but hasn't mmaped data yet. The tmpfile will get cleaned up when the * program exits. */ } }
void do_flashall(int erase_first) { 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: %s", strerror(errno)); setup_requirements(data, sz); fname = find_item("boot", product); data = load_file(fname, &sz); if (data == 0) die("could not load boot.img: %s", strerror(errno)); do_send_signature(fname); if (erase_first && needs_erase("boot")) { fb_queue_erase("boot"); } fb_queue_flash("boot", data, sz); fname = find_item("recovery", product); data = load_file(fname, &sz); if (data != 0) { do_send_signature(fname); if (erase_first && needs_erase("recovery")) { fb_queue_erase("recovery"); } 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: %s", strerror(errno)); do_send_signature(fname); if (erase_first && needs_erase("system")) { fb_queue_erase("system"); } fb_queue_flash("system", data, sz); }
void do_update(usb_handle *usb, const char *filename, int erase_first) { queue_info_dump(); fb_queue_query_save("product", cur_product, sizeof(cur_product)); ZipArchiveHandle zip; int error = OpenArchive(filename, &zip); if (error != 0) { CloseArchive(zip); die("failed to open zip file '%s': %s", filename, ErrorCodeString(error)); } unsigned sz; void* data = unzip_file(zip, "android-info.txt", &sz); if (data == 0) { CloseArchive(zip); die("update package '%s' has no android-info.txt", filename); } setup_requirements(reinterpret_cast<char*>(data), sz); for (size_t i = 0; i < ARRAY_SIZE(images); ++i) { int fd = unzip_to_file(zip, images[i].img_name); if (fd == -1) { if (images[i].is_optional) { continue; } CloseArchive(zip); exit(1); // unzip_to_file already explained why. } fastboot_buffer buf; int rc = load_buf_fd(usb, fd, &buf); if (rc) die("cannot load %s from flash", images[i].img_name); do_update_signature(zip, images[i].sig_name); if (erase_first && needs_erase(usb, images[i].part_name)) { fb_queue_erase(images[i].part_name); } flash_buf(images[i].part_name, &buf); /* not closing the fd here since the sparse code keeps the fd around * but hasn't mmaped data yet. The tmpfile will get cleaned up when the * program exits. */ } CloseArchive(zip); }
int main(int argc, char **argv) { int wants_wipe = 0; int wants_reboot = 0; int wants_reboot_bootloader = 0; int erase_first = 1; void *data; unsigned sz; int status; int c; int longindex; const struct option longopts[] = { {"base", required_argument, 0, 'b'}, {"kernel_offset", required_argument, 0, 'k'}, {"page_size", required_argument, 0, 'n'}, {"ramdisk_offset", required_argument, 0, 'r'}, {"tags_offset", required_argument, 0, 't'}, {"help", no_argument, 0, 'h'}, {"unbuffered", no_argument, 0, 0}, {"version", no_argument, 0, 0}, {0, 0, 0, 0} }; serial = getenv("ANDROID_SERIAL"); while (1) { c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, &longindex); if (c < 0) { break; } /* Alphabetical cases */ switch (c) { case 'b': base_addr = strtoul(optarg, 0, 16); break; case 'c': cmdline = optarg; break; case 'h': usage(); return 1; case 'i': { char *endptr = NULL; unsigned long val; val = strtoul(optarg, &endptr, 0); if (!endptr || *endptr != '\0' || (val & ~0xffff)) die("invalid vendor id '%s'", optarg); vendor_id = (unsigned short)val; break; } case 'k': kernel_offset = strtoul(optarg, 0, 16); break; case 'l': long_listing = 1; break; case 'n': page_size = (unsigned)strtoul(optarg, NULL, 0); if (!page_size) die("invalid page size"); break; case 'p': product = optarg; break; case 'r': ramdisk_offset = strtoul(optarg, 0, 16); break; case 't': tags_offset = strtoul(optarg, 0, 16); break; case 's': serial = optarg; break; case 'S': sparse_limit = parse_num(optarg); if (sparse_limit < 0) { die("invalid sparse limit"); } break; case 'u': erase_first = 0; break; case 'w': wants_wipe = 1; break; case '?': return 1; case 0: if (strcmp("unbuffered", longopts[longindex].name) == 0) { setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); } else if (strcmp("version", longopts[longindex].name) == 0) { fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION); return 0; } break; default: abort(); } } argc -= optind; argv += optind; if (argc == 0 && !wants_wipe) { usage(); return 1; } if (argc > 0 && !strcmp(*argv, "devices")) { skip(1); list_devices(); return 0; } if (argc > 0 && !strcmp(*argv, "help")) { usage(); return 0; } usb_handle* usb = open_device(); while (argc > 0) { if(!strcmp(*argv, "getvar")) { require(2); fb_queue_display(argv[1], argv[1]); skip(2); } else if(!strcmp(*argv, "erase")) { require(2); if (fb_format_supported(usb, argv[1], NULL)) { fprintf(stderr, "******** Did you mean to fastboot format this partition?\n"); } fb_queue_erase(argv[1]); skip(2); } else if(!strncmp(*argv, "format", strlen("format"))) { char *overrides; char *type_override = NULL; char *size_override = NULL; require(2); /* * Parsing for: "format[:[type][:[size]]]" * Some valid things: * - select ontly the size, and leave default fs type: * format::0x4000000 userdata * - default fs type and size: * format userdata * format:: userdata */ overrides = strchr(*argv, ':'); if (overrides) { overrides++; size_override = strchr(overrides, ':'); if (size_override) { size_override[0] = '\0'; size_override++; } type_override = overrides; } if (type_override && !type_override[0]) type_override = NULL; if (size_override && !size_override[0]) size_override = NULL; if (erase_first && needs_erase(usb, argv[1])) { fb_queue_erase(argv[1]); } fb_perform_format(usb, argv[1], 0, type_override, size_override); skip(2); } else if(!strcmp(*argv, "signature")) { require(2); data = load_file(argv[1], &sz); if (data == 0) die("could not load '%s': %s", argv[1], strerror(errno)); 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); if (argc > 0) { if (!strcmp(*argv, "bootloader")) { wants_reboot = 0; wants_reboot_bootloader = 1; skip(1); } } require(0); } 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(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); if (erase_first && needs_erase(usb, pname)) { fb_queue_erase(pname); } do_flash(usb, pname, fname); } 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(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(usb, erase_first); wants_reboot = 1; } else if(!strcmp(*argv, "update")) { if (argc > 1) { do_update(usb, argv[1], erase_first); skip(2); } else { do_update(usb, "update.zip", erase_first); skip(1); } wants_reboot = 1; } else if(!strcmp(*argv, "oem")) { argc = do_oem_command(argc, argv); } else if(!strcmp(*argv, "flashing") && argc == 2) { if(!strcmp(*(argv+1), "unlock") || !strcmp(*(argv+1), "lock") || !strcmp(*(argv+1), "unlock_critical") || !strcmp(*(argv+1), "lock_critical") || !strcmp(*(argv+1), "get_unlock_ability")) { argc = do_oem_command(argc, argv); } else { usage(); return 1; } } else { usage(); return 1; } } if (wants_wipe) { fb_queue_erase("userdata"); fb_perform_format(usb, "userdata", 1, NULL, NULL); fb_queue_erase("cache"); fb_perform_format(usb, "cache", 1, NULL, NULL); } if (wants_reboot) { fb_queue_reboot(); fb_queue_wait_for_disconnect(); } else if (wants_reboot_bootloader) { fb_queue_command("reboot-bootloader", "rebooting into bootloader"); fb_queue_wait_for_disconnect(); } if (fb_queue_is_empty()) return 0; status = fb_execute_queue(usb); return (status) ? 1 : 0; }
int main(int argc, char **argv) { int wants_wipe = 0; int wants_reboot = 0; int wants_reboot_bootloader = 0; int erase_first = 1; void *data; unsigned sz; unsigned page_size = 2048; int status; int c; int r; const struct option longopts = { 0, 0, 0, 0 }; serial = getenv("ANDROID_SERIAL"); while (1) { c = getopt_long(argc, argv, "wub:n:s:S:lp:c:i:m:ht:", &longopts, NULL); if (c < 0) { break; } switch (c) { case 'w': wants_wipe = 1; break; case 'u': erase_first = 0; break; case 'b': base_addr = strtoul(optarg, 0, 16); break; case 'n': page_size = (unsigned)strtoul(optarg, NULL, 0); if (!page_size) die("invalid page size"); break; case 's': serial = optarg; break; case 'S': sparse_limit = parse_num(optarg); if (sparse_limit < 0) { die("invalid sparse limit"); } break; case 'l': long_listing = 1; break; case 'p': product = optarg; break; case 'c': cmdline = optarg; break; case 'i': { char *endptr = NULL; unsigned long val; val = strtoul(optarg, &endptr, 0); if (!endptr || *endptr != '\0' || (val & ~0xffff)) die("invalid vendor id '%s'", optarg); vendor_id = (unsigned short)val; break; } case 't': host = optarg; break; case 'h': usage(); return 1; case '?': return 1; default: abort(); } } argc -= optind; argv += optind; if (argc == 0 && !wants_wipe) { usage(); return 1; } if (argc > 0 && !strcmp(*argv, "devices")) { skip(1); list_devices(); return 0; } if (argc > 0 && !strcmp(*argv, "help")) { usage(); return 0; } if(host) { transport.userdata = open_device_tcp(); transport.close = tcp_close; transport.read = tcp_read; transport.write = tcp_write; } else { transport.userdata = open_device(); transport.close = usb_close; transport.read = usb_read; transport.write = usb_write; } while (argc > 0) { 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': %s", argv[1], strerror(errno)); 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); if (erase_first && needs_erase(pname)) { fb_queue_erase(pname); } data = load_file(fname, &sz); if (data == 0) die("cannot load '%s': %s\n", fname, strerror(errno)); 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(erase_first); wants_reboot = 1; } else if(!strcmp(*argv, "update")) { if (argc > 1) { do_update(argv[1], erase_first); skip(2); } else { do_update("update.zip", erase_first); 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"); } if (fb_queue_is_empty()) return 0; status = fb_execute_queue(&transport); return (status) ? 1 : 0; }
int main(int argc, char **argv) { int wants_wipe = 0; int wants_reboot = 0; int wants_reboot_bootloader = 0; int erase_first = 1; void *data; unsigned sz; int status; int c; int r; const struct option longopts[] = { {"base", required_argument, 0, 'b'}, {"kernel_offset", required_argument, 0, 'k'}, {"page_size", required_argument, 0, 'n'}, {"ramdisk_offset", required_argument, 0, 'r'}, {"help", 0, 0, 'h'}, {0, 0, 0, 0} }; serial = getenv("ANDROID_SERIAL"); while (1) { int option_index = 0; c = getopt_long(argc, argv, "wub:k:n:r:s:S:lp:c:i:m:h", longopts, NULL); if (c < 0) { break; } /* Alphabetical cases */ switch (c) { case 'b': base_addr = strtoul(optarg, 0, 16); break; case 'c': cmdline = optarg; break; case 'h': usage(); return 1; case 'i': { char *endptr = NULL; unsigned long val; val = strtoul(optarg, &endptr, 0); if (!endptr || *endptr != '\0' || (val & ~0xffff)) die("invalid vendor id '%s'", optarg); vendor_id = (unsigned short)val; break; } case 'k': kernel_offset = strtoul(optarg, 0, 16); break; case 'l': long_listing = 1; break; case 'n': page_size = (unsigned)strtoul(optarg, NULL, 0); if (!page_size) die("invalid page size"); break; case 'p': product = optarg; break; case 'r': ramdisk_offset = strtoul(optarg, 0, 16); break; case 's': serial = optarg; break; case 'S': sparse_limit = parse_num(optarg); if (sparse_limit < 0) { die("invalid sparse limit"); } break; case 'u': erase_first = 0; break; case 'w': wants_wipe = 1; break; case '?': return 1; default: abort(); } } argc -= optind; argv += optind; if (argc == 0 && !wants_wipe) { usage(); return 1; } if (argc > 0 && !strcmp(*argv, "devices")) { skip(1); list_devices(); return 0; } if (argc > 0 && !strcmp(*argv, "help")) { usage(); return 0; } usb = open_device(); while (argc > 0) { if(!strcmp(*argv, "getvar")) { require(2); fb_queue_display(argv[1], argv[1]); skip(2); } else if(!strcmp(*argv, "erase")) { require(2); if (fb_format_supported(usb, argv[1])) { fprintf(stderr, "******** Did you mean to fastboot format this partition?\n"); } fb_queue_erase(argv[1]); skip(2); } else if(!strcmp(*argv, "format")) { require(2); if (erase_first && needs_erase(argv[1])) { fb_queue_erase(argv[1]); } 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': %s", argv[1], strerror(errno)); 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(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); if (erase_first && needs_erase(pname)) { fb_queue_erase(pname); } do_flash(usb, pname, fname); } 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(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(usb, erase_first); wants_reboot = 1; } else if(!strcmp(*argv, "update")) { if (argc > 1) { do_update(usb, argv[1], erase_first); skip(2); } else { do_update(usb, "update.zip", erase_first); 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"); } if (fb_queue_is_empty()) return 0; status = fb_execute_queue(usb); return (status) ? 1 : 0; }