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