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

Commit 65cf84f3 authored by Anatol Pomazau's avatar Anatol Pomazau Committed by Mike J. Chen
Browse files

Implement 'fastboot format' command

Some filesystems (e.g. ext4) require flushing an initial
fs image, right after erasing it the partition is unusable.

Doing erase,flush emptyfs is a little bit scaring so we have a
separate command that performs it as atomic step:

 - get size of partition
 - create an empty filesystem image
 - erase the partition
 - flush empty fs to the partition

This command applicable only for ext4 filesystem and checks the
partition type before formatting it.

Change-Id: I8529bc1dc64698f1f0d91312f7c0ab1a6e5d8b44
parent 05025357
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -16,7 +16,8 @@ LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
  $(LOCAL_PATH)/../../extras/ext4_utils
LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c
LOCAL_MODULE := fastboot

@@ -47,7 +48,7 @@ ifeq ($(HOST_OS),windows)
  LOCAL_C_INCLUDES += development/host/windows/usb/api
endif

LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz
LOCAL_STATIC_LIBRARIES := $(EXTRA_STATIC_LIBS) libzipfile libunz libext4_utils libz

include $(BUILD_HOST_EXECUTABLE)
$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
+147 −2
Original line number Diff line number Diff line
@@ -26,13 +26,24 @@
 * SUCH DAMAGE.
 */

#include "fastboot.h"
#include "make_ext4fs.h"
#include "ext4_utils.h"

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

#include "fastboot.h"
extern struct fs_info info;

#define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))

double now()
{
@@ -60,15 +71,18 @@ char *mkmsg(const char *fmt, ...)
#define OP_COMMAND    2
#define OP_QUERY      3
#define OP_NOTICE     4
#define OP_FORMAT     5

typedef struct Action Action;

#define CMD_SIZE 64

struct Action 
{
    unsigned op;
    Action *next;

    char cmd[64];    
    char cmd[CMD_SIZE];
    const char *prod;
    void *data;
    unsigned size;
@@ -82,6 +96,35 @@ struct Action
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 munmap_image(struct image_data *image);

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, munmap_image }
};

static int cb_default(Action *a, int status, char *resp)
{
    if (status) {
@@ -133,6 +176,104 @@ void fb_queue_erase(const char *ptn)
    a->msg = mkmsg("erasing '%s'", ptn);
}

void munmap_image(struct image_data *image)
{
    munmap(image->buffer, image->image_size);
}

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

    fd = fileno(tmpfile());
    info.len = image->partition_size;
    make_ext4fs_internal(fd, NULL, NULL, 0, 0, 1, 0, 0, 0);

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

    image->buffer = mmap(NULL, image->image_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if (image->buffer == MAP_FAILED) {
        perror("mmap");
        image->buffer = NULL;
    }

    close(fd);
}

int fb_format(Action *a, usb_handle *usb)
{
    const char *partition = a->cmd;
    char query[256];
    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];

    response[FB_RESPONSE_SZ] = '\0';
    snprintf(query, sizeof(query), "getvar:partition-type:%s", partition);
    status = fb_command_response(usb, query, response);
    if (status) {
        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) {
        fprintf(stderr,"Formatting is not supported for filesystem with type '%s'.\n",
                response);
        return -1;
    }

    response[FB_RESPONSE_SZ] = '\0';
    snprintf(query, sizeof(query), "getvar:partition-size:%s", partition);
    status = fb_command_response(usb, query, response);
    if (status) {
        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, CMD_SIZE, "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)
{
    Action *a;

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

void fb_queue_flash(const char *ptn, void *data, unsigned sz)
{
    Action *a;
@@ -340,6 +481,10 @@ 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);
            status = a->func(a, status, status ? fb_get_error() : "");
            if (status) break;
        } else {
            die("bogus action");
        }
+5 −0
Original line number Diff line number Diff line
@@ -222,6 +222,7 @@ void usage(void)
            "  flashall                                 flash boot + recovery + system\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"
            "  getvar <variable>                        display a bootloader variable\n"
            "  boot <kernel> [ <ramdisk> ]              download and boot kernel\n"
            "  flash:raw boot <kernel> [ <ramdisk> ]    create bootimage and flash it\n"
@@ -633,6 +634,10 @@ int main(int argc, char **argv)
            require(2);
            fb_queue_erase(argv[1]);
            skip(2);
        } else if(!strcmp(*argv, "format")) {
            require(2);
            fb_queue_format(argv[1]);
            skip(2);
        } else if(!strcmp(*argv, "signature")) {
            require(2);
            data = load_file(argv[1], &sz);
+1 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ char *fb_get_error(void);
/* engine.c - high level command queue engine */
void fb_queue_flash(const char *ptn, void *data, unsigned sz);;
void fb_queue_erase(const char *ptn);
void fb_queue_format(const char *ptn);
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);