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]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2015 Toomas Soome <tsoome@me.com>
26 * Copyright 2015 Gary Mills
27 * Copyright (c) 2015 by Delphix. All rights reserved.
28 * Copyright 2017 Jason King
29 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
44 #include <sys/types.h>
45 #include <sys/debug.h>
46 #include <libcmdutils.h>
50 #define _(x) gettext(x)
53 #define TEXT_DOMAIN "SYS_TEST"
56 #define DT_BUF_LEN (128)
58 CTASSERT(DT_BUF_LEN
>= NN_NUMBUF_SZ
);
60 static int be_do_activate(int argc
, char **argv
);
61 static int be_do_create(int argc
, char **argv
);
62 static int be_do_destroy(int argc
, char **argv
);
63 static int be_do_list(int argc
, char **argv
);
64 static int be_do_mount(int argc
, char **argv
);
65 static int be_do_unmount(int argc
, char **argv
);
66 static int be_do_rename(int argc
, char **argv
);
67 static int be_do_rollback(int argc
, char **argv
);
68 static void usage(void);
71 * single column name/width output format description
79 * all columns output format
82 struct col_info cols
[NUM_COLS
];
86 * type of possible output formats
96 * command handler description
98 typedef struct be_command
{
100 int (*func
)(int argc
, char **argv
);
104 * sorted list of be commands
106 static const be_command_t be_command_tbl
[] = {
107 { "activate", be_do_activate
},
108 { "create", be_do_create
},
109 { "destroy", be_do_destroy
},
110 { "list", be_do_list
},
111 { "mount", be_do_mount
},
112 { "unmount", be_do_unmount
},
113 { "umount", be_do_unmount
}, /* unmount alias */
114 { "rename", be_do_rename
},
115 { "rollback", be_do_rollback
},
122 (void) fprintf(stderr
, _("usage:\n"
123 "\tbeadm subcommand cmd_options\n"
127 "\tbeadm activate [-v] beName\n"
128 "\tbeadm create [-a] [-d BE_desc]\n"
129 "\t\t[-o property=value] ... [-p zpool] \n"
130 "\t\t[-e nonActiveBe | beName@snapshot] [-v] beName\n"
131 "\tbeadm create [-d BE_desc]\n"
132 "\t\t[-o property=value] ... [-p zpool] [-v] beName@snapshot\n"
133 "\tbeadm destroy [-fsv] beName \n"
134 "\tbeadm destroy [-v] beName@snapshot \n"
135 "\tbeadm list [[-a] | [-d] [-s]] [-H]\n"
136 "\t\t[-k|-K date | name | space] [-v] [beName]\n"
137 "\tbeadm mount [-s ro|rw] [-v] beName [mountpoint]\n"
138 "\tbeadm unmount [-fv] beName | mountpoint\n"
139 "\tbeadm umount [-fv] beName | mountpoint\n"
140 "\tbeadm rename [-v] origBeName newBeName\n"
141 "\tbeadm rollback [-v] beName snapshot\n"
142 "\tbeadm rollback [-v] beName@snapshot\n"));
146 run_be_cmd(const char *cmdname
, int argc
, char **argv
)
148 const be_command_t
*command
;
150 for (command
= &be_command_tbl
[0]; command
->name
!= NULL
; command
++)
151 if (strcmp(command
->name
, cmdname
) == 0)
152 return (command
->func(argc
, argv
));
154 (void) fprintf(stderr
, _("Invalid command: %s\n"), cmdname
);
160 main(int argc
, char **argv
)
164 (void) setlocale(LC_ALL
, "");
165 (void) textdomain(TEXT_DOMAIN
);
169 return (be_do_list(1, &arg
));
174 /* Turn error printing off */
175 libbe_print_errors(B_FALSE
);
177 return (run_be_cmd(cmdname
, --argc
, ++argv
));
181 print_hdr(struct hdr_info
*hdr_info
)
183 boolean_t first
= B_TRUE
;
185 for (i
= 0; i
< NUM_COLS
; i
++) {
186 struct col_info
*col_info
= &hdr_info
->cols
[i
];
187 const char *name
= col_info
->col_name
;
188 size_t width
= col_info
->width
;
193 (void) printf("%-*s", width
, name
);
196 (void) printf(" %-*s", width
, name
);
198 (void) putchar('\n');
202 init_hdr_cols(enum be_fmt be_fmt
, struct hdr_info
*hdr
)
204 struct col_info
*col
= hdr
->cols
;
207 col
[1].col_name
= _("Active");
208 col
[2].col_name
= _("Mountpoint");
209 col
[3].col_name
= _("Space");
210 col
[4].col_name
= _("Policy");
211 col
[5].col_name
= _("Created");
212 col
[6].col_name
= NULL
;
216 col
[0].col_name
= _("BE/Dataset/Snapshot");
219 col
[0].col_name
= _("BE/Dataset");
221 case BE_FMT_SNAPSHOT
:
222 col
[0].col_name
= _("BE/Snapshot");
223 col
[1].col_name
= NULL
;
224 col
[2].col_name
= NULL
;
228 col
[0].col_name
= _("BE");
231 for (i
= 0; i
< NUM_COLS
; i
++) {
232 const char *name
= col
[i
].col_name
;
237 size_t sz
= mbstowcs(wname
, name
, sizeof (wname
) /
240 int wcsw
= wcswidth(wname
, sz
);
246 col
[i
].width
= strlen(name
);
253 count_widths(enum be_fmt be_fmt
, struct hdr_info
*hdr
, be_node_list_t
*be_nodes
)
255 size_t len
[NUM_COLS
];
256 char buf
[DT_BUF_LEN
];
258 be_node_list_t
*cur_be
;
260 for (i
= 0; i
< NUM_COLS
; i
++)
261 len
[i
] = hdr
->cols
[i
].width
;
263 for (cur_be
= be_nodes
; cur_be
!= NULL
; cur_be
= cur_be
->be_next_node
) {
264 char name
[ZFS_MAX_DATASET_NAME_LEN
+ 1];
265 const char *be_name
= cur_be
->be_node_name
;
266 const char *root_ds
= cur_be
->be_root_ds
;
268 size_t node_name_len
= strlen(cur_be
->be_node_name
);
269 size_t root_ds_len
= strlen(cur_be
->be_root_ds
);
270 size_t mntpt_len
= 0;
271 size_t policy_len
= 0;
273 uint64_t used
= cur_be
->be_space_used
;
274 be_snapshot_list_t
*snap
= NULL
;
276 if (cur_be
->be_mntpt
!= NULL
)
277 mntpt_len
= strlen(cur_be
->be_mntpt
);
278 if (cur_be
->be_policy_type
!= NULL
)
279 policy_len
= strlen(cur_be
->be_policy_type
);
281 (void) strlcpy(name
, root_ds
, sizeof (name
));
282 pos
= strstr(name
, be_name
);
284 if (be_fmt
== BE_FMT_DEFAULT
) {
285 if (node_name_len
> len
[0])
286 len
[0] = node_name_len
;
288 if (root_ds_len
+ 3 > len
[0])
289 len
[0] = root_ds_len
+ 3;
292 if (mntpt_len
> len
[2])
294 if (policy_len
> len
[4])
297 for (snap
= cur_be
->be_node_snapshots
; snap
!= NULL
;
298 snap
= snap
->be_next_snapshot
) {
299 uint64_t snap_used
= snap
->be_snapshot_space_used
;
300 const char *snap_name
= snap
->be_snapshot_name
;
301 (void) strcpy(pos
, snap_name
);
303 if (be_fmt
== BE_FMT_DEFAULT
)
305 else if (be_fmt
& BE_FMT_SNAPSHOT
) {
306 int snap_len
= strlen(name
) + 3;
307 if (be_fmt
== BE_FMT_SNAPSHOT
)
308 snap_len
-= pos
- name
;
309 if (snap_len
> len
[0])
311 nicenum(snap_used
, buf
, sizeof (buf
));
312 used_len
= strlen(buf
);
313 if (used_len
> len
[3])
318 if (be_fmt
== BE_FMT_DEFAULT
) {
320 nicenum(used
, buf
, sizeof (buf
));
321 used_len
= strlen(buf
);
322 if (used_len
> len
[3])
326 nicenum(used
, buf
, sizeof (buf
));
329 for (i
= 0; i
< NUM_COLS
; i
++)
330 hdr
->cols
[i
].width
= len
[i
];
334 print_be_nodes(const char *be_name
, boolean_t parsable
, struct hdr_info
*hdr
,
335 be_node_list_t
*nodes
)
338 char datetime
[DT_BUF_LEN
];
339 be_node_list_t
*cur_be
;
341 for (cur_be
= nodes
; cur_be
!= NULL
; cur_be
= cur_be
->be_next_node
) {
342 char active
[3] = "-\0";
344 const char *datetime_fmt
= "%F %R";
345 const char *name
= cur_be
->be_node_name
;
346 const char *mntpt
= cur_be
->be_mntpt
;
347 const char *uuid_str
= cur_be
->be_uuid_str
;
348 be_snapshot_list_t
*snap
= NULL
;
349 uint64_t used
= cur_be
->be_space_used
;
350 time_t creation
= cur_be
->be_node_creation
;
353 if (be_name
!= NULL
&& strcmp(be_name
, name
) != 0)
359 tm
= localtime(&creation
);
360 (void) strftime(datetime
, DT_BUF_LEN
, datetime_fmt
, tm
);
362 for (snap
= cur_be
->be_node_snapshots
; snap
!= NULL
;
363 snap
= snap
->be_next_snapshot
)
364 used
+= snap
->be_snapshot_space_used
;
366 if (!cur_be
->be_global_active
)
369 if (cur_be
->be_active
)
371 if (cur_be
->be_active_on_boot
) {
372 if (!cur_be
->be_global_active
)
378 nicenum(used
, buf
, sizeof (buf
));
380 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
382 (uuid_str
!= NULL
? uuid_str
: ""),
384 (cur_be
->be_mounted
? mntpt
: ""),
386 cur_be
->be_policy_type
,
389 (void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n",
390 hdr
->cols
[0].width
, name
,
391 hdr
->cols
[1].width
, active
,
392 hdr
->cols
[2].width
, (cur_be
->be_mounted
? mntpt
:
394 hdr
->cols
[3].width
, buf
,
395 hdr
->cols
[4].width
, cur_be
->be_policy_type
,
396 hdr
->cols
[5].width
, datetime
);
401 print_be_snapshots(be_node_list_t
*be
, struct hdr_info
*hdr
, boolean_t parsable
)
404 char datetime
[DT_BUF_LEN
];
405 be_snapshot_list_t
*snap
= NULL
;
407 for (snap
= be
->be_node_snapshots
; snap
!= NULL
;
408 snap
= snap
->be_next_snapshot
) {
409 char name
[ZFS_MAX_DATASET_NAME_LEN
+ 1];
410 const char *datetime_fmt
= "%F %R";
411 const char *be_name
= be
->be_node_name
;
412 const char *root_ds
= be
->be_root_ds
;
413 const char *snap_name
= snap
->be_snapshot_name
;
415 uint64_t used
= snap
->be_snapshot_space_used
;
416 time_t creation
= snap
->be_snapshot_creation
;
417 struct tm
*tm
= localtime(&creation
);
419 (void) strncpy(name
, root_ds
, sizeof (name
));
420 pos
= strstr(name
, be_name
);
421 (void) strcpy(pos
, snap_name
);
423 (void) strftime(datetime
, DT_BUF_LEN
, datetime_fmt
, tm
);
424 nicenum(used
, buf
, sizeof (buf
));
427 if (hdr
->cols
[1].width
!= 0)
428 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
437 (void) printf("%s;%s;%llu;%s;%ld\n",
444 if (hdr
->cols
[1].width
!= 0)
445 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
447 hdr
->cols
[0].width
-3, name
,
448 hdr
->cols
[1].width
, "-",
449 hdr
->cols
[2].width
, "-",
450 hdr
->cols
[3].width
, buf
,
451 hdr
->cols
[4].width
, be
->be_policy_type
,
452 hdr
->cols
[5].width
, datetime
);
454 (void) printf(" %-*s %-*s %-*s %-*s\n",
455 hdr
->cols
[0].width
-3, snap_name
,
456 hdr
->cols
[3].width
, buf
,
457 hdr
->cols
[4].width
, be
->be_policy_type
,
458 hdr
->cols
[5].width
, datetime
);
463 print_fmt_nodes(const char *be_name
, enum be_fmt be_fmt
, boolean_t parsable
,
464 struct hdr_info
*hdr
, be_node_list_t
*nodes
)
467 char datetime
[DT_BUF_LEN
];
468 be_node_list_t
*cur_be
;
470 for (cur_be
= nodes
; cur_be
!= NULL
; cur_be
= cur_be
->be_next_node
) {
471 char active
[3] = "-\0";
473 const char *datetime_fmt
= "%F %R";
474 const char *name
= cur_be
->be_node_name
;
475 const char *mntpt
= cur_be
->be_mntpt
;
476 uint64_t used
= cur_be
->be_space_used
;
477 time_t creation
= cur_be
->be_node_creation
;
480 if (be_name
!= NULL
&& strcmp(be_name
, name
) != 0)
484 (void) printf("%-s\n", name
);
488 tm
= localtime(&creation
);
489 (void) strftime(datetime
, DT_BUF_LEN
, datetime_fmt
, tm
);
491 if (cur_be
->be_active
)
493 if (cur_be
->be_active_on_boot
)
496 nicenum(used
, buf
, sizeof (buf
));
497 if (be_fmt
& BE_FMT_DATASET
)
499 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
500 cur_be
->be_node_name
,
503 (cur_be
->be_mounted
? mntpt
: ""),
505 cur_be
->be_policy_type
,
508 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
510 hdr
->cols
[0].width
-3, cur_be
->be_root_ds
,
511 hdr
->cols
[1].width
, active
,
512 hdr
->cols
[2].width
, (cur_be
->be_mounted
?
514 hdr
->cols
[3].width
, buf
,
515 hdr
->cols
[4].width
, cur_be
->be_policy_type
,
516 hdr
->cols
[5].width
, datetime
);
518 if (be_fmt
& BE_FMT_SNAPSHOT
)
519 print_be_snapshots(cur_be
, hdr
, parsable
);
524 print_nodes(const char *be_name
, boolean_t dsets
, boolean_t snaps
,
525 boolean_t parsable
, be_node_list_t
*be_nodes
)
528 enum be_fmt be_fmt
= BE_FMT_DEFAULT
;
531 be_fmt
|= BE_FMT_DATASET
;
533 be_fmt
|= BE_FMT_SNAPSHOT
;
536 init_hdr_cols(be_fmt
, &hdr
);
537 count_widths(be_fmt
, &hdr
, be_nodes
);
541 if (be_fmt
== BE_FMT_DEFAULT
)
542 print_be_nodes(be_name
, parsable
, &hdr
, be_nodes
);
544 print_fmt_nodes(be_name
, be_fmt
, parsable
, &hdr
, be_nodes
);
548 be_nvl_alloc(nvlist_t
**nvlp
)
550 assert(nvlp
!= NULL
);
552 if (nvlist_alloc(nvlp
, NV_UNIQUE_NAME
, 0) != 0) {
553 (void) perror(_("nvlist_alloc failed.\n"));
561 be_nvl_add_string(nvlist_t
*nvl
, const char *name
, const char *val
)
565 if (nvlist_add_string(nvl
, name
, val
) != 0) {
566 (void) fprintf(stderr
, _("nvlist_add_string failed for "
567 "%s (%s).\n"), name
, val
);
575 be_nvl_add_nvlist(nvlist_t
*nvl
, const char *name
, nvlist_t
*val
)
579 if (nvlist_add_nvlist(nvl
, name
, val
) != 0) {
580 (void) fprintf(stderr
, _("nvlist_add_nvlist failed for %s.\n"),
589 be_nvl_add_uint16(nvlist_t
*nvl
, const char *name
, uint16_t val
)
593 if (nvlist_add_uint16(nvl
, name
, val
) != 0) {
594 (void) fprintf(stderr
, _("nvlist_add_uint16 failed for "
595 "%s (%hu).\n"), name
, val
);
603 be_do_activate(int argc
, char **argv
)
610 while ((c
= getopt(argc
, argv
, "v")) != -1) {
613 libbe_print_errors(B_TRUE
);
631 if (be_nvl_alloc(&be_attrs
) != 0)
634 if (be_nvl_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, obe_name
) != 0)
637 err
= be_activate(be_attrs
);
641 (void) printf(_("Activated successfully\n"));
643 case BE_ERR_BE_NOENT
:
644 (void) fprintf(stderr
, _("%s does not exist or appear "
645 "to be a valid BE.\nPlease check that the name of "
646 "the BE provided is correct.\n"), obe_name
);
650 (void) fprintf(stderr
, _("Unable to activate %s.\n"), obe_name
);
651 (void) fprintf(stderr
, _("You have insufficient privileges to "
652 "execute this command.\n"));
654 case BE_ERR_ACTIVATE_CURR
:
656 (void) fprintf(stderr
, _("Unable to activate %s.\n"), obe_name
);
657 (void) fprintf(stderr
, "%s\n", be_err_to_str(err
));
661 nvlist_free(be_attrs
);
666 be_do_create(int argc
, char **argv
)
669 nvlist_t
*zfs_props
= NULL
;
670 boolean_t activate
= B_FALSE
;
671 boolean_t is_snap
= B_FALSE
;
674 char *obe_name
= NULL
;
675 char *snap_name
= NULL
;
676 char *nbe_zpool
= NULL
;
677 char *nbe_name
= NULL
;
678 char *nbe_desc
= NULL
;
679 char *propname
= NULL
;
680 char *propval
= NULL
;
683 while ((c
= getopt(argc
, argv
, "ad:e:io:p:v")) != -1) {
695 if (zfs_props
== NULL
&& be_nvl_alloc(&zfs_props
) != 0)
699 if ((propval
= strchr(propname
, '=')) == NULL
) {
700 (void) fprintf(stderr
, _("missing "
701 "'=' for -o option\n"));
706 if (nvlist_lookup_string(zfs_props
, propname
,
708 (void) fprintf(stderr
, _("property '%s' "
709 "specified multiple times\n"), propname
);
713 if (be_nvl_add_string(zfs_props
, propname
, propval
)
722 libbe_print_errors(B_TRUE
);
740 if ((snap_name
= strrchr(nbe_name
, '@')) != NULL
) {
741 if (snap_name
[1] == '\0') {
758 * Check if obe_name is really a snapshot name.
759 * If so, split it out.
761 if ((snap_name
= strrchr(obe_name
, '@')) != NULL
) {
762 if (snap_name
[1] == '\0') {
770 } else if (is_snap
) {
775 if (be_nvl_alloc(&be_attrs
) != 0)
779 if (zfs_props
!= NULL
&& be_nvl_add_nvlist(be_attrs
,
780 BE_ATTR_ORIG_BE_NAME
, zfs_props
) != 0)
783 if (obe_name
!= NULL
&& be_nvl_add_string(be_attrs
,
784 BE_ATTR_ORIG_BE_NAME
, obe_name
) != 0)
787 if (snap_name
!= NULL
&& be_nvl_add_string(be_attrs
,
788 BE_ATTR_SNAP_NAME
, snap_name
) != 0)
791 if (nbe_zpool
!= NULL
&& be_nvl_add_string(be_attrs
,
792 BE_ATTR_NEW_BE_POOL
, nbe_zpool
) != 0)
795 if (nbe_name
!= NULL
&& be_nvl_add_string(be_attrs
,
796 BE_ATTR_NEW_BE_NAME
, nbe_name
) != 0)
799 if (nbe_desc
!= NULL
&& be_nvl_add_string(be_attrs
,
800 BE_ATTR_NEW_BE_DESC
, nbe_desc
) != 0)
804 err
= be_create_snapshot(be_attrs
);
806 err
= be_copy(be_attrs
);
810 if (!is_snap
&& !nbe_name
) {
812 * We requested an auto named BE; find out the
813 * name of the BE that was created for us and
814 * the auto snapshot created from the original BE.
816 if (nvlist_lookup_string(be_attrs
, BE_ATTR_NEW_BE_NAME
,
818 (void) fprintf(stderr
, _("failed to get %s "
819 "attribute\n"), BE_ATTR_NEW_BE_NAME
);
822 (void) printf(_("Auto named BE: %s\n"),
825 if (nvlist_lookup_string(be_attrs
, BE_ATTR_SNAP_NAME
,
827 (void) fprintf(stderr
, _("failed to get %s "
828 "attribute\n"), BE_ATTR_SNAP_NAME
);
831 (void) printf(_("Auto named snapshot: %s\n"),
835 if (!is_snap
&& activate
) {
836 char *args
[] = { "activate", "", NULL
};
840 err
= be_do_activate(2, args
);
844 (void) printf(_("Created successfully\n"));
846 case BE_ERR_BE_EXISTS
:
847 (void) fprintf(stderr
, _("BE %s already exists\n."
848 "Please choose a different BE name.\n"), nbe_name
);
850 case BE_ERR_SS_EXISTS
:
851 (void) fprintf(stderr
, _("BE %s snapshot %s already exists.\n"
852 "Please choose a different snapshot name.\n"), obe_name
,
858 (void) fprintf(stderr
, _("Unable to create snapshot "
859 "%s.\n"), snap_name
);
861 (void) fprintf(stderr
, _("Unable to create %s.\n"),
863 (void) fprintf(stderr
, _("You have insufficient privileges to "
864 "execute this command.\n"));
868 (void) fprintf(stderr
, _("Unable to create snapshot "
869 "%s.\n"), snap_name
);
871 (void) fprintf(stderr
, _("Unable to create %s.\n"),
873 (void) fprintf(stderr
, "%s\n", be_err_to_str(err
));
877 nvlist_free(be_attrs
);
879 nvlist_free(zfs_props
);
885 be_do_destroy(int argc
, char **argv
)
888 boolean_t is_snap
= B_FALSE
;
891 int destroy_flags
= 0;
895 while ((c
= getopt(argc
, argv
, "fFsv")) != -1) {
898 destroy_flags
|= BE_DESTROY_FLAG_FORCE_UNMOUNT
;
903 destroy_flags
|= BE_DESTROY_FLAG_SNAPSHOTS
;
906 libbe_print_errors(B_TRUE
);
923 if ((snap_name
= strrchr(be_name
, '@')) != NULL
) {
924 if (snap_name
[1] == '\0') {
934 if (be_nvl_alloc(&be_attrs
) != 0)
938 if (be_nvl_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, be_name
) != 0)
942 if (be_nvl_add_string(be_attrs
, BE_ATTR_SNAP_NAME
,
946 err
= be_destroy_snapshot(be_attrs
);
948 if (be_nvl_add_uint16(be_attrs
, BE_ATTR_DESTROY_FLAGS
,
952 err
= be_destroy(be_attrs
);
959 (void) fprintf(stderr
, _("Unable to destroy %s.\n"), be_name
);
960 (void) fprintf(stderr
, _("It is currently mounted and must be "
961 "unmounted before it can be destroyed.\n" "Use 'beadm "
962 "unmount %s' to unmount the BE before destroying\nit or "
963 "'beadm destroy -f %s'.\n"), be_name
, be_name
);
965 case BE_ERR_DESTROY_CURR_BE
:
966 (void) fprintf(stderr
, _("%s is the currently active BE and "
967 "cannot be destroyed.\nYou must boot from another BE in "
968 "order to destroy %s.\n"), be_name
, be_name
);
970 case BE_ERR_ZONES_UNMOUNT
:
971 (void) fprintf(stderr
, _("Unable to destroy one of " "%s's "
972 "zone BE's.\nUse 'beadm destroy -f %s' or "
973 "'zfs -f destroy <dataset>'.\n"), be_name
, be_name
);
975 case BE_ERR_SS_NOENT
:
976 (void) fprintf(stderr
, _("%s does not exist or appear "
977 "to be a valid snapshot.\nPlease check that the name of "
978 "the snapshot provided is correct.\n"), snap_name
);
982 (void) fprintf(stderr
, _("Unable to destroy %s.\n"), be_name
);
983 (void) fprintf(stderr
, _("You have insufficient privileges to "
984 "execute this command.\n"));
986 case BE_ERR_SS_EXISTS
:
987 (void) fprintf(stderr
, _("Unable to destroy %s: "
988 "BE has snapshots.\nUse 'beadm destroy -s %s' or "
989 "'zfs -r destroy <dataset>'.\n"), be_name
, be_name
);
992 (void) fprintf(stderr
, _("Unable to destroy %s.\n"), be_name
);
993 (void) fprintf(stderr
, "%s\n", be_err_to_str(err
));
997 nvlist_free(be_attrs
);
1002 be_do_list(int argc
, char **argv
)
1004 be_node_list_t
*be_nodes
= NULL
;
1005 boolean_t all
= B_FALSE
;
1006 boolean_t dsets
= B_FALSE
;
1007 boolean_t snaps
= B_FALSE
;
1008 boolean_t parsable
= B_FALSE
;
1011 char *be_name
= NULL
;
1012 be_sort_t order
= BE_SORT_UNSPECIFIED
;
1014 while ((c
= getopt(argc
, argv
, "adk:svHK:")) != -1) {
1024 if (order
!= BE_SORT_UNSPECIFIED
) {
1025 (void) fprintf(stderr
, _("Sort key can be "
1026 "specified only once.\n"));
1030 if (strcmp(optarg
, "date") == 0) {
1032 order
= BE_SORT_DATE
;
1034 order
= BE_SORT_DATE_REV
;
1037 if (strcmp(optarg
, "name") == 0) {
1039 order
= BE_SORT_NAME
;
1041 order
= BE_SORT_NAME_REV
;
1044 if (strcmp(optarg
, "space") == 0) {
1046 order
= BE_SORT_SPACE
;
1048 order
= BE_SORT_SPACE_REV
;
1051 (void) fprintf(stderr
, _("Unknown sort key: %s\n"),
1059 libbe_print_errors(B_TRUE
);
1072 (void) fprintf(stderr
, _("Invalid options: -a and %s "
1073 "are mutually exclusive.\n"), "-d");
1078 (void) fprintf(stderr
, _("Invalid options: -a and %s "
1079 "are mutually exclusive.\n"), "-s");
1095 err
= be_list(be_name
, &be_nodes
,
1096 snaps
? BE_LIST_SNAPSHOTS
: BE_LIST_DEFAULT
);
1100 /* the default sort is ascending date, no need to sort twice */
1101 if (order
== BE_SORT_UNSPECIFIED
)
1102 order
= BE_SORT_DATE
;
1104 if (order
!= BE_SORT_DATE
) {
1105 err
= be_sort(&be_nodes
, order
);
1106 if (err
!= BE_SUCCESS
) {
1107 (void) fprintf(stderr
, _("Unable to sort Boot "
1109 (void) fprintf(stderr
, "%s\n",
1110 be_err_to_str(err
));
1115 print_nodes(be_name
, dsets
, snaps
, parsable
, be_nodes
);
1117 case BE_ERR_BE_NOENT
:
1118 if (be_name
== NULL
)
1119 (void) fprintf(stderr
, _("No boot environments found "
1120 "on this system.\n"));
1122 (void) fprintf(stderr
, _("%s does not exist or appear "
1123 "to be a valid BE.\nPlease check that the name of "
1124 "the BE provided is correct.\n"), be_name
);
1128 (void) fprintf(stderr
, _("Unable to display Boot "
1130 (void) fprintf(stderr
, "%s\n", be_err_to_str(err
));
1133 if (be_nodes
!= NULL
)
1134 be_free_list(be_nodes
);
1139 be_do_mount(int argc
, char **argv
)
1142 boolean_t shared_fs
= B_FALSE
;
1145 int mount_flags
= 0;
1148 char *tmp_mp
= NULL
;
1150 while ((c
= getopt(argc
, argv
, "s:v")) != -1) {
1155 mount_flags
|= BE_MOUNT_FLAG_SHARED_FS
;
1157 if (strcmp(optarg
, "rw") == 0) {
1158 mount_flags
|= BE_MOUNT_FLAG_SHARED_RW
;
1159 } else if (strcmp(optarg
, "ro") != 0) {
1160 (void) fprintf(stderr
, _("The -s flag "
1161 "requires an argument [ rw | ro ]\n"));
1168 libbe_print_errors(B_TRUE
);
1179 if (argc
< 1 || argc
> 2) {
1187 mountpoint
= argv
[1];
1188 if (mountpoint
[0] != '/') {
1189 (void) fprintf(stderr
, _("Invalid mount point %s. "
1190 "Mount point must start with a /.\n"), mountpoint
);
1194 const char *tmpdir
= getenv("TMPDIR");
1195 const char *tmpname
= "tmp.XXXXXX";
1201 sz
= asprintf(&tmp_mp
, "%s/%s", tmpdir
, tmpname
);
1203 (void) fprintf(stderr
, _("internal error: "
1204 "out of memory\n"));
1208 mountpoint
= mkdtemp(tmp_mp
);
1211 if (be_nvl_alloc(&be_attrs
) != 0)
1214 if (be_nvl_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, obe_name
) != 0)
1217 if (be_nvl_add_string(be_attrs
, BE_ATTR_MOUNTPOINT
, mountpoint
) != 0)
1220 if (shared_fs
&& be_nvl_add_uint16(be_attrs
, BE_ATTR_MOUNT_FLAGS
,
1224 err
= be_mount(be_attrs
);
1228 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint
);
1230 case BE_ERR_BE_NOENT
:
1231 (void) fprintf(stderr
, _("%s does not exist or appear "
1232 "to be a valid BE.\nPlease check that the name of "
1233 "the BE provided is correct.\n"), obe_name
);
1235 case BE_ERR_MOUNTED
:
1236 (void) fprintf(stderr
, _("%s is already mounted.\n"
1237 "Please unmount the BE before mounting it again.\n"),
1242 (void) fprintf(stderr
, _("Unable to mount %s.\n"), obe_name
);
1243 (void) fprintf(stderr
, _("You have insufficient privileges to "
1244 "execute this command.\n"));
1246 case BE_ERR_NO_MOUNTED_ZONE
:
1247 (void) fprintf(stderr
, _("Mounted on '%s'.\nUnable to mount "
1248 "one of %s's zone BE's.\n"), mountpoint
, obe_name
);
1251 (void) fprintf(stderr
, _("Unable to mount %s.\n"), obe_name
);
1252 (void) fprintf(stderr
, "%s\n", be_err_to_str(err
));
1257 nvlist_free(be_attrs
);
1262 be_do_unmount(int argc
, char **argv
)
1268 int unmount_flags
= 0;
1270 while ((c
= getopt(argc
, argv
, "fv")) != -1) {
1273 unmount_flags
|= BE_UNMOUNT_FLAG_FORCE
;
1276 libbe_print_errors(B_TRUE
);
1294 if (be_nvl_alloc(&be_attrs
) != 0)
1298 if (be_nvl_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, obe_name
) != 0)
1301 if (be_nvl_add_uint16(be_attrs
, BE_ATTR_UNMOUNT_FLAGS
,
1302 unmount_flags
) != 0)
1305 err
= be_unmount(be_attrs
);
1309 (void) printf(_("Unmounted successfully\n"));
1311 case BE_ERR_BE_NOENT
:
1312 (void) fprintf(stderr
, _("%s does not exist or appear "
1313 "to be a valid BE.\nPlease check that the name of "
1314 "the BE provided is correct.\n"), obe_name
);
1316 case BE_ERR_UMOUNT_CURR_BE
:
1317 (void) fprintf(stderr
, _("%s is the currently active BE.\n"
1318 "It cannot be unmounted unless another BE is the "
1319 "currently active BE.\n"), obe_name
);
1321 case BE_ERR_UMOUNT_SHARED
:
1322 (void) fprintf(stderr
, _("%s is a shared file system and it "
1323 "cannot be unmounted.\n"), obe_name
);
1327 (void) fprintf(stderr
, _("Unable to unmount %s.\n"), obe_name
);
1328 (void) fprintf(stderr
, _("You have insufficient privileges to "
1329 "execute this command.\n"));
1332 (void) fprintf(stderr
, _("Unable to unmount %s.\n"), obe_name
);
1333 (void) fprintf(stderr
, "%s\n", be_err_to_str(err
));
1337 nvlist_free(be_attrs
);
1342 be_do_rename(int argc
, char **argv
)
1350 while ((c
= getopt(argc
, argv
, "v")) != -1) {
1353 libbe_print_errors(B_TRUE
);
1372 if (be_nvl_alloc(&be_attrs
) != 0)
1375 if (be_nvl_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, obe_name
) != 0)
1378 if (be_nvl_add_string(be_attrs
, BE_ATTR_NEW_BE_NAME
, nbe_name
) != 0)
1381 err
= be_rename(be_attrs
);
1385 (void) printf(_("Renamed successfully\n"));
1387 case BE_ERR_BE_NOENT
:
1388 (void) fprintf(stderr
, _("%s does not exist or appear "
1389 "to be a valid BE.\nPlease check that the name of "
1390 "the BE provided is correct.\n"), obe_name
);
1394 (void) fprintf(stderr
, _("Rename of BE %s failed.\n"),
1396 (void) fprintf(stderr
, _("You have insufficient privileges to "
1397 "execute this command.\n"));
1400 (void) fprintf(stderr
, _("Rename of BE %s failed.\n"),
1402 (void) fprintf(stderr
, "%s\n", be_err_to_str(err
));
1406 nvlist_free(be_attrs
);
1411 be_do_rollback(int argc
, char **argv
)
1419 while ((c
= getopt(argc
, argv
, "v")) != -1) {
1422 libbe_print_errors(B_TRUE
);
1433 if (argc
< 1 || argc
> 2) {
1440 snap_name
= argv
[1];
1441 else { /* argc == 1 */
1442 if ((snap_name
= strrchr(obe_name
, '@')) != NULL
) {
1443 if (snap_name
[1] == '\0') {
1448 snap_name
[0] = '\0';
1456 if (be_nvl_alloc(&be_attrs
) != 0)
1459 if (be_nvl_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, obe_name
) != 0)
1462 if (be_nvl_add_string(be_attrs
, BE_ATTR_SNAP_NAME
, snap_name
) != 0)
1465 err
= be_rollback(be_attrs
);
1469 (void) printf(_("Rolled back successfully\n"));
1471 case BE_ERR_BE_NOENT
:
1472 (void) fprintf(stderr
, _("%s does not exist or appear "
1473 "to be a valid BE.\nPlease check that the name of "
1474 "the BE provided is correct.\n"), obe_name
);
1476 case BE_ERR_SS_NOENT
:
1477 (void) fprintf(stderr
, _("%s does not exist or appear "
1478 "to be a valid snapshot.\nPlease check that the name of "
1479 "the snapshot provided is correct.\n"), snap_name
);
1483 (void) fprintf(stderr
, _("Rollback of BE %s snapshot %s "
1484 "failed.\n"), obe_name
, snap_name
);
1485 (void) fprintf(stderr
, _("You have insufficient privileges to "
1486 "execute this command.\n"));
1489 (void) fprintf(stderr
, _("Rollback of BE %s snapshot %s "
1490 "failed.\n"), obe_name
, snap_name
);
1491 (void) fprintf(stderr
, "%s\n", be_err_to_str(err
));
1495 nvlist_free(be_attrs
);