xref: /titanic_53/usr/src/cmd/boot/installboot/i386/installboot.c (revision 161da084b704271993dcfe6c1ed128c60a3a75b0)
14c1177a4SToomas Soome /*
24c1177a4SToomas Soome  * CDDL HEADER START
34c1177a4SToomas Soome  *
44c1177a4SToomas Soome  * The contents of this file are subject to the terms of the
54c1177a4SToomas Soome  * Common Development and Distribution License (the "License").
64c1177a4SToomas Soome  * You may not use this file except in compliance with the License.
74c1177a4SToomas Soome  *
84c1177a4SToomas Soome  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94c1177a4SToomas Soome  * or http://www.opensolaris.org/os/licensing.
104c1177a4SToomas Soome  * See the License for the specific language governing permissions
114c1177a4SToomas Soome  * and limitations under the License.
124c1177a4SToomas Soome  *
134c1177a4SToomas Soome  * When distributing Covered Code, include this CDDL HEADER in each
144c1177a4SToomas Soome  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154c1177a4SToomas Soome  * If applicable, add the following below this CDDL HEADER, with the
164c1177a4SToomas Soome  * fields enclosed by brackets "[]" replaced with your own identifying
174c1177a4SToomas Soome  * information: Portions Copyright [yyyy] [name of copyright owner]
184c1177a4SToomas Soome  *
194c1177a4SToomas Soome  * CDDL HEADER END
204c1177a4SToomas Soome  */
214c1177a4SToomas Soome /*
224c1177a4SToomas Soome  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
234c1177a4SToomas Soome  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
24*161da084SToomas Soome  * Copyright 2017 Toomas Soome <tsoome@me.com>
254c1177a4SToomas Soome  */
264c1177a4SToomas Soome 
274c1177a4SToomas Soome #include <stdio.h>
284c1177a4SToomas Soome #include <errno.h>
294c1177a4SToomas Soome #include <unistd.h>
304c1177a4SToomas Soome #include <fcntl.h>
314c1177a4SToomas Soome #include <assert.h>
324c1177a4SToomas Soome #include <locale.h>
334c1177a4SToomas Soome #include <strings.h>
344c1177a4SToomas Soome #include <libfdisk.h>
354c1177a4SToomas Soome 
364c1177a4SToomas Soome #include <sys/dktp/fdisk.h>
374c1177a4SToomas Soome #include <sys/dkio.h>
384c1177a4SToomas Soome #include <sys/vtoc.h>
394c1177a4SToomas Soome #include <sys/multiboot.h>
404c1177a4SToomas Soome #include <sys/types.h>
414c1177a4SToomas Soome #include <sys/stat.h>
424c1177a4SToomas Soome #include <sys/sysmacros.h>
434c1177a4SToomas Soome #include <sys/efi_partition.h>
444c1177a4SToomas Soome #include <libfstyp.h>
454c1177a4SToomas Soome #include <uuid/uuid.h>
464c1177a4SToomas Soome 
474c1177a4SToomas Soome #include "installboot.h"
484c1177a4SToomas Soome #include "../../common/bblk_einfo.h"
494c1177a4SToomas Soome #include "../../common/boot_utils.h"
504c1177a4SToomas Soome #include "../../common/mboot_extra.h"
514c1177a4SToomas Soome #include "getresponse.h"
524c1177a4SToomas Soome 
534c1177a4SToomas Soome #ifndef	TEXT_DOMAIN
544c1177a4SToomas Soome #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
554c1177a4SToomas Soome #endif
564c1177a4SToomas Soome 
574c1177a4SToomas Soome /*
584c1177a4SToomas Soome  * BIOS bootblock installation:
594c1177a4SToomas Soome  *
604c1177a4SToomas Soome  * 1. MBR is first sector of the disk. If the file system on target is
614c1177a4SToomas Soome  *    ufs or zfs, the same MBR code is installed on first sector of the
624c1177a4SToomas Soome  *    partition as well; this will allow to have real MBR sector to be
634c1177a4SToomas Soome  *    replaced by some other boot loader and have illumos chainloaded.
644c1177a4SToomas Soome  *
654c1177a4SToomas Soome  * installboot will record the start LBA and size of stage2 code in MBR code.
664c1177a4SToomas Soome  * On boot, the MBR code will read the stage2 code and executes it.
674c1177a4SToomas Soome  *
684c1177a4SToomas Soome  * 2. Stage2 location depends on file system type;
694c1177a4SToomas Soome  *    In case of zfs, installboot will store stage2 to zfs bootblk area,
704c1177a4SToomas Soome  *    which is 512k bytes from partition start and size is 3.5MB.
714c1177a4SToomas Soome  *
724c1177a4SToomas Soome  *    In case of ufs, the stage2 location is 50 512B sectors from
734c1177a4SToomas Soome  *    Solaris2 MBR partition start, within boot slice, boot slice size is
744c1177a4SToomas Soome  *    one cylinder.
754c1177a4SToomas Soome  *
764c1177a4SToomas Soome  *    In case of pcfs, the stage2 location is 50 512B sectors from beginning
774c1177a4SToomas Soome  *    of the disk, filling the space between MBR and first partition.
784c1177a4SToomas Soome  *    This location assumes no other bootloader and the space is one cylinder,
794c1177a4SToomas Soome  *    as first partition is starting from cylinder 1.
804c1177a4SToomas Soome  *
814c1177a4SToomas Soome  *    In case of GPT partitioning and if file system is not zfs, the boot
824c1177a4SToomas Soome  *    support is only possible with dedicated boot partition. For GPT,
834c1177a4SToomas Soome  *    the current implementation is using BOOT partition, which must exist.
844c1177a4SToomas Soome  *    BOOT partition does only contain raw boot blocks, without any file system.
854c1177a4SToomas Soome  *
864c1177a4SToomas Soome  * Loader stage2 is created with embedded version, by using fake multiboot (MB)
874c1177a4SToomas Soome  * header within first 32k and EINFO block is at the end of the actual
884c1177a4SToomas Soome  * boot block. MB header load_addr is set to 0 and load_end_addr is set to
894c1177a4SToomas Soome  * actual block end, so the EINFO size is (file size - load_end_addr).
904c1177a4SToomas Soome  * installboot does also store the illumos boot partition LBA to MB space,
914c1177a4SToomas Soome  * starting from bss_end_addr structure member location; stage2 will
924c1177a4SToomas Soome  * detect the partition and file system based on this value.
934c1177a4SToomas Soome  *
944c1177a4SToomas Soome  * Stored location values in MBR/stage2 also mean the bootblocks must be
954c1177a4SToomas Soome  * reinstalled in case the partition content is relocated.
964c1177a4SToomas Soome  */
974c1177a4SToomas Soome 
984c1177a4SToomas Soome static boolean_t	write_mbr = B_FALSE;
994c1177a4SToomas Soome static boolean_t	force_mbr = B_FALSE;
1004c1177a4SToomas Soome static boolean_t	force_update = B_FALSE;
1014c1177a4SToomas Soome static boolean_t	do_getinfo = B_FALSE;
1024c1177a4SToomas Soome static boolean_t	do_version = B_FALSE;
1034c1177a4SToomas Soome static boolean_t	do_mirror_bblk = B_FALSE;
1044c1177a4SToomas Soome static boolean_t	strip = B_FALSE;
1054c1177a4SToomas Soome static boolean_t	verbose_dump = B_FALSE;
1064c1177a4SToomas Soome 
1074c1177a4SToomas Soome /* Versioning string, if present. */
1084c1177a4SToomas Soome static char		*update_str;
1094c1177a4SToomas Soome 
1104c1177a4SToomas Soome /*
1114c1177a4SToomas Soome  * Temporary buffer to store the first 32K of data looking for a multiboot
1124c1177a4SToomas Soome  * signature.
1134c1177a4SToomas Soome  */
1144c1177a4SToomas Soome char			mboot_scan[MBOOT_SCAN_SIZE];
1154c1177a4SToomas Soome 
1164c1177a4SToomas Soome /* Function prototypes. */
1174c1177a4SToomas Soome static void check_options(char *);
1184c1177a4SToomas Soome static int get_start_sector(ib_device_t *);
1194c1177a4SToomas Soome 
120*161da084SToomas Soome static int read_stage1_from_file(char *, ib_data_t *);
121*161da084SToomas Soome static int read_bootblock_from_file(char *, ib_bootblock_t *);
122*161da084SToomas Soome static int read_bootblock_from_disk(ib_device_t *, ib_bootblock_t *, char **);
1234c1177a4SToomas Soome static void add_bootblock_einfo(ib_bootblock_t *, char *);
1244c1177a4SToomas Soome static int prepare_stage1(ib_data_t *);
1254c1177a4SToomas Soome static int prepare_bootblock(ib_data_t *, char *);
1264c1177a4SToomas Soome static int write_stage1(ib_data_t *);
1274c1177a4SToomas Soome static int write_bootblock(ib_data_t *);
1284c1177a4SToomas Soome static int init_device(ib_device_t *, char *);
1294c1177a4SToomas Soome static void cleanup_device(ib_device_t *);
1304c1177a4SToomas Soome static int commit_to_disk(ib_data_t *, char *);
1314c1177a4SToomas Soome static int handle_install(char *, char **);
1324c1177a4SToomas Soome static int handle_getinfo(char *, char **);
1334c1177a4SToomas Soome static int handle_mirror(char *, char **);
1344c1177a4SToomas Soome static boolean_t is_update_necessary(ib_data_t *, char *);
1354c1177a4SToomas Soome static int propagate_bootblock(ib_data_t *, ib_data_t *, char *);
1364c1177a4SToomas Soome static void usage(char *);
1374c1177a4SToomas Soome 
1384c1177a4SToomas Soome static int
read_stage1_from_file(char * path,ib_data_t * dest)1394c1177a4SToomas Soome read_stage1_from_file(char *path, ib_data_t *dest)
1404c1177a4SToomas Soome {
1414c1177a4SToomas Soome 	int	fd;
1424c1177a4SToomas Soome 
1434c1177a4SToomas Soome 	assert(dest != NULL);
1444c1177a4SToomas Soome 
1454c1177a4SToomas Soome 	/* read the stage1 file from filesystem */
1464c1177a4SToomas Soome 	fd = open(path, O_RDONLY);
1474c1177a4SToomas Soome 	if (fd == -1 ||
1484c1177a4SToomas Soome 	    read(fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) {
1494c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("cannot read stage1 file %s\n"),
1504c1177a4SToomas Soome 		    path);
1514c1177a4SToomas Soome 		return (BC_ERROR);
1524c1177a4SToomas Soome 	}
1534c1177a4SToomas Soome 	(void) close(fd);
1544c1177a4SToomas Soome 	return (BC_SUCCESS);
1554c1177a4SToomas Soome }
1564c1177a4SToomas Soome 
1574c1177a4SToomas Soome static int
read_bootblock_from_file(char * file,ib_bootblock_t * bblock)158*161da084SToomas Soome read_bootblock_from_file(char *file, ib_bootblock_t *bblock)
1594c1177a4SToomas Soome {
1604c1177a4SToomas Soome 	struct stat	sb;
1614c1177a4SToomas Soome 	uint32_t	buf_size;
1624c1177a4SToomas Soome 	uint32_t	mboot_off;
1634c1177a4SToomas Soome 	int		fd = -1;
1644c1177a4SToomas Soome 	int		retval = BC_ERROR;
1654c1177a4SToomas Soome 
166*161da084SToomas Soome 	assert(bblock != NULL);
1674c1177a4SToomas Soome 	assert(file != NULL);
1684c1177a4SToomas Soome 
1694c1177a4SToomas Soome 	fd = open(file, O_RDONLY);
1704c1177a4SToomas Soome 	if (fd == -1) {
1714c1177a4SToomas Soome 		BOOT_DEBUG("Error opening %s\n", file);
1724c1177a4SToomas Soome 		perror("open");
1734c1177a4SToomas Soome 		goto out;
1744c1177a4SToomas Soome 	}
1754c1177a4SToomas Soome 
1764c1177a4SToomas Soome 	if (fstat(fd, &sb) == -1) {
1774c1177a4SToomas Soome 		BOOT_DEBUG("Error getting information (stat) about %s", file);
1784c1177a4SToomas Soome 		perror("stat");
1794c1177a4SToomas Soome 		goto outfd;
1804c1177a4SToomas Soome 	}
1814c1177a4SToomas Soome 
1824c1177a4SToomas Soome 	/* loader bootblock has version built in */
1834c1177a4SToomas Soome 	buf_size = sb.st_size;
1844c1177a4SToomas Soome 
1854c1177a4SToomas Soome 	bblock->buf_size = buf_size;
1864c1177a4SToomas Soome 	BOOT_DEBUG("bootblock in-memory buffer size is %d\n",
1874c1177a4SToomas Soome 	    bblock->buf_size);
1884c1177a4SToomas Soome 
1894c1177a4SToomas Soome 	bblock->buf = malloc(buf_size);
1904c1177a4SToomas Soome 	if (bblock->buf == NULL) {
1914c1177a4SToomas Soome 		perror(gettext("Memory allocation failure"));
1924c1177a4SToomas Soome 		goto outbuf;
1934c1177a4SToomas Soome 	}
1944c1177a4SToomas Soome 	bblock->file = bblock->buf;
1954c1177a4SToomas Soome 
1964c1177a4SToomas Soome 	if (read(fd, bblock->file, bblock->buf_size) != bblock->buf_size) {
1974c1177a4SToomas Soome 		BOOT_DEBUG("Read from %s failed\n", file);
1984c1177a4SToomas Soome 		perror("read");
1994c1177a4SToomas Soome 		goto outfd;
2004c1177a4SToomas Soome 	}
2014c1177a4SToomas Soome 
2024c1177a4SToomas Soome 	if (find_multiboot(bblock->file, MBOOT_SCAN_SIZE, &mboot_off)
2034c1177a4SToomas Soome 	    != BC_SUCCESS) {
2044c1177a4SToomas Soome 		(void) fprintf(stderr,
2054c1177a4SToomas Soome 		    gettext("Unable to find multiboot header\n"));
2064c1177a4SToomas Soome 		goto outfd;
2074c1177a4SToomas Soome 	}
2084c1177a4SToomas Soome 
2094c1177a4SToomas Soome 	bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off);
2104c1177a4SToomas Soome 	bblock->mboot_off = mboot_off;
2114c1177a4SToomas Soome 
2124c1177a4SToomas Soome 	bblock->file_size =
2134c1177a4SToomas Soome 	    bblock->mboot->load_end_addr - bblock->mboot->load_addr;
2144c1177a4SToomas Soome 	BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size);
2154c1177a4SToomas Soome 
2164c1177a4SToomas Soome 	bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
2174c1177a4SToomas Soome 	bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
2184c1177a4SToomas Soome 
2194c1177a4SToomas Soome 	BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
2204c1177a4SToomas Soome 	    "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
2214c1177a4SToomas Soome 	    bblock->extra_size, bblock->buf, bblock->buf_size);
2224c1177a4SToomas Soome 
2234c1177a4SToomas Soome 	(void) close(fd);
2244c1177a4SToomas Soome 	return (BC_SUCCESS);
2254c1177a4SToomas Soome 
2264c1177a4SToomas Soome outbuf:
2274c1177a4SToomas Soome 	(void) free(bblock->buf);
2284c1177a4SToomas Soome 	bblock->buf = NULL;
2294c1177a4SToomas Soome outfd:
2304c1177a4SToomas Soome 	(void) close(fd);
2314c1177a4SToomas Soome out:
2324c1177a4SToomas Soome 	return (retval);
2334c1177a4SToomas Soome }
2344c1177a4SToomas Soome 
2354c1177a4SToomas Soome static int
read_bootblock_from_disk(ib_device_t * device,ib_bootblock_t * bblock,char ** path)2364c1177a4SToomas Soome read_bootblock_from_disk(ib_device_t *device, ib_bootblock_t *bblock,
2374c1177a4SToomas Soome     char **path)
2384c1177a4SToomas Soome {
2394c1177a4SToomas Soome 	int			dev_fd;
2404c1177a4SToomas Soome 	uint32_t		size, offset;
2414c1177a4SToomas Soome 	uint32_t		buf_size;
2424c1177a4SToomas Soome 	uint32_t		mboot_off;
2434c1177a4SToomas Soome 	multiboot_header_t	*mboot;
2444c1177a4SToomas Soome 
2454c1177a4SToomas Soome 	assert(device != NULL);
2464c1177a4SToomas Soome 	assert(bblock != NULL);
2474c1177a4SToomas Soome 
2484c1177a4SToomas Soome 	if (device->target.fstype == IG_FS_ZFS) {
2494c1177a4SToomas Soome 		dev_fd = device->target.fd;
2504c1177a4SToomas Soome 		offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE;
2514c1177a4SToomas Soome 		*path = device->target.path;
2524c1177a4SToomas Soome 	} else {
2534c1177a4SToomas Soome 		dev_fd = device->stage.fd;
2544c1177a4SToomas Soome 		offset = device->stage.offset * SECTOR_SIZE;
2554c1177a4SToomas Soome 		*path = device->stage.path;
2564c1177a4SToomas Soome 	}
2574c1177a4SToomas Soome 
2584c1177a4SToomas Soome 	if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan), offset)
2594c1177a4SToomas Soome 	    != BC_SUCCESS) {
2604c1177a4SToomas Soome 		BOOT_DEBUG("Error reading bootblock area\n");
2614c1177a4SToomas Soome 		perror("read");
2624c1177a4SToomas Soome 		return (BC_ERROR);
2634c1177a4SToomas Soome 	}
2644c1177a4SToomas Soome 
2654c1177a4SToomas Soome 	/* No multiboot means no chance of knowing bootblock size */
2664c1177a4SToomas Soome 	if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off)
2674c1177a4SToomas Soome 	    != BC_SUCCESS) {
2684c1177a4SToomas Soome 		BOOT_DEBUG("Unable to find multiboot header\n");
2694c1177a4SToomas Soome 		return (BC_NOEXTRA);
2704c1177a4SToomas Soome 	}
2714c1177a4SToomas Soome 	mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
2724c1177a4SToomas Soome 
2734c1177a4SToomas Soome 	/*
2744c1177a4SToomas Soome 	 * make sure mboot has sane values
2754c1177a4SToomas Soome 	 */
2764c1177a4SToomas Soome 	if (mboot->load_end_addr == 0 ||
2774c1177a4SToomas Soome 	    mboot->load_end_addr < mboot->load_addr)
2784c1177a4SToomas Soome 		return (BC_NOEXTRA);
2794c1177a4SToomas Soome 
2804c1177a4SToomas Soome 	/*
2814c1177a4SToomas Soome 	 * Currently, the amount of space reserved for extra information
2824c1177a4SToomas Soome 	 * is "fixed". We may have to scan for the terminating extra payload
2834c1177a4SToomas Soome 	 * in the future.
2844c1177a4SToomas Soome 	 */
2854c1177a4SToomas Soome 	size = mboot->load_end_addr - mboot->load_addr;
2864c1177a4SToomas Soome 	buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
2874c1177a4SToomas Soome 	bblock->file_size = size;
2884c1177a4SToomas Soome 
2894c1177a4SToomas Soome 	bblock->buf = malloc(buf_size);
2904c1177a4SToomas Soome 	if (bblock->buf == NULL) {
2914c1177a4SToomas Soome 		BOOT_DEBUG("Unable to allocate enough memory to read"
2924c1177a4SToomas Soome 		    " the extra bootblock from the disk\n");
2934c1177a4SToomas Soome 		perror(gettext("Memory allocation failure"));
2944c1177a4SToomas Soome 		return (BC_ERROR);
2954c1177a4SToomas Soome 	}
2964c1177a4SToomas Soome 	bblock->buf_size = buf_size;
2974c1177a4SToomas Soome 
2984c1177a4SToomas Soome 	if (read_in(dev_fd, bblock->buf, buf_size, offset) != BC_SUCCESS) {
2994c1177a4SToomas Soome 		BOOT_DEBUG("Error reading the bootblock\n");
3004c1177a4SToomas Soome 		(void) free(bblock->buf);
3014c1177a4SToomas Soome 		bblock->buf = NULL;
3024c1177a4SToomas Soome 		return (BC_ERROR);
3034c1177a4SToomas Soome 	}
3044c1177a4SToomas Soome 
3054c1177a4SToomas Soome 	/* Update pointers. */
3064c1177a4SToomas Soome 	bblock->file = bblock->buf;
3074c1177a4SToomas Soome 	bblock->mboot_off = mboot_off;
3084c1177a4SToomas Soome 	bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off);
3094c1177a4SToomas Soome 	bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
3104c1177a4SToomas Soome 	bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
3114c1177a4SToomas Soome 
3124c1177a4SToomas Soome 	BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
3134c1177a4SToomas Soome 	    "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
3144c1177a4SToomas Soome 	    bblock->extra_size, bblock->buf, bblock->buf_size);
3154c1177a4SToomas Soome 
3164c1177a4SToomas Soome 	return (BC_SUCCESS);
3174c1177a4SToomas Soome }
3184c1177a4SToomas Soome 
3194c1177a4SToomas Soome static boolean_t
is_update_necessary(ib_data_t * data,char * updt_str)3204c1177a4SToomas Soome is_update_necessary(ib_data_t *data, char *updt_str)
3214c1177a4SToomas Soome {
3224c1177a4SToomas Soome 	bblk_einfo_t	*einfo;
3234c1177a4SToomas Soome 	bblk_einfo_t	*einfo_file;
3244c1177a4SToomas Soome 	bblk_hs_t	bblock_hs;
3254c1177a4SToomas Soome 	ib_bootblock_t	bblock_disk;
3264c1177a4SToomas Soome 	ib_bootblock_t	*bblock_file = &data->bootblock;
3274c1177a4SToomas Soome 	ib_device_t	*device = &data->device;
3284c1177a4SToomas Soome 	int		ret;
3294c1177a4SToomas Soome 	char		*path;
3304c1177a4SToomas Soome 
3314c1177a4SToomas Soome 	assert(data != NULL);
3324c1177a4SToomas Soome 
3334c1177a4SToomas Soome 	bzero(&bblock_disk, sizeof (ib_bootblock_t));
3344c1177a4SToomas Soome 
3354c1177a4SToomas Soome 	ret = read_bootblock_from_disk(device, &bblock_disk, &path);
3364c1177a4SToomas Soome 	if (ret != BC_SUCCESS) {
3374c1177a4SToomas Soome 		BOOT_DEBUG("Unable to read bootblock from %s\n", path);
3384c1177a4SToomas Soome 		return (B_TRUE);
3394c1177a4SToomas Soome 	}
3404c1177a4SToomas Soome 
3414c1177a4SToomas Soome 	einfo = find_einfo(bblock_disk.extra, bblock_disk.extra_size);
3424c1177a4SToomas Soome 	if (einfo == NULL) {
3434c1177a4SToomas Soome 		BOOT_DEBUG("No extended information available on disk\n");
3444c1177a4SToomas Soome 		return (B_TRUE);
3454c1177a4SToomas Soome 	}
3464c1177a4SToomas Soome 
3474c1177a4SToomas Soome 	einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size);
3484c1177a4SToomas Soome 	if (einfo_file == NULL) {
3494c1177a4SToomas Soome 		/*
3504c1177a4SToomas Soome 		 * loader bootblock is versioned. missing version means
3514c1177a4SToomas Soome 		 * probably incompatible block. installboot can not install
3524c1177a4SToomas Soome 		 * grub, for example.
3534c1177a4SToomas Soome 		 */
3544c1177a4SToomas Soome 		(void) fprintf(stderr,
3554c1177a4SToomas Soome 		    gettext("ERROR: non versioned bootblock in file\n"));
3564c1177a4SToomas Soome 		return (B_FALSE);
3574c1177a4SToomas Soome 	} else {
3584c1177a4SToomas Soome 		if (updt_str == NULL) {
3594c1177a4SToomas Soome 			updt_str = einfo_get_string(einfo_file);
3604c1177a4SToomas Soome 			do_version = B_TRUE;
3614c1177a4SToomas Soome 		}
3624c1177a4SToomas Soome 	}
3634c1177a4SToomas Soome 
3644c1177a4SToomas Soome 	if (!do_version || updt_str == NULL) {
3654c1177a4SToomas Soome 		(void) fprintf(stderr,
3664c1177a4SToomas Soome 		    gettext("WARNING: target device %s has a "
3674c1177a4SToomas Soome 		    "versioned bootblock that is going to be overwritten by a "
3684c1177a4SToomas Soome 		    "non versioned one\n"), device->path);
3694c1177a4SToomas Soome 		return (B_TRUE);
3704c1177a4SToomas Soome 	}
3714c1177a4SToomas Soome 
3724c1177a4SToomas Soome 	if (force_update) {
3734c1177a4SToomas Soome 		BOOT_DEBUG("Forcing update of %s bootblock\n", device->path);
3744c1177a4SToomas Soome 		return (B_TRUE);
3754c1177a4SToomas Soome 	}
3764c1177a4SToomas Soome 
3774c1177a4SToomas Soome 	BOOT_DEBUG("Ready to check installed version vs %s\n", updt_str);
3784c1177a4SToomas Soome 
3794c1177a4SToomas Soome 	bblock_hs.src_buf = (unsigned char *)bblock_file->file;
3804c1177a4SToomas Soome 	bblock_hs.src_size = bblock_file->file_size;
3814c1177a4SToomas Soome 
3824c1177a4SToomas Soome 	return (einfo_should_update(einfo, &bblock_hs, updt_str));
3834c1177a4SToomas Soome }
3844c1177a4SToomas Soome 
3854c1177a4SToomas Soome static void
add_bootblock_einfo(ib_bootblock_t * bblock,char * updt_str)3864c1177a4SToomas Soome add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str)
3874c1177a4SToomas Soome {
3884c1177a4SToomas Soome 	bblk_hs_t	hs;
3894c1177a4SToomas Soome 	uint32_t	avail_space;
3904c1177a4SToomas Soome 
3914c1177a4SToomas Soome 	assert(bblock != NULL);
3924c1177a4SToomas Soome 
3934c1177a4SToomas Soome 	if (updt_str == NULL) {
3944c1177a4SToomas Soome 		BOOT_DEBUG("WARNING: no update string passed to "
3954c1177a4SToomas Soome 		    "add_bootblock_einfo()\n");
3964c1177a4SToomas Soome 		return;
3974c1177a4SToomas Soome 	}
3984c1177a4SToomas Soome 
3994c1177a4SToomas Soome 	/* Fill bootblock hashing source information. */
4004c1177a4SToomas Soome 	hs.src_buf = (unsigned char *)bblock->file;
4014c1177a4SToomas Soome 	hs.src_size = bblock->file_size;
4024c1177a4SToomas Soome 	/* How much space for the extended information structure? */
4034c1177a4SToomas Soome 	avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
4044c1177a4SToomas Soome 	/* Place the extended information structure. */
4054c1177a4SToomas Soome 	add_einfo(bblock->extra, updt_str, &hs, avail_space);
4064c1177a4SToomas Soome }
4074c1177a4SToomas Soome 
4084c1177a4SToomas Soome /*
4094c1177a4SToomas Soome  * set up data for case stage1 is installed as MBR
4104c1177a4SToomas Soome  * set up location and size of bootblock
4114c1177a4SToomas Soome  * set disk guid to provide unique information for biosdev command
4124c1177a4SToomas Soome  */
4134c1177a4SToomas Soome static int
prepare_stage1(ib_data_t * data)4144c1177a4SToomas Soome prepare_stage1(ib_data_t *data)
4154c1177a4SToomas Soome {
4164c1177a4SToomas Soome 	ib_device_t	*device;
4174c1177a4SToomas Soome 
4184c1177a4SToomas Soome 	assert(data != NULL);
4194c1177a4SToomas Soome 	device = &data->device;
4204c1177a4SToomas Soome 
4214c1177a4SToomas Soome 	/* copy BPB */
4224c1177a4SToomas Soome 	bcopy(device->mbr + STAGE1_BPB_OFFSET,
4234c1177a4SToomas Soome 	    data->stage1 + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
4244c1177a4SToomas Soome 
4254c1177a4SToomas Soome 
4264c1177a4SToomas Soome 	/* copy MBR, note STAGE1_SIG == BOOTSZ */
4274c1177a4SToomas Soome 	bcopy(device->mbr + STAGE1_SIG, data->stage1 + STAGE1_SIG,
4284c1177a4SToomas Soome 	    SECTOR_SIZE - STAGE1_SIG);
4294c1177a4SToomas Soome 
4304c1177a4SToomas Soome 	/* set stage2 size */
4314c1177a4SToomas Soome 	*((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) =
4324c1177a4SToomas Soome 	    (uint16_t)(data->bootblock.buf_size / SECTOR_SIZE);
4334c1177a4SToomas Soome 
4344c1177a4SToomas Soome 	/*
4354c1177a4SToomas Soome 	 * set stage2 location.
4364c1177a4SToomas Soome 	 * for zfs always use zfs embedding, for ufs/pcfs use partition_start
4374c1177a4SToomas Soome 	 * as base for stage2 location, for ufs/pcfs in MBR partition, use
4384c1177a4SToomas Soome 	 * free space after MBR record.
4394c1177a4SToomas Soome 	 */
4404c1177a4SToomas Soome 	if (device->target.fstype == IG_FS_ZFS)
4414c1177a4SToomas Soome 		*((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) =
4424c1177a4SToomas Soome 		    device->target.start + device->target.offset;
4434c1177a4SToomas Soome 	else {
4444c1177a4SToomas Soome 		*((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) =
4454c1177a4SToomas Soome 		    device->stage.start + device->stage.offset;
4464c1177a4SToomas Soome 	}
4474c1177a4SToomas Soome 
4484c1177a4SToomas Soome 	/*
4494c1177a4SToomas Soome 	 * set disk uuid. we only need reasonable amount of uniqueness
4504c1177a4SToomas Soome 	 * to allow biosdev to identify disk based on mbr differences.
4514c1177a4SToomas Soome 	 */
4524c1177a4SToomas Soome 	uuid_generate(data->stage1 + STAGE1_STAGE2_UUID);
4534c1177a4SToomas Soome 
4544c1177a4SToomas Soome 	return (BC_SUCCESS);
4554c1177a4SToomas Soome }
4564c1177a4SToomas Soome 
4574c1177a4SToomas Soome static int
prepare_bootblock(ib_data_t * data,char * updt_str)4584c1177a4SToomas Soome prepare_bootblock(ib_data_t *data, char *updt_str)
4594c1177a4SToomas Soome {
4604c1177a4SToomas Soome 	ib_bootblock_t		*bblock;
4614c1177a4SToomas Soome 	ib_device_t		*device;
4624c1177a4SToomas Soome 	uint64_t		*ptr;
4634c1177a4SToomas Soome 
4644c1177a4SToomas Soome 	assert(data != NULL);
4654c1177a4SToomas Soome 
4664c1177a4SToomas Soome 	bblock = &data->bootblock;
4674c1177a4SToomas Soome 	device = &data->device;
4684c1177a4SToomas Soome 
4694c1177a4SToomas Soome 	ptr = (uint64_t *)(&bblock->mboot->bss_end_addr);
4704c1177a4SToomas Soome 	*ptr = device->target.start;
4714c1177a4SToomas Soome 
4724c1177a4SToomas Soome 	/*
4734c1177a4SToomas Soome 	 * the loader bootblock has built in version, if custom
4744c1177a4SToomas Soome 	 * version was provided, update it.
4754c1177a4SToomas Soome 	 */
4764c1177a4SToomas Soome 	if (do_version)
4774c1177a4SToomas Soome 		add_bootblock_einfo(bblock, updt_str);
4784c1177a4SToomas Soome 
4794c1177a4SToomas Soome 	return (BC_SUCCESS);
4804c1177a4SToomas Soome }
4814c1177a4SToomas Soome 
4824c1177a4SToomas Soome static int
write_bootblock(ib_data_t * data)4834c1177a4SToomas Soome write_bootblock(ib_data_t *data)
4844c1177a4SToomas Soome {
4854c1177a4SToomas Soome 	ib_device_t	*device = &data->device;
4864c1177a4SToomas Soome 	ib_bootblock_t	*bblock = &data->bootblock;
4874c1177a4SToomas Soome 	uint64_t abs;
4884c1177a4SToomas Soome 	int dev_fd, ret;
4894c1177a4SToomas Soome 	off_t offset;
4904c1177a4SToomas Soome 	char *path;
4914c1177a4SToomas Soome 
4924c1177a4SToomas Soome 	assert(data != NULL);
4934c1177a4SToomas Soome 
4944c1177a4SToomas Soome 	/*
4954c1177a4SToomas Soome 	 * ZFS bootblock area is 3.5MB, make sure we can fit.
4964c1177a4SToomas Soome 	 * buf_size is size of bootblk+EINFO.
4974c1177a4SToomas Soome 	 */
4984c1177a4SToomas Soome 	if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) {
4994c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("bootblock is too large\n"));
5004c1177a4SToomas Soome 		return (BC_ERROR);
5014c1177a4SToomas Soome 	}
5024c1177a4SToomas Soome 
5034c1177a4SToomas Soome 	if (device->target.fstype == IG_FS_ZFS) {
5044c1177a4SToomas Soome 		dev_fd = device->target.fd;
5054c1177a4SToomas Soome 		abs = device->target.start + device->target.offset;
5064c1177a4SToomas Soome 		offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE;
5074c1177a4SToomas Soome 		path = device->target.path;
5084c1177a4SToomas Soome 	} else {
5094c1177a4SToomas Soome 		dev_fd = device->stage.fd;
5104c1177a4SToomas Soome 		abs = device->stage.start + device->stage.offset;
5114c1177a4SToomas Soome 		offset = device->stage.offset * SECTOR_SIZE;
5124c1177a4SToomas Soome 		path = device->stage.path;
5134c1177a4SToomas Soome 		if (bblock->buf_size >
5144c1177a4SToomas Soome 		    (device->stage.size - device->stage.offset) * SECTOR_SIZE) {
5154c1177a4SToomas Soome 			(void) fprintf(stderr, gettext("Device %s is "
5164c1177a4SToomas Soome 			    "too small to fit the stage2\n"), path);
5174c1177a4SToomas Soome 			return (BC_ERROR);
5184c1177a4SToomas Soome 		}
5194c1177a4SToomas Soome 	}
5204c1177a4SToomas Soome 	ret = write_out(dev_fd, bblock->buf, bblock->buf_size, offset);
5214c1177a4SToomas Soome 	if (ret != BC_SUCCESS) {
5224c1177a4SToomas Soome 		BOOT_DEBUG("Error writing the ZFS bootblock "
5234c1177a4SToomas Soome 		    "to %s at offset %d\n", path, offset);
5244c1177a4SToomas Soome 		return (BC_ERROR);
5254c1177a4SToomas Soome 	}
5264c1177a4SToomas Soome 
5274c1177a4SToomas Soome 	(void) fprintf(stdout, gettext("bootblock written for %s,"
5284c1177a4SToomas Soome 	    " %d sectors starting at %d (abs %lld)\n"), path,
5294c1177a4SToomas Soome 	    (bblock->buf_size / SECTOR_SIZE) + 1, offset / SECTOR_SIZE, abs);
5304c1177a4SToomas Soome 
5314c1177a4SToomas Soome 	return (BC_SUCCESS);
5324c1177a4SToomas Soome }
5334c1177a4SToomas Soome 
534ed24e3c9SToomas Soome /*
535ed24e3c9SToomas Soome  * Partition boot block or volume boot record (VBR). The VBR is
536ed24e3c9SToomas Soome  * stored on partition relative sector 0 and allows chainloading
537ed24e3c9SToomas Soome  * to read boot program from partition.
538ed24e3c9SToomas Soome  *
539ed24e3c9SToomas Soome  * As the VBR will use the first sector of the partition,
540ed24e3c9SToomas Soome  * this means, we need to be sure the space is not used.
541ed24e3c9SToomas Soome  * We do support three partitioning chemes:
542ed24e3c9SToomas Soome  * 1. GPT: zfs and ufs have reserved space for first 8KB, but
543ed24e3c9SToomas Soome  *	only zfs does have space for boot2. The pcfs has support
544ed24e3c9SToomas Soome  *	for VBR, but no space for boot2. So with GPT, to support
545ed24e3c9SToomas Soome  *	ufs or pcfs boot, we must have separate dedicated boot
546ed24e3c9SToomas Soome  *	partition and we will store VBR on it.
547ed24e3c9SToomas Soome  * 2. MBR: we have almost the same situation as with GPT, except that
548ed24e3c9SToomas Soome  *	if the partitions start from cylinder 1, we will have space
549ed24e3c9SToomas Soome  *	between MBR and cylinder 0. If so, we do not require separate
550ed24e3c9SToomas Soome  *	boot partition.
551ed24e3c9SToomas Soome  * 3. MBR+VTOC: with this combination we store VBR in sector 0 of the
552ed24e3c9SToomas Soome  *	solaris2 MBR partition. The slice 0 will start from cylinder 1,
553ed24e3c9SToomas Soome  *	and we do have space for boot2, so we do not require separate
554ed24e3c9SToomas Soome  *	boot partition.
555ed24e3c9SToomas Soome  */
5564c1177a4SToomas Soome static int
write_stage1(ib_data_t * data)5574c1177a4SToomas Soome write_stage1(ib_data_t *data)
5584c1177a4SToomas Soome {
5594c1177a4SToomas Soome 	ib_device_t	*device = &data->device;
560ed24e3c9SToomas Soome 	uint64_t	start = 0;
5614c1177a4SToomas Soome 
5624c1177a4SToomas Soome 	assert(data != NULL);
5634c1177a4SToomas Soome 
5644c1177a4SToomas Soome 	/*
565ed24e3c9SToomas Soome 	 * We have separate partition for boot programs and the stage1
566ed24e3c9SToomas Soome 	 * location is not absolute sector 0.
567ed24e3c9SToomas Soome 	 * We will write VBR and trigger MBR to read 1 sector from VBR.
568ed24e3c9SToomas Soome 	 * This case does also cover MBR+VTOC case, as the solaris 2 partition
569ed24e3c9SToomas Soome 	 * name and the root file system slice names are different.
5704c1177a4SToomas Soome 	 */
5714c1177a4SToomas Soome 	if (device->stage.start != 0 &&
5724c1177a4SToomas Soome 	    strcmp(device->target.path, device->stage.path)) {
5734c1177a4SToomas Soome 		/* we got separate stage area, use it */
5744c1177a4SToomas Soome 		if (write_out(device->stage.fd, data->stage1,
5754c1177a4SToomas Soome 		    sizeof (data->stage1), 0) != BC_SUCCESS) {
5764c1177a4SToomas Soome 			(void) fprintf(stdout, gettext("cannot write "
5774c1177a4SToomas Soome 			    "partition boot sector\n"));
5784c1177a4SToomas Soome 			perror("write");
5794c1177a4SToomas Soome 			return (BC_ERROR);
5804c1177a4SToomas Soome 		}
5814c1177a4SToomas Soome 
5824c1177a4SToomas Soome 		(void) fprintf(stdout, gettext("stage1 written to "
5834c1177a4SToomas Soome 		    "%s %d sector 0 (abs %d)\n"),
5844c1177a4SToomas Soome 		    device->devtype == IG_DEV_MBR? "partition":"slice",
5854c1177a4SToomas Soome 		    device->stage.id, device->stage.start);
586ed24e3c9SToomas Soome 		start = device->stage.start;
5874c1177a4SToomas Soome 	}
5884c1177a4SToomas Soome 
5894c1177a4SToomas Soome 	/*
590ed24e3c9SToomas Soome 	 * We have either GPT or MBR (without VTOC) and if the root
591ed24e3c9SToomas Soome 	 * file system is not pcfs, we can store VBR. Also trigger
592ed24e3c9SToomas Soome 	 * MBR to read 1 sector from VBR.
5934c1177a4SToomas Soome 	 */
5944c1177a4SToomas Soome 	if (device->devtype != IG_DEV_VTOC &&
5954c1177a4SToomas Soome 	    device->target.fstype != IG_FS_PCFS) {
5964c1177a4SToomas Soome 		if (write_out(device->target.fd, data->stage1,
5974c1177a4SToomas Soome 		    sizeof (data->stage1), 0) != BC_SUCCESS) {
5984c1177a4SToomas Soome 			(void) fprintf(stdout, gettext("cannot write "
5994c1177a4SToomas Soome 			    "partition boot sector\n"));
6004c1177a4SToomas Soome 			perror("write");
6014c1177a4SToomas Soome 			return (BC_ERROR);
6024c1177a4SToomas Soome 		}
6034c1177a4SToomas Soome 
6044c1177a4SToomas Soome 		(void) fprintf(stdout, gettext("stage1 written to "
6054c1177a4SToomas Soome 		    "%s %d sector 0 (abs %d)\n"),
6064c1177a4SToomas Soome 		    device->devtype == IG_DEV_MBR? "partition":"slice",
6074c1177a4SToomas Soome 		    device->target.id, device->target.start);
608ed24e3c9SToomas Soome 		start = device->target.start;
6094c1177a4SToomas Soome 	}
6104c1177a4SToomas Soome 
6114c1177a4SToomas Soome 	if (write_mbr) {
612ed24e3c9SToomas Soome 		/*
613ed24e3c9SToomas Soome 		 * If we did write partition boot block, update MBR to
614ed24e3c9SToomas Soome 		 * read partition boot block, not boot2.
615ed24e3c9SToomas Soome 		 */
616ed24e3c9SToomas Soome 		if (start != 0) {
617ed24e3c9SToomas Soome 			*((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) = 1;
618ed24e3c9SToomas Soome 			*((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) =
619ed24e3c9SToomas Soome 			    start;
620ed24e3c9SToomas Soome 		}
6214c1177a4SToomas Soome 		if (write_out(device->fd, data->stage1,
6224c1177a4SToomas Soome 		    sizeof (data->stage1), 0) != BC_SUCCESS) {
6234c1177a4SToomas Soome 			(void) fprintf(stdout,
6244c1177a4SToomas Soome 			    gettext("cannot write master boot sector\n"));
6254c1177a4SToomas Soome 			perror("write");
6264c1177a4SToomas Soome 			return (BC_ERROR);
6274c1177a4SToomas Soome 		}
6284c1177a4SToomas Soome 		(void) fprintf(stdout,
6294c1177a4SToomas Soome 		    gettext("stage1 written to master boot sector\n"));
6304c1177a4SToomas Soome 	}
6314c1177a4SToomas Soome 
6324c1177a4SToomas Soome 	return (BC_SUCCESS);
6334c1177a4SToomas Soome }
6344c1177a4SToomas Soome 
6354c1177a4SToomas Soome /*
6364c1177a4SToomas Soome  * find partition/slice start sector. will be recorded in stage2 and used
6374c1177a4SToomas Soome  * by stage2 to identify partition with boot file system.
6384c1177a4SToomas Soome  */
6394c1177a4SToomas Soome static int
get_start_sector(ib_device_t * device)6404c1177a4SToomas Soome get_start_sector(ib_device_t *device)
6414c1177a4SToomas Soome {
6424c1177a4SToomas Soome 	uint32_t		secnum = 0, numsec = 0;
6434c1177a4SToomas Soome 	int			i, pno, rval, log_part = 0;
6444c1177a4SToomas Soome 	struct mboot		*mboot;
6454c1177a4SToomas Soome 	struct ipart		*part = NULL;
6464c1177a4SToomas Soome 	ext_part_t		*epp;
6474c1177a4SToomas Soome 	struct part_info	dkpi;
6484c1177a4SToomas Soome 	struct extpart_info	edkpi;
6494c1177a4SToomas Soome 
6504c1177a4SToomas Soome 	if (device->devtype == IG_DEV_EFI) {
6514c1177a4SToomas Soome 		struct dk_gpt *vtoc;
6524c1177a4SToomas Soome 
6534c1177a4SToomas Soome 		if (efi_alloc_and_read(device->fd, &vtoc) < 0)
6544c1177a4SToomas Soome 			return (BC_ERROR);
6554c1177a4SToomas Soome 
6564c1177a4SToomas Soome 		if (device->stage.start == 0) {
6574c1177a4SToomas Soome 			/* zero size means the fstype must be zfs */
6584c1177a4SToomas Soome 			assert(device->target.fstype == IG_FS_ZFS);
6594c1177a4SToomas Soome 
6604c1177a4SToomas Soome 			device->stage.start =
6614c1177a4SToomas Soome 			    vtoc->efi_parts[device->stage.id].p_start;
6624c1177a4SToomas Soome 			device->stage.size =
6634c1177a4SToomas Soome 			    vtoc->efi_parts[device->stage.id].p_size;
6644c1177a4SToomas Soome 			device->stage.offset = BBLK_ZFS_BLK_OFF;
6654c1177a4SToomas Soome 			device->target.offset = BBLK_ZFS_BLK_OFF;
6664c1177a4SToomas Soome 		}
6674c1177a4SToomas Soome 
6684c1177a4SToomas Soome 		device->target.start =
6694c1177a4SToomas Soome 		    vtoc->efi_parts[device->target.id].p_start;
6704c1177a4SToomas Soome 		device->target.size =
6714c1177a4SToomas Soome 		    vtoc->efi_parts[device->target.id].p_size;
6724c1177a4SToomas Soome 
6734c1177a4SToomas Soome 		/* with pcfs we always write MBR */
6744c1177a4SToomas Soome 		if (device->target.fstype == IG_FS_PCFS) {
6754c1177a4SToomas Soome 			force_mbr = 1;
6764c1177a4SToomas Soome 			write_mbr = 1;
6774c1177a4SToomas Soome 		}
6784c1177a4SToomas Soome 
6794c1177a4SToomas Soome 		efi_free(vtoc);
6804c1177a4SToomas Soome 		goto found_part;
6814c1177a4SToomas Soome 	}
6824c1177a4SToomas Soome 
6834c1177a4SToomas Soome 	mboot = (struct mboot *)device->mbr;
6844c1177a4SToomas Soome 
6854c1177a4SToomas Soome 	/* For MBR we have device->stage filled already. */
6864c1177a4SToomas Soome 	if (device->devtype == IG_DEV_MBR) {
6874c1177a4SToomas Soome 		/* MBR partition starts from 0 */
6884c1177a4SToomas Soome 		pno = device->target.id - 1;
6894c1177a4SToomas Soome 		part = (struct ipart *)mboot->parts + pno;
6904c1177a4SToomas Soome 
6914c1177a4SToomas Soome 		if (part->relsect == 0) {
6924c1177a4SToomas Soome 			(void) fprintf(stderr, gettext("Partition %d of the "
6934c1177a4SToomas Soome 			    "disk has an incorrect offset\n"),
6944c1177a4SToomas Soome 			    device->target.id);
6954c1177a4SToomas Soome 			return (BC_ERROR);
6964c1177a4SToomas Soome 		}
6974c1177a4SToomas Soome 		device->target.start = part->relsect;
6984c1177a4SToomas Soome 		device->target.size = part->numsect;
6994c1177a4SToomas Soome 
7004c1177a4SToomas Soome 		/* with pcfs we always write MBR */
7014c1177a4SToomas Soome 		if (device->target.fstype == IG_FS_PCFS) {
7024c1177a4SToomas Soome 			force_mbr = 1;
7034c1177a4SToomas Soome 			write_mbr = 1;
7044c1177a4SToomas Soome 		}
7054c1177a4SToomas Soome 		if (device->target.fstype == IG_FS_ZFS)
7064c1177a4SToomas Soome 			device->target.offset = BBLK_ZFS_BLK_OFF;
7074c1177a4SToomas Soome 
7084c1177a4SToomas Soome 		goto found_part;
7094c1177a4SToomas Soome 	}
7104c1177a4SToomas Soome 
7114c1177a4SToomas Soome 	/*
7124c1177a4SToomas Soome 	 * Search for Solaris fdisk partition
7134c1177a4SToomas Soome 	 * Get the solaris partition information from the device
7144c1177a4SToomas Soome 	 * and compare the offset of S2 with offset of solaris partition
7154c1177a4SToomas Soome 	 * from fdisk partition table.
7164c1177a4SToomas Soome 	 */
7174c1177a4SToomas Soome 	if (ioctl(device->target.fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
7184c1177a4SToomas Soome 		if (ioctl(device->target.fd, DKIOCPARTINFO, &dkpi) < 0) {
7194c1177a4SToomas Soome 			(void) fprintf(stderr, gettext("cannot get the "
7204c1177a4SToomas Soome 			    "slice information of the disk\n"));
7214c1177a4SToomas Soome 			return (BC_ERROR);
7224c1177a4SToomas Soome 		} else {
7234c1177a4SToomas Soome 			edkpi.p_start = dkpi.p_start;
7244c1177a4SToomas Soome 			edkpi.p_length = dkpi.p_length;
7254c1177a4SToomas Soome 		}
7264c1177a4SToomas Soome 	}
7274c1177a4SToomas Soome 
7284c1177a4SToomas Soome 	device->target.start = edkpi.p_start;
7294c1177a4SToomas Soome 	device->target.size = edkpi.p_length;
7304c1177a4SToomas Soome 	if (device->target.fstype == IG_FS_ZFS)
7314c1177a4SToomas Soome 		device->target.offset = BBLK_ZFS_BLK_OFF;
7324c1177a4SToomas Soome 
7334c1177a4SToomas Soome 	for (i = 0; i < FD_NUMPART; i++) {
7344c1177a4SToomas Soome 		part = (struct ipart *)mboot->parts + i;
7354c1177a4SToomas Soome 
7364c1177a4SToomas Soome 		if (part->relsect == 0) {
7374c1177a4SToomas Soome 			(void) fprintf(stderr, gettext("Partition %d of the "
7384c1177a4SToomas Soome 			    "disk has an incorrect offset\n"), i+1);
7394c1177a4SToomas Soome 			return (BC_ERROR);
7404c1177a4SToomas Soome 		}
7414c1177a4SToomas Soome 
7424c1177a4SToomas Soome 		if (edkpi.p_start >= part->relsect &&
7434c1177a4SToomas Soome 		    edkpi.p_start < (part->relsect + part->numsect)) {
7444c1177a4SToomas Soome 			/* Found the partition */
7454c1177a4SToomas Soome 			break;
7464c1177a4SToomas Soome 		}
7474c1177a4SToomas Soome 	}
7484c1177a4SToomas Soome 
7494c1177a4SToomas Soome 	if (i == FD_NUMPART) {
7504c1177a4SToomas Soome 		/* No solaris fdisk partitions (primary or logical) */
7514c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Solaris partition not found. "
7524c1177a4SToomas Soome 		    "Aborting operation.\n"));
7534c1177a4SToomas Soome 		return (BC_ERROR);
7544c1177a4SToomas Soome 	}
7554c1177a4SToomas Soome 
7564c1177a4SToomas Soome 	/*
7574c1177a4SToomas Soome 	 * We have found a Solaris fdisk partition (primary or extended)
7584c1177a4SToomas Soome 	 * Handle the simple case first: Solaris in a primary partition
7594c1177a4SToomas Soome 	 */
7604c1177a4SToomas Soome 	if (!fdisk_is_dos_extended(part->systid)) {
7614c1177a4SToomas Soome 		device->stage.start = part->relsect;
7624c1177a4SToomas Soome 		device->stage.size = part->numsect;
7634c1177a4SToomas Soome 		if (device->target.fstype == IG_FS_ZFS)
7644c1177a4SToomas Soome 			device->stage.offset = BBLK_ZFS_BLK_OFF;
7654c1177a4SToomas Soome 		else
7664c1177a4SToomas Soome 			device->stage.offset = BBLK_BLKLIST_OFF;
7674c1177a4SToomas Soome 		device->stage.id = i + 1;
7684c1177a4SToomas Soome 		goto found_part;
7694c1177a4SToomas Soome 	}
7704c1177a4SToomas Soome 
7714c1177a4SToomas Soome 	/*
7724c1177a4SToomas Soome 	 * Solaris in a logical partition. Find that partition in the
7734c1177a4SToomas Soome 	 * extended part.
7744c1177a4SToomas Soome 	 */
7754c1177a4SToomas Soome 
7764c1177a4SToomas Soome 	if ((rval = libfdisk_init(&epp, device->path, NULL, FDISK_READ_DISK))
7774c1177a4SToomas Soome 	    != FDISK_SUCCESS) {
7784c1177a4SToomas Soome 		switch (rval) {
7794c1177a4SToomas Soome 			/*
7804c1177a4SToomas Soome 			 * The first 3 cases are not an error per-se, just that
7814c1177a4SToomas Soome 			 * there is no Solaris logical partition
7824c1177a4SToomas Soome 			 */
7834c1177a4SToomas Soome 			case FDISK_EBADLOGDRIVE:
7844c1177a4SToomas Soome 			case FDISK_ENOLOGDRIVE:
7854c1177a4SToomas Soome 			case FDISK_EBADMAGIC:
7864c1177a4SToomas Soome 				(void) fprintf(stderr, gettext("Solaris "
7874c1177a4SToomas Soome 				    "partition not found. "
7884c1177a4SToomas Soome 				    "Aborting operation.\n"));
7894c1177a4SToomas Soome 				return (BC_ERROR);
7904c1177a4SToomas Soome 			case FDISK_ENOVGEOM:
7914c1177a4SToomas Soome 				(void) fprintf(stderr, gettext("Could not get "
7924c1177a4SToomas Soome 				    "virtual geometry\n"));
7934c1177a4SToomas Soome 				return (BC_ERROR);
7944c1177a4SToomas Soome 			case FDISK_ENOPGEOM:
7954c1177a4SToomas Soome 				(void) fprintf(stderr, gettext("Could not get "
7964c1177a4SToomas Soome 				    "physical geometry\n"));
7974c1177a4SToomas Soome 				return (BC_ERROR);
7984c1177a4SToomas Soome 			case FDISK_ENOLGEOM:
7994c1177a4SToomas Soome 				(void) fprintf(stderr, gettext("Could not get "
8004c1177a4SToomas Soome 				    "label geometry\n"));
8014c1177a4SToomas Soome 				return (BC_ERROR);
8024c1177a4SToomas Soome 			default:
8034c1177a4SToomas Soome 				(void) fprintf(stderr, gettext("Failed to "
8044c1177a4SToomas Soome 				    "initialize libfdisk.\n"));
8054c1177a4SToomas Soome 				return (BC_ERROR);
8064c1177a4SToomas Soome 		}
8074c1177a4SToomas Soome 	}
8084c1177a4SToomas Soome 
8094c1177a4SToomas Soome 	rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
8104c1177a4SToomas Soome 	libfdisk_fini(&epp);
8114c1177a4SToomas Soome 	if (rval != FDISK_SUCCESS) {
8124c1177a4SToomas Soome 		/* No solaris logical partition */
8134c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Solaris partition not found. "
8144c1177a4SToomas Soome 		    "Aborting operation.\n"));
8154c1177a4SToomas Soome 		return (BC_ERROR);
8164c1177a4SToomas Soome 	}
8174c1177a4SToomas Soome 
8184c1177a4SToomas Soome 	device->stage.start = secnum;
8194c1177a4SToomas Soome 	device->stage.size = numsec;
8204c1177a4SToomas Soome 	device->stage.id = pno;
8214c1177a4SToomas Soome 	log_part = 1;
8224c1177a4SToomas Soome 
8234c1177a4SToomas Soome found_part:
8244c1177a4SToomas Soome 	/* get confirmation for -m */
8254c1177a4SToomas Soome 	if (write_mbr && !force_mbr) {
8264c1177a4SToomas Soome 		(void) fprintf(stdout, gettext("Updating master boot sector "
8274c1177a4SToomas Soome 		    "destroys existing boot managers (if any).\n"
8284c1177a4SToomas Soome 		    "continue (y/n)? "));
8294c1177a4SToomas Soome 		if (!yes()) {
8304c1177a4SToomas Soome 			write_mbr = 0;
8314c1177a4SToomas Soome 			(void) fprintf(stdout, gettext("master boot sector "
8324c1177a4SToomas Soome 			    "not updated\n"));
8334c1177a4SToomas Soome 			return (BC_ERROR);
8344c1177a4SToomas Soome 		}
8354c1177a4SToomas Soome 	}
8364c1177a4SToomas Soome 
8374c1177a4SToomas Soome 	/*
8384c1177a4SToomas Soome 	 * warn, if illumos in primary partition and loader not in MBR and
8394c1177a4SToomas Soome 	 * partition is not active
8404c1177a4SToomas Soome 	 */
8414c1177a4SToomas Soome 	if (device->devtype != IG_DEV_EFI) {
8424c1177a4SToomas Soome 		if (!log_part && part->bootid != 128 && !write_mbr) {
8434c1177a4SToomas Soome 			(void) fprintf(stdout, gettext("Solaris fdisk "
8444c1177a4SToomas Soome 			    "partition is inactive.\n"), device->stage.id);
8454c1177a4SToomas Soome 		}
8464c1177a4SToomas Soome 	}
8474c1177a4SToomas Soome 
8484c1177a4SToomas Soome 	return (BC_SUCCESS);
8494c1177a4SToomas Soome }
8504c1177a4SToomas Soome 
8514c1177a4SToomas Soome static int
open_device(char * path)8524c1177a4SToomas Soome open_device(char *path)
8534c1177a4SToomas Soome {
8544c1177a4SToomas Soome 	struct stat	statbuf = {0};
8554c1177a4SToomas Soome 	int		fd = -1;
8564c1177a4SToomas Soome 
8574c1177a4SToomas Soome 	if (nowrite)
8584c1177a4SToomas Soome 		fd = open(path, O_RDONLY);
8594c1177a4SToomas Soome 	else
8604c1177a4SToomas Soome 		fd = open(path, O_RDWR);
8614c1177a4SToomas Soome 
8624c1177a4SToomas Soome 	if (fd == -1) {
8634c1177a4SToomas Soome 		BOOT_DEBUG("Unable to open %s\n", path);
8644c1177a4SToomas Soome 		perror("open");
8654c1177a4SToomas Soome 		return (-1);
8664c1177a4SToomas Soome 	}
8674c1177a4SToomas Soome 
8684c1177a4SToomas Soome 	if (fstat(fd, &statbuf) != 0) {
8694c1177a4SToomas Soome 		BOOT_DEBUG("Unable to stat %s\n", path);
8704c1177a4SToomas Soome 		perror("stat");
8714c1177a4SToomas Soome 		(void) close(fd);
8724c1177a4SToomas Soome 		return (-1);
8734c1177a4SToomas Soome 	}
8744c1177a4SToomas Soome 
8754c1177a4SToomas Soome 	if (S_ISCHR(statbuf.st_mode) == 0) {
8764c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("%s: Not a character device\n"),
8774c1177a4SToomas Soome 		    path);
8784c1177a4SToomas Soome 		(void) close(fd);
8794c1177a4SToomas Soome 		return (-1);
8804c1177a4SToomas Soome 	}
8814c1177a4SToomas Soome 
8824c1177a4SToomas Soome 	return (fd);
8834c1177a4SToomas Soome }
8844c1177a4SToomas Soome 
8854c1177a4SToomas Soome static int
get_boot_partition(ib_device_t * device,struct mboot * mbr)8864c1177a4SToomas Soome get_boot_partition(ib_device_t *device, struct mboot *mbr)
8874c1177a4SToomas Soome {
8884c1177a4SToomas Soome 	struct ipart *part;
8894c1177a4SToomas Soome 	char *path, *ptr;
8904c1177a4SToomas Soome 	int i;
8914c1177a4SToomas Soome 
8924c1177a4SToomas Soome 	part = (struct ipart *)mbr->parts;
8934c1177a4SToomas Soome 	for (i = 0; i < FD_NUMPART; i++) {
8944c1177a4SToomas Soome 		if (part[i].systid == X86BOOT)
8954c1177a4SToomas Soome 			break;
8964c1177a4SToomas Soome 	}
8974c1177a4SToomas Soome 
8984c1177a4SToomas Soome 	/* no X86BOOT, try to use space between MBR and first partition */
8994c1177a4SToomas Soome 	if (i == FD_NUMPART) {
9004c1177a4SToomas Soome 		device->stage.path = strdup(device->path);
9014c1177a4SToomas Soome 		if (device->stage.path == NULL) {
9024c1177a4SToomas Soome 			perror(gettext("Memory allocation failure"));
9034c1177a4SToomas Soome 			return (BC_ERROR);
9044c1177a4SToomas Soome 		}
9054c1177a4SToomas Soome 		device->stage.fd = dup(device->fd);
9064c1177a4SToomas Soome 		device->stage.id = 0;
9074c1177a4SToomas Soome 		device->stage.devtype = IG_DEV_MBR;
9084c1177a4SToomas Soome 		device->stage.fstype = IG_FS_NONE;
9094c1177a4SToomas Soome 		device->stage.start = 0;
9104c1177a4SToomas Soome 		device->stage.size = part[0].relsect;
9114c1177a4SToomas Soome 		device->stage.offset = BBLK_BLKLIST_OFF;
9124c1177a4SToomas Soome 		return (BC_SUCCESS);
9134c1177a4SToomas Soome 	}
9144c1177a4SToomas Soome 
9154c1177a4SToomas Soome 	if ((path = strdup(device->path)) == NULL) {
9164c1177a4SToomas Soome 		perror(gettext("Memory allocation failure"));
9174c1177a4SToomas Soome 		return (BC_ERROR);
9184c1177a4SToomas Soome 	}
9194c1177a4SToomas Soome 
9204c1177a4SToomas Soome 	ptr = strrchr(path, 'p');
9214c1177a4SToomas Soome 	ptr++;
9224c1177a4SToomas Soome 	*ptr = '\0';
9234c1177a4SToomas Soome 	(void) asprintf(&ptr, "%s%d", path, i+1); /* partitions are p1..p4 */
9244c1177a4SToomas Soome 	free(path);
9254c1177a4SToomas Soome 	if (ptr == NULL) {
9264c1177a4SToomas Soome 		perror(gettext("Memory allocation failure"));
9274c1177a4SToomas Soome 		return (BC_ERROR);
9284c1177a4SToomas Soome 	}
9294c1177a4SToomas Soome 	device->stage.path = ptr;
9304c1177a4SToomas Soome 	device->stage.fd = open_device(ptr);
9314c1177a4SToomas Soome 	device->stage.id = i + 1;
9324c1177a4SToomas Soome 	device->stage.devtype = IG_DEV_MBR;
9334c1177a4SToomas Soome 	device->stage.fstype = IG_FS_NONE;
9344c1177a4SToomas Soome 	device->stage.start = part[i].relsect;
9354c1177a4SToomas Soome 	device->stage.size = part[i].numsect;
9364c1177a4SToomas Soome 	device->stage.offset = 1; /* leave sector 0 for VBR */
9374c1177a4SToomas Soome 	return (BC_SUCCESS);
9384c1177a4SToomas Soome }
9394c1177a4SToomas Soome 
9404c1177a4SToomas Soome static int
get_boot_slice(ib_device_t * device,struct dk_gpt * vtoc)9414c1177a4SToomas Soome get_boot_slice(ib_device_t *device, struct dk_gpt *vtoc)
9424c1177a4SToomas Soome {
9434c1177a4SToomas Soome 	uint_t i;
9444c1177a4SToomas Soome 	char *path, *ptr;
9454c1177a4SToomas Soome 
9464c1177a4SToomas Soome 	for (i = 0; i < vtoc->efi_nparts; i++) {
9474c1177a4SToomas Soome 		if (vtoc->efi_parts[i].p_tag == V_BOOT) {
9484c1177a4SToomas Soome 			if ((path = strdup(device->target.path)) == NULL) {
9494c1177a4SToomas Soome 				perror(gettext("Memory allocation failure"));
9504c1177a4SToomas Soome 				return (BC_ERROR);
9514c1177a4SToomas Soome 			}
9524c1177a4SToomas Soome 			ptr = strrchr(path, 's');
9534c1177a4SToomas Soome 			ptr++;
9544c1177a4SToomas Soome 			*ptr = '\0';
9554c1177a4SToomas Soome 			(void) asprintf(&ptr, "%s%d", path, i);
9564c1177a4SToomas Soome 			free(path);
9574c1177a4SToomas Soome 			if (ptr == NULL) {
9584c1177a4SToomas Soome 				perror(gettext("Memory allocation failure"));
9594c1177a4SToomas Soome 				return (BC_ERROR);
9604c1177a4SToomas Soome 			}
9614c1177a4SToomas Soome 			device->stage.path = ptr;
9624c1177a4SToomas Soome 			device->stage.fd = open_device(ptr);
9634c1177a4SToomas Soome 			device->stage.id = i;
9644c1177a4SToomas Soome 			device->stage.devtype = IG_DEV_EFI;
9654c1177a4SToomas Soome 			device->stage.fstype = IG_FS_NONE;
9664c1177a4SToomas Soome 			device->stage.start = vtoc->efi_parts[i].p_start;
9674c1177a4SToomas Soome 			device->stage.size = vtoc->efi_parts[i].p_size;
9684c1177a4SToomas Soome 			device->stage.offset = 1; /* leave sector 0 for VBR */
9694c1177a4SToomas Soome 			return (BC_SUCCESS);
9704c1177a4SToomas Soome 		}
9714c1177a4SToomas Soome 	}
9724c1177a4SToomas Soome 	return (BC_SUCCESS);
9734c1177a4SToomas Soome }
9744c1177a4SToomas Soome 
9754c1177a4SToomas Soome static int
init_device(ib_device_t * device,char * path)9764c1177a4SToomas Soome init_device(ib_device_t *device, char *path)
9774c1177a4SToomas Soome {
9784c1177a4SToomas Soome 	struct dk_gpt *vtoc;
9794c1177a4SToomas Soome 	fstyp_handle_t fhdl;
9804c1177a4SToomas Soome 	const char *fident;
9814c1177a4SToomas Soome 	char *p;
9824c1177a4SToomas Soome 	int pathlen = strlen(path);
9834c1177a4SToomas Soome 	int ret;
9844c1177a4SToomas Soome 
9854c1177a4SToomas Soome 	bzero(device, sizeof (*device));
9864c1177a4SToomas Soome 	device->fd = -1;	/* whole disk fd */
9874c1177a4SToomas Soome 	device->stage.fd = -1;	/* bootblock partition fd */
9884c1177a4SToomas Soome 	device->target.fd = -1;	/* target fs partition fd */
9894c1177a4SToomas Soome 
9904c1177a4SToomas Soome 	/* basic check, whole disk is not allowed */
9914c1177a4SToomas Soome 	if ((p = strrchr(path, '/')) == NULL)
9924c1177a4SToomas Soome 		p = path;
9934c1177a4SToomas Soome 	if ((strrchr(p, 'p') == NULL && strrchr(p, 's') == NULL) ||
9944c1177a4SToomas Soome 	    (path[pathlen-2] == 'p' && path[pathlen-1] == '0')) {
9954c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("installing loader to "
9964c1177a4SToomas Soome 		    "whole disk device is not supported\n"));
9974c1177a4SToomas Soome 	}
9984c1177a4SToomas Soome 
9994c1177a4SToomas Soome 	device->target.path = strdup(path);
10004c1177a4SToomas Soome 	if (device->target.path == NULL) {
10014c1177a4SToomas Soome 		perror(gettext("Memory allocation failure"));
10024c1177a4SToomas Soome 		return (BC_ERROR);
10034c1177a4SToomas Soome 	}
10044c1177a4SToomas Soome 	device->path = strdup(path);
10054c1177a4SToomas Soome 	if (device->path == NULL) {
10064c1177a4SToomas Soome 		perror(gettext("Memory allocation failure"));
10074c1177a4SToomas Soome 		return (BC_ERROR);
10084c1177a4SToomas Soome 	}
10094c1177a4SToomas Soome 
10104c1177a4SToomas Soome 	/* change device name to p0 */
10114c1177a4SToomas Soome 	device->path[pathlen - 2] = 'p';
10124c1177a4SToomas Soome 	device->path[pathlen - 1] = '0';
10134c1177a4SToomas Soome 
10144c1177a4SToomas Soome 	if (strstr(device->target.path, "diskette")) {
10154c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("installing loader to a floppy "
10164c1177a4SToomas Soome 		    "disk is not supported\n"));
10174c1177a4SToomas Soome 		return (BC_ERROR);
10184c1177a4SToomas Soome 	}
10194c1177a4SToomas Soome 
10204c1177a4SToomas Soome 	/* Detect if the target device is a pcfs partition. */
10214c1177a4SToomas Soome 	if (strstr(device->target.path, "p0:boot")) {
10224c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("installing loader to x86 boot "
10234c1177a4SToomas Soome 		    "partition is not supported\n"));
10244c1177a4SToomas Soome 		return (BC_ERROR);
10254c1177a4SToomas Soome 	}
10264c1177a4SToomas Soome 
10274c1177a4SToomas Soome 	if ((device->fd = open_device(device->path)) == -1)
10284c1177a4SToomas Soome 		return (BC_ERROR);
10294c1177a4SToomas Soome 
10304c1177a4SToomas Soome 	/* read in the device boot sector. */
10314c1177a4SToomas Soome 	if (read(device->fd, device->mbr, SECTOR_SIZE) != SECTOR_SIZE) {
10324c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Error reading boot sector\n"));
10334c1177a4SToomas Soome 		perror("read");
10344c1177a4SToomas Soome 		return (BC_ERROR);
10354c1177a4SToomas Soome 	}
10364c1177a4SToomas Soome 
10374c1177a4SToomas Soome 	device->devtype = IG_DEV_VTOC;
10384c1177a4SToomas Soome 	if (efi_alloc_and_read(device->fd, &vtoc) >= 0) {
10394c1177a4SToomas Soome 		ret = get_boot_slice(device, vtoc);
10404c1177a4SToomas Soome 		device->devtype = IG_DEV_EFI;
10414c1177a4SToomas Soome 		efi_free(vtoc);
10424c1177a4SToomas Soome 		if (ret == BC_ERROR)
10434c1177a4SToomas Soome 			return (BC_ERROR);
10444c1177a4SToomas Soome 	} else if (device->target.path[pathlen - 2] == 'p') {
10454c1177a4SToomas Soome 		device->devtype = IG_DEV_MBR;
10464c1177a4SToomas Soome 		ret = get_boot_partition(device, (struct mboot *)device->mbr);
10474c1177a4SToomas Soome 		if (ret == BC_ERROR)
10484c1177a4SToomas Soome 			return (BC_ERROR);
10494c1177a4SToomas Soome 	} else if (device->target.path[pathlen - 1] == '2') {
10504c1177a4SToomas Soome 		/*
10514c1177a4SToomas Soome 		 * NOTE: we could relax there and allow zfs boot on
10524c1177a4SToomas Soome 		 * slice 2 for instance, but lets keep traditional limits.
10534c1177a4SToomas Soome 		 */
10544c1177a4SToomas Soome 		(void) fprintf(stderr,
10554c1177a4SToomas Soome 		    gettext("raw device must be a root slice (not s2)\n"));
10564c1177a4SToomas Soome 		return (BC_ERROR);
10574c1177a4SToomas Soome 	}
10584c1177a4SToomas Soome 
10594c1177a4SToomas Soome 	/* fill stage partition for case there is no boot partition */
10604c1177a4SToomas Soome 	if (device->stage.path == NULL) {
10614c1177a4SToomas Soome 		if ((device->stage.path = strdup(path)) == NULL) {
10624c1177a4SToomas Soome 			perror(gettext("Memory allocation failure"));
10634c1177a4SToomas Soome 			return (BC_ERROR);
10644c1177a4SToomas Soome 		}
10654c1177a4SToomas Soome 		if (device->devtype == IG_DEV_VTOC) {
10664c1177a4SToomas Soome 			/* use slice 2 */
10674c1177a4SToomas Soome 			device->stage.path[pathlen - 2] = 's';
10684c1177a4SToomas Soome 			device->stage.path[pathlen - 1] = '2';
10694c1177a4SToomas Soome 			device->stage.id = 2;
10704c1177a4SToomas Soome 		} else {
10714c1177a4SToomas Soome 			p = strrchr(device->stage.path, 'p');
10724c1177a4SToomas Soome 			if (p == NULL)
10734c1177a4SToomas Soome 				p = strrchr(device->stage.path, 's');
10744c1177a4SToomas Soome 			device->stage.id = atoi(++p);
10754c1177a4SToomas Soome 		}
10764c1177a4SToomas Soome 		device->stage.devtype = device->devtype;
10774c1177a4SToomas Soome 		device->stage.fd = open_device(device->stage.path);
10784c1177a4SToomas Soome 	}
10794c1177a4SToomas Soome 
10804c1177a4SToomas Soome 	p = strrchr(device->target.path, 'p');
10814c1177a4SToomas Soome 	if (p == NULL)
10824c1177a4SToomas Soome 		p = strrchr(device->target.path, 's');
10834c1177a4SToomas Soome 	device->target.id = atoi(++p);
10844c1177a4SToomas Soome 
10854c1177a4SToomas Soome 	if (strcmp(device->stage.path, device->target.path) == 0)
10864c1177a4SToomas Soome 		device->target.fd = dup(device->stage.fd);
10874c1177a4SToomas Soome 	else
10884c1177a4SToomas Soome 		device->target.fd = open_device(device->target.path);
10894c1177a4SToomas Soome 
10904c1177a4SToomas Soome 	if (fstyp_init(device->target.fd, 0, NULL, &fhdl) != 0)
10914c1177a4SToomas Soome 		return (BC_ERROR);
10924c1177a4SToomas Soome 
10934c1177a4SToomas Soome 	if (fstyp_ident(fhdl, NULL, &fident) != 0) {
10944c1177a4SToomas Soome 		fstyp_fini(fhdl);
10954c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Failed to detect file "
10964c1177a4SToomas Soome 		    "system type\n"));
10974c1177a4SToomas Soome 		return (BC_ERROR);
10984c1177a4SToomas Soome 	}
10994c1177a4SToomas Soome 
11004c1177a4SToomas Soome 	/* at this moment non-boot partition has no size set, use this fact */
11014c1177a4SToomas Soome 	if (device->devtype == IG_DEV_EFI && strcmp(fident, "zfs") &&
11024c1177a4SToomas Soome 	    device->stage.size == 0) {
11034c1177a4SToomas Soome 		fstyp_fini(fhdl);
11044c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Booting %s of EFI labeled "
11054c1177a4SToomas Soome 		    "disks requires the boot partition.\n"), fident);
11064c1177a4SToomas Soome 		return (BC_ERROR);
11074c1177a4SToomas Soome 	}
11084c1177a4SToomas Soome 	if (strcmp(fident, "zfs") == 0)
11094c1177a4SToomas Soome 		device->target.fstype = IG_FS_ZFS;
11104c1177a4SToomas Soome 	else if (strcmp(fident, "ufs") == 0) {
11114c1177a4SToomas Soome 		device->target.fstype = IG_FS_UFS;
11124c1177a4SToomas Soome 	} else if (strcmp(fident, "pcfs") == 0) {
11134c1177a4SToomas Soome 		device->target.fstype = IG_FS_PCFS;
11144c1177a4SToomas Soome 	} else {
11154c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("File system %s is not "
11164c1177a4SToomas Soome 		    "supported by loader\n"), fident);
11174c1177a4SToomas Soome 		fstyp_fini(fhdl);
11184c1177a4SToomas Soome 		return (BC_ERROR);
11194c1177a4SToomas Soome 	}
11204c1177a4SToomas Soome 	fstyp_fini(fhdl);
11214c1177a4SToomas Soome 
11224c1177a4SToomas Soome 	/* check for boot partition content */
11234c1177a4SToomas Soome 	if (device->stage.size) {
11244c1177a4SToomas Soome 		if (fstyp_init(device->stage.fd, 0, NULL, &fhdl) != 0)
11254c1177a4SToomas Soome 			return (BC_ERROR);
11264c1177a4SToomas Soome 
11274c1177a4SToomas Soome 		if (fstyp_ident(fhdl, NULL, &fident) == 0) {
11284c1177a4SToomas Soome 			(void) fprintf(stderr, gettext("Unexpected %s file "
11294c1177a4SToomas Soome 			    "system on boot partition\n"), fident);
11304c1177a4SToomas Soome 			fstyp_fini(fhdl);
11314c1177a4SToomas Soome 			return (BC_ERROR);
11324c1177a4SToomas Soome 		}
11334c1177a4SToomas Soome 		fstyp_fini(fhdl);
11344c1177a4SToomas Soome 	}
11354c1177a4SToomas Soome 	return (get_start_sector(device));
11364c1177a4SToomas Soome }
11374c1177a4SToomas Soome 
11384c1177a4SToomas Soome static void
cleanup_device(ib_device_t * device)11394c1177a4SToomas Soome cleanup_device(ib_device_t *device)
11404c1177a4SToomas Soome {
11414c1177a4SToomas Soome 	if (device->path)
11424c1177a4SToomas Soome 		free(device->path);
11434c1177a4SToomas Soome 	if (device->stage.path)
11444c1177a4SToomas Soome 		free(device->stage.path);
11454c1177a4SToomas Soome 	if (device->target.path)
11464c1177a4SToomas Soome 		free(device->target.path);
11474c1177a4SToomas Soome 
11484c1177a4SToomas Soome 	if (device->fd != -1)
11494c1177a4SToomas Soome 		(void) close(device->fd);
11504c1177a4SToomas Soome 	if (device->stage.fd != -1)
11514c1177a4SToomas Soome 		(void) close(device->stage.fd);
11524c1177a4SToomas Soome 	if (device->target.fd != -1)
11534c1177a4SToomas Soome 		(void) close(device->target.fd);
11544c1177a4SToomas Soome 	bzero(device, sizeof (*device));
11554c1177a4SToomas Soome }
11564c1177a4SToomas Soome 
11574c1177a4SToomas Soome static void
cleanup_bootblock(ib_bootblock_t * bblock)11584c1177a4SToomas Soome cleanup_bootblock(ib_bootblock_t *bblock)
11594c1177a4SToomas Soome {
11604c1177a4SToomas Soome 	free(bblock->buf);
11614c1177a4SToomas Soome 	bzero(bblock, sizeof (ib_bootblock_t));
11624c1177a4SToomas Soome }
11634c1177a4SToomas Soome 
11644c1177a4SToomas Soome /*
11654c1177a4SToomas Soome  * Propagate the bootblock on the source disk to the destination disk and
11664c1177a4SToomas Soome  * version it with 'updt_str' in the process. Since we cannot trust any data
11674c1177a4SToomas Soome  * on the attaching disk, we do not perform any specific check on a potential
11684c1177a4SToomas Soome  * target extended information structure and we just blindly update.
11694c1177a4SToomas Soome  */
11704c1177a4SToomas Soome static int
propagate_bootblock(ib_data_t * src,ib_data_t * dest,char * updt_str)11714c1177a4SToomas Soome propagate_bootblock(ib_data_t *src, ib_data_t *dest, char *updt_str)
11724c1177a4SToomas Soome {
11734c1177a4SToomas Soome 	ib_bootblock_t	*src_bblock = &src->bootblock;
11744c1177a4SToomas Soome 	ib_bootblock_t	*dest_bblock = &dest->bootblock;
11754c1177a4SToomas Soome 
11764c1177a4SToomas Soome 	assert(src != NULL);
11774c1177a4SToomas Soome 	assert(dest != NULL);
11784c1177a4SToomas Soome 
11794c1177a4SToomas Soome 	/* read the stage1 file from source disk */
11804c1177a4SToomas Soome 	if (read(src->device.fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) {
11814c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("cannot read stage1 from %s\n"),
11824c1177a4SToomas Soome 		    src->device.path);
11834c1177a4SToomas Soome 		return (BC_ERROR);
11844c1177a4SToomas Soome 	}
11854c1177a4SToomas Soome 
11864c1177a4SToomas Soome 	cleanup_bootblock(dest_bblock);
11874c1177a4SToomas Soome 
11884c1177a4SToomas Soome 	dest_bblock->buf_size = src_bblock->buf_size;
11894c1177a4SToomas Soome 	dest_bblock->buf = malloc(dest_bblock->buf_size);
11904c1177a4SToomas Soome 	if (dest_bblock->buf == NULL) {
11914c1177a4SToomas Soome 		perror(gettext("Memory Allocation Failure"));
11924c1177a4SToomas Soome 		return (BC_ERROR);
11934c1177a4SToomas Soome 	}
11944c1177a4SToomas Soome 	dest_bblock->file = dest_bblock->buf;
11954c1177a4SToomas Soome 	dest_bblock->file_size = src_bblock->file_size;
11964c1177a4SToomas Soome 	(void) memcpy(dest_bblock->buf, src_bblock->buf,
11974c1177a4SToomas Soome 	    dest_bblock->buf_size);
11984c1177a4SToomas Soome 
11994c1177a4SToomas Soome 	dest_bblock->mboot = (multiboot_header_t *)(dest_bblock->file +
12004c1177a4SToomas Soome 	    src_bblock->mboot_off);
12014c1177a4SToomas Soome 	dest_bblock->mboot_off = src_bblock->mboot_off;
12024c1177a4SToomas Soome 	dest_bblock->extra = (char *)dest_bblock->file +
12034c1177a4SToomas Soome 	    P2ROUNDUP(dest_bblock->file_size, 8);
12044c1177a4SToomas Soome 	dest_bblock->extra_size = src_bblock->extra_size;
12054c1177a4SToomas Soome 
12064c1177a4SToomas Soome 	(void) fprintf(stdout, gettext("Propagating %s bootblock to %s\n"),
12074c1177a4SToomas Soome 	    src->device.path, dest->device.path);
12084c1177a4SToomas Soome 
12094c1177a4SToomas Soome 	return (commit_to_disk(dest, updt_str));
12104c1177a4SToomas Soome }
12114c1177a4SToomas Soome 
12124c1177a4SToomas Soome static int
commit_to_disk(ib_data_t * data,char * update_str)12134c1177a4SToomas Soome commit_to_disk(ib_data_t *data, char *update_str)
12144c1177a4SToomas Soome {
12154c1177a4SToomas Soome 	assert(data != NULL);
12164c1177a4SToomas Soome 
12174c1177a4SToomas Soome 	if (prepare_bootblock(data, update_str) != BC_SUCCESS) {
12184c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Error updating the bootblock "
12194c1177a4SToomas Soome 		    "image\n"));
12204c1177a4SToomas Soome 		return (BC_ERROR);
12214c1177a4SToomas Soome 	}
12224c1177a4SToomas Soome 
12234c1177a4SToomas Soome 	if (prepare_stage1(data) != BC_SUCCESS) {
12244c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Error updating the stage1 "
12254c1177a4SToomas Soome 		    "image\n"));
12264c1177a4SToomas Soome 		return (BC_ERROR);
12274c1177a4SToomas Soome 	}
12284c1177a4SToomas Soome 
12294c1177a4SToomas Soome 	if (write_bootblock(data) != BC_SUCCESS) {
12304c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Error writing bootblock to "
12314c1177a4SToomas Soome 		    "disk\n"));
12324c1177a4SToomas Soome 		return (BC_ERROR);
12334c1177a4SToomas Soome 	}
12344c1177a4SToomas Soome 
12354c1177a4SToomas Soome 	return (write_stage1(data));
12364c1177a4SToomas Soome }
12374c1177a4SToomas Soome 
12384c1177a4SToomas Soome /*
12394c1177a4SToomas Soome  * Install a new bootblock on the given device. handle_install() expects argv
12404c1177a4SToomas Soome  * to contain 3 parameters (the target device path and the path to the
12414c1177a4SToomas Soome  * bootblock.
12424c1177a4SToomas Soome  *
12434c1177a4SToomas Soome  * Returns:	BC_SUCCESS - if the installation is successful
12444c1177a4SToomas Soome  *		BC_ERROR   - if the installation failed
12454c1177a4SToomas Soome  *		BC_NOUPDT  - if no installation was performed because the
12464c1177a4SToomas Soome  *		             version currently installed is more recent than the
12474c1177a4SToomas Soome  *			     supplied one.
12484c1177a4SToomas Soome  *
12494c1177a4SToomas Soome  */
12504c1177a4SToomas Soome static int
handle_install(char * progname,char ** argv)12514c1177a4SToomas Soome handle_install(char *progname, char **argv)
12524c1177a4SToomas Soome {
12534c1177a4SToomas Soome 	ib_data_t	install_data;
1254*161da084SToomas Soome 	ib_bootblock_t	*bblock = &install_data.bootblock;
12554c1177a4SToomas Soome 	char		*stage1 = NULL;
12564c1177a4SToomas Soome 	char		*bootblock = NULL;
12574c1177a4SToomas Soome 	char		*device_path = NULL;
12584c1177a4SToomas Soome 	int		ret = BC_ERROR;
12594c1177a4SToomas Soome 
12604c1177a4SToomas Soome 	stage1 = strdup(argv[0]);
12614c1177a4SToomas Soome 	bootblock = strdup(argv[1]);
12624c1177a4SToomas Soome 	device_path = strdup(argv[2]);
12634c1177a4SToomas Soome 
12644c1177a4SToomas Soome 	if (!device_path || !bootblock || !stage1) {
12654c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Missing parameter"));
12664c1177a4SToomas Soome 		usage(progname);
12674c1177a4SToomas Soome 		goto out;
12684c1177a4SToomas Soome 	}
12694c1177a4SToomas Soome 
12704c1177a4SToomas Soome 	BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n",
12714c1177a4SToomas Soome 	    device_path, stage1, bootblock);
12724c1177a4SToomas Soome 	bzero(&install_data, sizeof (ib_data_t));
12734c1177a4SToomas Soome 
12744c1177a4SToomas Soome 	if (init_device(&install_data.device, device_path) != BC_SUCCESS) {
12754c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Unable to open device %s\n"),
12764c1177a4SToomas Soome 		    device_path);
12774c1177a4SToomas Soome 		goto out;
12784c1177a4SToomas Soome 	}
12794c1177a4SToomas Soome 
12804c1177a4SToomas Soome 	if (read_stage1_from_file(stage1, &install_data) != BC_SUCCESS) {
12814c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Error opening %s\n"), stage1);
12824c1177a4SToomas Soome 		goto out_dev;
12834c1177a4SToomas Soome 	}
12844c1177a4SToomas Soome 
1285*161da084SToomas Soome 	if (read_bootblock_from_file(bootblock, bblock) != BC_SUCCESS) {
12864c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Error reading %s\n"),
12874c1177a4SToomas Soome 		    bootblock);
12884c1177a4SToomas Soome 		goto out_dev;
12894c1177a4SToomas Soome 	}
12904c1177a4SToomas Soome 
12914c1177a4SToomas Soome 	/*
12924c1177a4SToomas Soome 	 * is_update_necessary() will take care of checking if versioning and/or
12934c1177a4SToomas Soome 	 * forcing the update have been specified. It will also emit a warning
12944c1177a4SToomas Soome 	 * if a non-versioned update is attempted over a versioned bootblock.
12954c1177a4SToomas Soome 	 */
12964c1177a4SToomas Soome 	if (!is_update_necessary(&install_data, update_str)) {
12974c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("bootblock version installed "
12984c1177a4SToomas Soome 		    "on %s is more recent or identical\n"
12994c1177a4SToomas Soome 		    "Use -F to override or install without the -u option\n"),
13004c1177a4SToomas Soome 		    device_path);
13014c1177a4SToomas Soome 		ret = BC_NOUPDT;
13024c1177a4SToomas Soome 		goto out_dev;
13034c1177a4SToomas Soome 	}
13044c1177a4SToomas Soome 
13054c1177a4SToomas Soome 	BOOT_DEBUG("Ready to commit to disk\n");
13064c1177a4SToomas Soome 	ret = commit_to_disk(&install_data, update_str);
13074c1177a4SToomas Soome 
13084c1177a4SToomas Soome out_dev:
13094c1177a4SToomas Soome 	cleanup_device(&install_data.device);
13104c1177a4SToomas Soome out:
13114c1177a4SToomas Soome 	free(stage1);
13124c1177a4SToomas Soome 	free(bootblock);
13134c1177a4SToomas Soome 	free(device_path);
13144c1177a4SToomas Soome 	return (ret);
13154c1177a4SToomas Soome }
13164c1177a4SToomas Soome 
13174c1177a4SToomas Soome /*
13184c1177a4SToomas Soome  * Retrieves from a device the extended information (einfo) associated to the
1319*161da084SToomas Soome  * file or installed stage2.
1320*161da084SToomas Soome  * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0
1321*161da084SToomas Soome  * or file name.
13224c1177a4SToomas Soome  * Returns:
13234c1177a4SToomas Soome  *        - BC_SUCCESS (and prints out einfo contents depending on 'flags')
13244c1177a4SToomas Soome  *	  - BC_ERROR (on error)
13254c1177a4SToomas Soome  *        - BC_NOEINFO (no extended information available)
13264c1177a4SToomas Soome  */
13274c1177a4SToomas Soome static int
handle_getinfo(char * progname,char ** argv)13284c1177a4SToomas Soome handle_getinfo(char *progname, char **argv)
13294c1177a4SToomas Soome {
1330*161da084SToomas Soome 	struct stat	sb;
1331*161da084SToomas Soome 	ib_bootblock_t	bblock;
1332*161da084SToomas Soome 	ib_device_t	device;
13334c1177a4SToomas Soome 	bblk_einfo_t	*einfo;
13344c1177a4SToomas Soome 	uint8_t		flags = 0;
13354c1177a4SToomas Soome 	char		*device_path, *path;
13364c1177a4SToomas Soome 	int		retval = BC_ERROR;
13374c1177a4SToomas Soome 	int		ret;
13384c1177a4SToomas Soome 
13394c1177a4SToomas Soome 	device_path = strdup(argv[0]);
13404c1177a4SToomas Soome 	if (!device_path) {
13414c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Missing parameter"));
13424c1177a4SToomas Soome 		usage(progname);
13434c1177a4SToomas Soome 		goto out;
13444c1177a4SToomas Soome 	}
13454c1177a4SToomas Soome 
1346*161da084SToomas Soome 	if (stat(device_path, &sb) == -1) {
1347*161da084SToomas Soome 		perror("stat");
1348*161da084SToomas Soome 		goto out;
13494c1177a4SToomas Soome 	}
13504c1177a4SToomas Soome 
1351*161da084SToomas Soome 	bzero(&bblock, sizeof (bblock));
1352*161da084SToomas Soome 	bzero(&device, sizeof (device));
1353*161da084SToomas Soome 	BOOT_DEBUG("device path: %s\n", device_path);
1354*161da084SToomas Soome 
1355*161da084SToomas Soome 	if (S_ISREG(sb.st_mode) != 0) {
1356*161da084SToomas Soome 		path = device_path;
1357*161da084SToomas Soome 		ret = read_bootblock_from_file(device_path, &bblock);
1358*161da084SToomas Soome 	} else {
1359*161da084SToomas Soome 		if (init_device(&device, device_path) != BC_SUCCESS) {
1360*161da084SToomas Soome 			(void) fprintf(stderr, gettext("Unable to gather "
1361*161da084SToomas Soome 			    "device information from %s\n"), device_path);
1362*161da084SToomas Soome 			goto out_dev;
1363*161da084SToomas Soome 		}
1364*161da084SToomas Soome 		ret = read_bootblock_from_disk(&device, &bblock, &path);
1365*161da084SToomas Soome 	}
1366*161da084SToomas Soome 
13674c1177a4SToomas Soome 	if (ret == BC_ERROR) {
13684c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Error reading bootblock from "
13694c1177a4SToomas Soome 		    "%s\n"), path);
13704c1177a4SToomas Soome 		goto out_dev;
13714c1177a4SToomas Soome 	}
13724c1177a4SToomas Soome 
13734c1177a4SToomas Soome 	if (ret == BC_NOEXTRA) {
13744c1177a4SToomas Soome 		BOOT_DEBUG("No multiboot header found on %s, unable "
13754c1177a4SToomas Soome 		    "to locate extra information area (old/non versioned "
13764c1177a4SToomas Soome 		    "bootblock?) \n", device_path);
13774c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("No extended information "
13784c1177a4SToomas Soome 		    "found\n"));
13794c1177a4SToomas Soome 		retval = BC_NOEINFO;
13804c1177a4SToomas Soome 		goto out_dev;
13814c1177a4SToomas Soome 	}
13824c1177a4SToomas Soome 
1383*161da084SToomas Soome 	einfo = find_einfo(bblock.extra, bblock.extra_size);
13844c1177a4SToomas Soome 	if (einfo == NULL) {
13854c1177a4SToomas Soome 		retval = BC_NOEINFO;
13864c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("No extended information "
13874c1177a4SToomas Soome 		    "found\n"));
13884c1177a4SToomas Soome 		goto out_dev;
13894c1177a4SToomas Soome 	}
13904c1177a4SToomas Soome 
13914c1177a4SToomas Soome 	/* Print the extended information. */
13924c1177a4SToomas Soome 	if (strip)
13934c1177a4SToomas Soome 		flags |= EINFO_EASY_PARSE;
13944c1177a4SToomas Soome 	if (verbose_dump)
13954c1177a4SToomas Soome 		flags |= EINFO_PRINT_HEADER;
13964c1177a4SToomas Soome 
1397*161da084SToomas Soome 	print_einfo(flags, einfo, bblock.extra_size);
13984c1177a4SToomas Soome 	retval = BC_SUCCESS;
13994c1177a4SToomas Soome 
14004c1177a4SToomas Soome out_dev:
1401*161da084SToomas Soome 	if (S_ISREG(sb.st_mode) == 0)
1402*161da084SToomas Soome 		cleanup_device(&device);
14034c1177a4SToomas Soome out:
14044c1177a4SToomas Soome 	free(device_path);
14054c1177a4SToomas Soome 	return (retval);
14064c1177a4SToomas Soome }
14074c1177a4SToomas Soome 
14084c1177a4SToomas Soome /*
14094c1177a4SToomas Soome  * Attempt to mirror (propagate) the current bootblock over the attaching disk.
14104c1177a4SToomas Soome  *
14114c1177a4SToomas Soome  * Returns:
14124c1177a4SToomas Soome  *	- BC_SUCCESS (a successful propagation happened)
14134c1177a4SToomas Soome  *	- BC_ERROR (an error occurred)
14144c1177a4SToomas Soome  *	- BC_NOEXTRA (it is not possible to dump the current bootblock since
14154c1177a4SToomas Soome  *			there is no multiboot information)
14164c1177a4SToomas Soome  */
14174c1177a4SToomas Soome static int
handle_mirror(char * progname,char ** argv)14184c1177a4SToomas Soome handle_mirror(char *progname, char **argv)
14194c1177a4SToomas Soome {
14204c1177a4SToomas Soome 	ib_data_t	curr_data;
14214c1177a4SToomas Soome 	ib_data_t	attach_data;
14224c1177a4SToomas Soome 	ib_device_t	*curr_device = &curr_data.device;
14234c1177a4SToomas Soome 	ib_device_t	*attach_device = &attach_data.device;
14244c1177a4SToomas Soome 	ib_bootblock_t	*bblock_curr = &curr_data.bootblock;
14254c1177a4SToomas Soome 	ib_bootblock_t	*bblock_attach = &attach_data.bootblock;
14264c1177a4SToomas Soome 	bblk_einfo_t	*einfo_curr = NULL;
14274c1177a4SToomas Soome 	char		*curr_device_path;
14284c1177a4SToomas Soome 	char		*attach_device_path;
14294c1177a4SToomas Soome 	char		*updt_str = NULL;
14304c1177a4SToomas Soome 	char		*path;
14314c1177a4SToomas Soome 	int		retval = BC_ERROR;
14324c1177a4SToomas Soome 	int		ret;
14334c1177a4SToomas Soome 
14344c1177a4SToomas Soome 	curr_device_path = strdup(argv[0]);
14354c1177a4SToomas Soome 	attach_device_path = strdup(argv[1]);
14364c1177a4SToomas Soome 
14374c1177a4SToomas Soome 	if (!curr_device_path || !attach_device_path) {
14384c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Missing parameter"));
14394c1177a4SToomas Soome 		usage(progname);
14404c1177a4SToomas Soome 		goto out;
14414c1177a4SToomas Soome 	}
14424c1177a4SToomas Soome 	BOOT_DEBUG("Current device path is: %s, attaching device path is: "
14434c1177a4SToomas Soome 	    " %s\n", curr_device_path, attach_device_path);
14444c1177a4SToomas Soome 
14454c1177a4SToomas Soome 	bzero(&curr_data, sizeof (ib_data_t));
14464c1177a4SToomas Soome 	bzero(&attach_data, sizeof (ib_data_t));
14474c1177a4SToomas Soome 
14484c1177a4SToomas Soome 	if (init_device(curr_device, curr_device_path) != BC_SUCCESS) {
14494c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Unable to gather device "
14504c1177a4SToomas Soome 		    "information from %s (current device)\n"),
14514c1177a4SToomas Soome 		    curr_device_path);
14524c1177a4SToomas Soome 		goto out_currdev;
14534c1177a4SToomas Soome 	}
14544c1177a4SToomas Soome 
14554c1177a4SToomas Soome 	if (init_device(attach_device, attach_device_path) != BC_SUCCESS) {
14564c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Unable to gather device "
14574c1177a4SToomas Soome 		    "information from %s (attaching device)\n"),
14584c1177a4SToomas Soome 		    attach_device_path);
14594c1177a4SToomas Soome 		goto out_devs;
14604c1177a4SToomas Soome 	}
14614c1177a4SToomas Soome 
14624c1177a4SToomas Soome 	ret = read_bootblock_from_disk(curr_device, bblock_curr, &path);
14634c1177a4SToomas Soome 	if (ret == BC_ERROR) {
14644c1177a4SToomas Soome 		BOOT_DEBUG("Error reading bootblock from %s\n", path);
14654c1177a4SToomas Soome 		retval = BC_ERROR;
14664c1177a4SToomas Soome 		goto out_devs;
14674c1177a4SToomas Soome 	}
14684c1177a4SToomas Soome 
14694c1177a4SToomas Soome 	if (ret == BC_NOEXTRA) {
14704c1177a4SToomas Soome 		BOOT_DEBUG("No multiboot header found on %s, unable to retrieve"
14714c1177a4SToomas Soome 		    " the bootblock\n", path);
14724c1177a4SToomas Soome 		retval = BC_NOEXTRA;
14734c1177a4SToomas Soome 		goto out_devs;
14744c1177a4SToomas Soome 	}
14754c1177a4SToomas Soome 
14764c1177a4SToomas Soome 	write_mbr = B_TRUE;
14774c1177a4SToomas Soome 	force_mbr = B_TRUE;
14784c1177a4SToomas Soome 	einfo_curr = find_einfo(bblock_curr->extra, bblock_curr->extra_size);
14794c1177a4SToomas Soome 	if (einfo_curr != NULL)
14804c1177a4SToomas Soome 		updt_str = einfo_get_string(einfo_curr);
14814c1177a4SToomas Soome 
14824c1177a4SToomas Soome 	retval = propagate_bootblock(&curr_data, &attach_data, updt_str);
14834c1177a4SToomas Soome 	cleanup_bootblock(bblock_curr);
14844c1177a4SToomas Soome 	cleanup_bootblock(bblock_attach);
14854c1177a4SToomas Soome out_devs:
14864c1177a4SToomas Soome 	cleanup_device(attach_device);
14874c1177a4SToomas Soome out_currdev:
14884c1177a4SToomas Soome 	cleanup_device(curr_device);
14894c1177a4SToomas Soome out:
14904c1177a4SToomas Soome 	free(curr_device_path);
14914c1177a4SToomas Soome 	free(attach_device_path);
14924c1177a4SToomas Soome 	return (retval);
14934c1177a4SToomas Soome }
14944c1177a4SToomas Soome 
14954c1177a4SToomas Soome #define	USAGE_STRING	"Usage:\t%s [-h|-m|-f|-n|-F|-u verstr] stage1 stage2 " \
14964c1177a4SToomas Soome 			"raw-device\n"					\
14974c1177a4SToomas Soome 			"\t%s -M [-n] raw-device attach-raw-device\n"	\
1498*161da084SToomas Soome 			"\t%s [-e|-V] -i raw-device | file\n"
14994c1177a4SToomas Soome 
15004c1177a4SToomas Soome #define	CANON_USAGE_STR	gettext(USAGE_STRING)
15014c1177a4SToomas Soome 
15024c1177a4SToomas Soome static void
usage(char * progname)15034c1177a4SToomas Soome usage(char *progname)
15044c1177a4SToomas Soome {
15054c1177a4SToomas Soome 	(void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
15064c1177a4SToomas Soome }
15074c1177a4SToomas Soome 
15084c1177a4SToomas Soome int
main(int argc,char ** argv)15094c1177a4SToomas Soome main(int argc, char **argv)
15104c1177a4SToomas Soome {
15114c1177a4SToomas Soome 	int	opt;
15124c1177a4SToomas Soome 	int	params = 3;
15134c1177a4SToomas Soome 	int	ret;
15144c1177a4SToomas Soome 	char	*progname;
15154c1177a4SToomas Soome 	char	**handle_args;
15164c1177a4SToomas Soome 
15174c1177a4SToomas Soome 	(void) setlocale(LC_ALL, "");
15184c1177a4SToomas Soome 	(void) textdomain(TEXT_DOMAIN);
15194c1177a4SToomas Soome 	if (init_yes() < 0) {
15204c1177a4SToomas Soome 		(void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
15214c1177a4SToomas Soome 		    strerror(errno));
15224c1177a4SToomas Soome 		exit(BC_ERROR);
15234c1177a4SToomas Soome 	}
15244c1177a4SToomas Soome 
15254c1177a4SToomas Soome 	while ((opt = getopt(argc, argv, "deFfhiMmnu:V")) != EOF) {
15264c1177a4SToomas Soome 		switch (opt) {
15274c1177a4SToomas Soome 		case 'd':
15284c1177a4SToomas Soome 			boot_debug = B_TRUE;
15294c1177a4SToomas Soome 			break;
15304c1177a4SToomas Soome 		case 'e':
15314c1177a4SToomas Soome 			strip = B_TRUE;
15324c1177a4SToomas Soome 			break;
15334c1177a4SToomas Soome 		case 'F':
15344c1177a4SToomas Soome 			force_update = B_TRUE;
15354c1177a4SToomas Soome 			break;
15364c1177a4SToomas Soome 		case 'f':
15374c1177a4SToomas Soome 			force_mbr = B_TRUE;
15384c1177a4SToomas Soome 			break;
15394c1177a4SToomas Soome 		case 'h':
15404c1177a4SToomas Soome 			usage(argv[0]);
15414c1177a4SToomas Soome 			exit(BC_SUCCESS);
15424c1177a4SToomas Soome 			break;
15434c1177a4SToomas Soome 		case 'i':
15444c1177a4SToomas Soome 			do_getinfo = B_TRUE;
15454c1177a4SToomas Soome 			params = 1;
15464c1177a4SToomas Soome 			break;
15474c1177a4SToomas Soome 		case 'M':
15484c1177a4SToomas Soome 			do_mirror_bblk = B_TRUE;
15494c1177a4SToomas Soome 			params = 2;
15504c1177a4SToomas Soome 			break;
15514c1177a4SToomas Soome 		case 'm':
15524c1177a4SToomas Soome 			write_mbr = B_TRUE;
15534c1177a4SToomas Soome 			break;
15544c1177a4SToomas Soome 		case 'n':
15554c1177a4SToomas Soome 			nowrite = B_TRUE;
15564c1177a4SToomas Soome 			break;
15574c1177a4SToomas Soome 		case 'u':
15584c1177a4SToomas Soome 			do_version = B_TRUE;
15594c1177a4SToomas Soome 
15604c1177a4SToomas Soome 			update_str = malloc(strlen(optarg) + 1);
15614c1177a4SToomas Soome 			if (update_str == NULL) {
15624c1177a4SToomas Soome 				perror(gettext("Memory allocation failure"));
15634c1177a4SToomas Soome 				exit(BC_ERROR);
15644c1177a4SToomas Soome 			}
15654c1177a4SToomas Soome 			(void) strlcpy(update_str, optarg, strlen(optarg) + 1);
15664c1177a4SToomas Soome 			break;
15674c1177a4SToomas Soome 		case 'V':
15684c1177a4SToomas Soome 			verbose_dump = B_TRUE;
15694c1177a4SToomas Soome 			break;
15704c1177a4SToomas Soome 		default:
15714c1177a4SToomas Soome 			/* fall through to process non-optional args */
15724c1177a4SToomas Soome 			break;
15734c1177a4SToomas Soome 		}
15744c1177a4SToomas Soome 	}
15754c1177a4SToomas Soome 
15764c1177a4SToomas Soome 	/* check arguments */
15774c1177a4SToomas Soome 	if (argc != optind + params) {
15784c1177a4SToomas Soome 		usage(argv[0]);
15794c1177a4SToomas Soome 		exit(BC_ERROR);
15804c1177a4SToomas Soome 	}
15814c1177a4SToomas Soome 	progname = argv[0];
15824c1177a4SToomas Soome 	check_options(progname);
15834c1177a4SToomas Soome 	handle_args = argv + optind;
15844c1177a4SToomas Soome 
15854c1177a4SToomas Soome 	if (nowrite)
15864c1177a4SToomas Soome 		(void) fprintf(stdout, gettext("Dry run requested. Nothing will"
15874c1177a4SToomas Soome 		    " be written to disk.\n"));
15884c1177a4SToomas Soome 
15894c1177a4SToomas Soome 	if (do_getinfo) {
15904c1177a4SToomas Soome 		ret = handle_getinfo(progname, handle_args);
15914c1177a4SToomas Soome 	} else if (do_mirror_bblk) {
15924c1177a4SToomas Soome 		ret = handle_mirror(progname, handle_args);
15934c1177a4SToomas Soome 	} else {
15944c1177a4SToomas Soome 		ret = handle_install(progname, handle_args);
15954c1177a4SToomas Soome 	}
15964c1177a4SToomas Soome 	return (ret);
15974c1177a4SToomas Soome }
15984c1177a4SToomas Soome 
15994c1177a4SToomas Soome #define	MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n")
16004c1177a4SToomas Soome static void
check_options(char * progname)16014c1177a4SToomas Soome check_options(char *progname)
16024c1177a4SToomas Soome {
16034c1177a4SToomas Soome 	if (do_getinfo && do_mirror_bblk) {
16044c1177a4SToomas Soome 		(void) fprintf(stderr, gettext("Only one of -M and -i can be "
16054c1177a4SToomas Soome 		    "specified at the same time\n"));
16064c1177a4SToomas Soome 		usage(progname);
16074c1177a4SToomas Soome 		exit(BC_ERROR);
16084c1177a4SToomas Soome 	}
16094c1177a4SToomas Soome 
16104c1177a4SToomas Soome 	if (do_mirror_bblk) {
16114c1177a4SToomas Soome 		/*
16124c1177a4SToomas Soome 		 * -u and -F may actually reflect a user intent that is not
16134c1177a4SToomas Soome 		 * correct with this command (mirror can be interpreted
16144c1177a4SToomas Soome 		 * "similar" to install. Emit a message and continue.
16154c1177a4SToomas Soome 		 * -e and -V have no meaning, be quiet here and only report the
16164c1177a4SToomas Soome 		 * incongruence if a debug output is requested.
16174c1177a4SToomas Soome 		 */
16184c1177a4SToomas Soome 		if (do_version) {
16194c1177a4SToomas Soome 			(void) fprintf(stderr, MEANINGLESS_OPT, "-u");
16204c1177a4SToomas Soome 			do_version = B_FALSE;
16214c1177a4SToomas Soome 		}
16224c1177a4SToomas Soome 		if (force_update) {
16234c1177a4SToomas Soome 			(void) fprintf(stderr, MEANINGLESS_OPT, "-F");
16244c1177a4SToomas Soome 			force_update = B_FALSE;
16254c1177a4SToomas Soome 		}
16264c1177a4SToomas Soome 		if (strip || verbose_dump) {
16274c1177a4SToomas Soome 			BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V");
16284c1177a4SToomas Soome 			strip = B_FALSE;
16294c1177a4SToomas Soome 			verbose_dump = B_FALSE;
16304c1177a4SToomas Soome 		}
16314c1177a4SToomas Soome 	}
16324c1177a4SToomas Soome 
16334c1177a4SToomas Soome 	if (do_getinfo) {
16344c1177a4SToomas Soome 		if (write_mbr || force_mbr || do_version || force_update) {
16354c1177a4SToomas Soome 			BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F");
16364c1177a4SToomas Soome 			write_mbr = force_mbr = do_version = B_FALSE;
16374c1177a4SToomas Soome 			force_update = B_FALSE;
16384c1177a4SToomas Soome 		}
16394c1177a4SToomas Soome 	}
16404c1177a4SToomas Soome }
1641