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

Commit 2d2fd4cd authored by JP Abgrall's avatar JP Abgrall Committed by Gerrit Code Review
Browse files

Merge changes Ibff1f74e,Ic82595cf,If4e01cab

* changes:
  fastboot: Added tos as an optional image
  fastboot: Fixed optional entries
  fastboot: allow format on devices with small buffers
parents 52dd7cc0 73a4ad28
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ include $(CLEAR_VARS)

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
  $(LOCAL_PATH)/../../extras/ext4_utils
LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c
LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
LOCAL_MODULE := fastboot
LOCAL_MODULE_TAGS := debug
LOCAL_CFLAGS += -std=gnu99
+5 −204
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@
 */

#include "fastboot.h"
#include "make_ext4fs.h"
#include "fs.h"

#include <errno.h>
#include <stdio.h>
@@ -51,9 +51,8 @@
#define OP_COMMAND    2
#define OP_QUERY      3
#define OP_NOTICE     4
#define OP_FORMAT     5
#define OP_DOWNLOAD_SPARSE 6
#define OP_WAIT_FOR_DISCONNECT 7
#define OP_DOWNLOAD_SPARSE 5
#define OP_WAIT_FOR_DISCONNECT 6

typedef struct Action Action;

@@ -79,14 +78,7 @@ static Action *action_list = 0;
static Action *action_last = 0;


struct image_data {
    long long partition_size;
    long long image_size; // real size of image file
    void *buffer;
};

void generate_ext4_image(struct image_data *image);
void cleanup_image(struct image_data *image);

int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...)
{
@@ -102,24 +94,6 @@ int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...)
    return fb_command_response(usb, cmd, response);
}

struct generator {
    char *fs_type;

    /* generate image and return it as image->buffer.
     * size of the buffer returned as image->image_size.
     *
     * image->partition_size specifies what is the size of the
     * file partition we generate image for.
     */
    void (*generate)(struct image_data *image);

    /* it cleans the buffer allocated during image creation.
     * this function probably does free() or munmap().
     */
    void (*cleanup)(struct image_data *image);
} generators[] = {
    { "ext4", generate_ext4_image, cleanup_image }
};

/* 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
@@ -130,8 +104,7 @@ struct generator {
 */
int fb_format_supported(usb_handle *usb, const char *partition)
{
    char response[FB_RESPONSE_SZ+1];
    struct generator *generator = NULL;
    char response[FB_RESPONSE_SZ + 1] = {0,};
    int status;
    unsigned int i;

@@ -140,18 +113,7 @@ int fb_format_supported(usb_handle *usb, const char *partition)
        return 0;
    }

    for (i = 0; i < ARRAY_SIZE(generators); i++) {
        if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) {
            generator = &generators[i];
            break;
        }
    }

    if (generator) {
        return 1;
    }

    return 0;
    return !!fs_get_generator(response);
}

static int cb_default(Action *a, int status, char *resp)
@@ -205,163 +167,6 @@ void fb_queue_erase(const char *ptn)
    a->msg = mkmsg("erasing '%s'", ptn);
}

/* Loads file content into buffer. Returns NULL on error. */
static void *load_buffer(int fd, off_t size)
{
    void *buffer;

#ifdef USE_MINGW
    ssize_t count = 0;

    // mmap is more efficient but mingw does not support it.
    // In this case we read whole image into memory buffer.
    buffer = malloc(size);
    if (!buffer) {
        perror("malloc");
        return NULL;
    }

    lseek(fd, 0, SEEK_SET);
    while(count < size) {
        ssize_t actually_read = read(fd, (char*)buffer+count, size-count);

        if (actually_read == 0) {
            break;
        }
        if (actually_read < 0) {
            if (errno == EINTR) {
                continue;
            }
            perror("read");
            free(buffer);
            return NULL;
        }

        count += actually_read;
    }
#else
    buffer = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (buffer == MAP_FAILED) {
        perror("mmap");
        return NULL;
    }
#endif

    return buffer;
}

void cleanup_image(struct image_data *image)
{
#ifdef USE_MINGW
    free(image->buffer);
#else
    munmap(image->buffer, image->image_size);
#endif
}

void generate_ext4_image(struct image_data *image)
{
    int fd;
    struct stat st;

    fd = fileno(tmpfile());
    make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL);

    fstat(fd, &st);
    image->image_size = st.st_size;
    image->buffer = load_buffer(fd, st.st_size);

    close(fd);
}

