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) + 1, 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 will be written to %s\n", plist->pl_src_name, 457 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 data = malloc(SECTOR_SIZE); 584 if (data == NULL) 585 return (rv); 586 587 /* read the stage1 file from filesystem */ 588 fd = open(plist->pl_src_name, O_RDONLY); 589 if (fd == -1 || 590 read(fd, data, SECTOR_SIZE) != SECTOR_SIZE) { 591 (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"), 592 plist->pl_src_name); 593 free(data); 594 if (fd != -1) 595 (void) close(fd); 596 return (rv); 597 } 598 599 plist->pl_src_data = data; 600 (void) close(fd); 601 return (true); 602 } 603 604 static bool 605 read_stage2_cb(struct partlist *plist) 606 { 607 ib_device_t *device; 608 ib_bootblock_t *bblock; 609 int fd; 610 uint32_t size, offset; 611 uint32_t buf_size; 612 uint32_t mboot_off; 613 multiboot_header_t *mboot; 614 size_t scan_size; 615 616 bblock = calloc(1, sizeof (ib_bootblock_t)); 617 if (bblock == NULL) 618 return (false); 619 620 if ((fd = open_device(plist->pl_devname)) == -1) { 621 free(bblock); 622 return (false); 623 } 624 625 device = plist->pl_device; 626 plist->pl_stage = bblock; 627 offset = device->stage.offset * SECTOR_SIZE; 628 scan_size = MIN(sizeof (mboot_scan), 629 (device->stage.size - device->stage.offset) * sector_size); 630 631 if (read_in(fd, mboot_scan, scan_size, offset) 632 != BC_SUCCESS) { 633 BOOT_DEBUG("Error reading bootblock area\n"); 634 perror("read"); 635 (void) close(fd); 636 return (false); 637 } 638 639 /* No multiboot means no chance of knowing bootblock size */ 640 if (find_multiboot(mboot_scan, scan_size, &mboot_off) 641 != BC_SUCCESS) { 642 BOOT_DEBUG("Unable to find multiboot header\n"); 643 (void) close(fd); 644 return (false); 645 } 646 mboot = (multiboot_header_t *)(mboot_scan + mboot_off); 647 648 /* 649 * make sure mboot has sane values 650 */ 651 if (mboot->load_end_addr == 0 || 652 mboot->load_end_addr < mboot->load_addr) { 653 (void) close(fd); 654 return (false); 655 } 656 657 /* 658 * Currently, the amount of space reserved for extra information 659 * is "fixed". We may have to scan for the terminating extra payload 660 * in the future. 661 */ 662 size = mboot->load_end_addr - mboot->load_addr; 663 buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE); 664 bblock->file_size = size; 665 666 bblock->buf = malloc(buf_size); 667 if (bblock->buf == NULL) { 668 BOOT_DEBUG("Unable to allocate enough memory to read" 669 " the extra bootblock from the disk\n"); 670 perror(gettext("Memory allocation failure")); 671 (void) close(fd); 672 return (false); 673 } 674 bblock->buf_size = buf_size; 675 676 if (read_in(fd, bblock->buf, buf_size, offset) != BC_SUCCESS) { 677 BOOT_DEBUG("Error reading the bootblock\n"); 678 (void) free(bblock->buf); 679 bblock->buf = NULL; 680 (void) close(fd); 681 return (false); 682 } 683 684 /* Update pointers. */ 685 bblock->file = bblock->buf; 686 bblock->mboot_off = mboot_off; 687 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off); 688 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 689 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 690 691 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 692 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 693 bblock->extra_size, bblock->buf, bblock->buf_size); 694 695 return (true); 696 } 697 698 static bool 699 read_einfo_file_cb(struct partlist *plist) 700 { 701 int rc; 702 void *stage; 703 704 stage = calloc(1, sizeof (ib_bootblock_t)); 705 if (stage == NULL) 706 return (false); 707 708 rc = read_bootblock_from_file(plist->pl_devname, stage); 709 if (rc != BC_SUCCESS) { 710 free(stage); 711 stage = NULL; 712 } 713 plist->pl_stage = stage; 714 return (rc == BC_SUCCESS); 715 } 716 717 static bool 718 read_stage2_file_cb(struct partlist *plist) 719 { 720 int rc; 721 void *data; 722 723 data = calloc(1, sizeof (ib_bootblock_t)); 724 if (data == NULL) 725 return (false); 726 727 rc = read_bootblock_from_file(plist->pl_src_name, data); 728 if (rc != BC_SUCCESS) { 729 free(data); 730 data = NULL; 731 } 732 plist->pl_src_data = data; 733 return (rc == BC_SUCCESS); 734 } 735 736 /* 737 * convert /dev/rdsk/... to /dev/dsk/... 738 */ 739 static char * 740 make_blkdev(const char *path) 741 { 742 char *tmp; 743 char *ptr = strdup(path); 744 745 if (ptr == NULL) 746 return (ptr); 747 748 tmp = strstr(ptr, "rdsk"); 749 if (tmp == NULL) { 750 free(ptr); 751 return (NULL); /* Something is very wrong */ 752 } 753 /* This is safe because we do shorten the string */ 754 (void) memmove(tmp, tmp + 1, strlen(tmp)); 755 return (ptr); 756 } 757 758 /* 759 * Try to mount ESP and read boot program. 760 */ 761 static bool 762 read_einfo_esp_cb(struct partlist *plist) 763 { 764 fstyp_handle_t fhdl; 765 const char *fident; 766 char *blkdev, *path, *file; 767 bool rv = false; 768 FILE *fp; 769 struct mnttab mp, mpref = { 0 }; 770 int fd, ret; 771 772 if ((fd = open_device(plist->pl_devname)) == -1) 773 return (rv); 774 775 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 776 (void) close(fd); 777 return (rv); 778 } 779 780 if (fstyp_ident(fhdl, NULL, &fident) != 0) { 781 fstyp_fini(fhdl); 782 (void) close(fd); 783 (void) fprintf(stderr, gettext("Failed to detect file " 784 "system type\n")); 785 return (rv); 786 } 787 788 /* We only do expect pcfs. */ 789 if (strcmp(fident, MNTTYPE_PCFS) != 0) { 790 (void) fprintf(stderr, 791 gettext("File system %s is not supported.\n"), fident); 792 fstyp_fini(fhdl); 793 (void) close(fd); 794 return (rv); 795 } 796 fstyp_fini(fhdl); 797 (void) close(fd); 798 799 blkdev = make_blkdev(plist->pl_devname); 800 if (blkdev == NULL) 801 return (rv); 802 803 /* mount ESP if needed, read boot program(s) and unmount. */ 804 fp = fopen(MNTTAB, "r"); 805 if (fp == NULL) { 806 perror("fopen"); 807 free(blkdev); 808 return (rv); 809 } 810 811 mpref.mnt_special = blkdev; 812 ret = getmntany(fp, &mp, &mpref); 813 (void) fclose(fp); 814 if (ret == 0) 815 path = mp.mnt_mountp; 816 else 817 path = stagefs_mount(blkdev, plist); 818 819 free(blkdev); 820 if (path == NULL) 821 return (rv); 822 823 if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) { 824 return (rv); 825 } 826 827 plist->pl_stage = calloc(1, sizeof (ib_bootblock_t)); 828 if (plist->pl_stage == NULL) { 829 free(file); 830 return (rv); 831 } 832 if (read_bootblock_from_file(file, plist->pl_stage) != BC_SUCCESS) { 833 free(plist->pl_stage); 834 plist->pl_stage = NULL; 835 } else { 836 rv = true; 837 } 838 839 free(file); 840 return (rv); 841 } 842 843 static void 844 print_stage1_cb(struct partlist *plist) 845 { 846 struct mboot *mbr; 847 struct ipart *part; 848 mbr_type_t type = MBR_TYPE_UNKNOWN; 849 bool pmbr = false; 850 char *label; 851 852 mbr = plist->pl_stage; 853 854 if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) { 855 type = MBR_TYPE_GRUB1; 856 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) { 857 type = MBR_TYPE_LOADER; 858 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) { 859 type = MBR_TYPE_LOADER_JOYENT; 860 } 861 862 part = (struct ipart *)mbr->parts; 863 for (int i = 0; i < FD_NUMPART; i++) { 864 if (part[i].systid == EFI_PMBR) 865 pmbr = true; 866 } 867 868 if (plist->pl_type == IB_BBLK_MBR) 869 label = pmbr ? "PMBR" : "MBR"; 870 else 871 label = "VBR"; 872 873 printf("%s block from %s:\n", label, plist->pl_devname); 874 875 switch (type) { 876 case MBR_TYPE_UNKNOWN: 877 printf("Format: unknown\n"); 878 break; 879 case MBR_TYPE_GRUB1: 880 printf("Format: grub1\n"); 881 break; 882 case MBR_TYPE_LOADER: 883 printf("Format: loader (illumos)\n"); 884 break; 885 case MBR_TYPE_LOADER_JOYENT: 886 printf("Format: loader (joyent)\n"); 887 break; 888 } 889 890 printf("Signature: 0x%hx (%s)\n", mbr->signature, 891 mbr->signature == MBB_MAGIC ? "valid" : "invalid"); 892 893 printf("UniqueMBRDiskSignature: %#lx\n", 894 *(uint32_t *)&mbr->bootinst[STAGE1_SIG]); 895 896 if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) { 897 char uuid[UUID_PRINTABLE_STRING_LENGTH]; 898 899 printf("Loader STAGE1_STAGE2_LBA: %llu\n", 900 *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]); 901 902 printf("Loader STAGE1_STAGE2_SIZE: %hu\n", 903 *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]); 904 905 uuid_unparse((uchar_t *)&mbr->bootinst[STAGE1_STAGE2_UUID], 906 uuid); 907 908 printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid); 909 } 910 printf("\n"); 911 } 912 913 static void 914 print_einfo_cb(struct partlist *plist) 915 { 916 uint8_t flags = 0; 917 ib_bootblock_t *bblock; 918 bblk_einfo_t *einfo = NULL; 919 const char *filepath; 920 921 /* No stage, get out. */ 922 bblock = plist->pl_stage; 923 if (bblock == NULL) 924 return; 925 926 if (plist->pl_device->stage.path == NULL) 927 filepath = ""; 928 else 929 filepath = plist->pl_device->stage.path; 930 931 printf("Boot block from %s:%s\n", plist->pl_devname, filepath); 932 933 if (bblock->extra != NULL) 934 einfo = find_einfo(bblock->extra, bblock->extra_size); 935 936 if (einfo == NULL) { 937 (void) fprintf(stderr, 938 gettext("No extended information found.\n\n")); 939 return; 940 } 941 942 /* Print the extended information. */ 943 if (strip) 944 flags |= EINFO_EASY_PARSE; 945 if (verbose_dump) 946 flags |= EINFO_PRINT_HEADER; 947 948 print_einfo(flags, einfo, bblock->extra_size); 949 printf("\n"); 950 } 951 952 static size_t 953 get_media_info(int fd) 954 { 955 struct dk_minfo disk_info; 956 957 if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1) 958 return (SECTOR_SIZE); 959 960 return (disk_info.dki_lbsize); 961 } 962 963 static struct partlist * 964 partlist_alloc(void) 965 { 966 struct partlist *pl; 967 968 if ((pl = calloc(1, sizeof (*pl))) == NULL) { 969 perror("calloc"); 970 return (NULL); 971 } 972 973 pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 974 if (pl->pl_device == NULL) { 975 perror("calloc"); 976 free(pl); 977 return (NULL); 978 } 979 980 return (pl); 981 } 982 983 static void 984 partlist_free(struct partlist *pl) 985 { 986 ib_bootblock_t *bblock; 987 ib_device_t *device; 988 989 switch (pl->pl_type) { 990 case IB_BBLK_MBR: 991 case IB_BBLK_STAGE1: 992 free(pl->pl_stage); 993 break; 994 default: 995 if (pl->pl_stage != NULL) { 996 bblock = pl->pl_stage; 997 free(bblock->buf); 998 free(bblock); 999 } 1000 } 1001 1002 /* umount the stage fs. */ 1003 if (pl->pl_device->stage.mntpnt != NULL) { 1004 if (umount(pl->pl_device->stage.mntpnt) == 0) 1005 (void) rmdir(pl->pl_device->stage.mntpnt); 1006 free(pl->pl_device->stage.mntpnt); 1007 } 1008 device = pl->pl_device; 1009 free(device->target.path); 1010 free(pl->pl_device); 1011 1012 free(pl->pl_src_data); 1013 free(pl->pl_devname); 1014 free(pl); 1015 } 1016 1017 static bool 1018 probe_fstyp(ib_data_t *data) 1019 { 1020 fstyp_handle_t fhdl; 1021 const char *fident; 1022 char *ptr; 1023 int fd; 1024 bool rv = false; 1025 1026 /* Record partition id */ 1027 ptr = strrchr(data->target.path, 'p'); 1028 if (ptr == NULL) 1029 ptr = strrchr(data->target.path, 's'); 1030 data->target.id = atoi(++ptr); 1031 if ((fd = open_device(data->target.path)) == -1) 1032 return (rv); 1033 1034 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 1035 (void) close(fd); 1036 return (rv); 1037 } 1038 1039 if (fstyp_ident(fhdl, NULL, &fident) != 0) { 1040 fstyp_fini(fhdl); 1041 (void) fprintf(stderr, gettext("Failed to detect file " 1042 "system type\n")); 1043 (void) close(fd); 1044 return (rv); 1045 } 1046 1047 rv = true; 1048 if (strcmp(fident, MNTTYPE_ZFS) == 0) 1049 data->target.fstype = IB_FS_ZFS; 1050 else if (strcmp(fident, MNTTYPE_UFS) == 0) { 1051 data->target.fstype = IB_FS_UFS; 1052 } else if (strcmp(fident, MNTTYPE_PCFS) == 0) { 1053 data->target.fstype = IB_FS_PCFS; 1054 /* with pcfs we always write MBR */ 1055 force_mbr = true; 1056 write_mbr = true; 1057 } else { 1058 (void) fprintf(stderr, gettext("File system %s is not " 1059 "supported by loader\n"), fident); 1060 rv = false; 1061 } 1062 fstyp_fini(fhdl); 1063 (void) close(fd); 1064 return (rv); 1065 } 1066 1067 static bool 1068 get_slice(ib_data_t *data, struct partlist *pl, struct dk_gpt *vtoc, 1069 uint16_t tag) 1070 { 1071 uint_t i; 1072 ib_device_t *device = pl->pl_device; 1073 char *path, *ptr; 1074 1075 if (tag != V_BOOT && tag != V_SYSTEM) 1076 return (false); 1077 1078 for (i = 0; i < vtoc->efi_nparts; i++) { 1079 if (vtoc->efi_parts[i].p_tag == tag) { 1080 if ((path = strdup(data->target.path)) == NULL) { 1081 perror(gettext("Memory allocation failure")); 1082 return (false); 1083 } 1084 ptr = strrchr(path, 's'); 1085 ptr++; 1086 *ptr = '\0'; 1087 (void) asprintf(&ptr, "%s%d", path, i); 1088 free(path); 1089 if (ptr == NULL) { 1090 perror(gettext("Memory allocation failure")); 1091 return (false); 1092 } 1093 pl->pl_devname = ptr; 1094 device->stage.id = i; 1095 device->stage.devtype = IB_DEV_EFI; 1096 switch (vtoc->efi_parts[i].p_tag) { 1097 case V_BOOT: 1098 device->stage.fstype = IB_FS_NONE; 1099 /* leave sector 0 for VBR */ 1100 device->stage.offset = 1; 1101 break; 1102 case V_SYSTEM: 1103 device->stage.fstype = IB_FS_PCFS; 1104 break; 1105 } 1106 device->stage.tag = vtoc->efi_parts[i].p_tag; 1107 device->stage.start = vtoc->efi_parts[i].p_start; 1108 device->stage.size = vtoc->efi_parts[i].p_size; 1109 break; 1110 } 1111 } 1112 return (true); 1113 } 1114 1115 static bool 1116 allocate_slice(ib_data_t *data, struct dk_gpt *vtoc, uint16_t tag, 1117 struct partlist **plp) 1118 { 1119 struct partlist *pl; 1120 1121 *plp = NULL; 1122 if ((pl = partlist_alloc()) == NULL) 1123 return (false); 1124 1125 pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 1126 if (pl->pl_device == NULL) { 1127 perror("calloc"); 1128 partlist_free(pl); 1129 return (false); 1130 } 1131 if (!get_slice(data, pl, vtoc, tag)) { 1132 partlist_free(pl); 1133 return (false); 1134 } 1135 1136 /* tag was not found */ 1137 if (pl->pl_devname == NULL) 1138 partlist_free(pl); 1139 else 1140 *plp = pl; 1141 1142 return (true); 1143 } 1144 1145 static bool 1146 probe_gpt(ib_data_t *data) 1147 { 1148 struct partlist *pl; 1149 struct dk_gpt *vtoc; 1150 ib_device_t *device; 1151 int slice, fd; 1152 bool rv = false; 1153 1154 if ((fd = open_device(data->target.path)) < 0) 1155 return (rv); 1156 1157 slice = efi_alloc_and_read(fd, &vtoc); 1158 (void) close(fd); 1159 if (slice < 0) 1160 return (rv); 1161 1162 data->device.devtype = IB_DEV_EFI; 1163 data->target.start = vtoc->efi_parts[slice].p_start; 1164 data->target.size = vtoc->efi_parts[slice].p_size; 1165 1166 /* Always update PMBR. */ 1167 force_mbr = true; 1168 write_mbr = true; 1169 1170 /* 1171 * With GPT we can have boot partition and ESP. 1172 * Boot partition can have both stage 1 and stage 2. 1173 */ 1174 if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1175 goto done; 1176 if (pl != NULL) { 1177 pl->pl_src_name = stage1; 1178 pl->pl_type = IB_BBLK_STAGE1; 1179 pl->pl_cb.compare = compare_stage1_cb; 1180 pl->pl_cb.install = install_stage1_cb; 1181 pl->pl_cb.read = read_stage1_cb; 1182 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1183 pl->pl_cb.print = print_stage1_cb; 1184 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1185 } else if (data->target.fstype != IB_FS_ZFS) { 1186 (void) fprintf(stderr, gettext("Booting %s from EFI " 1187 "labeled disks requires the boot partition.\n"), 1188 data->target.fstype == IB_FS_UFS? 1189 MNTTYPE_UFS : MNTTYPE_PCFS); 1190 goto done; 1191 } 1192 /* Add stage 2 */ 1193 if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1194 goto done; 1195 if (pl != NULL) { 1196 pl->pl_src_name = stage2; 1197 pl->pl_type = IB_BBLK_STAGE2; 1198 pl->pl_cb.compare = compare_einfo_cb; 1199 pl->pl_cb.install = install_stage2_cb; 1200 pl->pl_cb.read = read_stage2_cb; 1201 pl->pl_cb.read_bbl = read_stage2_file_cb; 1202 pl->pl_cb.print = print_einfo_cb; 1203 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1204 } 1205 1206 /* ESP can have 32- and 64-bit boot code. */ 1207 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1208 goto done; 1209 if (pl != NULL) { 1210 pl->pl_device->stage.path = "/EFI/Boot/" BOOTIA32; 1211 pl->pl_src_name = efi32; 1212 pl->pl_type = IB_BBLK_EFI; 1213 pl->pl_cb.compare = compare_einfo_cb; 1214 pl->pl_cb.install = install_esp_cb; 1215 pl->pl_cb.read = read_einfo_esp_cb; 1216 pl->pl_cb.read_bbl = read_stage2_file_cb; 1217 pl->pl_cb.print = print_einfo_cb; 1218 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1219 } 1220 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1221 goto done; 1222 if (pl != NULL) { 1223 pl->pl_device->stage.path = "/EFI/Boot/" BOOTX64; 1224 pl->pl_src_name = efi64; 1225 pl->pl_type = IB_BBLK_EFI; 1226 pl->pl_cb.compare = compare_einfo_cb; 1227 pl->pl_cb.install = install_esp_cb; 1228 pl->pl_cb.read = read_einfo_esp_cb; 1229 pl->pl_cb.read_bbl = read_stage2_file_cb; 1230 pl->pl_cb.print = print_einfo_cb; 1231 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1232 } 1233 1234 /* add stage for our target file system slice */ 1235 pl = partlist_alloc(); 1236 if (pl == NULL) 1237 goto done; 1238 1239 device = pl->pl_device; 1240 device->stage.devtype = data->device.devtype; 1241 if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1242 perror(gettext("Memory allocation failure")); 1243 partlist_free(pl); 1244 goto done; 1245 } 1246 1247 device->stage.id = slice; 1248 device->stage.start = vtoc->efi_parts[slice].p_start; 1249 device->stage.size = vtoc->efi_parts[slice].p_size; 1250 1251 /* ZFS and UFS can have stage1 in boot area. */ 1252 if (data->target.fstype == IB_FS_ZFS || 1253 data->target.fstype == IB_FS_UFS) { 1254 pl->pl_src_name = stage1; 1255 pl->pl_type = IB_BBLK_STAGE1; 1256 pl->pl_cb.compare = compare_stage1_cb; 1257 pl->pl_cb.install = install_stage1_cb; 1258 pl->pl_cb.read = read_stage1_cb; 1259 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1260 pl->pl_cb.print = print_stage1_cb; 1261 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1262 } 1263 1264 if (data->target.fstype == IB_FS_ZFS) { 1265 pl = partlist_alloc(); 1266 if (pl == NULL) 1267 goto done; 1268 1269 device = pl->pl_device; 1270 device->stage.devtype = data->device.devtype; 1271 1272 if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1273 perror(gettext("Memory allocation failure")); 1274 goto done; 1275 } 1276 1277 device->stage.id = slice; 1278 device->stage.start = vtoc->efi_parts[slice].p_start; 1279 device->stage.size = vtoc->efi_parts[slice].p_size; 1280 1281 device->stage.offset = BBLK_ZFS_BLK_OFF; 1282 pl->pl_src_name = stage2; 1283 pl->pl_type = IB_BBLK_STAGE2; 1284 pl->pl_cb.compare = compare_einfo_cb; 1285 pl->pl_cb.install = install_stage2_cb; 1286 pl->pl_cb.read = read_stage2_cb; 1287 pl->pl_cb.read_bbl = read_stage2_file_cb; 1288 pl->pl_cb.print = print_einfo_cb; 1289 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1290 } 1291 rv = true; 1292 done: 1293 efi_free(vtoc); 1294 return (rv); 1295 } 1296 1297 static bool 1298 get_start_sector(ib_data_t *data, struct extpartition *v_part, 1299 diskaddr_t *start) 1300 { 1301 struct partlist *pl; 1302 struct mboot *mbr; 1303 struct ipart *part; 1304 struct part_info dkpi; 1305 struct extpart_info edkpi; 1306 uint32_t secnum, numsec; 1307 ext_part_t *epp; 1308 ushort_t i; 1309 int fd, rval, pno; 1310 1311 if ((fd = open_device(data->target.path)) < 0) 1312 return (false); 1313 1314 if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) { 1315 if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) { 1316 (void) fprintf(stderr, gettext("cannot get the " 1317 "slice information of the disk\n")); 1318 (void) close(fd); 1319 return (false); 1320 } else { 1321 edkpi.p_start = dkpi.p_start; 1322 edkpi.p_length = dkpi.p_length; 1323 } 1324 } 1325 (void) close(fd); 1326 1327 /* Set target file system start and size */ 1328 data->target.start = edkpi.p_start; 1329 data->target.size = edkpi.p_length; 1330 1331 /* This is our MBR partition start. */ 1332 edkpi.p_start -= v_part->p_start; 1333 1334 /* Head is always MBR */ 1335 pl = STAILQ_FIRST(data->plist); 1336 if (!read_stage1_cb(pl)) 1337 return (false); 1338 1339 mbr = (struct mboot *)pl->pl_stage; 1340 part = (struct ipart *)mbr->parts; 1341 1342 for (i = 0; i < FD_NUMPART; i++) { 1343 if (part[i].relsect == edkpi.p_start) { 1344 *start = part[i].relsect; 1345 return (true); 1346 } 1347 } 1348 1349 rval = libfdisk_init(&epp, pl->pl_devname, part, FDISK_READ_DISK); 1350 if (rval != FDISK_SUCCESS) { 1351 switch (rval) { 1352 /* 1353 * The first 3 cases are not an error per-se, just that 1354 * there is no Solaris logical partition 1355 */ 1356 case FDISK_EBADLOGDRIVE: 1357 case FDISK_ENOLOGDRIVE: 1358 case FDISK_EBADMAGIC: 1359 (void) fprintf(stderr, gettext("Solaris " 1360 "partition not found. " 1361 "Aborting operation. %d\n"), rval); 1362 return (false); 1363 case FDISK_ENOVGEOM: 1364 (void) fprintf(stderr, gettext("Could not get " 1365 "virtual geometry\n")); 1366 return (false); 1367 case FDISK_ENOPGEOM: 1368 (void) fprintf(stderr, gettext("Could not get " 1369 "physical geometry\n")); 1370 return (false); 1371 case FDISK_ENOLGEOM: 1372 (void) fprintf(stderr, gettext("Could not get " 1373 "label geometry\n")); 1374 return (false); 1375 default: 1376 (void) fprintf(stderr, gettext("Failed to " 1377 "initialize libfdisk.\n")); 1378 return (false); 1379 } 1380 } 1381 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); 1382 libfdisk_fini(&epp); 1383 if (rval != FDISK_SUCCESS) { 1384 /* No solaris logical partition */ 1385 (void) fprintf(stderr, gettext("Solaris partition not found. " 1386 "Aborting operation.\n")); 1387 return (false); 1388 } 1389 *start = secnum; 1390 return (true); 1391 } 1392 1393 /* 1394 * On x86 the VTOC table is inside MBR partition and to get 1395 * absolute sectors, we need to add MBR partition start to VTOC slice start. 1396 */ 1397 static bool 1398 probe_vtoc(ib_data_t *data) 1399 { 1400 struct partlist *pl; 1401 struct extvtoc exvtoc; 1402 ib_device_t *device; 1403 char *path, *ptr; 1404 ushort_t i; 1405 int slice, fd; 1406 diskaddr_t start; 1407 bool rv; 1408 1409 rv = false; 1410 1411 if ((fd = open_device(data->target.path)) < 0) 1412 return (rv); 1413 1414 slice = read_extvtoc(fd, &exvtoc); 1415 (void) close(fd); 1416 if (slice < 0) 1417 return (rv); 1418 data->device.devtype = IB_DEV_VTOC; 1419 1420 if (!get_start_sector(data, exvtoc.v_part + slice, &start)) 1421 return (rv); 1422 1423 if (exvtoc.v_part[slice].p_tag == V_BACKUP) { 1424 /* 1425 * NOTE: we could relax there and allow zfs boot on 1426 * slice 2, but lets keep traditional limits. 1427 */ 1428 (void) fprintf(stderr, gettext( 1429 "raw device must be a root slice (not backup)\n")); 1430 return (rv); 1431 } 1432 1433 if ((path = strdup(data->target.path)) == NULL) { 1434 perror(gettext("Memory allocation failure")); 1435 return (false); 1436 } 1437 1438 data->target.start = start + exvtoc.v_part[slice].p_start; 1439 data->target.size = exvtoc.v_part[slice].p_size; 1440 1441 /* Search for boot slice. */ 1442 for (i = 0; i < exvtoc.v_nparts; i++) { 1443 if (exvtoc.v_part[i].p_tag == V_BOOT) 1444 break; 1445 } 1446 1447 if (i == exvtoc.v_nparts || 1448 exvtoc.v_part[i].p_size == 0) { 1449 /* fall back to slice V_BACKUP */ 1450 for (i = 0; i < exvtoc.v_nparts; i++) { 1451 if (exvtoc.v_part[i].p_tag == V_BACKUP) 1452 break; 1453 } 1454 /* Still nothing? Error out. */ 1455 if (i == exvtoc.v_nparts || 1456 exvtoc.v_part[i].p_size == 0) { 1457 free(path); 1458 return (false); 1459 } 1460 } 1461 1462 /* Create path. */ 1463 ptr = strrchr(path, 's'); 1464 ptr++; 1465 *ptr = '\0'; 1466 (void) asprintf(&ptr, "%s%d", path, i); 1467 free(path); 1468 if (ptr == NULL) { 1469 perror(gettext("Memory allocation failure")); 1470 return (false); 1471 } 1472 1473 pl = partlist_alloc(); 1474 if (pl == NULL) { 1475 free(ptr); 1476 return (false); 1477 } 1478 pl->pl_devname = ptr; 1479 device = pl->pl_device; 1480 device->stage.devtype = data->device.devtype; 1481 device->stage.id = i; 1482 device->stage.tag = exvtoc.v_part[i].p_tag; 1483 device->stage.start = start + exvtoc.v_part[i].p_start; 1484 device->stage.size = exvtoc.v_part[i].p_size; 1485 1486 /* Fix size if this slice is in fact V_BACKUP */ 1487 if (exvtoc.v_part[i].p_tag == V_BACKUP) { 1488 for (i = 0; i < exvtoc.v_nparts; i++) { 1489 if (exvtoc.v_part[i].p_start == 0) 1490 continue; 1491 if (exvtoc.v_part[i].p_size == 0) 1492 continue; 1493 if (exvtoc.v_part[i].p_start < 1494 device->stage.size) 1495 device->stage.size = 1496 exvtoc.v_part[i].p_start; 1497 } 1498 } 1499 1500 pl->pl_src_name = stage1; 1501 pl->pl_type = IB_BBLK_STAGE1; 1502 pl->pl_cb.compare = compare_stage1_cb; 1503 pl->pl_cb.install = install_stage1_cb; 1504 pl->pl_cb.read = read_stage1_cb; 1505 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1506 pl->pl_cb.print = print_stage1_cb; 1507 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1508 1509 /* Create instance for stage 2 */ 1510 pl = partlist_alloc(); 1511 if (pl == NULL) { 1512 free(ptr); 1513 return (false); 1514 } 1515 pl->pl_devname = strdup(ptr); 1516 if (pl->pl_devname == NULL) { 1517 partlist_free(pl); 1518 return (false); 1519 } 1520 pl->pl_device->stage.devtype = data->device.devtype; 1521 pl->pl_device->stage.id = device->stage.id; 1522 pl->pl_device->stage.offset = BBLK_BLKLIST_OFF; 1523 pl->pl_device->stage.tag = device->stage.tag; 1524 pl->pl_device->stage.start = device->stage.start; 1525 pl->pl_device->stage.size = device->stage.size; 1526 pl->pl_src_name = stage2; 1527 pl->pl_type = IB_BBLK_STAGE2; 1528 pl->pl_cb.compare = compare_einfo_cb; 1529 pl->pl_cb.install = install_stage2_cb; 1530 pl->pl_cb.read = read_stage2_cb; 1531 pl->pl_cb.read_bbl = read_stage2_file_cb; 1532 pl->pl_cb.print = print_einfo_cb; 1533 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1534 1535 /* And we are done. */ 1536 rv = true; 1537 return (rv); 1538 } 1539 1540 static bool 1541 probe_mbr(ib_data_t *data) 1542 { 1543 struct partlist *pl; 1544 struct ipart *part; 1545 struct mboot *mbr; 1546 ib_device_t *device; 1547 char *path, *ptr; 1548 int i, rv; 1549 1550 data->device.devtype = IB_DEV_MBR; 1551 1552 /* Head is always MBR */ 1553 pl = STAILQ_FIRST(data->plist); 1554 if (!read_stage1_cb(pl)) 1555 return (false); 1556 1557 mbr = (struct mboot *)pl->pl_stage; 1558 part = (struct ipart *)mbr->parts; 1559 1560 /* Set target file system start and size */ 1561 data->target.start = part[data->target.id - 1].relsect; 1562 data->target.size = part[data->target.id - 1].numsect; 1563 1564 /* Use X86BOOT partition if we have one. */ 1565 for (i = 0; i < FD_NUMPART; i++) { 1566 if (part[i].systid == X86BOOT) 1567 break; 1568 } 1569 1570 /* Keep device name of whole disk device. */ 1571 path = (char *)pl->pl_devname; 1572 if ((pl = partlist_alloc()) == NULL) 1573 return (false); 1574 device = pl->pl_device; 1575 1576 /* 1577 * No X86BOOT, try to use space between MBR and first 1578 * partition. 1579 */ 1580 if (i == FD_NUMPART) { 1581 pl->pl_devname = strdup(path); 1582 if (pl->pl_devname == NULL) { 1583 perror(gettext("Memory allocation failure")); 1584 partlist_free(pl); 1585 return (false); 1586 } 1587 device->stage.id = 0; 1588 device->stage.devtype = IB_DEV_MBR; 1589 device->stage.fstype = IB_FS_NONE; 1590 device->stage.start = 0; 1591 device->stage.size = part[0].relsect; 1592 device->stage.offset = BBLK_BLKLIST_OFF; 1593 pl->pl_src_name = stage2; 1594 pl->pl_type = IB_BBLK_STAGE2; 1595 pl->pl_cb.compare = compare_einfo_cb; 1596 pl->pl_cb.install = install_stage2_cb; 1597 pl->pl_cb.read = read_stage2_cb; 1598 pl->pl_cb.read_bbl = read_stage2_file_cb; 1599 pl->pl_cb.print = print_einfo_cb; 1600 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1601 1602 /* We have MBR for stage1 and gap for stage2, we are done. */ 1603 return (true); 1604 } 1605 1606 if ((path = strdup(path)) == NULL) { 1607 perror(gettext("Memory allocation failure")); 1608 partlist_free(pl); 1609 return (false); 1610 } 1611 ptr = strrchr(path, 'p'); 1612 ptr++; 1613 *ptr = '\0'; 1614 /* partitions are p1..p4 */ 1615 rv = asprintf(&ptr, "%s%d", path, i + 1); 1616 free(path); 1617 if (rv < 0) { 1618 perror(gettext("Memory allocation failure")); 1619 partlist_free(pl); 1620 return (false); 1621 } 1622 pl->pl_devname = ptr; 1623 device->stage.id = i + 1; 1624 device->stage.devtype = IB_DEV_MBR; 1625 device->stage.fstype = IB_FS_NONE; 1626 device->stage.start = part[i].relsect; 1627 device->stage.size = part[i].numsect; 1628 pl->pl_src_name = stage1; 1629 pl->pl_type = IB_BBLK_STAGE1; 1630 pl->pl_cb.compare = compare_stage1_cb; 1631 pl->pl_cb.install = install_stage1_cb; 1632 pl->pl_cb.read = read_stage1_cb; 1633 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1634 pl->pl_cb.print = print_stage1_cb; 1635 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1636 1637 pl = partlist_alloc(); 1638 if (pl == NULL) 1639 return (false); 1640 device = pl->pl_device; 1641 pl->pl_devname = strdup(ptr); 1642 if (pl->pl_devname == NULL) { 1643 perror(gettext("Memory allocation failure")); 1644 partlist_free(pl); 1645 return (false); 1646 } 1647 device->stage.id = i + 1; 1648 device->stage.devtype = IB_DEV_MBR; 1649 device->stage.fstype = IB_FS_NONE; 1650 device->stage.start = part[i].relsect; 1651 device->stage.size = part[i].numsect; 1652 device->stage.offset = 1; 1653 /* This is boot partition */ 1654 device->stage.tag = V_BOOT; 1655 pl->pl_src_name = stage2; 1656 pl->pl_type = IB_BBLK_STAGE2; 1657 pl->pl_cb.compare = compare_einfo_cb; 1658 pl->pl_cb.install = install_stage2_cb; 1659 pl->pl_cb.read = read_stage2_cb; 1660 pl->pl_cb.read_bbl = read_stage2_file_cb; 1661 pl->pl_cb.print = print_einfo_cb; 1662 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1663 1664 return (true); 1665 } 1666 1667 static bool 1668 probe_device(ib_data_t *data, const char *dev) 1669 { 1670 struct partlist *pl; 1671 struct stat sb; 1672 const char *ptr; 1673 char *p0; 1674 int fd, len; 1675 1676 if (dev == NULL) 1677 return (NULL); 1678 1679 len = strlen(dev); 1680 1681 if ((pl = partlist_alloc()) == NULL) 1682 return (false); 1683 1684 if (stat(dev, &sb) == -1) { 1685 perror("stat"); 1686 partlist_free(pl); 1687 return (false); 1688 } 1689 1690 /* We have regular file, register it and we are done. */ 1691 if (S_ISREG(sb.st_mode) != 0) { 1692 pl->pl_devname = (char *)dev; 1693 1694 pl->pl_type = IB_BBLK_FILE; 1695 pl->pl_cb.read = read_einfo_file_cb; 1696 pl->pl_cb.print = print_einfo_cb; 1697 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1698 return (true); 1699 } 1700 1701 /* 1702 * This is block device. 1703 * We do not allow to specify whole disk device (cXtYdZp0 or cXtYdZ). 1704 */ 1705 if ((ptr = strrchr(dev, '/')) == NULL) 1706 ptr = dev; 1707 if ((strrchr(ptr, 'p') == NULL && strrchr(ptr, 's') == NULL) || 1708 (dev[len - 2] == 'p' && dev[len - 1] == '0')) { 1709 (void) fprintf(stderr, 1710 gettext("whole disk device is not supported\n")); 1711 partlist_free(pl); 1712 return (false); 1713 } 1714 1715 data->target.path = (char *)dev; 1716 if (!probe_fstyp(data)) { 1717 partlist_free(pl); 1718 return (false); 1719 } 1720 1721 /* We start from identifying the whole disk. */ 1722 if ((p0 = strdup(dev)) == NULL) { 1723 perror("calloc"); 1724 partlist_free(pl); 1725 return (false); 1726 } 1727 1728 pl->pl_devname = p0; 1729 /* Change device name to p0 */ 1730 if ((ptr = strrchr(p0, 'p')) == NULL) 1731 ptr = strrchr(p0, 's'); 1732 p0 = (char *)ptr; 1733 p0[0] = 'p'; 1734 p0[1] = '0'; 1735 p0[2] = '\0'; 1736 1737 if ((fd = open_device(pl->pl_devname)) == -1) { 1738 partlist_free(pl); 1739 return (false); 1740 } 1741 1742 sector_size = get_media_info(fd); 1743 (void) close(fd); 1744 1745 pl->pl_src_name = stage1; 1746 pl->pl_type = IB_BBLK_MBR; 1747 pl->pl_cb.compare = compare_mbr_cb; 1748 pl->pl_cb.install = install_stage1_cb; 1749 pl->pl_cb.read = read_stage1_cb; 1750 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1751 pl->pl_cb.print = print_stage1_cb; 1752 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1753 1754 if (probe_gpt(data)) 1755 return (true); 1756 1757 if (data->device.devtype == IB_DEV_UNKNOWN) 1758 if (probe_vtoc(data)) 1759 return (true); 1760 1761 if (data->device.devtype == IB_DEV_UNKNOWN) 1762 return (probe_mbr(data)); 1763 1764 return (false); 1765 } 1766 1767 static int 1768 read_bootblock_from_file(const char *file, ib_bootblock_t *bblock) 1769 { 1770 struct stat sb; 1771 uint32_t buf_size; 1772 uint32_t mboot_off; 1773 int fd = -1; 1774 int retval = BC_ERROR; 1775 1776 assert(bblock != NULL); 1777 assert(file != NULL); 1778 1779 fd = open(file, O_RDONLY); 1780 if (fd == -1) { 1781 BOOT_DEBUG("Error opening %s\n", file); 1782 goto out; 1783 } 1784 1785 if (fstat(fd, &sb) == -1) { 1786 BOOT_DEBUG("Error getting information (stat) about %s", file); 1787 perror("stat"); 1788 goto outfd; 1789 } 1790 1791 /* loader bootblock has version built in */ 1792 buf_size = sb.st_size; 1793 if (buf_size == 0) 1794 goto outfd; 1795 1796 bblock->buf_size = buf_size; 1797 BOOT_DEBUG("bootblock in-memory buffer size is %d\n", 1798 bblock->buf_size); 1799 1800 bblock->buf = malloc(buf_size); 1801 if (bblock->buf == NULL) { 1802 perror(gettext("Memory allocation failure")); 1803 goto outbuf; 1804 } 1805 bblock->file = bblock->buf; 1806 1807 if (read(fd, bblock->file, bblock->buf_size) != bblock->buf_size) { 1808 BOOT_DEBUG("Read from %s failed\n", file); 1809 perror("read"); 1810 goto outfd; 1811 } 1812 1813 buf_size = MIN(buf_size, MBOOT_SCAN_SIZE); 1814 if (find_multiboot(bblock->file, buf_size, &mboot_off) 1815 != BC_SUCCESS) { 1816 (void) fprintf(stderr, 1817 gettext("Unable to find multiboot header\n")); 1818 goto outfd; 1819 } 1820 1821 bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off); 1822 bblock->mboot_off = mboot_off; 1823 1824 bblock->file_size = 1825 bblock->mboot->load_end_addr - bblock->mboot->load_addr; 1826 BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size); 1827 1828 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 1829 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 1830 1831 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 1832 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 1833 bblock->extra_size, bblock->buf, bblock->buf_size); 1834 1835 (void) close(fd); 1836 return (BC_SUCCESS); 1837 1838 outbuf: 1839 (void) free(bblock->buf); 1840 bblock->buf = NULL; 1841 outfd: 1842 (void) close(fd); 1843 out: 1844 if (retval == BC_ERROR) { 1845 (void) fprintf(stderr, 1846 gettext("Error reading bootblock from %s\n"), 1847 file); 1848 } 1849 1850 if (retval == BC_NOEXTRA) { 1851 BOOT_DEBUG("No multiboot header found on %s, unable to " 1852 "locate extra information area (old/non versioned " 1853 "bootblock?) \n", file); 1854 (void) fprintf(stderr, gettext("No extended information" 1855 " found\n")); 1856 } 1857 return (retval); 1858 } 1859 1860 static void 1861 add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str) 1862 { 1863 bblk_hs_t hs; 1864 uint32_t avail_space; 1865 1866 assert(bblock != NULL); 1867 1868 if (updt_str == NULL) { 1869 BOOT_DEBUG("WARNING: no update string passed to " 1870 "add_bootblock_einfo()\n"); 1871 return; 1872 } 1873 1874 /* Fill bootblock hashing source information. */ 1875 hs.src_buf = (unsigned char *)bblock->file; 1876 hs.src_size = bblock->file_size; 1877 /* How much space for the extended information structure? */ 1878 avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 1879 /* Place the extended information structure. */ 1880 add_einfo(bblock->extra, updt_str, &hs, avail_space); 1881 } 1882 1883 /* 1884 * set up data for case stage1 is installed as MBR 1885 * set up location and size of bootblock 1886 * set disk guid to provide unique information for biosdev command 1887 */ 1888 static void 1889 prepare_stage1(struct partlist *stage1, struct partlist *stage2, uuid_t uuid) 1890 { 1891 char *src, *dest; 1892 ib_bootblock_t *bblk; 1893 ib_device_t *device; 1894 uint16_t size; 1895 struct mboot *mbr; 1896 1897 src = stage1->pl_stage; 1898 dest = stage1->pl_src_data; 1899 device = stage2->pl_device; 1900 1901 /* Only copy from valid source. */ 1902 mbr = stage1->pl_stage; 1903 if (mbr->signature == MBB_MAGIC) { 1904 /* copy BPB */ 1905 bcopy(src + STAGE1_BPB_OFFSET, dest + STAGE1_BPB_OFFSET, 1906 STAGE1_BPB_SIZE); 1907 1908 /* copy MBR, note STAGE1_SIG == BOOTSZ */ 1909 bcopy(src + STAGE1_SIG, dest + STAGE1_SIG, 1910 SECTOR_SIZE - STAGE1_SIG); 1911 } 1912 1913 bcopy(uuid, dest + STAGE1_STAGE2_UUID, UUID_LEN); 1914 1915 /* set stage2 size */ 1916 bblk = stage2->pl_src_data; 1917 size = bblk->buf_size / SECTOR_SIZE; 1918 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = size; 1919 1920 /* set stage2 LBA */ 1921 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) = 1922 device->stage.start + device->stage.offset; 1923 1924 /* Copy prepared data to stage1 block read from the disk. */ 1925 bcopy(dest, src, SECTOR_SIZE); 1926 } 1927 1928 static void 1929 prepare_bootblock(ib_data_t *data, struct partlist *pl, char *updt_str) 1930 { 1931 ib_bootblock_t *bblock; 1932 uint64_t *ptr; 1933 1934 assert(pl != NULL); 1935 1936 bblock = pl->pl_src_data; 1937 if (bblock == NULL) 1938 return; 1939 1940 ptr = (uint64_t *)(&bblock->mboot->bss_end_addr); 1941 *ptr = data->target.start; 1942 1943 /* 1944 * the loader bootblock has built in version, if custom 1945 * version was provided, update it. 1946 */ 1947 if (do_version) 1948 add_bootblock_einfo(bblock, updt_str); 1949 } 1950 1951 static int 1952 open_device(const char *path) 1953 { 1954 struct stat statbuf = {0}; 1955 int fd = -1; 1956 1957 if (nowrite) 1958 fd = open(path, O_RDONLY); 1959 else 1960 fd = open(path, O_RDWR); 1961 1962 if (fd == -1) { 1963 BOOT_DEBUG("Unable to open %s\n", path); 1964 perror("open"); 1965 return (-1); 1966 } 1967 1968 if (fstat(fd, &statbuf) != 0) { 1969 BOOT_DEBUG("Unable to stat %s\n", path); 1970 perror("stat"); 1971 (void) close(fd); 1972 return (-1); 1973 } 1974 1975 if (S_ISCHR(statbuf.st_mode) == 0) { 1976 (void) fprintf(stderr, gettext("%s: Not a character device\n"), 1977 path); 1978 (void) close(fd); 1979 return (-1); 1980 } 1981 1982 return (fd); 1983 } 1984 1985 /* 1986 * We need to record stage2 location and size into pmbr/vbr. 1987 * We need to record target partiton LBA to stage2. 1988 */ 1989 static void 1990 prepare_bblocks(ib_data_t *data) 1991 { 1992 struct partlist *pl; 1993 struct partlist *mbr, *stage1, *stage2; 1994 uuid_t uuid; 1995 1996 mbr = stage1 = stage2 = NULL; 1997 /* 1998 * Walk list and pick up BIOS boot blocks. EFI boot programs 1999 * can be set in place. 2000 */ 2001 STAILQ_FOREACH(pl, data->plist, pl_next) { 2002 switch (pl->pl_type) { 2003 case IB_BBLK_MBR: 2004 mbr = pl; 2005 break; 2006 case IB_BBLK_STAGE1: 2007 stage1 = pl; 2008 break; 2009 case IB_BBLK_STAGE2: 2010 stage2 = pl; 2011 /* FALLTHROUGH */ 2012 case IB_BBLK_EFI: 2013 prepare_bootblock(data, pl, update_str); 2014 break; 2015 default: 2016 break; 2017 } 2018 } 2019 2020 /* If stage2 is missing, we are done. */ 2021 if (stage2 == NULL) 2022 return; 2023 2024 /* 2025 * Create disk uuid. We only need reasonable amount of uniqueness 2026 * to allow biosdev to identify disk based on mbr differences. 2027 */ 2028 uuid_generate(uuid); 2029 2030 if (mbr != NULL) { 2031 prepare_stage1(mbr, stage2, uuid); 2032 2033 /* 2034 * If we have stage1, we point MBR to read stage 1. 2035 */ 2036 if (stage1 != NULL) { 2037 char *dest = mbr->pl_stage; 2038 2039 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = 1; 2040 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) = 2041 stage1->pl_device->stage.start; 2042 } 2043 } 2044 2045 if (stage1 != NULL) { 2046 prepare_stage1(stage1, stage2, uuid); 2047 } 2048 } 2049 2050 /* 2051 * Install a new bootblock on the given device. handle_install() expects argv 2052 * to contain 3 parameters (the target device path and the path to the 2053 * bootblock. 2054 * 2055 * Returns: BC_SUCCESS - if the installation is successful 2056 * BC_ERROR - if the installation failed 2057 * BC_NOUPDT - if no installation was performed because the 2058 * version currently installed is more recent than the 2059 * supplied one. 2060 * 2061 */ 2062 static int 2063 handle_install(char *progname, int argc, char **argv) 2064 { 2065 struct partlist *pl; 2066 ib_data_t data = { 0 }; 2067 char *device_path = NULL; 2068 int ret = BC_ERROR; 2069 2070 switch (argc) { 2071 case 1: 2072 if ((device_path = strdup(argv[0])) == NULL) { 2073 perror(gettext("Memory Allocation Failure")); 2074 goto done; 2075 } 2076 if (asprintf(&stage1, "%s/%s", boot_dir, STAGE1) < 0) { 2077 perror(gettext("Memory Allocation Failure")); 2078 goto done; 2079 } 2080 if (asprintf(&stage2, "%s/%s", boot_dir, STAGE2) < 0) { 2081 perror(gettext("Memory Allocation Failure")); 2082 goto done; 2083 } 2084 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) { 2085 perror(gettext("Memory Allocation Failure")); 2086 goto done; 2087 } 2088 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) { 2089 perror(gettext("Memory Allocation Failure")); 2090 goto done; 2091 } 2092 break; 2093 case 3: 2094 if ((stage1 = strdup(argv[0])) == NULL) { 2095 perror(gettext("Memory Allocation Failure")); 2096 goto done; 2097 } 2098 if ((stage2 = strdup(argv[1])) == NULL) { 2099 perror(gettext("Memory Allocation Failure")); 2100 goto done; 2101 } 2102 if ((device_path = strdup(argv[2])) == NULL) { 2103 perror(gettext("Memory Allocation Failure")); 2104 goto done; 2105 } 2106 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) { 2107 perror(gettext("Memory Allocation Failure")); 2108 goto done; 2109 } 2110 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) { 2111 perror(gettext("Memory Allocation Failure")); 2112 goto done; 2113 } 2114 break; 2115 default: 2116 usage(progname, ret); 2117 } 2118 2119 data.plist = malloc(sizeof (*data.plist)); 2120 if (data.plist == NULL) { 2121 perror(gettext("Memory Allocation Failure")); 2122 goto done; 2123 } 2124 STAILQ_INIT(data.plist); 2125 2126 BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n", 2127 device_path, stage1, stage2); 2128 2129 if (probe_device(&data, device_path)) { 2130 /* Read all data. */ 2131 STAILQ_FOREACH(pl, data.plist, pl_next) { 2132 if (!pl->pl_cb.read(pl)) { 2133 printf("\n"); 2134 } 2135 if (!pl->pl_cb.read_bbl(pl)) { 2136 /* 2137 * We will ignore ESP updates in case of 2138 * older system where we are missing 2139 * loader64.efi and loader32.efi. 2140 */ 2141 if (pl->pl_type != IB_BBLK_EFI) 2142 goto cleanup; 2143 } 2144 } 2145 2146 /* Prepare data. */ 2147 prepare_bblocks(&data); 2148 2149 /* Commit data to disk. */ 2150 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != 2151 NULL) { 2152 if (pl->pl_cb.compare != NULL && 2153 pl->pl_cb.compare(pl)) { 2154 if (pl->pl_cb.install != NULL) 2155 pl->pl_cb.install(&data, pl); 2156 } 2157 STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2158 partlist_free(pl); 2159 } 2160 } 2161 ret = BC_SUCCESS; 2162 2163 cleanup: 2164 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) { 2165 STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2166 partlist_free(pl); 2167 } 2168 free(data.plist); 2169 done: 2170 free(stage1); 2171 free(stage2); 2172 free(efi32); 2173 free(efi64); 2174 free(device_path); 2175 return (ret); 2176 } 2177 2178 /* 2179 * Retrieves from a device the extended information (einfo) associated to the 2180 * file or installed stage2. 2181 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0 2182 * or file name. 2183 * Returns: 2184 * - BC_SUCCESS (and prints out einfo contents depending on 'flags') 2185 * - BC_ERROR (on error) 2186 * - BC_NOEINFO (no extended information available) 2187 */ 2188 static int 2189 handle_getinfo(char *progname, int argc, char **argv) 2190 { 2191 struct partlist *pl; 2192 ib_data_t data = { 0 }; 2193 char *device_path; 2194 2195 if (argc != 1) { 2196 (void) fprintf(stderr, gettext("Missing parameter")); 2197 usage(progname, BC_ERROR); 2198 } 2199 2200 if ((device_path = strdup(argv[0])) == NULL) { 2201 perror(gettext("Memory Allocation Failure")); 2202 return (BC_ERROR); 2203 } 2204 2205 data.plist = malloc(sizeof (*data.plist)); 2206 if (data.plist == NULL) { 2207 perror("malloc"); 2208 free(device_path); 2209 return (BC_ERROR); 2210 } 2211 STAILQ_INIT(data.plist); 2212 2213 if (probe_device(&data, device_path)) { 2214 STAILQ_FOREACH(pl, data.plist, pl_next) { 2215 if (pl->pl_cb.read(pl)) 2216 pl->pl_cb.print(pl); 2217 else 2218 printf("\n"); 2219 } 2220 } 2221 2222 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) { 2223 STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2224 partlist_free(pl); 2225 } 2226 free(data.plist); 2227 2228 return (BC_SUCCESS); 2229 } 2230 2231 /* 2232 * Attempt to mirror (propagate) the current bootblock over the attaching disk. 2233 * 2234 * Returns: 2235 * - BC_SUCCESS (a successful propagation happened) 2236 * - BC_ERROR (an error occurred) 2237 * - BC_NOEXTRA (it is not possible to dump the current bootblock since 2238 * there is no multiboot information) 2239 */ 2240 static int 2241 handle_mirror(char *progname, int argc, char **argv) 2242 { 2243 ib_data_t src = { 0 }; 2244 ib_data_t dest = { 0 }; 2245 struct partlist *pl_src, *pl_dest; 2246 char *curr_device_path = NULL; 2247 char *attach_device_path = NULL; 2248 int retval = BC_ERROR; 2249 2250 if (argc == 2) { 2251 curr_device_path = strdup(argv[0]); 2252 attach_device_path = strdup(argv[1]); 2253 } 2254 2255 if (!curr_device_path || !attach_device_path) { 2256 free(curr_device_path); 2257 free(attach_device_path); 2258 (void) fprintf(stderr, gettext("Missing parameter")); 2259 usage(progname, BC_ERROR); 2260 } 2261 BOOT_DEBUG("Current device path is: %s, attaching device path is: " 2262 " %s\n", curr_device_path, attach_device_path); 2263 2264 src.plist = malloc(sizeof (*src.plist)); 2265 if (src.plist == NULL) { 2266 perror("malloc"); 2267 return (BC_ERROR); 2268 } 2269 STAILQ_INIT(src.plist); 2270 2271 dest.plist = malloc(sizeof (*dest.plist)); 2272 if (dest.plist == NULL) { 2273 perror("malloc"); 2274 goto out; 2275 } 2276 STAILQ_INIT(dest.plist); 2277 2278 if (!probe_device(&src, curr_device_path)) { 2279 (void) fprintf(stderr, gettext("Unable to gather device " 2280 "information from %s (current device)\n"), 2281 curr_device_path); 2282 goto out; 2283 } 2284 2285 if (!probe_device(&dest, attach_device_path) != BC_SUCCESS) { 2286 (void) fprintf(stderr, gettext("Unable to gather device " 2287 "information from %s (attaching device)\n"), 2288 attach_device_path); 2289 goto cleanup_src; 2290 } 2291 2292 write_vbr = true; 2293 write_mbr = true; 2294 force_mbr = true; 2295 2296 pl_dest = STAILQ_FIRST(dest.plist); 2297 STAILQ_FOREACH(pl_src, src.plist, pl_next) { 2298 if (pl_dest == NULL) { 2299 (void) fprintf(stderr, 2300 gettext("Destination disk layout is different " 2301 "from source, can not mirror.\n")); 2302 goto cleanup; 2303 } 2304 if (!pl_src->pl_cb.read(pl_src)) { 2305 (void) fprintf(stderr, gettext("Failed to read " 2306 "boot block from %s\n"), pl_src->pl_devname); 2307 goto cleanup; 2308 } 2309 if (!pl_dest->pl_cb.read(pl_dest)) { 2310 (void) fprintf(stderr, gettext("Failed to read " 2311 "boot block from %s\n"), pl_dest->pl_devname); 2312 } 2313 2314 /* Set source pl_stage to destination source data */ 2315 pl_dest->pl_src_data = pl_src->pl_stage; 2316 pl_src->pl_stage = NULL; 2317 2318 pl_dest = STAILQ_NEXT(pl_dest, pl_next); 2319 } 2320 2321 /* Prepare data. */ 2322 prepare_bblocks(&dest); 2323 2324 /* Commit data to disk. */ 2325 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) { 2326 pl_dest->pl_cb.install(&dest, pl_dest); 2327 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next); 2328 partlist_free(pl_dest); 2329 2330 /* Free source list */ 2331 pl_src = STAILQ_LAST(src.plist, partlist, pl_next); 2332 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next); 2333 partlist_free(pl_src); 2334 } 2335 retval = BC_SUCCESS; 2336 2337 cleanup: 2338 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) { 2339 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next); 2340 partlist_free(pl_dest); 2341 } 2342 free(dest.plist); 2343 cleanup_src: 2344 while ((pl_src = STAILQ_LAST(src.plist, partlist, pl_next)) != NULL) { 2345 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next); 2346 partlist_free(pl_src); 2347 } 2348 free(src.plist); 2349 out: 2350 free(curr_device_path); 2351 free(attach_device_path); 2352 return (retval); 2353 } 2354 2355 #define USAGE_STRING \ 2356 "Usage:\t%s [-fFmn] [-b boot_dir] [-u verstr]\n" \ 2357 "\t\t[stage1 stage2] raw-device\n" \ 2358 "\t%s -M [-n] raw-device attach-raw-device\n" \ 2359 "\t%s [-e|-V] -i raw-device | file\n" 2360 2361 #define CANON_USAGE_STR gettext(USAGE_STRING) 2362 2363 static void 2364 usage(char *progname, int rc) 2365 { 2366 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname); 2367 fini_yes(); 2368 exit(rc); 2369 } 2370 2371 int 2372 main(int argc, char **argv) 2373 { 2374 int opt; 2375 int ret; 2376 char *progname; 2377 struct stat sb; 2378 2379 (void) setlocale(LC_ALL, ""); 2380 (void) textdomain(TEXT_DOMAIN); 2381 if (init_yes() < 0) 2382 errx(BC_ERROR, gettext(ERR_MSG_INIT_YES), strerror(errno)); 2383 2384 /* Needed for mount pcfs. */ 2385 tzset(); 2386 2387 /* Determine our name */ 2388 progname = basename(argv[0]); 2389 2390 while ((opt = getopt(argc, argv, "b:deFfhiMmnu:V")) != EOF) { 2391 switch (opt) { 2392 case 'b': 2393 boot_dir = strdup(optarg); 2394 if (boot_dir == NULL) { 2395 err(BC_ERROR, 2396 gettext("Memory allocation failure")); 2397 } 2398 if (lstat(boot_dir, &sb) != 0) { 2399 err(BC_ERROR, boot_dir); 2400 } 2401 if (!S_ISDIR(sb.st_mode)) { 2402 errx(BC_ERROR, gettext("%s: not a directory"), 2403 boot_dir); 2404 } 2405 break; 2406 case 'd': 2407 boot_debug = true; 2408 break; 2409 case 'e': 2410 strip = true; 2411 break; 2412 case 'F': 2413 force_update = true; 2414 break; 2415 case 'f': 2416 force_mbr = true; 2417 break; 2418 case 'h': 2419 usage(progname, BC_SUCCESS); 2420 break; 2421 case 'i': 2422 do_getinfo = true; 2423 break; 2424 case 'M': 2425 do_mirror_bblk = true; 2426 break; 2427 case 'm': 2428 write_mbr = true; 2429 break; 2430 case 'n': 2431 nowrite = true; 2432 break; 2433 case 'u': 2434 do_version = true; 2435 2436 update_str = strdup(optarg); 2437 if (update_str == NULL) { 2438 perror(gettext("Memory allocation failure")); 2439 exit(BC_ERROR); 2440 } 2441 break; 2442 case 'V': 2443 verbose_dump = true; 2444 break; 2445 default: 2446 /* fall through to process non-optional args */ 2447 break; 2448 } 2449 } 2450 2451 /* check arguments */ 2452 check_options(progname); 2453 2454 if (nowrite) 2455 (void) fprintf(stdout, gettext("Dry run requested. Nothing will" 2456 " be written to disk.\n")); 2457 2458 if (do_getinfo) { 2459 ret = handle_getinfo(progname, argc - optind, argv + optind); 2460 } else if (do_mirror_bblk) { 2461 ret = handle_mirror(progname, argc - optind, argv + optind); 2462 } else { 2463 ret = handle_install(progname, argc - optind, argv + optind); 2464 } 2465 fini_yes(); 2466 return (ret); 2467 } 2468 2469 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n") 2470 static void 2471 check_options(char *progname) 2472 { 2473 if (do_getinfo && do_mirror_bblk) { 2474 (void) fprintf(stderr, gettext("Only one of -M and -i can be " 2475 "specified at the same time\n")); 2476 usage(progname, BC_ERROR); 2477 } 2478 2479 if (do_mirror_bblk) { 2480 /* 2481 * -u and -F may actually reflect a user intent that is not 2482 * correct with this command (mirror can be interpreted 2483 * "similar" to install. Emit a message and continue. 2484 * -e and -V have no meaning, be quiet here and only report the 2485 * incongruence if a debug output is requested. 2486 */ 2487 if (do_version) { 2488 (void) fprintf(stderr, MEANINGLESS_OPT, "-u"); 2489 do_version = false; 2490 } 2491 if (force_update) { 2492 (void) fprintf(stderr, MEANINGLESS_OPT, "-F"); 2493 force_update = false; 2494 } 2495 if (strip || verbose_dump) { 2496 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V"); 2497 strip = false; 2498 verbose_dump = false; 2499 } 2500 } 2501 2502 if ((strip || verbose_dump) && !do_getinfo) 2503 usage(progname, BC_ERROR); 2504 2505 if (do_getinfo) { 2506 if (write_mbr || force_mbr || do_version || force_update) { 2507 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F"); 2508 write_mbr = force_mbr = do_version = false; 2509 force_update = false; 2510 } 2511 } 2512 } 2513