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