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