Sync with master fastboot.

This brings us all the fastboot changes, plus a change we need from libbase,
and then reverts part of a libziparchive cleanup and fixes dependencies on
new changes to the build system.

Bug: http://b/25375777
Change-Id: I813464da95dc6c81b0a1dc7145152f89bb2d14cd
This commit is contained in:
Elliott Hughes 2015-11-04 11:24:59 -08:00 committed by Rom Lemarchand
parent c48d249c37
commit 98699eca48
23 changed files with 553 additions and 648 deletions

View file

@ -0,0 +1,73 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BASE_PARSEINT_H
#define BASE_PARSEINT_H
#include <errno.h>
#include <stdlib.h>
#include <limits>
namespace android {
namespace base {
// Parses the unsigned decimal integer in the string 's' and sets 'out' to
// that value. Optionally allows the caller to define a 'max' beyond which
// otherwise valid values will be rejected. Returns boolean success.
template <typename T>
bool ParseUint(const char* s, T* out,
T max = std::numeric_limits<T>::max()) {
int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
errno = 0;
char* end;
unsigned long long int result = strtoull(s, &end, base);
if (errno != 0 || s == end || *end != '\0') {
return false;
}
if (max < result) {
return false;
}
*out = static_cast<T>(result);
return true;
}
// Parses the signed decimal integer in the string 's' and sets 'out' to
// that value. Optionally allows the caller to define a 'min' and 'max
// beyond which otherwise valid values will be rejected. Returns boolean
// success.
template <typename T>
bool ParseInt(const char* s, T* out,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max()) {
int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
errno = 0;
char* end;
long long int result = strtoll(s, &end, base);
if (errno != 0 || s == end || *end != '\0') {
return false;
}
if (result < min || max < result) {
return false;
}
*out = static_cast<T>(result);
return true;
}
} // namespace base
} // namespace android
#endif // BASE_PARSEINT_H

View file

@ -21,7 +21,7 @@ include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \ LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
$(LOCAL_PATH)/../../extras/ext4_utils \ $(LOCAL_PATH)/../../extras/ext4_utils \
$(LOCAL_PATH)/../../extras/f2fs_utils $(LOCAL_PATH)/../../extras/f2fs_utils
LOCAL_SRC_FILES := protocol.c engine.c bootimg_utils.cpp fastboot.cpp util.c fs.c LOCAL_SRC_FILES := protocol.cpp engine.cpp bootimg_utils.cpp fastboot.cpp util.cpp fs.cpp
LOCAL_MODULE := fastboot LOCAL_MODULE := fastboot
LOCAL_MODULE_TAGS := debug LOCAL_MODULE_TAGS := debug
LOCAL_CONLYFLAGS += -std=gnu99 LOCAL_CONLYFLAGS += -std=gnu99
@ -29,33 +29,7 @@ LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"' LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
ifeq ($(HOST_OS),linux) LOCAL_STATIC_LIBRARIES += \
LOCAL_SRC_FILES += usb_linux.c util_linux.c
endif
ifeq ($(HOST_OS),darwin)
LOCAL_SRC_FILES += usb_osx.c util_osx.c
LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_CFLAGS += -Wno-unused-parameter
endif
ifeq ($(HOST_OS),windows)
LOCAL_SRC_FILES += usb_windows.c util_windows.c
EXTRA_STATIC_LIBS := AdbWinApi
ifneq ($(strip $(USE_CYGWIN)),)
# Pure cygwin case
LOCAL_LDLIBS += -lpthread
endif
ifneq ($(strip $(USE_MINGW)),)
# MinGW under Linux case
LOCAL_LDLIBS += -lws2_32
USE_SYSDEPS_WIN32 := 1
endif
LOCAL_C_INCLUDES += development/host/windows/usb/api
endif
LOCAL_STATIC_LIBRARIES := \
$(EXTRA_STATIC_LIBS) \
libziparchive-host \ libziparchive-host \
libext4_utils_host \ libext4_utils_host \
libsparse_host \ libsparse_host \
@ -64,23 +38,37 @@ LOCAL_STATIC_LIBRARIES := \
libz \ libz \
libbase libbase
ifneq ($(HOST_OS),windows)
LOCAL_STATIC_LIBRARIES += libselinux
endif # HOST_OS != windows
ifeq ($(HOST_OS),linux) ifeq ($(HOST_OS),linux)
# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn") LOCAL_SRC_FILES += usb_linux.cpp util_linux.cpp
LOCAL_CFLAGS += -DUSE_F2FS LOCAL_STATIC_LIBRARIES += libselinux
LOCAL_LDFLAGS += -ldl -rdynamic -Wl,-rpath,.
LOCAL_REQUIRED_MODULES := libf2fs_fmt_host_dyn # libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
# The following libf2fs_* are from system/extras/f2fs_utils, LOCAL_CFLAGS += -DUSE_F2FS
# and do not use code in external/f2fs-tools. LOCAL_LDFLAGS += -ldl -rdynamic -Wl,-rpath,.
LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host LOCAL_REQUIRED_MODULES += libf2fs_fmt_host_dyn
# The following libf2fs_* are from system/extras/f2fs_utils,
# and do not use code in external/f2fs-tools.
LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
endif endif
# libc++ not available on windows yet ifeq ($(HOST_OS),darwin)
LOCAL_SRC_FILES += usb_osx.cpp util_osx.cpp
LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_STATIC_LIBRARIES += libselinux
endif
ifeq ($(HOST_OS),windows)
LOCAL_SRC_FILES += usb_windows.cpp util_windows.cpp
LOCAL_STATIC_LIBRARIES += AdbWinApi
LOCAL_REQUIRED_MODULES += AdbWinApi
LOCAL_LDLIBS += -lws2_32
LOCAL_C_INCLUDES += development/host/windows/usb/api
endif
# libc++ not available on windows yet.
ifneq ($(HOST_OS),windows) ifneq ($(HOST_OS),windows)
LOCAL_CXX_STL := libc++_static LOCAL_CXX_STL := libc++_static
endif endif
# Don't add anything here, we don't want additional shared dependencies # Don't add anything here, we don't want additional shared dependencies
@ -97,10 +85,9 @@ endif
$(call dist-for-goals,dist_files sdk,$(my_dist_files)) $(call dist-for-goals,dist_files sdk,$(my_dist_files))
my_dist_files := my_dist_files :=
ifeq ($(HOST_OS),linux) ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_SRC_FILES := usbtest.c usb_linux.c util.c LOCAL_SRC_FILES := usbtest.cpp usb_linux.cpp util.cpp
LOCAL_MODULE := usbtest LOCAL_MODULE := usbtest
LOCAL_CFLAGS := -Werror LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_EXECUTABLE) include $(BUILD_HOST_EXECUTABLE)

View file

@ -32,32 +32,27 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline) void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline)
{ {
strcpy((char*) h->cmdline, cmdline); strcpy((char*) h->cmdline, cmdline);
} }
boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset, boot_img_hdr* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset,
void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset, void* ramdisk, int64_t ramdisk_size, off_t ramdisk_offset,
void *second, unsigned second_size, unsigned second_offset, void* second, int64_t second_size, off_t second_offset,
unsigned page_size, unsigned base, unsigned tags_offset, size_t page_size, size_t base, off_t tags_offset,
unsigned *bootimg_size) int64_t* bootimg_size)
{ {
unsigned kernel_actual; size_t page_mask = page_size - 1;
unsigned ramdisk_actual;
unsigned second_actual;
unsigned page_mask;
page_mask = page_size - 1; int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask);
int64_t ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
kernel_actual = (kernel_size + page_mask) & (~page_mask); int64_t second_actual = (second_size + page_mask) & (~page_mask);
ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
second_actual = (second_size + page_mask) & (~page_mask);
*bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual; *bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual;
boot_img_hdr* hdr = reinterpret_cast<boot_img_hdr*>(calloc(*bootimg_size, 1)); boot_img_hdr* hdr = reinterpret_cast<boot_img_hdr*>(calloc(*bootimg_size, 1));
if (hdr == 0) { if (hdr == nullptr) {
return hdr; return hdr;
} }
@ -74,12 +69,9 @@ boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offs
hdr->page_size = page_size; hdr->page_size = page_size;
memcpy(hdr->magic + page_size, kernel, kernel_size);
memcpy(hdr->magic + page_size + kernel_actual, ramdisk, ramdisk_size);
memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual, second, second_size);
memcpy(hdr->magic + page_size,
kernel, kernel_size);
memcpy(hdr->magic + page_size + kernel_actual,
ramdisk, ramdisk_size);
memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual,
second, second_size);
return hdr; return hdr;
} }

View file

@ -30,20 +30,14 @@
#define _FASTBOOT_BOOTIMG_UTILS_H_ #define _FASTBOOT_BOOTIMG_UTILS_H_
#include <bootimg.h> #include <bootimg.h>
#include <inttypes.h>
#include <sys/types.h>
#if defined(__cplusplus) void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline);
extern "C" { boot_img_hdr* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset,
#endif void* ramdisk, int64_t ramdisk_size, off_t ramdisk_offset,
void* second, int64_t second_size, off_t second_offset,
void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); size_t page_size, size_t base, off_t tags_offset,
boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset, int64_t* bootimg_size);
void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
void *second, unsigned second_size, unsigned second_offset,
unsigned page_size, unsigned base, unsigned tags_offset,
unsigned *bootimg_size);
#if defined(__cplusplus)
}
#endif
#endif #endif

View file

