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