xref: /onnv-gate/usr/src/cmd/boot/installgrub/installgrub.c (revision 12947:f5f96e09bf49)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55589Ssy25831  * Common Development and Distribution License (the "License").
65589Ssy25831  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12947SEnrico.Perla@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <stdio.h>
260Sstevel@tonic-gate #include <stdlib.h>
270Sstevel@tonic-gate #include <libgen.h>
280Sstevel@tonic-gate #include <malloc.h>
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate #include <fcntl.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <strings.h>
33*12947SEnrico.Perla@Sun.COM #include <libintl.h>
34*12947SEnrico.Perla@Sun.COM #include <locale.h>
35*12947SEnrico.Perla@Sun.COM #include <errno.h>
36*12947SEnrico.Perla@Sun.COM #include <libfdisk.h>
37*12947SEnrico.Perla@Sun.COM #include <stdarg.h>
38*12947SEnrico.Perla@Sun.COM #include <assert.h>
39*12947SEnrico.Perla@Sun.COM 
400Sstevel@tonic-gate #include <sys/mount.h>
410Sstevel@tonic-gate #include <sys/mnttab.h>
420Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
435589Ssy25831 #include <sys/dkio.h>
445589Ssy25831 #include <sys/vtoc.h>
45*12947SEnrico.Perla@Sun.COM #include <sys/types.h>
46*12947SEnrico.Perla@Sun.COM #include <sys/stat.h>
47*12947SEnrico.Perla@Sun.COM #include <sys/multiboot.h>
48*12947SEnrico.Perla@Sun.COM #include <sys/sysmacros.h>
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include "message.h"
51*12947SEnrico.Perla@Sun.COM #include "installgrub.h"
52*12947SEnrico.Perla@Sun.COM #include "./../common/bblk_einfo.h"
53*12947SEnrico.Perla@Sun.COM #include "./../common/boot_utils.h"
54*12947SEnrico.Perla@Sun.COM #include "./../common/mboot_extra.h"
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #ifndef	TEXT_DOMAIN
570Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
580Sstevel@tonic-gate #endif
590Sstevel@tonic-gate 
60*12947SEnrico.Perla@Sun.COM /*
61*12947SEnrico.Perla@Sun.COM  * Variables to track installgrub desired mode of operation.
62*12947SEnrico.Perla@Sun.COM  * 'nowrite' and 'boot_debug' come from boot_common.h.
63*12947SEnrico.Perla@Sun.COM  */
64*12947SEnrico.Perla@Sun.COM static boolean_t write_mbr = B_FALSE;
65*12947SEnrico.Perla@Sun.COM static boolean_t force_mbr = B_FALSE;
66*12947SEnrico.Perla@Sun.COM static boolean_t force_update = B_FALSE;
67*12947SEnrico.Perla@Sun.COM static boolean_t do_getinfo = B_FALSE;
68*12947SEnrico.Perla@Sun.COM static boolean_t do_version = B_FALSE;
69*12947SEnrico.Perla@Sun.COM static boolean_t do_mirror_bblk = B_FALSE;
70*12947SEnrico.Perla@Sun.COM static boolean_t strip = B_FALSE;
71*12947SEnrico.Perla@Sun.COM static boolean_t verbose_dump = B_FALSE;
720Sstevel@tonic-gate 
73*12947SEnrico.Perla@Sun.COM /* Installing the bootblock is the default operation. */
74*12947SEnrico.Perla@Sun.COM static boolean_t do_install = B_TRUE;
75*12947SEnrico.Perla@Sun.COM 
76*12947SEnrico.Perla@Sun.COM /* Versioning string, if present. */
77*12947SEnrico.Perla@Sun.COM static char *update_str;
780Sstevel@tonic-gate 
79*12947SEnrico.Perla@Sun.COM /*
80*12947SEnrico.Perla@Sun.COM  * Temporary buffer to store the first 32K of data looking for a multiboot
81*12947SEnrico.Perla@Sun.COM  * signature.
82*12947SEnrico.Perla@Sun.COM  */
83*12947SEnrico.Perla@Sun.COM char	mboot_scan[MBOOT_SCAN_SIZE];
848434SEnrico.Perla@Sun.COM 
85*12947SEnrico.Perla@Sun.COM /* Function prototypes. */
86*12947SEnrico.Perla@Sun.COM static void check_options(char *);
87*12947SEnrico.Perla@Sun.COM static int handle_install(char *, char **);
88*12947SEnrico.Perla@Sun.COM static int handle_mirror(char *, char **);
89*12947SEnrico.Perla@Sun.COM static int handle_getinfo(char *, char **);
90*12947SEnrico.Perla@Sun.COM static int commit_to_disk(ig_data_t *, char *);
91*12947SEnrico.Perla@Sun.COM static int init_device(ig_device_t *, char *path);
92*12947SEnrico.Perla@Sun.COM static void cleanup_device(ig_device_t *);
93*12947SEnrico.Perla@Sun.COM static void cleanup_stage2(ig_stage2_t *);
94*12947SEnrico.Perla@Sun.COM static int get_start_sector(ig_device_t *);
95*12947SEnrico.Perla@Sun.COM static int get_disk_fd(ig_device_t *device);
96*12947SEnrico.Perla@Sun.COM static int get_raw_partition_fd(ig_device_t *);
97*12947SEnrico.Perla@Sun.COM static char *get_raw_partition_path(ig_device_t *);
98*12947SEnrico.Perla@Sun.COM static boolean_t gather_stage2_from_dev(ig_data_t *);
99*12947SEnrico.Perla@Sun.COM static int propagate_bootblock(ig_data_t *, ig_data_t *, char *);
100*12947SEnrico.Perla@Sun.COM static int find_x86_bootpar(struct mboot *, int *, uint32_t *);
101*12947SEnrico.Perla@Sun.COM static int copy_stage2_to_pcfs(ig_data_t *);
102*12947SEnrico.Perla@Sun.COM static int write_stage2(ig_data_t *);
103*12947SEnrico.Perla@Sun.COM static int write_stage1(ig_data_t *);
1040Sstevel@tonic-gate static void usage(char *);
105*12947SEnrico.Perla@Sun.COM static int read_stage1_from_file(char *, ig_data_t *);
106*12947SEnrico.Perla@Sun.COM static int read_stage2_from_file(char *, ig_data_t *);
107*12947SEnrico.Perla@Sun.COM static int read_stage1_from_disk(int, char *);
108*12947SEnrico.Perla@Sun.COM static int read_stage2_from_disk(int, ig_stage2_t *);
109*12947SEnrico.Perla@Sun.COM static int prepare_stage1(ig_data_t *);
110*12947SEnrico.Perla@Sun.COM static int prepare_stage2(ig_data_t *, char *);
111*12947SEnrico.Perla@Sun.COM static void prepare_fake_multiboot(ig_stage2_t *);
112*12947SEnrico.Perla@Sun.COM static void add_stage2_einfo(ig_stage2_t *, char *updt_str);
113*12947SEnrico.Perla@Sun.COM static boolean_t is_update_necessary(ig_data_t *, char *);
1140Sstevel@tonic-gate 
1157563SPrasad.Singamsetty@Sun.COM extern int read_stage2_blocklist(int, unsigned int *);
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate int
main(int argc,char * argv[])1180Sstevel@tonic-gate main(int argc, char *argv[])
1190Sstevel@tonic-gate {
120*12947SEnrico.Perla@Sun.COM 	int	opt;
121*12947SEnrico.Perla@Sun.COM 	int	params = 3;
122*12947SEnrico.Perla@Sun.COM 	int	ret;
123*12947SEnrico.Perla@Sun.COM 	char	**handle_args;
124*12947SEnrico.Perla@Sun.COM 	char	*progname;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1270Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1280Sstevel@tonic-gate 
129*12947SEnrico.Perla@Sun.COM 	/*
130*12947SEnrico.Perla@Sun.COM 	 * retro-compatibility: installing the bootblock is the default
131*12947SEnrico.Perla@Sun.COM 	 * and there is no switch for it.
132*12947SEnrico.Perla@Sun.COM 	 */
133*12947SEnrico.Perla@Sun.COM 	do_install = B_TRUE;
134*12947SEnrico.Perla@Sun.COM 
135*12947SEnrico.Perla@Sun.COM 	while ((opt = getopt(argc, argv, "dVMFfmneiu:")) != EOF) {
1360Sstevel@tonic-gate 		switch (opt) {
1370Sstevel@tonic-gate 		case 'm':
138*12947SEnrico.Perla@Sun.COM 			write_mbr = B_TRUE;
1390Sstevel@tonic-gate 			break;
1400Sstevel@tonic-gate 		case 'n':
141*12947SEnrico.Perla@Sun.COM 			nowrite = B_TRUE;
1420Sstevel@tonic-gate 			break;
1430Sstevel@tonic-gate 		case 'f':
144*12947SEnrico.Perla@Sun.COM 			force_mbr = B_TRUE;
1450Sstevel@tonic-gate 			break;
1468434SEnrico.Perla@Sun.COM 		case 'i':
147*12947SEnrico.Perla@Sun.COM 			do_getinfo = B_TRUE;
148*12947SEnrico.Perla@Sun.COM 			do_install = B_FALSE;
1498434SEnrico.Perla@Sun.COM 			params = 1;
1508434SEnrico.Perla@Sun.COM 			break;
151*12947SEnrico.Perla@Sun.COM 		case 'V':
152*12947SEnrico.Perla@Sun.COM 			verbose_dump = B_TRUE;
153*12947SEnrico.Perla@Sun.COM 			break;
154*12947SEnrico.Perla@Sun.COM 		case 'd':
155*12947SEnrico.Perla@Sun.COM 			boot_debug = B_TRUE;
156*12947SEnrico.Perla@Sun.COM 			break;
157*12947SEnrico.Perla@Sun.COM 		case 'F':
158*12947SEnrico.Perla@Sun.COM 			force_update = B_TRUE;
159*12947SEnrico.Perla@Sun.COM 			break;
1608434SEnrico.Perla@Sun.COM 		case 'e':
161*12947SEnrico.Perla@Sun.COM 			strip = B_TRUE;
162*12947SEnrico.Perla@Sun.COM 			break;
163*12947SEnrico.Perla@Sun.COM 		case 'M':
164*12947SEnrico.Perla@Sun.COM 			do_mirror_bblk = B_TRUE;
165*12947SEnrico.Perla@Sun.COM 			do_install = B_FALSE;
166*12947SEnrico.Perla@Sun.COM 			params = 2;
1678434SEnrico.Perla@Sun.COM 			break;
168*12947SEnrico.Perla@Sun.COM 		case 'u':
169*12947SEnrico.Perla@Sun.COM 			do_version = B_TRUE;
170*12947SEnrico.Perla@Sun.COM 
171*12947SEnrico.Perla@Sun.COM 			update_str = malloc(strlen(optarg) + 1);
172*12947SEnrico.Perla@Sun.COM 			if (update_str == NULL) {
173*12947SEnrico.Perla@Sun.COM 				(void) fprintf(stderr, gettext("Unable to "
174*12947SEnrico.Perla@Sun.COM 				    "allocate memory\n"));
175*12947SEnrico.Perla@Sun.COM 				exit(BC_ERROR);
176*12947SEnrico.Perla@Sun.COM 			}
177*12947SEnrico.Perla@Sun.COM 			(void) strlcpy(update_str, optarg, strlen(optarg) + 1);
1788434SEnrico.Perla@Sun.COM 			break;
1790Sstevel@tonic-gate 		default:
1800Sstevel@tonic-gate 			/* fall through to process non-optional args */
1810Sstevel@tonic-gate 			break;
1820Sstevel@tonic-gate 		}
1830Sstevel@tonic-gate 	}
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	/* check arguments */
1868434SEnrico.Perla@Sun.COM 	if (argc != optind + params) {
1870Sstevel@tonic-gate 		usage(argv[0]);
188*12947SEnrico.Perla@Sun.COM 		exit(BC_ERROR);
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 
191*12947SEnrico.Perla@Sun.COM 	/*
192*12947SEnrico.Perla@Sun.COM 	 * clean up options (and bail out if an unrecoverable combination is
193*12947SEnrico.Perla@Sun.COM 	 * requested.
194*12947SEnrico.Perla@Sun.COM 	 */
195*12947SEnrico.Perla@Sun.COM 	progname = argv[0];
196*12947SEnrico.Perla@Sun.COM 	check_options(progname);
197*12947SEnrico.Perla@Sun.COM 	handle_args = argv + optind;
198*12947SEnrico.Perla@Sun.COM 
199*12947SEnrico.Perla@Sun.COM 	if (nowrite)
200*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, DRY_RUN);
201*12947SEnrico.Perla@Sun.COM 
202*12947SEnrico.Perla@Sun.COM 	if (do_getinfo) {
203*12947SEnrico.Perla@Sun.COM 		ret = handle_getinfo(progname, handle_args);
204*12947SEnrico.Perla@Sun.COM 	} else if (do_mirror_bblk) {
205*12947SEnrico.Perla@Sun.COM 		ret = handle_mirror(progname, handle_args);
206*12947SEnrico.Perla@Sun.COM 	} else {
207*12947SEnrico.Perla@Sun.COM 		ret = handle_install(progname, handle_args);
208*12947SEnrico.Perla@Sun.COM 	}
209*12947SEnrico.Perla@Sun.COM 	return (ret);
210*12947SEnrico.Perla@Sun.COM }
211*12947SEnrico.Perla@Sun.COM 
212*12947SEnrico.Perla@Sun.COM #define	MEANINGLESS_OPT	gettext("%s specified but meaningless, ignoring\n")
213*12947SEnrico.Perla@Sun.COM static void
check_options(char * progname)214*12947SEnrico.Perla@Sun.COM check_options(char *progname)
215*12947SEnrico.Perla@Sun.COM {
216*12947SEnrico.Perla@Sun.COM 	if (do_getinfo && do_mirror_bblk) {
217*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Only one of -M and -i can be "
218*12947SEnrico.Perla@Sun.COM 		    "specified at the same time\n"));
219*12947SEnrico.Perla@Sun.COM 		usage(progname);
220*12947SEnrico.Perla@Sun.COM 		exit(BC_ERROR);
221*12947SEnrico.Perla@Sun.COM 	}
222*12947SEnrico.Perla@Sun.COM 
223*12947SEnrico.Perla@Sun.COM 	if (do_mirror_bblk) {
224*12947SEnrico.Perla@Sun.COM 		/*
225*12947SEnrico.Perla@Sun.COM 		 * -u and -F may actually reflect a user intent that is not
226*12947SEnrico.Perla@Sun.COM 		 * correct with this command (mirror can be interpreted
227*12947SEnrico.Perla@Sun.COM 		 * "similar" to install. Emit a message and continue.
228*12947SEnrico.Perla@Sun.COM 		 * -e and -V have no meaning, be quiet here and only report the
229*12947SEnrico.Perla@Sun.COM 		 * incongruence if a debug output is requested.
230*12947SEnrico.Perla@Sun.COM 		 */
231*12947SEnrico.Perla@Sun.COM 		if (do_version) {
232*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stderr, MEANINGLESS_OPT, "-u");
233*12947SEnrico.Perla@Sun.COM 			do_version = B_FALSE;
2348434SEnrico.Perla@Sun.COM 		}
235*12947SEnrico.Perla@Sun.COM 		if (force_update) {
236*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stderr, MEANINGLESS_OPT, "-F");
237*12947SEnrico.Perla@Sun.COM 			force_update = B_FALSE;
238*12947SEnrico.Perla@Sun.COM 		}
239*12947SEnrico.Perla@Sun.COM 		if (strip || verbose_dump) {
240*12947SEnrico.Perla@Sun.COM 			BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V");
241*12947SEnrico.Perla@Sun.COM 			strip = B_FALSE;
242*12947SEnrico.Perla@Sun.COM 			verbose_dump = B_FALSE;
2438434SEnrico.Perla@Sun.COM 		}
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 
246*12947SEnrico.Perla@Sun.COM 	if (do_getinfo) {
247*12947SEnrico.Perla@Sun.COM 		if (write_mbr || force_mbr || do_version || force_update) {
248*12947SEnrico.Perla@Sun.COM 			BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F");
249*12947SEnrico.Perla@Sun.COM 			write_mbr = force_mbr = do_version = B_FALSE;
250*12947SEnrico.Perla@Sun.COM 			force_update = B_FALSE;
251*12947SEnrico.Perla@Sun.COM 		}
252*12947SEnrico.Perla@Sun.COM 	}
253*12947SEnrico.Perla@Sun.COM }
254*12947SEnrico.Perla@Sun.COM 
255*12947SEnrico.Perla@Sun.COM /*
256*12947SEnrico.Perla@Sun.COM  * Install a new stage1/stage2 pair on the specified device. handle_install()
257*12947SEnrico.Perla@Sun.COM  * expects argv to contain 3 parameters (the path to stage1, the path to stage2,
258*12947SEnrico.Perla@Sun.COM  * the target device).
259*12947SEnrico.Perla@Sun.COM  *
260*12947SEnrico.Perla@Sun.COM  * Returns:	BC_SUCCESS - if the installation is successful
261*12947SEnrico.Perla@Sun.COM  *		BC_ERROR   - if the installation failed
262*12947SEnrico.Perla@Sun.COM  *		BC_NOUPDT  - if no installation was performed because the GRUB
263*12947SEnrico.Perla@Sun.COM  *		             version currently installed is more recent than the
264*12947SEnrico.Perla@Sun.COM  *			     supplied one.
265*12947SEnrico.Perla@Sun.COM  *
266*12947SEnrico.Perla@Sun.COM  */
267*12947SEnrico.Perla@Sun.COM static int
handle_install(char * progname,char ** argv)268*12947SEnrico.Perla@Sun.COM handle_install(char *progname, char **argv)
269*12947SEnrico.Perla@Sun.COM {
270*12947SEnrico.Perla@Sun.COM 	ig_data_t	install_data;
271*12947SEnrico.Perla@Sun.COM 	char		*stage1_path = NULL;
272*12947SEnrico.Perla@Sun.COM 	char		*stage2_path = NULL;
273*12947SEnrico.Perla@Sun.COM 	char		*device_path = NULL;
274*12947SEnrico.Perla@Sun.COM 	int		ret = BC_ERROR;
2750Sstevel@tonic-gate 
276*12947SEnrico.Perla@Sun.COM 	stage1_path = strdup(argv[0]);
277*12947SEnrico.Perla@Sun.COM 	stage2_path = strdup(argv[1]);
278*12947SEnrico.Perla@Sun.COM 	device_path = strdup(argv[2]);
279*12947SEnrico.Perla@Sun.COM 
280*12947SEnrico.Perla@Sun.COM 	bzero(&install_data, sizeof (ig_data_t));
281*12947SEnrico.Perla@Sun.COM 
282*12947SEnrico.Perla@Sun.COM 	if (!stage1_path || !stage2_path || !device_path) {
283*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Missing parameter"));
284*12947SEnrico.Perla@Sun.COM 		usage(progname);
285*12947SEnrico.Perla@Sun.COM 		goto out;
286*12947SEnrico.Perla@Sun.COM 	}
287*12947SEnrico.Perla@Sun.COM 
288*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("stage1 path: %s, stage2 path: %s, device: %s\n",
289*12947SEnrico.Perla@Sun.COM 	    stage1_path, stage2_path, device_path);
290*12947SEnrico.Perla@Sun.COM 
291*12947SEnrico.Perla@Sun.COM 	if (init_device(&install_data.device, device_path) != BC_SUCCESS) {
292*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Unable to gather device "
293*12947SEnrico.Perla@Sun.COM 		    "information for %s\n"), device_path);
294*12947SEnrico.Perla@Sun.COM 		goto out;
295*12947SEnrico.Perla@Sun.COM 	}
296*12947SEnrico.Perla@Sun.COM 
297*12947SEnrico.Perla@Sun.COM 	/* read in stage1 and stage2. */
298*12947SEnrico.Perla@Sun.COM 	if (read_stage1_from_file(stage1_path, &install_data) != BC_SUCCESS) {
299*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error opening %s\n"),
300*12947SEnrico.Perla@Sun.COM 		    stage1_path);
301*12947SEnrico.Perla@Sun.COM 		goto out_dev;
302*12947SEnrico.Perla@Sun.COM 	}
303*12947SEnrico.Perla@Sun.COM 
304*12947SEnrico.Perla@Sun.COM 	if (read_stage2_from_file(stage2_path, &install_data) != BC_SUCCESS) {
305*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error opening %s\n"),
306*12947SEnrico.Perla@Sun.COM 		    stage2_path);
307*12947SEnrico.Perla@Sun.COM 		goto out_dev;
3088434SEnrico.Perla@Sun.COM 	}
3098434SEnrico.Perla@Sun.COM 
310*12947SEnrico.Perla@Sun.COM 	/* We do not support versioning on PCFS. */
311*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(install_data.device.type) && do_version)
312*12947SEnrico.Perla@Sun.COM 		do_version = B_FALSE;
313*12947SEnrico.Perla@Sun.COM 
314*12947SEnrico.Perla@Sun.COM 	/*
315*12947SEnrico.Perla@Sun.COM 	 * is_update_necessary() will take care of checking if versioning and/or
316*12947SEnrico.Perla@Sun.COM 	 * forcing the update have been specified. It will also emit a warning
317*12947SEnrico.Perla@Sun.COM 	 * if a non-versioned update is attempted over a versioned bootblock.
318*12947SEnrico.Perla@Sun.COM 	 */
319*12947SEnrico.Perla@Sun.COM 	if (!is_update_necessary(&install_data, update_str)) {
320*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("GRUB version installed "
321*12947SEnrico.Perla@Sun.COM 		    "on %s is more recent or identical\n"
322*12947SEnrico.Perla@Sun.COM 		    "Use -F to override or install without the -u option\n"),
323*12947SEnrico.Perla@Sun.COM 		    device_path);
324*12947SEnrico.Perla@Sun.COM 		ret = BC_NOUPDT;
325*12947SEnrico.Perla@Sun.COM 		goto out_dev;
326*12947SEnrico.Perla@Sun.COM 	}
327*12947SEnrico.Perla@Sun.COM 	/*
328*12947SEnrico.Perla@Sun.COM 	 * We get here if:
329*12947SEnrico.Perla@Sun.COM 	 * - the installed GRUB version is older than the one about to be
330*12947SEnrico.Perla@Sun.COM 	 *   installed.
331*12947SEnrico.Perla@Sun.COM 	 * - no versioning string has been passed through the command line.
332*12947SEnrico.Perla@Sun.COM 	 * - a forced update is requested (-F).
333*12947SEnrico.Perla@Sun.COM 	 */
334*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("Ready to commit to disk\n");
335*12947SEnrico.Perla@Sun.COM 	ret = commit_to_disk(&install_data, update_str);
336*12947SEnrico.Perla@Sun.COM 
337*12947SEnrico.Perla@Sun.COM out_dev:
338*12947SEnrico.Perla@Sun.COM 	cleanup_device(&install_data.device);
339*12947SEnrico.Perla@Sun.COM out:
340*12947SEnrico.Perla@Sun.COM 	free(stage1_path);
341*12947SEnrico.Perla@Sun.COM 	free(stage2_path);
342*12947SEnrico.Perla@Sun.COM 	free(device_path);
343*12947SEnrico.Perla@Sun.COM 	return (ret);
344*12947SEnrico.Perla@Sun.COM }
345*12947SEnrico.Perla@Sun.COM 
346*12947SEnrico.Perla@Sun.COM /*
347*12947SEnrico.Perla@Sun.COM  * Retrieves from a device the extended information (einfo) associated to the
348*12947SEnrico.Perla@Sun.COM  * installed stage2.
349*12947SEnrico.Perla@Sun.COM  * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0.
350*12947SEnrico.Perla@Sun.COM  * Returns:
351*12947SEnrico.Perla@Sun.COM  *        - BC_SUCCESS (and prints out einfo contents depending on 'flags')
352*12947SEnrico.Perla@Sun.COM  *	  - BC_ERROR (on error)
353*12947SEnrico.Perla@Sun.COM  *        - BC_NOEINFO (no extended information available)
354*12947SEnrico.Perla@Sun.COM  */
355*12947SEnrico.Perla@Sun.COM static int
handle_getinfo(char * progname,char ** argv)356*12947SEnrico.Perla@Sun.COM handle_getinfo(char *progname, char **argv)
357*12947SEnrico.Perla@Sun.COM {
358*12947SEnrico.Perla@Sun.COM 	ig_data_t	data;
359*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	*stage2 = &data.stage2;
360*12947SEnrico.Perla@Sun.COM 	ig_device_t	*device = &data.device;
361*12947SEnrico.Perla@Sun.COM 	bblk_einfo_t	*einfo;
362*12947SEnrico.Perla@Sun.COM 	uint8_t		flags = 0;
363*12947SEnrico.Perla@Sun.COM 	uint32_t	size;
364*12947SEnrico.Perla@Sun.COM 	char		*device_path;
365*12947SEnrico.Perla@Sun.COM 	int		retval = BC_ERROR;
366*12947SEnrico.Perla@Sun.COM 	int		ret;
367*12947SEnrico.Perla@Sun.COM 
368*12947SEnrico.Perla@Sun.COM 	device_path = strdup(argv[0]);
369*12947SEnrico.Perla@Sun.COM 	if (!device_path) {
370*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Missing parameter"));
371*12947SEnrico.Perla@Sun.COM 		usage(progname);
372*12947SEnrico.Perla@Sun.COM 		goto out;
373*12947SEnrico.Perla@Sun.COM 	}
374*12947SEnrico.Perla@Sun.COM 
375*12947SEnrico.Perla@Sun.COM 	bzero(&data, sizeof (ig_data_t));
376*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("device path: %s\n", device_path);
377*12947SEnrico.Perla@Sun.COM 
378*12947SEnrico.Perla@Sun.COM 	if (init_device(device, device_path) != BC_SUCCESS) {
379*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Unable to gather device "
380*12947SEnrico.Perla@Sun.COM 		    "information for %s\n"), device_path);
381*12947SEnrico.Perla@Sun.COM 		goto out_dev;
382*12947SEnrico.Perla@Sun.COM 	}
383*12947SEnrico.Perla@Sun.COM 
384*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(device->type)) {
385*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Versioning not supported on "
386*12947SEnrico.Perla@Sun.COM 		    "PCFS\n"));
387*12947SEnrico.Perla@Sun.COM 		goto out_dev;
388*12947SEnrico.Perla@Sun.COM 	}
3890Sstevel@tonic-gate 
390*12947SEnrico.Perla@Sun.COM 	ret = read_stage2_from_disk(device->part_fd, stage2);
391*12947SEnrico.Perla@Sun.COM 	if (ret == BC_ERROR) {
392*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error reading stage2 from "
393*12947SEnrico.Perla@Sun.COM 		    "%s\n"), device_path);
394*12947SEnrico.Perla@Sun.COM 		goto out_dev;
395*12947SEnrico.Perla@Sun.COM 	}
396*12947SEnrico.Perla@Sun.COM 
397*12947SEnrico.Perla@Sun.COM 	if (ret == BC_NOEXTRA) {
398*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, gettext("No multiboot header found on "
399*12947SEnrico.Perla@Sun.COM 		    "%s, unable to locate extra information area\n"),
400*12947SEnrico.Perla@Sun.COM 		    device_path);
401*12947SEnrico.Perla@Sun.COM 		retval = BC_NOEINFO;
402*12947SEnrico.Perla@Sun.COM 		goto out_dev;
403*12947SEnrico.Perla@Sun.COM 	}
404*12947SEnrico.Perla@Sun.COM 
405*12947SEnrico.Perla@Sun.COM 	einfo = find_einfo(stage2->extra);
406*12947SEnrico.Perla@Sun.COM 	if (einfo == NULL) {
407*12947SEnrico.Perla@Sun.COM 		retval = BC_NOEINFO;
408*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("No extended information "
409*12947SEnrico.Perla@Sun.COM 		    "found\n"));
410*12947SEnrico.Perla@Sun.COM 		goto out_dev;
411*12947SEnrico.Perla@Sun.COM 	}
412*12947SEnrico.Perla@Sun.COM 
413*12947SEnrico.Perla@Sun.COM 	/* Print the extended information. */
414*12947SEnrico.Perla@Sun.COM 	if (strip)
415*12947SEnrico.Perla@Sun.COM 		flags |= EINFO_EASY_PARSE;
416*12947SEnrico.Perla@Sun.COM 	if (verbose_dump)
417*12947SEnrico.Perla@Sun.COM 		flags |= EINFO_PRINT_HEADER;
418*12947SEnrico.Perla@Sun.COM 
419*12947SEnrico.Perla@Sun.COM 	size = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8);
420*12947SEnrico.Perla@Sun.COM 	print_einfo(flags, einfo, size);
421*12947SEnrico.Perla@Sun.COM 	retval = BC_SUCCESS;
422*12947SEnrico.Perla@Sun.COM 
423*12947SEnrico.Perla@Sun.COM out_dev:
424*12947SEnrico.Perla@Sun.COM 	cleanup_device(&data.device);
425*12947SEnrico.Perla@Sun.COM out:
426*12947SEnrico.Perla@Sun.COM 	free(device_path);
427*12947SEnrico.Perla@Sun.COM 	return (retval);
428*12947SEnrico.Perla@Sun.COM }
4298434SEnrico.Perla@Sun.COM 
430*12947SEnrico.Perla@Sun.COM /*
431*12947SEnrico.Perla@Sun.COM  * Attempt to mirror (propagate) the current stage2 over the attaching disk.
432*12947SEnrico.Perla@Sun.COM  *
433*12947SEnrico.Perla@Sun.COM  * Returns:
434*12947SEnrico.Perla@Sun.COM  *	- BC_SUCCESS (a successful propagation happened)
435*12947SEnrico.Perla@Sun.COM  *	- BC_ERROR (an error occurred)
436*12947SEnrico.Perla@Sun.COM  *	- BC_NOEXTRA (it is not possible to dump the current bootblock since
437*12947SEnrico.Perla@Sun.COM  *			there is no multiboot information)
438*12947SEnrico.Perla@Sun.COM  */
439*12947SEnrico.Perla@Sun.COM static int
handle_mirror(char * progname,char ** argv)440*12947SEnrico.Perla@Sun.COM handle_mirror(char *progname, char **argv)
441*12947SEnrico.Perla@Sun.COM {
442*12947SEnrico.Perla@Sun.COM 	ig_data_t	curr_data;
443*12947SEnrico.Perla@Sun.COM 	ig_data_t	attach_data;
444*12947SEnrico.Perla@Sun.COM 	ig_device_t	*curr_device = &curr_data.device;
445*12947SEnrico.Perla@Sun.COM 	ig_device_t	*attach_device = &attach_data.device;
446*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	*stage2_curr = &curr_data.stage2;
447*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	*stage2_attach = &attach_data.stage2;
448*12947SEnrico.Perla@Sun.COM 	bblk_einfo_t	*einfo_curr = NULL;
449*12947SEnrico.Perla@Sun.COM 	char		*curr_device_path;
450*12947SEnrico.Perla@Sun.COM 	char		*attach_device_path;
451*12947SEnrico.Perla@Sun.COM 	char		*updt_str = NULL;
452*12947SEnrico.Perla@Sun.COM 	int		retval = BC_ERROR;
453*12947SEnrico.Perla@Sun.COM 	int		ret;
454*12947SEnrico.Perla@Sun.COM 
455*12947SEnrico.Perla@Sun.COM 	curr_device_path = strdup(argv[0]);
456*12947SEnrico.Perla@Sun.COM 	attach_device_path = strdup(argv[1]);
457*12947SEnrico.Perla@Sun.COM 
458*12947SEnrico.Perla@Sun.COM 	if (!curr_device_path || !attach_device_path) {
459*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Missing parameter"));
460*12947SEnrico.Perla@Sun.COM 		usage(progname);
461*12947SEnrico.Perla@Sun.COM 		goto out;
462*12947SEnrico.Perla@Sun.COM 	}
463*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("Current device path is: %s, attaching device path is: "
464*12947SEnrico.Perla@Sun.COM 	    " %s\n", curr_device_path, attach_device_path);
465*12947SEnrico.Perla@Sun.COM 
466*12947SEnrico.Perla@Sun.COM 	bzero(&curr_data, sizeof (ig_data_t));
467*12947SEnrico.Perla@Sun.COM 	bzero(&attach_data, sizeof (ig_data_t));
468*12947SEnrico.Perla@Sun.COM 
469*12947SEnrico.Perla@Sun.COM 	if (init_device(curr_device, curr_device_path) != BC_SUCCESS) {
470*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Unable to gather device "
471*12947SEnrico.Perla@Sun.COM 		    "information for %s (current device)\n"), curr_device_path);
472*12947SEnrico.Perla@Sun.COM 		goto out_currdev;
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 
475*12947SEnrico.Perla@Sun.COM 	if (init_device(attach_device, attach_device_path) != BC_SUCCESS) {
476*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Unable to gather device "
477*12947SEnrico.Perla@Sun.COM 		    "information for %s (attaching device)\n"),
478*12947SEnrico.Perla@Sun.COM 		    attach_device_path);
479*12947SEnrico.Perla@Sun.COM 		goto out_devs;
480*12947SEnrico.Perla@Sun.COM 	}
481*12947SEnrico.Perla@Sun.COM 
482*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(curr_device->type) || is_bootpar(attach_device->type)) {
483*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("boot block mirroring is not "
484*12947SEnrico.Perla@Sun.COM 		    "supported on PCFS\n"));
485*12947SEnrico.Perla@Sun.COM 		goto out_devs;
486*12947SEnrico.Perla@Sun.COM 	}
4870Sstevel@tonic-gate 
488*12947SEnrico.Perla@Sun.COM 	ret = read_stage2_from_disk(curr_device->part_fd, stage2_curr);
489*12947SEnrico.Perla@Sun.COM 	if (ret == BC_ERROR) {
490*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Error reading first stage2 blocks from %s\n",
491*12947SEnrico.Perla@Sun.COM 		    curr_device->path);
492*12947SEnrico.Perla@Sun.COM 		retval = BC_ERROR;
493*12947SEnrico.Perla@Sun.COM 		goto out_devs;
494*12947SEnrico.Perla@Sun.COM 	}
4950Sstevel@tonic-gate 
496*12947SEnrico.Perla@Sun.COM 	if (ret == BC_NOEXTRA) {
497*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("No multiboot header found on %s, unable to grab "
498*12947SEnrico.Perla@Sun.COM 		    "stage2\n", curr_device->path);
499*12947SEnrico.Perla@Sun.COM 		retval = BC_NOEXTRA;
500*12947SEnrico.Perla@Sun.COM 		goto out_devs;
501*12947SEnrico.Perla@Sun.COM 	}
502*12947SEnrico.Perla@Sun.COM 
503*12947SEnrico.Perla@Sun.COM 	einfo_curr = find_einfo(stage2_curr->extra);
504*12947SEnrico.Perla@Sun.COM 	if (einfo_curr != NULL)
505*12947SEnrico.Perla@Sun.COM 		updt_str = einfo_get_string(einfo_curr);
506*12947SEnrico.Perla@Sun.COM 
507*12947SEnrico.Perla@Sun.COM 	write_mbr = B_TRUE;
508*12947SEnrico.Perla@Sun.COM 	force_mbr = B_TRUE;
509*12947SEnrico.Perla@Sun.COM 	retval = propagate_bootblock(&curr_data, &attach_data, updt_str);
510*12947SEnrico.Perla@Sun.COM 	cleanup_stage2(stage2_curr);
511*12947SEnrico.Perla@Sun.COM 	cleanup_stage2(stage2_attach);
5120Sstevel@tonic-gate 
513*12947SEnrico.Perla@Sun.COM out_devs:
514*12947SEnrico.Perla@Sun.COM 	cleanup_device(attach_device);
515*12947SEnrico.Perla@Sun.COM out_currdev:
516*12947SEnrico.Perla@Sun.COM 	cleanup_device(curr_device);
517*12947SEnrico.Perla@Sun.COM out:
518*12947SEnrico.Perla@Sun.COM 	free(curr_device_path);
519*12947SEnrico.Perla@Sun.COM 	free(attach_device_path);
520*12947SEnrico.Perla@Sun.COM 	return (retval);
521*12947SEnrico.Perla@Sun.COM }
5228434SEnrico.Perla@Sun.COM 
523*12947SEnrico.Perla@Sun.COM static int
commit_to_disk(ig_data_t * install,char * updt_str)524*12947SEnrico.Perla@Sun.COM commit_to_disk(ig_data_t *install, char *updt_str)
525*12947SEnrico.Perla@Sun.COM {
526*12947SEnrico.Perla@Sun.COM 	assert(install != NULL);
527*12947SEnrico.Perla@Sun.COM 	/*
528*12947SEnrico.Perla@Sun.COM 	 * vanilla stage1 and stage2 need to be updated at runtime.
529*12947SEnrico.Perla@Sun.COM 	 * Update stage2 before stage1 because stage1 needs to know the first
530*12947SEnrico.Perla@Sun.COM 	 * sector stage2 will be written to.
531*12947SEnrico.Perla@Sun.COM 	 */
532*12947SEnrico.Perla@Sun.COM 	if (prepare_stage2(install, updt_str) != BC_SUCCESS) {
533*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error building stage2\n"));
534*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
535*12947SEnrico.Perla@Sun.COM 	}
536*12947SEnrico.Perla@Sun.COM 	if (prepare_stage1(install) != BC_SUCCESS) {
537*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error building stage1\n"));
538*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
539*12947SEnrico.Perla@Sun.COM 	}
5400Sstevel@tonic-gate 
541*12947SEnrico.Perla@Sun.COM 	/* Write stage2 out to disk. */
542*12947SEnrico.Perla@Sun.COM 	if (write_stage2(install) != BC_SUCCESS) {
543*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error writing stage2 to "
544*12947SEnrico.Perla@Sun.COM 		    "disk\n"));
545*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
546*12947SEnrico.Perla@Sun.COM 	}
547*12947SEnrico.Perla@Sun.COM 
548*12947SEnrico.Perla@Sun.COM 	/* Write stage1 to disk and, if requested, to the MBR. */
549*12947SEnrico.Perla@Sun.COM 	if (write_stage1(install) != BC_SUCCESS) {
550*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error writing stage1 to "
551*12947SEnrico.Perla@Sun.COM 		    "disk\n"));
552*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
553*12947SEnrico.Perla@Sun.COM 	}
554*12947SEnrico.Perla@Sun.COM 
555*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate 
558*12947SEnrico.Perla@Sun.COM /*
559*12947SEnrico.Perla@Sun.COM  * Propagate the bootblock on the source disk to the destination disk and
560*12947SEnrico.Perla@Sun.COM  * version it with 'updt_str' in the process. Since we cannot trust any data
561*12947SEnrico.Perla@Sun.COM  * on the attaching disk, we do not perform any specific check on a potential
562*12947SEnrico.Perla@Sun.COM  * target extended information structure and we just blindly update.
563*12947SEnrico.Perla@Sun.COM  */
564*12947SEnrico.Perla@Sun.COM static int
propagate_bootblock(ig_data_t * source,ig_data_t * target,char * updt_str)565*12947SEnrico.Perla@Sun.COM propagate_bootblock(ig_data_t *source, ig_data_t *target, char *updt_str)
5660Sstevel@tonic-gate {
567*12947SEnrico.Perla@Sun.COM 	ig_device_t	*src_device = &source->device;
568*12947SEnrico.Perla@Sun.COM 	ig_device_t	*dest_device = &target->device;
569*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	*src_stage2 = &source->stage2;
570*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	*dest_stage2 = &target->stage2;
571*12947SEnrico.Perla@Sun.COM 	uint32_t	buf_size;
572*12947SEnrico.Perla@Sun.COM 	int		retval;
573*12947SEnrico.Perla@Sun.COM 
574*12947SEnrico.Perla@Sun.COM 	assert(source != NULL);
575*12947SEnrico.Perla@Sun.COM 	assert(target != NULL);
576*12947SEnrico.Perla@Sun.COM 
577*12947SEnrico.Perla@Sun.COM 	/* read in stage1 from the source disk. */
578*12947SEnrico.Perla@Sun.COM 	if (read_stage1_from_disk(src_device->part_fd, target->stage1_buf)
579*12947SEnrico.Perla@Sun.COM 	    != BC_SUCCESS)
580*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
581*12947SEnrico.Perla@Sun.COM 
582*12947SEnrico.Perla@Sun.COM 	/* Prepare target stage2 for commit_to_disk. */
583*12947SEnrico.Perla@Sun.COM 	cleanup_stage2(dest_stage2);
584*12947SEnrico.Perla@Sun.COM 
585*12947SEnrico.Perla@Sun.COM 	if (updt_str != NULL)
586*12947SEnrico.Perla@Sun.COM 		do_version = B_TRUE;
587*12947SEnrico.Perla@Sun.COM 	else
588*12947SEnrico.Perla@Sun.COM 		do_version = B_FALSE;
589*12947SEnrico.Perla@Sun.COM 
590*12947SEnrico.Perla@Sun.COM 	buf_size = src_stage2->file_size + SECTOR_SIZE;
591*12947SEnrico.Perla@Sun.COM 
592*12947SEnrico.Perla@Sun.COM 	dest_stage2->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE);
593*12947SEnrico.Perla@Sun.COM 	dest_stage2->buf = malloc(dest_stage2->buf_size);
594*12947SEnrico.Perla@Sun.COM 	if (dest_stage2->buf == NULL) {
595*12947SEnrico.Perla@Sun.COM 		perror(gettext("Memory allocation failed"));
596*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
597*12947SEnrico.Perla@Sun.COM 	}
598*12947SEnrico.Perla@Sun.COM 	dest_stage2->file = dest_stage2->buf;
599*12947SEnrico.Perla@Sun.COM 	dest_stage2->file_size = src_stage2->file_size;
600*12947SEnrico.Perla@Sun.COM 	memcpy(dest_stage2->file, src_stage2->file, dest_stage2->file_size);
601*12947SEnrico.Perla@Sun.COM 	dest_stage2->extra = dest_stage2->buf +
602*12947SEnrico.Perla@Sun.COM 	    P2ROUNDUP(dest_stage2->file_size, 8);
603*12947SEnrico.Perla@Sun.COM 
604*12947SEnrico.Perla@Sun.COM 	/* If we get down here we do have a mboot structure. */
605*12947SEnrico.Perla@Sun.COM 	assert(src_stage2->mboot);
606*12947SEnrico.Perla@Sun.COM 
607*12947SEnrico.Perla@Sun.COM 	dest_stage2->mboot_off = src_stage2->mboot_off;
608*12947SEnrico.Perla@Sun.COM 	dest_stage2->mboot = (multiboot_header_t *)(dest_stage2->buf +
609*12947SEnrico.Perla@Sun.COM 	    dest_stage2->mboot_off);
610*12947SEnrico.Perla@Sun.COM 
611*12947SEnrico.Perla@Sun.COM 	(void) fprintf(stdout, gettext("Propagating %s stage1/stage2 to %s\n"),
612*12947SEnrico.Perla@Sun.COM 	    src_device->path, dest_device->path);
613*12947SEnrico.Perla@Sun.COM 	retval = commit_to_disk(target, updt_str);
614*12947SEnrico.Perla@Sun.COM 
615*12947SEnrico.Perla@Sun.COM 	return (retval);
616*12947SEnrico.Perla@Sun.COM }
617*12947SEnrico.Perla@Sun.COM 
618*12947SEnrico.Perla@Sun.COM /*
619*12947SEnrico.Perla@Sun.COM  * open the device and fill the various members of ig_device_t.
620*12947SEnrico.Perla@Sun.COM  */
621*12947SEnrico.Perla@Sun.COM static int
init_device(ig_device_t * device,char * path)622*12947SEnrico.Perla@Sun.COM init_device(ig_device_t *device, char *path)
623*12947SEnrico.Perla@Sun.COM {
624*12947SEnrico.Perla@Sun.COM 	bzero(device, sizeof (*device));
625*12947SEnrico.Perla@Sun.COM 	device->part_fd = -1;
626*12947SEnrico.Perla@Sun.COM 	device->disk_fd = -1;
627*12947SEnrico.Perla@Sun.COM 	device->path_p0 = NULL;
628*12947SEnrico.Perla@Sun.COM 
629*12947SEnrico.Perla@Sun.COM 	device->path = strdup(path);
630*12947SEnrico.Perla@Sun.COM 	if (device->path == NULL) {
631*12947SEnrico.Perla@Sun.COM 		perror(gettext("Memory allocation failed"));
632*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
633*12947SEnrico.Perla@Sun.COM 	}
6340Sstevel@tonic-gate 
635*12947SEnrico.Perla@Sun.COM 	if (strstr(device->path, "diskette")) {
636*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("installing GRUB to a floppy "
637*12947SEnrico.Perla@Sun.COM 		    "disk is no longer supported\n"));
638*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
639*12947SEnrico.Perla@Sun.COM 	}
640*12947SEnrico.Perla@Sun.COM 
641*12947SEnrico.Perla@Sun.COM 	/* Detect if the target device is a pcfs partition. */
642*12947SEnrico.Perla@Sun.COM 	if (strstr(device->path, "p0:boot"))
643*12947SEnrico.Perla@Sun.COM 		device->type = IG_DEV_X86BOOTPAR;
644*12947SEnrico.Perla@Sun.COM 
645*12947SEnrico.Perla@Sun.COM 	if (get_disk_fd(device) != BC_SUCCESS)
646*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
647*12947SEnrico.Perla@Sun.COM 
648*12947SEnrico.Perla@Sun.COM 	/* read in the device boot sector. */
649*12947SEnrico.Perla@Sun.COM 	if (read(device->disk_fd, device->boot_sector, SECTOR_SIZE)
650*12947SEnrico.Perla@Sun.COM 	    != SECTOR_SIZE) {
651*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error reading boot sector\n"));
652*12947SEnrico.Perla@Sun.COM 		perror("read");
653*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
654*12947SEnrico.Perla@Sun.COM 	}
655*12947SEnrico.Perla@Sun.COM 
656*12947SEnrico.Perla@Sun.COM 	if (get_raw_partition_fd(device) != BC_SUCCESS)
657*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
658*12947SEnrico.Perla@Sun.COM 
659*12947SEnrico.Perla@Sun.COM 	if (get_start_sector(device) != BC_SUCCESS)
660*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
661*12947SEnrico.Perla@Sun.COM 
662*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
663*12947SEnrico.Perla@Sun.COM }
664*12947SEnrico.Perla@Sun.COM 
665*12947SEnrico.Perla@Sun.COM static void
cleanup_device(ig_device_t * device)666*12947SEnrico.Perla@Sun.COM cleanup_device(ig_device_t *device)
667*12947SEnrico.Perla@Sun.COM {
668*12947SEnrico.Perla@Sun.COM 	if (device->path)
669*12947SEnrico.Perla@Sun.COM 		free(device->path);
670*12947SEnrico.Perla@Sun.COM 	if (device->path_p0)
671*12947SEnrico.Perla@Sun.COM 		free(device->path_p0);
6720Sstevel@tonic-gate 
673*12947SEnrico.Perla@Sun.COM 	if (device->part_fd != -1)
674*12947SEnrico.Perla@Sun.COM 		(void) close(device->part_fd);
675*12947SEnrico.Perla@Sun.COM 	if (device->disk_fd != -1)
676*12947SEnrico.Perla@Sun.COM 		(void) close(device->disk_fd);
677*12947SEnrico.Perla@Sun.COM 
678*12947SEnrico.Perla@Sun.COM 	bzero(device, sizeof (ig_device_t));
679*12947SEnrico.Perla@Sun.COM 	device->part_fd = -1;
680*12947SEnrico.Perla@Sun.COM 	device->disk_fd = -1;
681*12947SEnrico.Perla@Sun.COM }
682*12947SEnrico.Perla@Sun.COM 
683*12947SEnrico.Perla@Sun.COM static void
cleanup_stage2(ig_stage2_t * stage2)684*12947SEnrico.Perla@Sun.COM cleanup_stage2(ig_stage2_t *stage2)
685*12947SEnrico.Perla@Sun.COM {
686*12947SEnrico.Perla@Sun.COM 	if (stage2->buf)
687*12947SEnrico.Perla@Sun.COM 		free(stage2->buf);
688*12947SEnrico.Perla@Sun.COM 	bzero(stage2, sizeof (ig_stage2_t));
689*12947SEnrico.Perla@Sun.COM }
690*12947SEnrico.Perla@Sun.COM 
691*12947SEnrico.Perla@Sun.COM static int
get_start_sector(ig_device_t * device)692*12947SEnrico.Perla@Sun.COM get_start_sector(ig_device_t *device)
693*12947SEnrico.Perla@Sun.COM {
694*12947SEnrico.Perla@Sun.COM 	uint32_t		secnum = 0, numsec = 0;
695*12947SEnrico.Perla@Sun.COM 	int			i, pno, rval, log_part = 0;
696*12947SEnrico.Perla@Sun.COM 	struct mboot		*mboot;
697*12947SEnrico.Perla@Sun.COM 	struct ipart		*part;
698*12947SEnrico.Perla@Sun.COM 	ext_part_t		*epp;
699*12947SEnrico.Perla@Sun.COM 	struct part_info	dkpi;
700*12947SEnrico.Perla@Sun.COM 	struct extpart_info	edkpi;
701*12947SEnrico.Perla@Sun.COM 
702*12947SEnrico.Perla@Sun.COM 	mboot = (struct mboot *)device->boot_sector;
703*12947SEnrico.Perla@Sun.COM 
704*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(device->type)) {
705*12947SEnrico.Perla@Sun.COM 		if (find_x86_bootpar(mboot, &pno, &secnum) != BC_SUCCESS) {
706*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stderr, NOBOOTPAR);
707*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
708*12947SEnrico.Perla@Sun.COM 		} else {
709*12947SEnrico.Perla@Sun.COM 			device->start_sector = secnum;
710*12947SEnrico.Perla@Sun.COM 			device->partition = pno;
711*12947SEnrico.Perla@Sun.COM 			goto found_part;
71210568SVikram.Hegde@Sun.COM 		}
71310568SVikram.Hegde@Sun.COM 	}
71410568SVikram.Hegde@Sun.COM 
71510568SVikram.Hegde@Sun.COM 	/*
716*12947SEnrico.Perla@Sun.COM 	 * Search for Solaris fdisk partition
71710568SVikram.Hegde@Sun.COM 	 * Get the solaris partition information from the device
71810568SVikram.Hegde@Sun.COM 	 * and compare the offset of S2 with offset of solaris partition
71910568SVikram.Hegde@Sun.COM 	 * from fdisk partition table.
72010568SVikram.Hegde@Sun.COM 	 */
721*12947SEnrico.Perla@Sun.COM 	if (ioctl(device->part_fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
722*12947SEnrico.Perla@Sun.COM 		if (ioctl(device->part_fd, DKIOCPARTINFO, &dkpi) < 0) {
72310568SVikram.Hegde@Sun.COM 			(void) fprintf(stderr, PART_FAIL);
724*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
72510568SVikram.Hegde@Sun.COM 		} else {
72610568SVikram.Hegde@Sun.COM 			edkpi.p_start = dkpi.p_start;
7275589Ssy25831 		}
7285589Ssy25831 	}
7295589Ssy25831 
73010568SVikram.Hegde@Sun.COM 	for (i = 0; i < FD_NUMPART; i++) {
73110568SVikram.Hegde@Sun.COM 		part = (struct ipart *)mboot->parts + i;
73210568SVikram.Hegde@Sun.COM 
73310568SVikram.Hegde@Sun.COM 		if (part->relsect == 0) {
73410568SVikram.Hegde@Sun.COM 			(void) fprintf(stderr, BAD_PART, i);
735*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
73610568SVikram.Hegde@Sun.COM 		}
73710568SVikram.Hegde@Sun.COM 
73810568SVikram.Hegde@Sun.COM 		if (edkpi.p_start >= part->relsect &&
73910568SVikram.Hegde@Sun.COM 		    edkpi.p_start < (part->relsect + part->numsect)) {
74010568SVikram.Hegde@Sun.COM 			/* Found the partition */
74110568SVikram.Hegde@Sun.COM 			break;
74210568SVikram.Hegde@Sun.COM 		}
74310568SVikram.Hegde@Sun.COM 	}
74410568SVikram.Hegde@Sun.COM 
74510568SVikram.Hegde@Sun.COM 	if (i == FD_NUMPART) {
74610568SVikram.Hegde@Sun.COM 		/* No solaris fdisk partitions (primary or logical) */
74710568SVikram.Hegde@Sun.COM 		(void) fprintf(stderr, NOSOLPAR);
748*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
74910568SVikram.Hegde@Sun.COM 	}
75010568SVikram.Hegde@Sun.COM 
75110568SVikram.Hegde@Sun.COM 	/*
75210568SVikram.Hegde@Sun.COM 	 * We have found a Solaris fdisk partition (primary or extended)
75310568SVikram.Hegde@Sun.COM 	 * Handle the simple case first: Solaris in a primary partition
75410568SVikram.Hegde@Sun.COM 	 */
75510568SVikram.Hegde@Sun.COM 	if (!fdisk_is_dos_extended(part->systid)) {
756*12947SEnrico.Perla@Sun.COM 		device->start_sector = part->relsect;
757*12947SEnrico.Perla@Sun.COM 		device->partition = i;
75810568SVikram.Hegde@Sun.COM 		goto found_part;
75910568SVikram.Hegde@Sun.COM 	}
76010568SVikram.Hegde@Sun.COM 
76110568SVikram.Hegde@Sun.COM 	/*
76210568SVikram.Hegde@Sun.COM 	 * Solaris in a logical partition. Find that partition in the
76310568SVikram.Hegde@Sun.COM 	 * extended part.
76410568SVikram.Hegde@Sun.COM 	 */
765*12947SEnrico.Perla@Sun.COM 	if ((rval = libfdisk_init(&epp, device->path_p0, NULL, FDISK_READ_DISK))
76610021SSheshadri.Vasudevan@Sun.COM 	    != FDISK_SUCCESS) {
76710021SSheshadri.Vasudevan@Sun.COM 		switch (rval) {
76810021SSheshadri.Vasudevan@Sun.COM 			/*
76911246SSharath.Srinivasan@Sun.COM 			 * The first 3 cases are not an error per-se, just that
77010568SVikram.Hegde@Sun.COM 			 * there is no Solaris logical partition
77110021SSheshadri.Vasudevan@Sun.COM 			 */
77210021SSheshadri.Vasudevan@Sun.COM 			case FDISK_EBADLOGDRIVE:
77310021SSheshadri.Vasudevan@Sun.COM 			case FDISK_ENOLOGDRIVE:
77411246SSharath.Srinivasan@Sun.COM 			case FDISK_EBADMAGIC:
77510568SVikram.Hegde@Sun.COM 				(void) fprintf(stderr, NOSOLPAR);
776*12947SEnrico.Perla@Sun.COM 				return (BC_ERROR);
77710021SSheshadri.Vasudevan@Sun.COM 			case FDISK_ENOVGEOM:
77810021SSheshadri.Vasudevan@Sun.COM 				(void) fprintf(stderr, NO_VIRT_GEOM);
779*12947SEnrico.Perla@Sun.COM 				return (BC_ERROR);
78010021SSheshadri.Vasudevan@Sun.COM 			case FDISK_ENOPGEOM:
78110021SSheshadri.Vasudevan@Sun.COM 				(void) fprintf(stderr, NO_PHYS_GEOM);
782*12947SEnrico.Perla@Sun.COM 				return (BC_ERROR);
78310021SSheshadri.Vasudevan@Sun.COM 			case FDISK_ENOLGEOM:
78410021SSheshadri.Vasudevan@Sun.COM 				(void) fprintf(stderr, NO_LABEL_GEOM);
785*12947SEnrico.Perla@Sun.COM 				return (BC_ERROR);
78610021SSheshadri.Vasudevan@Sun.COM 			default:
78710021SSheshadri.Vasudevan@Sun.COM 				(void) fprintf(stderr, LIBFDISK_INIT_FAIL);
788*12947SEnrico.Perla@Sun.COM 				return (BC_ERROR);
78910021SSheshadri.Vasudevan@Sun.COM 				break;
79010021SSheshadri.Vasudevan@Sun.COM 		}
79110021SSheshadri.Vasudevan@Sun.COM 	}
79210021SSheshadri.Vasudevan@Sun.COM 
79310021SSheshadri.Vasudevan@Sun.COM 	rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
79411246SSharath.Srinivasan@Sun.COM 	libfdisk_fini(&epp);
79510568SVikram.Hegde@Sun.COM 	if (rval != FDISK_SUCCESS) {
79610568SVikram.Hegde@Sun.COM 		/* No solaris logical partition */
79710568SVikram.Hegde@Sun.COM 		(void) fprintf(stderr, NOSOLPAR);
798*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
79910021SSheshadri.Vasudevan@Sun.COM 	}
80010021SSheshadri.Vasudevan@Sun.COM 
801*12947SEnrico.Perla@Sun.COM 	device->start_sector = secnum;
802*12947SEnrico.Perla@Sun.COM 	device->partition = pno - 1;
80310568SVikram.Hegde@Sun.COM 	log_part = 1;
8045589Ssy25831 
80510568SVikram.Hegde@Sun.COM found_part:
8060Sstevel@tonic-gate 	/* get confirmation for -m */
807*12947SEnrico.Perla@Sun.COM 	if (write_mbr && !force_mbr) {
8080Sstevel@tonic-gate 		(void) fprintf(stdout, MBOOT_PROMPT);
8090Sstevel@tonic-gate 		if (getchar() != 'y') {
810*12947SEnrico.Perla@Sun.COM 			write_mbr = 0;
8110Sstevel@tonic-gate 			(void) fprintf(stdout, MBOOT_NOT_UPDATED);
812*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
8130Sstevel@tonic-gate 		}
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 
81610568SVikram.Hegde@Sun.COM 	/*
81710568SVikram.Hegde@Sun.COM 	 * Currently if Solaris is in an extended partition we need to
81810568SVikram.Hegde@Sun.COM 	 * write GRUB to the MBR. Check for this.
81910568SVikram.Hegde@Sun.COM 	 */
820*12947SEnrico.Perla@Sun.COM 	if (log_part && !write_mbr) {
821*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, gettext("Installing Solaris on an "
822*12947SEnrico.Perla@Sun.COM 		    "extended partition... forcing MBR update\n"));
823*12947SEnrico.Perla@Sun.COM 		write_mbr = 1;
82410021SSheshadri.Vasudevan@Sun.COM 	}
82510021SSheshadri.Vasudevan@Sun.COM 
82610568SVikram.Hegde@Sun.COM 	/*
82710568SVikram.Hegde@Sun.COM 	 * warn, if Solaris in primary partition and GRUB not in MBR and
82810568SVikram.Hegde@Sun.COM 	 * partition is not active
82910568SVikram.Hegde@Sun.COM 	 */
830*12947SEnrico.Perla@Sun.COM 	if (!log_part && part->bootid != 128 && !write_mbr) {
831*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, SOLPAR_INACTIVE, device->partition + 1);
832*12947SEnrico.Perla@Sun.COM 	}
833*12947SEnrico.Perla@Sun.COM 
834*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
835*12947SEnrico.Perla@Sun.COM }
836*12947SEnrico.Perla@Sun.COM 
837*12947SEnrico.Perla@Sun.COM static int
get_disk_fd(ig_device_t * device)838*12947SEnrico.Perla@Sun.COM get_disk_fd(ig_device_t *device)
839*12947SEnrico.Perla@Sun.COM {
840*12947SEnrico.Perla@Sun.COM 	int	i;
841*12947SEnrico.Perla@Sun.COM 	char	save[2];
842*12947SEnrico.Perla@Sun.COM 	char	*end = NULL;
843*12947SEnrico.Perla@Sun.COM 
844*12947SEnrico.Perla@Sun.COM 	assert(device != NULL);
845*12947SEnrico.Perla@Sun.COM 	assert(device->path != NULL);
846*12947SEnrico.Perla@Sun.COM 
847*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(device->type)) {
848*12947SEnrico.Perla@Sun.COM 		end = strstr(device->path, "p0:boot");
849*12947SEnrico.Perla@Sun.COM 		/* tested at the start of init_device() */
850*12947SEnrico.Perla@Sun.COM 		assert(end != NULL);
851*12947SEnrico.Perla@Sun.COM 		/* chop off :boot */
852*12947SEnrico.Perla@Sun.COM 		save[0] = end[2];
853*12947SEnrico.Perla@Sun.COM 		end[2] = '\0';
854*12947SEnrico.Perla@Sun.COM 	} else {
855*12947SEnrico.Perla@Sun.COM 		i = strlen(device->path);
856*12947SEnrico.Perla@Sun.COM 		save[0] = device->path[i - 2];
857*12947SEnrico.Perla@Sun.COM 		save[1] = device->path[i - 1];
858*12947SEnrico.Perla@Sun.COM 		device->path[i - 2] = 'p';
859*12947SEnrico.Perla@Sun.COM 		device->path[i - 1] = '0';
860*12947SEnrico.Perla@Sun.COM 	}
861*12947SEnrico.Perla@Sun.COM 
862*12947SEnrico.Perla@Sun.COM 	if (nowrite)
863*12947SEnrico.Perla@Sun.COM 		device->disk_fd = open(device->path, O_RDONLY);
864*12947SEnrico.Perla@Sun.COM 	else
865*12947SEnrico.Perla@Sun.COM 		device->disk_fd = open(device->path, O_RDWR);
866*12947SEnrico.Perla@Sun.COM 
867*12947SEnrico.Perla@Sun.COM 	device->path_p0 = strdup(device->path);
868*12947SEnrico.Perla@Sun.COM 	if (device->path_p0 == NULL) {
869*12947SEnrico.Perla@Sun.COM 		perror("strdup");
870*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
871*12947SEnrico.Perla@Sun.COM 	}
872*12947SEnrico.Perla@Sun.COM 
873*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(device->type)) {
874*12947SEnrico.Perla@Sun.COM 		end[2] = save[0];
875*12947SEnrico.Perla@Sun.COM 	} else {
876*12947SEnrico.Perla@Sun.COM 		device->path[i - 2] = save[0];
877*12947SEnrico.Perla@Sun.COM 		device->path[i - 1] = save[1];
878*12947SEnrico.Perla@Sun.COM 	}
879*12947SEnrico.Perla@Sun.COM 
880*12947SEnrico.Perla@Sun.COM 	if (device->disk_fd == -1) {
881*12947SEnrico.Perla@Sun.COM 		perror("open");
882*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 
885*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
886*12947SEnrico.Perla@Sun.COM }
887*12947SEnrico.Perla@Sun.COM 
888*12947SEnrico.Perla@Sun.COM static void
prepare_fake_multiboot(ig_stage2_t * stage2)889*12947SEnrico.Perla@Sun.COM prepare_fake_multiboot(ig_stage2_t *stage2)
890*12947SEnrico.Perla@Sun.COM {
891*12947SEnrico.Perla@Sun.COM 	multiboot_header_t	*mboot;
892*12947SEnrico.Perla@Sun.COM 
893*12947SEnrico.Perla@Sun.COM 	assert(stage2 != NULL);
894*12947SEnrico.Perla@Sun.COM 	assert(stage2->mboot != NULL);
895*12947SEnrico.Perla@Sun.COM 	assert(stage2->buf != NULL);
896*12947SEnrico.Perla@Sun.COM 
897*12947SEnrico.Perla@Sun.COM 	mboot = stage2->mboot;
898*12947SEnrico.Perla@Sun.COM 
899*12947SEnrico.Perla@Sun.COM 	/*
900*12947SEnrico.Perla@Sun.COM 	 * Currently we expect find_multiboot() to have located a multiboot
901*12947SEnrico.Perla@Sun.COM 	 * header with the AOUT kludge flag set.
902*12947SEnrico.Perla@Sun.COM 	 */
903*12947SEnrico.Perla@Sun.COM 	assert(mboot->flags & BB_MBOOT_AOUT_FLAG);
904*12947SEnrico.Perla@Sun.COM 
905*12947SEnrico.Perla@Sun.COM 	/* Insert the information necessary to locate stage2. */
906*12947SEnrico.Perla@Sun.COM 	mboot->header_addr = stage2->mboot_off;
907*12947SEnrico.Perla@Sun.COM 	mboot->load_addr = 0;
908*12947SEnrico.Perla@Sun.COM 	mboot->load_end_addr = stage2->file_size;
909*12947SEnrico.Perla@Sun.COM }
910*12947SEnrico.Perla@Sun.COM 
911*12947SEnrico.Perla@Sun.COM static void
add_stage2_einfo(ig_stage2_t * stage2,char * updt_str)912*12947SEnrico.Perla@Sun.COM add_stage2_einfo(ig_stage2_t *stage2, char *updt_str)
913*12947SEnrico.Perla@Sun.COM {
914*12947SEnrico.Perla@Sun.COM 	bblk_hs_t	hs;
915*12947SEnrico.Perla@Sun.COM 	uint32_t	avail_space;
916*12947SEnrico.Perla@Sun.COM 
917*12947SEnrico.Perla@Sun.COM 	assert(stage2 != NULL);
918*12947SEnrico.Perla@Sun.COM 
919*12947SEnrico.Perla@Sun.COM 	/* Fill bootblock hashing source information. */
920*12947SEnrico.Perla@Sun.COM 	hs.src_buf = (unsigned char *)stage2->file;
921*12947SEnrico.Perla@Sun.COM 	hs.src_size = stage2->file_size;
922*12947SEnrico.Perla@Sun.COM 	/* How much space for the extended information structure? */
923*12947SEnrico.Perla@Sun.COM 	avail_space = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8);
924*12947SEnrico.Perla@Sun.COM 	add_einfo(stage2->extra, updt_str, &hs, avail_space);
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate 
927*12947SEnrico.Perla@Sun.COM 
928*12947SEnrico.Perla@Sun.COM static int
write_stage2(ig_data_t * install)929*12947SEnrico.Perla@Sun.COM write_stage2(ig_data_t *install)
930*12947SEnrico.Perla@Sun.COM {
931*12947SEnrico.Perla@Sun.COM 	ig_device_t		*device = &install->device;
932*12947SEnrico.Perla@Sun.COM 	ig_stage2_t		*stage2 = &install->stage2;
933*12947SEnrico.Perla@Sun.COM 	off_t			offset;
934*12947SEnrico.Perla@Sun.COM 
935*12947SEnrico.Perla@Sun.COM 	assert(install != NULL);
936*12947SEnrico.Perla@Sun.COM 
937*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(device->type)) {
938*12947SEnrico.Perla@Sun.COM 		/*
939*12947SEnrico.Perla@Sun.COM 		 * stage2 is already on the filesystem, we only need to update
940*12947SEnrico.Perla@Sun.COM 		 * the first two blocks (that we have modified during
941*12947SEnrico.Perla@Sun.COM 		 * prepare_stage2())
942*12947SEnrico.Perla@Sun.COM 		 */
943*12947SEnrico.Perla@Sun.COM 		if (write_out(device->part_fd, stage2->file, SECTOR_SIZE,
944*12947SEnrico.Perla@Sun.COM 		    stage2->pcfs_first_sectors[0] * SECTOR_SIZE)
945*12947SEnrico.Perla@Sun.COM 		    != BC_SUCCESS ||
946*12947SEnrico.Perla@Sun.COM 		    write_out(device->part_fd, stage2->file + SECTOR_SIZE,
947*12947SEnrico.Perla@Sun.COM 		    SECTOR_SIZE, stage2->pcfs_first_sectors[1] * SECTOR_SIZE)
948*12947SEnrico.Perla@Sun.COM 		    != BC_SUCCESS) {
949*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stderr, WRITE_FAIL_STAGE2);
950*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
951*12947SEnrico.Perla@Sun.COM 		}
952*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, WRITE_STAGE2_PCFS);
953*12947SEnrico.Perla@Sun.COM 		return (BC_SUCCESS);
954*12947SEnrico.Perla@Sun.COM 	}
955*12947SEnrico.Perla@Sun.COM 
956*12947SEnrico.Perla@Sun.COM 	/*
957*12947SEnrico.Perla@Sun.COM 	 * For disk, write stage2 starting at STAGE2_BLKOFF sector.
958*12947SEnrico.Perla@Sun.COM 	 * Note that we use stage2->buf rather than stage2->file, because we
959*12947SEnrico.Perla@Sun.COM 	 * may have extended information after the latter.
960*12947SEnrico.Perla@Sun.COM 	 */
961*12947SEnrico.Perla@Sun.COM 	offset = STAGE2_BLKOFF * SECTOR_SIZE;
962*12947SEnrico.Perla@Sun.COM 	if (write_out(device->part_fd, stage2->buf, stage2->buf_size,
963*12947SEnrico.Perla@Sun.COM 	    offset) != BC_SUCCESS) {
964*12947SEnrico.Perla@Sun.COM 		perror("write");
965*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
966*12947SEnrico.Perla@Sun.COM 	}
967*12947SEnrico.Perla@Sun.COM 
968*12947SEnrico.Perla@Sun.COM 	/* Simulate the "old" installgrub output. */
969*12947SEnrico.Perla@Sun.COM 	(void) fprintf(stdout, WRITE_STAGE2_DISK, device->partition,
970*12947SEnrico.Perla@Sun.COM 	    (stage2->buf_size / SECTOR_SIZE) + 1, STAGE2_BLKOFF,
971*12947SEnrico.Perla@Sun.COM 	    stage2->first_sector);
972*12947SEnrico.Perla@Sun.COM 
973*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
974*12947SEnrico.Perla@Sun.COM }
975*12947SEnrico.Perla@Sun.COM 
976*12947SEnrico.Perla@Sun.COM static int
write_stage1(ig_data_t * install)977*12947SEnrico.Perla@Sun.COM write_stage1(ig_data_t *install)
978*12947SEnrico.Perla@Sun.COM {
979*12947SEnrico.Perla@Sun.COM 	ig_device_t	*device = &install->device;
980*12947SEnrico.Perla@Sun.COM 
981*12947SEnrico.Perla@Sun.COM 	assert(install != NULL);
982*12947SEnrico.Perla@Sun.COM 
983*12947SEnrico.Perla@Sun.COM 	if (write_out(device->part_fd, install->stage1_buf,
984*12947SEnrico.Perla@Sun.COM 	    sizeof (install->stage1_buf), 0) != BC_SUCCESS) {
985*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, WRITE_FAIL_PBOOT);
986*12947SEnrico.Perla@Sun.COM 		perror("write");
987*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
988*12947SEnrico.Perla@Sun.COM 	}
989*12947SEnrico.Perla@Sun.COM 
990*12947SEnrico.Perla@Sun.COM 	/* Simulate "old" installgrub output. */
991*12947SEnrico.Perla@Sun.COM 	(void) fprintf(stdout, WRITE_PBOOT, device->partition,
992*12947SEnrico.Perla@Sun.COM 	    device->start_sector);
993*12947SEnrico.Perla@Sun.COM 
994*12947SEnrico.Perla@Sun.COM 	if (write_mbr) {
995*12947SEnrico.Perla@Sun.COM 		if (write_out(device->disk_fd, install->stage1_buf,
996*12947SEnrico.Perla@Sun.COM 		    sizeof (install->stage1_buf), 0) != BC_SUCCESS) {
997*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stdout, WRITE_FAIL_BOOTSEC);
998*12947SEnrico.Perla@Sun.COM 			perror("write");
999*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
1000*12947SEnrico.Perla@Sun.COM 		}
1001*12947SEnrico.Perla@Sun.COM 		/* Simulate "old" installgrub output. */
1002*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, WRITE_MBOOT);
1003*12947SEnrico.Perla@Sun.COM 	}
1004*12947SEnrico.Perla@Sun.COM 
1005*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
1006*12947SEnrico.Perla@Sun.COM }
1007*12947SEnrico.Perla@Sun.COM 
1008*12947SEnrico.Perla@Sun.COM #define	USAGE_STRING	"%s [-m|-f|-n|-F|-u verstr] stage1 stage2 device\n"    \
1009*12947SEnrico.Perla@Sun.COM 			"%s -M [-n] device1 device2\n"			       \
1010*12947SEnrico.Perla@Sun.COM 			"%s [-V|-e] -i device\n"			       \
1011*12947SEnrico.Perla@Sun.COM 
1012*12947SEnrico.Perla@Sun.COM #define	CANON_USAGE_STR	gettext(USAGE_STRING)
1013*12947SEnrico.Perla@Sun.COM 
10140Sstevel@tonic-gate static void
usage(char * progname)10150Sstevel@tonic-gate usage(char *progname)
10160Sstevel@tonic-gate {
1017*12947SEnrico.Perla@Sun.COM 	(void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
10188434SEnrico.Perla@Sun.COM }
10198434SEnrico.Perla@Sun.COM 
10208434SEnrico.Perla@Sun.COM 
10218434SEnrico.Perla@Sun.COM static int
read_stage1_from_file(char * path,ig_data_t * dest)1022*12947SEnrico.Perla@Sun.COM read_stage1_from_file(char *path, ig_data_t *dest)
10238434SEnrico.Perla@Sun.COM {
1024*12947SEnrico.Perla@Sun.COM 	int	fd;
1025*12947SEnrico.Perla@Sun.COM 
1026*12947SEnrico.Perla@Sun.COM 	assert(dest);
1027*12947SEnrico.Perla@Sun.COM 
1028*12947SEnrico.Perla@Sun.COM 	/* read the stage1 file from filesystem */
1029*12947SEnrico.Perla@Sun.COM 	fd = open(path, O_RDONLY);
1030*12947SEnrico.Perla@Sun.COM 	if (fd == -1 ||
1031*12947SEnrico.Perla@Sun.COM 	    read(fd, dest->stage1_buf, SECTOR_SIZE) != SECTOR_SIZE) {
1032*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, READ_FAIL_STAGE1, path);
1033*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
1034*12947SEnrico.Perla@Sun.COM 	}
1035*12947SEnrico.Perla@Sun.COM 	(void) close(fd);
1036*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
1037*12947SEnrico.Perla@Sun.COM }
1038*12947SEnrico.Perla@Sun.COM 
1039*12947SEnrico.Perla@Sun.COM static int
read_stage2_from_file(char * path,ig_data_t * dest)1040*12947SEnrico.Perla@Sun.COM read_stage2_from_file(char *path, ig_data_t *dest)
1041*12947SEnrico.Perla@Sun.COM {
1042*12947SEnrico.Perla@Sun.COM 	int		fd;
10438434SEnrico.Perla@Sun.COM 	struct stat	sb;
1044*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	*stage2 = &dest->stage2;
1045*12947SEnrico.Perla@Sun.COM 	ig_device_t	*device = &dest->device;
1046*12947SEnrico.Perla@Sun.COM 	uint32_t	buf_size;
1047*12947SEnrico.Perla@Sun.COM 
1048*12947SEnrico.Perla@Sun.COM 	assert(dest);
1049*12947SEnrico.Perla@Sun.COM 	assert(stage2->buf == NULL);
1050*12947SEnrico.Perla@Sun.COM 
1051*12947SEnrico.Perla@Sun.COM 	fd = open(path, O_RDONLY);
1052*12947SEnrico.Perla@Sun.COM 	if (fstat(fd, &sb) == -1) {
1053*12947SEnrico.Perla@Sun.COM 		perror("fstat");
1054*12947SEnrico.Perla@Sun.COM 		goto out;
1055*12947SEnrico.Perla@Sun.COM 	}
1056*12947SEnrico.Perla@Sun.COM 
1057*12947SEnrico.Perla@Sun.COM 	stage2->file_size = sb.st_size;
1058*12947SEnrico.Perla@Sun.COM 
1059*12947SEnrico.Perla@Sun.COM 	if (!is_bootpar(device->type)) {
1060*12947SEnrico.Perla@Sun.COM 		/*
1061*12947SEnrico.Perla@Sun.COM 		 * buffer size needs to account for stage2 plus the extra
1062*12947SEnrico.Perla@Sun.COM 		 * versioning information at the end of it. We reserve one
1063*12947SEnrico.Perla@Sun.COM 		 * extra sector (plus we round up to the next sector boundary).
1064*12947SEnrico.Perla@Sun.COM 		 */
1065*12947SEnrico.Perla@Sun.COM 		buf_size = stage2->file_size + SECTOR_SIZE;
1066*12947SEnrico.Perla@Sun.COM 	} else {
1067*12947SEnrico.Perla@Sun.COM 		/* In the PCFS case we only need to read in stage2. */
1068*12947SEnrico.Perla@Sun.COM 		buf_size = stage2->file_size;
1069*12947SEnrico.Perla@Sun.COM 	}
1070*12947SEnrico.Perla@Sun.COM 
1071*12947SEnrico.Perla@Sun.COM 	stage2->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE);
1072*12947SEnrico.Perla@Sun.COM 
1073*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("stage2 buffer size = %d (%d sectors)\n", stage2->buf_size,
1074*12947SEnrico.Perla@Sun.COM 	    stage2->buf_size / SECTOR_SIZE);
1075*12947SEnrico.Perla@Sun.COM 
1076*12947SEnrico.Perla@Sun.COM 	stage2->buf = malloc(stage2->buf_size);
1077*12947SEnrico.Perla@Sun.COM 	if (stage2->buf == NULL) {
1078*12947SEnrico.Perla@Sun.COM 		perror(gettext("Memory allocation failed"));
1079*12947SEnrico.Perla@Sun.COM 		goto out_fd;
1080*12947SEnrico.Perla@Sun.COM 	}
1081*12947SEnrico.Perla@Sun.COM 
1082*12947SEnrico.Perla@Sun.COM 	stage2->file = stage2->buf;
1083*12947SEnrico.Perla@Sun.COM 
1084*12947SEnrico.Perla@Sun.COM 	/*
1085*12947SEnrico.Perla@Sun.COM 	 * Extra information (e.g. the versioning structure) is placed at the
1086*12947SEnrico.Perla@Sun.COM 	 * end of stage2, aligned on a 8-byte boundary.
1087*12947SEnrico.Perla@Sun.COM 	 */
1088*12947SEnrico.Perla@Sun.COM 	if (!(is_bootpar(device->type)))
1089*12947SEnrico.Perla@Sun.COM 		stage2->extra = stage2->file + P2ROUNDUP(stage2->file_size, 8);
1090*12947SEnrico.Perla@Sun.COM 
1091*12947SEnrico.Perla@Sun.COM 	if (lseek(fd, 0, SEEK_SET) == -1) {
1092*12947SEnrico.Perla@Sun.COM 		perror("lseek");
1093*12947SEnrico.Perla@Sun.COM 		goto out_alloc;
1094*12947SEnrico.Perla@Sun.COM 	}
10958434SEnrico.Perla@Sun.COM 
1096*12947SEnrico.Perla@Sun.COM 	if (read(fd, stage2->file, stage2->file_size) < 0) {
1097*12947SEnrico.Perla@Sun.COM 		perror(gettext("unable to read stage2"));
1098*12947SEnrico.Perla@Sun.COM 		goto out_alloc;
1099*12947SEnrico.Perla@Sun.COM 	}
1100*12947SEnrico.Perla@Sun.COM 
1101*12947SEnrico.Perla@Sun.COM 	(void) close(fd);
1102*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
1103*12947SEnrico.Perla@Sun.COM 
1104*12947SEnrico.Perla@Sun.COM out_alloc:
1105*12947SEnrico.Perla@Sun.COM 	free(stage2->buf);
1106*12947SEnrico.Perla@Sun.COM 	stage2->buf = NULL;
1107*12947SEnrico.Perla@Sun.COM out_fd:
1108*12947SEnrico.Perla@Sun.COM 	(void) close(fd);
1109*12947SEnrico.Perla@Sun.COM out:
1110*12947SEnrico.Perla@Sun.COM 	return (BC_ERROR);
1111*12947SEnrico.Perla@Sun.COM }
1112*12947SEnrico.Perla@Sun.COM 
1113*12947SEnrico.Perla@Sun.COM static int
prepare_stage1(ig_data_t * install)1114*12947SEnrico.Perla@Sun.COM prepare_stage1(ig_data_t *install)
1115*12947SEnrico.Perla@Sun.COM {
1116*12947SEnrico.Perla@Sun.COM 	ig_device_t	*device = &install->device;
1117*12947SEnrico.Perla@Sun.COM 
1118*12947SEnrico.Perla@Sun.COM 	assert(install != NULL);
1119*12947SEnrico.Perla@Sun.COM 
1120*12947SEnrico.Perla@Sun.COM 	/* If PCFS add the BIOS Parameter Block. */
1121*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(device->type)) {
1122*12947SEnrico.Perla@Sun.COM 		char	bpb_sect[SECTOR_SIZE];
1123*12947SEnrico.Perla@Sun.COM 
1124*12947SEnrico.Perla@Sun.COM 		if (pread(device->part_fd, bpb_sect, SECTOR_SIZE, 0)
1125*12947SEnrico.Perla@Sun.COM 		    != SECTOR_SIZE) {
1126*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stderr, READ_FAIL_BPB);
1127*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
1128*12947SEnrico.Perla@Sun.COM 		}
1129*12947SEnrico.Perla@Sun.COM 		bcopy(bpb_sect + STAGE1_BPB_OFFSET,
1130*12947SEnrico.Perla@Sun.COM 		    install->stage1_buf + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
1131*12947SEnrico.Perla@Sun.COM 	}
1132*12947SEnrico.Perla@Sun.COM 
1133*12947SEnrico.Perla@Sun.COM 	/* copy MBR to stage1 in case of overwriting MBR sector. */
1134*12947SEnrico.Perla@Sun.COM 	bcopy(device->boot_sector + BOOTSZ, install->stage1_buf + BOOTSZ,
1135*12947SEnrico.Perla@Sun.COM 	    SECTOR_SIZE - BOOTSZ);
1136*12947SEnrico.Perla@Sun.COM 	/* modify default stage1 file generated by GRUB. */
1137*12947SEnrico.Perla@Sun.COM 	*((unsigned char *)(install->stage1_buf + STAGE1_FORCE_LBA)) = 1;
1138*12947SEnrico.Perla@Sun.COM 	*((ulong_t *)(install->stage1_buf + STAGE1_STAGE2_SECTOR))
1139*12947SEnrico.Perla@Sun.COM 	    = install->stage2.first_sector;
1140*12947SEnrico.Perla@Sun.COM 	*((ushort_t *)(install->stage1_buf + STAGE1_STAGE2_ADDRESS))
1141*12947SEnrico.Perla@Sun.COM 	    = STAGE2_MEMADDR;
1142*12947SEnrico.Perla@Sun.COM 	*((ushort_t *)(install->stage1_buf + STAGE1_STAGE2_SEGMENT))
1143*12947SEnrico.Perla@Sun.COM 	    = STAGE2_MEMADDR >> 4;
1144*12947SEnrico.Perla@Sun.COM 
1145*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
1146*12947SEnrico.Perla@Sun.COM }
11478434SEnrico.Perla@Sun.COM 
1148*12947SEnrico.Perla@Sun.COM /*
1149*12947SEnrico.Perla@Sun.COM  * Grab stage1 from the specified device file descriptor.
1150*12947SEnrico.Perla@Sun.COM  */
1151*12947SEnrico.Perla@Sun.COM static int
read_stage1_from_disk(int dev_fd,char * stage1_buf)1152*12947SEnrico.Perla@Sun.COM read_stage1_from_disk(int dev_fd, char *stage1_buf)
1153*12947SEnrico.Perla@Sun.COM {
1154*12947SEnrico.Perla@Sun.COM 	assert(stage1_buf != NULL);
1155*12947SEnrico.Perla@Sun.COM 
1156*12947SEnrico.Perla@Sun.COM 	if (read_in(dev_fd, stage1_buf, SECTOR_SIZE, 0) != BC_SUCCESS) {
1157*12947SEnrico.Perla@Sun.COM 		perror(gettext("Unable to read stage1 from disk"));
1158*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
1159*12947SEnrico.Perla@Sun.COM 	}
1160*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
1161*12947SEnrico.Perla@Sun.COM }
1162*12947SEnrico.Perla@Sun.COM 
1163*12947SEnrico.Perla@Sun.COM static int
read_stage2_from_disk(int dev_fd,ig_stage2_t * stage2)1164*12947SEnrico.Perla@Sun.COM read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2)
1165*12947SEnrico.Perla@Sun.COM {
1166*12947SEnrico.Perla@Sun.COM 	uint32_t		size;
1167*12947SEnrico.Perla@Sun.COM 	uint32_t		buf_size;
1168*12947SEnrico.Perla@Sun.COM 	uint32_t		mboot_off;
1169*12947SEnrico.Perla@Sun.COM 	multiboot_header_t	*mboot;
1170*12947SEnrico.Perla@Sun.COM 
1171*12947SEnrico.Perla@Sun.COM 	assert(stage2 != NULL);
1172*12947SEnrico.Perla@Sun.COM 	assert(dev_fd != -1);
1173*12947SEnrico.Perla@Sun.COM 
1174*12947SEnrico.Perla@Sun.COM 	if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan),
1175*12947SEnrico.Perla@Sun.COM 	    STAGE2_BLKOFF * SECTOR_SIZE) != BC_SUCCESS) {
1176*12947SEnrico.Perla@Sun.COM 		perror(gettext("Error reading stage2 sectors"));
1177*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
1178*12947SEnrico.Perla@Sun.COM 	}
1179*12947SEnrico.Perla@Sun.COM 
1180*12947SEnrico.Perla@Sun.COM 	/* No multiboot means no chance of knowing stage2 size */
1181*12947SEnrico.Perla@Sun.COM 	if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off)
1182*12947SEnrico.Perla@Sun.COM 	    != BC_SUCCESS) {
1183*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Unable to find multiboot header\n");
1184*12947SEnrico.Perla@Sun.COM 		return (BC_NOEXTRA);
1185*12947SEnrico.Perla@Sun.COM 	}
1186*12947SEnrico.Perla@Sun.COM 	mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
1187*12947SEnrico.Perla@Sun.COM 
1188*12947SEnrico.Perla@Sun.COM 	/*
1189*12947SEnrico.Perla@Sun.COM 	 * Unfilled mboot values mean an older version of installgrub installed
1190*12947SEnrico.Perla@Sun.COM 	 * the stage2. Again we have no chance of knowing stage2 size.
1191*12947SEnrico.Perla@Sun.COM 	 */
1192*12947SEnrico.Perla@Sun.COM 	if (mboot->load_end_addr == 0 ||
1193*12947SEnrico.Perla@Sun.COM 	    mboot->load_end_addr < mboot->load_addr)
1194*12947SEnrico.Perla@Sun.COM 		return (BC_NOEXTRA);
1195*12947SEnrico.Perla@Sun.COM 
1196*12947SEnrico.Perla@Sun.COM 	/*
1197*12947SEnrico.Perla@Sun.COM 	 * Currently, the amount of space reserved for extra information
1198*12947SEnrico.Perla@Sun.COM 	 * is "fixed". We may have to scan for the terminating extra payload
1199*12947SEnrico.Perla@Sun.COM 	 * in the future.
1200*12947SEnrico.Perla@Sun.COM 	 */
1201*12947SEnrico.Perla@Sun.COM 	size = mboot->load_end_addr - mboot->load_addr;
1202*12947SEnrico.Perla@Sun.COM 	buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
1203*12947SEnrico.Perla@Sun.COM 
1204*12947SEnrico.Perla@Sun.COM 	stage2->buf = malloc(buf_size);
1205*12947SEnrico.Perla@Sun.COM 	if (stage2->buf == NULL) {
1206*12947SEnrico.Perla@Sun.COM 		perror(gettext("Memory allocation failed"));
1207*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
1208*12947SEnrico.Perla@Sun.COM 	}
1209*12947SEnrico.Perla@Sun.COM 	stage2->buf_size = buf_size;
12108434SEnrico.Perla@Sun.COM 
1211*12947SEnrico.Perla@Sun.COM 	if (read_in(dev_fd, stage2->buf, buf_size, STAGE2_BLKOFF *
1212*12947SEnrico.Perla@Sun.COM 	    SECTOR_SIZE) != BC_SUCCESS) {
1213*12947SEnrico.Perla@Sun.COM 		perror("read");
1214*12947SEnrico.Perla@Sun.COM 		free(stage2->buf);
1215*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
1216*12947SEnrico.Perla@Sun.COM 	}
1217*12947SEnrico.Perla@Sun.COM 
1218*12947SEnrico.Perla@Sun.COM 	/* Update pointers. */
1219*12947SEnrico.Perla@Sun.COM 	stage2->file = stage2->buf;
1220*12947SEnrico.Perla@Sun.COM 	stage2->file_size = size;
1221*12947SEnrico.Perla@Sun.COM 	stage2->mboot_off = mboot_off;
1222*12947SEnrico.Perla@Sun.COM 	stage2->mboot = (multiboot_header_t *)(stage2->buf + stage2->mboot_off);
1223*12947SEnrico.Perla@Sun.COM 	stage2->extra = stage2->buf + P2ROUNDUP(stage2->file_size, 8);
1224*12947SEnrico.Perla@Sun.COM 
1225*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
1226*12947SEnrico.Perla@Sun.COM }
1227*12947SEnrico.Perla@Sun.COM 
1228*12947SEnrico.Perla@Sun.COM static boolean_t
is_update_necessary(ig_data_t * data,char * updt_str)1229*12947SEnrico.Perla@Sun.COM is_update_necessary(ig_data_t *data, char *updt_str)
1230*12947SEnrico.Perla@Sun.COM {
1231*12947SEnrico.Perla@Sun.COM 	bblk_einfo_t	*einfo;
1232*12947SEnrico.Perla@Sun.COM 	bblk_hs_t	stage2_hs;
1233*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	stage2_disk;
1234*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	*stage2_file = &data->stage2;
1235*12947SEnrico.Perla@Sun.COM 	ig_device_t	*device = &data->device;
1236*12947SEnrico.Perla@Sun.COM 	int		dev_fd = device->part_fd;
1237*12947SEnrico.Perla@Sun.COM 
1238*12947SEnrico.Perla@Sun.COM 	assert(data != NULL);
1239*12947SEnrico.Perla@Sun.COM 	assert(device->part_fd != -1);
1240*12947SEnrico.Perla@Sun.COM 
1241*12947SEnrico.Perla@Sun.COM 	bzero(&stage2_disk, sizeof (ig_stage2_t));
12428434SEnrico.Perla@Sun.COM 
1243*12947SEnrico.Perla@Sun.COM 	/* Gather stage2 (if present) from the target device. */
1244*12947SEnrico.Perla@Sun.COM 	if (read_stage2_from_disk(dev_fd, &stage2_disk) != BC_SUCCESS) {
1245*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Unable to read stage2 from %s\n", device->path);
1246*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("No multiboot wrapped stage2 on %s\n", device->path);
1247*12947SEnrico.Perla@Sun.COM 		return (B_TRUE);
1248*12947SEnrico.Perla@Sun.COM 	}
1249*12947SEnrico.Perla@Sun.COM 
1250*12947SEnrico.Perla@Sun.COM 	/*
1251*12947SEnrico.Perla@Sun.COM 	 * Look for the extended information structure in the extra payload
1252*12947SEnrico.Perla@Sun.COM 	 * area.
1253*12947SEnrico.Perla@Sun.COM 	 */
1254*12947SEnrico.Perla@Sun.COM 	einfo = find_einfo(stage2_disk.extra);
1255*12947SEnrico.Perla@Sun.COM 	if (einfo == NULL) {
1256*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("No extended information available\n");
1257*12947SEnrico.Perla@Sun.COM 		return (B_TRUE);
1258*12947SEnrico.Perla@Sun.COM 	}
1259*12947SEnrico.Perla@Sun.COM 
1260*12947SEnrico.Perla@Sun.COM 	if (!do_version || updt_str == NULL) {
1261*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, "WARNING: target device %s has a "
1262*12947SEnrico.Perla@Sun.COM 		    "versioned stage2 that is going to be overwritten by a non "
1263*12947SEnrico.Perla@Sun.COM 		    "versioned one\n", device->path);
1264*12947SEnrico.Perla@Sun.COM 		return (B_TRUE);
1265*12947SEnrico.Perla@Sun.COM 	}
1266*12947SEnrico.Perla@Sun.COM 
1267*12947SEnrico.Perla@Sun.COM 	if (force_update) {
1268*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Forcing update of %s bootblock\n", device->path);
1269*12947SEnrico.Perla@Sun.COM 		return (B_TRUE);
1270*12947SEnrico.Perla@Sun.COM 	}
1271*12947SEnrico.Perla@Sun.COM 
1272*12947SEnrico.Perla@Sun.COM 	/* Compare the two extended information structures. */
1273*12947SEnrico.Perla@Sun.COM 	stage2_hs.src_buf = (unsigned char *)stage2_file->file;
1274*12947SEnrico.Perla@Sun.COM 	stage2_hs.src_size = stage2_file->file_size;
1275*12947SEnrico.Perla@Sun.COM 
1276*12947SEnrico.Perla@Sun.COM 	return (einfo_should_update(einfo, &stage2_hs, updt_str));
12778434SEnrico.Perla@Sun.COM }
12788434SEnrico.Perla@Sun.COM 
12798434SEnrico.Perla@Sun.COM 
12800Sstevel@tonic-gate #define	START_BLOCK(pos)	(*(ulong_t *)(pos))
12810Sstevel@tonic-gate #define	NUM_BLOCK(pos)		(*(ushort_t *)((pos) + 4))
12820Sstevel@tonic-gate #define	START_SEG(pos)		(*(ushort_t *)((pos) + 6))
12830Sstevel@tonic-gate 
1284*12947SEnrico.Perla@Sun.COM static int
prepare_stage2(ig_data_t * install,char * updt_str)1285*12947SEnrico.Perla@Sun.COM prepare_stage2(ig_data_t *install, char *updt_str)
12860Sstevel@tonic-gate {
1287*12947SEnrico.Perla@Sun.COM 	ig_device_t	*device = &install->device;
1288*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	*stage2 = &install->stage2;
1289*12947SEnrico.Perla@Sun.COM 	uint32_t	mboot_off = 0;
1290*12947SEnrico.Perla@Sun.COM 
1291*12947SEnrico.Perla@Sun.COM 	assert(install != NULL);
1292*12947SEnrico.Perla@Sun.COM 	assert(stage2->file != NULL);
12938434SEnrico.Perla@Sun.COM 
1294*12947SEnrico.Perla@Sun.COM 	/* New stage2 files come with an embedded stage2. */
1295*12947SEnrico.Perla@Sun.COM 	if (find_multiboot(stage2->file, stage2->file_size, &mboot_off)
1296*12947SEnrico.Perla@Sun.COM 	    != BC_SUCCESS) {
1297*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("WARNING: no multiboot structure found in stage2, "
1298*12947SEnrico.Perla@Sun.COM 		    "are you using an old GRUB stage2?\n");
1299*12947SEnrico.Perla@Sun.COM 		if (do_version == B_TRUE) {
1300*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stderr, gettext("Versioning requested "
1301*12947SEnrico.Perla@Sun.COM 			    "but stage2 does not support it.. skipping.\n"));
1302*12947SEnrico.Perla@Sun.COM 			do_version = B_FALSE;
1303*12947SEnrico.Perla@Sun.COM 		}
1304*12947SEnrico.Perla@Sun.COM 	} else {
1305*12947SEnrico.Perla@Sun.COM 		/* Keep track of where the multiboot header is. */
1306*12947SEnrico.Perla@Sun.COM 		stage2->mboot_off = mboot_off;
1307*12947SEnrico.Perla@Sun.COM 		stage2->mboot = (multiboot_header_t *)(stage2->file +
1308*12947SEnrico.Perla@Sun.COM 		    mboot_off);
1309*12947SEnrico.Perla@Sun.COM 		if (do_version) {
1310*12947SEnrico.Perla@Sun.COM 			/*
1311*12947SEnrico.Perla@Sun.COM 			 * Adding stage2 information needs to happen before
1312*12947SEnrico.Perla@Sun.COM 			 * we modify the copy of stage2 we have in memory, so
1313*12947SEnrico.Perla@Sun.COM 			 * that the hashing reflects the one of the file.
1314*12947SEnrico.Perla@Sun.COM 			 * An error here is not fatal.
1315*12947SEnrico.Perla@Sun.COM 			 */
1316*12947SEnrico.Perla@Sun.COM 			add_stage2_einfo(stage2, updt_str);
1317*12947SEnrico.Perla@Sun.COM 		}
1318*12947SEnrico.Perla@Sun.COM 		/*
1319*12947SEnrico.Perla@Sun.COM 		 * Fill multiboot information. We add them even without
1320*12947SEnrico.Perla@Sun.COM 		 * versioning to support as much as possible mirroring.
1321*12947SEnrico.Perla@Sun.COM 		 */
1322*12947SEnrico.Perla@Sun.COM 		prepare_fake_multiboot(stage2);
13238434SEnrico.Perla@Sun.COM 	}
13240Sstevel@tonic-gate 
1325*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(device->type)) {
1326*12947SEnrico.Perla@Sun.COM 		uint32_t	blocklist[SECTOR_SIZE / sizeof (uint32_t)];
1327*12947SEnrico.Perla@Sun.COM 		uint32_t	install_addr = STAGE2_MEMADDR + SECTOR_SIZE;
1328*12947SEnrico.Perla@Sun.COM 		int		i = 0;
1329*12947SEnrico.Perla@Sun.COM 		uchar_t		*pos;
13300Sstevel@tonic-gate 
1331*12947SEnrico.Perla@Sun.COM 		bzero(blocklist, sizeof (blocklist));
1332*12947SEnrico.Perla@Sun.COM 		if (read_stage2_blocklist(device->part_fd, blocklist) != 0) {
1333*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stderr, gettext("Error reading pcfs "
1334*12947SEnrico.Perla@Sun.COM 			    "stage2 blocklist\n"));
1335*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
1336*12947SEnrico.Perla@Sun.COM 		}
13370Sstevel@tonic-gate 
1338*12947SEnrico.Perla@Sun.COM 		pos = (uchar_t *)stage2->file + STAGE2_BLOCKLIST;
1339*12947SEnrico.Perla@Sun.COM 		stage2->first_sector = device->start_sector + blocklist[0];
1340*12947SEnrico.Perla@Sun.COM 		stage2->pcfs_first_sectors[0] = blocklist[0];
1341*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
1342*12947SEnrico.Perla@Sun.COM 
1343*12947SEnrico.Perla@Sun.COM 
13440Sstevel@tonic-gate 		if (blocklist[1] > 1) {
13450Sstevel@tonic-gate 			blocklist[0]++;
13460Sstevel@tonic-gate 			blocklist[1]--;
13470Sstevel@tonic-gate 		} else {
13480Sstevel@tonic-gate 			i += 2;
13490Sstevel@tonic-gate 		}
13500Sstevel@tonic-gate 
1351*12947SEnrico.Perla@Sun.COM 		stage2->pcfs_first_sectors[1] = blocklist[i];
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 		while (blocklist[i]) {
13540Sstevel@tonic-gate 			if (START_BLOCK(pos - 8) != 0 &&
13550Sstevel@tonic-gate 			    START_BLOCK(pos - 8) != blocklist[i + 2]) {
13560Sstevel@tonic-gate 				(void) fprintf(stderr, PCFS_FRAGMENTED);
1357*12947SEnrico.Perla@Sun.COM 				return (BC_ERROR);
13580Sstevel@tonic-gate 			}
1359*12947SEnrico.Perla@Sun.COM 			START_BLOCK(pos) = blocklist[i] + device->start_sector;
13600Sstevel@tonic-gate 			START_SEG(pos) = (ushort_t)(install_addr >> 4);
13610Sstevel@tonic-gate 			NUM_BLOCK(pos) = blocklist[i + 1];
13620Sstevel@tonic-gate 			install_addr += blocklist[i + 1] * SECTOR_SIZE;
13630Sstevel@tonic-gate 			pos -= 8;
13640Sstevel@tonic-gate 			i += 2;
13650Sstevel@tonic-gate 		}
13660Sstevel@tonic-gate 	} else {
1367*12947SEnrico.Perla@Sun.COM 		/* Solaris VTOC */
1368*12947SEnrico.Perla@Sun.COM 		stage2->first_sector = device->start_sector + STAGE2_BLKOFF;
1369*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
13700Sstevel@tonic-gate 		/*
13710Sstevel@tonic-gate 		 * In a solaris partition, stage2 is written to contiguous
13720Sstevel@tonic-gate 		 * blocks. So we update the starting block only.
13730Sstevel@tonic-gate 		 */
1374*12947SEnrico.Perla@Sun.COM 		*((ulong_t *)(stage2->file + STAGE2_BLOCKLIST)) =
1375*12947SEnrico.Perla@Sun.COM 		    stage2->first_sector + 1;
13760Sstevel@tonic-gate 	}
13770Sstevel@tonic-gate 
1378*12947SEnrico.Perla@Sun.COM 	/* force lba and set disk partition */
1379*12947SEnrico.Perla@Sun.COM 	*((unsigned char *) (stage2->file + STAGE2_FORCE_LBA)) = 1;
1380*12947SEnrico.Perla@Sun.COM 	*((long *)(stage2->file + STAGE2_INSTALLPART))
1381*12947SEnrico.Perla@Sun.COM 	    = (device->partition << 16) | (device->slice << 8) | 0xff;
13820Sstevel@tonic-gate 
1383*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
1384*12947SEnrico.Perla@Sun.COM }
1385*12947SEnrico.Perla@Sun.COM 
1386*12947SEnrico.Perla@Sun.COM static int
find_x86_bootpar(struct mboot * mboot,int * part_num,uint32_t * start_sect)1387*12947SEnrico.Perla@Sun.COM find_x86_bootpar(struct mboot *mboot, int *part_num, uint32_t *start_sect)
1388*12947SEnrico.Perla@Sun.COM {
1389*12947SEnrico.Perla@Sun.COM 	int	i;
13900Sstevel@tonic-gate 
1391*12947SEnrico.Perla@Sun.COM 	for (i = 0; i < FD_NUMPART; i++) {
1392*12947SEnrico.Perla@Sun.COM 		struct ipart	*part;
1393*12947SEnrico.Perla@Sun.COM 
1394*12947SEnrico.Perla@Sun.COM 		part = (struct ipart *)mboot->parts + i;
1395*12947SEnrico.Perla@Sun.COM 		if (part->systid == 0xbe) {
1396*12947SEnrico.Perla@Sun.COM 			if (start_sect)
1397*12947SEnrico.Perla@Sun.COM 				*start_sect = part->relsect;
1398*12947SEnrico.Perla@Sun.COM 			if (part_num)
1399*12947SEnrico.Perla@Sun.COM 				*part_num = i;
1400*12947SEnrico.Perla@Sun.COM 			/* solaris boot part */
1401*12947SEnrico.Perla@Sun.COM 			return (BC_SUCCESS);
14020Sstevel@tonic-gate 		}
14030Sstevel@tonic-gate 	}
1404*12947SEnrico.Perla@Sun.COM 	return (BC_ERROR);
14050Sstevel@tonic-gate }
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate static char *
get_raw_partition_path(ig_device_t * device)1408*12947SEnrico.Perla@Sun.COM get_raw_partition_path(ig_device_t *device)
14090Sstevel@tonic-gate {
1410*12947SEnrico.Perla@Sun.COM 	char	*raw;
1411*12947SEnrico.Perla@Sun.COM 	int	len;
14120Sstevel@tonic-gate 
1413*12947SEnrico.Perla@Sun.COM 	if (is_bootpar(device->type)) {
1414*12947SEnrico.Perla@Sun.COM 		int		part;
1415*12947SEnrico.Perla@Sun.COM 		struct mboot	*mboot;
14160Sstevel@tonic-gate 
1417*12947SEnrico.Perla@Sun.COM 		mboot = (struct mboot *)device->boot_sector;
1418*12947SEnrico.Perla@Sun.COM 		if (find_x86_bootpar(mboot, &part, NULL) != BC_SUCCESS) {
1419*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stderr, BOOTPAR_NOTFOUND,
1420*12947SEnrico.Perla@Sun.COM 			    device->path_p0);
1421*12947SEnrico.Perla@Sun.COM 			return (NULL);
14220Sstevel@tonic-gate 		}
14230Sstevel@tonic-gate 
1424*12947SEnrico.Perla@Sun.COM 		raw = strdup(device->path_p0);
1425*12947SEnrico.Perla@Sun.COM 		if (raw == NULL) {
1426*12947SEnrico.Perla@Sun.COM 			perror(gettext("Memory allocation failed"));
1427*12947SEnrico.Perla@Sun.COM 			return (NULL);
14280Sstevel@tonic-gate 		}
1429*12947SEnrico.Perla@Sun.COM 
1430*12947SEnrico.Perla@Sun.COM 		raw[strlen(raw) - 2] = '1' + part;
14310Sstevel@tonic-gate 		return (raw);
14320Sstevel@tonic-gate 	}
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 	/* For disk, remember slice and return whole fdisk partition  */
1435*12947SEnrico.Perla@Sun.COM 	raw = strdup(device->path);
1436*12947SEnrico.Perla@Sun.COM 	if (raw == NULL) {
1437*12947SEnrico.Perla@Sun.COM 		perror(gettext("Memory allocation failed"));
1438*12947SEnrico.Perla@Sun.COM 		return (NULL);
1439*12947SEnrico.Perla@Sun.COM 	}
1440*12947SEnrico.Perla@Sun.COM 
14410Sstevel@tonic-gate 	len = strlen(raw);
14420Sstevel@tonic-gate 	if (raw[len - 2] != 's' || raw[len - 1] == '2') {
14430Sstevel@tonic-gate 		(void) fprintf(stderr, NOT_ROOT_SLICE);
1444*12947SEnrico.Perla@Sun.COM 		free(raw);
1445*12947SEnrico.Perla@Sun.COM 		return (NULL);
14460Sstevel@tonic-gate 	}
1447*12947SEnrico.Perla@Sun.COM 	device->slice = atoi(&raw[len - 1]);
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	raw[len - 2] = 's';
14500Sstevel@tonic-gate 	raw[len - 1] = '2';
1451*12947SEnrico.Perla@Sun.COM 
14520Sstevel@tonic-gate 	return (raw);
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate 
1455*12947SEnrico.Perla@Sun.COM static int
get_raw_partition_fd(ig_device_t * device)1456*12947SEnrico.Perla@Sun.COM get_raw_partition_fd(ig_device_t *device)
1457*12947SEnrico.Perla@Sun.COM {
1458*12947SEnrico.Perla@Sun.COM 	struct stat	stat = {0};
1459*12947SEnrico.Perla@Sun.COM 	char		*raw;
1460*12947SEnrico.Perla@Sun.COM 
1461*12947SEnrico.Perla@Sun.COM 	raw = get_raw_partition_path(device);
1462*12947SEnrico.Perla@Sun.COM 	if (raw == NULL)
1463*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
1464*12947SEnrico.Perla@Sun.COM 
1465*12947SEnrico.Perla@Sun.COM 	if (nowrite)
1466*12947SEnrico.Perla@Sun.COM 		device->part_fd = open(raw, O_RDONLY);
1467*12947SEnrico.Perla@Sun.COM 	else
1468*12947SEnrico.Perla@Sun.COM 		device->part_fd = open(raw, O_RDWR);
1469*12947SEnrico.Perla@Sun.COM 
1470*12947SEnrico.Perla@Sun.COM 	if (device->part_fd < 0 || fstat(device->part_fd, &stat) != 0) {
1471*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, OPEN_FAIL, raw);
1472*12947SEnrico.Perla@Sun.COM 		free(raw);
1473*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
1474*12947SEnrico.Perla@Sun.COM 	}
1475*12947SEnrico.Perla@Sun.COM 
1476*12947SEnrico.Perla@Sun.COM 	if (S_ISCHR(stat.st_mode) == 0) {
1477*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, NOT_RAW_DEVICE, raw);
1478*12947SEnrico.Perla@Sun.COM 		(void) close(device->part_fd);
1479*12947SEnrico.Perla@Sun.COM 		device->part_fd = -1;
1480*12947SEnrico.Perla@Sun.COM 		free(raw);
1481*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
1482*12947SEnrico.Perla@Sun.COM 	}
1483*12947SEnrico.Perla@Sun.COM 
1484*12947SEnrico.Perla@Sun.COM 	free(raw);
1485*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
1486*12947SEnrico.Perla@Sun.COM }
1487*12947SEnrico.Perla@Sun.COM 
14880Sstevel@tonic-gate #define	TMP_MNTPT	"/tmp/installgrub_pcfs"
1489*12947SEnrico.Perla@Sun.COM static int
copy_stage2_to_pcfs(ig_data_t * install)1490*12947SEnrico.Perla@Sun.COM copy_stage2_to_pcfs(ig_data_t *install)
14910Sstevel@tonic-gate {
1492*12947SEnrico.Perla@Sun.COM 	FILE		*mntfp;
1493*12947SEnrico.Perla@Sun.COM 	int		pcfs_fp;
1494*12947SEnrico.Perla@Sun.COM 	int		status = BC_ERROR;
1495*12947SEnrico.Perla@Sun.COM 	char		buf[SECTOR_SIZE];
1496*12947SEnrico.Perla@Sun.COM 	char		*cp;
1497*12947SEnrico.Perla@Sun.COM 	struct mnttab	mp = {0}, mpref = {0};
1498*12947SEnrico.Perla@Sun.COM 	ig_device_t	*device = &install->device;
1499*12947SEnrico.Perla@Sun.COM 	ig_stage2_t	*stage2 = &install->stage2;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	/* convert raw to block device name by removing the first 'r' */
1502*12947SEnrico.Perla@Sun.COM 	(void) strncpy(buf, device->path, sizeof (buf));
15030Sstevel@tonic-gate 	buf[sizeof (buf) - 1] = 0;
15040Sstevel@tonic-gate 	cp = strchr(buf, 'r');
15050Sstevel@tonic-gate 	if (cp == NULL) {
1506*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, CONVERT_FAIL, device->path);
1507*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 	do {
15100Sstevel@tonic-gate 		*cp = *(cp + 1);
15110Sstevel@tonic-gate 	} while (*(++cp));
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	/* get the mount point, if any */
15140Sstevel@tonic-gate 	mntfp = fopen("/etc/mnttab", "r");
15150Sstevel@tonic-gate 	if (mntfp == NULL) {
15160Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL_FILE, "/etc/mnttab");
1517*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
15180Sstevel@tonic-gate 	}
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	mpref.mnt_special = buf;
15210Sstevel@tonic-gate 	if (getmntany(mntfp, &mp, &mpref) != 0) {
15220Sstevel@tonic-gate 		char cmd[128];
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 		/* not mounted, try remount */
15250Sstevel@tonic-gate 		(void) mkdir(TMP_MNTPT, S_IRWXU);
15260Sstevel@tonic-gate 		(void) snprintf(cmd, sizeof (cmd), "mount -F pcfs %s %s",
15270Sstevel@tonic-gate 		    buf, TMP_MNTPT);
15280Sstevel@tonic-gate 		(void) system(cmd);
15290Sstevel@tonic-gate 		rewind(mntfp);
15300Sstevel@tonic-gate 		bzero(&mp, sizeof (mp));
15310Sstevel@tonic-gate 		if (getmntany(mntfp, &mp, &mpref) != 0) {
15320Sstevel@tonic-gate 			(void) fprintf(stderr, MOUNT_FAIL, buf);
1533*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
15340Sstevel@tonic-gate 		}
15350Sstevel@tonic-gate 	}
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf),
15380Sstevel@tonic-gate 	    "%s/boot", mp.mnt_mountp);
15390Sstevel@tonic-gate 	(void) mkdir(buf, S_IRWXU);
15400Sstevel@tonic-gate 	(void) strcat(buf, "/grub");
15410Sstevel@tonic-gate 	(void) mkdir(buf, S_IRWXU);
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 	(void) strcat(buf, "/stage2");
15440Sstevel@tonic-gate 	pcfs_fp = open(buf, O_WRONLY | O_CREAT, S_IRWXU);
15450Sstevel@tonic-gate 	if (pcfs_fp == -1) {
15460Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL_FILE, buf);
15470Sstevel@tonic-gate 		perror("open:");
1548*12947SEnrico.Perla@Sun.COM 		goto out;
15490Sstevel@tonic-gate 	}
15500Sstevel@tonic-gate 
1551*12947SEnrico.Perla@Sun.COM 	/* write stage2 to the pcfs mounted filesystem. */
1552*12947SEnrico.Perla@Sun.COM 	if (write(pcfs_fp, stage2->file, stage2->file_size)
1553*12947SEnrico.Perla@Sun.COM 	    != stage2->file_size) {
1554*12947SEnrico.Perla@Sun.COM 		perror(gettext("Error writing stage2"));
1555*12947SEnrico.Perla@Sun.COM 		goto out;
15560Sstevel@tonic-gate 	}
1557*12947SEnrico.Perla@Sun.COM 
1558*12947SEnrico.Perla@Sun.COM 	status = BC_SUCCESS;
1559*12947SEnrico.Perla@Sun.COM out_fd:
15600Sstevel@tonic-gate 	(void) close(pcfs_fp);
1561*12947SEnrico.Perla@Sun.COM out:
15620Sstevel@tonic-gate 	(void) umount(TMP_MNTPT);
1563*12947SEnrico.Perla@Sun.COM 	(void) rmdir(TMP_MNTPT);
1564*12947SEnrico.Perla@Sun.COM 	return (status);
15650Sstevel@tonic-gate }
1566