Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 622810ce authored by Rom Lemarchand's avatar Rom Lemarchand
Browse files

fastboot: add support for sparse images in flashall and update



Change-Id: I66a73b16a988a65fc91fb22a26d11986025089de
Signed-off-by: default avatarRom Lemarchand <romlem@google.com>
parent c9cce4b9
Loading
Loading
Loading
Loading
+171 −95
Original line number Diff line number Diff line
@@ -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;

    off = lseek64(fd, 0, SEEK_END);
    close(fd);
    ret = fstat(fd, &st);

    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);
            return -1;
        }
        buf->type = FB_BUFFER_SPARSE;
        buf->data = s;
    } else {
        unsigned int 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) {
            sz64 = sparse_file_len(*s, true, false);
                int64_t 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': %s\n", fname, strerror(errno));
        fb_queue_flash(pname, data, sz);
            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");
        }
        fb_queue_flash("recovery", data, sz);
    }

    data = unzip_file(zip, "system.img", &sz);
    if (data == 0) die("update package missing system.img");
    do_update_signature(zip, "system.sig");
    if (erase_first && needs_erase("system")) {
        fb_queue_erase("system");
    for (i = 0; i < ARRAY_SIZE(images); i++) {
        fd = unzip_to_file(zip, images[i].img_name);
        if (fd < 0) {
            if (images[i].is_optional)
                continue;
            die("update package missing %s", images[i].img_name);
        }
        rc = load_buf_fd(usb, fd, &buf);
        if (rc) die("cannot load %s from flash", images[i].img_name);
        do_update_signature(zip, images[i].sig_name);
        if (erase_first && needs_erase(images[i].part_name)) {
            fb_queue_erase(images[i].part_name);
        }
        flash_buf(images[i].part_name, &buf);
        /* not closing the fd here since the sparse code keeps the fd around
         * but hasn't mmaped data yet. The tmpfile will get cleaned up when the
         * program exits.
         */
    }
    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");
    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("boot", data, sz);

    fname = find_item("recovery", product);
    data = load_file(fname, &sz);
    if (data != 0) {
        do_send_signature(fname);
        if (erase_first && needs_erase("recovery")) {
            fb_queue_erase("recovery");
        }
        fb_queue_flash("recovery", data, sz);
        if (erase_first && needs_erase(images[i].part_name)) {
            fb_queue_erase(images[i].part_name);
        }

    fname = find_item("system", product);
    data = load_file(fname, &sz);
    if (data == 0) die("could not load system.img: %s", strerror(errno));
    do_send_signature(fname);
    if (erase_first && needs_erase("system")) {
        fb_queue_erase("system");
        flash_buf(images[i].part_name, &buf);
    }
    fb_queue_flash("system", data, sz);
}

#define skip(n) do { argc -= (n); argv += (n); } while (0)
@@ -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;