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