17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*d33344bbSsy  * Common Development and Distribution License (the "License").
6*d33344bbSsy  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*d33344bbSsy  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <libgen.h>
317c478bd9Sstevel@tonic-gate #include <malloc.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/stat.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <unistd.h>
377c478bd9Sstevel@tonic-gate #include <strings.h>
387c478bd9Sstevel@tonic-gate #include <sys/mount.h>
397c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
407c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
41*d33344bbSsy #include <sys/dkio.h>
42*d33344bbSsy #include <sys/vtoc.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <libintl.h>
457c478bd9Sstevel@tonic-gate #include <locale.h>
467c478bd9Sstevel@tonic-gate #include "message.h"
47c6fe1048Sjongkis #include <errno.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #ifndef	TEXT_DOMAIN
507c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
517c478bd9Sstevel@tonic-gate #endif
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #define	SECTOR_SIZE	0x200
547c478bd9Sstevel@tonic-gate #define	STAGE2_MEMADDR	0x8000	/* loading addr of stage2 */
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #define	STAGE1_BPB_OFFSET	0x3
577c478bd9Sstevel@tonic-gate #define	STAGE1_BPB_SIZE		0x3B
587c478bd9Sstevel@tonic-gate #define	STAGE1_BOOT_DRIVE	0x40
597c478bd9Sstevel@tonic-gate #define	STAGE1_FORCE_LBA	0x41
607c478bd9Sstevel@tonic-gate #define	STAGE1_STAGE2_ADDRESS	0x42
617c478bd9Sstevel@tonic-gate #define	STAGE1_STAGE2_SECTOR	0x44
627c478bd9Sstevel@tonic-gate #define	STAGE1_STAGE2_SEGMENT	0x48
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #define	STAGE2_BLOCKLIST	(SECTOR_SIZE - 0x8)
657c478bd9Sstevel@tonic-gate #define	STAGE2_INSTALLPART	(SECTOR_SIZE + 0x8)
667c478bd9Sstevel@tonic-gate #define	STAGE2_FORCE_LBA	(SECTOR_SIZE + 0x11)
677c478bd9Sstevel@tonic-gate #define	STAGE2_VER_STRING	(SECTOR_SIZE + 0x12)
687c478bd9Sstevel@tonic-gate #define	STAGE2_BLKOFF		50	/* offset from start of fdisk part */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static int nowrite = 0;
717c478bd9Sstevel@tonic-gate static int write_mboot = 0;
727c478bd9Sstevel@tonic-gate static int force_mboot = 0;
737c478bd9Sstevel@tonic-gate static int is_floppy = 0;
747c478bd9Sstevel@tonic-gate static int is_bootpar = 0;
757c478bd9Sstevel@tonic-gate static int stage2_fd;
767c478bd9Sstevel@tonic-gate static int partition, slice = 0xff;
777c478bd9Sstevel@tonic-gate static int stage2_first_sector, stage2_second_sector;
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate static char bpb_sect[SECTOR_SIZE];
817c478bd9Sstevel@tonic-gate static char boot_sect[SECTOR_SIZE];
827c478bd9Sstevel@tonic-gate static char stage1_buffer[SECTOR_SIZE];
837c478bd9Sstevel@tonic-gate static char stage2_buffer[2 * SECTOR_SIZE];
847c478bd9Sstevel@tonic-gate static int blocklist[SECTOR_SIZE / sizeof (int)];
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate static int open_device(char *);
877c478bd9Sstevel@tonic-gate static void read_bpb_sect(int);
887c478bd9Sstevel@tonic-gate static void read_boot_sect(char *);
897c478bd9Sstevel@tonic-gate static void write_boot_sect(char *);
907c478bd9Sstevel@tonic-gate static void read_stage1_stage2(char *, char *);
917c478bd9Sstevel@tonic-gate static void modify_and_write_stage1(int);
927c478bd9Sstevel@tonic-gate static void modify_and_write_stage2(int);
93*d33344bbSsy static int get_start_sector(int);
947c478bd9Sstevel@tonic-gate static void copy_stage2(int, char *);
957c478bd9Sstevel@tonic-gate static char *get_raw_partition(char *);
967c478bd9Sstevel@tonic-gate static void usage(char *);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate extern int read_stage2_blocklist(int, int *);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate int
1017c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate 	int dev_fd, opt;
1047c478bd9Sstevel@tonic-gate 	char *stage1, *stage2, *device;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1077c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "fmn")) != EOF) {
1107c478bd9Sstevel@tonic-gate 		switch (opt) {
1117c478bd9Sstevel@tonic-gate 		case 'm':
1127c478bd9Sstevel@tonic-gate 			write_mboot = 1;
1137c478bd9Sstevel@tonic-gate 			break;
1147c478bd9Sstevel@tonic-gate 		case 'n':
1157c478bd9Sstevel@tonic-gate 			nowrite = 1;
1167c478bd9Sstevel@tonic-gate 			break;
1177c478bd9Sstevel@tonic-gate 		case 'f':
1187c478bd9Sstevel@tonic-gate 			force_mboot = 1;
1197c478bd9Sstevel@tonic-gate 			break;
1207c478bd9Sstevel@tonic-gate 		default:
1217c478bd9Sstevel@tonic-gate 			/* fall through to process non-optional args */
1227c478bd9Sstevel@tonic-gate 			break;
1237c478bd9Sstevel@tonic-gate 		}
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	/* check arguments */
1277c478bd9Sstevel@tonic-gate 	if (argc != optind + 3) {
1287c478bd9Sstevel@tonic-gate 		usage(argv[0]);
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	if (nowrite) {
1327c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, DRY_RUN);
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	stage1 = strdup(argv[optind]);
1367c478bd9Sstevel@tonic-gate 	stage2 = strdup(argv[optind + 1]);
1377c478bd9Sstevel@tonic-gate 	device = strdup(argv[optind + 2]);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	if (!stage1 || !stage2 || !device) {
1407c478bd9Sstevel@tonic-gate 		usage(argv[0]);
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	/* open and check device type */
1447c478bd9Sstevel@tonic-gate 	dev_fd = open_device(device);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	/* read in stage1 and stage2 into buffer */
1477c478bd9Sstevel@tonic-gate 	read_stage1_stage2(stage1, stage2);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	/* In the pcfs case, write a fresh stage2 */
1507c478bd9Sstevel@tonic-gate 	if (is_floppy || is_bootpar) {
1517c478bd9Sstevel@tonic-gate 		copy_stage2(dev_fd, device);
1527c478bd9Sstevel@tonic-gate 		read_bpb_sect(dev_fd);
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/* read in boot sector */
1567c478bd9Sstevel@tonic-gate 	if (!is_floppy)
1577c478bd9Sstevel@tonic-gate 		read_boot_sect(device);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	/* modify stage1 based on grub needs */
1607c478bd9Sstevel@tonic-gate 	modify_and_write_stage1(dev_fd);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/* modify stage2 and write to media */
1637c478bd9Sstevel@tonic-gate 	modify_and_write_stage2(dev_fd);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	if (!is_floppy && write_mboot)
1667c478bd9Sstevel@tonic-gate 		write_boot_sect(device);
1677c478bd9Sstevel@tonic-gate 	(void) close(dev_fd);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	return (0);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate static int
173*d33344bbSsy get_start_sector(int fd)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	static int start_sect = 0;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	int i;
1787c478bd9Sstevel@tonic-gate 	struct mboot *mboot;
1797c478bd9Sstevel@tonic-gate 	struct ipart *part;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (start_sect)
1827c478bd9Sstevel@tonic-gate 		return (start_sect);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	mboot = (struct mboot *)boot_sect;
1857c478bd9Sstevel@tonic-gate 	for (i = 0; i < FD_NUMPART; i++) {
1867c478bd9Sstevel@tonic-gate 		part = (struct ipart *)mboot->parts + i;
1877c478bd9Sstevel@tonic-gate 		if (is_bootpar) {
1887c478bd9Sstevel@tonic-gate 			if (part->systid == 0xbe)
1897c478bd9Sstevel@tonic-gate 				break;
190*d33344bbSsy 		}
191*d33344bbSsy 	}
192*d33344bbSsy 
193*d33344bbSsy 	/*
194*d33344bbSsy 	 * If there is no boot partition, find the solaris partition
195*d33344bbSsy 	 */
196*d33344bbSsy 
197*d33344bbSsy 	if (i == FD_NUMPART) {
198*d33344bbSsy 		struct part_info dkpi;
199*d33344bbSsy 
200*d33344bbSsy 		/*
201*d33344bbSsy 		 * Get the solaris partition information from the device
202*d33344bbSsy 		 * and compare the offset of S2 with offset of solaris partition
203*d33344bbSsy 		 * from fdisk partition table.
204*d33344bbSsy 		 */
205*d33344bbSsy 		if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) {
206*d33344bbSsy 			(void) fprintf(stderr, PART_FAIL);
207*d33344bbSsy 			exit(-1);
208*d33344bbSsy 		}
209*d33344bbSsy 
210*d33344bbSsy 		for (i = 0; i < FD_NUMPART; i++) {
211*d33344bbSsy 			part = (struct ipart *)mboot->parts + i;
212*d33344bbSsy 
213*d33344bbSsy 			if (part->relsect == 0) {
214*d33344bbSsy 				(void) fprintf(stderr, BAD_PART, i);
215*d33344bbSsy 				exit(-1);
216*d33344bbSsy 			}
217*d33344bbSsy 			if (part->relsect == dkpi.p_start) {
218*d33344bbSsy 				/* Found the partition */
2197c478bd9Sstevel@tonic-gate 				break;
220*d33344bbSsy 			} else if (part->relsect > dkpi.p_start) {
221*d33344bbSsy 				/*
222*d33344bbSsy 				 * The next fdisk partition starts beyond
223*d33344bbSsy 				 * offset of Solaris partition.
224*d33344bbSsy 				 * So the previous partition is the right one.
225*d33344bbSsy 				 */
226*d33344bbSsy 				i--;
227*d33344bbSsy 				part = (struct ipart *)mboot->parts + i;
228*d33344bbSsy 				break;
229*d33344bbSsy 			}
2307c478bd9Sstevel@tonic-gate 		}
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	if (i == FD_NUMPART) {
2347c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, BOOTPAR);
2357c478bd9Sstevel@tonic-gate 		exit(-1);
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	/* get confirmation for -m */
2397c478bd9Sstevel@tonic-gate 	if (write_mboot && !force_mboot) {
2407c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, MBOOT_PROMPT);
2417c478bd9Sstevel@tonic-gate 		if (getchar() != 'y') {
2427c478bd9Sstevel@tonic-gate 			write_mboot = 0;
2437c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, MBOOT_NOT_UPDATED);
2447c478bd9Sstevel@tonic-gate 		}
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	start_sect = part->relsect;
2487c478bd9Sstevel@tonic-gate 	if (part->bootid != 128 && write_mboot == 0) {
2497c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, BOOTPAR_INACTIVE, i + 1);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	partition = i;
2537c478bd9Sstevel@tonic-gate 	return (start_sect);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate static void
2577c478bd9Sstevel@tonic-gate usage(char *progname)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, USAGE, basename(progname));
2607c478bd9Sstevel@tonic-gate 	exit(-1);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate static int
2647c478bd9Sstevel@tonic-gate open_device(char *device)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	int dev_fd;
2677c478bd9Sstevel@tonic-gate 	struct stat stat;
2687c478bd9Sstevel@tonic-gate 	char *raw_part;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	is_floppy = strncmp(device, "/dev/rdsk", strlen("/dev/rdsk")) &&
2717c478bd9Sstevel@tonic-gate 	    strncmp(device, "/dev/dsk", strlen("/dev/dsk"));
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	/* handle boot partition specification */
2747c478bd9Sstevel@tonic-gate 	if (!is_floppy && strstr(device, "p0:boot")) {
2757c478bd9Sstevel@tonic-gate 		is_bootpar = 1;
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	raw_part = get_raw_partition(device);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	if (nowrite)
2817c478bd9Sstevel@tonic-gate 		dev_fd = open(raw_part, O_RDONLY);
2827c478bd9Sstevel@tonic-gate 	else
2837c478bd9Sstevel@tonic-gate 		dev_fd = open(raw_part, O_RDWR);
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	if (dev_fd == -1 || fstat(dev_fd, &stat) != 0) {
2867c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL, raw_part);
2877c478bd9Sstevel@tonic-gate 		exit(-1);
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 	if (S_ISCHR(stat.st_mode) == 0) {
2907c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, NOT_RAW_DEVICE, raw_part);
2917c478bd9Sstevel@tonic-gate 		exit(-1);
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	return (dev_fd);
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate static void
2987c478bd9Sstevel@tonic-gate read_stage1_stage2(char *stage1, char *stage2)
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate 	int fd;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/* read the stage1 file from filesystem */
3037c478bd9Sstevel@tonic-gate 	fd = open(stage1, O_RDONLY);
3047c478bd9Sstevel@tonic-gate 	if (fd == -1 || read(fd, stage1_buffer, SECTOR_SIZE) != SECTOR_SIZE) {
3057c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_STAGE1, stage1);
3067c478bd9Sstevel@tonic-gate 		exit(-1);
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 	(void) close(fd);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/* read first two blocks of stage 2 from filesystem */
3117c478bd9Sstevel@tonic-gate 	stage2_fd = open(stage2, O_RDONLY);
3127c478bd9Sstevel@tonic-gate 	if (stage2_fd == -1 ||
3137c478bd9Sstevel@tonic-gate 	    read(stage2_fd, stage2_buffer, 2 * SECTOR_SIZE)
3147c478bd9Sstevel@tonic-gate 	    != 2 * SECTOR_SIZE) {
3157c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_STAGE2, stage2);
3167c478bd9Sstevel@tonic-gate 		exit(-1);
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 	/* leave the stage2 file open for later */
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate static void
3227c478bd9Sstevel@tonic-gate read_bpb_sect(int dev_fd)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate 	if (pread(dev_fd, bpb_sect, SECTOR_SIZE, 0) != SECTOR_SIZE) {
3257c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_BPB);
3267c478bd9Sstevel@tonic-gate 		exit(-1);
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate static void
3317c478bd9Sstevel@tonic-gate read_boot_sect(char *device)
3327c478bd9Sstevel@tonic-gate {
3337c478bd9Sstevel@tonic-gate 	static int read_mbr = 0;
3347c478bd9Sstevel@tonic-gate 	int i, fd;
3357c478bd9Sstevel@tonic-gate 	char save[2];
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	if (read_mbr)
3387c478bd9Sstevel@tonic-gate 		return;
3397c478bd9Sstevel@tonic-gate 	read_mbr = 1;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	/* get the whole disk (p0) */
3427c478bd9Sstevel@tonic-gate 	i = strlen(device);
3437c478bd9Sstevel@tonic-gate 	save[0] = device[i - 2];
3447c478bd9Sstevel@tonic-gate 	save[1] = device[i - 1];
3457c478bd9Sstevel@tonic-gate 	device[i - 2] = 'p';
3467c478bd9Sstevel@tonic-gate 	device[i - 1] = '0';
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	fd = open(device, O_RDONLY);
3497c478bd9Sstevel@tonic-gate 	if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) {
3507c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_MBR, device);
3517c478bd9Sstevel@tonic-gate 		if (fd == -1)
3527c478bd9Sstevel@tonic-gate 			perror("open");
3537c478bd9Sstevel@tonic-gate 		else
3547c478bd9Sstevel@tonic-gate 			perror("read");
3557c478bd9Sstevel@tonic-gate 		exit(-1);
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate 	(void) close(fd);
3587c478bd9Sstevel@tonic-gate 	device[i - 2] = save[0];
3597c478bd9Sstevel@tonic-gate 	device[i - 1] = save[1];
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate static void
3637c478bd9Sstevel@tonic-gate write_boot_sect(char *device)
3647c478bd9Sstevel@tonic-gate {
3657c478bd9Sstevel@tonic-gate 	int fd, len;
3667c478bd9Sstevel@tonic-gate 	char *raw, *end;
3677c478bd9Sstevel@tonic-gate 	struct stat stat;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	/* make a copy and chop off ":boot" */
3707c478bd9Sstevel@tonic-gate 	raw = strdup(device);
3717c478bd9Sstevel@tonic-gate 	end = strstr(raw, "p0:boot");
3727c478bd9Sstevel@tonic-gate 	if (end)
3737c478bd9Sstevel@tonic-gate 		end[2] = 0;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	/* open p0 (whole disk) */
3767c478bd9Sstevel@tonic-gate 	len = strlen(raw);
3777c478bd9Sstevel@tonic-gate 	raw[len - 2] = 'p';
3787c478bd9Sstevel@tonic-gate 	raw[len - 1] = '0';
3797c478bd9Sstevel@tonic-gate 	fd = open(raw, O_WRONLY);
3807c478bd9Sstevel@tonic-gate 	if (fd == -1 || fstat(fd, &stat) != 0) {
3817c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL, raw);
3827c478bd9Sstevel@tonic-gate 		exit(-1);
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 	if (!nowrite &&
3857c478bd9Sstevel@tonic-gate 	    pwrite(fd, stage1_buffer, SECTOR_SIZE, 0) != SECTOR_SIZE) {
3867c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, WRITE_FAIL_BOOTSEC);
3877c478bd9Sstevel@tonic-gate 		exit(-1);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, WRITE_MBOOT);
3907c478bd9Sstevel@tonic-gate 	(void) close(fd);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate static void
3947c478bd9Sstevel@tonic-gate modify_and_write_stage1(int dev_fd)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	if (is_floppy) {
3977c478bd9Sstevel@tonic-gate 		stage2_first_sector = blocklist[0];
3987c478bd9Sstevel@tonic-gate 		/* copy bios parameter block (for fat fs) */
3997c478bd9Sstevel@tonic-gate 		bcopy(bpb_sect + STAGE1_BPB_OFFSET,
4007c478bd9Sstevel@tonic-gate 		    stage1_buffer + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
4017c478bd9Sstevel@tonic-gate 	} else if (is_bootpar) {
402*d33344bbSsy 		stage2_first_sector = get_start_sector(dev_fd) + blocklist[0];
4037c478bd9Sstevel@tonic-gate 		/* copy bios parameter block (for fat fs) and MBR */
4047c478bd9Sstevel@tonic-gate 		bcopy(bpb_sect + STAGE1_BPB_OFFSET,
4057c478bd9Sstevel@tonic-gate 		    stage1_buffer + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
4067c478bd9Sstevel@tonic-gate 		bcopy(boot_sect + BOOTSZ, stage1_buffer + BOOTSZ, 512 - BOOTSZ);
4077c478bd9Sstevel@tonic-gate 		*((unsigned char *)(stage1_buffer + STAGE1_FORCE_LBA)) = 1;
4087c478bd9Sstevel@tonic-gate 	} else {
409*d33344bbSsy 		stage2_first_sector = get_start_sector(dev_fd) + STAGE2_BLKOFF;
4107c478bd9Sstevel@tonic-gate 		/* copy MBR to stage1 in case of overwriting MBR sector */
4117c478bd9Sstevel@tonic-gate 		bcopy(boot_sect + BOOTSZ, stage1_buffer + BOOTSZ, 512 - BOOTSZ);
4127c478bd9Sstevel@tonic-gate 		*((unsigned char *)(stage1_buffer + STAGE1_FORCE_LBA)) = 1;
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/* modify default stage1 file generated by GRUB */
4167c478bd9Sstevel@tonic-gate 	*((ulong_t *)(stage1_buffer + STAGE1_STAGE2_SECTOR))
417*d33344bbSsy 	    = stage2_first_sector;
4187c478bd9Sstevel@tonic-gate 	*((ushort_t *)(stage1_buffer + STAGE1_STAGE2_ADDRESS))
419*d33344bbSsy 	    = STAGE2_MEMADDR;
4207c478bd9Sstevel@tonic-gate 	*((ushort_t *)(stage1_buffer + STAGE1_STAGE2_SEGMENT))
421*d33344bbSsy 	    = STAGE2_MEMADDR >> 4;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	/*
4247c478bd9Sstevel@tonic-gate 	 * XXX the default grub distribution also:
4257c478bd9Sstevel@tonic-gate 	 * - Copy the possible MBR/extended part table
4267c478bd9Sstevel@tonic-gate 	 * - Set the boot drive of stage1
4277c478bd9Sstevel@tonic-gate 	 */
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	/* write stage1/pboot to 1st sector */
4307c478bd9Sstevel@tonic-gate 	if (!nowrite &&
4317c478bd9Sstevel@tonic-gate 	    pwrite(dev_fd, stage1_buffer, SECTOR_SIZE, 0) != SECTOR_SIZE) {
4327c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, WRITE_FAIL_PBOOT);
4337c478bd9Sstevel@tonic-gate 		exit(-1);
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	if (is_floppy) {
4377c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, WRITE_BOOTSEC_FLOPPY);
4387c478bd9Sstevel@tonic-gate 	} else {
4397c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, WRITE_PBOOT,
440*d33344bbSsy 		    partition, get_start_sector(dev_fd));
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate #define	START_BLOCK(pos)	(*(ulong_t *)(pos))
4457c478bd9Sstevel@tonic-gate #define	NUM_BLOCK(pos)		(*(ushort_t *)((pos) + 4))
4467c478bd9Sstevel@tonic-gate #define	START_SEG(pos)		(*(ushort_t *)((pos) + 6))
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate static void
4497c478bd9Sstevel@tonic-gate modify_and_write_stage2(int dev_fd)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	int nrecord;
4527c478bd9Sstevel@tonic-gate 	off_t offset;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (is_floppy || is_bootpar) {
4557c478bd9Sstevel@tonic-gate 		int i = 0;
4567c478bd9Sstevel@tonic-gate 		uint_t partition_offset;
4577c478bd9Sstevel@tonic-gate 		uint_t install_addr = 0x8200;
4587c478bd9Sstevel@tonic-gate 		uchar_t *pos = (uchar_t *)stage2_buffer + STAGE2_BLOCKLIST;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 		stage2_first_sector = blocklist[0];
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 		/* figure out the second sector */
4637c478bd9Sstevel@tonic-gate 		if (blocklist[1] > 1) {
4647c478bd9Sstevel@tonic-gate 			blocklist[0]++;
4657c478bd9Sstevel@tonic-gate 			blocklist[1]--;
4667c478bd9Sstevel@tonic-gate 		} else {
4677c478bd9Sstevel@tonic-gate 			i += 2;
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 		stage2_second_sector = blocklist[i];
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 		if (is_floppy)
4727c478bd9Sstevel@tonic-gate 			partition_offset = 0;
4737c478bd9Sstevel@tonic-gate 		else	/* solaris boot partition */
474*d33344bbSsy 			partition_offset = get_start_sector(dev_fd);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 		/* install the blocklist at the end of stage2_buffer */
4777c478bd9Sstevel@tonic-gate 		while (blocklist[i]) {
4787c478bd9Sstevel@tonic-gate 			if (START_BLOCK(pos - 8) != 0 &&
4797c478bd9Sstevel@tonic-gate 			    START_BLOCK(pos - 8) != blocklist[i + 2]) {
4807c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, PCFS_FRAGMENTED);
4817c478bd9Sstevel@tonic-gate 				exit(-1);
4827c478bd9Sstevel@tonic-gate 			}
4837c478bd9Sstevel@tonic-gate 			START_BLOCK(pos) = blocklist[i] + partition_offset;
4847c478bd9Sstevel@tonic-gate 			START_SEG(pos) = (ushort_t)(install_addr >> 4);
4857c478bd9Sstevel@tonic-gate 			NUM_BLOCK(pos) = blocklist[i + 1];
4867c478bd9Sstevel@tonic-gate 			install_addr += blocklist[i + 1] * SECTOR_SIZE;
4877c478bd9Sstevel@tonic-gate 			pos -= 8;
4887c478bd9Sstevel@tonic-gate 			i += 2;
4897c478bd9Sstevel@tonic-gate 		}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	} else {
4927c478bd9Sstevel@tonic-gate 		/*
4937c478bd9Sstevel@tonic-gate 		 * In a solaris partition, stage2 is written to contiguous
4947c478bd9Sstevel@tonic-gate 		 * blocks. So we update the starting block only.
4957c478bd9Sstevel@tonic-gate 		 */
4967c478bd9Sstevel@tonic-gate 		*((ulong_t *)(stage2_buffer + STAGE2_BLOCKLIST)) =
4977c478bd9Sstevel@tonic-gate 		    stage2_first_sector + 1;
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	if (is_floppy) {
5017c478bd9Sstevel@tonic-gate 		/* modify the config file to add (fd0) */
5027c478bd9Sstevel@tonic-gate 		char *config_file = stage2_buffer + STAGE2_VER_STRING;
5037c478bd9Sstevel@tonic-gate 		while (*config_file++)
5047c478bd9Sstevel@tonic-gate 			;
5057c478bd9Sstevel@tonic-gate 		strcpy(config_file, "(fd0)/boot/grub/menu.lst");
5067c478bd9Sstevel@tonic-gate 	} else {
5077c478bd9Sstevel@tonic-gate 		/* force lba and set disk partition */
5087c478bd9Sstevel@tonic-gate 		*((unsigned char *) (stage2_buffer + STAGE2_FORCE_LBA)) = 1;
5097c478bd9Sstevel@tonic-gate 		*((long *)(stage2_buffer + STAGE2_INSTALLPART))
5107c478bd9Sstevel@tonic-gate 		    = (partition << 16) | (slice << 8) | 0xff;
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	/* modification done, now do the writing */
5147c478bd9Sstevel@tonic-gate 	if (is_floppy || is_bootpar) {
5157c478bd9Sstevel@tonic-gate 		/* we rewrite block 0 and 1 and that's it */
5167c478bd9Sstevel@tonic-gate 		if (!nowrite &&
5177c478bd9Sstevel@tonic-gate 		    (pwrite(dev_fd, stage2_buffer, SECTOR_SIZE,
5187c478bd9Sstevel@tonic-gate 		    stage2_first_sector * SECTOR_SIZE) != SECTOR_SIZE ||
5197c478bd9Sstevel@tonic-gate 		    pwrite(dev_fd, stage2_buffer + SECTOR_SIZE, SECTOR_SIZE,
5207c478bd9Sstevel@tonic-gate 		    stage2_second_sector * SECTOR_SIZE) != SECTOR_SIZE)) {
5217c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, WRITE_FAIL_STAGE2);
5227c478bd9Sstevel@tonic-gate 			exit(-1);
5237c478bd9Sstevel@tonic-gate 		}
5247c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, WRITE_STAGE2_PCFS);
5257c478bd9Sstevel@tonic-gate 		return;
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	/* for disk, write stage2 starting at STAGE2_BLKOFF sector */
5297c478bd9Sstevel@tonic-gate 	offset = STAGE2_BLKOFF;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	/* write the modified first two sectors */
5327c478bd9Sstevel@tonic-gate 	if (!nowrite && pwrite(dev_fd, stage2_buffer, 2 * SECTOR_SIZE,
5337c478bd9Sstevel@tonic-gate 	    offset * SECTOR_SIZE) != 2 * SECTOR_SIZE) {
5347c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, WRITE_FAIL_STAGE2);
5357c478bd9Sstevel@tonic-gate 		exit(-1);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	/* write the remaining sectors */
5397c478bd9Sstevel@tonic-gate 	nrecord = 2;
5407c478bd9Sstevel@tonic-gate 	offset += 2;
5417c478bd9Sstevel@tonic-gate 	for (;;) {
5427c478bd9Sstevel@tonic-gate 		int nread, nwrite;
5437c478bd9Sstevel@tonic-gate 		nread = pread(stage2_fd, stage2_buffer, SECTOR_SIZE,
5447c478bd9Sstevel@tonic-gate 		    nrecord * SECTOR_SIZE);
5457c478bd9Sstevel@tonic-gate 		if (nread > 0 && !nowrite)
5467c478bd9Sstevel@tonic-gate 			nwrite = pwrite(dev_fd, stage2_buffer, SECTOR_SIZE,
5477c478bd9Sstevel@tonic-gate 			    offset * SECTOR_SIZE);
5487c478bd9Sstevel@tonic-gate 		else
5497c478bd9Sstevel@tonic-gate 			nwrite = SECTOR_SIZE;
5507c478bd9Sstevel@tonic-gate 		if (nread < 0 || nwrite != SECTOR_SIZE) {
5517c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, WRITE_FAIL_STAGE2_BLOCKS,
5527c478bd9Sstevel@tonic-gate 			    nread, nwrite);
5537c478bd9Sstevel@tonic-gate 			break;
5547c478bd9Sstevel@tonic-gate 		}
555c6fe1048Sjongkis 		if (nread > 0) {
556c6fe1048Sjongkis 			nrecord ++;
557c6fe1048Sjongkis 			offset ++;
558c6fe1048Sjongkis 		}
5597c478bd9Sstevel@tonic-gate 		if (nread < SECTOR_SIZE)
5607c478bd9Sstevel@tonic-gate 			break;	/* end of file */
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, WRITE_STAGE2_DISK,
5637c478bd9Sstevel@tonic-gate 	    partition, nrecord, STAGE2_BLKOFF, stage2_first_sector);
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate static char *
5677c478bd9Sstevel@tonic-gate get_raw_partition(char *device)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 	int len;
5707c478bd9Sstevel@tonic-gate 	struct mboot *mboot;
5717c478bd9Sstevel@tonic-gate 	static char *raw = NULL;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (raw)
5747c478bd9Sstevel@tonic-gate 		return (raw);
5757c478bd9Sstevel@tonic-gate 	raw = strdup(device);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	if (is_floppy)
5787c478bd9Sstevel@tonic-gate 		return (raw);
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	if (is_bootpar) {
5817c478bd9Sstevel@tonic-gate 		int i;
5827c478bd9Sstevel@tonic-gate 		char *end = strstr(raw, "p0:boot");
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 		end[2] = 0;		/* chop off :boot */
5857c478bd9Sstevel@tonic-gate 		read_boot_sect(raw);
5867c478bd9Sstevel@tonic-gate 		mboot = (struct mboot *)boot_sect;
5877c478bd9Sstevel@tonic-gate 		for (i = 0; i < FD_NUMPART; i++) {
5887c478bd9Sstevel@tonic-gate 			struct ipart *part = (struct ipart *)mboot->parts + i;
5897c478bd9Sstevel@tonic-gate 			if (part->systid == 0xbe)	/* solaris boot part */
5907c478bd9Sstevel@tonic-gate 				break;
5917c478bd9Sstevel@tonic-gate 		}
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 		if (i == FD_NUMPART) {
5947c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, BOOTPAR_NOTFOUND, device);
5957c478bd9Sstevel@tonic-gate 			exit(-1);
5967c478bd9Sstevel@tonic-gate 		}
5977c478bd9Sstevel@tonic-gate 		end[1] = '1' + i;	/* set partition name */
5987c478bd9Sstevel@tonic-gate 		return (raw);
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	/* For disk, remember slice and return whole fdisk partition  */
6027c478bd9Sstevel@tonic-gate 	len = strlen(raw);
6037c478bd9Sstevel@tonic-gate 	if (raw[len - 2] != 's' || raw[len - 1] == '2') {
6047c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, NOT_ROOT_SLICE);
6057c478bd9Sstevel@tonic-gate 		exit(-1);
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 	slice = atoi(&raw[len - 1]);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	raw[len - 2] = 's';
6107c478bd9Sstevel@tonic-gate 	raw[len - 1] = '2';
6117c478bd9Sstevel@tonic-gate 	return (raw);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate #define	TMP_MNTPT	"/tmp/installgrub_pcfs"
6157c478bd9Sstevel@tonic-gate static void
6167c478bd9Sstevel@tonic-gate copy_stage2(int dev_fd, char *device)
6177c478bd9Sstevel@tonic-gate {
6187c478bd9Sstevel@tonic-gate 	FILE *mntfp;
6197c478bd9Sstevel@tonic-gate 	int i, pcfs_fp;
6207c478bd9Sstevel@tonic-gate 	char buf[SECTOR_SIZE];
6217c478bd9Sstevel@tonic-gate 	char *cp;
6227c478bd9Sstevel@tonic-gate 	struct mnttab mp = {0}, mpref = {0};
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	/* convert raw to block device name by removing the first 'r' */
6257c478bd9Sstevel@tonic-gate 	(void) strncpy(buf, device, sizeof (buf));
6267c478bd9Sstevel@tonic-gate 	buf[sizeof (buf) - 1] = 0;
6277c478bd9Sstevel@tonic-gate 	cp = strchr(buf, 'r');
6287c478bd9Sstevel@tonic-gate 	if (cp == NULL) {
6297c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, CONVERT_FAIL, device);
6307c478bd9Sstevel@tonic-gate 		exit(-1);
6317c478bd9Sstevel@tonic-gate 	}
6327c478bd9Sstevel@tonic-gate 	do {
6337c478bd9Sstevel@tonic-gate 		*cp = *(cp + 1);
6347c478bd9Sstevel@tonic-gate 	} while (*(++cp));
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/* get the mount point, if any */
6377c478bd9Sstevel@tonic-gate 	mntfp = fopen("/etc/mnttab", "r");
6387c478bd9Sstevel@tonic-gate 	if (mntfp == NULL) {
6397c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL_FILE, "/etc/mnttab");
6407c478bd9Sstevel@tonic-gate 		exit(-1);
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	mpref.mnt_special = buf;
6447c478bd9Sstevel@tonic-gate 	if (getmntany(mntfp, &mp, &mpref) != 0) {
6457c478bd9Sstevel@tonic-gate 		char cmd[128];
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 		/* not mounted, try remount */
6487c478bd9Sstevel@tonic-gate 		(void) mkdir(TMP_MNTPT, S_IRWXU);
6497c478bd9Sstevel@tonic-gate 		(void) snprintf(cmd, sizeof (cmd), "mount -F pcfs %s %s",
6507c478bd9Sstevel@tonic-gate 		    buf, TMP_MNTPT);
6517c478bd9Sstevel@tonic-gate 		(void) system(cmd);
6527c478bd9Sstevel@tonic-gate 		rewind(mntfp);
6537c478bd9Sstevel@tonic-gate 		bzero(&mp, sizeof (mp));
6547c478bd9Sstevel@tonic-gate 		if (getmntany(mntfp, &mp, &mpref) != 0) {
6557c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, MOUNT_FAIL, buf);
6567c478bd9Sstevel@tonic-gate 			exit(-1);
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf),
6617c478bd9Sstevel@tonic-gate 	    "%s/boot", mp.mnt_mountp);
6627c478bd9Sstevel@tonic-gate 	(void) mkdir(buf, S_IRWXU);
6637c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "/grub");
6647c478bd9Sstevel@tonic-gate 	(void) mkdir(buf, S_IRWXU);
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "/stage2");
6677c478bd9Sstevel@tonic-gate 	pcfs_fp = open(buf, O_WRONLY | O_CREAT, S_IRWXU);
6687c478bd9Sstevel@tonic-gate 	if (pcfs_fp == -1) {
6697c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL_FILE, buf);
6707c478bd9Sstevel@tonic-gate 		perror("open:");
6717c478bd9Sstevel@tonic-gate 		(void) umount(TMP_MNTPT);
6727c478bd9Sstevel@tonic-gate 		exit(-1);
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/* write stage2 to pcfs */
6767c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
6777c478bd9Sstevel@tonic-gate 		int nread, nwrite;
6787c478bd9Sstevel@tonic-gate 		nread = pread(stage2_fd, buf, SECTOR_SIZE, i * SECTOR_SIZE);
6797c478bd9Sstevel@tonic-gate 		if (nowrite)
6807c478bd9Sstevel@tonic-gate 			nwrite = nread;
6817c478bd9Sstevel@tonic-gate 		else
6827c478bd9Sstevel@tonic-gate 			nwrite = pwrite(pcfs_fp, buf, nread, i * SECTOR_SIZE);
6837c478bd9Sstevel@tonic-gate 		if (nread < 0 || nwrite != nread) {
6847c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, WRITE_FAIL_STAGE2_BLOCKS,
6857c478bd9Sstevel@tonic-gate 			    nread, nwrite);
6867c478bd9Sstevel@tonic-gate 			break;
6877c478bd9Sstevel@tonic-gate 		}
6887c478bd9Sstevel@tonic-gate 		if (nread < SECTOR_SIZE)
6897c478bd9Sstevel@tonic-gate 			break;	/* end of file */
6907c478bd9Sstevel@tonic-gate 	}
6917c478bd9Sstevel@tonic-gate 	(void) close(pcfs_fp);
6927c478bd9Sstevel@tonic-gate 	(void) umount(TMP_MNTPT);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	/*
6957c478bd9Sstevel@tonic-gate 	 * Now, get the blocklist from the device.
6967c478bd9Sstevel@tonic-gate 	 */
6977c478bd9Sstevel@tonic-gate 	bzero(blocklist, sizeof (blocklist));
6987c478bd9Sstevel@tonic-gate 	if (read_stage2_blocklist(dev_fd, blocklist) != 0)
6997c478bd9Sstevel@tonic-gate 		exit(-1);
7007c478bd9Sstevel@tonic-gate }
701