blob: b7348aa08b2d6fff218b2bb9f892b9d27a5283fb [file] [log] [blame]
/* 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.
*
* Show GPT details.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include "cgpt.h"
#include "cgptlib_internal.h"
#include "cgpt_tofix.h"
#include "utility.h"
/* Integers to store parsed argument. */
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 = "number", .has_arg = no_argument, .flag = 0, .val = 'n'},
{.name = "verbose", .has_arg = no_argument, .flag = 0, .val = 'v'},
{ /* last element, which should be zero. */ }
};
/* Extra information than struct option, please update this structure if you
* add/remove any line in attribute_options[]. */
static struct option_details show_options_details[] = {
/* help */
{ .comment = "print this help",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &help},
/* number */
{ .comment = "print raw numbers (don't interpret)",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &number},
/* verbose */
{ .comment = "verbose print",
.validator = AssignTrue,
.valid_range = 0,
.parsed = &verbose},
{ /* last element, which should be zero. */ }
};
void ShowHelp() {
printf("\nUsage: %s show [OPTIONS] device_name\n\n", progname);
ShowOptions(show_options, show_options_details, ARRAY_COUNT(show_options));
printf("\n");
}
/* 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';
}
/* 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("%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 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;
/* 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
* preprocessor doesn't know sizeof() for #if directive. */
assert(ARRAY_COUNT(show_options) ==
ARRAY_COUNT(show_options_details));
help = number = NOT_INITED;
if (CGPT_OK != HandleOptions(argc, argv,
"hnv",
ARRAY_COUNT(show_options),
show_options,
show_options_details))
return CGPT_FAILED;
if (help != NOT_INITED) {
ShowHelp();
return CGPT_FAILED;
}
if (CGPT_OK != OpenDriveInLastArgument(argc, argv, &drive))
return CGPT_FAILED;
printf(TITLE_FMT, "start", "size", "index", "contents");
printf(GPT_FMT, 0, GPT_PMBR_SECTOR, "", "PMBR");
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);
}
} 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,
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;
}