diff options
Diffstat (limited to 'util-linux/fdisk_gpt.c')
-rw-r--r-- | util-linux/fdisk_gpt.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c new file mode 100644 index 000000000..98803ec88 --- /dev/null +++ b/util-linux/fdisk_gpt.c | |||
@@ -0,0 +1,203 @@ | |||
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 | ||
9 | enum { | ||
10 | LEGACY_GPT_TYPE = 0xee, | ||
11 | GPT_MAX_PARTS = 256, | ||
12 | GPT_MAX_PART_ENTRY_LEN = 4096, | ||
13 | GUID_LEN = 16, | ||
14 | }; | ||
15 | |||
16 | typedef 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 | |||
33 | typedef 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 | |||
42 | static gpt_header *gpt_hdr; | ||
43 | |||
44 | static char *part_array; | ||
45 | static unsigned int n_parts; | ||
46 | static unsigned int part_array_len; | ||
47 | static unsigned int part_entry_len; | ||
48 | |||
49 | static uint32_t *crc32_table; | ||
50 | |||
51 | static inline gpt_partition * | ||
52 | gpt_part(int i) | ||
53 | { | ||
54 | if (i >= n_parts) { | ||
55 | return NULL; | ||
56 | } | ||
57 | return (gpt_partition *)&part_array[i * part_entry_len]; | ||
58 | } | ||
59 | |||
60 | /* TODO: move to libbb */ | ||
61 | static uint32_t | ||
62 | gpt_crc32(void *buf, int len) | ||
63 | { | ||
64 | uint32_t crc = 0xffffffff; | ||
65 | |||
66 | for (; len > 0; len--, buf++) { | ||
67 | crc = crc32_table[(crc ^ *((char *)buf)) & 0xff] ^ (crc >> 8); | ||
68 | } | ||
69 | return crc ^ 0xffffffff; | ||
70 | } | ||
71 | |||
72 | static void | ||
73 | gpt_print_guid(uint8_t *buf) | ||
74 | { | ||
75 | printf( | ||
76 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | ||
77 | buf[3], buf[2], buf[1], buf[0], | ||
78 | buf[5], buf[4], | ||
79 | buf[7], buf[6], | ||
80 | buf[8], buf[9], | ||
81 | buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); | ||
82 | } | ||
83 | |||
84 | /* TODO: real unicode support */ | ||
85 | static void | ||
86 | gpt_print_wide(uint16_t *s, int max_len) | ||
87 | { | ||
88 | int i = 0; | ||
89 | |||
90 | while (i < max_len) { | ||
91 | if (*s == 0) | ||
92 | return; | ||
93 | fputc(*s, stdout); | ||
94 | s++; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | static void | ||
99 | gpt_list_table(int xtra UNUSED_PARAM) | ||
100 | { | ||
101 | int i; | ||
102 | char numstr6[6]; | ||
103 | |||
104 | numstr6[5] = '\0'; | ||
105 | |||
106 | smart_ulltoa5(total_number_of_sectors, numstr6, " KMGTPEZY"); | ||
107 | printf("Disk %s: %llu sectors, %s\n", disk_device, | ||
108 | (unsigned long long)total_number_of_sectors, | ||
109 | numstr6); | ||
110 | printf("Logical sector size: %u\n", sector_size); | ||
111 | printf("Disk identifier (GUID): "); | ||
112 | gpt_print_guid(gpt_hdr->disk_guid); | ||
113 | printf("\nPartition table holds up to %u entries\n", | ||
114 | (int)SWAP_LE32(gpt_hdr->n_parts)); | ||
115 | printf("First usable sector is %llu, last usable sector is %llu\n\n", | ||
116 | (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba), | ||
117 | (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba)); | ||
118 | |||
119 | printf("Number Start (sector) End (sector) Size Code Name\n"); | ||
120 | for (i = 0; i < n_parts; i++) { | ||
121 | gpt_partition *p = gpt_part(i); | ||
122 | if (p->lba_start) { | ||
123 | smart_ulltoa5(1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start), | ||
124 | numstr6, " KMGTPEZY"); | ||
125 | printf("%4u %15llu %15llu %11s %04x ", | ||
126 | i + 1, | ||
127 | (unsigned long long)SWAP_LE64(p->lba_start), | ||
128 | (unsigned long long)SWAP_LE64(p->lba_end), | ||
129 | numstr6, | ||
130 | 0x0700 /* FIXME */); | ||
131 | gpt_print_wide(p->name, 18); | ||
132 | printf("\n"); | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | static int | ||
138 | check_gpt_label(void) | ||
139 | { | ||
140 | struct partition *first = pt_offset(MBRbuffer, 0); | ||
141 | struct pte pe; | ||
142 | uint32_t crc; | ||
143 | |||
144 | /* LBA 0 contains the legacy MBR */ | ||
145 | |||
146 | if (!valid_part_table_flag(MBRbuffer) | ||
147 | || first->sys_ind != LEGACY_GPT_TYPE | ||
148 | ) { | ||
149 | current_label_type = 0; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | /* LBA 1 contains the GPT header */ | ||
154 | |||
155 | read_pte(&pe, 1); | ||
156 | gpt_hdr = (void *)pe.sectorbuffer; | ||
157 | |||
158 | if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) { | ||
159 | current_label_type = 0; | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | if (!crc32_table) { | ||
164 | crc32_table = crc32_filltable(NULL, 0); | ||
165 | } | ||
166 | |||
167 | crc = SWAP_LE32(gpt_hdr->hdr_crc32); | ||
168 | gpt_hdr->hdr_crc32 = 0; | ||
169 | if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) { | ||
170 | /* FIXME: read the backup table */ | ||
171 | puts("\nwarning: GPT header CRC is invalid\n"); | ||
172 | } | ||
173 | |||
174 | n_parts = SWAP_LE32(gpt_hdr->n_parts); | ||
175 | part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len); | ||
176 | if (n_parts > GPT_MAX_PARTS | ||
177 | || part_entry_len > GPT_MAX_PART_ENTRY_LEN | ||
178 | || SWAP_LE32(gpt_hdr->hdr_size) > sector_size | ||
179 | ) { | ||
180 | puts("\nwarning: unable to parse GPT disklabel\n"); | ||
181 | current_label_type = 0; | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | part_array_len = n_parts * part_entry_len; | ||
186 | part_array = xmalloc(part_array_len); | ||
187 | seek_sector(SWAP_LE64(gpt_hdr->first_part_lba)); | ||
188 | if (full_read(dev_fd, part_array, part_array_len) != part_array_len) { | ||
189 | fdisk_fatal(unable_to_read); | ||
190 | } | ||
191 | |||
192 | if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) { | ||
193 | /* FIXME: read the backup table */ | ||
194 | puts("\nwarning: GPT array CRC is invalid\n"); | ||
195 | } | ||
196 | |||
197 | puts("Found valid GPT with protective MBR; using GPT\n"); | ||
198 | |||
199 | current_label_type = LABEL_GPT; | ||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | #endif /* GPT_LABEL */ | ||