1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 24 * Copyright 2019 Toomas Soome <tsoome@me.com> 25 * Copyright 2025 Edgecast Cloud LLC. 26 */ 27 28 #include <stdio.h> 29 #include <stdbool.h> 30 #include <errno.h> 31 #include <unistd.h> 32 #include <fcntl.h> 33 #include <assert.h> 34 #include <locale.h> 35 #include <strings.h> 36 #include <libfdisk.h> 37 #include <err.h> 38 #include <time.h> 39 #include <spawn.h> 40 41 #include <sys/dktp/fdisk.h> 42 #include <sys/dkio.h> 43 #include <sys/vtoc.h> 44 #include <sys/multiboot.h> 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 #include <sys/sysmacros.h> 48 #include <sys/efi_partition.h> 49 #include <sys/queue.h> 50 #include <sys/mount.h> 51 #include <sys/mntent.h> 52 #include <sys/mnttab.h> 53 #include <sys/wait.h> 54 #include <libfstyp.h> 55 #include <libgen.h> 56 #include <uuid/uuid.h> 57 58 #include "installboot.h" 59 #include "bblk_einfo.h" 60 #include "boot_utils.h" 61 #include "mboot_extra.h" 62 #include "getresponse.h" 63 64 #ifndef TEXT_DOMAIN 65 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 66 #endif 67 68 /* 69 * BIOS bootblock installation: 70 * 71 * 1. MBR is first sector of the disk. If the file system on target is 72 * ufs or zfs, the same MBR code is installed on first sector of the 73 * partition as well; this will allow to have real MBR sector to be 74 * replaced by some other boot loader and have illumos chainloaded. 75 * 76 * installboot will record the start LBA and size of stage2 code in MBR code. 77 * On boot, the MBR code will read the stage2 code and executes it. 78 * 79 * 2. Stage2 location depends on file system type; 80 * In case of zfs, installboot will store stage2 to zfs bootblk area, 81 * which is 512k bytes from partition start and size is 3.5MB. 82 * 83 * In case of ufs, the stage2 location is 50 512B sectors from 84 * Solaris2 MBR partition start, within boot slice, boot slice size is 85 * one cylinder. 86 * 87 * In case of pcfs, the stage2 location is 50 512B sectors from beginning 88 * of the disk, filling the space between MBR and first partition. 89 * This location assumes no other bootloader and the space is one cylinder, 90 * as first partition is starting from cylinder 1. 91 * 92 * In case of GPT partitioning and if file system is not zfs, the boot 93 * support is only possible with dedicated boot partition. For GPT, 94 * the current implementation is using BOOT partition, which must exist. 95 * BOOT partition does only contain raw boot blocks, without any file system. 96 * 97 * Loader stage2 is created with embedded version, by using fake multiboot (MB) 98 * header within first 32k and EINFO block is at the end of the actual 99 * boot block. MB header load_addr is set to 0 and load_end_addr is set to 100 * actual block end, so the EINFO size is (file size - load_end_addr). 101 * installboot does also store the illumos boot partition LBA to MB space, 102 * starting from bss_end_addr structure member location; stage2 will 103 * detect the partition and file system based on this value. 104 * 105 * Stored location values in MBR/stage2 also mean the bootblocks must be 106 * reinstalled in case the partition content is relocated. 107 */ 108 109 static bool write_mbr = false; 110 static bool write_vbr = false; 111 static bool force_mbr = false; 112 static bool force_update = false; 113 static bool do_getinfo = false; 114 static bool do_version = false; 115 static bool do_mirror_bblk = false; 116 static bool strip = false; 117 static bool verbose_dump = false; 118 static size_t sector_size = SECTOR_SIZE; 119 120 /* Versioning string, if present. */ 121 static char *update_str; 122 123 /* Default location of boot programs. */ 124 static char *boot_dir = "/boot"; 125 126 /* Our boot programs */ 127 #define STAGE1 "pmbr" 128 #define STAGE2 "gptzfsboot" 129 #define BOOTIA32 "bootia32.efi" 130 #define BOOTX64 "bootx64.efi" 131 #define LOADER32 "loader32.efi" 132 #define LOADER64 "loader64.efi" 133 134 static char *stage1; 135 static char *stage2; 136 static char *efi32; 137 static char *efi64; 138 139 #define GRUB_VERSION_OFF (0x3e) 140 #define GRUB_COMPAT_VERSION_MAJOR 3 141 #define GRUB_COMPAT_VERSION_MINOR 2 142 #define GRUB_VERSION (2 << 8 | 3) /* 3.2 */ 143 144 #define LOADER_VERSION (1) 145 #define LOADER_JOYENT_VERSION (2) 146 147 typedef enum { 148 MBR_TYPE_UNKNOWN, 149 MBR_TYPE_GRUB1, 150 MBR_TYPE_LOADER, 151 MBR_TYPE_LOADER_JOYENT, 152 } mbr_type_t; 153 154 /* 155 * Temporary buffer to store the first 32K of data looking for a multiboot 156 * signature. 157 */ 158 char mboot_scan[MBOOT_SCAN_SIZE]; 159 160 /* Function prototypes. */ 161 static void check_options(char *); 162 static int open_device(const char *); 163 static char *make_blkdev(const char *); 164 165 static int read_bootblock_from_file(const char *, ib_bootblock_t *); 166 static void add_bootblock_einfo(ib_bootblock_t *, char *); 167 static void prepare_bootblock(ib_data_t *, struct partlist *, char *); 168 static int handle_install(char *, int, char **); 169 static int handle_getinfo(char *, int, char **); 170 static int handle_mirror(char *, int, char **); 171 static void usage(char *, int) __NORETURN; 172 173 static char * 174 stagefs_mount(char *blkdev, struct partlist *plist) 175 { 176 char *path; 177 char optbuf[MAX_MNTOPT_STR] = { '\0', }; 178 char *template = strdup("/tmp/ibootXXXXXX"); 179 int ret; 180 181 if (template == NULL) 182 return (NULL); 183 184 if ((path = mkdtemp(template)) == NULL) { 185 free(template); 186 return (NULL); 187 } 188 189 (void) snprintf(optbuf, MAX_MNTOPT_STR, "timezone=%d", 190 timezone); 191 ret = mount(blkdev, path, MS_OPTIONSTR, 192 MNTTYPE_PCFS, NULL, 0, optbuf, MAX_MNTOPT_STR); 193 if (ret != 0) { 194 (void) rmdir(path); 195 free(path); 196 path = NULL; 197 } 198 plist->pl_device->stage.mntpnt = path; 199 return (path); 200 } 201 202 static void 203 install_stage1_cb(void *data, struct partlist *plist) 204 { 205 int rv, fd; 206 ib_device_t *device = plist->pl_device; 207 208 if (plist->pl_type == IB_BBLK_MBR && !write_mbr) 209 return; 210 211 if ((fd = open_device(plist->pl_devname)) == -1) { 212 (void) fprintf(stdout, gettext("cannot open " 213 "device %s\n"), plist->pl_devname); 214 perror("open"); 215 return; 216 } 217 218 rv = write_out(fd, plist->pl_stage, sector_size, 0); 219 if (rv != BC_SUCCESS) { 220 (void) fprintf(stdout, gettext("cannot write " 221 "partition boot sector\n")); 222 perror("write"); 223 } else { 224 (void) fprintf(stdout, gettext("stage1 written to " 225 "%s %d sector 0 (abs %d)\n\n"), 226 device->devtype == IB_DEV_MBR? "partition" : "slice", 227 device->stage.id, device->stage.start); 228 } 229 } 230 231 static void 232 install_stage2_cb(void *data, struct partlist *plist) 233 { 234 ib_bootblock_t *bblock = plist->pl_src_data; 235 int fd, ret; 236 off_t offset; 237 uint64_t abs; 238 239 /* 240 * ZFS bootblock area is 3.5MB, make sure we can fit. 241 * buf_size is size of bootblk+EINFO. 242 */ 243 if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) { 244 (void) fprintf(stderr, gettext("bootblock is too large\n")); 245 return; 246 } 247 248 abs = plist->pl_device->stage.start + plist->pl_device->stage.offset; 249 250 if ((fd = open_device(plist->pl_devname)) == -1) { 251 (void) fprintf(stdout, gettext("cannot open " 252 "device %s\n"), plist->pl_devname); 253 perror("open"); 254 return; 255 } 256 offset = plist->pl_device->stage.offset * sector_size; 257 ret = write_out(fd, bblock->buf, bblock->buf_size, offset); 258 (void) close(fd); 259 if (ret != BC_SUCCESS) { 260 BOOT_DEBUG("Error writing the ZFS bootblock " 261 "to %s at offset %d\n", plist->pl_devname, offset); 262 return; 263 } 264 (void) fprintf(stdout, gettext("bootblock written for %s," 265 " %d sectors starting at %d (abs %lld)\n\n"), plist->pl_devname, 266 bblock->buf_size / sector_size, offset / sector_size, abs); 267 } 268 269 static bool 270 mkfs_pcfs(const char *dev) 271 { 272 pid_t pid, w; 273 posix_spawnattr_t attr; 274 posix_spawn_file_actions_t file_actions; 275 int status; 276 char *cmd[7]; 277 278 if (posix_spawnattr_init(&attr)) 279 return (false); 280 if (posix_spawn_file_actions_init(&file_actions)) { 281 (void) posix_spawnattr_destroy(&attr); 282 return (false); 283 } 284 285 if (posix_spawnattr_setflags(&attr, 286 POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP)) { 287 (void) posix_spawnattr_destroy(&attr); 288 (void) posix_spawn_file_actions_destroy(&file_actions); 289 return (false); 290 } 291 if (posix_spawn_file_actions_addopen(&file_actions, 0, "/dev/null", 292 O_RDONLY, 0)) { 293 (void) posix_spawnattr_destroy(&attr); 294 (void) posix_spawn_file_actions_destroy(&file_actions); 295 return (false); 296 } 297 298 cmd[0] = "/usr/sbin/mkfs"; 299 cmd[1] = "-F"; 300 cmd[2] = "pcfs"; 301 cmd[3] = "-o"; 302 cmd[4] = "fat=32"; 303 cmd[5] = (char *)dev; 304 cmd[6] = NULL; 305 306 if (posix_spawn(&pid, cmd[0], &file_actions, &attr, cmd, NULL)) 307 return (false); 308 (void) posix_spawnattr_destroy(&attr); 309 (void) posix_spawn_file_actions_destroy(&file_actions); 310 311 do { 312 w = waitpid(pid, &status, 0); 313 } while (w == -1 && errno == EINTR); 314 if (w == -1) 315 status = -1; 316 317 return (status != -1); 318 } 319 320 static void 321 install_esp_cb(void *data, struct partlist *plist) 322 { 323 fstyp_handle_t fhdl; 324 const char *fident; 325 bool pcfs; 326 char *blkdev, *path, *file; 327 FILE *fp; 328 struct mnttab mp, mpref = { 0 }; 329 ib_bootblock_t *bblock = plist->pl_src_data; 330 int fd, ret; 331 332 if ((fd = open_device(plist->pl_devname)) == -1) 333 return; 334 335 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 336 (void) close(fd); 337 return; 338 } 339 340 pcfs = false; 341 if (fstyp_ident(fhdl, NULL, &fident) == 0) { 342 if (strcmp(fident, MNTTYPE_PCFS) == 0) 343 pcfs = true; 344 } 345 fstyp_fini(fhdl); 346 (void) close(fd); 347 348 if (!pcfs) { 349 (void) printf(gettext("Creating pcfs on ESP %s\n"), 350 plist->pl_devname); 351 352 if (!mkfs_pcfs(plist->pl_devname)) { 353 (void) fprintf(stderr, gettext("mkfs -F pcfs failed " 354 "on %s\n"), plist->pl_devname); 355 return; 356 } 357 } 358 blkdev = make_blkdev(plist->pl_devname); 359 if (blkdev == NULL) 360 return; 361 362 fp = fopen(MNTTAB, "r"); 363 if (fp == NULL) { 364 perror("fopen"); 365 free(blkdev); 366 return; 367 } 368 369 mpref.mnt_special = blkdev; 370 ret = getmntany(fp, &mp, &mpref); 371 (void) fclose(fp); 372 if (ret == 0) 373 path = mp.mnt_mountp; 374 else 375 path = stagefs_mount(blkdev, plist); 376 377 free(blkdev); 378 if (path == NULL) 379 return; 380 381 if (asprintf(&file, "%s%s", path, "/EFI") < 0) { 382 perror(gettext("Memory allocation failure")); 383 return; 384 } 385 386 ret = mkdir(file, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 387 if (ret == 0 || errno == EEXIST) { 388 free(file); 389 if (asprintf(&file, "%s%s", path, "/EFI/Boot") < 0) { 390 perror(gettext("Memory allocation failure")); 391 return; 392 } 393 ret = mkdir(file, 394 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 395 if (errno == EEXIST) 396 ret = 0; 397 } 398 free(file); 399 if (ret < 0) { 400 perror("mkdir"); 401 return; 402 } 403 404 if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) { 405 perror(gettext("Memory allocation failure")); 406 return; 407 } 408 409 /* Write stage file. Should create temp file and rename. */ 410 (void) chmod(file, S_IRUSR | S_IWUSR); 411 fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 412 if (fd != -1) { 413 ret = write_out(fd, bblock->buf, bblock->buf_size, 0); 414 if (ret == BC_SUCCESS) { 415 (void) fprintf(stdout, 416 gettext("bootblock written to %s\n\n"), file); 417 } else { 418 (void) fprintf(stdout, 419 gettext("error while writing %s\n"), file); 420 } 421 (void) fchmod(fd, S_IRUSR | S_IRGRP | S_IROTH); 422 (void) close(fd); 423 } 424 free(file); 425 } 426 427 /* 428 * MBR setup only depends on write_mbr toggle. 429 */ 430 static bool 431 compare_mbr_cb(struct partlist *plist) 432 { 433 /* get confirmation for -m */ 434 if (write_mbr && !force_mbr) { 435 (void) fprintf(stdout, gettext("Updating master boot sector " 436 "destroys existing boot managers (if any).\n" 437 "continue (y/n)? ")); 438 if (!yes()) { 439 write_mbr = false; 440 (void) fprintf(stdout, gettext("master boot sector " 441 "not updated\n")); 442 } 443 } 444 if (write_mbr) 445 (void) printf("%s is newer than one in %s\n", 446 plist->pl_src_name, plist->pl_devname); 447 return (write_mbr); 448 } 449 450 /* 451 * VBR setup is done in pair with stage2. 452 */ 453 static bool 454 compare_stage1_cb(struct partlist *plist) 455 { 456 if (write_vbr) { 457 (void) printf("%s is newer than one in %s\n", 458 plist->pl_src_name, plist->pl_devname); 459 } 460 return (write_vbr); 461 } 462 463 /* 464 * Return true if we can update, false if not. 465 */ 466 static bool 467 compare_einfo_cb(struct partlist *plist) 468 { 469 ib_bootblock_t *bblock, *bblock_file; 470 bblk_einfo_t *einfo, *einfo_file; 471 bblk_hs_t bblock_hs; 472 bool rv; 473 474 bblock_file = plist->pl_src_data; 475 if (bblock_file == NULL) 476 return (false); /* source is missing, cannot update */ 477 478 bblock = plist->pl_stage; 479 if (bblock == NULL || 480 bblock->extra == NULL || 481 bblock->extra_size == 0) { 482 if (plist->pl_type == IB_BBLK_STAGE2) 483 write_vbr = true; 484 return (true); 485 } 486 487 einfo = find_einfo(bblock->extra, bblock->extra_size); 488 if (einfo == NULL) { 489 BOOT_DEBUG("No extended information available on disk\n"); 490 if (plist->pl_type == IB_BBLK_STAGE2) 491 write_vbr = true; 492 return (true); 493 } 494 495 einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size); 496 if (einfo_file == NULL) { 497 /* 498 * loader bootblock is versioned. missing version means 499 * probably incompatible block. installboot can not install 500 * grub, for example. 501 */ 502 (void) fprintf(stderr, 503 gettext("ERROR: non versioned bootblock in file\n")); 504 return (false); 505 } else { 506 if (update_str == NULL) { 507 update_str = einfo_get_string(einfo_file); 508 do_version = true; 509 } 510 } 511 512 if (!do_version || update_str == NULL) { 513 (void) fprintf(stderr, 514 gettext("WARNING: target device %s has a " 515 "versioned bootblock that is going to be overwritten by a " 516 "non versioned one\n"), plist->pl_devname); 517 if (plist->pl_type == IB_BBLK_STAGE2) 518 write_vbr = true; 519 return (true); 520 } 521 522 if (force_update) { 523 BOOT_DEBUG("Forcing update of %s bootblock\n", 524 plist->pl_devname); 525 if (plist->pl_type == IB_BBLK_STAGE2) 526 write_vbr = true; 527 return (true); 528 } 529 530 BOOT_DEBUG("Ready to check installed version vs %s\n", update_str); 531 532 bblock_hs.src_buf = (unsigned char *)bblock_file->file; 533 bblock_hs.src_size = bblock_file->file_size; 534 535 rv = einfo_should_update(einfo, &bblock_hs, update_str); 536 if (rv == false) { 537 (void) fprintf(stderr, gettext("Bootblock version installed " 538 "on %s is more recent or identical to\n%s\n" 539 "Use -F to override or install without the -u option.\n\n"), 540 plist->pl_devname, plist->pl_src_name); 541 } else { 542 (void) printf("%s is newer than one in %s\n", 543 plist->pl_src_name, plist->pl_devname); 544 if (plist->pl_type == IB_BBLK_STAGE2) 545 write_vbr = true; 546 } 547 return (rv); 548 } 549 550 static bool 551 read_stage1_cb(struct partlist *plist) 552 { 553 int fd; 554 bool rv = false; 555 556 if ((fd = open_device(plist->pl_devname)) == -1) 557 return (rv); 558 559 if (plist->pl_stage == NULL) 560 plist->pl_stage = calloc(1, sector_size); 561 562 if (plist->pl_stage == NULL) { 563 perror("calloc"); 564 goto done; 565 } 566 567 if (pread(fd, plist->pl_stage, sector_size, 0) == -1) { 568 perror("pread"); 569 goto done; 570 } 571 rv = true; 572 done: 573 (void) close(fd); 574 return (rv); 575 } 576 577 static bool 578 read_stage1_bbl_cb(struct partlist *plist) 579 { 580 int fd; 581 void *data; 582 bool rv = false; 583 584 /* Allocate actual sector size. */ 585 data = calloc(1, sector_size); 586 if (data == NULL) 587 return (rv); 588 589 /* read the stage1 file from filesystem */ 590 fd = open(plist->pl_src_name, O_RDONLY); 591 if (fd == -1 || 592 read(fd, data, SECTOR_SIZE) != SECTOR_SIZE) { 593 (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"), 594 plist->pl_src_name); 595 free(data); 596 if (fd != -1) 597 (void) close(fd); 598 return (rv); 599 } 600 601 plist->pl_src_data = data; 602 (void) close(fd); 603 return (true); 604 } 605 606 static bool 607 read_stage2_cb(struct partlist *plist) 608 { 609 ib_device_t *device; 610 ib_bootblock_t *bblock; 611 int fd; 612 uint32_t size, offset; 613 uint32_t buf_size; 614 uint32_t mboot_off; 615 multiboot_header_t *mboot; 616 size_t scan_size; 617 618 bblock = calloc(1, sizeof (ib_bootblock_t)); 619 if (bblock == NULL) 620 return (false); 621 622 if ((fd = open_device(plist->pl_devname)) == -1) { 623 free(bblock); 624 return (false); 625 } 626 627 device = plist->pl_device; 628 plist->pl_stage = bblock; 629 offset = device->stage.offset * sector_size; 630 scan_size = MIN(sizeof (mboot_scan), 631 (device->stage.size - device->stage.offset) * sector_size); 632 633 if (read_in(fd, mboot_scan, scan_size, offset) 634 != BC_SUCCESS) { 635 BOOT_DEBUG("Error reading bootblock area\n"); 636 perror("read"); 637 (void) close(fd); 638 return (false); 639 } 640 641 /* No multiboot means no chance of knowing bootblock size */ 642 if (find_multiboot(mboot_scan, scan_size, &mboot_off) 643 != BC_SUCCESS) { 644 BOOT_DEBUG("Unable to find multiboot header\n"); 645 (void) close(fd); 646 return (false); 647 } 648 mboot = (multiboot_header_t *)(mboot_scan + mboot_off); 649 650 /* 651 * make sure mboot has sane values 652 */ 653 if (mboot->load_end_addr == 0 || 654 mboot->load_end_addr < mboot->load_addr) { 655 (void) close(fd); 656 return (false); 657 } 658 659 /* 660 * Currently, the amount of space reserved for extra information 661 * is "fixed". We may have to scan for the terminating extra payload 662 * in the future. 663 */ 664 size = mboot->load_end_addr - mboot->load_addr; 665 buf_size = P2ROUNDUP(size + sector_size, sector_size); 666 bblock->file_size = size; 667 668 bblock->buf = malloc(buf_size); 669 if (bblock->buf == NULL) { 670 BOOT_DEBUG("Unable to allocate enough memory to read" 671 " the extra bootblock from the disk\n"); 672 perror(gettext("Memory allocation failure")); 673 (void) close(fd); 674 return (false); 675 } 676 bblock->buf_size = buf_size; 677 678 if (read_in(fd, bblock->buf, buf_size, offset) != BC_SUCCESS) { 679 BOOT_DEBUG("Error reading the bootblock\n"); 680 (void) free(bblock->buf); 681 bblock->buf = NULL; 682 (void) close(fd); 683 return (false); 684 } 685 686 /* Update pointers. */ 687 bblock->file = bblock->buf; 688 bblock->mboot_off = mboot_off; 689 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off); 690 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 691 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 692 693 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 694 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 695 bblock->extra_size, bblock->buf, bblock->buf_size); 696 697 return (true); 698 } 699 700 static bool 701 read_einfo_file_cb(struct partlist *plist) 702 { 703 int rc; 704 void *stage; 705 706 stage = calloc(1, sizeof (ib_bootblock_t)); 707 if (stage == NULL) 708 return (false); 709 710 rc = read_bootblock_from_file(plist->pl_devname, stage); 711 if (rc != BC_SUCCESS) { 712 free(stage); 713 stage = NULL; 714 } 715 plist->pl_stage = stage; 716 return (rc == BC_SUCCESS); 717 } 718 719 static bool 720 read_stage2_file_cb(struct partlist *plist) 721 { 722 int rc; 723 void *data; 724 725 data = calloc(1, sizeof (ib_bootblock_t)); 726 if (data == NULL) 727 return (false); 728 729 rc = read_bootblock_from_file(plist->pl_src_name, data); 730 if (rc != BC_SUCCESS) { 731 free(data); 732 data = NULL; 733 } 734 plist->pl_src_data = data; 735 return (rc == BC_SUCCESS); 736 } 737 738 /* 739 * convert /dev/rdsk/... to /dev/dsk/... 740 */ 741 static char * 742 make_blkdev(const char *path) 743 { 744 char *tmp; 745 char *ptr = strdup(path); 746 747 if (ptr == NULL) 748 return (ptr); 749 750 tmp = strstr(ptr, "rdsk"); 751 if (tmp == NULL) { 752 free(ptr); 753 return (NULL); /* Something is very wrong */ 754 } 755 /* This is safe because we do shorten the string */ 756 (void) memmove(tmp, tmp + 1, strlen(tmp)); 757 return (ptr); 758 } 759 760 /* 761 * Try to mount ESP and read boot program. 762 */ 763 static bool 764 read_einfo_esp_cb(struct partlist *plist) 765 { 766 fstyp_handle_t fhdl; 767 const char *fident; 768 char *blkdev, *path, *file; 769 bool rv = false; 770 FILE *fp; 771 struct mnttab mp, mpref = { 0 }; 772 int fd, ret; 773 774 if ((fd = open_device(plist->pl_devname)) == -1) 775 return (rv); 776 777 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 778 (void) close(fd); 779 return (rv); 780 } 781 782 if (fstyp_ident(fhdl, NULL, &fident) != 0) { 783 fstyp_fini(fhdl); 784 (void) close(fd); 785 (void) fprintf(stderr, gettext("Failed to detect file " 786 "system type\n")); 787 return (rv); 788 } 789 790 /* We only do expect pcfs. */ 791 if (strcmp(fident, MNTTYPE_PCFS) != 0) { 792 (void) fprintf(stderr, 793 gettext("File system %s is not supported.\n"), fident); 794 fstyp_fini(fhdl); 795 (void) close(fd); 796 return (rv); 797 } 798 fstyp_fini(fhdl); 799 (void) close(fd); 800 801 blkdev = make_blkdev(plist->pl_devname); 802 if (blkdev == NULL) 803 return (rv); 804 805 /* mount ESP if needed, read boot program(s) and unmount. */ 806 fp = fopen(MNTTAB, "r"); 807 if (fp == NULL) { 808 perror("fopen"); 809 free(blkdev); 810 return (rv); 811 } 812 813 mpref.mnt_special = blkdev; 814 ret = getmntany(fp, &mp, &mpref); 815 (void) fclose(fp); 816 if (ret == 0) 817 path = mp.mnt_mountp; 818 else 819 path = stagefs_mount(blkdev, plist); 820 821 free(blkdev); 822 if (path == NULL) 823 return (rv); 824 825 if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) { 826 return (rv); 827 } 828 829 plist->pl_stage = calloc(1, sizeof (ib_bootblock_t)); 830 if (plist->pl_stage == NULL) { 831 free(file); 832 return (rv); 833 } 834 if (read_bootblock_from_file(file, plist->pl_stage) != BC_SUCCESS) { 835 free(plist->pl_stage); 836 plist->pl_stage = NULL; 837 } else { 838 rv = true; 839 } 840 841 free(file); 842 return (rv); 843 } 844 845 static void 846 print_stage1_cb(struct partlist *plist) 847 { 848 struct mboot *mbr; 849 struct ipart *part; 850 mbr_type_t type = MBR_TYPE_UNKNOWN; 851 bool pmbr = false; 852 char *label; 853 854 mbr = plist->pl_stage; 855 856 if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) { 857 type = MBR_TYPE_GRUB1; 858 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) { 859 type = MBR_TYPE_LOADER; 860 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) { 861 type = MBR_TYPE_LOADER_JOYENT; 862 } 863 864 part = (struct ipart *)mbr->parts; 865 for (int i = 0; i < FD_NUMPART; i++) { 866 if (part[i].systid == EFI_PMBR) 867 pmbr = true; 868 } 869 870 if (plist->pl_type == IB_BBLK_MBR) 871 label = pmbr ? "PMBR" : "MBR"; 872 else 873 label = "VBR"; 874 875 printf("%s block from %s:\n", label, plist->pl_devname); 876 877 switch (type) { 878 case MBR_TYPE_UNKNOWN: 879 printf("Format: unknown\n"); 880 break; 881 case MBR_TYPE_GRUB1: 882 printf("Format: grub1\n"); 883 break; 884 case MBR_TYPE_LOADER: 885 printf("Format: loader (illumos)\n"); 886 break; 887 case MBR_TYPE_LOADER_JOYENT: 888 printf("Format: loader (joyent)\n"); 889 break; 890 } 891 892 printf("Signature: 0x%hx (%s)\n", mbr->signature, 893 mbr->signature == MBB_MAGIC ? "valid" : "invalid"); 894 895 printf("UniqueMBRDiskSignature: %#lx\n", 896 *(uint32_t *)&mbr->bootinst[STAGE1_SIG]); 897 898 if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) { 899 char uuid[UUID_PRINTABLE_STRING_LENGTH]; 900 901 printf("Loader STAGE1_STAGE2_LBA: %llu\n", 902 *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]); 903 904 printf("Loader STAGE1_STAGE2_SIZE: %hu\n", 905 *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]); 906 907 uuid_unparse((uchar_t *)&mbr->bootinst[STAGE1_STAGE2_UUID], 908 uuid); 909 910 printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid); 911 } 912 printf("\n"); 913 } 914 915 static void 916 print_einfo_cb(struct partlist *plist) 917 { 918 uint8_t flags = 0; 919 ib_bootblock_t *bblock; 920 bblk_einfo_t *einfo = NULL; 921 const char *filepath; 922 923 /* No stage, get out. */ 924 bblock = plist->pl_stage; 925 if (bblock == NULL) 926 return; 927 928 if (plist->pl_device->stage.path == NULL) 929 filepath = ""; 930 else 931 filepath = plist->pl_device->stage.path; 932 933 printf("Boot block from %s:%s\n", plist->pl_devname, filepath); 934 935 if (bblock->extra != NULL) 936 einfo = find_einfo(bblock->extra, bblock->extra_size); 937 938 if (einfo == NULL) { 939 (void) fprintf(stderr, 940 gettext("No extended information found.\n\n")); 941 return; 942 } 943 944 /* Print the extended information. */ 945 if (strip) 946 flags |= EINFO_EASY_PARSE; 947 if (verbose_dump) 948 flags |= EINFO_PRINT_HEADER; 949 950 print_einfo(flags, einfo, bblock->extra_size); 951 printf("\n"); 952 } 953 954 static size_t 955 get_media_info(int fd) 956 { 957 struct dk_minfo disk_info; 958 959 if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1) 960 return (SECTOR_SIZE); 961 962 return (disk_info.dki_lbsize); 963 } 964 965 static struct partlist * 966 partlist_alloc(void) 967 { 968 struct partlist *pl; 969 970 if ((pl = calloc(1, sizeof (*pl))) == NULL) { 971 perror("calloc"); 972 return (NULL); 973 } 974 975 pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 976 if (pl->pl_device == NULL) { 977 perror("calloc"); 978 free(pl); 979 return (NULL); 980 } 981 982 return (pl); 983 } 984 985 static void 986 partlist_free(struct partlist *pl) 987 { 988 ib_bootblock_t *bblock; 989 ib_device_t *device; 990 991 switch (pl->pl_type) { 992 case IB_BBLK_MBR: 993 case IB_BBLK_STAGE1: 994 free(pl->pl_stage); 995 break; 996 default: 997 if (pl->pl_stage != NULL) { 998 bblock = pl->pl_stage; 999 free(bblock->buf); 1000 free(bblock); 1001 } 1002 } 1003 1004 /* umount the stage fs. */ 1005 if (pl->pl_device->stage.mntpnt != NULL) { 1006 if (umount(pl->pl_device->stage.mntpnt) == 0) 1007 (void) rmdir(pl->pl_device->stage.mntpnt); 1008 free(pl->pl_device->stage.mntpnt); 1009 } 1010 device = pl->pl_device; 1011 free(device->target.path); 1012 free(pl->pl_device); 1013 1014 free(pl->pl_src_data); 1015 free(pl->pl_devname); 1016 free(pl); 1017 } 1018 1019 static bool 1020 probe_fstyp(ib_data_t *data) 1021 { 1022 fstyp_handle_t fhdl; 1023 const char *fident; 1024 char *ptr; 1025 int fd; 1026 bool rv = false; 1027 1028 /* Record partition id */ 1029 ptr = strrchr(data->target.path, 'p'); 1030 if (ptr == NULL) 1031 ptr = strrchr(data->target.path, 's'); 1032 data->target.id = atoi(++ptr); 1033 if ((fd = open_device(data->target.path)) == -1) 1034 return (rv); 1035 1036 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 1037 (void) close(fd); 1038 return (rv); 1039 } 1040 1041 if (fstyp_ident(fhdl, NULL, &fident) != 0) { 1042 fstyp_fini(fhdl); 1043 (void) fprintf(stderr, gettext("Failed to detect file " 1044 "system type\n")); 1045 (void) close(fd); 1046 return (rv); 1047 } 1048 1049 rv = true; 1050 if (strcmp(fident, MNTTYPE_ZFS) == 0) 1051 data->target.fstype = IB_FS_ZFS; 1052 else if (strcmp(fident, MNTTYPE_UFS) == 0) { 1053 data->target.fstype = IB_FS_UFS; 1054 } else if (strcmp(fident, MNTTYPE_PCFS) == 0) { 1055 data->target.fstype = IB_FS_PCFS; 1056 /* with pcfs we always write MBR */ 1057 force_mbr = true; 1058 write_mbr = true; 1059 } else { 1060 (void) fprintf(stderr, gettext("File system %s is not " 1061 "supported by loader\n"), fident); 1062 rv = false; 1063 } 1064 fstyp_fini(fhdl); 1065 (void) close(fd); 1066 return (rv); 1067 } 1068 1069 static bool 1070 get_slice(ib_data_t *data, struct partlist *pl, struct dk_gpt *vtoc, 1071 uint16_t tag) 1072 { 1073 uint_t i; 1074 ib_device_t *device = pl->pl_device; 1075 char *path, *ptr; 1076 1077 if (tag != V_BOOT && tag != V_SYSTEM) 1078 return (false); 1079 1080 for (i = 0; i < vtoc->efi_nparts; i++) { 1081 if (vtoc->efi_parts[i].p_tag == tag) { 1082 if ((path = strdup(data->target.path)) == NULL) { 1083 perror(gettext("Memory allocation failure")); 1084 return (false); 1085 } 1086 ptr = strrchr(path, 's'); 1087 ptr++; 1088 *ptr = '\0'; 1089 (void) asprintf(&ptr, "%s%d", path, i); 1090 free(path); 1091 if (ptr == NULL) { 1092 perror(gettext("Memory allocation failure")); 1093 return (false); 1094 } 1095 pl->pl_devname = ptr; 1096 device->stage.id = i; 1097 device->stage.devtype = IB_DEV_EFI; 1098 switch (vtoc->efi_parts[i].p_tag) { 1099 case V_BOOT: 1100 device->stage.fstype = IB_FS_NONE; 1101 /* leave sector 0 for VBR */ 1102 device->stage.offset = 1; 1103 break; 1104 case V_SYSTEM: 1105 device->stage.fstype = IB_FS_PCFS; 1106 break; 1107 } 1108 device->stage.tag = vtoc->efi_parts[i].p_tag; 1109 device->stage.start = vtoc->efi_parts[i].p_start; 1110 device->stage.size = vtoc->efi_parts[i].p_size; 1111 break; 1112 } 1113 } 1114 return (true); 1115 } 1116 1117 static bool 1118 allocate_slice(ib_data_t *data, struct dk_gpt *vtoc, uint16_t tag, 1119 struct partlist **plp) 1120 { 1121 struct partlist *pl; 1122 1123 *plp = NULL; 1124 if ((pl = partlist_alloc()) == NULL) 1125 return (false); 1126 1127 pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 1128 if (pl->pl_device == NULL) { 1129 perror("calloc"); 1130 partlist_free(pl); 1131 return (false); 1132 } 1133 if (!get_slice(data, pl, vtoc, tag)) { 1134 partlist_free(pl); 1135 return (false); 1136 } 1137 1138 /* tag was not found */ 1139 if (pl->pl_devname == NULL) 1140 partlist_free(pl); 1141 else 1142 *plp = pl; 1143 1144 return (true); 1145 } 1146 1147 static bool 1148 probe_gpt(ib_data_t *data) 1149 { 1150 struct partlist *pl; 1151 struct dk_gpt *vtoc; 1152 ib_device_t *device; 1153 int slice, fd; 1154 bool rv = false; 1155 1156 if ((fd = open_device(data->target.path)) < 0) 1157 return (rv); 1158 1159 slice = efi_alloc_and_read(fd, &vtoc); 1160 (void) close(fd); 1161 if (slice < 0) 1162 return (rv); 1163 1164 data->device.devtype = IB_DEV_EFI; 1165 data->target.start = vtoc->efi_parts[slice].p_start; 1166 data->target.size = vtoc->efi_parts[slice].p_size; 1167 1168 /* Always update PMBR. */ 1169 force_mbr = true; 1170 write_mbr = true; 1171 1172 /* 1173 * With GPT we can have boot partition and ESP. 1174 * Boot partition can have both stage 1 and stage 2. 1175 */ 1176 if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1177 goto done; 1178 if (pl != NULL) { 1179 pl->pl_src_name = stage1; 1180 pl->pl_type = IB_BBLK_STAGE1; 1181 pl->pl_cb.compare = compare_stage1_cb; 1182 pl->pl_cb.install = install_stage1_cb; 1183 pl->pl_cb.read = read_stage1_cb; 1184 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1185 pl->pl_cb.print = print_stage1_cb; 1186 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1187 } else if (data->target.fstype != IB_FS_ZFS) { 1188 (void) fprintf(stderr, gettext("Booting %s from EFI " 1189 "labeled disks requires the boot partition.\n"), 1190 data->target.fstype == IB_FS_UFS? 1191 MNTTYPE_UFS : MNTTYPE_PCFS); 1192 goto done; 1193 } 1194 /* Add stage 2 */ 1195 if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1196 goto done; 1197 if (pl != NULL) { 1198 pl->pl_src_name = stage2; 1199 pl->pl_type = IB_BBLK_STAGE2; 1200 pl->pl_cb.compare = compare_einfo_cb; 1201 pl->pl_cb.install = install_stage2_cb; 1202 pl->pl_cb.read = read_stage2_cb; 1203 pl->pl_cb.read_bbl = read_stage2_file_cb; 1204 pl->pl_cb.print = print_einfo_cb; 1205 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1206 } 1207 1208 /* ESP can have 32- and 64-bit boot code. */ 1209 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1210 goto done; 1211 if (pl != NULL) { 1212 pl->pl_device->stage.path = "/EFI/Boot/" BOOTIA32; 1213 pl->pl_src_name = efi32; 1214 pl->pl_type = IB_BBLK_EFI; 1215 pl->pl_cb.compare = compare_einfo_cb; 1216 pl->pl_cb.install = install_esp_cb; 1217 pl->pl_cb.read = read_einfo_esp_cb; 1218 pl->pl_cb.read_bbl = read_stage2_file_cb; 1219 pl->pl_cb.print = print_einfo_cb; 1220 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1221 } 1222 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1223 goto done; 1224 if (pl != NULL) { 1225 pl->pl_device->stage.path = "/EFI/Boot/" BOOTX64; 1226 pl->pl_src_name = efi64; 1227 pl->pl_type = IB_BBLK_EFI; 1228 pl->pl_cb.compare = compare_einfo_cb; 1229 pl->pl_cb.install = install_esp_cb; 1230 pl->pl_cb.read = read_einfo_esp_cb; 1231 pl->pl_cb.read_bbl = read_stage2_file_cb; 1232 pl->pl_cb.print = print_einfo_cb; 1233 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1234 } 1235 1236 /* add stage for our target file system slice */ 1237 pl = partlist_alloc(); 1238 if (pl == NULL) 1239 goto done; 1240 1241 device = pl->pl_device; 1242 device->stage.devtype = data->device.devtype; 1243 if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1244 perror(gettext("Memory allocation failure")); 1245 partlist_free(pl); 1246 goto done; 1247 } 1248 1249 device->stage.id = slice; 1250 device->stage.start = vtoc->efi_parts[slice].p_start; 1251 device->stage.size = vtoc->efi_parts[slice].p_size; 1252 1253 /* ZFS and UFS can have stage1 in boot area. */ 1254 if (data->target.fstype == IB_FS_ZFS || 1255 data->target.fstype == IB_FS_UFS) { 1256 pl->pl_src_name = stage1; 1257 pl->pl_type = IB_BBLK_STAGE1; 1258 pl->pl_cb.compare = compare_stage1_cb; 1259 pl->pl_cb.install = install_stage1_cb; 1260 pl->pl_cb.read = read_stage1_cb; 1261 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1262 pl->pl_cb.print = print_stage1_cb; 1263 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1264 } 1265 1266 if (data->target.fstype == IB_FS_ZFS) { 1267 pl = partlist_alloc(); 1268 if (pl == NULL) 1269 goto done; 1270 1271 device = pl->pl_device; 1272 device->stage.devtype = data->device.devtype; 1273 1274 if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1275 perror(gettext("Memory allocation failure")); 1276 goto done; 1277 } 1278 1279 device->stage.id = slice; 1280 device->stage.start = vtoc->efi_parts[slice].p_start; 1281 device->stage.size = vtoc->efi_parts[slice].p_size; 1282 1283 device->stage.offset = BBLK_ZFS_BLK_OFF / sector_size; 1284 pl->pl_src_name = stage2; 1285 pl->pl_type = IB_BBLK_STAGE2; 1286 pl->pl_cb.compare = compare_einfo_cb; 1287 pl->pl_cb.install = install_stage2_cb; 1288 pl->pl_cb.read = read_stage2_cb; 1289 pl->pl_cb.read_bbl = read_stage2_file_cb; 1290 pl->pl_cb.print = print_einfo_cb; 1291 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1292 } 1293 rv = true; 1294 done: 1295 efi_free(vtoc); 1296 return (rv); 1297 } 1298 1299 static bool 1300 get_start_sector(ib_data_t *data, struct extpartition *v_part, 1301 diskaddr_t *start) 1302 { 1303 struct partlist *pl; 1304 struct mboot *mbr; 1305 struct ipart *part; 1306 struct part_info dkpi; 1307 struct extpart_info edkpi; 1308 uint32_t secnum, numsec; 1309 ext_part_t *epp; 1310 ushort_t i; 1311 int fd, rval, pno; 1312 1313 if ((fd = open_device(data->target.path)) < 0) 1314 return (false); 1315 1316 if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) { 1317 if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) { 1318 (void) fprintf(stderr, gettext("cannot get the " 1319 "slice information of the disk\n")); 1320 (void) close(fd); 1321 return (false); 1322 } else { 1323 edkpi.p_start = dkpi.p_start; 1324 edkpi.p_length = dkpi.p_length; 1325 } 1326 } 1327 (void) close(fd); 1328 1329 /* Set target file system start and size */ 1330 data->target.start = edkpi.p_start; 1331 data->target.size = edkpi.p_length; 1332 1333 /* This is our MBR partition start. */ 1334 edkpi.p_start -= v_part->p_start; 1335 1336 /* Head is always MBR */ 1337 pl = STAILQ_FIRST(data->plist); 1338 if (!read_stage1_cb(pl)) 1339 return (false); 1340 1341 mbr = (struct mboot *)pl->pl_stage; 1342 part = (struct ipart *)mbr->parts; 1343 1344 for (i = 0; i < FD_NUMPART; i++) { 1345 if (part[i].relsect == edkpi.p_start) { 1346 *start = part[i].relsect; 1347 return (true); 1348 } 1349 } 1350 1351 rval = libfdisk_init(&epp, pl->pl_devname, part, FDISK_READ_DISK); 1352 if (rval != FDISK_SUCCESS) { 1353 switch (rval) { 1354 /* 1355 * The first 3 cases are not an error per-se, just that 1356 * there is no Solaris logical partition 1357 */ 1358 case FDISK_EBADLOGDRIVE: 1359 case FDISK_ENOLOGDRIVE: 1360 case FDISK_EBADMAGIC: 1361 (void) fprintf(stderr, gettext("Solaris " 1362 "partition not found. " 1363 "Aborting operation. %d\n"), rval); 1364 return (false); 1365 case FDISK_ENOVGEOM: 1366 (void) fprintf(stderr, gettext("Could not get " 1367 "virtual geometry\n")); 1368 return (false); 1369 case FDISK_ENOPGEOM: 1370 (void) fprintf(stderr, gettext("Could not get " 1371 "physical geometry\n")); 1372 return (false); 1373 case FDISK_ENOLGEOM: 1374 (void) fprintf(stderr, gettext("Could not get " 1375 "label geometry\n")); 1376 return (false); 1377 default: 1378 (void) fprintf(stderr, gettext("Failed to " 1379 "initialize libfdisk.\n")); 1380 return (false); 1381 } 1382 } 1383 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); 1384 libfdisk_fini(&epp); 1385 if (rval != FDISK_SUCCESS) { 1386 /* No solaris logical partition */ 1387 (void) fprintf(stderr, gettext("Solaris partition not found. " 1388 "Aborting operation.\n")); 1389 return (false); 1390 } 1391 *start = secnum; 1392 return (true); 1393 } 1394 1395 /* 1396 * On x86 the VTOC table is inside MBR partition and to get 1397 * absolute sectors, we need to add MBR partition start to VTOC slice start. 1398 */ 1399 static bool 1400 probe_vtoc(ib_data_t *data) 1401 { 1402 struct partlist *pl; 1403 struct extvtoc exvtoc; 1404 ib_device_t *device; 1405 char *path, *ptr; 1406 ushort_t i; 1407 int slice, fd; 1408 diskaddr_t start; 1409 bool rv; 1410 1411 rv = false; 1412 1413 if ((fd = open_device(data->target.path)) < 0) 1414 return (rv); 1415 1416 slice = read_extvtoc(fd, &exvtoc); 1417 (void) close(fd); 1418 if (slice < 0) 1419 return (rv); 1420 data->device.devtype = IB_DEV_VTOC; 1421 1422 if (!get_start_sector(data, exvtoc.v_part + slice, &start)) 1423 return (rv); 1424 1425 if (exvtoc.v_part[slice].p_tag == V_BACKUP) { 1426 /* 1427 * NOTE: we could relax there and allow zfs boot on 1428 * slice 2, but lets keep traditional limits. 1429 */ 1430 (void) fprintf(stderr, gettext( 1431 "raw device must be a root slice (not backup)\n")); 1432 return (rv); 1433 } 1434 1435 if ((path = strdup(data->target.path)) == NULL) { 1436 perror(gettext("Memory allocation failure")); 1437 return (false); 1438 } 1439 1440 data->target.start = start + exvtoc.v_part[slice].p_start; 1441 data->target.size = exvtoc.v_part[slice].p_size; 1442 1443 /* Search for boot slice. */ 1444 for (i = 0; i < exvtoc.v_nparts; i++) { 1445 if (exvtoc.v_part[i].p_tag == V_BOOT) 1446 break; 1447 } 1448 1449 if (i == exvtoc.v_nparts || 1450 exvtoc.v_part[i].p_size == 0) { 1451 /* fall back to slice V_BACKUP */ 1452 for (i = 0; i < exvtoc.v_nparts; i++) { 1453 if (exvtoc.v_part[i].p_tag == V_BACKUP) 1454 break; 1455 } 1456 /* Still nothing? Error out. */ 1457 if (i == exvtoc.v_nparts || 1458 exvtoc.v_part[i].p_size == 0) { 1459 free(path); 1460 return (false); 1461 } 1462 } 1463 1464 /* Create path. */ 1465 ptr = strrchr(path, 's'); 1466 ptr++; 1467 *ptr = '\0'; 1468 (void) asprintf(&ptr, "%s%d", path, i); 1469 free(path); 1470 if (ptr == NULL) { 1471 perror(gettext("Memory allocation failure")); 1472 return (false); 1473 } 1474 1475 pl = partlist_alloc(); 1476 if (pl == NULL) { 1477 free(ptr); 1478 return (false); 1479 } 1480 pl->pl_devname = ptr; 1481 device = pl->pl_device; 1482 device->stage.devtype = data->device.devtype; 1483 device->stage.id = i; 1484 device->stage.tag = exvtoc.v_part[i].p_tag; 1485 device->stage.start = start + exvtoc.v_part[i].p_start; 1486 device->stage.size = exvtoc.v_part[i].p_size; 1487 1488 /* Fix size if this slice is in fact V_BACKUP */ 1489 if (exvtoc.v_part[i].p_tag == V_BACKUP) { 1490 for (i = 0; i < exvtoc.v_nparts; i++) { 1491 if (exvtoc.v_part[i].p_start == 0) 1492 continue; 1493 if (exvtoc.v_part[i].p_size == 0) 1494 continue; 1495 if (exvtoc.v_part[i].p_start < 1496 device->stage.size) 1497 device->stage.size = 1498 exvtoc.v_part[i].p_start; 1499 } 1500 } 1501 1502 pl->pl_src_name = stage1; 1503 pl->pl_type = IB_BBLK_STAGE1; 1504 pl->pl_cb.compare = compare_stage1_cb; 1505 pl->pl_cb.install = install_stage1_cb; 1506 pl->pl_cb.read = read_stage1_cb; 1507 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1508 pl->pl_cb.print = print_stage1_cb; 1509 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1510 1511 /* Create instance for stage 2 */ 1512 pl = partlist_alloc(); 1513 if (pl == NULL) { 1514 free(ptr); 1515 return (false); 1516 } 1517 pl->pl_devname = strdup(ptr); 1518 if (pl->pl_devname == NULL) { 1519 partlist_free(pl); 1520 return (false); 1521 } 1522 pl->pl_device->stage.devtype = data->device.devtype; 1523 pl->pl_device->stage.id = device->stage.id; 1524 pl->pl_device->stage.offset = BBLK_BLKLIST_OFF; 1525 pl->pl_device->stage.tag = device->stage.tag; 1526 pl->pl_device->stage.start = device->stage.start; 1527 pl->pl_device->stage.size = device->stage.size; 1528 pl->pl_src_name = stage2; 1529 pl->pl_type = IB_BBLK_STAGE2; 1530 pl->pl_cb.compare = compare_einfo_cb; 1531 pl->pl_cb.install = install_stage2_cb; 1532 pl->pl_cb.read = read_stage2_cb; 1533 pl->pl_cb.read_bbl = read_stage2_file_cb; 1534 pl->pl_cb.print = print_einfo_cb; 1535 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1536 1537 /* And we are done. */ 1538 rv = true; 1539 return (rv); 1540 } 1541 1542 static bool 1543 probe_mbr(ib_data_t *data) 1544 { 1545 struct partlist *pl; 1546 struct ipart *part; 1547 struct mboot *mbr; 1548 ib_device_t *device; 1549 char *path, *ptr; 1550 int i, rv; 1551 1552 data->device.devtype = IB_DEV_MBR; 1553 1554 /* Head is always MBR */ 1555 pl = STAILQ_FIRST(data->plist); 1556 if (!read_stage1_cb(pl)) 1557 return (false); 1558 1559 mbr = (struct mboot *)pl->pl_stage; 1560 part = (struct ipart *)mbr->parts; 1561 1562 /* Set target file system start and size */ 1563 data->target.start = part[data->target.id - 1].relsect; 1564 data->target.size = part[data->target.id - 1].numsect; 1565 1566 /* Use X86BOOT partition if we have one. */ 1567 for (i = 0; i < FD_NUMPART; i++) { 1568 if (part[i].systid == X86BOOT) 1569 break; 1570 } 1571 1572 /* Keep device name of whole disk device. */ 1573 path = (char *)pl->pl_devname; 1574 if ((pl = partlist_alloc()) == NULL) 1575 return (false); 1576 device = pl->pl_device; 1577 1578 /* 1579 * No X86BOOT, try to use space between MBR and first 1580 * partition. 1581 */ 1582 if (i == FD_NUMPART) { 1583 pl->pl_devname = strdup(path); 1584 if (pl->pl_devname == NULL) { 1585 perror(gettext("Memory allocation failure")); 1586 partlist_free(pl); 1587 return (false); 1588 } 1589 device->stage.id = 0; 1590 device->stage.devtype = IB_DEV_MBR; 1591 device->stage.fstype = IB_FS_NONE; 1592 device->stage.start = 0; 1593 device->stage.size = part[0].relsect; 1594 device->stage.offset = BBLK_BLKLIST_OFF; 1595 pl->pl_src_name = stage2; 1596 pl->pl_type = IB_BBLK_STAGE2; 1597 pl->pl_cb.compare = compare_einfo_cb; 1598 pl->pl_cb.install = install_stage2_cb; 1599 pl->pl_cb.read = read_stage2_cb; 1600 pl->pl_cb.read_bbl = read_stage2_file_cb; 1601 pl->pl_cb.print = print_einfo_cb; 1602 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1603 1604 /* We have MBR for stage1 and gap for stage2, we are done. */ 1605 return (true); 1606 } 1607 1608 if ((path = strdup(path)) == NULL) { 1609 perror(gettext("Memory allocation failure")); 1610 partlist_free(pl); 1611 return (false); 1612 } 1613 ptr = strrchr(path, 'p'); 1614 ptr++; 1615 *ptr = '\0'; 1616 /* partitions are p1..p4 */ 1617 rv = asprintf(&ptr, "%s%d", path, i + 1); 1618 free(path); 1619 if (rv < 0) { 1620 perror(gettext("Memory allocation failure")); 1621 partlist_free(pl); 1622 return (false); 1623 } 1624 pl->pl_devname = ptr; 1625 device->stage.id = i + 1; 1626 device->stage.devtype = IB_DEV_MBR; 1627 device->stage.fstype = IB_FS_NONE; 1628 device->stage.start = part[i].relsect; 1629 device->stage.size = part[i].numsect; 1630 pl->pl_src_name = stage1; 1631 pl->pl_type = IB_BBLK_STAGE1; 1632 pl->pl_cb.compare = compare_stage1_cb; 1633 pl->pl_cb.install = install_stage1_cb; 1634 pl->pl_cb.read = read_stage1_cb; 1635 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1636 pl->pl_cb.print = print_stage1_cb; 1637 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1638 1639 pl = partlist_alloc(); 1640 if (pl == NULL) 1641 return (false); 1642 device = pl->pl_device; 1643 pl->pl_devname = strdup(ptr); 1644 if (pl->pl_devname == NULL) { 1645 perror(gettext("Memory allocation failure")); 1646 partlist_free(pl); 1647 return (false); 1648 } 1649 device->stage.id = i + 1; 1650 device->stage.devtype = IB_DEV_MBR; 1651 device->stage.fstype = IB_FS_NONE; 1652 device->stage.start = part[i].relsect; 1653 device->stage.size = part[i].numsect; 1654 device->stage.offset = 1; 1655 /* This is boot partition */ 1656 device->stage.tag = V_BOOT; 1657 pl->pl_src_name = stage2; 1658 pl->pl_type = IB_BBLK_STAGE2; 1659 pl->pl_cb.compare = compare_einfo_cb; 1660 pl->pl_cb.install = install_stage2_cb; 1661 pl->pl_cb.read = read_stage2_cb; 1662 pl->pl_cb.read_bbl = read_stage2_file_cb; 1663 pl->pl_cb.print = print_einfo_cb; 1664 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1665 1666 return (true); 1667 } 1668 1669 static bool 1670 probe_device(ib_data_t *data, const char *dev) 1671 { 1672 struct partlist *pl; 1673 struct stat sb; 1674 const char *ptr; 1675 char *p0; 1676 int fd, len; 1677 1678 if (dev == NULL) 1679 return (NULL); 1680 1681 len = strlen(dev); 1682 1683 if ((pl = partlist_alloc()) == NULL) 1684 return (false); 1685 1686 if (stat(dev, &sb) == -1) { 1687 perror("stat"); 1688 partlist_free(pl); 1689 return (false); 1690 } 1691 1692 /* We have regular file, register it and we are done. */ 1693 if (S_ISREG(sb.st_mode) != 0) { 1694 pl->pl_devname = (char *)dev; 1695 1696 pl->pl_type = IB_BBLK_FILE; 1697 pl->pl_cb.read = read_einfo_file_cb; 1698 pl->pl_cb.print = print_einfo_cb; 1699 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1700 return (true); 1701 } 1702 1703 /* 1704 * This is block device. 1705 * We do not allow to specify whole disk device (cXtYdZp0 or cXtYdZ). 1706 */ 1707 if ((ptr = strrchr(dev, '/')) == NULL) 1708 ptr = dev; 1709 if ((strrchr(ptr, 'p') == NULL && strrchr(ptr, 's') == NULL) || 1710 (dev[len - 2] == 'p' && dev[len - 1] == '0')) { 1711 (void) fprintf(stderr, 1712 gettext("whole disk device is not supported\n")); 1713 partlist_free(pl); 1714 return (false); 1715 } 1716 1717 data->target.path = (char *)dev; 1718 if (!probe_fstyp(data)) { 1719 partlist_free(pl); 1720 return (false); 1721 } 1722 1723 /* We start from identifying the whole disk. */ 1724 if ((p0 = strdup(dev)) == NULL) { 1725 perror("calloc"); 1726 partlist_free(pl); 1727 return (false); 1728 } 1729 1730 pl->pl_devname = p0; 1731 /* Change device name to p0 */ 1732 if ((ptr = strrchr(p0, 'p')) == NULL) 1733 ptr = strrchr(p0, 's'); 1734 p0 = (char *)ptr; 1735 p0[0] = 'p'; 1736 p0[1] = '0'; 1737 p0[2] = '\0'; 1738 1739 if ((fd = open_device(pl->pl_devname)) == -1) { 1740 partlist_free(pl); 1741 return (false); 1742 } 1743 1744 sector_size = get_media_info(fd); 1745 (void) close(fd); 1746 1747 pl->pl_src_name = stage1; 1748 pl->pl_type = IB_BBLK_MBR; 1749 pl->pl_cb.compare = compare_mbr_cb; 1750 pl->pl_cb.install = install_stage1_cb; 1751 pl->pl_cb.read = read_stage1_cb; 1752 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1753 pl->pl_cb.print = print_stage1_cb; 1754 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1755 1756 if (probe_gpt(data)) 1757 return (true); 1758 1759 /* 1760 * We only do support sector size 512 with MBR and VTOC. 1761 * The 4kn sector size with actual hardware is currently 1762 * available with large disks and MBR/VTOC are not usable 1763 * with such devices. 1764 */ 1765 if (sector_size != SECTOR_SIZE) 1766 return (false); 1767 1768 if (data->device.devtype == IB_DEV_UNKNOWN) 1769 if (probe_vtoc(data)) 1770 return (true); 1771 1772 if (data->device.devtype == IB_DEV_UNKNOWN) 1773 return (probe_mbr(data)); 1774 1775 return (false); 1776 } 1777 1778 static int 1779 read_bootblock_from_file(const char *file, ib_bootblock_t *bblock) 1780 { 1781 struct stat sb; 1782 uint32_t buf_size; 1783 uint32_t mboot_off; 1784 int fd = -1; 1785 int retval = BC_ERROR; 1786 1787 assert(bblock != NULL); 1788 assert(file != NULL); 1789 1790 fd = open(file, O_RDONLY); 1791 if (fd == -1) { 1792 BOOT_DEBUG("Error opening %s\n", file); 1793 goto out; 1794 } 1795 1796 if (fstat(fd, &sb) == -1) { 1797 BOOT_DEBUG("Error getting information (stat) about %s", file); 1798 perror("stat"); 1799 goto outfd; 1800 } 1801 1802 /* loader bootblock has version built in */ 1803 buf_size = sb.st_size; 1804 if (buf_size == 0) 1805 goto outfd; 1806 1807 /* Round up to sector size for raw disk write */ 1808 bblock->buf_size = P2ROUNDUP(buf_size, sector_size); 1809 BOOT_DEBUG("bootblock in-memory buffer size is %d\n", 1810 bblock->buf_size); 1811 1812 bblock->buf = malloc(bblock->buf_size); 1813 if (bblock->buf == NULL) { 1814 perror(gettext("Memory allocation failure")); 1815 goto outbuf; 1816 } 1817 bblock->file = bblock->buf; 1818 1819 if (read(fd, bblock->file, buf_size) != buf_size) { 1820 BOOT_DEBUG("Read from %s failed\n", file); 1821 perror("read"); 1822 goto outfd; 1823 } 1824 1825 buf_size = MIN(buf_size, MBOOT_SCAN_SIZE); 1826 if (find_multiboot(bblock->file, buf_size, &mboot_off) 1827 != BC_SUCCESS) { 1828 (void) fprintf(stderr, 1829 gettext("Unable to find multiboot header\n")); 1830 goto outfd; 1831 } 1832 1833 bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off); 1834 bblock->mboot_off = mboot_off; 1835 1836 bblock->file_size = 1837 bblock->mboot->load_end_addr - bblock->mboot->load_addr; 1838 BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size); 1839 1840 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 1841 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 1842 1843 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 1844 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 1845 bblock->extra_size, bblock->buf, bblock->buf_size); 1846 1847 (void) close(fd); 1848 return (BC_SUCCESS); 1849 1850 outbuf: 1851 (void) free(bblock->buf); 1852 bblock->buf = NULL; 1853 outfd: 1854 (void) close(fd); 1855 out: 1856 if (retval == BC_ERROR) { 1857 (void) fprintf(stderr, 1858 gettext("Error reading bootblock from %s\n"), 1859 file); 1860 } 1861 1862 if (retval == BC_NOEXTRA) { 1863 BOOT_DEBUG("No multiboot header found on %s, unable to " 1864 "locate extra information area (old/non versioned " 1865 "bootblock?) \n", file); 1866 (void) fprintf(stderr, gettext("No extended information" 1867 " found\n")); 1868 } 1869 return (retval); 1870 } 1871 1872 static void 1873 add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str) 1874 { 1875 bblk_hs_t hs; 1876 uint32_t avail_space; 1877 1878 assert(bblock != NULL); 1879 1880 if (updt_str == NULL) { 1881 BOOT_DEBUG("WARNING: no update string passed to " 1882 "add_bootblock_einfo()\n"); 1883 return; 1884 } 1885 1886 /* Fill bootblock hashing source information. */ 1887 hs.src_buf = (unsigned char *)bblock->file; 1888 hs.src_size = bblock->file_size; 1889 /* How much space for the extended information structure? */ 1890 avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 1891 /* Place the extended information structure. */ 1892 add_einfo(bblock->extra, updt_str, &hs, avail_space); 1893 } 1894 1895 /* 1896 * set up data for case stage1 is installed as MBR 1897 * set up location and size of bootblock 1898 * set disk guid to provide unique information for biosdev command 1899 */ 1900 static void 1901 prepare_stage1(struct partlist *stage1, struct partlist *stage2, uuid_t uuid) 1902 { 1903 char *src, *dest; 1904 ib_bootblock_t *bblk; 1905 ib_device_t *device; 1906 uint16_t size; 1907 struct mboot *mbr; 1908 1909 src = stage1->pl_stage; 1910 dest = stage1->pl_src_data; 1911 device = stage2->pl_device; 1912 1913 /* Only copy from valid source. */ 1914 mbr = stage1->pl_stage; 1915 if (mbr->signature == MBB_MAGIC) { 1916 /* copy BPB */ 1917 bcopy(src + STAGE1_BPB_OFFSET, dest + STAGE1_BPB_OFFSET, 1918 STAGE1_BPB_SIZE); 1919 1920 /* copy MBR, note STAGE1_SIG == BOOTSZ */ 1921 bcopy(src + STAGE1_SIG, dest + STAGE1_SIG, 1922 SECTOR_SIZE - STAGE1_SIG); 1923 } 1924 1925 bcopy(uuid, dest + STAGE1_STAGE2_UUID, UUID_LEN); 1926 1927 /* store bytes per sector */ 1928 *((uint16_t *)(dest + STAGE1_BPB_BPS)) = sector_size; 1929 /* set stage2 size */ 1930 bblk = stage2->pl_src_data; 1931 size = bblk->buf_size / sector_size; 1932 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = size; 1933 1934 /* set stage2 LBA */ 1935 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) = 1936 device->stage.start + device->stage.offset; 1937 1938 /* Copy prepared data to stage1 block read from the disk. */ 1939 bcopy(dest, src, SECTOR_SIZE); 1940 } 1941 1942 static void 1943 prepare_bootblock(ib_data_t *data, struct partlist *pl, char *updt_str) 1944 { 1945 ib_bootblock_t *bblock; 1946 uint64_t *ptr; 1947 1948 assert(pl != NULL); 1949 1950 bblock = pl->pl_src_data; 1951 if (bblock == NULL) 1952 return; 1953 1954 ptr = (uint64_t *)(&bblock->mboot->bss_end_addr); 1955 *ptr = data->target.start; 1956 1957 /* 1958 * the loader bootblock has built in version, if custom 1959 * version was provided, update it. 1960 */ 1961 if (do_version) 1962 add_bootblock_einfo(bblock, updt_str); 1963 } 1964 1965 static int 1966 open_device(const char *path) 1967 { 1968 struct stat statbuf = {0}; 1969 int fd = -1; 1970 1971 if (nowrite) 1972 fd = open(path, O_RDONLY); 1973 else 1974 fd = open(path, O_RDWR); 1975 1976 if (fd == -1) { 1977 BOOT_DEBUG("Unable to open %s\n", path); 1978 perror("open"); 1979 return (-1); 1980 } 1981 1982 if (fstat(fd, &statbuf) != 0) { 1983 BOOT_DEBUG("Unable to stat %s\n", path); 1984 perror("stat"); 1985 (void) close(fd); 1986 return (-1); 1987 } 1988 1989 if (S_ISCHR(statbuf.st_mode) == 0) { 1990 (void) fprintf(stderr, gettext("%s: Not a character device\n"), 1991 path); 1992 (void) close(fd); 1993 return (-1); 1994 } 1995 1996 return (fd); 1997 } 1998 1999 /* 2000 * We need to record stage2 location and size into pmbr/vbr. 2001 * We need to record target partiton LBA to stage2. 2002 */ 2003 static void 2004 prepare_bblocks(ib_data_t *data) 2005 { 2006 struct partlist *pl; 2007 struct partlist *mbr, *stage1, *stage2; 2008 uuid_t uuid; 2009 2010 /* 2011 * Create disk uuid. We only need reasonable amount of uniqueness 2012 * to allow biosdev to identify disk based on mbr differences. 2013 */ 2014 uuid_generate(uuid); 2015 2016 mbr = stage1 = stage2 = NULL; 2017 2018 /* First find stage 2. */ 2019 STAILQ_FOREACH(pl, data->plist, pl_next) { 2020 if (pl->pl_type == IB_BBLK_STAGE2) { 2021 stage2 = pl; 2022 2023 /* 2024 * When stage2 needs update, make sure we also 2025 * update stage1. 2026 */ 2027 if (pl->pl_cb.compare != NULL && 2028 pl->pl_cb.compare(pl)) 2029 write_vbr = true; 2030 break; 2031 } 2032 } 2033 /* 2034 * Walk list and pick up BIOS boot blocks. EFI boot programs 2035 * can be set in place. 2036 */ 2037 STAILQ_FOREACH(pl, data->plist, pl_next) { 2038 switch (pl->pl_type) { 2039 case IB_BBLK_MBR: 2040 mbr = pl; 2041 break; 2042 case IB_BBLK_STAGE1: 2043 stage1 = pl; 2044 if (stage2 != NULL) 2045 prepare_stage1(stage1, stage2, uuid); 2046 break; 2047 case IB_BBLK_STAGE2: 2048 case IB_BBLK_EFI: 2049 prepare_bootblock(data, pl, update_str); 2050 break; 2051 default: 2052 break; 2053 } 2054 } 2055 2056 /* If stage2 is missing, we are done. */ 2057 if (stage2 == NULL) 2058 return; 2059 2060 if (mbr != NULL) { 2061 prepare_stage1(mbr, stage2, uuid); 2062 2063 /* 2064 * If we have stage1, we point MBR to read stage 1. 2065 */ 2066 if (stage1 != NULL) { 2067 char *dest = mbr->pl_stage; 2068 2069 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = 1; 2070 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) = 2071 stage1->pl_device->stage.start; 2072 } 2073 } 2074 } 2075 2076 /* 2077 * Install a new bootblock on the given device. handle_install() expects argv 2078 * to contain 3 parameters (the target device path and the path to the 2079 * bootblock. 2080 * 2081 * Returns: BC_SUCCESS - if the installation is successful 2082 * BC_ERROR - if the installation failed 2083 * BC_NOUPDT - if no installation was performed because the 2084 * version currently installed is more recent than the 2085 * supplied one. 2086 * 2087 */ 2088 static int 2089 handle_install(char *progname, int argc, char **argv) 2090 { 2091 struct partlist *pl; 2092 ib_data_t data = { 0 }; 2093 char *device_path = NULL; 2094 int ret = BC_ERROR; 2095 2096 switch (argc) { 2097 case 1: 2098 if ((device_path = strdup(argv[0])) == NULL) { 2099 perror(gettext("Memory Allocation Failure")); 2100 goto done; 2101 } 2102 if (asprintf(&stage1, "%s/%s", boot_dir, STAGE1) < 0) { 2103 perror(gettext("Memory Allocation Failure")); 2104 goto done; 2105 } 2106 if (asprintf(&stage2, "%s/%s", boot_dir, STAGE2) < 0) { 2107 perror(gettext("Memory Allocation Failure")); 2108 goto done; 2109 } 2110 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) { 2111 perror(gettext("Memory Allocation Failure")); 2112 goto done; 2113 } 2114 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) { 2115 perror(gettext("Memory Allocation Failure")); 2116 goto done; 2117 } 2118 break; 2119 case 3: 2120 if ((stage1 = strdup(argv[0])) == NULL) { 2121 perror(gettext("Memory Allocation Failure")); 2122 goto done; 2123 } 2124 if ((stage2 = strdup(argv[1])) == NULL) { 2125 perror(gettext("Memory Allocation Failure")); 2126 goto done; 2127 } 2128 if ((device_path = strdup(argv[2])) == NULL) { 2129 perror(gettext("Memory Allocation Failure")); 2130 goto done; 2131 } 2132 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) { 2133 perror(gettext("Memory Allocation Failure")); 2134 goto done; 2135 } 2136 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) { 2137 perror(gettext("Memory Allocation Failure")); 2138 goto done; 2139 } 2140 break; 2141 default: 2142 usage(progname, ret); 2143 } 2144 2145 data.plist = malloc(sizeof (*data.plist)); 2146 if (data.plist == NULL) { 2147 perror(gettext("Memory Allocation Failure")); 2148 goto done; 2149 } 2150 STAILQ_INIT(data.plist); 2151 2152 BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n", 2153 device_path, stage1, stage2); 2154 2155 if (probe_device(&data, device_path)) { 2156 /* Read all data. */ 2157 STAILQ_FOREACH(pl, data.plist, pl_next) { 2158 if (!pl->pl_cb.read(pl)) { 2159 printf("\n"); 2160 } 2161 if (!pl->pl_cb.read_bbl(pl)) { 2162 /* 2163 * We will ignore ESP updates in case of 2164 * older system where we are missing 2165 * loader64.efi and loader32.efi. 2166 */ 2167 if (pl->pl_type != IB_BBLK_EFI) 2168 goto cleanup; 2169 } 2170 } 2171 2172 /* Prepare data. */ 2173 prepare_bblocks(&data); 2174 2175 /* Commit data to disk. */ 2176 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != 2177 NULL) { 2178 if (pl->pl_cb.compare != NULL && 2179 pl->pl_cb.compare(pl)) { 2180 if (pl->pl_cb.install != NULL) 2181 pl->pl_cb.install(&data, pl); 2182 } 2183 STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2184 partlist_free(pl); 2185 } 2186 } 2187 ret = BC_SUCCESS; 2188 2189 cleanup: 2190 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) { 2191 STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2192 partlist_free(pl); 2193 } 2194 free(data.plist); 2195 done: 2196 free(stage1); 2197 free(stage2); 2198 free(efi32); 2199 free(efi64); 2200 free(device_path); 2201 return (ret); 2202 } 2203 2204 /* 2205 * Retrieves from a device the extended information (einfo) associated to the 2206 * file or installed stage2. 2207 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0 2208 * or file name. 2209 * Returns: 2210 * - BC_SUCCESS (and prints out einfo contents depending on 'flags') 2211 * - BC_ERROR (on error) 2212 * - BC_NOEINFO (no extended information available) 2213 */ 2214 static int 2215 handle_getinfo(char *progname, int argc, char **argv) 2216 { 2217 struct partlist *pl; 2218 ib_data_t data = { 0 }; 2219 char *device_path; 2220 2221 if (argc != 1) { 2222 (void) fprintf(stderr, gettext("Missing parameter")); 2223 usage(progname, BC_ERROR); 2224 } 2225 2226 if ((device_path = strdup(argv[0])) == NULL) { 2227 perror(gettext("Memory Allocation Failure")); 2228 return (BC_ERROR); 2229 } 2230 2231 data.plist = malloc(sizeof (*data.plist)); 2232 if (data.plist == NULL) { 2233 perror("malloc"); 2234 free(device_path); 2235 return (BC_ERROR); 2236 } 2237 STAILQ_INIT(data.plist); 2238 2239 if (probe_device(&data, device_path)) { 2240 STAILQ_FOREACH(pl, data.plist, pl_next) { 2241 if (pl->pl_cb.read(pl)) 2242 pl->pl_cb.print(pl); 2243 else 2244 printf("\n"); 2245 } 2246 } 2247 2248 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) { 2249 STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2250 partlist_free(pl); 2251 } 2252 free(data.plist); 2253 2254 return (BC_SUCCESS); 2255 } 2256 2257 /* 2258 * Attempt to mirror (propagate) the current bootblock over the attaching disk. 2259 * 2260 * Returns: 2261 * - BC_SUCCESS (a successful propagation happened) 2262 * - BC_ERROR (an error occurred) 2263 * - BC_NOEXTRA (it is not possible to dump the current bootblock since 2264 * there is no multiboot information) 2265 */ 2266 static int 2267 handle_mirror(char *progname, int argc, char **argv) 2268 { 2269 ib_data_t src = { 0 }; 2270 ib_data_t dest = { 0 }; 2271 struct partlist *pl_src, *pl_dest; 2272 char *curr_device_path = NULL; 2273 char *attach_device_path = NULL; 2274 int retval = BC_ERROR; 2275 2276 if (argc == 2) { 2277 curr_device_path = strdup(argv[0]); 2278 attach_device_path = strdup(argv[1]); 2279 } 2280 2281 if (!curr_device_path || !attach_device_path) { 2282 free(curr_device_path); 2283 free(attach_device_path); 2284 (void) fprintf(stderr, gettext("Missing parameter")); 2285 usage(progname, BC_ERROR); 2286 } 2287 BOOT_DEBUG("Current device path is: %s, attaching device path is: " 2288 " %s\n", curr_device_path, attach_device_path); 2289 2290 src.plist = malloc(sizeof (*src.plist)); 2291 if (src.plist == NULL) { 2292 perror("malloc"); 2293 return (BC_ERROR); 2294 } 2295 STAILQ_INIT(src.plist); 2296 2297 dest.plist = malloc(sizeof (*dest.plist)); 2298 if (dest.plist == NULL) { 2299 perror("malloc"); 2300 goto out; 2301 } 2302 STAILQ_INIT(dest.plist); 2303 2304 if (!probe_device(&src, curr_device_path)) { 2305 (void) fprintf(stderr, gettext("Unable to gather device " 2306 "information from %s (current device)\n"), 2307 curr_device_path); 2308 goto out; 2309 } 2310 2311 if (!probe_device(&dest, attach_device_path) != BC_SUCCESS) { 2312 (void) fprintf(stderr, gettext("Unable to gather device " 2313 "information from %s (attaching device)\n"), 2314 attach_device_path); 2315 goto cleanup_src; 2316 } 2317 2318 write_vbr = true; 2319 write_mbr = true; 2320 force_mbr = true; 2321 2322 pl_dest = STAILQ_FIRST(dest.plist); 2323 STAILQ_FOREACH(pl_src, src.plist, pl_next) { 2324 if (pl_dest == NULL) { 2325 (void) fprintf(stderr, 2326 gettext("Destination disk layout is different " 2327 "from source, can not mirror.\n")); 2328 goto cleanup; 2329 } 2330 if (!pl_src->pl_cb.read(pl_src)) { 2331 (void) fprintf(stderr, gettext("Failed to read " 2332 "boot block from %s\n"), pl_src->pl_devname); 2333 goto cleanup; 2334 } 2335 if (!pl_dest->pl_cb.read(pl_dest)) { 2336 (void) fprintf(stderr, gettext("Failed to read " 2337 "boot block from %s\n"), pl_dest->pl_devname); 2338 } 2339 2340 /* Set source pl_stage to destination source data */ 2341 pl_dest->pl_src_data = pl_src->pl_stage; 2342 pl_src->pl_stage = NULL; 2343 2344 pl_dest = STAILQ_NEXT(pl_dest, pl_next); 2345 } 2346 2347 /* Prepare data. */ 2348 prepare_bblocks(&dest); 2349 2350 /* Commit data to disk. */ 2351 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) { 2352 pl_dest->pl_cb.install(&dest, pl_dest); 2353 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next); 2354 partlist_free(pl_dest); 2355 2356 /* Free source list */ 2357 pl_src = STAILQ_LAST(src.plist, partlist, pl_next); 2358 if (pl_src != NULL) { 2359 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next); 2360 partlist_free(pl_src); 2361 } 2362 } 2363 retval = BC_SUCCESS; 2364 2365 cleanup: 2366 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) { 2367 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next); 2368 partlist_free(pl_dest); 2369 } 2370 free(dest.plist); 2371 cleanup_src: 2372 while ((pl_src = STAILQ_LAST(src.plist, partlist, pl_next)) != NULL) { 2373 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next); 2374 partlist_free(pl_src); 2375 } 2376 free(src.plist); 2377 out: 2378 free(curr_device_path); 2379 free(attach_device_path); 2380 return (retval); 2381 } 2382 2383 #define USAGE_STRING \ 2384 "Usage:\t%s [-fFmn] [-b boot_dir] [-u verstr]\n" \ 2385 "\t\t[stage1 stage2] raw-device\n" \ 2386 "\t%s -M [-n] raw-device attach-raw-device\n" \ 2387 "\t%s [-e|-V] -i raw-device | file\n" 2388 2389 #define CANON_USAGE_STR gettext(USAGE_STRING) 2390 2391 static void 2392 usage(char *progname, int rc) 2393 { 2394 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname); 2395 fini_yes(); 2396 exit(rc); 2397 } 2398 2399 int 2400 main(int argc, char **argv) 2401 { 2402 int opt; 2403 int ret; 2404 char *progname; 2405 struct stat sb; 2406 2407 (void) setlocale(LC_ALL, ""); 2408 (void) textdomain(TEXT_DOMAIN); 2409 if (init_yes() < 0) 2410 errx(BC_ERROR, gettext(ERR_MSG_INIT_YES), strerror(errno)); 2411 2412 /* Needed for mount pcfs. */ 2413 tzset(); 2414 2415 /* Determine our name */ 2416 progname = basename(argv[0]); 2417 2418 while ((opt = getopt(argc, argv, "b:deFfhiMmnu:V")) != EOF) { 2419 switch (opt) { 2420 case 'b': 2421 boot_dir = strdup(optarg); 2422 if (boot_dir == NULL) { 2423 err(BC_ERROR, 2424 gettext("Memory allocation failure")); 2425 } 2426 if (lstat(boot_dir, &sb) != 0) { 2427 err(BC_ERROR, boot_dir); 2428 } 2429 if (!S_ISDIR(sb.st_mode)) { 2430 errx(BC_ERROR, gettext("%s: not a directory"), 2431 boot_dir); 2432 } 2433 break; 2434 case 'd': 2435 boot_debug = true; 2436 break; 2437 case 'e': 2438 strip = true; 2439 break; 2440 case 'F': 2441 force_update = true; 2442 break; 2443 case 'f': 2444 force_mbr = true; 2445 break; 2446 case 'h': 2447 usage(progname, BC_SUCCESS); 2448 break; 2449 case 'i': 2450 do_getinfo = true; 2451 break; 2452 case 'M': 2453 do_mirror_bblk = true; 2454 break; 2455 case 'm': 2456 write_mbr = true; 2457 break; 2458 case 'n': 2459 nowrite = true; 2460 break; 2461 case 'u': 2462 do_version = true; 2463 2464 update_str = strdup(optarg); 2465 if (update_str == NULL) { 2466 perror(gettext("Memory allocation failure")); 2467 exit(BC_ERROR); 2468 } 2469 break; 2470 case 'V': 2471 verbose_dump = true; 2472 break; 2473 default: 2474 /* fall through to process non-optional args */ 2475 break; 2476 } 2477 } 2478 2479 /* check arguments */ 2480 check_options(progname); 2481 2482 if (nowrite) 2483 (void) fprintf(stdout, gettext("Dry run requested. Nothing will" 2484 " be written to disk.\n")); 2485 2486 if (do_getinfo) { 2487 ret = handle_getinfo(progname, argc - optind, argv + optind); 2488 } else if (do_mirror_bblk) { 2489 ret = handle_mirror(progname, argc - optind, argv + optind); 2490 } else { 2491 ret = handle_install(progname, argc - optind, argv + optind); 2492 } 2493 fini_yes(); 2494 return (ret); 2495 } 2496 2497 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n") 2498 static void 2499 check_options(char *progname) 2500 { 2501 if (do_getinfo && do_mirror_bblk) { 2502 (void) fprintf(stderr, gettext("Only one of -M and -i can be " 2503 "specified at the same time\n")); 2504 usage(progname, BC_ERROR); 2505 } 2506 2507 if (do_mirror_bblk) { 2508 /* 2509 * -u and -F may actually reflect a user intent that is not 2510 * correct with this command (mirror can be interpreted 2511 * "similar" to install. Emit a message and continue. 2512 * -e and -V have no meaning, be quiet here and only report the 2513 * incongruence if a debug output is requested. 2514 */ 2515 if (do_version) { 2516 (void) fprintf(stderr, MEANINGLESS_OPT, "-u"); 2517 do_version = false; 2518 } 2519 if (force_update) { 2520 (void) fprintf(stderr, MEANINGLESS_OPT, "-F"); 2521 force_update = false; 2522 } 2523 if (strip || verbose_dump) { 2524 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V"); 2525 strip = false; 2526 verbose_dump = false; 2527 } 2528 } 2529 2530 if ((strip || verbose_dump) && !do_getinfo) 2531 usage(progname, BC_ERROR); 2532 2533 if (do_getinfo) { 2534 if (write_mbr || force_mbr || do_version || force_update) { 2535 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F"); 2536 write_mbr = force_mbr = do_version = false; 2537 force_update = false; 2538 } 2539 } 2540 } 2541