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