fastbootd: erase, boot and partitioning commands

Change-Id: I49ba2ba2e002fd5b6bbd37cc3fd0caa106f42010
diff --git a/fastbootd/Android.mk b/fastbootd/Android.mk
index 76b28e2..148d9fd 100644
--- a/fastbootd/Android.mk
+++ b/fastbootd/Android.mk
@@ -16,23 +16,81 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_C_INCLUDES := \
+    external/openssl/include \
+    $(LOCAL_PATH)/include \
+    external/zlib/ \
+
 LOCAL_SRC_FILES := \
     config.c \
     commands.c \
+    commands/boot.c \
+    commands/flash.c \
+    commands/partitions.c \
     fastbootd.c \
     protocol.c \
     transport.c \
-    usb_linux_client.c
+    trigger.c \
+    usb_linux_client.c \
+    utils.c
 
 LOCAL_MODULE := fastbootd
 LOCAL_MODULE_TAGS := optional
 LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
+LOCAL_LDFLAGS := -ldl
+
+LOCAL_SHARED_LIBRARIES := \
+    libhardware \
+    libhardware_legacy
+
+LOCAL_STATIC_LIBRARIES := \
+    libsparse_static \
+    libc \
+    libcutils \
+    libz
+
+#LOCAL_FORCE_STATIC_EXECUTABLE := true
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    external/zlib/
+
+LOCAL_SRC_FILES := \
+    commands/partitions.c \
+    other/gptedit.c \
+    utils.c
+
+LOCAL_MODULE := gptedit
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
 
 LOCAL_STATIC_LIBRARIES := \
     libsparse_static \
     libc \
-    libcutils
+    libcutils \
+    libz
 
 LOCAL_FORCE_STATIC_EXECUTABLE := true
 
 include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+
+LOCAL_STATIC_LIBRARIES := \
+    $(EXTRA_STATIC_LIBS) \
+    libcutils
+
+LOCAL_SRC_FILES := \
+    other/vendor_trigger.c
+
+LOCAL_MODULE := libvendortrigger.default
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter
+
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/fastbootd/commands.c b/fastbootd/commands.c
index 252f655..83e86b0 100644
--- a/fastbootd/commands.c
+++ b/fastbootd/commands.c
@@ -32,114 +32,279 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/reboot.h>
+#include <fcntl.h>
 
 #include "bootimg.h"
+#include "commands/boot.h"
+#include "commands/flash.h"
+#include "commands/partitions.h"
+#include "commands/virtual_partitions.h"
 #include "debug.h"
 #include "protocol.h"
+#include "trigger.h"
+#include "utils.h"
+
+#define ATAGS_LOCATION "/proc/atags"
 
 static void cmd_boot(struct protocol_handle *phandle, const char *arg)
 {
-#if 0
     unsigned kernel_actual;
     unsigned ramdisk_actual;
-    static struct boot_img_hdr hdr;
-    char *ptr = ((char*) data);
+    unsigned second_actual;
+    void *kernel_ptr;
+    void *ramdisk_ptr;
+    void *second_ptr;
+    struct boot_img_hdr *hdr;
+    int sz, atags_sz, new_atags_sz;
+    int rv;
+    char *ptr = NULL, *atags_ptr = NULL, *new_atags = NULL;
+    D(DEBUG, "cmd_boot %s\n", arg);
 
-    if (sz < sizeof(hdr)) {
+    if (phandle->download_fd < 0) {
+        fastboot_fail(phandle, "no kernel file");
+        return;
+    }
+
+    atags_ptr = read_atags(ATAGS_LOCATION, &atags_sz);
+    if (atags_ptr == NULL) {
+        fastboot_fail(phandle, "atags read error");
+        goto error;
+    }
+
+    sz = get_file_size(phandle->download_fd);
+    ptr = (char *) mmap(NULL, sz, PROT_READ,
+                        MAP_POPULATE | MAP_PRIVATE, phandle->download_fd, 0);
+    hdr = (struct boot_img_hdr *) ptr;
+
+    if (ptr == MAP_FAILED) {
+        fastboot_fail(phandle, "internal fastbootd error");
+        goto error;
+    }
+
+    if ((size_t) sz < sizeof(*hdr)) {
         fastboot_fail(phandle, "invalid bootimage header");
-        return;
+        goto error;
     }
 
-    memcpy(&hdr, data, sizeof(hdr));
+    kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, hdr->page_size);
+    ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, hdr->page_size);
+    second_actual = ROUND_TO_PAGE(hdr->second_size, hdr->page_size);
 
-    /* ensure commandline is terminated */
-    hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
+    new_atags = (char *) create_atags((unsigned *) atags_ptr, atags_sz, hdr, &new_atags_sz);
 
-    kernel_actual = ROUND_TO_PAGE(hdr.kernel_size);
-    ramdisk_actual = ROUND_TO_PAGE(hdr.ramdisk_size);
+    if (new_atags == NULL) {
+        fastboot_fail(phandle, "atags generate error");
+        goto error;
+    }
+    if (new_atags_sz > 0x4000) {
+        fastboot_fail(phandle, "atags file to large");
+        goto error;
+    }
 