int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported)
{
    const char *partition = a->cmd;
    char response[FB_RESPONSE_SZ+1];
    int status = 0;
    struct image_data image;
    struct generator *generator = NULL;
    int fd;
    unsigned i;
    char cmd[CMD_SIZE];

    status = fb_getvar(usb, response, "partition-type:%s", partition);
    if (status) {
        if (skip_if_not_supported) {
            fprintf(stderr,
                    "Erase successful, but not automatically formatting.\n");
            fprintf(stderr,
                    "Can't determine partition type.\n");
            return 0;
        }
        fprintf(stderr,"FAILED (%s)\n", fb_get_error());
        return status;
    }

    for (i = 0; i < ARRAY_SIZE(generators); i++) {
        if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) {
            generator = &generators[i];
            break;
        }
    }
    if (!generator) {
        if (skip_if_not_supported) {
            fprintf(stderr,
                    "Erase successful, but not automatically formatting.\n");
            fprintf(stderr,
                    "File system type %s not supported.\n", response);
            return 0;
        }
        fprintf(stderr,"Formatting is not supported for filesystem with type '%s'.\n",
                response);
        return -1;
    }

    status = fb_getvar(usb, response, "partition-size:%s", partition);
    if (status) {
        if (skip_if_not_supported) {
            fprintf(stderr,
                    "Erase successful, but not automatically formatting.\n");
            fprintf(stderr, "Unable to get partition size\n.");
            return 0;
        }
        fprintf(stderr,"FAILED (%s)\n", fb_get_error());
        return status;
    }
    image.partition_size = strtoll(response, (char **)NULL, 16);

    generator->generate(&image);
    if (!image.buffer) {
        fprintf(stderr,"Cannot generate image.\n");
        return -1;
    }

    // Following piece of code is similar to fb_queue_flash() but executes
    // actions directly without queuing
    fprintf(stderr, "sending '%s' (%lli KB)...\n", partition, image.image_size/1024);
    status = fb_download_data(usb, image.buffer, image.image_size);
    if (status) goto cleanup;

    fprintf(stderr, "writing '%s'...\n", partition);
    snprintf(cmd, sizeof(cmd), "flash:%s", partition);
    status = fb_command(usb, cmd);
    if (status) goto cleanup;

cleanup:
    generator->cleanup(&image);

    return status;
}

void fb_queue_format(const char *partition, int skip_if_not_supported)
{
    Action *a;

    a = queue_action(OP_FORMAT, partition);
    a->data = (void*)skip_if_not_supported;
    a->msg = mkmsg("formatting '%s' partition", partition);
}

