| Index: cgpt/cmd_show.c
|
| diff --git a/cgpt/cmd_show.c b/cgpt/cmd_show.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9f52cb1d4b100b32b140474463fcc65c4338cae8
|
| --- /dev/null
|
| +++ b/cgpt/cmd_show.c
|
| @@ -0,0 +1,413 @@
|
| +// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "cgpt.h"
|
| +
|
| +#define __STDC_FORMAT_MACROS
|
| +#include <getopt.h>
|
| +#include <inttypes.h>
|
| +#include <stdio.h>
|
| +#include <stdlib.h>
|
| +#include <string.h>
|
| +
|
| +#include "cgptlib_internal.h"
|
| +
|
| +static void Usage(void)
|
| +{
|
| + printf("\nUsage: %s show [OPTIONS] DRIVE\n\n"
|
| + "Display the GPT table\n\n"
|
| + "Options:\n"
|
| + " -n Numeric output only\n"
|
| + " -v Verbose output\n"
|
| + " -q Quick output\n"
|
| + " -i NUM Show specified partition only - pick one of:\n"
|
| + " -b beginning sector\n"
|
| + " -s partition size\n"
|
| + " -t type guid\n"
|
| + " -u unique guid\n"
|
| + " -l label\n"
|
| + " -S Successful flag\n"
|
| + " -T Tries flag\n"
|
| + " -P Priority flag\n"
|
| + " -A raw 64-bit attribute value\n"
|
| + "\n", progname);
|
| +}
|
| +
|
| +
|
| +/* Generate output like:
|
| + *
|
| + * [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' (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;
|
| + h = (h >= 0xA) ? h - 0xA + 'A' : h + '0';
|
| + 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 group) {
|
| + int i, outlen = 0;
|
| + buf[outlen++] = '[';
|
| + for (i = 0; i < size; ++i) {
|
| + short c2 = Uint8To2Chars(memory[i]);
|
| + buf[outlen++] = c2 >> 8;
|
| + buf[outlen++] = c2 & 0xff;
|
| + if (i != (size - 1) && ((i + 1) % group) == 0)
|
| + buf[outlen++] = '-';
|
| + }
|
| + buf[outlen++] = ']';
|
| + buf[outlen++] = '\0';
|
| +}
|
| +
|
| +/* Output 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 raw) {
|
| + int i;
|
| +
|
| + printf("%sSig: ", indent);
|
| + if (!raw) {
|
| + 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("%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);
|
| +}
|
| +
|
| +void EntryDetails(GptEntry *entry, int index, int raw) {
|
| + char contents[256];
|
| + uint8_t label[sizeof(entry->name) * 3 / 2];
|
| +
|
| + if (!raw) {
|
| + 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),
|
| + index+1, 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);
|
| + if (!memcmp(&guid_chromeos_kernel, &entry->type, sizeof(Guid))) {
|
| + int tries = (entry->attributes & CGPT_ATTRIBUTE_TRIES_MASK) >>
|
| + CGPT_ATTRIBUTE_TRIES_OFFSET;
|
| + int successful = (entry->attributes & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
|
| + CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
|
| + int priority = (entry->attributes & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
|
| + CGPT_ATTRIBUTE_PRIORITY_OFFSET;
|
| + snprintf(contents, sizeof(contents),
|
| + "priority=%d tries=%d successful=%d",
|
| + priority, tries, successful);
|
| + printf(PARTITION_MORE, "Attr: ", contents);
|
| + }
|
| + } else {
|
| + 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),
|
| + index+1, contents);
|
| + GuidToStr(&entry->type, type);
|
| + printf(PARTITION_MORE, "Type: ", type);
|
| + GuidToStr(&entry->unique, unique);
|
| + printf(PARTITION_MORE, "UUID: ", unique);
|
| + snprintf(contents, sizeof(contents), "[%" PRIx64 "]", entry->attributes);
|
| + printf(PARTITION_MORE, "Attr: ", contents);
|
| + }
|
| +}
|
| +
|
| +
|
| +void EntriesDetails(GptData *gpt, const int secondary, int raw) {
|
| + int i;
|
| +
|
| + for (i = 0; i < GetNumberOfEntries(gpt); ++i) {
|
| + GptEntry *entry;
|
| + entry = GetEntry(gpt, secondary, i);
|
| +
|
| + if (!memcmp(&guid_unused, &entry->type, sizeof(Guid))) continue;
|
| +
|
| + EntryDetails(entry, i, raw);
|
| + }
|
| +}
|
| +
|
| +int cmd_show(int argc, char *argv[]) {
|
| + struct drive drive;
|
| + int numeric = 0;
|
| + int verbose = 0;
|
| + int quick = 0;
|
| + int partition = 0;
|
| + int single_item = 0;
|
| + int gpt_retval;
|
| +
|
| + int c;
|
| + int errorcnt = 0;
|
| + char *e = 0;
|
| +
|
| + opterr = 0; // quiet, you
|
| + while ((c=getopt(argc, argv, ":hnvqi:bstulSTPA")) != -1)
|
| + {
|
| + switch (c)
|
| + {
|
| + case 'n':
|
| + numeric = 1;
|
| + break;
|
| + case 'v':
|
| + verbose = 1;
|
| + break;
|
| + case 'q':
|
| + quick = 1;
|
| + break;
|
| + case 'i':
|
| + partition = (uint32_t)strtoul(optarg, &e, 0);
|
| + if (!*optarg || (e && *e))
|
| + {
|
| + Error("invalid argument to -%c: \"%s\"\n", c, optarg);
|
| + errorcnt++;
|
| + }
|
| + break;
|
| + case 'b':
|
| + case 's':
|
| + case 't':
|
| + case 'u':
|
| + case 'l':
|
| + case 'S':
|
| + case 'T':
|
| + case 'P':
|
| + case 'A':
|
| + single_item = c;
|
| + break;
|
| +
|
| + case 'h':
|
| + Usage();
|
| + return CGPT_OK;
|
| + case '?':
|
| + Error("unrecognized option: -%c\n", optopt);
|
| + errorcnt++;
|
| + break;
|
| + case ':':
|
| + Error("missing argument to -%c\n", optopt);
|
| + errorcnt++;
|
| + break;
|
| + default:
|
| + errorcnt++;
|
| + break;
|
| + }
|
| + }
|
| + if (errorcnt)
|
| + {
|
| + Usage();
|
| + return CGPT_FAILED;
|
| + }
|
| +
|
| + if (optind >= argc) {
|
| + Error("missing drive argument\n");
|
| + Usage();
|
| + return CGPT_FAILED;
|
| + }
|
| +
|
| + if (CGPT_OK != DriveOpen(argv[optind], &drive))
|
| + return CGPT_FAILED;
|
| +
|
| + if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive.gpt))) {
|
| + Error("GptSanityCheck() returned %d: %s\n",
|
| + gpt_retval, GptError(gpt_retval));
|
| + return CGPT_FAILED;
|
| + }
|
| +
|
| + if (partition) { // show single partition
|
| +
|
| + if (partition > GetNumberOfEntries(&drive.gpt)) {
|
| + Error("invalid partition number: %d\n", partition);
|
| + return CGPT_FAILED;
|
| + }
|
| +
|
| + int index = partition - 1;
|
| + GptEntry *entry = GetEntry(&drive.gpt, PRIMARY, index);
|
| + char buf[256];
|
| +
|
| + if (single_item) {
|
| + switch(single_item) {
|
| + case 'b':
|
| + printf("%" PRId64 "\n", entry->starting_lba);
|
| + break;
|
| + case 's':
|
| + printf("%" PRId64 "\n", entry->ending_lba - entry->starting_lba + 1);
|
| + break;
|
| + case 't':
|
| + GuidToStr(&entry->type, buf);
|
| + printf("%s\n", buf);
|
| + break;
|
| + case 'u':
|
| + GuidToStr(&entry->unique, buf);
|
| + printf("%s\n", buf);
|
| + break;
|
| + case 'l':
|
| + UTF16ToUTF8(entry->name, (uint8_t *)buf);
|
| + printf("%s\n", buf);
|
| + break;
|
| + case 'S':
|
| + printf("%d\n", GetSuccessful(&drive.gpt, PRIMARY, index));
|
| + break;
|
| + case 'T':
|
| + printf("%d\n", GetTries(&drive.gpt, PRIMARY, index));
|
| + break;
|
| + case 'P':
|
| + printf("%d\n", GetPriority(&drive.gpt, PRIMARY, index));
|
| + break;
|
| + case 'A':
|
| + printf("0x%" PRIx64 "\n", entry->attributes);
|
| + break;
|
| + }
|
| + } else {
|
| + printf(TITLE_FMT, "start", "size", "part", "contents");
|
| + EntryDetails(entry, index, numeric);
|
| + }
|
| +
|
| + } else if (quick) { // show all partitions, quickly
|
| + int i;
|
| + GptEntry *entry;
|
| + char type[GUID_STRLEN];
|
| +
|
| + for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) {
|
| + entry = GetEntry(&drive.gpt, PRIMARY, i);
|
| +
|
| + if (IsZero(&entry->type))
|
| + continue;
|
| +
|
| + if (!numeric && CGPT_OK == ResolveType(&entry->type, type)) {
|
| + } else {
|
| + GuidToStr(&entry->type, type);
|
| + }
|
| + printf(PARTITION_FMT, (int)entry->starting_lba,
|
| + (int)(entry->ending_lba - entry->starting_lba + 1),
|
| + i+1, type);
|
| + }
|
| +
|
| + } else { // show all partitions
|
| +
|
| + if (CGPT_OK != ReadPMBR(&drive)) {
|
| + Error("Unable to read PMBR\n");
|
| + return CGPT_FAILED;
|
| + }
|
| +
|
| + printf(TITLE_FMT, "start", "size", "part", "contents");
|
| + char buf[256];
|
| + PMBRToStr(&drive.pmbr, buf);
|
| + printf(GPT_FMT, 0, GPT_PMBR_SECTOR, "", buf);
|
| +
|
| + 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];
|
| +
|
| + snprintf(indent, sizeof(indent), GPT_MORE);
|
| + header = (GptHeader*)drive.gpt.primary_header;
|
| + HeaderDetails(header, indent, numeric);
|
| + }
|
| + } 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, numeric);
|
| +
|
| + printf(GPT_FMT, (int)(drive.gpt.drive_sectors - GPT_HEADER_SECTOR -
|
| + GPT_ENTRIES_SECTORS),
|
| + (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, numeric);
|
| + }
|
| +
|
| + 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, numeric);
|
| + }
|
| + }
|
| + }
|
| +
|
| + (void) CheckValid(&drive);
|
| + (void) DriveClose(&drive, 0);
|
| +
|
| + return CGPT_OK;
|
| +}
|
| +
|
| +
|
| +
|
|
|