gptedit.c revision b88fa3292d70f3a1e1512628f12cce87731ce160
1/*
2 * Copyright (c) 2009-2013, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *  * Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 *  * Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in
12 *    the documentation and/or other materials provided with the
13 *    distribution.
14 *  * Neither the name of Google, Inc. nor the names of its contributors
15 *    may be used to endorse or promote products derived from this
16 *    software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <getopt.h>
35#include <unistd.h>
36
37#include <cutils/klog.h>
38
39#include "commands/partitions.h"
40#include "debug.h"
41
42unsigned int debug_level = DEBUG;
43//TODO: add tool to generate config file
44
45void usage() {
46    fprintf(stderr,
47            "usage: test_gpt [ <option> ] <file>\n"
48            "\n"
49            "options:\n"
50            "  -p                                       print partitions\n"
51            "  -c                                       print config file\n"
52            "  -a                                       adds new partition\n"
53            "  -d                                       deletes partition (-o needed)\n"
54            "\n"
55            "  -n name@startlba,endlba                  new partition detail\n"
56            "  -o                                       old partition name\n"
57            "  -t                                       type guid\n"
58            "  -g                                       partition guid\n"
59            "  -l gpt_location                          specyfies gpt secto\n"
60    );
61
62}
63
64void printGPT(struct GPT_entry_table *table);
65void addGPT(struct GPT_entry_table *table, const char *arg, const char *guid, const char *tguid);
66void deleteGPT(struct GPT_entry_table *table, const char *name);
67void configPrintGPT(struct GPT_entry_table *table);
68
69int main(int argc, char *argv[]) {
70    int print_cmd = 0;
71    int config_cmd = 0;
72    int add_cmd = 0;
73    int del_cmd = 0;
74    int sync_cmd = 0;
75    int c;
76    const char *new_partition = NULL;
77    const char *old_partition = NULL;
78    const char *type_guid = NULL;
79    const char *partition_guid = NULL;
80    unsigned gpt_location = 1;
81
82    klog_init();
83    klog_set_level(6);
84
85    const struct option longopts[] = {
86        {"print", no_argument, 0, 'p'},
87        {"config-print", no_argument, 0, 'c'},
88        {"add", no_argument, 0, 'a'},
89        {"del", no_argument, 0, 'd'},
90        {"new", required_argument, 0, 'n'},
91        {"old", required_argument, 0, 'o'},
92        {"type", required_argument, 0, 't'},
93        {"sync", required_argument, 0, 's'},
94        {"guid", required_argument, 0, 'g'},
95        {"location", required_argument, 0, 'l'},
96        {0, 0, 0, 0}
97    };
98
99    while (1) {
100        c = getopt_long(argc, argv, "pcadt:g:n:o:sl:", longopts, NULL);
101        /* Alphabetical cases */
102        if (c < 0)
103            break;
104        switch (c) {
105        case 'p':
106            print_cmd = 1;
107            break;
108        case 'c':
109            config_cmd = 1;
110            break;
111        case 'a':
112            add_cmd = 1;
113            break;
114        case 'd':
115            del_cmd = 1;
116            break;
117        case 'n':
118            new_partition = optarg;
119            break;
120        case 'o':
121            old_partition = optarg;
122            break;
123        case 't':
124            type_guid = optarg;
125        case 'g':
126            partition_guid = optarg;
127            break;
128        case 's':
129            sync_cmd = 1;
130            break;
131        case 'l':
132            gpt_location = strtoul(optarg, NULL, 10);
133            fprintf(stderr, "Got offset as %d", gpt_location);
134            break;
135        case '?':
136            return 1;
137        default:
138            abort();
139        }
140    }
141
142    argc -= optind;
143    argv += optind;
144
145    if (argc < 1) {
146        usage();
147        return 1;
148    }
149
150    const char *path = argv[0];
151    struct GPT_entry_table *table = GPT_get_device(path, gpt_location);
152    if (table == NULL) {
153        fprintf(stderr, "unable to get GPT table from %s\n", path);
154        return 1;
155    }
156
157    fprintf(stderr, "entries %d, name %s\n", table->header->entries_count, (char *) table->header->signature);
158
159
160    if (add_cmd)
161        addGPT(table, new_partition, partition_guid, type_guid);
162    if (del_cmd)
163        deleteGPT(table, old_partition);
164    if (print_cmd)
165        printGPT(table);
166    if (config_cmd)
167        configPrintGPT(table);
168    if (sync_cmd)
169        GPT_sync(table);
170
171    GPT_release_device(table);
172
173    return 0;
174}
175
176void printGPT(struct GPT_entry_table *table) {
177    struct GPT_entry_raw *entry = table->entries;
178    unsigned n, m;
179    char name[GPT_NAMELEN + 1];
180
181    printf("ptn  start block   end block     name\n");
182    printf("---- ------------- -------------\n");
183
184    for (n = 0; n < table->header->entries_count; n++, entry++) {
185        if (entry->type_guid[0] == 0)
186            continue;
187        for (m = 0; m < GPT_NAMELEN; m++) {
188            name[m] = entry->name[m] & 127;
189        }
190        name[m] = 0;
191        printf("#%03d %13lld %13lld %s\n",
192            n + 1, entry->first_lba, entry->last_lba, name);
193    }
194}
195
196void configPrintGPT(struct GPT_entry_table *table) {
197    struct GPT_entry_raw *entry = table->entries;
198    unsigned n, m;
199    char name[GPT_NAMELEN + 1];
200    char temp_guid[17];
201    temp_guid[16] = 0;
202
203    printf("header_lba %lld\n", table->header->current_lba);
204    printf("backup_lba %lld\n", table->header->backup_lba);
205    printf("first_lba %lld\n", table->header->first_usable_lba);
206    printf("last_lba %lld\n", table->header->last_usable_lba);
207    printf("entries_lba %lld\n", table->header->entries_lba);
208    snprintf(temp_guid, 17, "%s", table->header->disk_guid);
209    printf("guid \"%s\"", temp_guid);
210
211    printf("\npartitions {\n");
212
213    for (n = 0; n < table->header->entries_count; n++, entry++) {
214        uint64_t size = entry->last_lba - entry->first_lba + 1;
215
216        if (entry->type_guid[0] == 0)
217            continue;
218        for (m = 0; m < GPT_NAMELEN; m++) {
219            name[m] = entry->name[m] & 127;
220        }
221        name[m] = 0;
222
223        printf("    %s {\n", name);
224        snprintf(temp_guid, 17, "%s", entry->partition_guid);
225        printf("        guid \"%s\"\n", temp_guid);
226        printf("        first_lba %lld\n", entry->first_lba);
227        printf("        partition_size %lld\n", size);
228        if (entry->flags & GPT_FLAG_SYSTEM)
229            printf("        system\n");
230        if (entry->flags & GPT_FLAG_BOOTABLE)
231            printf("        bootable\n");
232        if (entry->flags & GPT_FLAG_READONLY)
233            printf("        readonly\n");
234        if (entry->flags & GPT_FLAG_DOAUTOMOUNT)
235            printf("        automount\n");
236        printf("    }\n\n");
237    }
238    printf("}\n");
239}
240
241void addGPT(struct GPT_entry_table *table, const char *str  , const char *guid, const char *tguid) {
242    char *c, *c2;
243    char *arg = malloc(strlen(str));
244    char *name = arg;
245    unsigned start, end;
246    strcpy(arg, str);
247    if (guid == NULL || tguid == NULL) {
248        fprintf(stderr, "Type guid and partion guid needed");
249        free(arg);
250        return;
251    }
252
253    c = strchr(arg, '@');
254
255    if (c == NULL) {
256        fprintf(stderr, "Wrong entry format");
257        free(arg);
258        return;
259    }
260
261    *c++ = '\0';
262
263    c2 = strchr(c, ',');
264
265    if (c2 == NULL) {
266        fprintf(stderr, "Wrong entry format");
267        free(arg);
268        return;
269    }
270
271    start = strtoul(c, NULL, 10);
272    *c2++ = '\0';
273    end = strtoul(c2, NULL, 10);
274
275    struct GPT_entry_raw data;
276    strncpy((char *)data.partition_guid, guid, 15);
277    data.partition_guid[15] = '\0';
278    strncpy((char *)data.type_guid, tguid, 15);
279    data.type_guid[15] = '\0';
280    GPT_to_UTF16(data.name, name, GPT_NAMELEN);
281    data.first_lba = start;
282    data.last_lba = end;
283
284    fprintf(stderr, "Adding (%d,%d) %s as, [%s, %s]", start, end, name, (char *) data.type_guid, (char *) data.partition_guid);
285    GPT_add_entry(table, &data);
286    free(arg);
287}
288
289void deleteGPT(struct GPT_entry_table *table, const char *name) {
290    struct GPT_entry_raw *entry;
291
292    if (name == NULL) {
293        fprintf(stderr, "Need partition name");
294        return;
295    }
296
297    entry = GPT_get_pointer_by_name(table, name);
298
299    if (!entry) {
300        fprintf(stderr, "Unable to find partition: %s", name);
301        return;
302    }
303    GPT_delete_entry(table, entry);
304}
305
306