beadm: do not prompt for destroy
[unleashed.git] / usr / src / cmd / beadm / beadm.c
blob9acd2690e4019b890bd556e08f1c4cfaa7a94f27
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
32 * System includes
35 #include <assert.h>
36 #include <stdio.h>
37 #include <strings.h>
38 #include <libzfs.h>
39 #include <locale.h>
40 #include <langinfo.h>
41 #include <stdlib.h>
42 #include <wchar.h>
43 #include <sys/types.h>
44 #include <sys/debug.h>
45 #include <libcmdutils.h>
47 #include "libbe.h"
49 #define _(x) gettext(x)
51 #ifndef TEXT_DOMAIN
52 #define TEXT_DOMAIN "SYS_TEST"
53 #endif
55 #define DT_BUF_LEN (128)
56 #define NUM_COLS (6)
57 CTASSERT(DT_BUF_LEN >= NN_NUMBUF_SZ);
59 static int be_do_activate(int argc, char **argv);
60 static int be_do_create(int argc, char **argv);
61 static int be_do_destroy(int argc, char **argv);
62 static int be_do_list(int argc, char **argv);
63 static int be_do_mount(int argc, char **argv);
64 static int be_do_unmount(int argc, char **argv);
65 static int be_do_rename(int argc, char **argv);
66 static int be_do_rollback(int argc, char **argv);
67 static void usage(void);
70 * single column name/width output format description
72 struct col_info {
73 const char *col_name;
74 size_t width;
78 * all columns output format
80 struct hdr_info {
81 struct col_info cols[NUM_COLS];
85 * type of possible output formats
87 enum be_fmt {
88 BE_FMT_DEFAULT,
89 BE_FMT_DATASET,
90 BE_FMT_SNAPSHOT,
91 BE_FMT_ALL
95 * command handler description
97 typedef struct be_command {
98 const char *name;
99 int (*func)(int argc, char **argv);
100 } be_command_t;
103 * sorted list of be commands
105 static const be_command_t be_command_tbl[] = {
106 { "activate", be_do_activate },
107 { "create", be_do_create },
108 { "destroy", be_do_destroy },
109 { "list", be_do_list },
110 { "mount", be_do_mount },
111 { "unmount", be_do_unmount },
112 { "umount", be_do_unmount }, /* unmount alias */
113 { "rename", be_do_rename },
114 { "rollback", be_do_rollback },
115 { NULL, NULL },
118 static void
119 usage(void)
121 (void) fprintf(stderr, _("usage:\n"
122 "\tbeadm subcommand cmd_options\n"
123 "\n"
124 "\tsubcommands:\n"
125 "\n"
126 "\tbeadm activate [-v] beName\n"
127 "\tbeadm create [-a] [-d BE_desc]\n"
128 "\t\t[-o property=value] ... [-p zpool] \n"
129 "\t\t[-e nonActiveBe | beName@snapshot] [-v] beName\n"
130 "\tbeadm create [-d BE_desc]\n"
131 "\t\t[-o property=value] ... [-p zpool] [-v] beName@snapshot\n"
132 "\tbeadm destroy [-Ffsv] beName \n"
133 "\tbeadm destroy [-Fv] beName@snapshot \n"
134 "\tbeadm list [[-a] | [-d] [-s]] [-H]\n"
135 "\t\t[-k|-K date | name | space] [-v] [beName]\n"
136 "\tbeadm mount [-s ro|rw] [-v] beName [mountpoint]\n"
137 "\tbeadm unmount [-fv] beName | mountpoint\n"
138 "\tbeadm umount [-fv] beName | mountpoint\n"
139 "\tbeadm rename [-v] origBeName newBeName\n"
140 "\tbeadm rollback [-v] beName snapshot\n"
141 "\tbeadm rollback [-v] beName@snapshot\n"));
144 static int
145 run_be_cmd(const char *cmdname, int argc, char **argv)
147 const be_command_t *command;
149 for (command = &be_command_tbl[0]; command->name != NULL; command++)
150 if (strcmp(command->name, cmdname) == 0)
151 return (command->func(argc, argv));
153 (void) fprintf(stderr, _("Invalid command: %s\n"), cmdname);
154 usage();
155 return (1);
159 main(int argc, char **argv)
161 const char *cmdname;
163 (void) setlocale(LC_ALL, "");
164 (void) textdomain(TEXT_DOMAIN);
166 if (argc < 2) {
167 usage();
168 return (1);
171 cmdname = argv[1];
173 /* Turn error printing off */
174 libbe_print_errors(B_FALSE);
176 return (run_be_cmd(cmdname, --argc, ++argv));
179 static void
180 print_hdr(struct hdr_info *hdr_info)
182 boolean_t first = B_TRUE;
183 size_t i;
184 for (i = 0; i < NUM_COLS; i++) {
185 struct col_info *col_info = &hdr_info->cols[i];
186 const char *name = col_info->col_name;
187 size_t width = col_info->width;
188 if (name == NULL)
189 continue;
191 if (first) {
192 (void) printf("%-*s", width, name);
193 first = B_FALSE;
194 } else
195 (void) printf(" %-*s", width, name);
197 (void) putchar('\n');
200 static void
201 init_hdr_cols(enum be_fmt be_fmt, struct hdr_info *hdr)
203 struct col_info *col = hdr->cols;
204 size_t i;
206 col[1].col_name = _("Active");
207 col[2].col_name = _("Mountpoint");
208 col[3].col_name = _("Space");
209 col[4].col_name = _("Policy");
210 col[5].col_name = _("Created");
211 col[6].col_name = NULL;
213 switch (be_fmt) {
214 case BE_FMT_ALL:
215 col[0].col_name = _("BE/Dataset/Snapshot");
216 break;
217 case BE_FMT_DATASET:
218 col[0].col_name = _("BE/Dataset");
219 break;
220 case BE_FMT_SNAPSHOT:
221 col[0].col_name = _("BE/Snapshot");
222 col[1].col_name = NULL;
223 col[2].col_name = NULL;
224 break;
225 case BE_FMT_DEFAULT:
226 default:
227 col[0].col_name = _("BE");
230 for (i = 0; i < NUM_COLS; i++) {
231 const char *name = col[i].col_name;
232 col[i].width = 0;
234 if (name != NULL) {
235 wchar_t wname[128];
236 size_t sz = mbstowcs(wname, name, sizeof (wname) /
237 sizeof (wchar_t));
238 if (sz > 0) {
239 int wcsw = wcswidth(wname, sz);
240 if (wcsw > 0)
241 col[i].width = wcsw;
242 else
243 col[i].width = sz;
244 } else {
245 col[i].width = strlen(name);
251 static void
252 count_widths(enum be_fmt be_fmt, struct hdr_info *hdr, be_node_list_t *be_nodes)
254 size_t len[NUM_COLS];
255 char buf[DT_BUF_LEN];
256 int i;
257 be_node_list_t *cur_be;
259 for (i = 0; i < NUM_COLS; i++)
260 len[i] = hdr->cols[i].width;
262 for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
263 char name[ZFS_MAX_DATASET_NAME_LEN + 1];
264 const char *be_name = cur_be->be_node_name;
265 const char *root_ds = cur_be->be_root_ds;
266 char *pos;
267 size_t node_name_len = strlen(cur_be->be_node_name);
268 size_t root_ds_len = strlen(cur_be->be_root_ds);
269 size_t mntpt_len = 0;
270 size_t policy_len = 0;
271 size_t used_len;
272 uint64_t used = cur_be->be_space_used;
273 be_snapshot_list_t *snap = NULL;
275 if (cur_be->be_mntpt != NULL)
276 mntpt_len = strlen(cur_be->be_mntpt);
277 if (cur_be->be_policy_type != NULL)
278 policy_len = strlen(cur_be->be_policy_type);
280 (void) strlcpy(name, root_ds, sizeof (name));
281 pos = strstr(name, be_name);
283 if (be_fmt == BE_FMT_DEFAULT) {
284 if (node_name_len > len[0])
285 len[0] = node_name_len;
286 } else {
287 if (root_ds_len + 3 > len[0])
288 len[0] = root_ds_len + 3;
291 if (mntpt_len > len[2])
292 len[2] = mntpt_len;
293 if (policy_len > len[4])
294 len[4] = policy_len;
296 for (snap = cur_be->be_node_snapshots; snap != NULL;
297 snap = snap->be_next_snapshot) {
298 uint64_t snap_used = snap->be_snapshot_space_used;
299 const char *snap_name = snap->be_snapshot_name;
300 (void) strcpy(pos, snap_name);
302 if (be_fmt == BE_FMT_DEFAULT)
303 used += snap_used;
304 else if (be_fmt & BE_FMT_SNAPSHOT) {
305 int snap_len = strlen(name) + 3;
306 if (be_fmt == BE_FMT_SNAPSHOT)
307 snap_len -= pos - name;
308 if (snap_len > len[0])
309 len[0] = snap_len;
310 nicenum(snap_used, buf, sizeof (buf));
311 used_len = strlen(buf);
312 if (used_len > len[3])
313 len[3] = used_len;
317 if (be_fmt == BE_FMT_DEFAULT) {
318 int used_len;
319 nicenum(used, buf, sizeof (buf));
320 used_len = strlen(buf);
321 if (used_len > len[3])
322 len[3] = used_len;
325 nicenum(used, buf, sizeof (buf));
328 for (i = 0; i < NUM_COLS; i++)
329 hdr->cols[i].width = len[i];
332 static void
333 print_be_nodes(const char *be_name, boolean_t parsable, struct hdr_info *hdr,
334 be_node_list_t *nodes)
336 char buf[64];
337 char datetime[DT_BUF_LEN];
338 be_node_list_t *cur_be;
340 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
341 char active[3] = "-\0";
342 int ai = 0;
343 const char *datetime_fmt = "%F %R";
344 const char *name = cur_be->be_node_name;
345 const char *mntpt = cur_be->be_mntpt;
346 const char *uuid_str = cur_be->be_uuid_str;
347 be_snapshot_list_t *snap = NULL;
348 uint64_t used = cur_be->be_space_used;
349 time_t creation = cur_be->be_node_creation;
350 struct tm *tm;
352 if (be_name != NULL && strcmp(be_name, name) != 0)
353 continue;
355 if (parsable)
356 active[0] = '\0';
358 tm = localtime(&creation);
359 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
361 for (snap = cur_be->be_node_snapshots; snap != NULL;
362 snap = snap->be_next_snapshot)
363 used += snap->be_snapshot_space_used;
365 if (!cur_be->be_global_active)
366 active[ai++] = 'x';
368 if (cur_be->be_active)
369 active[ai++] = 'N';
370 if (cur_be->be_active_on_boot) {
371 if (!cur_be->be_global_active)
372 active[ai] = 'b';
373 else
374 active[ai] = 'R';
377 nicenum(used, buf, sizeof (buf));
378 if (parsable)
379 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
380 name,
381 (uuid_str != NULL ? uuid_str: ""),
382 active,
383 (cur_be->be_mounted ? mntpt: ""),
384 used,
385 cur_be->be_policy_type,
386 creation);
387 else
388 (void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n",
389 hdr->cols[0].width, name,
390 hdr->cols[1].width, active,
391 hdr->cols[2].width, (cur_be->be_mounted ? mntpt:
392 "-"),
393 hdr->cols[3].width, buf,
394 hdr->cols[4].width, cur_be->be_policy_type,
395 hdr->cols[5].width, datetime);
399 static void
400 print_be_snapshots(be_node_list_t *be, struct hdr_info *hdr, boolean_t parsable)
402 char buf[64];
403 char datetime[DT_BUF_LEN];
404 be_snapshot_list_t *snap = NULL;
406 for (snap = be->be_node_snapshots; snap != NULL;
407 snap = snap->be_next_snapshot) {
408 char name[ZFS_MAX_DATASET_NAME_LEN + 1];
409 const char *datetime_fmt = "%F %R";
410 const char *be_name = be->be_node_name;
411 const char *root_ds = be->be_root_ds;
412 const char *snap_name = snap->be_snapshot_name;
413 char *pos;
414 uint64_t used = snap->be_snapshot_space_used;
415 time_t creation = snap->be_snapshot_creation;
416 struct tm *tm = localtime(&creation);
418 (void) strncpy(name, root_ds, sizeof (name));
419 pos = strstr(name, be_name);
420 (void) strcpy(pos, snap_name);
422 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
423 nicenum(used, buf, sizeof (buf));
425 if (parsable)
426 if (hdr->cols[1].width != 0)
427 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
428 be_name,
429 snap_name,
432 used,
433 be->be_policy_type,
434 creation);
435 else
436 (void) printf("%s;%s;%llu;%s;%ld\n",
437 be_name,
438 snap_name,
439 used,
440 be->be_policy_type,
441 creation);
442 else
443 if (hdr->cols[1].width != 0)
444 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
445 "%-*s\n",
446 hdr->cols[0].width-3, name,
447 hdr->cols[1].width, "-",
448 hdr->cols[2].width, "-",
449 hdr->cols[3].width, buf,
450 hdr->cols[4].width, be->be_policy_type,
451 hdr->cols[5].width, datetime);
452 else
453 (void) printf(" %-*s %-*s %-*s %-*s\n",
454 hdr->cols[0].width-3, snap_name,
455 hdr->cols[3].width, buf,
456 hdr->cols[4].width, be->be_policy_type,
457 hdr->cols[5].width, datetime);
461 static void
462 print_fmt_nodes(const char *be_name, enum be_fmt be_fmt, boolean_t parsable,
463 struct hdr_info *hdr, be_node_list_t *nodes)
465 char buf[64];
466 char datetime[DT_BUF_LEN];
467 be_node_list_t *cur_be;
469 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
470 char active[3] = "-\0";
471 int ai = 0;
472 const char *datetime_fmt = "%F %R";
473 const char *name = cur_be->be_node_name;
474 const char *mntpt = cur_be->be_mntpt;
475 uint64_t used = cur_be->be_space_used;
476 time_t creation = cur_be->be_node_creation;
477 struct tm *tm;
479 if (be_name != NULL && strcmp(be_name, name) != 0)
480 continue;
482 if (!parsable)
483 (void) printf("%-s\n", name);
484 else
485 active[0] = '\0';
487 tm = localtime(&creation);
488 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
490 if (cur_be->be_active)
491 active[ai++] = 'N';
492 if (cur_be->be_active_on_boot)
493 active[ai] = 'R';
495 nicenum(used, buf, sizeof (buf));
496 if (be_fmt & BE_FMT_DATASET)
497 if (parsable)
498 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
499 cur_be->be_node_name,
500 cur_be->be_root_ds,
501 active,
502 (cur_be->be_mounted ? mntpt: ""),
503 used,
504 cur_be->be_policy_type,
505 creation);
506 else
507 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
508 "%-*s\n",
509 hdr->cols[0].width-3, cur_be->be_root_ds,
510 hdr->cols[1].width, active,
511 hdr->cols[2].width, (cur_be->be_mounted ?
512 mntpt: "-"),
513 hdr->cols[3].width, buf,
514 hdr->cols[4].width, cur_be->be_policy_type,
515 hdr->cols[5].width, datetime);
517 if (be_fmt & BE_FMT_SNAPSHOT)
518 print_be_snapshots(cur_be, hdr, parsable);
522 static void
523 print_nodes(const char *be_name, boolean_t dsets, boolean_t snaps,
524 boolean_t parsable, be_node_list_t *be_nodes)
526 struct hdr_info hdr;
527 enum be_fmt be_fmt = BE_FMT_DEFAULT;
529 if (dsets)
530 be_fmt |= BE_FMT_DATASET;
531 if (snaps)
532 be_fmt |= BE_FMT_SNAPSHOT;
534 if (!parsable) {
535 init_hdr_cols(be_fmt, &hdr);
536 count_widths(be_fmt, &hdr, be_nodes);
537 print_hdr(&hdr);
540 if (be_fmt == BE_FMT_DEFAULT)
541 print_be_nodes(be_name, parsable, &hdr, be_nodes);
542 else
543 print_fmt_nodes(be_name, be_fmt, parsable, &hdr, be_nodes);
546 static int
547 be_nvl_alloc(nvlist_t **nvlp)
549 assert(nvlp != NULL);
551 if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) {
552 (void) perror(_("nvlist_alloc failed.\n"));
553 return (1);
556 return (0);
559 static int
560 be_nvl_add_string(nvlist_t *nvl, const char *name, const char *val)
562 assert(nvl != NULL);
564 if (nvlist_add_string(nvl, name, val) != 0) {
565 (void) fprintf(stderr, _("nvlist_add_string failed for "
566 "%s (%s).\n"), name, val);
567 return (1);
570 return (0);
573 static int
574 be_nvl_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
576 assert(nvl != NULL);
578 if (nvlist_add_nvlist(nvl, name, val) != 0) {
579 (void) fprintf(stderr, _("nvlist_add_nvlist failed for %s.\n"),
580 name);
581 return (1);
584 return (0);
587 static int
588 be_nvl_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
590 assert(nvl != NULL);
592 if (nvlist_add_uint16(nvl, name, val) != 0) {
593 (void) fprintf(stderr, _("nvlist_add_uint16 failed for "
594 "%s (%hu).\n"), name, val);
595 return (1);
598 return (0);
601 static int
602 be_do_activate(int argc, char **argv)
604 nvlist_t *be_attrs;
605 int err = 1;
606 int c;
607 char *obe_name;
609 while ((c = getopt(argc, argv, "v")) != -1) {
610 switch (c) {
611 case 'v':
612 libbe_print_errors(B_TRUE);
613 break;
614 default:
615 usage();
616 return (1);
620 argc -= optind;
621 argv += optind;
623 if (argc != 1) {
624 usage();
625 return (1);
628 obe_name = argv[0];
630 if (be_nvl_alloc(&be_attrs) != 0)
631 return (1);
633 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
634 goto out;
636 err = be_activate(be_attrs);
638 switch (err) {
639 case BE_SUCCESS:
640 (void) printf(_("Activated successfully\n"));
641 break;
642 case BE_ERR_BE_NOENT:
643 (void) fprintf(stderr, _("%s does not exist or appear "
644 "to be a valid BE.\nPlease check that the name of "
645 "the BE provided is correct.\n"), obe_name);
646 break;
647 case BE_ERR_PERM:
648 case BE_ERR_ACCESS:
649 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
650 (void) fprintf(stderr, _("You have insufficient privileges to "
651 "execute this command.\n"));
652 break;
653 case BE_ERR_ACTIVATE_CURR:
654 default:
655 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
656 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
659 out:
660 nvlist_free(be_attrs);
661 return (err);
664 static int
665 be_do_create(int argc, char **argv)
667 nvlist_t *be_attrs;
668 nvlist_t *zfs_props = NULL;
669 boolean_t activate = B_FALSE;
670 boolean_t is_snap = B_FALSE;
671 int c;
672 int err = 1;
673 char *obe_name = NULL;
674 char *snap_name = NULL;
675 char *nbe_zpool = NULL;
676 char *nbe_name = NULL;
677 char *nbe_desc = NULL;
678 char *propname = NULL;
679 char *propval = NULL;
680 char *strval = NULL;
682 while ((c = getopt(argc, argv, "ad:e:io:p:v")) != -1) {
683 switch (c) {
684 case 'a':
685 activate = B_TRUE;
686 break;
687 case 'd':
688 nbe_desc = optarg;
689 break;
690 case 'e':
691 obe_name = optarg;
692 break;
693 case 'o':
694 if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0)
695 return (1);
697 propname = optarg;
698 if ((propval = strchr(propname, '=')) == NULL) {
699 (void) fprintf(stderr, _("missing "
700 "'=' for -o option\n"));
701 goto out2;
703 *propval = '\0';
704 propval++;
705 if (nvlist_lookup_string(zfs_props, propname,
706 &strval) == 0) {
707 (void) fprintf(stderr, _("property '%s' "
708 "specified multiple times\n"), propname);
709 goto out2;
712 if (be_nvl_add_string(zfs_props, propname, propval)
713 != 0)
714 goto out2;
716 break;
717 case 'p':
718 nbe_zpool = optarg;
719 break;
720 case 'v':
721 libbe_print_errors(B_TRUE);
722 break;
723 default:
724 usage();
725 goto out2;
729 argc -= optind;
730 argv += optind;
732 if (argc != 1) {
733 usage();
734 goto out2;
737 nbe_name = argv[0];
739 if ((snap_name = strrchr(nbe_name, '@')) != NULL) {
740 if (snap_name[1] == '\0') {
741 usage();
742 goto out2;
745 snap_name[0] = '\0';
746 snap_name++;
747 is_snap = B_TRUE;
750 if (obe_name) {
751 if (is_snap) {
752 usage();
753 goto out2;
757 * Check if obe_name is really a snapshot name.
758 * If so, split it out.
760 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
761 if (snap_name[1] == '\0') {
762 usage();
763 goto out2;
766 snap_name[0] = '\0';
767 snap_name++;
769 } else if (is_snap) {
770 obe_name = nbe_name;
771 nbe_name = NULL;
774 if (be_nvl_alloc(&be_attrs) != 0)
775 goto out2;
778 if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs,
779 BE_ATTR_ORIG_BE_NAME, zfs_props) != 0)
780 goto out;
782 if (obe_name != NULL && be_nvl_add_string(be_attrs,
783 BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
784 goto out;
786 if (snap_name != NULL && be_nvl_add_string(be_attrs,
787 BE_ATTR_SNAP_NAME, snap_name) != 0)
788 goto out;
790 if (nbe_zpool != NULL && be_nvl_add_string(be_attrs,
791 BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0)
792 goto out;
794 if (nbe_name != NULL && be_nvl_add_string(be_attrs,
795 BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
796 goto out;
798 if (nbe_desc != NULL && be_nvl_add_string(be_attrs,
799 BE_ATTR_NEW_BE_DESC, nbe_desc) != 0)
800 goto out;
802 if (is_snap)
803 err = be_create_snapshot(be_attrs);
804 else
805 err = be_copy(be_attrs);
807 switch (err) {
808 case BE_SUCCESS:
809 if (!is_snap && !nbe_name) {
811 * We requested an auto named BE; find out the
812 * name of the BE that was created for us and
813 * the auto snapshot created from the original BE.
815 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME,
816 &nbe_name) != 0) {
817 (void) fprintf(stderr, _("failed to get %s "
818 "attribute\n"), BE_ATTR_NEW_BE_NAME);
819 break;
820 } else
821 (void) printf(_("Auto named BE: %s\n"),
822 nbe_name);
824 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
825 &snap_name) != 0) {
826 (void) fprintf(stderr, _("failed to get %s "
827 "attribute\n"), BE_ATTR_SNAP_NAME);
828 break;
829 } else
830 (void) printf(_("Auto named snapshot: %s\n"),
831 snap_name);
834 if (!is_snap && activate) {
835 char *args[] = { "activate", "", NULL };
836 args[1] = nbe_name;
837 optind = 1;
839 err = be_do_activate(2, args);
840 goto out;
843 (void) printf(_("Created successfully\n"));
844 break;
845 case BE_ERR_BE_EXISTS:
846 (void) fprintf(stderr, _("BE %s already exists\n."
847 "Please choose a different BE name.\n"), nbe_name);
848 break;
849 case BE_ERR_SS_EXISTS:
850 (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n"
851 "Please choose a different snapshot name.\n"), obe_name,
852 snap_name);
853 break;
854 case BE_ERR_PERM:
855 case BE_ERR_ACCESS:
856 if (is_snap)
857 (void) fprintf(stderr, _("Unable to create snapshot "
858 "%s.\n"), snap_name);
859 else
860 (void) fprintf(stderr, _("Unable to create %s.\n"),
861 nbe_name);
862 (void) fprintf(stderr, _("You have insufficient privileges to "
863 "execute this command.\n"));
864 break;
865 default:
866 if (is_snap)
867 (void) fprintf(stderr, _("Unable to create snapshot "
868 "%s.\n"), snap_name);
869 else
870 (void) fprintf(stderr, _("Unable to create %s.\n"),
871 nbe_name);
872 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
875 out:
876 nvlist_free(be_attrs);
877 out2:
878 nvlist_free(zfs_props);
880 return (err);
883 static int
884 be_do_destroy(int argc, char **argv)
886 nvlist_t *be_attrs;
887 boolean_t is_snap = B_FALSE;
888 int err = 1;
889 int c;
890 int destroy_flags = 0;
891 char *snap_name;
892 char *be_name;
894 while ((c = getopt(argc, argv, "fFsv")) != -1) {
895 switch (c) {
896 case 'f':
897 destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
898 break;
899 case 'F':
900 break;
901 case 's':
902 destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
903 break;
904 case 'v':
905 libbe_print_errors(B_TRUE);
906 break;
907 default:
908 usage();
909 return (1);
913 argc -= optind;
914 argv += optind;
916 if (argc != 1) {
917 usage();
918 return (1);
921 be_name = argv[0];
922 if ((snap_name = strrchr(be_name, '@')) != NULL) {
923 if (snap_name[1] == '\0') {
924 usage();
925 return (1);
928 is_snap = B_TRUE;
929 *snap_name = '\0';
930 snap_name++;
933 if (be_nvl_alloc(&be_attrs) != 0)
934 return (1);
937 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0)
938 goto out;
940 if (is_snap) {
941 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME,
942 snap_name) != 0)
943 goto out;
945 err = be_destroy_snapshot(be_attrs);
946 } else {
947 if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS,
948 destroy_flags) != 0)
949 goto out;
951 err = be_destroy(be_attrs);
954 switch (err) {
955 case BE_SUCCESS:
956 break;
957 case BE_ERR_MOUNTED:
958 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
959 (void) fprintf(stderr, _("It is currently mounted and must be "
960 "unmounted before it can be destroyed.\n" "Use 'beadm "
961 "unmount %s' to unmount the BE before destroying\nit or "
962 "'beadm destroy -f %s'.\n"), be_name, be_name);
963 break;
964 case BE_ERR_DESTROY_CURR_BE:
965 (void) fprintf(stderr, _("%s is the currently active BE and "
966 "cannot be destroyed.\nYou must boot from another BE in "
967 "order to destroy %s.\n"), be_name, be_name);
968 break;
969 case BE_ERR_ZONES_UNMOUNT:
970 (void) fprintf(stderr, _("Unable to destroy one of " "%s's "
971 "zone BE's.\nUse 'beadm destroy -f %s' or "
972 "'zfs -f destroy <dataset>'.\n"), be_name, be_name);
973 break;
974 case BE_ERR_SS_NOENT:
975 (void) fprintf(stderr, _("%s does not exist or appear "
976 "to be a valid snapshot.\nPlease check that the name of "
977 "the snapshot provided is correct.\n"), snap_name);
978 break;
979 case BE_ERR_PERM:
980 case BE_ERR_ACCESS:
981 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
982 (void) fprintf(stderr, _("You have insufficient privileges to "
983 "execute this command.\n"));
984 break;
985 case BE_ERR_SS_EXISTS:
986 (void) fprintf(stderr, _("Unable to destroy %s: "
987 "BE has snapshots.\nUse 'beadm destroy -s %s' or "
988 "'zfs -r destroy <dataset>'.\n"), be_name, be_name);
989 break;
990 default:
991 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
992 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
995 out:
996 nvlist_free(be_attrs);
997 return (err);
1000 static int
1001 be_do_list(int argc, char **argv)
1003 be_node_list_t *be_nodes = NULL;
1004 boolean_t all = B_FALSE;
1005 boolean_t dsets = B_FALSE;
1006 boolean_t snaps = B_FALSE;
1007 boolean_t parsable = B_FALSE;
1008 int err = 1;
1009 int c = 0;
1010 char *be_name = NULL;
1011 be_sort_t order = BE_SORT_UNSPECIFIED;
1013 while ((c = getopt(argc, argv, "adk:svHK:")) != -1) {
1014 switch (c) {
1015 case 'a':
1016 all = B_TRUE;
1017 break;
1018 case 'd':
1019 dsets = B_TRUE;
1020 break;
1021 case 'k':
1022 case 'K':
1023 if (order != BE_SORT_UNSPECIFIED) {
1024 (void) fprintf(stderr, _("Sort key can be "
1025 "specified only once.\n"));
1026 usage();
1027 return (1);
1029 if (strcmp(optarg, "date") == 0) {
1030 if (c == 'k')
1031 order = BE_SORT_DATE;
1032 else
1033 order = BE_SORT_DATE_REV;
1034 break;
1036 if (strcmp(optarg, "name") == 0) {
1037 if (c == 'k')
1038 order = BE_SORT_NAME;
1039 else
1040 order = BE_SORT_NAME_REV;
1041 break;
1043 if (strcmp(optarg, "space") == 0) {
1044 if (c == 'k')
1045 order = BE_SORT_SPACE;
1046 else
1047 order = BE_SORT_SPACE_REV;
1048 break;
1050 (void) fprintf(stderr, _("Unknown sort key: %s\n"),
1051 optarg);
1052 usage();
1053 return (1);
1054 case 's':
1055 snaps = B_TRUE;
1056 break;
1057 case 'v':
1058 libbe_print_errors(B_TRUE);
1059 break;
1060 case 'H':
1061 parsable = B_TRUE;
1062 break;
1063 default:
1064 usage();
1065 return (1);
1069 if (all) {
1070 if (dsets) {
1071 (void) fprintf(stderr, _("Invalid options: -a and %s "
1072 "are mutually exclusive.\n"), "-d");
1073 usage();
1074 return (1);
1076 if (snaps) {
1077 (void) fprintf(stderr, _("Invalid options: -a and %s "
1078 "are mutually exclusive.\n"), "-s");
1079 usage();
1080 return (1);
1083 dsets = B_TRUE;
1084 snaps = B_TRUE;
1087 argc -= optind;
1088 argv += optind;
1091 if (argc == 1)
1092 be_name = argv[0];
1094 err = be_list(be_name, &be_nodes);
1096 switch (err) {
1097 case BE_SUCCESS:
1098 /* the default sort is ascending date, no need to sort twice */
1099 if (order == BE_SORT_UNSPECIFIED)
1100 order = BE_SORT_DATE;
1102 if (order != BE_SORT_DATE) {
1103 err = be_sort(&be_nodes, order);
1104 if (err != BE_SUCCESS) {
1105 (void) fprintf(stderr, _("Unable to sort Boot "
1106 "Environment\n"));
1107 (void) fprintf(stderr, "%s\n",
1108 be_err_to_str(err));
1109 break;
1113 print_nodes(be_name, dsets, snaps, parsable, be_nodes);
1114 break;
1115 case BE_ERR_BE_NOENT:
1116 if (be_name == NULL)
1117 (void) fprintf(stderr, _("No boot environments found "
1118 "on this system.\n"));
1119 else {
1120 (void) fprintf(stderr, _("%s does not exist or appear "
1121 "to be a valid BE.\nPlease check that the name of "
1122 "the BE provided is correct.\n"), be_name);
1124 break;
1125 default:
1126 (void) fprintf(stderr, _("Unable to display Boot "
1127 "Environment\n"));
1128 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1131 if (be_nodes != NULL)
1132 be_free_list(be_nodes);
1133 return (err);
1136 static int
1137 be_do_mount(int argc, char **argv)
1139 nvlist_t *be_attrs;
1140 boolean_t shared_fs = B_FALSE;
1141 int err = 1;
1142 int c;
1143 int mount_flags = 0;
1144 char *obe_name;
1145 char *mountpoint;
1146 char *tmp_mp = NULL;
1148 while ((c = getopt(argc, argv, "s:v")) != -1) {
1149 switch (c) {
1150 case 's':
1151 shared_fs = B_TRUE;
1153 mount_flags |= BE_MOUNT_FLAG_SHARED_FS;
1155 if (strcmp(optarg, "rw") == 0) {
1156 mount_flags |= BE_MOUNT_FLAG_SHARED_RW;
1157 } else if (strcmp(optarg, "ro") != 0) {
1158 (void) fprintf(stderr, _("The -s flag "
1159 "requires an argument [ rw | ro ]\n"));
1160 usage();
1161 return (1);
1164 break;
1165 case 'v':
1166 libbe_print_errors(B_TRUE);
1167 break;
1168 default:
1169 usage();
1170 return (1);
1174 argc -= optind;
1175 argv += optind;
1177 if (argc < 1 || argc > 2) {
1178 usage();
1179 return (1);
1182 obe_name = argv[0];
1184 if (argc == 2) {
1185 mountpoint = argv[1];
1186 if (mountpoint[0] != '/') {
1187 (void) fprintf(stderr, _("Invalid mount point %s. "
1188 "Mount point must start with a /.\n"), mountpoint);
1189 return (1);
1191 } else {
1192 const char *tmpdir = getenv("TMPDIR");
1193 const char *tmpname = "tmp.XXXXXX";
1194 int sz;
1196 if (tmpdir == NULL)
1197 tmpdir = "/tmp";
1199 sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname);
1200 if (sz < 0) {
1201 (void) fprintf(stderr, _("internal error: "
1202 "out of memory\n"));
1203 return (1);
1206 mountpoint = mkdtemp(tmp_mp);
1209 if (be_nvl_alloc(&be_attrs) != 0)
1210 return (1);
1212 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1213 goto out;
1215 if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0)
1216 goto out;
1218 if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS,
1219 mount_flags) != 0)
1220 goto out;
1222 err = be_mount(be_attrs);
1224 switch (err) {
1225 case BE_SUCCESS:
1226 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint);
1227 break;
1228 case BE_ERR_BE_NOENT:
1229 (void) fprintf(stderr, _("%s does not exist or appear "
1230 "to be a valid BE.\nPlease check that the name of "
1231 "the BE provided is correct.\n"), obe_name);
1232 break;
1233 case BE_ERR_MOUNTED:
1234 (void) fprintf(stderr, _("%s is already mounted.\n"
1235 "Please unmount the BE before mounting it again.\n"),
1236 obe_name);
1237 break;
1238 case BE_ERR_PERM:
1239 case BE_ERR_ACCESS:
1240 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1241 (void) fprintf(stderr, _("You have insufficient privileges to "
1242 "execute this command.\n"));
1243 break;
1244 case BE_ERR_NO_MOUNTED_ZONE:
1245 (void) fprintf(stderr, _("Mounted on '%s'.\nUnable to mount "
1246 "one of %s's zone BE's.\n"), mountpoint, obe_name);
1247 break;
1248 default:
1249 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1250 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1253 out:
1254 free(tmp_mp);
1255 nvlist_free(be_attrs);
1256 return (err);
1259 static int
1260 be_do_unmount(int argc, char **argv)
1262 nvlist_t *be_attrs;
1263 char *obe_name;
1264 int err = 1;
1265 int c;
1266 int unmount_flags = 0;
1268 while ((c = getopt(argc, argv, "fv")) != -1) {
1269 switch (c) {
1270 case 'f':
1271 unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
1272 break;
1273 case 'v':
1274 libbe_print_errors(B_TRUE);
1275 break;
1276 default:
1277 usage();
1278 return (1);
1282 argc -= optind;
1283 argv += optind;
1285 if (argc != 1) {
1286 usage();
1287 return (1);
1290 obe_name = argv[0];
1292 if (be_nvl_alloc(&be_attrs) != 0)
1293 return (1);
1296 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1297 goto out;
1299 if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS,
1300 unmount_flags) != 0)
1301 goto out;
1303 err = be_unmount(be_attrs);
1305 switch (err) {
1306 case BE_SUCCESS:
1307 (void) printf(_("Unmounted successfully\n"));
1308 break;
1309 case BE_ERR_BE_NOENT:
1310 (void) fprintf(stderr, _("%s does not exist or appear "
1311 "to be a valid BE.\nPlease check that the name of "
1312 "the BE provided is correct.\n"), obe_name);
1313 break;
1314 case BE_ERR_UMOUNT_CURR_BE:
1315 (void) fprintf(stderr, _("%s is the currently active BE.\n"
1316 "It cannot be unmounted unless another BE is the "
1317 "currently active BE.\n"), obe_name);
1318 break;
1319 case BE_ERR_UMOUNT_SHARED:
1320 (void) fprintf(stderr, _("%s is a shared file system and it "
1321 "cannot be unmounted.\n"), obe_name);
1322 break;
1323 case BE_ERR_PERM:
1324 case BE_ERR_ACCESS:
1325 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1326 (void) fprintf(stderr, _("You have insufficient privileges to "
1327 "execute this command.\n"));
1328 break;
1329 default:
1330 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1331 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1334 out:
1335 nvlist_free(be_attrs);
1336 return (err);
1339 static int
1340 be_do_rename(int argc, char **argv)
1342 nvlist_t *be_attrs;
1343 char *obe_name;
1344 char *nbe_name;
1345 int err = 1;
1346 int c;
1348 while ((c = getopt(argc, argv, "v")) != -1) {
1349 switch (c) {
1350 case 'v':
1351 libbe_print_errors(B_TRUE);
1352 break;
1353 default:
1354 usage();
1355 return (1);
1359 argc -= optind;
1360 argv += optind;
1362 if (argc != 2) {
1363 usage();
1364 return (1);
1367 obe_name = argv[0];
1368 nbe_name = argv[1];
1370 if (be_nvl_alloc(&be_attrs) != 0)
1371 return (1);
1373 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1374 goto out;
1376 if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
1377 goto out;
1379 err = be_rename(be_attrs);
1381 switch (err) {
1382 case BE_SUCCESS:
1383 (void) printf(_("Renamed successfully\n"));
1384 break;
1385 case BE_ERR_BE_NOENT:
1386 (void) fprintf(stderr, _("%s does not exist or appear "
1387 "to be a valid BE.\nPlease check that the name of "
1388 "the BE provided is correct.\n"), obe_name);
1389 break;
1390 case BE_ERR_PERM:
1391 case BE_ERR_ACCESS:
1392 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1393 obe_name);
1394 (void) fprintf(stderr, _("You have insufficient privileges to "
1395 "execute this command.\n"));
1396 break;
1397 default:
1398 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1399 obe_name);
1400 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1403 out:
1404 nvlist_free(be_attrs);
1405 return (err);
1408 static int
1409 be_do_rollback(int argc, char **argv)
1411 nvlist_t *be_attrs;
1412 char *obe_name;
1413 char *snap_name;
1414 int err = 1;
1415 int c;
1417 while ((c = getopt(argc, argv, "v")) != -1) {
1418 switch (c) {
1419 case 'v':
1420 libbe_print_errors(B_TRUE);
1421 break;
1422 default:
1423 usage();
1424 return (1);
1428 argc -= optind;
1429 argv += optind;
1431 if (argc < 1 || argc > 2) {
1432 usage();
1433 return (1);
1436 obe_name = argv[0];
1437 if (argc == 2)
1438 snap_name = argv[1];
1439 else { /* argc == 1 */
1440 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
1441 if (snap_name[1] == '\0') {
1442 usage();
1443 return (1);
1446 snap_name[0] = '\0';
1447 snap_name++;
1448 } else {
1449 usage();
1450 return (1);
1454 if (be_nvl_alloc(&be_attrs) != 0)
1455 return (1);
1457 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1458 goto out;
1460 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0)
1461 goto out;
1463 err = be_rollback(be_attrs);
1465 switch (err) {
1466 case BE_SUCCESS:
1467 (void) printf(_("Rolled back successfully\n"));
1468 break;
1469 case BE_ERR_BE_NOENT:
1470 (void) fprintf(stderr, _("%s does not exist or appear "
1471 "to be a valid BE.\nPlease check that the name of "
1472 "the BE provided is correct.\n"), obe_name);
1473 break;
1474 case BE_ERR_SS_NOENT:
1475 (void) fprintf(stderr, _("%s does not exist or appear "
1476 "to be a valid snapshot.\nPlease check that the name of "
1477 "the snapshot provided is correct.\n"), snap_name);
1478 break;
1479 case BE_ERR_PERM:
1480 case BE_ERR_ACCESS:
1481 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1482 "failed.\n"), obe_name, snap_name);
1483 (void) fprintf(stderr, _("You have insufficient privileges to "
1484 "execute this command.\n"));
1485 break;
1486 default:
1487 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1488 "failed.\n"), obe_name, snap_name);
1489 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1492 out:
1493 nvlist_free(be_attrs);
1494 return (err);