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