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) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2012 Milan Jurik. All rights reserved. 24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <libgen.h> 30 #include <malloc.h> 31 #include <string.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <strings.h> 35 #include <libintl.h> 36 #include <locale.h> 37 #include <errno.h> 38 #include <libfdisk.h> 39 #include <stdarg.h> 40 #include <assert.h> 41 42 #include <sys/mount.h> 43 #include <sys/mnttab.h> 44 #include <sys/dktp/fdisk.h> 45 #include <sys/dkio.h> 46 #include <sys/vtoc.h> 47 #include <sys/types.h> 48 #include <sys/stat.h> 49 #include <sys/multiboot.h> 50 #include <sys/sysmacros.h> 51 52 #include "message.h" 53 #include "installgrub.h" 54 #include "./../common/bblk_einfo.h" 55 #include "./../common/boot_utils.h" 56 #include "./../common/mboot_extra.h" 57 58 #ifndef TEXT_DOMAIN 59 #define TEXT_DOMAIN "SUNW_OST_OSCMD" 60 #endif 61 62 /* 63 * Variables to track installgrub desired mode of operation. 64 * 'nowrite' and 'boot_debug' come from boot_common.h. 65 */ 66 static boolean_t write_mbr = B_FALSE; 67 static boolean_t force_mbr = B_FALSE; 68 static boolean_t force_update = B_FALSE; 69 static boolean_t do_getinfo = B_FALSE; 70 static boolean_t do_version = B_FALSE; 71 static boolean_t do_mirror_bblk = B_FALSE; 72 static boolean_t strip = B_FALSE; 73 static boolean_t verbose_dump = B_FALSE; 74 75 /* Installing the bootblock is the default operation. */ 76 static boolean_t do_install = B_TRUE; 77 78 /* Versioning string, if present. */ 79 static char *update_str; 80 81 /* 82 * Temporary buffer to store the first 32K of data looking for a multiboot 83 * signature. 84 */ 85 char mboot_scan[MBOOT_SCAN_SIZE]; 86 87 /* Function prototypes. */ 88 static void check_options(char *); 89 static int handle_install(char *, char **); 90 static int handle_mirror(char *, char **); 91 static int handle_getinfo(char *, char **); 92 static int commit_to_disk(ig_data_t *, char *); 93 static int init_device(ig_device_t *, char *path); 94 static void cleanup_device(ig_device_t *); 95 static void cleanup_stage2(ig_stage2_t *); 96 static int get_start_sector(ig_device_t *); 97 static int get_disk_fd(ig_device_t *device); 98 static int get_raw_partition_fd(ig_device_t *); 99 static char *get_raw_partition_path(ig_device_t *); 100 static boolean_t gather_stage2_from_dev(ig_data_t *); 101 static int propagate_bootblock(ig_data_t *, ig_data_t *, char *); 102 static int find_x86_bootpar(struct mboot *, int *, uint32_t *); 103 static int copy_stage2_to_pcfs(ig_data_t *); 104 static int write_stage2(ig_data_t *); 105 static int write_stage1(ig_data_t *); 106 static void usage(char *); 107 static int read_stage1_from_file(char *, ig_data_t *); 108 static int read_stage2_from_file(char *, ig_data_t *); 109 static int read_stage1_from_disk(int, char *); 110 static int read_stage2_from_disk(int, ig_stage2_t *); 111 static int prepare_stage1(ig_data_t *); 112 static int prepare_stage2(ig_data_t *, char *); 113 static void prepare_fake_multiboot(ig_stage2_t *); 114 static void add_stage2_einfo(ig_stage2_t *, char *updt_str); 115 static boolean_t is_update_necessary(ig_data_t *, char *); 116 117 extern int read_stage2_blocklist(int, unsigned int *); 118 119 int 120 main(int argc, char *argv[]) 121 { 122 int opt; 123 int params = 3; 124 int ret; 125 char **handle_args; 126 char *progname; 127 128 (void) setlocale(LC_ALL, ""); 129 (void) textdomain(TEXT_DOMAIN); 130 131 /* 132 * retro-compatibility: installing the bootblock is the default 133 * and there is no switch for it. 134 */ 135 do_install = B_TRUE; 136 137 while ((opt = getopt(argc, argv, "dVMFfmneiu:")) != EOF) { 138 switch (opt) { 139 case 'm': 140 write_mbr = B_TRUE; 141 break; 142 case 'n': 143 nowrite = B_TRUE; 144 break; 145 case 'f': 146 force_mbr = B_TRUE; 147 break; 148 case 'i': 149 do_getinfo = B_TRUE; 150 do_install = B_FALSE; 151 params = 1; 152 break; 153 case 'V': 154 verbose_dump = B_TRUE; 155 break; 156 case 'd': 157 boot_debug = B_TRUE; 158 break; 159 case 'F': 160 force_update = B_TRUE; 161 break; 162 case 'e': 163 strip = B_TRUE; 164 break; 165 case 'M': 166 do_mirror_bblk = B_TRUE; 167 do_install = B_FALSE; 168 params = 2; 169 break; 170 case 'u': 171 do_version = B_TRUE; 172 173 update_str = malloc(strlen(optarg) + 1); 174 if (update_str == NULL) { 175 (void) fprintf(stderr, gettext("Unable to " 176 "allocate memory\n")); 177 exit(BC_ERROR); 178 } 179 (void) strlcpy(update_str, optarg, strlen(optarg) + 1); 180 break; 181 default: 182 /* fall through to process non-optional args */ 183 break; 184 } 185 } 186 187 /* check arguments */ 188 if (argc != optind + params) { 189 usage(argv[0]); 190 exit(BC_ERROR); 191 } 192 193 /* 194 * clean up options (and bail out if an unrecoverable combination is 195 * requested. 196 */ 197 progname = argv[0]; 198 check_options(progname); 199 handle_args = argv + optind; 200 201 if (nowrite) 202 (void) fprintf(stdout, DRY_RUN); 203 204 if (do_getinfo) { 205 ret = handle_getinfo(progname, handle_args); 206 } else if (do_mirror_bblk) { 207 ret = handle_mirror(progname, handle_args); 208 } else { 209 ret = handle_install(progname, handle_args); 210 } 211 return (ret); 212 } 213 214 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n") 215 static void 216 check_options(char *progname) 217 { 218 if (do_getinfo && do_mirror_bblk) { 219 (void) fprintf(stderr, gettext("Only one of -M and -i can be " 220 "specified at the same time\n")); 221 usage(progname); 222 exit(BC_ERROR); 223 } 224 225 if (do_mirror_bblk) { 226 /* 227 * -u and -F may actually reflect a user intent that is not 228 * correct with this command (mirror can be interpreted 229 * "similar" to install. Emit a message and continue. 230 * -e and -V have no meaning, be quiet here and only report the 231 * incongruence if a debug output is requested. 232 */ 233 if (do_version) { 234 (void) fprintf(stderr, MEANINGLESS_OPT, "-u"); 235 do_version = B_FALSE; 236 } 237 if (force_update) { 238 (void) fprintf(stderr, MEANINGLESS_OPT, "-F"); 239 force_update = B_FALSE; 240 } 241 if (strip || verbose_dump) { 242 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V"); 243 strip = B_FALSE; 244 verbose_dump = B_FALSE; 245 } 246 } 247 248 if (do_getinfo) { 249 if (write_mbr || force_mbr || do_version || force_update) { 250 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F"); 251 write_mbr = force_mbr = do_version = B_FALSE; 252 force_update = B_FALSE; 253 } 254 } 255 } 256 257 /* 258 * Install a new stage1/stage2 pair on the specified device. handle_install() 259 * expects argv to contain 3 parameters (the path to stage1, the path to stage2, 260 * the target device). 261 * 262 * Returns: BC_SUCCESS - if the installation is successful 263 * BC_ERROR - if the installation failed 264 * BC_NOUPDT - if no installation was performed because the GRUB 265 * version currently installed is more recent than the 266 * supplied one. 267 * 268 */ 269 static int 270 handle_install(char *progname, char **argv) 271 { 272 ig_data_t install_data; 273 char *stage1_path = NULL; 274 char *stage2_path = NULL; 275 char *device_path = NULL; 276 int ret = BC_ERROR; 277 278 stage1_path = strdup(argv[0]); 279 stage2_path = strdup(argv[1]); 280 device_path = strdup(argv[2]); 281 282 bzero(&install_data, sizeof (ig_data_t)); 283 284 if (!stage1_path || !stage2_path || !device_path) { 285 (void) fprintf(stderr, gettext("Missing parameter")); 286 usage(progname); 287 goto out; 288 } 289 290 BOOT_DEBUG("stage1 path: %s, stage2 path: %s, device: %s\n", 291 stage1_path, stage2_path, device_path); 292 293 if (init_device(&install_data.device, device_path) != BC_SUCCESS) { 294 (void) fprintf(stderr, gettext("Unable to gather device " 295 "information for %s\n"), device_path); 296 goto out; 297 } 298 299 /* read in stage1 and stage2. */ 300 if (read_stage1_from_file(stage1_path, &install_data) != BC_SUCCESS) { 301 (void) fprintf(stderr, gettext("Error opening %s\n"), 302 stage1_path); 303 goto out_dev; 304 } 305 306 if (read_stage2_from_file(stage2_path, &install_data) != BC_SUCCESS) { 307 (void) fprintf(stderr, gettext("Error opening %s\n"), 308 stage2_path); 309 goto out_dev; 310 } 311 312 /* We do not support versioning on PCFS. */ 313 if (is_bootpar(install_data.device.type) && do_version) 314 do_version = B_FALSE; 315 316 /* 317 * is_update_necessary() will take care of checking if versioning and/or 318 * forcing the update have been specified. It will also emit a warning 319 * if a non-versioned update is attempted over a versioned bootblock. 320 */ 321 if (!is_update_necessary(&install_data, update_str)) { 322 (void) fprintf(stderr, gettext("GRUB version installed " 323 "on %s is more recent or identical\n" 324 "Use -F to override or install without the -u option\n"), 325 device_path); 326 ret = BC_NOUPDT; 327 goto out_dev; 328 } 329 /* 330 * We get here if: 331 * - the installed GRUB version is older than the one about to be 332 * installed. 333 * - no versioning string has been passed through the command line. 334 * - a forced update is requested (-F). 335 */ 336 BOOT_DEBUG("Ready to commit to disk\n"); 337 ret = commit_to_disk(&install_data, update_str); 338 339 out_dev: 340 cleanup_device(&install_data.device); 341 out: 342 free(stage1_path); 343 free(stage2_path); 344 free(device_path); 345 return (ret); 346 } 347 348 /* 349 * Retrieves from a device the extended information (einfo) associated to the 350 * installed stage2. 351 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0. 352 * Returns: 353 * - BC_SUCCESS (and prints out einfo contents depending on 'flags') 354 * - BC_ERROR (on error) 355 * - BC_NOEINFO (no extended information available) 356 */ 357 static int 358 handle_getinfo(char *progname, char **argv) 359 { 360 ig_data_t data; 361 ig_stage2_t *stage2 = &data.stage2; 362 ig_device_t *device = &data.device; 363 bblk_einfo_t *einfo; 364 uint8_t flags = 0; 365 uint32_t size; 366 char *device_path; 367 int retval = BC_ERROR; 368 int ret; 369 370 device_path = strdup(argv[0]); 371 if (!device_path) { 372 (void) fprintf(stderr, gettext("Missing parameter")); 373 usage(progname); 374 goto out; 375 } 376 377 bzero(&data, sizeof (ig_data_t)); 378 BOOT_DEBUG("device path: %s\n", device_path); 379 380 if (init_device(device, device_path) != BC_SUCCESS) { 381 (void) fprintf(stderr, gettext("Unable to gather device " 382 "information for %s\n"), device_path); 383 goto out_dev; 384 } 385 386 if (is_bootpar(device->type)) { 387 (void) fprintf(stderr, gettext("Versioning not supported on " 388 "PCFS\n")); 389 goto out_dev; 390 } 391 392 ret = read_stage2_from_disk(device->part_fd, stage2); 393 if (ret == BC_ERROR) { 394 (void) fprintf(stderr, gettext("Error reading stage2 from " 395 "%s\n"), device_path); 396 goto out_dev; 397 } 398 399 if (ret == BC_NOEXTRA) { 400 (void) fprintf(stdout, gettext("No multiboot header found on " 401 "%s, unable to locate extra information area\n"), 402 device_path); 403 retval = BC_NOEINFO; 404 goto out_dev; 405 } 406 407 einfo = find_einfo(stage2->extra, stage2->extra_size); 408 if (einfo == NULL) { 409 retval = BC_NOEINFO; 410 (void) fprintf(stderr, gettext("No extended information " 411 "found\n")); 412 goto out_dev; 413 } 414 415 /* Print the extended information. */ 416 if (strip) 417 flags |= EINFO_EASY_PARSE; 418 if (verbose_dump) 419 flags |= EINFO_PRINT_HEADER; 420 421 size = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8); 422 print_einfo(flags, einfo, size); 423 retval = BC_SUCCESS; 424 425 out_dev: 426 cleanup_device(&data.device); 427 out: 428 free(device_path); 429 return (retval); 430 } 431 432 /* 433 * Attempt to mirror (propagate) the current stage2 over the attaching disk. 434 * 435 * Returns: 436 * - BC_SUCCESS (a successful propagation happened) 437 * - BC_ERROR (an error occurred) 438 * - BC_NOEXTRA (it is not possible to dump the current bootblock since 439 * there is no multiboot information) 440 */ 441 static int 442 handle_mirror(char *progname, char **argv) 443 { 444 ig_data_t curr_data; 445 ig_data_t attach_data; 446 ig_device_t *curr_device = &curr_data.device; 447 ig_device_t *attach_device = &attach_data.device; 448 ig_stage2_t *stage2_curr = &curr_data.stage2; 449 ig_stage2_t *stage2_attach = &attach_data.stage2; 450 bblk_einfo_t *einfo_curr = NULL; 451 char *curr_device_path; 452 char *attach_device_path; 453 char *updt_str = NULL; 454 int retval = BC_ERROR; 455 int ret; 456 457 curr_device_path = strdup(argv[0]); 458 attach_device_path = strdup(argv[1]); 459 460 if (!curr_device_path || !attach_device_path) { 461 (void) fprintf(stderr, gettext("Missing parameter")); 462 usage(progname); 463 goto out; 464 } 465 BOOT_DEBUG("Current device path is: %s, attaching device path is: " 466 " %s\n", curr_device_path, attach_device_path); 467 468 bzero(&curr_data, sizeof (ig_data_t)); 469 bzero(&attach_data, sizeof (ig_data_t)); 470 471 if (init_device(curr_device, curr_device_path) != BC_SUCCESS) { 472 (void) fprintf(stderr, gettext("Unable to gather device " 473 "information for %s (current device)\n"), curr_device_path); 474 goto out_currdev; 475 } 476 477 if (init_device(attach_device, attach_device_path) != BC_SUCCESS) { 478 (void) fprintf(stderr, gettext("Unable to gather device " 479 "information for %s (attaching device)\n"), 480 attach_device_path); 481 goto out_devs; 482 } 483 484 if (is_bootpar(curr_device->type) || is_bootpar(attach_device->type)) { 485 (void) fprintf(stderr, gettext("boot block mirroring is not " 486 "supported on PCFS\n")); 487 goto out_devs; 488 } 489 490 ret = read_stage2_from_disk(curr_device->part_fd, stage2_curr); 491 if (ret == BC_ERROR) { 492 BOOT_DEBUG("Error reading first stage2 blocks from %s\n", 493 curr_device->path); 494 retval = BC_ERROR; 495 goto out_devs; 496 } 497 498 if (ret == BC_NOEXTRA) { 499 BOOT_DEBUG("No multiboot header found on %s, unable to grab " 500 "stage2\n", curr_device->path); 501 retval = BC_NOEXTRA; 502 goto out_devs; 503 } 504 505 einfo_curr = find_einfo(stage2_curr->extra, stage2_curr->extra_size); 506 if (einfo_curr != NULL) 507 updt_str = einfo_get_string(einfo_curr); 508 509 write_mbr = B_TRUE; 510 force_mbr = B_TRUE; 511 retval = propagate_bootblock(&curr_data, &attach_data, updt_str); 512 cleanup_stage2(stage2_curr); 513 cleanup_stage2(stage2_attach); 514 515 out_devs: 516 cleanup_device(attach_device); 517 out_currdev: 518 cleanup_device(curr_device); 519 out: 520 free(curr_device_path); 521 free(attach_device_path); 522 return (retval); 523 } 524 525 static int 526 commit_to_disk(ig_data_t *install, char *updt_str) 527 { 528 assert(install != NULL); 529 /* 530 * vanilla stage1 and stage2 need to be updated at runtime. 531 * Update stage2 before stage1 because stage1 needs to know the first 532 * sector stage2 will be written to. 533 */ 534 if (prepare_stage2(install, updt_str) != BC_SUCCESS) { 535 (void) fprintf(stderr, gettext("Error building stage2\n")); 536 return (BC_ERROR); 537 } 538 if (prepare_stage1(install) != BC_SUCCESS) { 539 (void) fprintf(stderr, gettext("Error building stage1\n")); 540 return (BC_ERROR); 541 } 542 543 /* Write stage2 out to disk. */ 544 if (write_stage2(install) != BC_SUCCESS) { 545 (void) fprintf(stderr, gettext("Error writing stage2 to " 546 "disk\n")); 547 return (BC_ERROR); 548 } 549 550 /* Write stage1 to disk and, if requested, to the MBR. */ 551 if (write_stage1(install) != BC_SUCCESS) { 552 (void) fprintf(stderr, gettext("Error writing stage1 to " 553 "disk\n")); 554 return (BC_ERROR); 555 } 556 557 return (BC_SUCCESS); 558 } 559 560 /* 561 * Propagate the bootblock on the source disk to the destination disk and 562 * version it with 'updt_str' in the process. Since we cannot trust any data 563 * on the attaching disk, we do not perform any specific check on a potential 564 * target extended information structure and we just blindly update. 565 */ 566 static int 567 propagate_bootblock(ig_data_t *source, ig_data_t *target, char *updt_str) 568 { 569 ig_device_t *src_device = &source->device; 570 ig_device_t *dest_device = &target->device; 571 ig_stage2_t *src_stage2 = &source->stage2; 572 ig_stage2_t *dest_stage2 = &target->stage2; 573 uint32_t buf_size; 574 int retval; 575 576 assert(source != NULL); 577 assert(target != NULL); 578 579 /* read in stage1 from the source disk. */ 580 if (read_stage1_from_disk(src_device->part_fd, target->stage1_buf) 581 != BC_SUCCESS) 582 return (BC_ERROR); 583 584 /* Prepare target stage2 for commit_to_disk. */ 585 cleanup_stage2(dest_stage2); 586 587 if (updt_str != NULL) 588 do_version = B_TRUE; 589 else 590 do_version = B_FALSE; 591 592 buf_size = src_stage2->file_size + SECTOR_SIZE; 593 594 dest_stage2->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE); 595 dest_stage2->buf = malloc(dest_stage2->buf_size); 596 if (dest_stage2->buf == NULL) { 597 perror(gettext("Memory allocation failed")); 598 return (BC_ERROR); 599 } 600 dest_stage2->file = dest_stage2->buf; 601 dest_stage2->file_size = src_stage2->file_size; 602 memcpy(dest_stage2->file, src_stage2->file, dest_stage2->file_size); 603 dest_stage2->extra = dest_stage2->buf + 604 P2ROUNDUP(dest_stage2->file_size, 8); 605 606 /* If we get down here we do have a mboot structure. */ 607 assert(src_stage2->mboot); 608 609 dest_stage2->mboot_off = src_stage2->mboot_off; 610 dest_stage2->mboot = (multiboot_header_t *)(dest_stage2->buf + 611 dest_stage2->mboot_off); 612 613 (void) fprintf(stdout, gettext("Propagating %s stage1/stage2 to %s\n"), 614 src_device->path, dest_device->path); 615 retval = commit_to_disk(target, updt_str); 616 617 return (retval); 618 } 619 620 /* 621 * open the device and fill the various members of ig_device_t. 622 */ 623 static int 624 init_device(ig_device_t *device, char *path) 625 { 626 bzero(device, sizeof (*device)); 627 device->part_fd = -1; 628 device->disk_fd = -1; 629 device->path_p0 = NULL; 630 631 device->path = strdup(path); 632 if (device->path == NULL) { 633 perror(gettext("Memory allocation failed")); 634 return (BC_ERROR); 635 } 636 637 if (strstr(device->path, "diskette")) { 638 (void) fprintf(stderr, gettext("installing GRUB to a floppy " 639 "disk is no longer supported\n")); 640 return (BC_ERROR); 641 } 642 643 /* Detect if the target device is a pcfs partition. */ 644 if (strstr(device->path, "p0:boot")) 645 device->type = IG_DEV_X86BOOTPAR; 646 647 if (get_disk_fd(device) != BC_SUCCESS) 648 return (BC_ERROR); 649 650 /* read in the device boot sector. */ 651 if (read(device->disk_fd, device->boot_sector, SECTOR_SIZE) 652 != SECTOR_SIZE) { 653 (void) fprintf(stderr, gettext("Error reading boot sector\n")); 654 perror("read"); 655 return (BC_ERROR); 656 } 657 658 if (get_raw_partition_fd(device) != BC_SUCCESS) 659 return (BC_ERROR); 660 661 if (get_start_sector(device) != BC_SUCCESS) 662 return (BC_ERROR); 663 664 return (BC_SUCCESS); 665 } 666 667 static void 668 cleanup_device(ig_device_t *device) 669 { 670 if (device->path) 671 free(device->path); 672 if (device->path_p0) 673 free(device->path_p0); 674 675 if (device->part_fd != -1) 676 (void) close(device->part_fd); 677 if (device->disk_fd != -1) 678 (void) close(device->disk_fd); 679 680 bzero(device, sizeof (ig_device_t)); 681 device->part_fd = -1; 682 device->disk_fd = -1; 683 } 684 685 static void 686 cleanup_stage2(ig_stage2_t *stage2) 687 { 688 if (stage2->buf) 689 free(stage2->buf); 690 bzero(stage2, sizeof (ig_stage2_t)); 691 } 692 693 static int 694 get_start_sector(ig_device_t *device) 695 { 696 uint32_t secnum = 0, numsec = 0; 697 int i, pno, rval, log_part = 0; 698 struct mboot *mboot; 699 struct ipart *part; 700 ext_part_t *epp; 701 struct part_info dkpi; 702 struct extpart_info edkpi; 703 704 mboot = (struct mboot *)device->boot_sector; 705 706 if (is_bootpar(device->type)) { 707 if (find_x86_bootpar(mboot, &pno, &secnum) != BC_SUCCESS) { 708 (void) fprintf(stderr, NOBOOTPAR); 709 return (BC_ERROR); 710 } else { 711 device->start_sector = secnum; 712 device->partition = pno; 713 goto found_part; 714 } 715 } 716 717 /* 718 * Search for Solaris fdisk partition 719 * Get the solaris partition information from the device 720 * and compare the offset of S2 with offset of solaris partition 721 * from fdisk partition table. 722 */ 723 if (ioctl(device->part_fd, DKIOCEXTPARTINFO, &edkpi) < 0) { 724 if (ioctl(device->part_fd, DKIOCPARTINFO, &dkpi) < 0) { 725 (void) fprintf(stderr, PART_FAIL); 726 return (BC_ERROR); 727 } else { 728 edkpi.p_start = dkpi.p_start; 729 } 730 } 731 732 for (i = 0; i < FD_NUMPART; i++) { 733 part = (struct ipart *)mboot->parts + i; 734 735 if (part->relsect == 0) { 736 (void) fprintf(stderr, BAD_PART, i); 737 return (BC_ERROR); 738 } 739 740 if (edkpi.p_start >= part->relsect && 741 edkpi.p_start < (part->relsect + part->numsect)) { 742 /* Found the partition */ 743 break; 744 } 745 } 746 747 if (i == FD_NUMPART) { 748 /* No solaris fdisk partitions (primary or logical) */ 749 (void) fprintf(stderr, NOSOLPAR); 750 return (BC_ERROR); 751 } 752 753 /* 754 * We have found a Solaris fdisk partition (primary or extended) 755 * Handle the simple case first: Solaris in a primary partition 756 */ 757 if (!fdisk_is_dos_extended(part->systid)) { 758 device->start_sector = part->relsect; 759 device->partition = i; 760 goto found_part; 761 } 762 763 /* 764 * Solaris in a logical partition. Find that partition in the 765 * extended part. 766 */ 767 if ((rval = libfdisk_init(&epp, device->path_p0, NULL, FDISK_READ_DISK)) 768 != FDISK_SUCCESS) { 769 switch (rval) { 770 /* 771 * The first 3 cases are not an error per-se, just that 772 * there is no Solaris logical partition 773 */ 774 case FDISK_EBADLOGDRIVE: 775 case FDISK_ENOLOGDRIVE: 776 case FDISK_EBADMAGIC: 777 (void) fprintf(stderr, NOSOLPAR); 778 return (BC_ERROR); 779 case FDISK_ENOVGEOM: 780 (void) fprintf(stderr, NO_VIRT_GEOM); 781 return (BC_ERROR); 782 case FDISK_ENOPGEOM: 783 (void) fprintf(stderr, NO_PHYS_GEOM); 784 return (BC_ERROR); 785 case FDISK_ENOLGEOM: 786 (void) fprintf(stderr, NO_LABEL_GEOM); 787 return (BC_ERROR); 788 default: 789 (void) fprintf(stderr, LIBFDISK_INIT_FAIL); 790 return (BC_ERROR); 791 } 792 } 793 794 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); 795 libfdisk_fini(&epp); 796 if (rval != FDISK_SUCCESS) { 797 /* No solaris logical partition */ 798 (void) fprintf(stderr, NOSOLPAR); 799 return (BC_ERROR); 800 } 801 802 device->start_sector = secnum; 803 device->partition = pno - 1; 804 log_part = 1; 805 806 found_part: 807 /* get confirmation for -m */ 808 if (write_mbr && !force_mbr) { 809 (void) fprintf(stdout, MBOOT_PROMPT); 810 if (getchar() != 'y') { 811 write_mbr = 0; 812 (void) fprintf(stdout, MBOOT_NOT_UPDATED); 813 return (BC_ERROR); 814 } 815 } 816 817 /* 818 * Currently if Solaris is in an extended partition we need to 819 * write GRUB to the MBR. Check for this. 820 */ 821 if (log_part && !write_mbr) { 822 (void) fprintf(stdout, gettext("Installing Solaris on an " 823 "extended partition... forcing MBR update\n")); 824 write_mbr = 1; 825 } 826 827 /* 828 * warn, if Solaris in primary partition and GRUB not in MBR and 829 * partition is not active 830 */ 831 if (!log_part && part->bootid != 128 && !write_mbr) { 832 (void) fprintf(stdout, SOLPAR_INACTIVE, device->partition + 1); 833 } 834 835 return (BC_SUCCESS); 836 } 837 838 static int 839 get_disk_fd(ig_device_t *device) 840 { 841 int i; 842 char save[2]; 843 char *end = NULL; 844 845 assert(device != NULL); 846 assert(device->path != NULL); 847 848 if (is_bootpar(device->type)) { 849 end = strstr(device->path, "p0:boot"); 850 /* tested at the start of init_device() */ 851 assert(end != NULL); 852 /* chop off :boot */ 853 save[0] = end[2]; 854 end[2] = '\0'; 855 } else { 856 i = strlen(device->path); 857 save[0] = device->path[i - 2]; 858 save[1] = device->path[i - 1]; 859 device->path[i - 2] = 'p'; 860 device->path[i - 1] = '0'; 861 } 862 863 if (nowrite) 864 device->disk_fd = open(device->path, O_RDONLY); 865 else 866 device->disk_fd = open(device->path, O_RDWR); 867 868 device->path_p0 = strdup(device->path); 869 if (device->path_p0 == NULL) { 870 perror("strdup"); 871 return (BC_ERROR); 872 } 873 874 if (is_bootpar(device->type)) { 875 end[2] = save[0]; 876 } else { 877 device->path[i - 2] = save[0]; 878 device->path[i - 1] = save[1]; 879 } 880 881 if (device->disk_fd == -1) { 882 perror("open"); 883 return (BC_ERROR); 884 } 885 886 return (BC_SUCCESS); 887 } 888 889 static void 890 prepare_fake_multiboot(ig_stage2_t *stage2) 891 { 892 multiboot_header_t *mboot; 893 894 assert(stage2 != NULL); 895 assert(stage2->mboot != NULL); 896 assert(stage2->buf != NULL); 897 898 mboot = stage2->mboot; 899 900 /* 901 * Currently we expect find_multiboot() to have located a multiboot 902 * header with the AOUT kludge flag set. 903 */ 904 assert(mboot->flags & BB_MBOOT_AOUT_FLAG); 905 906 /* Insert the information necessary to locate stage2. */ 907 mboot->header_addr = stage2->mboot_off; 908 mboot->load_addr = 0; 909 mboot->load_end_addr = stage2->file_size; 910 } 911 912 static void 913 add_stage2_einfo(ig_stage2_t *stage2, char *updt_str) 914 { 915 bblk_hs_t hs; 916 uint32_t avail_space; 917 918 assert(stage2 != NULL); 919 920 /* Fill bootblock hashing source information. */ 921 hs.src_buf = (unsigned char *)stage2->file; 922 hs.src_size = stage2->file_size; 923 /* How much space for the extended information structure? */ 924 avail_space = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8); 925 add_einfo(stage2->extra, updt_str, &hs, avail_space); 926 } 927 928 929 static int 930 write_stage2(ig_data_t *install) 931 { 932 ig_device_t *device = &install->device; 933 ig_stage2_t *stage2 = &install->stage2; 934 off_t offset; 935 936 assert(install != NULL); 937 938 if (is_bootpar(device->type)) { 939 /* 940 * stage2 is already on the filesystem, we only need to update 941 * the first two blocks (that we have modified during 942 * prepare_stage2()) 943 */ 944 if (write_out(device->part_fd, stage2->file, SECTOR_SIZE, 945 stage2->pcfs_first_sectors[0] * SECTOR_SIZE) 946 != BC_SUCCESS || 947 write_out(device->part_fd, stage2->file + SECTOR_SIZE, 948 SECTOR_SIZE, stage2->pcfs_first_sectors[1] * SECTOR_SIZE) 949 != BC_SUCCESS) { 950 (void) fprintf(stderr, WRITE_FAIL_STAGE2); 951 return (BC_ERROR); 952 } 953 (void) fprintf(stdout, WRITE_STAGE2_PCFS); 954 return (BC_SUCCESS); 955 } 956 957 /* 958 * For disk, write stage2 starting at STAGE2_BLKOFF sector. 959 * Note that we use stage2->buf rather than stage2->file, because we 960 * may have extended information after the latter. 961 */ 962 offset = STAGE2_BLKOFF * SECTOR_SIZE; 963 if (write_out(device->part_fd, stage2->buf, stage2->buf_size, 964 offset) != BC_SUCCESS) { 965 perror("write"); 966 return (BC_ERROR); 967 } 968 969 /* Simulate the "old" installgrub output. */ 970 (void) fprintf(stdout, WRITE_STAGE2_DISK, device->partition, 971 (stage2->buf_size / SECTOR_SIZE) + 1, STAGE2_BLKOFF, 972 stage2->first_sector); 973 974 return (BC_SUCCESS); 975 } 976 977 static int 978 write_stage1(ig_data_t *install) 979 { 980 ig_device_t *device = &install->device; 981 982 assert(install != NULL); 983 984 if (write_out(device->part_fd, install->stage1_buf, 985 sizeof (install->stage1_buf), 0) != BC_SUCCESS) { 986 (void) fprintf(stdout, WRITE_FAIL_PBOOT); 987 perror("write"); 988 return (BC_ERROR); 989 } 990 991 /* Simulate "old" installgrub output. */ 992 (void) fprintf(stdout, WRITE_PBOOT, device->partition, 993 device->start_sector); 994 995 if (write_mbr) { 996 if (write_out(device->disk_fd, install->stage1_buf, 997 sizeof (install->stage1_buf), 0) != BC_SUCCESS) { 998 (void) fprintf(stdout, WRITE_FAIL_BOOTSEC); 999 perror("write"); 1000 return (BC_ERROR); 1001 } 1002 /* Simulate "old" installgrub output. */ 1003 (void) fprintf(stdout, WRITE_MBOOT); 1004 } 1005 1006 return (BC_SUCCESS); 1007 } 1008 1009 #define USAGE_STRING "%s [-m|-f|-n|-F|-u verstr] stage1 stage2 device\n" \ 1010 "%s -M [-n] device1 device2\n" \ 1011 "%s [-V|-e] -i device\n" \ 1012 1013 #define CANON_USAGE_STR gettext(USAGE_STRING) 1014 1015 static void 1016 usage(char *progname) 1017 { 1018 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname); 1019 } 1020 1021 1022 static int 1023 read_stage1_from_file(char *path, ig_data_t *dest) 1024 { 1025 int fd; 1026 1027 assert(dest); 1028 1029 /* read the stage1 file from filesystem */ 1030 fd = open(path, O_RDONLY); 1031 if (fd == -1 || 1032 read(fd, dest->stage1_buf, SECTOR_SIZE) != SECTOR_SIZE) { 1033 (void) fprintf(stderr, READ_FAIL_STAGE1, path); 1034 return (BC_ERROR); 1035 } 1036 (void) close(fd); 1037 return (BC_SUCCESS); 1038 } 1039 1040 static int 1041 read_stage2_from_file(char *path, ig_data_t *dest) 1042 { 1043 int fd; 1044 struct stat sb; 1045 ig_stage2_t *stage2 = &dest->stage2; 1046 ig_device_t *device = &dest->device; 1047 uint32_t buf_size; 1048 1049 assert(dest); 1050 assert(stage2->buf == NULL); 1051 1052 fd = open(path, O_RDONLY); 1053 if (fstat(fd, &sb) == -1) { 1054 perror("fstat"); 1055 goto out; 1056 } 1057 1058 stage2->file_size = sb.st_size; 1059 1060 if (!is_bootpar(device->type)) { 1061 /* 1062 * buffer size needs to account for stage2 plus the extra 1063 * versioning information at the end of it. We reserve one 1064 * extra sector (plus we round up to the next sector boundary). 1065 */ 1066 buf_size = stage2->file_size + SECTOR_SIZE; 1067 } else { 1068 /* In the PCFS case we only need to read in stage2. */ 1069 buf_size = stage2->file_size; 1070 } 1071 1072 stage2->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE); 1073 1074 BOOT_DEBUG("stage2 buffer size = %d (%d sectors)\n", stage2->buf_size, 1075 stage2->buf_size / SECTOR_SIZE); 1076 1077 stage2->buf = malloc(stage2->buf_size); 1078 if (stage2->buf == NULL) { 1079 perror(gettext("Memory allocation failed")); 1080 goto out_fd; 1081 } 1082 1083 stage2->file = stage2->buf; 1084 1085 /* 1086 * Extra information (e.g. the versioning structure) is placed at the 1087 * end of stage2, aligned on a 8-byte boundary. 1088 */ 1089 if (!(is_bootpar(device->type))) 1090 stage2->extra = stage2->file + P2ROUNDUP(stage2->file_size, 8); 1091 1092 if (lseek(fd, 0, SEEK_SET) == -1) { 1093 perror("lseek"); 1094 goto out_alloc; 1095 } 1096 1097 if (read(fd, stage2->file, stage2->file_size) < 0) { 1098 perror(gettext("unable to read stage2")); 1099 goto out_alloc; 1100 } 1101 1102 (void) close(fd); 1103 return (BC_SUCCESS); 1104 1105 out_alloc: 1106 free(stage2->buf); 1107 stage2->buf = NULL; 1108 out_fd: 1109 (void) close(fd); 1110 out: 1111 return (BC_ERROR); 1112 } 1113 1114 static int 1115 prepare_stage1(ig_data_t *install) 1116 { 1117 ig_device_t *device = &install->device; 1118 1119 assert(install != NULL); 1120 1121 /* If PCFS add the BIOS Parameter Block. */ 1122 if (is_bootpar(device->type)) { 1123 char bpb_sect[SECTOR_SIZE]; 1124 1125 if (pread(device->part_fd, bpb_sect, SECTOR_SIZE, 0) 1126 != SECTOR_SIZE) { 1127 (void) fprintf(stderr, READ_FAIL_BPB); 1128 return (BC_ERROR); 1129 } 1130 bcopy(bpb_sect + STAGE1_BPB_OFFSET, 1131 install->stage1_buf + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE); 1132 } 1133 1134 /* copy MBR to stage1 in case of overwriting MBR sector. */ 1135 bcopy(device->boot_sector + BOOTSZ, install->stage1_buf + BOOTSZ, 1136 SECTOR_SIZE - BOOTSZ); 1137 /* modify default stage1 file generated by GRUB. */ 1138 *((unsigned char *)(install->stage1_buf + STAGE1_FORCE_LBA)) = 1; 1139 *((ulong_t *)(install->stage1_buf + STAGE1_STAGE2_SECTOR)) 1140 = install->stage2.first_sector; 1141 *((ushort_t *)(install->stage1_buf + STAGE1_STAGE2_ADDRESS)) 1142 = STAGE2_MEMADDR; 1143 *((ushort_t *)(install->stage1_buf + STAGE1_STAGE2_SEGMENT)) 1144 = STAGE2_MEMADDR >> 4; 1145 1146 return (BC_SUCCESS); 1147 } 1148 1149 /* 1150 * Grab stage1 from the specified device file descriptor. 1151 */ 1152 static int 1153 read_stage1_from_disk(int dev_fd, char *stage1_buf) 1154 { 1155 assert(stage1_buf != NULL); 1156 1157 if (read_in(dev_fd, stage1_buf, SECTOR_SIZE, 0) != BC_SUCCESS) { 1158 perror(gettext("Unable to read stage1 from disk")); 1159 return (BC_ERROR); 1160 } 1161 return (BC_SUCCESS); 1162 } 1163 1164 static int 1165 read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2) 1166 { 1167 uint32_t size; 1168 uint32_t buf_size; 1169 uint32_t mboot_off; 1170 multiboot_header_t *mboot; 1171 1172 assert(stage2 != NULL); 1173 assert(dev_fd != -1); 1174 1175 if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan), 1176 STAGE2_BLKOFF * SECTOR_SIZE) != BC_SUCCESS) { 1177 perror(gettext("Error reading stage2 sectors")); 1178 return (BC_ERROR); 1179 } 1180 1181 /* No multiboot means no chance of knowing stage2 size */ 1182 if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off) 1183 != BC_SUCCESS) { 1184 BOOT_DEBUG("Unable to find multiboot header\n"); 1185 return (BC_NOEXTRA); 1186 } 1187 mboot = (multiboot_header_t *)(mboot_scan + mboot_off); 1188 1189 /* 1190 * Unfilled mboot values mean an older version of installgrub installed 1191 * the stage2. Again we have no chance of knowing stage2 size. 1192 */ 1193 if (mboot->load_end_addr == 0 || 1194 mboot->load_end_addr < mboot->load_addr) 1195 return (BC_NOEXTRA); 1196 1197 /* 1198 * Currently, the amount of space reserved for extra information 1199 * is "fixed". We may have to scan for the terminating extra payload 1200 * in the future. 1201 */ 1202 size = mboot->load_end_addr - mboot->load_addr; 1203 buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE); 1204 1205 stage2->buf = malloc(buf_size); 1206 if (stage2->buf == NULL) { 1207 perror(gettext("Memory allocation failed")); 1208 return (BC_ERROR); 1209 } 1210 stage2->buf_size = buf_size; 1211 1212 if (read_in(dev_fd, stage2->buf, buf_size, STAGE2_BLKOFF * 1213 SECTOR_SIZE) != BC_SUCCESS) { 1214 perror("read"); 1215 free(stage2->buf); 1216 return (BC_ERROR); 1217 } 1218 1219 /* Update pointers. */ 1220 stage2->file = stage2->buf; 1221 stage2->file_size = size; 1222 stage2->mboot_off = mboot_off; 1223 stage2->mboot = (multiboot_header_t *)(stage2->buf + stage2->mboot_off); 1224 stage2->extra = stage2->buf + P2ROUNDUP(stage2->file_size, 8); 1225 stage2->extra_size = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8); 1226 1227 return (BC_SUCCESS); 1228 } 1229 1230 static boolean_t 1231 is_update_necessary(ig_data_t *data, char *updt_str) 1232 { 1233 bblk_einfo_t *einfo; 1234 bblk_hs_t stage2_hs; 1235 ig_stage2_t stage2_disk; 1236 ig_stage2_t *stage2_file = &data->stage2; 1237 ig_device_t *device = &data->device; 1238 int dev_fd = device->part_fd; 1239 1240 assert(data != NULL); 1241 assert(device->part_fd != -1); 1242 1243 bzero(&stage2_disk, sizeof (ig_stage2_t)); 1244 1245 /* Gather stage2 (if present) from the target device. */ 1246 if (read_stage2_from_disk(dev_fd, &stage2_disk) != BC_SUCCESS) { 1247 BOOT_DEBUG("Unable to read stage2 from %s\n", device->path); 1248 BOOT_DEBUG("No multiboot wrapped stage2 on %s\n", device->path); 1249 return (B_TRUE); 1250 } 1251 1252 /* 1253 * Look for the extended information structure in the extra payload 1254 * area. 1255 */ 1256 einfo = find_einfo(stage2_disk.extra, stage2_disk.extra_size); 1257 if (einfo == NULL) { 1258 BOOT_DEBUG("No extended information available\n"); 1259 return (B_TRUE); 1260 } 1261 1262 if (!do_version || updt_str == NULL) { 1263 (void) fprintf(stdout, "WARNING: target device %s has a " 1264 "versioned stage2 that is going to be overwritten by a non " 1265 "versioned one\n", device->path); 1266 return (B_TRUE); 1267 } 1268 1269 if (force_update) { 1270 BOOT_DEBUG("Forcing update of %s bootblock\n", device->path); 1271 return (B_TRUE); 1272 } 1273 1274 /* Compare the two extended information structures. */ 1275 stage2_hs.src_buf = (unsigned char *)stage2_file->file; 1276 stage2_hs.src_size = stage2_file->file_size; 1277 1278 return (einfo_should_update(einfo, &stage2_hs, updt_str)); 1279 } 1280 1281 1282 #define START_BLOCK(pos) (*(ulong_t *)(pos)) 1283 #define NUM_BLOCK(pos) (*(ushort_t *)((pos) + 4)) 1284 #define START_SEG(pos) (*(ushort_t *)((pos) + 6)) 1285 1286 static int 1287 prepare_stage2(ig_data_t *install, char *updt_str) 1288 { 1289 ig_device_t *device = &install->device; 1290 ig_stage2_t *stage2 = &install->stage2; 1291 uint32_t mboot_off = 0; 1292 1293 assert(install != NULL); 1294 assert(stage2->file != NULL); 1295 1296 /* New stage2 files come with an embedded stage2. */ 1297 if (find_multiboot(stage2->file, stage2->file_size, &mboot_off) 1298 != BC_SUCCESS) { 1299 BOOT_DEBUG("WARNING: no multiboot structure found in stage2, " 1300 "are you using an old GRUB stage2?\n"); 1301 if (do_version == B_TRUE) { 1302 (void) fprintf(stderr, gettext("Versioning requested " 1303 "but stage2 does not support it.. skipping.\n")); 1304 do_version = B_FALSE; 1305 } 1306 } else { 1307 /* Keep track of where the multiboot header is. */ 1308 stage2->mboot_off = mboot_off; 1309 stage2->mboot = (multiboot_header_t *)(stage2->file + 1310 mboot_off); 1311 if (do_version) { 1312 /* 1313 * Adding stage2 information needs to happen before 1314 * we modify the copy of stage2 we have in memory, so 1315 * that the hashing reflects the one of the file. 1316 * An error here is not fatal. 1317 */ 1318 add_stage2_einfo(stage2, updt_str); 1319 } 1320 /* 1321 * Fill multiboot information. We add them even without 1322 * versioning to support as much as possible mirroring. 1323 */ 1324 prepare_fake_multiboot(stage2); 1325 } 1326 1327 if (is_bootpar(device->type)) { 1328 uint32_t blocklist[SECTOR_SIZE / sizeof (uint32_t)]; 1329 uint32_t install_addr = STAGE2_MEMADDR + SECTOR_SIZE; 1330 int i = 0; 1331 uchar_t *pos; 1332 1333 bzero(blocklist, sizeof (blocklist)); 1334 if (read_stage2_blocklist(device->part_fd, blocklist) != 0) { 1335 (void) fprintf(stderr, gettext("Error reading pcfs " 1336 "stage2 blocklist\n")); 1337 return (BC_ERROR); 1338 } 1339 1340 pos = (uchar_t *)stage2->file + STAGE2_BLOCKLIST; 1341 stage2->first_sector = device->start_sector + blocklist[0]; 1342 stage2->pcfs_first_sectors[0] = blocklist[0]; 1343 BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector); 1344 1345 1346 if (blocklist[1] > 1) { 1347 blocklist[0]++; 1348 blocklist[1]--; 1349 } else { 1350 i += 2; 1351 } 1352 1353 stage2->pcfs_first_sectors[1] = blocklist[i]; 1354 1355 while (blocklist[i]) { 1356 if (START_BLOCK(pos - 8) != 0 && 1357 START_BLOCK(pos - 8) != blocklist[i + 2]) { 1358 (void) fprintf(stderr, PCFS_FRAGMENTED); 1359 return (BC_ERROR); 1360 } 1361 START_BLOCK(pos) = blocklist[i] + device->start_sector; 1362 START_SEG(pos) = (ushort_t)(install_addr >> 4); 1363 NUM_BLOCK(pos) = blocklist[i + 1]; 1364 install_addr += blocklist[i + 1] * SECTOR_SIZE; 1365 pos -= 8; 1366 i += 2; 1367 } 1368 } else { 1369 /* Solaris VTOC */ 1370 stage2->first_sector = device->start_sector + STAGE2_BLKOFF; 1371 BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector); 1372 /* 1373 * In a solaris partition, stage2 is written to contiguous 1374 * blocks. So we update the starting block only. 1375 */ 1376 *((ulong_t *)(stage2->file + STAGE2_BLOCKLIST)) = 1377 stage2->first_sector + 1; 1378 } 1379 1380 /* force lba and set disk partition */ 1381 *((unsigned char *) (stage2->file + STAGE2_FORCE_LBA)) = 1; 1382 *((long *)(stage2->file + STAGE2_INSTALLPART)) 1383 = (device->partition << 16) | (device->slice << 8) | 0xff; 1384 1385 return (BC_SUCCESS); 1386 } 1387 1388 static int 1389 find_x86_bootpar(struct mboot *mboot, int *part_num, uint32_t *start_sect) 1390 { 1391 int i; 1392 1393 for (i = 0; i < FD_NUMPART; i++) { 1394 struct ipart *part; 1395 1396 part = (struct ipart *)mboot->parts + i; 1397 if (part->systid == 0xbe) { 1398 if (start_sect) 1399 *start_sect = part->relsect; 1400 if (part_num) 1401 *part_num = i; 1402 /* solaris boot part */ 1403 return (BC_SUCCESS); 1404 } 1405 } 1406 return (BC_ERROR); 1407 } 1408 1409 static char * 1410 get_raw_partition_path(ig_device_t *device) 1411 { 1412 char *raw; 1413 int len; 1414 1415 if (is_bootpar(device->type)) { 1416 int part; 1417 struct mboot *mboot; 1418 1419 mboot = (struct mboot *)device->boot_sector; 1420 if (find_x86_bootpar(mboot, &part, NULL) != BC_SUCCESS) { 1421 (void) fprintf(stderr, BOOTPAR_NOTFOUND, 1422 device->path_p0); 1423 return (NULL); 1424 } 1425 1426 raw = strdup(device->path_p0); 1427 if (raw == NULL) { 1428 perror(gettext("Memory allocation failed")); 1429 return (NULL); 1430 } 1431 1432 raw[strlen(raw) - 2] = '1' + part; 1433 return (raw); 1434 } 1435 1436 /* For disk, remember slice and return whole fdisk partition */ 1437 raw = strdup(device->path); 1438 if (raw == NULL) { 1439 perror(gettext("Memory allocation failed")); 1440 return (NULL); 1441 } 1442 1443 len = strlen(raw); 1444 if (raw[len - 2] != 's' || raw[len - 1] == '2') { 1445 (void) fprintf(stderr, NOT_ROOT_SLICE); 1446 free(raw); 1447 return (NULL); 1448 } 1449 device->slice = atoi(&raw[len - 1]); 1450 1451 raw[len - 2] = 's'; 1452 raw[len - 1] = '2'; 1453 1454 return (raw); 1455 } 1456 1457 static int 1458 get_raw_partition_fd(ig_device_t *device) 1459 { 1460 struct stat stat = {0}; 1461 char *raw; 1462 1463 raw = get_raw_partition_path(device); 1464 if (raw == NULL) 1465 return (BC_ERROR); 1466 1467 if (nowrite) 1468 device->part_fd = open(raw, O_RDONLY); 1469 else 1470 device->part_fd = open(raw, O_RDWR); 1471 1472 if (device->part_fd < 0 || fstat(device->part_fd, &stat) != 0) { 1473 (void) fprintf(stderr, OPEN_FAIL, raw); 1474 free(raw); 1475 return (BC_ERROR); 1476 } 1477 1478 if (S_ISCHR(stat.st_mode) == 0) { 1479 (void) fprintf(stderr, NOT_RAW_DEVICE, raw); 1480 (void) close(device->part_fd); 1481 device->part_fd = -1; 1482 free(raw); 1483 return (BC_ERROR); 1484 } 1485 1486 free(raw); 1487 return (BC_SUCCESS); 1488 } 1489 1490 #define TMP_MNTPT "/tmp/installgrub_pcfs" 1491 static int 1492 copy_stage2_to_pcfs(ig_data_t *install) 1493 { 1494 FILE *mntfp; 1495 int pcfs_fp; 1496 int status = BC_ERROR; 1497 char buf[SECTOR_SIZE]; 1498 char *cp; 1499 struct mnttab mp = {0}, mpref = {0}; 1500 ig_device_t *device = &install->device; 1501 ig_stage2_t *stage2 = &install->stage2; 1502 1503 /* convert raw to block device name by removing the first 'r' */ 1504 (void) strncpy(buf, device->path, sizeof (buf)); 1505 buf[sizeof (buf) - 1] = 0; 1506 cp = strchr(buf, 'r'); 1507 if (cp == NULL) { 1508 (void) fprintf(stderr, CONVERT_FAIL, device->path); 1509 return (BC_ERROR); 1510 } 1511 do { 1512 *cp = *(cp + 1); 1513 } while (*(++cp)); 1514 1515 /* get the mount point, if any */ 1516 mntfp = fopen("/etc/mnttab", "r"); 1517 if (mntfp == NULL) { 1518 (void) fprintf(stderr, OPEN_FAIL_FILE, "/etc/mnttab"); 1519 return (BC_ERROR); 1520 } 1521 1522 mpref.mnt_special = buf; 1523 if (getmntany(mntfp, &mp, &mpref) != 0) { 1524 char cmd[128]; 1525 1526 /* not mounted, try remount */ 1527 (void) mkdir(TMP_MNTPT, S_IRWXU); 1528 (void) snprintf(cmd, sizeof (cmd), "mount -F pcfs %s %s", 1529 buf, TMP_MNTPT); 1530 (void) system(cmd); 1531 rewind(mntfp); 1532 bzero(&mp, sizeof (mp)); 1533 if (getmntany(mntfp, &mp, &mpref) != 0) { 1534 (void) fprintf(stderr, MOUNT_FAIL, buf); 1535 return (BC_ERROR); 1536 } 1537 } 1538 1539 (void) snprintf(buf, sizeof (buf), 1540 "%s/boot", mp.mnt_mountp); 1541 (void) mkdir(buf, S_IRWXU); 1542 (void) strcat(buf, "/grub"); 1543 (void) mkdir(buf, S_IRWXU); 1544 1545 (void) strcat(buf, "/stage2"); 1546 pcfs_fp = open(buf, O_WRONLY | O_CREAT, S_IRWXU); 1547 if (pcfs_fp == -1) { 1548 (void) fprintf(stderr, OPEN_FAIL_FILE, buf); 1549 perror("open:"); 1550 goto out; 1551 } 1552 1553 /* write stage2 to the pcfs mounted filesystem. */ 1554 if (write(pcfs_fp, stage2->file, stage2->file_size) 1555 != stage2->file_size) { 1556 perror(gettext("Error writing stage2")); 1557 goto out; 1558 } 1559 1560 status = BC_SUCCESS; 1561 out_fd: 1562 (void) close(pcfs_fp); 1563 out: 1564 (void) umount(TMP_MNTPT); 1565 (void) rmdir(TMP_MNTPT); 1566 return (status); 1567 } 1568