FEATURES: add notes about compilation env changes
[unleashed.git] / bin / beadm / beadm.c
blob2b6bc0ab07c9588b323e08c62c1fc24b86d0526a
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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.
33 * System includes
36 #include <assert.h>
37 #include <stdio.h>
38 #include <strings.h>
39 #include <libzfs.h>
40 #include <locale.h>
41 #include <langinfo.h>
42 #include <stdlib.h>
43 #include <wchar.h>
44 #include <sys/types.h>
45 #include <sys/debug.h>
46 #include <libcmdutils.h>
48 #include "libbe.h"
50 #define _(x) gettext(x)
52 #ifndef TEXT_DOMAIN
53 #define TEXT_DOMAIN "SYS_TEST"
54 #endif
56 #define DT_BUF_LEN (128)
57 #define NUM_COLS (6)
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
73 struct col_info {
74 const char *col_name;
75 size_t width;
79 * all columns output format
81 struct hdr_info {
82 struct col_info cols[NUM_COLS];
86 * type of possible output formats
88 enum be_fmt {
89 BE_FMT_DEFAULT,
90 BE_FMT_DATASET,
91 BE_FMT_SNAPSHOT,
92 BE_FMT_ALL
96 * command handler description
98 typedef struct be_command {
99 const char *name;
100 int (*func)(int argc, char **argv);
101 } be_command_t;
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 },
116 { NULL, NULL },
119 static void
120 usage(void)
122 (void) fprintf(stderr, _("usage:\n"
123 "\tbeadm subcommand cmd_options\n"
124 "\n"
125 "\tsubcommands:\n"
126 "\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"));
145 static int
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);
155 usage();
156 return (1);
160 main(int argc, char **argv)
162 const char *cmdname;
164 (void) setlocale(LC_ALL, "");
165 (void) textdomain(TEXT_DOMAIN);
167 if (argc < 2) {
168 char *arg = "list";
169 return (be_do_list(1, &arg));
172 cmdname = argv[1];
174 /* Turn error printing off */
175 libbe_print_errors(B_FALSE);
177 return (run_be_cmd(cmdname, --argc, ++argv));
180 static void
181 print_hdr(struct hdr_info *hdr_info)
183 boolean_t first = B_TRUE;
184 size_t i;
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;
189 if (name == NULL)
190 continue;
192 if (first) {
193 (void) printf("%-*s", width, name);
194 first = B_FALSE;
195 } else
196 (void) printf(" %-*s", width, name);
198 (void) putchar('\n');
201 static void
202 init_hdr_cols(enum be_fmt be_fmt, struct hdr_info *hdr)
204 struct col_info *col = hdr->cols;
205 size_t i;
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;
214 switch (be_fmt) {
215 case BE_FMT_ALL:
216 col[0].col_name = _("BE/Dataset/Snapshot");
217 break;
218 case BE_FMT_DATASET:
219 col[0].col_name = _("BE/Dataset");
220 break;
221 case BE_FMT_SNAPSHOT:
222 col[0].col_name = _("BE/Snapshot");
223 col[1].col_name = NULL;
224 col[2].col_name = NULL;
225 break;
226 case BE_FMT_DEFAULT:
227 default:
228 col[0].col_name = _("BE");
231 for (i = 0; i < NUM_COLS; i++) {
232 const char *name = col[i].col_name;
233 col[i].width = 0;
235 if (name != NULL) {
236 wchar_t wname[128];
237 size_t sz = mbstowcs(wname, name, sizeof (wname) /
238 sizeof (wchar_t));
239 if (sz > 0) {
240 int wcsw = wcswidth(wname, sz);
241 if (wcsw > 0)
242 col[i].width = wcsw;
243 else
244 col[i].width = sz;
245 } else {
246 col[i].width = strlen(name);
252 static void
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];
257 int i;
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;
267 char *pos;
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;
272 size_t used_len;
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;
287 } else {
288 if (root_ds_len + 3 > len[0])
289 len[0] = root_ds_len + 3;
292 if (mntpt_len > len[2])
293 len[2] = mntpt_len;
294 if (policy_len > len[4])
295 len[4] = policy_len;
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)
304 used += snap_used;
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])
310 len[0] = snap_len;
311 nicenum(snap_used, buf, sizeof (buf));
312 used_len = strlen(buf);
313 if (used_len > len[3])
314 len[3] = used_len;
318 if (be_fmt == BE_FMT_DEFAULT) {
319 int used_len;
320 nicenum(used, buf, sizeof (buf));
321 used_len = strlen(buf);
322 if (used_len > len[3])
323 len[3] = used_len;
326 nicenum(used, buf, sizeof (buf));
329 for (i = 0; i < NUM_COLS; i++)
330 hdr->cols[i].width = len[i];
333 static void
334 print_be_nodes(const char *be_name, boolean_t parsable, struct hdr_info *hdr,
335 be_node_list_t *nodes)
337 char buf[64];
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";
343 int ai = 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;
351 struct tm *tm;
353 if (be_name != NULL && strcmp(be_name, name) != 0)
354 continue;
356 if (parsable)
357 active[0] = '\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)
367 active[ai++] = 'x';
369 if (cur_be->be_active)
370 active[ai++] = 'N';
371 if (cur_be->be_active_on_boot) {
372 if (!cur_be->be_global_active)
373 active[ai] = 'b';
374 else
375 active[ai] = 'R';
378 nicenum(used, buf, sizeof (buf));
379 if (parsable)
380 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
381 name,
382 (uuid_str != NULL ? uuid_str: ""),
383 active,
384 (cur_be->be_mounted ? mntpt: ""),
385 used,
386 cur_be->be_policy_type,
387 creation);
388 else
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:
393 "-"),
394 hdr->cols[3].width, buf,
395 hdr->cols[4].width, cur_be->be_policy_type,
396 hdr->cols[5].width, datetime);
400 static void
401 print_be_snapshots(be_node_list_t *be, struct hdr_info *hdr, boolean_t parsable)
403 char buf[64];
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;
414 char *pos;
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));
426 if (parsable)
427 if (hdr->cols[1].width != 0)
428 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
429 be_name,
430 snap_name,
433 used,
434 be->be_policy_type,
435 creation);
436 else
437 (void) printf("%s;%s;%llu;%s;%ld\n",
438 be_name,
439 snap_name,
440 used,
441 be->be_policy_type,
442 creation);
443 else
444 if (hdr->cols[1].width != 0)
445 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
446 "%-*s\n",
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);
453 else
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);
462 static void
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)
466 char buf[64];
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";
472 int ai = 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;
478 struct tm *tm;
480 if (be_name != NULL && strcmp(be_name, name) != 0)
481 continue;
483 if (!parsable)
484 (void) printf("%-s\n", name);
485 else
486 active[0] = '\0';
488 tm = localtime(&creation);
489 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
491 if (cur_be->be_active)
492 active[ai++] = 'N';
493 if (cur_be->be_active_on_boot)
494 active[ai] = 'R';
496 nicenum(used, buf, sizeof (buf));
497 if (be_fmt & BE_FMT_DATASET)
498 if (parsable)
499 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
500 cur_be->be_node_name,
501 cur_be->be_root_ds,
502 active,
503 (cur_be->be_mounted ? mntpt: ""),
504 used,
505 cur_be->be_policy_type,
506 creation);
507 else
508 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
509 "%-*s\n",
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 ?
513 mntpt: "-"),
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);
523 static void
524 print_nodes(const char *be_name, boolean_t dsets, boolean_t snaps,
525 boolean_t parsable, be_node_list_t *be_nodes)
527 struct hdr_info hdr;
528 enum be_fmt be_fmt = BE_FMT_DEFAULT;
530 if (dsets)
531 be_fmt |= BE_FMT_DATASET;
532 if (snaps)
533 be_fmt |= BE_FMT_SNAPSHOT;
535 if (!parsable) {
536 init_hdr_cols(be_fmt, &hdr);
537 count_widths(be_fmt, &hdr, be_nodes);
538 print_hdr(&hdr);
541 if (be_fmt == BE_FMT_DEFAULT)
542 print_be_nodes(be_name, parsable, &hdr, be_nodes);
543 else
544 print_fmt_nodes(be_name, be_fmt, parsable, &hdr, be_nodes);
547 static int
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"));
554 return (1);
557 return (0);
560 static int
561 be_nvl_add_string(nvlist_t *nvl, const char *name, const char *val)
563 assert(nvl != NULL);
565 if (nvlist_add_string(nvl, name, val) != 0) {
566 (void) fprintf(stderr, _("nvlist_add_string failed for "
567 "%s (%s).\n"), name, val);
568 return (1);
571 return (0);
574 static int
575 be_nvl_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
577 assert(nvl != NULL);
579 if (nvlist_add_nvlist(nvl, name, val) != 0) {
580 (void) fprintf(stderr, _("nvlist_add_nvlist failed for %s.\n"),
581 name);
582 return (1);
585 return (0);
588 static int
589 be_nvl_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
591 assert(nvl != NULL);
593 if (nvlist_add_uint16(nvl, name, val) != 0) {
594 (void) fprintf(stderr, _("nvlist_add_uint16 failed for "
595 "%s (%hu).\n"), name, val);
596 return (1);
599 return (0);
602 static int
603 be_do_activate(int argc, char **argv)
605 nvlist_t *be_attrs;
606 int err = 1;
607 int c;
608 char *obe_name;
610 while ((c = getopt(argc, argv, "v")) != -1) {
611 switch (c) {
612 case 'v':
613 libbe_print_errors(B_TRUE);
614 break;
615 default:
616 usage();
617 return (1);
621 argc -= optind;
622 argv += optind;
624 if (argc != 1) {
625 usage();
626 return (1);
629 obe_name = argv[0];
631 if (be_nvl_alloc(&be_attrs) != 0)
632 return (1);
634 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
635 goto out;
637 err = be_activate(be_attrs);
639 switch (err) {
640 case BE_SUCCESS:
641 (void) printf(_("Activated successfully\n"));
642 break;
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);
647 break;
648 case BE_ERR_PERM:
649 case BE_ERR_ACCESS:
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"));
653 break;
654 case BE_ERR_ACTIVATE_CURR:
655 default:
656 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
657 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
660 out:
661 nvlist_free(be_attrs);
662 return (err);
665 static int
666 be_do_create(int argc, char **argv)
668 nvlist_t *be_attrs;
669 nvlist_t *zfs_props = NULL;
670 boolean_t activate = B_FALSE;
671 boolean_t is_snap = B_FALSE;
672 int c;
673 int err = 1;
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;
681 char *strval = NULL;
683 while ((c = getopt(argc, argv, "ad:e:io:p:v")) != -1) {
684 switch (c) {
685 case 'a':
686 activate = B_TRUE;
687 break;
688 case 'd':
689 nbe_desc = optarg;
690 break;
691 case 'e':
692 obe_name = optarg;
693 break;
694 case 'o':
695 if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0)
696 return (1);
698 propname = optarg;
699 if ((propval = strchr(propname, '=')) == NULL) {
700 (void) fprintf(stderr, _("missing "
701 "'=' for -o option\n"));
702 goto out2;
704 *propval = '\0';
705 propval++;
706 if (nvlist_lookup_string(zfs_props, propname,
707 &strval) == 0) {
708 (void) fprintf(stderr, _("property '%s' "
709 "specified multiple times\n"), propname);
710 goto out2;
713 if (be_nvl_add_string(zfs_props, propname, propval)
714 != 0)
715 goto out2;
717 break;
718 case 'p':
719 nbe_zpool = optarg;
720 break;
721 case 'v':
722 libbe_print_errors(B_TRUE);
723 break;
724 default:
725 usage();
726 goto out2;
730 argc -= optind;
731 argv += optind;
733 if (argc != 1) {
734 usage();
735 goto out2;
738 nbe_name = argv[0];
740 if ((snap_name = strrchr(nbe_name, '@')) != NULL) {
741 if (snap_name[1] == '\0') {
742 usage();
743 goto out2;
746 snap_name[0] = '\0';
747 snap_name++;
748 is_snap = B_TRUE;
751 if (obe_name) {
752 if (is_snap) {
753 usage();
754 goto out2;
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') {
763 usage();
764 goto out2;
767 snap_name[0] = '\0';
768 snap_name++;
770 } else if (is_snap) {
771 obe_name = nbe_name;
772 nbe_name = NULL;
775 if (be_nvl_alloc(&be_attrs) != 0)
776 goto out2;
779 if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs,
780 BE_ATTR_ORIG_BE_NAME, zfs_props) != 0)
781 goto out;
783 if (obe_name != NULL && be_nvl_add_string(be_attrs,
784 BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
785 goto out;
787 if (snap_name != NULL && be_nvl_add_string(be_attrs,
788 BE_ATTR_SNAP_NAME, snap_name) != 0)
789 goto out;
791 if (nbe_zpool != NULL && be_nvl_add_string(be_attrs,
792 BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0)
793 goto out;
795 if (nbe_name != NULL && be_nvl_add_string(be_attrs,
796 BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
797 goto out;
799 if (nbe_desc != NULL && be_nvl_add_string(be_attrs,
800 BE_ATTR_NEW_BE_DESC, nbe_desc) != 0)
801 goto out;
803 if (is_snap)
804 err = be_create_snapshot(be_attrs);
805 else
806 err = be_copy(be_attrs);
808 switch (err) {
809 case BE_SUCCESS:
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,
817 &nbe_name) != 0) {
818 (void) fprintf(stderr, _("failed to get %s "
819 "attribute\n"), BE_ATTR_NEW_BE_NAME);
820 break;
821 } else
822 (void) printf(_("Auto named BE: %s\n"),
823 nbe_name);
825 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
826 &snap_name) != 0) {
827 (void) fprintf(stderr, _("failed to get %s "
828 "attribute\n"), BE_ATTR_SNAP_NAME);
829 break;
830 } else
831 (void) printf(_("Auto named snapshot: %s\n"),
832 snap_name);
835 if (!is_snap && activate) {
836 char *args[] = { "activate", "", NULL };
837 args[1] = nbe_name;
838 optind = 1;
840 err = be_do_activate(2, args);
841 goto out;
844 (void) printf(_("Created successfully\n"));
845 break;
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);
849 break;
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,
853 snap_name);
854 break;
855 case BE_ERR_PERM:
856 case BE_ERR_ACCESS:
857 if (is_snap)
858 (void) fprintf(stderr, _("Unable to create snapshot "
859 "%s.\n"), snap_name);
860 else
861 (void) fprintf(stderr, _("Unable to create %s.\n"),
862 nbe_name);
863 (void) fprintf(stderr, _("You have insufficient privileges to "
864 "execute this command.\n"));
865 break;
866 default:
867 if (is_snap)
868 (void) fprintf(stderr, _("Unable to create snapshot "
869 "%s.\n"), snap_name);
870 else
871 (void) fprintf(stderr, _("Unable to create %s.\n"),
872 nbe_name);
873 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
876 out:
877 nvlist_free(be_attrs);
878 out2:
879 nvlist_free(zfs_props);
881 return (err);
884 static int
885 be_do_destroy(int argc, char **argv)
887 nvlist_t *be_attrs;
888 boolean_t is_snap = B_FALSE;
889 int err = 1;
890 int c;
891 int destroy_flags = 0;
892 char *snap_name;
893 char *be_name;
895 while ((c = getopt(argc, argv, "fFsv")) != -1) {
896 switch (c) {
897 case 'f':
898 destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
899 break;
900 case 'F':
901 break;
902 case 's':
903 destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
904 break;
905 case 'v':
906 libbe_print_errors(B_TRUE);
907 break;
908 default:
909 usage();
910 return (1);
914 argc -= optind;
915 argv += optind;
917 if (argc != 1) {
918 usage();
919 return (1);
922 be_name = argv[0];
923 if ((snap_name = strrchr(be_name, '@')) != NULL) {
924 if (snap_name[1] == '\0') {
925 usage();
926 return (1);
929 is_snap = B_TRUE;
930 *snap_name = '\0';
931 snap_name++;
934 if (be_nvl_alloc(&be_attrs) != 0)
935 return (1);
938 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0)
939 goto out;
941 if (is_snap) {
942 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME,
943 snap_name) != 0)
944 goto out;
946 err = be_destroy_snapshot(be_attrs);
947 } else {
948 if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS,
949 destroy_flags) != 0)
950 goto out;
952 err = be_destroy(be_attrs);
955 switch (err) {
956 case BE_SUCCESS:
957 break;
958 case BE_ERR_MOUNTED:
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);
964 break;
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);
969 break;
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);
974 break;
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);
979 break;
980 case BE_ERR_PERM:
981 case BE_ERR_ACCESS:
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"));
985 break;
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);
990 break;
991 default:
992 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
993 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
996 out:
997 nvlist_free(be_attrs);
998 return (err);
1001 static int
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;
1009 int err = 1;
1010 int c = 0;
1011 char *be_name = NULL;
1012 be_sort_t order = BE_SORT_UNSPECIFIED;
1014 while ((c = getopt(argc, argv, "adk:svHK:")) != -1) {
1015 switch (c) {
1016 case 'a':
1017 all = B_TRUE;
1018 break;
1019 case 'd':
1020 dsets = B_TRUE;
1021 break;
1022 case 'k':
1023 case 'K':
1024 if (order != BE_SORT_UNSPECIFIED) {
1025 (void) fprintf(stderr, _("Sort key can be "
1026 "specified only once.\n"));
1027 usage();
1028 return (1);
1030 if (strcmp(optarg, "date") == 0) {
1031 if (c == 'k')
1032 order = BE_SORT_DATE;
1033 else
1034 order = BE_SORT_DATE_REV;
1035 break;
1037 if (strcmp(optarg, "name") == 0) {
1038 if (c == 'k')
1039 order = BE_SORT_NAME;
1040 else
1041 order = BE_SORT_NAME_REV;
1042 break;
1044 if (strcmp(optarg, "space") == 0) {
1045 if (c == 'k')
1046 order = BE_SORT_SPACE;
1047 else
1048 order = BE_SORT_SPACE_REV;
1049 break;
1051 (void) fprintf(stderr, _("Unknown sort key: %s\n"),
1052 optarg);
1053 usage();
1054 return (1);
1055 case 's':
1056 snaps = B_TRUE;
1057 break;
1058 case 'v':
1059 libbe_print_errors(B_TRUE);
1060 break;
1061 case 'H':
1062 parsable = B_TRUE;
1063 break;
1064 default:
1065 usage();
1066 return (1);
1070 if (all) {
1071 if (dsets) {
1072 (void) fprintf(stderr, _("Invalid options: -a and %s "
1073 "are mutually exclusive.\n"), "-d");
1074 usage();
1075 return (1);
1077 if (snaps) {
1078 (void) fprintf(stderr, _("Invalid options: -a and %s "
1079 "are mutually exclusive.\n"), "-s");
1080 usage();
1081 return (1);
1084 dsets = B_TRUE;
1085 snaps = B_TRUE;
1088 argc -= optind;
1089 argv += optind;
1092 if (argc == 1)
1093 be_name = argv[0];
1095 err = be_list(be_name, &be_nodes,
1096 snaps ? BE_LIST_SNAPSHOTS : BE_LIST_DEFAULT);
1098 switch (err) {
1099 case BE_SUCCESS:
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 "
1108 "Environment\n"));
1109 (void) fprintf(stderr, "%s\n",
1110 be_err_to_str(err));
1111 break;
1115 print_nodes(be_name, dsets, snaps, parsable, be_nodes);
1116 break;
1117 case BE_ERR_BE_NOENT:
1118 if (be_name == NULL)
1119 (void) fprintf(stderr, _("No boot environments found "
1120 "on this system.\n"));
1121 else {
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);
1126 break;
1127 default:
1128 (void) fprintf(stderr, _("Unable to display Boot "
1129 "Environment\n"));
1130 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1133 if (be_nodes != NULL)
1134 be_free_list(be_nodes);
1135 return (err);
1138 static int
1139 be_do_mount(int argc, char **argv)
1141 nvlist_t *be_attrs;
1142 boolean_t shared_fs = B_FALSE;
1143 int err = 1;
1144 int c;
1145 int mount_flags = 0;
1146 char *obe_name;
1147 char *mountpoint;
1148 char *tmp_mp = NULL;
1150 while ((c = getopt(argc, argv, "s:v")) != -1) {
1151 switch (c) {
1152 case 's':
1153 shared_fs = B_TRUE;
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"));
1162 usage();
1163 return (1);
1166 break;
1167 case 'v':
1168 libbe_print_errors(B_TRUE);
1169 break;
1170 default:
1171 usage();
1172 return (1);
1176 argc -= optind;
1177 argv += optind;
1179 if (argc < 1 || argc > 2) {
1180 usage();
1181 return (1);
1184 obe_name = argv[0];
1186 if (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);
1191 return (1);
1193 } else {
1194 const char *tmpdir = getenv("TMPDIR");
1195 const char *tmpname = "tmp.XXXXXX";
1196 int sz;
1198 if (tmpdir == NULL)
1199 tmpdir = "/tmp";
1201 sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname);
1202 if (sz < 0) {
1203 (void) fprintf(stderr, _("internal error: "
1204 "out of memory\n"));
1205 return (1);
1208 mountpoint = mkdtemp(tmp_mp);
1211 if (be_nvl_alloc(&be_attrs) != 0)
1212 return (1);
1214 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1215 goto out;
1217 if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0)
1218 goto out;
1220 if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS,
1221 mount_flags) != 0)
1222 goto out;
1224 err = be_mount(be_attrs);
1226 switch (err) {
1227 case BE_SUCCESS:
1228 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint);
1229 break;
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);
1234 break;
1235 case BE_ERR_MOUNTED:
1236 (void) fprintf(stderr, _("%s is already mounted.\n"
1237 "Please unmount the BE before mounting it again.\n"),
1238 obe_name);
1239 break;
1240 case BE_ERR_PERM:
1241 case BE_ERR_ACCESS:
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"));
1245 break;
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);
1249 break;
1250 default:
1251 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1252 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1255 out:
1256 free(tmp_mp);
1257 nvlist_free(be_attrs);
1258 return (err);
1261 static int
1262 be_do_unmount(int argc, char **argv)
1264 nvlist_t *be_attrs;
1265 char *obe_name;
1266 int err = 1;
1267 int c;
1268 int unmount_flags = 0;
1270 while ((c = getopt(argc, argv, "fv")) != -1) {
1271 switch (c) {
1272 case 'f':
1273 unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
1274 break;
1275 case 'v':
1276 libbe_print_errors(B_TRUE);
1277 break;
1278 default:
1279 usage();
1280 return (1);
1284 argc -= optind;
1285 argv += optind;
1287 if (argc != 1) {
1288 usage();
1289 return (1);
1292 obe_name = argv[0];
1294 if (be_nvl_alloc(&be_attrs) != 0)
1295 return (1);
1298 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1299 goto out;
1301 if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS,
1302 unmount_flags) != 0)
1303 goto out;
1305 err = be_unmount(be_attrs);
1307 switch (err) {
1308 case BE_SUCCESS:
1309 (void) printf(_("Unmounted successfully\n"));
1310 break;
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);
1315 break;
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);
1320 break;
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);
1324 break;
1325 case BE_ERR_PERM:
1326 case BE_ERR_ACCESS:
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"));
1330 break;
1331 default:
1332 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1333 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1336 out:
1337 nvlist_free(be_attrs);
1338 return (err);
1341 static int
1342 be_do_rename(int argc, char **argv)
1344 nvlist_t *be_attrs;
1345 char *obe_name;
1346 char *nbe_name;
1347 int err = 1;
1348 int c;
1350 while ((c = getopt(argc, argv, "v")) != -1) {
1351 switch (c) {
1352 case 'v':
1353 libbe_print_errors(B_TRUE);
1354 break;
1355 default:
1356 usage();
1357 return (1);
1361 argc -= optind;
1362 argv += optind;
1364 if (argc != 2) {
1365 usage();
1366 return (1);
1369 obe_name = argv[0];
1370 nbe_name = argv[1];
1372 if (be_nvl_alloc(&be_attrs) != 0)
1373 return (1);
1375 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1376 goto out;
1378 if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
1379 goto out;
1381 err = be_rename(be_attrs);
1383 switch (err) {
1384 case BE_SUCCESS:
1385 (void) printf(_("Renamed successfully\n"));
1386 break;
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);
1391 break;
1392 case BE_ERR_PERM:
1393 case BE_ERR_ACCESS:
1394 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1395 obe_name);
1396 (void) fprintf(stderr, _("You have insufficient privileges to "
1397 "execute this command.\n"));
1398 break;
1399 default:
1400 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1401 obe_name);
1402 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1405 out:
1406 nvlist_free(be_attrs);
1407 return (err);
1410 static int
1411 be_do_rollback(int argc, char **argv)
1413 nvlist_t *be_attrs;
1414 char *obe_name;
1415 char *snap_name;
1416 int err = 1;
1417 int c;
1419 while ((c = getopt(argc, argv, "v")) != -1) {
1420 switch (c) {
1421 case 'v':
1422 libbe_print_errors(B_TRUE);
1423 break;
1424 default:
1425 usage();
1426 return (1);
1430 argc -= optind;
1431 argv += optind;
1433 if (argc < 1 || argc > 2) {
1434 usage();
1435 return (1);
1438 obe_name = argv[0];
1439 if (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') {
1444 usage();
1445 return (1);
1448 snap_name[0] = '\0';
1449 snap_name++;
1450 } else {
1451 usage();
1452 return (1);
1456 if (be_nvl_alloc(&be_attrs) != 0)
1457 return (1);
1459 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1460 goto out;
1462 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0)
1463 goto out;
1465 err = be_rollback(be_attrs);
1467 switch (err) {
1468 case BE_SUCCESS:
1469 (void) printf(_("Rolled back successfully\n"));
1470 break;
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);
1475 break;
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);
1480 break;
1481 case BE_ERR_PERM:
1482 case BE_ERR_ACCESS:
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"));
1487 break;
1488 default:
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));
1494 out:
1495 nvlist_free(be_attrs);
1496 return (err);