fastboot: add support for sparse images in flashall and update
Change-Id: I66a73b16a988a65fc91fb22a26d11986025089de Signed-off-by: Rom Lemarchand <romlem@google.com>
This commit is contained in:
parent
c9cce4b981
commit
622810ceff
1 changed files with 172 additions and 96 deletions
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <bootimg.h>
|
||||
#include <sparse/sparse.h>
|
||||
|
|
@ -54,6 +55,8 @@
|
|||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
|
||||
|
||||
char cur_product[FB_RESPONSE_SZ + 1];
|
||||
|
||||
void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
|
||||
|
|
@ -81,6 +84,27 @@ unsigned ramdisk_offset = 0x01000000;
|
|||
unsigned second_offset = 0x00f00000;
|
||||
unsigned tags_offset = 0x00000100;
|
||||
|
||||
enum fb_buffer_type {
|
||||
FB_BUFFER,
|
||||
FB_BUFFER_SPARSE,
|
||||
};
|
||||
|
||||
struct fastboot_buffer {
|
||||
enum fb_buffer_type type;
|
||||
void *data;
|
||||
unsigned int sz;
|
||||
};
|
||||
|
||||
static struct {
|
||||
char img_name[13];
|
||||
char sig_name[13];
|
||||
char part_name[9];
|
||||
bool is_optional;
|
||||
} images[3] = {
|
||||
{"boot.img", "boot.sig", "boot", false},
|
||||
{"recovery.img", "recovery.sig", "recovery", true},
|
||||
{"system.img", "system.sig", "system", false},
|
||||
};
|
||||
|
||||
void die(const char *fmt, ...)
|
||||
{
|
||||
|
|
@ -135,40 +159,28 @@ char *find_item(const char *item, const char *product)
|
|||
return strdup(path);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define lseek64 lseek
|
||||
#define off64_t off_t
|
||||
#endif
|
||||
|
||||
static int64_t file_size(const char *fn)
|
||||
static int64_t file_size(int fd)
|
||||
{
|
||||
off64_t off;
|
||||
int fd;
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
fd = open(fn, O_RDONLY | O_BINARY);
|
||||
if (fd < 0) return -1;
|
||||
ret = fstat(fd, &st);
|
||||
|
||||
off = lseek64(fd, 0, SEEK_END);
|
||||
close(fd);
|
||||
|
||||
return off;
|
||||
return ret ? -1 : st.st_size;
|
||||
}
|
||||
|
||||
static void *load_file(const char *fn, unsigned *_sz)
|
||||
static void *load_fd(int fd, unsigned *_sz)
|
||||
{
|
||||
char *data;
|
||||
int sz;
|
||||
int fd;
|
||||
int errno_tmp;
|
||||
|
||||
data = 0;
|
||||
fd = open(fn, O_RDONLY | O_BINARY);
|
||||
if(fd < 0) return 0;
|
||||
|
||||
sz = lseek(fd, 0, SEEK_END);
|
||||
if(sz < 0) goto oops;
|
||||
|
||||
if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
|
||||
sz = file_size(fd);
|
||||
if (sz < 0) {
|
||||
goto oops;
|
||||
}
|
||||
|
||||
data = (char*) malloc(sz);
|
||||
if(data == 0) goto oops;
|
||||
|
|
@ -187,6 +199,16 @@ oops:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void *load_file(const char *fn, unsigned *_sz)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(fn, O_RDONLY | O_BINARY);
|
||||
if(fd < 0) return 0;
|
||||
|
||||
return load_fd(fd, _sz);
|
||||
}
|
||||
|
||||
int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial)
|
||||
{
|
||||
if(!(vendor_id && (info->dev_vendor == vendor_id)) &&
|
||||
|
|
@ -392,6 +414,31 @@ void *unzip_file(zipfile_t zip, const char *name, unsigned *sz)
|
|||
return data;
|
||||
}
|
||||
|
||||
static int unzip_to_file(zipfile_t zip, char *name)
|
||||
{
|
||||
int fd;
|
||||
char *data;
|
||||
unsigned sz;
|
||||
|
||||
fd = fileno(tmpfile());
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = unzip_file(zip, name, &sz);
|
||||
if (data == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write(fd, data, sz) != sz) {
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
free(data);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static char *strip(char *s)
|
||||
{
|
||||
int n;
|
||||
|
|
@ -490,27 +537,20 @@ void queue_info_dump(void)
|
|||
fb_queue_notice("--------------------------------------------");
|
||||
}
|
||||
|
||||
|
||||
struct sparse_file **load_sparse_files(const char *fname, int max_size)
|
||||
static struct sparse_file **load_sparse_files(int fd, int max_size)
|
||||
{
|
||||
int fd;
|
||||
struct sparse_file *s;
|
||||
int files;
|
||||
struct sparse_file **out_s;
|
||||
|
||||
fd = open(fname, O_RDONLY | O_BINARY);
|
||||
if (fd < 0) {
|
||||
die("cannot open '%s'\n", fname);
|
||||
}
|
||||
|
||||
s = sparse_file_import_auto(fd, false);
|
||||
if (!s) {
|
||||
die("cannot sparse read file '%s'\n", fname);
|
||||
die("cannot sparse read file\n");
|
||||
}
|
||||
|
||||
files = sparse_file_resparse(s, max_size, NULL, 0);
|
||||
if (files < 0) {
|
||||
die("Failed to resparse '%s'\n", fname);
|
||||
die("Failed to resparse\n");
|
||||
}
|
||||
|
||||
out_s = calloc(sizeof(struct sparse_file *), files + 1);
|
||||
|
|
@ -520,7 +560,7 @@ struct sparse_file **load_sparse_files(const char *fname, int max_size)
|
|||
|
||||
files = sparse_file_resparse(s, max_size, out_s, files);
|
||||
if (files < 0) {
|
||||
die("Failed to resparse '%s'\n", fname);
|
||||
die("Failed to resparse\n");
|
||||
}
|
||||
|
||||
return out_s;
|
||||
|
|
@ -581,29 +621,78 @@ static int needs_erase(const char *part)
|
|||
return fb_format_supported(usb, part);
|
||||
}
|
||||
|
||||
void do_flash(usb_handle *usb, const char *pname, const char *fname)
|
||||
static int load_buf_fd(usb_handle *usb, int fd,
|
||||
struct fastboot_buffer *buf)
|
||||
{
|
||||
int64_t sz64;
|
||||
void *data;
|
||||
int64_t limit;
|
||||
|
||||
sz64 = file_size(fname);
|
||||
sz64 = file_size(fd);
|
||||
if (sz64 < 0) {
|
||||
return -1;
|
||||
}
|
||||
limit = get_sparse_limit(usb, sz64);
|
||||
if (limit) {
|
||||
struct sparse_file **s = load_sparse_files(fname, limit);
|
||||
struct sparse_file **s = load_sparse_files(fd, limit);
|
||||
if (s == NULL) {
|
||||
die("cannot sparse load '%s'\n", fname);
|
||||
}
|
||||
while (*s) {
|
||||
sz64 = sparse_file_len(*s, true, false);
|
||||
fb_queue_flash_sparse(pname, *s++, sz64);
|
||||
return -1;
|
||||
}
|
||||
buf->type = FB_BUFFER_SPARSE;
|
||||
buf->data = s;
|
||||
} else {
|
||||
unsigned int sz;
|
||||
data = load_file(fname, &sz);
|
||||
if (data == 0) die("cannot load '%s': %s\n", fname, strerror(errno));
|
||||
fb_queue_flash(pname, data, sz);
|
||||
data = load_fd(fd, &sz);
|
||||
if (data == 0) return -1;
|
||||
buf->type = FB_BUFFER;
|
||||
buf->data = data;
|
||||
buf->sz = sz;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_buf(usb_handle *usb, const char *fname,
|
||||
struct fastboot_buffer *buf)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(fname, O_RDONLY | O_BINARY);
|
||||
if (fd < 0) {
|
||||
die("cannot open '%s'\n", fname);
|
||||
}
|
||||
|
||||
return load_buf_fd(usb, fd, buf);
|
||||
}
|
||||
|
||||
static void flash_buf(const char *pname, struct fastboot_buffer *buf)
|
||||
{
|
||||
struct sparse_file **s;
|
||||
|
||||
switch (buf->type) {
|
||||
case FB_BUFFER_SPARSE:
|
||||
s = buf->data;
|
||||
while (*s) {
|
||||
int64_t sz64 = sparse_file_len(*s, true, false);
|
||||
fb_queue_flash_sparse(pname, *s++, sz64);
|
||||
}
|
||||
break;
|
||||
case FB_BUFFER:
|
||||
fb_queue_flash(pname, buf->data, buf->sz);
|
||||
break;
|
||||
default:
|
||||
die("unknown buffer type: %d", buf->type);
|
||||
}
|
||||
}
|
||||
|
||||
void do_flash(usb_handle *usb, const char *pname, const char *fname)
|
||||
{
|
||||
struct fastboot_buffer buf;
|
||||
|
||||
if (load_buf(usb, fname, &buf)) {
|
||||
die("cannot load '%s'", fname);
|
||||
}
|
||||
flash_buf(pname, &buf);
|
||||
}
|
||||
|
||||
void do_update_signature(zipfile_t zip, char *fn)
|
||||
|
|
@ -616,13 +705,17 @@ void do_update_signature(zipfile_t zip, char *fn)
|
|||
fb_queue_command("signature", "installing signature");
|
||||
}
|
||||
|
||||
void do_update(char *fn, int erase_first)
|
||||
void do_update(usb_handle *usb, char *fn, int erase_first)
|
||||
{
|
||||
void *zdata;
|
||||
unsigned zsize;
|
||||
void *data;
|
||||
unsigned sz;
|
||||
zipfile_t zip;
|
||||
int fd;
|
||||
int rc;
|
||||
struct fastboot_buffer buf;
|
||||
int i;
|
||||
|
||||
queue_info_dump();
|
||||
|
||||
|
|
@ -651,30 +744,25 @@ void do_update(char *fn, int erase_first)
|
|||
|
||||
setup_requirements(data, sz);
|
||||
|
||||
data = unzip_file(zip, "boot.img", &sz);
|
||||
if (data == 0) die("update package missing boot.img");
|
||||
do_update_signature(zip, "boot.sig");
|
||||
if (erase_first && needs_erase("boot")) {
|
||||
fb_queue_erase("boot");
|
||||
}
|
||||
fb_queue_flash("boot", data, sz);
|
||||
|
||||
data = unzip_file(zip, "recovery.img", &sz);
|
||||
if (data != 0) {
|
||||
do_update_signature(zip, "recovery.sig");
|
||||
if (erase_first && needs_erase("recovery")) {
|
||||
fb_queue_erase("recovery");
|
||||
for (i = 0; i < ARRAY_SIZE(images); i++) {
|
||||
fd = unzip_to_file(zip, images[i].img_name);
|
||||
if (fd < 0) {
|
||||
if (images[i].is_optional)
|
||||
continue;
|
||||
die("update package missing %s", images[i].img_name);
|
||||
}
|
||||
fb_queue_flash("recovery", data, sz);
|
||||
rc = load_buf_fd(usb, fd, &buf);
|
||||
if (rc) die("cannot load %s from flash", images[i].img_name);
|
||||
do_update_signature(zip, images[i].sig_name);
|
||||
if (erase_first && needs_erase(images[i].part_name)) {
|
||||
fb_queue_erase(images[i].part_name);
|
||||
}
|
||||
flash_buf(images[i].part_name, &buf);
|
||||
/* not closing the fd here since the sparse code keeps the fd around
|
||||
* but hasn't mmaped data yet. The tmpfile will get cleaned up when the
|
||||
* program exits.
|
||||
*/
|
||||
}
|
||||
|
||||
data = unzip_file(zip, "system.img", &sz);
|
||||
if (data == 0) die("update package missing system.img");
|
||||
do_update_signature(zip, "system.sig");
|
||||
if (erase_first && needs_erase("system")) {
|
||||
fb_queue_erase("system");
|
||||
}
|
||||
fb_queue_flash("system", data, sz);
|
||||
}
|
||||
|
||||
void do_send_signature(char *fn)
|
||||
|
|
@ -695,11 +783,13 @@ void do_send_signature(char *fn)
|
|||
fb_queue_command("signature", "installing signature");
|
||||
}
|
||||
|
||||
void do_flashall(int erase_first)
|
||||
void do_flashall(usb_handle *usb, int erase_first)
|
||||
{
|
||||
char *fname;
|
||||
void *data;
|
||||
unsigned sz;
|
||||
struct fastboot_buffer buf;
|
||||
int i;
|
||||
|
||||
queue_info_dump();
|
||||
|
||||
|
|
@ -711,33 +801,19 @@ void do_flashall(int erase_first)
|
|||
if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
|
||||
setup_requirements(data, sz);
|
||||
|
||||
fname = find_item("boot", product);
|
||||
data = load_file(fname, &sz);
|
||||
if (data == 0) die("could not load boot.img: %s", strerror(errno));
|
||||
do_send_signature(fname);
|
||||
if (erase_first && needs_erase("boot")) {
|
||||
fb_queue_erase("boot");
|
||||
}
|
||||
fb_queue_flash("boot", data, sz);
|
||||
|
||||
fname = find_item("recovery", product);
|
||||
data = load_file(fname, &sz);
|
||||
if (data != 0) {
|
||||
do_send_signature(fname);
|
||||
if (erase_first && needs_erase("recovery")) {
|
||||
fb_queue_erase("recovery");
|
||||
for (i = 0; i < ARRAY_SIZE(images); i++) {
|
||||
fname = find_item(images[i].part_name, product);
|
||||
if (load_buf(usb, fname, &buf)) {
|
||||
if (images[i].is_optional)
|
||||
continue;
|
||||
die("could not load %s\n", images[i].img_name);
|
||||
}
|
||||
fb_queue_flash("recovery", data, sz);
|
||||
do_send_signature(fname);
|
||||
if (erase_first && needs_erase(images[i].part_name)) {
|
||||
fb_queue_erase(images[i].part_name);
|
||||
}
|
||||
flash_buf(images[i].part_name, &buf);
|
||||
}
|
||||
|
||||
fname = find_item("system", product);
|
||||
data = load_file(fname, &sz);
|
||||
if (data == 0) die("could not load system.img: %s", strerror(errno));
|
||||
do_send_signature(fname);
|
||||
if (erase_first && needs_erase("system")) {
|
||||
fb_queue_erase("system");
|
||||
}
|
||||
fb_queue_flash("system", data, sz);
|
||||
}
|
||||
|
||||
#define skip(n) do { argc -= (n); argv += (n); } while (0)
|
||||
|
|
@ -997,14 +1073,14 @@ int main(int argc, char **argv)
|
|||
fb_queue_flash(pname, data, sz);
|
||||
} else if(!strcmp(*argv, "flashall")) {
|
||||
skip(1);
|
||||
do_flashall(erase_first);
|
||||
do_flashall(usb, erase_first);
|
||||
wants_reboot = 1;
|
||||
} else if(!strcmp(*argv, "update")) {
|
||||
if (argc > 1) {
|
||||
do_update(argv[1], erase_first);
|
||||
do_update(usb, argv[1], erase_first);
|
||||
skip(2);
|
||||
} else {
|
||||
do_update("update.zip", erase_first);
|
||||
do_update(usb, "update.zip", erase_first);
|
||||
skip(1);
|
||||
}
|
||||
wants_reboot = 1;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue