| Index: src/platform/vboot_reference/utility/cgpt/cgpt_show.c
|
| diff --git a/src/platform/vboot_reference/utility/cgpt/cgpt_show.c b/src/platform/vboot_reference/utility/cgpt/cgpt_show.c
|
| index c34e793d629f5a63d89dd130882fc0e146d8fb27..59fd46a8704597c77e92cbfe9c52d9de8007002b 100644
|
| --- a/src/platform/vboot_reference/utility/cgpt/cgpt_show.c
|
| +++ b/src/platform/vboot_reference/utility/cgpt/cgpt_show.c
|
| @@ -12,13 +12,14 @@
|
| #include "utility.h"
|
|
|
| /* Integers to store parsed argument. */
|
| -static int help, raw;
|
| +static int help, number, verbose;
|
|
|
| /* The structure for getopt_long(). When you add/delete any line, please refine
|
| * attribute_comments[] and third parameter of getopt_long() too. */
|
| static struct option show_options[] = {
|
| {.name = "help", .has_arg = no_argument, .flag = 0, .val = 'h'},
|
| - {.name = "raw", .has_arg = no_argument, .flag = 0, .val = 'r'},
|
| + {.name = "number", .has_arg = no_argument, .flag = 0, .val = 'n'},
|
| + {.name = "verbose", .has_arg = no_argument, .flag = 0, .val = 'v'},
|
| };
|
|
|
| /* Extra information than struct option, please update this structure if you
|
| @@ -29,11 +30,16 @@ static struct option_details show_options_details[] = {
|
| .validator = AssignTrue,
|
| .valid_range = 0,
|
| .parsed = &help},
|
| - /* raw */
|
| - { .comment = "print raw data (byte-by-byte)",
|
| + /* number */
|
| + { .comment = "print raw numbers (don't interpret)",
|
| .validator = AssignTrue,
|
| .valid_range = 0,
|
| - .parsed = &raw},
|
| + .parsed = &number},
|
| + /* verbose */
|
| + { .comment = "verbose print",
|
| + .validator = AssignTrue,
|
| + .valid_range = 0,
|
| + .parsed = &verbose},
|
| };
|
|
|
| void ShowHelp() {
|
| @@ -44,10 +50,12 @@ void ShowHelp() {
|
|
|
| /* Generate output like:
|
| *
|
| - * {AB-CD-EF-01}
|
| + * [AB-CD-EF-01] for group = 1
|
| + * [ABCD-EF01] for group = 3 (low byte first)
|
| *
|
| - * Needs (size*3-1+3) bytes of space in 'buf'.
|
| + * Needs (size*3-1+3) bytes of space in 'buf' (included the tailing '\0').
|
| */
|
| +#define BUFFER_SIZE(size) (size *3 - 1 + 3)
|
| static short Uint8To2Chars(const uint8_t t) {
|
| int h = t >> 4;
|
| int l = t & 0xf;
|
| @@ -55,25 +63,159 @@ static short Uint8To2Chars(const uint8_t t) {
|
| l = (l >= 0xA) ? l - 0xA + 'A' : l + '0';
|
| return (h << 8) + l;
|
| }
|
| -static void RawDump(const uint8_t *memory, const int size, char *buf) {
|
| - int i;
|
| - buf[0] = '{';
|
| +static void RawDump(const uint8_t *memory, const int size,
|
| + char *buf, int group) {
|
| + int i, outlen = 0;
|
| + buf[outlen++] = '[';
|
| for (i = 0; i < size; ++i) {
|
| short c2 = Uint8To2Chars(memory[i]);
|
| - buf[i * 3 + 1] = c2 >> 8;
|
| - buf[i * 3 + 2] = c2 & 0xff;
|
| - if (i != (size - 1))
|
| - buf[i * 3 + 3] = '-';
|
| + buf[outlen++] = c2 >> 8;
|
| + buf[outlen++] = c2 & 0xff;
|
| + if (i != (size - 1) && ((i + 1) % group) == 0)
|
| + buf[outlen++] = '-';
|
| }
|
| - buf[i * 3 + 0] = '}';
|
| - buf[i * 3 + 1] = '\0';
|
| + buf[outlen++] = ']';
|
| + buf[outlen++] = '\0';
|
| }
|
|
|
| -/* Parses all options (and validates them), then opens the drive and sets
|
| - * corresponding bits in GPT entry. */
|
| +/* Outpur formatters */
|
| +#define TITLE_FMT "%10s%10s%8s %s\n"
|
| +#define GPT_FMT "%10d%10d%8s %s\n"
|
| +#define GPT_MORE "%10s%10s%8s ", "", "", ""
|
| +#define PARTITION_FMT "%10d%10d%8d %s\n"
|
| +#define PARTITION_MORE "%10s%10s%8s %s%s\n", "", "", ""
|
| +
|
| +static void HeaderDetails(GptHeader *header, const char *indent) {
|
| + int i;
|
| +
|
| + printf("%sSig: ", indent);
|
| + if (number == NOT_INITED) {
|
| + printf("[");
|
| + for (i = 0; i < sizeof(header->signature); ++i)
|
| + printf("%c", header->signature[i]);
|
| + printf("]");
|
| + } else {
|
| + char buf[BUFFER_SIZE(sizeof(header->signature))];
|
| + RawDump((uint8_t *)header->signature, sizeof(header->signature), buf, 1);
|
| + printf("%s", buf);
|
| + }
|
| + printf("\n");
|
| +
|
| + printf("%sRev: 0x%08x\n", indent, header->revision);
|
| + printf("%sSize: %d\n", indent, header->size);
|
| + printf("%sHeader CRC: 0x%08x\n", indent, header->header_crc32);
|
| + printf("%sMy LBA: %lld\n", indent, (long long)header->my_lba);
|
| + printf("%sAlter LBA: %lld\n", indent, (long long)header->alternate_lba);
|
| + printf("%sFirst LBA: %lld\n", indent, (long long)header->first_usable_lba);
|
| + printf("%sLast LBA: %lld\n", indent, (long long)header->last_usable_lba);
|
| +
|
| + { /* For disk guid */
|
| + char buf[GUID_STRLEN];
|
| + GuidToStr(&header->disk_uuid, buf);
|
| + printf("%sDisk UUID: %s\n", indent, buf);
|
| + }
|
| +
|
| + printf("%sEntries LBA: %lld\n", indent, (long long)header->entries_lba);
|
| + printf("%sNumber of entries: %d\n", indent, header->number_of_entries);
|
| + printf("%sSize of entry: %d\n", indent, header->size_of_entry);
|
| + printf("%sEntries CRC: 0x%08x\n", indent, header->entries_crc32);
|
| +}
|
| +
|
| +/* Resolves human-readable GPT type.
|
| + * Returns CGPT_OK if found.
|
| + * Returns CGPT_FAILED if no known type found. */
|
| +int ResolveType(const Guid *type, char *buf) {
|
| + struct {
|
| + Guid type;
|
| + char *description;
|
| + } known[] = {
|
| + {GPT_ENT_TYPE_UNUSED, "Unused partition"},
|
| + {GPT_ENT_TYPE_EFI, "EFI partition"},
|
| + {GPT_ENT_TYPE_CHROMEOS_KERNEL, "ChromeOS kernel"},
|
| + {GPT_ENT_TYPE_CHROMEOS_ROOTFS, "ChromeOS rootfs"},
|
| + {GPT_ENT_TYPE_CHROMEOS_RESERVED, "ChromeOS reserved"},
|
| + };
|
| + int i;
|
| +
|
| + for (i = 0; i < ARRAY_COUNT(known); ++i) {
|
| + if (!Memcmp(type, &known[i].type, sizeof(Guid))) {
|
| + strcpy(buf, known[i].description);
|
| + return CGPT_OK;
|
| + }
|
| + }
|
| + return CGPT_FAILED;
|
| +}
|
| +
|
| +void EntriesDetails(GptData *gpt, const int secondary) {
|
| + int i;
|
| +
|
| + for (i = 0; i < GetNumberOfEntries(gpt); ++i) {
|
| + static Guid unused = GPT_ENT_TYPE_UNUSED;
|
| + char contents[256];
|
| +
|
| + GptEntry *entry;
|
| + entry = GetEntry(gpt, secondary, i);
|
| +
|
| + if (!Memcmp(&unused, &entry->type, sizeof(unused))) continue;
|
| +
|
| + if (number == NOT_INITED) {
|
| + uint8_t label[sizeof(entry->name) * 3 / 2];
|
| + char type[GUID_STRLEN], unique[GUID_STRLEN];;
|
| +
|
| + UTF16ToUTF8(entry->name, label);
|
| + snprintf(contents, sizeof(contents), "Label: \"%s\"", label);
|
| + printf(PARTITION_FMT, (int)entry->starting_lba,
|
| + (int)(entry->ending_lba - entry->starting_lba + 1),
|
| + i, contents);
|
| + if (CGPT_OK == ResolveType(&entry->type, type)) {
|
| + printf(PARTITION_MORE, "Type: ", type);
|
| + } else {
|
| + GuidToStr(&entry->type, type);
|
| + printf(PARTITION_MORE, "Type: ", type);
|
| + }
|
| + GuidToStr(&entry->unique, unique);
|
| + printf(PARTITION_MORE, "UUID: ", unique);
|
| + } else {
|
| + char label[BUFFER_SIZE(sizeof(entry->name))];
|
| + char type[GUID_STRLEN], unique[GUID_STRLEN],
|
| + attributes[BUFFER_SIZE(sizeof(uint64_t))];
|
| +
|
| + RawDump((void*)entry->name, sizeof(entry->name), label, 2);
|
| + snprintf(contents, sizeof(contents), "Label: %s", label);
|
| + printf(PARTITION_FMT, (int)entry->starting_lba,
|
| + (int)(entry->ending_lba - entry->starting_lba + 1),
|
| + i, contents);
|
| + GuidToStr(&entry->type, type);
|
| + printf(PARTITION_MORE, "Type: ", type);
|
| + GuidToStr(&entry->unique, unique);
|
| + printf(PARTITION_MORE, "UUID: ", unique);
|
| + RawDump((uint8_t*)&entry->attributes, 8, attributes, 4);
|
| + printf(PARTITION_MORE, "Attr: ", attributes);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/* Parses all options (and validates them), then opens the drive.
|
| + * Show GPT information in following order:
|
| + *
|
| + * Primary header sector
|
| + * details (if -v applied)
|
| + *
|
| + * Primary table sectors
|
| + *
|
| + * 1st partition
|
| + * details (if -v applied)
|
| + * :
|
| + * last partition
|
| + * details (if -v applied)
|
| + *
|
| + * Secondary table sectors
|
| + *
|
| + * Secondary header sector
|
| + * details (if -v applied)
|
| + */
|
| int CgptShow(int argc, char *argv[]) {
|
| struct drive drive;
|
| - int i;
|
|
|
| /* I know this is NOT the perfect place to put code to make options[] and
|
| * details[] are synced. But this is the best place we have right now since C
|
| @@ -81,10 +223,10 @@ int CgptShow(int argc, char *argv[]) {
|
| assert(ARRAY_COUNT(show_options) ==
|
| ARRAY_COUNT(show_options_details));
|
|
|
| - help = raw = NOT_INITED;
|
| + help = number = NOT_INITED;
|
|
|
| if (CGPT_OK != HandleOptions(argc, argv,
|
| - "hr",
|
| + "hnv",
|
| ARRAY_COUNT(show_options),
|
| show_options,
|
| show_options_details))
|
| @@ -97,56 +239,74 @@ int CgptShow(int argc, char *argv[]) {
|
| if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
|
| return CGPT_FAILED;
|
|
|
| - #define TITLE_FMT "%7s%7s%7s %s\n"
|
| - #define GPT_FMT "%7d%7d%7s %s\n"
|
| - #define GPT_MORE "%7s%7s%7s %s\n", "", "", ""
|
| - #define PARTITION_FMT "%7d%7d%7d %s\n"
|
| - #define PARTITION_MORE "%7s%7s%7s %s%s\n", "", "", ""
|
| printf(TITLE_FMT, "start", "size", "index", "contents");
|
| printf(GPT_FMT, 0, GPT_PMBR_SECTOR, "", "PMBR");
|
| - printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
|
| - (int)GPT_HEADER_SECTOR, "", "Pri GPT header");
|
| - printf(GPT_FMT, (int)(GPT_PMBR_SECTOR + GPT_HEADER_SECTOR),
|
| - (int)GPT_ENTRIES_SECTORS, "", "Pri GPT table");
|
| -
|
| - for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
|
| - static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
|
| - char contents[128];
|
| - GptEntry *entry;
|
| - entry = GetEntry(&drive.gpt, PRIMARY, i);
|
|
|
| - if (!Memcmp(&zero, &entry->type, sizeof(zero))) continue;
|
| + if (drive.gpt.valid_headers & MASK_PRIMARY) {
|
| + printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
|
| + (int)GPT_HEADER_SECTOR, "", "Pri GPT header");
|
| + if (verbose) {
|
| + GptHeader *header;
|
| + char indent[64];
|
|
|
| - if (raw == NOT_INITED) {
|
| - /* TODO(yjlou): support pretty dump */
|
| - snprintf(contents, sizeof(contents),
|
| - "* Not supported yet *");
|
| - printf(PARTITION_FMT, (int)entry->starting_lba,
|
| - (int)(entry->ending_lba - entry->starting_lba + 1),
|
| - i, contents);
|
| - } else {
|
| - char type[50], unique[50], attributes[26];
|
| -
|
| - snprintf(contents, sizeof(contents),
|
| - "%s", "");
|
| - printf(PARTITION_FMT, (int)entry->starting_lba,
|
| - (int)(entry->ending_lba - entry->starting_lba + 1),
|
| - i, contents);
|
| - RawDump((uint8_t*)&entry->type, 16, type);
|
| - printf(PARTITION_MORE, "type: ", type);
|
| - RawDump((uint8_t*)&entry->unique, 16, unique);
|
| - printf(PARTITION_MORE, "uuid: ", unique);
|
| - RawDump((uint8_t*)&entry->attributes, 8, attributes);
|
| - printf(PARTITION_MORE, "attr: ", attributes);
|
| + snprintf(indent, sizeof(indent), GPT_MORE);
|
| + header = (GptHeader*)drive.gpt.primary_header;
|
| + HeaderDetails(header, indent);
|
| }
|
| + } else {
|
| + printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
|
| + (int)GPT_HEADER_SECTOR, "INVALID", "Pri GPT header");
|
| }
|
|
|
| + printf(GPT_FMT, (int)(GPT_PMBR_SECTOR + GPT_HEADER_SECTOR),
|
| + (int)GPT_ENTRIES_SECTORS,
|
| + drive.gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID",
|
| + "Pri GPT table");
|
| +
|
| + if (drive.gpt.valid_entries & MASK_PRIMARY)
|
| + EntriesDetails(&drive.gpt, PRIMARY);
|
| +
|
| printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR -
|
| GPT_ENTRIES_SECTORS),
|
| - (int)GPT_ENTRIES_SECTORS, "", "Sec GPT table");
|
| - printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR),
|
| - (int)GPT_HEADER_SECTOR, "", "Sec GPT header");
|
| + (int)GPT_ENTRIES_SECTORS,
|
| + drive.gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID",
|
| + "Sec GPT table");
|
| + /* We show secondary table details if any of following is true.
|
| + * 1. only secondary is valid.
|
| + * 2. secondary is not identical to promary.
|
| + */
|
| + if ((drive.gpt.valid_entries & MASK_SECONDARY) &&
|
| + (!(drive.gpt.valid_entries & MASK_PRIMARY) ||
|
| + Memcmp(drive.gpt.primary_entries, drive.gpt.secondary_entries,
|
| + TOTAL_ENTRIES_SIZE))) {
|
| + EntriesDetails(&drive.gpt, SECONDARY);
|
| + }
|
| +
|
| + if (drive.gpt.valid_headers & MASK_SECONDARY)
|
| + printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR),
|
| + (int)GPT_HEADER_SECTOR, "", "Sec GPT header");
|
| + else
|
| + printf(GPT_FMT, (int)GPT_PMBR_SECTOR,
|
| + (int)GPT_HEADER_SECTOR, "INVALID", "Sec GPT header");
|
| + /* We show secondary header if any of following is true:
|
| + * 1. only secondary is valid.
|
| + * 2. secondary is not synonymous to primary.
|
| + */
|
| + if ((drive.gpt.valid_headers & MASK_SECONDARY) &&
|
| + (!(drive.gpt.valid_headers & MASK_PRIMARY) ||
|
| + !IsSynonymous((GptHeader*)drive.gpt.primary_header,
|
| + (GptHeader*)drive.gpt.secondary_header))) {
|
| + if (verbose) {
|
| + GptHeader *header;
|
| + char indent[64];
|
| +
|
| + snprintf(indent, sizeof(indent), GPT_MORE);
|
| + header = (GptHeader*)drive.gpt.secondary_header;
|
| + HeaderDetails(header, indent);
|
| + }
|
| + }
|
|
|
| + CheckValid(&drive);
|
| DriveClose(&drive);
|
|
|
| return CGPT_OK;
|
|
|