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 size_t scan_size; 599 600 bblock = calloc(1, sizeof (ib_bootblock_t)); 601 if (bblock == NULL) 602 return (false); 603 604 if ((fd = open_device(plist->pl_devname)) == -1) { 605 free(bblock); 606 return (false); 607 } 608 609 device = plist->pl_device; 610 plist->pl_stage = bblock; 611 offset = device->stage.offset * SECTOR_SIZE; 612 scan_size = MIN(sizeof (mboot_scan), 613 (device->stage.size - device->stage.offset) * sector_size); 614 615 if (read_in(fd, mboot_scan, scan_size, offset) 616 != BC_SUCCESS) { 617 BOOT_DEBUG("Error reading bootblock area\n"); 618 perror("read"); 619 (void) close(fd); 620 return (false); 621 } 622 623 /* No multiboot means no chance of knowing bootblock size */ 624 if (find_multiboot(mboot_scan, scan_size, &mboot_off) 625 != BC_SUCCESS) { 626 BOOT_DEBUG("Unable to find multiboot header\n"); 627 (void) close(fd); 628 return (false); 629 } 630 mboot = (multiboot_header_t *)(mboot_scan + mboot_off); 631 632 /* 633 * make sure mboot has sane values 634 */ 635 if (mboot->load_end_addr == 0 || 636 mboot->load_end_addr < mboot->load_addr) { 637 (void) close(fd); 638 return (false); 639 } 640 641 /* 642 * Currently, the amount of space reserved for extra information 643 * is "fixed". We may have to scan for the terminating extra payload 644 * in the future. 645 */ 646 size = mboot->load_end_addr - mboot->load_addr; 647 buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE); 648 bblock->file_size = size; 649 650 bblock->buf = malloc(buf_size); 651 if (bblock->buf == NULL) { 652 BOOT_DEBUG("Unable to allocate enough memory to read" 653 " the extra bootblock from the disk\n"); 654 perror(gettext("Memory allocation failure")); 655 (void) close(fd); 656 return (false); 657 } 658 bblock->buf_size = buf_size; 659 660 if (read_in(fd, bblock->buf, buf_size, offset) != BC_SUCCESS) { 661 BOOT_DEBUG("Error reading the bootblock\n"); 662 (void) free(bblock->buf); 663 bblock->buf = NULL; 664 (void) close(fd); 665 return (false); 666 } 667 668 /* Update pointers. */ 669 bblock->file = bblock->buf; 670 bblock->mboot_off = mboot_off; 671 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off); 672 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 673 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 674 675 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 676 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 677 bblock->extra_size, bblock->buf, bblock->buf_size); 678 679 return (true); 680 } 681 682 static bool 683 read_einfo_file_cb(struct partlist *plist) 684 { 685 int rc; 686 void *stage; 687 688 stage = calloc(1, sizeof (ib_bootblock_t)); 689 if (stage == NULL) 690 return (false); 691 692 rc = read_bootblock_from_file(plist->pl_devname, stage); 693 if (rc != BC_SUCCESS) { 694 free(stage); 695 stage = NULL; 696 } 697 plist->pl_stage = stage; 698 return (rc == BC_SUCCESS); 699 } 700 701 static bool 702 read_stage2_file_cb(struct partlist *plist) 703 { 704 int rc; 705 void *data; 706 707 data = calloc(1, sizeof (ib_bootblock_t)); 708 if (data == NULL) 709 return (false); 710 711 rc = read_bootblock_from_file(plist->pl_src_name, data); 712 if (rc != BC_SUCCESS) { 713 free(data); 714 data = NULL; 715 } 716 plist->pl_src_data = data; 717 return (rc == BC_SUCCESS); 718 } 719 720 /* 721 * convert /dev/rdsk/... to /dev/dsk/... 722 */ 723 static char * 724 make_blkdev(const char *path) 725 { 726 char *tmp; 727 char *ptr = strdup(path); 728 729 if (ptr == NULL) 730 return (ptr); 731 732 tmp = strstr(ptr, "rdsk"); 733 if (tmp == NULL) { 734 free(ptr); 735 return (NULL); /* Something is very wrong */ 736 } 737 /* This is safe because we do shorten the string */ 738 (void) memmove(tmp, tmp + 1, strlen(tmp)); 739 return (ptr); 740 } 741 742 /* 743 * Try to mount ESP and read boot program. 744 */ 745 static bool 746 read_einfo_esp_cb(struct partlist *plist) 747 { 748 fstyp_handle_t fhdl; 749 const char *fident; 750 char *blkdev, *path, *file; 751 bool rv = false; 752 FILE *fp; 753 struct mnttab mp, mpref = { 0 }; 754 int fd, ret; 755 756 if ((fd = open_device(plist->pl_devname)) == -1) 757 return (rv); 758 759 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 760 (void) close(fd); 761 return (rv); 762 } 763 764 if (fstyp_ident(fhdl, NULL, &fident) != 0) { 765 fstyp_fini(fhdl); 766 (void) close(fd); 767 (void) fprintf(stderr, gettext("Failed to detect file " 768 "system type\n")); 769 return (rv); 770 } 771 772 /* We only do expect pcfs. */ 773 if (strcmp(fident, MNTTYPE_PCFS) != 0) { 774 (void) fprintf(stderr, 775 gettext("File system %s is not supported.\n"), fident); 776 fstyp_fini(fhdl); 777 (void) close(fd); 778 return (rv); 779 } 780 fstyp_fini(fhdl); 781 (void) close(fd); 782 783 blkdev = make_blkdev(plist->pl_devname); 784 if (blkdev == NULL) 785 return (rv); 786 787 /* mount ESP if needed, read boot program(s) and unmount. */ 788 fp = fopen(MNTTAB, "r"); 789 if (fp == NULL) { 790 perror("fopen"); 791 free(blkdev); 792 return (rv); 793 } 794 795 mpref.mnt_special = blkdev; 796 ret = getmntany(fp, &mp, &mpref); 797 (void) fclose(fp); 798 if (ret == 0) 799 path = mp.mnt_mountp; 800 else 801 path = stagefs_mount(blkdev, plist); 802 803 free(blkdev); 804 if (path == NULL) 805 return (rv); 806 807 if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) { 808 return (rv); 809 } 810 811 plist->pl_stage = calloc(1, sizeof (ib_bootblock_t)); 812 if (plist->pl_stage == NULL) { 813 free(file); 814 return (rv); 815 } 816 if (read_bootblock_from_file(file, plist->pl_stage) != BC_SUCCESS) { 817 free(plist->pl_stage); 818 plist->pl_stage = NULL; 819 } else { 820 rv = true; 821 } 822 823 free(file); 824 return (rv); 825 } 826 827 static void 828 print_stage1_cb(struct partlist *plist) 829 { 830 struct mboot *mbr; 831 struct ipart *part; 832 mbr_type_t type = MBR_TYPE_UNKNOWN; 833 bool pmbr = false; 834 char *label; 835 836 mbr = plist->pl_stage; 837 838 if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) { 839 type = MBR_TYPE_GRUB1; 840 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) { 841 type = MBR_TYPE_LOADER; 842 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) { 843 type = MBR_TYPE_LOADER_JOYENT; 844 } 845 846 part = (struct ipart *)mbr->parts; 847 for (int i = 0; i < FD_NUMPART; i++) { 848 if (part[i].systid == EFI_PMBR) 849 pmbr = true; 850 } 851 852 if (plist->pl_type == IB_BBLK_MBR) 853 label = pmbr ? "PMBR" : "MBR"; 854 else 855 label = "VBR"; 856 857 printf("%s block from %s:\n", label, plist->pl_devname); 858 859 switch (type) { 860 case MBR_TYPE_UNKNOWN: 861 printf("Format: unknown\n"); 862 break; 863 case MBR_TYPE_GRUB1: 864 printf("Format: grub1\n"); 865 break; 866 case MBR_TYPE_LOADER: 867 printf("Format: loader (illumos)\n"); 868 break; 869 case MBR_TYPE_LOADER_JOYENT: 870 printf("Format: loader (joyent)\n"); 871 break; 872 } 873 874 printf("Signature: 0x%hx (%s)\n", mbr->signature, 875 mbr->signature == MBB_MAGIC ? "valid" : "invalid"); 876 877 printf("UniqueMBRDiskSignature: %#lx\n", 878 *(uint32_t *)&mbr->bootinst[STAGE1_SIG]); 879 880 if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) { 881 char uuid[UUID_PRINTABLE_STRING_LENGTH]; 882 883 printf("Loader STAGE1_STAGE2_LBA: %llu\n", 884 *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]); 885 886 printf("Loader STAGE1_STAGE2_SIZE: %hu\n", 887 *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]); 888 889 uuid_unparse((uchar_t *)&mbr->bootinst[STAGE1_STAGE2_UUID], 890 uuid); 891 892 printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid); 893 } 894 printf("\n"); 895 } 896 897 static void 898 print_einfo_cb(struct partlist *plist) 899 { 900 uint8_t flags = 0; 901 ib_bootblock_t *bblock; 902 bblk_einfo_t *einfo = NULL; 903 const char *filepath; 904 905 /* No stage, get out. */ 906 bblock = plist->pl_stage; 907 if (bblock == NULL) 908 return; 909 910 if (plist->pl_device->stage.path == NULL) 911 filepath = ""; 912 else 913 filepath = plist->pl_device->stage.path; 914 915 printf("Boot block from %s:%s\n", plist->pl_devname, filepath); 916 917 if (bblock->extra != NULL) 918 einfo = find_einfo(bblock->extra, bblock->extra_size); 919 920 if (einfo == NULL) { 921 (void) fprintf(stderr, 922 gettext("No extended information found.\n\n")); 923 return; 924 } 925 926 /* Print the extended information. */ 927 if (strip) 928 flags |= EINFO_EASY_PARSE; 929 if (verbose_dump) 930 flags |= EINFO_PRINT_HEADER; 931 932 print_einfo(flags, einfo, bblock->extra_size); 933 printf("\n"); 934 } 935 936 static size_t 937 get_media_info(int fd) 938 { 939 struct dk_minfo disk_info; 940 941 if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1) 942 return (SECTOR_SIZE); 943 944 return (disk_info.dki_lbsize); 945 } 946 947 static struct partlist * 948 partlist_alloc(void) 949 { 950 struct partlist *pl; 951 952 if ((pl = calloc(1, sizeof (*pl))) == NULL) { 953 perror("calloc"); 954 return (NULL); 955 } 956 957 pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 958 if (pl->pl_device == NULL) { 959 perror("calloc"); 960 free(pl); 961 return (NULL); 962 } 963 964 return (pl); 965 } 966 967 static void 968 partlist_free(struct partlist *pl) 969 { 970 ib_bootblock_t *bblock; 971 ib_device_t *device; 972 973 switch (pl->pl_type) { 974 case IB_BBLK_MBR: 975 case IB_BBLK_STAGE1: 976 free(pl->pl_stage); 977 break; 978 default: 979 if (pl->pl_stage != NULL) { 980 bblock = pl->pl_stage; 981 free(bblock->buf); 982 free(bblock); 983 } 984 } 985 986 /* umount the stage fs. */ 987 if (pl->pl_device->stage.mntpnt != NULL) { 988 if (umount(pl->pl_device->stage.mntpnt) == 0) 989 (void) rmdir(pl->pl_device->stage.mntpnt); 990 free(pl->pl_device->stage.mntpnt); 991 } 992 device = pl->pl_device; 993 free(device->target.path); 994 free(pl->pl_device); 995 996 free(pl->pl_src_data); 997 free(pl->pl_devname); 998 free(pl); 999 } 1000 1001 static bool 1002 probe_fstyp(ib_data_t *data) 1003 { 1004 fstyp_handle_t fhdl; 1005 const char *fident; 1006 char *ptr; 1007 int fd; 1008 bool rv = false; 1009 1010 /* Record partition id */ 1011 ptr = strrchr(data->target.path, 'p'); 1012 if (ptr == NULL) 1013 ptr = strrchr(data->target.path, 's'); 1014 data->target.id = atoi(++ptr); 1015 if ((fd = open_device(data->target.path)) == -1) 1016 return (rv); 1017 1018 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 1019 (void) close(fd); 1020 return (rv); 1021 } 1022 1023 if (fstyp_ident(fhdl, NULL, &fident) != 0) { 1024 fstyp_fini(fhdl); 1025 (void) fprintf(stderr, gettext("Failed to detect file " 1026 "system type\n")); 1027 (void) close(fd); 1028 return (rv); 1029 } 1030 1031 rv = true; 1032 if (strcmp(fident, MNTTYPE_ZFS) == 0) 1033 data->target.fstype = IB_FS_ZFS; 1034 else if (strcmp(fident, MNTTYPE_UFS) == 0) { 1035 data->target.fstype = IB_FS_UFS; 1036 } else if (strcmp(fident, MNTTYPE_PCFS) == 0) { 1037 data->target.fstype = IB_FS_PCFS; 1038 /* with pcfs we always write MBR */ 1039 force_mbr = true; 1040 write_mbr = true; 1041 } else { 1042 (void) fprintf(stderr, gettext("File system %s is not " 1043 "supported by loader\n"), fident); 1044 rv = false; 1045 } 1046 fstyp_fini(fhdl); 1047 (void) close(fd); 1048 return (rv); 1049 } 1050 1051 static bool 1052 get_slice(ib_data_t *data, struct partlist *pl, struct dk_gpt *vtoc, 1053 uint16_t tag) 1054 { 1055 uint_t i; 1056 ib_device_t *device = pl->pl_device; 1057 char *path, *ptr; 1058 1059 if (tag != V_BOOT && tag != V_SYSTEM) 1060 return (false); 1061 1062 for (i = 0; i < vtoc->efi_nparts; i++) { 1063 if (vtoc->efi_parts[i].p_tag == tag) { 1064 if ((path = strdup(data->target.path)) == NULL) { 1065 perror(gettext("Memory allocation failure")); 1066 return (false); 1067 } 1068 ptr = strrchr(path, 's'); 1069 ptr++; 1070 *ptr = '\0'; 1071 (void) asprintf(&ptr, "%s%d", path, i); 1072 free(path); 1073 if (ptr == NULL) { 1074 perror(gettext("Memory allocation failure")); 1075 return (false); 1076 } 1077 pl->pl_devname = ptr; 1078 device->stage.id = i; 1079 device->stage.devtype = IB_DEV_EFI; 1080 switch (vtoc->efi_parts[i].p_tag) { 1081 case V_BOOT: 1082 device->stage.fstype = IB_FS_NONE; 1083 /* leave sector 0 for VBR */ 1084 device->stage.offset = 1; 1085 break; 1086 case V_SYSTEM: 1087 device->stage.fstype = IB_FS_PCFS; 1088 break; 1089 } 1090 device->stage.tag = vtoc->efi_parts[i].p_tag; 1091 device->stage.start = vtoc->efi_parts[i].p_start; 1092 device->stage.size = vtoc->efi_parts[i].p_size; 1093 break; 1094 } 1095 } 1096 return (true); 1097 } 1098 1099 static bool 1100 allocate_slice(ib_data_t *data, struct dk_gpt *vtoc, uint16_t tag, 1101 struct partlist **plp) 1102 { 1103 struct partlist *pl; 1104 1105 *plp = NULL; 1106 if ((pl = partlist_alloc()) == NULL) 1107 return (false); 1108 1109 pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 1110 if (pl->pl_device == NULL) { 1111 perror("calloc"); 1112 partlist_free(pl); 1113 return (false); 1114 } 1115 if (!get_slice(data, pl, vtoc, tag)) { 1116 partlist_free(pl); 1117 return (false); 1118 } 1119 1120 /* tag was not found */ 1121 if (pl->pl_devname == NULL) 1122 partlist_free(pl); 1123 else 1124 *plp = pl; 1125 1126 return (true); 1127 } 1128 1129 static bool 1130 probe_gpt(ib_data_t *data) 1131 { 1132 struct partlist *pl; 1133 struct dk_gpt *vtoc; 1134 ib_device_t *device; 1135 int slice, fd; 1136 bool rv = false; 1137 1138 if ((fd = open_device(data->target.path)) < 0) 1139 return (rv); 1140 1141 slice = efi_alloc_and_read(fd, &vtoc); 1142 (void) close(fd); 1143 if (slice < 0) 1144 return (rv); 1145 1146 data->device.devtype = IB_DEV_EFI; 1147 data->target.start = vtoc->efi_parts[slice].p_start; 1148 data->target.size = vtoc->efi_parts[slice].p_size; 1149 1150 /* Always update PMBR. */ 1151 force_mbr = true; 1152 write_mbr = true; 1153 1154 /* 1155 * With GPT we can have boot partition and ESP. 1156 * Boot partition can have both stage 1 and stage 2. 1157 */ 1158 if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1159 goto done; 1160 if (pl != NULL) { 1161 pl->pl_src_name = stage1; 1162 pl->pl_type = IB_BBLK_STAGE1; 1163 pl->pl_cb.compare = compare_stage1_cb; 1164 pl->pl_cb.install = install_stage1_cb; 1165 pl->pl_cb.read = read_stage1_cb; 1166 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1167 pl->pl_cb.print = print_stage1_cb; 1168 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1169 } else if (data->target.fstype != IB_FS_ZFS) { 1170 (void) fprintf(stderr, gettext("Booting %s from EFI " 1171 "labeled disks requires the boot partition.\n"), 1172 data->target.fstype == IB_FS_UFS? 1173 MNTTYPE_UFS : MNTTYPE_PCFS); 1174 goto done; 1175 } 1176 /* Add stage 2 */ 1177 if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1178 goto done; 1179 if (pl != NULL) { 1180 pl->pl_src_name = stage2; 1181 pl->pl_type = IB_BBLK_STAGE2; 1182 pl->pl_cb.compare = compare_einfo_cb; 1183 pl->pl_cb.install = install_stage2_cb; 1184 pl->pl_cb.read = read_stage2_cb; 1185 pl->pl_cb.read_bbl = read_stage2_file_cb; 1186 pl->pl_cb.print = print_einfo_cb; 1187 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1188 } 1189 1190 /* ESP can have 32- and 64-bit boot code. */ 1191 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1192 goto done; 1193 if (pl != NULL) { 1194 pl->pl_device->stage.path = "/EFI/Boot/" BOOTIA32; 1195 pl->pl_src_name = efi32; 1196 pl->pl_type = IB_BBLK_EFI; 1197 pl->pl_cb.compare = compare_einfo_cb; 1198 pl->pl_cb.install = install_esp_cb; 1199 pl->pl_cb.read = read_einfo_esp_cb; 1200 pl->pl_cb.read_bbl = read_stage2_file_cb; 1201 pl->pl_cb.print = print_einfo_cb; 1202 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1203 } 1204 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1205 goto done; 1206 if (pl != NULL) { 1207 pl->pl_device->stage.path = "/EFI/Boot/" BOOTX64; 1208 pl->pl_src_name = efi64; 1209 pl->pl_type = IB_BBLK_EFI; 1210 pl->pl_cb.compare = compare_einfo_cb; 1211 pl->pl_cb.install = install_esp_cb; 1212 pl->pl_cb.read = read_einfo_esp_cb; 1213 pl->pl_cb.read_bbl = read_stage2_file_cb; 1214 pl->pl_cb.print = print_einfo_cb; 1215 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1216 } 1217 1218 /* add stage for our target file system slice */ 1219 pl = partlist_alloc(); 1220 if (pl == NULL) 1221 goto done; 1222 1223 device = pl->pl_device; 1224 device->stage.devtype = data->device.devtype; 1225 if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1226 perror(gettext("Memory allocation failure")); 1227 partlist_free(pl); 1228 goto done; 1229 } 1230 1231 device->stage.id = slice; 1232 device->stage.start = vtoc->efi_parts[slice].p_start; 1233 device->stage.size = vtoc->efi_parts[slice].p_size; 1234 1235 /* ZFS and UFS can have stage1 in boot area. */ 1236 if (data->target.fstype == IB_FS_ZFS || 1237 data->target.fstype == IB_FS_UFS) { 1238 pl->pl_src_name = stage1; 1239 pl->pl_type = IB_BBLK_STAGE1; 1240 pl->pl_cb.compare = compare_stage1_cb; 1241 pl->pl_cb.install = install_stage1_cb; 1242 pl->pl_cb.read = read_stage1_cb; 1243 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1244 pl->pl_cb.print = print_stage1_cb; 1245 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1246 } 1247 1248 if (data->target.fstype == IB_FS_ZFS) { 1249 pl = partlist_alloc(); 1250 if (pl == NULL) 1251 goto done; 1252 1253 device = pl->pl_device; 1254 device->stage.devtype = data->device.devtype; 1255 1256 if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1257 perror(gettext("Memory allocation failure")); 1258 goto done; 1259 } 1260 1261 device->stage.id = slice; 1262 device->stage.start = vtoc->efi_parts[slice].p_start; 1263 device->stage.size = vtoc->efi_parts[slice].p_size; 1264 1265 device->stage.offset = BBLK_ZFS_BLK_OFF; 1266 pl->pl_src_name = stage2; 1267 pl->pl_type = IB_BBLK_STAGE2; 1268 pl->pl_cb.compare = compare_einfo_cb; 1269 pl->pl_cb.install = install_stage2_cb; 1270 pl->pl_cb.read = read_stage2_cb; 1271 pl->pl_cb.read_bbl = read_stage2_file_cb; 1272 pl->pl_cb.print = print_einfo_cb; 1273 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1274 } 1275 rv = true; 1276 done: 1277 efi_free(vtoc); 1278 return (rv); 1279 } 1280 1281 static bool 1282 get_start_sector(ib_data_t *data, struct extpartition *v_part, 1283 diskaddr_t *start) 1284 { 1285 struct partlist *pl; 1286 struct mboot *mbr; 1287 struct ipart *part; 1288 struct part_info dkpi; 1289 struct extpart_info edkpi; 1290 uint32_t secnum, numsec; 1291 ext_part_t *epp; 1292 ushort_t i; 1293 int fd, rval, pno; 1294 1295 if ((fd = open_device(data->target.path)) < 0) 1296 return (false); 1297 1298 if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) { 1299 if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) { 1300 (void) fprintf(stderr, gettext("cannot get the " 1301 "slice information of the disk\n")); 1302 (void) close(fd); 1303 return (false); 1304 } else { 1305 edkpi.p_start = dkpi.p_start; 1306 edkpi.p_length = dkpi.p_length; 1307 } 1308 } 1309 (void) close(fd); 1310 1311 /* Set target file system start and size */ 1312 data->target.start = edkpi.p_start; 1313 data->target.size = edkpi.p_length; 1314 1315 /* This is our MBR partition start. */ 1316 edkpi.p_start -= v_part->p_start; 1317 1318 /* Head is always MBR */ 1319 pl = STAILQ_FIRST(data->plist); 1320 if (!read_stage1_cb(pl)) 1321 return (false); 1322 1323 mbr = (struct mboot *)pl->pl_stage; 1324 part = (struct ipart *)mbr->parts; 1325 1326 for (i = 0; i < FD_NUMPART; i++) { 1327 if (part[i].relsect == edkpi.p_start) { 1328 *start = part[i].relsect; 1329 return (true); 1330 } 1331 } 1332 1333 rval = libfdisk_init(&epp, pl->pl_devname, part, FDISK_READ_DISK); 1334 if (rval != FDISK_SUCCESS) { 1335 switch (rval) { 1336 /* 1337 * The first 3 cases are not an error per-se, just that 1338 * there is no Solaris logical partition 1339 */ 1340 case FDISK_EBADLOGDRIVE: 1341 case FDISK_ENOLOGDRIVE: 1342 case FDISK_EBADMAGIC: 1343 (void) fprintf(stderr, gettext("Solaris " 1344 "partition not found. " 1345 "Aborting operation. %d\n"), rval); 1346 return (false); 1347 case FDISK_ENOVGEOM: 1348 (void) fprintf(stderr, gettext("Could not get " 1349 "virtual geometry\n")); 1350 return (false); 1351 case FDISK_ENOPGEOM: 1352 (void) fprintf(stderr, gettext("Could not get " 1353 "physical geometry\n")); 1354 return (false); 1355 case FDISK_ENOLGEOM: 1356 (void) fprintf(stderr, gettext("Could not get " 1357 "label geometry\n")); 1358 return (false); 1359 default: 1360 (void) fprintf(stderr, gettext("Failed to " 1361 "initialize libfdisk.\n")); 1362 return (false); 1363 } 1364 } 1365 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); 1366 libfdisk_fini(&epp); 1367 if (rval != FDISK_SUCCESS) { 1368 /* No solaris logical partition */ 1369 (void) fprintf(stderr, gettext("Solaris partition not found. " 1370 "Aborting operation.\n")); 1371 return (false); 1372 } 1373 *start = secnum; 1374 return (true); 1375 } 1376 1377 /* 1378 * On x86 the VTOC table is inside MBR partition and to get 1379 * absolute sectors, we need to add MBR partition start to VTOC slice start. 1380 */ 1381 static bool 1382 probe_vtoc(ib_data_t *data) 1383 { 1384 struct partlist *pl; 1385 struct extvtoc exvtoc; 1386 ib_device_t *device; 1387 char *path, *ptr; 1388 ushort_t i; 1389 int slice, fd; 1390 diskaddr_t start; 1391 bool rv; 1392 1393 rv = false; 1394 1395 if ((fd = open_device(data->target.path)) < 0) 1396 return (rv); 1397 1398 slice = read_extvtoc(fd, &exvtoc); 1399 (void) close(fd); 1400 if (slice < 0) 1401 return (rv); 1402 data->device.devtype = IB_DEV_VTOC; 1403 1404 if (!get_start_sector(data, exvtoc.v_part + slice, &start)) 1405 return (rv); 1406 1407 if (exvtoc.v_part[slice].p_tag == V_BACKUP) { 1408 /* 1409 * NOTE: we could relax there and allow zfs boot on 1410 * slice 2, but lets keep traditional limits. 1411 */ 1412 (void) fprintf(stderr, gettext( 1413 "raw device must be a root slice (not backup)\n")); 1414 return (rv); 1415 } 1416 1417 if ((path = strdup(data->target.path)) == NULL) { 1418 perror(gettext("Memory allocation failure")); 1419 return (false); 1420 } 1421 1422 data->target.start = start + exvtoc.v_part[slice].p_start; 1423 data->target.size = exvtoc.v_part[slice].p_size; 1424 1425 /* Search for boot slice. */ 1426 for (i = 0; i < exvtoc.v_nparts; i++) { 1427 if (exvtoc.v_part[i].p_tag == V_BOOT) 1428 break; 1429 } 1430 1431 if (i == exvtoc.v_nparts || 1432 exvtoc.v_part[i].p_size == 0) { 1433 /* fall back to slice V_BACKUP */ 1434 for (i = 0; i < exvtoc.v_nparts; i++) { 1435 if (exvtoc.v_part[i].p_tag == V_BACKUP) 1436 break; 1437 } 1438 /* Still nothing? Error out. */ 1439 if (i == exvtoc.v_nparts || 1440 exvtoc.v_part[i].p_size == 0) { 1441 free(path); 1442 return (false); 1443 } 1444 } 1445 1446 /* Create path. */ 1447 ptr = strrchr(path, 's'); 1448 ptr++; 1449 *ptr = '\0'; 1450 (void) asprintf(&ptr, "%s%d", path, i); 1451 free(path); 1452 if (ptr == NULL) { 1453 perror(gettext("Memory allocation failure")); 1454 return (false); 1455 } 1456 1457 pl = partlist_alloc(); 1458 if (pl == NULL) { 1459 free(ptr); 1460 return (false); 1461 } 1462 pl->pl_devname = ptr; 1463 device = pl->pl_device; 1464 device->stage.devtype = data->device.devtype; 1465 device->stage.id = i; 1466 device->stage.tag = exvtoc.v_part[i].p_tag; 1467 device->stage.start = start + exvtoc.v_part[i].p_start; 1468 device->stage.size = exvtoc.v_part[i].p_size; 1469 1470 /* Fix size if this slice is in fact V_BACKUP */ 1471 if (exvtoc.v_part[i].p_tag == V_BACKUP) { 1472 for (i = 0; i < exvtoc.v_nparts; i++) { 1473 if (exvtoc.v_part[i].p_start == 0) 1474 continue; 1475 if (exvtoc.v_part[i].p_size == 0) 1476 continue; 1477 if (exvtoc.v_part[i].p_start < 1478 device->stage.size) 1479 device->stage.size = 1480 exvtoc.v_part[i].p_start; 1481 } 1482 } 1483 1484 pl->pl_src_name = stage1; 1485 pl->pl_type = IB_BBLK_STAGE1; 1486 pl->pl_cb.compare = compare_stage1_cb; 1487 pl->pl_cb.install = install_stage1_cb; 1488 pl->pl_cb.read = read_stage1_cb; 1489 pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1490 pl->pl_cb.print = print_stage1_cb; 1491 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1492 1493 /* Create instance for stage 2 */ 1494 pl = partlist_alloc(); 1495 if (pl == NULL) { 1496 free(ptr); 1497 return (false); 1498 } 1499 pl->pl_devname = strdup(ptr); 1500 if (pl->pl_devname == NULL) { 1501 partlist_free(pl); 1502 return (false); 1503 } 1504 pl->pl_device->stage.devtype = data->device.devtype; 1505 pl->pl_device->stage.id = device->stage.id; 1506 pl->pl_device->stage.offset = BBLK_BLKLIST_OFF; 1507 pl->pl_device->stage.tag = device->stage.tag; 1508 pl->pl_device->stage.start = device->stage.start; 1509 pl->pl_device->stage.size = device->stage.size; 1510 pl->pl_src_name = stage2; 1511 pl->pl_type = IB_BBLK_STAGE2; 1512 pl->pl_cb.compare = compare_einfo_cb; 1513 pl->pl_cb.install = install_stage2_cb; 1514 pl->pl_cb.read = read_stage2_cb; 1515 pl->pl_cb.read_bbl = read_stage2_file_cb; 1516 pl->pl_cb.print = print_einfo_cb; 1517 STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1518 1519 /* And we are done. */ 1520 rv = true; 1521 return (rv); 1522 } 1523 1524 static bool 1525 probe_mbr(ib_data_t *data) 1526 { 1527 struct partlist *pl; 1528 struct ipart *part; 1529 struct mboot *mbr; 1530 ib_device_t *device; 1531 char *path, *ptr; 1532 int i, rv; 1533 1534 data->device.devtype = IB_DEV_MBR; 1535 1536 /* Head is always MBR */ 1537 pl = STAILQ_FIRST(data->plist); 1538 if (!read_stage1_cb(pl)) 1539 return (false); 1540 1541 mbr = (struct mboot *)pl->pl_stage; 1542 part = (struct ipart *)mbr->parts; 1543 1544 /* Set target file system start and size */ 1545 data->target.start = part[data->target.id - 1].relsect; 1546 data->target.size = part[data->target.id - 1].numsect; 1547 1548 /* Use X86BOOT partition if we have one. */ 1549 for (i = 0; i < FD_NUMPART; i++) { 1550 if (part[i].systid == X86BOOT) 1551 break; 1552 } 1553 1554 /* Keep device name of whole disk device. */ 1555 path = (char *)pl->pl_devname; 1556 if ((pl = partlist_alloc()) == NULL) 1557 return (false); 1558 device = pl->pl_device; 1559 1560 /* 1561 * No X86BOOT, try to use space between MBR and first 1562 * partition. 1563 */ 1564 if (i == FD_NUMPART) { 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