@ -31,7 +31,6 @@
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -39,16 +38,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#ifdef USE_MINGW
#include <fcntl.h>
#else
#include <sys/mman.h>
#endif
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define OP_DOWNLOAD 1 #define OP_DOWNLOAD 1
@ -62,18 +51,20 @@ typedef struct Action Action;
#define CMD_SIZE 64 #define CMD_SIZE 64
struct Action struct Action {
{
unsigned op; unsigned op;
Action *next; Action* next;
char cmd[CMD_SIZE]; char cmd[CMD_SIZE];
const char *prod; const char* prod;
void *data; void* data;
unsigned size;
// The protocol only supports 32-bit sizes, so you'll have to break
// anything larger into chunks.
uint32_t size;
const char *msg; const char *msg;
int (*func)(Action *a, int status, char *resp); int (*func)(Action* a, int status, const char* resp);
double start; double start;
}; };
@ -84,45 +75,20 @@ static Action *action_last = 0;
int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...) bool fb_getvar(usb_handle* usb, const std::string& key, std::string* value) {
{ std::string cmd = "getvar:";
char cmd[CMD_SIZE] = "getvar:"; cmd += key;
int getvar_len = strlen(cmd);
va_list args;
response[FB_RESPONSE_SZ] = '\0'; char buf[FB_RESPONSE_SZ + 1];
va_start(args, fmt); memset(buf, 0, sizeof(buf));
vsnprintf(cmd + getvar_len, sizeof(cmd) - getvar_len, fmt, args); if (fb_command_response(usb, cmd.c_str(), buf)) {
va_end(args); return false;
cmd[CMD_SIZE - 1] = '\0'; }
return fb_command_response(usb, cmd, response); *value = buf;
return true;
} }
static int cb_default(Action* a, int status, const char* resp) {
/* Return true if this partition is supported by the fastboot format command.
* It is also used to determine if we should first erase a partition before
* flashing it with an ext4 filesystem. See needs_erase()
*
* Not all devices report the filesystem type, so don't report any errors,
* just return false.
*/
int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override)
{
char fs_type[FB_RESPONSE_SZ + 1] = {0,};
int status;
if (type_override) {
return !!fs_get_generator(type_override);
}
status = fb_getvar(usb, fs_type, "partition-type:%s", partition);
if (status) {
return 0;
}
return !!fs_get_generator(fs_type);
}
static int cb_default(Action *a, int status, char *resp)
{
if (status) { if (status) {
fprintf(stderr,"FAILED (%s)\n", resp); fprintf(stderr,"FAILED (%s)\n", resp);
} else { } else {
@ -135,12 +101,11 @@ static int cb_default(Action *a, int status, char *resp)
static Action *queue_action(unsigned op, const char *fmt, ...) static Action *queue_action(unsigned op, const char *fmt, ...)
{ {
Action *a;
va_list ap; va_list ap;
size_t cmdsize; size_t cmdsize;
a = calloc(1, sizeof(Action)); Action* a = reinterpret_cast<Action*>(calloc(1, sizeof(Action)));
if (a == 0) die("out of memory"); if (a == nullptr) die("out of memory");
va_start(ap, fmt); va_start(ap, fmt);
cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap); cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
@ -198,8 +163,7 @@ void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz)
a->msg = mkmsg("writing '%s'", ptn); a->msg = mkmsg("writing '%s'", ptn);
} }
static int match(char *str, const char **value, unsigned count) static int match(const char* str, const char** value, unsigned count) {
{
unsigned n; unsigned n;
for (n = 0; n < count; n++) { for (n = 0; n < count; n++) {
@ -222,9 +186,9 @@ static int match(char *str, const char **value, unsigned count)
static int cb_check(Action *a, int status, char *resp, int invert) static int cb_check(Action* a, int status, const char* resp, int invert)
{ {
const char **value = a->data; const char** value = reinterpret_cast<const char**>(a->data);
unsigned count = a->size; unsigned count = a->size;
unsigned n; unsigned n;
int yes; int yes;
@ -265,18 +229,16 @@ static int cb_check(Action *a, int status, char *resp, int invert)
return -1; return -1;
} }
static int cb_require(Action *a, int status, char *resp) static int cb_require(Action*a, int status, const char* resp) {
{
return cb_check(a, status, resp, 0); return cb_check(a, status, resp, 0);
} }
static int cb_reject(Action *a, int status, char *resp) static int cb_reject(Action* a, int status, const char* resp) {
{
return cb_check(a, status, resp, 1); return cb_check(a, status, resp, 1);
} }
void fb_queue_require(const char *prod, const char *var, void fb_queue_require(const char *prod, const char *var,
int invert, unsigned nvalues, const char **value) bool invert, size_t nvalues, const char **value)
{ {
Action *a; Action *a;
a = queue_action(OP_QUERY, "getvar:%s", var); a = queue_action(OP_QUERY, "getvar:%s", var);
@ -285,11 +247,10 @@ void fb_queue_require(const char *prod, const char *var,
a->size = nvalues; a->size = nvalues;
a->msg = mkmsg("checking %s", var); a->msg = mkmsg("checking %s", var);
a->func = invert ? cb_reject : cb_require; a->func = invert ? cb_reject : cb_require;
if (a->data == 0) die("out of memory"); if (a->data == nullptr) die("out of memory");
} }
static int cb_display(Action *a, int status, char *resp) static int cb_display(Action* a, int status, const char* resp) {
{
if (status) { if (status) {
fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp); fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
return status; return status;
@ -303,17 +264,16 @@ void fb_queue_display(const char *var, const char *prettyname)
Action *a; Action *a;
a = queue_action(OP_QUERY, "getvar:%s", var); a = queue_action(OP_QUERY, "getvar:%s", var);
a->data = strdup(prettyname); a->data = strdup(prettyname);
if (a->data == 0) die("out of memory"); if (a->data == nullptr) die("out of memory");
a->func = cb_display; a->func = cb_display;
} }
static int cb_save(Action *a, int status, char *resp) static int cb_save(Action* a, int status, const char* resp) {
{
if (status) { if (status) {
fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp); fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
return status; return status;
} }
strncpy(a->data, resp, a->size); strncpy(reinterpret_cast<char*>(a->data), resp, a->size);
return 0; return 0;
} }
@ -326,8 +286,7 @@ void fb_queue_query_save(const char *var, char *dest, unsigned dest_size)
a->func = cb_save; a->func = cb_save;
} }
static int cb_do_nothing(Action *a __unused, int status __unused, char *resp __unused) static int cb_do_nothing(Action*, int , const char*) {
{
fprintf(stderr,"\n"); fprintf(stderr,"\n");
return 0; return 0;
} }
@ -398,7 +357,7 @@ int fb_execute_queue(usb_handle *usb)
} else if (a->op == OP_NOTICE) { } else if (a->op == OP_NOTICE) {
fprintf(stderr,"%s\n",(char*)a->data); fprintf(stderr,"%s\n",(char*)a->data);
} else if (a->op == OP_DOWNLOAD_SPARSE) { } else if (a->op == OP_DOWNLOAD_SPARSE) {
status = fb_download_data_sparse(usb, a->data); status = fb_download_data_sparse(usb, reinterpret_cast<sparse_file*>(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_WAIT_FOR_DISCONNECT) { } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
@ -411,8 +370,3 @@ int fb_execute_queue(usb_handle *usb)
fprintf(stderr,"finished. total time: %.3fs\n", (now() - start)); fprintf(stderr,"finished. total time: %.3fs\n", (now() - start));
return status; return status;
} }
int fb_queue_is_empty(void)
{
return (action_list == NULL);
}

Binary file not shown.

View file

@ -34,7 +34,6 @@
#include <getopt.h> #include <getopt.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -44,6 +43,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <base/parseint.h>
#include <base/strings.h>
#include <sparse/sparse.h> #include <sparse/sparse.h>
#include <ziparchive/zip_archive.h> #include <ziparchive/zip_archive.h>
@ -67,12 +68,12 @@ static int long_listing = 0;
static int64_t sparse_limit = -1; static int64_t sparse_limit = -1;
static int64_t target_sparse_limit = -1; static int64_t target_sparse_limit = -1;
unsigned page_size = 2048; static unsigned page_size = 2048;
unsigned base_addr = 0x10000000; static unsigned base_addr = 0x10000000;
unsigned kernel_offset = 0x00008000; static unsigned kernel_offset = 0x00008000;
unsigned ramdisk_offset = 0x01000000; static unsigned ramdisk_offset = 0x01000000;
unsigned second_offset = 0x00f00000; static unsigned second_offset = 0x00f00000;
unsigned tags_offset = 0x00000100; static unsigned tags_offset = 0x00000100;
enum fb_buffer_type { enum fb_buffer_type {
FB_BUFFER, FB_BUFFER,
@ -81,8 +82,8 @@ enum fb_buffer_type {
struct fastboot_buffer { struct fastboot_buffer {
enum fb_buffer_type type; enum fb_buffer_type type;
void *data; void* data;
unsigned int sz; int64_t sz;
}; };
static struct { static struct {
@ -97,8 +98,7 @@ static struct {
{"vendor.img", "vendor.sig", "vendor", true}, {"vendor.img", "vendor.sig", "vendor", true},
}; };
char *find_item(const char *item, const char *product) static char* find_item(const char* item, const char* product) {
{
char *dir; char *dir;
const char *fn; const char *fn;
char path[PATH_MAX + 128]; char path[PATH_MAX + 128];
@ -139,36 +139,26 @@ char *find_item(const char *item, const char *product)
return strdup(path); return strdup(path);
} }
static int64_t file_size(int fd) static int64_t get_file_size(int fd) {
{ struct stat sb;
struct stat st; return fstat(fd, &sb) == -1 ? -1 : sb.st_size;
int ret;
ret = fstat(fd, &st);
return ret ? -1 : st.st_size;
} }
static void *load_fd(int fd, unsigned *_sz) static void* load_fd(int fd, int64_t* sz) {
{
char *data;
int sz;
int errno_tmp; int errno_tmp;
char* data = nullptr;
data = 0; *sz = get_file_size(fd);
if (*sz < 0) {
sz = file_size(fd);
if (sz < 0) {
goto oops; goto oops;
} }
data = (char*) malloc(sz); data = (char*) malloc(*sz);
if(data == 0) goto oops; if (data == nullptr) goto oops;
if(read(fd, data, sz) != sz) goto oops; if(read(fd, data, *sz) != *sz) goto oops;
close(fd); close(fd);
if(_sz) *_sz = sz;
return data; return data;
oops: oops:
@ -179,35 +169,22 @@ oops:
return 0; return 0;
} }
static void *load_file(const char *fn, unsigned *_sz) static void* load_file(const char* fn, int64_t* sz) {
{ int fd = open(fn, O_RDONLY | O_BINARY);
int fd; if (fd == -1) return nullptr;
return load_fd(fd, sz);
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) static int match_fastboot_with_serial(usb_ifc_info* info, const char* local_serial) {
{ // Require a matching vendor id if the user specified one with -i.
if(!(vendor_id && (info->dev_vendor == vendor_id)) && if (vendor_id != 0 && info->dev_vendor != vendor_id) {
(info->dev_vendor != 0x18d1) && // Google return -1;
(info->dev_vendor != 0x8087) && // Intel }
(info->dev_vendor != 0x0451) &&
(info->dev_vendor != 0x0502) && if (info->ifc_class != 0xff || info->ifc_subclass != 0x42 || info->ifc_protocol != 0x03) {
(info->dev_vendor != 0x0fce) && // Sony Ericsson return -1;
(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 or device path if requested // require matching serial number or device path if requested
// at the command line with the -s option. // at the command line with the -s option.
if (local_serial && (strcmp(local_serial, info->serial_number) != 0 && if (local_serial && (strcmp(local_serial, info->serial_number) != 0 &&
@ -215,14 +192,12 @@ int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
return 0; return 0;
} }
int match_fastboot(usb_ifc_info *info) static int match_fastboot(usb_ifc_info* info) {
{
return match_fastboot_with_serial(info, serial); return match_fastboot_with_serial(info, serial);
} }
int list_devices_callback(usb_ifc_info *info) static int list_devices_callback(usb_ifc_info* info) {
{ if (match_fastboot_with_serial(info, nullptr) == 0) {
if (match_fastboot_with_serial(info, NULL) == 0) {
const char* serial = info->serial_number; const char* serial = info->serial_number;
if (!info->writable) { if (!info->writable) {
serial = "no permissions"; // like "adb devices" serial = "no permissions"; // like "adb devices"
@ -243,8 +218,7 @@ int list_devices_callback(usb_ifc_info *info)
return -1; return -1;
} }
usb_handle *open_device(void) static usb_handle* open_device() {
{
static usb_handle *usb = 0; static usb_handle *usb = 0;
int announce = 1; int announce = 1;
@ -255,103 +229,99 @@ usb_handle *open_device(void)
if(usb) return usb; if(usb) return usb;
if(announce) { if(announce) {
announce = 0; announce = 0;
fprintf(stderr,"< waiting for device >\n"); fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device");
} }
usleep(1000); usleep(1000);
} }
} }
void list_devices(void) { static void list_devices() {
// We don't actually open a USB device here, // We don't actually open a USB device here,
// just getting our callback called so we can // just getting our callback called so we can
// list all the connected devices. // list all the connected devices.
usb_open(list_devices_callback); usb_open(list_devices_callback);
} }
void usage(void) static void usage() {
{
fprintf(stderr, fprintf(stderr,
/* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */ /* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */
"usage: fastboot [ <option> ] <command>\n" "usage: fastboot [ <option> ] <command>\n"
"\n" "\n"
"commands:\n" "commands:\n"
" update <filename> reflash device from update.zip\n" " update <filename> Reflash device from update.zip.\n"
" flashall flash boot, system, vendor and if found,\n" " flashall Flash boot, system, vendor, and --\n"
" recovery\n" " if found -- recovery.\n"
" flash <partition> [ <filename> ] write a file to a flash partition\n" " flash <partition> [ <filename> ] Write a file to a flash partition.\n"
" flashing lock locks the device. Prevents flashing\n" " flashing lock Locks the device. Prevents flashing.\n"
" partitions\n" " flashing unlock Unlocks the device. Allows flashing\n"
" flashing unlock unlocks the device. Allows user to\n" " any partition except\n"
" flash any partition except the ones\n" " bootloader-related partitions.\n"
" that are related to bootloader\n" " flashing lock_critical Prevents flashing bootloader-related\n"
" flashing lock_critical Prevents flashing bootloader related\n" " partitions.\n"
" partitions\n" " flashing unlock_critical Enables flashing bootloader-related\n"
" flashing unlock_critical Enables flashing bootloader related\n" " partitions.\n"
" partitions\n"
" flashing get_unlock_ability Queries bootloader to see if the\n" " flashing get_unlock_ability Queries bootloader to see if the\n"
" device is unlocked\n" " device is unlocked.\n"
" flashing get_unlock_bootloader_nonce Queries the bootloader to get the\n" " flashing get_unlock_bootloader_nonce Queries the bootloader to get the\n"
" unlock nonce\n" " unlock nonce.\n"
" flashing unlock_bootloader <request> Issue unlock bootloader using request\n" " flashing unlock_bootloader <request> Issue unlock bootloader using request.\n"
" flashing lock_bootloader Locks the bootloader to prevent\n" " flashing lock_bootloader Locks the bootloader to prevent\n"
" bootloader version rollback\n" " bootloader version rollback.\n"
" erase <partition> erase a flash partition\n" " erase <partition> Erase a flash partition.\n"
" format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n" " format[:[<fs type>][:[<size>]] <partition>\n"
" Can override the fs type and/or\n" " Format a flash partition. Can\n"
" size the bootloader reports.\n" " override the fs type and/or size\n"
" getvar <variable> display a bootloader variable\n" " the bootloader reports.\n"
" boot <kernel> [ <ramdisk> ] download and boot kernel\n" " getvar <variable> Display a bootloader variable.\n"
" flash:raw boot <kernel> [ <ramdisk> ] create bootimage and flash it\n" " boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
" devices list all connected devices\n" " flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
" continue continue with autoboot\n" " Create bootimage and flash it.\n"
" reboot [bootloader] reboot device, optionally into bootloader\n" " devices [-l] List all connected devices [with\n"
" reboot-bootloader reboot device into bootloader\n" " device paths].\n"
" help show this help message\n" " continue Continue with autoboot.\n"
" reboot [bootloader] Reboot device [into bootloader].\n"
" reboot-bootloader Reboot device into bootloader.\n"
" help Show this help message.\n"
"\n" "\n"
"options:\n" "options:\n"
" -w erase userdata and cache (and format\n" " -w Erase userdata and cache (and format\n"
" if supported by partition type)\n" " if supported by partition type).\n"
" -u do not first erase partition before\n" " -u Do not erase partition before\n"
" formatting\n" " formatting.\n"
" -s <specific device> specify device serial number\n" " -s <specific device> Specify device serial number\n"
" or path to device port\n" " or path to device port.\n"
" -l with \"devices\", lists device paths\n" " -p <product> Specify product name.\n"
" -p <product> specify product name\n" " -c <cmdline> Override kernel commandline.\n"
" -c <cmdline> override kernel commandline\n" " -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\n"
" -b <base_addr> specify a custom kernel base address.\n" " address (default: 0x10000000).\n"
" default: 0x10000000\n" " -n <page size> Specify the nand page size\n"
" -n <page size> specify the nand page size.\n" " (default: 2048).\n"
" default: 2048\n" " -S <size>[K|M|G] Automatically sparse files greater\n"
" -S <size>[K|M|G] automatically sparse files greater\n" " than 'size'. 0 to disable.\n"
" than size. 0 to disable\n"
); );
} }
void *load_bootable_image(const char *kernel, const char *ramdisk, static void* load_bootable_image(const char* kernel, const char* ramdisk,
unsigned *sz, const char *cmdline) const char* secondstage, int64_t* sz,
{ const char* cmdline) {
void *kdata = 0, *rdata = 0; if (kernel == nullptr) {
unsigned ksize = 0, rsize = 0;
void *bdata;
unsigned bsize;
if(kernel == 0) {
fprintf(stderr, "no image specified\n"); fprintf(stderr, "no image specified\n");
return 0; return 0;
} }
kdata = load_file(kernel, &ksize); int64_t ksize;
if(kdata == 0) { void* kdata = load_file(kernel, &ksize);
if (kdata == nullptr) {
fprintf(stderr, "cannot load '%s': %s\n", kernel, strerror(errno)); fprintf(stderr, "cannot load '%s': %s\n", kernel, strerror(errno));
return 0; return 0;
} }
/* is this actually a boot image? */ // Is this actually a boot image?
if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline); if (cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
if(ramdisk) { if (ramdisk) {
fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n"); fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
return 0; return 0;
} }
@ -360,31 +330,44 @@ void *load_bootable_image(const char *kernel, const char *ramdisk,
return kdata; return kdata;
} }
if(ramdisk) { void* rdata = nullptr;
int64_t rsize = 0;
if (ramdisk) {
rdata = load_file(ramdisk, &rsize); rdata = load_file(ramdisk, &rsize);
if(rdata == 0) { if (rdata == nullptr) {
fprintf(stderr,"cannot load '%s': %s\n", ramdisk, strerror(errno)); fprintf(stderr,"cannot load '%s': %s\n", ramdisk, strerror(errno));
return 0; return 0;
} }
} }
void* sdata = nullptr;
int64_t ssize = 0;
if (secondstage) {
sdata = load_file(secondstage, &ssize);
if (sdata == nullptr) {
fprintf(stderr,"cannot load '%s': %s\n", secondstage, strerror(errno));
return 0;
}
}
fprintf(stderr,"creating boot image...\n"); fprintf(stderr,"creating boot image...\n");
bdata = mkbootimg(kdata, ksize, kernel_offset, int64_t bsize = 0;
void* bdata = mkbootimg(kdata, ksize, kernel_offset,
rdata, rsize, ramdisk_offset, rdata, rsize, ramdisk_offset,
0, 0, second_offset, sdata, ssize, second_offset,
page_size, base_addr, tags_offset, &bsize); page_size, base_addr, tags_offset, &bsize);
if(bdata == 0) { if (bdata == nullptr) {
fprintf(stderr,"failed to create boot.img\n"); fprintf(stderr,"failed to create boot.img\n");
return 0; return 0;
} }
if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline); if (cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
fprintf(stderr,"creating boot image - %d bytes\n", bsize); fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize);
*sz = bsize; *sz = bsize;
return bdata; return bdata;
} }
static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, unsigned* sz) static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, int64_t* sz)
{ {
ZipEntryName zip_entry_name(entry_name); ZipEntryName zip_entry_name(entry_name);
ZipEntry zip_entry; ZipEntry zip_entry;
@ -396,8 +379,8 @@ static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, unsigned*
*sz = zip_entry.uncompressed_length; *sz = zip_entry.uncompressed_length;
uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length)); uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
if (data == NULL) { if (data == nullptr) {
fprintf(stderr, "failed to allocate %u bytes for '%s'\n", *sz, entry_name); fprintf(stderr, "failed to allocate %" PRId64 " bytes for '%s'\n", *sz, entry_name);
return 0; return 0;
} }
@ -442,7 +425,7 @@ static FILE* win32_tmpfile() {
static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) { static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
FILE* fp = tmpfile(); FILE* fp = tmpfile();
if (fp == NULL) { if (fp == nullptr) {
fprintf(stderr, "failed to create temporary file for '%s': %s\n", fprintf(stderr, "failed to create temporary file for '%s': %s\n",
entry_name, strerror(errno)); entry_name, strerror(errno));
return -1; return -1;
@ -482,7 +465,7 @@ static char *strip(char *s)
static int setup_requirement_line(char *name) static int setup_requirement_line(char *name)
{ {
char *val[MAX_OPTIONS]; char *val[MAX_OPTIONS];
char *prod = NULL; char *prod = nullptr;
unsigned n, count; unsigned n, count;
char *x; char *x;
int invert = 0; int invert = 0;
@ -543,13 +526,10 @@ static int setup_requirement_line(char *name)
return 0; return 0;
} }
static void setup_requirements(char *data, unsigned sz) static void setup_requirements(char* data, int64_t sz) {
{ char* s = data;
char *s;
s = data;
while (sz-- > 0) { while (sz-- > 0) {
if(*s == '\n') { if (*s == '\n') {
*s++ = 0; *s++ = 0;
if (setup_requirement_line(data)) { if (setup_requirement_line(data)) {
die("out of memory"); die("out of memory");
@ -561,8 +541,7 @@ static void setup_requirements(char *data, unsigned sz)
} }
} }
void queue_info_dump(void) static void queue_info_dump() {
{
fb_queue_notice("--------------------------------------------"); fb_queue_notice("--------------------------------------------");
fb_queue_display("version-bootloader", "Bootloader Version..."); fb_queue_display("version-bootloader", "Bootloader Version...");
fb_queue_display("version-baseband", "Baseband Version....."); fb_queue_display("version-baseband", "Baseband Version.....");
@ -577,7 +556,7 @@ static struct sparse_file **load_sparse_files(int fd, int max_size)
die("cannot sparse read file\n"); die("cannot sparse read file\n");
} }
int files = sparse_file_resparse(s, max_size, NULL, 0); int files = sparse_file_resparse(s, max_size, nullptr, 0);
if (files < 0) { if (files < 0) {
die("Failed to resparse\n"); die("Failed to resparse\n");
} }
@ -595,25 +574,28 @@ static struct sparse_file **load_sparse_files(int fd, int max_size)
return out_s; return out_s;
} }
static int64_t get_target_sparse_limit(struct usb_handle *usb) static int64_t get_target_sparse_limit(usb_handle* usb) {
{ std::string max_download_size;
int64_t limit = 0; if (!fb_getvar(usb, "max-download-size", &max_download_size) || max_download_size.empty()) {
char response[FB_RESPONSE_SZ + 1]; fprintf(stderr, "target didn't report max-download-size\n");
int status = fb_getvar(usb, response, "max-download-size"); return 0;
if (!status) {
limit = strtoul(response, NULL, 0);
if (limit > 0) {
fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n",
limit);
}
} }
// Some bootloaders (angler, for example) send spurious whitespace too.
max_download_size = android::base::Trim(max_download_size);
uint64_t limit;
if (!android::base::ParseUint(max_download_size.c_str(), &limit)) {
fprintf(stderr, "couldn't parse max-download-size '%s'\n", max_download_size.c_str());
return 0;
}
if (limit > 0) {
fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n", limit);
}
return limit; return limit;
} }
static int64_t get_sparse_limit(struct usb_handle *usb, int64_t size) static int64_t get_sparse_limit(usb_handle* usb, int64_t size) {
{
int64_t limit; int64_t limit;
if (sparse_limit == 0) { if (sparse_limit == 0) {
@ -638,44 +620,35 @@ static int64_t get_sparse_limit(struct usb_handle *usb, int64_t size)
return 0; return 0;
} }
/* Until we get lazy inode table init working in make_ext4fs, we need to // Until we get lazy inode table init working in make_ext4fs, we need to
* erase partitions of type ext4 before flashing a filesystem so no stale // erase partitions of type ext4 before flashing a filesystem so no stale
* inodes are left lying around. Otherwise, e2fsck gets very upset. // inodes are left lying around. Otherwise, e2fsck gets very upset.
*/ static bool needs_erase(usb_handle* usb, const char* partition) {
static int needs_erase(usb_handle* usb, const char *part) std::string partition_type;
{ if (!fb_getvar(usb, std::string("partition-type:") + partition, &partition_type)) {
/* The function fb_format_supported() currently returns the value return false;
* we want, so just call it. }
*/ return partition_type == "ext4";
return fb_format_supported(usb, part, NULL);
} }
static int load_buf_fd(usb_handle *usb, int fd, static int load_buf_fd(usb_handle* usb, int fd, struct fastboot_buffer* buf) {
struct fastboot_buffer *buf) int64_t sz = get_file_size(fd);
{ if (sz == -1) {
int64_t sz64;
void *data;
int64_t limit;
sz64 = file_size(fd);
if (sz64 < 0) {
return -1; return -1;
} }
lseek(fd, 0, SEEK_SET); lseek64(fd, 0, SEEK_SET);
limit = get_sparse_limit(usb, sz64); int64_t limit = get_sparse_limit(usb, sz);
if (limit) { if (limit) {
struct sparse_file **s = load_sparse_files(fd, limit); sparse_file** s = load_sparse_files(fd, limit);
if (s == NULL) { if (s == nullptr) {
return -1; return -1;
} }
buf->type = FB_BUFFER_SPARSE; buf->type = FB_BUFFER_SPARSE;
buf->data = s; buf->data = s;
} else { } else {
unsigned int sz; void* data = load_fd(fd, &sz);
data = load_fd(fd, &sz); if (data == nullptr) return -1;
if (data == 0) return -1;
buf->type = FB_BUFFER; buf->type = FB_BUFFER;
buf->data = data; buf->data = data;
buf->sz = sz; buf->sz = sz;
@ -705,8 +678,8 @@ static void flash_buf(const char *pname, struct fastboot_buffer *buf)
case FB_BUFFER_SPARSE: case FB_BUFFER_SPARSE:
s = reinterpret_cast<sparse_file**>(buf->data); s = reinterpret_cast<sparse_file**>(buf->data);
while (*s) { while (*s) {
int64_t sz64 = sparse_file_len(*s, true, false); int64_t sz = sparse_file_len(*s, true, false);
fb_queue_flash_sparse(pname, *s++, sz64); fb_queue_flash_sparse(pname, *s++, sz);
} }
break; break;
case FB_BUFFER: case FB_BUFFER:
@ -717,8 +690,7 @@ static void flash_buf(const char *pname, struct fastboot_buffer *buf)
} }
} }
void do_flash(usb_handle *usb, const char *pname, const char *fname) static void do_flash(usb_handle* usb, const char* pname, const char* fname) {
{
struct fastboot_buffer buf; struct fastboot_buffer buf;
if (load_buf(usb, fname, &buf)) { if (load_buf(usb, fname, &buf)) {
@ -727,17 +699,15 @@ void do_flash(usb_handle *usb, const char *pname, const char *fname)
flash_buf(pname, &buf); flash_buf(pname, &buf);
} }
void do_update_signature(ZipArchiveHandle zip, char *fn) static void do_update_signature(ZipArchiveHandle zip, char* fn) {
{ int64_t sz;
unsigned sz;
void* data = unzip_file(zip, fn, &sz); void* data = unzip_file(zip, fn, &sz);
if (data == 0) return; if (data == nullptr) return;
fb_queue_download("signature", data, sz); fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature"); fb_queue_command("signature", "installing signature");
} }
void do_update(usb_handle *usb, const char *filename, int erase_first) static void do_update(usb_handle* usb, const char* filename, bool erase_first) {
{
queue_info_dump(); queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product)); fb_queue_query_save("product", cur_product, sizeof(cur_product));
@ -749,9 +719,9 @@ void do_update(usb_handle *usb, const char *filename, int erase_first)
die("failed to open zip file '%s': %s", filename, ErrorCodeString(error)); die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
} }
unsigned sz; int64_t sz;
void* data = unzip_file(zip, "android-info.txt", &sz); void* data = unzip_file(zip, "android-info.txt", &sz);
if (data == 0) { if (data == nullptr) {
CloseArchive(zip); CloseArchive(zip);
die("update package '%s' has no android-info.txt", filename); die("update package '%s' has no android-info.txt", filename);
} }
@ -784,36 +754,33 @@ void do_update(usb_handle *usb, const char *filename, int erase_first)
CloseArchive(zip); CloseArchive(zip);
} }
void do_send_signature(char *fn) static void do_send_signature(char* fn) {
{ char* xtn = strrchr(fn, '.');
void *data;
unsigned sz;
char *xtn;
xtn = strrchr(fn, '.');
if (!xtn) return; if (!xtn) return;
if (strcmp(xtn, ".img")) return; if (strcmp(xtn, ".img")) return;
strcpy(xtn,".sig"); strcpy(xtn, ".sig");
data = load_file(fn, &sz);
strcpy(xtn,".img"); int64_t sz;
if (data == 0) return; void* data = load_file(fn, &sz);
strcpy(xtn, ".img");
if (data == nullptr) return;
fb_queue_download("signature", data, sz); fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature"); fb_queue_command("signature", "installing signature");
} }
void do_flashall(usb_handle *usb, int erase_first) static void do_flashall(usb_handle* usb, int erase_first) {
{
queue_info_dump(); queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product)); fb_queue_query_save("product", cur_product, sizeof(cur_product));
char* fname = find_item("info", product); char* fname = find_item("info", product);
if (fname == 0) die("cannot find android-info.txt"); if (fname == nullptr) die("cannot find android-info.txt");
unsigned sz; int64_t sz;
void* data = load_file(fname, &sz); void* data = load_file(fname, &sz);
if (data == 0) die("could not load android-info.txt: %s", strerror(errno)); if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
setup_requirements(reinterpret_cast<char*>(data), sz); setup_requirements(reinterpret_cast<char*>(data), sz);
@ -836,11 +803,8 @@ void do_flashall(usb_handle *usb, int erase_first)
#define skip(n) do { argc -= (n); argv += (n); } while (0) #define skip(n) do { argc -= (n); argv += (n); } while (0)
#define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0) #define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0)
int do_bypass_unlock_command(int argc, char **argv) static int do_bypass_unlock_command(int argc, char **argv)
{ {
unsigned sz;
void *data;
if (argc <= 2) return 0; if (argc <= 2) return 0;
skip(2); skip(2);
@ -849,15 +813,17 @@ int do_bypass_unlock_command(int argc, char **argv)
* and send that to the remote device. * and send that to the remote device.
*/ */
require(1); require(1);
data = load_file(*argv, &sz);
if (data == 0) die("could not load '%s': %s", *argv, strerror(errno)); int64_t sz;
void* data = load_file(*argv, &sz);
if (data == nullptr) die("could not load '%s': %s", *argv, strerror(errno));
fb_queue_download("unlock_message", data, sz); fb_queue_download("unlock_message", data, sz);
fb_queue_command("flashing unlock_bootloader", "unlocking bootloader"); fb_queue_command("flashing unlock_bootloader", "unlocking bootloader");
skip(1); skip(1);
return 0; return 0;
} }
int do_oem_command(int argc, char **argv) static int do_oem_command(int argc, char **argv)
{ {
char command[256]; char command[256];
if (argc <= 1) return 0; if (argc <= 1) return 0;
@ -915,89 +881,89 @@ static int64_t parse_num(const char *arg)
return num; return num;
} }
void fb_perform_format(usb_handle* usb, static void fb_perform_format(usb_handle* usb,
const char *partition, int skip_if_not_supported, const char* partition, int skip_if_not_supported,
const char *type_override, const char *size_override) const char* type_override, const char* size_override) {
{ std::string partition_type, partition_size;
char pTypeBuff[FB_RESPONSE_SZ + 1], pSizeBuff[FB_RESPONSE_SZ + 1];
char *pType = pTypeBuff;
char *pSize = pSizeBuff;
unsigned int limit = INT_MAX;
struct fastboot_buffer buf; struct fastboot_buffer buf;
const char *errMsg = NULL; const char* errMsg = nullptr;
const struct fs_generator *gen; const struct fs_generator* gen = nullptr;
uint64_t pSz;
int status;
int fd; int fd;
if (target_sparse_limit > 0 && target_sparse_limit < limit) unsigned int limit = INT_MAX;
if (target_sparse_limit > 0 && target_sparse_limit < limit) {
limit = target_sparse_limit; limit = target_sparse_limit;
if (sparse_limit > 0 && sparse_limit < limit) }
if (sparse_limit > 0 && sparse_limit < limit) {
limit = sparse_limit; limit = sparse_limit;
}
status = fb_getvar(usb, pType, "partition-type:%s", partition); if (!fb_getvar(usb, std::string("partition-type:") + partition, &partition_type)) {
if (status) {
errMsg = "Can't determine partition type.\n"; errMsg = "Can't determine partition type.\n";
goto failed; goto failed;
} }
if (type_override) { if (type_override) {
if (strcmp(type_override, pType)) { if (partition_type != type_override) {
fprintf(stderr, fprintf(stderr, "Warning: %s type is %s, but %s was requested for formatting.\n",
"Warning: %s type is %s, but %s was requested for formating.\n", partition, partition_type.c_str(), type_override);
partition, pType, type_override);
} }
pType = (char *)type_override; partition_type = type_override;
} }
status = fb_getvar(usb, pSize, "partition-size:%s", partition); if (!fb_getvar(usb, std::string("partition-size:") + partition, &partition_size)) {
if (status) {
errMsg = "Unable to get partition size\n"; errMsg = "Unable to get partition size\n";
goto failed; goto failed;
} }
if (size_override) { if (size_override) {
if (strcmp(size_override, pSize)) { if (partition_size != size_override) {
fprintf(stderr, fprintf(stderr, "Warning: %s size is %s, but %s was requested for formatting.\n",
"Warning: %s size is %s, but %s was requested for formating.\n", partition, partition_size.c_str(), size_override);
partition, pSize, size_override);
} }
pSize = (char *)size_override; partition_size = size_override;
} }
gen = fs_get_generator(pType); gen = fs_get_generator(partition_type);
if (!gen) { if (!gen) {
if (skip_if_not_supported) { if (skip_if_not_supported) {
fprintf(stderr, "Erase successful, but not automatically formatting.\n"); fprintf(stderr, "Erase successful, but not automatically formatting.\n");
fprintf(stderr, "File system type %s not supported.\n", pType); fprintf(stderr, "File system type %s not supported.\n", partition_type.c_str());
return; return;
} }
fprintf(stderr, "Formatting is not supported for filesystem with type '%s'.\n", pType); fprintf(stderr, "Formatting is not supported for file system with type '%s'.\n",
partition_type.c_str());
return; return;
} }
pSz = strtoll(pSize, (char **)NULL, 16); // Some bootloaders (hammerhead, for example) use implicit hex.
// This code used to use strtol with base 16.
if (!android::base::StartsWith(partition_size, "0x")) partition_size = "0x" + partition_size;
int64_t size;
if (!android::base::ParseInt(partition_size.c_str(), &size)) {
fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
return;
}
fd = fileno(tmpfile()); fd = fileno(tmpfile());
if (fs_generator_generate(gen, fd, pSz)) { if (fs_generator_generate(gen, fd, size)) {
fprintf(stderr, "Cannot generate image: %s\n", strerror(errno));
close(fd); close(fd);
fprintf(stderr, "Cannot generate image.\n");
return; return;
} }
if (load_buf_fd(usb, fd, &buf)) { if (load_buf_fd(usb, fd, &buf)) {
fprintf(stderr, "Cannot read image.\n"); fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
close(fd); close(fd);
return; return;
} }
flash_buf(partition, &buf); flash_buf(partition, &buf);
return; return;
failed: failed:
if (skip_if_not_supported) { if (skip_if_not_supported) {
fprintf(stderr, "Erase successful, but not automatically formatting.\n"); fprintf(stderr, "Erase successful, but not automatically formatting.\n");
if (errMsg) if (errMsg) fprintf(stderr, "%s", errMsg);
fprintf(stderr, "%s", errMsg);
} }
fprintf(stderr,"FAILED (%s)\n", fb_get_error()); fprintf(stderr,"FAILED (%s)\n", fb_get_error());
} }
@ -1007,11 +973,9 @@ 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 erase_first = 1; bool erase_first = true;
void *data; void *data;
unsigned sz; int64_t sz;
int status;
int c;
int longindex; int longindex;
const struct option longopts[] = { const struct option longopts[] = {
@ -1029,7 +993,7 @@ int main(int argc, char **argv)
serial = getenv("ANDROID_SERIAL"); serial = getenv("ANDROID_SERIAL");
while (1) { while (1) {
c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, &longindex); int c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, &longindex);
if (c < 0) { if (c < 0) {
break; break;
} }
@ -1045,7 +1009,7 @@ int main(int argc, char **argv)
usage(); usage();
return 1; return 1;
case 'i': { case 'i': {
char *endptr = NULL; char *endptr = nullptr;
unsigned long val; unsigned long val;
val = strtoul(optarg, &endptr, 0); val = strtoul(optarg, &endptr, 0);
@ -1061,7 +1025,7 @@ int main(int argc, char **argv)
long_listing = 1; long_listing = 1;
break; break;
case 'n': case 'n':
page_size = (unsigned)strtoul(optarg, NULL, 0); page_size = (unsigned)strtoul(optarg, nullptr, 0);
if (!page_size) die("invalid page size"); if (!page_size) die("invalid page size");
break; break;
case 'p': case 'p':
@ -1083,7 +1047,7 @@ int main(int argc, char **argv)
} }
break; break;
case 'u': case 'u':
erase_first = 0; erase_first = false;
break; break;
case 'w': case 'w':
wants_wipe = 1; wants_wipe = 1;
@ -1092,8 +1056,8 @@ int main(int argc, char **argv)
return 1; return 1;
case 0: case 0:
if (strcmp("unbuffered", longopts[longindex].name) == 0) { if (strcmp("unbuffered", longopts[longindex].name) == 0) {
setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0); setvbuf(stderr, nullptr, _IONBF, 0);
} else if (strcmp("version", longopts[longindex].name) == 0) { } else if (strcmp("version", longopts[longindex].name) == 0) {
fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION); fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION);
return 0; return 0;
@ -1126,23 +1090,26 @@ int main(int argc, char **argv)
usb_handle* usb = open_device(); usb_handle* usb = open_device();
while (argc > 0) { while (argc > 0) {
if(!strcmp(*argv, "getvar")) { 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);
} else if(!strcmp(*argv, "erase")) { } else if(!strcmp(*argv, "erase")) {
require(2); require(2);
if (fb_format_supported(usb, argv[1], NULL)) { std::string partition_type;
fprintf(stderr, "******** Did you mean to fastboot format this partition?\n"); if (fb_getvar(usb, std::string("partition-type:") + argv[1], &partition_type) &&
fs_get_generator(partition_type) != nullptr) {
fprintf(stderr, "******** Did you mean to fastboot format this %s partition?\n",
partition_type.c_str());
} }
fb_queue_erase(argv[1]); fb_queue_erase(argv[1]);
skip(2); skip(2);
} else if(!strncmp(*argv, "format", strlen("format"))) { } else if(!strncmp(*argv, "format", strlen("format"))) {
char *overrides; char *overrides;
char *type_override = NULL; char *type_override = nullptr;
char *size_override = NULL; char *size_override = nullptr;
require(2); require(2);
/* /*
* Parsing for: "format[:[type][:[size]]]" * Parsing for: "format[:[type][:[size]]]"
@ -1163,8 +1130,8 @@ int main(int argc, char **argv)
} }
type_override = overrides; type_override = overrides;
} }
if (type_override && !type_override[0]) type_override = NULL; if (type_override && !type_override[0]) type_override = nullptr;
if (size_override && !size_override[0]) size_override = NULL; if (size_override && !size_override[0]) size_override = nullptr;
if (erase_first && needs_erase(usb, argv[1])) { if (erase_first && needs_erase(usb, argv[1])) {
fb_queue_erase(argv[1]); fb_queue_erase(argv[1]);
} }
@ -1173,7 +1140,7 @@ int main(int argc, char **argv)
} else if(!strcmp(*argv, "signature")) { } else if(!strcmp(*argv, "signature")) {
require(2); require(2);
data = load_file(argv[1], &sz); data = load_file(argv[1], &sz);
if (data == 0) die("could not load '%s': %s", argv[1], strerror(errno)); if (data == nullptr) die("could not load '%s': %s", argv[1], strerror(errno));
if (sz != 256) die("signature must be 256 bytes"); if (sz != 256) die("signature must be 256 bytes");
fb_queue_download("signature", data, sz); fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature"); fb_queue_command("signature", "installing signature");
@ -1198,6 +1165,7 @@ int main(int argc, char **argv)
} else if(!strcmp(*argv, "boot")) { } else if(!strcmp(*argv, "boot")) {
char *kname = 0; char *kname = 0;
char *rname = 0; char *rname = 0;
char *sname = 0;
skip(1); skip(1);
if (argc > 0) { if (argc > 0) {
kname = argv[0]; kname = argv[0];
@ -1207,7 +1175,11 @@ int main(int argc, char **argv)
rname = argv[0]; rname = argv[0];
skip(1); skip(1);
} }
data = load_bootable_image(kname, rname, &sz, cmdline); if (argc > 0) {
sname = argv[0];
skip(1);
}
data = load_bootable_image(kname, rname, sname, &sz, cmdline);
if (data == 0) return 1; if (data == 0) return 1;
fb_queue_download("boot.img", data, sz); fb_queue_download("boot.img", data, sz);
fb_queue_command("boot", "booting"); fb_queue_command("boot", "booting");
@ -1231,14 +1203,18 @@ int main(int argc, char **argv)
char *pname = argv[1]; char *pname = argv[1];
char *kname = argv[2]; char *kname = argv[2];
char *rname = 0; char *rname = 0;
char *sname = 0;
require(3); require(3);
if(argc > 3) { skip(3);
rname = argv[3]; if (argc > 0) {
skip(4); rname = argv[0];
} else { skip(1);
skip(3);
} }
data = load_bootable_image(kname, rname, &sz, cmdline); if (argc > 0) {
sname = argv[0];
skip(1);
}
data = load_bootable_image(kname, rname, sname, &sz, cmdline);
if (data == 0) die("cannot load bootable image"); if (data == 0) die("cannot load bootable image");
fb_queue_flash(pname, data, sz); fb_queue_flash(pname, data, sz);
} else if(!strcmp(*argv, "flashall")) { } else if(!strcmp(*argv, "flashall")) {
@ -1279,10 +1255,16 @@ int main(int argc, char **argv)
} }
if (wants_wipe) { if (wants_wipe) {
fprintf(stderr, "wiping userdata...\n");
fb_queue_erase("userdata"); fb_queue_erase("userdata");
fb_perform_format(usb, "userdata", 1, NULL, NULL); fb_perform_format(usb, "userdata", 1, nullptr, nullptr);
fb_queue_erase("cache");
fb_perform_format(usb, "cache", 1, NULL, NULL); std::string cache_type;
if (fb_getvar(usb, "partition-type:cache", &cache_type) && !cache_type.empty()) {
fprintf(stderr, "wiping cache...\n");
fb_queue_erase("cache");
fb_perform_format(usb, "cache", 1, nullptr, nullptr);
}
} }
if (wants_reboot) { if (wants_reboot) {
fb_queue_reboot(); fb_queue_reboot();
@ -1292,9 +1274,5 @@ int main(int argc, char **argv)
fb_queue_wait_for_disconnect(); fb_queue_wait_for_disconnect();
} }
if (fb_queue_is_empty()) return fb_execute_queue(usb) ? EXIT_FAILURE : EXIT_SUCCESS;
return 0;
status = fb_execute_queue(usb);
return (status) ? 1 : 0;
} }

View file

@ -29,18 +29,19 @@
#ifndef _FASTBOOT_H_ #ifndef _FASTBOOT_H_
#define _FASTBOOT_H_ #define _FASTBOOT_H_
#include "usb.h" #include <inttypes.h>
#include <stdlib.h>
#if defined(__cplusplus) #include <string>
extern "C" {
#endif #include "usb.h"
struct sparse_file; 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, uint32_t size);
int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s); int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s);
char *fb_get_error(void); char *fb_get_error(void);
@ -48,23 +49,21 @@ char *fb_get_error(void);
#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, ...); bool fb_getvar(usb_handle* usb, const std::string& key, std::string* value);
int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override); void fb_queue_flash(const char *ptn, void *data, uint32_t sz);
void fb_queue_flash(const char *ptn, void *data, unsigned sz); void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, uint32_t 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, unsigned int max_chunk_sz); void fb_queue_format(const char *ptn, int skip_if_not_supported, int32_t max_chunk_sz);
void fb_queue_require(const char *prod, const char *var, int invert, void fb_queue_require(const char *prod, const char *var, bool invert,
unsigned nvalues, const char **value); size_t nvalues, const char **value);
void fb_queue_display(const char *var, const char *prettyname); void fb_queue_display(const char *var, const char *prettyname);
void fb_queue_query_save(const char *var, char *dest, unsigned dest_size); void fb_queue_query_save(const char *var, char *dest, uint32_t dest_size);
void fb_queue_reboot(void); void fb_queue_reboot(void);
void fb_queue_command(const char *cmd, const char *msg); void fb_queue_command(const char *cmd, const char *msg);
void fb_queue_download(const char *name, void *data, unsigned size); void fb_queue_download(const char *name, void *data, uint32_t size);
void fb_queue_notice(const char *notice); void fb_queue_notice(const char *notice);
void fb_queue_wait_for_disconnect(void); void fb_queue_wait_for_disconnect(void);
int fb_execute_queue(usb_handle *usb); int fb_execute_queue(usb_handle *usb);
int fb_queue_is_empty(void);
/* util stuff */ /* util stuff */
double now(); double now();
@ -76,8 +75,4 @@ void get_my_path(char *path);
/* Current product */ /* Current product */
extern char cur_product[FB_RESPONSE_SZ + 1]; extern char cur_product[FB_RESPONSE_SZ + 1];
#if defined(__cplusplus)
}
#endif
#endif #endif

View file

@ -41,7 +41,7 @@ Transport and Framing
d. DATA -> the requested command is ready for the data phase. d. DATA -> the requested command is ready for the data phase.
A DATA response packet will be 12 bytes long, in the form of A DATA response packet will be 12 bytes long, in the form of
DATA00000000 where the 8 digit hexidecimal number represents DATA00000000 where the 8 digit hexadecimal number represents
the total data size to transfer. the total data size to transfer.
3. Data phase. Depending on the command, the host or client will 3. Data phase. Depending on the command, the host or client will

View file

@ -6,21 +6,12 @@
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sparse/sparse.h>
#include <unistd.h> #include <unistd.h>
#ifdef USE_MINGW #include <sparse/sparse.h>
#include <fcntl.h>
#else
#include <sys/mman.h>
#endif
static int generate_ext4_image(int fd, long long partSize) static int generate_ext4_image(int fd, long long partSize)
{ {
@ -38,7 +29,7 @@ static int generate_f2fs_image(int fd, long long partSize)
static const struct fs_generator { static const struct fs_generator {
char *fs_type; //must match what fastboot reports for partition type const char* fs_type; //must match what fastboot reports for partition type
int (*generate)(int fd, long long partSize); //returns 0 or error value int (*generate)(int fd, long long partSize); //returns 0 or error value
} generators[] = { } generators[] = {
@ -48,15 +39,13 @@ static const struct fs_generator {
#endif #endif
}; };
const struct fs_generator* fs_get_generator(const char *fs_type) const struct fs_generator* fs_get_generator(const std::string& fs_type) {
{ for (size_t i = 0; i < sizeof(generators) / sizeof(*generators); i++) {
unsigned i; if (fs_type == generators[i].fs_type) {
for (i = 0; i < sizeof(generators) / sizeof(*generators); i++)
if (!strcmp(generators[i].fs_type, fs_type))
return generators + i; return generators + i;
}
return NULL; }
return nullptr;
} }
int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize) int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)

View file

@ -3,18 +3,9 @@
#include <stdint.h> #include <stdint.h>
#if defined(__cplusplus)
extern "C" {
#endif
struct fs_generator; struct fs_generator;
const struct fs_generator* fs_get_generator(const char *fs_type); const struct fs_generator* fs_get_generator(const std::string& fs_type);
int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize); int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
#if defined(__cplusplus)
}
#endif #endif
#endif

View file

@ -1,9 +0,0 @@
#!/bin/bash
if [ $# -ne 2 ]
then
echo "Usage: $0 alias passphrase"
exit -1
fi
openssl pkcs12 -passin pass:"$2" -passout pass:"$2" -in $1.p12 -out $1.pem

View file

@ -26,8 +26,6 @@
* 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) \ #define round_down(a, b) \
({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); }) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
@ -36,6 +34,8 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <algorithm>
#include <sparse/sparse.h> #include <sparse/sparse.h>
#include "fastboot.h" #include "fastboot.h"
@ -47,40 +47,38 @@ char *fb_get_error(void)
return ERROR; return ERROR;
} }
static int check_response(usb_handle *usb, unsigned int size, char *response) static int check_response(usb_handle* usb, uint32_t size, char* response) {
{ char status[65];
unsigned char status[65];
int r;
for(;;) { while (true) {
r = usb_read(usb, status, 64); int r = usb_read(usb, status, 64);
if(r < 0) { if (r < 0) {
sprintf(ERROR, "status read failed (%s)", strerror(errno)); sprintf(ERROR, "status read failed (%s)", strerror(errno));
usb_close(usb); usb_close(usb);
return -1; return -1;
} }
status[r] = 0; status[r] = 0;
if(r < 4) { if (r < 4) {
sprintf(ERROR, "status malformed (%d bytes)", r); sprintf(ERROR, "status malformed (%d bytes)", r);
usb_close(usb); usb_close(usb);
return -1; return -1;
} }
if(!memcmp(status, "INFO", 4)) { if (!memcmp(status, "INFO", 4)) {
fprintf(stderr,"(bootloader) %s\n", status + 4); fprintf(stderr,"(bootloader) %s\n", status + 4);
continue; continue;
} }
if(!memcmp(status, "OKAY", 4)) { if (!memcmp(status, "OKAY", 4)) {
if(response) { if (response) {
strcpy(response, (char*) status + 4); strcpy(response, (char*) status + 4);
} }
return 0; return 0;
} }
if(!memcmp(status, "FAIL", 4)) { if (!memcmp(status, "FAIL", 4)) {
if(r > 4) { if (r > 4) {
sprintf(ERROR, "remote: %s", status + 4); sprintf(ERROR, "remote: %s", status + 4);
} else { } else {
strcpy(ERROR, "remote failure"); strcpy(ERROR, "remote failure");
@ -88,9 +86,9 @@ static int check_response(usb_handle *usb, unsigned int size, char *response)
return -1; return -1;
} }
if(!memcmp(status, "DATA", 4) && size > 0){ if (!memcmp(status, "DATA", 4) && size > 0){
unsigned dsize = strtoul((char*) status + 4, 0, 16); uint32_t dsize = strtol(status + 4, 0, 16);
if(dsize > size) { if (dsize > size) {
strcpy(ERROR, "data size too large"); strcpy(ERROR, "data size too large");
usb_close(usb); usb_close(usb);
return -1; return -1;
@ -106,22 +104,19 @@ static int check_response(usb_handle *usb, unsigned int size, char *response)
return -1; return -1;
} }
static int _command_start(usb_handle *usb, const char *cmd, unsigned size, static int _command_start(usb_handle* usb, const char* cmd, uint32_t size, char* response) {
char *response) size_t cmdsize = strlen(cmd);
{ if (cmdsize > 64) {
int cmdsize = strlen(cmd); sprintf(ERROR, "command too large");
if(response) {
response[0] = 0;
}
if(cmdsize > 64) {
sprintf(ERROR,"command too large");
return -1; return -1;
} }
if(usb_write(usb, cmd, cmdsize) != cmdsize) { if (response) {
sprintf(ERROR,"command write failed (%s)", strerror(errno)); response[0] = 0;
}
if (usb_write(usb, cmd, cmdsize) != static_cast<int>(cmdsize)) {
sprintf(ERROR, "command write failed (%s)", strerror(errno));
usb_close(usb); usb_close(usb);
return -1; return -1;
} }
@ -129,45 +124,32 @@ static int _command_start(usb_handle *usb, const char *cmd, unsigned size,
return check_response(usb, size, response); return check_response(usb, size, response);
} }
static int _command_data(usb_handle *usb, const void *data, unsigned size) static int _command_data(usb_handle* usb, const void* data, uint32_t size) {
{ int r = usb_write(usb, data, size);
int r; if (r < 0) {
r = usb_write(usb, data, size);
if(r < 0) {
sprintf(ERROR, "data transfer failure (%s)", strerror(errno)); sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
usb_close(usb); usb_close(usb);
return -1; return -1;
} }
if(r != ((int) size)) { if (r != ((int) size)) {
sprintf(ERROR, "data transfer failure (short transfer)"); sprintf(ERROR, "data transfer failure (short transfer)");
usb_close(usb); usb_close(usb);
return -1; return -1;
} }
return r; return r;
} }
static int _command_end(usb_handle *usb) static int _command_end(usb_handle* usb) {
{ return check_response(usb, 0, 0) < 0 ? -1 : 0;
int r;
r = check_response(usb, 0, 0);
if(r < 0) {
return -1;
}
return 0;
} }
static int _command_send(usb_handle *usb, const char *cmd, static int _command_send(usb_handle* usb, const char* cmd, const void* data, uint32_t size,
const void *data, unsigned size, char* response) {
char *response)
{
int r;
if (size == 0) { if (size == 0) {
return -1; return -1;
} }
r = _command_start(usb, cmd, size, response); int r = _command_start(usb, cmd, size, response);
if (r < 0) { if (r < 0) {
return -1; return -1;
} }
@ -178,42 +160,29 @@ static int _command_send(usb_handle *usb, const char *cmd,
} }
r = _command_end(usb); r = _command_end(usb);
if(r < 0) { if (r < 0) {
return -1; return -1;
} }
return size; return size;
} }
static int _command_send_no_data(usb_handle *usb, const char *cmd, static int _command_send_no_data(usb_handle* usb, const char* cmd, char* response) {
char *response)
{
return _command_start(usb, cmd, 0, response); 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_no_data(usb, cmd, 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_no_data(usb, cmd, 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, uint32_t size) {
{
char cmd[64]; char cmd[64];
int r;
sprintf(cmd, "download:%08x", size); sprintf(cmd, "download:%08x", size);
r = _command_send(usb, cmd, data, size, 0); return _command_send(usb, cmd, data, size, 0) < 0 ? -1 : 0;
if(r < 0) {
return -1;
} else {
return 0;
}
} }
#define USB_BUF_SIZE 1024 #define USB_BUF_SIZE 1024
@ -223,12 +192,12 @@ static int usb_buf_len;
static int fb_download_data_sparse_write(void *priv, const void *data, int len) static int fb_download_data_sparse_write(void *priv, const void *data, int len)
{ {
int r; int r;
usb_handle *usb = priv; usb_handle* usb = reinterpret_cast<usb_handle*>(priv);
int to_write; int to_write;
const char *ptr = data; const char* ptr = reinterpret_cast<const char*>(data);
if (usb_buf_len) { if (usb_buf_len) {
to_write = min(USB_BUF_SIZE - usb_buf_len, len); to_write = std::min(USB_BUF_SIZE - usb_buf_len, len);
memcpy(usb_buf + usb_buf_len, ptr, to_write); memcpy(usb_buf + usb_buf_len, ptr, to_write);
usb_buf_len += to_write; usb_buf_len += to_write;
@ -270,32 +239,25 @@ static int fb_download_data_sparse_write(void *priv, const void *data, int len)
return 0; return 0;
} }
static int fb_download_data_sparse_flush(usb_handle *usb) static int fb_download_data_sparse_flush(usb_handle* usb) {
{
int r;
if (usb_buf_len > 0) { if (usb_buf_len > 0) {
r = _command_data(usb, usb_buf, usb_buf_len); if (_command_data(usb, usb_buf, usb_buf_len) != usb_buf_len) {
if (r != usb_buf_len) {
return -1; return -1;
} }
usb_buf_len = 0; usb_buf_len = 0;
} }
return 0; return 0;
} }
int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s) 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); int size = sparse_file_len(s, true, false);
if (size <= 0) { if (size <= 0) {
return -1; return -1;
} }
char cmd[64];
sprintf(cmd, "download:%08x", size); sprintf(cmd, "download:%08x", size);
r = _command_start(usb, cmd, size, 0); int r = _command_start(usb, cmd, size, 0);
if (r < 0) { if (r < 0) {
return -1; return -1;
} }

View file

@ -1,10 +0,0 @@
#!/bin/bash
if [ $# -ne 3 ]
then
echo "Usage: $0 alias filename passpharse"
exit -1
fi
openssl dgst -passin pass:"$3" -binary -sha1 -sign $1.pem $2 > $2.sign

View file

@ -29,16 +29,9 @@
#ifndef _USB_H_ #ifndef _USB_H_
#define _USB_H_ #define _USB_H_
#if defined(__cplusplus) struct usb_handle;
extern "C" {
#endif
typedef struct usb_handle usb_handle; struct usb_ifc_info {
typedef struct usb_ifc_info usb_ifc_info;
struct usb_ifc_info
{
/* from device descriptor */ /* from device descriptor */
unsigned short dev_vendor; unsigned short dev_vendor;
unsigned short dev_product; unsigned short dev_product;
@ -68,8 +61,4 @@ int usb_read(usb_handle *h, void *_data, int len);
int usb_write(usb_handle *h, const void *_data, int len); int usb_write(usb_handle *h, const void *_data, int len);
int usb_wait_for_disconnect(usb_handle *h); int usb_wait_for_disconnect(usb_handle *h);
#if defined(__cplusplus)
}
#endif
#endif #endif

View file

@ -26,29 +26,22 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <dirent.h> #include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <ctype.h>
#include <linux/usbdevice_fs.h>
#include <linux/usbdevice_fs.h> #include <linux/usbdevice_fs.h>
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#else
#include <linux/usb_ch9.h>
#endif
#include <asm/byteorder.h>
#include "fastboot.h" #include "fastboot.h"
#include "usb.h" #include "usb.h"
@ -69,9 +62,19 @@
#define DBG1(x...) #define DBG1(x...)
#endif #endif
/* The max bulk size for linux is 16384 which is defined // Kernels before 3.3 have a 16KiB transfer limit. That limit was replaced
* in drivers/usb/core/devio.c. // with a 16MiB global limit in 3.3, but each URB submitted required a
*/ // contiguous kernel allocation, so you would get ENOMEM if you tried to
// send something larger than the biggest available contiguous kernel
// memory region. 256KiB contiguous allocations are generally not reliable
// on a device kernel that has been running for a while fragmenting its
// memory, but that shouldn't be a problem for fastboot on the host.
// In 3.6, the contiguous buffer limit was removed by allocating multiple
// 16KiB chunks and having the USB driver stitch them back together while
// transmitting using a scatter-gather list, so 256KiB bulk transfers should
// be reliable.
// 256KiB seems to work, but 1MiB bulk transfers lock up my z620 with a 3.13
// kernel.
#define MAX_USBFS_BULK_SIZE (16 * 1024) #define MAX_USBFS_BULK_SIZE (16 * 1024)
struct usb_handle struct usb_handle
@ -340,7 +343,7 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
if(filter_usb_device(de->d_name, desc, n, writable, callback, if(filter_usb_device(de->d_name, desc, n, writable, callback,
&in, &out, &ifc) == 0) { &in, &out, &ifc) == 0) {
usb = calloc(1, sizeof(usb_handle)); usb = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
strcpy(usb->fname, devname); strcpy(usb->fname, devname);
usb->ep_in = in; usb->ep_in = in;
usb->ep_out = out; usb->ep_out = out;

View file

@ -26,6 +26,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include <inttypes.h>
#include <stdio.h> #include <stdio.h>
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h> #include <IOKit/IOKitLib.h>
@ -74,7 +75,6 @@ static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
HRESULT result; HRESULT result;
SInt32 score; SInt32 score;
UInt8 interfaceNumEndpoints; UInt8 interfaceNumEndpoints;
UInt8 endpoint;
UInt8 configuration; UInt8 configuration;
// Placing the constant KIOUSBFindInterfaceDontCare into the following // Placing the constant KIOUSBFindInterfaceDontCare into the following
@ -121,7 +121,7 @@ static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
result = (*plugInInterface)->QueryInterface( result = (*plugInInterface)->QueryInterface(
plugInInterface, plugInInterface,
CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
(LPVOID) &interface); (LPVOID*) &interface);
// No longer need the intermediate plugin // No longer need the intermediate plugin
(*plugInInterface)->Release(plugInInterface); (*plugInInterface)->Release(plugInInterface);
@ -181,7 +181,7 @@ static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
// Iterate over the endpoints for this interface and see if there // Iterate over the endpoints for this interface and see if there
// are any that do bulk in/out. // are any that do bulk in/out.
for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) { for (UInt8 endpoint = 1; endpoint <= interfaceNumEndpoints; endpoint++) {
UInt8 transferType; UInt8 transferType;
UInt16 maxPacketSize; UInt16 maxPacketSize;
UInt8 interval; UInt8 interval;
@ -209,7 +209,7 @@ static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
handle->zero_mask = maxPacketSize - 1; handle->zero_mask = maxPacketSize - 1;
} }
} else { } else {
ERR("could not get pipe properties\n"); ERR("could not get pipe properties for endpoint %u (%08x)\n", endpoint, kr);
} }
if (handle->info.has_bulk_in && handle->info.has_bulk_out) { if (handle->info.has_bulk_in && handle->info.has_bulk_out) {
@ -279,7 +279,7 @@ static int try_device(io_service_t device, usb_handle *handle) {
// Now create the device interface. // Now create the device interface.
result = (*plugin)->QueryInterface(plugin, result = (*plugin)->QueryInterface(plugin,
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev); CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &dev);
if ((result != 0) || (dev == NULL)) { if ((result != 0) || (dev == NULL)) {
ERR("Couldn't create a device interface (%08x)\n", (int) result); ERR("Couldn't create a device interface (%08x)\n", (int) result);
goto error; goto error;
@ -293,6 +293,13 @@ static int try_device(io_service_t device, usb_handle *handle) {
// So, we have a device, finally. Grab its vitals. // So, we have a device, finally. Grab its vitals.
kr = (*dev)->USBDeviceOpen(dev);
if (kr != 0) {
WARN("USBDeviceOpen");
goto out;
}
kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor); kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
if (kr != 0) { if (kr != 0) {
ERR("GetDeviceVendor"); ERR("GetDeviceVendor");
@ -365,12 +372,16 @@ static int try_device(io_service_t device, usb_handle *handle) {
goto error; goto error;
} }
out:
(*dev)->USBDeviceClose(dev);
(*dev)->Release(dev); (*dev)->Release(dev);
return 0; return 0;
error: error:
if (dev != NULL) { if (dev != NULL) {
(*dev)->USBDeviceClose(dev);
(*dev)->Release(dev); (*dev)->Release(dev);
} }
@ -432,7 +443,7 @@ static int init_usb(ifc_match_func callback, usb_handle **handle) {
} }
if (h.success) { if (h.success) {
*handle = calloc(1, sizeof(usb_handle)); *handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
memcpy(*handle, &h, sizeof(usb_handle)); memcpy(*handle, &h, sizeof(usb_handle));
ret = 0; ret = 0;
break; break;

View file

@ -26,6 +26,8 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include "fastboot.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View file

@ -26,6 +26,8 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include "fastboot.h"
#import <Carbon/Carbon.h> #import <Carbon/Carbon.h>
#include <unistd.h> #include <unistd.h>

View file

@ -26,6 +26,8 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include "fastboot.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>