Upload Tizen:Base source
[framework/base/util-linux-ng.git] / partx / gpt.c
1 /*
2     gpt.[ch]
3
4     Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
5
6     EFI GUID Partition Table handling
7     Per Intel EFI Specification v1.02
8     http://developer.intel.com/technology/efi/efi.htm
9
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <inttypes.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <errno.h>
33
34 #include "blkdev.h"
35 #include "crc32.h"
36 #include "gpt.h"
37 #include "partx.h"
38 #include "bitops.h"
39
40 static inline uint32_t
41 efi_crc32(const void *buf, unsigned long len)
42 {
43         return (crc32(~0L, buf, len) ^ ~0L);
44 }
45
46 /**
47  * is_pmbr_valid(): test Protective MBR for validity
48  * @mbr: pointer to a legacy mbr structure
49  *
50  * Description: Returns 1 if PMBR is valid, 0 otherwise.
51  * Validity depends on two things:
52  *  1) MSDOS signature is in the last two bytes of the MBR
53  *  2) One partition of type 0xEE is found
54  */
55 static int
56 is_pmbr_valid(legacy_mbr *mbr)
57 {
58         int i, found = 0, signature = 0;
59         if (!mbr)
60                 return 0;
61         signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
62         for (i = 0; signature && i < 4; i++) {
63                 if (mbr->partition[i].sys_type ==
64                     EFI_PMBR_OSTYPE_EFI_GPT) {
65                         found = 1;
66                         break;
67                 }
68         }
69         return (signature && found);
70 }
71
72 static int
73 get_sector_size (int fd)
74 {
75         int sector_size;
76
77         if (blkdev_get_sector_size(fd, &sector_size) == -1)
78                 return DEFAULT_SECTOR_SIZE;
79         return sector_size;
80 }
81
82 static uint64_t
83 get_num_sectors(int fd)
84 {
85         unsigned long long bytes=0;
86
87         if (blkdev_get_size(fd, &bytes) == -1)
88                 return 0;
89         return bytes / get_sector_size(fd);
90 }
91
92 static uint64_t
93 last_lba(int filedes)
94 {
95         int rc;
96         uint64_t sectors = 0;
97         struct stat s;
98         memset(&s, 0, sizeof (s));
99         rc = fstat(filedes, &s);
100         if (rc == -1) {
101                 fprintf(stderr, "last_lba() could not stat: %s\n",
102                         strerror(errno));
103                 return 0;
104         }
105
106         if (S_ISBLK(s.st_mode)) {
107                 sectors = get_num_sectors(filedes);
108         } else {
109                 fprintf(stderr,
110                         "last_lba(): I don't know how to handle files with mode %x\n",
111                         s.st_mode);
112                 sectors = 1;
113         }
114
115         return sectors - 1;
116 }
117
118 static ssize_t
119 read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
120 {
121         int sector_size = get_sector_size(fd);
122         off_t offset = lba * sector_size;
123
124         lseek(fd, offset, SEEK_SET);
125         return read(fd, buffer, bytes);
126 }
127
128 /**
129  * alloc_read_gpt_entries(): reads partition entries from disk
130  * @fd  is an open file descriptor to the whole disk
131  * @gpt is a buffer into which the GPT will be put  
132  * Description: Returns ptes on success,  NULL on error.
133  * Allocates space for PTEs based on information found in @gpt.
134  * Notes: remember to free pte when you're done!
135  */
136 static gpt_entry *
137 alloc_read_gpt_entries(int fd, gpt_header * gpt)
138 {
139         gpt_entry *pte;
140         size_t count = le32_to_cpu(gpt->num_partition_entries) *
141                 le32_to_cpu(gpt->sizeof_partition_entry);
142
143         if (!count) return NULL;
144
145         pte = (gpt_entry *)malloc(count);
146         if (!pte)
147                 return NULL;
148         memset(pte, 0, count);
149
150         if (!read_lba(fd, le64_to_cpu(gpt->partition_entry_lba), pte,
151                       count)) {
152                 free(pte);
153                 return NULL;
154         }
155         return pte;
156 }
157
158 /**
159  * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
160  * @fd  is an open file descriptor to the whole disk
161  * @lba is the Logical Block Address of the partition table
162  * 
163  * Description: returns GPT header on success, NULL on error.   Allocates
164  * and fills a GPT header starting at @ from @bdev.
165  * Note: remember to free gpt when finished with it.
166  */
167 static gpt_header *
168 alloc_read_gpt_header(int fd, uint64_t lba)
169 {
170         gpt_header *gpt;
171         gpt = (gpt_header *)
172             malloc(sizeof (gpt_header));
173         if (!gpt)
174                 return NULL;
175         memset(gpt, 0, sizeof (*gpt));
176         if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) {
177                 free(gpt);
178                 return NULL;
179         }
180
181         return gpt;
182 }
183
184 /**
185  * is_gpt_valid() - tests one GPT header and PTEs for validity
186  * @fd  is an open file descriptor to the whole disk
187  * @lba is the logical block address of the GPT header to test
188  * @gpt is a GPT header ptr, filled on return.
189  * @ptes is a PTEs ptr, filled on return.
190  *
191  * Description: returns 1 if valid,  0 on error.
192  * If valid, returns pointers to newly allocated GPT header and PTEs.
193  */
194 static int
195 is_gpt_valid(int fd, uint64_t lba,
196              gpt_header ** gpt, gpt_entry ** ptes)
197 {
198         int rc = 0;             /* default to not valid */
199         uint32_t crc, origcrc;
200
201         if (!gpt || !ptes)
202                 return 0;
203         if (!(*gpt = alloc_read_gpt_header(fd, lba)))
204                 return 0;
205
206         /* Check the GUID Partition Table signature */
207         if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
208                 /* 
209                    printf("GUID Partition Table Header signature is wrong: %" PRIx64" != %" PRIx64 "\n",
210                    le64_to_cpu((*gpt)->signature), GUID_PT_HEADER_SIGNATURE);
211                  */
212                 free(*gpt);
213                 *gpt = NULL;
214                 return rc;
215         }
216
217         /* Check the GUID Partition Table Header CRC */
218         origcrc = le32_to_cpu((*gpt)->header_crc32);
219         (*gpt)->header_crc32 = 0;
220         crc = efi_crc32(*gpt, le32_to_cpu((*gpt)->header_size));
221         if (crc != origcrc) {
222                 /* printf( "GPTH CRC check failed, %x != %x.\n", origcrc, crc); */
223                 (*gpt)->header_crc32 = cpu_to_le32(origcrc);
224                 free(*gpt);
225                 *gpt = NULL;
226                 return 0;
227         }
228         (*gpt)->header_crc32 = cpu_to_le32(origcrc);
229
230         /* Check that the my_lba entry points to the LBA
231          * that contains the GPT we read */
232         if (le64_to_cpu((*gpt)->my_lba) != lba) {
233                 /* printf( "my_lba % PRIx64 "x != lba %"PRIx64 "x.\n", le64_to_cpu((*gpt)->my_lba), lba); */
234                 free(*gpt);
235                 *gpt = NULL;
236                 return 0;
237         }
238
239         if (!(*ptes = alloc_read_gpt_entries(fd, *gpt))) {
240                 free(*gpt);
241                 *gpt = NULL;
242                 return 0;
243         }
244
245         /* Check the GUID Partition Entry Array CRC */
246         crc = efi_crc32(*ptes,
247                         le32_to_cpu((*gpt)->num_partition_entries) *
248                         le32_to_cpu((*gpt)->sizeof_partition_entry));
249         if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
250                 /* printf("GUID Partitition Entry Array CRC check failed.\n"); */
251                 free(*gpt);
252                 *gpt = NULL;
253                 free(*ptes);
254                 *ptes = NULL;
255                 return 0;
256         }
257
258         /* We're done, all's well */
259         return 1;
260 }
261 /**
262  * compare_gpts() - Search disk for valid GPT headers and PTEs
263  * @pgpt is the primary GPT header
264  * @agpt is the alternate GPT header
265  * @lastlba is the last LBA number
266  * Description: Returns nothing.  Sanity checks pgpt and agpt fields
267  * and prints warnings on discrepancies.
268  *
269  */
270 static void
271 compare_gpts(gpt_header *pgpt, gpt_header *agpt, uint64_t lastlba)
272 {
273         int error_found = 0;
274         if (!pgpt || !agpt)
275                 return;
276         if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
277                 fprintf(stderr,
278                        "GPT:Primary header LBA != Alt. header alternate_lba\n");
279                 fprintf(stderr,  "GPT:%" PRIx64 "x != %" PRIx64 "x\n",
280                        le64_to_cpu(pgpt->my_lba),
281                        le64_to_cpu(agpt->alternate_lba));
282                 error_found++;
283         }
284         if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
285                 fprintf(stderr,
286                        "GPT:Primary header alternate_lba != Alt. header my_lba\n");
287                 fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
288                        le64_to_cpu(pgpt->alternate_lba),
289                        le64_to_cpu(agpt->my_lba));
290                 error_found++;
291         }
292         if (le64_to_cpu(pgpt->first_usable_lba) !=
293             le64_to_cpu(agpt->first_usable_lba)) {
294                 fprintf(stderr,  "GPT:first_usable_lbas don't match.\n");
295                 fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
296                        le64_to_cpu(pgpt->first_usable_lba),
297                        le64_to_cpu(agpt->first_usable_lba));
298                 error_found++;
299         }
300         if (le64_to_cpu(pgpt->last_usable_lba) !=
301             le64_to_cpu(agpt->last_usable_lba)) {
302                 fprintf(stderr,  "GPT:last_usable_lbas don't match.\n");
303                 fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
304                        le64_to_cpu(pgpt->last_usable_lba),
305                        le64_to_cpu(agpt->last_usable_lba));
306                 error_found++;
307         }
308         if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
309                 fprintf(stderr,  "GPT:disk_guids don't match.\n");
310                 error_found++;
311         }
312         if (le32_to_cpu(pgpt->num_partition_entries) !=
313             le32_to_cpu(agpt->num_partition_entries)) {
314                 fprintf(stderr,  "GPT:num_partition_entries don't match: "
315                        "0x%x != 0x%x\n",
316                        le32_to_cpu(pgpt->num_partition_entries),
317                        le32_to_cpu(agpt->num_partition_entries));
318                 error_found++;
319         }
320         if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
321             le32_to_cpu(agpt->sizeof_partition_entry)) {
322                 fprintf(stderr,
323                        "GPT:sizeof_partition_entry values don't match: "
324                        "0x%x != 0x%x\n",
325                        le32_to_cpu(pgpt->sizeof_partition_entry),
326                        le32_to_cpu(agpt->sizeof_partition_entry));
327                 error_found++;
328         }
329         if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
330             le32_to_cpu(agpt->partition_entry_array_crc32)) {
331                 fprintf(stderr,
332                        "GPT:partition_entry_array_crc32 values don't match: "
333                        "0x%x != 0x%x\n",
334                        le32_to_cpu(pgpt->partition_entry_array_crc32),
335                        le32_to_cpu(agpt->partition_entry_array_crc32));
336                 error_found++;
337         }
338         if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
339                 fprintf(stderr,
340                        "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
341                 fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
342                        le64_to_cpu(pgpt->alternate_lba), lastlba);
343                 error_found++;
344         }
345
346         if (le64_to_cpu(agpt->my_lba) != lastlba) {
347                 fprintf(stderr,
348                        "GPT:Alternate GPT header not at the end of the disk.\n");
349                 fprintf(stderr,  "GPT:%" PRIx64 " != %" PRIx64 "\n",
350                        le64_to_cpu(agpt->my_lba), lastlba);
351                 error_found++;
352         }
353
354         if (error_found)
355                 fprintf(stderr,
356                        "GPT: Use GNU Parted to correct GPT errors.\n");
357         return;
358 }
359
360 /**
361  * find_valid_gpt() - Search disk for valid GPT headers and PTEs
362  * @fd  is an open file descriptor to the whole disk
363  * @gpt is a GPT header ptr, filled on return.
364  * @ptes is a PTEs ptr, filled on return.
365  * Description: Returns 1 if valid, 0 on error.
366  * If valid, returns pointers to newly allocated GPT header and PTEs.
367  * Validity depends on finding either the Primary GPT header and PTEs valid,
368  * or the Alternate GPT header and PTEs valid, and the PMBR valid.
369  */
370 static int
371 find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
372 {
373         extern int force_gpt;
374         int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
375         gpt_header *pgpt = NULL, *agpt = NULL;
376         gpt_entry *pptes = NULL, *aptes = NULL;
377         legacy_mbr *legacymbr = NULL;
378         uint64_t lastlba;
379         if (!gpt || !ptes)
380                 return 0;
381
382         lastlba = last_lba(fd);
383         good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
384                                  &pgpt, &pptes);
385         if (good_pgpt) {
386                 good_agpt = is_gpt_valid(fd,
387                                          le64_to_cpu(pgpt->alternate_lba),
388                                          &agpt, &aptes);
389                 if (!good_agpt) {
390                         good_agpt = is_gpt_valid(fd, lastlba,
391                                                  &agpt, &aptes);
392                 }
393         }
394         else {
395                 good_agpt = is_gpt_valid(fd, lastlba,
396                                          &agpt, &aptes);
397         }
398
399         /* The obviously unsuccessful case */
400         if (!good_pgpt && !good_agpt) {
401                 goto fail;
402         }
403
404         /* This will be added to the EFI Spec. per Intel after v1.02. */
405         legacymbr = malloc(sizeof (*legacymbr));
406         if (legacymbr) {
407                 memset(legacymbr, 0, sizeof (*legacymbr));
408                 read_lba(fd, 0, (uint8_t *) legacymbr,
409                          sizeof (*legacymbr));
410                 good_pmbr = is_pmbr_valid(legacymbr);
411                 free(legacymbr);
412                 legacymbr=NULL;
413         }
414
415         /* Failure due to bad PMBR */
416         if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
417                 fprintf(stderr,
418                        "  Warning: Disk has a valid GPT signature "
419                        "but invalid PMBR.\n"
420                        "  Assuming this disk is *not* a GPT disk anymore.\n"
421                        "  Use gpt kernel option to override.  "
422                        "Use GNU Parted to correct disk.\n");
423                 goto fail;
424         }
425
426         /* Would fail due to bad PMBR, but force GPT anyhow */
427         if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
428                 fprintf(stderr, 
429                        "  Warning: Disk has a valid GPT signature but "
430                        "invalid PMBR.\n"
431                        "  Use GNU Parted to correct disk.\n"
432                        "  gpt option taken, disk treated as GPT.\n");
433         }
434
435         compare_gpts(pgpt, agpt, lastlba);
436
437         /* The good cases */
438         if (good_pgpt && (good_pmbr || force_gpt)) {
439                 *gpt  = pgpt;
440                 *ptes = pptes;
441                 if (agpt)  { free(agpt);   agpt = NULL; }
442                 if (aptes) { free(aptes); aptes = NULL; }
443                 if (!good_agpt) {
444                         fprintf(stderr, 
445                                "Alternate GPT is invalid, "
446                                "using primary GPT.\n");
447                 }
448                 return 1;
449         }
450         else if (good_agpt && (good_pmbr || force_gpt)) {
451                 *gpt  = agpt;
452                 *ptes = aptes;
453                 if (pgpt)  { free(pgpt);   pgpt = NULL; }
454                 if (pptes) { free(pptes); pptes = NULL; }
455                 fprintf(stderr, 
456                        "Primary GPT is invalid, using alternate GPT.\n");
457                 return 1;
458         }
459
460  fail:
461         if (pgpt)  { free(pgpt);   pgpt=NULL; }
462         if (agpt)  { free(agpt);   agpt=NULL; }
463         if (pptes) { free(pptes); pptes=NULL; }
464         if (aptes) { free(aptes); aptes=NULL; }
465         *gpt = NULL;
466         *ptes = NULL;
467         return 0;
468 }
469
470 /**
471  * read_gpt_pt() 
472  * @fd
473  * @all - slice with start/size of whole disk
474  *
475  *  0 if this isn't our partition table
476  *  number of partitions if successful
477  *
478  */
479 int
480 read_gpt_pt (int fd, struct slice all, struct slice *sp, int ns)
481 {
482         gpt_header *gpt = NULL;
483         gpt_entry *ptes = NULL;
484         uint32_t i;
485         int n = 0;
486         int last_used_index=-1;
487
488         if (!find_valid_gpt (fd, &gpt, &ptes) || !gpt || !ptes) {
489                 free (gpt);
490                 free (ptes);
491                 return 0;
492         }
493
494         for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < ns; i++) {
495                 if (!efi_guidcmp (NULL_GUID, ptes[i].partition_type_guid)) {
496                         sp[n].start = 0;
497                         sp[n].size = 0;
498                         n++;
499                 } else {
500                         sp[n].start = le64_to_cpu(ptes[i].starting_lba);
501                         sp[n].size  = le64_to_cpu(ptes[i].ending_lba) -
502                                 le64_to_cpu(ptes[i].starting_lba) + 1;
503                         last_used_index=n;
504                         n++;
505                 }
506         }
507         free (ptes);
508         free (gpt);
509         return last_used_index+1;
510 }