disk.c revision 223712
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/boot/common/disk.c 223712 2011-07-01 18:31:59Z marius $"); 29 30/* 31 * MBR/GPT partitioned disk device handling. 32 * 33 * Ideas and algorithms from: 34 * 35 * - NetBSD libi386/biosdisk.c 36 * - FreeBSD biosboot/disk.c 37 * 38 */ 39 40#include <stand.h> 41 42#include <sys/diskmbr.h> 43#include <sys/disklabel.h> 44#include <sys/gpt.h> 45 46#include <stdarg.h> 47#include <uuid.h> 48 49#include <bootstrap.h> 50 51#include "disk.h" 52 53#ifdef DISK_DEBUG 54# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 55#else 56# define DEBUG(fmt, args...) 57#endif 58 59/* 60 * Search for a slice with the following preferences: 61 * 62 * 1: Active FreeBSD slice 63 * 2: Non-active FreeBSD slice 64 * 3: Active Linux slice 65 * 4: non-active Linux slice 66 * 5: Active FAT/FAT32 slice 67 * 6: non-active FAT/FAT32 slice 68 */ 69#define PREF_RAWDISK 0 70#define PREF_FBSD_ACT 1 71#define PREF_FBSD 2 72#define PREF_LINUX_ACT 3 73#define PREF_LINUX 4 74#define PREF_DOS_ACT 5 75#define PREF_DOS 6 76#define PREF_NONE 7 77 78#ifdef LOADER_GPT_SUPPORT 79 80struct gpt_part { 81 int gp_index; 82 uuid_t gp_type; 83 uint64_t gp_start; 84 uint64_t gp_end; 85}; 86 87static uuid_t efi = GPT_ENT_TYPE_EFI; 88static uuid_t freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; 89static uuid_t freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; 90static uuid_t freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; 91static uuid_t freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; 92static uuid_t ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; 93 94#endif 95 96#if defined(LOADER_GPT_SUPPORT) || defined(LOADER_MBR_SUPPORT) 97 98/* Given a size in 512 byte sectors, convert it to a human-readable number. */ 99static char * 100display_size(uint64_t size) 101{ 102 static char buf[80]; 103 char unit; 104 105 size /= 2; 106 unit = 'K'; 107 if (size >= 10485760000LL) { 108 size /= 1073741824; 109 unit = 'T'; 110 } else if (size >= 10240000) { 111 size /= 1048576; 112 unit = 'G'; 113 } else if (size >= 10000) { 114 size /= 1024; 115 unit = 'M'; 116 } 117 sprintf(buf, "%.6ld%cB", (long)size, unit); 118 return (buf); 119} 120 121#endif 122 123#ifdef LOADER_MBR_SUPPORT 124 125static void 126disk_checkextended(struct disk_devdesc *dev, 127 struct dos_partition *slicetab, int slicenum, int *nslicesp) 128{ 129 uint8_t buf[DISK_SECSIZE]; 130 struct dos_partition *dp; 131 uint32_t base; 132 int rc, i, start, end; 133 134 dp = &slicetab[slicenum]; 135 start = *nslicesp; 136 137 if (dp->dp_size == 0) 138 goto done; 139 if (dp->dp_typ != DOSPTYP_EXT) 140 goto done; 141 rc = dev->d_dev->dv_strategy(dev, F_READ, dp->dp_start, DISK_SECSIZE, 142 (char *) buf, NULL); 143 if (rc) 144 goto done; 145 if (buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) { 146 DEBUG("no magic in extended table"); 147 goto done; 148 } 149 base = dp->dp_start; 150 dp = (struct dos_partition *) &buf[DOSPARTOFF]; 151 for (i = 0; i < NDOSPART; i++, dp++) { 152 if (dp->dp_size == 0) 153 continue; 154 if (*nslicesp == NEXTDOSPART) 155 goto done; 156 dp->dp_start += base; 157 bcopy(dp, &slicetab[*nslicesp], sizeof(*dp)); 158 (*nslicesp)++; 159 } 160 end = *nslicesp; 161 162 /* 163 * now, recursively check the slices we just added 164 */ 165 for (i = start; i < end; i++) 166 disk_checkextended(dev, slicetab, i, nslicesp); 167done: 168 return; 169} 170 171static int 172disk_readslicetab(struct disk_devdesc *dev, 173 struct dos_partition **slicetabp, int *nslicesp) 174{ 175 struct dos_partition *slicetab = NULL; 176 int nslices, i; 177 int rc; 178 uint8_t buf[DISK_SECSIZE]; 179 180 /* 181 * Find the slice in the DOS slice table. 182 */ 183 rc = dev->d_dev->dv_strategy(dev, F_READ, 0, DISK_SECSIZE, 184 (char *) buf, NULL); 185 if (rc) { 186 DEBUG("error reading MBR"); 187 return (rc); 188 } 189 190 /* 191 * Check the slice table magic. 192 */ 193 if (buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) { 194 DEBUG("no slice table/MBR (no magic)"); 195 return (rc); 196 } 197 198 /* 199 * copy the partition table, then pick up any extended partitions. 200 */ 201 slicetab = malloc(NEXTDOSPART * sizeof(struct dos_partition)); 202 bcopy(buf + DOSPARTOFF, slicetab, 203 sizeof(struct dos_partition) * NDOSPART); 204 nslices = NDOSPART; /* extended slices start here */ 205 for (i = 0; i < NDOSPART; i++) 206 disk_checkextended(dev, slicetab, i, &nslices); 207 208 *slicetabp = slicetab; 209 *nslicesp = nslices; 210 return (0); 211} 212 213/* 214 * Search for the best MBR slice (typically the first FreeBSD slice). 215 */ 216static int 217disk_bestslice(struct dos_partition *slicetab, int nslices) 218{ 219 struct dos_partition *dp; 220 int pref, preflevel; 221 int i, prefslice; 222 223 prefslice = 0; 224 preflevel = PREF_NONE; 225 226 dp = &slicetab[0]; 227 for (i = 0; i < nslices; i++, dp++) { 228 switch (dp->dp_typ) { 229 case DOSPTYP_386BSD: /* FreeBSD */ 230 pref = dp->dp_flag & 0x80 ? PREF_FBSD_ACT : PREF_FBSD; 231 break; 232 233 case DOSPTYP_LINUX: 234 pref = dp->dp_flag & 0x80 ? PREF_LINUX_ACT : PREF_LINUX; 235 break; 236 237 case 0x01: /* DOS/Windows */ 238 case 0x04: 239 case 0x06: 240 case 0x0b: 241 case 0x0c: 242 case 0x0e: 243 pref = dp->dp_flag & 0x80 ? PREF_DOS_ACT : PREF_DOS; 244 break; 245 246 default: 247 pref = PREF_NONE; 248 } 249 if (pref < preflevel) { 250 preflevel = pref; 251 prefslice = i + 1; 252 } 253 } 254 return (prefslice); 255} 256 257static int 258disk_openmbr(struct disk_devdesc *dev) 259{ 260 struct dos_partition *slicetab = NULL, *dptr; 261 int nslices, sector, slice; 262 int rc; 263 uint8_t buf[DISK_SECSIZE]; 264 struct disklabel *lp; 265 266 /* 267 * Following calculations attempt to determine the correct value 268 * for dev->d_offset by looking for the slice and partition specified, 269 * or searching for reasonable defaults. 270 */ 271 rc = disk_readslicetab(dev, &slicetab, &nslices); 272 if (rc) 273 return (rc); 274 275 /* 276 * if a slice number was supplied but not found, this is an error. 277 */ 278 if (dev->d_slice > 0) { 279 slice = dev->d_slice - 1; 280 if (slice >= nslices) { 281 DEBUG("slice %d not found", slice); 282 rc = EPART; 283 goto out; 284 } 285 } 286 287 /* 288 * Check for the historically bogus MBR found on true dedicated disks 289 */ 290 if (slicetab[3].dp_typ == DOSPTYP_386BSD && 291 slicetab[3].dp_start == 0 && slicetab[3].dp_size == 50000) { 292 sector = 0; 293 goto unsliced; 294 } 295 296 /* 297 * Try to auto-detect the best slice; this should always give 298 * a slice number 299 */ 300 if (dev->d_slice == 0) { 301 slice = disk_bestslice(slicetab, nslices); 302 if (slice == -1) { 303 rc = ENOENT; 304 goto out; 305 } 306 dev->d_slice = slice; 307 } 308 309 /* 310 * Accept the supplied slice number unequivocally (we may be looking 311 * at a DOS partition). 312 * Note: we number 1-4, offsets are 0-3 313 */ 314 dptr = &slicetab[dev->d_slice - 1]; 315 sector = dptr->dp_start; 316 DEBUG("slice entry %d at %d, %d sectors", 317 dev->d_slice - 1, sector, dptr->dp_size); 318 319unsliced: 320 /* 321 * Now we have the slice offset, look for the partition in the 322 * disklabel if we have a partition to start with. 323 * 324 * XXX we might want to check the label checksum. 325 */ 326 if (dev->d_partition < 0) { 327 /* no partition, must be after the slice */ 328 DEBUG("opening raw slice"); 329 dev->d_offset = sector; 330 rc = 0; 331 goto out; 332 } 333 334 rc = dev->d_dev->dv_strategy(dev, F_READ, sector + LABELSECTOR, 335 DISK_SECSIZE, (char *) buf, NULL); 336 if (rc) { 337 DEBUG("error reading disklabel"); 338 goto out; 339 } 340 341 lp = (struct disklabel *) buf; 342 343 if (lp->d_magic != DISKMAGIC) { 344 DEBUG("no disklabel"); 345 rc = ENOENT; 346 goto out; 347 } 348 if (dev->d_partition >= lp->d_npartitions) { 349 DEBUG("partition '%c' exceeds partitions in table (a-'%c')", 350 'a' + dev->d_partition, 351 'a' + lp->d_npartitions); 352 rc = EPART; 353 goto out; 354 } 355 356 dev->d_offset = 357 lp->d_partitions[dev->d_partition].p_offset - 358 lp->d_partitions[RAW_PART].p_offset + 359 sector; 360 rc = 0; 361 362out: 363 if (slicetab) 364 free(slicetab); 365 return (rc); 366} 367 368/* 369 * Print out each valid partition in the disklabel of a FreeBSD slice. 370 * For size calculations, we assume a 512 byte sector size. 371 */ 372static void 373disk_printbsdslice(struct disk_devdesc *dev, daddr_t offset, 374 char *prefix, int verbose) 375{ 376 char line[80]; 377 char buf[DISK_SECSIZE]; 378 struct disklabel *lp; 379 int i, rc, fstype; 380 381 /* read disklabel */ 382 rc = dev->d_dev->dv_strategy(dev, F_READ, offset + LABELSECTOR, 383 DISK_SECSIZE, (char *) buf, NULL); 384 if (rc) 385 return; 386 lp =(struct disklabel *)(&buf[0]); 387 if (lp->d_magic != DISKMAGIC) { 388 sprintf(line, "%s: FFS bad disklabel\n", prefix); 389 pager_output(line); 390 return; 391 } 392 393 /* Print partitions */ 394 for (i = 0; i < lp->d_npartitions; i++) { 395 /* 396 * For each partition, make sure we know what type of fs it 397 * is. If not, then skip it. 398 */ 399 fstype = lp->d_partitions[i].p_fstype; 400 if (fstype != FS_BSDFFS && 401 fstype != FS_SWAP && 402 fstype != FS_VINUM) 403 continue; 404 405 /* Only print out statistics in verbose mode */ 406 if (verbose) 407 sprintf(line, " %s%c: %s %s (%d - %d)\n", 408 prefix, 'a' + i, 409 (fstype == FS_SWAP) ? "swap " : 410 (fstype == FS_VINUM) ? "vinum" : 411 "FFS ", 412 display_size(lp->d_partitions[i].p_size), 413 lp->d_partitions[i].p_offset, 414 (lp->d_partitions[i].p_offset 415 + lp->d_partitions[i].p_size)); 416 else 417 sprintf(line, " %s%c: %s\n", prefix, 'a' + i, 418 (fstype == FS_SWAP) ? "swap" : 419 (fstype == FS_VINUM) ? "vinum" : 420 "FFS"); 421 pager_output(line); 422 } 423} 424 425static void 426disk_printslice(struct disk_devdesc *dev, int slice, 427 struct dos_partition *dp, char *prefix, int verbose) 428{ 429 char stats[80]; 430 char line[80]; 431 432 if (verbose) 433 sprintf(stats, " %s (%d - %d)", display_size(dp->dp_size), 434 dp->dp_start, dp->dp_start + dp->dp_size); 435 else 436 stats[0] = '\0'; 437 438 switch (dp->dp_typ) { 439 case DOSPTYP_386BSD: 440 disk_printbsdslice(dev, (daddr_t)dp->dp_start, 441 prefix, verbose); 442 return; 443 case DOSPTYP_LINSWP: 444 sprintf(line, "%s: Linux swap%s\n", prefix, stats); 445 break; 446 case DOSPTYP_LINUX: 447 /* 448 * XXX 449 * read the superblock to confirm this is an ext2fs partition? 450 */ 451 sprintf(line, "%s: ext2fs%s\n", prefix, stats); 452 break; 453 case 0x00: /* unused partition */ 454 case DOSPTYP_EXT: 455 return; 456 case 0x01: 457 sprintf(line, "%s: FAT-12%s\n", prefix, stats); 458 break; 459 case 0x04: 460 case 0x06: 461 case 0x0e: 462 sprintf(line, "%s: FAT-16%s\n", prefix, stats); 463 break; 464 case 0x07: 465 sprintf(line, "%s: NTFS/HPFS%s\n", prefix, stats); 466 break; 467 case 0x0b: 468 case 0x0c: 469 sprintf(line, "%s: FAT-32%s\n", prefix, stats); 470 break; 471 default: 472 sprintf(line, "%s: Unknown fs: 0x%x %s\n", prefix, dp->dp_typ, 473 stats); 474 } 475 pager_output(line); 476} 477 478static int 479disk_printmbr(struct disk_devdesc *dev, char *prefix, int verbose) 480{ 481 struct dos_partition *slicetab; 482 int nslices, i; 483 int rc; 484 char line[80]; 485 486 rc = disk_readslicetab(dev, &slicetab, &nslices); 487 if (rc) 488 return (rc); 489 for (i = 0; i < nslices; i++) { 490 sprintf(line, "%ss%d", prefix, i + 1); 491 disk_printslice(dev, i, &slicetab[i], line, verbose); 492 } 493 free(slicetab); 494 return (0); 495} 496 497#endif 498 499#ifdef LOADER_GPT_SUPPORT 500 501static int 502disk_readgpt(struct disk_devdesc *dev, struct gpt_part **gptp, int *ngptp) 503{ 504 struct dos_partition *dp; 505 struct gpt_hdr *hdr; 506 struct gpt_ent *ent; 507 struct gpt_part *gptab = NULL; 508 int entries_per_sec, rc, i, part; 509 daddr_t lba, elba; 510 uint8_t gpt[DISK_SECSIZE], tbl[DISK_SECSIZE]; 511 512 /* 513 * Following calculations attempt to determine the correct value 514 * for dev->d_offset by looking for the slice and partition specified, 515 * or searching for reasonable defaults. 516 */ 517 rc = 0; 518 519 /* First, read the MBR and see if we have a PMBR. */ 520 rc = dev->d_dev->dv_strategy(dev, F_READ, 0, DISK_SECSIZE, 521 (char *) tbl, NULL); 522 if (rc) { 523 DEBUG("error reading MBR"); 524 return (EIO); 525 } 526 527 /* Check the slice table magic. */ 528 if (tbl[0x1fe] != 0x55 || tbl[0x1ff] != 0xaa) 529 return (ENXIO); 530 531 /* Check for GPT slice. */ 532 part = 0; 533 dp = (struct dos_partition *)(tbl + DOSPARTOFF); 534 for (i = 0; i < NDOSPART; i++) { 535 if (dp[i].dp_typ == 0xee) 536 part++; 537 else if ((part != 1) && (dp[i].dp_typ != 0x00)) 538 return (EINVAL); 539 } 540 if (part != 1) 541 return (EINVAL); 542 543 /* Read primary GPT table header. */ 544 rc = dev->d_dev->dv_strategy(dev, F_READ, 1, DISK_SECSIZE, 545 (char *) gpt, NULL); 546 if (rc) { 547 DEBUG("error reading GPT header"); 548 return (EIO); 549 } 550 hdr = (struct gpt_hdr *)gpt; 551 if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0 || 552 hdr->hdr_lba_self != 1 || hdr->hdr_revision < 0x00010000 || 553 hdr->hdr_entsz < sizeof(*ent) || 554 DISK_SECSIZE % hdr->hdr_entsz != 0) { 555 DEBUG("Invalid GPT header\n"); 556 return (EINVAL); 557 } 558 559 /* Walk the partition table to count valid partitions. */ 560 part = 0; 561 entries_per_sec = DISK_SECSIZE / hdr->hdr_entsz; 562 elba = hdr->hdr_lba_table + hdr->hdr_entries / entries_per_sec; 563 for (lba = hdr->hdr_lba_table; lba < elba; lba++) { 564 rc = dev->d_dev->dv_strategy(dev, F_READ, lba, DISK_SECSIZE, 565 (char *) tbl, NULL); 566 if (rc) { 567 DEBUG("error reading GPT table"); 568 return (EIO); 569 } 570 for (i = 0; i < entries_per_sec; i++) { 571 ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz); 572 if (uuid_is_nil(&ent->ent_type, NULL) || 573 ent->ent_lba_start == 0 || 574 ent->ent_lba_end < ent->ent_lba_start) 575 continue; 576 part++; 577 } 578 } 579 580 /* Save the important information about all the valid partitions. */ 581 if (part != 0) { 582 gptab = malloc(part * sizeof(struct gpt_part)); 583 part = 0; 584 for (lba = hdr->hdr_lba_table; lba < elba; lba++) { 585 rc = dev->d_dev->dv_strategy(dev, F_READ, lba, DISK_SECSIZE, 586 (char *) tbl, NULL); 587 if (rc) { 588 DEBUG("error reading GPT table"); 589 free(gptab); 590 return (EIO); 591 } 592 for (i = 0; i < entries_per_sec; i++) { 593 ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz); 594 if (uuid_is_nil(&ent->ent_type, NULL) || 595 ent->ent_lba_start == 0 || 596 ent->ent_lba_end < ent->ent_lba_start) 597 continue; 598 gptab[part].gp_index = (lba - hdr->hdr_lba_table) * 599 entries_per_sec + i + 1; 600 gptab[part].gp_type = ent->ent_type; 601 gptab[part].gp_start = ent->ent_lba_start; 602 gptab[part].gp_end = ent->ent_lba_end; 603 part++; 604 } 605 } 606 } 607 608 *gptp = gptab; 609 *ngptp = part; 610 return (0); 611} 612 613static struct gpt_part * 614disk_bestgpt(struct gpt_part *gpt, int ngpt) 615{ 616 struct gpt_part *gp, *prefpart; 617 int i, pref, preflevel; 618 619 prefpart = NULL; 620 preflevel = PREF_NONE; 621 622 gp = gpt; 623 for (i = 0; i < ngpt; i++, gp++) { 624 /* Windows. XXX: Also Linux. */ 625 if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL)) 626 pref = PREF_DOS; 627 /* FreeBSD */ 628 else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL) || 629 uuid_equal(&gp->gp_type, &freebsd_zfs, NULL)) 630 pref = PREF_FBSD; 631 else 632 pref = PREF_NONE; 633 if (pref < preflevel) { 634 preflevel = pref; 635 prefpart = gp; 636 } 637 } 638 return (prefpart); 639} 640 641static int 642disk_opengpt(struct disk_devdesc *dev) 643{ 644 struct gpt_part *gpt = NULL, *gp; 645 int rc, ngpt, i; 646 647 rc = disk_readgpt(dev, &gpt, &ngpt); 648 if (rc) 649 return (rc); 650 651 /* Is this a request for the whole disk? */ 652 if (dev->d_slice < 0) { 653 dev->d_offset = 0; 654 rc = 0; 655 goto out; 656 } 657 658 /* 659 * If a partition number was supplied, then the user is trying to use 660 * an MBR address rather than a GPT address, so fail. 661 */ 662 if (dev->d_partition != 0xff) { 663 rc = ENOENT; 664 goto out; 665 } 666 667 /* If a slice number was supplied but not found, this is an error. */ 668 gp = NULL; 669 if (dev->d_slice > 0) { 670 for (i = 0; i < ngpt; i++) { 671 if (gpt[i].gp_index == dev->d_slice) { 672 gp = &gpt[i]; 673 break; 674 } 675 } 676 if (gp == NULL) { 677 DEBUG("partition %d not found", dev->d_slice); 678 rc = ENOENT; 679 goto out; 680 } 681 } 682 683 /* Try to auto-detect the best partition. */ 684 if (dev->d_slice == 0) { 685 gp = disk_bestgpt(gpt, ngpt); 686 if (gp == NULL) { 687 rc = ENOENT; 688 goto out; 689 } 690 dev->d_slice = gp->gp_index; 691 } 692 693 dev->d_offset = gp->gp_start; 694 rc = 0; 695 696out: 697 if (gpt) 698 free(gpt); 699 return (rc); 700} 701 702static void 703disk_printgptpart(struct disk_devdesc *dev, struct gpt_part *gp, 704 char *prefix, int verbose) 705{ 706 char stats[80]; 707 char line[96]; 708 709 if (verbose) 710 sprintf(stats, " %s", 711 display_size(gp->gp_end + 1 - gp->gp_start)); 712 else 713 stats[0] = '\0'; 714 715 if (uuid_equal(&gp->gp_type, &efi, NULL)) 716 sprintf(line, "%s: EFI %s\n", prefix, stats); 717 else if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL)) 718 sprintf(line, "%s: FAT/NTFS %s\n", prefix, stats); 719 else if (uuid_equal(&gp->gp_type, &freebsd_boot, NULL)) 720 sprintf(line, "%s: FreeBSD boot%s\n", prefix, stats); 721 else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL)) 722 sprintf(line, "%s: FreeBSD UFS %s\n", prefix, stats); 723 else if (uuid_equal(&gp->gp_type, &freebsd_zfs, NULL)) 724 sprintf(line, "%s: FreeBSD ZFS %s\n", prefix, stats); 725 else if (uuid_equal(&gp->gp_type, &freebsd_swap, NULL)) 726 sprintf(line, "%s: FreeBSD swap%s\n", prefix, stats); 727 else 728 sprintf(line, 729 "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x%s\n", 730 prefix, 731 gp->gp_type.time_low, gp->gp_type.time_mid, 732 gp->gp_type.time_hi_and_version, 733 gp->gp_type.clock_seq_hi_and_reserved, 734 gp->gp_type.clock_seq_low, 735 gp->gp_type.node[0], 736 gp->gp_type.node[1], 737 gp->gp_type.node[2], 738 gp->gp_type.node[3], 739 gp->gp_type.node[4], 740 gp->gp_type.node[5], 741 stats); 742 pager_output(line); 743} 744 745static int 746disk_printgpt(struct disk_devdesc *dev, char *prefix, int verbose) 747{ 748 struct gpt_part *gpt = NULL; 749 int rc, ngpt, i; 750 char line[80]; 751 752 rc = disk_readgpt(dev, &gpt, &ngpt); 753 if (rc) 754 return (rc); 755 for (i = 0; i < ngpt; i++) { 756 sprintf(line, "%sp%d", prefix, i + 1); 757 disk_printgptpart(dev, &gpt[i], line, verbose); 758 } 759 free(gpt); 760 return (0); 761} 762 763#endif 764 765int 766disk_open(struct disk_devdesc *dev) 767{ 768 int rc; 769 770 rc = 0; 771 /* 772 * While we are reading disk metadata, make sure we do it relative 773 * to the start of the disk 774 */ 775 dev->d_offset = 0; 776 777#ifdef LOADER_GPT_SUPPORT 778 rc = disk_opengpt(dev); 779 if (rc) 780#endif 781#ifdef LOADER_MBR_SUPPORT 782 rc = disk_openmbr(dev); 783#endif 784 785 return (rc); 786} 787 788void 789disk_print(struct disk_devdesc *dev, char *prefix, int verbose) 790{ 791 792#ifdef LOADER_GPT_SUPPORT 793 if (disk_printgpt(dev, prefix, verbose) == 0) 794 return; 795#endif 796#ifdef LOADER_MBR_SUPPORT 797 disk_printmbr(dev, prefix, verbose); 798#endif 799} 800