summaryrefslogtreecommitdiff
path: root/cgpt/cmd_show.c
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2010-06-11 09:15:55 -0700
committerBill Richardson <wfrichar@chromium.org>2010-06-11 09:15:55 -0700
commitf1372d9109d638fbb1a177a89ebaf64e7ee0637e (patch)
tree243cdacbc1028e6a987d582d33927560af0b47e0 /cgpt/cmd_show.c
parent6a97b3e2a1bee35bf3c00f2fb0faafde4aaab9e2 (diff)
downloadvboot-f1372d9109d638fbb1a177a89ebaf64e7ee0637e.tar.gz
Nearly complete rewrite of cgpt tool.
This fixes a number of bugs, adds a bunch of commands, and essentially makes cgpt ready to use as a replacement for gpt. Still to do is to add commands and options that will let it generated intentionally bad partitions, for use in testing. Review URL: http://codereview.chromium.org/2719008
Diffstat (limited to 'cgpt/cmd_show.c')
-rw-r--r--cgpt/cmd_show.c413
1 files changed, 413 insertions, 0 deletions
diff --git a/cgpt/cmd_show.c b/cgpt/cmd_show.c
new file mode 100644
index 00000000..9f52cb1d
--- /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;
+}
+
+
+