void fb_queue_flash(const char *ptn, void *data, unsigned sz)
{
    Action *a;
@@ -589,10 +394,6 @@ int fb_execute_queue(usb_handle *usb)
            if (status) break;
        } else if (a->op == OP_NOTICE) {
            fprintf(stderr,"%s\n",(char*)a->data);
        } else if (a->op == OP_FORMAT) {
            status = fb_format(a, usb, (int)a->data);
            status = a->func(a, status, status ? fb_get_error() : "");
            if (status) break;
        } else if (a->op == OP_DOWNLOAD_SPARSE) {
            status = fb_download_data_sparse(usb, a->data);
            status = a->func(a, status, status ? fb_get_error() : "");
+80 −6
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#include <zipfile/zipfile.h>

#include "fastboot.h"
#include "fs.h"

#ifndef O_BINARY
#define O_BINARY 0
@@ -99,10 +100,11 @@ static struct {
    char sig_name[13];
    char part_name[9];
    bool is_optional;
} images[3] = {
} images[4] = {
    {"boot.img", "boot.sig", "boot", false},
    {"recovery.img", "recovery.sig", "recovery", true},
    {"system.img", "system.sig", "system", false},
    {"tos.img", "tos.sig", "tos", true},
};

void get_my_path(char *path);
@@ -119,6 +121,8 @@ char *find_item(const char *item, const char *product)
        fn = "recovery.img";
    } else if(!strcmp(item,"system")) {
        fn = "system.img";
    } else if(!strcmp(item,"tos")) {
        fn = "tos.img";
    } else if(!strcmp(item,"userdata")) {
        fn = "userdata.img";
    } else if(!strcmp(item,"cache")) {
@@ -284,7 +288,7 @@ void usage(void)
            "\n"
            "commands:\n"
            "  update <filename>                        reflash device from update.zip\n"
            "  flashall                                 flash boot + recovery + system\n"
            "  flashall                                 flash boot, system, and if found, recovery, tos\n"
            "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
            "  erase <partition>                        erase a flash partition\n"
            "  format <partition>                       format a flash partition \n"
@@ -622,10 +626,13 @@ static int load_buf_fd(usb_handle *usb, int fd,
    void *data;
    int64_t limit;


    sz64 = file_size(fd);
    if (sz64 < 0) {
        return -1;
    }

    lseek(fd, 0, SEEK_SET);
    limit = get_sparse_limit(usb, sz64);
    if (limit) {
        struct sparse_file **s = load_sparse_files(fd, limit);
@@ -653,7 +660,7 @@ static int load_buf(usb_handle *usb, const char *fname,

    fd = open(fname, O_RDONLY | O_BINARY);
    if (fd < 0) {
        die("cannot open '%s'\n", fname);
        return -1;
    }

    return load_buf_fd(usb, fd, buf);
@@ -872,6 +879,73 @@ static int64_t parse_num(const char *arg)
    return num;
}

void fb_perform_format(const char *partition, int skip_if_not_supported)
{
    char pType[FB_RESPONSE_SZ + 1], pSize[FB_RESPONSE_SZ + 1];
    unsigned int limit = INT_MAX;
    struct fastboot_buffer buf;
    const char *errMsg = NULL;
    const struct fs_generator *gen;
    uint64_t pSz;
    int status;
    int fd;

    if (target_sparse_limit > 0 && target_sparse_limit < limit)
        limit = target_sparse_limit;
    if (sparse_limit > 0 && sparse_limit < limit)
        limit = sparse_limit;

    status = fb_getvar(usb, pType, "partition-type:%s", partition);
    if (status) {
        errMsg = "Can't determine partition type.\n";
        goto failed;
    }

    status = fb_getvar(usb, pSize, "partition-size:%s", partition);
    if (status) {
        errMsg = "Unable to get partition size\n";
        goto failed;
    }

    gen = fs_get_generator(pType);
    if (!gen) {
        if (skip_if_not_supported) {
            fprintf(stderr, "Erase successful, but not automatically formatting.\n");
            fprintf(stderr, "File system type %s not supported.\n", pType);
            return;
        }
        fprintf(stderr, "Formatting is not supported for filesystem with type '%s'.\n", pType);
        return;
    }

    pSz = strtoll(pSize, (char **)NULL, 16);

    fd = fileno(tmpfile());
    if (fs_generator_generate(gen, fd, pSz)) {
        close(fd);
        fprintf(stderr, "Cannot generate image.\n");
        return;
    }

    if (load_buf_fd(usb, fd, &buf)) {
        fprintf(stderr, "Cannot read image.\n");
        close(fd);
        return;
    }
    flash_buf(partition, &buf);

    return;


failed:
    if (skip_if_not_supported) {
        fprintf(stderr, "Erase successful, but not automatically formatting.\n");
        if (errMsg)
            fprintf(stderr, "%s", errMsg);
    }
    fprintf(stderr,"FAILED (%s)\n", fb_get_error());
}

int main(int argc, char **argv)
{
    int wants_wipe = 0;
@@ -1004,7 +1078,7 @@ int main(int argc, char **argv)
            if (erase_first && needs_erase(argv[1])) {
                fb_queue_erase(argv[1]);
            }
            fb_queue_format(argv[1], 0);
            fb_perform_format(argv[1], 0);
            skip(2);
        } else if(!strcmp(*argv, "signature")) {
            require(2);
@@ -1092,9 +1166,9 @@ int main(int argc, char **argv)

    if (wants_wipe) {
        fb_queue_erase("userdata");
        fb_queue_format("userdata", 1);
        fb_perform_format("userdata", 1);
        fb_queue_erase("cache");
        fb_queue_format("cache", 1);
        fb_perform_format("cache", 1);
    }
    if (wants_reboot) {
        fb_queue_reboot();
+1 −1
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ int fb_format_supported(usb_handle *usb, const char *partition);
void fb_queue_flash(const char *ptn, void *data, unsigned sz);
void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz);
void fb_queue_erase(const char *ptn);
void fb_queue_format(const char *ptn, int skip_if_not_supported);
void fb_queue_format(const char *ptn, int skip_if_not_supported, unsigned int max_chunk_sz);
void fb_queue_require(const char *prod, const char *var, int invert,
        unsigned nvalues, const char **value);
void fb_queue_display(const char *var, const char *prettyname);

fastboot/fs.c

0 → 100644
+56 −0
Original line number Diff line number Diff line
#include "fastboot.h"
#include "make_ext4fs.h"
#include "fs.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sparse/sparse.h>
#include <unistd.h>

#ifdef USE_MINGW
#include <fcntl.h>
#else
#include <sys/mman.h>
#endif



static int generate_ext4_image(int fd, long long partSize)
{
    make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);

    return 0;
}

static const struct fs_generator {

    char *fs_type;  //must match what fastboot reports for partition type
    int (*generate)(int fd, long long partSize); //returns 0 or error value

} generators[] = {

    { "ext4", generate_ext4_image}

};

const struct fs_generator* fs_get_generator(const char* name)
{
    unsigned i;

    for (i = 0; i < sizeof(generators) / sizeof(*generators); i++)
        if (!strcmp(generators[i].fs_type, name))
            return generators + i;

    return NULL;
}

int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)
{
    return gen->generate(tmpFileNo, partSize);
}
Loading