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