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 2017 Toomas Soome <tsoome@me.com> 25 */ 26 27 #include <stdio.h> 28 #include <errno.h> 29 #include <unistd.h> 30 #include <fcntl.h> 31 #include <assert.h> 32 #include <locale.h> 33 #include <strings.h> 34 #include <libfdisk.h> 35 #include <err.h> 36 37 #include <sys/dktp/fdisk.h> 38 #include <sys/dkio.h> 39 #include <sys/vtoc.h> 40 #include <sys/multiboot.h> 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 #include <sys/sysmacros.h> 44 #include <sys/efi_partition.h> 45 #include <libfstyp.h> 46 #include <libgen.h> 47 #include <uuid/uuid.h> 48 49 #include "installboot.h" 50 #include "bblk_einfo.h" 51 #include "boot_utils.h" 52 #include "mboot_extra.h" 53 #include "getresponse.h" 54 55 #ifndef TEXT_DOMAIN 56 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 57 #endif 58 59 /* 60 * BIOS bootblock installation: 61 * 62 * 1. MBR is first sector of the disk. If the file system on target is 63 * ufs or zfs, the same MBR code is installed on first sector of the 64 * partition as well; this will allow to have real MBR sector to be 65 * replaced by some other boot loader and have illumos chainloaded. 66 * 67 * installboot will record the start LBA and size of stage2 code in MBR code. 68 * On boot, the MBR code will read the stage2 code and executes it. 69 * 70 * 2. Stage2 location depends on file system type; 71 * In case of zfs, installboot will store stage2 to zfs bootblk area, 72 * which is 512k bytes from partition start and size is 3.5MB. 73 * 74 * In case of ufs, the stage2 location is 50 512B sectors from 75 * Solaris2 MBR partition start, within boot slice, boot slice size is 76 * one cylinder. 77 * 78 * In case of pcfs, the stage2 location is 50 512B sectors from beginning 79 * of the disk, filling the space between MBR and first partition. 80 * This location assumes no other bootloader and the space is one cylinder, 81 * as first partition is starting from cylinder 1. 82 * 83 * In case of GPT partitioning and if file system is not zfs, the boot 84 * support is only possible with dedicated boot partition. For GPT, 85 * the current implementation is using BOOT partition, which must exist. 86 * BOOT partition does only contain raw boot blocks, without any file system. 87 * 88 * Loader stage2 is created with embedded version, by using fake multiboot (MB) 89 * header within first 32k and EINFO block is at the end of the actual 90 * boot block. MB header load_addr is set to 0 and load_end_addr is set to 91 * actual block end, so the EINFO size is (file size - load_end_addr). 92 * installboot does also store the illumos boot partition LBA to MB space, 93 * starting from bss_end_addr structure member location; stage2 will 94 * detect the partition and file system based on this value. 95 * 96 * Stored location values in MBR/stage2 also mean the bootblocks must be 97 * reinstalled in case the partition content is relocated. 98 */ 99 100 static boolean_t write_mbr = B_FALSE; 101 static boolean_t force_mbr = B_FALSE; 102 static boolean_t force_update = B_FALSE; 103 static boolean_t do_getinfo = B_FALSE; 104 static boolean_t do_version = B_FALSE; 105 static boolean_t do_mirror_bblk = B_FALSE; 106 static boolean_t strip = B_FALSE; 107 static boolean_t verbose_dump = B_FALSE; 108 109 /* Versioning string, if present. */ 110 static char *update_str; 111 112 /* 113 * Temporary buffer to store the first 32K of data looking for a multiboot 114 * signature. 115 */ 116 char mboot_scan[MBOOT_SCAN_SIZE]; 117 118 /* Function prototypes. */ 119 static void check_options(char *); 120 static int get_start_sector(ib_device_t *); 121 122 static int read_stage1_from_file(char *, ib_data_t *); 123 static int read_bootblock_from_file(char *, ib_bootblock_t *); 124 static int read_bootblock_from_disk(ib_device_t *, ib_bootblock_t *, char **); 125 static void add_bootblock_einfo(ib_bootblock_t *, char *); 126 static int prepare_stage1(ib_data_t *); 127 static int prepare_bootblock(ib_data_t *, char *); 128 static int write_stage1(ib_data_t *); 129 static int write_bootblock(ib_data_t *); 130 static int init_device(ib_device_t *, char *); 131 static void cleanup_device(ib_device_t *); 132 static int commit_to_disk(ib_data_t *, char *); 133 static int handle_install(char *, char **); 134 static int handle_getinfo(char *, char **); 135 static int handle_mirror(char *, char **); 136 static boolean_t is_update_necessary(ib_data_t *, char *); 137 static int propagate_bootblock(ib_data_t *, ib_data_t *, char *); 138 static void usage(char *, int) __NORETURN; 139 140 static int 141 read_stage1_from_file(char *path, ib_data_t *dest) 142 { 143 int fd; 144 145 assert(dest != NULL); 146 147 /* read the stage1 file from filesystem */ 148 fd = open(path, O_RDONLY); 149 if (fd == -1 || 150 read(fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) { 151 (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"), 152 path); 153 return (BC_ERROR); 154 } 155 (void) close(fd); 156 return (BC_SUCCESS); 157 } 158 159 static int 160 read_bootblock_from_file(char *file, ib_bootblock_t *bblock) 161 { 162 struct stat sb; 163 uint32_t buf_size; 164 uint32_t mboot_off; 165 int fd = -1; 166 int retval = BC_ERROR; 167 168 assert(bblock != NULL); 169 assert(file != NULL); 170 171 fd = open(file, O_RDONLY); 172 if (fd == -1) { 173 BOOT_DEBUG("Error opening %s\n", file); 174 perror("open"); 175 goto out; 176 } 177 178 if (fstat(fd, &sb) == -1) { 179 BOOT_DEBUG("Error getting information (stat) about %s", file); 180 perror("stat"); 181 goto outfd; 182 } 183 184 /* loader bootblock has version built in */ 185 buf_size = sb.st_size; 186 187 bblock->buf_size = buf_size; 188 BOOT_DEBUG("bootblock in-memory buffer size is %d\n", 189 bblock->buf_size); 190 191 bblock->buf = malloc(buf_size); 192 if (bblock->buf == NULL) { 193 perror(gettext("Memory allocation failure")); 194 goto outbuf; 195 } 196 bblock->file = bblock->buf; 197 198 if (read(fd, bblock->file, bblock->buf_size) != bblock->buf_size) { 199 BOOT_DEBUG("Read from %s failed\n", file); 200 perror("read"); 201 goto outfd; 202 } 203 204 buf_size = MIN(buf_size, MBOOT_SCAN_SIZE); 205 if (find_multiboot(bblock->file, buf_size, &mboot_off) 206 != BC_SUCCESS) { 207 (void) fprintf(stderr, 208 gettext("Unable to find multiboot header\n")); 209 goto outfd; 210 } 211 212 bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off); 213 bblock->mboot_off = mboot_off; 214 215 bblock->file_size = 216 bblock->mboot->load_end_addr - bblock->mboot->load_addr; 217 BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size); 218 219 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 220 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 221 222 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 223 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 224 bblock->extra_size, bblock->buf, bblock->buf_size); 225 226 (void) close(fd); 227 return (BC_SUCCESS); 228 229 outbuf: 230 (void) free(bblock->buf); 231 bblock->buf = NULL; 232 outfd: 233 (void) close(fd); 234 out: 235 return (retval); 236 } 237 238 static int 239 read_bootblock_from_disk(ib_device_t *device, ib_bootblock_t *bblock, 240 char **path) 241 { 242 int dev_fd; 243 uint32_t size, offset; 244 uint32_t buf_size; 245 uint32_t mboot_off; 246 multiboot_header_t *mboot; 247 248 assert(device != NULL); 249 assert(bblock != NULL); 250 251 if (device->target.fstype == IG_FS_ZFS) { 252 dev_fd = device->target.fd; 253 offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE; 254 *path = device->target.path; 255 } else { 256 dev_fd = device->stage.fd; 257 offset = device->stage.offset * SECTOR_SIZE; 258 *path = device->stage.path; 259 } 260 261 if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan), offset) 262 != BC_SUCCESS) { 263 BOOT_DEBUG("Error reading bootblock area\n"); 264 perror("read"); 265 return (BC_ERROR); 266 } 267 268 /* No multiboot means no chance of knowing bootblock size */ 269 if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off) 270 != BC_SUCCESS) { 271 BOOT_DEBUG("Unable to find multiboot header\n"); 272 return (BC_NOEXTRA); 273 } 274 mboot = (multiboot_header_t *)(mboot_scan + mboot_off); 275 276 /* 277 * make sure mboot has sane values 278 */ 279 if (mboot->load_end_addr == 0 || 280 mboot->load_end_addr < mboot->load_addr) 281 return (BC_NOEXTRA); 282 283 /* 284 * Currently, the amount of space reserved for extra information 285 * is "fixed". We may have to scan for the terminating extra payload 286 * in the future. 287 */ 288 size = mboot->load_end_addr - mboot->load_addr; 289 buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE); 290 bblock->file_size = size; 291 292 bblock->buf = malloc(buf_size); 293 if (bblock->buf == NULL) { 294 BOOT_DEBUG("Unable to allocate enough memory to read" 295 " the extra bootblock from the disk\n"); 296 perror(gettext("Memory allocation failure")); 297 return (BC_ERROR); 298 } 299 bblock->buf_size = buf_size; 300 301 if (read_in(dev_fd, bblock->buf, buf_size, offset) != BC_SUCCESS) { 302 BOOT_DEBUG("Error reading the bootblock\n"); 303 (void) free(bblock->buf); 304 bblock->buf = NULL; 305 return (BC_ERROR); 306 } 307 308 /* Update pointers. */ 309 bblock->file = bblock->buf; 310 bblock->mboot_off = mboot_off; 311 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off); 312 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 313 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 314 315 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 316 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 317 bblock->extra_size, bblock->buf, bblock->buf_size); 318 319 return (BC_SUCCESS); 320 } 321 322 static boolean_t 323 is_update_necessary(ib_data_t *data, char *updt_str) 324 { 325 bblk_einfo_t *einfo; 326 bblk_einfo_t *einfo_file; 327 bblk_hs_t bblock_hs; 328 ib_bootblock_t bblock_disk; 329 ib_bootblock_t *bblock_file = &data->bootblock; 330 ib_device_t *device = &data->device; 331 int ret; 332 char *path; 333 334 assert(data != NULL); 335 336 bzero(&bblock_disk, sizeof (ib_bootblock_t)); 337 338 ret = read_bootblock_from_disk(device, &bblock_disk, &path); 339 if (ret != BC_SUCCESS) { 340 BOOT_DEBUG("Unable to read bootblock from %s\n", path); 341 return (B_TRUE); 342 } 343 344 einfo = find_einfo(bblock_disk.extra, bblock_disk.extra_size); 345 if (einfo == NULL) { 346 BOOT_DEBUG("No extended information available on disk\n"); 347 return (B_TRUE); 348 } 349 350 einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size); 351 if (einfo_file == NULL) { 352 /* 353 * loader bootblock is versioned. missing version means 354 * probably incompatible block. installboot can not install 355 * grub, for example. 356 */ 357 (void) fprintf(stderr, 358 gettext("ERROR: non versioned bootblock in file\n")); 359 return (B_FALSE); 360 } else { 361 if (updt_str == NULL) { 362 updt_str = einfo_get_string(einfo_file); 363 do_version = B_TRUE; 364 } 365 } 366 367 if (!do_version || updt_str == NULL) { 368 (void) fprintf(stderr, 369 gettext("WARNING: target device %s has a " 370 "versioned bootblock that is going to be overwritten by a " 371 "non versioned one\n"), device->path); 372 return (B_TRUE); 373 } 374 375 if (force_update) { 376 BOOT_DEBUG("Forcing update of %s bootblock\n", device->path); 377 return (B_TRUE); 378 } 379 380 BOOT_DEBUG("Ready to check installed version vs %s\n", updt_str); 381 382 bblock_hs.src_buf = (unsigned char *)bblock_file->file; 383 bblock_hs.src_size = bblock_file->file_size; 384 385 return (einfo_should_update(einfo, &bblock_hs, updt_str)); 386 } 387 388 static void 389 add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str) 390 { 391 bblk_hs_t hs; 392 uint32_t avail_space; 393 394 assert(bblock != NULL); 395 396 if (updt_str == NULL) { 397 BOOT_DEBUG("WARNING: no update string passed to " 398 "add_bootblock_einfo()\n"); 399 return; 400 } 401 402 /* Fill bootblock hashing source information. */ 403 hs.src_buf = (unsigned char *)bblock->file; 404 hs.src_size = bblock->file_size; 405 /* How much space for the extended information structure? */ 406 avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 407 /* Place the extended information structure. */ 408 add_einfo(bblock->extra, updt_str, &hs, avail_space); 409 } 410 411 /* 412 * set up data for case stage1 is installed as MBR 413 * set up location and size of bootblock 414 * set disk guid to provide unique information for biosdev command 415 */ 416 static int 417 prepare_stage1(ib_data_t *data) 418 { 419 ib_device_t *device; 420 421 assert(data != NULL); 422 device = &data->device; 423 424 /* copy BPB */ 425 bcopy(device->mbr + STAGE1_BPB_OFFSET, 426 data->stage1 + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE); 427 428 429 /* copy MBR, note STAGE1_SIG == BOOTSZ */ 430 bcopy(device->mbr + STAGE1_SIG, data->stage1 + STAGE1_SIG, 431 SECTOR_SIZE - STAGE1_SIG); 432 433 /* set stage2 size */ 434 *((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) = 435 (uint16_t)(data->bootblock.buf_size / SECTOR_SIZE); 436 437 /* 438 * set stage2 location. 439 * for zfs always use zfs embedding, for ufs/pcfs use partition_start 440 * as base for stage2 location, for ufs/pcfs in MBR partition, use 441 * free space after MBR record. 442 */ 443 if (device->target.fstype == IG_FS_ZFS) 444 *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) = 445 device->target.start + device->target.offset; 446 else { 447 *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) = 448 device->stage.start + device->stage.offset; 449 } 450 451 /* 452 * set disk uuid. we only need reasonable amount of uniqueness 453 * to allow biosdev to identify disk based on mbr differences. 454 */ 455 uuid_generate(data->stage1 + STAGE1_STAGE2_UUID); 456 457 return (BC_SUCCESS); 458 } 459 460 static int 461 prepare_bootblock(ib_data_t *data, char *updt_str) 462 { 463 ib_bootblock_t *bblock; 464 ib_device_t *device; 465 uint64_t *ptr; 466 467 assert(data != NULL); 468 469 bblock = &data->bootblock; 470 device = &data->device; 471 472 ptr = (uint64_t *)(&bblock->mboot->bss_end_addr); 473 *ptr = device->target.start; 474 475 /* 476 * the loader bootblock has built in version, if custom 477 * version was provided, update it. 478 */ 479 if (do_version) 480 add_bootblock_einfo(bblock, updt_str); 481 482 return (BC_SUCCESS); 483 } 484 485 static int 486 write_bootblock(ib_data_t *data) 487 { 488 ib_device_t *device = &data->device; 489 ib_bootblock_t *bblock = &data->bootblock; 490 uint64_t abs; 491 int dev_fd, ret; 492 off_t offset; 493 char *path; 494 495 assert(data != NULL); 496 497 /* 498 * ZFS bootblock area is 3.5MB, make sure we can fit. 499 * buf_size is size of bootblk+EINFO. 500 */ 501 if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) { 502 (void) fprintf(stderr, gettext("bootblock is too large\n")); 503 return (BC_ERROR); 504 } 505 506 if (device->target.fstype == IG_FS_ZFS) { 507 dev_fd = device->target.fd; 508 abs = device->target.start + device->target.offset; 509 offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE; 510 path = device->target.path; 511 } else { 512 dev_fd = device->stage.fd; 513 abs = device->stage.start + device->stage.offset; 514 offset = device->stage.offset * SECTOR_SIZE; 515 path = device->stage.path; 516 if (bblock->buf_size > 517 (device->stage.size - device->stage.offset) * SECTOR_SIZE) { 518 (void) fprintf(stderr, gettext("Device %s is " 519 "too small to fit the stage2\n"), path); 520 return (BC_ERROR); 521 } 522 } 523 ret = write_out(dev_fd, bblock->buf, bblock->buf_size, offset); 524 if (ret != BC_SUCCESS) { 525 BOOT_DEBUG("Error writing the ZFS bootblock " 526 "to %s at offset %d\n", path, offset); 527 return (BC_ERROR); 528 } 529 530 (void) fprintf(stdout, gettext("bootblock written for %s," 531 " %d sectors starting at %d (abs %lld)\n"), path, 532 (bblock->buf_size / SECTOR_SIZE) + 1, offset / SECTOR_SIZE, abs); 533 534 return (BC_SUCCESS); 535 } 536 537 /* 538 * Partition boot block or volume boot record (VBR). The VBR is 539 * stored on partition relative sector 0 and allows chainloading 540 * to read boot program from partition. 541 * 542 * As the VBR will use the first sector of the partition, 543 * this means, we need to be sure the space is not used. 544 * We do support three partitioning chemes: 545 * 1. GPT: zfs and ufs have reserved space for first 8KB, but 546 * only zfs does have space for boot2. The pcfs has support 547 * for VBR, but no space for boot2. So with GPT, to support 548 * ufs or pcfs boot, we must have separate dedicated boot 549 * partition and we will store VBR on it. 550 * 2. MBR: we have almost the same situation as with GPT, except that 551 * if the partitions start from cylinder 1, we will have space 552 * between MBR and cylinder 0. If so, we do not require separate 553 * boot partition. 554 * 3. MBR+VTOC: with this combination we store VBR in sector 0 of the 555 * solaris2 MBR partition. The slice 0 will start from cylinder 1, 556 * and we do have space for boot2, so we do not require separate 557 * boot partition. 558 */ 559 static int 560 write_stage1(ib_data_t *data) 561 { 562 ib_device_t *device = &data->device; 563 uint64_t start = 0; 564 565 assert(data != NULL); 566 567 /* 568 * We have separate partition for boot programs and the stage1 569 * location is not absolute sector 0. 570 * We will write VBR and trigger MBR to read 1 sector from VBR. 571 * This case does also cover MBR+VTOC case, as the solaris 2 partition 572 * name and the root file system slice names are different. 573 */ 574 if (device->stage.start != 0 && 575 strcmp(device->target.path, device->stage.path)) { 576 /* we got separate stage area, use it */ 577 if (write_out(device->stage.fd, data->stage1, 578 sizeof (data->stage1), 0) != BC_SUCCESS) { 579 (void) fprintf(stdout, gettext("cannot write " 580 "partition boot sector\n")); 581 perror("write"); 582 return (BC_ERROR); 583 } 584 585 (void) fprintf(stdout, gettext("stage1 written to " 586 "%s %d sector 0 (abs %d)\n"), 587 device->devtype == IG_DEV_MBR? "partition":"slice", 588 device->stage.id, device->stage.start); 589 start = device->stage.start; 590 } 591 592 /* 593 * We have either GPT or MBR (without VTOC) and if the root 594 * file system is not pcfs, we can store VBR. Also trigger 595 * MBR to read 1 sector from VBR. 596 */ 597 if (device->devtype != IG_DEV_VTOC && 598 device->target.fstype != IG_FS_PCFS) { 599 if (write_out(device->target.fd, data->stage1, 600 sizeof (data->stage1), 0) != BC_SUCCESS) { 601 (void) fprintf(stdout, gettext("cannot write " 602 "partition boot sector\n")); 603 perror("write"); 604 return (BC_ERROR); 605 } 606 607 (void) fprintf(stdout, gettext("stage1 written to " 608 "%s %d sector 0 (abs %d)\n"), 609 device->devtype == IG_DEV_MBR? "partition":"slice", 610 device->target.id, device->target.start); 611 start = device->target.start; 612 } 613 614 if (write_mbr) { 615 /* 616 * If we did write partition boot block, update MBR to 617 * read partition boot block, not boot2. 618 */ 619 if (start != 0) { 620 *((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) = 1; 621 *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) = 622 start; 623 } 624 if (write_out(device->fd, data->stage1, 625 sizeof (data->stage1), 0) != BC_SUCCESS) { 626 (void) fprintf(stdout, 627 gettext("cannot write master boot sector\n")); 628 perror("write"); 629 return (BC_ERROR); 630 } 631 (void) fprintf(stdout, 632 gettext("stage1 written to master boot sector\n")); 633 } 634 635 return (BC_SUCCESS); 636 } 637 638 /* 639 * find partition/slice start sector. will be recorded in stage2 and used 640 * by stage2 to identify partition with boot file system. 641 */ 642 static int 643 get_start_sector(ib_device_t *device) 644 { 645 uint32_t secnum = 0, numsec = 0; 646 int i, pno, rval, log_part = 0; 647 struct mboot *mboot; 648 struct ipart *part = NULL; 649 ext_part_t *epp; 650 struct part_info dkpi; 651 struct extpart_info edkpi; 652 653 if (device->devtype == IG_DEV_EFI) { 654 struct dk_gpt *vtoc; 655 656 if (efi_alloc_and_read(device->fd, &vtoc) < 0) 657 return (BC_ERROR); 658 659 if (device->stage.start == 0) { 660 /* zero size means the fstype must be zfs */ 661 assert(device->target.fstype == IG_FS_ZFS); 662 663 device->stage.start = 664 vtoc->efi_parts[device->stage.id].p_start; 665 device->stage.size = 666 vtoc->efi_parts[device->stage.id].p_size; 667 device->stage.offset = BBLK_ZFS_BLK_OFF; 668 device->target.offset = BBLK_ZFS_BLK_OFF; 669 } 670 671 device->target.start = 672 vtoc->efi_parts[device->target.id].p_start; 673 device->target.size = 674 vtoc->efi_parts[device->target.id].p_size; 675 676 /* with pcfs we always write MBR */ 677 if (device->target.fstype == IG_FS_PCFS) { 678 force_mbr = 1; 679 write_mbr = 1; 680 } 681 682 efi_free(vtoc); 683 goto found_part; 684 } 685 686 mboot = (struct mboot *)device->mbr; 687 688 /* For MBR we have device->stage filled already. */ 689 if (device->devtype == IG_DEV_MBR) { 690 /* MBR partition starts from 0 */ 691 pno = device->target.id - 1; 692 part = (struct ipart *)mboot->parts + pno; 693 694 if (part->relsect == 0) { 695 (void) fprintf(stderr, gettext("Partition %d of the " 696 "disk has an incorrect offset\n"), 697 device->target.id); 698 return (BC_ERROR); 699 } 700 device->target.start = part->relsect; 701 device->target.size = part->numsect; 702 703 /* with pcfs we always write MBR */ 704 if (device->target.fstype == IG_FS_PCFS) { 705 force_mbr = 1; 706 write_mbr = 1; 707 } 708 if (device->target.fstype == IG_FS_ZFS) 709 device->target.offset = BBLK_ZFS_BLK_OFF; 710 711 goto found_part; 712 } 713 714 /* 715 * Search for Solaris fdisk partition 716 * Get the solaris partition information from the device 717 * and compare the offset of S2 with offset of solaris partition 718 * from fdisk partition table. 719 */ 720 if (ioctl(device->target.fd, DKIOCEXTPARTINFO, &edkpi) < 0) { 721 if (ioctl(device->target.fd, DKIOCPARTINFO, &dkpi) < 0) { 722 (void) fprintf(stderr, gettext("cannot get the " 723 "slice information of the disk\n")); 724 return (BC_ERROR); 725 } else { 726 edkpi.p_start = dkpi.p_start; 727 edkpi.p_length = dkpi.p_length; 728 } 729 } 730 731 device->target.start = edkpi.p_start; 732 device->target.size = edkpi.p_length; 733 if (device->target.fstype == IG_FS_ZFS) 734 device->target.offset = BBLK_ZFS_BLK_OFF; 735 736 for (i = 0; i < FD_NUMPART; i++) { 737 part = (struct ipart *)mboot->parts + i; 738 739 if (part->relsect == 0) { 740 (void) fprintf(stderr, gettext("Partition %d of the " 741 "disk has an incorrect offset\n"), i+1); 742 return (BC_ERROR); 743 } 744 745 if (edkpi.p_start >= part->relsect && 746 edkpi.p_start < (part->relsect + part->numsect)) { 747 /* Found the partition */ 748 break; 749 } 750 } 751 752 if (i == FD_NUMPART) { 753 /* No solaris fdisk partitions (primary or logical) */ 754 (void) fprintf(stderr, gettext("Solaris partition not found. " 755 "Aborting operation.\n")); 756 return (BC_ERROR); 757 } 758 759 /* 760 * We have found a Solaris fdisk partition (primary or extended) 761 * Handle the simple case first: Solaris in a primary partition 762 */ 763 if (!fdisk_is_dos_extended(part->systid)) { 764 device->stage.start = part->relsect; 765 device->stage.size = part->numsect; 766 if (device->target.fstype == IG_FS_ZFS) 767 device->stage.offset = BBLK_ZFS_BLK_OFF; 768 else 769 device->stage.offset = BBLK_BLKLIST_OFF; 770 device->stage.id = i + 1; 771 goto found_part; 772 } 773 774 /* 775 * Solaris in a logical partition. Find that partition in the 776 * extended part. 777 */ 778 779 if ((rval = libfdisk_init(&epp, device->path, NULL, FDISK_READ_DISK)) 780 != FDISK_SUCCESS) { 781 switch (rval) { 782 /* 783 * The first 3 cases are not an error per-se, just that 784 * there is no Solaris logical partition 785 */ 786 case FDISK_EBADLOGDRIVE: 787 case FDISK_ENOLOGDRIVE: 788 case FDISK_EBADMAGIC: 789 (void) fprintf(stderr, gettext("Solaris " 790 "partition not found. " 791 "Aborting operation.\n")); 792 return (BC_ERROR); 793 case FDISK_ENOVGEOM: 794 (void) fprintf(stderr, gettext("Could not get " 795 "virtual geometry\n")); 796 return (BC_ERROR); 797 case FDISK_ENOPGEOM: 798 (void) fprintf(stderr, gettext("Could not get " 799 "physical geometry\n")); 800 return (BC_ERROR); 801 case FDISK_ENOLGEOM: 802 (void) fprintf(stderr, gettext("Could not get " 803 "label geometry\n")); 804 return (BC_ERROR); 805 default: 806 (void) fprintf(stderr, gettext("Failed to " 807 "initialize libfdisk.\n")); 808 return (BC_ERROR); 809 } 810 } 811 812 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); 813 libfdisk_fini(&epp); 814 if (rval != FDISK_SUCCESS) { 815 /* No solaris logical partition */ 816 (void) fprintf(stderr, gettext("Solaris partition not found. " 817 "Aborting operation.\n")); 818 return (BC_ERROR); 819 } 820 821 device->stage.start = secnum; 822 device->stage.size = numsec; 823 device->stage.id = pno; 824 log_part = 1; 825 826 found_part: 827 /* get confirmation for -m */ 828 if (write_mbr && !force_mbr) { 829 (void) fprintf(stdout, gettext("Updating master boot sector " 830 "destroys existing boot managers (if any).\n" 831 "continue (y/n)? ")); 832 if (!yes()) { 833 write_mbr = 0; 834 (void) fprintf(stdout, gettext("master boot sector " 835 "not updated\n")); 836 return (BC_ERROR); 837 } 838 } 839 840 /* 841 * warn, if illumos in primary partition and loader not in MBR and 842 * partition is not active 843 */ 844 if (device->devtype != IG_DEV_EFI) { 845 if (!log_part && part->bootid != 128 && !write_mbr) { 846 (void) fprintf(stdout, gettext("Solaris fdisk " 847 "partition is inactive.\n"), device->stage.id); 848 } 849 } 850 851 return (BC_SUCCESS); 852 } 853 854 static int 855 open_device(char *path) 856 { 857 struct stat statbuf = {0}; 858 int fd = -1; 859 860 if (nowrite) 861 fd = open(path, O_RDONLY); 862 else 863 fd = open(path, O_RDWR); 864 865 if (fd == -1) { 866 BOOT_DEBUG("Unable to open %s\n", path); 867 perror("open"); 868 return (-1); 869 } 870 871 if (fstat(fd, &statbuf) != 0) { 872 BOOT_DEBUG("Unable to stat %s\n", path); 873 perror("stat"); 874 (void) close(fd); 875 return (-1); 876 } 877 878 if (S_ISCHR(statbuf.st_mode) == 0) { 879 (void) fprintf(stderr, gettext("%s: Not a character device\n"), 880 path); 881 (void) close(fd); 882 return (-1); 883 } 884 885 return (fd); 886 } 887 888 static int 889 get_boot_partition(ib_device_t *device, struct mboot *mbr) 890 { 891 struct ipart *part; 892 char *path, *ptr; 893 int i; 894 895 part = (struct ipart *)mbr->parts; 896 for (i = 0; i < FD_NUMPART; i++) { 897 if (part[i].systid == X86BOOT) 898 break; 899 } 900 901 /* no X86BOOT, try to use space between MBR and first partition */ 902 if (i == FD_NUMPART) { 903 device->stage.path = strdup(device->path); 904 if (device->stage.path == NULL) { 905 perror(gettext("Memory allocation failure")); 906 return (BC_ERROR); 907 } 908 device->stage.fd = dup(device->fd); 909 device->stage.id = 0; 910 device->stage.devtype = IG_DEV_MBR; 911 device->stage.fstype = IG_FS_NONE; 912 device->stage.start = 0; 913 device->stage.size = part[0].relsect; 914 device->stage.offset = BBLK_BLKLIST_OFF; 915 return (BC_SUCCESS); 916 } 917 918 if ((path = strdup(device->path)) == NULL) { 919 perror(gettext("Memory allocation failure")); 920 return (BC_ERROR); 921 } 922 923 ptr = strrchr(path, 'p'); 924 ptr++; 925 *ptr = '\0'; 926 (void) asprintf(&ptr, "%s%d", path, i+1); /* partitions are p1..p4 */ 927 free(path); 928 if (ptr == NULL) { 929 perror(gettext("Memory allocation failure")); 930 return (BC_ERROR); 931 } 932 device->stage.path = ptr; 933 device->stage.fd = open_device(ptr); 934 device->stage.id = i + 1; 935 device->stage.devtype = IG_DEV_MBR; 936 device->stage.fstype = IG_FS_NONE; 937 device->stage.start = part[i].relsect; 938 device->stage.size = part[i].numsect; 939 device->stage.offset = 1; /* leave sector 0 for VBR */ 940 return (BC_SUCCESS); 941 } 942 943 static int 944 get_boot_slice(ib_device_t *device, struct dk_gpt *vtoc) 945 { 946 uint_t i; 947 char *path, *ptr; 948 949 for (i = 0; i < vtoc->efi_nparts; i++) { 950 if (vtoc->efi_parts[i].p_tag == V_BOOT) { 951 if ((path = strdup(device->target.path)) == NULL) { 952 perror(gettext("Memory allocation failure")); 953 return (BC_ERROR); 954 } 955 ptr = strrchr(path, 's'); 956 ptr++; 957 *ptr = '\0'; 958 (void) asprintf(&ptr, "%s%d", path, i); 959 free(path); 960 if (ptr == NULL) { 961 perror(gettext("Memory allocation failure")); 962 return (BC_ERROR); 963 } 964 device->stage.path = ptr; 965 device->stage.fd = open_device(ptr); 966 device->stage.id = i; 967 device->stage.devtype = IG_DEV_EFI; 968 device->stage.fstype = IG_FS_NONE; 969 device->stage.start = vtoc->efi_parts[i].p_start; 970 device->stage.size = vtoc->efi_parts[i].p_size; 971 device->stage.offset = 1; /* leave sector 0 for VBR */ 972 return (BC_SUCCESS); 973 } 974 } 975 return (BC_SUCCESS); 976 } 977 978 static int 979 init_device(ib_device_t *device, char *path) 980 { 981 struct dk_gpt *vtoc; 982 fstyp_handle_t fhdl; 983 const char *fident; 984 char *p; 985 int pathlen = strlen(path); 986 int ret; 987 988 bzero(device, sizeof (*device)); 989 device->fd = -1; /* whole disk fd */ 990 device->stage.fd = -1; /* bootblock partition fd */ 991 device->target.fd = -1; /* target fs partition fd */ 992 993 /* basic check, whole disk is not allowed */ 994 if ((p = strrchr(path, '/')) == NULL) 995 p = path; 996 if ((strrchr(p, 'p') == NULL && strrchr(p, 's') == NULL) || 997 (path[pathlen-2] == 'p' && path[pathlen-1] == '0')) { 998 (void) fprintf(stderr, gettext("installing loader to " 999 "whole disk device is not supported\n")); 1000 } 1001 1002 device->target.path = strdup(path); 1003 if (device->target.path == NULL) { 1004 perror(gettext("Memory allocation failure")); 1005 return (BC_ERROR); 1006 } 1007 device->path = strdup(path); 1008 if (device->path == NULL) { 1009 perror(gettext("Memory allocation failure")); 1010 return (BC_ERROR); 1011 } 1012 1013 /* change device name to p0 */ 1014 device->path[pathlen - 2] = 'p'; 1015 device->path[pathlen - 1] = '0'; 1016 1017 if (strstr(device->target.path, "diskette")) { 1018 (void) fprintf(stderr, gettext("installing loader to a floppy " 1019 "disk is not supported\n")); 1020 return (BC_ERROR); 1021 } 1022 1023 /* Detect if the target device is a pcfs partition. */ 1024 if (strstr(device->target.path, "p0:boot")) { 1025 (void) fprintf(stderr, gettext("installing loader to x86 boot " 1026 "partition is not supported\n")); 1027 return (BC_ERROR); 1028 } 1029 1030 if ((device->fd = open_device(device->path)) == -1) 1031 return (BC_ERROR); 1032 1033 /* read in the device boot sector. */ 1034 if (read(device->fd, device->mbr, SECTOR_SIZE) != SECTOR_SIZE) { 1035 (void) fprintf(stderr, gettext("Error reading boot sector\n")); 1036 perror("read"); 1037 return (BC_ERROR); 1038 } 1039 1040 device->devtype = IG_DEV_VTOC; 1041 if (efi_alloc_and_read(device->fd, &vtoc) >= 0) { 1042 ret = get_boot_slice(device, vtoc); 1043 device->devtype = IG_DEV_EFI; 1044 efi_free(vtoc); 1045 if (ret == BC_ERROR) 1046 return (BC_ERROR); 1047 } else if (device->target.path[pathlen - 2] == 'p') { 1048 device->devtype = IG_DEV_MBR; 1049 ret = get_boot_partition(device, (struct mboot *)device->mbr); 1050 if (ret == BC_ERROR) 1051 return (BC_ERROR); 1052 } else if (device->target.path[pathlen - 1] == '2') { 1053 /* 1054 * NOTE: we could relax there and allow zfs boot on 1055 * slice 2 for instance, but lets keep traditional limits. 1056 */ 1057 (void) fprintf(stderr, 1058 gettext("raw device must be a root slice (not s2)\n")); 1059 return (BC_ERROR); 1060 } 1061 1062 /* fill stage partition for case there is no boot partition */ 1063 if (device->stage.path == NULL) { 1064 if ((device->stage.path = strdup(path)) == NULL) { 1065 perror(gettext("Memory allocation failure")); 1066 return (BC_ERROR); 1067 } 1068 if (device->devtype == IG_DEV_VTOC) { 1069 /* use slice 2 */ 1070 device->stage.path[pathlen - 2] = 's'; 1071 device->stage.path[pathlen - 1] = '2'; 1072 device->stage.id = 2; 1073 } else { 1074 p = strrchr(device->stage.path, 'p'); 1075 if (p == NULL) 1076 p = strrchr(device->stage.path, 's'); 1077 device->stage.id = atoi(++p); 1078 } 1079 device->stage.devtype = device->devtype; 1080 device->stage.fd = open_device(device->stage.path); 1081 } 1082 1083 p = strrchr(device->target.path, 'p'); 1084 if (p == NULL) 1085 p = strrchr(device->target.path, 's'); 1086 device->target.id = atoi(++p); 1087 1088 if (strcmp(device->stage.path, device->target.path) == 0) 1089 device->target.fd = dup(device->stage.fd); 1090 else 1091 device->target.fd = open_device(device->target.path); 1092 1093 if (fstyp_init(device->target.fd, 0, NULL, &fhdl) != 0) 1094 return (BC_ERROR); 1095 1096 if (fstyp_ident(fhdl, NULL, &fident) != 0) { 1097 fstyp_fini(fhdl); 1098 (void) fprintf(stderr, gettext("Failed to detect file " 1099 "system type\n")); 1100 return (BC_ERROR); 1101 } 1102 1103 /* at this moment non-boot partition has no size set, use this fact */ 1104 if (device->devtype == IG_DEV_EFI && strcmp(fident, "zfs") && 1105 device->stage.size == 0) { 1106 fstyp_fini(fhdl); 1107 (void) fprintf(stderr, gettext("Booting %s of EFI labeled " 1108 "disks requires the boot partition.\n"), fident); 1109 return (BC_ERROR); 1110 } 1111 if (strcmp(fident, "zfs") == 0) 1112 device->target.fstype = IG_FS_ZFS; 1113 else if (strcmp(fident, "ufs") == 0) { 1114 device->target.fstype = IG_FS_UFS; 1115 } else if (strcmp(fident, "pcfs") == 0) { 1116 device->target.fstype = IG_FS_PCFS; 1117 } else { 1118 (void) fprintf(stderr, gettext("File system %s is not " 1119 "supported by loader\n"), fident); 1120 fstyp_fini(fhdl); 1121 return (BC_ERROR); 1122 } 1123 fstyp_fini(fhdl); 1124 1125 /* check for boot partition content */ 1126 if (device->stage.size) { 1127 if (fstyp_init(device->stage.fd, 0, NULL, &fhdl) != 0) 1128 return (BC_ERROR); 1129 1130 if (fstyp_ident(fhdl, NULL, &fident) == 0) { 1131 (void) fprintf(stderr, gettext("Unexpected %s file " 1132 "system on boot partition\n"), fident); 1133 fstyp_fini(fhdl); 1134 return (BC_ERROR); 1135 } 1136 fstyp_fini(fhdl); 1137 } 1138 return (get_start_sector(device)); 1139 } 1140 1141 static void 1142 cleanup_device(ib_device_t *device) 1143 { 1144 if (device->path) 1145 free(device->path); 1146 if (device->stage.path) 1147 free(device->stage.path); 1148 if (device->target.path) 1149 free(device->target.path); 1150 1151 if (device->fd != -1) 1152 (void) close(device->fd); 1153 if (device->stage.fd != -1) 1154 (void) close(device->stage.fd); 1155 if (device->target.fd != -1) 1156 (void) close(device->target.fd); 1157 bzero(device, sizeof (*device)); 1158 } 1159 1160 static void 1161 cleanup_bootblock(ib_bootblock_t *bblock) 1162 { 1163 free(bblock->buf); 1164 bzero(bblock, sizeof (ib_bootblock_t)); 1165 } 1166 1167 /* 1168 * Propagate the bootblock on the source disk to the destination disk and 1169 * version it with 'updt_str' in the process. Since we cannot trust any data 1170 * on the attaching disk, we do not perform any specific check on a potential 1171 * target extended information structure and we just blindly update. 1172 */ 1173 static int 1174 propagate_bootblock(ib_data_t *src, ib_data_t *dest, char *updt_str) 1175 { 1176 ib_bootblock_t *src_bblock = &src->bootblock; 1177 ib_bootblock_t *dest_bblock = &dest->bootblock; 1178 1179 assert(src != NULL); 1180 assert(dest != NULL); 1181 1182 /* read the stage1 file from source disk */ 1183 if (read(src->device.fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) { 1184 (void) fprintf(stderr, gettext("cannot read stage1 from %s\n"), 1185 src->device.path); 1186 return (BC_ERROR); 1187 } 1188 1189 cleanup_bootblock(dest_bblock); 1190 1191 dest_bblock->buf_size = src_bblock->buf_size; 1192 dest_bblock->buf = malloc(dest_bblock->buf_size); 1193 if (dest_bblock->buf == NULL) { 1194 perror(gettext("Memory Allocation Failure")); 1195 return (BC_ERROR); 1196 } 1197 dest_bblock->file = dest_bblock->buf; 1198 dest_bblock->file_size = src_bblock->file_size; 1199 (void) memcpy(dest_bblock->buf, src_bblock->buf, 1200 dest_bblock->buf_size); 1201 1202 dest_bblock->mboot = (multiboot_header_t *)(dest_bblock->file + 1203 src_bblock->mboot_off); 1204 dest_bblock->mboot_off = src_bblock->mboot_off; 1205 dest_bblock->extra = (char *)dest_bblock->file + 1206 P2ROUNDUP(dest_bblock->file_size, 8); 1207 dest_bblock->extra_size = src_bblock->extra_size; 1208 1209 (void) fprintf(stdout, gettext("Propagating %s bootblock to %s\n"), 1210 src->device.path, dest->device.path); 1211 1212 return (commit_to_disk(dest, updt_str)); 1213 } 1214 1215 static int 1216 commit_to_disk(ib_data_t *data, char *update_str) 1217 { 1218 assert(data != NULL); 1219 1220 if (prepare_bootblock(data, update_str) != BC_SUCCESS) { 1221 (void) fprintf(stderr, gettext("Error updating the bootblock " 1222 "image\n")); 1223 return (BC_ERROR); 1224 } 1225 1226 if (prepare_stage1(data) != BC_SUCCESS) { 1227 (void) fprintf(stderr, gettext("Error updating the stage1 " 1228 "image\n")); 1229 return (BC_ERROR); 1230 } 1231 1232 if (write_bootblock(data) != BC_SUCCESS) { 1233 (void) fprintf(stderr, gettext("Error writing bootblock to " 1234 "disk\n")); 1235 return (BC_ERROR); 1236 } 1237 1238 return (write_stage1(data)); 1239 } 1240 1241 /* 1242 * Install a new bootblock on the given device. handle_install() expects argv 1243 * to contain 3 parameters (the target device path and the path to the 1244 * bootblock. 1245 * 1246 * Returns: BC_SUCCESS - if the installation is successful 1247 * BC_ERROR - if the installation failed 1248 * BC_NOUPDT - if no installation was performed because the 1249 * version currently installed is more recent than the 1250 * supplied one. 1251 * 1252 */ 1253 static int 1254 handle_install(char *progname, char **argv) 1255 { 1256 ib_data_t install_data; 1257 ib_bootblock_t *bblock = &install_data.bootblock; 1258 char *stage1 = NULL; 1259 char *bootblock = NULL; 1260 char *device_path = NULL; 1261 int ret = BC_ERROR; 1262 1263 stage1 = strdup(argv[0]); 1264 bootblock = strdup(argv[1]); 1265 device_path = strdup(argv[2]); 1266 1267 if (!device_path || !bootblock || !stage1) { 1268 (void) fprintf(stderr, gettext("Missing parameter")); 1269 usage(progname, BC_ERROR); 1270 } 1271 1272 BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n", 1273 device_path, stage1, bootblock); 1274 bzero(&install_data, sizeof (ib_data_t)); 1275 1276 if (init_device(&install_data.device, device_path) != BC_SUCCESS) { 1277 (void) fprintf(stderr, gettext("Unable to open device %s\n"), 1278 device_path); 1279 goto out; 1280 } 1281 1282 if (read_stage1_from_file(stage1, &install_data) != BC_SUCCESS) { 1283 (void) fprintf(stderr, gettext("Error opening %s\n"), stage1); 1284 goto out_dev; 1285 } 1286 1287 if (read_bootblock_from_file(bootblock, bblock) != BC_SUCCESS) { 1288 (void) fprintf(stderr, gettext("Error reading %s\n"), 1289 bootblock); 1290 goto out_dev; 1291 } 1292 1293 /* 1294 * is_update_necessary() will take care of checking if versioning and/or 1295 * forcing the update have been specified. It will also emit a warning 1296 * if a non-versioned update is attempted over a versioned bootblock. 1297 */ 1298 if (!is_update_necessary(&install_data, update_str)) { 1299 (void) fprintf(stderr, gettext("bootblock version installed " 1300 "on %s is more recent or identical\n" 1301 "Use -F to override or install without the -u option\n"), 1302 device_path); 1303 ret = BC_NOUPDT; 1304 goto out_dev; 1305 } 1306 1307 BOOT_DEBUG("Ready to commit to disk\n"); 1308 ret = commit_to_disk(&install_data, update_str); 1309 1310 out_dev: 1311 cleanup_device(&install_data.device); 1312 out: 1313 free(stage1); 1314 free(bootblock); 1315 free(device_path); 1316 return (ret); 1317 } 1318 1319 /* 1320 * Retrieves from a device the extended information (einfo) associated to the 1321 * file or installed stage2. 1322 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0 1323 * or file name. 1324 * Returns: 1325 * - BC_SUCCESS (and prints out einfo contents depending on 'flags') 1326 * - BC_ERROR (on error) 1327 * - BC_NOEINFO (no extended information available) 1328 */ 1329 static int 1330 handle_getinfo(char *progname, char **argv) 1331 { 1332 struct stat sb; 1333 ib_bootblock_t bblock; 1334 ib_device_t device; 1335 bblk_einfo_t *einfo; 1336 uint8_t flags = 0; 1337 char *device_path, *path; 1338 int retval = BC_ERROR; 1339 int ret; 1340 1341 device_path = strdup(argv[0]); 1342 if (!device_path) { 1343 (void) fprintf(stderr, gettext("Missing parameter")); 1344 usage(progname, BC_ERROR); 1345 } 1346 1347 if (stat(device_path, &sb) == -1) { 1348 perror("stat"); 1349 goto out; 1350 } 1351 1352 bzero(&bblock, sizeof (bblock)); 1353 bzero(&device, sizeof (device)); 1354 BOOT_DEBUG("device path: %s\n", device_path); 1355 1356 if (S_ISREG(sb.st_mode) != 0) { 1357 path = device_path; 1358 ret = read_bootblock_from_file(device_path, &bblock); 1359 } else { 1360 if (init_device(&device, device_path) != BC_SUCCESS) { 1361 (void) fprintf(stderr, gettext("Unable to gather " 1362 "device information from %s\n"), device_path); 1363 goto out_dev; 1364 } 1365 ret = read_bootblock_from_disk(&device, &bblock, &path); 1366 } 1367 1368 if (ret == BC_ERROR) { 1369 (void) fprintf(stderr, gettext("Error reading bootblock from " 1370 "%s\n"), path); 1371 goto out_dev; 1372 } 1373 1374 if (ret == BC_NOEXTRA) { 1375 BOOT_DEBUG("No multiboot header found on %s, unable " 1376 "to locate extra information area (old/non versioned " 1377 "bootblock?) \n", device_path); 1378 (void) fprintf(stderr, gettext("No extended information " 1379 "found\n")); 1380 retval = BC_NOEINFO; 1381 goto out_dev; 1382 } 1383 1384 einfo = find_einfo(bblock.extra, bblock.extra_size); 1385 if (einfo == NULL) { 1386 retval = BC_NOEINFO; 1387 (void) fprintf(stderr, gettext("No extended information " 1388 "found\n")); 1389 goto out_dev; 1390 } 1391 1392 /* Print the extended information. */ 1393 if (strip) 1394 flags |= EINFO_EASY_PARSE; 1395 if (verbose_dump) 1396 flags |= EINFO_PRINT_HEADER; 1397 1398 print_einfo(flags, einfo, bblock.extra_size); 1399 retval = BC_SUCCESS; 1400 1401 out_dev: 1402 if (S_ISREG(sb.st_mode) == 0) 1403 cleanup_device(&device); 1404 out: 1405 free(device_path); 1406 return (retval); 1407 } 1408 1409 /* 1410 * Attempt to mirror (propagate) the current bootblock over the attaching disk. 1411 * 1412 * Returns: 1413 * - BC_SUCCESS (a successful propagation happened) 1414 * - BC_ERROR (an error occurred) 1415 * - BC_NOEXTRA (it is not possible to dump the current bootblock since 1416 * there is no multiboot information) 1417 */ 1418 static int 1419 handle_mirror(char *progname, char **argv) 1420 { 1421 ib_data_t curr_data; 1422 ib_data_t attach_data; 1423 ib_device_t *curr_device = &curr_data.device; 1424 ib_device_t *attach_device = &attach_data.device; 1425 ib_bootblock_t *bblock_curr = &curr_data.bootblock; 1426 ib_bootblock_t *bblock_attach = &attach_data.bootblock; 1427 bblk_einfo_t *einfo_curr = NULL; 1428 char *curr_device_path; 1429 char *attach_device_path; 1430 char *updt_str = NULL; 1431 char *path; 1432 int retval = BC_ERROR; 1433 int ret; 1434 1435 curr_device_path = strdup(argv[0]); 1436 attach_device_path = strdup(argv[1]); 1437 1438 if (!curr_device_path || !attach_device_path) { 1439 (void) fprintf(stderr, gettext("Missing parameter")); 1440 usage(progname, BC_ERROR); 1441 } 1442 BOOT_DEBUG("Current device path is: %s, attaching device path is: " 1443 " %s\n", curr_device_path, attach_device_path); 1444 1445 bzero(&curr_data, sizeof (ib_data_t)); 1446 bzero(&attach_data, sizeof (ib_data_t)); 1447 1448 if (init_device(curr_device, curr_device_path) != BC_SUCCESS) { 1449 (void) fprintf(stderr, gettext("Unable to gather device " 1450 "information from %s (current device)\n"), 1451 curr_device_path); 1452 goto out_currdev; 1453 } 1454 1455 if (init_device(attach_device, attach_device_path) != BC_SUCCESS) { 1456 (void) fprintf(stderr, gettext("Unable to gather device " 1457 "information from %s (attaching device)\n"), 1458 attach_device_path); 1459 goto out_devs; 1460 } 1461 1462 ret = read_bootblock_from_disk(curr_device, bblock_curr, &path); 1463 if (ret == BC_ERROR) { 1464 BOOT_DEBUG("Error reading bootblock from %s\n", path); 1465 retval = BC_ERROR; 1466 goto out_devs; 1467 } 1468 1469 if (ret == BC_NOEXTRA) { 1470 BOOT_DEBUG("No multiboot header found on %s, unable to retrieve" 1471 " the bootblock\n", path); 1472 retval = BC_NOEXTRA; 1473 goto out_devs; 1474 } 1475 1476 write_mbr = B_TRUE; 1477 force_mbr = B_TRUE; 1478 einfo_curr = find_einfo(bblock_curr->extra, bblock_curr->extra_size); 1479 if (einfo_curr != NULL) 1480 updt_str = einfo_get_string(einfo_curr); 1481 1482 retval = propagate_bootblock(&curr_data, &attach_data, updt_str); 1483 cleanup_bootblock(bblock_curr); 1484 cleanup_bootblock(bblock_attach); 1485 out_devs: 1486 cleanup_device(attach_device); 1487 out_currdev: 1488 cleanup_device(curr_device); 1489 free(curr_device_path); 1490 free(attach_device_path); 1491 return (retval); 1492 } 1493 1494 #define USAGE_STRING "Usage:\t%s [-h|-m|-f|-n|-F|-u verstr] stage1 stage2 " \ 1495 "raw-device\n" \ 1496 "\t%s -M [-n] raw-device attach-raw-device\n" \ 1497 "\t%s [-e|-V] -i raw-device | file\n" 1498 1499 #define CANON_USAGE_STR gettext(USAGE_STRING) 1500 1501 static void 1502 usage(char *progname, int rc) 1503 { 1504 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname); 1505 exit(rc); 1506 } 1507 1508 int 1509 main(int argc, char **argv) 1510 { 1511 int opt; 1512 int params = 3; 1513 int ret; 1514 char *progname; 1515 char **handle_args; 1516 1517 (void) setlocale(LC_ALL, ""); 1518 (void) textdomain(TEXT_DOMAIN); 1519 if (init_yes() < 0) 1520 errx(BC_ERROR, gettext(ERR_MSG_INIT_YES), strerror(errno)); 1521 1522 /* Determine our name */ 1523 progname = basename(argv[0]); 1524 1525 while ((opt = getopt(argc, argv, "deFfhiMmnu:V")) != EOF) { 1526 switch (opt) { 1527 case 'd': 1528 boot_debug = B_TRUE; 1529 break; 1530 case 'e': 1531 strip = B_TRUE; 1532 break; 1533 case 'F': 1534 force_update = B_TRUE; 1535 break; 1536 case 'f': 1537 force_mbr = B_TRUE; 1538 break; 1539 case 'h': 1540 usage(progname, BC_SUCCESS); 1541 break; 1542 case 'i': 1543 do_getinfo = B_TRUE; 1544 params = 1; 1545 break; 1546 case 'M': 1547 do_mirror_bblk = B_TRUE; 1548 params = 2; 1549 break; 1550 case 'm': 1551 write_mbr = B_TRUE; 1552 break; 1553 case 'n': 1554 nowrite = B_TRUE; 1555 break; 1556 case 'u': 1557 do_version = B_TRUE; 1558 1559 update_str = strdup(optarg); 1560 if (update_str == NULL) { 1561 perror(gettext("Memory allocation failure")); 1562 exit(BC_ERROR); 1563 } 1564 break; 1565 case 'V': 1566 verbose_dump = B_TRUE; 1567 break; 1568 default: 1569 /* fall through to process non-optional args */ 1570 break; 1571 } 1572 } 1573 1574 /* check arguments */ 1575 if (argc != optind + params) { 1576 usage(progname, BC_ERROR); 1577 } 1578 check_options(progname); 1579 handle_args = argv + optind; 1580 1581 if (nowrite) 1582 (void) fprintf(stdout, gettext("Dry run requested. Nothing will" 1583 " be written to disk.\n")); 1584 1585 if (do_getinfo) { 1586 ret = handle_getinfo(progname, handle_args); 1587 } else if (do_mirror_bblk) { 1588 ret = handle_mirror(progname, handle_args); 1589 } else { 1590 ret = handle_install(progname, handle_args); 1591 } 1592 return (ret); 1593 } 1594 1595 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n") 1596 static void 1597 check_options(char *progname) 1598 { 1599 if (do_getinfo && do_mirror_bblk) { 1600 (void) fprintf(stderr, gettext("Only one of -M and -i can be " 1601 "specified at the same time\n")); 1602 usage(progname, BC_ERROR); 1603 } 1604 1605 if (do_mirror_bblk) { 1606 /* 1607 * -u and -F may actually reflect a user intent that is not 1608 * correct with this command (mirror can be interpreted 1609 * "similar" to install. Emit a message and continue. 1610 * -e and -V have no meaning, be quiet here and only report the 1611 * incongruence if a debug output is requested. 1612 */ 1613 if (do_version) { 1614 (void) fprintf(stderr, MEANINGLESS_OPT, "-u"); 1615 do_version = B_FALSE; 1616 } 1617 if (force_update) { 1618 (void) fprintf(stderr, MEANINGLESS_OPT, "-F"); 1619 force_update = B_FALSE; 1620 } 1621 if (strip || verbose_dump) { 1622 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V"); 1623 strip = B_FALSE; 1624 verbose_dump = B_FALSE; 1625 } 1626 } 1627 1628 if (do_getinfo) { 1629 if (write_mbr || force_mbr || do_version || force_update) { 1630 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F"); 1631 write_mbr = force_mbr = do_version = B_FALSE; 1632 force_update = B_FALSE; 1633 } 1634 } 1635 } 1636