blob: 5786d5f7d753d6e1e414e84a58cca306dcf5b5aa [file] [log] [blame]
Kevin Cernekeeccb07042010-10-25 02:00:24 +02001#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 {
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020010 LEGACY_GPT_TYPE = 0xee,
Kevin Cernekeeccb07042010-10-25 02:00:24 +020011 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 name[36];
40} gpt_partition;
41
42static gpt_header *gpt_hdr;
43
44static char *part_array;
45static unsigned int n_parts;
46static unsigned int part_array_len;
47static unsigned int part_entry_len;
48
Kevin Cernekeeccb07042010-10-25 02:00:24 +020049static inline gpt_partition *
50gpt_part(int i)
51{
52 if (i >= n_parts) {
53 return NULL;
54 }
55 return (gpt_partition *)&part_array[i * part_entry_len];
56}
57
Kevin Cernekeeccb07042010-10-25 02:00:24 +020058static uint32_t
59gpt_crc32(void *buf, int len)
60{
Denys Vlasenko16cc80e2010-10-28 05:38:11 +020061 return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table);
Kevin Cernekeeccb07042010-10-25 02:00:24 +020062}
63
64static void
65gpt_print_guid(uint8_t *buf)
66{
67 printf(
68 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
69 buf[3], buf[2], buf[1], buf[0],
70 buf[5], buf[4],
71 buf[7], buf[6],
72 buf[8], buf[9],
73 buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
74}
75
76/* TODO: real unicode support */
77static void
78gpt_print_wide(uint16_t *s, int max_len)
79{
80 int i = 0;
81
82 while (i < max_len) {
83 if (*s == 0)
84 return;
85 fputc(*s, stdout);
86 s++;
87 }
88}
89
90static void
91gpt_list_table(int xtra UNUSED_PARAM)
92{
93 int i;
94 char numstr6[6];
95
Denys Vlasenkoa407cf72013-09-06 12:53:14 +020096 smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY")[0] = '\0';
Kevin Cernekeeccb07042010-10-25 02:00:24 +020097 printf("Disk %s: %llu sectors, %s\n", disk_device,
98 (unsigned long long)total_number_of_sectors,
99 numstr6);
100 printf("Logical sector size: %u\n", sector_size);
101 printf("Disk identifier (GUID): ");
102 gpt_print_guid(gpt_hdr->disk_guid);
103 printf("\nPartition table holds up to %u entries\n",
104 (int)SWAP_LE32(gpt_hdr->n_parts));
105 printf("First usable sector is %llu, last usable sector is %llu\n\n",
106 (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba),
107 (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba));
108
109 printf("Number Start (sector) End (sector) Size Code Name\n");
110 for (i = 0; i < n_parts; i++) {
111 gpt_partition *p = gpt_part(i);
112 if (p->lba_start) {
Jody Bruchondeebdf52013-08-20 17:42:06 +0200113 smart_ulltoa5((1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start)) * sector_size,
Denys Vlasenkoa407cf72013-09-06 12:53:14 +0200114 numstr6, " KMGTPEZY")[0] = '\0';
Kevin Cernekeeccb07042010-10-25 02:00:24 +0200115 printf("%4u %15llu %15llu %11s %04x ",
116 i + 1,
117 (unsigned long long)SWAP_LE64(p->lba_start),
118 (unsigned long long)SWAP_LE64(p->lba_end),
119 numstr6,
120 0x0700 /* FIXME */);
121 gpt_print_wide(p->name, 18);
122 printf("\n");
123 }
124 }
125}
126
127static int
128check_gpt_label(void)
129{
130 struct partition *first = pt_offset(MBRbuffer, 0);
131 struct pte pe;
132 uint32_t crc;
133
134 /* LBA 0 contains the legacy MBR */
135
136 if (!valid_part_table_flag(MBRbuffer)
137 || first->sys_ind != LEGACY_GPT_TYPE
138 ) {
139 current_label_type = 0;
140 return 0;
141 }
142
143 /* LBA 1 contains the GPT header */
144
145 read_pte(&pe, 1);
146 gpt_hdr = (void *)pe.sectorbuffer;
147
148 if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) {
149 current_label_type = 0;
150 return 0;
151 }
152
Denys Vlasenko9ce642f2010-10-27 15:26:45 +0200153 if (!global_crc32_table) {
154 global_crc32_table = crc32_filltable(NULL, 0);
Kevin Cernekeeccb07042010-10-25 02:00:24 +0200155 }
156
157 crc = SWAP_LE32(gpt_hdr->hdr_crc32);
158 gpt_hdr->hdr_crc32 = 0;
159 if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) {
160 /* FIXME: read the backup table */
161 puts("\nwarning: GPT header CRC is invalid\n");
162 }
163
164 n_parts = SWAP_LE32(gpt_hdr->n_parts);
165 part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len);
166 if (n_parts > GPT_MAX_PARTS
167 || part_entry_len > GPT_MAX_PART_ENTRY_LEN
168 || SWAP_LE32(gpt_hdr->hdr_size) > sector_size
169 ) {
170 puts("\nwarning: unable to parse GPT disklabel\n");
171 current_label_type = 0;
172 return 0;
173 }
174
175 part_array_len = n_parts * part_entry_len;
176 part_array = xmalloc(part_array_len);
177 seek_sector(SWAP_LE64(gpt_hdr->first_part_lba));
178 if (full_read(dev_fd, part_array, part_array_len) != part_array_len) {
179 fdisk_fatal(unable_to_read);
180 }
181
182 if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) {
183 /* FIXME: read the backup table */
184 puts("\nwarning: GPT array CRC is invalid\n");
185 }
186
187 puts("Found valid GPT with protective MBR; using GPT\n");
188
189 current_label_type = LABEL_GPT;
190 return 1;
191}
192
193#endif /* GPT_LABEL */