xref: /onnv-gate/usr/src/cmd/boot/installboot/installboot.c (revision 12947:f5f96e09bf49)
1*12947SEnrico.Perla@Sun.COM /*
2*12947SEnrico.Perla@Sun.COM  * CDDL HEADER START
3*12947SEnrico.Perla@Sun.COM  *
4*12947SEnrico.Perla@Sun.COM  * The contents of this file are subject to the terms of the
5*12947SEnrico.Perla@Sun.COM  * Common Development and Distribution License (the "License").
6*12947SEnrico.Perla@Sun.COM  * You may not use this file except in compliance with the License.
7*12947SEnrico.Perla@Sun.COM  *
8*12947SEnrico.Perla@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12947SEnrico.Perla@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*12947SEnrico.Perla@Sun.COM  * See the License for the specific language governing permissions
11*12947SEnrico.Perla@Sun.COM  * and limitations under the License.
12*12947SEnrico.Perla@Sun.COM  *
13*12947SEnrico.Perla@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*12947SEnrico.Perla@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12947SEnrico.Perla@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*12947SEnrico.Perla@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*12947SEnrico.Perla@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*12947SEnrico.Perla@Sun.COM  *
19*12947SEnrico.Perla@Sun.COM  * CDDL HEADER END
20*12947SEnrico.Perla@Sun.COM  */
21*12947SEnrico.Perla@Sun.COM /*
22*12947SEnrico.Perla@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23*12947SEnrico.Perla@Sun.COM  */
24*12947SEnrico.Perla@Sun.COM 
25*12947SEnrico.Perla@Sun.COM #include <stdio.h>
26*12947SEnrico.Perla@Sun.COM #include <errno.h>
27*12947SEnrico.Perla@Sun.COM #include <unistd.h>
28*12947SEnrico.Perla@Sun.COM #include <fcntl.h>
29*12947SEnrico.Perla@Sun.COM #include <assert.h>
30*12947SEnrico.Perla@Sun.COM #include <locale.h>
31*12947SEnrico.Perla@Sun.COM #include <strings.h>
32*12947SEnrico.Perla@Sun.COM #include <sys/types.h>
33*12947SEnrico.Perla@Sun.COM #include <sys/stat.h>
34*12947SEnrico.Perla@Sun.COM #include <sys/multiboot.h>
35*12947SEnrico.Perla@Sun.COM #include <sys/sysmacros.h>
36*12947SEnrico.Perla@Sun.COM 
37*12947SEnrico.Perla@Sun.COM #include "installboot.h"
38*12947SEnrico.Perla@Sun.COM #include "./../common/bblk_einfo.h"
39*12947SEnrico.Perla@Sun.COM #include "./../common/boot_utils.h"
40*12947SEnrico.Perla@Sun.COM #include "./../common/mboot_extra.h"
41*12947SEnrico.Perla@Sun.COM 
42*12947SEnrico.Perla@Sun.COM #ifndef	TEXT_DOMAIN
43*12947SEnrico.Perla@Sun.COM #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
44*12947SEnrico.Perla@Sun.COM #endif
45*12947SEnrico.Perla@Sun.COM 
46*12947SEnrico.Perla@Sun.COM /*
47*12947SEnrico.Perla@Sun.COM  * SPARC bootblock installation:
48*12947SEnrico.Perla@Sun.COM  *
49*12947SEnrico.Perla@Sun.COM  * The bootblock resides in blocks 1 to 15 (disk label is at block 0).
50*12947SEnrico.Perla@Sun.COM  * The ZFS boot block is larger than what will fit into these first 7.5K so we
51*12947SEnrico.Perla@Sun.COM  * break it up and write the remaining portion into the ZFS provided boot block
52*12947SEnrico.Perla@Sun.COM  * region at offset 512K. If versioning is requested, we add a multiboot
53*12947SEnrico.Perla@Sun.COM  * header at the end of the bootblock, followed by the extra payload area and
54*12947SEnrico.Perla@Sun.COM  * place the extended information structure within the latter.
55*12947SEnrico.Perla@Sun.COM  */
56*12947SEnrico.Perla@Sun.COM 
57*12947SEnrico.Perla@Sun.COM static boolean_t	force_update = B_FALSE;
58*12947SEnrico.Perla@Sun.COM static boolean_t	do_getinfo = B_FALSE;
59*12947SEnrico.Perla@Sun.COM static boolean_t	do_version = B_FALSE;
60*12947SEnrico.Perla@Sun.COM static boolean_t	do_mirror_bblk = B_FALSE;
61*12947SEnrico.Perla@Sun.COM static boolean_t	strip = B_FALSE;
62*12947SEnrico.Perla@Sun.COM static boolean_t	verbose_dump = B_FALSE;
63*12947SEnrico.Perla@Sun.COM 
64*12947SEnrico.Perla@Sun.COM static char		*update_str;
65*12947SEnrico.Perla@Sun.COM static int		tgt_fs_type = TARGET_IS_UFS;
66*12947SEnrico.Perla@Sun.COM char			mboot_scan[MBOOT_SCAN_SIZE];
67*12947SEnrico.Perla@Sun.COM 
68*12947SEnrico.Perla@Sun.COM /* Function prototypes. */
69*12947SEnrico.Perla@Sun.COM static int read_bootblock_from_file(char *, ib_data_t *data);
70*12947SEnrico.Perla@Sun.COM static int read_bootblock_from_disk(int, ib_bootblock_t *);
71*12947SEnrico.Perla@Sun.COM static void add_bootblock_einfo(ib_bootblock_t *, char *);
72*12947SEnrico.Perla@Sun.COM static int prepare_bootblock(ib_data_t *, char *);
73*12947SEnrico.Perla@Sun.COM static int write_zfs_bootblock(ib_data_t *);
74*12947SEnrico.Perla@Sun.COM static int write_bootblock(ib_data_t *);
75*12947SEnrico.Perla@Sun.COM static int open_device(ib_device_t *);
76*12947SEnrico.Perla@Sun.COM static int init_device(ib_device_t *, char *);
77*12947SEnrico.Perla@Sun.COM static void cleanup_device(ib_device_t *);
78*12947SEnrico.Perla@Sun.COM static int commit_to_disk(ib_data_t *, char *);
79*12947SEnrico.Perla@Sun.COM static int handle_install(char *, char **);
80*12947SEnrico.Perla@Sun.COM static int handle_getinfo(char *, char **);
81*12947SEnrico.Perla@Sun.COM static int handle_mirror(char *, char **);
82*12947SEnrico.Perla@Sun.COM static boolean_t is_update_necessary(ib_data_t *, char *);
83*12947SEnrico.Perla@Sun.COM static int propagate_bootblock(ib_data_t *, ib_data_t *, char *);
84*12947SEnrico.Perla@Sun.COM static void usage(char *);
85*12947SEnrico.Perla@Sun.COM 
86*12947SEnrico.Perla@Sun.COM static int
read_bootblock_from_file(char * file,ib_data_t * data)87*12947SEnrico.Perla@Sun.COM read_bootblock_from_file(char *file, ib_data_t *data)
88*12947SEnrico.Perla@Sun.COM {
89*12947SEnrico.Perla@Sun.COM 	ib_device_t	*device = &data->device;
90*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	*bblock = &data->bootblock;
91*12947SEnrico.Perla@Sun.COM 	struct stat 	sb;
92*12947SEnrico.Perla@Sun.COM 	uint32_t	buf_size;
93*12947SEnrico.Perla@Sun.COM 	int		fd = -1;
94*12947SEnrico.Perla@Sun.COM 	int		retval = BC_ERROR;
95*12947SEnrico.Perla@Sun.COM 
96*12947SEnrico.Perla@Sun.COM 	assert(data != NULL);
97*12947SEnrico.Perla@Sun.COM 	assert(file != NULL);
98*12947SEnrico.Perla@Sun.COM 
99*12947SEnrico.Perla@Sun.COM 	fd = open(file, O_RDONLY);
100*12947SEnrico.Perla@Sun.COM 	if (fd == -1) {
101*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Error opening %s\n", file);
102*12947SEnrico.Perla@Sun.COM 		perror("open");
103*12947SEnrico.Perla@Sun.COM 		goto out;
104*12947SEnrico.Perla@Sun.COM 	}
105*12947SEnrico.Perla@Sun.COM 
106*12947SEnrico.Perla@Sun.COM 	if (fstat(fd, &sb) == -1) {
107*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Error getting information (stat) about %s", file);
108*12947SEnrico.Perla@Sun.COM 		perror("stat");
109*12947SEnrico.Perla@Sun.COM 		goto outfd;
110*12947SEnrico.Perla@Sun.COM 	}
111*12947SEnrico.Perla@Sun.COM 
112*12947SEnrico.Perla@Sun.COM 	bblock->file_size = sb.st_size;
113*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("bootblock file size is %x\n", bblock->file_size);
114*12947SEnrico.Perla@Sun.COM 
115*12947SEnrico.Perla@Sun.COM 	/* UFS and HSFS bootblocks need to fit in the reserved 7.5K. */
116*12947SEnrico.Perla@Sun.COM 	if (!is_zfs(device->type)) {
117*12947SEnrico.Perla@Sun.COM 		buf_size = P2ROUNDUP(bblock->file_size, SECTOR_SIZE);
118*12947SEnrico.Perla@Sun.COM 		if (buf_size > BBLK_DATA_RSVD_SIZE) {
119*12947SEnrico.Perla@Sun.COM 			BOOT_DEBUG("boot block size is bigger than allowed\n");
120*12947SEnrico.Perla@Sun.COM 			goto outfd;
121*12947SEnrico.Perla@Sun.COM 		}
122*12947SEnrico.Perla@Sun.COM 	} else {
123*12947SEnrico.Perla@Sun.COM 		buf_size = P2ROUNDUP(bblock->file_size + SECTOR_SIZE,
124*12947SEnrico.Perla@Sun.COM 		    SECTOR_SIZE);
125*12947SEnrico.Perla@Sun.COM 		if (buf_size > BBLK_DATA_RSVD_SIZE + MBOOT_SCAN_SIZE) {
126*12947SEnrico.Perla@Sun.COM 			(void) fprintf(stderr, gettext("WARNING, bootblock size"
127*12947SEnrico.Perla@Sun.COM 			    " does not allow to place extended versioning "
128*12947SEnrico.Perla@Sun.COM 			    "information.. skipping\n"));
129*12947SEnrico.Perla@Sun.COM 			do_version = B_FALSE;
130*12947SEnrico.Perla@Sun.COM 		}
131*12947SEnrico.Perla@Sun.COM 	}
132*12947SEnrico.Perla@Sun.COM 
133*12947SEnrico.Perla@Sun.COM 	bblock->buf_size = buf_size;
134*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("bootblock in-memory buffer size is %x\n",
135*12947SEnrico.Perla@Sun.COM 	    bblock->buf_size);
136*12947SEnrico.Perla@Sun.COM 
137*12947SEnrico.Perla@Sun.COM 	bblock->buf = malloc(buf_size);
138*12947SEnrico.Perla@Sun.COM 	if (bblock->buf == NULL) {
139*12947SEnrico.Perla@Sun.COM 		perror(gettext("Memory allocation failure"));
140*12947SEnrico.Perla@Sun.COM 		goto outbuf;
141*12947SEnrico.Perla@Sun.COM 	}
142*12947SEnrico.Perla@Sun.COM 	bblock->file = bblock->buf;
143*12947SEnrico.Perla@Sun.COM 
144*12947SEnrico.Perla@Sun.COM 	if (read(fd, bblock->file, bblock->file_size) != bblock->file_size) {
145*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Read from %s failed\n", file);
146*12947SEnrico.Perla@Sun.COM 		perror("read");
147*12947SEnrico.Perla@Sun.COM 		goto outfd;
148*12947SEnrico.Perla@Sun.COM 	}
149*12947SEnrico.Perla@Sun.COM 
150*12947SEnrico.Perla@Sun.COM 	/* If not on ZFS, we are done here. */
151*12947SEnrico.Perla@Sun.COM 	if (!is_zfs(device->type)) {
152*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Reading of the bootblock done\n");
153*12947SEnrico.Perla@Sun.COM 		retval = BC_SUCCESS;
154*12947SEnrico.Perla@Sun.COM 		goto outfd;
155*12947SEnrico.Perla@Sun.COM 	}
156*12947SEnrico.Perla@Sun.COM 	/*
157*12947SEnrico.Perla@Sun.COM 	 * We place the multiboot header right after the file, followed by
158*12947SEnrico.Perla@Sun.COM 	 * the extended information structure.
159*12947SEnrico.Perla@Sun.COM 	 */
160*12947SEnrico.Perla@Sun.COM 	bblock->mboot = (multiboot_header_t *)(bblock->file +
161*12947SEnrico.Perla@Sun.COM 	    P2ROUNDUP(bblock->file_size, 8));
162*12947SEnrico.Perla@Sun.COM 	bblock->extra = (char *)bblock->mboot + sizeof (multiboot_header_t);
163*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("mboot at %p, extra at %p, buf=%p (size=%d)\n",
164*12947SEnrico.Perla@Sun.COM 	    bblock->mboot, bblock->extra, bblock->buf, bblock->buf_size);
165*12947SEnrico.Perla@Sun.COM 
166*12947SEnrico.Perla@Sun.COM 	(void) close(fd);
167*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
168*12947SEnrico.Perla@Sun.COM 
169*12947SEnrico.Perla@Sun.COM outbuf:
170*12947SEnrico.Perla@Sun.COM 	(void) free(bblock->buf);
171*12947SEnrico.Perla@Sun.COM 	bblock->buf = NULL;
172*12947SEnrico.Perla@Sun.COM outfd:
173*12947SEnrico.Perla@Sun.COM 	(void) close(fd);
174*12947SEnrico.Perla@Sun.COM out:
175*12947SEnrico.Perla@Sun.COM 	return (retval);
176*12947SEnrico.Perla@Sun.COM }
177*12947SEnrico.Perla@Sun.COM 
178*12947SEnrico.Perla@Sun.COM static int
read_bootblock_from_disk(int dev_fd,ib_bootblock_t * bblock)179*12947SEnrico.Perla@Sun.COM read_bootblock_from_disk(int dev_fd, ib_bootblock_t *bblock)
180*12947SEnrico.Perla@Sun.COM {
181*12947SEnrico.Perla@Sun.COM 	char			*dest;
182*12947SEnrico.Perla@Sun.COM 	uint32_t		size;
183*12947SEnrico.Perla@Sun.COM 	uint32_t		buf_size;
184*12947SEnrico.Perla@Sun.COM 	uint32_t		mboot_off;
185*12947SEnrico.Perla@Sun.COM 	multiboot_header_t	*mboot;
186*12947SEnrico.Perla@Sun.COM 
187*12947SEnrico.Perla@Sun.COM 	assert(bblock != NULL);
188*12947SEnrico.Perla@Sun.COM 	assert(dev_fd != -1);
189*12947SEnrico.Perla@Sun.COM 
190*12947SEnrico.Perla@Sun.COM 	/*
191*12947SEnrico.Perla@Sun.COM 	 * The ZFS bootblock is divided in two parts, but the fake multiboot
192*12947SEnrico.Perla@Sun.COM 	 * header can only be in the second part (the one contained in the ZFS
193*12947SEnrico.Perla@Sun.COM 	 * reserved area).
194*12947SEnrico.Perla@Sun.COM 	 */
195*12947SEnrico.Perla@Sun.COM 	if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan),
196*12947SEnrico.Perla@Sun.COM 	    BBLK_ZFS_EXTRA_OFF) != BC_SUCCESS) {
197*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Error reading ZFS reserved area\n");
198*12947SEnrico.Perla@Sun.COM 		perror("read");
199*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
200*12947SEnrico.Perla@Sun.COM 	}
201*12947SEnrico.Perla@Sun.COM 
202*12947SEnrico.Perla@Sun.COM 	/* No multiboot means no chance of knowing bootblock size */
203*12947SEnrico.Perla@Sun.COM 	if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off)
204*12947SEnrico.Perla@Sun.COM 	    != BC_SUCCESS) {
205*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Unable to find multiboot header\n");
206*12947SEnrico.Perla@Sun.COM 		return (BC_NOEXTRA);
207*12947SEnrico.Perla@Sun.COM 	}
208*12947SEnrico.Perla@Sun.COM 	mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
209*12947SEnrico.Perla@Sun.COM 
210*12947SEnrico.Perla@Sun.COM 	/*
211*12947SEnrico.Perla@Sun.COM 	 * Currently, the amount of space reserved for extra information
212*12947SEnrico.Perla@Sun.COM 	 * is "fixed". We may have to scan for the terminating extra payload
213*12947SEnrico.Perla@Sun.COM 	 * in the future.
214*12947SEnrico.Perla@Sun.COM 	 */
215*12947SEnrico.Perla@Sun.COM 	size = mboot->load_end_addr - mboot->load_addr;
216*12947SEnrico.Perla@Sun.COM 	buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
217*12947SEnrico.Perla@Sun.COM 	bblock->file_size = size;
218*12947SEnrico.Perla@Sun.COM 
219*12947SEnrico.Perla@Sun.COM 	bblock->buf = malloc(buf_size);
220*12947SEnrico.Perla@Sun.COM 	if (bblock->buf == NULL) {
221*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Unable to allocate enough memory to read"
222*12947SEnrico.Perla@Sun.COM 		    " the extra bootblock from the disk\n");
223*12947SEnrico.Perla@Sun.COM 		perror(gettext("Memory allocation failure"));
224*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
225*12947SEnrico.Perla@Sun.COM 	}
226*12947SEnrico.Perla@Sun.COM 	bblock->buf_size = buf_size;
227*12947SEnrico.Perla@Sun.COM 
228*12947SEnrico.Perla@Sun.COM 	dest = bblock->buf;
229*12947SEnrico.Perla@Sun.COM 	size = BBLK_DATA_RSVD_SIZE;
230*12947SEnrico.Perla@Sun.COM 
231*12947SEnrico.Perla@Sun.COM 	if (read_in(dev_fd, dest, size, SECTOR_SIZE) != BC_SUCCESS) {
232*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Error reading first %d bytes of the bootblock\n",
233*12947SEnrico.Perla@Sun.COM 		    size);
234*12947SEnrico.Perla@Sun.COM 		(void) free(bblock->buf);
235*12947SEnrico.Perla@Sun.COM 		bblock->buf = NULL;
236*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
237*12947SEnrico.Perla@Sun.COM 	}
238*12947SEnrico.Perla@Sun.COM 
239*12947SEnrico.Perla@Sun.COM 	dest += BBLK_DATA_RSVD_SIZE;
240*12947SEnrico.Perla@Sun.COM 	size = bblock->buf_size - BBLK_DATA_RSVD_SIZE;
241*12947SEnrico.Perla@Sun.COM 
242*12947SEnrico.Perla@Sun.COM 	if (read_in(dev_fd, dest, size, BBLK_ZFS_EXTRA_OFF) != BC_SUCCESS) {
243*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Error reading ZFS reserved area the second time\n");
244*12947SEnrico.Perla@Sun.COM 		(void) free(bblock->buf);
245*12947SEnrico.Perla@Sun.COM 		bblock->buf = NULL;
246*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
247*12947SEnrico.Perla@Sun.COM 	}
248*12947SEnrico.Perla@Sun.COM 
249*12947SEnrico.Perla@Sun.COM 	/* Update pointers. */
250*12947SEnrico.Perla@Sun.COM 	bblock->file = bblock->buf;
251*12947SEnrico.Perla@Sun.COM 	bblock->mboot_off = mboot_off;
252*12947SEnrico.Perla@Sun.COM 	bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off
253*12947SEnrico.Perla@Sun.COM 	    + BBLK_DATA_RSVD_SIZE);
254*12947SEnrico.Perla@Sun.COM 	bblock->extra = (char *)bblock->mboot + sizeof (multiboot_header_t);
255*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
256*12947SEnrico.Perla@Sun.COM }
257*12947SEnrico.Perla@Sun.COM 
258*12947SEnrico.Perla@Sun.COM static boolean_t
is_update_necessary(ib_data_t * data,char * updt_str)259*12947SEnrico.Perla@Sun.COM is_update_necessary(ib_data_t *data, char *updt_str)
260*12947SEnrico.Perla@Sun.COM {
261*12947SEnrico.Perla@Sun.COM 	bblk_einfo_t	*einfo;
262*12947SEnrico.Perla@Sun.COM 	bblk_hs_t	bblock_hs;
263*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	bblock_disk;
264*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	*bblock_file = &data->bootblock;
265*12947SEnrico.Perla@Sun.COM 	ib_device_t	*device = &data->device;
266*12947SEnrico.Perla@Sun.COM 	int		dev_fd = device->fd;
267*12947SEnrico.Perla@Sun.COM 
268*12947SEnrico.Perla@Sun.COM 	assert(data != NULL);
269*12947SEnrico.Perla@Sun.COM 	assert(device->fd != -1);
270*12947SEnrico.Perla@Sun.COM 
271*12947SEnrico.Perla@Sun.COM 	/* Nothing to do if we are not updating a ZFS bootblock. */
272*12947SEnrico.Perla@Sun.COM 	if (!is_zfs(device->type))
273*12947SEnrico.Perla@Sun.COM 		return (B_TRUE);
274*12947SEnrico.Perla@Sun.COM 
275*12947SEnrico.Perla@Sun.COM 	bzero(&bblock_disk, sizeof (ib_bootblock_t));
276*12947SEnrico.Perla@Sun.COM 
277*12947SEnrico.Perla@Sun.COM 	if (read_bootblock_from_disk(dev_fd, &bblock_disk) != BC_SUCCESS) {
278*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Unable to read bootblock from %s\n", device->path);
279*12947SEnrico.Perla@Sun.COM 		return (B_TRUE);
280*12947SEnrico.Perla@Sun.COM 	}
281*12947SEnrico.Perla@Sun.COM 
282*12947SEnrico.Perla@Sun.COM 	einfo = find_einfo(bblock_disk.extra);
283*12947SEnrico.Perla@Sun.COM 	if (einfo == NULL) {
284*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("No extended information available\n");
285*12947SEnrico.Perla@Sun.COM 		return (B_TRUE);
286*12947SEnrico.Perla@Sun.COM 	}
287*12947SEnrico.Perla@Sun.COM 
288*12947SEnrico.Perla@Sun.COM 	if (!do_version || updt_str == NULL) {
289*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, "WARNING: target device %s has a "
290*12947SEnrico.Perla@Sun.COM 		    "versioned bootblock that is going to be overwritten by a "
291*12947SEnrico.Perla@Sun.COM 		    "non versioned one\n", device->path);
292*12947SEnrico.Perla@Sun.COM 		return (B_TRUE);
293*12947SEnrico.Perla@Sun.COM 	}
294*12947SEnrico.Perla@Sun.COM 
295*12947SEnrico.Perla@Sun.COM 	if (force_update) {
296*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Forcing update of %s bootblock\n", device->path);
297*12947SEnrico.Perla@Sun.COM 		return (B_TRUE);
298*12947SEnrico.Perla@Sun.COM 	}
299*12947SEnrico.Perla@Sun.COM 
300*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("Ready to check installed version vs %s\n", updt_str);
301*12947SEnrico.Perla@Sun.COM 
302*12947SEnrico.Perla@Sun.COM 	bblock_hs.src_buf = (unsigned char *)bblock_file->file;
303*12947SEnrico.Perla@Sun.COM 	bblock_hs.src_size = bblock_file->file_size;
304*12947SEnrico.Perla@Sun.COM 
305*12947SEnrico.Perla@Sun.COM 	return (einfo_should_update(einfo, &bblock_hs, updt_str));
306*12947SEnrico.Perla@Sun.COM }
307*12947SEnrico.Perla@Sun.COM 
308*12947SEnrico.Perla@Sun.COM static void
add_bootblock_einfo(ib_bootblock_t * bblock,char * updt_str)309*12947SEnrico.Perla@Sun.COM add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str)
310*12947SEnrico.Perla@Sun.COM {
311*12947SEnrico.Perla@Sun.COM 	bblk_hs_t	hs;
312*12947SEnrico.Perla@Sun.COM 	uint32_t	avail_space;
313*12947SEnrico.Perla@Sun.COM 
314*12947SEnrico.Perla@Sun.COM 	assert(bblock != NULL);
315*12947SEnrico.Perla@Sun.COM 
316*12947SEnrico.Perla@Sun.COM 	if (updt_str == NULL) {
317*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("WARNING: no update string passed to "
318*12947SEnrico.Perla@Sun.COM 		    "add_bootblock_einfo()\n");
319*12947SEnrico.Perla@Sun.COM 		return;
320*12947SEnrico.Perla@Sun.COM 	}
321*12947SEnrico.Perla@Sun.COM 
322*12947SEnrico.Perla@Sun.COM 	/* Fill bootblock hashing source information. */
323*12947SEnrico.Perla@Sun.COM 	hs.src_buf = (unsigned char *)bblock->file;
324*12947SEnrico.Perla@Sun.COM 	hs.src_size = bblock->file_size;
325*12947SEnrico.Perla@Sun.COM 	/* How much space for the extended information structure? */
326*12947SEnrico.Perla@Sun.COM 	avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
327*12947SEnrico.Perla@Sun.COM 	/* Place the extended information structure. */
328*12947SEnrico.Perla@Sun.COM 	add_einfo(bblock->extra, updt_str, &hs, avail_space);
329*12947SEnrico.Perla@Sun.COM }
330*12947SEnrico.Perla@Sun.COM 
331*12947SEnrico.Perla@Sun.COM 
332*12947SEnrico.Perla@Sun.COM static int
prepare_bootblock(ib_data_t * data,char * updt_str)333*12947SEnrico.Perla@Sun.COM prepare_bootblock(ib_data_t *data, char *updt_str)
334*12947SEnrico.Perla@Sun.COM {
335*12947SEnrico.Perla@Sun.COM 	ib_device_t		*device = &data->device;
336*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t		*bblock = &data->bootblock;
337*12947SEnrico.Perla@Sun.COM 	multiboot_header_t	*mboot;
338*12947SEnrico.Perla@Sun.COM 
339*12947SEnrico.Perla@Sun.COM 	assert(data != NULL);
340*12947SEnrico.Perla@Sun.COM 
341*12947SEnrico.Perla@Sun.COM 	/* Nothing to do if we are not on ZFS. */
342*12947SEnrico.Perla@Sun.COM 	if (!is_zfs(device->type))
343*12947SEnrico.Perla@Sun.COM 		return (BC_SUCCESS);
344*12947SEnrico.Perla@Sun.COM 
345*12947SEnrico.Perla@Sun.COM 	/*
346*12947SEnrico.Perla@Sun.COM 	 * Write the fake multiboot structure followed by the extra information
347*12947SEnrico.Perla@Sun.COM 	 * data. Both mboot and extra pointers have already been filled up to
348*12947SEnrico.Perla@Sun.COM 	 * point to the right location in the buffer. We prepare the fake
349*12947SEnrico.Perla@Sun.COM 	 * multiboot regardless if versioning was requested or not because
350*12947SEnrico.Perla@Sun.COM 	 * we need it for mirroring support.
351*12947SEnrico.Perla@Sun.COM 	 */
352*12947SEnrico.Perla@Sun.COM 	assert(bblock->mboot != NULL);
353*12947SEnrico.Perla@Sun.COM 	assert(bblock->extra != NULL);
354*12947SEnrico.Perla@Sun.COM 
355*12947SEnrico.Perla@Sun.COM 	mboot = bblock->mboot;
356*12947SEnrico.Perla@Sun.COM 
357*12947SEnrico.Perla@Sun.COM 	mboot->magic = MB_HEADER_MAGIC;
358*12947SEnrico.Perla@Sun.COM 	mboot->flags = MB_HEADER_FLAGS_64;
359*12947SEnrico.Perla@Sun.COM 	mboot->checksum = -(mboot->flags + mboot->magic);
360*12947SEnrico.Perla@Sun.COM 	/*
361*12947SEnrico.Perla@Sun.COM 	 * Flags include the AOUT_KLUDGE and we use the extra members to specify
362*12947SEnrico.Perla@Sun.COM 	 * the size of the bootblock.
363*12947SEnrico.Perla@Sun.COM 	 */
364*12947SEnrico.Perla@Sun.COM 	mboot->header_addr = bblock->mboot_off;
365*12947SEnrico.Perla@Sun.COM 	mboot->load_addr = 0;
366*12947SEnrico.Perla@Sun.COM 	mboot->load_end_addr = bblock->file_size;
367*12947SEnrico.Perla@Sun.COM 
368*12947SEnrico.Perla@Sun.COM 	/*
369*12947SEnrico.Perla@Sun.COM 	 * Now that we have the mboot header in place, we can add the extended
370*12947SEnrico.Perla@Sun.COM 	 * versioning information. Since the multiboot header has been placed
371*12947SEnrico.Perla@Sun.COM 	 * after the file image, the hashing will still reflect the one of the
372*12947SEnrico.Perla@Sun.COM 	 * file on the disk.
373*12947SEnrico.Perla@Sun.COM 	 */
374*12947SEnrico.Perla@Sun.COM 	if (do_version)
375*12947SEnrico.Perla@Sun.COM 		add_bootblock_einfo(bblock, updt_str);
376*12947SEnrico.Perla@Sun.COM 
377*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
378*12947SEnrico.Perla@Sun.COM }
379*12947SEnrico.Perla@Sun.COM 
380*12947SEnrico.Perla@Sun.COM static int
write_zfs_bootblock(ib_data_t * data)381*12947SEnrico.Perla@Sun.COM write_zfs_bootblock(ib_data_t *data)
382*12947SEnrico.Perla@Sun.COM {
383*12947SEnrico.Perla@Sun.COM 	ib_device_t	*device = &data->device;
384*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	*bblock = &data->bootblock;
385*12947SEnrico.Perla@Sun.COM 	char		*bufptr;
386*12947SEnrico.Perla@Sun.COM 	uint32_t	size;
387*12947SEnrico.Perla@Sun.COM 
388*12947SEnrico.Perla@Sun.COM 	assert(data != NULL);
389*12947SEnrico.Perla@Sun.COM 	assert(device->fd != -1);
390*12947SEnrico.Perla@Sun.COM 
391*12947SEnrico.Perla@Sun.COM 	/*
392*12947SEnrico.Perla@Sun.COM 	 * In the ZFS case we actually perform two different steps:
393*12947SEnrico.Perla@Sun.COM 	 * - write the first 15 blocks of the bootblock to the reserved disk
394*12947SEnrico.Perla@Sun.COM 	 *   blocks.
395*12947SEnrico.Perla@Sun.COM 	 * - write the remaining blocks in the ZFS reserved area at offset
396*12947SEnrico.Perla@Sun.COM 	 *   512K.
397*12947SEnrico.Perla@Sun.COM 	 */
398*12947SEnrico.Perla@Sun.COM 	bufptr = bblock->buf;
399*12947SEnrico.Perla@Sun.COM 	size = BBLK_DATA_RSVD_SIZE;
400*12947SEnrico.Perla@Sun.COM 
401*12947SEnrico.Perla@Sun.COM 	if (write_out(device->fd, bufptr, size, SECTOR_SIZE) != BC_SUCCESS) {
402*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Error writing first 15 blocks of %s\n",
403*12947SEnrico.Perla@Sun.COM 		    device->path);
404*12947SEnrico.Perla@Sun.COM 		perror("write");
405*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
406*12947SEnrico.Perla@Sun.COM 	}
407*12947SEnrico.Perla@Sun.COM 
408*12947SEnrico.Perla@Sun.COM 	bufptr += BBLK_DATA_RSVD_SIZE;
409*12947SEnrico.Perla@Sun.COM 	size = bblock->buf_size - BBLK_DATA_RSVD_SIZE;
410*12947SEnrico.Perla@Sun.COM 
411*12947SEnrico.Perla@Sun.COM 	if (write_out(device->fd, bufptr, size, BBLK_ZFS_EXTRA_OFF)
412*12947SEnrico.Perla@Sun.COM 	    != BC_SUCCESS) {
413*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Error writing the second part of ZFS bootblock "
414*12947SEnrico.Perla@Sun.COM 		    "to %s at offset %d\n", device->path, BBLK_ZFS_EXTRA_OFF);
415*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
416*12947SEnrico.Perla@Sun.COM 	}
417*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
418*12947SEnrico.Perla@Sun.COM }
419*12947SEnrico.Perla@Sun.COM 
420*12947SEnrico.Perla@Sun.COM static int
write_bootblock(ib_data_t * data)421*12947SEnrico.Perla@Sun.COM write_bootblock(ib_data_t *data)
422*12947SEnrico.Perla@Sun.COM {
423*12947SEnrico.Perla@Sun.COM 	ib_device_t	*device = &data->device;
424*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	*bblock = &data->bootblock;
425*12947SEnrico.Perla@Sun.COM 	int		ret;
426*12947SEnrico.Perla@Sun.COM 
427*12947SEnrico.Perla@Sun.COM 	assert(data != NULL);
428*12947SEnrico.Perla@Sun.COM 
429*12947SEnrico.Perla@Sun.COM 	/*
430*12947SEnrico.Perla@Sun.COM 	 * If we are on UFS or HSFS we simply write out to the reserved
431*12947SEnrico.Perla@Sun.COM 	 * blocks (1 to 15) the boot block.
432*12947SEnrico.Perla@Sun.COM 	 */
433*12947SEnrico.Perla@Sun.COM 	if (!is_zfs(device->type)) {
434*12947SEnrico.Perla@Sun.COM 		if (write_out(device->fd, bblock->buf, bblock->buf_size,
435*12947SEnrico.Perla@Sun.COM 		    SECTOR_SIZE) != BC_SUCCESS) {
436*12947SEnrico.Perla@Sun.COM 			BOOT_DEBUG("Error writing bootblock to %s\n",
437*12947SEnrico.Perla@Sun.COM 			    device->path);
438*12947SEnrico.Perla@Sun.COM 			return (BC_ERROR);
439*12947SEnrico.Perla@Sun.COM 		} else {
440*12947SEnrico.Perla@Sun.COM 			return (BC_SUCCESS);
441*12947SEnrico.Perla@Sun.COM 		}
442*12947SEnrico.Perla@Sun.COM 	} else {
443*12947SEnrico.Perla@Sun.COM 		ret = write_zfs_bootblock(data);
444*12947SEnrico.Perla@Sun.COM 		return (ret);
445*12947SEnrico.Perla@Sun.COM 	}
446*12947SEnrico.Perla@Sun.COM }
447*12947SEnrico.Perla@Sun.COM 
448*12947SEnrico.Perla@Sun.COM static int
open_device(ib_device_t * device)449*12947SEnrico.Perla@Sun.COM open_device(ib_device_t *device)
450*12947SEnrico.Perla@Sun.COM {
451*12947SEnrico.Perla@Sun.COM 	struct stat	statbuf;
452*12947SEnrico.Perla@Sun.COM 
453*12947SEnrico.Perla@Sun.COM 	device->fd = open(device->path, O_RDWR);
454*12947SEnrico.Perla@Sun.COM 	if (device->fd == -1) {
455*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Unable to open %s\n", device->path);
456*12947SEnrico.Perla@Sun.COM 		perror("open");
457*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
458*12947SEnrico.Perla@Sun.COM 	}
459*12947SEnrico.Perla@Sun.COM 
460*12947SEnrico.Perla@Sun.COM 	if (fstat(device->fd, &statbuf) != 0) {
461*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Unable to stat %s\n", device->path);
462*12947SEnrico.Perla@Sun.COM 		perror("stat");
463*12947SEnrico.Perla@Sun.COM 		(void) close(device->fd);
464*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
465*12947SEnrico.Perla@Sun.COM 	}
466*12947SEnrico.Perla@Sun.COM 
467*12947SEnrico.Perla@Sun.COM 	if (S_ISCHR(statbuf.st_mode) == 0) {
468*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("%s: Not a character device\n"),
469*12947SEnrico.Perla@Sun.COM 		    device->path);
470*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
471*12947SEnrico.Perla@Sun.COM 	}
472*12947SEnrico.Perla@Sun.COM 
473*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
474*12947SEnrico.Perla@Sun.COM }
475*12947SEnrico.Perla@Sun.COM 
476*12947SEnrico.Perla@Sun.COM static int
init_device(ib_device_t * device,char * path)477*12947SEnrico.Perla@Sun.COM init_device(ib_device_t *device, char *path)
478*12947SEnrico.Perla@Sun.COM {
479*12947SEnrico.Perla@Sun.COM 	bzero(device, sizeof (*device));
480*12947SEnrico.Perla@Sun.COM 	device->fd = -1;
481*12947SEnrico.Perla@Sun.COM 
482*12947SEnrico.Perla@Sun.COM 	device->path = strdup(path);
483*12947SEnrico.Perla@Sun.COM 	if (path == NULL) {
484*12947SEnrico.Perla@Sun.COM 		perror(gettext("Memory allocation failure"));
485*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
486*12947SEnrico.Perla@Sun.COM 	}
487*12947SEnrico.Perla@Sun.COM 
488*12947SEnrico.Perla@Sun.COM 	device->type = tgt_fs_type;
489*12947SEnrico.Perla@Sun.COM 	if (open_device(device) != BC_SUCCESS)
490*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
491*12947SEnrico.Perla@Sun.COM 
492*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
493*12947SEnrico.Perla@Sun.COM }
494*12947SEnrico.Perla@Sun.COM 
495*12947SEnrico.Perla@Sun.COM static void
cleanup_device(ib_device_t * device)496*12947SEnrico.Perla@Sun.COM cleanup_device(ib_device_t *device)
497*12947SEnrico.Perla@Sun.COM {
498*12947SEnrico.Perla@Sun.COM 	free(device->path);
499*12947SEnrico.Perla@Sun.COM 	bzero(device, sizeof (*device));
500*12947SEnrico.Perla@Sun.COM 
501*12947SEnrico.Perla@Sun.COM 	if (device->fd != -1)
502*12947SEnrico.Perla@Sun.COM 		(void) close(device->fd);
503*12947SEnrico.Perla@Sun.COM }
504*12947SEnrico.Perla@Sun.COM 
505*12947SEnrico.Perla@Sun.COM static void
cleanup_bootblock(ib_bootblock_t * bblock)506*12947SEnrico.Perla@Sun.COM cleanup_bootblock(ib_bootblock_t *bblock)
507*12947SEnrico.Perla@Sun.COM {
508*12947SEnrico.Perla@Sun.COM 	free(bblock->buf);
509*12947SEnrico.Perla@Sun.COM 	bzero(bblock, sizeof (ib_bootblock_t));
510*12947SEnrico.Perla@Sun.COM }
511*12947SEnrico.Perla@Sun.COM 
512*12947SEnrico.Perla@Sun.COM /*
513*12947SEnrico.Perla@Sun.COM  * Propagate the bootblock on the source disk to the destination disk and
514*12947SEnrico.Perla@Sun.COM  * version it with 'updt_str' in the process. Since we cannot trust any data
515*12947SEnrico.Perla@Sun.COM  * on the attaching disk, we do not perform any specific check on a potential
516*12947SEnrico.Perla@Sun.COM  * target extended information structure and we just blindly update.
517*12947SEnrico.Perla@Sun.COM  */
518*12947SEnrico.Perla@Sun.COM static int
propagate_bootblock(ib_data_t * src,ib_data_t * dest,char * updt_str)519*12947SEnrico.Perla@Sun.COM propagate_bootblock(ib_data_t *src, ib_data_t *dest, char *updt_str)
520*12947SEnrico.Perla@Sun.COM {
521*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	*src_bblock = &src->bootblock;
522*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	*dest_bblock = &dest->bootblock;
523*12947SEnrico.Perla@Sun.COM 	uint32_t	buf_size;
524*12947SEnrico.Perla@Sun.COM 
525*12947SEnrico.Perla@Sun.COM 	assert(src != NULL);
526*12947SEnrico.Perla@Sun.COM 	assert(dest != NULL);
527*12947SEnrico.Perla@Sun.COM 
528*12947SEnrico.Perla@Sun.COM 	cleanup_bootblock(dest_bblock);
529*12947SEnrico.Perla@Sun.COM 
530*12947SEnrico.Perla@Sun.COM 	if (updt_str != NULL) {
531*12947SEnrico.Perla@Sun.COM 		do_version = B_TRUE;
532*12947SEnrico.Perla@Sun.COM 	} else {
533*12947SEnrico.Perla@Sun.COM 		do_version = B_FALSE;
534*12947SEnrico.Perla@Sun.COM 	}
535*12947SEnrico.Perla@Sun.COM 
536*12947SEnrico.Perla@Sun.COM 	buf_size = src_bblock->file_size + SECTOR_SIZE;
537*12947SEnrico.Perla@Sun.COM 
538*12947SEnrico.Perla@Sun.COM 	dest_bblock->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE);
539*12947SEnrico.Perla@Sun.COM 	dest_bblock->buf = malloc(dest_bblock->buf_size);
540*12947SEnrico.Perla@Sun.COM 	if (dest_bblock->buf == NULL) {
541*12947SEnrico.Perla@Sun.COM 		perror(gettext("Memory Allocation Failure"));
542*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
543*12947SEnrico.Perla@Sun.COM 	}
544*12947SEnrico.Perla@Sun.COM 	dest_bblock->file = dest_bblock->buf;
545*12947SEnrico.Perla@Sun.COM 	dest_bblock->file_size = src_bblock->file_size;
546*12947SEnrico.Perla@Sun.COM 	(void) memcpy(dest_bblock->file, src_bblock->file,
547*12947SEnrico.Perla@Sun.COM 	    dest_bblock->file_size);
548*12947SEnrico.Perla@Sun.COM 
549*12947SEnrico.Perla@Sun.COM 	dest_bblock->mboot = (multiboot_header_t *)(dest_bblock->file +
550*12947SEnrico.Perla@Sun.COM 	    P2ROUNDUP(dest_bblock->file_size, 8));
551*12947SEnrico.Perla@Sun.COM 	dest_bblock->extra = (char *)dest_bblock->mboot +
552*12947SEnrico.Perla@Sun.COM 	    sizeof (multiboot_header_t);
553*12947SEnrico.Perla@Sun.COM 
554*12947SEnrico.Perla@Sun.COM 	(void) fprintf(stdout, gettext("Propagating %s bootblock to %s\n"),
555*12947SEnrico.Perla@Sun.COM 	    src->device.path, dest->device.path);
556*12947SEnrico.Perla@Sun.COM 
557*12947SEnrico.Perla@Sun.COM 	return (commit_to_disk(dest, updt_str));
558*12947SEnrico.Perla@Sun.COM }
559*12947SEnrico.Perla@Sun.COM 
560*12947SEnrico.Perla@Sun.COM static int
commit_to_disk(ib_data_t * data,char * update_str)561*12947SEnrico.Perla@Sun.COM commit_to_disk(ib_data_t *data, char *update_str)
562*12947SEnrico.Perla@Sun.COM {
563*12947SEnrico.Perla@Sun.COM 	assert(data != NULL);
564*12947SEnrico.Perla@Sun.COM 
565*12947SEnrico.Perla@Sun.COM 	if (prepare_bootblock(data, update_str) != BC_SUCCESS) {
566*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error updating the bootblock "
567*12947SEnrico.Perla@Sun.COM 		    "image\n"));
568*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
569*12947SEnrico.Perla@Sun.COM 	}
570*12947SEnrico.Perla@Sun.COM 
571*12947SEnrico.Perla@Sun.COM 	if (write_bootblock(data) != BC_SUCCESS) {
572*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error writing bootblock to "
573*12947SEnrico.Perla@Sun.COM 		    "disk\n"));
574*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
575*12947SEnrico.Perla@Sun.COM 	}
576*12947SEnrico.Perla@Sun.COM 
577*12947SEnrico.Perla@Sun.COM 	return (BC_SUCCESS);
578*12947SEnrico.Perla@Sun.COM }
579*12947SEnrico.Perla@Sun.COM 
580*12947SEnrico.Perla@Sun.COM 
581*12947SEnrico.Perla@Sun.COM /*
582*12947SEnrico.Perla@Sun.COM  * Install a new bootblock on the given device. handle_install() expects argv
583*12947SEnrico.Perla@Sun.COM  * to contain 2 parameters (the target device path and the path to the
584*12947SEnrico.Perla@Sun.COM  * bootblock.
585*12947SEnrico.Perla@Sun.COM  *
586*12947SEnrico.Perla@Sun.COM  * Returns:	BC_SUCCESS - if the installation is successful
587*12947SEnrico.Perla@Sun.COM  *		BC_ERROR   - if the installation failed
588*12947SEnrico.Perla@Sun.COM  *		BC_NOUPDT  - if no installation was performed because the
589*12947SEnrico.Perla@Sun.COM  *		             version currently installed is more recent than the
590*12947SEnrico.Perla@Sun.COM  *			     supplied one.
591*12947SEnrico.Perla@Sun.COM  *
592*12947SEnrico.Perla@Sun.COM  */
593*12947SEnrico.Perla@Sun.COM static int
handle_install(char * progname,char ** argv)594*12947SEnrico.Perla@Sun.COM handle_install(char *progname, char **argv)
595*12947SEnrico.Perla@Sun.COM {
596*12947SEnrico.Perla@Sun.COM 	ib_data_t	install_data;
597*12947SEnrico.Perla@Sun.COM 	char		*bootblock = NULL;
598*12947SEnrico.Perla@Sun.COM 	char		*device_path = NULL;
599*12947SEnrico.Perla@Sun.COM 	int		ret = BC_ERROR;
600*12947SEnrico.Perla@Sun.COM 
601*12947SEnrico.Perla@Sun.COM 	bootblock = strdup(argv[0]);
602*12947SEnrico.Perla@Sun.COM 	device_path = strdup(argv[1]);
603*12947SEnrico.Perla@Sun.COM 
604*12947SEnrico.Perla@Sun.COM 	if (!device_path || !bootblock) {
605*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Missing parameter"));
606*12947SEnrico.Perla@Sun.COM 		usage(progname);
607*12947SEnrico.Perla@Sun.COM 		goto out;
608*12947SEnrico.Perla@Sun.COM 	}
609*12947SEnrico.Perla@Sun.COM 
610*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("device path: %s, bootblock file path: %s\n", device_path,
611*12947SEnrico.Perla@Sun.COM 	    bootblock);
612*12947SEnrico.Perla@Sun.COM 	bzero(&install_data, sizeof (ib_data_t));
613*12947SEnrico.Perla@Sun.COM 
614*12947SEnrico.Perla@Sun.COM 	if (init_device(&install_data.device, device_path) != BC_SUCCESS) {
615*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Unable to open device %s\n"),
616*12947SEnrico.Perla@Sun.COM 		    device_path);
617*12947SEnrico.Perla@Sun.COM 		goto out;
618*12947SEnrico.Perla@Sun.COM 	}
619*12947SEnrico.Perla@Sun.COM 
620*12947SEnrico.Perla@Sun.COM 	if (read_bootblock_from_file(bootblock, &install_data) != BC_SUCCESS) {
621*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error reading %s\n"),
622*12947SEnrico.Perla@Sun.COM 		    bootblock);
623*12947SEnrico.Perla@Sun.COM 		goto out_dev;
624*12947SEnrico.Perla@Sun.COM 	}
625*12947SEnrico.Perla@Sun.COM 	/* Versioning is only supported for the ZFS bootblock. */
626*12947SEnrico.Perla@Sun.COM 	if (do_version && !is_zfs(install_data.device.type)) {
627*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Versioning is only supported on"
628*12947SEnrico.Perla@Sun.COM 		    " ZFS... skipping.\n"));
629*12947SEnrico.Perla@Sun.COM 		do_version = B_FALSE;
630*12947SEnrico.Perla@Sun.COM 	}
631*12947SEnrico.Perla@Sun.COM 
632*12947SEnrico.Perla@Sun.COM 	/*
633*12947SEnrico.Perla@Sun.COM 	 * is_update_necessary() will take care of checking if versioning and/or
634*12947SEnrico.Perla@Sun.COM 	 * forcing the update have been specified. It will also emit a warning
635*12947SEnrico.Perla@Sun.COM 	 * if a non-versioned update is attempted over a versioned bootblock.
636*12947SEnrico.Perla@Sun.COM 	 */
637*12947SEnrico.Perla@Sun.COM 	if (!is_update_necessary(&install_data, update_str)) {
638*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("bootblock version installed "
639*12947SEnrico.Perla@Sun.COM 		    "on %s is more recent or identical\n"
640*12947SEnrico.Perla@Sun.COM 		    "Use -F to override or install without the -u option\n"),
641*12947SEnrico.Perla@Sun.COM 		    device_path);
642*12947SEnrico.Perla@Sun.COM 		ret = BC_NOUPDT;
643*12947SEnrico.Perla@Sun.COM 		goto out_dev;
644*12947SEnrico.Perla@Sun.COM 	}
645*12947SEnrico.Perla@Sun.COM 
646*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("Ready to commit to disk\n");
647*12947SEnrico.Perla@Sun.COM 	ret = commit_to_disk(&install_data, update_str);
648*12947SEnrico.Perla@Sun.COM 
649*12947SEnrico.Perla@Sun.COM out_dev:
650*12947SEnrico.Perla@Sun.COM 	cleanup_device(&install_data.device);
651*12947SEnrico.Perla@Sun.COM out:
652*12947SEnrico.Perla@Sun.COM 	free(bootblock);
653*12947SEnrico.Perla@Sun.COM 	free(device_path);
654*12947SEnrico.Perla@Sun.COM 	return (ret);
655*12947SEnrico.Perla@Sun.COM }
656*12947SEnrico.Perla@Sun.COM 
657*12947SEnrico.Perla@Sun.COM /*
658*12947SEnrico.Perla@Sun.COM  * Retrieves from a device the extended information (einfo) associated to the
659*12947SEnrico.Perla@Sun.COM  * installed bootblock.
660*12947SEnrico.Perla@Sun.COM  * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0.
661*12947SEnrico.Perla@Sun.COM  * Returns:
662*12947SEnrico.Perla@Sun.COM  *        - BC_SUCCESS (and prints out einfo contents depending on 'flags')
663*12947SEnrico.Perla@Sun.COM  *	  - BC_ERROR (on error)
664*12947SEnrico.Perla@Sun.COM  *        - BC_NOEINFO (no extended information available)
665*12947SEnrico.Perla@Sun.COM  */
666*12947SEnrico.Perla@Sun.COM static int
handle_getinfo(char * progname,char ** argv)667*12947SEnrico.Perla@Sun.COM handle_getinfo(char *progname, char **argv)
668*12947SEnrico.Perla@Sun.COM {
669*12947SEnrico.Perla@Sun.COM 
670*12947SEnrico.Perla@Sun.COM 	ib_data_t	data;
671*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	*bblock = &data.bootblock;
672*12947SEnrico.Perla@Sun.COM 	ib_device_t	*device = &data.device;
673*12947SEnrico.Perla@Sun.COM 	bblk_einfo_t	*einfo;
674*12947SEnrico.Perla@Sun.COM 	uint8_t		flags = 0;
675*12947SEnrico.Perla@Sun.COM 	uint32_t	size;
676*12947SEnrico.Perla@Sun.COM 	char		*device_path;
677*12947SEnrico.Perla@Sun.COM 	int		retval = BC_ERROR;
678*12947SEnrico.Perla@Sun.COM 	int		ret;
679*12947SEnrico.Perla@Sun.COM 
680*12947SEnrico.Perla@Sun.COM 	device_path = strdup(argv[0]);
681*12947SEnrico.Perla@Sun.COM 	if (!device_path) {
682*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Missing parameter"));
683*12947SEnrico.Perla@Sun.COM 		usage(progname);
684*12947SEnrico.Perla@Sun.COM 		goto out;
685*12947SEnrico.Perla@Sun.COM 	}
686*12947SEnrico.Perla@Sun.COM 
687*12947SEnrico.Perla@Sun.COM 	bzero(&data, sizeof (ib_data_t));
688*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("device path: %s\n", device_path);
689*12947SEnrico.Perla@Sun.COM 
690*12947SEnrico.Perla@Sun.COM 	if (init_device(device, device_path) != BC_SUCCESS) {
691*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Unable to gather device "
692*12947SEnrico.Perla@Sun.COM 		    "information from %s\n"), device_path);
693*12947SEnrico.Perla@Sun.COM 		goto out_dev;
694*12947SEnrico.Perla@Sun.COM 	}
695*12947SEnrico.Perla@Sun.COM 
696*12947SEnrico.Perla@Sun.COM 	if (!is_zfs(device->type)) {
697*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Versioning only supported on "
698*12947SEnrico.Perla@Sun.COM 		    "ZFS\n"));
699*12947SEnrico.Perla@Sun.COM 		goto out_dev;
700*12947SEnrico.Perla@Sun.COM 	}
701*12947SEnrico.Perla@Sun.COM 
702*12947SEnrico.Perla@Sun.COM 	ret = read_bootblock_from_disk(device->fd, bblock);
703*12947SEnrico.Perla@Sun.COM 	if (ret == BC_ERROR) {
704*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Error reading bootblock from "
705*12947SEnrico.Perla@Sun.COM 		    "%s\n"), device_path);
706*12947SEnrico.Perla@Sun.COM 		goto out_dev;
707*12947SEnrico.Perla@Sun.COM 	}
708*12947SEnrico.Perla@Sun.COM 
709*12947SEnrico.Perla@Sun.COM 	if (ret == BC_NOEXTRA) {
710*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("No multiboot header found on %s, unable "
711*12947SEnrico.Perla@Sun.COM 		    "to locate extra information area (old/non versioned "
712*12947SEnrico.Perla@Sun.COM 		    "bootblock?) \n", device_path);
713*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("No extended information "
714*12947SEnrico.Perla@Sun.COM 		    "found\n"));
715*12947SEnrico.Perla@Sun.COM 		retval = BC_NOEINFO;
716*12947SEnrico.Perla@Sun.COM 		goto out_dev;
717*12947SEnrico.Perla@Sun.COM 	}
718*12947SEnrico.Perla@Sun.COM 
719*12947SEnrico.Perla@Sun.COM 	einfo = find_einfo(bblock->extra);
720*12947SEnrico.Perla@Sun.COM 	if (einfo == NULL) {
721*12947SEnrico.Perla@Sun.COM 		retval = BC_NOEINFO;
722*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("No extended information "
723*12947SEnrico.Perla@Sun.COM 		    "found\n"));
724*12947SEnrico.Perla@Sun.COM 		goto out_dev;
725*12947SEnrico.Perla@Sun.COM 	}
726*12947SEnrico.Perla@Sun.COM 
727*12947SEnrico.Perla@Sun.COM 	/* Print the extended information. */
728*12947SEnrico.Perla@Sun.COM 	if (strip)
729*12947SEnrico.Perla@Sun.COM 		flags |= EINFO_EASY_PARSE;
730*12947SEnrico.Perla@Sun.COM 	if (verbose_dump)
731*12947SEnrico.Perla@Sun.COM 		flags |= EINFO_PRINT_HEADER;
732*12947SEnrico.Perla@Sun.COM 
733*12947SEnrico.Perla@Sun.COM 	size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8) -
734*12947SEnrico.Perla@Sun.COM 	    sizeof (multiboot_header_t);
735*12947SEnrico.Perla@Sun.COM 	print_einfo(flags, einfo, size);
736*12947SEnrico.Perla@Sun.COM 	retval = BC_SUCCESS;
737*12947SEnrico.Perla@Sun.COM 
738*12947SEnrico.Perla@Sun.COM out_dev:
739*12947SEnrico.Perla@Sun.COM 	cleanup_device(&data.device);
740*12947SEnrico.Perla@Sun.COM out:
741*12947SEnrico.Perla@Sun.COM 	free(device_path);
742*12947SEnrico.Perla@Sun.COM 	return (retval);
743*12947SEnrico.Perla@Sun.COM 
744*12947SEnrico.Perla@Sun.COM }
745*12947SEnrico.Perla@Sun.COM 
746*12947SEnrico.Perla@Sun.COM /*
747*12947SEnrico.Perla@Sun.COM  * Attempt to mirror (propagate) the current bootblock over the attaching disk.
748*12947SEnrico.Perla@Sun.COM  *
749*12947SEnrico.Perla@Sun.COM  * Returns:
750*12947SEnrico.Perla@Sun.COM  *	- BC_SUCCESS (a successful propagation happened)
751*12947SEnrico.Perla@Sun.COM  *	- BC_ERROR (an error occurred)
752*12947SEnrico.Perla@Sun.COM  *	- BC_NOEXTRA (it is not possible to dump the current bootblock since
753*12947SEnrico.Perla@Sun.COM  *			there is no multiboot information)
754*12947SEnrico.Perla@Sun.COM  */
755*12947SEnrico.Perla@Sun.COM static int
handle_mirror(char * progname,char ** argv)756*12947SEnrico.Perla@Sun.COM handle_mirror(char *progname, char **argv)
757*12947SEnrico.Perla@Sun.COM {
758*12947SEnrico.Perla@Sun.COM 	ib_data_t	curr_data;
759*12947SEnrico.Perla@Sun.COM 	ib_data_t	attach_data;
760*12947SEnrico.Perla@Sun.COM 	ib_device_t	*curr_device = &curr_data.device;
761*12947SEnrico.Perla@Sun.COM 	ib_device_t	*attach_device = &attach_data.device;
762*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	*bblock_curr = &curr_data.bootblock;
763*12947SEnrico.Perla@Sun.COM 	ib_bootblock_t	*bblock_attach = &attach_data.bootblock;
764*12947SEnrico.Perla@Sun.COM 	bblk_einfo_t	*einfo_curr = NULL;
765*12947SEnrico.Perla@Sun.COM 	char		*curr_device_path;
766*12947SEnrico.Perla@Sun.COM 	char		*attach_device_path;
767*12947SEnrico.Perla@Sun.COM 	char		*updt_str = NULL;
768*12947SEnrico.Perla@Sun.COM 	int		retval = BC_ERROR;
769*12947SEnrico.Perla@Sun.COM 	int		ret;
770*12947SEnrico.Perla@Sun.COM 
771*12947SEnrico.Perla@Sun.COM 	curr_device_path = strdup(argv[0]);
772*12947SEnrico.Perla@Sun.COM 	attach_device_path = strdup(argv[1]);
773*12947SEnrico.Perla@Sun.COM 
774*12947SEnrico.Perla@Sun.COM 	if (!curr_device_path || !attach_device_path) {
775*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Missing parameter"));
776*12947SEnrico.Perla@Sun.COM 		usage(progname);
777*12947SEnrico.Perla@Sun.COM 		goto out;
778*12947SEnrico.Perla@Sun.COM 	}
779*12947SEnrico.Perla@Sun.COM 	BOOT_DEBUG("Current device path is: %s, attaching device path is: "
780*12947SEnrico.Perla@Sun.COM 	    " %s\n", curr_device_path, attach_device_path);
781*12947SEnrico.Perla@Sun.COM 
782*12947SEnrico.Perla@Sun.COM 	bzero(&curr_data, sizeof (ib_data_t));
783*12947SEnrico.Perla@Sun.COM 	bzero(&attach_data, sizeof (ib_data_t));
784*12947SEnrico.Perla@Sun.COM 
785*12947SEnrico.Perla@Sun.COM 	if (tgt_fs_type != TARGET_IS_ZFS) {
786*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Mirroring is only supported on "
787*12947SEnrico.Perla@Sun.COM 		    "ZFS\n"));
788*12947SEnrico.Perla@Sun.COM 		return (BC_ERROR);
789*12947SEnrico.Perla@Sun.COM 	}
790*12947SEnrico.Perla@Sun.COM 
791*12947SEnrico.Perla@Sun.COM 	if (init_device(curr_device, curr_device_path) != BC_SUCCESS) {
792*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Unable to gather device "
793*12947SEnrico.Perla@Sun.COM 		    "information from %s (current device)\n"),
794*12947SEnrico.Perla@Sun.COM 		    curr_device_path);
795*12947SEnrico.Perla@Sun.COM 		goto out_currdev;
796*12947SEnrico.Perla@Sun.COM 	}
797*12947SEnrico.Perla@Sun.COM 
798*12947SEnrico.Perla@Sun.COM 	if (init_device(attach_device, attach_device_path) != BC_SUCCESS) {
799*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Unable to gather device "
800*12947SEnrico.Perla@Sun.COM 		    "information from %s (attaching device)\n"),
801*12947SEnrico.Perla@Sun.COM 		    attach_device_path);
802*12947SEnrico.Perla@Sun.COM 		goto out_devs;
803*12947SEnrico.Perla@Sun.COM 	}
804*12947SEnrico.Perla@Sun.COM 
805*12947SEnrico.Perla@Sun.COM 	ret = read_bootblock_from_disk(curr_device->fd, bblock_curr);
806*12947SEnrico.Perla@Sun.COM 	if (ret == BC_ERROR) {
807*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("Error reading bootblock from %s\n",
808*12947SEnrico.Perla@Sun.COM 		    curr_device->path);
809*12947SEnrico.Perla@Sun.COM 		retval = BC_ERROR;
810*12947SEnrico.Perla@Sun.COM 		goto out_devs;
811*12947SEnrico.Perla@Sun.COM 	}
812*12947SEnrico.Perla@Sun.COM 
813*12947SEnrico.Perla@Sun.COM 	if (ret == BC_NOEXTRA) {
814*12947SEnrico.Perla@Sun.COM 		BOOT_DEBUG("No multiboot header found on %s, unable to retrieve"
815*12947SEnrico.Perla@Sun.COM 		    " the bootblock\n", curr_device->path);
816*12947SEnrico.Perla@Sun.COM 		retval = BC_NOEXTRA;
817*12947SEnrico.Perla@Sun.COM 		goto out_devs;
818*12947SEnrico.Perla@Sun.COM 	}
819*12947SEnrico.Perla@Sun.COM 
820*12947SEnrico.Perla@Sun.COM 	einfo_curr = find_einfo(bblock_curr->extra);
821*12947SEnrico.Perla@Sun.COM 	if (einfo_curr != NULL)
822*12947SEnrico.Perla@Sun.COM 		updt_str = einfo_get_string(einfo_curr);
823*12947SEnrico.Perla@Sun.COM 
824*12947SEnrico.Perla@Sun.COM 	retval = propagate_bootblock(&curr_data, &attach_data, updt_str);
825*12947SEnrico.Perla@Sun.COM 	cleanup_bootblock(bblock_curr);
826*12947SEnrico.Perla@Sun.COM 	cleanup_bootblock(bblock_attach);
827*12947SEnrico.Perla@Sun.COM out_devs:
828*12947SEnrico.Perla@Sun.COM 	cleanup_device(attach_device);
829*12947SEnrico.Perla@Sun.COM out_currdev:
830*12947SEnrico.Perla@Sun.COM 	cleanup_device(curr_device);
831*12947SEnrico.Perla@Sun.COM out:
832*12947SEnrico.Perla@Sun.COM 	free(curr_device_path);
833*12947SEnrico.Perla@Sun.COM 	free(attach_device_path);
834*12947SEnrico.Perla@Sun.COM 	return (retval);
835*12947SEnrico.Perla@Sun.COM }
836*12947SEnrico.Perla@Sun.COM 
837*12947SEnrico.Perla@Sun.COM #define	USAGE_STRING	"Usage: %s [-h|-f|-F fstype|-u verstr] bootblk "       \
838*12947SEnrico.Perla@Sun.COM 			"raw-device\n"					       \
839*12947SEnrico.Perla@Sun.COM 			"\t%s [-e|-V] -i -F zfs raw-device\n"	               \
840*12947SEnrico.Perla@Sun.COM 			"\t%s -M -F zfs raw-device attach-raw-device\n"        \
841*12947SEnrico.Perla@Sun.COM 			"\tfstype is one of: 'ufs', 'hsfs' or 'zfs'\n"
842*12947SEnrico.Perla@Sun.COM 
843*12947SEnrico.Perla@Sun.COM #define	CANON_USAGE_STR	gettext(USAGE_STRING)
844*12947SEnrico.Perla@Sun.COM 
845*12947SEnrico.Perla@Sun.COM static void
usage(char * progname)846*12947SEnrico.Perla@Sun.COM usage(char *progname)
847*12947SEnrico.Perla@Sun.COM {
848*12947SEnrico.Perla@Sun.COM 	(void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
849*12947SEnrico.Perla@Sun.COM }
850*12947SEnrico.Perla@Sun.COM 
851*12947SEnrico.Perla@Sun.COM int
main(int argc,char ** argv)852*12947SEnrico.Perla@Sun.COM main(int argc, char **argv)
853*12947SEnrico.Perla@Sun.COM {
854*12947SEnrico.Perla@Sun.COM 	int	opt;
855*12947SEnrico.Perla@Sun.COM 	int	params = 2;
856*12947SEnrico.Perla@Sun.COM 	int	ret;
857*12947SEnrico.Perla@Sun.COM 	char	*progname;
858*12947SEnrico.Perla@Sun.COM 	char	**handle_args;
859*12947SEnrico.Perla@Sun.COM 
860*12947SEnrico.Perla@Sun.COM 	(void) setlocale(LC_ALL, "");
861*12947SEnrico.Perla@Sun.COM 	(void) textdomain(TEXT_DOMAIN);
862*12947SEnrico.Perla@Sun.COM 
863*12947SEnrico.Perla@Sun.COM 	while ((opt = getopt(argc, argv, "F:efiVMndhu:")) != EOF) {
864*12947SEnrico.Perla@Sun.COM 		switch (opt) {
865*12947SEnrico.Perla@Sun.COM 		case 'F':
866*12947SEnrico.Perla@Sun.COM 			if (strcmp(optarg, "ufs") == 0) {
867*12947SEnrico.Perla@Sun.COM 				tgt_fs_type = TARGET_IS_UFS;
868*12947SEnrico.Perla@Sun.COM 			} else if (strcmp(optarg, "hsfs") == 0) {
869*12947SEnrico.Perla@Sun.COM 				tgt_fs_type = TARGET_IS_HSFS;
870*12947SEnrico.Perla@Sun.COM 			} else if (strcmp(optarg, "zfs") == 0) {
871*12947SEnrico.Perla@Sun.COM 				tgt_fs_type = TARGET_IS_ZFS;
872*12947SEnrico.Perla@Sun.COM 			} else {
873*12947SEnrico.Perla@Sun.COM 				(void) fprintf(stderr, gettext("Wrong "
874*12947SEnrico.Perla@Sun.COM 				    "filesystem specified\n\n"));
875*12947SEnrico.Perla@Sun.COM 				usage(argv[0]);
876*12947SEnrico.Perla@Sun.COM 				exit(BC_ERROR);
877*12947SEnrico.Perla@Sun.COM 			}
878*12947SEnrico.Perla@Sun.COM 			break;
879*12947SEnrico.Perla@Sun.COM 		case 'e':
880*12947SEnrico.Perla@Sun.COM 			strip = B_TRUE;
881*12947SEnrico.Perla@Sun.COM 			break;
882*12947SEnrico.Perla@Sun.COM 		case 'f':
883*12947SEnrico.Perla@Sun.COM 			force_update = B_TRUE;
884*12947SEnrico.Perla@Sun.COM 			break;
885*12947SEnrico.Perla@Sun.COM 		case 'V':
886*12947SEnrico.Perla@Sun.COM 			verbose_dump = B_TRUE;
887*12947SEnrico.Perla@Sun.COM 			break;
888*12947SEnrico.Perla@Sun.COM 		case 'i':
889*12947SEnrico.Perla@Sun.COM 			do_getinfo = B_TRUE;
890*12947SEnrico.Perla@Sun.COM 			params = 1;
891*12947SEnrico.Perla@Sun.COM 			break;
892*12947SEnrico.Perla@Sun.COM 		case 'u':
893*12947SEnrico.Perla@Sun.COM 			do_version = B_TRUE;
894*12947SEnrico.Perla@Sun.COM 
895*12947SEnrico.Perla@Sun.COM 			update_str = malloc(strlen(optarg) + 1);
896*12947SEnrico.Perla@Sun.COM 			if (update_str == NULL) {
897*12947SEnrico.Perla@Sun.COM 				perror(gettext("Memory allocation failure"));
898*12947SEnrico.Perla@Sun.COM 				exit(BC_ERROR);
899*12947SEnrico.Perla@Sun.COM 			}
900*12947SEnrico.Perla@Sun.COM 			(void) strlcpy(update_str, optarg, strlen(optarg) + 1);
901*12947SEnrico.Perla@Sun.COM 			break;
902*12947SEnrico.Perla@Sun.COM 		case 'M':
903*12947SEnrico.Perla@Sun.COM 			do_mirror_bblk = B_TRUE;
904*12947SEnrico.Perla@Sun.COM 			break;
905*12947SEnrico.Perla@Sun.COM 		case 'h':
906*12947SEnrico.Perla@Sun.COM 			usage(argv[0]);
907*12947SEnrico.Perla@Sun.COM 			exit(BC_SUCCESS);
908*12947SEnrico.Perla@Sun.COM 			break;
909*12947SEnrico.Perla@Sun.COM 		case 'd':
910*12947SEnrico.Perla@Sun.COM 			boot_debug = B_TRUE;
911*12947SEnrico.Perla@Sun.COM 			break;
912*12947SEnrico.Perla@Sun.COM 		case 'n':
913*12947SEnrico.Perla@Sun.COM 			nowrite = B_TRUE;
914*12947SEnrico.Perla@Sun.COM 			break;
915*12947SEnrico.Perla@Sun.COM 		default:
916*12947SEnrico.Perla@Sun.COM 			/* fall through to process non-optional args */
917*12947SEnrico.Perla@Sun.COM 			break;
918*12947SEnrico.Perla@Sun.COM 		}
919*12947SEnrico.Perla@Sun.COM 	}
920*12947SEnrico.Perla@Sun.COM 
921*12947SEnrico.Perla@Sun.COM 	/* check arguments */
922*12947SEnrico.Perla@Sun.COM 	if (argc != optind + params) {
923*12947SEnrico.Perla@Sun.COM 		usage(argv[0]);
924*12947SEnrico.Perla@Sun.COM 		exit(BC_ERROR);
925*12947SEnrico.Perla@Sun.COM 	}
926*12947SEnrico.Perla@Sun.COM 	progname = argv[0];
927*12947SEnrico.Perla@Sun.COM 	handle_args = argv + optind;
928*12947SEnrico.Perla@Sun.COM 
929*12947SEnrico.Perla@Sun.COM 	/* check options. */
930*12947SEnrico.Perla@Sun.COM 	if (do_getinfo && do_mirror_bblk) {
931*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stderr, gettext("Only one of -M and -i can be "
932*12947SEnrico.Perla@Sun.COM 		    "specified at the same time\n"));
933*12947SEnrico.Perla@Sun.COM 		usage(progname);
934*12947SEnrico.Perla@Sun.COM 		exit(BC_ERROR);
935*12947SEnrico.Perla@Sun.COM 	}
936*12947SEnrico.Perla@Sun.COM 
937*12947SEnrico.Perla@Sun.COM 	if (nowrite)
938*12947SEnrico.Perla@Sun.COM 		(void) fprintf(stdout, gettext("Dry run requested. Nothing will"
939*12947SEnrico.Perla@Sun.COM 		    " be written to disk.\n"));
940*12947SEnrico.Perla@Sun.COM 
941*12947SEnrico.Perla@Sun.COM 	if (do_getinfo) {
942*12947SEnrico.Perla@Sun.COM 		ret = handle_getinfo(progname, handle_args);
943*12947SEnrico.Perla@Sun.COM 	} else if (do_mirror_bblk) {
944*12947SEnrico.Perla@Sun.COM 		ret = handle_mirror(progname, handle_args);
945*12947SEnrico.Perla@Sun.COM 	} else {
946*12947SEnrico.Perla@Sun.COM 		ret = handle_install(progname, handle_args);
947*12947SEnrico.Perla@Sun.COM 	}
948*12947SEnrico.Perla@Sun.COM 	return (ret);
949*12947SEnrico.Perla@Sun.COM }
950