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