diff options
Diffstat (limited to 'fastboot/fastboot.c')
-rw-r--r-- | fastboot/fastboot.c | 271 |
1 files changed, 171 insertions, 100 deletions
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 447b257..f186c93 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -43,6 +43,7 @@ #include <sys/time.h> #include <sys/types.h> +#include <sys/stat.h> #include <bootimg.h> #include <sparse/sparse.h> @@ -54,6 +55,8 @@ #define O_BINARY 0 #endif +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) + char cur_product[FB_RESPONSE_SZ + 1]; void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); @@ -81,6 +84,27 @@ unsigned ramdisk_offset = 0x01000000; unsigned second_offset = 0x00f00000; unsigned tags_offset = 0x00000100; +enum fb_buffer_type { + FB_BUFFER, + FB_BUFFER_SPARSE, +}; + +struct fastboot_buffer { + enum fb_buffer_type type; + void *data; + unsigned int sz; +}; + +static struct { + char img_name[13]; + char sig_name[13]; + char part_name[9]; + bool is_optional; +} images[3] = { + {"boot.img", "boot.sig", "boot", false}, + {"recovery.img", "recovery.sig", "recovery", true}, + {"system.img", "system.sig", "system", false}, +}; void die(const char *fmt, ...) { @@ -135,44 +159,28 @@ char *find_item(const char *item, const char *product) return strdup(path); } -#ifdef _WIN32 -void *load_file(const char *fn, unsigned *_sz); -int64_t file_size(const char *fn); -#else -#if defined(__APPLE__) && defined(__MACH__) -#define lseek64 lseek -#define off64_t off_t -#endif - -int64_t file_size(const char *fn) +static int64_t file_size(int fd) { - off64_t off; - int fd; + struct stat st; + int ret; - fd = open(fn, O_RDONLY); - if (fd < 0) return -1; + ret = fstat(fd, &st); - off = lseek64(fd, 0, SEEK_END); - close(fd); - - return off; + return ret ? -1 : st.st_size; } -void *load_file(const char *fn, unsigned *_sz) +static void *load_fd(int fd, unsigned *_sz) { char *data; int sz; - int fd; int errno_tmp; 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; + sz = file_size(fd); + if (sz < 0) { + goto oops; + } data = (char*) malloc(sz); if(data == 0) goto oops; @@ -190,7 +198,16 @@ oops: errno = errno_tmp; return 0; } -#endif + +static void *load_file(const char *fn, unsigned *_sz) +{ + int fd; + + fd = open(fn, O_RDONLY | O_BINARY); + if(fd < 0) return 0; + + return load_fd(fd, _sz); +} int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial) { @@ -397,6 +414,31 @@ void *unzip_file(zipfile_t zip, const char *name, unsigned *sz) return data; } +static int unzip_to_file(zipfile_t zip, char *name) +{ + int fd; + char *data; + unsigned sz; + + fd = fileno(tmpfile()); + if (fd < 0) { + return -1; + } + + data = unzip_file(zip, name, &sz); + if (data == 0) { + return -1; + } + + if (write(fd, data, sz) != sz) { + fd = -1; + } + + free(data); + lseek(fd, 0, SEEK_SET); + return fd; +} + static char *strip(char *s) { int n; @@ -495,27 +537,20 @@ void queue_info_dump(void) fb_queue_notice("--------------------------------------------"); } - -struct sparse_file **load_sparse_files(const char *fname, int max_size) +static struct sparse_file **load_sparse_files(int fd, int max_size) { - int fd; struct sparse_file *s; int files; struct sparse_file **out_s; - fd = open(fname, O_RDONLY | O_BINARY); - if (fd < 0) { - die("cannot open '%s'\n", fname); - } - s = sparse_file_import_auto(fd, false); if (!s) { - die("cannot sparse read file '%s'\n", fname); + die("cannot sparse read file\n"); } files = sparse_file_resparse(s, max_size, NULL, 0); if (files < 0) { - die("Failed to resparse '%s'\n", fname); + die("Failed to resparse\n"); } out_s = calloc(sizeof(struct sparse_file *), files + 1); @@ -525,7 +560,7 @@ struct sparse_file **load_sparse_files(const char *fname, int max_size) files = sparse_file_resparse(s, max_size, out_s, files); if (files < 0) { - die("Failed to resparse '%s'\n", fname); + die("Failed to resparse\n"); } return out_s; @@ -586,31 +621,80 @@ static int needs_erase(const char *part) return fb_format_supported(usb, part); } -void do_flash(usb_handle *usb, const char *pname, const char *fname) +static int load_buf_fd(usb_handle *usb, int fd, + struct fastboot_buffer *buf) { int64_t sz64; void *data; int64_t limit; - sz64 = file_size(fname); + sz64 = file_size(fd); + if (sz64 < 0) { + return -1; + } limit = get_sparse_limit(usb, sz64); if (limit) { - struct sparse_file **s = load_sparse_files(fname, limit); + struct sparse_file **s = load_sparse_files(fd, limit); if (s == NULL) { - die("cannot sparse load '%s'\n", fname); - } - while (*s) { - sz64 = sparse_file_len(*s, true, false); - fb_queue_flash_sparse(pname, *s++, sz64); + return -1; } + buf->type = FB_BUFFER_SPARSE; + buf->data = s; } else { unsigned int sz; - data = load_file(fname, &sz); - if (data == 0) die("cannot load '%s': %s\n", fname, strerror(errno)); - fb_queue_flash(pname, data, sz); + data = load_fd(fd, &sz); + if (data == 0) return -1; + buf->type = FB_BUFFER; + buf->data = data; + buf->sz = sz; + } + + return 0; +} + +static int load_buf(usb_handle *usb, const char *fname, + struct fastboot_buffer *buf) +{ + int fd; + + fd = open(fname, O_RDONLY | O_BINARY); + if (fd < 0) { + die("cannot open '%s'\n", fname); + } + + return load_buf_fd(usb, fd, buf); +} + +static void flash_buf(const char *pname, struct fastboot_buffer *buf) +{ + struct sparse_file **s; + + switch (buf->type) { + case FB_BUFFER_SPARSE: + s = buf->data; + while (*s) { + int64_t sz64 = sparse_file_len(*s, true, false); + fb_queue_flash_sparse(pname, *s++, sz64); + } + break; + case FB_BUFFER: + fb_queue_flash(pname, buf->data, buf->sz); + break; + default: + die("unknown buffer type: %d", buf->type); } } +void do_flash(usb_handle *usb, const char *pname, const char *fname) +{ + struct fastboot_buffer buf; + + if (load_buf(usb, fname, &buf)) { + die("cannot load '%s'", fname); + } + flash_buf(pname, &buf); +} + void do_update_signature(zipfile_t zip, char *fn) { void *data; @@ -621,13 +705,17 @@ void do_update_signature(zipfile_t zip, char *fn) fb_queue_command("signature", "installing signature"); } -void do_update(char *fn, int erase_first) +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; + int i; queue_info_dump(); @@ -656,30 +744,25 @@ void do_update(char *fn, int erase_first) 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"); + 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); } - 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"); + 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. + */ } - fb_queue_flash("system", data, sz); } void do_send_signature(char *fn) @@ -700,11 +783,13 @@ void do_send_signature(char *fn) fb_queue_command("signature", "installing signature"); } -void do_flashall(int erase_first) +void do_flashall(usb_handle *usb, int erase_first) { char *fname; void *data; unsigned sz; + struct fastboot_buffer buf; + int i; queue_info_dump(); @@ -716,33 +801,19 @@ void do_flashall(int erase_first) 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) { + for (i = 0; i < ARRAY_SIZE(images); i++) { + fname = find_item(images[i].part_name, product); + 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("recovery")) { - fb_queue_erase("recovery"); + if (erase_first && needs_erase(images[i].part_name)) { + fb_queue_erase(images[i].part_name); } - 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"); + flash_buf(images[i].part_name, &buf); } - fb_queue_flash("system", data, sz); } #define skip(n) do { argc -= (n); argv += (n); } while (0) @@ -1002,14 +1073,14 @@ int main(int argc, char **argv) fb_queue_flash(pname, data, sz); } else if(!strcmp(*argv, "flashall")) { skip(1); - do_flashall(erase_first); + do_flashall(usb, erase_first); wants_reboot = 1; } else if(!strcmp(*argv, "update")) { if (argc > 1) { - do_update(argv[1], erase_first); + do_update(usb, argv[1], erase_first); skip(2); } else { - do_update("update.zip", erase_first); + do_update(usb, "update.zip", erase_first); skip(1); } wants_reboot = 1; |