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
This commit is contained in:
parent
05025357e6
commit
65cf84f3ff
|
@ -16,8 +16,9 @@ LOCAL_PATH:= $(call my-dir)
|
|||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg
|
||||
LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c
|
||||
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
|
||||
|
||||
ifeq ($(HOST_OS),linux)
|
||||
|
@ -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))
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue