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