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