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; |
+} |
+ |
+ |
+ |