#if ENABLE_FEATURE_GPT_LABEL /* * Copyright (C) 2010 Kevin Cernekee * * Licensed under GPLv2, see file LICENSE in this source tree. */ #define GPT_MAGIC 0x5452415020494645ULL enum { LEGACY_GPT_TYPE = 0xee, GPT_MAX_PARTS = 256, GPT_MAX_PART_ENTRY_LEN = 4096, GUID_LEN = 16, }; typedef struct { uint64_t magic; uint32_t revision; uint32_t hdr_size; uint32_t hdr_crc32; uint32_t reserved; uint64_t current_lba; uint64_t backup_lba; uint64_t first_usable_lba; uint64_t last_usable_lba; uint8_t disk_guid[GUID_LEN]; uint64_t first_part_lba; uint32_t n_parts; uint32_t part_entry_len; uint32_t part_array_crc32; } gpt_header; typedef struct { uint8_t type_guid[GUID_LEN]; uint8_t part_guid[GUID_LEN]; uint64_t lba_start; uint64_t lba_end; uint64_t flags; uint16_t name36[36]; } gpt_partition; static gpt_header *gpt_hdr; static char *part_array; static unsigned int n_parts; static unsigned int part_entry_len; static inline gpt_partition * gpt_part(int i) { if (i >= n_parts) { return NULL; } return (gpt_partition *)&part_array[i * part_entry_len]; } static uint32_t gpt_crc32(void *buf, int len) { return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table); } static void gpt_print_guid(uint8_t *buf) { printf( "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", buf[3], buf[2], buf[1], buf[0], buf[5], buf[4], buf[7], buf[6], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); } static void gpt_print_wide36(uint16_t *s) { #if ENABLE_UNICODE_SUPPORT char buf[37 * 4]; wchar_t wc[37]; int i = 0; while (i < ARRAY_SIZE(wc)-1) { if (s[i] == 0) break; wc[i] = s[i]; i++; } wc[i] = 0; if (wcstombs(buf, wc, sizeof(buf)) <= sizeof(buf)-1) fputs_stdout(printable_string(buf)); #else char buf[37]; int i = 0; while (i < ARRAY_SIZE(buf)-1) { if (s[i] == 0) break; buf[i] = (0x20 <= s[i] && s[i] < 0x7f) ? s[i] : '?'; i++; } buf[i] = '\0'; fputs_stdout(buf); #endif } static void gpt_list_table(int xtra UNUSED_PARAM) { int i; char numstr6[6]; smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY")[0] = '\0'; printf("Disk %s: %llu sectors, %s\n", disk_device, (unsigned long long)total_number_of_sectors, numstr6); printf("Logical sector size: %u\n", sector_size); printf("Disk identifier (GUID): "); gpt_print_guid(gpt_hdr->disk_guid); printf("\nPartition table holds up to %u entries\n", (int)SWAP_LE32(gpt_hdr->n_parts)); printf("First usable sector is %llu, last usable sector is %llu\n\n", (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba), (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba)); /* "GPT fdisk" has a concept of 16-bit extension of the original MBR 8-bit type codes, * which it displays here: its output columns are ... Size Code Name * They are their own invention and are not stored on disk. * Looks like they use them to support "hybrid" GPT: for example, they have * AddType(0x8307, "69DAD710-2CE4-4E3C-B16C-21A1D49ABED3", "Linux ARM32 root (/)"); * and then (code>>8) matches what you need to put into MBR's type field for such a partition. * To print those codes, we'd need a GUID lookup table. Lets just drop the "Code" column instead: */ puts("Number Start (sector) End (sector) Size Name"); // 123456 123456789012345 123456789012345 12345 abc for (i = 0; i < n_parts; i++) { gpt_partition *p = gpt_part(i); if (p->lba_start) { smart_ulltoa5((1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start)) * sector_size, numstr6, " KMGTPEZY")[0] = '\0'; printf("%6u %15llu %15llu %s ", i + 1, (unsigned long long)SWAP_LE64(p->lba_start), (unsigned long long)SWAP_LE64(p->lba_end), numstr6 ); gpt_print_wide36(p->name36); bb_putchar('\n'); } } } static int check_gpt_label(void) { unsigned part_array_len; struct partition *first = pt_offset(MBRbuffer, 0); struct pte pe; uint32_t crc; /* LBA 0 contains the legacy MBR */ if (!valid_part_table_flag(MBRbuffer) || first->sys_ind != LEGACY_GPT_TYPE ) { current_label_type = LABEL_DOS; return 0; } /* LBA 1 contains the GPT header */ read_pte(&pe, 1); gpt_hdr = (void *)pe.sectorbuffer; if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) { current_label_type = LABEL_DOS; return 0; } init_unicode(); if (!global_crc32_table) { global_crc32_new_table_le(); } crc = SWAP_LE32(gpt_hdr->hdr_crc32); gpt_hdr->hdr_crc32 = 0; if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) { /* FIXME: read the backup table */ puts("\nwarning: GPT header CRC is invalid\n"); } n_parts = SWAP_LE32(gpt_hdr->n_parts); part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len); if (n_parts > GPT_MAX_PARTS || part_entry_len > GPT_MAX_PART_ENTRY_LEN || SWAP_LE32(gpt_hdr->hdr_size) > sector_size ) { puts("\nwarning: unable to parse GPT disklabel\n"); current_label_type = LABEL_DOS; return 0; } part_array_len = n_parts * part_entry_len; part_array = xmalloc(part_array_len); seek_sector(SWAP_LE64(gpt_hdr->first_part_lba)); if (full_read(dev_fd, part_array, part_array_len) != part_array_len) { fdisk_fatal(unable_to_read); } if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) { /* FIXME: read the backup table */ puts("\nwarning: GPT array CRC is invalid\n"); } puts("Found valid GPT with protective MBR; using GPT\n"); current_label_type = LABEL_GPT; return 1; } #endif /* GPT_LABEL */