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 /*
2210021SSheshadri.Vasudevan@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <stdlib.h>
280Sstevel@tonic-gate #include <libgen.h>
290Sstevel@tonic-gate #include <malloc.h>
300Sstevel@tonic-gate #include <string.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/stat.h>
330Sstevel@tonic-gate #include <fcntl.h>
340Sstevel@tonic-gate #include <unistd.h>
350Sstevel@tonic-gate #include <strings.h>
360Sstevel@tonic-gate #include <sys/mount.h>
370Sstevel@tonic-gate #include <sys/mnttab.h>
380Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
395589Ssy25831 #include <sys/dkio.h>
405589Ssy25831 #include <sys/vtoc.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include <libintl.h>
430Sstevel@tonic-gate #include <locale.h>
440Sstevel@tonic-gate #include "message.h"
45322Sjongkis #include <errno.h>
4610021SSheshadri.Vasudevan@Sun.COM #include <libfdisk.h>
478434SEnrico.Perla@Sun.COM #include <md5.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #ifndef	TEXT_DOMAIN
500Sstevel@tonic-gate #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
510Sstevel@tonic-gate #endif
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #define	SECTOR_SIZE	0x200
548434SEnrico.Perla@Sun.COM #define	HASH_SIZE	0x10
558434SEnrico.Perla@Sun.COM #define	VERSION_SIZE	0x50
560Sstevel@tonic-gate #define	STAGE2_MEMADDR	0x8000	/* loading addr of stage2 */
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #define	STAGE1_BPB_OFFSET	0x3
590Sstevel@tonic-gate #define	STAGE1_BPB_SIZE		0x3B
600Sstevel@tonic-gate #define	STAGE1_BOOT_DRIVE	0x40
610Sstevel@tonic-gate #define	STAGE1_FORCE_LBA	0x41
620Sstevel@tonic-gate #define	STAGE1_STAGE2_ADDRESS	0x42
630Sstevel@tonic-gate #define	STAGE1_STAGE2_SECTOR	0x44
640Sstevel@tonic-gate #define	STAGE1_STAGE2_SEGMENT	0x48
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #define	STAGE2_BLOCKLIST	(SECTOR_SIZE - 0x8)
670Sstevel@tonic-gate #define	STAGE2_INSTALLPART	(SECTOR_SIZE + 0x8)
680Sstevel@tonic-gate #define	STAGE2_FORCE_LBA	(SECTOR_SIZE + 0x11)
690Sstevel@tonic-gate #define	STAGE2_VER_STRING	(SECTOR_SIZE + 0x12)
708434SEnrico.Perla@Sun.COM #define	STAGE2_SIGN_OFFSET	(SECTOR_SIZE + 0x60)
718434SEnrico.Perla@Sun.COM #define	STAGE2_PKG_VERSION	(SECTOR_SIZE + 0x70)
720Sstevel@tonic-gate #define	STAGE2_BLKOFF		50	/* offset from start of fdisk part */
730Sstevel@tonic-gate 
748434SEnrico.Perla@Sun.COM static char extended_sig[] = "\xCC\xCC\xCC\xCC\xAA\xAA\xAA\xAA\xBB\xBB\xBB\xBB"
758434SEnrico.Perla@Sun.COM "\xBB\xBB\xBB\xBB";
768434SEnrico.Perla@Sun.COM 
770Sstevel@tonic-gate static int nowrite = 0;
780Sstevel@tonic-gate static int write_mboot = 0;
790Sstevel@tonic-gate static int force_mboot = 0;
808434SEnrico.Perla@Sun.COM static int getinfo = 0;
818434SEnrico.Perla@Sun.COM static int do_version = 0;
820Sstevel@tonic-gate static int is_floppy = 0;
830Sstevel@tonic-gate static int is_bootpar = 0;
848434SEnrico.Perla@Sun.COM static int strip = 0;
850Sstevel@tonic-gate static int stage2_fd;
860Sstevel@tonic-gate static int partition, slice = 0xff;
8710021SSheshadri.Vasudevan@Sun.COM static char *device_p0;
8810021SSheshadri.Vasudevan@Sun.COM static uint32_t stage2_first_sector, stage2_second_sector;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static char bpb_sect[SECTOR_SIZE];
920Sstevel@tonic-gate static char boot_sect[SECTOR_SIZE];
930Sstevel@tonic-gate static char stage1_buffer[SECTOR_SIZE];
940Sstevel@tonic-gate static char stage2_buffer[2 * SECTOR_SIZE];
958434SEnrico.Perla@Sun.COM static char signature[HASH_SIZE];
968434SEnrico.Perla@Sun.COM static char verstring[VERSION_SIZE];
977563SPrasad.Singamsetty@Sun.COM static unsigned int blocklist[SECTOR_SIZE / sizeof (unsigned int)];
980Sstevel@tonic-gate 
990Sstevel@tonic-gate static int open_device(char *);
1000Sstevel@tonic-gate static void read_bpb_sect(int);
1010Sstevel@tonic-gate static void read_boot_sect(char *);
1020Sstevel@tonic-gate static void write_boot_sect(char *);
1030Sstevel@tonic-gate static void read_stage1_stage2(char *, char *);
1040Sstevel@tonic-gate static void modify_and_write_stage1(int);
1050Sstevel@tonic-gate static void modify_and_write_stage2(int);
1067563SPrasad.Singamsetty@Sun.COM static unsigned int get_start_sector(int);
1070Sstevel@tonic-gate static void copy_stage2(int, char *);
1080Sstevel@tonic-gate static char *get_raw_partition(char *);
1090Sstevel@tonic-gate static void usage(char *);
1108434SEnrico.Perla@Sun.COM static void print_info();
1118434SEnrico.Perla@Sun.COM static int read_stage2_info(int);
1128434SEnrico.Perla@Sun.COM static void check_extended_support();
1130Sstevel@tonic-gate 
1147563SPrasad.Singamsetty@Sun.COM extern int read_stage2_blocklist(int, unsigned int *);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate int
1170Sstevel@tonic-gate main(int argc, char *argv[])
1180Sstevel@tonic-gate {
1198434SEnrico.Perla@Sun.COM 	int dev_fd, opt, params = 3;
1200Sstevel@tonic-gate 	char *stage1, *stage2, *device;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1230Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1240Sstevel@tonic-gate 
1258434SEnrico.Perla@Sun.COM 	while ((opt = getopt(argc, argv, "fmneis:")) != EOF) {
1260Sstevel@tonic-gate 		switch (opt) {
1270Sstevel@tonic-gate 		case 'm':
1280Sstevel@tonic-gate 			write_mboot = 1;
1290Sstevel@tonic-gate 			break;
1300Sstevel@tonic-gate 		case 'n':
1310Sstevel@tonic-gate 			nowrite = 1;
1320Sstevel@tonic-gate 			break;
1330Sstevel@tonic-gate 		case 'f':
1340Sstevel@tonic-gate 			force_mboot = 1;
1350Sstevel@tonic-gate 			break;
1368434SEnrico.Perla@Sun.COM 		case 'i':
1378434SEnrico.Perla@Sun.COM 			getinfo = 1;
1388434SEnrico.Perla@Sun.COM 			params = 1;
1398434SEnrico.Perla@Sun.COM 			break;
1408434SEnrico.Perla@Sun.COM 		case 'e':
1418434SEnrico.Perla@Sun.COM 			strip = 1;
1428434SEnrico.Perla@Sun.COM 			break;
1438434SEnrico.Perla@Sun.COM 		case 's':
1448434SEnrico.Perla@Sun.COM 			do_version = 1;
1458434SEnrico.Perla@Sun.COM 			(void) snprintf(verstring, sizeof (verstring), "%s",
1468434SEnrico.Perla@Sun.COM 			    optarg);
1478434SEnrico.Perla@Sun.COM 			break;
1480Sstevel@tonic-gate 		default:
1490Sstevel@tonic-gate 			/* fall through to process non-optional args */
1500Sstevel@tonic-gate 			break;
1510Sstevel@tonic-gate 		}
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	/* check arguments */
1558434SEnrico.Perla@Sun.COM 	if (argc != optind + params) {
1560Sstevel@tonic-gate 		usage(argv[0]);
1570Sstevel@tonic-gate 	}
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	if (nowrite) {
1600Sstevel@tonic-gate 		(void) fprintf(stdout, DRY_RUN);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 
1638434SEnrico.Perla@Sun.COM 	if (params == 1) {
1648434SEnrico.Perla@Sun.COM 		device = strdup(argv[optind]);
1658434SEnrico.Perla@Sun.COM 		if (!device) {
1668434SEnrico.Perla@Sun.COM 			usage(argv[0]);
1678434SEnrico.Perla@Sun.COM 		}
1688434SEnrico.Perla@Sun.COM 	} else if (params == 3) {
1698434SEnrico.Perla@Sun.COM 		stage1 = strdup(argv[optind]);
1708434SEnrico.Perla@Sun.COM 		stage2 = strdup(argv[optind + 1]);
1718434SEnrico.Perla@Sun.COM 		device = strdup(argv[optind + 2]);
1720Sstevel@tonic-gate 
1738434SEnrico.Perla@Sun.COM 		if (!stage1 || !stage2 || !device) {
1748434SEnrico.Perla@Sun.COM 			usage(argv[0]);
1758434SEnrico.Perla@Sun.COM 		}
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	/* open and check device type */
1790Sstevel@tonic-gate 	dev_fd = open_device(device);
1800Sstevel@tonic-gate 
1818434SEnrico.Perla@Sun.COM 	if (getinfo) {
1828434SEnrico.Perla@Sun.COM 		if (read_stage2_info(dev_fd) != 0) {
1838434SEnrico.Perla@Sun.COM 			fprintf(stderr, "Unable to read extended information"
1848434SEnrico.Perla@Sun.COM 			    " from %s\n", device);
1858434SEnrico.Perla@Sun.COM 			exit(1);
1868434SEnrico.Perla@Sun.COM 		}
1878434SEnrico.Perla@Sun.COM 		print_info();
1888434SEnrico.Perla@Sun.COM 		(void) free(device);
1898434SEnrico.Perla@Sun.COM 		(void) close(dev_fd);
1908434SEnrico.Perla@Sun.COM 		return (0);
1918434SEnrico.Perla@Sun.COM 	}
1928434SEnrico.Perla@Sun.COM 
1930Sstevel@tonic-gate 	/* read in stage1 and stage2 into buffer */
1940Sstevel@tonic-gate 	read_stage1_stage2(stage1, stage2);
1950Sstevel@tonic-gate 
1968434SEnrico.Perla@Sun.COM 	/* check if stage2 supports extended versioning */
1978434SEnrico.Perla@Sun.COM 	if (do_version)
1988434SEnrico.Perla@Sun.COM 		check_extended_support(stage2);
1998434SEnrico.Perla@Sun.COM 
2000Sstevel@tonic-gate 	/* In the pcfs case, write a fresh stage2 */
2010Sstevel@tonic-gate 	if (is_floppy || is_bootpar) {
2020Sstevel@tonic-gate 		copy_stage2(dev_fd, device);
2030Sstevel@tonic-gate 		read_bpb_sect(dev_fd);
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/* read in boot sector */
2070Sstevel@tonic-gate 	if (!is_floppy)
2080Sstevel@tonic-gate 		read_boot_sect(device);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/* modify stage1 based on grub needs */
2110Sstevel@tonic-gate 	modify_and_write_stage1(dev_fd);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	/* modify stage2 and write to media */
2140Sstevel@tonic-gate 	modify_and_write_stage2(dev_fd);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	if (!is_floppy && write_mboot)
2170Sstevel@tonic-gate 		write_boot_sect(device);
2188434SEnrico.Perla@Sun.COM 
2190Sstevel@tonic-gate 	(void) close(dev_fd);
2208434SEnrico.Perla@Sun.COM 	free(device);
2218434SEnrico.Perla@Sun.COM 	free(stage1);
2228434SEnrico.Perla@Sun.COM 	free(stage2);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	return (0);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate 
2277563SPrasad.Singamsetty@Sun.COM static unsigned int
2285589Ssy25831 get_start_sector(int fd)
2290Sstevel@tonic-gate {
2307563SPrasad.Singamsetty@Sun.COM 	static unsigned int start_sect = 0;
231*10568SVikram.Hegde@Sun.COM 	uint32_t secnum = 0, numsec = 0;
232*10568SVikram.Hegde@Sun.COM 	int i, pno, rval, log_part = 0;
2330Sstevel@tonic-gate 	struct mboot *mboot;
2340Sstevel@tonic-gate 	struct ipart *part;
23510021SSheshadri.Vasudevan@Sun.COM 	ext_part_t *epp;
236*10568SVikram.Hegde@Sun.COM 	struct part_info dkpi;
237*10568SVikram.Hegde@Sun.COM 	struct extpart_info edkpi;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	if (start_sect)
2400Sstevel@tonic-gate 		return (start_sect);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	mboot = (struct mboot *)boot_sect;
2430Sstevel@tonic-gate 	for (i = 0; i < FD_NUMPART; i++) {
2440Sstevel@tonic-gate 		part = (struct ipart *)mboot->parts + i;
2450Sstevel@tonic-gate 		if (is_bootpar) {
246*10568SVikram.Hegde@Sun.COM 			if (part->systid == 0xbe) {
247*10568SVikram.Hegde@Sun.COM 				start_sect = part->relsect;
248*10568SVikram.Hegde@Sun.COM 				partition = i;
249*10568SVikram.Hegde@Sun.COM 				goto found_part;
250*10568SVikram.Hegde@Sun.COM 			}
251*10568SVikram.Hegde@Sun.COM 		}
252*10568SVikram.Hegde@Sun.COM 	}
253*10568SVikram.Hegde@Sun.COM 
254*10568SVikram.Hegde@Sun.COM 	/*
255*10568SVikram.Hegde@Sun.COM 	 * We will not support x86 boot partition on extended partitions
256*10568SVikram.Hegde@Sun.COM 	 */
257*10568SVikram.Hegde@Sun.COM 	if (is_bootpar) {
258*10568SVikram.Hegde@Sun.COM 		(void) fprintf(stderr, NOBOOTPAR);
259*10568SVikram.Hegde@Sun.COM 		exit(-1);
260*10568SVikram.Hegde@Sun.COM 	}
261*10568SVikram.Hegde@Sun.COM 
262*10568SVikram.Hegde@Sun.COM 	/*
263*10568SVikram.Hegde@Sun.COM 	 * Not an x86 boot partition. Search for Solaris fdisk partition
264*10568SVikram.Hegde@Sun.COM 	 * Get the solaris partition information from the device
265*10568SVikram.Hegde@Sun.COM 	 * and compare the offset of S2 with offset of solaris partition
266*10568SVikram.Hegde@Sun.COM 	 * from fdisk partition table.
267*10568SVikram.Hegde@Sun.COM 	 */
268*10568SVikram.Hegde@Sun.COM 	if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
269*10568SVikram.Hegde@Sun.COM 		if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) {
270*10568SVikram.Hegde@Sun.COM 			(void) fprintf(stderr, PART_FAIL);
271*10568SVikram.Hegde@Sun.COM 			exit(-1);
272*10568SVikram.Hegde@Sun.COM 		} else {
273*10568SVikram.Hegde@Sun.COM 			edkpi.p_start = dkpi.p_start;
2745589Ssy25831 		}
2755589Ssy25831 	}
2765589Ssy25831 
277*10568SVikram.Hegde@Sun.COM 	for (i = 0; i < FD_NUMPART; i++) {
278*10568SVikram.Hegde@Sun.COM 		part = (struct ipart *)mboot->parts + i;
279*10568SVikram.Hegde@Sun.COM 
280*10568SVikram.Hegde@Sun.COM 		if (part->relsect == 0) {
281*10568SVikram.Hegde@Sun.COM 			(void) fprintf(stderr, BAD_PART, i);
282*10568SVikram.Hegde@Sun.COM 			exit(-1);
283*10568SVikram.Hegde@Sun.COM 		}
284*10568SVikram.Hegde@Sun.COM 
285*10568SVikram.Hegde@Sun.COM 		if (edkpi.p_start >= part->relsect &&
286*10568SVikram.Hegde@Sun.COM 		    edkpi.p_start < (part->relsect + part->numsect)) {
287*10568SVikram.Hegde@Sun.COM 			/* Found the partition */
288*10568SVikram.Hegde@Sun.COM 			break;
289*10568SVikram.Hegde@Sun.COM 		}
290*10568SVikram.Hegde@Sun.COM 	}
291*10568SVikram.Hegde@Sun.COM 
292*10568SVikram.Hegde@Sun.COM 	if (i == FD_NUMPART) {
293*10568SVikram.Hegde@Sun.COM 		/* No solaris fdisk partitions (primary or logical) */
294*10568SVikram.Hegde@Sun.COM 		(void) fprintf(stderr, NOSOLPAR);
295*10568SVikram.Hegde@Sun.COM 		exit(-1);
296*10568SVikram.Hegde@Sun.COM 	}
297*10568SVikram.Hegde@Sun.COM 
298*10568SVikram.Hegde@Sun.COM 	/*
299*10568SVikram.Hegde@Sun.COM 	 * We have found a Solaris fdisk partition (primary or extended)
300*10568SVikram.Hegde@Sun.COM 	 * Handle the simple case first: Solaris in a primary partition
301*10568SVikram.Hegde@Sun.COM 	 */
302*10568SVikram.Hegde@Sun.COM 	if (!fdisk_is_dos_extended(part->systid)) {
303*10568SVikram.Hegde@Sun.COM 		start_sect = part->relsect;
304*10568SVikram.Hegde@Sun.COM 		partition = i;
305*10568SVikram.Hegde@Sun.COM 		goto found_part;
306*10568SVikram.Hegde@Sun.COM 	}
307*10568SVikram.Hegde@Sun.COM 
308*10568SVikram.Hegde@Sun.COM 	/*
309*10568SVikram.Hegde@Sun.COM 	 * Solaris in a logical partition. Find that partition in the
310*10568SVikram.Hegde@Sun.COM 	 * extended part.
311*10568SVikram.Hegde@Sun.COM 	 */
31210021SSheshadri.Vasudevan@Sun.COM 	if ((rval = libfdisk_init(&epp, device_p0, NULL, FDISK_READ_DISK))
31310021SSheshadri.Vasudevan@Sun.COM 	    != FDISK_SUCCESS) {
31410021SSheshadri.Vasudevan@Sun.COM 		switch (rval) {
31510021SSheshadri.Vasudevan@Sun.COM 			/*
316*10568SVikram.Hegde@Sun.COM 			 * The first 2 cases are not an error per-se, just that
317*10568SVikram.Hegde@Sun.COM 			 * there is no Solaris logical partition
31810021SSheshadri.Vasudevan@Sun.COM 			 */
31910021SSheshadri.Vasudevan@Sun.COM 			case FDISK_EBADLOGDRIVE:
32010021SSheshadri.Vasudevan@Sun.COM 			case FDISK_ENOLOGDRIVE:
321*10568SVikram.Hegde@Sun.COM 				(void) fprintf(stderr, NOSOLPAR);
322*10568SVikram.Hegde@Sun.COM 				exit(-1);
323*10568SVikram.Hegde@Sun.COM 				/*NOTREACHED*/
32410021SSheshadri.Vasudevan@Sun.COM 			case FDISK_ENOVGEOM:
32510021SSheshadri.Vasudevan@Sun.COM 				(void) fprintf(stderr, NO_VIRT_GEOM);
32610021SSheshadri.Vasudevan@Sun.COM 				exit(1);
32710021SSheshadri.Vasudevan@Sun.COM 				break;
32810021SSheshadri.Vasudevan@Sun.COM 			case FDISK_ENOPGEOM:
32910021SSheshadri.Vasudevan@Sun.COM 				(void) fprintf(stderr, NO_PHYS_GEOM);
33010021SSheshadri.Vasudevan@Sun.COM 				exit(1);
33110021SSheshadri.Vasudevan@Sun.COM 				break;
33210021SSheshadri.Vasudevan@Sun.COM 			case FDISK_ENOLGEOM:
33310021SSheshadri.Vasudevan@Sun.COM 				(void) fprintf(stderr, NO_LABEL_GEOM);
33410021SSheshadri.Vasudevan@Sun.COM 				exit(1);
33510021SSheshadri.Vasudevan@Sun.COM 				break;
33610021SSheshadri.Vasudevan@Sun.COM 			default:
33710021SSheshadri.Vasudevan@Sun.COM 				(void) fprintf(stderr, LIBFDISK_INIT_FAIL);
33810021SSheshadri.Vasudevan@Sun.COM 				exit(1);
33910021SSheshadri.Vasudevan@Sun.COM 				break;
34010021SSheshadri.Vasudevan@Sun.COM 		}
34110021SSheshadri.Vasudevan@Sun.COM 	}
34210021SSheshadri.Vasudevan@Sun.COM 
34310021SSheshadri.Vasudevan@Sun.COM 	rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
344*10568SVikram.Hegde@Sun.COM 	if (rval != FDISK_SUCCESS) {
345*10568SVikram.Hegde@Sun.COM 		/* No solaris logical partition */
346*10568SVikram.Hegde@Sun.COM 		(void) fprintf(stderr, NOSOLPAR);
347*10568SVikram.Hegde@Sun.COM 		exit(-1);
34810021SSheshadri.Vasudevan@Sun.COM 	}
34910021SSheshadri.Vasudevan@Sun.COM 	libfdisk_fini(&epp);
35010021SSheshadri.Vasudevan@Sun.COM 
351*10568SVikram.Hegde@Sun.COM 	start_sect = secnum;
352*10568SVikram.Hegde@Sun.COM 	partition = pno - 1;
353*10568SVikram.Hegde@Sun.COM 	log_part = 1;
3545589Ssy25831 
355*10568SVikram.Hegde@Sun.COM found_part:
3560Sstevel@tonic-gate 	/* get confirmation for -m */
3570Sstevel@tonic-gate 	if (write_mboot && !force_mboot) {
3580Sstevel@tonic-gate 		(void) fprintf(stdout, MBOOT_PROMPT);
3590Sstevel@tonic-gate 		if (getchar() != 'y') {
3600Sstevel@tonic-gate 			write_mboot = 0;
3610Sstevel@tonic-gate 			(void) fprintf(stdout, MBOOT_NOT_UPDATED);
3620Sstevel@tonic-gate 		}
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate 
365*10568SVikram.Hegde@Sun.COM 	/*
366*10568SVikram.Hegde@Sun.COM 	 * Currently if Solaris is in an extended partition we need to
367*10568SVikram.Hegde@Sun.COM 	 * write GRUB to the MBR. Check for this.
368*10568SVikram.Hegde@Sun.COM 	 */
369*10568SVikram.Hegde@Sun.COM 	if (log_part && !write_mboot) {
370*10568SVikram.Hegde@Sun.COM 		(void) fprintf(stderr, EXTSOLPAR);
371*10568SVikram.Hegde@Sun.COM 		exit(-1);
37210021SSheshadri.Vasudevan@Sun.COM 	}
37310021SSheshadri.Vasudevan@Sun.COM 
374*10568SVikram.Hegde@Sun.COM 	/*
375*10568SVikram.Hegde@Sun.COM 	 * warn, if Solaris in primary partition and GRUB not in MBR and
376*10568SVikram.Hegde@Sun.COM 	 * partition is not active
377*10568SVikram.Hegde@Sun.COM 	 */
378*10568SVikram.Hegde@Sun.COM 	if (!log_part && part->bootid != 128 && !write_mboot) {
379*10568SVikram.Hegde@Sun.COM 		(void) fprintf(stdout, SOLPAR_INACTIVE, partition + 1);
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	return (start_sect);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate static void
3860Sstevel@tonic-gate usage(char *progname)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	(void) fprintf(stderr, USAGE, basename(progname));
3890Sstevel@tonic-gate 	exit(-1);
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate static int
3930Sstevel@tonic-gate open_device(char *device)
3940Sstevel@tonic-gate {
3950Sstevel@tonic-gate 	int dev_fd;
3960Sstevel@tonic-gate 	struct stat stat;
3970Sstevel@tonic-gate 	char *raw_part;
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	is_floppy = strncmp(device, "/dev/rdsk", strlen("/dev/rdsk")) &&
4000Sstevel@tonic-gate 	    strncmp(device, "/dev/dsk", strlen("/dev/dsk"));
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/* handle boot partition specification */
4030Sstevel@tonic-gate 	if (!is_floppy && strstr(device, "p0:boot")) {
4040Sstevel@tonic-gate 		is_bootpar = 1;
4050Sstevel@tonic-gate 	}
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	raw_part = get_raw_partition(device);
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	if (nowrite)
4100Sstevel@tonic-gate 		dev_fd = open(raw_part, O_RDONLY);
4110Sstevel@tonic-gate 	else
4120Sstevel@tonic-gate 		dev_fd = open(raw_part, O_RDWR);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	if (dev_fd == -1 || fstat(dev_fd, &stat) != 0) {
4150Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL, raw_part);
4160Sstevel@tonic-gate 		exit(-1);
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 	if (S_ISCHR(stat.st_mode) == 0) {
4190Sstevel@tonic-gate 		(void) fprintf(stderr, NOT_RAW_DEVICE, raw_part);
4200Sstevel@tonic-gate 		exit(-1);
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	return (dev_fd);
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate static void
4270Sstevel@tonic-gate read_stage1_stage2(char *stage1, char *stage2)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	int fd;
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	/* read the stage1 file from filesystem */
4320Sstevel@tonic-gate 	fd = open(stage1, O_RDONLY);
4330Sstevel@tonic-gate 	if (fd == -1 || read(fd, stage1_buffer, SECTOR_SIZE) != SECTOR_SIZE) {
4340Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_STAGE1, stage1);
4350Sstevel@tonic-gate 		exit(-1);
4360Sstevel@tonic-gate 	}
4370Sstevel@tonic-gate 	(void) close(fd);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	/* read first two blocks of stage 2 from filesystem */
4400Sstevel@tonic-gate 	stage2_fd = open(stage2, O_RDONLY);
4410Sstevel@tonic-gate 	if (stage2_fd == -1 ||
4420Sstevel@tonic-gate 	    read(stage2_fd, stage2_buffer, 2 * SECTOR_SIZE)
4430Sstevel@tonic-gate 	    != 2 * SECTOR_SIZE) {
4440Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_STAGE2, stage2);
4450Sstevel@tonic-gate 		exit(-1);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 	/* leave the stage2 file open for later */
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate static void
4510Sstevel@tonic-gate read_bpb_sect(int dev_fd)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 	if (pread(dev_fd, bpb_sect, SECTOR_SIZE, 0) != SECTOR_SIZE) {
4540Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_BPB);
4550Sstevel@tonic-gate 		exit(-1);
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate static void
4600Sstevel@tonic-gate read_boot_sect(char *device)
4610Sstevel@tonic-gate {
4620Sstevel@tonic-gate 	static int read_mbr = 0;
4630Sstevel@tonic-gate 	int i, fd;
4640Sstevel@tonic-gate 	char save[2];
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	if (read_mbr)
4670Sstevel@tonic-gate 		return;
4680Sstevel@tonic-gate 	read_mbr = 1;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	/* get the whole disk (p0) */
4710Sstevel@tonic-gate 	i = strlen(device);
4720Sstevel@tonic-gate 	save[0] = device[i - 2];
4730Sstevel@tonic-gate 	save[1] = device[i - 1];
4740Sstevel@tonic-gate 	device[i - 2] = 'p';
4750Sstevel@tonic-gate 	device[i - 1] = '0';
4760Sstevel@tonic-gate 
47710021SSheshadri.Vasudevan@Sun.COM 	device_p0 = strdup(device);
4780Sstevel@tonic-gate 	fd = open(device, O_RDONLY);
4790Sstevel@tonic-gate 	if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) {
4800Sstevel@tonic-gate 		(void) fprintf(stderr, READ_FAIL_MBR, device);
4810Sstevel@tonic-gate 		if (fd == -1)
4820Sstevel@tonic-gate 			perror("open");
4830Sstevel@tonic-gate 		else
4840Sstevel@tonic-gate 			perror("read");
4850Sstevel@tonic-gate 		exit(-1);
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 	(void) close(fd);
4880Sstevel@tonic-gate 	device[i - 2] = save[0];
4890Sstevel@tonic-gate 	device[i - 1] = save[1];
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate static void
4930Sstevel@tonic-gate write_boot_sect(char *device)
4940Sstevel@tonic-gate {
4950Sstevel@tonic-gate 	int fd, len;
4960Sstevel@tonic-gate 	char *raw, *end;
4970Sstevel@tonic-gate 	struct stat stat;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	/* make a copy and chop off ":boot" */
5000Sstevel@tonic-gate 	raw = strdup(device);
5010Sstevel@tonic-gate 	end = strstr(raw, "p0:boot");
5020Sstevel@tonic-gate 	if (end)
5030Sstevel@tonic-gate 		end[2] = 0;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/* open p0 (whole disk) */
5060Sstevel@tonic-gate 	len = strlen(raw);
5070Sstevel@tonic-gate 	raw[len - 2] = 'p';
5080Sstevel@tonic-gate 	raw[len - 1] = '0';
5090Sstevel@tonic-gate 	fd = open(raw, O_WRONLY);
5100Sstevel@tonic-gate 	if (fd == -1 || fstat(fd, &stat) != 0) {
5110Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL, raw);
5120Sstevel@tonic-gate 		exit(-1);
5130Sstevel@tonic-gate 	}
5140Sstevel@tonic-gate 	if (!nowrite &&
5150Sstevel@tonic-gate 	    pwrite(fd, stage1_buffer, SECTOR_SIZE, 0) != SECTOR_SIZE) {
5160Sstevel@tonic-gate 		(void) fprintf(stderr, WRITE_FAIL_BOOTSEC);
5170Sstevel@tonic-gate 		exit(-1);
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 	(void) fprintf(stdout, WRITE_MBOOT);
5200Sstevel@tonic-gate 	(void) close(fd);
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate static void
5240Sstevel@tonic-gate modify_and_write_stage1(int dev_fd)
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate 	if (is_floppy) {
5270Sstevel@tonic-gate 		stage2_first_sector = blocklist[0];
5280Sstevel@tonic-gate 		/* copy bios parameter block (for fat fs) */
5290Sstevel@tonic-gate 		bcopy(bpb_sect + STAGE1_BPB_OFFSET,
5300Sstevel@tonic-gate 		    stage1_buffer + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
5310Sstevel@tonic-gate 	} else if (is_bootpar) {
5325589Ssy25831 		stage2_first_sector = get_start_sector(dev_fd) + blocklist[0];
5330Sstevel@tonic-gate 		/* copy bios parameter block (for fat fs) and MBR */
5340Sstevel@tonic-gate 		bcopy(bpb_sect + STAGE1_BPB_OFFSET,
5350Sstevel@tonic-gate 		    stage1_buffer + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
5360Sstevel@tonic-gate 		bcopy(boot_sect + BOOTSZ, stage1_buffer + BOOTSZ, 512 - BOOTSZ);
5370Sstevel@tonic-gate 		*((unsigned char *)(stage1_buffer + STAGE1_FORCE_LBA)) = 1;
5380Sstevel@tonic-gate 	} else {
5395589Ssy25831 		stage2_first_sector = get_start_sector(dev_fd) + STAGE2_BLKOFF;
5400Sstevel@tonic-gate 		/* copy MBR to stage1 in case of overwriting MBR sector */
5410Sstevel@tonic-gate 		bcopy(boot_sect + BOOTSZ, stage1_buffer + BOOTSZ, 512 - BOOTSZ);
5420Sstevel@tonic-gate 		*((unsigned char *)(stage1_buffer + STAGE1_FORCE_LBA)) = 1;
5430Sstevel@tonic-gate 	}
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	/* modify default stage1 file generated by GRUB */
5460Sstevel@tonic-gate 	*((ulong_t *)(stage1_buffer + STAGE1_STAGE2_SECTOR))
5475589Ssy25831 	    = stage2_first_sector;
5480Sstevel@tonic-gate 	*((ushort_t *)(stage1_buffer + STAGE1_STAGE2_ADDRESS))
5495589Ssy25831 	    = STAGE2_MEMADDR;
5500Sstevel@tonic-gate 	*((ushort_t *)(stage1_buffer + STAGE1_STAGE2_SEGMENT))
5515589Ssy25831 	    = STAGE2_MEMADDR >> 4;
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	/*
5540Sstevel@tonic-gate 	 * XXX the default grub distribution also:
5550Sstevel@tonic-gate 	 * - Copy the possible MBR/extended part table
5560Sstevel@tonic-gate 	 * - Set the boot drive of stage1
5570Sstevel@tonic-gate 	 */
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	/* write stage1/pboot to 1st sector */
5600Sstevel@tonic-gate 	if (!nowrite &&
5610Sstevel@tonic-gate 	    pwrite(dev_fd, stage1_buffer, SECTOR_SIZE, 0) != SECTOR_SIZE) {
5620Sstevel@tonic-gate 		(void) fprintf(stderr, WRITE_FAIL_PBOOT);
5630Sstevel@tonic-gate 		exit(-1);
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	if (is_floppy) {
5670Sstevel@tonic-gate 		(void) fprintf(stdout, WRITE_BOOTSEC_FLOPPY);
5680Sstevel@tonic-gate 	} else {
5690Sstevel@tonic-gate 		(void) fprintf(stdout, WRITE_PBOOT,
5705589Ssy25831 		    partition, get_start_sector(dev_fd));
5710Sstevel@tonic-gate 	}
5720Sstevel@tonic-gate }
5730Sstevel@tonic-gate 
5748434SEnrico.Perla@Sun.COM static void check_extended_support(char *stage2)
5758434SEnrico.Perla@Sun.COM {
5768434SEnrico.Perla@Sun.COM 	char	*cmp = stage2_buffer + STAGE2_SIGN_OFFSET - 1;
5778434SEnrico.Perla@Sun.COM 
5788434SEnrico.Perla@Sun.COM 	if ((*cmp++ != '\xEE') && memcmp(cmp, extended_sig, HASH_SIZE) != 0) {
5798434SEnrico.Perla@Sun.COM 		fprintf(stderr, "%s does not support extended versioning\n",
5808434SEnrico.Perla@Sun.COM 		    stage2);
5818434SEnrico.Perla@Sun.COM 		do_version = 0;
5828434SEnrico.Perla@Sun.COM 	}
5838434SEnrico.Perla@Sun.COM }
5848434SEnrico.Perla@Sun.COM 
5858434SEnrico.Perla@Sun.COM 
5868434SEnrico.Perla@Sun.COM static void print_info()
5878434SEnrico.Perla@Sun.COM {
5888434SEnrico.Perla@Sun.COM 	int	i;
5898434SEnrico.Perla@Sun.COM 
5908434SEnrico.Perla@Sun.COM 	if (strip) {
5918434SEnrico.Perla@Sun.COM 		fprintf(stdout, "%s\n", verstring);
5928434SEnrico.Perla@Sun.COM 	} else {
5938434SEnrico.Perla@Sun.COM 		fprintf(stdout, "Grub extended version information : %s\n",
5948434SEnrico.Perla@Sun.COM 		    verstring);
5958434SEnrico.Perla@Sun.COM 		fprintf(stdout, "Grub stage2 (MD5) signature : ");
5968434SEnrico.Perla@Sun.COM 	}
5978434SEnrico.Perla@Sun.COM 
5988434SEnrico.Perla@Sun.COM 	for (i = 0; i < HASH_SIZE; i++)
5998434SEnrico.Perla@Sun.COM 		fprintf(stdout, "%02x", (unsigned char)signature[i]);
6008434SEnrico.Perla@Sun.COM 
6018434SEnrico.Perla@Sun.COM 	fprintf(stdout, "\n");
6028434SEnrico.Perla@Sun.COM }
6038434SEnrico.Perla@Sun.COM 
6048434SEnrico.Perla@Sun.COM static int
6058434SEnrico.Perla@Sun.COM read_stage2_info(int dev_fd)
6068434SEnrico.Perla@Sun.COM {
6078434SEnrico.Perla@Sun.COM 	int 	ret;
6088434SEnrico.Perla@Sun.COM 	int	first_offset, second_offset;
6098434SEnrico.Perla@Sun.COM 	char	*sign;
6108434SEnrico.Perla@Sun.COM 
6118434SEnrico.Perla@Sun.COM 	if (is_floppy || is_bootpar) {
6128434SEnrico.Perla@Sun.COM 
6138434SEnrico.Perla@Sun.COM 		ret = pread(dev_fd, stage1_buffer, SECTOR_SIZE, 0);
6148434SEnrico.Perla@Sun.COM 		if (ret != SECTOR_SIZE) {
6158434SEnrico.Perla@Sun.COM 			perror("Error reading stage1 sector");
6168434SEnrico.Perla@Sun.COM 			return (1);
6178434SEnrico.Perla@Sun.COM 		}
6188434SEnrico.Perla@Sun.COM 
6198434SEnrico.Perla@Sun.COM 		first_offset = *((ulong_t *)(stage1_buffer +
6208434SEnrico.Perla@Sun.COM 		    STAGE1_STAGE2_SECTOR));
6218434SEnrico.Perla@Sun.COM 
6228434SEnrico.Perla@Sun.COM 		/* Start reading in the first sector of stage 2 */
6238434SEnrico.Perla@Sun.COM 
6248434SEnrico.Perla@Sun.COM 		ret = pread(dev_fd, stage2_buffer, SECTOR_SIZE, first_offset *
6258434SEnrico.Perla@Sun.COM 		    SECTOR_SIZE);
6268434SEnrico.Perla@Sun.COM 		if (ret != SECTOR_SIZE) {
6278434SEnrico.Perla@Sun.COM 			perror("Error reading stage2 first sector");
6288434SEnrico.Perla@Sun.COM 			return (1);
6298434SEnrico.Perla@Sun.COM 		}
6308434SEnrico.Perla@Sun.COM 
6318434SEnrico.Perla@Sun.COM 		/* From the block list section grab stage2 second sector */
6328434SEnrico.Perla@Sun.COM 
6338434SEnrico.Perla@Sun.COM 		second_offset = *((ulong_t *)(stage2_buffer +
6348434SEnrico.Perla@Sun.COM 		    STAGE2_BLOCKLIST));
6358434SEnrico.Perla@Sun.COM 
6368434SEnrico.Perla@Sun.COM 		ret = pread(dev_fd, stage2_buffer + SECTOR_SIZE, SECTOR_SIZE,
6378434SEnrico.Perla@Sun.COM 		    second_offset * SECTOR_SIZE);
6388434SEnrico.Perla@Sun.COM 		if (ret != SECTOR_SIZE) {
6398434SEnrico.Perla@Sun.COM 			perror("Error reading stage2 second sector");
6408434SEnrico.Perla@Sun.COM 			return (1);
6418434SEnrico.Perla@Sun.COM 		}
6428434SEnrico.Perla@Sun.COM 	} else {
6438434SEnrico.Perla@Sun.COM 		ret = pread(dev_fd, stage2_buffer, 2 * SECTOR_SIZE,
6448434SEnrico.Perla@Sun.COM 		    STAGE2_BLKOFF * SECTOR_SIZE);
6458434SEnrico.Perla@Sun.COM 		if (ret != 2 * SECTOR_SIZE) {
6468434SEnrico.Perla@Sun.COM 			perror("Error reading stage2 sectors");
6478434SEnrico.Perla@Sun.COM 			return (1);
6488434SEnrico.Perla@Sun.COM 		}
6498434SEnrico.Perla@Sun.COM 	}
6508434SEnrico.Perla@Sun.COM 
6518434SEnrico.Perla@Sun.COM 	sign = stage2_buffer + STAGE2_SIGN_OFFSET - 1;
6528434SEnrico.Perla@Sun.COM 	if (*sign++ != '\xEE')
6538434SEnrico.Perla@Sun.COM 		return (1);
6548434SEnrico.Perla@Sun.COM 	(void) memcpy(signature, sign, HASH_SIZE);
6558434SEnrico.Perla@Sun.COM 	sign = stage2_buffer + STAGE2_PKG_VERSION;
6568434SEnrico.Perla@Sun.COM 	(void) strncpy(verstring, sign, VERSION_SIZE);
6578434SEnrico.Perla@Sun.COM 	return (0);
6588434SEnrico.Perla@Sun.COM }
6598434SEnrico.Perla@Sun.COM 
6608434SEnrico.Perla@Sun.COM 
6618434SEnrico.Perla@Sun.COM static int
6628434SEnrico.Perla@Sun.COM compute_and_write_md5hash(char *dest)
6638434SEnrico.Perla@Sun.COM {
6648434SEnrico.Perla@Sun.COM 	struct stat	sb;
6658434SEnrico.Perla@Sun.COM 	char		*buffer;
6668434SEnrico.Perla@Sun.COM 
6678434SEnrico.Perla@Sun.COM 	if (fstat(stage2_fd, &sb) == -1)
6688434SEnrico.Perla@Sun.COM 		return (-1);
6698434SEnrico.Perla@Sun.COM 
6708434SEnrico.Perla@Sun.COM 	buffer = malloc(sb.st_size);
6718434SEnrico.Perla@Sun.COM 	if (buffer == NULL)
6728434SEnrico.Perla@Sun.COM 		return (-1);
6738434SEnrico.Perla@Sun.COM 
6748434SEnrico.Perla@Sun.COM 	if (lseek(stage2_fd, 0, SEEK_SET) == -1)
6758434SEnrico.Perla@Sun.COM 		return (-1);
6768434SEnrico.Perla@Sun.COM 	if (read(stage2_fd, buffer, sb.st_size) < 0)
6778434SEnrico.Perla@Sun.COM 		return (-1);
6788434SEnrico.Perla@Sun.COM 
6798434SEnrico.Perla@Sun.COM 	md5_calc(dest, buffer, sb.st_size);
6808434SEnrico.Perla@Sun.COM 	free(buffer);
6818434SEnrico.Perla@Sun.COM 	return (0);
6828434SEnrico.Perla@Sun.COM }
6838434SEnrico.Perla@Sun.COM 
6848434SEnrico.Perla@Sun.COM 
6850Sstevel@tonic-gate #define	START_BLOCK(pos)	(*(ulong_t *)(pos))
6860Sstevel@tonic-gate #define	NUM_BLOCK(pos)		(*(ushort_t *)((pos) + 4))
6870Sstevel@tonic-gate #define	START_SEG(pos)		(*(ushort_t *)((pos) + 6))
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate static void
6900Sstevel@tonic-gate modify_and_write_stage2(int dev_fd)
6910Sstevel@tonic-gate {
6928434SEnrico.Perla@Sun.COM 	int 	nrecord;
6938434SEnrico.Perla@Sun.COM 	off_t 	offset;
6948434SEnrico.Perla@Sun.COM 	char	*dest;
6958434SEnrico.Perla@Sun.COM 
6968434SEnrico.Perla@Sun.COM 	if (do_version) {
6978434SEnrico.Perla@Sun.COM 		dest = stage2_buffer + STAGE2_SIGN_OFFSET;
6988434SEnrico.Perla@Sun.COM 		if (compute_and_write_md5hash(dest) < 0)
6998434SEnrico.Perla@Sun.COM 			perror("MD5 operation");
7008434SEnrico.Perla@Sun.COM 		dest = stage2_buffer + STAGE2_PKG_VERSION;
7018434SEnrico.Perla@Sun.COM 		(void) strncpy(dest, verstring, VERSION_SIZE);
7028434SEnrico.Perla@Sun.COM 	}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	if (is_floppy || is_bootpar) {
7050Sstevel@tonic-gate 		int i = 0;
70610021SSheshadri.Vasudevan@Sun.COM 		uint32_t partition_offset;
70710021SSheshadri.Vasudevan@Sun.COM 		uint32_t install_addr = 0x8200;
7080Sstevel@tonic-gate 		uchar_t *pos = (uchar_t *)stage2_buffer + STAGE2_BLOCKLIST;
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 		stage2_first_sector = blocklist[0];
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 		/* figure out the second sector */
7130Sstevel@tonic-gate 		if (blocklist[1] > 1) {
7140Sstevel@tonic-gate 			blocklist[0]++;
7150Sstevel@tonic-gate 			blocklist[1]--;
7160Sstevel@tonic-gate 		} else {
7170Sstevel@tonic-gate 			i += 2;
7180Sstevel@tonic-gate 		}
7190Sstevel@tonic-gate 		stage2_second_sector = blocklist[i];
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 		if (is_floppy)
7220Sstevel@tonic-gate 			partition_offset = 0;
7230Sstevel@tonic-gate 		else	/* solaris boot partition */
7245589Ssy25831 			partition_offset = get_start_sector(dev_fd);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 		/* install the blocklist at the end of stage2_buffer */
7270Sstevel@tonic-gate 		while (blocklist[i]) {
7280Sstevel@tonic-gate 			if (START_BLOCK(pos - 8) != 0 &&
7290Sstevel@tonic-gate 			    START_BLOCK(pos - 8) != blocklist[i + 2]) {
7300Sstevel@tonic-gate 				(void) fprintf(stderr, PCFS_FRAGMENTED);
7310Sstevel@tonic-gate 				exit(-1);
7320Sstevel@tonic-gate 			}
7330Sstevel@tonic-gate 			START_BLOCK(pos) = blocklist[i] + partition_offset;
7340Sstevel@tonic-gate 			START_SEG(pos) = (ushort_t)(install_addr >> 4);
7350Sstevel@tonic-gate 			NUM_BLOCK(pos) = blocklist[i + 1];
7360Sstevel@tonic-gate 			install_addr += blocklist[i + 1] * SECTOR_SIZE;
7370Sstevel@tonic-gate 			pos -= 8;
7380Sstevel@tonic-gate 			i += 2;
7390Sstevel@tonic-gate 		}
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	} else {
7420Sstevel@tonic-gate 		/*
7430Sstevel@tonic-gate 		 * In a solaris partition, stage2 is written to contiguous
7440Sstevel@tonic-gate 		 * blocks. So we update the starting block only.
7450Sstevel@tonic-gate 		 */
7460Sstevel@tonic-gate 		*((ulong_t *)(stage2_buffer + STAGE2_BLOCKLIST)) =
7470Sstevel@tonic-gate 		    stage2_first_sector + 1;
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	if (is_floppy) {
7510Sstevel@tonic-gate 		/* modify the config file to add (fd0) */
7520Sstevel@tonic-gate 		char *config_file = stage2_buffer + STAGE2_VER_STRING;
7530Sstevel@tonic-gate 		while (*config_file++)
7540Sstevel@tonic-gate 			;
7550Sstevel@tonic-gate 		strcpy(config_file, "(fd0)/boot/grub/menu.lst");
7560Sstevel@tonic-gate 	} else {
7570Sstevel@tonic-gate 		/* force lba and set disk partition */
7580Sstevel@tonic-gate 		*((unsigned char *) (stage2_buffer + STAGE2_FORCE_LBA)) = 1;
7590Sstevel@tonic-gate 		*((long *)(stage2_buffer + STAGE2_INSTALLPART))
7600Sstevel@tonic-gate 		    = (partition << 16) | (slice << 8) | 0xff;
7610Sstevel@tonic-gate 	}
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	/* modification done, now do the writing */
7640Sstevel@tonic-gate 	if (is_floppy || is_bootpar) {
7650Sstevel@tonic-gate 		/* we rewrite block 0 and 1 and that's it */
7660Sstevel@tonic-gate 		if (!nowrite &&
7670Sstevel@tonic-gate 		    (pwrite(dev_fd, stage2_buffer, SECTOR_SIZE,
7680Sstevel@tonic-gate 		    stage2_first_sector * SECTOR_SIZE) != SECTOR_SIZE ||
7690Sstevel@tonic-gate 		    pwrite(dev_fd, stage2_buffer + SECTOR_SIZE, SECTOR_SIZE,
7700Sstevel@tonic-gate 		    stage2_second_sector * SECTOR_SIZE) != SECTOR_SIZE)) {
7710Sstevel@tonic-gate 			(void) fprintf(stderr, WRITE_FAIL_STAGE2);
7720Sstevel@tonic-gate 			exit(-1);
7730Sstevel@tonic-gate 		}
7740Sstevel@tonic-gate 		(void) fprintf(stdout, WRITE_STAGE2_PCFS);
7750Sstevel@tonic-gate 		return;
7760Sstevel@tonic-gate 	}
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	/* for disk, write stage2 starting at STAGE2_BLKOFF sector */
7790Sstevel@tonic-gate 	offset = STAGE2_BLKOFF;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	/* write the modified first two sectors */
7820Sstevel@tonic-gate 	if (!nowrite && pwrite(dev_fd, stage2_buffer, 2 * SECTOR_SIZE,
7830Sstevel@tonic-gate 	    offset * SECTOR_SIZE) != 2 * SECTOR_SIZE) {
7840Sstevel@tonic-gate 		(void) fprintf(stderr, WRITE_FAIL_STAGE2);
7850Sstevel@tonic-gate 		exit(-1);
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	/* write the remaining sectors */
7890Sstevel@tonic-gate 	nrecord = 2;
7900Sstevel@tonic-gate 	offset += 2;
7910Sstevel@tonic-gate 	for (;;) {
7920Sstevel@tonic-gate 		int nread, nwrite;
7930Sstevel@tonic-gate 		nread = pread(stage2_fd, stage2_buffer, SECTOR_SIZE,
7940Sstevel@tonic-gate 		    nrecord * SECTOR_SIZE);
7950Sstevel@tonic-gate 		if (nread > 0 && !nowrite)
7960Sstevel@tonic-gate 			nwrite = pwrite(dev_fd, stage2_buffer, SECTOR_SIZE,
7970Sstevel@tonic-gate 			    offset * SECTOR_SIZE);
7980Sstevel@tonic-gate 		else
7990Sstevel@tonic-gate 			nwrite = SECTOR_SIZE;
8000Sstevel@tonic-gate 		if (nread < 0 || nwrite != SECTOR_SIZE) {
8010Sstevel@tonic-gate 			(void) fprintf(stderr, WRITE_FAIL_STAGE2_BLOCKS,
8020Sstevel@tonic-gate 			    nread, nwrite);
8030Sstevel@tonic-gate 			break;
8040Sstevel@tonic-gate 		}
805322Sjongkis 		if (nread > 0) {
806322Sjongkis 			nrecord ++;
807322Sjongkis 			offset ++;
808322Sjongkis 		}
8090Sstevel@tonic-gate 		if (nread < SECTOR_SIZE)
8100Sstevel@tonic-gate 			break;	/* end of file */
8110Sstevel@tonic-gate 	}
8120Sstevel@tonic-gate 	(void) fprintf(stdout, WRITE_STAGE2_DISK,
8130Sstevel@tonic-gate 	    partition, nrecord, STAGE2_BLKOFF, stage2_first_sector);
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate static char *
8170Sstevel@tonic-gate get_raw_partition(char *device)
8180Sstevel@tonic-gate {
8190Sstevel@tonic-gate 	int len;
8200Sstevel@tonic-gate 	struct mboot *mboot;
8210Sstevel@tonic-gate 	static char *raw = NULL;
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	if (raw)
8240Sstevel@tonic-gate 		return (raw);
8250Sstevel@tonic-gate 	raw = strdup(device);
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	if (is_floppy)
8280Sstevel@tonic-gate 		return (raw);
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	if (is_bootpar) {
8310Sstevel@tonic-gate 		int i;
8320Sstevel@tonic-gate 		char *end = strstr(raw, "p0:boot");
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 		end[2] = 0;		/* chop off :boot */
8350Sstevel@tonic-gate 		read_boot_sect(raw);
8360Sstevel@tonic-gate 		mboot = (struct mboot *)boot_sect;
8370Sstevel@tonic-gate 		for (i = 0; i < FD_NUMPART; i++) {
8380Sstevel@tonic-gate 			struct ipart *part = (struct ipart *)mboot->parts + i;
8390Sstevel@tonic-gate 			if (part->systid == 0xbe)	/* solaris boot part */
8400Sstevel@tonic-gate 				break;
8410Sstevel@tonic-gate 		}
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 		if (i == FD_NUMPART) {
8440Sstevel@tonic-gate 			(void) fprintf(stderr, BOOTPAR_NOTFOUND, device);
8450Sstevel@tonic-gate 			exit(-1);
8460Sstevel@tonic-gate 		}
8470Sstevel@tonic-gate 		end[1] = '1' + i;	/* set partition name */
8480Sstevel@tonic-gate 		return (raw);
8490Sstevel@tonic-gate 	}
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	/* For disk, remember slice and return whole fdisk partition  */
8520Sstevel@tonic-gate 	len = strlen(raw);
8530Sstevel@tonic-gate 	if (raw[len - 2] != 's' || raw[len - 1] == '2') {
8540Sstevel@tonic-gate 		(void) fprintf(stderr, NOT_ROOT_SLICE);
8550Sstevel@tonic-gate 		exit(-1);
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 	slice = atoi(&raw[len - 1]);
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	raw[len - 2] = 's';
8600Sstevel@tonic-gate 	raw[len - 1] = '2';
8610Sstevel@tonic-gate 	return (raw);
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate #define	TMP_MNTPT	"/tmp/installgrub_pcfs"
8650Sstevel@tonic-gate static void
8660Sstevel@tonic-gate copy_stage2(int dev_fd, char *device)
8670Sstevel@tonic-gate {
8680Sstevel@tonic-gate 	FILE *mntfp;
8690Sstevel@tonic-gate 	int i, pcfs_fp;
8700Sstevel@tonic-gate 	char buf[SECTOR_SIZE];
8710Sstevel@tonic-gate 	char *cp;
8720Sstevel@tonic-gate 	struct mnttab mp = {0}, mpref = {0};
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	/* convert raw to block device name by removing the first 'r' */
8750Sstevel@tonic-gate 	(void) strncpy(buf, device, sizeof (buf));
8760Sstevel@tonic-gate 	buf[sizeof (buf) - 1] = 0;
8770Sstevel@tonic-gate 	cp = strchr(buf, 'r');
8780Sstevel@tonic-gate 	if (cp == NULL) {
8790Sstevel@tonic-gate 		(void) fprintf(stderr, CONVERT_FAIL, device);
8800Sstevel@tonic-gate 		exit(-1);
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 	do {
8830Sstevel@tonic-gate 		*cp = *(cp + 1);
8840Sstevel@tonic-gate 	} while (*(++cp));
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	/* get the mount point, if any */
8870Sstevel@tonic-gate 	mntfp = fopen("/etc/mnttab", "r");
8880Sstevel@tonic-gate 	if (mntfp == NULL) {
8890Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL_FILE, "/etc/mnttab");
8900Sstevel@tonic-gate 		exit(-1);
8910Sstevel@tonic-gate 	}
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	mpref.mnt_special = buf;
8940Sstevel@tonic-gate 	if (getmntany(mntfp, &mp, &mpref) != 0) {
8950Sstevel@tonic-gate 		char cmd[128];
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 		/* not mounted, try remount */
8980Sstevel@tonic-gate 		(void) mkdir(TMP_MNTPT, S_IRWXU);
8990Sstevel@tonic-gate 		(void) snprintf(cmd, sizeof (cmd), "mount -F pcfs %s %s",
9000Sstevel@tonic-gate 		    buf, TMP_MNTPT);
9010Sstevel@tonic-gate 		(void) system(cmd);
9020Sstevel@tonic-gate 		rewind(mntfp);
9030Sstevel@tonic-gate 		bzero(&mp, sizeof (mp));
9040Sstevel@tonic-gate 		if (getmntany(mntfp, &mp, &mpref) != 0) {
9050Sstevel@tonic-gate 			(void) fprintf(stderr, MOUNT_FAIL, buf);
9060Sstevel@tonic-gate 			exit(-1);
9070Sstevel@tonic-gate 		}
9080Sstevel@tonic-gate 	}
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf),
9110Sstevel@tonic-gate 	    "%s/boot", mp.mnt_mountp);
9120Sstevel@tonic-gate 	(void) mkdir(buf, S_IRWXU);
9130Sstevel@tonic-gate 	(void) strcat(buf, "/grub");
9140Sstevel@tonic-gate 	(void) mkdir(buf, S_IRWXU);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	(void) strcat(buf, "/stage2");
9170Sstevel@tonic-gate 	pcfs_fp = open(buf, O_WRONLY | O_CREAT, S_IRWXU);
9180Sstevel@tonic-gate 	if (pcfs_fp == -1) {
9190Sstevel@tonic-gate 		(void) fprintf(stderr, OPEN_FAIL_FILE, buf);
9200Sstevel@tonic-gate 		perror("open:");
9210Sstevel@tonic-gate 		(void) umount(TMP_MNTPT);
9220Sstevel@tonic-gate 		exit(-1);
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	/* write stage2 to pcfs */
9260Sstevel@tonic-gate 	for (i = 0; ; i++) {
9270Sstevel@tonic-gate 		int nread, nwrite;
9280Sstevel@tonic-gate 		nread = pread(stage2_fd, buf, SECTOR_SIZE, i * SECTOR_SIZE);
9290Sstevel@tonic-gate 		if (nowrite)
9300Sstevel@tonic-gate 			nwrite = nread;
9310Sstevel@tonic-gate 		else
9320Sstevel@tonic-gate 			nwrite = pwrite(pcfs_fp, buf, nread, i * SECTOR_SIZE);
9330Sstevel@tonic-gate 		if (nread < 0 || nwrite != nread) {
9340Sstevel@tonic-gate 			(void) fprintf(stderr, WRITE_FAIL_STAGE2_BLOCKS,
9350Sstevel@tonic-gate 			    nread, nwrite);
9360Sstevel@tonic-gate 			break;
9370Sstevel@tonic-gate 		}
9380Sstevel@tonic-gate 		if (nread < SECTOR_SIZE)
9390Sstevel@tonic-gate 			break;	/* end of file */
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 	(void) close(pcfs_fp);
9420Sstevel@tonic-gate 	(void) umount(TMP_MNTPT);
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	/*
9450Sstevel@tonic-gate 	 * Now, get the blocklist from the device.
9460Sstevel@tonic-gate 	 */
9470Sstevel@tonic-gate 	bzero(blocklist, sizeof (blocklist));
9480Sstevel@tonic-gate 	if (read_stage2_blocklist(dev_fd, blocklist) != 0)
9490Sstevel@tonic-gate 		exit(-1);
9500Sstevel@tonic-gate }
951