xref: /illumos-gate/usr/src/cmd/beadm/beadm.c (revision 621be8d08fd45483b5ca1cb8e2e88239f1502b4d)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28  * Copyright 2015 Toomas Soome <tsoome@me.com>
29  * Copyright 2015 Gary Mills
30  */
31 
32 /*
33  * System includes
34  */
35 
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 
46 #include "libbe.h"
47 
48 #ifndef lint
49 #define	_(x) gettext(x)
50 #else
51 #define	_(x) (x)
52 #endif
53 
54 #ifndef TEXT_DOMAIN
55 #define	TEXT_DOMAIN "SYS_TEST"
56 #endif
57 
58 #define	DT_BUF_LEN (128)
59 #define	NUM_COLS (6)
60 
61 static int be_do_activate(int argc, char **argv);
62 static int be_do_create(int argc, char **argv);
63 static int be_do_destroy(int argc, char **argv);
64 static int be_do_list(int argc, char **argv);
65 static int be_do_mount(int argc, char **argv);
66 static int be_do_unmount(int argc, char **argv);
67 static int be_do_rename(int argc, char **argv);
68 static int be_do_rollback(int argc, char **argv);
69 static void usage(void);
70 
71 /*
72  * single column name/width output format description
73  */
74 struct col_info {
75 	const char *col_name;
76 	size_t width;
77 };
78 
79 /*
80  * all columns output format
81  */
82 struct hdr_info {
83 	struct col_info cols[NUM_COLS];
84 };
85 
86 /*
87  * type of possible output formats
88  */
89 enum be_fmt {
90 	BE_FMT_DEFAULT,
91 	BE_FMT_DATASET,
92 	BE_FMT_SNAPSHOT,
93 	BE_FMT_ALL
94 };
95 
96 /*
97  * command handler description
98  */
99 typedef struct be_command {
100 	const char	*name;
101 	int		(*func)(int argc, char **argv);
102 } be_command_t;
103 
104 /*
105  * sorted list of be commands
106  */
107 static const be_command_t be_command_tbl[] = {
108 	{ "activate",		be_do_activate },
109 	{ "create",		be_do_create },
110 	{ "destroy",		be_do_destroy },
111 	{ "list",		be_do_list },
112 	{ "mount",		be_do_mount },
113 	{ "unmount",		be_do_unmount },
114 	{ "umount",		be_do_unmount }, /* unmount alias */
115 	{ "rename",		be_do_rename },
116 	{ "rollback",		be_do_rollback },
117 	{ NULL,			NULL },
118 };
119 
120 static void
121 usage(void)
122 {
123 	(void) fprintf(stderr, _("usage:\n"
124 	    "\tbeadm subcommand cmd_options\n"
125 	    "\n"
126 	    "\tsubcommands:\n"
127 	    "\n"
128 	    "\tbeadm activate [-v] beName\n"
129 	    "\tbeadm create [-a] [-d BE_desc]\n"
130 	    "\t\t[-o property=value] ... [-p zpool] \n"
131 	    "\t\t[-e nonActiveBe | beName@snapshot] [-v] beName\n"
132 	    "\tbeadm create [-d BE_desc]\n"
133 	    "\t\t[-o property=value] ... [-p zpool] [-v] beName@snapshot\n"
134 	    "\tbeadm destroy [-Ffsv] beName \n"
135 	    "\tbeadm destroy [-Fv] beName@snapshot \n"
136 	    "\tbeadm list [[-a] | [-d] [-s]] [-H]\n"
137 	    "\t\t[-k|-K date | name | space] [-v] [beName]\n"
138 	    "\tbeadm mount [-s ro|rw] [-v] beName [mountpoint]\n"
139 	    "\tbeadm unmount [-fv] beName | mountpoint\n"
140 	    "\tbeadm umount [-fv] beName | mountpoint\n"
141 	    "\tbeadm rename [-v] origBeName newBeName\n"
142 	    "\tbeadm rollback [-v] beName snapshot\n"
143 	    "\tbeadm rollback [-v] beName@snapshot\n"));
144 }
145 
146 static int
147 run_be_cmd(const char *cmdname, int argc, char **argv)
148 {
149 	const be_command_t *command;
150 
151 	for (command = &be_command_tbl[0]; command->name != NULL; command++)
152 		if (strcmp(command->name, cmdname) == 0)
153 			return (command->func(argc, argv));
154 
155 	(void) fprintf(stderr, _("Invalid command: %s\n"), cmdname);
156 	usage();
157 	return (1);
158 }
159 
160 int
161 main(int argc, char **argv)
162 {
163 	const char *cmdname;
164 
165 	(void) setlocale(LC_ALL, "");
166 	(void) textdomain(TEXT_DOMAIN);
167 
168 	if (argc < 2) {
169 		usage();
170 		return (1);
171 	}
172 
173 	cmdname = argv[1];
174 
175 	/* Turn error printing off */
176 	libbe_print_errors(B_FALSE);
177 
178 	return (run_be_cmd(cmdname, --argc, ++argv));
179 }
180 
181 static void
182 print_hdr(struct hdr_info *hdr_info)
183 {
184 	boolean_t first = B_TRUE;
185 	size_t i;
186 	for (i = 0; i < NUM_COLS; i++) {
187 		struct col_info *col_info = &hdr_info->cols[i];
188 		const char *name = col_info->col_name;
189 		size_t width = col_info->width;
190 		if (name == NULL)
191 			continue;
192 
193 		if (first) {
194 			(void) printf("%-*s", width, name);
195 			first = B_FALSE;
196 		} else
197 			(void) printf(" %-*s", width, name);
198 	}
199 	(void) putchar('\n');
200 }
201 
202 static void
203 init_hdr_cols(enum be_fmt be_fmt, struct hdr_info *hdr)
204 {
205 	struct col_info *col = hdr->cols;
206 	size_t i;
207 
208 	col[1].col_name = _("Active");
209 	col[2].col_name = _("Mountpoint");
210 	col[3].col_name = _("Space");
211 	col[4].col_name = _("Policy");
212 	col[5].col_name = _("Created");
213 	col[6].col_name = NULL;
214 
215 	switch (be_fmt) {
216 	case BE_FMT_ALL:
217 		col[0].col_name = _("BE/Dataset/Snapshot");
218 		break;
219 	case BE_FMT_DATASET:
220 		col[0].col_name = _("BE/Dataset");
221 		break;
222 	case BE_FMT_SNAPSHOT:
223 		col[0].col_name = _("BE/Snapshot");
224 		col[1].col_name = NULL;
225 		col[2].col_name = NULL;
226 		break;
227 	case BE_FMT_DEFAULT:
228 	default:
229 		col[0].col_name = _("BE");
230 	}
231 
232 	for (i = 0; i < NUM_COLS; i++) {
233 		const char *name = col[i].col_name;
234 		col[i].width = 0;
235 
236 		if (name != NULL) {
237 			wchar_t wname[128];
238 			size_t sz = mbstowcs(wname, name, sizeof (wname) /
239 			    sizeof (wchar_t));
240 			if (sz > 0) {
241 				int wcsw = wcswidth(wname, sz);
242 				if (wcsw > 0)
243 					col[i].width = wcsw;
244 				else
245 					col[i].width = sz;
246 			} else {
247 				col[i].width = strlen(name);
248 			}
249 		}
250 	}
251 }
252 
253 static void
254 nicenum(uint64_t num, char *buf, size_t buflen)
255 {
256 	uint64_t n = num;
257 	int index = 0;
258 	char u;
259 
260 	while (n >= 1024) {
261 		n /= 1024;
262 		index++;
263 	}
264 
265 	u = " KMGTPE"[index];
266 
267 	if (index == 0) {
268 		(void) snprintf(buf, buflen, "%llu", n);
269 	} else {
270 		int i;
271 		for (i = 2; i >= 0; i--) {
272 			if (snprintf(buf, buflen, "%.*f%c", i,
273 			    (double)num / (1ULL << 10 * index), u) <= 5)
274 				break;
275 		}
276 	}
277 }
278 
279 static void
280 count_widths(enum be_fmt be_fmt, struct hdr_info *hdr, be_node_list_t *be_nodes)
281 {
282 	size_t len[NUM_COLS];
283 	char buf[DT_BUF_LEN];
284 	int i;
285 	be_node_list_t *cur_be;
286 
287 	for (i = 0; i < NUM_COLS; i++)
288 		len[i] = hdr->cols[i].width;
289 
290 	for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
291 		char name[ZFS_MAXNAMELEN+1];
292 		const char *be_name = cur_be->be_node_name;
293 		const char *root_ds = cur_be->be_root_ds;
294 		char *pos;
295 		size_t node_name_len = strlen(cur_be->be_node_name);
296 		size_t root_ds_len = strlen(cur_be->be_root_ds);
297 		size_t mntpt_len = 0;
298 		size_t policy_len = 0;
299 		size_t used_len;
300 		uint64_t used = cur_be->be_space_used;
301 		be_snapshot_list_t *snap = NULL;
302 
303 		if (cur_be->be_mntpt != NULL)
304 			mntpt_len = strlen(cur_be->be_mntpt);
305 		if (cur_be->be_policy_type != NULL)
306 			policy_len = strlen(cur_be->be_policy_type);
307 
308 		(void) strlcpy(name, root_ds, sizeof (name));
309 		pos = strstr(name, be_name);
310 
311 		if (be_fmt == BE_FMT_DEFAULT) {
312 			if (node_name_len > len[0])
313 				len[0] = node_name_len;
314 		} else {
315 			if (root_ds_len + 3 > len[0])
316 				len[0] = root_ds_len + 3;
317 		}
318 
319 		if (mntpt_len > len[2])
320 			len[2] = mntpt_len;
321 		if (policy_len > len[4])
322 			len[4] = policy_len;
323 
324 		for (snap = cur_be->be_node_snapshots; snap != NULL;
325 		    snap = snap->be_next_snapshot) {
326 			uint64_t snap_used = snap->be_snapshot_space_used;
327 			const char *snap_name = snap->be_snapshot_name;
328 			(void) strcpy(pos, snap_name);
329 
330 			if (be_fmt == BE_FMT_DEFAULT)
331 				used += snap_used;
332 			else if (be_fmt & BE_FMT_SNAPSHOT) {
333 				int snap_len = strlen(name) + 3;
334 				if (be_fmt == BE_FMT_SNAPSHOT)
335 					snap_len -= pos - name;
336 				if (snap_len > len[0])
337 					len[0] = snap_len;
338 				nicenum(snap_used, buf, sizeof (buf));
339 				used_len = strlen(buf);
340 				if (used_len > len[3])
341 					len[3] = used_len;
342 			}
343 		}
344 
345 		if (be_fmt == BE_FMT_DEFAULT) {
346 			int used_len;
347 			nicenum(used, buf, sizeof (buf));
348 			used_len = strlen(buf);
349 			if (used_len > len[3])
350 				len[3] = used_len;
351 		}
352 
353 		nicenum(used, buf, sizeof (buf));
354 	}
355 
356 	for (i = 0; i < NUM_COLS; i++)
357 		hdr->cols[i].width = len[i];
358 }
359 
360 static void
361 print_be_nodes(const char *be_name, boolean_t parsable, struct hdr_info *hdr,
362     be_node_list_t *nodes)
363 {
364 	char buf[64];
365 	char datetime[DT_BUF_LEN];
366 	be_node_list_t	*cur_be;
367 
368 	for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
369 		char active[3] = "-\0";
370 		int ai = 0;
371 		const char *datetime_fmt = "%F %R";
372 		const char *name = cur_be->be_node_name;
373 		const char *mntpt = cur_be->be_mntpt;
374 		be_snapshot_list_t *snap = NULL;
375 		uint64_t used = cur_be->be_space_used;
376 		time_t creation = cur_be->be_node_creation;
377 		struct tm *tm;
378 
379 		if (be_name != NULL && strcmp(be_name, name) != 0)
380 			continue;
381 
382 		if (parsable)
383 			active[0] = '\0';
384 
385 		tm = localtime(&creation);
386 		(void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
387 
388 		for (snap = cur_be->be_node_snapshots; snap != NULL;
389 		    snap = snap->be_next_snapshot)
390 			used += snap->be_snapshot_space_used;
391 
392 		if (!cur_be->be_global_active)
393 			active[ai++] = 'x';
394 
395 		if (cur_be->be_active)
396 			active[ai++] = 'N';
397 		if (cur_be->be_active_on_boot) {
398 			if (!cur_be->be_global_active)
399 				active[ai] = 'b';
400 			else
401 				active[ai] = 'R';
402 		}
403 
404 		nicenum(used, buf, sizeof (buf));
405 		if (parsable)
406 			(void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
407 			    name,
408 			    cur_be->be_uuid_str,
409 			    active,
410 			    (cur_be->be_mounted ? mntpt: ""),
411 			    used,
412 			    cur_be->be_policy_type,
413 			    creation);
414 		else
415 			(void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n",
416 			    hdr->cols[0].width, name,
417 			    hdr->cols[1].width, active,
418 			    hdr->cols[2].width, (cur_be->be_mounted ? mntpt:
419 			    "-"),
420 			    hdr->cols[3].width, buf,
421 			    hdr->cols[4].width, cur_be->be_policy_type,
422 			    hdr->cols[5].width, datetime);
423 	}
424 }
425 
426 static void
427 print_be_snapshots(be_node_list_t *be, struct hdr_info *hdr, boolean_t parsable)
428 {
429 	char buf[64];
430 	char datetime[DT_BUF_LEN];
431 	be_snapshot_list_t *snap = NULL;
432 
433 	for (snap = be->be_node_snapshots; snap != NULL;
434 	    snap = snap->be_next_snapshot) {
435 		char name[ZFS_MAXNAMELEN+1];
436 		const char *datetime_fmt = "%F %R";
437 		const char *be_name = be->be_node_name;
438 		const char *root_ds = be->be_root_ds;
439 		const char *snap_name = snap->be_snapshot_name;
440 		char *pos;
441 		uint64_t used = snap->be_snapshot_space_used;
442 		time_t creation = snap->be_snapshot_creation;
443 		struct tm *tm = localtime(&creation);
444 
445 		(void) strncpy(name, root_ds, sizeof (name));
446 		pos = strstr(name, be_name);
447 		(void) strcpy(pos, snap_name);
448 
449 		(void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
450 		nicenum(used, buf, sizeof (buf));
451 
452 		if (parsable)
453 			if (hdr->cols[1].width != 0)
454 				(void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
455 				    be_name,
456 				    snap_name,
457 				    "",
458 				    "",
459 				    used,
460 				    be->be_policy_type,
461 				    creation);
462 			else
463 				(void) printf("%s;%s;%llu;%s;%ld\n",
464 				    be_name,
465 				    snap_name,
466 				    used,
467 				    be->be_policy_type,
468 				    creation);
469 		else
470 			if (hdr->cols[1].width != 0)
471 				(void) printf("   %-*s %-*s %-*s %-*s %-*s "
472 				    "%-*s\n",
473 				    hdr->cols[0].width-3, name,
474 				    hdr->cols[1].width, "-",
475 				    hdr->cols[2].width, "-",
476 				    hdr->cols[3].width, buf,
477 				    hdr->cols[4].width, be->be_policy_type,
478 				    hdr->cols[5].width, datetime);
479 			else
480 				(void) printf("   %-*s %-*s %-*s %-*s\n",
481 				    hdr->cols[0].width-3, snap_name,
482 				    hdr->cols[3].width, buf,
483 				    hdr->cols[4].width, be->be_policy_type,
484 				    hdr->cols[5].width, datetime);
485 	}
486 }
487 
488 static void
489 print_fmt_nodes(const char *be_name, enum be_fmt be_fmt, boolean_t parsable,
490     struct hdr_info *hdr, be_node_list_t *nodes)
491 {
492 	char buf[64];
493 	char datetime[DT_BUF_LEN];
494 	be_node_list_t	*cur_be;
495 
496 	for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
497 		char active[3] = "-\0";
498 		int ai = 0;
499 		const char *datetime_fmt = "%F %R";
500 		const char *name = cur_be->be_node_name;
501 		const char *mntpt = cur_be->be_mntpt;
502 		uint64_t used = cur_be->be_space_used;
503 		time_t creation = cur_be->be_node_creation;
504 		struct tm *tm;
505 
506 		if (be_name != NULL && strcmp(be_name, name) != 0)
507 			continue;
508 
509 		if (!parsable)
510 			(void) printf("%-s\n", name);
511 		else
512 			active[0] = '\0';
513 
514 		tm = localtime(&creation);
515 		(void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
516 
517 		if (cur_be->be_active)
518 			active[ai++] = 'N';
519 		if (cur_be->be_active_on_boot)
520 			active[ai] = 'R';
521 
522 		nicenum(used, buf, sizeof (buf));
523 		if (be_fmt & BE_FMT_DATASET)
524 			if (parsable)
525 				(void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
526 				    cur_be->be_node_name,
527 				    cur_be->be_root_ds,
528 				    active,
529 				    (cur_be->be_mounted ? mntpt: ""),
530 				    used,
531 				    cur_be->be_policy_type,
532 				    creation);
533 			else
534 				(void) printf("   %-*s %-*s %-*s %-*s %-*s "
535 				    "%-*s\n",
536 				    hdr->cols[0].width-3, cur_be->be_root_ds,
537 				    hdr->cols[1].width, active,
538 				    hdr->cols[2].width, (cur_be->be_mounted ?
539 				    mntpt: "-"),
540 				    hdr->cols[3].width, buf,
541 				    hdr->cols[4].width, cur_be->be_policy_type,
542 				    hdr->cols[5].width, datetime);
543 
544 		if (be_fmt & BE_FMT_SNAPSHOT)
545 			print_be_snapshots(cur_be, hdr, parsable);
546 	}
547 }
548 
549 static void
550 print_nodes(const char *be_name, boolean_t dsets, boolean_t snaps,
551     boolean_t parsable, be_node_list_t *be_nodes)
552 {
553 	struct hdr_info hdr;
554 	enum be_fmt be_fmt  = BE_FMT_DEFAULT;
555 
556 	if (dsets)
557 		be_fmt |= BE_FMT_DATASET;
558 	if (snaps)
559 		be_fmt |= BE_FMT_SNAPSHOT;
560 
561 	if (!parsable) {
562 		init_hdr_cols(be_fmt, &hdr);
563 		count_widths(be_fmt, &hdr, be_nodes);
564 		print_hdr(&hdr);
565 	}
566 
567 	if (be_fmt == BE_FMT_DEFAULT)
568 		print_be_nodes(be_name, parsable, &hdr, be_nodes);
569 	else
570 		print_fmt_nodes(be_name, be_fmt, parsable, &hdr, be_nodes);
571 }
572 
573 static boolean_t
574 confirm_destroy(const char *name)
575 {
576 	boolean_t res = B_FALSE;
577 	const char *yesre = nl_langinfo(YESEXPR);
578 	const char *nore = nl_langinfo(NOEXPR);
579 	regex_t yes_re;
580 	regex_t no_re;
581 	char buf[128];
582 	char *answer;
583 	int cflags = REG_EXTENDED;
584 
585 	if (regcomp(&yes_re, yesre, cflags) != 0) {
586 		/* should not happen */
587 		(void) fprintf(stderr, _("Failed to compile 'yes' regexp\n"));
588 		return (res);
589 	}
590 	if (regcomp(&no_re, nore, cflags) != 0) {
591 		/* should not happen */
592 		(void) fprintf(stderr, _("Failed to compile 'no' regexp\n"));
593 		regfree(&yes_re);
594 		return (res);
595 	}
596 
597 	(void) printf(_("Are you sure you want to destroy %s?\n"
598 	    "This action cannot be undone (y/[n]): "), name);
599 
600 	answer = fgets(buf, sizeof (buf), stdin);
601 	if (answer == NULL || *answer == '\0' || *answer == 10)
602 		goto out;
603 
604 	if (regexec(&yes_re, answer, 0, NULL, 0) == 0) {
605 		res = B_TRUE;
606 	} else if (regexec(&no_re, answer, 0, NULL, 0) != 0) {
607 		(void) fprintf(stderr, _("Invalid response. "
608 		    "Please enter 'y' or 'n'.\n"));
609 	}
610 
611 out:
612 	regfree(&yes_re);
613 	regfree(&no_re);
614 	return (res);
615 }
616 
617 static int
618 be_nvl_alloc(nvlist_t **nvlp)
619 {
620 	assert(nvlp != NULL);
621 
622 	if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) {
623 		(void) perror(_("nvlist_alloc failed.\n"));
624 		return (1);
625 	}
626 
627 	return (0);
628 }
629 
630 static int
631 be_nvl_add_string(nvlist_t *nvl, const char *name, const char *val)
632 {
633 	assert(nvl != NULL);
634 
635 	if (nvlist_add_string(nvl, name, val) != 0) {
636 		(void) fprintf(stderr, _("nvlist_add_string failed for "
637 		    "%s (%s).\n"), name, val);
638 		return (1);
639 	}
640 
641 	return (0);
642 }
643 
644 static int
645 be_nvl_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
646 {
647 	assert(nvl != NULL);
648 
649 	if (nvlist_add_nvlist(nvl, name, val) != 0) {
650 		(void) fprintf(stderr, _("nvlist_add_nvlist failed for %s.\n"),
651 		    name);
652 		return (1);
653 	}
654 
655 	return (0);
656 }
657 
658 static int
659 be_nvl_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
660 {
661 	assert(nvl != NULL);
662 
663 	if (nvlist_add_uint16(nvl, name, val) != 0) {
664 		(void) fprintf(stderr, _("nvlist_add_uint16 failed for "
665 		    "%s (%hu).\n"), name, val);
666 		return (1);
667 	}
668 
669 	return (0);
670 }
671 
672 static int
673 be_do_activate(int argc, char **argv)
674 {
675 	nvlist_t	*be_attrs;
676 	int		err = 1;
677 	int		c;
678 	char		*obe_name;
679 
680 	while ((c = getopt(argc, argv, "v")) != -1) {
681 		switch (c) {
682 		case 'v':
683 			libbe_print_errors(B_TRUE);
684 			break;
685 		default:
686 			usage();
687 			return (1);
688 		}
689 	}
690 
691 	argc -= optind;
692 	argv += optind;
693 
694 	if (argc != 1) {
695 		usage();
696 		return (1);
697 	}
698 
699 	obe_name = argv[0];
700 
701 	if (be_nvl_alloc(&be_attrs) != 0)
702 		return (1);
703 
704 	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
705 		goto out;
706 
707 	err = be_activate(be_attrs);
708 
709 	switch (err) {
710 	case BE_SUCCESS:
711 		(void) printf(_("Activated successfully\n"));
712 		break;
713 	case BE_ERR_BE_NOENT:
714 		(void) fprintf(stderr, _("%s does not exist or appear "
715 		    "to be a valid BE.\nPlease check that the name of "
716 		    "the BE provided is correct.\n"), obe_name);
717 		break;
718 	case BE_ERR_PERM:
719 	case BE_ERR_ACCESS:
720 		(void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
721 		(void) fprintf(stderr, _("You have insufficient privileges to "
722 		    "execute this command.\n"));
723 		break;
724 	case BE_ERR_ACTIVATE_CURR:
725 	default:
726 		(void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
727 		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
728 	}
729 
730 out:
731 	nvlist_free(be_attrs);
732 	return (err);
733 }
734 
735 static int
736 be_do_create(int argc, char **argv)
737 {
738 	nvlist_t	*be_attrs;
739 	nvlist_t	*zfs_props = NULL;
740 	boolean_t	activate = B_FALSE;
741 	boolean_t	is_snap = B_FALSE;
742 	int		c;
743 	int		err = 1;
744 	char		*obe_name = NULL;
745 	char		*snap_name = NULL;
746 	char		*nbe_zpool = NULL;
747 	char		*nbe_name = NULL;
748 	char		*nbe_desc = NULL;
749 	char		*propname = NULL;
750 	char		*propval = NULL;
751 	char		*strval = NULL;
752 
753 	while ((c = getopt(argc, argv, "ad:e:io:p:v")) != -1) {
754 		switch (c) {
755 		case 'a':
756 			activate = B_TRUE;
757 			break;
758 		case 'd':
759 			nbe_desc = optarg;
760 			break;
761 		case 'e':
762 			obe_name = optarg;
763 			break;
764 		case 'o':
765 			if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0)
766 				return (1);
767 
768 			propname = optarg;
769 			if ((propval = strchr(propname, '=')) == NULL) {
770 				(void) fprintf(stderr, _("missing "
771 				    "'=' for -o option\n"));
772 				goto out2;
773 			}
774 			*propval = '\0';
775 			propval++;
776 			if (nvlist_lookup_string(zfs_props, propname,
777 			    &strval) == 0) {
778 				(void) fprintf(stderr, _("property '%s' "
779 				    "specified multiple times\n"), propname);
780 				goto out2;
781 
782 			}
783 			if (be_nvl_add_string(zfs_props, propname, propval)
784 			    != 0)
785 				goto out2;
786 
787 			break;
788 		case 'p':
789 			nbe_zpool = optarg;
790 			break;
791 		case 'v':
792 			libbe_print_errors(B_TRUE);
793 			break;
794 		default:
795 			usage();
796 			goto out2;
797 		}
798 	}
799 
800 	argc -= optind;
801 	argv += optind;
802 
803 	if (argc != 1) {
804 		usage();
805 		goto out2;
806 	}
807 
808 	nbe_name = argv[0];
809 
810 	if ((snap_name = strrchr(nbe_name, '@')) != NULL) {
811 		if (snap_name[1] == '\0') {
812 			usage();
813 			goto out2;
814 		}
815 
816 		snap_name[0] = '\0';
817 		snap_name++;
818 		is_snap = B_TRUE;
819 	}
820 
821 	if (obe_name) {
822 		if (is_snap) {
823 			usage();
824 			goto out2;
825 		}
826 
827 		/*
828 		 * Check if obe_name is really a snapshot name.
829 		 * If so, split it out.
830 		 */
831 		if ((snap_name = strrchr(obe_name, '@')) != NULL) {
832 			if (snap_name[1] == '\0') {
833 				usage();
834 				goto out2;
835 			}
836 
837 			snap_name[0] = '\0';
838 			snap_name++;
839 		}
840 	} else if (is_snap) {
841 		obe_name = nbe_name;
842 		nbe_name = NULL;
843 	}
844 
845 	if (be_nvl_alloc(&be_attrs) != 0)
846 		goto out2;
847 
848 
849 	if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs,
850 	    BE_ATTR_ORIG_BE_NAME, zfs_props) != 0)
851 		goto out;
852 
853 	if (obe_name != NULL && be_nvl_add_string(be_attrs,
854 	    BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
855 		goto out;
856 
857 	if (snap_name != NULL && be_nvl_add_string(be_attrs,
858 	    BE_ATTR_SNAP_NAME, snap_name) != 0)
859 		goto out;
860 
861 	if (nbe_zpool != NULL && be_nvl_add_string(be_attrs,
862 	    BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0)
863 		goto out;
864 
865 	if (nbe_name != NULL && be_nvl_add_string(be_attrs,
866 	    BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
867 		goto out;
868 
869 	if (nbe_desc != NULL && be_nvl_add_string(be_attrs,
870 	    BE_ATTR_NEW_BE_DESC, nbe_desc) != 0)
871 		goto out;
872 
873 	if (is_snap)
874 		err = be_create_snapshot(be_attrs);
875 	else
876 		err = be_copy(be_attrs);
877 
878 	switch (err) {
879 	case BE_SUCCESS:
880 		if (!is_snap && !nbe_name) {
881 			/*
882 			 * We requested an auto named BE; find out the
883 			 * name of the BE that was created for us and
884 			 * the auto snapshot created from the original BE.
885 			 */
886 			if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME,
887 			    &nbe_name) != 0) {
888 				(void) fprintf(stderr, _("failed to get %s "
889 				    "attribute\n"), BE_ATTR_NEW_BE_NAME);
890 				break;
891 			} else
892 				(void) printf(_("Auto named BE: %s\n"),
893 				    nbe_name);
894 
895 			if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
896 			    &snap_name) != 0) {
897 				(void) fprintf(stderr, _("failed to get %s "
898 				    "attribute\n"), BE_ATTR_SNAP_NAME);
899 				break;
900 			} else
901 				(void) printf(_("Auto named snapshot: %s\n"),
902 				    snap_name);
903 		}
904 
905 		if (!is_snap && activate) {
906 			char *args[] = { "activate", "", NULL };
907 			args[1] = nbe_name;
908 			optind = 1;
909 
910 			err = be_do_activate(2, args);
911 			goto out;
912 		}
913 
914 		(void) printf(_("Created successfully\n"));
915 		break;
916 	case BE_ERR_BE_EXISTS:
917 		(void) fprintf(stderr, _("BE %s already exists\n."
918 		    "Please choose a different BE name.\n"), nbe_name);
919 		break;
920 	case BE_ERR_SS_EXISTS:
921 		(void) fprintf(stderr, _("BE %s snapshot %s already exists.\n"
922 		    "Please choose a different snapshot name.\n"), obe_name,
923 		    snap_name);
924 		break;
925 	case BE_ERR_PERM:
926 	case BE_ERR_ACCESS:
927 		if (is_snap)
928 			(void) fprintf(stderr, _("Unable to create snapshot "
929 			    "%s.\n"), snap_name);
930 		else
931 			(void) fprintf(stderr, _("Unable to create %s.\n"),
932 			    nbe_name);
933 		(void) fprintf(stderr, _("You have insufficient privileges to "
934 		    "execute this command.\n"));
935 		break;
936 	default:
937 		if (is_snap)
938 			(void) fprintf(stderr, _("Unable to create snapshot "
939 			    "%s.\n"), snap_name);
940 		else
941 			(void) fprintf(stderr, _("Unable to create %s.\n"),
942 			    nbe_name);
943 		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
944 	}
945 
946 out:
947 	nvlist_free(be_attrs);
948 out2:
949 	nvlist_free(zfs_props);
950 
951 	return (err);
952 }
953 
954 static int
955 be_do_destroy(int argc, char **argv)
956 {
957 	nvlist_t	*be_attrs;
958 	boolean_t	is_snap = B_FALSE;
959 	boolean_t	suppress_prompt = B_FALSE;
960 	int		err = 1;
961 	int		c;
962 	int		destroy_flags = 0;
963 	char		*snap_name;
964 	char		*be_name;
965 
966 	while ((c = getopt(argc, argv, "fFsv")) != -1) {
967 		switch (c) {
968 		case 'f':
969 			destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
970 			break;
971 		case 's':
972 			destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
973 			break;
974 		case 'v':
975 			libbe_print_errors(B_TRUE);
976 			break;
977 		case 'F':
978 			suppress_prompt = B_TRUE;
979 			break;
980 		default:
981 			usage();
982 			return (1);
983 		}
984 	}
985 
986 	argc -= optind;
987 	argv += optind;
988 
989 	if (argc != 1) {
990 		usage();
991 		return (1);
992 	}
993 
994 	be_name = argv[0];
995 	if (!suppress_prompt && !confirm_destroy(be_name)) {
996 		(void) printf(_("%s has not been destroyed.\n"), be_name);
997 		return (0);
998 	}
999 
1000 	if ((snap_name = strrchr(be_name, '@')) != NULL) {
1001 		if (snap_name[1] == '\0') {
1002 			usage();
1003 			return (1);
1004 		}
1005 
1006 		is_snap = B_TRUE;
1007 		*snap_name = '\0';
1008 		snap_name++;
1009 	}
1010 
1011 	if (be_nvl_alloc(&be_attrs) != 0)
1012 		return (1);
1013 
1014 
1015 	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0)
1016 		goto out;
1017 
1018 	if (is_snap) {
1019 		if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME,
1020 		    snap_name) != 0)
1021 			goto out;
1022 
1023 		err = be_destroy_snapshot(be_attrs);
1024 	} else {
1025 		if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS,
1026 		    destroy_flags) != 0)
1027 			goto out;
1028 
1029 		err = be_destroy(be_attrs);
1030 	}
1031 
1032 	switch (err) {
1033 	case BE_SUCCESS:
1034 		(void) printf(_("Destroyed successfully\n"));
1035 		break;
1036 	case BE_ERR_MOUNTED:
1037 		(void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1038 		(void) fprintf(stderr, _("It is currently mounted and must be "
1039 		    "unmounted before it can be destroyed.\n" "Use 'beadm "
1040 		    "unmount %s' to unmount the BE before destroying\nit or "
1041 		    "'beadm destroy -f %s'.\n"), be_name, be_name);
1042 		break;
1043 	case BE_ERR_DESTROY_CURR_BE:
1044 		(void) fprintf(stderr, _("%s is the currently active BE and "
1045 		    "cannot be destroyed.\nYou must boot from another BE in "
1046 		    "order to destroy %s.\n"), be_name, be_name);
1047 		break;
1048 	case BE_ERR_ZONES_UNMOUNT:
1049 		(void) fprintf(stderr, _("Unable to destroy one of " "%s's "
1050 		    "zone BE's.\nUse 'beadm destroy -f %s' or "
1051 		    "'zfs -f destroy <dataset>'.\n"), be_name, be_name);
1052 		break;
1053 	case BE_ERR_SS_NOENT:
1054 		(void) fprintf(stderr, _("%s does not exist or appear "
1055 		    "to be a valid snapshot.\nPlease check that the name of "
1056 		    "the snapshot provided is correct.\n"), snap_name);
1057 		break;
1058 	case BE_ERR_PERM:
1059 	case BE_ERR_ACCESS:
1060 		(void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1061 		(void) fprintf(stderr, _("You have insufficient privileges to "
1062 		    "execute this command.\n"));
1063 		break;
1064 	case BE_ERR_SS_EXISTS:
1065 		(void) fprintf(stderr, _("Unable to destroy %s: "
1066 		    "BE has snapshots.\nUse 'beadm destroy -s %s' or "
1067 		    "'zfs -r destroy <dataset>'.\n"), be_name, be_name);
1068 		break;
1069 	default:
1070 		(void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1071 		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
1072 	}
1073 
1074 out:
1075 	nvlist_free(be_attrs);
1076 	return (err);
1077 }
1078 
1079 static int
1080 be_do_list(int argc, char **argv)
1081 {
1082 	be_node_list_t	*be_nodes = NULL;
1083 	boolean_t	all = B_FALSE;
1084 	boolean_t	dsets = B_FALSE;
1085 	boolean_t	snaps = B_FALSE;
1086 	boolean_t	parsable = B_FALSE;
1087 	int		err = 1;
1088 	int		c = 0;
1089 	char		*be_name = NULL;
1090 	be_sort_t	order = BE_SORT_UNSPECIFIED;
1091 
1092 	while ((c = getopt(argc, argv, "adk:svHK:")) != -1) {
1093 		switch (c) {
1094 		case 'a':
1095 			all = B_TRUE;
1096 			break;
1097 		case 'd':
1098 			dsets = B_TRUE;
1099 			break;
1100 		case 'k':
1101 		case 'K':
1102 			if (order != BE_SORT_UNSPECIFIED) {
1103 				(void) fprintf(stderr, _("Sort key can be "
1104 				    "specified only once.\n"));
1105 				usage();
1106 				return (1);
1107 			}
1108 			if (strcmp(optarg, "date") == 0) {
1109 				if (c == 'k')
1110 					order = BE_SORT_DATE;
1111 				else
1112 					order = BE_SORT_DATE_REV;
1113 				break;
1114 			}
1115 			if (strcmp(optarg, "name") == 0) {
1116 				if (c == 'k')
1117 					order = BE_SORT_NAME;
1118 				else
1119 					order = BE_SORT_NAME_REV;
1120 				break;
1121 			}
1122 			if (strcmp(optarg, "space") == 0) {
1123 				if (c == 'k')
1124 					order = BE_SORT_SPACE;
1125 				else
1126 					order = BE_SORT_SPACE_REV;
1127 				break;
1128 			}
1129 			(void) fprintf(stderr, _("Unknown sort key: %s\n"),
1130 			    optarg);
1131 			usage();
1132 			return (1);
1133 		case 's':
1134 			snaps = B_TRUE;
1135 			break;
1136 		case 'v':
1137 			libbe_print_errors(B_TRUE);
1138 			break;
1139 		case 'H':
1140 			parsable = B_TRUE;
1141 			break;
1142 		default:
1143 			usage();
1144 			return (1);
1145 		}
1146 	}
1147 
1148 	if (all) {
1149 		if (dsets) {
1150 			(void) fprintf(stderr, _("Invalid options: -a and %s "
1151 			    "are mutually exclusive.\n"), "-d");
1152 			usage();
1153 			return (1);
1154 		}
1155 		if (snaps) {
1156 			(void) fprintf(stderr, _("Invalid options: -a and %s "
1157 			    "are mutually exclusive.\n"), "-s");
1158 			usage();
1159 			return (1);
1160 		}
1161 
1162 		dsets = B_TRUE;
1163 		snaps = B_TRUE;
1164 	}
1165 
1166 	argc -= optind;
1167 	argv += optind;
1168 
1169 
1170 	if (argc == 1)
1171 		be_name = argv[0];
1172 
1173 	err = be_list(be_name, &be_nodes);
1174 
1175 	switch (err) {
1176 	case BE_SUCCESS:
1177 		/* the default sort is ascending date, no need to sort twice */
1178 		if (order == BE_SORT_UNSPECIFIED)
1179 			order = BE_SORT_DATE;
1180 
1181 		if (order != BE_SORT_DATE) {
1182 			err = be_sort(&be_nodes, order);
1183 			if (err != BE_SUCCESS) {
1184 				(void) fprintf(stderr, _("Unable to sort Boot "
1185 				    "Environment\n"));
1186 				(void) fprintf(stderr, "%s\n",
1187 				    be_err_to_str(err));
1188 				break;
1189 			}
1190 		}
1191 
1192 		print_nodes(be_name, dsets, snaps, parsable, be_nodes);
1193 		break;
1194 	case BE_ERR_BE_NOENT:
1195 		if (be_name == NULL)
1196 			(void) fprintf(stderr, _("No boot environments found "
1197 			    "on this system.\n"));
1198 		else {
1199 			(void) fprintf(stderr, _("%s does not exist or appear "
1200 			    "to be a valid BE.\nPlease check that the name of "
1201 			    "the BE provided is correct.\n"), be_name);
1202 		}
1203 		break;
1204 	default:
1205 		(void) fprintf(stderr, _("Unable to display Boot "
1206 		    "Environment\n"));
1207 		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
1208 	}
1209 
1210 	if (be_nodes != NULL)
1211 		be_free_list(be_nodes);
1212 	return (err);
1213 }
1214 
1215 static int
1216 be_do_mount(int argc, char **argv)
1217 {
1218 	nvlist_t	*be_attrs;
1219 	boolean_t	shared_fs = B_FALSE;
1220 	int		err = 1;
1221 	int		c;
1222 	int		mount_flags = 0;
1223 	char		*obe_name;
1224 	char		*mountpoint;
1225 	char		*tmp_mp = NULL;
1226 
1227 	while ((c = getopt(argc, argv, "s:v")) != -1) {
1228 		switch (c) {
1229 		case 's':
1230 			shared_fs = B_TRUE;
1231 
1232 			mount_flags |= BE_MOUNT_FLAG_SHARED_FS;
1233 
1234 			if (strcmp(optarg, "rw") == 0) {
1235 				mount_flags |= BE_MOUNT_FLAG_SHARED_RW;
1236 			} else if (strcmp(optarg, "ro") != 0) {
1237 				(void) fprintf(stderr, _("The -s flag "
1238 				    "requires an argument [ rw | ro ]\n"));
1239 				usage();
1240 				return (1);
1241 			}
1242 
1243 			break;
1244 		case 'v':
1245 			libbe_print_errors(B_TRUE);
1246 			break;
1247 		default:
1248 			usage();
1249 			return (1);
1250 		}
1251 	}
1252 
1253 	argc -= optind;
1254 	argv += optind;
1255 
1256 	if (argc < 1 || argc > 2) {
1257 		usage();
1258 		return (1);
1259 	}
1260 
1261 	obe_name = argv[0];
1262 
1263 	if (argc == 2) {
1264 		mountpoint = argv[1];
1265 		if (mountpoint[0] != '/') {
1266 			(void) fprintf(stderr, _("Invalid mount point %s. "
1267 			    "Mount point must start with a /.\n"), mountpoint);
1268 			return (1);
1269 		}
1270 	} else {
1271 		const char *tmpdir = getenv("TMPDIR");
1272 		const char *tmpname = "tmp.XXXXXX";
1273 		int sz;
1274 
1275 		if (tmpdir == NULL)
1276 			tmpdir = "/tmp";
1277 
1278 		sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname);
1279 		if (sz < 0) {
1280 			(void) fprintf(stderr, _("internal error: "
1281 			    "out of memory\n"));
1282 			return (1);
1283 		}
1284 
1285 		mountpoint = mkdtemp(tmp_mp);
1286 	}
1287 
1288 	if (be_nvl_alloc(&be_attrs) != 0)
1289 		return (1);
1290 
1291 	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1292 		goto out;
1293 
1294 	if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0)
1295 		goto out;
1296 
1297 	if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS,
1298 	    mount_flags) != 0)
1299 		goto out;
1300 
1301 	err = be_mount(be_attrs);
1302 
1303 	switch (err) {
1304 	case BE_SUCCESS:
1305 		(void) printf(_("Mounted successfully on: '%s'\n"), mountpoint);
1306 		break;
1307 	case BE_ERR_BE_NOENT:
1308 		(void) fprintf(stderr, _("%s does not exist or appear "
1309 		    "to be a valid BE.\nPlease check that the name of "
1310 		    "the BE provided is correct.\n"), obe_name);
1311 		break;
1312 	case BE_ERR_MOUNTED:
1313 		(void) fprintf(stderr, _("%s is already mounted.\n"
1314 		    "Please unmount the BE before mounting it again.\n"),
1315 		    obe_name);
1316 		break;
1317 	case BE_ERR_PERM:
1318 	case BE_ERR_ACCESS:
1319 		(void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1320 		(void) fprintf(stderr, _("You have insufficient privileges to "
1321 		    "execute this command.\n"));
1322 		break;
1323 	case BE_ERR_NO_MOUNTED_ZONE:
1324 		(void) fprintf(stderr, _("Mounted on '%s'.\nUnable to mount "
1325 		    "one of %s's zone BE's.\n"), mountpoint, obe_name);
1326 		break;
1327 	default:
1328 		(void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1329 		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
1330 	}
1331 
1332 out:
1333 	if (tmp_mp != NULL)
1334 		free(tmp_mp);
1335 	nvlist_free(be_attrs);
1336 	return (err);
1337 }
1338 
1339 static int
1340 be_do_unmount(int argc, char **argv)
1341 {
1342 	nvlist_t	*be_attrs;
1343 	char		*obe_name;
1344 	int		err = 1;
1345 	int		c;
1346 	int		unmount_flags = 0;
1347 
1348 	while ((c = getopt(argc, argv, "fv")) != -1) {
1349 		switch (c) {
1350 		case 'f':
1351 			unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
1352 			break;
1353 		case 'v':
1354 			libbe_print_errors(B_TRUE);
1355 			break;
1356 		default:
1357 			usage();
1358 			return (1);
1359 		}
1360 	}
1361 
1362 	argc -= optind;
1363 	argv += optind;
1364 
1365 	if (argc != 1) {
1366 		usage();
1367 		return (1);
1368 	}
1369 
1370 	obe_name = argv[0];
1371 
1372 	if (be_nvl_alloc(&be_attrs) != 0)
1373 		return (1);
1374 
1375 
1376 	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1377 		goto out;
1378 
1379 	if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS,
1380 	    unmount_flags) != 0)
1381 		goto out;
1382 
1383 	err = be_unmount(be_attrs);
1384 
1385 	switch (err) {
1386 	case BE_SUCCESS:
1387 		(void) printf(_("Unmounted successfully\n"));
1388 		break;
1389 	case BE_ERR_BE_NOENT:
1390 		(void) fprintf(stderr, _("%s does not exist or appear "
1391 		    "to be a valid BE.\nPlease check that the name of "
1392 		    "the BE provided is correct.\n"), obe_name);
1393 		break;
1394 	case BE_ERR_UMOUNT_CURR_BE:
1395 		(void) fprintf(stderr, _("%s is the currently active BE.\n"
1396 		    "It cannot be unmounted unless another BE is the "
1397 		    "currently active BE.\n"), obe_name);
1398 		break;
1399 	case BE_ERR_UMOUNT_SHARED:
1400 		(void) fprintf(stderr, _("%s is a shared file system and it "
1401 		    "cannot be unmounted.\n"), obe_name);
1402 		break;
1403 	case BE_ERR_PERM:
1404 	case BE_ERR_ACCESS:
1405 		(void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1406 		(void) fprintf(stderr, _("You have insufficient privileges to "
1407 		    "execute this command.\n"));
1408 		break;
1409 	default:
1410 		(void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1411 		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
1412 	}
1413 
1414 out:
1415 	nvlist_free(be_attrs);
1416 	return (err);
1417 }
1418 
1419 static int
1420 be_do_rename(int argc, char **argv)
1421 {
1422 	nvlist_t	*be_attrs;
1423 	char		*obe_name;
1424 	char		*nbe_name;
1425 	int err = 1;
1426 	int c;
1427 
1428 	while ((c = getopt(argc, argv, "v")) != -1) {
1429 		switch (c) {
1430 		case 'v':
1431 			libbe_print_errors(B_TRUE);
1432 			break;
1433 		default:
1434 			usage();
1435 			return (1);
1436 		}
1437 	}
1438 
1439 	argc -= optind;
1440 	argv += optind;
1441 
1442 	if (argc != 2) {
1443 		usage();
1444 		return (1);
1445 	}
1446 
1447 	obe_name = argv[0];
1448 	nbe_name = argv[1];
1449 
1450 	if (be_nvl_alloc(&be_attrs) != 0)
1451 		return (1);
1452 
1453 	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1454 		goto out;
1455 
1456 	if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
1457 		goto out;
1458 
1459 	err = be_rename(be_attrs);
1460 
1461 	switch (err) {
1462 	case BE_SUCCESS:
1463 		(void) printf(_("Renamed successfully\n"));
1464 		break;
1465 	case BE_ERR_BE_NOENT:
1466 		(void) fprintf(stderr, _("%s does not exist or appear "
1467 		    "to be a valid BE.\nPlease check that the name of "
1468 		    "the BE provided is correct.\n"), obe_name);
1469 		break;
1470 	case BE_ERR_PERM:
1471 	case BE_ERR_ACCESS:
1472 		(void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1473 		    obe_name);
1474 		(void) fprintf(stderr, _("You have insufficient privileges to "
1475 		    "execute this command.\n"));
1476 		break;
1477 	default:
1478 		(void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1479 		    obe_name);
1480 		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
1481 	}
1482 
1483 out:
1484 	nvlist_free(be_attrs);
1485 	return (err);
1486 }
1487 
1488 static int
1489 be_do_rollback(int argc, char **argv)
1490 {
1491 	nvlist_t	*be_attrs;
1492 	char		*obe_name;
1493 	char		*snap_name;
1494 	int		err = 1;
1495 	int		c;
1496 
1497 	while ((c = getopt(argc, argv, "v")) != -1) {
1498 		switch (c) {
1499 		case 'v':
1500 			libbe_print_errors(B_TRUE);
1501 			break;
1502 		default:
1503 			usage();
1504 			return (1);
1505 		}
1506 	}
1507 
1508 	argc -= optind;
1509 	argv += optind;
1510 
1511 	if (argc < 1 || argc > 2) {
1512 		usage();
1513 		return (1);
1514 	}
1515 
1516 	obe_name = argv[0];
1517 	if (argc == 2)
1518 		snap_name = argv[1];
1519 	else { /* argc == 1 */
1520 		if ((snap_name = strrchr(obe_name, '@')) != NULL) {
1521 			if (snap_name[1] == '\0') {
1522 				usage();
1523 				return (1);
1524 			}
1525 
1526 			snap_name[0] = '\0';
1527 			snap_name++;
1528 		} else {
1529 			usage();
1530 			return (1);
1531 		}
1532 	}
1533 
1534 	if (be_nvl_alloc(&be_attrs) != 0)
1535 		return (1);
1536 
1537 	if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1538 		goto out;
1539 
1540 	if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0)
1541 		goto out;
1542 
1543 	err = be_rollback(be_attrs);
1544 
1545 	switch (err) {
1546 	case BE_SUCCESS:
1547 		(void) printf(_("Rolled back successfully\n"));
1548 		break;
1549 	case BE_ERR_BE_NOENT:
1550 		(void) fprintf(stderr, _("%s does not exist or appear "
1551 		    "to be a valid BE.\nPlease check that the name of "
1552 		    "the BE provided is correct.\n"), obe_name);
1553 		break;
1554 	case BE_ERR_SS_NOENT:
1555 		(void) fprintf(stderr, _("%s does not exist or appear "
1556 		    "to be a valid snapshot.\nPlease check that the name of "
1557 		    "the snapshot provided is correct.\n"), snap_name);
1558 		break;
1559 	case BE_ERR_PERM:
1560 	case BE_ERR_ACCESS:
1561 		(void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1562 		    "failed.\n"), obe_name, snap_name);
1563 		(void) fprintf(stderr, _("You have insufficient privileges to "
1564 		    "execute this command.\n"));
1565 		break;
1566 	default:
1567 		(void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1568 		    "failed.\n"), obe_name, snap_name);
1569 		(void) fprintf(stderr, "%s\n", be_err_to_str(err));
1570 	}
1571 
1572 out:
1573 	nvlist_free(be_attrs);
1574 	return (err);
1575 }
1576