diff options
Diffstat (limited to 'cgpt/cgpt_show.c')
-rw-r--r-- | cgpt/cgpt_show.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/cgpt/cgpt_show.c b/cgpt/cgpt_show.c new file mode 100644 index 00000000..068895cb --- /dev/null +++ b/cgpt/cgpt_show.c @@ -0,0 +1,346 @@ +// Copyright (c) 2012 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 <string.h> + +#include "cgptlib_internal.h" +#include "cgpt_params.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("%sAlternate 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, GUID_STRLEN); + 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, uint32_t index, int raw) { + char contents[256]; // scratch buffer for formatting output + uint8_t label[GPT_PARTNAME_LEN]; + + if (!raw) { + char type[GUID_STRLEN], unique[GUID_STRLEN]; + + UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]), + label, sizeof(label)); + require(snprintf(contents, sizeof(contents), + "Label: \"%s\"", label) < sizeof(contents)); + 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, GUID_STRLEN); + printf(PARTITION_MORE, "Type: ", type); + } + GuidToStr(&entry->unique, unique, GUID_STRLEN); + printf(PARTITION_MORE, "UUID: ", unique); + if (GuidEqual(&guid_chromeos_kernel, &entry->type)) { + int tries = (entry->attrs.fields.gpt_att & + CGPT_ATTRIBUTE_TRIES_MASK) >> + CGPT_ATTRIBUTE_TRIES_OFFSET; + int successful = (entry->attrs.fields.gpt_att & + CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> + CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; + int priority = (entry->attrs.fields.gpt_att & + CGPT_ATTRIBUTE_PRIORITY_MASK) >> + CGPT_ATTRIBUTE_PRIORITY_OFFSET; + require(snprintf(contents, sizeof(contents), + "priority=%d tries=%d successful=%d", + priority, tries, successful) < sizeof(contents)); + printf(PARTITION_MORE, "Attr: ", contents); + } + } else { + char type[GUID_STRLEN], unique[GUID_STRLEN]; + + UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]), + label, sizeof(label)); + require(snprintf(contents, sizeof(contents), + "Label: \"%s\"", label) < sizeof(contents)); + printf(PARTITION_FMT, (int)entry->starting_lba, + (int)(entry->ending_lba - entry->starting_lba + 1), + index+1, contents); + GuidToStr(&entry->type, type, GUID_STRLEN); + printf(PARTITION_MORE, "Type: ", type); + GuidToStr(&entry->unique, unique, GUID_STRLEN); + printf(PARTITION_MORE, "UUID: ", unique); + require(snprintf(contents, sizeof(contents), + "[%x]", entry->attrs.fields.gpt_att) < sizeof(contents)); + printf(PARTITION_MORE, "Attr: ", contents); + } +} + + +void EntriesDetails(GptData *gpt, const int secondary, int raw) { + uint32_t i; + + for (i = 0; i < GetNumberOfEntries(gpt); ++i) { + GptEntry *entry; + entry = GetEntry(gpt, secondary, i); + + if (IsZero(&entry->type)) + continue; + + EntryDetails(entry, i, raw); + } +} + +int cgpt_show(CgptShowParams *params) { + struct drive drive; + int gpt_retval; + + if (params == NULL) + return CGPT_FAILED; + + if (CGPT_OK != DriveOpen(params->driveName, &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 (params->partition) { // show single partition + + if (params->partition > GetNumberOfEntries(&drive.gpt)) { + Error("invalid partition number: %d\n", params->partition); + return CGPT_FAILED; + } + + uint32_t index = params->partition - 1; + GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, index); + char buf[256]; // scratch buffer for string conversion + + if (params->single_item) { + switch(params->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, sizeof(buf)); + printf("%s\n", buf); + break; + case 'u': + GuidToStr(&entry->unique, buf, sizeof(buf)); + printf("%s\n", buf); + break; + case 'l': + UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]), + (uint8_t *)buf, sizeof(buf)); + printf("%s\n", buf); + break; + case 'S': + printf("%d\n", GetSuccessful(&drive.gpt, ANY_VALID, index)); + break; + case 'T': + printf("%d\n", GetTries(&drive.gpt, ANY_VALID, index)); + break; + case 'P': + printf("%d\n", GetPriority(&drive.gpt, ANY_VALID, index)); + break; + case 'A': + printf("0x%x\n", entry->attrs.fields.gpt_att); + break; + } + } else { + printf(TITLE_FMT, "start", "size", "part", "contents"); + EntryDetails(entry, index, params->numeric); + } + + } else if (params->quick) { // show all partitions, quickly + uint32_t i; + GptEntry *entry; + char type[GUID_STRLEN]; + + for (i = 0; i < GetNumberOfEntries(&drive.gpt); ++i) { + entry = GetEntry(&drive.gpt, ANY_VALID, i); + + if (IsZero(&entry->type)) + continue; + + if (!params->numeric && CGPT_OK == ResolveType(&entry->type, type)) { + } else { + GuidToStr(&entry->type, type, GUID_STRLEN); + } + 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]; // buffer for formatted PMBR content + PMBRToStr(&drive.pmbr, buf, sizeof(buf)); // will exit if buf is too small + 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 (params->verbose) { + GptHeader *header; + char indent[64]; + + require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent)); + header = (GptHeader*)drive.gpt.primary_header; + HeaderDetails(header, indent, params->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, params->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, params->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 (params->verbose) { + GptHeader *header; + char indent[64]; + + require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent)); + header = (GptHeader*)drive.gpt.secondary_header; + HeaderDetails(header, indent, params->numeric); + } + } + } + + (void) CheckValid(&drive); + (void) DriveClose(&drive, 0); + + return CGPT_OK; +} |