4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
33 #include <sys/types.h>
35 #include <sys/multiboot.h>
36 #include <sys/sysmacros.h>
38 #include "installboot.h"
39 #include "../../common/bblk_einfo.h"
40 #include "../../common/boot_utils.h"
41 #include "../../common/mboot_extra.h"
44 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
48 * SPARC bootblock installation:
50 * The bootblock resides in blocks 1 to 15 (disk label is at block 0).
51 * The ZFS boot block is larger than what will fit into these first 7.5K so we
52 * break it up and write the remaining portion into the ZFS provided boot block
53 * region at offset 512K. If versioning is requested, we add a multiboot
54 * header at the end of the bootblock, followed by the extra payload area and
55 * place the extended information structure within the latter.
58 static boolean_t force_update
= B_FALSE
;
59 static boolean_t do_getinfo
= B_FALSE
;
60 static boolean_t do_version
= B_FALSE
;
61 static boolean_t do_mirror_bblk
= B_FALSE
;
62 static boolean_t strip
= B_FALSE
;
63 static boolean_t verbose_dump
= B_FALSE
;
65 static char *update_str
;
66 static int tgt_fs_type
= TARGET_IS_UFS
;
67 char mboot_scan
[MBOOT_SCAN_SIZE
];
69 /* Function prototypes. */
70 static int read_bootblock_from_file(char *, ib_data_t
*data
);
71 static int read_bootblock_from_disk(int, ib_bootblock_t
*);
72 static void add_bootblock_einfo(ib_bootblock_t
*, char *);
73 static int prepare_bootblock(ib_data_t
*, char *);
74 static int write_zfs_bootblock(ib_data_t
*);
75 static int write_bootblock(ib_data_t
*);
76 static int open_device(ib_device_t
*);
77 static int init_device(ib_device_t
*, char *);
78 static void cleanup_device(ib_device_t
*);
79 static int commit_to_disk(ib_data_t
*, char *);
80 static int handle_install(char *, char **);
81 static int handle_getinfo(char *, char **);
82 static int handle_mirror(char *, char **);
83 static boolean_t
is_update_necessary(ib_data_t
*, char *);
84 static int propagate_bootblock(ib_data_t
*, ib_data_t
*, char *);
85 static void usage(char *);
88 read_bootblock_from_file(char *file
, ib_data_t
*data
)
90 ib_device_t
*device
= &data
->device
;
91 ib_bootblock_t
*bblock
= &data
->bootblock
;
95 int retval
= BC_ERROR
;
100 fd
= open(file
, O_RDONLY
);
102 BOOT_DEBUG("Error opening %s\n", file
);
107 if (fstat(fd
, &sb
) == -1) {
108 BOOT_DEBUG("Error getting information (stat) about %s", file
);
113 bblock
->file_size
= sb
.st_size
;
114 BOOT_DEBUG("bootblock file size is %x\n", bblock
->file_size
);
116 /* UFS and HSFS bootblocks need to fit in the reserved 7.5K. */
117 if (!is_zfs(device
->type
)) {
118 buf_size
= P2ROUNDUP(bblock
->file_size
, SECTOR_SIZE
);
119 if (buf_size
> BBLK_DATA_RSVD_SIZE
) {
120 BOOT_DEBUG("boot block size is bigger than allowed\n");
124 buf_size
= P2ROUNDUP(bblock
->file_size
+ SECTOR_SIZE
,
126 if (buf_size
> BBLK_DATA_RSVD_SIZE
+ MBOOT_SCAN_SIZE
) {
127 (void) fprintf(stderr
, gettext("WARNING, bootblock size"
128 " does not allow to place extended versioning "
129 "information.. skipping\n"));
130 do_version
= B_FALSE
;
134 bblock
->buf_size
= buf_size
;
135 BOOT_DEBUG("bootblock in-memory buffer size is %x\n",
138 bblock
->buf
= malloc(buf_size
);
139 if (bblock
->buf
== NULL
) {
140 perror(gettext("Memory allocation failure"));
143 bblock
->file
= bblock
->buf
;
145 if (read(fd
, bblock
->file
, bblock
->file_size
) != bblock
->file_size
) {
146 BOOT_DEBUG("Read from %s failed\n", file
);
151 /* If not on ZFS, we are done here. */
152 if (!is_zfs(device
->type
)) {
153 BOOT_DEBUG("Reading of the bootblock done\n");
158 * We place the multiboot header right after the file, followed by
159 * the extended information structure.
161 bblock
->mboot
= (multiboot_header_t
*)(bblock
->file
+
162 P2ROUNDUP(bblock
->file_size
, 8));
163 bblock
->extra
= (char *)bblock
->mboot
+ sizeof (multiboot_header_t
);
164 BOOT_DEBUG("mboot at %p, extra at %p, buf=%p (size=%d)\n",
165 bblock
->mboot
, bblock
->extra
, bblock
->buf
, bblock
->buf_size
);
171 (void) free(bblock
->buf
);
180 read_bootblock_from_disk(int dev_fd
, ib_bootblock_t
*bblock
)
186 multiboot_header_t
*mboot
;
188 assert(bblock
!= NULL
);
189 assert(dev_fd
!= -1);
192 * The ZFS bootblock is divided in two parts, but the fake multiboot
193 * header can only be in the second part (the one contained in the ZFS
196 if (read_in(dev_fd
, mboot_scan
, sizeof (mboot_scan
),
197 BBLK_ZFS_EXTRA_OFF
) != BC_SUCCESS
) {
198 BOOT_DEBUG("Error reading ZFS reserved area\n");
203 /* No multiboot means no chance of knowing bootblock size */
204 if (find_multiboot(mboot_scan
, sizeof (mboot_scan
), &mboot_off
)
206 BOOT_DEBUG("Unable to find multiboot header\n");
209 mboot
= (multiboot_header_t
*)(mboot_scan
+ mboot_off
);
212 * Currently, the amount of space reserved for extra information
213 * is "fixed". We may have to scan for the terminating extra payload
216 size
= mboot
->load_end_addr
- mboot
->load_addr
;
217 buf_size
= P2ROUNDUP(size
+ SECTOR_SIZE
, SECTOR_SIZE
);
218 bblock
->file_size
= size
;
220 bblock
->buf
= malloc(buf_size
);
221 if (bblock
->buf
== NULL
) {
222 BOOT_DEBUG("Unable to allocate enough memory to read"
223 " the extra bootblock from the disk\n");
224 perror(gettext("Memory allocation failure"));
227 bblock
->buf_size
= buf_size
;
230 size
= BBLK_DATA_RSVD_SIZE
;
232 if (read_in(dev_fd
, dest
, size
, SECTOR_SIZE
) != BC_SUCCESS
) {
233 BOOT_DEBUG("Error reading first %d bytes of the bootblock\n",
235 (void) free(bblock
->buf
);
240 dest
+= BBLK_DATA_RSVD_SIZE
;
241 size
= bblock
->buf_size
- BBLK_DATA_RSVD_SIZE
;
243 if (read_in(dev_fd
, dest
, size
, BBLK_ZFS_EXTRA_OFF
) != BC_SUCCESS
) {
244 BOOT_DEBUG("Error reading ZFS reserved area the second time\n");
245 (void) free(bblock
->buf
);
250 /* Update pointers. */
251 bblock
->file
= bblock
->buf
;
252 bblock
->mboot_off
= mboot_off
;
253 bblock
->mboot
= (multiboot_header_t
*)(bblock
->buf
+ bblock
->mboot_off
254 + BBLK_DATA_RSVD_SIZE
);
255 bblock
->extra
= (char *)bblock
->mboot
+ sizeof (multiboot_header_t
);
256 bblock
->extra_size
= bblock
->buf_size
- bblock
->mboot_off
257 - BBLK_DATA_RSVD_SIZE
- sizeof (multiboot_header_t
);
262 is_update_necessary(ib_data_t
*data
, char *updt_str
)
266 ib_bootblock_t bblock_disk
;
267 ib_bootblock_t
*bblock_file
= &data
->bootblock
;
268 ib_device_t
*device
= &data
->device
;
269 int dev_fd
= device
->fd
;
271 assert(data
!= NULL
);
272 assert(device
->fd
!= -1);
274 /* Nothing to do if we are not updating a ZFS bootblock. */
275 if (!is_zfs(device
->type
))
278 bzero(&bblock_disk
, sizeof (ib_bootblock_t
));
280 if (read_bootblock_from_disk(dev_fd
, &bblock_disk
) != BC_SUCCESS
) {
281 BOOT_DEBUG("Unable to read bootblock from %s\n", device
->path
);
285 einfo
= find_einfo(bblock_disk
.extra
, bblock_disk
.extra_size
);
287 BOOT_DEBUG("No extended information available\n");
291 if (!do_version
|| updt_str
== NULL
) {
292 (void) fprintf(stdout
, "WARNING: target device %s has a "
293 "versioned bootblock that is going to be overwritten by a "
294 "non versioned one\n", device
->path
);
299 BOOT_DEBUG("Forcing update of %s bootblock\n", device
->path
);
303 BOOT_DEBUG("Ready to check installed version vs %s\n", updt_str
);
305 bblock_hs
.src_buf
= (unsigned char *)bblock_file
->file
;
306 bblock_hs
.src_size
= bblock_file
->file_size
;
308 return (einfo_should_update(einfo
, &bblock_hs
, updt_str
));
312 add_bootblock_einfo(ib_bootblock_t
*bblock
, char *updt_str
)
315 uint32_t avail_space
;
317 assert(bblock
!= NULL
);
319 if (updt_str
== NULL
) {
320 BOOT_DEBUG("WARNING: no update string passed to "
321 "add_bootblock_einfo()\n");
325 /* Fill bootblock hashing source information. */
326 hs
.src_buf
= (unsigned char *)bblock
->file
;
327 hs
.src_size
= bblock
->file_size
;
328 /* How much space for the extended information structure? */
329 avail_space
= bblock
->buf_size
- P2ROUNDUP(bblock
->file_size
, 8);
330 /* Place the extended information structure. */
331 add_einfo(bblock
->extra
, updt_str
, &hs
, avail_space
);
336 prepare_bootblock(ib_data_t
*data
, char *updt_str
)
338 ib_device_t
*device
= &data
->device
;
339 ib_bootblock_t
*bblock
= &data
->bootblock
;
340 multiboot_header_t
*mboot
;
342 assert(data
!= NULL
);
344 /* Nothing to do if we are not on ZFS. */
345 if (!is_zfs(device
->type
))
349 * Write the fake multiboot structure followed by the extra information
350 * data. Both mboot and extra pointers have already been filled up to
351 * point to the right location in the buffer. We prepare the fake
352 * multiboot regardless if versioning was requested or not because
353 * we need it for mirroring support.
355 assert(bblock
->mboot
!= NULL
);
356 assert(bblock
->extra
!= NULL
);
358 mboot
= bblock
->mboot
;
360 mboot
->magic
= MB_HEADER_MAGIC
;
361 mboot
->flags
= MB_HEADER_FLAGS_64
;
362 mboot
->checksum
= -(mboot
->flags
+ mboot
->magic
);
364 * Flags include the AOUT_KLUDGE and we use the extra members to specify
365 * the size of the bootblock.
367 mboot
->header_addr
= bblock
->mboot_off
;
368 mboot
->load_addr
= 0;
369 mboot
->load_end_addr
= bblock
->file_size
;
372 * Now that we have the mboot header in place, we can add the extended
373 * versioning information. Since the multiboot header has been placed
374 * after the file image, the hashing will still reflect the one of the
378 add_bootblock_einfo(bblock
, updt_str
);
384 write_zfs_bootblock(ib_data_t
*data
)
386 ib_device_t
*device
= &data
->device
;
387 ib_bootblock_t
*bblock
= &data
->bootblock
;
391 assert(data
!= NULL
);
392 assert(device
->fd
!= -1);
395 * In the ZFS case we actually perform two different steps:
396 * - write the first 15 blocks of the bootblock to the reserved disk
398 * - write the remaining blocks in the ZFS reserved area at offset
401 bufptr
= bblock
->buf
;
402 size
= BBLK_DATA_RSVD_SIZE
;
404 if (write_out(device
->fd
, bufptr
, size
, SECTOR_SIZE
) != BC_SUCCESS
) {
405 BOOT_DEBUG("Error writing first 15 blocks of %s\n",
411 bufptr
+= BBLK_DATA_RSVD_SIZE
;
412 size
= bblock
->buf_size
- BBLK_DATA_RSVD_SIZE
;
414 if (write_out(device
->fd
, bufptr
, size
, BBLK_ZFS_EXTRA_OFF
)
416 BOOT_DEBUG("Error writing the second part of ZFS bootblock "
417 "to %s at offset %d\n", device
->path
, BBLK_ZFS_EXTRA_OFF
);
424 write_bootblock(ib_data_t
*data
)
426 ib_device_t
*device
= &data
->device
;
427 ib_bootblock_t
*bblock
= &data
->bootblock
;
430 assert(data
!= NULL
);
433 * If we are on UFS or HSFS we simply write out to the reserved
434 * blocks (1 to 15) the boot block.
436 if (!is_zfs(device
->type
)) {
437 if (write_out(device
->fd
, bblock
->buf
, bblock
->buf_size
,
438 SECTOR_SIZE
) != BC_SUCCESS
) {
439 BOOT_DEBUG("Error writing bootblock to %s\n",
446 ret
= write_zfs_bootblock(data
);
452 open_device(ib_device_t
*device
)
456 device
->fd
= open(device
->path
, O_RDWR
);
457 if (device
->fd
== -1) {
458 BOOT_DEBUG("Unable to open %s\n", device
->path
);
463 if (fstat(device
->fd
, &statbuf
) != 0) {
464 BOOT_DEBUG("Unable to stat %s\n", device
->path
);
466 (void) close(device
->fd
);
470 if (S_ISCHR(statbuf
.st_mode
) == 0) {
471 (void) fprintf(stderr
, gettext("%s: Not a character device\n"),
480 init_device(ib_device_t
*device
, char *path
)
482 bzero(device
, sizeof (*device
));
485 device
->path
= strdup(path
);
487 perror(gettext("Memory allocation failure"));
491 device
->type
= tgt_fs_type
;
492 if (open_device(device
) != BC_SUCCESS
)
499 cleanup_device(ib_device_t
*device
)
502 bzero(device
, sizeof (*device
));
504 if (device
->fd
!= -1)
505 (void) close(device
->fd
);
509 cleanup_bootblock(ib_bootblock_t
*bblock
)
512 bzero(bblock
, sizeof (ib_bootblock_t
));
516 * Propagate the bootblock on the source disk to the destination disk and
517 * version it with 'updt_str' in the process. Since we cannot trust any data
518 * on the attaching disk, we do not perform any specific check on a potential
519 * target extended information structure and we just blindly update.
522 propagate_bootblock(ib_data_t
*src
, ib_data_t
*dest
, char *updt_str
)
524 ib_bootblock_t
*src_bblock
= &src
->bootblock
;
525 ib_bootblock_t
*dest_bblock
= &dest
->bootblock
;
529 assert(dest
!= NULL
);
531 cleanup_bootblock(dest_bblock
);
533 if (updt_str
!= NULL
) {
536 do_version
= B_FALSE
;
539 buf_size
= src_bblock
->file_size
+ SECTOR_SIZE
;
541 dest_bblock
->buf_size
= P2ROUNDUP(buf_size
, SECTOR_SIZE
);
542 dest_bblock
->buf
= malloc(dest_bblock
->buf_size
);
543 if (dest_bblock
->buf
== NULL
) {
544 perror(gettext("Memory Allocation Failure"));
547 dest_bblock
->file
= dest_bblock
->buf
;
548 dest_bblock
->file_size
= src_bblock
->file_size
;
549 (void) memcpy(dest_bblock
->file
, src_bblock
->file
,
550 dest_bblock
->file_size
);
552 dest_bblock
->mboot
= (multiboot_header_t
*)(dest_bblock
->file
+
553 P2ROUNDUP(dest_bblock
->file_size
, 8));
554 dest_bblock
->extra
= (char *)dest_bblock
->mboot
+
555 sizeof (multiboot_header_t
);
557 (void) fprintf(stdout
, gettext("Propagating %s bootblock to %s\n"),
558 src
->device
.path
, dest
->device
.path
);
560 return (commit_to_disk(dest
, updt_str
));
564 commit_to_disk(ib_data_t
*data
, char *update_str
)
566 assert(data
!= NULL
);
568 if (prepare_bootblock(data
, update_str
) != BC_SUCCESS
) {
569 (void) fprintf(stderr
, gettext("Error updating the bootblock "
574 if (write_bootblock(data
) != BC_SUCCESS
) {
575 (void) fprintf(stderr
, gettext("Error writing bootblock to "
585 * Install a new bootblock on the given device. handle_install() expects argv
586 * to contain 2 parameters (the target device path and the path to the
589 * Returns: BC_SUCCESS - if the installation is successful
590 * BC_ERROR - if the installation failed
591 * BC_NOUPDT - if no installation was performed because the
592 * version currently installed is more recent than the
597 handle_install(char *progname
, char **argv
)
599 ib_data_t install_data
;
600 char *bootblock
= NULL
;
601 char *device_path
= NULL
;
604 bootblock
= strdup(argv
[0]);
605 device_path
= strdup(argv
[1]);
607 if (!device_path
|| !bootblock
) {
608 (void) fprintf(stderr
, gettext("Missing parameter"));
613 BOOT_DEBUG("device path: %s, bootblock file path: %s\n", device_path
,
615 bzero(&install_data
, sizeof (ib_data_t
));
617 if (init_device(&install_data
.device
, device_path
) != BC_SUCCESS
) {
618 (void) fprintf(stderr
, gettext("Unable to open device %s\n"),
623 if (read_bootblock_from_file(bootblock
, &install_data
) != BC_SUCCESS
) {
624 (void) fprintf(stderr
, gettext("Error reading %s\n"),
628 /* Versioning is only supported for the ZFS bootblock. */
629 if (do_version
&& !is_zfs(install_data
.device
.type
)) {
630 (void) fprintf(stderr
, gettext("Versioning is only supported on"
631 " ZFS... skipping.\n"));
632 do_version
= B_FALSE
;
636 * is_update_necessary() will take care of checking if versioning and/or
637 * forcing the update have been specified. It will also emit a warning
638 * if a non-versioned update is attempted over a versioned bootblock.
640 if (!is_update_necessary(&install_data
, update_str
)) {
641 (void) fprintf(stderr
, gettext("bootblock version installed "
642 "on %s is more recent or identical\n"
643 "Use -F to override or install without the -u option\n"),
649 BOOT_DEBUG("Ready to commit to disk\n");
650 ret
= commit_to_disk(&install_data
, update_str
);
653 cleanup_device(&install_data
.device
);
661 * Retrieves from a device the extended information (einfo) associated to the
662 * installed bootblock.
663 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0.
665 * - BC_SUCCESS (and prints out einfo contents depending on 'flags')
666 * - BC_ERROR (on error)
667 * - BC_NOEINFO (no extended information available)
670 handle_getinfo(char *progname
, char **argv
)
674 ib_bootblock_t
*bblock
= &data
.bootblock
;
675 ib_device_t
*device
= &data
.device
;
680 int retval
= BC_ERROR
;
683 device_path
= strdup(argv
[0]);
685 (void) fprintf(stderr
, gettext("Missing parameter"));
690 bzero(&data
, sizeof (ib_data_t
));
691 BOOT_DEBUG("device path: %s\n", device_path
);
693 if (init_device(device
, device_path
) != BC_SUCCESS
) {
694 (void) fprintf(stderr
, gettext("Unable to gather device "
695 "information from %s\n"), device_path
);
699 if (!is_zfs(device
->type
)) {
700 (void) fprintf(stderr
, gettext("Versioning only supported on "
705 ret
= read_bootblock_from_disk(device
->fd
, bblock
);
706 if (ret
== BC_ERROR
) {
707 (void) fprintf(stderr
, gettext("Error reading bootblock from "
708 "%s\n"), device_path
);
712 if (ret
== BC_NOEXTRA
) {
713 BOOT_DEBUG("No multiboot header found on %s, unable "
714 "to locate extra information area (old/non versioned "
715 "bootblock?) \n", device_path
);
716 (void) fprintf(stderr
, gettext("No extended information "
722 einfo
= find_einfo(bblock
->extra
, bblock
->extra_size
);
725 (void) fprintf(stderr
, gettext("No extended information "
730 /* Print the extended information. */
732 flags
|= EINFO_EASY_PARSE
;
734 flags
|= EINFO_PRINT_HEADER
;
736 size
= bblock
->buf_size
- P2ROUNDUP(bblock
->file_size
, 8) -
737 sizeof (multiboot_header_t
);
738 print_einfo(flags
, einfo
, size
);
742 cleanup_device(&data
.device
);
750 * Attempt to mirror (propagate) the current bootblock over the attaching disk.
753 * - BC_SUCCESS (a successful propagation happened)
754 * - BC_ERROR (an error occurred)
755 * - BC_NOEXTRA (it is not possible to dump the current bootblock since
756 * there is no multiboot information)
759 handle_mirror(char *progname
, char **argv
)
762 ib_data_t attach_data
;
763 ib_device_t
*curr_device
= &curr_data
.device
;
764 ib_device_t
*attach_device
= &attach_data
.device
;
765 ib_bootblock_t
*bblock_curr
= &curr_data
.bootblock
;
766 ib_bootblock_t
*bblock_attach
= &attach_data
.bootblock
;
767 bblk_einfo_t
*einfo_curr
= NULL
;
768 char *curr_device_path
;
769 char *attach_device_path
;
770 char *updt_str
= NULL
;
771 int retval
= BC_ERROR
;
774 curr_device_path
= strdup(argv
[0]);
775 attach_device_path
= strdup(argv
[1]);
777 if (!curr_device_path
|| !attach_device_path
) {
778 (void) fprintf(stderr
, gettext("Missing parameter"));
782 BOOT_DEBUG("Current device path is: %s, attaching device path is: "
783 " %s\n", curr_device_path
, attach_device_path
);
785 bzero(&curr_data
, sizeof (ib_data_t
));
786 bzero(&attach_data
, sizeof (ib_data_t
));
788 if (tgt_fs_type
!= TARGET_IS_ZFS
) {
789 (void) fprintf(stderr
, gettext("Mirroring is only supported on "
794 if (init_device(curr_device
, curr_device_path
) != BC_SUCCESS
) {
795 (void) fprintf(stderr
, gettext("Unable to gather device "
796 "information from %s (current device)\n"),
801 if (init_device(attach_device
, attach_device_path
) != BC_SUCCESS
) {
802 (void) fprintf(stderr
, gettext("Unable to gather device "
803 "information from %s (attaching device)\n"),
808 ret
= read_bootblock_from_disk(curr_device
->fd
, bblock_curr
);
809 if (ret
== BC_ERROR
) {
810 BOOT_DEBUG("Error reading bootblock from %s\n",
816 if (ret
== BC_NOEXTRA
) {
817 BOOT_DEBUG("No multiboot header found on %s, unable to retrieve"
818 " the bootblock\n", curr_device
->path
);
823 einfo_curr
= find_einfo(bblock_curr
->extra
, bblock_curr
->extra_size
);
824 if (einfo_curr
!= NULL
)
825 updt_str
= einfo_get_string(einfo_curr
);
827 retval
= propagate_bootblock(&curr_data
, &attach_data
, updt_str
);
828 cleanup_bootblock(bblock_curr
);
829 cleanup_bootblock(bblock_attach
);
831 cleanup_device(attach_device
);
833 cleanup_device(curr_device
);
835 free(curr_device_path
);
836 free(attach_device_path
);
840 #define USAGE_STRING "Usage: %s [-h|-f|-F fstype|-u verstr] bootblk " \
842 "\t%s [-e|-V] -i -F zfs raw-device\n" \
843 "\t%s -M -F zfs raw-device attach-raw-device\n" \
844 "\tfstype is one of: 'ufs', 'hsfs' or 'zfs'\n"
846 #define CANON_USAGE_STR gettext(USAGE_STRING)
849 usage(char *progname
)
851 (void) fprintf(stdout
, CANON_USAGE_STR
, progname
, progname
, progname
);
855 main(int argc
, char **argv
)
863 (void) setlocale(LC_ALL
, "");
864 (void) textdomain(TEXT_DOMAIN
);
866 while ((opt
= getopt(argc
, argv
, "F:efiVMndhu:")) != EOF
) {
869 if (strcmp(optarg
, "ufs") == 0) {
870 tgt_fs_type
= TARGET_IS_UFS
;
871 } else if (strcmp(optarg
, "hsfs") == 0) {
872 tgt_fs_type
= TARGET_IS_HSFS
;
873 } else if (strcmp(optarg
, "zfs") == 0) {
874 tgt_fs_type
= TARGET_IS_ZFS
;
876 (void) fprintf(stderr
, gettext("Wrong "
877 "filesystem specified\n\n"));
886 force_update
= B_TRUE
;
889 verbose_dump
= B_TRUE
;
898 update_str
= malloc(strlen(optarg
) + 1);
899 if (update_str
== NULL
) {
900 perror(gettext("Memory allocation failure"));
903 (void) strlcpy(update_str
, optarg
, strlen(optarg
) + 1);
906 do_mirror_bblk
= B_TRUE
;
919 /* fall through to process non-optional args */
924 /* check arguments */
925 if (argc
!= optind
+ params
) {
930 handle_args
= argv
+ optind
;
933 if (do_getinfo
&& do_mirror_bblk
) {
934 (void) fprintf(stderr
, gettext("Only one of -M and -i can be "
935 "specified at the same time\n"));
941 (void) fprintf(stdout
, gettext("Dry run requested. Nothing will"
942 " be written to disk.\n"));
945 ret
= handle_getinfo(progname
, handle_args
);
946 } else if (do_mirror_bblk
) {
947 ret
= handle_mirror(progname
, handle_args
);
949 ret
= handle_install(progname
, handle_args
);