Loading fastboot/Android.mk +1 −1 Original line number Original line Diff line number Diff line Loading @@ -48,7 +48,7 @@ ifeq ($(HOST_OS),windows) LOCAL_C_INCLUDES += development/host/windows/usb/api LOCAL_C_INCLUDES += development/host/windows/usb/api endif endif LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libz LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libsparse libz ifneq ($(HOST_OS),windows) ifneq ($(HOST_OS),windows) ifeq ($(HAVE_SELINUX), true) ifeq ($(HAVE_SELINUX), true) Loading fastboot/engine.c +34 −7 Original line number Original line Diff line number Diff line Loading @@ -28,7 +28,6 @@ #include "fastboot.h" #include "fastboot.h" #include "make_ext4fs.h" #include "make_ext4fs.h" #include "ext4_utils.h" #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> Loading Loading @@ -77,6 +76,7 @@ char *mkmsg(const char *fmt, ...) #define OP_QUERY 3 #define OP_QUERY 3 #define OP_NOTICE 4 #define OP_NOTICE 4 #define OP_FORMAT 5 #define OP_FORMAT 5 #define OP_DOWNLOAD_SPARSE 6 typedef struct Action Action; typedef struct Action Action; Loading Loading @@ -111,6 +111,20 @@ struct image_data { void generate_ext4_image(struct image_data *image); void generate_ext4_image(struct image_data *image); void cleanup_image(struct image_data *image); void cleanup_image(struct image_data *image); int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...) { char cmd[CMD_SIZE] = "getvar:"; int getvar_len = strlen(cmd); va_list args; response[FB_RESPONSE_SZ] = '\0'; va_start(args, fmt); vsnprintf(cmd + getvar_len, sizeof(cmd) - getvar_len, fmt, args); va_end(args); cmd[CMD_SIZE - 1] = '\0'; return fb_command_response(usb, cmd, response); } struct generator { struct generator { char *fs_type; char *fs_type; Loading Loading @@ -278,9 +292,7 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported) unsigned i; unsigned i; char cmd[CMD_SIZE]; char cmd[CMD_SIZE]; response[FB_RESPONSE_SZ] = '\0'; status = fb_getvar(usb, response, "partition-type:%s", partition); snprintf(cmd, sizeof(cmd), "getvar:partition-type:%s", partition); status = fb_command_response(usb, cmd, response); if (status) { if (status) { if (skip_if_not_supported) { if (skip_if_not_supported) { fprintf(stderr, fprintf(stderr, Loading Loading @@ -312,9 +324,7 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported) return -1; return -1; } } response[FB_RESPONSE_SZ] = '\0'; status = fb_getvar(usb, response, "partition-size:%s", partition); snprintf(cmd, sizeof(cmd), "getvar:partition-size:%s", partition); status = fb_command_response(usb, cmd, response); if (status) { if (status) { if (skip_if_not_supported) { if (skip_if_not_supported) { fprintf(stderr, fprintf(stderr, Loading Loading @@ -372,6 +382,19 @@ void fb_queue_flash(const char *ptn, void *data, unsigned sz) a->msg = mkmsg("writing '%s'", ptn); a->msg = mkmsg("writing '%s'", ptn); } } void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz) { Action *a; a = queue_action(OP_DOWNLOAD_SPARSE, ""); a->data = s; a->size = 0; a->msg = mkmsg("sending sparse '%s' (%d KB)", ptn, sz / 1024); a = queue_action(OP_COMMAND, "flash:%s", ptn); a->msg = mkmsg("writing '%s'", ptn); } static int match(char *str, const char **value, unsigned count) static int match(char *str, const char **value, unsigned count) { { const char *val; const char *val; Loading Loading @@ -572,6 +595,10 @@ int fb_execute_queue(usb_handle *usb) status = fb_format(a, usb, (int)a->data); status = fb_format(a, usb, (int)a->data); status = a->func(a, status, status ? fb_get_error() : ""); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; if (status) break; } else if (a->op == OP_DOWNLOAD_SPARSE) { status = fb_download_data_sparse(usb, a->data); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; } else { } else { die("bogus action"); die("bogus action"); } } Loading fastboot/fastboot.c +257 −56 Original line number Original line Diff line number Diff line Loading @@ -26,22 +26,36 @@ * SUCH DAMAGE. * SUCH DAMAGE. */ */ #define _LARGEFILE64_SOURCE #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> #include <stdarg.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <string.h> #include <string.h> #include <errno.h> #include <errno.h> #include <fcntl.h> #include <fcntl.h> #include <unistd.h> #include <unistd.h> #include <limits.h> #include <limits.h> #include <ctype.h> #include <ctype.h> #include <getopt.h> #include <sys/time.h> #include <sys/time.h> #include <sys/types.h> #include <bootimg.h> #include <bootimg.h> #include <sparse/sparse.h> #include <zipfile/zipfile.h> #include <zipfile/zipfile.h> #include "fastboot.h" #include "fastboot.h" #ifndef O_BINARY #define O_BINARY 0 #endif #define DEFAULT_SPARSE_LIMIT (256 * 1024 * 1024) char cur_product[FB_RESPONSE_SZ + 1]; char cur_product[FB_RESPONSE_SZ + 1]; void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); Loading @@ -59,6 +73,8 @@ static const char *cmdline = 0; static int wipe_data = 0; static int wipe_data = 0; static unsigned short vendor_id = 0; static unsigned short vendor_id = 0; static int long_listing = 0; static int long_listing = 0; static int64_t sparse_limit = -1; static int64_t target_sparse_limit = -1; static unsigned base_addr = 0x10000000; static unsigned base_addr = 0x10000000; Loading Loading @@ -117,7 +133,27 @@ char *find_item(const char *item, const char *product) #ifdef _WIN32 #ifdef _WIN32 void *load_file(const char *fn, unsigned *_sz); void *load_file(const char *fn, unsigned *_sz); int64_t file_size(const char *fn); #else #else #if defined(__APPLE__) && defined(__MACH__) #define lseek64 lseek #define off64_t off_t #endif int64_t file_size(const char *fn) { off64_t off; int fd; fd = open(fn, O_RDONLY); if (fd < 0) return -1; off = lseek64(fd, 0, SEEK_END); close(fd); return off; } void *load_file(const char *fn, unsigned *_sz) void *load_file(const char *fn, unsigned *_sz) { { char *data; char *data; Loading Loading @@ -259,6 +295,8 @@ void usage(void) " -i <vendor id> specify a custom USB vendor id\n" " -i <vendor id> specify a custom USB vendor id\n" " -b <base_addr> specify a custom kernel base address\n" " -b <base_addr> specify a custom kernel base address\n" " -n <page size> specify the nand page size. default: 2048\n" " -n <page size> specify the nand page size. default: 2048\n" " -S <size>[K|M|G] automatically sparse files greater than\n" " size. default: 256M, 0 to disable\n" ); ); } } Loading Loading @@ -444,6 +482,110 @@ void queue_info_dump(void) fb_queue_notice("--------------------------------------------"); fb_queue_notice("--------------------------------------------"); } } struct sparse_file **load_sparse_files(const char *fname, 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); } files = sparse_file_resparse(s, max_size, NULL, 0); if (files < 0) { die("Failed to resparse '%s'\n", fname); } out_s = calloc(sizeof(struct sparse_file *), files + 1); if (!out_s) { die("Failed to allocate sparse file array\n"); } files = sparse_file_resparse(s, max_size, out_s, files); if (files < 0) { die("Failed to resparse '%s'\n", fname); } return out_s; } static int64_t get_target_sparse_limit(struct usb_handle *usb) { int64_t limit = 0; char response[FB_RESPONSE_SZ + 1]; int status = fb_getvar(usb, response, "max-download-size"); if (!status) { limit = strtoul(response, NULL, 0); if (limit > 0) { fprintf(stderr, "target reported max download size of %lld bytes\n", limit); } } return limit; } static int64_t get_sparse_limit(struct usb_handle *usb, int64_t size) { int64_t limit; if (sparse_limit == 0) { return 0; } else if (sparse_limit > 0) { limit = sparse_limit; } else { if (target_sparse_limit == -1) { target_sparse_limit = get_target_sparse_limit(usb); } if (target_sparse_limit > 0) { limit = target_sparse_limit; } else { limit = DEFAULT_SPARSE_LIMIT; } } if (size > limit) { return limit; } return 0; } void do_flash(usb_handle *usb, const char *pname, const char *fname) { int64_t sz64; void *data; int64_t limit; sz64 = file_size(fname); limit = get_sparse_limit(usb, sz64); if (limit) { struct sparse_file **s = load_sparse_files(fname, 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); } } else { unsigned int sz; data = load_file(fname, &sz); if (data == 0) die("cannot load '%s'\n", fname); fb_queue_flash(pname, data, sz); } } void do_update_signature(zipfile_t zip, char *fn) void do_update_signature(zipfile_t zip, char *fn) { { void *data; void *data; Loading Loading @@ -581,73 +723,136 @@ int do_oem_command(int argc, char **argv) return 0; return 0; } } static int64_t parse_num(const char *arg) { char *endptr; unsigned long long num; num = strtoull(arg, &endptr, 0); if (endptr == arg) { return -1; } if (*endptr == 'k' || *endptr == 'K') { if (num >= (-1ULL) / 1024) { return -1; } num *= 1024LL; endptr++; } else if (*endptr == 'm' || *endptr == 'M') { if (num >= (-1ULL) / (1024 * 1024)) { return -1; } num *= 1024LL * 1024LL; endptr++; } else if (*endptr == 'g' || *endptr == 'G') { if (num >= (-1ULL) / (1024 * 1024 * 1024)) { return -1; } num *= 1024LL * 1024LL * 1024LL; endptr++; } if (*endptr != '\0') { return -1; } if (num > INT64_MAX) { return -1; } return num; } int main(int argc, char **argv) int main(int argc, char **argv) { { int wants_wipe = 0; int wants_wipe = 0; int wants_reboot = 0; int wants_reboot = 0; int wants_reboot_bootloader = 0; int wants_reboot_bootloader = 0; int wants_device_list = 0; void *data; void *data; unsigned sz; unsigned sz; unsigned page_size = 2048; unsigned page_size = 2048; int status; int status; int c; int r; skip(1); const struct option longopts = { 0, 0, 0, 0 }; if (argc == 0) { usage(); return 1; } if (!strcmp(*argv, "help")) { usage(); return 0; } serial = getenv("ANDROID_SERIAL"); serial = getenv("ANDROID_SERIAL"); while (argc > 0) { while (1) { if(!strcmp(*argv, "-w")) { c = getopt_long(argc, argv, "wb:n:s:S:lp:c:i:m:h", &longopts, NULL); if (c < 0) { break; } switch (c) { case 'w': wants_wipe = 1; wants_wipe = 1; skip(1); break; } else if(!strcmp(*argv, "-b")) { case 'b': require(2); base_addr = strtoul(optarg, 0, 16); base_addr = strtoul(argv[1], 0, 16); break; skip(2); case 'n': } else if(!strcmp(*argv, "-n")) { page_size = (unsigned)strtoul(optarg, NULL, 0); require(2); page_size = (unsigned)strtoul(argv[1], NULL, 0); if (!page_size) die("invalid page size"); if (!page_size) die("invalid page size"); skip(2); break; } else if(!strcmp(*argv, "-s")) { case 's': require(2); serial = optarg; serial = argv[1]; break; skip(2); case 'S': } else if(!strcmp(*argv, "-l")) { sparse_limit = parse_num(optarg); if (sparse_limit < 0) { die("invalid sparse limit"); } break; case 'l': long_listing = 1; long_listing = 1; skip(1); break; } else if(!strcmp(*argv, "-p")) { case 'p': require(2); product = optarg; product = argv[1]; break; skip(2); case 'c': } else if(!strcmp(*argv, "-c")) { cmdline = optarg; require(2); break; cmdline = argv[1]; case 'i': { skip(2); } else if(!strcmp(*argv, "-i")) { char *endptr = NULL; char *endptr = NULL; unsigned long val; unsigned long val; require(2); val = strtoul(optarg, &endptr, 0); val = strtoul(argv[1], &endptr, 0); if (!endptr || *endptr != '\0' || (val & ~0xffff)) if (!endptr || *endptr != '\0' || (val & ~0xffff)) die("invalid vendor id '%s'", argv[1]); die("invalid vendor id '%s'", optarg); vendor_id = (unsigned short)val; vendor_id = (unsigned short)val; skip(2); break; } else if (!strcmp(*argv, "devices")) { } case 'h': usage(); return 1; case '?': return 1; default: abort(); } } argc -= optind; argv += optind; if (argc == 0 && !wants_wipe) { usage(); return 1; } if (!strcmp(*argv, "devices")) { skip(1); skip(1); wants_device_list = 1; list_devices(); } else if(!strcmp(*argv, "getvar")) { return 0; } usb = open_device(); while (argc > 0) { if(!strcmp(*argv, "getvar")) { require(2); require(2); fb_queue_display(argv[1], argv[1]); fb_queue_display(argv[1], argv[1]); skip(2); skip(2); Loading Loading @@ -704,9 +909,7 @@ int main(int argc, char **argv) skip(2); skip(2); } } if (fname == 0) die("cannot determine image filename for '%s'", pname); if (fname == 0) die("cannot determine image filename for '%s'", pname); data = load_file(fname, &sz); do_flash(usb, pname, fname); if (data == 0) die("cannot load '%s'\n", fname); fb_queue_flash(pname, data, sz); } else if(!strcmp(*argv, "flash:raw")) { } else if(!strcmp(*argv, "flash:raw")) { char *pname = argv[1]; char *pname = argv[1]; char *kname = argv[2]; char *kname = argv[2]; Loading Loading @@ -736,15 +939,15 @@ int main(int argc, char **argv) wants_reboot = 1; wants_reboot = 1; } else if(!strcmp(*argv, "oem")) { } else if(!strcmp(*argv, "oem")) { argc = do_oem_command(argc, argv); argc = do_oem_command(argc, argv); } else if (!strcmp(*argv, "help")) { usage(); return 0; } else { } else { usage(); usage(); return 1; return 1; } } } } if (wants_device_list) list_devices(); if (wants_wipe) { if (wants_wipe) { fb_queue_erase("userdata"); fb_queue_erase("userdata"); fb_queue_format("userdata", 1); fb_queue_format("userdata", 1); Loading @@ -760,8 +963,6 @@ int main(int argc, char **argv) if (fb_queue_is_empty()) if (fb_queue_is_empty()) return 0; return 0; usb = open_device(); status = fb_execute_queue(usb); status = fb_execute_queue(usb); return (status) ? 1 : 0; return (status) ? 1 : 0; } } fastboot/fastboot.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -31,17 +31,22 @@ #include "usb.h" #include "usb.h" struct sparse_file; /* protocol.c - fastboot protocol */ /* protocol.c - fastboot protocol */ int fb_command(usb_handle *usb, const char *cmd); int fb_command(usb_handle *usb, const char *cmd); int fb_command_response(usb_handle *usb, const char *cmd, char *response); int fb_command_response(usb_handle *usb, const char *cmd, char *response); int fb_download_data(usb_handle *usb, const void *data, unsigned size); int fb_download_data(usb_handle *usb, const void *data, unsigned size); int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s); char *fb_get_error(void); char *fb_get_error(void); #define FB_COMMAND_SZ 64 #define FB_COMMAND_SZ 64 #define FB_RESPONSE_SZ 64 #define FB_RESPONSE_SZ 64 /* engine.c - high level command queue engine */ /* engine.c - high level command queue engine */ int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...); void fb_queue_flash(const char *ptn, void *data, unsigned sz);; void fb_queue_flash(const char *ptn, void *data, unsigned sz);; void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz); void fb_queue_erase(const char *ptn); void fb_queue_erase(const char *ptn); void fb_queue_format(const char *ptn, int skip_if_not_supported); void fb_queue_format(const char *ptn, int skip_if_not_supported); void fb_queue_require(const char *prod, const char *var, int invert, void fb_queue_require(const char *prod, const char *var, int invert, Loading fastboot/protocol.c +160 −27 Original line number Original line Diff line number Diff line Loading @@ -26,11 +26,18 @@ * SUCH DAMAGE. * SUCH DAMAGE. */ */ #define min(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; }) #define round_down(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> #include <string.h> #include <string.h> #include <errno.h> #include <errno.h> #include <sparse/sparse.h> #include "fastboot.h" #include "fastboot.h" static char ERROR[128]; static char ERROR[128]; Loading @@ -40,8 +47,7 @@ char *fb_get_error(void) return ERROR; return ERROR; } } static int check_response(usb_handle *usb, unsigned size, static int check_response(usb_handle *usb, unsigned int size, char *response) unsigned data_okay, char *response) { { unsigned char status[65]; unsigned char status[65]; int r; int r; Loading Loading @@ -82,7 +88,7 @@ static int check_response(usb_handle *usb, unsigned size, return -1; return -1; } } if(!memcmp(status, "DATA", 4) && data_okay){ if(!memcmp(status, "DATA", 4) && size > 0){ unsigned dsize = strtoul((char*) status + 4, 0, 16); unsigned dsize = strtoul((char*) status + 4, 0, 16); if(dsize > size) { if(dsize > size) { strcpy(ERROR, "data size too large"); strcpy(ERROR, "data size too large"); Loading @@ -100,8 +106,7 @@ static int check_response(usb_handle *usb, unsigned size, return -1; return -1; } } static int _command_send(usb_handle *usb, const char *cmd, static int _command_start(usb_handle *usb, const char *cmd, unsigned size, const void *data, unsigned size, char *response) char *response) { { int cmdsize = strlen(cmd); int cmdsize = strlen(cmd); Loading @@ -122,17 +127,13 @@ static int _command_send(usb_handle *usb, const char *cmd, return -1; return -1; } } if(data == 0) { return check_response(usb, size, response); return check_response(usb, size, 0, response); } } r = check_response(usb, size, 1, 0); static int _command_data(usb_handle *usb, const void *data, unsigned size) if(r < 0) { { return -1; int r; } size = r; if(size) { r = usb_write(usb, data, size); r = usb_write(usb, data, size); if(r < 0) { if(r < 0) { sprintf(ERROR, "data transfer failure (%s)", strerror(errno)); sprintf(ERROR, "data transfer failure (%s)", strerror(errno)); Loading @@ -144,24 +145,63 @@ static int _command_send(usb_handle *usb, const char *cmd, usb_close(usb); usb_close(usb); return -1; return -1; } } return r; } } r = check_response(usb, 0, 0, 0); static int _command_end(usb_handle *usb) { int r; r = check_response(usb, 0, 0); if(r < 0) { if(r < 0) { return -1; return -1; } else { } return 0; } static int _command_send(usb_handle *usb, const char *cmd, const void *data, unsigned size, char *response) { int r; if (size == 0) { return -1; } r = _command_start(usb, cmd, size, response); if (r < 0) { return -1; } r = _command_data(usb, data, size); if (r < 0) { return -1; } r = _command_end(usb); if(r < 0) { return -1; } return size; return size; } } static int _command_send_no_data(usb_handle *usb, const char *cmd, char *response) { int r; return _command_start(usb, cmd, 0, response); } } int fb_command(usb_handle *usb, const char *cmd) int fb_command(usb_handle *usb, const char *cmd) { { return _command_send(usb, cmd, 0, 0, 0); return _command_send_no_data(usb, cmd, 0); } } int fb_command_response(usb_handle *usb, const char *cmd, char *response) int fb_command_response(usb_handle *usb, const char *cmd, char *response) { { return _command_send(usb, cmd, 0, 0, response); return _command_send_no_data(usb, cmd, response); } } int fb_download_data(usb_handle *usb, const void *data, unsigned size) int fb_download_data(usb_handle *usb, const void *data, unsigned size) Loading @@ -179,3 +219,96 @@ int fb_download_data(usb_handle *usb, const void *data, unsigned size) } } } } #define USB_BUF_SIZE 512 static char usb_buf[USB_BUF_SIZE]; static int usb_buf_len; static int fb_download_data_sparse_write(void *priv, const void *data, int len) { int r; usb_handle *usb = priv; int to_write; const char *ptr = data; if (usb_buf_len) { to_write = min(USB_BUF_SIZE - usb_buf_len, len); memcpy(usb_buf + usb_buf_len, ptr, to_write); usb_buf_len += to_write; ptr += to_write; len -= to_write; } if (usb_buf_len == USB_BUF_SIZE) { r = _command_data(usb, usb_buf, USB_BUF_SIZE); if (r != USB_BUF_SIZE) { return -1; } usb_buf_len = 0; } if (len > USB_BUF_SIZE) { if (usb_buf_len > 0) { sprintf(ERROR, "internal error: usb_buf not empty\n"); return -1; } to_write = round_down(len, USB_BUF_SIZE); r = _command_data(usb, ptr, to_write); if (r != to_write) { return -1; } ptr += to_write; len -= to_write; } if (len > 0) { if (len > USB_BUF_SIZE) { sprintf(ERROR, "internal error: too much left for usb_buf\n"); return -1; } memcpy(usb_buf, ptr, len); usb_buf_len = len; } return 0; } static int fb_download_data_sparse_flush(usb_handle *usb) { int r; if (usb_buf_len > 0) { r = _command_data(usb, usb_buf, usb_buf_len); if (r != usb_buf_len) { return -1; } usb_buf_len = 0; } return 0; } int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s) { char cmd[64]; int r; int size = sparse_file_len(s, true, false); if (size <= 0) { return -1; } sprintf(cmd, "download:%08x", size); r = _command_start(usb, cmd, size, 0); if (r < 0) { return -1; } r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, usb); if (r < 0) { return -1; } fb_download_data_sparse_flush(usb); return _command_end(usb); } Loading
fastboot/Android.mk +1 −1 Original line number Original line Diff line number Diff line Loading @@ -48,7 +48,7 @@ ifeq ($(HOST_OS),windows) LOCAL_C_INCLUDES += development/host/windows/usb/api LOCAL_C_INCLUDES += development/host/windows/usb/api endif endif LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libz LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libsparse libz ifneq ($(HOST_OS),windows) ifneq ($(HOST_OS),windows) ifeq ($(HAVE_SELINUX), true) ifeq ($(HAVE_SELINUX), true) Loading
fastboot/engine.c +34 −7 Original line number Original line Diff line number Diff line Loading @@ -28,7 +28,6 @@ #include "fastboot.h" #include "fastboot.h" #include "make_ext4fs.h" #include "make_ext4fs.h" #include "ext4_utils.h" #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> Loading Loading @@ -77,6 +76,7 @@ char *mkmsg(const char *fmt, ...) #define OP_QUERY 3 #define OP_QUERY 3 #define OP_NOTICE 4 #define OP_NOTICE 4 #define OP_FORMAT 5 #define OP_FORMAT 5 #define OP_DOWNLOAD_SPARSE 6 typedef struct Action Action; typedef struct Action Action; Loading Loading @@ -111,6 +111,20 @@ struct image_data { void generate_ext4_image(struct image_data *image); void generate_ext4_image(struct image_data *image); void cleanup_image(struct image_data *image); void cleanup_image(struct image_data *image); int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...) { char cmd[CMD_SIZE] = "getvar:"; int getvar_len = strlen(cmd); va_list args; response[FB_RESPONSE_SZ] = '\0'; va_start(args, fmt); vsnprintf(cmd + getvar_len, sizeof(cmd) - getvar_len, fmt, args); va_end(args); cmd[CMD_SIZE - 1] = '\0'; return fb_command_response(usb, cmd, response); } struct generator { struct generator { char *fs_type; char *fs_type; Loading Loading @@ -278,9 +292,7 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported) unsigned i; unsigned i; char cmd[CMD_SIZE]; char cmd[CMD_SIZE]; response[FB_RESPONSE_SZ] = '\0'; status = fb_getvar(usb, response, "partition-type:%s", partition); snprintf(cmd, sizeof(cmd), "getvar:partition-type:%s", partition); status = fb_command_response(usb, cmd, response); if (status) { if (status) { if (skip_if_not_supported) { if (skip_if_not_supported) { fprintf(stderr, fprintf(stderr, Loading Loading @@ -312,9 +324,7 @@ int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported) return -1; return -1; } } response[FB_RESPONSE_SZ] = '\0'; status = fb_getvar(usb, response, "partition-size:%s", partition); snprintf(cmd, sizeof(cmd), "getvar:partition-size:%s", partition); status = fb_command_response(usb, cmd, response); if (status) { if (status) { if (skip_if_not_supported) { if (skip_if_not_supported) { fprintf(stderr, fprintf(stderr, Loading Loading @@ -372,6 +382,19 @@ void fb_queue_flash(const char *ptn, void *data, unsigned sz) a->msg = mkmsg("writing '%s'", ptn); a->msg = mkmsg("writing '%s'", ptn); } } void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz) { Action *a; a = queue_action(OP_DOWNLOAD_SPARSE, ""); a->data = s; a->size = 0; a->msg = mkmsg("sending sparse '%s' (%d KB)", ptn, sz / 1024); a = queue_action(OP_COMMAND, "flash:%s", ptn); a->msg = mkmsg("writing '%s'", ptn); } static int match(char *str, const char **value, unsigned count) static int match(char *str, const char **value, unsigned count) { { const char *val; const char *val; Loading Loading @@ -572,6 +595,10 @@ int fb_execute_queue(usb_handle *usb) status = fb_format(a, usb, (int)a->data); status = fb_format(a, usb, (int)a->data); status = a->func(a, status, status ? fb_get_error() : ""); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; if (status) break; } else if (a->op == OP_DOWNLOAD_SPARSE) { status = fb_download_data_sparse(usb, a->data); status = a->func(a, status, status ? fb_get_error() : ""); if (status) break; } else { } else { die("bogus action"); die("bogus action"); } } Loading
fastboot/fastboot.c +257 −56 Original line number Original line Diff line number Diff line Loading @@ -26,22 +26,36 @@ * SUCH DAMAGE. * SUCH DAMAGE. */ */ #define _LARGEFILE64_SOURCE #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> #include <stdarg.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <string.h> #include <string.h> #include <errno.h> #include <errno.h> #include <fcntl.h> #include <fcntl.h> #include <unistd.h> #include <unistd.h> #include <limits.h> #include <limits.h> #include <ctype.h> #include <ctype.h> #include <getopt.h> #include <sys/time.h> #include <sys/time.h> #include <sys/types.h> #include <bootimg.h> #include <bootimg.h> #include <sparse/sparse.h> #include <zipfile/zipfile.h> #include <zipfile/zipfile.h> #include "fastboot.h" #include "fastboot.h" #ifndef O_BINARY #define O_BINARY 0 #endif #define DEFAULT_SPARSE_LIMIT (256 * 1024 * 1024) char cur_product[FB_RESPONSE_SZ + 1]; char cur_product[FB_RESPONSE_SZ + 1]; void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); Loading @@ -59,6 +73,8 @@ static const char *cmdline = 0; static int wipe_data = 0; static int wipe_data = 0; static unsigned short vendor_id = 0; static unsigned short vendor_id = 0; static int long_listing = 0; static int long_listing = 0; static int64_t sparse_limit = -1; static int64_t target_sparse_limit = -1; static unsigned base_addr = 0x10000000; static unsigned base_addr = 0x10000000; Loading Loading @@ -117,7 +133,27 @@ char *find_item(const char *item, const char *product) #ifdef _WIN32 #ifdef _WIN32 void *load_file(const char *fn, unsigned *_sz); void *load_file(const char *fn, unsigned *_sz); int64_t file_size(const char *fn); #else #else #if defined(__APPLE__) && defined(__MACH__) #define lseek64 lseek #define off64_t off_t #endif int64_t file_size(const char *fn) { off64_t off; int fd; fd = open(fn, O_RDONLY); if (fd < 0) return -1; off = lseek64(fd, 0, SEEK_END); close(fd); return off; } void *load_file(const char *fn, unsigned *_sz) void *load_file(const char *fn, unsigned *_sz) { { char *data; char *data; Loading Loading @@ -259,6 +295,8 @@ void usage(void) " -i <vendor id> specify a custom USB vendor id\n" " -i <vendor id> specify a custom USB vendor id\n" " -b <base_addr> specify a custom kernel base address\n" " -b <base_addr> specify a custom kernel base address\n" " -n <page size> specify the nand page size. default: 2048\n" " -n <page size> specify the nand page size. default: 2048\n" " -S <size>[K|M|G] automatically sparse files greater than\n" " size. default: 256M, 0 to disable\n" ); ); } } Loading Loading @@ -444,6 +482,110 @@ void queue_info_dump(void) fb_queue_notice("--------------------------------------------"); fb_queue_notice("--------------------------------------------"); } } struct sparse_file **load_sparse_files(const char *fname, 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); } files = sparse_file_resparse(s, max_size, NULL, 0); if (files < 0) { die("Failed to resparse '%s'\n", fname); } out_s = calloc(sizeof(struct sparse_file *), files + 1); if (!out_s) { die("Failed to allocate sparse file array\n"); } files = sparse_file_resparse(s, max_size, out_s, files); if (files < 0) { die("Failed to resparse '%s'\n", fname); } return out_s; } static int64_t get_target_sparse_limit(struct usb_handle *usb) { int64_t limit = 0; char response[FB_RESPONSE_SZ + 1]; int status = fb_getvar(usb, response, "max-download-size"); if (!status) { limit = strtoul(response, NULL, 0); if (limit > 0) { fprintf(stderr, "target reported max download size of %lld bytes\n", limit); } } return limit; } static int64_t get_sparse_limit(struct usb_handle *usb, int64_t size) { int64_t limit; if (sparse_limit == 0) { return 0; } else if (sparse_limit > 0) { limit = sparse_limit; } else { if (target_sparse_limit == -1) { target_sparse_limit = get_target_sparse_limit(usb); } if (target_sparse_limit > 0) { limit = target_sparse_limit; } else { limit = DEFAULT_SPARSE_LIMIT; } } if (size > limit) { return limit; } return 0; } void do_flash(usb_handle *usb, const char *pname, const char *fname) { int64_t sz64; void *data; int64_t limit; sz64 = file_size(fname); limit = get_sparse_limit(usb, sz64); if (limit) { struct sparse_file **s = load_sparse_files(fname, 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); } } else { unsigned int sz; data = load_file(fname, &sz); if (data == 0) die("cannot load '%s'\n", fname); fb_queue_flash(pname, data, sz); } } void do_update_signature(zipfile_t zip, char *fn) void do_update_signature(zipfile_t zip, char *fn) { { void *data; void *data; Loading Loading @@ -581,73 +723,136 @@ int do_oem_command(int argc, char **argv) return 0; return 0; } } static int64_t parse_num(const char *arg) { char *endptr; unsigned long long num; num = strtoull(arg, &endptr, 0); if (endptr == arg) { return -1; } if (*endptr == 'k' || *endptr == 'K') { if (num >= (-1ULL) / 1024) { return -1; } num *= 1024LL; endptr++; } else if (*endptr == 'm' || *endptr == 'M') { if (num >= (-1ULL) / (1024 * 1024)) { return -1; } num *= 1024LL * 1024LL; endptr++; } else if (*endptr == 'g' || *endptr == 'G') { if (num >= (-1ULL) / (1024 * 1024 * 1024)) { return -1; } num *= 1024LL * 1024LL * 1024LL; endptr++; } if (*endptr != '\0') { return -1; } if (num > INT64_MAX) { return -1; } return num; } int main(int argc, char **argv) int main(int argc, char **argv) { { int wants_wipe = 0; int wants_wipe = 0; int wants_reboot = 0; int wants_reboot = 0; int wants_reboot_bootloader = 0; int wants_reboot_bootloader = 0; int wants_device_list = 0; void *data; void *data; unsigned sz; unsigned sz; unsigned page_size = 2048; unsigned page_size = 2048; int status; int status; int c; int r; skip(1); const struct option longopts = { 0, 0, 0, 0 }; if (argc == 0) { usage(); return 1; } if (!strcmp(*argv, "help")) { usage(); return 0; } serial = getenv("ANDROID_SERIAL"); serial = getenv("ANDROID_SERIAL"); while (argc > 0) { while (1) { if(!strcmp(*argv, "-w")) { c = getopt_long(argc, argv, "wb:n:s:S:lp:c:i:m:h", &longopts, NULL); if (c < 0) { break; } switch (c) { case 'w': wants_wipe = 1; wants_wipe = 1; skip(1); break; } else if(!strcmp(*argv, "-b")) { case 'b': require(2); base_addr = strtoul(optarg, 0, 16); base_addr = strtoul(argv[1], 0, 16); break; skip(2); case 'n': } else if(!strcmp(*argv, "-n")) { page_size = (unsigned)strtoul(optarg, NULL, 0); require(2); page_size = (unsigned)strtoul(argv[1], NULL, 0); if (!page_size) die("invalid page size"); if (!page_size) die("invalid page size"); skip(2); break; } else if(!strcmp(*argv, "-s")) { case 's': require(2); serial = optarg; serial = argv[1]; break; skip(2); case 'S': } else if(!strcmp(*argv, "-l")) { sparse_limit = parse_num(optarg); if (sparse_limit < 0) { die("invalid sparse limit"); } break; case 'l': long_listing = 1; long_listing = 1; skip(1); break; } else if(!strcmp(*argv, "-p")) { case 'p': require(2); product = optarg; product = argv[1]; break; skip(2); case 'c': } else if(!strcmp(*argv, "-c")) { cmdline = optarg; require(2); break; cmdline = argv[1]; case 'i': { skip(2); } else if(!strcmp(*argv, "-i")) { char *endptr = NULL; char *endptr = NULL; unsigned long val; unsigned long val; require(2); val = strtoul(optarg, &endptr, 0); val = strtoul(argv[1], &endptr, 0); if (!endptr || *endptr != '\0' || (val & ~0xffff)) if (!endptr || *endptr != '\0' || (val & ~0xffff)) die("invalid vendor id '%s'", argv[1]); die("invalid vendor id '%s'", optarg); vendor_id = (unsigned short)val; vendor_id = (unsigned short)val; skip(2); break; } else if (!strcmp(*argv, "devices")) { } case 'h': usage(); return 1; case '?': return 1; default: abort(); } } argc -= optind; argv += optind; if (argc == 0 && !wants_wipe) { usage(); return 1; } if (!strcmp(*argv, "devices")) { skip(1); skip(1); wants_device_list = 1; list_devices(); } else if(!strcmp(*argv, "getvar")) { return 0; } usb = open_device(); while (argc > 0) { if(!strcmp(*argv, "getvar")) { require(2); require(2); fb_queue_display(argv[1], argv[1]); fb_queue_display(argv[1], argv[1]); skip(2); skip(2); Loading Loading @@ -704,9 +909,7 @@ int main(int argc, char **argv) skip(2); skip(2); } } if (fname == 0) die("cannot determine image filename for '%s'", pname); if (fname == 0) die("cannot determine image filename for '%s'", pname); data = load_file(fname, &sz); do_flash(usb, pname, fname); if (data == 0) die("cannot load '%s'\n", fname); fb_queue_flash(pname, data, sz); } else if(!strcmp(*argv, "flash:raw")) { } else if(!strcmp(*argv, "flash:raw")) { char *pname = argv[1]; char *pname = argv[1]; char *kname = argv[2]; char *kname = argv[2]; Loading Loading @@ -736,15 +939,15 @@ int main(int argc, char **argv) wants_reboot = 1; wants_reboot = 1; } else if(!strcmp(*argv, "oem")) { } else if(!strcmp(*argv, "oem")) { argc = do_oem_command(argc, argv); argc = do_oem_command(argc, argv); } else if (!strcmp(*argv, "help")) { usage(); return 0; } else { } else { usage(); usage(); return 1; return 1; } } } } if (wants_device_list) list_devices(); if (wants_wipe) { if (wants_wipe) { fb_queue_erase("userdata"); fb_queue_erase("userdata"); fb_queue_format("userdata", 1); fb_queue_format("userdata", 1); Loading @@ -760,8 +963,6 @@ int main(int argc, char **argv) if (fb_queue_is_empty()) if (fb_queue_is_empty()) return 0; return 0; usb = open_device(); status = fb_execute_queue(usb); status = fb_execute_queue(usb); return (status) ? 1 : 0; return (status) ? 1 : 0; } }
fastboot/fastboot.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -31,17 +31,22 @@ #include "usb.h" #include "usb.h" struct sparse_file; /* protocol.c - fastboot protocol */ /* protocol.c - fastboot protocol */ int fb_command(usb_handle *usb, const char *cmd); int fb_command(usb_handle *usb, const char *cmd); int fb_command_response(usb_handle *usb, const char *cmd, char *response); int fb_command_response(usb_handle *usb, const char *cmd, char *response); int fb_download_data(usb_handle *usb, const void *data, unsigned size); int fb_download_data(usb_handle *usb, const void *data, unsigned size); int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s); char *fb_get_error(void); char *fb_get_error(void); #define FB_COMMAND_SZ 64 #define FB_COMMAND_SZ 64 #define FB_RESPONSE_SZ 64 #define FB_RESPONSE_SZ 64 /* engine.c - high level command queue engine */ /* engine.c - high level command queue engine */ int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...); void fb_queue_flash(const char *ptn, void *data, unsigned sz);; void fb_queue_flash(const char *ptn, void *data, unsigned sz);; void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz); void fb_queue_erase(const char *ptn); void fb_queue_erase(const char *ptn); void fb_queue_format(const char *ptn, int skip_if_not_supported); void fb_queue_format(const char *ptn, int skip_if_not_supported); void fb_queue_require(const char *prod, const char *var, int invert, void fb_queue_require(const char *prod, const char *var, int invert, Loading
fastboot/protocol.c +160 −27 Original line number Original line Diff line number Diff line Loading @@ -26,11 +26,18 @@ * SUCH DAMAGE. * SUCH DAMAGE. */ */ #define min(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; }) #define round_down(a, b) \ ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) #include <stdio.h> #include <stdio.h> #include <stdlib.h> #include <stdlib.h> #include <string.h> #include <string.h> #include <errno.h> #include <errno.h> #include <sparse/sparse.h> #include "fastboot.h" #include "fastboot.h" static char ERROR[128]; static char ERROR[128]; Loading @@ -40,8 +47,7 @@ char *fb_get_error(void) return ERROR; return ERROR; } } static int check_response(usb_handle *usb, unsigned size, static int check_response(usb_handle *usb, unsigned int size, char *response) unsigned data_okay, char *response) { { unsigned char status[65]; unsigned char status[65]; int r; int r; Loading Loading @@ -82,7 +88,7 @@ static int check_response(usb_handle *usb, unsigned size, return -1; return -1; } } if(!memcmp(status, "DATA", 4) && data_okay){ if(!memcmp(status, "DATA", 4) && size > 0){ unsigned dsize = strtoul((char*) status + 4, 0, 16); unsigned dsize = strtoul((char*) status + 4, 0, 16); if(dsize > size) { if(dsize > size) { strcpy(ERROR, "data size too large"); strcpy(ERROR, "data size too large"); Loading @@ -100,8 +106,7 @@ static int check_response(usb_handle *usb, unsigned size, return -1; return -1; } } static int _command_send(usb_handle *usb, const char *cmd, static int _command_start(usb_handle *usb, const char *cmd, unsigned size, const void *data, unsigned size, char *response) char *response) { { int cmdsize = strlen(cmd); int cmdsize = strlen(cmd); Loading @@ -122,17 +127,13 @@ static int _command_send(usb_handle *usb, const char *cmd, return -1; return -1; } } if(data == 0) { return check_response(usb, size, response); return check_response(usb, size, 0, response); } } r = check_response(usb, size, 1, 0); static int _command_data(usb_handle *usb, const void *data, unsigned size) if(r < 0) { { return -1; int r; } size = r; if(size) { r = usb_write(usb, data, size); r = usb_write(usb, data, size); if(r < 0) { if(r < 0) { sprintf(ERROR, "data transfer failure (%s)", strerror(errno)); sprintf(ERROR, "data transfer failure (%s)", strerror(errno)); Loading @@ -144,24 +145,63 @@ static int _command_send(usb_handle *usb, const char *cmd, usb_close(usb); usb_close(usb); return -1; return -1; } } return r; } } r = check_response(usb, 0, 0, 0); static int _command_end(usb_handle *usb) { int r; r = check_response(usb, 0, 0); if(r < 0) { if(r < 0) { return -1; return -1; } else { } return 0; } static int _command_send(usb_handle *usb, const char *cmd, const void *data, unsigned size, char *response) { int r; if (size == 0) { return -1; } r = _command_start(usb, cmd, size, response); if (r < 0) { return -1; } r = _command_data(usb, data, size); if (r < 0) { return -1; } r = _command_end(usb); if(r < 0) { return -1; } return size; return size; } } static int _command_send_no_data(usb_handle *usb, const char *cmd, char *response) { int r; return _command_start(usb, cmd, 0, response); } } int fb_command(usb_handle *usb, const char *cmd) int fb_command(usb_handle *usb, const char *cmd) { { return _command_send(usb, cmd, 0, 0, 0); return _command_send_no_data(usb, cmd, 0); } } int fb_command_response(usb_handle *usb, const char *cmd, char *response) int fb_command_response(usb_handle *usb, const char *cmd, char *response) { { return _command_send(usb, cmd, 0, 0, response); return _command_send_no_data(usb, cmd, response); } } int fb_download_data(usb_handle *usb, const void *data, unsigned size) int fb_download_data(usb_handle *usb, const void *data, unsigned size) Loading @@ -179,3 +219,96 @@ int fb_download_data(usb_handle *usb, const void *data, unsigned size) } } } } #define USB_BUF_SIZE 512 static char usb_buf[USB_BUF_SIZE]; static int usb_buf_len; static int fb_download_data_sparse_write(void *priv, const void *data, int len) { int r; usb_handle *usb = priv; int to_write; const char *ptr = data; if (usb_buf_len) { to_write = min(USB_BUF_SIZE - usb_buf_len, len); memcpy(usb_buf + usb_buf_len, ptr, to_write); usb_buf_len += to_write; ptr += to_write; len -= to_write; } if (usb_buf_len == USB_BUF_SIZE) { r = _command_data(usb, usb_buf, USB_BUF_SIZE); if (r != USB_BUF_SIZE) { return -1; } usb_buf_len = 0; } if (len > USB_BUF_SIZE) { if (usb_buf_len > 0) { sprintf(ERROR, "internal error: usb_buf not empty\n"); return -1; } to_write = round_down(len, USB_BUF_SIZE); r = _command_data(usb, ptr, to_write); if (r != to_write) { return -1; } ptr += to_write; len -= to_write; } if (len > 0) { if (len > USB_BUF_SIZE) { sprintf(ERROR, "internal error: too much left for usb_buf\n"); return -1; } memcpy(usb_buf, ptr, len); usb_buf_len = len; } return 0; } static int fb_download_data_sparse_flush(usb_handle *usb) { int r; if (usb_buf_len > 0) { r = _command_data(usb, usb_buf, usb_buf_len); if (r != usb_buf_len) { return -1; } usb_buf_len = 0; } return 0; } int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s) { char cmd[64]; int r; int size = sparse_file_len(s, true, false); if (size <= 0) { return -1; } sprintf(cmd, "download:%08x", size); r = _command_start(usb, cmd, size, 0); if (r < 0) { return -1; } r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, usb); if (r < 0) { return -1; } fb_download_data_sparse_flush(usb); return _command_end(usb); }