-    if (2048 + kernel_actual + ramdisk_actual < sz) {
+    if ((int) (hdr->page_size + kernel_actual + ramdisk_actual) < sz) {
         fastboot_fail(phandle, "incomplete bootimage");
-        return;
+        goto error;
     }
 
-    /*memmove((void*) KERNEL_ADDR, ptr + 2048, hdr.kernel_size);
-    memmove((void*) RAMDISK_ADDR, ptr + 2048 + kernel_actual, hdr.ramdisk_size);*/
+    kernel_ptr = (void *)((unsigned) ptr + hdr->page_size);
+    ramdisk_ptr = (void *)((unsigned) kernel_ptr + kernel_actual);
+    second_ptr = (void *)((unsigned) ramdisk_ptr + ramdisk_actual);
+
+    D(INFO, "preparing to boot");
+    // Prepares boot physical addresses from header are ignored
+    rv = prepare_boot_linux(hdr->kernel_addr, kernel_ptr, kernel_actual,
+                            hdr->ramdisk_addr, ramdisk_ptr, ramdisk_actual,
+                            hdr->second_addr, second_ptr, second_actual,
+                            hdr->tags_addr, new_atags, ROUND_TO_PAGE(new_atags_sz, hdr->page_size));
+    if (rv < 0) {
+        fastboot_fail(phandle, "kexec prepare failed");
+        goto error;
+    }
 
     fastboot_okay(phandle, "");
-    udc_stop();
 
+    free(atags_ptr);
+    munmap(ptr, sz);
+    free(new_atags);
 
-    /*boot_linux((void*) KERNEL_ADDR, (void*) TAGS_ADDR,
-           (const char*) hdr.cmdline, LINUX_MACHTYPE,
-           (void*) RAMDISK_ADDR, hdr.ramdisk_size);*/
-#endif
+    D(INFO, "Kexec going to reboot");
+    reboot(LINUX_REBOOT_CMD_KEXEC);
+
+    fastboot_fail(phandle, "reboot error");
+
+    return;
+
+error:
+
+    if (atags_ptr != NULL)
+        free(atags_ptr);
+    if (ptr != NULL)
+        munmap(ptr, sz);
+
 }
 
 static void cmd_erase(struct protocol_handle *phandle, const char *arg)
 {
-#if 0
-    struct ptentry *ptn;
-    struct ptable *ptable;
+    int partition_fd;
+    char path[PATH_MAX];
+    D(DEBUG, "cmd_erase %s\n", arg);
 
-    ptable = flash_get_ptable();
-    if (ptable == NULL) {
+    if (flash_find_entry(arg, path, PATH_MAX)) {
         fastboot_fail(phandle, "partition table doesn't exist");
         return;
     }
 
-    ptn = ptable_find(ptable, arg);
-    if (ptn == NULL) {
-        fastboot_fail(phandle, "unknown partition name");
+    if (path == NULL) {
+        fastboot_fail(phandle, "Couldn't find partition");
         return;
     }
 
-    if (flash_erase(ptn)) {
+    partition_fd = flash_get_partiton(path);
+    if (partition_fd < 0) {
+        fastboot_fail(phandle, "partiton file does not exists");
+    }
+
+    if (flash_erase(partition_fd)) {
+        fastboot_fail(phandle, "failed to erase partition");
+        flash_close(partition_fd);
+        return;
+    }
+
+    if (flash_close(partition_fd) < 0) {
+        D(ERR, "could not close device %s", strerror(errno));
         fastboot_fail(phandle, "failed to erase partition");
         return;
     }
     fastboot_okay(phandle, "");
-#endif
+}
+
+static int GPT_header_location() {
+    const char *location_str = fastboot_getvar("gpt_sector");
+    char *str;
+    int location;
+
+    if (!strcmp("", location_str)) {
+        D(INFO, "GPT location not specified using second sector");
+        return 1;
+    }
+    else {
+        location = strtoul(location_str, &str, 10);
+        D(INFO, "GPT location specified as %d", location);
+
+        if (*str != '\0')
+            return -1;
+
+        return location - 1;
+    }
+}
+
+static void cmd_gpt_layout(struct protocol_handle *phandle, const char *arg) {
+    struct GPT_entry_table *oldtable;
+    int location;
+    struct GPT_content content;
+    const char *device;
+    device = fastboot_getvar("blockdev");
+
+    if (!strcmp(device, "")) {
+        fastboot_fail(phandle, "blockdev not defined in config file");
+        return;
+    }
+
+    if (phandle->download_fd < 0) {
+        fastboot_fail(phandle, "no layout file");
+        return;
+    }
+
+    location = GPT_header_location();
+    oldtable = GPT_get_device(device, location);
+
+    GPT_default_content(&content, oldtable);
+    if (oldtable == NULL)
+        D(WARN, "Could not get old gpt table");
+    else
+        GPT_release_device(oldtable);
+
+    if (!GPT_parse_file(phandle->download_fd, &content)) {
+        fastboot_fail(phandle, "Could not parse partition config file");
+        return;
+    }
+
+    if (trigger_gpt_layout(&content)) {
+        fastboot_fail(phandle, "Vendor forbids this opperation");
+        GPT_release_content(&content);
+        return;
+    }
+
+    if (!GPT_write_content(device, &content)) {
+        fastboot_fail(phandle, "Unable to write gpt file");
+        GPT_release_content(&content);
+        return;
+    }
+
+    GPT_release_content(&content);
+    fastboot_okay(phandle, "");
 }
 
 static void cmd_flash(struct protocol_handle *phandle, const char *arg)
 {
-#if 0
-    struct ptentry *ptn;
-    struct ptable *ptable;
-    unsigned extra = 0;
+    int partition;
+    uint64_t sz;
+    char data[BOOT_MAGIC_SIZE];
+    char path[PATH_MAX];
+    ssize_t header_sz = 0;
 
-    ptable = flash_get_ptable();
-    if (ptable == NULL) {
+    D(DEBUG, "cmd_flash %s\n", arg);
+
+    if (try_handle_virtual_partition(phandle, arg)) {
+        return;
+    }
+
+    if (phandle->download_fd < 0) {
+        fastboot_fail(phandle, "no kernel file");
+        return;
+    }
+
+    if (flash_find_entry(arg, path, PATH_MAX)) {
         fastboot_fail(phandle, "partition table doesn't exist");
         return;
     }
 
-    ptn = ptable_find(ptable, arg);
-    if (ptn == NULL) {
-        fastboot_fail(phandle, "unknown partition name");
-        return;
-    }
-
-    if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) {
+    // TODO: Maybe its goot idea to check whether the partition is just bootable partition
+    if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) {
+        if (read_data_once(phandle->download_fd, data, BOOT_MAGIC_SIZE) < BOOT_MAGIC_SIZE) {
+            fastboot_fail(phandle, "incoming data read error, cannot read boot header");
+            return;
+        }
         if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
             fastboot_fail(phandle, "image is not a boot image");
             return;
         }
     }
 
-    if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata"))
-        extra = 64;
-    else
-        sz = ROUND_TO_PAGE(sz);
+    partition = flash_get_partiton(path);
 
-    D(INFO, "writing %d bytes to '%s'\n", sz, ptn->name);
-    if (flash_write(ptn, extra, data, sz)) {
+    sz = get_file_size64(phandle->download_fd);
+    if (sz > get_file_size64(partition)) {
+        flash_close(partition);
+        D(WARN, "size of file too large");
+        fastboot_fail(phandle, "size of file too large");
+        return;
+    }
+
+    D(INFO, "writing %lld bytes to '%s'\n", sz, arg);
+
+    if (flash_write(partition, phandle->download_fd, sz, header_sz)) {
         fastboot_fail(phandle, "flash write failure");
         return;
     }
-    D(INFO, "partition '%s' updated\n", ptn->name);
-#endif
+    D(INFO, "partition '%s' updated\n", arg);
+
+    flash_close(partition);
+
     fastboot_okay(phandle, "");
 }
 
@@ -192,14 +357,26 @@
     fastboot_okay(phandle, "");
 }
 
+static void cmd_oem(struct protocol_handle *phandle, const char *arg) {
+    const char *response = "";
+
+    if (trigger_oem_cmd(arg, &response))
+        fastboot_fail(phandle, response);
+    else
+        fastboot_okay(phandle, response);
+}
+
 void commands_init()
 {
+    virtual_partition_register("partition-table", cmd_gpt_layout);
+
     fastboot_register("boot", cmd_boot);
     fastboot_register("erase:", cmd_erase);
     fastboot_register("flash:", cmd_flash);
     fastboot_register("continue", cmd_continue);
     fastboot_register("getvar:", cmd_getvar);
     fastboot_register("download:", cmd_download);
+    fastboot_register("oem", cmd_oem);
     //fastboot_publish("version", "0.5");
     //fastboot_publish("product", "swordfish");
     //fastboot_publish("kernel", "lk");
diff --git a/fastbootd/commands/boot.c b/fastbootd/commands/boot.c
new file mode 100644
index 0000000..8da9a28
--- /dev/null
+++ b/fastbootd/commands/boot.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/syscall.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "boot.h"
+#include "debug.h"
+#include "utils.h"
+#include "bootimg.h"
+
+
+#define KEXEC_ARM_ATAGS_OFFSET  0x1000
+#define KEXEC_ARM_ZIMAGE_OFFSET 0x8000
+
+#define MEMORY_SIZE 0x0800000
+#define START_ADDRESS 0x44000000
+#define KERNEL_START (START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET)
+
+#define ATAG_NONE_TYPE      0x00000000
+#define ATAG_CORE_TYPE      0x54410001
+#define ATAG_RAMDISK_TYPE   0x54410004
+#define ATAG_INITRD2_TYPE   0x54420005
+#define ATAG_CMDLINE_TYPE   0x54410009
+
+#define MAX_ATAG_SIZE 0x4000
+
+struct atag_info {
+    unsigned size;
+    unsigned type;
+};
+
+struct atag_initrd2 {
+    unsigned start;
+    unsigned size;
+};
+
+struct atag_cmdline {
+    char cmdline[0];
+};
+
+struct atag {
+    struct atag_info info;
+    union {
+        struct atag_initrd2 initrd2;
+        struct atag_cmdline cmdline;
+    } data;
+};
+
+
+long kexec_load(unsigned int entry, unsigned long nr_segments,
+                struct kexec_segment *segment, unsigned long flags) {
+   return syscall(__NR_kexec_load, entry, nr_segments, segment, flags);
+}
+
+/*
+ * Prepares arguments for kexec
+ * Kernel address is not set into kernel_phys
+ * Ramdisk is set to position relative to kernel
+ */
+int prepare_boot_linux(unsigned kernel_phys, void *kernel_addr, int kernel_size,
+                       unsigned ramdisk_phys, void *ramdisk_addr, int ramdisk_size,
+                       unsigned second_phys, void *second_addr, int second_size,
+                       unsigned atags_phys, void *atags_addr, int atags_size) {
+    struct kexec_segment segment[4];
+    int segment_count = 2;
+    unsigned entry = START_ADDRESS + KEXEC_ARM_ZIMAGE_OFFSET;
+    int rv;
+    int page_size = getpagesize();
+
+    segment[0].buf = kernel_addr;
+    segment[0].bufsz = kernel_size;
+    segment[0].mem = (void *) KERNEL_START;
+    segment[0].memsz = ROUND_TO_PAGE(kernel_size, page_size);
+
+    if (kernel_size > MEMORY_SIZE - KEXEC_ARM_ZIMAGE_OFFSET) {
+        D(INFO, "Kernel image too big");
+        return -1;
+    }
+
+    segment[1].buf = atags_addr;
+    segment[1].bufsz = atags_size;
+    segment[1].mem = (void *) (START_ADDRESS + KEXEC_ARM_ATAGS_OFFSET);
+    segment[1].memsz = ROUND_TO_PAGE(atags_size, page_size);
+
+    D(INFO, "Ramdisk size is %d", ramdisk_size);
+
+    if (ramdisk_size != 0) {
+        segment[segment_count].buf = ramdisk_addr;
+        segment[segment_count].bufsz = ramdisk_size;
+        segment[segment_count].mem = (void *) (KERNEL_START + ramdisk_phys - kernel_phys);
+        segment[segment_count].memsz = ROUND_TO_PAGE(ramdisk_phys, page_size);
+        ++segment_count;
+    }
+
+    D(INFO, "Ramdisk size is %d", ramdisk_size);
+    if (second_size != 0) {
+        segment[segment_count].buf = second_addr;
+        segment[segment_count].bufsz = second_size;
+        segment[segment_count].mem = (void *) (KERNEL_START + second_phys - kernel_phys);
+        segment[segment_count].memsz = ROUND_TO_PAGE(second_size, page_size);
+        entry = second_phys;
+        ++segment_count;
+    }
+
+    rv = kexec_load(entry, segment_count, segment, KEXEC_ARCH_DEFAULT);
+
+    if (rv != 0) {
+        D(INFO, "Kexec_load returned non-zero exit code: %s\n", strerror(errno));
+        return -1;
+    }
+
+    return 1;
+
+}
+
+unsigned *create_atags(unsigned *atags_position, int atag_size, const struct boot_img_hdr *hdr, int *size) {
+    struct atag *current_tag = (struct atag *) atags_position;
+    unsigned *current_tag_raw = atags_position;
+    unsigned *new_atags = malloc(ROUND_TO_PAGE(atag_size + BOOT_ARGS_SIZE * sizeof(char),
+                                               hdr->page_size));
+    //This pointer will point into the beggining of buffer free space
+    unsigned *natags_raw_buff = new_atags;
+    int new_atags_size = 0;
+    int current_size;
+    int cmdl_length;
+
+    // copy tags from current atag file
+    while (current_tag->info.type != ATAG_NONE_TYPE) {
+        switch (current_tag->info.type) {
+            case ATAG_CMDLINE_TYPE:
+            case ATAG_RAMDISK_TYPE:
+            case ATAG_INITRD2_TYPE: break;
+            default:
+                memcpy((void *)natags_raw_buff, (void *)current_tag_raw, current_tag->info.size * sizeof(unsigned));
+                natags_raw_buff += current_tag->info.size;
+                new_atags_size += current_tag->info.size;
+        }
+
+        current_tag_raw += current_tag->info.size;
+        current_tag = (struct atag *) current_tag_raw;
+
+        if (current_tag_raw >= atags_position + atag_size) {
+            D(ERR, "Critical error in atags");
+            return NULL;
+        }
+    }
+
+    // set INITRD2 tag
+    if (hdr->ramdisk_size > 0) {
+        current_size = (sizeof(struct atag_info) + sizeof(struct atag_initrd2)) / sizeof(unsigned);
+        *((struct atag *) natags_raw_buff) = (struct atag) {
+            .info = {
+                .size = current_size,
+                .type = ATAG_INITRD2_TYPE
+            },
+            .data = {
+                .initrd2 = (struct atag_initrd2) {
+                    .start = hdr->ramdisk_addr,
+                    .size = hdr->ramdisk_size
+                }
+            }
+        };
+
+        new_atags_size += current_size;
+        natags_raw_buff += current_size;
+    }
+
+    // set ATAG_CMDLINE
+    cmdl_length = strnlen((char *) hdr->cmdline, BOOT_ARGS_SIZE - 1);
+    current_size = sizeof(struct atag_info) + (1 + cmdl_length);
+    current_size = (current_size + sizeof(unsigned) - 1) / sizeof(unsigned);
+    *((struct atag *) natags_raw_buff) = (struct atag) {
+        .info = {
+            .size = current_size,
+            .type = ATAG_CMDLINE_TYPE
+        },
+    };
+
+    //copy cmdline and ensure that there is null character
+    memcpy(((struct atag *) natags_raw_buff)->data.cmdline.cmdline,
+           (char *) hdr->cmdline, cmdl_length);
+    ((struct atag *) natags_raw_buff)->data.cmdline.cmdline[cmdl_length] = '\0';
+
+    new_atags_size += current_size;
+    natags_raw_buff += current_size;
+
+    // set ATAG_NONE
+    *((struct atag *) natags_raw_buff) = (struct atag) {
+        .info = {
+            .size = 0,
+            .type = ATAG_NONE_TYPE
+        },
+    };
+    new_atags_size += sizeof(struct atag_info) / sizeof(unsigned);
+    natags_raw_buff += sizeof(struct atag_info) / sizeof(unsigned);
+
+    *size = new_atags_size * sizeof(unsigned);
+    return new_atags;
+}
+
+char *read_atags(const char * path, int *atags_sz) {
+    int afd = -1;
+    char *atags_ptr = NULL;
+
+    afd = open(path, O_RDONLY);
+    if (afd < 0) {
+        D(ERR, "wrong atags file");
+        return 0;
+    }
+
+    atags_ptr = (char *) malloc(MAX_ATAG_SIZE);
+    if (atags_ptr == NULL) {
+        D(ERR, "insufficient memory");
+        return 0;
+    }
+
+    *atags_sz = read(afd, atags_ptr, MAX_ATAG_SIZE);
+
+    close(afd);
+    return atags_ptr;
+}
+
diff --git a/fastbootd/commands/boot.h b/fastbootd/commands/boot.h
new file mode 100644
index 0000000..bfbf1de
--- /dev/null
+++ b/fastbootd/commands/boot.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __FASTBOOT_BOOT_H
+#define __FASTBOOT_BOOT_H
+
+#include <sys/cdefs.h>
+#include <uapi/linux/kexec.h>
+
+#include "bootimg.h"
+
+#define KEXEC_SEGMENT_MAX 16
+
+#define KEXEC_TYPE_DEFAULT 0
+#define KEXEC_TYPE_CRASH   1
+
+int prepare_boot_linux(unsigned, void *, int, unsigned, void *, int,
+                       unsigned, void *, int, unsigned, void *, int);
+unsigned *create_atags(unsigned *, int, const struct boot_img_hdr *, int *);
+long kexec_load(unsigned int, unsigned long, struct kexec_segment *, unsigned long);
+char *read_atags(const char *, int *);
+
+#endif /* _SYS_KEXEC_H */
+
diff --git a/fastbootd/commands/flash.c b/fastbootd/commands/flash.c
new file mode 100644
index 0000000..5f8b931
--- /dev/null
+++ b/fastbootd/commands/flash.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "flash.h"
+#include "protocol.h"
+#include "debug.h"
+#include "utils.h"
+#include "commands/partitions.h"
+
+
+#define ALLOWED_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-."
+#define BUFFER_SIZE 1024 * 1024
+#define MIN(a, b) (a > b ? b : a)
+
+
+int flash_find_entry(const char *name, char *out, size_t outlen)
+{
+//TODO: Assumption: All the partitions has they unique name
+
+    const char *path = fastboot_getvar("device-directory");
+    size_t length;
+    if (strcmp(path, "") == 0) {
+        D(ERR, "device-directory: not defined in config file");
+        return -1;
+    }
+
+    length = strspn(name, ALLOWED_CHARS);
+    if (length != strlen(name)) {
+        D(ERR, "Not allowed char in name: %c", name[length]);
+        return -1;
+    }
+
+    if (snprintf(out, outlen, "%s%s", path, name) >= (int) outlen) {
+        D(ERR, "Too long path to partition file");
+        return -1;
+    }
+
+    if (access(out, F_OK ) == -1) {
+        D(ERR, "could not find partition file %s", name);
+        return -1;
+    }
+
+    return 0;
+}
+
+int flash_erase(int fd)
+{
+    int64_t size;
+    size = get_block_device_size(fd);
+    D(DEBUG, "erase %llu data from %d\n", size, fd);
+
+    return wipe_block_device(fd, size);
+}
+
+int flash_write(int partition_fd, int data_fd, ssize_t size, ssize_t skip)
+{
+    ssize_t written = 0;
+    struct GPT_mapping input;
+    struct GPT_mapping output;
+
+    while (written < size) {
+        int current_size = MIN(size - written, BUFFER_SIZE);
+
+        if (gpt_mmap(&input, written + skip, current_size, data_fd)) {
+            D(ERR, "Error in writing data, unable to map data file %d at %d size %d", size, skip, current_size);
+            return -1;
+        }
+        if (gpt_mmap(&output, written, current_size, partition_fd)) {
+            D(ERR, "Error in writing data, unable to map output partition");
+            return -1;
+        }
+
+        memcpy(output.ptr, input.ptr, current_size);
+
+        gpt_unmap(&input);
+        gpt_unmap(&output);
+
+        written += current_size;
+    }
+
+    return 0;
+}
diff --git a/fastbootd/commands/flash.h b/fastbootd/commands/flash.h
new file mode 100644
index 0000000..8ffd688
--- /dev/null
+++ b/fastbootd/commands/flash.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FASTBOOTD_ERASE_H
+#define _FASTBOOTD_ERASE_H
+
+int flash_find_entry(const char *, char *, size_t);
+int flash_erase(int fd);
+
+static inline int flash_get_partiton(const char *path) {
+    return open(path, O_RDWR);
+}
+
+static inline int flash_close(int fd) {
+    return close(fd);
+}
+
+int flash_write(int partition, int data, ssize_t size, ssize_t skip);
+
+static inline ssize_t read_data_once(int fd, char *buffer, ssize_t size) {
+    ssize_t readcount = 0;
+    ssize_t len;
+
+    while ((len = TEMP_FAILURE_RETRY(read(fd, (void *) &buffer[readcount], size - readcount))) > 0) {
+        readcount -= len;
+    }
+    if (len < 0)
+        return len;
+
+    return readcount;
+}
+
+#endif
+
diff --git a/fastbootd/commands/partitions.c b/fastbootd/commands/partitions.c
new file mode 100644
index 0000000..3bfc298
--- /dev/null
+++ b/fastbootd/commands/partitions.c
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <endian.h>
+#include <zlib.h>
+#include <linux/hdreg.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <cutils/config_utils.h>
+
+#include "partitions.h"
+#include "debug.h"
+#include "utils.h"
+#include "protocol.h"
+
+#define MMAP2_SHIFT 12
+
+#define BLKRRPART  _IO(0x12,95) /* re-read partition table */
+#define BLKSSZGET  _IO(0x12,104)
+
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
+#define ALIGN_DOWN(x, y) ((y) * ((x) / (y)))
+
+
+const uint16_t partition_type_uuid[16] = {
+    0xa2, 0xa0, 0xd0, 0xeb, 0xe5, 0xb9, 0x33, 0x44,
+    0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7,
+};
+
+//TODO: If both blocks are invalid should I leave everything to vendor (through libvendor)
+
+static void GPT_entry_clear(struct GPT_entry_raw *entry)
+{
+    memset(entry, 0, sizeof(*entry));
+}
+
+extern void*  __mmap2(void *, size_t, int, int, int, off_t);
+
+static inline void *mmap64(void *addr, size_t length, int prot,
+                           int flags, int fd, uint64_t offset) {
+    return __mmap2(addr, length, prot, flags, fd, offset >> MMAP2_SHIFT);
+}
+
+/*
+ * returns mapped location to choosen area
+ * mapped_ptr is pointer to whole area mapped (it can be bigger then requested)
+ */
+int gpt_mmap(struct GPT_mapping *mapping, uint64_t location, int size, int fd)
+{
+    unsigned int location_diff = location & ~PAGE_MASK;
+
+    mapping->size = ALIGN(size + location_diff, PAGE_SIZE);
+
+    uint64_t sz = get_file_size64(fd);
+    if (sz < size + location) {
+        D(ERR, "the location of mapping area is outside of the device size %lld", sz);
+        return 1;
+    }
+
+    mapping->map_ptr = mmap64(NULL, mapping->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, location);
+
+    if (mapping->map_ptr == MAP_FAILED) {
+        mapping->ptr = MAP_FAILED;
+        D(ERR, "map failed %d", (int) mapping->map_ptr);
+        return 1;
+    }
+
+    mapping->ptr = (void *)((char *) mapping->map_ptr + location_diff);
+    return 0;
+}
+
+void gpt_unmap(struct GPT_mapping *mapping) {
+    munmap(mapping->map_ptr, mapping->size);
+}
+
+
+#define LBA_ADDR(table, value)   ((uint64_t) (table)->sector_size * (value))
+
+int GPT_map_from_content(struct GPT_entry_table *table, const struct GPT_content *content)
+{
+
+    // Mapping header
+    if (gpt_mmap(&table->header_map, LBA_ADDR(table, content->header.current_lba),
+                 table->sector_size, table->fd)) {
+        D(ERR, "unable to map header:%s\n", strerror(errno));
+        goto error_header;
+    }
+
+    table->header = (struct GPT_header *) table->header_map.ptr;
+
+    table->partition_table_size = ROUND_UP(content->header.entries_count * sizeof(*table->entries),
+                                           table->sector_size);
+
+    // Mapping entry table
+    if (gpt_mmap(&table->entries_map, LBA_ADDR(table, content->header.entries_lba),
+                 table->partition_table_size, table->fd)) {
+        D(ERR, "unable to map entries");
+        goto error_signature;
+    }
+
+    table->entries = (struct GPT_entry_raw *) table->entries_map.ptr;
+
+    // Mapping secondary header
+    if (gpt_mmap(&table->sec_header_map, LBA_ADDR(table, content->header.backup_lba),
+                 table->sector_size, table->fd)) {
+        D(ERR, "unable to map backup gpt header");
+        goto error_sec_header;
+    }
+
+    // Mapping secondary entries table
+    if (gpt_mmap(&table->sec_entries_map,
+                 LBA_ADDR(table, content->header.backup_lba) - table->partition_table_size,
+                 table->partition_table_size, table->fd)) {
+        D(ERR, "unable to map secondary gpt table");
+        goto error_sec_entries;
+    }
+
+    table->second_header = (struct GPT_header *) table->sec_header_map.ptr;
+    table->second_entries = (struct GPT_entry_raw *) table->sec_entries_map.ptr;
+    table->second_valid = strcmp("EFI PART", (char *) table->second_header->signature) == 0;
+
+    return 0;
+
+error_sec_entries:
+    gpt_unmap(&table->sec_header_map);
+error_sec_header:
+    gpt_unmap(&table->entries_map);
+error_signature:
+    gpt_unmap(&table->header_map);
+error_header:
+    return 1;
+}
+
+int GPT_map(struct GPT_entry_table *table, unsigned header_lba)
+{
+    struct GPT_content content;
+    struct GPT_mapping mapping;
+    struct GPT_header *header;
+
+    if (gpt_mmap(&mapping, LBA_ADDR(table, header_lba), table->sector_size, table->fd)) {
+        D(ERR, "unable to map header: %s", strerror(errno));
+        goto error_header;
+    }
+
+    header = (struct GPT_header *) mapping.ptr;
+
+    if (strcmp("EFI PART", (char *) header->signature)) {
+        D(ERR, "GPT entry not valid");
+        goto error_signature;
+    }
+
+    content.header = *header;
+
+    gpt_unmap(&mapping);
+
+    return GPT_map_from_content(table, &content);
+
+error_signature:
+    gpt_unmap(&table->header_map);
+error_header:
+    return 1;
+}
+
+struct GPT_entry_table* GPT_get_device(const char *path, unsigned header_lba)
+{
+    struct GPT_entry_table *table;
+    size_t sector_bytes;
+
+    table = (struct GPT_entry_table *) malloc(sizeof(*table));
+    table->fd = open(path, O_RDWR);
+
+    if (table->fd < 0) {
+        D(ERR, "unable to open file %s:%s\n", path, strerror(errno));
+        return NULL;
+    }
+
+    if (!ioctl(table->fd, BLKSSZGET, &sector_bytes)) {
+        table->sector_size = (unsigned) sector_bytes;
+        D(INFO, "Got sector size %d", table->sector_size);
+    } else {
+        D(WARN, "unable to get sector size, assuming 512");
+        table->sector_size = 512;
+    }
+
+    if (GPT_map(table, header_lba)) {
+        D(ERR, "Could not map gpt");
+        return NULL;
+    }
+
+    return table;
+}
+
+static struct GPT_entry_table* GPT_get_from_content(const char *path, const struct GPT_content *content)
+{
+    struct GPT_entry_table *table;
+    size_t sector_bytes;
+
+    table = (struct GPT_entry_table *) malloc(sizeof(*table));
+    table->fd = open(path, O_RDWR);
+
+    if (table->fd < 0) {
+        D(ERR, "unable to open file %s:%s\n", path, strerror(errno));
+        return NULL;
+    }
+
+    if (!ioctl(table->fd, BLKSSZGET, &sector_bytes)) {
+        table->sector_size = (unsigned) sector_bytes;
+        D(INFO, "Got sector size %d", table->sector_size);
+    } else {
+        D(WARN, "unable to get sector size %s, assuming 512", strerror(errno));
+        table->sector_size = 512;
+    }
+
+    if (GPT_map_from_content(table, content)) {
+        D(ERR, "Could not map gpt");
+        return NULL;
+    }
+
+    return table;
+}
+
+
+void GPT_release_device(struct GPT_entry_table *table)
+{
+    gpt_unmap(&table->header_map);
+    gpt_unmap(&table->entries_map);
+    gpt_unmap(&table->sec_header_map);
+    gpt_unmap(&table->sec_entries_map);
+    close(table->fd);
+    free(table);
+}
+
+static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
+static int GPT_check_overlap_except(struct GPT_entry_table *table,
+                                    struct GPT_entry_raw *entry,
+                                    struct GPT_entry_raw *exclude);
+
+void GPT_edit_entry(struct GPT_entry_table *table,
+                    struct GPT_entry_raw *old_entry,
+                    struct GPT_entry_raw *new_entry)
+{
+    struct GPT_entry_raw *current_entry = GPT_get_pointer(table, old_entry);
+
+    if (GPT_check_overlap_except(table, new_entry, current_entry)) {
+        D(ERR, "Couldn't add overlaping partition");
+        return;
+    }
+
+    if (current_entry == NULL) {
+        D(ERR, "Couldn't find entry");
+        return;
+    }
+
+    *current_entry = *new_entry;
+}
+
+int GPT_delete_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
+{
+    struct GPT_entry_raw *raw = GPT_get_pointer(table, entry);
+
+    if (raw == NULL) {
+        D(ERR, "could not find entry");
+        return 1;
+    }
+    D(DEBUG, "Deleting gpt entry '%s'\n", raw->partition_guid);
+
+    // This entry can be empty in the middle
+    GPT_entry_clear(raw);
+
+    return 0;
+}
+
+void GPT_add_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
+{
+    unsigned i;
+    int inserted = 0;
+    if (GPT_check_overlap(table, entry)) {
+        D(ERR, "Couldn't add overlaping partition");
+        return;
+    }
+
+    if (GPT_get_pointer(table, entry) != NULL) {
+        D(WARN, "Add entry fault, this entry already exists");
+        return;
+    }
+
+    struct GPT_entry_raw *entries = table->entries;
+
+    for (i = 0; i < table->header->entries_count; ++i) {
+        if (!entries[i].type_guid[0]) {
+            inserted = 1;
+            D(DEBUG, "inserting");
+            memcpy(&entries[i], entry, sizeof(entries[i]));
+            break;
+        }
+    }
+
+    if (!inserted) {
+        D(ERR, "Unable to find empty partion entry");
+    }
+}
+
+struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name);
+
+struct GPT_entry_raw *GPT_get_pointer(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
+{
+    if (entry->partition_guid[0] != 0)
+        return GPT_get_pointer_by_guid(table, (const char *) entry->partition_guid);
+    else if (entry->name[0] != 0)
+        return GPT_get_pointer_by_UTFname(table, entry->name);
+
+    D(WARN, "Name or guid needed to find entry");
+    return NULL;
+}
+
+struct GPT_entry_raw *GPT_get_pointer_by_guid(struct GPT_entry_table *table, const char *name)
+{
+    int current = (int) table->header->entries_count;
+
+    for (current = current - 1; current >= 0; --current) {
+        if (strncmp((char *) name,
+                    (char *) table->entries[current].partition_guid, 16) == 0) {
+                return &table->entries[current];
+        }
+    }
+
+    return NULL;
+}
+
+int strncmp_UTF16_char(const uint16_t *s1, const char *s2, size_t n)
+{
+    if (n == 0)
+        return (0);
+    do {
+        if (((*s1) & 127) != *s2++)
+            return (((unsigned char) ((*s1) & 127)) - *(unsigned char *)--s2);
+        if (*s1++ == 0)
+            break;
+    } while (--n != 0);
+    return (0);
+}
+
+int strncmp_UTF16(const uint16_t *s1, const uint16_t *s2, size_t n)
+{
+    if (n == 0)
+        return (0);
+    do {
+        if ((*s1) != *s2++)
+            return (*s1 - *--s2);
+        if (*s1++ == 0)
+            break;
+    } while (--n != 0);
+    return (0);
+}
+
+struct GPT_entry_raw *GPT_get_pointer_by_name(struct GPT_entry_table *table, const char *name)
+{
+    //TODO: reverse direction
+    int count = (int) table->header->entries_count;
+    int current;
+
+    for (current = 0; current < count; ++current) {
+        if (strncmp_UTF16_char(table->entries[current].name,
+                         (char *) name, 16) == 0) {
+                    return &table->entries[current];
+        }
+    }
+
+    return NULL;
+}
+
+struct GPT_entry_raw *GPT_get_pointer_by_UTFname(struct GPT_entry_table *table, const uint16_t *name)
+{
+    int count = (int) table->header->entries_count;
+    int current;
+
+    for (current = 0; current < count; ++current) {
+        if (strncmp_UTF16(table->entries[current].name,
+                          name, GPT_NAMELEN) == 0) {
+                return &table->entries[current];
+        }
+    }
+
+    return NULL;
+}
+
+void GPT_sync(struct GPT_entry_table *table)
+{
+    uint32_t crc;
+
+    //calculate crc32
+    crc = crc32(0, Z_NULL, 0);
+    crc = crc32(crc, (void*) table->entries, table->header->entries_count * sizeof(*table->entries));
+    table->header->partition_array_checksum = crc;
+
+    table->header->header_checksum = 0;
+    crc = crc32(0, Z_NULL, 0);
+    crc = crc32(crc, (void*) table->header, sizeof(*table->header));
+    table->header->header_checksum = crc;
+
+    //sync secondary partion
+    if (table->second_valid) {
+        memcpy((void *)table->second_entries, (void *) table->entries, table->partition_table_size);
+        memcpy((void *)table->second_header, (void *)table->header, sizeof(*table->header));
+    }
+
+    if(!ioctl(table->fd, BLKRRPART, NULL)) {
+        D(WARN, "Unable to force kernel to refresh partition table");
+    }
+}
+
+void GPT_to_UTF16(uint16_t *to, const char *from, int n)
+{
+    int i;
+    for (i = 0; i < (n - 1) && (to[i] = from[i]) != '\0'; ++i);
+    to[i] = '\0';
+}
+
+void GPT_from_UTF16(char *to, const uint16_t *from, int n)
+{
+    int i;
+    for (i = 0; i < (n - 1) && (to[i] = from[i] & 127) != '\0'; ++i);
+    to[i] = '\0';
+}
+
+static int GPT_check_overlap_except(struct GPT_entry_table *table,
+                                    struct GPT_entry_raw *entry,
+                                    struct GPT_entry_raw *exclude) {
+    int current = (int) table->header->entries_count;
+    int dontcheck;
+    struct GPT_entry_raw *current_entry;
+    if (entry->last_lba < entry->first_lba) {
+        D(WARN, "Start address have to be less than end address");
+        return 1;
+    }
+
+    for (current = current - 1; current >= 0; --current) {
+        current_entry = &table->entries[current];
+        dontcheck = strncmp((char *) entry->partition_guid,
+                           (char *) current_entry->partition_guid , 16) == 0;
+        dontcheck |= current_entry->type_guid[0] == 0;
+        dontcheck |= current_entry == exclude;
+
+        if (!dontcheck && ((entry->last_lba >= current_entry->first_lba &&
+                            entry->first_lba < current_entry->last_lba ))) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int GPT_check_overlap(struct GPT_entry_table *table, struct GPT_entry_raw *entry)
+{
+    return GPT_check_overlap_except(table, entry, NULL);
+}
+
+static char *get_key_value(char *ptr, char **key, char **value)
+{
+    *key = ptr;
+    ptr = strchr(ptr, '=');
+
+    if (ptr == NULL)
+        return NULL;
+
+    *ptr++ = '\0';
+    *value = ptr;
+    ptr = strchr(ptr, ';');
+
+    if (ptr == NULL)
+        ptr = *value + strlen(*value);
+    else
+        *ptr = '\0';
+
+    *key = strip(*key);
+    *value = strip(*value);
+
+    return ptr;
+}
+
+//TODO: little endian?
+static int add_key_value(const char *key, const char *value, struct GPT_entry_raw *entry)
+{
+    char *endptr;
+    if (!strcmp(key, "type")) {
+        strncpy((char *) entry->type_guid, value, 16);
+        entry->type_guid[15] = 0;
+    }
+    else if (!strcmp(key, "guid")) {
+        strncpy((char *) entry->partition_guid, value, 16);
+        entry->type_guid[15] = 0;
+    }
+    else if (!strcmp(key, "firstlba")) {
+        entry->first_lba = strtoul(value, &endptr, 10);
+        if (*endptr != '\0') goto error;
+    }
+    else if (!strcmp(key, "lastlba")) {
+        entry->last_lba = strtoul(value, &endptr, 10);
+        if (*endptr != '\0') goto error;
+    }
+    else if (!strcmp(key, "flags")) {
+        entry->flags = strtoul(value, &endptr, 10);
+        if (*endptr != '\0') goto error;
+    }
+    else if (!strcmp(key, "name")) {
+        GPT_to_UTF16(entry->name, value, GPT_NAMELEN);
+    }
+    else {
+        goto error;
+    }
+
+    return 0;
+
+error:
+    D(ERR, "Could not find key or parse value: %s,%s", key, value);
+    return 1;
+}
+
+int GPT_parse_entry(char *string, struct GPT_entry_raw *entry)
+{
+    char *ptr = string;
+    char *key, *value;
+
+    while ((ptr = get_key_value(ptr, &key, &value)) != NULL) {
+        if (add_key_value(key, value, entry)) {
+            D(WARN, "key or value not valid: %s %s", key, value);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static void entry_set_guid(int n, uint8_t *guid)
+{
+    guid[0] = (uint8_t) (n + 1);
+    int fd;
+    fd = open("/dev/urandom", O_RDONLY);
+    read(fd, &guid[1], 15);
+    close(fd);
+}
+
+void GPT_default_content(struct GPT_content *content, struct GPT_entry_table *table)
+{
+    if (table != NULL) {
+        memcpy(&content->header, table->header, sizeof(content->header));
+    }
+    else {
+        D(WARN, "Could not locate old gpt table, using default values");
+        memset(&content->header, 0, sizeof(content->header) / sizeof(int));
+        content->header = (struct GPT_header) {
+            .revision = 0x0100,
+            .header_size = sizeof(content->header),
+            .header_checksum = 0,
+            .reserved_zeros = 0,
+            .current_lba = 1,
+            .backup_lba = 1,
+            .entry_size = sizeof(struct GPT_entry_raw),
+            .partition_array_checksum = 0
+        };
+        strncpy((char *)content->header.signature, "EFI PART", 8);
+        entry_set_guid(0, content->header.disk_guid);
+    }
+}
+
+static int get_config_uint64(cnode *node, uint64_t *ptr, const char *name)
+{
+    const char *tmp;
+    uint64_t val;
+    char *endptr;
+    if ((tmp = config_str(node, name, NULL))) {
+        val = strtoull(tmp, &endptr, 10);
+        if (*endptr != '\0') {
+            D(WARN, "Value for %s is not a number: %s", name, tmp);
+            return 1;
+        }
+        *ptr = val;
+        return 0;
+    }
+    return 1;
+}
+
+static void GPT_parse_header(cnode *node, struct GPT_content *content)
+{
+    get_config_uint64(node, &content->header.current_lba, "header_lba");
+    get_config_uint64(node, &content->header.backup_lba, "backup_lba");
+    get_config_uint64(node, &content->header.first_usable_lba, "first_lba");
+    get_config_uint64(node, &content->header.last_usable_lba, "last_lba");
+    get_config_uint64(node, &content->header.entries_lba, "entries_lba");
+}
+
+static int GPT_parse_partitions(cnode *node, struct GPT_content *content)
+{
+    cnode *current;
+    int i;
+    uint64_t partition_size;
+    for (i = 0, current = node->first_child; current; current = current->next, ++i) {
+        entry_set_guid(i, content->entries[i].partition_guid);
+        memcpy(&content->entries[i].type_guid, partition_type_uuid, 16);
+        if (get_config_uint64(current, &content->entries[i].first_lba, "first_lba")) {
+            D(ERR, "first_lba not specified");
+            return 1;
+        }
+        if (get_config_uint64(current, &partition_size, "partition_size")) {
+            D(ERR, "partition_size not specified");
+            return 1;
+        }
+        get_config_uint64(current, &content->entries[i].flags, "flags");
+        content->entries[i].last_lba = content->entries[i].first_lba + partition_size - 1;
+        GPT_to_UTF16(content->entries[i].name, current->name, 16);
+    }
+    return 0;
+}
+
+static inline int cnode_count(cnode *node)
+{
+    int i;
+    cnode *current;
+    for (i = 0, current = node->first_child; current; current = current->next, ++i)
+        ;
+    return i;
+}
+
+
+static int GPT_parse_cnode(cnode *root, struct GPT_content *content)
+{
+    cnode *partnode;
+
+    if (!(partnode = config_find(root, "partitions"))) {
+        D(ERR, "Could not find partition table");
+        return 0;
+    }
+
+    GPT_parse_header(root, content);
+
+    content->header.entries_count = cnode_count(partnode);
+    content->entries = malloc(content->header.entries_count * sizeof(struct GPT_entry_raw));
+
+    if (GPT_parse_partitions(partnode, content)) {
+        D(ERR, "Could not parse partitions");
+        return 0;
+    }
+
+    return 1;
+}
+
+int GPT_parse_file(int fd, struct GPT_content *content)
+{
+    char *data;
+    int size;
+    int ret;
+    cnode *root = config_node("", "");
+
+    size = get_file_size(fd);
+    data = (char *) mmap(NULL, size + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+
+    if (data == NULL) {
+        if (size == 0)
+            D(ERR, "config file empty");
+        else
+            D(ERR, "Out of memory");
+        return 0;
+    }
+
+    data[size - 1] = 0;
+    config_load(root, data);
+
+    if (root->first_child == NULL) {
+        D(ERR, "Could not read config file");
+        return 0;
+    }
+
+    ret = GPT_parse_cnode(root, content);
+    munmap(data, size);
+    return ret;
+}
+
+void GPT_release_content(struct GPT_content *content)
+{
+    free(content->entries);
+}
+
+int GPT_write_content(const char *device, struct GPT_content *content)
+{
+    struct GPT_entry_table *maptable;
+
+    maptable = GPT_get_from_content(device, content);
+    if (maptable == NULL) {
+        D(ERR, "could not map device");
+        return 0;
+    }
+
+    memcpy(maptable->header, &content->header, sizeof(*maptable->header));
+    memcpy(maptable->entries, content->entries,
+           content->header.entries_count * sizeof(*maptable->entries));
+
+    //GPT_sync(maptable);
+    GPT_release_device(maptable);
+
+    return 1;
+}
+
diff --git a/fastbootd/commands/partitions.h b/fastbootd/commands/partitions.h
new file mode 100644
index 0000000..f2d590f
--- /dev/null
+++ b/fastbootd/commands/partitions.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef __FASTBOOTD_PATITIONS_
+#define __FASTBOOTD_PATITIONS_
+
+#include <stdint.h>
+
+#define GPT_ENTRIES 128
+#define GPT_NAMELEN 36
+
+// it should be passed in little endian order
+struct GPT_entry_raw {
+    uint8_t type_guid[16];
+    uint8_t partition_guid[16];
+    uint64_t first_lba; // little endian
+    uint64_t last_lba;
+    uint64_t flags;
+    uint16_t name[GPT_NAMELEN]; // UTF-16 LE
+};
+
+struct GPT_mapping {
+    void *map_ptr;
+    void *ptr;
+    unsigned size;
+};
+
+struct GPT_entry_table {
+    int fd;
+
+    struct GPT_mapping header_map;
+    struct GPT_mapping entries_map;
+    struct GPT_mapping sec_header_map;
+    struct GPT_mapping sec_entries_map;
+
+    struct GPT_header *header;
+    struct GPT_entry_raw *entries;
+    struct GPT_header *second_header;
+    struct GPT_entry_raw *second_entries;
+
+    unsigned sector_size;
+    unsigned partition_table_size;
+    int second_valid;
+};
+
+struct GPT_header {
+    uint8_t signature[8];
+    uint32_t revision;
+    uint32_t header_size;
+    uint32_t header_checksum;
+    uint32_t reserved_zeros;
+    uint64_t current_lba;
+    uint64_t backup_lba;
+    uint64_t first_usable_lba;
+    uint64_t last_usable_lba;
+    uint8_t disk_guid[16];
+    uint64_t entries_lba;
+    uint32_t entries_count;
+    uint32_t entry_size;
+    uint32_t partition_array_checksum;
+    // the rest should be filled with zeros
+} __attribute__((packed));
+
+struct GPT_content {
+    struct GPT_header header;
+    struct GPT_entry_raw *entries;
+};
+
+
+struct GPT_entry_table* GPT_get_device(const char *, unsigned lba);
+
+void GPT_release_device(struct GPT_entry_table *);
+
+void GPT_edit_entry(struct GPT_entry_table *table,
+                    struct GPT_entry_raw *old_entry,
+                    struct GPT_entry_raw *new_entry);
+
+int GPT_delete_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
+
+void GPT_add_entry(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
+
+struct GPT_entry_raw *GPT_get_pointer(struct GPT_entry_table *table, struct GPT_entry_raw *entry);
+struct GPT_entry_raw *GPT_get_pointer_by_guid(struct GPT_entry_table *, const char *);
+struct GPT_entry_raw *GPT_get_pointer_by_name(struct GPT_entry_table *, const char *);
+
+//Use after every edit operation
+void GPT_sync();
+
+void GPT_to_UTF16(uint16_t *, const char *, int );
+void GPT_from_UTF16(char *, const uint16_t *, int);
+
+int GPT_parse_entry(char *string, struct GPT_entry_raw *entry);
+
+void GPT_default_content(struct GPT_content *content, struct GPT_entry_table *table);
+
+void GPT_release_content(struct GPT_content *content);
+
+int GPT_parse_file(int fd, struct GPT_content *content);
+
+int GPT_write_content(const char *device, struct GPT_content *content);
+
+int gpt_mmap(struct GPT_mapping *mapping, uint64_t location, int size, int fd);
+
+void gpt_unmap(struct GPT_mapping *mapping);
+
+#endif
diff --git a/fastbootd/commands/virtual_partitions.c b/fastbootd/commands/virtual_partitions.c
new file mode 100644
index 0000000..813f485
--- /dev/null
+++ b/fastbootd/commands/virtual_partitions.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "commands/virtual_partitions.h"
+#include "debug.h"
+
+static struct virtual_partition *partitions = NULL;
+
+int try_handle_virtual_partition(struct protocol_handle *handle, const char *arg)
+{
+    struct virtual_partition *current;
+
+    for (current = partitions; current != NULL; current = current->next) {
+        if (!strcmp(current->name, arg)) {
+            current->handler(handle, arg);
+        }
+    }
+
+    return 0;
+}
+
+void virtual_partition_register(
+        const char * name,
+        void (*handler)(struct protocol_handle *phandle, const char *arg))
+{
+    struct virtual_partition *new;
+    new = malloc(sizeof(*new));
+    if (new) {
+        new->name = name;
+        new->handler = handler;
+        new->next = partitions;
+        partitions = new;
+    }
+    else {
+        D(ERR, "Out of memory");
+    }
+}
diff --git a/fastbootd/commands/virtual_partitions.h b/fastbootd/commands/virtual_partitions.h
new file mode 100644
index 0000000..88df71e
--- /dev/null
+++ b/fastbootd/commands/virtual_partitions.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef FASTBOOTD_VIRTUAL_PARTITIONS_H
+#define FASTBOOTD_VIRTUAL_PARTITIONS_H
+
+#include "protocol.h"
+
+struct virtual_partition {
+    struct virtual_partition *next;
+    const char *name;
+    void (*handler)(struct protocol_handle *phandle, const char *arg);
+};
+
+int try_handle_virtual_partition(struct protocol_handle *handle, const char *arg);
+
+void virtual_partition_register(
+        const char * name,
+        void (*handler)(struct protocol_handle *phandle, const char *arg));
+
+#endif
diff --git a/fastbootd/config.c b/fastbootd/config.c
index b8503fd..fe6da69 100644
--- a/fastbootd/config.c
+++ b/fastbootd/config.c
@@ -35,29 +35,13 @@
 #include <sys/types.h>
 
 #include "protocol.h"
+#include "utils.h"
 
 #include "debug.h"
 
 // TODO: change config path
 #define CONFIG_PATH "/data/fastboot.cfg"
 
-static char *strip(char *str)
-{
-    int n;
-
-    n = strspn(str, " \t");
-    str += n;
-
-    for (n = strlen(str) - 1; n >= 0; n--) {
-        if (str[n] == ' ' || str[n] == '\t')
-            str[n] = '\0';
-        else
-            break;
-    }
-
-    return str;
-}
-
 static int config_parse_line(char *line)
 {
     char *c;
diff --git a/fastbootd/fastbootd.c b/fastbootd/fastbootd.c
index 98df0db..90b9ef9 100644
--- a/fastbootd/fastbootd.c
+++ b/fastbootd/fastbootd.c
@@ -20,6 +20,7 @@
 #include <cutils/klog.h>
 
 #include "debug.h"
+#include "trigger.h"
 
 unsigned int debug_level = DEBUG;
 
@@ -36,6 +37,7 @@
     klog_set_level(6);
 
     config_init();
+    load_trigger();
     commands_init();
     usb_init();
     while (1) {
diff --git a/fastbootd/include/vendor_trigger.h b/fastbootd/include/vendor_trigger.h
new file mode 100644
index 0000000..66f65c4
--- /dev/null
+++ b/fastbootd/include/vendor_trigger.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __VENDOR_TRIGGER_H_
+#define __VENDOR_TRIGGER_H_
+
+#define TRIGGER_MODULE_ID "vendortrigger"
+#include <hardware/hardware.h>
+
+__BEGIN_DECLS
+
+struct GPT_entry_raw;
+struct GPT_content;
+
+/*
+ * Structer with function pointers may become longer in the future
+ */
+
+struct vendor_trigger_t {
+    struct hw_device_t common;
+
+    /*
+     * This function runs at the beggining and shoud never be changed
+     *
+     * version is number parameter indicating version on the fastbootd side
+     * libversion is version indicateing version of the library version
+     *
+     * returns 0 if it can cooperate with the current version and 1 in opposite
+     */
+    int (*check_version)(const int version, int *libversion);
+
+
+    /*
+     * Return value 1 forbid the action from the vendor site and sets errno
+     */
+    int (* gpt_layout)(struct GPT_content *);
+    int (* oem_cmd)(const char *arg, const char **response);
+};
+
+__END_DECLS
+
+#endif
diff --git a/fastbootd/other/gptedit.c b/fastbootd/other/gptedit.c
new file mode 100644
index 0000000..07d01cb
--- /dev/null
+++ b/fastbootd/other/gptedit.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <cutils/klog.h>
+
+#include "commands/partitions.h"
+#include "debug.h"
+
+unsigned int debug_level = DEBUG;
+//TODO: add tool to generate config file
+
+void usage() {
+    fprintf(stderr,
+            "usage: test_gpt [ <option> ] <file>\n"
+            "\n"
+            "options:\n"
+            "  -p                                       print partitions\n"
+            "  -c                                       print config file\n"
+            "  -a                                       adds new partition\n"
+            "  -d                                       deletes partition (-o needed)\n"
+            "\n"
+            "  -n name@startlba,endlba                  new partition detail\n"
+            "  -o                                       old partition name\n"
+            "  -t                                       type guid\n"
+            "  -g                                       partition guid\n"
+            "  -l gpt_location                          specyfies gpt secto\n"
+    );
+
+}
+
+void printGPT(struct GPT_entry_table *table);
+void addGPT(struct GPT_entry_table *table, const char *arg, const char *guid, const char *tguid);
+void deleteGPT(struct GPT_entry_table *table, const char *name);
+void configPrintGPT(struct GPT_entry_table *table);
+
+int main(int argc, char *argv[]) {
+    int print_cmd = 0;
+    int config_cmd = 0;
+    int add_cmd = 0;
+    int del_cmd = 0;
+    int sync_cmd = 0;
+    int c;
+    const char *new_partition = NULL;
+    const char *old_partition = NULL;
+    const char *type_guid = NULL;
+    const char *partition_guid = NULL;
+    unsigned gpt_location = 1;
+
+    klog_init();
+    klog_set_level(6);
+
+    const struct option longopts[] = {
+        {"print", no_argument, 0, 'p'},
+        {"config-print", no_argument, 0, 'c'},
+        {"add", no_argument, 0, 'a'},
+        {"del", no_argument, 0, 'd'},
+        {"new", required_argument, 0, 'n'},
+        {"old", required_argument, 0, 'o'},
+        {"type", required_argument, 0, 't'},
+        {"sync", required_argument, 0, 's'},
+        {"guid", required_argument, 0, 'g'},
+        {"location", required_argument, 0, 'l'},
+        {0, 0, 0, 0}
+    };
+
+    while (1) {
+        c = getopt_long(argc, argv, "pcadt:g:n:o:sl:", longopts, NULL);
+        /* Alphabetical cases */
+        if (c < 0)
+            break;
+        switch (c) {
+        case 'p':
+            print_cmd = 1;
+            break;
+        case 'c':
+            config_cmd = 1;
+            break;
+        case 'a':
+            add_cmd = 1;
+            break;
+        case 'd':
+            del_cmd = 1;
+            break;
+        case 'n':
+            new_partition = optarg;
+            break;
+        case 'o':
+            old_partition = optarg;
+            break;
+        case 't':
+            type_guid = optarg;
+        case 'g':
+            partition_guid = optarg;
+            break;
+        case 's':
+            sync_cmd = 1;
+            break;
+        case 'l':
+            gpt_location = strtoul(optarg, NULL, 10);
+            fprintf(stderr, "Got offset as %d", gpt_location);
+            break;
+        case '?':
+            return 1;
+        default:
+            abort();
+        }
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    if (argc < 1) {
+        usage();
+        return 1;
+    }
+
+    const char *path = argv[0];
+    struct GPT_entry_table *table = GPT_get_device(path, gpt_location);
+    if (table == NULL) {
+        fprintf(stderr, "unable to get GPT table from %s\n", path);
+        return 1;
+    }
+
+    fprintf(stderr, "entries %d, name %s\n", table->header->entries_count, (char *) table->header->signature);
+
+
+    if (add_cmd)
+        addGPT(table, new_partition, partition_guid, type_guid);
+    if (del_cmd)
+        deleteGPT(table, old_partition);
+    if (print_cmd)
+        printGPT(table);
+    if (config_cmd)
+        configPrintGPT(table);
+    if (sync_cmd)
+        GPT_sync(table);
+
+    GPT_release_device(table);
+
+    return 0;
+}
+
+void printGPT(struct GPT_entry_table *table) {
+    struct GPT_entry_raw *entry = table->entries;
+    unsigned n, m;
+    char name[GPT_NAMELEN + 1];
+
+    printf("ptn  start block   end block     name\n");
+    printf("---- ------------- -------------\n");
+
+    for (n = 0; n < table->header->entries_count; n++, entry++) {
+        if (entry->type_guid[0] == 0)
+            continue;
+        for (m = 0; m < GPT_NAMELEN; m++) {
+            name[m] = entry->name[m] & 127;
+        }
+        name[m] = 0;
+        printf("#%03d %13lld %13lld %s\n",
+            n + 1, entry->first_lba, entry->last_lba, name);
+    }
+}
+
+void configPrintGPT(struct GPT_entry_table *table) {
+    struct GPT_entry_raw *entry = table->entries;
+    unsigned n, m;
+    char name[GPT_NAMELEN + 1];
+
+    printf("header_lba %lld\n", table->header->current_lba);
+    printf("backup_lba %lld\n", table->header->backup_lba);
+    printf("first_lba %lld\n", table->header->first_usable_lba);
+    printf("last_lba %lld\n", table->header->last_usable_lba);
+    printf("entries_lba %lld\n", table->header->entries_lba);
+
+    printf("\npartitions {\n");
+
+    for (n = 0; n < table->header->entries_count; n++, entry++) {
+        uint64_t size = entry->last_lba - entry->first_lba + 1;
+
+        if (entry->type_guid[0] == 0)
+            continue;
+        for (m = 0; m < GPT_NAMELEN; m++) {
+            name[m] = entry->name[m] & 127;
+        }
+        name[m] = 0;
+
+        printf("    %s {\n", name);
+        printf("        first_lba %lld\n", entry->first_lba);
+        printf("        partition_size %lld\n", size);
+        if (entry->flags != 0)
+            printf("        flags %lld\n", entry->flags);
+        printf("    }\n\n");
+    }
+    printf("}\n");
+}
+
+void addGPT(struct GPT_entry_table *table, const char *str  , const char *guid, const char *tguid) {
+    char *c, *c2;
+    char *arg = malloc(strlen(str));
+    char *name = arg;
+    unsigned start, end;
+    strcpy(arg, str);
+    if (guid == NULL || tguid == NULL) {
+        fprintf(stderr, "Type guid and partion guid needed");
+        free(arg);
+        return;
+    }
+
+    c = strchr(arg, '@');
+
+    if (c == NULL) {
+        fprintf(stderr, "Wrong entry format");
+        free(arg);
+        return;
+    }
+
+    *c++ = '\0';
+
+    c2 = strchr(c, ',');
+
+    if (c2 == NULL) {
+        fprintf(stderr, "Wrong entry format");
+        free(arg);
+        return;
+    }
+
+    start = strtoul(c, NULL, 10);
+    *c2++ = '\0';
+    end = strtoul(c2, NULL, 10);
+
+    struct GPT_entry_raw data;
+    strncpy((char *)data.partition_guid, guid, 15);
+    data.partition_guid[15] = '\0';
+    strncpy((char *)data.type_guid, tguid, 15);
+    data.type_guid[15] = '\0';
+    GPT_to_UTF16(data.name, name, GPT_NAMELEN);
+    data.first_lba = start;
+    data.last_lba = end;
+
+    fprintf(stderr, "Adding (%d,%d) %s as, [%s, %s]", start, end, name, (char *) data.type_guid, (char *) data.partition_guid);
+    GPT_add_entry(table, &data);
+    free(arg);
+}
+
+void deleteGPT(struct GPT_entry_table *table, const char *name) {
+    struct GPT_entry_raw *entry;
+
+    if (name == NULL) {
+        fprintf(stderr, "Need partition name");
+        return;
+    }
+
+    entry = GPT_get_pointer_by_name(table, name);
+
+    if (!entry) {
+        fprintf(stderr, "Unable to find partition: %s", name);
+        return;
+    }
+    GPT_delete_entry(table, entry);
+}
+
diff --git a/fastbootd/other/partitions.sample.cfg b/fastbootd/other/partitions.sample.cfg
new file mode 100644
index 0000000..49562cf
--- /dev/null
+++ b/fastbootd/other/partitions.sample.cfg
@@ -0,0 +1,60 @@
+
+header_lba 1
+backup_lba 101
+first_lba 43
+last_lba 100
+entries_lba 2
+
+partitions {
+    #You can generate this as output from gptedit -c
+    SOS {
+        first_lba 28672
+        partition_size 16384
+    }
+
+    DTB {
+        first_lba 45056
+        partition_size 8192
+    }
+
+    LNX {
+        first_lba 53248
+        partition_size 16384
+    }
+
+    APP {
+        first_lba 69632
+        partition_size 1048576
+    }
+
+    CAC {
+        first_lba 1118208
+        partition_size 1572864
+    }
+
+    MSC {
+        first_lba 2691072
+        partition_size 4096
+    }
+
+    USP {
+        first_lba 2695168
+        partition_size 65536
+    }
+
+    MDA {
+        first_lba 2760704
+        partition_size 4096
+    }
+
+    FCT {
+        first_lba 2764800
+        partition_size 32768
+    }
+
+    UDA {
+        first_lba 2797568
+        partition_size 27975680
+    }
+}
+
diff --git a/fastbootd/other/vendor_trigger.c b/fastbootd/other/vendor_trigger.c
new file mode 100644
index 0000000..9b7562c
--- /dev/null
+++ b/fastbootd/other/vendor_trigger.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+#include "vendor_trigger.h"
+#include "debug.h"
+
+unsigned int debug_level = DEBUG;
+
+static const int version = 1;
+
+int delete_partition(struct GPT_entry_raw *);
+int add_partition(struct GPT_entry_raw *);
+int modify_partition(struct GPT_entry_raw *, struct GPT_entry_raw *);
+
+int check_version(const int fastboot_version, int *libversion) {
+    *libversion = version;
+    return !(fastboot_version == version);
+}
+
+int delete_partition(struct GPT_entry_raw *entry) {
+    D(DEBUG, "message from libvendor");
+    return 0;
+}
+
+int add_partition(struct GPT_entry_raw *entry) {
+    D(DEBUG, "message from libvendor");
+    return 0;
+}
+
+int modify_partition(struct GPT_entry_raw *oldentry, struct GPT_entry_raw *newentry) {
+    D(DEBUG, "message from libvendor");
+    return 0;
+}
+
+int gpt_layout(struct GPT_content *table) {
+    D(DEBUG, "message from libvendor");
+    return 0;
+}
+
+int oem_cmd(const char *arg, const char **response) {
+    D(DEBUG, "message from libvendor, oem catched request %s", arg);
+    return 0;
+}
+
+static int close_triggers(struct vendor_trigger_t *dev)
+{
+    if (dev)
+        free(dev);
+
+    return 0;
+}
+
+static int open_triggers(const struct hw_module_t *module, char const *name,
+                         struct hw_device_t **device) {
+    struct vendor_trigger_t *dev = malloc(sizeof(struct vendor_trigger_t));
+    klog_init();
+    klog_set_level(6);
+
+    memset(dev, 0, sizeof(*dev));
+    dev->common.module = (struct hw_module_t *) module;
+    dev->common.close  = (int (*)(struct hw_device_t *)) close_triggers;
+
+    dev->gpt_layout = gpt_layout;
+    dev->oem_cmd = oem_cmd;
+
+    *device = (struct hw_device_t *) dev;
+
+    return 0;
+}
+
+
+static struct hw_module_methods_t trigger_module_methods = {
+    .open = open_triggers,
+};
+
+struct hw_module_t HAL_MODULE_INFO_SYM = {
+    .tag = HARDWARE_MODULE_TAG,
+    .version_major = 1,
+    .version_minor = 0,
+    .id = TRIGGER_MODULE_ID,
+    .name = "vendor trigger library for fastbootd",
+    .author = "Google, Inc.",
+    .methods = &trigger_module_methods,
+};
+
diff --git a/fastbootd/trigger.c b/fastbootd/trigger.c
new file mode 100644
index 0000000..e63e64d
--- /dev/null
+++ b/fastbootd/trigger.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <dlfcn.h>
+
+#include <hardware/hardware.h>
+#include "debug.h"
+#include "trigger.h"
+#include "protocol.h"
+#include "vendor_trigger.h"
+
+static const int version = 1;
+
+static struct vendor_trigger_t *triggers = NULL;
+
+int load_trigger() {
+    int err;
+    hw_module_t* module;
+    hw_device_t* device;
+    int libversion;
+
+    err = hw_get_module(TRIGGER_MODULE_ID, (hw_module_t const**)&module);
+
+    if (err == 0) {
+        err = module->methods->open(module, NULL, &device);
+
+        if (err == 0) {
+            triggers = (struct vendor_trigger_t *) device;
+        } else {
+            D(WARN, "Libvendor load error");
+            return 1;
+        }
+    }
+    else {
+        D(WARN, "Libvendor not load: %s", strerror(-err));
+        return 0;
+    }
+
+    if (triggers->check_version != NULL &&
+        triggers->check_version(version, &libversion)) {
+
+        triggers = NULL;
+        D(ERR, "Library report incompability");
+        return 1;
+    }
+    D(INFO, "libvendortrigger loaded");
+
+    return 0;
+}
+
+int trigger_oem_cmd(const char *arg, const char **response) {
+    if (triggers != NULL && triggers->oem_cmd != NULL)
+        return triggers->oem_cmd(arg, response);
+    return 0;
+}
+
+int trigger_gpt_layout(struct GPT_content *table) {
+    if (triggers != NULL && triggers->gpt_layout != NULL)
+        return triggers->gpt_layout(table);
+    return 0;
+}
+
diff --git a/fastbootd/trigger.h b/fastbootd/trigger.h
new file mode 100644
index 0000000..404acb4
--- /dev/null
+++ b/fastbootd/trigger.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __FASTBOOTD_TRIGGER_H_
+#define __FASTBOOTD_TRIGGER_H_
+
+#include "commands/partitions.h"
+#include "vendor_trigger.h"
+
+int load_trigger();
+
+/* same as in struct triggers */
+
+int trigger_gpt_layout(struct GPT_content *table);
+int trigger_oem_cmd(const char *arg, const char **response);
+
+#endif
diff --git a/fastbootd/utils.c b/fastbootd/utils.c
new file mode 100644
index 0000000..16e1c09
--- /dev/null
+++ b/fastbootd/utils.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+
+#include "utils.h"
+#include "debug.h"
+
+#ifndef BLKDISCARD
+#define BLKDISCARD _IO(0x12,119)
+#endif
+
+#ifndef BLKSECDISCARD
+#define BLKSECDISCARD _IO(0x12,125)
+#endif
+
+
+int get_stream_size(FILE *stream) {
+    int size;
+    fseek(stream, 0, SEEK_END);
+    size = ftell(stream);
+    fseek(stream, 0, SEEK_SET);
+    return size;
+}
+
+uint64_t get_block_device_size(int fd)
+{
+    uint64_t size = 0;
+    int ret;
+
+    ret = ioctl(fd, BLKGETSIZE64, &size);
+
+    if (ret)
+        return 0;
+
+    return size;
+}
+
+uint64_t get_file_size(int fd)
+{
+    struct stat buf;
+    int ret;
+    int64_t computed_size;
+
+    ret = fstat(fd, &buf);
+    if (ret)
+        return 0;
+
+    if (S_ISREG(buf.st_mode))
+        computed_size = buf.st_size;
+    else if (S_ISBLK(buf.st_mode))
+        computed_size = get_block_device_size(fd);
+    else
+        computed_size = 0;
+
+    return computed_size;
+}
+
+uint64_t get_file_size64(int fd)
+{
+    struct stat64 buf;
+    int ret;
+    uint64_t computed_size;
+
+    ret = fstat64(fd, &buf);
+    if (ret)
+        return 0;
+
+    if (S_ISREG(buf.st_mode))
+        computed_size = buf.st_size;
+    else if (S_ISBLK(buf.st_mode))
+        computed_size = get_block_device_size(fd);
+    else
+        computed_size = 0;
+
+    return computed_size;
+}
+
+
+char *strip(char *str)
+{
+    int n;
+
+    n = strspn(str, " \t");
+    str += n;
+    n = strcspn(str, " \t");
+    str[n] = '\0';
+
+    return str;
+}
+
+int wipe_block_device(int fd, int64_t len)
+{
+    uint64_t range[2];
+    int ret;
+
+    range[0] = 0;
+    range[1] = len;
+    ret = ioctl(fd, BLKSECDISCARD, &range);
+    if (ret < 0) {
+        range[0] = 0;
+        range[1] = len;
+        ret = ioctl(fd, BLKDISCARD, &range);
+        if (ret < 0) {
+            D(WARN, "Discard failed\n");
+            return 1;
+        } else {
+            D(WARN, "Wipe via secure discard failed, used discard instead\n");
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
diff --git a/fastbootd/utils.h b/fastbootd/utils.h
new file mode 100644
index 0000000..a553a25
--- /dev/null
+++ b/fastbootd/utils.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2009-2013, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Google, Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _FASTBOOT_UTLIS_H
+#define _FASTBOOT_UTILS_H
+
+#include <stdio.h>
+
+int get_stream_size(FILE *);
+
+char *strip(char *str);
+
+uint64_t get_file_size64(int fd);
+uint64_t get_file_size(int fd);
+uint64_t get_block_device_size(int fd);
+int wipe_block_device(int fd, int64_t len);
+
+#define ROUND_TO_PAGE(address,pagesize) ((address + pagesize - 1) & (~(pagesize - 1)))
+
+#define ROUND_UP(number,size) (((number + size - 1) / size) * size)
+
+#endif