fastbootd: erase, boot and partitioning commands

Change-Id: I49ba2ba2e002fd5b6bbd37cc3fd0caa106f42010
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);
+}
+