8672 proc_t changes broke genunix dmods and walker
[unleashed.git] / usr / src / cmd / beadm / beadm.c
blob3667c762a40a36228b2dcb97fa2e74a1c17eaa92
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 #ifndef lint
50 #define _(x) gettext(x)
51 #else
52 #define _(x) (x)
53 #endif
55 #ifndef TEXT_DOMAIN
56 #define TEXT_DOMAIN "SYS_TEST"
57 #endif
59 #define DT_BUF_LEN (128)
60 #define NUM_COLS (6)
61 CTASSERT(DT_BUF_LEN >= NN_NUMBUF_SZ);
63 static int be_do_activate(int argc, char **argv);
64 static int be_do_create(int argc, char **argv);
65 static int be_do_destroy(int argc, char **argv);
66 static int be_do_list(int argc, char **argv);
67 static int be_do_mount(int argc, char **argv);
68 static int be_do_unmount(int argc, char **argv);
69 static int be_do_rename(int argc, char **argv);
70 static int be_do_rollback(int argc, char **argv);
71 static void usage(void);
74 * single column name/width output format description
76 struct col_info {
77 const char *col_name;
78 size_t width;
82 * all columns output format
84 struct hdr_info {
85 struct col_info cols[NUM_COLS];
89 * type of possible output formats
91 enum be_fmt {
92 BE_FMT_DEFAULT,
93 BE_FMT_DATASET,
94 BE_FMT_SNAPSHOT,
95 BE_FMT_ALL
99 * command handler description
101 typedef struct be_command {
102 const char *name;
103 int (*func)(int argc, char **argv);
104 } be_command_t;
107 * sorted list of be commands
109 static const be_command_t be_command_tbl[] = {
110 { "activate", be_do_activate },
111 { "create", be_do_create },
112 { "destroy", be_do_destroy },
113 { "list", be_do_list },
114 { "mount", be_do_mount },
115 { "unmount", be_do_unmount },
116 { "umount", be_do_unmount }, /* unmount alias */
117 { "rename", be_do_rename },
118 { "rollback", be_do_rollback },
119 { NULL, NULL },
122 static void
123 usage(void)
125 (void) fprintf(stderr, _("usage:\n"
126 "\tbeadm subcommand cmd_options\n"
127 "\n"
128 "\tsubcommands:\n"
129 "\n"
130 "\tbeadm activate [-v] beName\n"
131 "\tbeadm create [-a] [-d BE_desc]\n"
132 "\t\t[-o property=value] ... [-p zpool] \n"
133 "\t\t[-e nonActiveBe | beName@snapshot] [-v] beName\n"
134 "\tbeadm create [-d BE_desc]\n"
135 "\t\t[-o property=value] ... [-p zpool] [-v] beName@snapshot\n"
136 "\tbeadm destroy [-Ffsv] beName \n"
137 "\tbeadm destroy [-Fv] beName@snapshot \n"
138 "\tbeadm list [[-a] | [-d] [-s]] [-H]\n"
139 "\t\t[-k|-K date | name | space] [-v] [beName]\n"
140 "\tbeadm mount [-s ro|rw] [-v] beName [mountpoint]\n"
141 "\tbeadm unmount [-fv] beName | mountpoint\n"
142 "\tbeadm umount [-fv] beName | mountpoint\n"
143 "\tbeadm rename [-v] origBeName newBeName\n"
144 "\tbeadm rollback [-v] beName snapshot\n"
145 "\tbeadm rollback [-v] beName@snapshot\n"));
148 static int
149 run_be_cmd(const char *cmdname, int argc, char **argv)
151 const be_command_t *command;
153 for (command = &be_command_tbl[0]; command->name != NULL; command++)
154 if (strcmp(command->name, cmdname) == 0)
155 return (command->func(argc, argv));
157 (void) fprintf(stderr, _("Invalid command: %s\n"), cmdname);
158 usage();
159 return (1);
163 main(int argc, char **argv)
165 const char *cmdname;
167 (void) setlocale(LC_ALL, "");
168 (void) textdomain(TEXT_DOMAIN);
170 if (argc < 2) {
171 usage();
172 return (1);
175 cmdname = argv[1];
177 /* Turn error printing off */
178 libbe_print_errors(B_FALSE);
180 return (run_be_cmd(cmdname, --argc, ++argv));
183 static void
184 print_hdr(struct hdr_info *hdr_info)
186 boolean_t first = B_TRUE;
187 size_t i;
188 for (i = 0; i < NUM_COLS; i++) {
189 struct col_info *col_info = &hdr_info->cols[i];
190 const char *name = col_info->col_name;
191 size_t width = col_info->width;
192 if (name == NULL)
193 continue;
195 if (first) {
196 (void) printf("%-*s", width, name);
197 first = B_FALSE;
198 } else
199 (void) printf(" %-*s", width, name);
201 (void) putchar('\n');
204 static void
205 init_hdr_cols(enum be_fmt be_fmt, struct hdr_info *hdr)
207 struct col_info *col = hdr->cols;
208 size_t i;
210 col[1].col_name = _("Active");
211 col[2].col_name = _("Mountpoint");
212 col[3].col_name = _("Space");
213 col[4].col_name = _("Policy");
214 col[5].col_name = _("Created");
215 col[6].col_name = NULL;
217 switch (be_fmt) {
218 case BE_FMT_ALL:
219 col[0].col_name = _("BE/Dataset/Snapshot");
220 break;
221 case BE_FMT_DATASET:
222 col[0].col_name = _("BE/Dataset");
223 break;
224 case BE_FMT_SNAPSHOT:
225 col[0].col_name = _("BE/Snapshot");
226 col[1].col_name = NULL;
227 col[2].col_name = NULL;
228 break;
229 case BE_FMT_DEFAULT:
230 default:
231 col[0].col_name = _("BE");
234 for (i = 0; i < NUM_COLS; i++) {
235 const char *name = col[i].col_name;
236 col[i].width = 0;
238 if (name != NULL) {
239 wchar_t wname[128];
240 size_t sz = mbstowcs(wname, name, sizeof (wname) /
241 sizeof (wchar_t));
242 if (sz > 0) {
243 int wcsw = wcswidth(wname, sz);
244 if (wcsw > 0)
245 col[i].width = wcsw;
246 else
247 col[i].width = sz;
248 } else {
249 col[i].width = strlen(name);
255 static void
256 count_widths(enum be_fmt be_fmt, struct hdr_info *hdr, be_node_list_t *be_nodes)
258 size_t len[NUM_COLS];
259 char buf[DT_BUF_LEN];
260 int i;
261 be_node_list_t *cur_be;
263 for (i = 0; i < NUM_COLS; i++)
264 len[i] = hdr->cols[i].width;
266 for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
267 char name[ZFS_MAX_DATASET_NAME_LEN + 1];
268 const char *be_name = cur_be->be_node_name;
269 const char *root_ds = cur_be->be_root_ds;
270 char *pos;
271 size_t node_name_len = strlen(cur_be->be_node_name);
272 size_t root_ds_len = strlen(cur_be->be_root_ds);
273 size_t mntpt_len = 0;
274 size_t policy_len = 0;
275 size_t used_len;
276 uint64_t used = cur_be->be_space_used;
277 be_snapshot_list_t *snap = NULL;
279 if (cur_be->be_mntpt != NULL)
280 mntpt_len = strlen(cur_be->be_mntpt);
281 if (cur_be->be_policy_type != NULL)
282 policy_len = strlen(cur_be->be_policy_type);
284 (void) strlcpy(name, root_ds, sizeof (name));
285 pos = strstr(name, be_name);
287 if (be_fmt == BE_FMT_DEFAULT) {
288 if (node_name_len > len[0])
289 len[0] = node_name_len;
290 } else {
291 if (root_ds_len + 3 > len[0])
292 len[0] = root_ds_len + 3;
295 if (mntpt_len > len[2])
296 len[2] = mntpt_len;
297 if (policy_len > len[4])
298 len[4] = policy_len;
300 for (snap = cur_be->be_node_snapshots; snap != NULL;
301 snap = snap->be_next_snapshot) {
302 uint64_t snap_used = snap->be_snapshot_space_used;
303 const char *snap_name = snap->be_snapshot_name;
304 (void) strcpy(pos, snap_name);
306 if (be_fmt == BE_FMT_DEFAULT)
307 used += snap_used;
308 else if (be_fmt & BE_FMT_SNAPSHOT) {
309 int snap_len = strlen(name) + 3;
310 if (be_fmt == BE_FMT_SNAPSHOT)
311 snap_len -= pos - name;
312 if (snap_len > len[0])
313 len[0] = snap_len;
314 nicenum(snap_used, buf, sizeof (buf));
315 used_len = strlen(buf);
316 if (used_len > len[3])
317 len[3] = used_len;
321 if (be_fmt == BE_FMT_DEFAULT) {
322 int used_len;
323 nicenum(used, buf, sizeof (buf));
324 used_len = strlen(buf);
325 if (used_len > len[3])
326 len[3] = used_len;
329 nicenum(used, buf, sizeof (buf));
332 for (i = 0; i < NUM_COLS; i++)
333 hdr->cols[i].width = len[i];
336 static void
337 print_be_nodes(const char *be_name, boolean_t parsable, struct hdr_info *hdr,
338 be_node_list_t *nodes)
340 char buf[64];
341 char datetime[DT_BUF_LEN];
342 be_node_list_t *cur_be;
344 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
345 char active[3] = "-\0";
346 int ai = 0;
347 const char *datetime_fmt = "%F %R";
348 const char *name = cur_be->be_node_name;
349 const char *mntpt = cur_be->be_mntpt;
350 const char *uuid_str = cur_be->be_uuid_str;
351 be_snapshot_list_t *snap = NULL;
352 uint64_t used = cur_be->be_space_used;
353 time_t creation = cur_be->be_node_creation;
354 struct tm *tm;
356 if (be_name != NULL && strcmp(be_name, name) != 0)
357 continue;
359 if (parsable)
360 active[0] = '\0';
362 tm = localtime(&creation);
363 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
365 for (snap = cur_be->be_node_snapshots; snap != NULL;
366 snap = snap->be_next_snapshot)
367 used += snap->be_snapshot_space_used;
369 if (!cur_be->be_global_active)
370 active[ai++] = 'x';
372 if (cur_be->be_active)
373 active[ai++] = 'N';
374 if (cur_be->be_active_on_boot) {
375 if (!cur_be->be_global_active)
376 active[ai] = 'b';
377 else
378 active[ai] = 'R';
381 nicenum(used, buf, sizeof (buf));
382 if (parsable)
383 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
384 name,
385 (uuid_str != NULL ? uuid_str: ""),
386 active,
387 (cur_be->be_mounted ? mntpt: ""),
388 used,
389 cur_be->be_policy_type,
390 creation);
391 else
392 (void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n",
393 hdr->cols[0].width, name,
394 hdr->cols[1].width, active,
395 hdr->cols[2].width, (cur_be->be_mounted ? mntpt:
396 "-"),
397 hdr->cols[3].width, buf,
398 hdr->cols[4].width, cur_be->be_policy_type,
399 hdr->cols[5].width, datetime);
403 static void
404 print_be_snapshots(be_node_list_t *be, struct hdr_info *hdr, boolean_t parsable)
406 char buf[64];
407 char datetime[DT_BUF_LEN];
408 be_snapshot_list_t *snap = NULL;
410 for (snap = be->be_node_snapshots; snap != NULL;
411 snap = snap->be_next_snapshot) {
412 char name[ZFS_MAX_DATASET_NAME_LEN + 1];
413 const char *datetime_fmt = "%F %R";
414 const char *be_name = be->be_node_name;
415 const char *root_ds = be->be_root_ds;
416 const char *snap_name = snap->be_snapshot_name;
417 char *pos;
418 uint64_t used = snap->be_snapshot_space_used;
419 time_t creation = snap->be_snapshot_creation;
420 struct tm *tm = localtime(&creation);
422 (void) strncpy(name, root_ds, sizeof (name));
423 pos = strstr(name, be_name);
424 (void) strcpy(pos, snap_name);
426 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
427 nicenum(used, buf, sizeof (buf));
429 if (parsable)
430 if (hdr->cols[1].width != 0)
431 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
432 be_name,
433 snap_name,
436 used,
437 be->be_policy_type,
438 creation);
439 else
440 (void) printf("%s;%s;%llu;%s;%ld\n",
441 be_name,
442 snap_name,
443 used,
444 be->be_policy_type,
445 creation);
446 else
447 if (hdr->cols[1].width != 0)
448 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
449 "%-*s\n",
450 hdr->cols[0].width-3, name,
451 hdr->cols[1].width, "-",
452 hdr->cols[2].width, "-",
453 hdr->cols[3].width, buf,
454 hdr->cols[4].width, be->be_policy_type,
455 hdr->cols[5].width, datetime);
456 else
457 (void) printf(" %-*s %-*s %-*s %-*s\n",
458 hdr->cols[0].width-3, snap_name,
459 hdr->cols[3].width, buf,
460 hdr->cols[4].width, be->be_policy_type,
461 hdr->cols[5].width, datetime);
465 static void
466 print_fmt_nodes(const char *be_name, enum be_fmt be_fmt, boolean_t parsable,
467 struct hdr_info *hdr, be_node_list_t *nodes)
469 char buf[64];
470 char datetime[DT_BUF_LEN];
471 be_node_list_t *cur_be;
473 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
474 char active[3] = "-\0";
475 int ai = 0;
476 const char *datetime_fmt = "%F %R";
477 const char *name = cur_be->be_node_name;
478 const char *mntpt = cur_be->be_mntpt;
479 uint64_t used = cur_be->be_space_used;
480 time_t creation = cur_be->be_node_creation;
481 struct tm *tm;
483 if (be_name != NULL && strcmp(be_name, name) != 0)
484 continue;
486 if (!parsable)
487 (void) printf("%-s\n", name);
488 else
489 active[0] = '\0';
491 tm = localtime(&creation);
492 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
494 if (cur_be->be_active)
495 active[ai++] = 'N';
496 if (cur_be->be_active_on_boot)
497 active[ai] = 'R';
499 nicenum(used, buf, sizeof (buf));
500 if (be_fmt & BE_FMT_DATASET)
501 if (parsable)
502 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
503 cur_be->be_node_name,
504 cur_be->be_root_ds,
505 active,
506 (cur_be->be_mounted ? mntpt: ""),
507 used,
508 cur_be->be_policy_type,
509 creation);
510 else
511 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
512 "%-*s\n",
513 hdr->cols[0].width-3, cur_be->be_root_ds,
514 hdr->cols[1].width, active,
515 hdr->cols[2].width, (cur_be->be_mounted ?
516 mntpt: "-"),
517 hdr->cols[3].width, buf,
518 hdr->cols[4].width, cur_be->be_policy_type,
519 hdr->cols[5].width, datetime);
521 if (be_fmt & BE_FMT_SNAPSHOT)
522 print_be_snapshots(cur_be, hdr, parsable);
526 static void
527 print_nodes(const char *be_name, boolean_t dsets, boolean_t snaps,
528 boolean_t parsable, be_node_list_t *be_nodes)
530 struct hdr_info hdr;
531 enum be_fmt be_fmt = BE_FMT_DEFAULT;
533 if (dsets)
534 be_fmt |= BE_FMT_DATASET;
535 if (snaps)
536 be_fmt |= BE_FMT_SNAPSHOT;
538 if (!parsable) {
539 init_hdr_cols(be_fmt, &hdr);
540 count_widths(be_fmt, &hdr, be_nodes);
541 print_hdr(&hdr);
544 if (be_fmt == BE_FMT_DEFAULT)
545 print_be_nodes(be_name, parsable, &hdr, be_nodes);
546 else
547 print_fmt_nodes(be_name, be_fmt, parsable, &hdr, be_nodes);
550 static boolean_t
551 confirm_destroy(const char *name)
553 boolean_t res = B_FALSE;
554 const char *yesre = nl_langinfo(YESEXPR);
555 const char *nore = nl_langinfo(NOEXPR);
556 regex_t yes_re;
557 regex_t no_re;
558 char buf[128];
559 char *answer;
560 int cflags = REG_EXTENDED;
562 if (regcomp(&yes_re, yesre, cflags) != 0) {
563 /* should not happen */
564 (void) fprintf(stderr, _("Failed to compile 'yes' regexp\n"));
565 return (res);
567 if (regcomp(&no_re, nore, cflags) != 0) {
568 /* should not happen */
569 (void) fprintf(stderr, _("Failed to compile 'no' regexp\n"));
570 regfree(&yes_re);
571 return (res);
574 (void) printf(_("Are you sure you want to destroy %s?\n"
575 "This action cannot be undone (y/[n]): "), name);
577 answer = fgets(buf, sizeof (buf), stdin);
578 if (answer == NULL || *answer == '\0' || *answer == 10)
579 goto out;
581 if (regexec(&yes_re, answer, 0, NULL, 0) == 0) {
582 res = B_TRUE;
583 } else if (regexec(&no_re, answer, 0, NULL, 0) != 0) {
584 (void) fprintf(stderr, _("Invalid response. "
585 "Please enter 'y' or 'n'.\n"));
588 out:
589 regfree(&yes_re);
590 regfree(&no_re);
591 return (res);
594 static int
595 be_nvl_alloc(nvlist_t **nvlp)
597 assert(nvlp != NULL);
599 if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) {
600 (void) perror(_("nvlist_alloc failed.\n"));
601 return (1);
604 return (0);
607 static int
608 be_nvl_add_string(nvlist_t *nvl, const char *name, const char *val)
610 assert(nvl != NULL);
612 if (nvlist_add_string(nvl, name, val) != 0) {
613 (void) fprintf(stderr, _("nvlist_add_string failed for "
614 "%s (%s).\n"), name, val);
615 return (1);
618 return (0);
621 static int
622 be_nvl_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
624 assert(nvl != NULL);
626 if (nvlist_add_nvlist(nvl, name, val) != 0) {
627 (void) fprintf(stderr, _("nvlist_add_nvlist failed for %s.\n"),
628 name);
629 return (1);
632 return (0);
635 static int
636 be_nvl_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
638 assert(nvl != NULL);
640 if (nvlist_add_uint16(nvl, name, val) != 0) {
641 (void) fprintf(stderr, _("nvlist_add_uint16 failed for "
642 "%s (%hu).\n"), name, val);
643 return (1);
646 return (0);
649 static int
650 be_do_activate(int argc, char **argv)
652 nvlist_t *be_attrs;
653 int err = 1;
654 int c;
655 char *obe_name;
657 while ((c = getopt(argc, argv, "v")) != -1) {
658 switch (c) {
659 case 'v':
660 libbe_print_errors(B_TRUE);
661 break;
662 default:
663 usage();
664 return (1);
668 argc -= optind;
669 argv += optind;
671 if (argc != 1) {
672 usage();
673 return (1);
676 obe_name = argv[0];
678 if (be_nvl_alloc(&be_attrs) != 0)
679 return (1);
681 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
682 goto out;
684 err = be_activate(be_attrs);
686 switch (err) {
687 case BE_SUCCESS:
688 (void) printf(_("Activated successfully\n"));
689 break;
690 case BE_ERR_BE_NOENT:
691 (void) fprintf(stderr, _("%s does not exist or appear "
692 "to be a valid BE.\nPlease check that the name of "
693 "the BE provided is correct.\n"), obe_name);
694 break;
695 case BE_ERR_PERM:
696 case BE_ERR_ACCESS:
697 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
698 (void) fprintf(stderr, _("You have insufficient privileges to "
699 "execute this command.\n"));
700 break;
701 case BE_ERR_ACTIVATE_CURR:
702 default:
703 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
704 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
707 out:
708 nvlist_free(be_attrs);
709 return (err);
712 static int
713 be_do_create(int argc, char **argv)
715 nvlist_t *be_attrs;
716 nvlist_t *zfs_props = NULL;
717 boolean_t activate = B_FALSE;
718 boolean_t is_snap = B_FALSE;
719 int c;
720 int err = 1;
721 char *obe_name = NULL;
722 char *snap_name = NULL;
723 char *nbe_zpool = NULL;
724 char *nbe_name = NULL;
725 char *nbe_desc = NULL;
726 char *propname = NULL;
727 char *propval = NULL;
728 char *strval = NULL;
730 while ((c = getopt(argc, argv, "ad:e:io:p:v")) != -1) {
731 switch (c) {
732 case 'a':
733 activate = B_TRUE;
734 break;
735 case 'd':
736 nbe_desc = optarg;
737 break;
738 case 'e':
739 obe_name = optarg;
740 break;
741 case 'o':
742 if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0)
743 return (1);
745 propname = optarg;
746 if ((propval = strchr(propname, '=')) == NULL) {
747 (void) fprintf(stderr, _("missing "
748 "'=' for -o option\n"));
749 goto out2;
751 *propval = '\0';
752 propval++;
753 if (nvlist_lookup_string(zfs_props, propname,
754 &strval) == 0) {
755 (void) fprintf(stderr, _("property '%s' "
756 "specified multiple times\n"), propname);
757 goto out2;
760 if (be_nvl_add_string(zfs_props, propname, propval)
761 != 0)
762 goto out2;
764 break;
765 case 'p':
766 nbe_zpool = optarg;
767 break;
768 case 'v':
769 libbe_print_errors(B_TRUE);
770 break;
771 default:
772 usage();
773 goto out2;
777 argc -= optind;
778 argv += optind;
780 if (argc != 1) {
781 usage();
782 goto out2;
785 nbe_name = argv[0];
787 if ((snap_name = strrchr(nbe_name, '@')) != NULL) {
788 if (snap_name[1] == '\0') {
789 usage();
790 goto out2;
793 snap_name[0] = '\0';
794 snap_name++;
795 is_snap = B_TRUE;
798 if (obe_name) {
799 if (is_snap) {
800 usage();
801 goto out2;
805 * Check if obe_name is really a snapshot name.
806 * If so, split it out.
808 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
809 if (snap_name[1] == '\0') {
810 usage();
811 goto out2;
814 snap_name[0] = '\0';
815 snap_name++;
817 } else if (is_snap) {
818 obe_name = nbe_name;
819 nbe_name = NULL;
822 if (be_nvl_alloc(&be_attrs) != 0)
823 goto out2;
826 if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs,
827 BE_ATTR_ORIG_BE_NAME, zfs_props) != 0)
828 goto out;
830 if (obe_name != NULL && be_nvl_add_string(be_attrs,
831 BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
832 goto out;
834 if (snap_name != NULL && be_nvl_add_string(be_attrs,
835 BE_ATTR_SNAP_NAME, snap_name) != 0)
836 goto out;
838 if (nbe_zpool != NULL && be_nvl_add_string(be_attrs,
839 BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0)
840 goto out;
842 if (nbe_name != NULL && be_nvl_add_string(be_attrs,
843 BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
844 goto out;
846 if (nbe_desc != NULL && be_nvl_add_string(be_attrs,
847 BE_ATTR_NEW_BE_DESC, nbe_desc) != 0)
848 goto out;
850 if (is_snap)
851 err = be_create_snapshot(be_attrs);
852 else
853 err = be_copy(be_attrs);
855 switch (err) {
856 case BE_SUCCESS:
857 if (!is_snap && !nbe_name) {
859 * We requested an auto named BE; find out the
860 * name of the BE that was created for us and
861 * the auto snapshot created from the original BE.
863 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME,
864 &nbe_name) != 0) {
865 (void) fprintf(stderr, _("failed to get %s "
866 "attribute\n"), BE_ATTR_NEW_BE_NAME);
867 break;
868 } else
869 (void) printf(_("Auto named BE: %s\n"),
870 nbe_name);
872 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
873 &snap_name) != 0) {
874 (void) fprintf(stderr, _("failed to get %s "
875 "attribute\n"), BE_ATTR_SNAP_NAME);
876 break;
877 } else
878 (void) printf(_("Auto named snapshot: %s\n"),
879 snap_name);
882 if (!is_snap && activate) {
883 char *args[] = { "activate", "", NULL };
884 args[1] = nbe_name;
885 optind = 1;
887 err = be_do_activate(2, args);
888 goto out;
891 (void) printf(_("Created successfully\n"));
892 break;
893 case BE_ERR_BE_EXISTS:
894 (void) fprintf(stderr, _("BE %s already exists\n."
895 "Please choose a different BE name.\n"), nbe_name);
896 break;
897 case BE_ERR_SS_EXISTS:
898 (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n"
899 "Please choose a different snapshot name.\n"), obe_name,
900 snap_name);
901 break;
902 case BE_ERR_PERM:
903 case BE_ERR_ACCESS:
904 if (is_snap)
905 (void) fprintf(stderr, _("Unable to create snapshot "
906 "%s.\n"), snap_name);
907 else
908 (void) fprintf(stderr, _("Unable to create %s.\n"),
909 nbe_name);
910 (void) fprintf(stderr, _("You have insufficient privileges to "
911 "execute this command.\n"));
912 break;
913 default:
914 if (is_snap)
915 (void) fprintf(stderr, _("Unable to create snapshot "
916 "%s.\n"), snap_name);
917 else
918 (void) fprintf(stderr, _("Unable to create %s.\n"),
919 nbe_name);
920 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
923 out:
924 nvlist_free(be_attrs);
925 out2:
926 nvlist_free(zfs_props);
928 return (err);
931 static int
932 be_do_destroy(int argc, char **argv)
934 nvlist_t *be_attrs;
935 boolean_t is_snap = B_FALSE;
936 boolean_t suppress_prompt = B_FALSE;
937 int err = 1;
938 int c;
939 int destroy_flags = 0;
940 char *snap_name;
941 char *be_name;
943 while ((c = getopt(argc, argv, "fFsv")) != -1) {
944 switch (c) {
945 case 'f':
946 destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
947 break;
948 case 's':
949 destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
950 break;
951 case 'v':
952 libbe_print_errors(B_TRUE);
953 break;
954 case 'F':
955 suppress_prompt = B_TRUE;
956 break;
957 default:
958 usage();
959 return (1);
963 argc -= optind;
964 argv += optind;
966 if (argc != 1) {
967 usage();
968 return (1);
971 be_name = argv[0];
972 if (!suppress_prompt && !confirm_destroy(be_name)) {
973 (void) printf(_("%s has not been destroyed.\n"), be_name);
974 return (0);
977 if ((snap_name = strrchr(be_name, '@')) != NULL) {
978 if (snap_name[1] == '\0') {
979 usage();
980 return (1);
983 is_snap = B_TRUE;
984 *snap_name = '\0';
985 snap_name++;
988 if (be_nvl_alloc(&be_attrs) != 0)
989 return (1);
992 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0)
993 goto out;
995 if (is_snap) {
996 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME,
997 snap_name) != 0)
998 goto out;
1000 err = be_destroy_snapshot(be_attrs);
1001 } else {
1002 if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS,
1003 destroy_flags) != 0)
1004 goto out;
1006 err = be_destroy(be_attrs);
1009 switch (err) {
1010 case BE_SUCCESS:
1011 (void) printf(_("Destroyed successfully\n"));
1012 break;
1013 case BE_ERR_MOUNTED:
1014 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1015 (void) fprintf(stderr, _("It is currently mounted and must be "
1016 "unmounted before it can be destroyed.\n" "Use 'beadm "
1017 "unmount %s' to unmount the BE before destroying\nit or "
1018 "'beadm destroy -f %s'.\n"), be_name, be_name);
1019 break;
1020 case BE_ERR_DESTROY_CURR_BE:
1021 (void) fprintf(stderr, _("%s is the currently active BE and "
1022 "cannot be destroyed.\nYou must boot from another BE in "
1023 "order to destroy %s.\n"), be_name, be_name);
1024 break;
1025 case BE_ERR_ZONES_UNMOUNT:
1026 (void) fprintf(stderr, _("Unable to destroy one of " "%s's "
1027 "zone BE's.\nUse 'beadm destroy -f %s' or "
1028 "'zfs -f destroy <dataset>'.\n"), be_name, be_name);
1029 break;
1030 case BE_ERR_SS_NOENT:
1031 (void) fprintf(stderr, _("%s does not exist or appear "
1032 "to be a valid snapshot.\nPlease check that the name of "
1033 "the snapshot provided is correct.\n"), snap_name);
1034 break;
1035 case BE_ERR_PERM:
1036 case BE_ERR_ACCESS:
1037 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1038 (void) fprintf(stderr, _("You have insufficient privileges to "
1039 "execute this command.\n"));
1040 break;
1041 case BE_ERR_SS_EXISTS:
1042 (void) fprintf(stderr, _("Unable to destroy %s: "
1043 "BE has snapshots.\nUse 'beadm destroy -s %s' or "
1044 "'zfs -r destroy <dataset>'.\n"), be_name, be_name);
1045 break;
1046 default:
1047 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1048 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1051 out:
1052 nvlist_free(be_attrs);
1053 return (err);
1056 static int
1057 be_do_list(int argc, char **argv)
1059 be_node_list_t *be_nodes = NULL;
1060 boolean_t all = B_FALSE;
1061 boolean_t dsets = B_FALSE;
1062 boolean_t snaps = B_FALSE;
1063 boolean_t parsable = B_FALSE;
1064 int err = 1;
1065 int c = 0;
1066 char *be_name = NULL;
1067 be_sort_t order = BE_SORT_UNSPECIFIED;
1069 while ((c = getopt(argc, argv, "adk:svHK:")) != -1) {
1070 switch (c) {
1071 case 'a':
1072 all = B_TRUE;
1073 break;
1074 case 'd':
1075 dsets = B_TRUE;
1076 break;
1077 case 'k':
1078 case 'K':
1079 if (order != BE_SORT_UNSPECIFIED) {
1080 (void) fprintf(stderr, _("Sort key can be "
1081 "specified only once.\n"));
1082 usage();
1083 return (1);
1085 if (strcmp(optarg, "date") == 0) {
1086 if (c == 'k')
1087 order = BE_SORT_DATE;
1088 else
1089 order = BE_SORT_DATE_REV;
1090 break;
1092 if (strcmp(optarg, "name") == 0) {
1093 if (c == 'k')
1094 order = BE_SORT_NAME;
1095 else
1096 order = BE_SORT_NAME_REV;
1097 break;
1099 if (strcmp(optarg, "space") == 0) {
1100 if (c == 'k')
1101 order = BE_SORT_SPACE;
1102 else
1103 order = BE_SORT_SPACE_REV;
1104 break;
1106 (void) fprintf(stderr, _("Unknown sort key: %s\n"),
1107 optarg);
1108 usage();
1109 return (1);
1110 case 's':
1111 snaps = B_TRUE;
1112 break;
1113 case 'v':
1114 libbe_print_errors(B_TRUE);
1115 break;
1116 case 'H':
1117 parsable = B_TRUE;
1118 break;
1119 default:
1120 usage();
1121 return (1);
1125 if (all) {
1126 if (dsets) {
1127 (void) fprintf(stderr, _("Invalid options: -a and %s "
1128 "are mutually exclusive.\n"), "-d");
1129 usage();
1130 return (1);
1132 if (snaps) {
1133 (void) fprintf(stderr, _("Invalid options: -a and %s "
1134 "are mutually exclusive.\n"), "-s");
1135 usage();
1136 return (1);
1139 dsets = B_TRUE;
1140 snaps = B_TRUE;
1143 argc -= optind;
1144 argv += optind;
1147 if (argc == 1)
1148 be_name = argv[0];
1150 err = be_list(be_name, &be_nodes);
1152 switch (err) {
1153 case BE_SUCCESS:
1154 /* the default sort is ascending date, no need to sort twice */
1155 if (order == BE_SORT_UNSPECIFIED)
1156 order = BE_SORT_DATE;
1158 if (order != BE_SORT_DATE) {
1159 err = be_sort(&be_nodes, order);
1160 if (err != BE_SUCCESS) {
1161 (void) fprintf(stderr, _("Unable to sort Boot "
1162 "Environment\n"));
1163 (void) fprintf(stderr, "%s\n",
1164 be_err_to_str(err));
1165 break;
1169 print_nodes(be_name, dsets, snaps, parsable, be_nodes);
1170 break;
1171 case BE_ERR_BE_NOENT:
1172 if (be_name == NULL)
1173 (void) fprintf(stderr, _("No boot environments found "
1174 "on this system.\n"));
1175 else {
1176 (void) fprintf(stderr, _("%s does not exist or appear "
1177 "to be a valid BE.\nPlease check that the name of "
1178 "the BE provided is correct.\n"), be_name);
1180 break;
1181 default:
1182 (void) fprintf(stderr, _("Unable to display Boot "
1183 "Environment\n"));
1184 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1187 if (be_nodes != NULL)
1188 be_free_list(be_nodes);
1189 return (err);
1192 static int
1193 be_do_mount(int argc, char **argv)
1195 nvlist_t *be_attrs;
1196 boolean_t shared_fs = B_FALSE;
1197 int err = 1;
1198 int c;
1199 int mount_flags = 0;
1200 char *obe_name;
1201 char *mountpoint;
1202 char *tmp_mp = NULL;
1204 while ((c = getopt(argc, argv, "s:v")) != -1) {
1205 switch (c) {
1206 case 's':
1207 shared_fs = B_TRUE;
1209 mount_flags |= BE_MOUNT_FLAG_SHARED_FS;
1211 if (strcmp(optarg, "rw") == 0) {
1212 mount_flags |= BE_MOUNT_FLAG_SHARED_RW;
1213 } else if (strcmp(optarg, "ro") != 0) {
1214 (void) fprintf(stderr, _("The -s flag "
1215 "requires an argument [ rw | ro ]\n"));
1216 usage();
1217 return (1);
1220 break;
1221 case 'v':
1222 libbe_print_errors(B_TRUE);
1223 break;
1224 default:
1225 usage();
1226 return (1);
1230 argc -= optind;
1231 argv += optind;
1233 if (argc < 1 || argc > 2) {
1234 usage();
1235 return (1);
1238 obe_name = argv[0];
1240 if (argc == 2) {
1241 mountpoint = argv[1];
1242 if (mountpoint[0] != '/') {
1243 (void) fprintf(stderr, _("Invalid mount point %s. "
1244 "Mount point must start with a /.\n"), mountpoint);
1245 return (1);
1247 } else {
1248 const char *tmpdir = getenv("TMPDIR");
1249 const char *tmpname = "tmp.XXXXXX";
1250 int sz;
1252 if (tmpdir == NULL)
1253 tmpdir = "/tmp";
1255 sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname);
1256 if (sz < 0) {
1257 (void) fprintf(stderr, _("internal error: "
1258 "out of memory\n"));
1259 return (1);
1262 mountpoint = mkdtemp(tmp_mp);
1265 if (be_nvl_alloc(&be_attrs) != 0)
1266 return (1);
1268 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1269 goto out;
1271 if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0)
1272 goto out;
1274 if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS,
1275 mount_flags) != 0)
1276 goto out;
1278 err = be_mount(be_attrs);
1280 switch (err) {
1281 case BE_SUCCESS:
1282 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint);
1283 break;
1284 case BE_ERR_BE_NOENT:
1285 (void) fprintf(stderr, _("%s does not exist or appear "
1286 "to be a valid BE.\nPlease check that the name of "
1287 "the BE provided is correct.\n"), obe_name);
1288 break;
1289 case BE_ERR_MOUNTED:
1290 (void) fprintf(stderr, _("%s is already mounted.\n"
1291 "Please unmount the BE before mounting it again.\n"),
1292 obe_name);
1293 break;
1294 case BE_ERR_PERM:
1295 case BE_ERR_ACCESS:
1296 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1297 (void) fprintf(stderr, _("You have insufficient privileges to "
1298 "execute this command.\n"));
1299 break;
1300 case BE_ERR_NO_MOUNTED_ZONE:
1301 (void) fprintf(stderr, _("Mounted on '%s'.\nUnable to mount "
1302 "one of %s's zone BE's.\n"), mountpoint, obe_name);
1303 break;
1304 default:
1305 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1306 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1309 out:
1310 if (tmp_mp != NULL)
1311 free(tmp_mp);
1312 nvlist_free(be_attrs);
1313 return (err);
1316 static int
1317 be_do_unmount(int argc, char **argv)
1319 nvlist_t *be_attrs;
1320 char *obe_name;
1321 int err = 1;
1322 int c;
1323 int unmount_flags = 0;
1325 while ((c = getopt(argc, argv, "fv")) != -1) {
1326 switch (c) {
1327 case 'f':
1328 unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
1329 break;
1330 case 'v':
1331 libbe_print_errors(B_TRUE);
1332 break;
1333 default:
1334 usage();
1335 return (1);
1339 argc -= optind;
1340 argv += optind;
1342 if (argc != 1) {
1343 usage();
1344 return (1);
1347 obe_name = argv[0];
1349 if (be_nvl_alloc(&be_attrs) != 0)
1350 return (1);
1353 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1354 goto out;
1356 if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS,
1357 unmount_flags) != 0)
1358 goto out;
1360 err = be_unmount(be_attrs);
1362 switch (err) {
1363 case BE_SUCCESS:
1364 (void) printf(_("Unmounted successfully\n"));
1365 break;
1366 case BE_ERR_BE_NOENT:
1367 (void) fprintf(stderr, _("%s does not exist or appear "
1368 "to be a valid BE.\nPlease check that the name of "
1369 "the BE provided is correct.\n"), obe_name);
1370 break;
1371 case BE_ERR_UMOUNT_CURR_BE:
1372 (void) fprintf(stderr, _("%s is the currently active BE.\n"
1373 "It cannot be unmounted unless another BE is the "
1374 "currently active BE.\n"), obe_name);
1375 break;
1376 case BE_ERR_UMOUNT_SHARED:
1377 (void) fprintf(stderr, _("%s is a shared file system and it "
1378 "cannot be unmounted.\n"), obe_name);
1379 break;
1380 case BE_ERR_PERM:
1381 case BE_ERR_ACCESS:
1382 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1383 (void) fprintf(stderr, _("You have insufficient privileges to "
1384 "execute this command.\n"));
1385 break;
1386 default:
1387 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1388 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1391 out:
1392 nvlist_free(be_attrs);
1393 return (err);
1396 static int
1397 be_do_rename(int argc, char **argv)
1399 nvlist_t *be_attrs;
1400 char *obe_name;
1401 char *nbe_name;
1402 int err = 1;
1403 int c;
1405 while ((c = getopt(argc, argv, "v")) != -1) {
1406 switch (c) {
1407 case 'v':
1408 libbe_print_errors(B_TRUE);
1409 break;
1410 default:
1411 usage();
1412 return (1);
1416 argc -= optind;
1417 argv += optind;
1419 if (argc != 2) {
1420 usage();
1421 return (1);
1424 obe_name = argv[0];
1425 nbe_name = argv[1];
1427 if (be_nvl_alloc(&be_attrs) != 0)
1428 return (1);
1430 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1431 goto out;
1433 if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
1434 goto out;
1436 err = be_rename(be_attrs);
1438 switch (err) {
1439 case BE_SUCCESS:
1440 (void) printf(_("Renamed successfully\n"));
1441 break;
1442 case BE_ERR_BE_NOENT:
1443 (void) fprintf(stderr, _("%s does not exist or appear "
1444 "to be a valid BE.\nPlease check that the name of "
1445 "the BE provided is correct.\n"), obe_name);
1446 break;
1447 case BE_ERR_PERM:
1448 case BE_ERR_ACCESS:
1449 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1450 obe_name);
1451 (void) fprintf(stderr, _("You have insufficient privileges to "
1452 "execute this command.\n"));
1453 break;
1454 default:
1455 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1456 obe_name);
1457 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1460 out:
1461 nvlist_free(be_attrs);
1462 return (err);
1465 static int
1466 be_do_rollback(int argc, char **argv)
1468 nvlist_t *be_attrs;
1469 char *obe_name;
1470 char *snap_name;
1471 int err = 1;
1472 int c;
1474 while ((c = getopt(argc, argv, "v")) != -1) {
1475 switch (c) {
1476 case 'v':
1477 libbe_print_errors(B_TRUE);
1478 break;
1479 default:
1480 usage();
1481 return (1);
1485 argc -= optind;
1486 argv += optind;
1488 if (argc < 1 || argc > 2) {
1489 usage();
1490 return (1);
1493 obe_name = argv[0];
1494 if (argc == 2)
1495 snap_name = argv[1];
1496 else { /* argc == 1 */
1497 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
1498 if (snap_name[1] == '\0') {
1499 usage();
1500 return (1);
1503 snap_name[0] = '\0';
1504 snap_name++;
1505 } else {
1506 usage();
1507 return (1);
1511 if (be_nvl_alloc(&be_attrs) != 0)
1512 return (1);
1514 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1515 goto out;
1517 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0)
1518 goto out;
1520 err = be_rollback(be_attrs);
1522 switch (err) {
1523 case BE_SUCCESS:
1524 (void) printf(_("Rolled back successfully\n"));
1525 break;
1526 case BE_ERR_BE_NOENT:
1527 (void) fprintf(stderr, _("%s does not exist or appear "
1528 "to be a valid BE.\nPlease check that the name of "
1529 "the BE provided is correct.\n"), obe_name);
1530 break;
1531 case BE_ERR_SS_NOENT:
1532 (void) fprintf(stderr, _("%s does not exist or appear "
1533 "to be a valid snapshot.\nPlease check that the name of "
1534 "the snapshot provided is correct.\n"), snap_name);
1535 break;
1536 case BE_ERR_PERM:
1537 case BE_ERR_ACCESS:
1538 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1539 "failed.\n"), obe_name, snap_name);
1540 (void) fprintf(stderr, _("You have insufficient privileges to "
1541 "execute this command.\n"));
1542 break;
1543 default:
1544 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1545 "failed.\n"), obe_name, snap_name);
1546 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1549 out:
1550 nvlist_free(be_attrs);
1551 return (err);