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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <libgen.h>
320Sstevel@tonic-gate #include <malloc.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <sys/types.h>
350Sstevel@tonic-gate #include <sys/stat.h>
360Sstevel@tonic-gate #include <fcntl.h>
370Sstevel@tonic-gate #include <unistd.h>
380Sstevel@tonic-gate #include <strings.h>
390Sstevel@tonic-gate #include <sys/mount.h>
400Sstevel@tonic-gate #include <sys/mnttab.h>
410Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include <libintl.h>
440Sstevel@tonic-gate #include <locale.h>
450Sstevel@tonic-gate #include "message.h"
46*322Sjongkis #include <errno.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #ifndef	TEXT_DOMAIN
490Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
500Sstevel@tonic-gate #endif
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #define	SECTOR_SIZE	0x200
530Sstevel@tonic-gate #define	STAGE2_MEMADDR	0x8000	/* loading addr of stage2 */
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #define	STAGE1_BPB_OFFSET	0x3
560Sstevel@tonic-gate #define	STAGE1_BPB_SIZE		0x3B
570Sstevel@tonic-gate #define	STAGE1_BOOT_DRIVE	0x40
580Sstevel@tonic-gate #define	STAGE1_FORCE_LBA	0x41
590Sstevel@tonic-gate #define	STAGE1_STAGE2_ADDRESS	0x42
600Sstevel@tonic-gate #define	STAGE1_STAGE2_SECTOR	0x44
610Sstevel@tonic-gate #define	STAGE1_STAGE2_SEGMENT	0x48
620Sstevel@tonic-gate 
630Sstevel@tonic-gate #define	STAGE2_BLOCKLIST	(SECTOR_SIZE - 0x8)
640Sstevel@tonic-gate #define	STAGE2_INSTALLPART	(SECTOR_SIZE + 0x8)
650Sstevel@tonic-gate #define	STAGE2_FORCE_LBA	(SECTOR_SIZE + 0x11)
660Sstevel@tonic-gate #define	STAGE2_VER_STRING	(SECTOR_SIZE + 0x12)
670Sstevel@tonic-gate #define	STAGE2_BLKOFF		50	/* offset from start of fdisk part */
680Sstevel@tonic-gate 
690Sstevel@tonic-gate static int nowrite = 0;
700Sstevel@tonic-gate static int write_mboot = 0;
710Sstevel@tonic-gate static int force_mboot = 0;
720Sstevel@tonic-gate static int is_floppy = 0;
730Sstevel@tonic-gate static int is_bootpar = 0;
740Sstevel@tonic-gate static int stage2_fd;
750Sstevel@tonic-gate static int partition, slice = 0xff;
760Sstevel@tonic-gate static int stage2_first_sector, stage2_second_sector;
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 
790Sstevel@tonic-gate static char bpb_sect[SECTOR_SIZE];
800Sstevel@tonic-gate static char boot_sect[SECTOR_SIZE];
810Sstevel@tonic-gate static char stage1_buffer[SECTOR_SIZE];
820Sstevel@tonic-gate static char stage2_buffer[2 * SECTOR_SIZE];
830Sstevel@tonic-gate static int blocklist[SECTOR_SIZE / sizeof (int)];
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static int open_device(char *);
860Sstevel@tonic-gate static void read_bpb_sect(int);
870Sstevel@tonic-gate static void read_boot_sect(char *);
880Sstevel@tonic-gate static void write_boot_sect(char *);
890Sstevel@tonic-gate static void read_stage1_stage2(char *, char *);
900Sstevel@tonic-gate static void modify_and_write_stage1(int);
910Sstevel@tonic-gate static void modify_and_write_stage2(int);
920Sstevel@tonic-gate static int get_start_sector();
930Sstevel@tonic-gate static void copy_stage2(int, char *);
940Sstevel@tonic-gate static char *get_raw_partition(char *);
950Sstevel@tonic-gate static void usage(char *);
960Sstevel@tonic-gate 
970Sstevel@tonic-gate extern int read_stage2_blocklist(int, int *);
980Sstevel@tonic-gate 
990Sstevel@tonic-gate int
1000Sstevel@tonic-gate main(int argc, char *argv[])
1010Sstevel@tonic-gate {
1020Sstevel@tonic-gate 	int dev_fd, opt;
1030Sstevel@tonic-gate 	char *stage1, *stage2, *device;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1060Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "fmn")) != EOF) {
1090Sstevel@tonic-gate 		switch (opt) {
1100Sstevel@tonic-gate 		case 'm':
1110Sstevel@tonic-gate 			write_mboot = 1;
1120Sstevel@tonic-gate 			break;
1130Sstevel@tonic-gate 		case 'n':
1140Sstevel@tonic-gate 			nowrite = 1;
1150Sstevel@tonic-gate 			break;
1160Sstevel@tonic-gate 		case 'f':
1170Sstevel@tonic-gate 			force_mboot = 1;
1180Sstevel@tonic-gate 			break;
1190Sstevel@tonic-gate 		default:
1200Sstevel@tonic-gate 			/* fall through to process non-optional args */
1210Sstevel@tonic-gate 			break;
1220Sstevel@tonic-gate 		}
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	/* check arguments */
1260Sstevel@tonic-gate 	if (argc != optind + 3) {
1270Sstevel@tonic-gate 		usage(argv[0]);
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	if (nowrite) {
1310Sstevel@tonic-gate 		(void) fprintf(stdout, DRY_RUN);
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	stage1 = strdup(argv[optind]);
1350Sstevel@tonic-gate 	stage2 = strdup(argv[optind + 1]);
1360Sstevel@tonic-gate 	device = strdup(argv[optind + 2]);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if (!stage1 || !stage2 || !device) {
1390Sstevel@tonic-gate 		usage(argv[0]);
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	/* open and check device type */
1430Sstevel@tonic-gate 	dev_fd = open_device(device);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	/* read in stage1 and stage2 into buffer */
1460Sstevel@tonic-gate 	read_stage1_stage2(stage1, stage2);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	/* In the pcfs case, write a fresh stage2 */
1490Sstevel@tonic-gate 	if (is_floppy || is_bootpar) {
1500Sstevel@tonic-gate 		copy_stage2(dev_fd, device);
1510Sstevel@tonic-gate 		read_bpb_sect(dev_fd);
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	/* read in boot sector */
1550Sstevel@tonic-gate 	if (!is_floppy)
1560Sstevel@tonic-gate 		read_boot_sect(device);
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	/* modify stage1 based on grub needs */
1590Sstevel@tonic-gate 	modify_and_write_stage1(dev_fd);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	/* modify stage2 and write to media */
1620Sstevel@tonic-gate 	modify_and_write_stage2(dev_fd);
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	if (!is_floppy && write_mboot)
1650Sstevel@tonic-gate 		write_boot_sect(device);
1660Sstevel@tonic-gate 	(void) close(dev_fd);
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	return (0);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate static int
1720Sstevel@tonic-gate get_start_sector()
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	static int start_sect = 0;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	int i;
1770Sstevel@tonic-gate 	struct mboot *mboot;
1780Sstevel@tonic-gate 	struct ipart *part;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	if (start_sect)
1810Sstevel@tonic-gate 		return (start_sect);
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	mboot = (struct mboot *)boot_sect;
1840Sstevel@tonic-gate 	for (i = 0; i < FD_NUMPART; i++) {
1850Sstevel@tonic-gate 		part = (struct ipart *)mboot->parts + i;
1860Sstevel@tonic-gate 		if (is_bootpar) {
1870Sstevel@tonic-gate 			if (part->systid == 0xbe)
1880Sstevel@tonic-gate 				break;
1890Sstevel@tonic-gate 		} else {
1900Sstevel@tonic-gate 			if (part->systid == 0x82 || part->systid == 0xbf)
1910Sstevel@tonic-gate 				break;
1920Sstevel@tonic-gate 		}
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	if (i == FD_NUMPART) {
1960Sstevel@tonic-gate 		(void) fprintf(stderr, BOOTPAR);
1970Sstevel@tonic-gate 		exit(-1);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/* get confirmation for -m */
2010Sstevel@tonic-gate 	if (write_mboot && !force_mboot) {
2020Sstevel@tonic-gate 		(void) fprintf(stdout, MBOOT_PROMPT);
2030Sstevel@tonic-gate 		if (getchar() != 'y') {
2040Sstevel@tonic-gate 			write_mboot = 0;
2050Sstevel@tonic-gate 			(void) fprintf(stdout, MBOOT_NOT_UPDATED);
2060Sstevel@tonic-gate 		}
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	start_sect = part->relsect;
2100Sstevel@tonic-gate 	if (part->bootid != 128 && write_mboot == 0) {
2110Sstevel@tonic-gate 		(void) fprintf(stdout, BOOTPAR_INACTIVE, i + 1);
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	partition = i;
2150Sstevel@tonic-gate 	return (start_sect);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate static void
2190Sstevel@tonic-gate usage(char *progname)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	(void) fprintf(stderr, USAGE, basename(progname));
2220Sstevel@tonic-gate 	exit(-1);
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate static int
2260Sstevel@tonic-gate open_device(char *device)
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate 	int dev_fd;
2290Sstevel@tonic-gate 	struct stat stat;
2300Sstevel@tonic-gate 	char *raw_part;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	is_floppy = strncmp(device, "/dev/rdsk", strlen("/dev/rdsk")) &&
2330Sstevel@tonic-gate 	    strncmp(device, "/dev/dsk", strlen("/dev/dsk"));
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	/* handle boot partition specification */
2360Sstevel@tonic-gate 	if (!is_floppy && strstr(device, "p0:boot")) {
2370Sstevel@tonic-gate 		is_bootpar = 1;
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	raw_part = get_raw_partition(device);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	if (nowrite)
2430Sstevel@tonic-gate 		dev_fd = open(raw_part, O_RDONLY);
2440Sstevel@tonic-gate 	else
2450Sstevel@tonic-gate 		dev_fd = open(raw_part, O_RDWR);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	if (dev_fd == -1 || fstat(dev_fd, &stat) != 0) {
2480Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL, raw_part);
2490Sstevel@tonic-gate 		exit(-1);
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 	if (S_ISCHR(stat.st_mode) == 0) {
2520Sstevel@tonic-gate 		(void) fprintf(stderr, NOT_RAW_DEVICE, raw_part);
2530Sstevel@tonic-gate 		exit(-1);
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	return (dev_fd);
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate static void
2600Sstevel@tonic-gate read_stage1_stage2(char *stage1, char *stage2)
2610Sstevel@tonic-gate {
2620Sstevel@tonic-gate 	int fd;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	/* read the stage1 file from filesystem */
2650Sstevel@tonic-gate 	fd = open(stage1, O_RDONLY);
2660Sstevel@tonic-gate 	if (fd == -1 || read(fd, stage1_buffer, SECTOR_SIZE) != SECTOR_SIZE) {
2670Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_STAGE1, stage1);
2680Sstevel@tonic-gate 		exit(-1);
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 	(void) close(fd);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	/* read first two blocks of stage 2 from filesystem */
2730Sstevel@tonic-gate 	stage2_fd = open(stage2, O_RDONLY);
2740Sstevel@tonic-gate 	if (stage2_fd == -1 ||
2750Sstevel@tonic-gate 	    read(stage2_fd, stage2_buffer, 2 * SECTOR_SIZE)
2760Sstevel@tonic-gate 	    != 2 * SECTOR_SIZE) {
2770Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_STAGE2, stage2);
2780Sstevel@tonic-gate 		exit(-1);
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 	/* leave the stage2 file open for later */
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate static void
2840Sstevel@tonic-gate read_bpb_sect(int dev_fd)
2850Sstevel@tonic-gate {
2860Sstevel@tonic-gate 	if (pread(dev_fd, bpb_sect, SECTOR_SIZE, 0) != SECTOR_SIZE) {
2870Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_BPB);
2880Sstevel@tonic-gate 		exit(-1);
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate static void
2930Sstevel@tonic-gate read_boot_sect(char *device)
2940Sstevel@tonic-gate {
2950Sstevel@tonic-gate 	static int read_mbr = 0;
2960Sstevel@tonic-gate 	int i, fd;
2970Sstevel@tonic-gate 	char save[2];
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	if (read_mbr)
3000Sstevel@tonic-gate 		return;
3010Sstevel@tonic-gate 	read_mbr = 1;
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	/* get the whole disk (p0) */
3040Sstevel@tonic-gate 	i = strlen(device);
3050Sstevel@tonic-gate 	save[0] = device[i - 2];
3060Sstevel@tonic-gate 	save[1] = device[i - 1];
3070Sstevel@tonic-gate 	device[i - 2] = 'p';
3080Sstevel@tonic-gate 	device[i - 1] = '0';
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	fd = open(device, O_RDONLY);
3110Sstevel@tonic-gate 	if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) {
3120Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_MBR, device);
3130Sstevel@tonic-gate 		if (fd == -1)
3140Sstevel@tonic-gate 			perror("open");
3150Sstevel@tonic-gate 		else
3160Sstevel@tonic-gate 			perror("read");
3170Sstevel@tonic-gate 		exit(-1);
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 	(void) close(fd);
3200Sstevel@tonic-gate 	device[i - 2] = save[0];
3210Sstevel@tonic-gate 	device[i - 1] = save[1];
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate static void
3250Sstevel@tonic-gate write_boot_sect(char *device)
3260Sstevel@tonic-gate {
3270Sstevel@tonic-gate 	int fd, len;
3280Sstevel@tonic-gate 	char *raw, *end;
3290Sstevel@tonic-gate 	struct stat stat;
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	/* make a copy and chop off ":boot" */
3320Sstevel@tonic-gate 	raw = strdup(device);
3330Sstevel@tonic-gate 	end = strstr(raw, "p0:boot");
3340Sstevel@tonic-gate 	if (end)
3350Sstevel@tonic-gate 		end[2] = 0;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	/* open p0 (whole disk) */
3380Sstevel@tonic-gate 	len = strlen(raw);
3390Sstevel@tonic-gate 	raw[len - 2] = 'p';
3400Sstevel@tonic-gate 	raw[len - 1] = '0';
3410Sstevel@tonic-gate 	fd = open(raw, O_WRONLY);
3420Sstevel@tonic-gate 	if (fd == -1 || fstat(fd, &stat) != 0) {
3430Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL, raw);
3440Sstevel@tonic-gate 		exit(-1);
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate 	if (!nowrite &&
3470Sstevel@tonic-gate 	    pwrite(fd, stage1_buffer, SECTOR_SIZE, 0) != SECTOR_SIZE) {
3480Sstevel@tonic-gate 		(void) fprintf(stderr, WRITE_FAIL_BOOTSEC);
3490Sstevel@tonic-gate 		exit(-1);
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 	(void) fprintf(stdout, WRITE_MBOOT);
3520Sstevel@tonic-gate 	(void) close(fd);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate static void
3560Sstevel@tonic-gate modify_and_write_stage1(int dev_fd)
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate 	if (is_floppy) {
3590Sstevel@tonic-gate 		stage2_first_sector = blocklist[0];
3600Sstevel@tonic-gate 		/* copy bios parameter block (for fat fs) */
3610Sstevel@tonic-gate 		bcopy(bpb_sect + STAGE1_BPB_OFFSET,
3620Sstevel@tonic-gate 		    stage1_buffer + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
3630Sstevel@tonic-gate 	} else if (is_bootpar) {
3640Sstevel@tonic-gate 		stage2_first_sector = get_start_sector() + blocklist[0];
3650Sstevel@tonic-gate 		/* copy bios parameter block (for fat fs) and MBR */
3660Sstevel@tonic-gate 		bcopy(bpb_sect + STAGE1_BPB_OFFSET,
3670Sstevel@tonic-gate 		    stage1_buffer + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
3680Sstevel@tonic-gate 		bcopy(boot_sect + BOOTSZ, stage1_buffer + BOOTSZ, 512 - BOOTSZ);
3690Sstevel@tonic-gate 		*((unsigned char *)(stage1_buffer + STAGE1_FORCE_LBA)) = 1;
3700Sstevel@tonic-gate 	} else {
3710Sstevel@tonic-gate 		stage2_first_sector = get_start_sector() + STAGE2_BLKOFF;
3720Sstevel@tonic-gate 		/* copy MBR to stage1 in case of overwriting MBR sector */
3730Sstevel@tonic-gate 		bcopy(boot_sect + BOOTSZ, stage1_buffer + BOOTSZ, 512 - BOOTSZ);
3740Sstevel@tonic-gate 		*((unsigned char *)(stage1_buffer + STAGE1_FORCE_LBA)) = 1;
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	/* modify default stage1 file generated by GRUB */
3780Sstevel@tonic-gate 	*((ulong_t *)(stage1_buffer + STAGE1_STAGE2_SECTOR))
3790Sstevel@tonic-gate 		= stage2_first_sector;
3800Sstevel@tonic-gate 	*((ushort_t *)(stage1_buffer + STAGE1_STAGE2_ADDRESS))
3810Sstevel@tonic-gate 		= STAGE2_MEMADDR;
3820Sstevel@tonic-gate 	*((ushort_t *)(stage1_buffer + STAGE1_STAGE2_SEGMENT))
3830Sstevel@tonic-gate 		= STAGE2_MEMADDR >> 4;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	/*
3860Sstevel@tonic-gate 	 * XXX the default grub distribution also:
3870Sstevel@tonic-gate 	 * - Copy the possible MBR/extended part table
3880Sstevel@tonic-gate 	 * - Set the boot drive of stage1
3890Sstevel@tonic-gate 	 */
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	/* write stage1/pboot to 1st sector */
3920Sstevel@tonic-gate 	if (!nowrite &&
3930Sstevel@tonic-gate 	    pwrite(dev_fd, stage1_buffer, SECTOR_SIZE, 0) != SECTOR_SIZE) {
3940Sstevel@tonic-gate 		(void) fprintf(stderr, WRITE_FAIL_PBOOT);
3950Sstevel@tonic-gate 		exit(-1);
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	if (is_floppy) {
3990Sstevel@tonic-gate 		(void) fprintf(stdout, WRITE_BOOTSEC_FLOPPY);
4000Sstevel@tonic-gate 	} else {
4010Sstevel@tonic-gate 		(void) fprintf(stdout, WRITE_PBOOT,
4020Sstevel@tonic-gate 		    partition, get_start_sector());
4030Sstevel@tonic-gate 	}
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate #define	START_BLOCK(pos)	(*(ulong_t *)(pos))
4070Sstevel@tonic-gate #define	NUM_BLOCK(pos)		(*(ushort_t *)((pos) + 4))
4080Sstevel@tonic-gate #define	START_SEG(pos)		(*(ushort_t *)((pos) + 6))
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate static void
4110Sstevel@tonic-gate modify_and_write_stage2(int dev_fd)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate 	int nrecord;
4140Sstevel@tonic-gate 	off_t offset;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	if (is_floppy || is_bootpar) {
4170Sstevel@tonic-gate 		int i = 0;
4180Sstevel@tonic-gate 		uint_t partition_offset;
4190Sstevel@tonic-gate 		uint_t install_addr = 0x8200;
4200Sstevel@tonic-gate 		uchar_t *pos = (uchar_t *)stage2_buffer + STAGE2_BLOCKLIST;
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 		stage2_first_sector = blocklist[0];
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 		/* figure out the second sector */
4250Sstevel@tonic-gate 		if (blocklist[1] > 1) {
4260Sstevel@tonic-gate 			blocklist[0]++;
4270Sstevel@tonic-gate 			blocklist[1]--;
4280Sstevel@tonic-gate 		} else {
4290Sstevel@tonic-gate 			i += 2;
4300Sstevel@tonic-gate 		}
4310Sstevel@tonic-gate 		stage2_second_sector = blocklist[i];
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 		if (is_floppy)
4340Sstevel@tonic-gate 			partition_offset = 0;
4350Sstevel@tonic-gate 		else	/* solaris boot partition */
4360Sstevel@tonic-gate 			partition_offset = get_start_sector();
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 		/* install the blocklist at the end of stage2_buffer */
4390Sstevel@tonic-gate 		while (blocklist[i]) {
4400Sstevel@tonic-gate 			if (START_BLOCK(pos - 8) != 0 &&
4410Sstevel@tonic-gate 			    START_BLOCK(pos - 8) != blocklist[i + 2]) {
4420Sstevel@tonic-gate 				(void) fprintf(stderr, PCFS_FRAGMENTED);
4430Sstevel@tonic-gate 				exit(-1);
4440Sstevel@tonic-gate 			}
4450Sstevel@tonic-gate 			START_BLOCK(pos) = blocklist[i] + partition_offset;
4460Sstevel@tonic-gate 			START_SEG(pos) = (ushort_t)(install_addr >> 4);
4470Sstevel@tonic-gate 			NUM_BLOCK(pos) = blocklist[i + 1];
4480Sstevel@tonic-gate 			install_addr += blocklist[i + 1] * SECTOR_SIZE;
4490Sstevel@tonic-gate 			pos -= 8;
4500Sstevel@tonic-gate 			i += 2;
4510Sstevel@tonic-gate 		}
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	} else {
4540Sstevel@tonic-gate 		/*
4550Sstevel@tonic-gate 		 * In a solaris partition, stage2 is written to contiguous
4560Sstevel@tonic-gate 		 * blocks. So we update the starting block only.
4570Sstevel@tonic-gate 		 */
4580Sstevel@tonic-gate 		*((ulong_t *)(stage2_buffer + STAGE2_BLOCKLIST)) =
4590Sstevel@tonic-gate 		    stage2_first_sector + 1;
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	if (is_floppy) {
4630Sstevel@tonic-gate 		/* modify the config file to add (fd0) */
4640Sstevel@tonic-gate 		char *config_file = stage2_buffer + STAGE2_VER_STRING;
4650Sstevel@tonic-gate 		while (*config_file++)
4660Sstevel@tonic-gate 			;
4670Sstevel@tonic-gate 		strcpy(config_file, "(fd0)/boot/grub/menu.lst");
4680Sstevel@tonic-gate 	} else {
4690Sstevel@tonic-gate 		/* force lba and set disk partition */
4700Sstevel@tonic-gate 		*((unsigned char *) (stage2_buffer + STAGE2_FORCE_LBA)) = 1;
4710Sstevel@tonic-gate 		*((long *)(stage2_buffer + STAGE2_INSTALLPART))
4720Sstevel@tonic-gate 		    = (partition << 16) | (slice << 8) | 0xff;
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	/* modification done, now do the writing */
4760Sstevel@tonic-gate 	if (is_floppy || is_bootpar) {
4770Sstevel@tonic-gate 		/* we rewrite block 0 and 1 and that's it */
4780Sstevel@tonic-gate 		if (!nowrite &&
4790Sstevel@tonic-gate 		    (pwrite(dev_fd, stage2_buffer, SECTOR_SIZE,
4800Sstevel@tonic-gate 		    stage2_first_sector * SECTOR_SIZE) != SECTOR_SIZE ||
4810Sstevel@tonic-gate 		    pwrite(dev_fd, stage2_buffer + SECTOR_SIZE, SECTOR_SIZE,
4820Sstevel@tonic-gate 		    stage2_second_sector * SECTOR_SIZE) != SECTOR_SIZE)) {
4830Sstevel@tonic-gate 			(void) fprintf(stderr, WRITE_FAIL_STAGE2);
4840Sstevel@tonic-gate 			exit(-1);
4850Sstevel@tonic-gate 		}
4860Sstevel@tonic-gate 		(void) fprintf(stdout, WRITE_STAGE2_PCFS);
4870Sstevel@tonic-gate 		return;
4880Sstevel@tonic-gate 	}
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	/* for disk, write stage2 starting at STAGE2_BLKOFF sector */
4910Sstevel@tonic-gate 	offset = STAGE2_BLKOFF;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	/* write the modified first two sectors */
4940Sstevel@tonic-gate 	if (!nowrite && pwrite(dev_fd, stage2_buffer, 2 * SECTOR_SIZE,
4950Sstevel@tonic-gate 	    offset * SECTOR_SIZE) != 2 * SECTOR_SIZE) {
4960Sstevel@tonic-gate 		(void) fprintf(stderr, WRITE_FAIL_STAGE2);
4970Sstevel@tonic-gate 		exit(-1);
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	/* write the remaining sectors */
5010Sstevel@tonic-gate 	nrecord = 2;
5020Sstevel@tonic-gate 	offset += 2;
5030Sstevel@tonic-gate 	for (;;) {
5040Sstevel@tonic-gate 		int nread, nwrite;
5050Sstevel@tonic-gate 		nread = pread(stage2_fd, stage2_buffer, SECTOR_SIZE,
5060Sstevel@tonic-gate 		    nrecord * SECTOR_SIZE);
5070Sstevel@tonic-gate 		if (nread > 0 && !nowrite)
5080Sstevel@tonic-gate 			nwrite = pwrite(dev_fd, stage2_buffer, SECTOR_SIZE,
5090Sstevel@tonic-gate 			    offset * SECTOR_SIZE);
5100Sstevel@tonic-gate 		else
5110Sstevel@tonic-gate 			nwrite = SECTOR_SIZE;
5120Sstevel@tonic-gate 		if (nread < 0 || nwrite != SECTOR_SIZE) {
5130Sstevel@tonic-gate 			(void) fprintf(stderr, WRITE_FAIL_STAGE2_BLOCKS,
5140Sstevel@tonic-gate 			    nread, nwrite);
5150Sstevel@tonic-gate 			break;
5160Sstevel@tonic-gate 		}
517*322Sjongkis 		if (nread > 0) {
518*322Sjongkis 			nrecord ++;
519*322Sjongkis 			offset ++;
520*322Sjongkis 		}
5210Sstevel@tonic-gate 		if (nread < SECTOR_SIZE)
5220Sstevel@tonic-gate 			break;	/* end of file */
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 	(void) fprintf(stdout, WRITE_STAGE2_DISK,
5250Sstevel@tonic-gate 	    partition, nrecord, STAGE2_BLKOFF, stage2_first_sector);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate static char *
5290Sstevel@tonic-gate get_raw_partition(char *device)
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate 	int len;
5320Sstevel@tonic-gate 	struct mboot *mboot;
5330Sstevel@tonic-gate 	static char *raw = NULL;
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	if (raw)
5360Sstevel@tonic-gate 		return (raw);
5370Sstevel@tonic-gate 	raw = strdup(device);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if (is_floppy)
5400Sstevel@tonic-gate 		return (raw);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	if (is_bootpar) {
5430Sstevel@tonic-gate 		int i;
5440Sstevel@tonic-gate 		char *end = strstr(raw, "p0:boot");
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 		end[2] = 0;		/* chop off :boot */
5470Sstevel@tonic-gate 		read_boot_sect(raw);
5480Sstevel@tonic-gate 		mboot = (struct mboot *)boot_sect;
5490Sstevel@tonic-gate 		for (i = 0; i < FD_NUMPART; i++) {
5500Sstevel@tonic-gate 			struct ipart *part = (struct ipart *)mboot->parts + i;
5510Sstevel@tonic-gate 			if (part->systid == 0xbe)	/* solaris boot part */
5520Sstevel@tonic-gate 				break;
5530Sstevel@tonic-gate 		}
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 		if (i == FD_NUMPART) {
5560Sstevel@tonic-gate 			(void) fprintf(stderr, BOOTPAR_NOTFOUND, device);
5570Sstevel@tonic-gate 			exit(-1);
5580Sstevel@tonic-gate 		}
5590Sstevel@tonic-gate 		end[1] = '1' + i;	/* set partition name */
5600Sstevel@tonic-gate 		return (raw);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	/* For disk, remember slice and return whole fdisk partition  */
5640Sstevel@tonic-gate 	len = strlen(raw);
5650Sstevel@tonic-gate 	if (raw[len - 2] != 's' || raw[len - 1] == '2') {
5660Sstevel@tonic-gate 		(void) fprintf(stderr, NOT_ROOT_SLICE);
5670Sstevel@tonic-gate 		exit(-1);
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 	slice = atoi(&raw[len - 1]);
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	raw[len - 2] = 's';
5720Sstevel@tonic-gate 	raw[len - 1] = '2';
5730Sstevel@tonic-gate 	return (raw);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate #define	TMP_MNTPT	"/tmp/installgrub_pcfs"
5770Sstevel@tonic-gate static void
5780Sstevel@tonic-gate copy_stage2(int dev_fd, char *device)
5790Sstevel@tonic-gate {
5800Sstevel@tonic-gate 	FILE *mntfp;
5810Sstevel@tonic-gate 	int i, pcfs_fp;
5820Sstevel@tonic-gate 	char buf[SECTOR_SIZE];
5830Sstevel@tonic-gate 	char *cp;
5840Sstevel@tonic-gate 	struct mnttab mp = {0}, mpref = {0};
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	/* convert raw to block device name by removing the first 'r' */
5870Sstevel@tonic-gate 	(void) strncpy(buf, device, sizeof (buf));
5880Sstevel@tonic-gate 	buf[sizeof (buf) - 1] = 0;
5890Sstevel@tonic-gate 	cp = strchr(buf, 'r');
5900Sstevel@tonic-gate 	if (cp == NULL) {
5910Sstevel@tonic-gate 		(void) fprintf(stderr, CONVERT_FAIL, device);
5920Sstevel@tonic-gate 		exit(-1);
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 	do {
5950Sstevel@tonic-gate 		*cp = *(cp + 1);
5960Sstevel@tonic-gate 	} while (*(++cp));
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	/* get the mount point, if any */
5990Sstevel@tonic-gate 	mntfp = fopen("/etc/mnttab", "r");
6000Sstevel@tonic-gate 	if (mntfp == NULL) {
6010Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL_FILE, "/etc/mnttab");
6020Sstevel@tonic-gate 		exit(-1);
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	mpref.mnt_special = buf;
6060Sstevel@tonic-gate 	if (getmntany(mntfp, &mp, &mpref) != 0) {
6070Sstevel@tonic-gate 		char cmd[128];
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 		/* not mounted, try remount */
6100Sstevel@tonic-gate 		(void) mkdir(TMP_MNTPT, S_IRWXU);
6110Sstevel@tonic-gate 		(void) snprintf(cmd, sizeof (cmd), "mount -F pcfs %s %s",
6120Sstevel@tonic-gate 		    buf, TMP_MNTPT);
6130Sstevel@tonic-gate 		(void) system(cmd);
6140Sstevel@tonic-gate 		rewind(mntfp);
6150Sstevel@tonic-gate 		bzero(&mp, sizeof (mp));
6160Sstevel@tonic-gate 		if (getmntany(mntfp, &mp, &mpref) != 0) {
6170Sstevel@tonic-gate 			(void) fprintf(stderr, MOUNT_FAIL, buf);
6180Sstevel@tonic-gate 			exit(-1);
6190Sstevel@tonic-gate 		}
6200Sstevel@tonic-gate 	}
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf),
6230Sstevel@tonic-gate 	    "%s/boot", mp.mnt_mountp);
6240Sstevel@tonic-gate 	(void) mkdir(buf, S_IRWXU);
6250Sstevel@tonic-gate 	(void) strcat(buf, "/grub");
6260Sstevel@tonic-gate 	(void) mkdir(buf, S_IRWXU);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	(void) strcat(buf, "/stage2");
6290Sstevel@tonic-gate 	pcfs_fp = open(buf, O_WRONLY | O_CREAT, S_IRWXU);
6300Sstevel@tonic-gate 	if (pcfs_fp == -1) {
6310Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL_FILE, buf);
6320Sstevel@tonic-gate 		perror("open:");
6330Sstevel@tonic-gate 		(void) umount(TMP_MNTPT);
6340Sstevel@tonic-gate 		exit(-1);
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	/* write stage2 to pcfs */
6380Sstevel@tonic-gate 	for (i = 0; ; i++) {
6390Sstevel@tonic-gate 		int nread, nwrite;
6400Sstevel@tonic-gate 		nread = pread(stage2_fd, buf, SECTOR_SIZE, i * SECTOR_SIZE);
6410Sstevel@tonic-gate 		if (nowrite)
6420Sstevel@tonic-gate 			nwrite = nread;
6430Sstevel@tonic-gate 		else
6440Sstevel@tonic-gate 			nwrite = pwrite(pcfs_fp, buf, nread, i * SECTOR_SIZE);
6450Sstevel@tonic-gate 		if (nread < 0 || nwrite != nread) {
6460Sstevel@tonic-gate 			(void) fprintf(stderr, WRITE_FAIL_STAGE2_BLOCKS,
6470Sstevel@tonic-gate 			    nread, nwrite);
6480Sstevel@tonic-gate 			break;
6490Sstevel@tonic-gate 		}
6500Sstevel@tonic-gate 		if (nread < SECTOR_SIZE)
6510Sstevel@tonic-gate 			break;	/* end of file */
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate 	(void) close(pcfs_fp);
6540Sstevel@tonic-gate 	(void) umount(TMP_MNTPT);
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	/*
6570Sstevel@tonic-gate 	 * Now, get the blocklist from the device.
6580Sstevel@tonic-gate 	 */
6590Sstevel@tonic-gate 	bzero(blocklist, sizeof (blocklist));
6600Sstevel@tonic-gate 	if (read_stage2_blocklist(dev_fd, blocklist) != 0)
6610Sstevel@tonic-gate 		exit(-1);
6620Sstevel@tonic-gate }
663