Home | History | Annotate | Download | only in chain
      1 /* ----------------------------------------------------------------------- *
      2  *
      3  *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
      4  *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
      5  *   Copyright 2010 Shao Miller
      6  *   Copyright 2010-2012 Michal Soltys
      7  *
      8  *   Permission is hereby granted, free of charge, to any person
      9  *   obtaining a copy of this software and associated documentation
     10  *   files (the "Software"), to deal in the Software without
     11  *   restriction, including without limitation the rights to use,
     12  *   copy, modify, merge, publish, distribute, sublicense, and/or
     13  *   sell copies of the Software, and to permit persons to whom
     14  *   the Software is furnished to do so, subject to the following
     15  *   conditions:
     16  *
     17  *   The above copyright notice and this permission notice shall
     18  *   be included in all copies or substantial portions of the Software.
     19  *
     20  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     21  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     22  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     23  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     24  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     25  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     26  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     27  *   OTHER DEALINGS IN THE SOFTWARE.
     28  *
     29  * ----------------------------------------------------------------------- */
     30 
     31 /*
     32  * partiter.c
     33  *
     34  * Provides disk / partition iteration.
     35  */
     36 
     37 #include <stdlib.h>
     38 #include <stdio.h>
     39 #include <string.h>
     40 #include <stdarg.h>
     41 #include <zlib.h>
     42 #include <syslinux/disk.h>
     43 #include "partiter.h"
     44 #include "utility.h"
     45 
     46 #define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85)
     47 #define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
     48 #define sane(s,l) ((s)+(l) > (s))
     49 
     50 /* virtual forwards */
     51 
     52 static void pi_dtor_(struct part_iter *);
     53 static int  pi_next_(struct part_iter *);
     54 static int  pi_dos_next(struct part_iter *);
     55 static int  pi_gpt_next(struct part_iter *);
     56 
     57 /* vtab and types */
     58 
     59 static struct itertype types[] = {
     60    [0] = {
     61 	.dtor = &pi_dtor_,
     62 	.next = &pi_dos_next,
     63 }, [1] = {
     64 	.dtor = &pi_dtor_,
     65 	.next = &pi_gpt_next,
     66 }, [2] = {
     67 	.dtor = &pi_dtor_,
     68 	.next = &pi_next_,
     69 }};
     70 
     71 const struct itertype * const typedos = types;
     72 const struct itertype * const typegpt = types+1;
     73 const struct itertype * const typeraw = types+2;
     74 
     75 /* pi_dtor_() - common/raw iterator cleanup */
     76 static void pi_dtor_(struct part_iter *iter)
     77 {
     78     /* syslinux's free is null resilient */
     79     free(iter->data);
     80 }
     81 
     82 /* pi_ctor() - common/raw iterator initialization */
     83 static int pi_ctor(struct part_iter *iter,
     84 	const struct disk_info *di, int flags
     85 )
     86 {
     87     memcpy(&iter->di, di, sizeof *di);
     88     iter->flags = flags;
     89     iter->index0 = -1;
     90     iter->length = di->lbacnt;
     91 
     92     iter->type = typeraw;
     93     return 0;
     94 }
     95 
     96 /* pi_dos_ctor() - MBR/EBR iterator specific initialization */
     97 static int pi_dos_ctor(struct part_iter *iter,
     98 	const struct disk_info *di, int flags,
     99 	const struct disk_dos_mbr *mbr
    100 )
    101 {
    102     if (pi_ctor(iter, di, flags))
    103 	return -1;
    104 
    105     if (!(iter->data = malloc(sizeof *mbr))) {
    106 	critm();
    107 	goto bail;
    108     }
    109 
    110     memcpy(iter->data, mbr, sizeof *mbr);
    111 
    112     iter->dos.bebr_index0 = -1;
    113     iter->dos.disk_sig = mbr->disk_sig;
    114 
    115     iter->type = typedos;
    116     return 0;
    117 bail:
    118     pi_dtor_(iter);
    119     return -1;
    120 }
    121 
    122 /* pi_gpt_ctor() - GPT iterator specific initialization */
    123 static int pi_gpt_ctor(struct part_iter *iter,
    124 	const struct disk_info *di, int flags,
    125 	const struct disk_gpt_header *gpth, const struct disk_gpt_part_entry *gptl
    126 )
    127 {
    128     uint64_t siz;
    129 
    130     if (pi_ctor(iter, di, flags))
    131 	return -1;
    132 
    133     siz = (uint64_t)gpth->part_count * gpth->part_size;
    134 
    135     if (!(iter->data = malloc((size_t)siz))) {
    136 	critm();
    137 	goto bail;
    138     }
    139 
    140     memcpy(iter->data, gptl, (size_t)siz);
    141 
    142     iter->gpt.pe_count = (int)gpth->part_count;
    143     iter->gpt.pe_size = (int)gpth->part_size;
    144     iter->gpt.ufirst = gpth->lba_first_usable;
    145     iter->gpt.ulast = gpth->lba_last_usable;
    146 
    147     memcpy(&iter->gpt.disk_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
    148     memcpy(&iter->gpt.part_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
    149 
    150     iter->type = typegpt;
    151     return 0;
    152 bail:
    153     pi_dtor_(iter);
    154     return -1;
    155 }
    156 
    157 /* Logical partition must be sane, meaning:
    158  * - must be data or empty
    159  * - must have non-0 start and length
    160  * - values must not wrap around 32bit
    161  * - must be inside current EBR frame
    162  */
    163 
    164 static int notsane_logical(const struct part_iter *iter)
    165 {
    166     const struct disk_dos_part_entry *dp;
    167     uint32_t end_log;
    168 
    169     dp = ((struct disk_dos_mbr *)iter->data)->table;
    170 
    171     if (!dp[0].ostype)
    172 	return 0;
    173 
    174     if (ost_is_ext(dp[0].ostype)) {
    175 	error("The 1st EBR entry must be data or empty.");
    176 	return -1;
    177     }
    178 
    179     if (!(iter->flags & PIF_STRICT))
    180 	return 0;
    181 
    182     end_log = dp[0].start_lba + dp[0].length;
    183 
    184     if (!dp[0].start_lba ||
    185 	!dp[0].length ||
    186 	!sane(dp[0].start_lba, dp[0].length) ||
    187 	end_log > iter->dos.nebr_siz) {
    188 
    189 	error("Logical partition (in EBR) with invalid offset and/or length.");
    190 	return -1;
    191     }
    192 
    193     return 0;
    194 }
    195 
    196 /* Extended partition must be sane, meaning:
    197  * - must be extended or empty
    198  * - must have non-0 start and length
    199  * - values must not wrap around 32bit
    200  * - must be inside base EBR frame
    201  */
    202 
    203 static int notsane_extended(const struct part_iter *iter)
    204 {
    205     const struct disk_dos_part_entry *dp;
    206     uint32_t end_ebr;
    207 
    208     dp = ((struct disk_dos_mbr *)iter->data)->table;
    209 
    210     if (!dp[1].ostype)
    211 	return 0;
    212 
    213     if (!ost_is_nondata(dp[1].ostype)) {
    214 	error("The 2nd EBR entry must be extended or empty.");
    215 	return -1;
    216     }
    217 
    218     if (!(iter->flags & PIF_STRICT))
    219 	return 0;
    220 
    221     end_ebr = dp[1].start_lba + dp[1].length;
    222 
    223     if (!dp[1].start_lba ||
    224 	!dp[1].length ||
    225 	!sane(dp[1].start_lba, dp[1].length) ||
    226 	end_ebr > iter->dos.bebr_siz) {
    227 
    228 	error("Extended partition (EBR) with invalid offset and/or length.");
    229 	return -1;
    230     }
    231 
    232     return 0;
    233 }
    234 
    235 /* Primary partition must be sane, meaning:
    236  * - must have non-0 start and length
    237  * - values must not wrap around 32bit
    238  */
    239 
    240 static int notsane_primary(const struct part_iter *iter)
    241 {
    242     const struct disk_dos_part_entry *dp;
    243     dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
    244 
    245     if (!dp->ostype)
    246 	return 0;
    247 
    248     if (!(iter->flags & PIF_STRICT))
    249 	return 0;
    250 
    251     if (!dp->start_lba ||
    252 	!dp->length ||
    253 	!sane(dp->start_lba, dp->length) ||
    254 	((iter->flags & PIF_STRICTER) && (dp->start_lba + dp->length > iter->di.lbacnt))) {
    255 	error("Primary partition (in MBR) with invalid offset and/or length.");
    256 	return -1;
    257     }
    258 
    259     return 0;
    260 }
    261 
    262 static int notsane_gpt(const struct part_iter *iter)
    263 {
    264     const struct disk_gpt_part_entry *gp;
    265     gp = (const struct disk_gpt_part_entry *)
    266 	(iter->data + iter->index0 * iter->gpt.pe_size);
    267 
    268     if (guid_is0(&gp->type))
    269 	return 0;
    270 
    271     if (!(iter->flags & PIF_STRICT))
    272 	return 0;
    273 
    274     if (gp->lba_first < iter->gpt.ufirst ||
    275 	gp->lba_last > iter->gpt.ulast) {
    276 	error("LBA sectors of GPT partition are beyond the range allowed in GPT header.");
    277 	return -1;
    278     }
    279 
    280     return 0;
    281 }
    282 
    283 static int dos_next_mbr(struct part_iter *iter, uint32_t *lba,
    284 			    struct disk_dos_part_entry **_dp)
    285 {
    286     struct disk_dos_part_entry *dp;
    287 
    288     while (++iter->index0 < 4) {
    289 	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
    290 
    291 	if (notsane_primary(iter)) {
    292 	    iter->status = PI_INSANE;
    293 	    return -1;
    294 	}
    295 
    296 	if (ost_is_ext(dp->ostype)) {
    297 	    if (iter->dos.bebr_index0 >= 0) {
    298 		error("More than 1 extended partition.");
    299 		iter->status = PI_INSANE;
    300 		return -1;
    301 	    }
    302 	    /* record base EBR index */
    303 	    iter->dos.bebr_index0 = iter->index0;
    304 	}
    305 	if (!ost_is_nondata(dp->ostype) || (iter->flags & PIF_STEPALL)) {
    306 	    *lba = dp->start_lba;
    307 	    *_dp = dp;
    308 	    break;
    309 	}
    310     }
    311 
    312     return 0;
    313 }
    314 
    315 static int prep_base_ebr(struct part_iter *iter)
    316 {
    317     struct disk_dos_part_entry *dp;
    318 
    319     if (iter->dos.bebr_index0 < 0)	/* if we don't have base extended partition at all */
    320 	return -1;
    321     else if (!iter->dos.bebr_lba) { /* if not initialized yet */
    322 	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->dos.bebr_index0;
    323 
    324 	iter->dos.bebr_lba = dp->start_lba;
    325 	iter->dos.bebr_siz = dp->length;
    326 
    327 	iter->dos.nebr_lba = dp->start_lba;
    328 	iter->dos.nebr_siz = dp->length;
    329 
    330 	iter->index0--;
    331     }
    332     return 0;
    333 }
    334 
    335 static int dos_next_ebr(struct part_iter *iter, uint32_t *lba,
    336 			    struct disk_dos_part_entry **_dp)
    337 {
    338     struct disk_dos_part_entry *dp;
    339 
    340     if (prep_base_ebr(iter) < 0) {
    341 	iter->status = PI_DONE;
    342 	return -1;
    343     }
    344 
    345     while (++iter->index0 < 1024 && iter->dos.nebr_lba) {
    346 	free(iter->data);
    347 	if (!(iter->data =
    348 		    disk_read_sectors(&iter->di, iter->dos.nebr_lba, 1))) {
    349 	    error("Couldn't load EBR.");
    350 	    iter->status = PI_ERRLOAD;
    351 	    return -1;
    352 	}
    353 
    354 	/* check sanity of loaded data */
    355 	if (notsane_logical(iter) || notsane_extended(iter)) {
    356 	    iter->status = PI_INSANE;
    357 	    return -1;
    358 	}
    359 
    360 	dp = ((struct disk_dos_mbr *)iter->data)->table;
    361 
    362 	iter->dos.cebr_lba = iter->dos.nebr_lba;
    363 	iter->dos.cebr_siz = iter->dos.nebr_siz;
    364 
    365 	/* setup next frame values */
    366 	if (dp[1].ostype) {
    367 	    iter->dos.nebr_lba = iter->dos.bebr_lba + dp[1].start_lba;
    368 	    iter->dos.nebr_siz = dp[1].length;
    369 	} else {
    370 	    iter->dos.nebr_lba = 0;
    371 	    iter->dos.nebr_siz = 0;
    372 	}
    373 
    374 	if (!dp[0].ostype)
    375 	    iter->dos.logskipcnt++;
    376 
    377 	if (dp[0].ostype || (iter->flags & PIF_STEPALL)) {
    378 	    *lba = dp[0].start_lba ? iter->dos.cebr_lba + dp[0].start_lba : 0;
    379 	    *_dp = dp;
    380 	    return 0;
    381 	}
    382 	/*
    383 	 * This way it's possible to continue, if some crazy soft left a "hole"
    384 	 * - EBR with a valid extended partition without a logical one. In
    385 	 * such case, linux will not reserve a number for such hole - so we
    386 	 * don't increase index0. If PIF_STEPALL flag is set, we will never
    387 	 * reach this place.
    388 	 */
    389     }
    390     iter->status = PI_DONE;
    391     return -1;
    392 }
    393 
    394 static void gpt_conv_label(struct part_iter *iter)
    395 {
    396     const struct disk_gpt_part_entry *gp;
    397     const int16_t *orig_lab;
    398 
    399     gp = (const struct disk_gpt_part_entry *)
    400 	(iter->data + iter->index0 * iter->gpt.pe_size);
    401     orig_lab = (const int16_t *)gp->name;
    402 
    403     /* caveat: this is very crude conversion */
    404     for (int i = 0; i < PI_GPTLABSIZE/2; i++) {
    405 	iter->gpt.part_label[i] = (char)orig_lab[i];
    406     }
    407     iter->gpt.part_label[PI_GPTLABSIZE/2] = 0;
    408 }
    409 
    410 static inline int valid_crc(uint32_t crc, const uint8_t *buf, unsigned int siz)
    411 {
    412     return crc == crc32(crc32(0, NULL, 0), buf, siz);
    413 }
    414 
    415 static int valid_crc_hdr(void *buf)
    416 {
    417     struct disk_gpt_header *gh = buf;
    418     uint32_t crc = gh->chksum;
    419     int valid;
    420 
    421     gh->chksum = 0;
    422     valid = crc == crc32(crc32(0, NULL, 0), buf, gh->hdr_size);
    423     gh->chksum = crc;
    424     return valid;
    425 }
    426 
    427 static int pi_next_(struct part_iter *iter)
    428 {
    429     iter->status = PI_DONE;
    430     return iter->status;
    431 }
    432 
    433 static int pi_dos_next(struct part_iter *iter)
    434 {
    435     uint32_t abs_lba = 0;
    436     struct disk_dos_part_entry *dos_part = NULL;
    437 
    438     if (iter->status)
    439 	return iter->status;
    440 
    441     /* look for primary partitions */
    442     if (iter->index0 < 4 &&
    443 	    dos_next_mbr(iter, &abs_lba, &dos_part) < 0)
    444 	return iter->status;
    445 
    446     /* look for logical partitions */
    447     if (iter->index0 >= 4 &&
    448 	    dos_next_ebr(iter, &abs_lba, &dos_part) < 0)
    449 	return iter->status;
    450 
    451     /*
    452      * note special index handling:
    453      * in case PIF_STEPALL is set - this makes the index consistent with
    454      * non-PIF_STEPALL iterators
    455      */
    456 
    457     if (!dos_part->ostype)
    458 	iter->index = -1;
    459     else
    460 	iter->index = iter->index0 + 1 - iter->dos.logskipcnt;
    461     iter->abs_lba = abs_lba;
    462     iter->length = dos_part->length;
    463     iter->record = (char *)dos_part;
    464 
    465 #ifdef DEBUG
    466     disk_dos_part_dump(dos_part);
    467 #endif
    468 
    469     return iter->status;
    470 }
    471 
    472 static int pi_gpt_next(struct part_iter *iter)
    473 {
    474     const struct disk_gpt_part_entry *gpt_part = NULL;
    475 
    476     if (iter->status)
    477 	return iter->status;
    478 
    479     while (++iter->index0 < iter->gpt.pe_count) {
    480 	gpt_part = (const struct disk_gpt_part_entry *)
    481 	    (iter->data + iter->index0 * iter->gpt.pe_size);
    482 
    483 	if (notsane_gpt(iter)) {
    484 	    iter->status = PI_INSANE;
    485 	    return iter->status;
    486 	}
    487 
    488 	if (!guid_is0(&gpt_part->type) || (iter->flags & PIF_STEPALL))
    489 	    break;
    490     }
    491     /* no more partitions ? */
    492     if (iter->index0 == iter->gpt.pe_count) {
    493 	iter->status = PI_DONE;
    494 	return iter->status;
    495     }
    496     /* gpt_part is guaranteed to be valid here */
    497     iter->index = iter->index0 + 1;
    498     iter->abs_lba = gpt_part->lba_first;
    499     iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
    500     iter->record = (char *)gpt_part;
    501     memcpy(&iter->gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
    502     gpt_conv_label(iter);
    503 
    504 #ifdef DEBUG
    505     disk_gpt_part_dump(gpt_part);
    506 #endif
    507 
    508     return iter->status;
    509 }
    510 
    511 static struct part_iter *pi_alloc(void)
    512 {
    513     struct part_iter *iter;
    514     if (!(iter = malloc(sizeof *iter)))
    515 	critm();
    516     else
    517 	memset(iter, 0, sizeof *iter);
    518     return iter;
    519 }
    520 
    521 /* pi_del() - delete iterator */
    522 void pi_del(struct part_iter **_iter)
    523 {
    524     if(!_iter || !*_iter)
    525 	return;
    526     pi_dtor(*_iter);
    527     free(*_iter);
    528     *_iter = NULL;
    529 }
    530 
    531 static void try_gpt_we(const char *str, int sec)
    532 {
    533     if (sec)
    534 	error(str);
    535     else
    536 	warn(str);
    537 }
    538 
    539 static struct disk_gpt_header *try_gpt_hdr(const struct disk_info *di, int sec)
    540 {
    541     const char *desc = sec ? "backup" : "primary";
    542     uint64_t gpt_cur = sec ? di->lbacnt - 1 : 1;
    543     struct disk_gpt_header *gpth;
    544     char errbuf[64];
    545 
    546     gpth = disk_read_sectors(di, gpt_cur, 1);
    547     if (!gpth) {
    548 	sprintf(errbuf, "Unable to read %s GPT header.", desc);
    549 	try_gpt_we(errbuf, sec);
    550 	return NULL;
    551     }
    552     if(!valid_crc_hdr(gpth)) {
    553 	sprintf(errbuf, "Invalid checksum of %s GPT header.", desc);
    554 	try_gpt_we(errbuf, sec);
    555 	free(gpth);
    556 	return NULL;
    557     }
    558     return gpth;
    559 }
    560 
    561 static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, const struct disk_gpt_header *gpth, int alt)
    562 {
    563     int pri = gpth->lba_cur < gpth->lba_alt;
    564     const char *desc = alt ? "alternative" : "main";
    565     struct disk_gpt_part_entry *gptl;
    566     char errbuf[64];
    567     uint64_t gpt_lsiz;	    /* size of GPT partition list in bytes */
    568     uint64_t gpt_lcnt;	    /* size of GPT partition in sectors */
    569     uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
    570 
    571     gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count;
    572     gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps;
    573     if (!alt) {
    574 	/* prefer header value for partition table if not asking for alternative */
    575 	gpt_loff = gpth->lba_table;
    576     } else {
    577 	/* try to read alternative, we have to calculate its position */
    578 	if (!pri)
    579 	    gpt_loff = gpth->lba_alt + 1;
    580 	else
    581 	    gpt_loff = gpth->lba_alt - gpt_lcnt;
    582     }
    583 
    584     gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt);
    585     if (!gptl) {
    586 	sprintf(errbuf, "Unable to read %s GPT partition list.", desc);
    587 	try_gpt_we(errbuf, alt);
    588 	return NULL;
    589     }
    590     if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) {
    591 	sprintf(errbuf, "Invalid checksum of %s GPT partition list.", desc);
    592 	try_gpt_we(errbuf, alt);
    593 	free(gptl);
    594 	return NULL;
    595     }
    596     return gptl;
    597 }
    598 
    599 static int notsane_gpt_hdr(const struct disk_info *di, const struct disk_gpt_header *gpth, int flags)
    600 {
    601     uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
    602     uint64_t gpt_lsiz;	    /* size of GPT partition list in bytes */
    603     uint64_t gpt_lcnt;	    /* size of GPT partition in sectors */
    604     uint64_t gpt_sec;	    /* secondary gpt header */
    605 
    606     if (!(flags & PIF_STRICT))
    607 	return 0;
    608 
    609     if (gpth->lba_alt < gpth->lba_cur)
    610 	gpt_sec = gpth->lba_cur;
    611     else
    612 	gpt_sec = gpth->lba_alt;
    613     gpt_loff = gpth->lba_table;
    614     gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count;
    615     gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps;
    616 
    617     /*
    618      * disk_read_sectors allows reading of max 255 sectors, so we use
    619      * it as a sanity check base. EFI doesn't specify max (AFAIK).
    620      */
    621     if (gpt_loff < 2 || !gpt_lsiz || gpt_lcnt > 255u ||
    622 	    gpth->lba_first_usable > gpth->lba_last_usable ||
    623 	    !sane(gpt_loff, gpt_lcnt) ||
    624 	    (gpt_loff + gpt_lcnt > gpth->lba_first_usable && gpt_loff <= gpth->lba_last_usable) ||
    625 	     gpt_loff + gpt_lcnt > gpt_sec ||
    626 	    ((flags & PIF_STRICTER) && (gpt_sec >= di->lbacnt)) ||
    627 	    gpth->part_size < sizeof(struct disk_gpt_part_entry))
    628 	return -1;
    629 
    630     return 0;
    631 }
    632 
    633 /* pi_begin() - validate and and get proper iterator for a disk described by di */
    634 struct part_iter *pi_begin(const struct disk_info *di, int flags)
    635 {
    636     int isgpt = 0, ret = -1;
    637     struct part_iter *iter;
    638     struct disk_dos_mbr *mbr = NULL;
    639     struct disk_gpt_header *gpth = NULL;
    640     struct disk_gpt_part_entry *gptl = NULL;
    641 
    642     /* Preallocate iterator */
    643     if (!(iter = pi_alloc()))
    644 	goto out;
    645 
    646     /* Read MBR */
    647     if (!(mbr = disk_read_sectors(di, 0, 1))) {
    648 	error("Unable to read the first disk sector.");
    649 	goto out;
    650     }
    651 
    652     /* Check for MBR magic */
    653     if (mbr->sig != disk_mbr_sig_magic) {
    654 	warn("No MBR magic, treating disk as raw.");
    655 	/* looks like RAW */
    656 	ret = pi_ctor(iter, di, flags);
    657 	goto out;
    658     }
    659 
    660     /* Check for GPT protective MBR */
    661     for (size_t i = 0; i < 4; i++)
    662 	isgpt |= (mbr->table[i].ostype == 0xEE);
    663     isgpt = isgpt && !(flags & PIF_PREFMBR);
    664 
    665     /* Try to read GPT header */
    666     if (isgpt) {
    667 	gpth = try_gpt_hdr(di, 0);
    668 	if (!gpth)
    669 	    /*
    670 	     * this read might fail if bios reports different disk size (different vm/pc)
    671 	     * not much we can do here to avoid it
    672 	     */
    673 	    gpth = try_gpt_hdr(di, 1);
    674 	if (!gpth)
    675 	    goto out;
    676     }
    677 
    678     if (gpth && gpth->rev.uint32 == 0x00010000 &&
    679 	    !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) {
    680 	/* looks like GPT v1.0 */
    681 #ifdef DEBUG
    682 	dprintf("Looks like a GPT v1.0 disk.\n");
    683 	disk_gpt_header_dump(gpth);
    684 #endif
    685 	if (notsane_gpt_hdr(di, gpth, flags)) {
    686 	    error("GPT header values are corrupted.");
    687 	    goto out;
    688 	}
    689 
    690 	gptl = try_gpt_list(di, gpth, 0);
    691 	if (!gptl)
    692 	    gptl = try_gpt_list(di, gpth, 1);
    693 	if (!gptl)
    694 	    goto out;
    695 
    696 	/* looks like GPT */
    697 	ret = pi_gpt_ctor(iter, di, flags, gpth, gptl);
    698     } else {
    699 	/* looks like MBR */
    700 	ret = pi_dos_ctor(iter, di, flags, mbr);
    701     }
    702 out:
    703     if (ret < 0) {
    704 	free(iter);
    705 	iter = NULL;
    706     }
    707     free(mbr);
    708     free(gpth);
    709     free(gptl);
    710 
    711     return iter;
    712 }
    713 
    714 /* vim: set ts=8 sts=4 sw=4 noet: */
    715