blob: dbe889f7c32681ef5efa7de0cf342df637661d17 [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;
Denys Vlasenko29516ac2016-11-27 06:13:43 +010039 uint16_t name36[36];
Kevin Cernekeeccb07042010-10-25 02:00:24 +020040} gpt_partition;
41
42static gpt_header *gpt_hdr;
43
44static char *part_array;
45static unsigned int n_parts;
Kevin Cernekeeccb07042010-10-25 02:00:24 +020046static unsigned int part_entry_len;
47
Kevin Cernekeeccb07042010-10-25 02:00:24 +020048static 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
Kevin Cernekeeccb07042010-10-25 02:00:24 +020057static uint32_t
58gpt_crc32(void *buf, int len)
59{
Denys Vlasenko16cc80e2010-10-28 05:38:11 +020060 return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table);
Kevin Cernekeeccb07042010-10-25 02:00:24 +020061}
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
Kevin Cernekeeccb07042010-10-25 02:00:24 +020075static void
Denys Vlasenko29516ac2016-11-27 06:13:43 +010076gpt_print_wide36(uint16_t *s)
Kevin Cernekeeccb07042010-10-25 02:00:24 +020077{
Denys Vlasenko29516ac2016-11-27 06:13:43 +010078#if ENABLE_UNICODE_SUPPORT
79 char buf[37 * 4];
80 wchar_t wc[37];
Kevin Cernekeeccb07042010-10-25 02:00:24 +020081 int i = 0;
Denys Vlasenko29516ac2016-11-27 06:13:43 +010082 while (i < ARRAY_SIZE(wc)-1) {
83 if (s[i] == 0)
84 break;
85 wc[i] = s[i];
86 i++;
Kevin Cernekeeccb07042010-10-25 02:00:24 +020087 }
Denys Vlasenko29516ac2016-11-27 06:13:43 +010088 wc[i] = 0;
89 if (wcstombs(buf, wc, sizeof(buf)) <= sizeof(buf)-1)
Denys Vlasenko349d72c2018-09-30 16:56:56 +020090 fputs(printable_string(buf), stdout);
Denys Vlasenko29516ac2016-11-27 06:13:43 +010091#else
92 char buf[37];
93 int i = 0;
94 while (i < ARRAY_SIZE(buf)-1) {
95 if (s[i] == 0)
96 break;
Denys Vlasenko710b6ce2016-11-27 20:47:01 +010097 buf[i] = (0x20 <= s[i] && s[i] < 0x7f) ? s[i] : '?';
Denys Vlasenko29516ac2016-11-27 06:13:43 +010098 i++;
99 }
100 buf[i] = '\0';
Denys Vlasenko710b6ce2016-11-27 20:47:01 +0100101 fputs(buf, stdout);
Denys Vlasenko29516ac2016-11-27 06:13:43 +0100102#endif
Kevin Cernekeeccb07042010-10-25 02:00:24 +0200103}
104
105static void
106gpt_list_table(int xtra UNUSED_PARAM)
107{
108 int i;
109 char numstr6[6];
110
Denys Vlasenkoa407cf72013-09-06 12:53:14 +0200111 smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY")[0] = '\0';
Kevin Cernekeeccb07042010-10-25 02:00:24 +0200112 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
Denys Vlasenko29516ac2016-11-27 06:13:43 +0100124/* "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
Kevin Cernekeeccb07042010-10-25 02:00:24 +0200134 for (i = 0; i < n_parts; i++) {
135 gpt_partition *p = gpt_part(i);
136 if (p->lba_start) {
Jody Bruchondeebdf52013-08-20 17:42:06 +0200137 smart_ulltoa5((1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start)) * sector_size,
Denys Vlasenkoa407cf72013-09-06 12:53:14 +0200138 numstr6, " KMGTPEZY")[0] = '\0';
Denys Vlasenko29516ac2016-11-27 06:13:43 +0100139 printf("%6u %15llu %15llu %s ",
Kevin Cernekeeccb07042010-10-25 02:00:24 +0200140 i + 1,
141 (unsigned long long)SWAP_LE64(p->lba_start),
142 (unsigned long long)SWAP_LE64(p->lba_end),
Denys Vlasenko29516ac2016-11-27 06:13:43 +0100143 numstr6
144 );
145 gpt_print_wide36(p->name36);
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200146 bb_putchar('\n');
Kevin Cernekeeccb07042010-10-25 02:00:24 +0200147 }
148 }
149}
150
151static int
152check_gpt_label(void)
153{
Denys Vlasenko29516ac2016-11-27 06:13:43 +0100154 unsigned part_array_len;
Kevin Cernekeeccb07042010-10-25 02:00:24 +0200155 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
Denys Vlasenko29516ac2016-11-27 06:13:43 +0100178 init_unicode();
Denys Vlasenko9ce642f2010-10-27 15:26:45 +0200179 if (!global_crc32_table) {
Denys Vlasenkoddacb032018-02-01 10:56:19 +0100180 global_crc32_new_table_le();
Kevin Cernekeeccb07042010-10-25 02:00:24 +0200181 }
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 */