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