busybox/util-linux/fdisk_gpt.c
<<
>>
Prefs
   1#if ENABLE_FEATURE_GPT_LABEL
   2/*
   3 * Copyright (C) 2010 Kevin Cernekee <cernekee@gmail.com>
   4 *
   5 * Licensed under GPLv2, see file LICENSE in this source tree.
   6 */
   7
   8#define GPT_MAGIC 0x5452415020494645ULL
   9enum {
  10        LEGACY_GPT_TYPE = 0xee,
  11        GPT_MAX_PARTS   = 256,
  12        GPT_MAX_PART_ENTRY_LEN = 4096,
  13        GUID_LEN        = 16,
  14};
  15
  16typedef struct {
  17        uint64_t magic;
  18        uint32_t revision;
  19        uint32_t hdr_size;
  20        uint32_t hdr_crc32;
  21        uint32_t reserved;
  22        uint64_t current_lba;
  23        uint64_t backup_lba;
  24        uint64_t first_usable_lba;
  25        uint64_t last_usable_lba;
  26        uint8_t  disk_guid[GUID_LEN];
  27        uint64_t first_part_lba;
  28        uint32_t n_parts;
  29        uint32_t part_entry_len;
  30        uint32_t part_array_crc32;
  31} gpt_header;
  32
  33typedef struct {
  34        uint8_t  type_guid[GUID_LEN];
  35        uint8_t  part_guid[GUID_LEN];
  36        uint64_t lba_start;
  37        uint64_t lba_end;
  38        uint64_t flags;
  39        uint16_t name36[36];
  40} gpt_partition;
  41
  42static gpt_header *gpt_hdr;
  43
  44static char *part_array;
  45static unsigned int n_parts;
  46static unsigned int part_entry_len;
  47
  48static inline gpt_partition *
  49gpt_part(int i)
  50{
  51        if (i >= n_parts) {
  52                return NULL;
  53        }
  54        return (gpt_partition *)&part_array[i * part_entry_len];
  55}
  56
  57static uint32_t
  58gpt_crc32(void *buf, int len)
  59{
  60        return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table);
  61}
  62
  63static void
  64gpt_print_guid(uint8_t *buf)
  65{
  66        printf(
  67                "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  68                buf[3], buf[2], buf[1], buf[0],
  69                buf[5], buf[4],
  70                buf[7], buf[6],
  71                buf[8], buf[9],
  72                buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
  73}
  74
  75static void
  76gpt_print_wide36(uint16_t *s)
  77{
  78#if ENABLE_UNICODE_SUPPORT
  79        char buf[37 * 4];
  80        wchar_t wc[37];
  81        int i = 0;
  82        while (i < ARRAY_SIZE(wc)-1) {
  83                if (s[i] == 0)
  84                        break;
  85                wc[i] = s[i];
  86                i++;
  87        }
  88        wc[i] = 0;
  89        if (wcstombs(buf, wc, sizeof(buf)) <= sizeof(buf)-1)
  90                fputs(printable_string(buf), stdout);
  91#else
  92        char buf[37];
  93        int i = 0;
  94        while (i < ARRAY_SIZE(buf)-1) {
  95                if (s[i] == 0)
  96                        break;
  97                buf[i] = (0x20 <= s[i] && s[i] < 0x7f) ? s[i] : '?';
  98                i++;
  99        }
 100        buf[i] = '\0';
 101        fputs(buf, stdout);
 102#endif
 103}
 104
 105static void
 106gpt_list_table(int xtra UNUSED_PARAM)
 107{
 108        int i;
 109        char numstr6[6];
 110
 111        smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY")[0] = '\0';
 112        printf("Disk %s: %llu sectors, %s\n", disk_device,
 113                (unsigned long long)total_number_of_sectors,
 114                numstr6);
 115        printf("Logical sector size: %u\n", sector_size);
 116        printf("Disk identifier (GUID): ");
 117        gpt_print_guid(gpt_hdr->disk_guid);
 118        printf("\nPartition table holds up to %u entries\n",
 119                (int)SWAP_LE32(gpt_hdr->n_parts));
 120        printf("First usable sector is %llu, last usable sector is %llu\n\n",
 121                (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba),
 122                (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba));
 123
 124/* "GPT fdisk" has a concept of 16-bit extension of the original MBR 8-bit type codes,
 125 * which it displays here: its output columns are ... Size Code Name
 126 * They are their own invention and are not stored on disk.
 127 * Looks like they use them to support "hybrid" GPT: for example, they have
 128 *   AddType(0x8307, "69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", "Linux ARM32 root (/)");
 129 * and then (code>>8) matches what you need to put into MBR's type field for such a partition.
 130 * To print those codes, we'd need a GUID lookup table. Lets just drop the "Code" column instead:
 131 */
 132        puts("Number  Start (sector)    End (sector)  Size Name");
 133        //    123456 123456789012345 123456789012345 12345 abc
 134        for (i = 0; i < n_parts; i++) {
 135                gpt_partition *p = gpt_part(i);
 136                if (p->lba_start) {
 137                        smart_ulltoa5((1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start)) * sector_size,
 138                                numstr6, " KMGTPEZY")[0] = '\0';
 139                        printf("%6u %15llu %15llu %s ",
 140                                i + 1,
 141                                (unsigned long long)SWAP_LE64(p->lba_start),
 142                                (unsigned long long)SWAP_LE64(p->lba_end),
 143                                numstr6
 144                        );
 145                        gpt_print_wide36(p->name36);
 146                        bb_putchar('\n');
 147                }
 148        }
 149}
 150
 151static int
 152check_gpt_label(void)
 153{
 154        unsigned part_array_len;
 155        struct partition *first = pt_offset(MBRbuffer, 0);
 156        struct pte pe;
 157        uint32_t crc;
 158
 159        /* LBA 0 contains the legacy MBR */
 160
 161        if (!valid_part_table_flag(MBRbuffer)
 162         || first->sys_ind != LEGACY_GPT_TYPE
 163        ) {
 164                current_label_type = 0;
 165                return 0;
 166        }
 167
 168        /* LBA 1 contains the GPT header */
 169
 170        read_pte(&pe, 1);
 171        gpt_hdr = (void *)pe.sectorbuffer;
 172
 173        if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) {
 174                current_label_type = 0;
 175                return 0;
 176        }
 177
 178        init_unicode();
 179        if (!global_crc32_table) {
 180                global_crc32_new_table_le();
 181        }
 182
 183        crc = SWAP_LE32(gpt_hdr->hdr_crc32);
 184        gpt_hdr->hdr_crc32 = 0;
 185        if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) {
 186                /* FIXME: read the backup table */
 187                puts("\nwarning: GPT header CRC is invalid\n");
 188        }
 189
 190        n_parts = SWAP_LE32(gpt_hdr->n_parts);
 191        part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len);
 192        if (n_parts > GPT_MAX_PARTS
 193         || part_entry_len > GPT_MAX_PART_ENTRY_LEN
 194         || SWAP_LE32(gpt_hdr->hdr_size) > sector_size
 195        ) {
 196                puts("\nwarning: unable to parse GPT disklabel\n");
 197                current_label_type = 0;
 198                return 0;
 199        }
 200
 201        part_array_len = n_parts * part_entry_len;
 202        part_array = xmalloc(part_array_len);
 203        seek_sector(SWAP_LE64(gpt_hdr->first_part_lba));
 204        if (full_read(dev_fd, part_array, part_array_len) != part_array_len) {
 205                fdisk_fatal(unable_to_read);
 206        }
 207
 208        if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) {
 209                /* FIXME: read the backup table */
 210                puts("\nwarning: GPT array CRC is invalid\n");
 211        }
 212
 213        puts("Found valid GPT with protective MBR; using GPT\n");
 214
 215        current_label_type = LABEL_GPT;
 216        return 1;
 217}
 218
 219#endif /* GPT_LABEL */
 220