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, stage2->extra_size);
 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, stage2_curr->extra_size);
 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         stage2->extra_size = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8);
1225 
1226         return (BC_SUCCESS);
1227 }
1228 
1229 static boolean_t
1230 is_update_necessary(ig_data_t *data, char *updt_str)
1231 {
1232         bblk_einfo_t    *einfo;
1233         bblk_hs_t       stage2_hs;
1234         ig_stage2_t     stage2_disk;
1235         ig_stage2_t     *stage2_file = &data->stage2;
1236         ig_device_t     *device = &data->device;
1237         int             dev_fd = device->part_fd;
1238 
1239         assert(data != NULL);
1240         assert(device->part_fd != -1);
1241 
1242         bzero(&stage2_disk, sizeof (ig_stage2_t));
1243 
1244         /* Gather stage2 (if present) from the target device. */
1245         if (read_stage2_from_disk(dev_fd, &stage2_disk) != BC_SUCCESS) {
1246                 BOOT_DEBUG("Unable to read stage2 from %s\n", device->path);
1247                 BOOT_DEBUG("No multiboot wrapped stage2 on %s\n", device->path);
1248                 return (B_TRUE);
1249         }
1250 
1251         /*
1252          * Look for the extended information structure in the extra payload
1253          * area.
1254          */
1255         einfo = find_einfo(stage2_disk.extra, stage2_disk.extra_size);
1256         if (einfo == NULL) {
1257                 BOOT_DEBUG("No extended information available\n");
1258                 return (B_TRUE);
1259         }
1260 
1261         if (!do_version || updt_str == NULL) {
1262                 (void) fprintf(stdout, "WARNING: target device %s has a "
1263                     "versioned stage2 that is going to be overwritten by a non "
1264                     "versioned one\n", device->path);
1265                 return (B_TRUE);
1266         }
1267 
1268         if (force_update) {
1269                 BOOT_DEBUG("Forcing update of %s bootblock\n", device->path);
1270                 return (B_TRUE);
1271         }
1272 
1273         /* Compare the two extended information structures. */
1274         stage2_hs.src_buf = (unsigned char *)stage2_file->file;
1275         stage2_hs.src_size = stage2_file->file_size;
1276 
1277         return (einfo_should_update(einfo, &stage2_hs, updt_str));
1278 }
1279 
1280 
1281 #define START_BLOCK(pos)        (*(ulong_t *)(pos))
1282 #define NUM_BLOCK(pos)          (*(ushort_t *)((pos) + 4))
1283 #define START_SEG(pos)          (*(ushort_t *)((pos) + 6))
1284 
1285 static int
1286 prepare_stage2(ig_data_t *install, char *updt_str)
1287 {
1288         ig_device_t     *device = &install->device;
1289         ig_stage2_t     *stage2 = &install->stage2;
1290         uint32_t        mboot_off = 0;
1291 
1292         assert(install != NULL);
1293         assert(stage2->file != NULL);
1294 
1295         /* New stage2 files come with an embedded stage2. */
1296         if (find_multiboot(stage2->file, stage2->file_size, &mboot_off)
1297             != BC_SUCCESS) {
1298                 BOOT_DEBUG("WARNING: no multiboot structure found in stage2, "
1299                     "are you using an old GRUB stage2?\n");
1300                 if (do_version == B_TRUE) {
1301                         (void) fprintf(stderr, gettext("Versioning requested "
1302                             "but stage2 does not support it.. skipping.\n"));
1303                         do_version = B_FALSE;
1304                 }
1305         } else {
1306                 /* Keep track of where the multiboot header is. */
1307                 stage2->mboot_off = mboot_off;
1308                 stage2->mboot = (multiboot_header_t *)(stage2->file +
1309                     mboot_off);
1310                 if (do_version) {
1311                         /*
1312                          * Adding stage2 information needs to happen before
1313                          * we modify the copy of stage2 we have in memory, so
1314                          * that the hashing reflects the one of the file.
1315                          * An error here is not fatal.
1316                          */
1317                         add_stage2_einfo(stage2, updt_str);
1318                 }
1319                 /*
1320                  * Fill multiboot information. We add them even without
1321                  * versioning to support as much as possible mirroring.
1322                  */
1323                 prepare_fake_multiboot(stage2);
1324         }
1325 
1326         if (is_bootpar(device->type)) {
1327                 uint32_t        blocklist[SECTOR_SIZE / sizeof (uint32_t)];
1328                 uint32_t        install_addr = STAGE2_MEMADDR + SECTOR_SIZE;
1329                 int             i = 0;
1330                 uchar_t         *pos;
1331 
1332                 bzero(blocklist, sizeof (blocklist));
1333                 if (read_stage2_blocklist(device->part_fd, blocklist) != 0) {
1334                         (void) fprintf(stderr, gettext("Error reading pcfs "
1335                             "stage2 blocklist\n"));
1336                         return (BC_ERROR);
1337                 }
1338 
1339                 pos = (uchar_t *)stage2->file + STAGE2_BLOCKLIST;
1340                 stage2->first_sector = device->start_sector + blocklist[0];
1341                 stage2->pcfs_first_sectors[0] = blocklist[0];
1342                 BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
1343 
1344 
1345                 if (blocklist[1] > 1) {
1346                         blocklist[0]++;
1347                         blocklist[1]--;
1348                 } else {
1349                         i += 2;
1350                 }
1351 
1352                 stage2->pcfs_first_sectors[1] = blocklist[i];
1353 
1354                 while (blocklist[i]) {
1355                         if (START_BLOCK(pos - 8) != 0 &&
1356                             START_BLOCK(pos - 8) != blocklist[i + 2]) {
1357                                 (void) fprintf(stderr, PCFS_FRAGMENTED);
1358                                 return (BC_ERROR);
1359                         }
1360                         START_BLOCK(pos) = blocklist[i] + device->start_sector;
1361                         START_SEG(pos) = (ushort_t)(install_addr >> 4);
1362                         NUM_BLOCK(pos) = blocklist[i + 1];
1363                         install_addr += blocklist[i + 1] * SECTOR_SIZE;
1364                         pos -= 8;
1365                         i += 2;
1366                 }
1367         } else {
1368                 /* Solaris VTOC */
1369                 stage2->first_sector = device->start_sector + STAGE2_BLKOFF;
1370                 BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
1371                 /*
1372                  * In a solaris partition, stage2 is written to contiguous
1373                  * blocks. So we update the starting block only.
1374                  */
1375                 *((ulong_t *)(stage2->file + STAGE2_BLOCKLIST)) =
1376                     stage2->first_sector + 1;
1377         }
1378 
1379         /* force lba and set disk partition */
1380         *((unsigned char *) (stage2->file + STAGE2_FORCE_LBA)) = 1;
1381         *((long *)(stage2->file + STAGE2_INSTALLPART))
1382             = (device->partition << 16) | (device->slice << 8) | 0xff;
1383 
1384         return (BC_SUCCESS);
1385 }
1386 
1387 static int
1388 find_x86_bootpar(struct mboot *mboot, int *part_num, uint32_t *start_sect)
1389 {
1390         int     i;
1391 
1392         for (i = 0; i < FD_NUMPART; i++) {
1393                 struct ipart    *part;
1394 
1395                 part = (struct ipart *)mboot->parts + i;
1396                 if (part->systid == 0xbe) {
1397                         if (start_sect)
1398                                 *start_sect = part->relsect;
1399                         if (part_num)
1400                                 *part_num = i;
1401                         /* solaris boot part */
1402                         return (BC_SUCCESS);
1403                 }
1404         }
1405         return (BC_ERROR);
1406 }
1407 
1408 static char *
1409 get_raw_partition_path(ig_device_t *device)
1410 {
1411         char    *raw;
1412         int     len;
1413 
1414         if (is_bootpar(device->type)) {
1415                 int             part;
1416                 struct mboot    *mboot;
1417 
1418                 mboot = (struct mboot *)device->boot_sector;
1419                 if (find_x86_bootpar(mboot, &part, NULL) != BC_SUCCESS) {
1420                         (void) fprintf(stderr, BOOTPAR_NOTFOUND,
1421                             device->path_p0);
1422                         return (NULL);
1423                 }
1424 
1425                 raw = strdup(device->path_p0);
1426                 if (raw == NULL) {
1427                         perror(gettext("Memory allocation failed"));
1428                         return (NULL);
1429                 }
1430 
1431                 raw[strlen(raw) - 2] = '1' + part;
1432                 return (raw);
1433         }
1434 
1435         /* For disk, remember slice and return whole fdisk partition  */
1436         raw = strdup(device->path);
1437         if (raw == NULL) {
1438                 perror(gettext("Memory allocation failed"));
1439                 return (NULL);
1440         }
1441 
1442         len = strlen(raw);
1443         if (raw[len - 2] != 's' || raw[len - 1] == '2') {
1444                 (void) fprintf(stderr, NOT_ROOT_SLICE);
1445                 free(raw);
1446                 return (NULL);
1447         }
1448         device->slice = atoi(&raw[len - 1]);
1449 
1450         raw[len - 2] = 's';
1451         raw[len - 1] = '2';
1452 
1453         return (raw);
1454 }
1455 
1456 static int
1457 get_raw_partition_fd(ig_device_t *device)
1458 {
1459         struct stat     stat = {0};
1460         char            *raw;
1461 
1462         raw = get_raw_partition_path(device);
1463         if (raw == NULL)
1464                 return (BC_ERROR);
1465 
1466         if (nowrite)
1467                 device->part_fd = open(raw, O_RDONLY);
1468         else
1469                 device->part_fd = open(raw, O_RDWR);
1470 
1471         if (device->part_fd < 0 || fstat(device->part_fd, &stat) != 0) {
1472                 (void) fprintf(stderr, OPEN_FAIL, raw);
1473                 free(raw);
1474                 return (BC_ERROR);
1475         }
1476 
1477         if (S_ISCHR(stat.st_mode) == 0) {
1478                 (void) fprintf(stderr, NOT_RAW_DEVICE, raw);
1479                 (void) close(device->part_fd);
1480                 device->part_fd = -1;
1481                 free(raw);
1482                 return (BC_ERROR);
1483         }
1484 
1485         free(raw);
1486         return (BC_SUCCESS);
1487 }
1488 
1489 #define TMP_MNTPT       "/tmp/installgrub_pcfs"
1490 static int
1491 copy_stage2_to_pcfs(ig_data_t *install)
1492 {
1493         FILE            *mntfp;
1494         int             pcfs_fp;
1495         int             status = BC_ERROR;
1496         char            buf[SECTOR_SIZE];
1497         char            *cp;
1498         struct mnttab   mp = {0}, mpref = {0};
1499         ig_device_t     *device = &install->device;
1500         ig_stage2_t     *stage2 = &install->stage2;
1501 
1502         /* convert raw to block device name by removing the first 'r' */
1503         (void) strncpy(buf, device->path, sizeof (buf));
1504         buf[sizeof (buf) - 1] = 0;
1505         cp = strchr(buf, 'r');
1506         if (cp == NULL) {
1507                 (void) fprintf(stderr, CONVERT_FAIL, device->path);
1508                 return (BC_ERROR);
1509         }
1510         do {
1511                 *cp = *(cp + 1);
1512         } while (*(++cp));
1513 
1514         /* get the mount point, if any */
1515         mntfp = fopen("/etc/mnttab", "r");
1516         if (mntfp == NULL) {
1517                 (void) fprintf(stderr, OPEN_FAIL_FILE, "/etc/mnttab");
1518                 return (BC_ERROR);
1519         }
1520 
1521         mpref.mnt_special = buf;
1522         if (getmntany(mntfp, &mp, &mpref) != 0) {
1523                 char cmd[128];
1524 
1525                 /* not mounted, try remount */
1526                 (void) mkdir(TMP_MNTPT, S_IRWXU);
1527                 (void) snprintf(cmd, sizeof (cmd), "mount -F pcfs %s %s",
1528                     buf, TMP_MNTPT);
1529                 (void) system(cmd);
1530                 rewind(mntfp);
1531                 bzero(&mp, sizeof (mp));
1532                 if (getmntany(mntfp, &mp, &mpref) != 0) {
1533                         (void) fprintf(stderr, MOUNT_FAIL, buf);
1534                         return (BC_ERROR);
1535                 }
1536         }
1537 
1538         (void) snprintf(buf, sizeof (buf),
1539             "%s/boot", mp.mnt_mountp);
1540         (void) mkdir(buf, S_IRWXU);
1541         (void) strcat(buf, "/grub");
1542         (void) mkdir(buf, S_IRWXU);
1543 
1544         (void) strcat(buf, "/stage2");
1545         pcfs_fp = open(buf, O_WRONLY | O_CREAT, S_IRWXU);
1546         if (pcfs_fp == -1) {
1547                 (void) fprintf(stderr, OPEN_FAIL_FILE, buf);
1548                 perror("open:");
1549                 goto out;
1550         }
1551 
1552         /* write stage2 to the pcfs mounted filesystem. */
1553         if (write(pcfs_fp, stage2->file, stage2->file_size)
1554             != stage2->file_size) {
1555                 perror(gettext("Error writing stage2"));
1556                 goto out;
1557         }
1558 
1559         status = BC_SUCCESS;
1560 out_fd:
1561         (void) close(pcfs_fp);
1562 out:
1563         (void) umount(TMP_MNTPT);
1564         (void) rmdir(TMP_MNTPT);
1565         return (status);
1566 }