Home | History | Annotate | Download | only in cgpt
      1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #define __STDC_FORMAT_MACROS
      6 
      7 #include <string.h>
      8 
      9 #include "cgpt.h"
     10 #include "cgptlib_internal.h"
     11 #include "crc32.h"
     12 #include "vboot_host.h"
     13 
     14 /* Generate output like:
     15  *
     16  *  [AB-CD-EF-01]   for group = 1
     17  *  [ABCD-EF01]     for group = 3  (low byte first)
     18  *
     19  * Needs (size*3-1+3) bytes of space in 'buf' (included the tailing '\0').
     20  */
     21 #define BUFFER_SIZE(size) (size *3 - 1 + 3)
     22 static short Uint8To2Chars(const uint8_t t) {
     23   int h = t >> 4;
     24   int l = t & 0xf;
     25   h = (h >= 0xA) ? h - 0xA + 'A' : h + '0';
     26   l = (l >= 0xA) ? l - 0xA + 'A' : l + '0';
     27   return (h << 8) + l;
     28 }
     29 
     30 static void RawDump(const uint8_t *memory, const int size,
     31                     char *buf, int group) {
     32   int i, outlen = 0;
     33   buf[outlen++] = '[';
     34   for (i = 0; i < size; ++i) {
     35     short c2 = Uint8To2Chars(memory[i]);
     36     buf[outlen++] = c2 >> 8;
     37     buf[outlen++] = c2 & 0xff;
     38     if (i != (size - 1) && ((i + 1) % group) == 0)
     39       buf[outlen++] = '-';
     40   }
     41   buf[outlen++] = ']';
     42   buf[outlen++] = '\0';
     43 }
     44 
     45 /* Output formatters */
     46 #define TITLE_FMT      "%12s%12s%8s  %s\n"
     47 #define GPT_FMT        "%12d%12d%8s  %s\n"
     48 #define GPT_MORE       "%12s%12s%8s  ", "", "", ""
     49 #define PARTITION_FMT  "%12d%12d%8d  %s\n"
     50 #define PARTITION_MORE "%12s%12s%8s  %s%s\n", "", "", ""
     51 
     52 void PrintSignature(const char *indent, const char *sig, size_t n, int raw) {
     53   size_t i;
     54   printf("%sSig: ", indent);
     55   if (!raw) {
     56     printf("[");
     57     for (i = 0; i < n; ++i)
     58       printf("%c", sig[i]);
     59     printf("]");
     60   } else {
     61     char *buf = malloc(BUFFER_SIZE(n));
     62     RawDump((uint8_t *)sig, n, buf, 1);
     63     printf("%s", buf);
     64     free(buf);
     65   }
     66   printf("\n");
     67 }
     68 
     69 static void HeaderDetails(GptHeader *header, GptEntry *entries,
     70                           const char *indent, int raw) {
     71   PrintSignature(indent, header->signature, sizeof(header->signature), raw);
     72 
     73   printf("%sRev: 0x%08x\n", indent, header->revision);
     74   printf("%sSize: %d\n", indent, header->size);
     75   printf("%sHeader CRC: 0x%08x %s\n", indent, header->header_crc32,
     76          (HeaderCrc(header) != header->header_crc32) ? "(INVALID)" : "");
     77   printf("%sMy LBA: %lld\n", indent, (long long)header->my_lba);
     78   printf("%sAlternate LBA: %lld\n", indent, (long long)header->alternate_lba);
     79   printf("%sFirst LBA: %lld\n", indent, (long long)header->first_usable_lba);
     80   printf("%sLast LBA: %lld\n", indent, (long long)header->last_usable_lba);
     81 
     82   {  /* For disk guid */
     83     char buf[GUID_STRLEN];
     84     GuidToStr(&header->disk_uuid, buf, GUID_STRLEN);
     85     printf("%sDisk UUID: %s\n", indent, buf);
     86   }
     87 
     88   printf("%sEntries LBA: %lld\n", indent, (long long)header->entries_lba);
     89   printf("%sNumber of entries: %d\n", indent, header->number_of_entries);
     90   printf("%sSize of entry: %d\n", indent, header->size_of_entry);
     91   printf("%sEntries CRC: 0x%08x %s\n", indent, header->entries_crc32,
     92          header->entries_crc32 !=
     93              Crc32((const uint8_t *)entries,header->size_of_entry *
     94                                             header->number_of_entries)
     95              ? "INVALID" : ""
     96          );
     97 }
     98 
     99 void EntryDetails(GptEntry *entry, uint32_t index, int raw) {
    100   char contents[256];                   // scratch buffer for formatting output
    101   uint8_t label[GPT_PARTNAME_LEN];
    102   char type[GUID_STRLEN], unique[GUID_STRLEN];
    103 
    104   UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
    105               label, sizeof(label));
    106   require(snprintf(contents, sizeof(contents),
    107                    "Label: \"%s\"", label) < sizeof(contents));
    108   printf(PARTITION_FMT, (int)entry->starting_lba,
    109          (int)(entry->ending_lba - entry->starting_lba + 1),
    110          index+1, contents);
    111 
    112   if (!raw && CGPT_OK == ResolveType(&entry->type, type)) {
    113     printf(PARTITION_MORE, "Type: ", type);
    114   } else {
    115     GuidToStr(&entry->type, type, GUID_STRLEN);
    116     printf(PARTITION_MORE, "Type: ", type);
    117   }
    118   GuidToStr(&entry->unique, unique, GUID_STRLEN);
    119   printf(PARTITION_MORE, "UUID: ", unique);
    120 
    121   if (!raw) {
    122     if (GuidEqual(&guid_chromeos_kernel, &entry->type)) {
    123       int tries = (entry->attrs.fields.gpt_att &
    124                    CGPT_ATTRIBUTE_TRIES_MASK) >>
    125           CGPT_ATTRIBUTE_TRIES_OFFSET;
    126       int successful = (entry->attrs.fields.gpt_att &
    127                         CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
    128           CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
    129       int priority = (entry->attrs.fields.gpt_att &
    130                       CGPT_ATTRIBUTE_PRIORITY_MASK) >>
    131           CGPT_ATTRIBUTE_PRIORITY_OFFSET;
    132       require(snprintf(contents, sizeof(contents),
    133                        "priority=%d tries=%d successful=%d",
    134                        priority, tries, successful) < sizeof(contents));
    135       printf(PARTITION_MORE, "Attr: ", contents);
    136     }
    137   } else {
    138     require(snprintf(contents, sizeof(contents),
    139                      "[%x]", entry->attrs.fields.gpt_att) < sizeof(contents));
    140     printf(PARTITION_MORE, "Attr: ", contents);
    141   }
    142 }
    143 
    144 void EntriesDetails(struct drive *drive, const int secondary, int raw) {
    145   uint32_t i;
    146 
    147   for (i = 0; i < GetNumberOfEntries(drive); ++i) {
    148     GptEntry *entry;
    149     entry = GetEntry(&drive->gpt, secondary, i);
    150 
    151     if (GuidIsZero(&entry->type))
    152       continue;
    153 
    154     EntryDetails(entry, i, raw);
    155   }
    156 }
    157 
    158 static int GptShow(struct drive *drive, CgptShowParams *params) {
    159   int gpt_retval;
    160   if (GPT_SUCCESS != (gpt_retval = GptSanityCheck(&drive->gpt))) {
    161     Error("GptSanityCheck() returned %d: %s\n",
    162           gpt_retval, GptError(gpt_retval));
    163     return CGPT_FAILED;
    164   }
    165 
    166   if (params->partition) {                      // show single partition
    167 
    168     if (params->partition > GetNumberOfEntries(drive)) {
    169       Error("invalid partition number: %d\n", params->partition);
    170       return CGPT_FAILED;
    171     }
    172 
    173     uint32_t index = params->partition - 1;
    174     GptEntry *entry = GetEntry(&drive->gpt, ANY_VALID, index);
    175     char buf[256];                      // scratch buffer for string conversion
    176 
    177     if (params->single_item) {
    178       switch(params->single_item) {
    179       case 'b':
    180         printf("%" PRId64 "\n", entry->starting_lba);
    181         break;
    182       case 's': {
    183         uint64_t size = 0;
    184         // If these aren't actually defined, don't show anything
    185         if (entry->ending_lba || entry->starting_lba)
    186           size = entry->ending_lba - entry->starting_lba + 1;
    187         printf("%" PRId64 "\n", size);
    188         break;
    189       }
    190       case 't':
    191         GuidToStr(&entry->type, buf, sizeof(buf));
    192         printf("%s\n", buf);
    193         break;
    194       case 'u':
    195         GuidToStr(&entry->unique, buf, sizeof(buf));
    196         printf("%s\n", buf);
    197         break;
    198       case 'l':
    199         UTF16ToUTF8(entry->name, sizeof(entry->name) / sizeof(entry->name[0]),
    200                     (uint8_t *)buf, sizeof(buf));
    201         printf("%s\n", buf);
    202         break;
    203       case 'S':
    204         printf("%d\n", GetSuccessful(drive, ANY_VALID, index));
    205         break;
    206       case 'T':
    207         printf("%d\n", GetTries(drive, ANY_VALID, index));
    208         break;
    209       case 'P':
    210         printf("%d\n", GetPriority(drive, ANY_VALID, index));
    211         break;
    212       case 'A':
    213         printf("0x%x\n", entry->attrs.fields.gpt_att);
    214         break;
    215       }
    216     } else {
    217       printf(TITLE_FMT, "start", "size", "part", "contents");
    218       EntryDetails(entry, index, params->numeric);
    219     }
    220 
    221   } else if (params->quick) {                   // show all partitions, quickly
    222     uint32_t i;
    223     GptEntry *entry;
    224     char type[GUID_STRLEN];
    225 
    226     for (i = 0; i < GetNumberOfEntries(drive); ++i) {
    227       entry = GetEntry(&drive->gpt, ANY_VALID, i);
    228 
    229       if (GuidIsZero(&entry->type))
    230         continue;
    231 
    232       if (!params->numeric && CGPT_OK == ResolveType(&entry->type, type)) {
    233       } else {
    234         GuidToStr(&entry->type, type, GUID_STRLEN);
    235       }
    236       printf(PARTITION_FMT, (int)entry->starting_lba,
    237              (int)(entry->ending_lba - entry->starting_lba + 1),
    238              i+1, type);
    239     }
    240   } else {                              // show all partitions
    241     GptEntry *entries;
    242 
    243     if (CGPT_OK != ReadPMBR(drive)) {
    244       Error("Unable to read PMBR\n");
    245       return CGPT_FAILED;
    246     }
    247 
    248     printf(TITLE_FMT, "start", "size", "part", "contents");
    249     char buf[256];                      // buffer for formatted PMBR content
    250     PMBRToStr(&drive->pmbr, buf, sizeof(buf)); // will exit if buf is too small
    251     printf(GPT_FMT, 0, GPT_PMBR_SECTORS, "", buf);
    252 
    253     if (drive->gpt.valid_headers & MASK_PRIMARY) {
    254       printf(GPT_FMT, (int)GPT_PMBR_SECTORS,
    255              (int)GPT_HEADER_SECTORS, "", "Pri GPT header");
    256     } else {
    257       printf(GPT_FMT, (int)GPT_PMBR_SECTORS,
    258              (int)GPT_HEADER_SECTORS, "INVALID", "Pri GPT header");
    259     }
    260 
    261     if (params->debug ||
    262         ((drive->gpt.valid_headers & MASK_PRIMARY) && params->verbose)) {
    263       GptHeader *header;
    264       char indent[64];
    265 
    266       require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
    267       header = (GptHeader*)drive->gpt.primary_header;
    268       entries = (GptEntry*)drive->gpt.primary_entries;
    269       HeaderDetails(header, entries, indent, params->numeric);
    270     }
    271 
    272     GptHeader* primary_header = (GptHeader*)drive->gpt.primary_header;
    273     printf(GPT_FMT, (int)primary_header->entries_lba,
    274            (int)CalculateEntriesSectors(primary_header),
    275            drive->gpt.valid_entries & MASK_PRIMARY ? "" : "INVALID",
    276            "Pri GPT table");
    277 
    278     if (params->debug ||
    279         (drive->gpt.valid_entries & MASK_PRIMARY))
    280       EntriesDetails(drive, PRIMARY, params->numeric);
    281 
    282     /****************************** Secondary *************************/
    283     GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header;
    284     printf(GPT_FMT, (int)secondary_header->entries_lba,
    285            (int)CalculateEntriesSectors(secondary_header),
    286            drive->gpt.valid_entries & MASK_SECONDARY ? "" : "INVALID",
    287            "Sec GPT table");
    288     /* We show secondary table details if any of following is true.
    289      *   1. in debug mode.
    290      *   2. only secondary is valid.
    291      *   3. secondary is not identical to promary.
    292      */
    293     if (params->debug ||
    294         ((drive->gpt.valid_entries & MASK_SECONDARY) &&
    295          (!(drive->gpt.valid_entries & MASK_PRIMARY) ||
    296           memcmp(drive->gpt.primary_entries, drive->gpt.secondary_entries,
    297                  secondary_header->number_of_entries *
    298                  secondary_header->size_of_entry)))) {
    299       EntriesDetails(drive, SECONDARY, params->numeric);
    300     }
    301 
    302     if (drive->gpt.valid_headers & MASK_SECONDARY)
    303       printf(GPT_FMT, (int)(drive->gpt.gpt_drive_sectors - GPT_HEADER_SECTORS),
    304              (int)GPT_HEADER_SECTORS, "", "Sec GPT header");
    305     else
    306       printf(GPT_FMT, (int)GPT_PMBR_SECTORS,
    307              (int)GPT_HEADER_SECTORS, "INVALID", "Sec GPT header");
    308     /* We show secondary header if any of following is true:
    309      *   1. in debug mode.
    310      *   2. only secondary is valid.
    311      *   3. secondary is not synonymous to primary.
    312      */
    313     if (params->debug ||
    314         ((drive->gpt.valid_headers & MASK_SECONDARY) &&
    315          (!(drive->gpt.valid_headers & MASK_PRIMARY) ||
    316           !IsSynonymous((GptHeader*)drive->gpt.primary_header,
    317                         (GptHeader*)drive->gpt.secondary_header)) &&
    318          params->verbose)) {
    319       GptHeader *header;
    320       char indent[64];
    321 
    322       require(snprintf(indent, sizeof(indent), GPT_MORE) < sizeof(indent));
    323       header = (GptHeader*)drive->gpt.secondary_header;
    324       entries = (GptEntry*)drive->gpt.secondary_entries;
    325       HeaderDetails(header, entries, indent, params->numeric);
    326     }
    327   }
    328 
    329   CheckValid(drive);
    330 
    331   return CGPT_OK;
    332 }
    333 
    334 int CgptShow(CgptShowParams *params) {
    335   struct drive drive;
    336 
    337   if (params == NULL)
    338     return CGPT_FAILED;
    339 
    340   if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDONLY,
    341                            params->drive_size))
    342     return CGPT_FAILED;
    343 
    344   if (GptShow(&drive, params))
    345     return CGPT_FAILED;
    346 
    347   DriveClose(&drive, 0);
    348   return CGPT_OK;
    349 }
    350