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