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