304 lines
9.2 KiB
C
304 lines
9.2 KiB
C
/*
|
|
* 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 <getopt.h>
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.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;
|
|
}
|
|
|
|
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 %13"PRId64" %13"PRId64" %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];
|
|
char temp_guid[17];
|
|
temp_guid[16] = 0;
|
|
|
|
printf("header_lba %"PRId64"\n", table->header->current_lba);
|
|
printf("backup_lba %"PRId64"\n", table->header->backup_lba);
|
|
printf("first_lba %"PRId64"\n", table->header->first_usable_lba);
|
|
printf("last_lba %"PRId64"\n", table->header->last_usable_lba);
|
|
printf("entries_lba %"PRId64"\n", table->header->entries_lba);
|
|
snprintf(temp_guid, 17, "%s", table->header->disk_guid);
|
|
printf("guid \"%s\"", temp_guid);
|
|
|
|
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);
|
|
snprintf(temp_guid, 17, "%s", entry->partition_guid);
|
|
printf(" guid \"%s\"\n", temp_guid);
|
|
printf(" first_lba %"PRId64"\n", entry->first_lba);
|
|
printf(" partition_size %"PRId64"\n", size);
|
|
if (entry->flags & GPT_FLAG_SYSTEM)
|
|
printf(" system\n");
|
|
if (entry->flags & GPT_FLAG_BOOTABLE)
|
|
printf(" bootable\n");
|
|
if (entry->flags & GPT_FLAG_READONLY)
|
|
printf(" readonly\n");
|
|
if (entry->flags & GPT_FLAG_DOAUTOMOUNT)
|
|
printf(" automount\n");
|
|
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);
|
|
}
|
|
|