1*f169c0eaSGlenn Lagasse /*
2*f169c0eaSGlenn Lagasse  * CDDL HEADER START
3*f169c0eaSGlenn Lagasse  *
4*f169c0eaSGlenn Lagasse  * The contents of this file are subject to the terms of the
5*f169c0eaSGlenn Lagasse  * Common Development and Distribution License (the "License").
6*f169c0eaSGlenn Lagasse  * You may not use this file except in compliance with the License.
7*f169c0eaSGlenn Lagasse  *
8*f169c0eaSGlenn Lagasse  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f169c0eaSGlenn Lagasse  * or http://www.opensolaris.org/os/licensing.
10*f169c0eaSGlenn Lagasse  * See the License for the specific language governing permissions
11*f169c0eaSGlenn Lagasse  * and limitations under the License.
12*f169c0eaSGlenn Lagasse  *
13*f169c0eaSGlenn Lagasse  * When distributing Covered Code, include this CDDL HEADER in each
14*f169c0eaSGlenn Lagasse  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f169c0eaSGlenn Lagasse  * If applicable, add the following below this CDDL HEADER, with the
16*f169c0eaSGlenn Lagasse  * fields enclosed by brackets "[]" replaced with your own identifying
17*f169c0eaSGlenn Lagasse  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f169c0eaSGlenn Lagasse  *
19*f169c0eaSGlenn Lagasse  * CDDL HEADER END
20*f169c0eaSGlenn Lagasse  */
21*f169c0eaSGlenn Lagasse 
22*f169c0eaSGlenn Lagasse /*
23*f169c0eaSGlenn Lagasse  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24*f169c0eaSGlenn Lagasse  */
25*f169c0eaSGlenn Lagasse 
26*f169c0eaSGlenn Lagasse /*
27*f169c0eaSGlenn Lagasse  * System includes
28*f169c0eaSGlenn Lagasse  */
29*f169c0eaSGlenn Lagasse 
30*f169c0eaSGlenn Lagasse #include <assert.h>
31*f169c0eaSGlenn Lagasse #include <ctype.h>
32*f169c0eaSGlenn Lagasse #include <errno.h>
33*f169c0eaSGlenn Lagasse #include <libgen.h>
34*f169c0eaSGlenn Lagasse #include <libintl.h>
35*f169c0eaSGlenn Lagasse #include <libnvpair.h>
36*f169c0eaSGlenn Lagasse #include <libzfs.h>
37*f169c0eaSGlenn Lagasse #include <stdio.h>
38*f169c0eaSGlenn Lagasse #include <stdlib.h>
39*f169c0eaSGlenn Lagasse #include <string.h>
40*f169c0eaSGlenn Lagasse #include <sys/mnttab.h>
41*f169c0eaSGlenn Lagasse #include <sys/mount.h>
42*f169c0eaSGlenn Lagasse #include <sys/stat.h>
43*f169c0eaSGlenn Lagasse #include <sys/types.h>
44*f169c0eaSGlenn Lagasse #include <sys/wait.h>
45*f169c0eaSGlenn Lagasse #include <unistd.h>
46*f169c0eaSGlenn Lagasse 
47*f169c0eaSGlenn Lagasse #include <libbe.h>
48*f169c0eaSGlenn Lagasse #include <libbe_priv.h>
49*f169c0eaSGlenn Lagasse 
50*f169c0eaSGlenn Lagasse /* Library wide variables */
51*f169c0eaSGlenn Lagasse libzfs_handle_t *g_zfs = NULL;
52*f169c0eaSGlenn Lagasse 
53*f169c0eaSGlenn Lagasse /* Private function prototypes */
54*f169c0eaSGlenn Lagasse static int _be_destroy(const char *, be_destroy_data_t *);
55*f169c0eaSGlenn Lagasse static int be_destroy_zones(char *, char *, be_destroy_data_t *);
56*f169c0eaSGlenn Lagasse static int be_destroy_zone_roots(char *, be_destroy_data_t *);
57*f169c0eaSGlenn Lagasse static int be_destroy_zone_roots_callback(zfs_handle_t *, void *);
58*f169c0eaSGlenn Lagasse static int be_copy_zones(char *, char *, char *);
59*f169c0eaSGlenn Lagasse static int be_clone_fs_callback(zfs_handle_t *, void *);
60*f169c0eaSGlenn Lagasse static int be_destroy_callback(zfs_handle_t *, void *);
61*f169c0eaSGlenn Lagasse static int be_send_fs_callback(zfs_handle_t *, void *);
62*f169c0eaSGlenn Lagasse static int be_demote_callback(zfs_handle_t *, void *);
63*f169c0eaSGlenn Lagasse static int be_demote_find_clone_callback(zfs_handle_t *, void *);
64*f169c0eaSGlenn Lagasse static int be_demote_get_one_clone(zfs_handle_t *, void *);
65*f169c0eaSGlenn Lagasse static int be_get_snap(char *, char **);
66*f169c0eaSGlenn Lagasse static int be_prep_clone_send_fs(zfs_handle_t *, be_transaction_data_t *,
67*f169c0eaSGlenn Lagasse     char *, int);
68*f169c0eaSGlenn Lagasse static boolean_t be_create_container_ds(char *);
69*f169c0eaSGlenn Lagasse static char *be_get_zone_be_name(char *root_ds, char *container_ds);
70*f169c0eaSGlenn Lagasse static int be_zone_root_exists_callback(zfs_handle_t *, void *);
71*f169c0eaSGlenn Lagasse 
72*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
73*f169c0eaSGlenn Lagasse /*			Public Functions				*/
74*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
75*f169c0eaSGlenn Lagasse 
76*f169c0eaSGlenn Lagasse /*
77*f169c0eaSGlenn Lagasse  * Function:	be_init
78*f169c0eaSGlenn Lagasse  * Description:	Creates the initial datasets for a BE and leaves them
79*f169c0eaSGlenn Lagasse  *		unpopulated.  The resultant BE can be mounted but can't
80*f169c0eaSGlenn Lagasse  *		yet be activated or booted.
81*f169c0eaSGlenn Lagasse  * Parameters:
82*f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
83*f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
84*f169c0eaSGlenn Lagasse  *
85*f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_NAME		*required
86*f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_POOL		*required
87*f169c0eaSGlenn Lagasse  *			BE_ATTR_ZFS_PROPERTIES		*optional
88*f169c0eaSGlenn Lagasse  *			BE_ATTR_FS_NAMES		*optional
89*f169c0eaSGlenn Lagasse  *			BE_ATTR_FS_NUM			*optional
90*f169c0eaSGlenn Lagasse  *			BE_ATTR_SHARED_FS_NAMES		*optional
91*f169c0eaSGlenn Lagasse  *			BE_ATTR_SHARED_FS_NUM		*optional
92*f169c0eaSGlenn Lagasse  * Return:
93*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
94*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
95*f169c0eaSGlenn Lagasse  * Scope:
96*f169c0eaSGlenn Lagasse  *		Public
97*f169c0eaSGlenn Lagasse  */
98*f169c0eaSGlenn Lagasse int
99*f169c0eaSGlenn Lagasse be_init(nvlist_t *be_attrs)
100*f169c0eaSGlenn Lagasse {
101*f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
102*f169c0eaSGlenn Lagasse 	zpool_handle_t	*zlp;
103*f169c0eaSGlenn Lagasse 	nvlist_t	*zfs_props = NULL;
104*f169c0eaSGlenn Lagasse 	char		nbe_root_ds[MAXPATHLEN];
105*f169c0eaSGlenn Lagasse 	char		child_fs[MAXPATHLEN];
106*f169c0eaSGlenn Lagasse 	char		**fs_names = NULL;
107*f169c0eaSGlenn Lagasse 	char		**shared_fs_names = NULL;
108*f169c0eaSGlenn Lagasse 	uint16_t	fs_num = 0;
109*f169c0eaSGlenn Lagasse 	uint16_t	shared_fs_num = 0;
110*f169c0eaSGlenn Lagasse 	int		nelem;
111*f169c0eaSGlenn Lagasse 	int		i;
112*f169c0eaSGlenn Lagasse 	int		zret = 0, ret = BE_SUCCESS;
113*f169c0eaSGlenn Lagasse 
114*f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
115*f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
116*f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
117*f169c0eaSGlenn Lagasse 
118*f169c0eaSGlenn Lagasse 	/* Get new BE name */
119*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name)
120*f169c0eaSGlenn Lagasse 	    != 0) {
121*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup "
122*f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_NAME attribute\n"));
123*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
124*f169c0eaSGlenn Lagasse 	}
125*f169c0eaSGlenn Lagasse 
126*f169c0eaSGlenn Lagasse 	/* Validate new BE name */
127*f169c0eaSGlenn Lagasse 	if (!be_valid_be_name(bt.nbe_name)) {
128*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: invalid BE name %s\n"),
129*f169c0eaSGlenn Lagasse 		    bt.nbe_name);
130*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
131*f169c0eaSGlenn Lagasse 	}
132*f169c0eaSGlenn Lagasse 
133*f169c0eaSGlenn Lagasse 	/* Get zpool name */
134*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_POOL, &bt.nbe_zpool)
135*f169c0eaSGlenn Lagasse 	    != 0) {
136*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup "
137*f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_POOL attribute\n"));
138*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
139*f169c0eaSGlenn Lagasse 	}
140*f169c0eaSGlenn Lagasse 
141*f169c0eaSGlenn Lagasse 	/* Get file system attributes */
142*f169c0eaSGlenn Lagasse 	nelem = 0;
143*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, 0,
144*f169c0eaSGlenn Lagasse 	    BE_ATTR_FS_NUM, DATA_TYPE_UINT16, &fs_num,
145*f169c0eaSGlenn Lagasse 	    BE_ATTR_FS_NAMES, DATA_TYPE_STRING_ARRAY, &fs_names, &nelem,
146*f169c0eaSGlenn Lagasse 	    NULL) != 0) {
147*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup fs "
148*f169c0eaSGlenn Lagasse 		    "attributes\n"));
149*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
150*f169c0eaSGlenn Lagasse 	}
151*f169c0eaSGlenn Lagasse 	if (nelem != fs_num) {
152*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: size of FS_NAMES array (%d) "
153*f169c0eaSGlenn Lagasse 		    "does not match FS_NUM (%d)\n"), nelem, fs_num);
154*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
155*f169c0eaSGlenn Lagasse 	}
156*f169c0eaSGlenn Lagasse 
157*f169c0eaSGlenn Lagasse 	/* Get shared file system attributes */
158*f169c0eaSGlenn Lagasse 	nelem = 0;
159*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
160*f169c0eaSGlenn Lagasse 	    BE_ATTR_SHARED_FS_NUM, DATA_TYPE_UINT16, &shared_fs_num,
161*f169c0eaSGlenn Lagasse 	    BE_ATTR_SHARED_FS_NAMES, DATA_TYPE_STRING_ARRAY, &shared_fs_names,
162*f169c0eaSGlenn Lagasse 	    &nelem, NULL) != 0) {
163*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup "
164*f169c0eaSGlenn Lagasse 		    "shared fs attributes\n"));
165*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
166*f169c0eaSGlenn Lagasse 	}
167*f169c0eaSGlenn Lagasse 	if (nelem != shared_fs_num) {
168*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: size of SHARED_FS_NAMES "
169*f169c0eaSGlenn Lagasse 		    "array does not match SHARED_FS_NUM\n"));
170*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
171*f169c0eaSGlenn Lagasse 	}
172*f169c0eaSGlenn Lagasse 
173*f169c0eaSGlenn Lagasse 	/* Verify that nbe_zpool exists */
174*f169c0eaSGlenn Lagasse 	if ((zlp = zpool_open(g_zfs, bt.nbe_zpool)) == NULL) {
175*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to "
176*f169c0eaSGlenn Lagasse 		    "find existing zpool (%s): %s\n"), bt.nbe_zpool,
177*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
178*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
179*f169c0eaSGlenn Lagasse 	}
180*f169c0eaSGlenn Lagasse 	zpool_close(zlp);
181*f169c0eaSGlenn Lagasse 
182*f169c0eaSGlenn Lagasse 	/*
183*f169c0eaSGlenn Lagasse 	 * Verify BE container dataset in nbe_zpool exists.
184*f169c0eaSGlenn Lagasse 	 * If not, create it.
185*f169c0eaSGlenn Lagasse 	 */
186*f169c0eaSGlenn Lagasse 	if (!be_create_container_ds(bt.nbe_zpool))
187*f169c0eaSGlenn Lagasse 		return (BE_ERR_CREATDS);
188*f169c0eaSGlenn Lagasse 
189*f169c0eaSGlenn Lagasse 	/*
190*f169c0eaSGlenn Lagasse 	 * Verify that nbe_name doesn't already exist in some pool.
191*f169c0eaSGlenn Lagasse 	 */
192*f169c0eaSGlenn Lagasse 	if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name)) > 0) {
193*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: BE (%s) already exists\n"),
194*f169c0eaSGlenn Lagasse 		    bt.nbe_name);
195*f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_EXISTS);
196*f169c0eaSGlenn Lagasse 	} else if (zret < 0) {
197*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: zpool_iter failed: %s\n"),
198*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
199*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
200*f169c0eaSGlenn Lagasse 	}
201*f169c0eaSGlenn Lagasse 
202*f169c0eaSGlenn Lagasse 	/* Generate string for BE's root dataset */
203*f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
204*f169c0eaSGlenn Lagasse 	    sizeof (nbe_root_ds));
205*f169c0eaSGlenn Lagasse 
206*f169c0eaSGlenn Lagasse 	/*
207*f169c0eaSGlenn Lagasse 	 * Create property list for new BE root dataset.  If some
208*f169c0eaSGlenn Lagasse 	 * zfs properties were already provided by the caller, dup
209*f169c0eaSGlenn Lagasse 	 * that list.  Otherwise initialize a new property list.
210*f169c0eaSGlenn Lagasse 	 */
211*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
212*f169c0eaSGlenn Lagasse 	    BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
213*f169c0eaSGlenn Lagasse 	    != 0) {
214*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup "
215*f169c0eaSGlenn Lagasse 		    "BE_ATTR_ZFS_PROPERTIES attribute\n"));
216*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
217*f169c0eaSGlenn Lagasse 	}
218*f169c0eaSGlenn Lagasse 	if (zfs_props != NULL) {
219*f169c0eaSGlenn Lagasse 		/* Make sure its a unique nvlist */
220*f169c0eaSGlenn Lagasse 		if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
221*f169c0eaSGlenn Lagasse 		    !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
222*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: ZFS property list "
223*f169c0eaSGlenn Lagasse 			    "not unique\n"));
224*f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
225*f169c0eaSGlenn Lagasse 		}
226*f169c0eaSGlenn Lagasse 
227*f169c0eaSGlenn Lagasse 		/* Dup the list */
228*f169c0eaSGlenn Lagasse 		if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
229*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: failed to dup ZFS "
230*f169c0eaSGlenn Lagasse 			    "property list\n"));
231*f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
232*f169c0eaSGlenn Lagasse 		}
233*f169c0eaSGlenn Lagasse 	} else {
234*f169c0eaSGlenn Lagasse 		/* Initialize new nvlist */
235*f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
236*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: internal "
237*f169c0eaSGlenn Lagasse 			    "error: out of memory\n"));
238*f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
239*f169c0eaSGlenn Lagasse 		}
240*f169c0eaSGlenn Lagasse 	}
241*f169c0eaSGlenn Lagasse 
242*f169c0eaSGlenn Lagasse 	/* Set the mountpoint property for the root dataset */
243*f169c0eaSGlenn Lagasse 	if (nvlist_add_string(bt.nbe_zfs_props,
244*f169c0eaSGlenn Lagasse 	    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), "/") != 0) {
245*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: internal error "
246*f169c0eaSGlenn Lagasse 		    "out of memory\n"));
247*f169c0eaSGlenn Lagasse 		ret = BE_ERR_NOMEM;
248*f169c0eaSGlenn Lagasse 		goto done;
249*f169c0eaSGlenn Lagasse 	}
250*f169c0eaSGlenn Lagasse 
251*f169c0eaSGlenn Lagasse 	/* Set the 'canmount' property */
252*f169c0eaSGlenn Lagasse 	if (nvlist_add_string(bt.nbe_zfs_props,
253*f169c0eaSGlenn Lagasse 	    zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
254*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: internal error "
255*f169c0eaSGlenn Lagasse 		    "out of memory\n"));
256*f169c0eaSGlenn Lagasse 		ret = BE_ERR_NOMEM;
257*f169c0eaSGlenn Lagasse 		goto done;
258*f169c0eaSGlenn Lagasse 	}
259*f169c0eaSGlenn Lagasse 
260*f169c0eaSGlenn Lagasse 	/* Create BE root dataset for the new BE */
261*f169c0eaSGlenn Lagasse 	if (zfs_create(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM,
262*f169c0eaSGlenn Lagasse 	    bt.nbe_zfs_props) != 0) {
263*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to "
264*f169c0eaSGlenn Lagasse 		    "create BE root dataset (%s): %s\n"), nbe_root_ds,
265*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
266*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
267*f169c0eaSGlenn Lagasse 		goto done;
268*f169c0eaSGlenn Lagasse 	}
269*f169c0eaSGlenn Lagasse 
270*f169c0eaSGlenn Lagasse 	/* Set UUID for new BE */
271*f169c0eaSGlenn Lagasse 	if ((ret = be_set_uuid(nbe_root_ds)) != BE_SUCCESS) {
272*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to "
273*f169c0eaSGlenn Lagasse 		    "set uuid for new BE\n"));
274*f169c0eaSGlenn Lagasse 	}
275*f169c0eaSGlenn Lagasse 
276*f169c0eaSGlenn Lagasse 	/*
277*f169c0eaSGlenn Lagasse 	 * Clear the mountpoint property so that the non-shared
278*f169c0eaSGlenn Lagasse 	 * file systems created below inherit their mountpoints.
279*f169c0eaSGlenn Lagasse 	 */
280*f169c0eaSGlenn Lagasse 	(void) nvlist_remove(bt.nbe_zfs_props,
281*f169c0eaSGlenn Lagasse 	    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), DATA_TYPE_STRING);
282*f169c0eaSGlenn Lagasse 
283*f169c0eaSGlenn Lagasse 	/* Create the new BE's non-shared file systems */
284*f169c0eaSGlenn Lagasse 	for (i = 0; i < fs_num && fs_names[i]; i++) {
285*f169c0eaSGlenn Lagasse 		/*
286*f169c0eaSGlenn Lagasse 		 * If fs == "/", skip it;
287*f169c0eaSGlenn Lagasse 		 * we already created the root dataset
288*f169c0eaSGlenn Lagasse 		 */
289*f169c0eaSGlenn Lagasse 		if (strcmp(fs_names[i], "/") == 0)
290*f169c0eaSGlenn Lagasse 			continue;
291*f169c0eaSGlenn Lagasse 
292*f169c0eaSGlenn Lagasse 		/* Generate string for file system */
293*f169c0eaSGlenn Lagasse 		(void) snprintf(child_fs, sizeof (child_fs), "%s%s",
294*f169c0eaSGlenn Lagasse 		    nbe_root_ds, fs_names[i]);
295*f169c0eaSGlenn Lagasse 
296*f169c0eaSGlenn Lagasse 		/* Create file system */
297*f169c0eaSGlenn Lagasse 		if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
298*f169c0eaSGlenn Lagasse 		    bt.nbe_zfs_props) != 0) {
299*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: failed to create "
300*f169c0eaSGlenn Lagasse 			    "BE's child dataset (%s): %s\n"), child_fs,
301*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
302*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
303*f169c0eaSGlenn Lagasse 			goto done;
304*f169c0eaSGlenn Lagasse 		}
305*f169c0eaSGlenn Lagasse 	}
306*f169c0eaSGlenn Lagasse 
307*f169c0eaSGlenn Lagasse 	/* Create the new BE's shared file systems */
308*f169c0eaSGlenn Lagasse 	if (shared_fs_num > 0) {
309*f169c0eaSGlenn Lagasse 		nvlist_t	*props = NULL;
310*f169c0eaSGlenn Lagasse 
311*f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
312*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: nvlist_alloc failed\n"));
313*f169c0eaSGlenn Lagasse 			ret = BE_ERR_NOMEM;
314*f169c0eaSGlenn Lagasse 			goto done;
315*f169c0eaSGlenn Lagasse 		}
316*f169c0eaSGlenn Lagasse 
317*f169c0eaSGlenn Lagasse 		for (i = 0; i < shared_fs_num; i++) {
318*f169c0eaSGlenn Lagasse 			/* Generate string for shared file system */
319*f169c0eaSGlenn Lagasse 			(void) snprintf(child_fs, sizeof (child_fs), "%s%s",
320*f169c0eaSGlenn Lagasse 			    bt.nbe_zpool, shared_fs_names[i]);
321*f169c0eaSGlenn Lagasse 
322*f169c0eaSGlenn Lagasse 			if (nvlist_add_string(props,
323*f169c0eaSGlenn Lagasse 			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
324*f169c0eaSGlenn Lagasse 			    shared_fs_names[i]) != 0) {
325*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_init: "
326*f169c0eaSGlenn Lagasse 				    "internal error: out of memory\n"));
327*f169c0eaSGlenn Lagasse 				nvlist_free(props);
328*f169c0eaSGlenn Lagasse 				ret = BE_ERR_NOMEM;
329*f169c0eaSGlenn Lagasse 				goto done;
330*f169c0eaSGlenn Lagasse 			}
331*f169c0eaSGlenn Lagasse 
332*f169c0eaSGlenn Lagasse 			/* Create file system if it doesn't already exist */
333*f169c0eaSGlenn Lagasse 			if (zfs_dataset_exists(g_zfs, child_fs,
334*f169c0eaSGlenn Lagasse 			    ZFS_TYPE_FILESYSTEM)) {
335*f169c0eaSGlenn Lagasse 				continue;
336*f169c0eaSGlenn Lagasse 			}
337*f169c0eaSGlenn Lagasse 			if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
338*f169c0eaSGlenn Lagasse 			    props) != 0) {
339*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_init: failed to "
340*f169c0eaSGlenn Lagasse 				    "create BE's shared dataset (%s): %s\n"),
341*f169c0eaSGlenn Lagasse 				    child_fs, libzfs_error_description(g_zfs));
342*f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
343*f169c0eaSGlenn Lagasse 				nvlist_free(props);
344*f169c0eaSGlenn Lagasse 				goto done;
345*f169c0eaSGlenn Lagasse 			}
346*f169c0eaSGlenn Lagasse 		}
347*f169c0eaSGlenn Lagasse 
348*f169c0eaSGlenn Lagasse 		nvlist_free(props);
349*f169c0eaSGlenn Lagasse 	}
350*f169c0eaSGlenn Lagasse 
351*f169c0eaSGlenn Lagasse done:
352*f169c0eaSGlenn Lagasse 	if (bt.nbe_zfs_props != NULL)
353*f169c0eaSGlenn Lagasse 		nvlist_free(bt.nbe_zfs_props);
354*f169c0eaSGlenn Lagasse 
355*f169c0eaSGlenn Lagasse 	be_zfs_fini();
356*f169c0eaSGlenn Lagasse 
357*f169c0eaSGlenn Lagasse 	return (ret);
358*f169c0eaSGlenn Lagasse }
359*f169c0eaSGlenn Lagasse 
360*f169c0eaSGlenn Lagasse /*
361*f169c0eaSGlenn Lagasse  * Function:	be_destroy
362*f169c0eaSGlenn Lagasse  * Description:	Destroy a BE and all of its children datasets, snapshots and
363*f169c0eaSGlenn Lagasse  *		zones that belong to the parent BE.
364*f169c0eaSGlenn Lagasse  * Parameters:
365*f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
366*f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
367*f169c0eaSGlenn Lagasse  *
368*f169c0eaSGlenn Lagasse  *			BE_ATTR_ORIG_BE_NAME		*required
369*f169c0eaSGlenn Lagasse  *			BE_ATTR_DESTROY_FLAGS		*optional
370*f169c0eaSGlenn Lagasse  * Return:
371*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
372*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
373*f169c0eaSGlenn Lagasse  * Scope:
374*f169c0eaSGlenn Lagasse  *		Public
375*f169c0eaSGlenn Lagasse  */
376*f169c0eaSGlenn Lagasse int
377*f169c0eaSGlenn Lagasse be_destroy(nvlist_t *be_attrs)
378*f169c0eaSGlenn Lagasse {
379*f169c0eaSGlenn Lagasse 	zfs_handle_t		*zhp = NULL;
380*f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
381*f169c0eaSGlenn Lagasse 	be_transaction_data_t	cur_bt = { 0 };
382*f169c0eaSGlenn Lagasse 	be_destroy_data_t	dd = { 0 };
383*f169c0eaSGlenn Lagasse 	int			ret = BE_SUCCESS;
384*f169c0eaSGlenn Lagasse 	uint16_t		flags = 0;
385*f169c0eaSGlenn Lagasse 	int			zret;
386*f169c0eaSGlenn Lagasse 	char			obe_root_ds[MAXPATHLEN];
387*f169c0eaSGlenn Lagasse 	char			*mp = NULL;
388*f169c0eaSGlenn Lagasse 
389*f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
390*f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
391*f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
392*f169c0eaSGlenn Lagasse 
393*f169c0eaSGlenn Lagasse 	/* Get name of BE to delete */
394*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name)
395*f169c0eaSGlenn Lagasse 	    != 0) {
396*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to lookup "
397*f169c0eaSGlenn Lagasse 		    "BE_ATTR_ORIG_BE_NAME attribute\n"));
398*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
399*f169c0eaSGlenn Lagasse 	}
400*f169c0eaSGlenn Lagasse 
401*f169c0eaSGlenn Lagasse 	/*
402*f169c0eaSGlenn Lagasse 	 * Validate BE name. If valid, then check that the original BE is not
403*f169c0eaSGlenn Lagasse 	 * the active BE. If it is the 'active' BE then return an error code
404*f169c0eaSGlenn Lagasse 	 * since we can't destroy the active BE.
405*f169c0eaSGlenn Lagasse 	 */
406*f169c0eaSGlenn Lagasse 	if (!be_valid_be_name(bt.obe_name)) {
407*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: invalid BE name %s\n"),
408*f169c0eaSGlenn Lagasse 		    bt.obe_name);
409*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
410*f169c0eaSGlenn Lagasse 	} else if (bt.obe_name != NULL) {
411*f169c0eaSGlenn Lagasse 		if ((ret = be_find_current_be(&cur_bt)) != BE_SUCCESS) {
412*f169c0eaSGlenn Lagasse 			return (ret);
413*f169c0eaSGlenn Lagasse 		}
414*f169c0eaSGlenn Lagasse 		if (strcmp(cur_bt.obe_name, bt.obe_name) == 0) {
415*f169c0eaSGlenn Lagasse 			return (BE_ERR_DESTROY_CURR_BE);
416*f169c0eaSGlenn Lagasse 		}
417*f169c0eaSGlenn Lagasse 	}
418*f169c0eaSGlenn Lagasse 
419*f169c0eaSGlenn Lagasse 	/* Get destroy flags if provided */
420*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
421*f169c0eaSGlenn Lagasse 	    BE_ATTR_DESTROY_FLAGS, DATA_TYPE_UINT16, &flags, NULL)
422*f169c0eaSGlenn Lagasse 	    != 0) {
423*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to lookup "
424*f169c0eaSGlenn Lagasse 		    "BE_ATTR_DESTROY_FLAGS attribute\n"));
425*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
426*f169c0eaSGlenn Lagasse 	}
427*f169c0eaSGlenn Lagasse 
428*f169c0eaSGlenn Lagasse 	dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
429*f169c0eaSGlenn Lagasse 	dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
430*f169c0eaSGlenn Lagasse 
431*f169c0eaSGlenn Lagasse 	/* Find which zpool obe_name lives in */
432*f169c0eaSGlenn Lagasse 	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
433*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to find zpool "
434*f169c0eaSGlenn Lagasse 		    "for BE (%s)\n"), bt.obe_name);
435*f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_NOENT);
436*f169c0eaSGlenn Lagasse 	} else if (zret < 0) {
437*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
438*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
439*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
440*f169c0eaSGlenn Lagasse 	}
441*f169c0eaSGlenn Lagasse 
442*f169c0eaSGlenn Lagasse 	/* Generate string for obe_name's root dataset */
443*f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
444*f169c0eaSGlenn Lagasse 	    sizeof (obe_root_ds));
445*f169c0eaSGlenn Lagasse 	bt.obe_root_ds = obe_root_ds;
446*f169c0eaSGlenn Lagasse 
447*f169c0eaSGlenn Lagasse 	/*
448*f169c0eaSGlenn Lagasse 	 * Detect if the BE to destroy has the 'active on boot' property set.
449*f169c0eaSGlenn Lagasse 	 * If so, set the 'active on boot' property on the the 'active' BE.
450*f169c0eaSGlenn Lagasse 	 */
451*f169c0eaSGlenn Lagasse 	if (be_is_active_on_boot(bt.obe_name)) {
452*f169c0eaSGlenn Lagasse 		if ((ret = be_activate_current_be()) != BE_SUCCESS) {
453*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
454*f169c0eaSGlenn Lagasse 			    "make the current BE 'active on boot'\n"));
455*f169c0eaSGlenn Lagasse 			return (ret);
456*f169c0eaSGlenn Lagasse 		}
457*f169c0eaSGlenn Lagasse 	}
458*f169c0eaSGlenn Lagasse 
459*f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
460*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
461*f169c0eaSGlenn Lagasse 	    NULL) {
462*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to "
463*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
464*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
465*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
466*f169c0eaSGlenn Lagasse 	}
467*f169c0eaSGlenn Lagasse 
468*f169c0eaSGlenn Lagasse 	/* Get the UUID of the global BE */
469*f169c0eaSGlenn Lagasse 	if (be_get_uuid(zfs_get_name(zhp), &dd.gz_be_uuid) != BE_SUCCESS) {
470*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: BE has no UUID (%s)\n"),
471*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp));
472*f169c0eaSGlenn Lagasse 	}
473*f169c0eaSGlenn Lagasse 
474*f169c0eaSGlenn Lagasse 	/*
475*f169c0eaSGlenn Lagasse 	 * If the global BE is mounted, make sure we've been given the
476*f169c0eaSGlenn Lagasse 	 * flag to forcibly unmount it.
477*f169c0eaSGlenn Lagasse 	 */
478*f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &mp)) {
479*f169c0eaSGlenn Lagasse 		if (!(dd.force_unmount)) {
480*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: "
481*f169c0eaSGlenn Lagasse 			    "%s is currently mounted at %s, cannot destroy\n"),
482*f169c0eaSGlenn Lagasse 			    bt.obe_name, mp != NULL ? mp : "<unknown>");
483*f169c0eaSGlenn Lagasse 
484*f169c0eaSGlenn Lagasse 			free(mp);
485*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
486*f169c0eaSGlenn Lagasse 			return (BE_ERR_MOUNTED);
487*f169c0eaSGlenn Lagasse 		}
488*f169c0eaSGlenn Lagasse 		free(mp);
489*f169c0eaSGlenn Lagasse 	}
490*f169c0eaSGlenn Lagasse 
491*f169c0eaSGlenn Lagasse 	/*
492*f169c0eaSGlenn Lagasse 	 * Destroy the non-global zone BE's if we are in the global zone
493*f169c0eaSGlenn Lagasse 	 * and there is a UUID associated with the global zone BE
494*f169c0eaSGlenn Lagasse 	 */
495*f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID && !uuid_is_null(dd.gz_be_uuid)) {
496*f169c0eaSGlenn Lagasse 		if ((ret = be_destroy_zones(bt.obe_name, bt.obe_root_ds, &dd))
497*f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
498*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
499*f169c0eaSGlenn Lagasse 			    "destroy one or more zones for BE %s\n"),
500*f169c0eaSGlenn Lagasse 			    bt.obe_name);
501*f169c0eaSGlenn Lagasse 			goto done;
502*f169c0eaSGlenn Lagasse 		}
503*f169c0eaSGlenn Lagasse 	}
504*f169c0eaSGlenn Lagasse 
505*f169c0eaSGlenn Lagasse 	/* Unmount the BE if it was mounted */
506*f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, NULL)) {
507*f169c0eaSGlenn Lagasse 		if ((ret = _be_unmount(bt.obe_name, BE_UNMOUNT_FLAG_FORCE))
508*f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
509*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: "
510*f169c0eaSGlenn Lagasse 			    "failed to unmount %s\n"), bt.obe_name);
511*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
512*f169c0eaSGlenn Lagasse 			return (ret);
513*f169c0eaSGlenn Lagasse 		}
514*f169c0eaSGlenn Lagasse 	}
515*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
516*f169c0eaSGlenn Lagasse 
517*f169c0eaSGlenn Lagasse 	/* Destroy this BE */
518*f169c0eaSGlenn Lagasse 	if ((ret = _be_destroy((const char *)bt.obe_root_ds, &dd))
519*f169c0eaSGlenn Lagasse 	    != BE_SUCCESS) {
520*f169c0eaSGlenn Lagasse 		goto done;
521*f169c0eaSGlenn Lagasse 	}
522*f169c0eaSGlenn Lagasse 
523*f169c0eaSGlenn Lagasse 	/* Remove BE's entry from the boot menu */
524*f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID) {
525*f169c0eaSGlenn Lagasse 		if ((ret = be_remove_menu(bt.obe_name, bt.obe_zpool, NULL))
526*f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
527*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
528*f169c0eaSGlenn Lagasse 			    "remove BE %s from the boot menu\n"),
529*f169c0eaSGlenn Lagasse 			    bt.obe_root_ds);
530*f169c0eaSGlenn Lagasse 			goto done;
531*f169c0eaSGlenn Lagasse 		}
532*f169c0eaSGlenn Lagasse 	}
533*f169c0eaSGlenn Lagasse 
534*f169c0eaSGlenn Lagasse done:
535*f169c0eaSGlenn Lagasse 	be_zfs_fini();
536*f169c0eaSGlenn Lagasse 
537*f169c0eaSGlenn Lagasse 	return (ret);
538*f169c0eaSGlenn Lagasse }
539*f169c0eaSGlenn Lagasse 
540*f169c0eaSGlenn Lagasse /*
541*f169c0eaSGlenn Lagasse  * Function:	be_copy
542*f169c0eaSGlenn Lagasse  * Description:	This function makes a copy of an existing BE.  If the original
543*f169c0eaSGlenn Lagasse  *		BE and the new BE are in the same pool, it uses zfs cloning to
544*f169c0eaSGlenn Lagasse  *		create the new BE, otherwise it does a physical copy.
545*f169c0eaSGlenn Lagasse  *		If the original BE name isn't provided, it uses the currently
546*f169c0eaSGlenn Lagasse  *		booted BE.  If the new BE name isn't provided, it creates an
547*f169c0eaSGlenn Lagasse  *		auto named BE and returns that name to the caller.
548*f169c0eaSGlenn Lagasse  * Parameters:
549*f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
550*f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
551*f169c0eaSGlenn Lagasse  *
552*f169c0eaSGlenn Lagasse  *			BE_ATTR_ORIG_BE_NAME		*optional
553*f169c0eaSGlenn Lagasse  *			BE_ATTR_SNAP_NAME		*optional
554*f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_NAME		*optional
555*f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_POOL		*optional
556*f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_DESC		*optional
557*f169c0eaSGlenn Lagasse  *			BE_ATTR_ZFS_PROPERTIES		*optional
558*f169c0eaSGlenn Lagasse  *			BE_ATTR_POLICY			*optional
559*f169c0eaSGlenn Lagasse  *
560*f169c0eaSGlenn Lagasse  *			If the BE_ATTR_NEW_BE_NAME was not passed in, upon
561*f169c0eaSGlenn Lagasse  *			successful BE creation, the following attribute values
562*f169c0eaSGlenn Lagasse  *			will be returned to the caller by setting them in the
563*f169c0eaSGlenn Lagasse  *			be_attrs parameter passed in:
564*f169c0eaSGlenn Lagasse  *
565*f169c0eaSGlenn Lagasse  *			BE_ATTR_SNAP_NAME
566*f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_NAME
567*f169c0eaSGlenn Lagasse  * Return:
568*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
569*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
570*f169c0eaSGlenn Lagasse  * Scope:
571*f169c0eaSGlenn Lagasse  *		Public
572*f169c0eaSGlenn Lagasse  */
573*f169c0eaSGlenn Lagasse int
574*f169c0eaSGlenn Lagasse be_copy(nvlist_t *be_attrs)
575*f169c0eaSGlenn Lagasse {
576*f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
577*f169c0eaSGlenn Lagasse 	be_fs_list_data_t	fld = { 0 };
578*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
579*f169c0eaSGlenn Lagasse 	nvlist_t	*zfs_props = NULL;
580*f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
581*f169c0eaSGlenn Lagasse 	char		obe_root_ds[MAXPATHLEN];
582*f169c0eaSGlenn Lagasse 	char		nbe_root_ds[MAXPATHLEN];
583*f169c0eaSGlenn Lagasse 	char		ss[MAXPATHLEN];
584*f169c0eaSGlenn Lagasse 	char		*new_mp = NULL;
585*f169c0eaSGlenn Lagasse 	boolean_t	autoname = B_FALSE;
586*f169c0eaSGlenn Lagasse 	boolean_t	be_created = B_FALSE;
587*f169c0eaSGlenn Lagasse 	int		i;
588*f169c0eaSGlenn Lagasse 	int		zret;
589*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
590*f169c0eaSGlenn Lagasse 
591*f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
592*f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
593*f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
594*f169c0eaSGlenn Lagasse 
595*f169c0eaSGlenn Lagasse 	/* Get original BE name */
596*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
597*f169c0eaSGlenn Lagasse 	    BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &bt.obe_name, NULL) != 0) {
598*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
599*f169c0eaSGlenn Lagasse 		    "BE_ATTR_ORIG_BE_NAME attribute\n"));
600*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
601*f169c0eaSGlenn Lagasse 	}
602*f169c0eaSGlenn Lagasse 
603*f169c0eaSGlenn Lagasse 	/* If original BE name not provided, use current BE */
604*f169c0eaSGlenn Lagasse 	if (bt.obe_name == NULL) {
605*f169c0eaSGlenn Lagasse 		if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
606*f169c0eaSGlenn Lagasse 			return (ret);
607*f169c0eaSGlenn Lagasse 		}
608*f169c0eaSGlenn Lagasse 	} else {
609*f169c0eaSGlenn Lagasse 		/* Validate original BE name */
610*f169c0eaSGlenn Lagasse 		if (!be_valid_be_name(bt.obe_name)) {
611*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
612*f169c0eaSGlenn Lagasse 			    "invalid BE name %s\n"), bt.obe_name);
613*f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
614*f169c0eaSGlenn Lagasse 		}
615*f169c0eaSGlenn Lagasse 	}
616*f169c0eaSGlenn Lagasse 
617*f169c0eaSGlenn Lagasse 	/* Find which zpool obe_name lives in */
618*f169c0eaSGlenn Lagasse 	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
619*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
620*f169c0eaSGlenn Lagasse 		    "find zpool for BE (%s)\n"), bt.obe_name);
621*f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_NOENT);
622*f169c0eaSGlenn Lagasse 	} else if (zret < 0) {
623*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: "
624*f169c0eaSGlenn Lagasse 		    "zpool_iter failed: %s\n"),
625*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
626*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
627*f169c0eaSGlenn Lagasse 	}
628*f169c0eaSGlenn Lagasse 
629*f169c0eaSGlenn Lagasse 	/* Get snapshot name of original BE if one was provided */
630*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
631*f169c0eaSGlenn Lagasse 	    BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &bt.obe_snap_name, NULL)
632*f169c0eaSGlenn Lagasse 	    != 0) {
633*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
634*f169c0eaSGlenn Lagasse 		    "BE_ATTR_SNAP_NAME attribute\n"));
635*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
636*f169c0eaSGlenn Lagasse 	}
637*f169c0eaSGlenn Lagasse 
638*f169c0eaSGlenn Lagasse 	/* Get new BE name */
639*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
640*f169c0eaSGlenn Lagasse 	    BE_ATTR_NEW_BE_NAME, DATA_TYPE_STRING, &bt.nbe_name, NULL)
641*f169c0eaSGlenn Lagasse 	    != 0) {
642*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
643*f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_NAME attribute\n"));
644*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
645*f169c0eaSGlenn Lagasse 	}
646*f169c0eaSGlenn Lagasse 
647*f169c0eaSGlenn Lagasse 	/* Get zpool name to create new BE in */
648*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
649*f169c0eaSGlenn Lagasse 	    BE_ATTR_NEW_BE_POOL, DATA_TYPE_STRING, &bt.nbe_zpool, NULL) != 0) {
650*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
651*f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_POOL attribute\n"));
652*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
653*f169c0eaSGlenn Lagasse 	}
654*f169c0eaSGlenn Lagasse 
655*f169c0eaSGlenn Lagasse 	/* Get new BE's description if one was provided */
656*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
657*f169c0eaSGlenn Lagasse 	    BE_ATTR_NEW_BE_DESC, DATA_TYPE_STRING, &bt.nbe_desc, NULL) != 0) {
658*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
659*f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_DESC attribute\n"));
660*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
661*f169c0eaSGlenn Lagasse 	}
662*f169c0eaSGlenn Lagasse 
663*f169c0eaSGlenn Lagasse 	/* Get BE policy to create this snapshot under */
664*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
665*f169c0eaSGlenn Lagasse 	    BE_ATTR_POLICY, DATA_TYPE_STRING, &bt.policy, NULL) != 0) {
666*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
667*f169c0eaSGlenn Lagasse 		    "BE_ATTR_POLICY attribute\n"));
668*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
669*f169c0eaSGlenn Lagasse 	}
670*f169c0eaSGlenn Lagasse 
671*f169c0eaSGlenn Lagasse 	/*
672*f169c0eaSGlenn Lagasse 	 * Create property list for new BE root dataset.  If some
673*f169c0eaSGlenn Lagasse 	 * zfs properties were already provided by the caller, dup
674*f169c0eaSGlenn Lagasse 	 * that list.  Otherwise initialize a new property list.
675*f169c0eaSGlenn Lagasse 	 */
676*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
677*f169c0eaSGlenn Lagasse 	    BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
678*f169c0eaSGlenn Lagasse 	    != 0) {
679*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
680*f169c0eaSGlenn Lagasse 		    "BE_ATTR_ZFS_PROPERTIES attribute\n"));
681*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
682*f169c0eaSGlenn Lagasse 	}
683*f169c0eaSGlenn Lagasse 	if (zfs_props != NULL) {
684*f169c0eaSGlenn Lagasse 		/* Make sure its a unique nvlist */
685*f169c0eaSGlenn Lagasse 		if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
686*f169c0eaSGlenn Lagasse 		    !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
687*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: ZFS property list "
688*f169c0eaSGlenn Lagasse 			    "not unique\n"));
689*f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
690*f169c0eaSGlenn Lagasse 		}
691*f169c0eaSGlenn Lagasse 
692*f169c0eaSGlenn Lagasse 		/* Dup the list */
693*f169c0eaSGlenn Lagasse 		if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
694*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
695*f169c0eaSGlenn Lagasse 			    "failed to dup ZFS property list\n"));
696*f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
697*f169c0eaSGlenn Lagasse 		}
698*f169c0eaSGlenn Lagasse 	} else {
699*f169c0eaSGlenn Lagasse 		/* Initialize new nvlist */
700*f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
701*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: internal "
702*f169c0eaSGlenn Lagasse 			    "error: out of memory\n"));
703*f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
704*f169c0eaSGlenn Lagasse 		}
705*f169c0eaSGlenn Lagasse 	}
706*f169c0eaSGlenn Lagasse 
707*f169c0eaSGlenn Lagasse 	/*
708*f169c0eaSGlenn Lagasse 	 * If new BE name provided, validate the BE name and then verify
709*f169c0eaSGlenn Lagasse 	 * that new BE name doesn't already exist in some pool.
710*f169c0eaSGlenn Lagasse 	 */
711*f169c0eaSGlenn Lagasse 	if (bt.nbe_name) {
712*f169c0eaSGlenn Lagasse 		/* Validate original BE name */
713*f169c0eaSGlenn Lagasse 		if (!be_valid_be_name(bt.nbe_name)) {
714*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
715*f169c0eaSGlenn Lagasse 			    "invalid BE name %s\n"), bt.nbe_name);
716*f169c0eaSGlenn Lagasse 			ret = BE_ERR_INVAL;
717*f169c0eaSGlenn Lagasse 			goto done;
718*f169c0eaSGlenn Lagasse 		}
719*f169c0eaSGlenn Lagasse 
720*f169c0eaSGlenn Lagasse 		/* Verify it doesn't already exist */
721*f169c0eaSGlenn Lagasse 		if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name))
722*f169c0eaSGlenn Lagasse 		    > 0) {
723*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: BE (%s) already "
724*f169c0eaSGlenn Lagasse 			    "exists\n"), bt.nbe_name);
725*f169c0eaSGlenn Lagasse 			ret = BE_ERR_BE_EXISTS;
726*f169c0eaSGlenn Lagasse 			goto done;
727*f169c0eaSGlenn Lagasse 		} else if (zret < 0) {
728*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: zpool_iter failed: "
729*f169c0eaSGlenn Lagasse 			    "%s\n"), libzfs_error_description(g_zfs));
730*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
731*f169c0eaSGlenn Lagasse 			goto done;
732*f169c0eaSGlenn Lagasse 		}
733*f169c0eaSGlenn Lagasse 	} else {
734*f169c0eaSGlenn Lagasse 		/*
735*f169c0eaSGlenn Lagasse 		 * If an auto named BE is desired, it must be in the same
736*f169c0eaSGlenn Lagasse 		 * pool is the original BE.
737*f169c0eaSGlenn Lagasse 		 */
738*f169c0eaSGlenn Lagasse 		if (bt.nbe_zpool != NULL) {
739*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: cannot specify pool "
740*f169c0eaSGlenn Lagasse 			    "name when creating an auto named BE\n"));
741*f169c0eaSGlenn Lagasse 			ret = BE_ERR_INVAL;
742*f169c0eaSGlenn Lagasse 			goto done;
743*f169c0eaSGlenn Lagasse 		}
744*f169c0eaSGlenn Lagasse 
745*f169c0eaSGlenn Lagasse 		/*
746*f169c0eaSGlenn Lagasse 		 * Generate auto named BE
747*f169c0eaSGlenn Lagasse 		 */
748*f169c0eaSGlenn Lagasse 		if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
749*f169c0eaSGlenn Lagasse 		    == NULL) {
750*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
751*f169c0eaSGlenn Lagasse 			    "failed to generate auto BE name\n"));
752*f169c0eaSGlenn Lagasse 			ret = BE_ERR_AUTONAME;
753*f169c0eaSGlenn Lagasse 			goto done;
754*f169c0eaSGlenn Lagasse 		}
755*f169c0eaSGlenn Lagasse 
756*f169c0eaSGlenn Lagasse 		autoname = B_TRUE;
757*f169c0eaSGlenn Lagasse 	}
758*f169c0eaSGlenn Lagasse 
759*f169c0eaSGlenn Lagasse 	/*
760*f169c0eaSGlenn Lagasse 	 * If zpool name to create new BE in is not provided,
761*f169c0eaSGlenn Lagasse 	 * create new BE in original BE's pool.
762*f169c0eaSGlenn Lagasse 	 */
763*f169c0eaSGlenn Lagasse 	if (bt.nbe_zpool == NULL) {
764*f169c0eaSGlenn Lagasse 		bt.nbe_zpool = bt.obe_zpool;
765*f169c0eaSGlenn Lagasse 	}
766*f169c0eaSGlenn Lagasse 
767*f169c0eaSGlenn Lagasse 	/* Get root dataset names for obe_name and nbe_name */
768*f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
769*f169c0eaSGlenn Lagasse 	    sizeof (obe_root_ds));
770*f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
771*f169c0eaSGlenn Lagasse 	    sizeof (nbe_root_ds));
772*f169c0eaSGlenn Lagasse 
773*f169c0eaSGlenn Lagasse 	bt.obe_root_ds = obe_root_ds;
774*f169c0eaSGlenn Lagasse 	bt.nbe_root_ds = nbe_root_ds;
775*f169c0eaSGlenn Lagasse 
776*f169c0eaSGlenn Lagasse 	/*
777*f169c0eaSGlenn Lagasse 	 * If an existing snapshot name has been provided to create from,
778*f169c0eaSGlenn Lagasse 	 * verify that it exists for the original BE's root dataset.
779*f169c0eaSGlenn Lagasse 	 */
780*f169c0eaSGlenn Lagasse 	if (bt.obe_snap_name != NULL) {
781*f169c0eaSGlenn Lagasse 
782*f169c0eaSGlenn Lagasse 		/* Generate dataset name for snapshot to use. */
783*f169c0eaSGlenn Lagasse 		(void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds,
784*f169c0eaSGlenn Lagasse 		    bt.obe_snap_name);
785*f169c0eaSGlenn Lagasse 
786*f169c0eaSGlenn Lagasse 		/* Verify snapshot exists */
787*f169c0eaSGlenn Lagasse 		if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) {
788*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
789*f169c0eaSGlenn Lagasse 			    "snapshot does not exist (%s): %s\n"), ss,
790*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
791*f169c0eaSGlenn Lagasse 			ret = BE_ERR_SS_NOENT;
792*f169c0eaSGlenn Lagasse 			goto done;
793*f169c0eaSGlenn Lagasse 		}
794*f169c0eaSGlenn Lagasse 	} else {
795*f169c0eaSGlenn Lagasse 		/*
796*f169c0eaSGlenn Lagasse 		 * Else snapshot name was not provided, generate an
797*f169c0eaSGlenn Lagasse 		 * auto named snapshot to use as its origin.
798*f169c0eaSGlenn Lagasse 		 */
799*f169c0eaSGlenn Lagasse 		if ((ret = _be_create_snapshot(bt.obe_name,
800*f169c0eaSGlenn Lagasse 		    &bt.obe_snap_name, bt.policy)) != BE_SUCCESS) {
801*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
802*f169c0eaSGlenn Lagasse 			    "failed to create auto named snapshot\n"));
803*f169c0eaSGlenn Lagasse 			goto done;
804*f169c0eaSGlenn Lagasse 		}
805*f169c0eaSGlenn Lagasse 
806*f169c0eaSGlenn Lagasse 		if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME,
807*f169c0eaSGlenn Lagasse 		    bt.obe_snap_name) != 0) {
808*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
809*f169c0eaSGlenn Lagasse 			    "failed to add snap name to be_attrs\n"));
810*f169c0eaSGlenn Lagasse 			ret = BE_ERR_NOMEM;
811*f169c0eaSGlenn Lagasse 			goto done;
812*f169c0eaSGlenn Lagasse 		}
813*f169c0eaSGlenn Lagasse 	}
814*f169c0eaSGlenn Lagasse 
815*f169c0eaSGlenn Lagasse 	/* Get handle to original BE's root dataset. */
816*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM))
817*f169c0eaSGlenn Lagasse 	    == NULL) {
818*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
819*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
820*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
821*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
822*f169c0eaSGlenn Lagasse 		goto done;
823*f169c0eaSGlenn Lagasse 	}
824*f169c0eaSGlenn Lagasse 
825*f169c0eaSGlenn Lagasse 	/* If original BE is currently mounted, record its altroot. */
826*f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &bt.obe_altroot) && bt.obe_altroot == NULL) {
827*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
828*f169c0eaSGlenn Lagasse 		    "get altroot of mounted BE %s: %s\n"),
829*f169c0eaSGlenn Lagasse 		    bt.obe_name, libzfs_error_description(g_zfs));
830*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
831*f169c0eaSGlenn Lagasse 		goto done;
832*f169c0eaSGlenn Lagasse 	}
833*f169c0eaSGlenn Lagasse 
834*f169c0eaSGlenn Lagasse 	if (strcmp(bt.obe_zpool, bt.nbe_zpool) == 0) {
835*f169c0eaSGlenn Lagasse 
836*f169c0eaSGlenn Lagasse 		/* Do clone */
837*f169c0eaSGlenn Lagasse 
838*f169c0eaSGlenn Lagasse 		/*
839*f169c0eaSGlenn Lagasse 		 * Iterate through original BE's datasets and clone
840*f169c0eaSGlenn Lagasse 		 * them to create new BE.  This call will end up closing
841*f169c0eaSGlenn Lagasse 		 * the zfs handle passed in whether it succeeds for fails.
842*f169c0eaSGlenn Lagasse 		 */
843*f169c0eaSGlenn Lagasse 		if ((ret = be_clone_fs_callback(zhp, &bt)) != 0) {
844*f169c0eaSGlenn Lagasse 			zhp = NULL;
845*f169c0eaSGlenn Lagasse 			/* Creating clone BE failed */
846*f169c0eaSGlenn Lagasse 			if (!autoname || ret != BE_ERR_BE_EXISTS) {
847*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy: "
848*f169c0eaSGlenn Lagasse 				    "failed to clone new BE (%s) from "
849*f169c0eaSGlenn Lagasse 				    "orig BE (%s)\n"),
850*f169c0eaSGlenn Lagasse 				    bt.nbe_name, bt.obe_name);
851*f169c0eaSGlenn Lagasse 				ret = BE_ERR_CLONE;
852*f169c0eaSGlenn Lagasse 				goto done;
853*f169c0eaSGlenn Lagasse 			}
854*f169c0eaSGlenn Lagasse 
855*f169c0eaSGlenn Lagasse 			/*
856*f169c0eaSGlenn Lagasse 			 * We failed to create the new BE because a BE with
857*f169c0eaSGlenn Lagasse 			 * the auto-name we generated above has since come
858*f169c0eaSGlenn Lagasse 			 * into existence.  Regenerate a new auto-name
859*f169c0eaSGlenn Lagasse 			 * and retry.
860*f169c0eaSGlenn Lagasse 			 */
861*f169c0eaSGlenn Lagasse 			for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) {
862*f169c0eaSGlenn Lagasse 
863*f169c0eaSGlenn Lagasse 				/* Sleep 1 before retrying */
864*f169c0eaSGlenn Lagasse 				(void) sleep(1);
865*f169c0eaSGlenn Lagasse 
866*f169c0eaSGlenn Lagasse 				/* Generate new auto BE name */
867*f169c0eaSGlenn Lagasse 				free(bt.nbe_name);
868*f169c0eaSGlenn Lagasse 				if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
869*f169c0eaSGlenn Lagasse 				    == NULL) {
870*f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy: "
871*f169c0eaSGlenn Lagasse 					    "failed to generate auto "
872*f169c0eaSGlenn Lagasse 					    "BE name\n"));
873*f169c0eaSGlenn Lagasse 					ret = BE_ERR_AUTONAME;
874*f169c0eaSGlenn Lagasse 					goto done;
875*f169c0eaSGlenn Lagasse 				}
876*f169c0eaSGlenn Lagasse 
877*f169c0eaSGlenn Lagasse 				/*
878*f169c0eaSGlenn Lagasse 				 * Regenerate string for new BE's
879*f169c0eaSGlenn Lagasse 				 * root dataset name
880*f169c0eaSGlenn Lagasse 				 */
881*f169c0eaSGlenn Lagasse 				be_make_root_ds(bt.nbe_zpool, bt.nbe_name,
882*f169c0eaSGlenn Lagasse 				    nbe_root_ds, sizeof (nbe_root_ds));
883*f169c0eaSGlenn Lagasse 				bt.nbe_root_ds = nbe_root_ds;
884*f169c0eaSGlenn Lagasse 
885*f169c0eaSGlenn Lagasse 				/*
886*f169c0eaSGlenn Lagasse 				 * Get handle to original BE's root dataset.
887*f169c0eaSGlenn Lagasse 				 */
888*f169c0eaSGlenn Lagasse 				if ((zhp = zfs_open(g_zfs, bt.obe_root_ds,
889*f169c0eaSGlenn Lagasse 				    ZFS_TYPE_FILESYSTEM)) == NULL) {
890*f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy: "
891*f169c0eaSGlenn Lagasse 					    "failed to open BE root dataset "
892*f169c0eaSGlenn Lagasse 					    "(%s): %s\n"), bt.obe_root_ds,
893*f169c0eaSGlenn Lagasse 					    libzfs_error_description(g_zfs));
894*f169c0eaSGlenn Lagasse 					ret = zfs_err_to_be_err(g_zfs);
895*f169c0eaSGlenn Lagasse 					goto done;
896*f169c0eaSGlenn Lagasse 				}
897*f169c0eaSGlenn Lagasse 
898*f169c0eaSGlenn Lagasse 				/*
899*f169c0eaSGlenn Lagasse 				 * Try to clone the BE again.  This
900*f169c0eaSGlenn Lagasse 				 * call will end up closing the zfs
901*f169c0eaSGlenn Lagasse 				 * handle passed in whether it
902*f169c0eaSGlenn Lagasse 				 * succeeds or fails.
903*f169c0eaSGlenn Lagasse 				 */
904*f169c0eaSGlenn Lagasse 				ret = be_clone_fs_callback(zhp, &bt);
905*f169c0eaSGlenn Lagasse 				zhp = NULL;
906*f169c0eaSGlenn Lagasse 				if (ret == 0) {
907*f169c0eaSGlenn Lagasse 					break;
908*f169c0eaSGlenn Lagasse 				} else if (ret != BE_ERR_BE_EXISTS) {
909*f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy: "
910*f169c0eaSGlenn Lagasse 					    "failed to clone new BE "
911*f169c0eaSGlenn Lagasse 					    "(%s) from orig BE (%s)\n"),
912*f169c0eaSGlenn Lagasse 					    bt.nbe_name, bt.obe_name);
913*f169c0eaSGlenn Lagasse 					ret = BE_ERR_CLONE;
914*f169c0eaSGlenn Lagasse 					goto done;
915*f169c0eaSGlenn Lagasse 				}
916*f169c0eaSGlenn Lagasse 			}
917*f169c0eaSGlenn Lagasse 
918*f169c0eaSGlenn Lagasse 			/*
919*f169c0eaSGlenn Lagasse 			 * If we've exhausted the maximum number of
920*f169c0eaSGlenn Lagasse 			 * tries, free the auto BE name and return
921*f169c0eaSGlenn Lagasse 			 * error.
922*f169c0eaSGlenn Lagasse 			 */
923*f169c0eaSGlenn Lagasse 			if (i == BE_AUTO_NAME_MAX_TRY) {
924*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy: failed "
925*f169c0eaSGlenn Lagasse 				    "to create unique auto BE name\n"));
926*f169c0eaSGlenn Lagasse 				free(bt.nbe_name);
927*f169c0eaSGlenn Lagasse 				bt.nbe_name = NULL;
928*f169c0eaSGlenn Lagasse 				ret = BE_ERR_AUTONAME;
929*f169c0eaSGlenn Lagasse 				goto done;
930*f169c0eaSGlenn Lagasse 			}
931*f169c0eaSGlenn Lagasse 		}
932*f169c0eaSGlenn Lagasse 		zhp = NULL;
933*f169c0eaSGlenn Lagasse 
934*f169c0eaSGlenn Lagasse 	} else {
935*f169c0eaSGlenn Lagasse 
936*f169c0eaSGlenn Lagasse 		/* Do copy (i.e. send BE datasets via zfs_send/recv) */
937*f169c0eaSGlenn Lagasse 
938*f169c0eaSGlenn Lagasse 		/*
939*f169c0eaSGlenn Lagasse 		 * Verify BE container dataset in nbe_zpool exists.
940*f169c0eaSGlenn Lagasse 		 * If not, create it.
941*f169c0eaSGlenn Lagasse 		 */
942*f169c0eaSGlenn Lagasse 		if (!be_create_container_ds(bt.nbe_zpool)) {
943*f169c0eaSGlenn Lagasse 			ret = BE_ERR_CREATDS;
944*f169c0eaSGlenn Lagasse 			goto done;
945*f169c0eaSGlenn Lagasse 		}
946*f169c0eaSGlenn Lagasse 
947*f169c0eaSGlenn Lagasse 		/*
948*f169c0eaSGlenn Lagasse 		 * Iterate through original BE's datasets and send
949*f169c0eaSGlenn Lagasse 		 * them to the other pool.  This call will end up closing
950*f169c0eaSGlenn Lagasse 		 * the zfs handle passed in whether it succeeds or fails.
951*f169c0eaSGlenn Lagasse 		 */
952*f169c0eaSGlenn Lagasse 		if ((ret = be_send_fs_callback(zhp, &bt)) != 0) {
953*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: failed to "
954*f169c0eaSGlenn Lagasse 			    "send BE (%s) to pool (%s)\n"), bt.obe_name,
955*f169c0eaSGlenn Lagasse 			    bt.nbe_zpool);
956*f169c0eaSGlenn Lagasse 			ret = BE_ERR_COPY;
957*f169c0eaSGlenn Lagasse 			zhp = NULL;
958*f169c0eaSGlenn Lagasse 			goto done;
959*f169c0eaSGlenn Lagasse 		}
960*f169c0eaSGlenn Lagasse 		zhp = NULL;
961*f169c0eaSGlenn Lagasse 	}
962*f169c0eaSGlenn Lagasse 
963*f169c0eaSGlenn Lagasse 	/*
964*f169c0eaSGlenn Lagasse 	 * Set flag to note that the dataset(s) for the new BE have been
965*f169c0eaSGlenn Lagasse 	 * successfully created so that if a failure happens from this point
966*f169c0eaSGlenn Lagasse 	 * on, we know to cleanup these datasets.
967*f169c0eaSGlenn Lagasse 	 */
968*f169c0eaSGlenn Lagasse 	be_created = B_TRUE;
969*f169c0eaSGlenn Lagasse 
970*f169c0eaSGlenn Lagasse 	/*
971*f169c0eaSGlenn Lagasse 	 * Validate that the new BE is mountable.
972*f169c0eaSGlenn Lagasse 	 * Do not attempt to mount non-global zone datasets
973*f169c0eaSGlenn Lagasse 	 * since they are not cloned yet.
974*f169c0eaSGlenn Lagasse 	 */
975*f169c0eaSGlenn Lagasse 	if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
976*f169c0eaSGlenn Lagasse 	    != BE_SUCCESS) {
977*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
978*f169c0eaSGlenn Lagasse 		    "mount newly created BE\n"));
979*f169c0eaSGlenn Lagasse 		(void) _be_unmount(bt.nbe_name, 0);
980*f169c0eaSGlenn Lagasse 		goto done;
981*f169c0eaSGlenn Lagasse 	}
982*f169c0eaSGlenn Lagasse 
983*f169c0eaSGlenn Lagasse 	/* Set UUID for new BE */
984*f169c0eaSGlenn Lagasse 	if (be_set_uuid(bt.nbe_root_ds) != BE_SUCCESS) {
985*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
986*f169c0eaSGlenn Lagasse 		    "set uuid for new BE\n"));
987*f169c0eaSGlenn Lagasse 	}
988*f169c0eaSGlenn Lagasse 
989*f169c0eaSGlenn Lagasse 	/*
990*f169c0eaSGlenn Lagasse 	 * Process zones outside of the private BE namespace.
991*f169c0eaSGlenn Lagasse 	 * This has to be done here because we need the uuid set in the
992*f169c0eaSGlenn Lagasse 	 * root dataset of the new BE. The uuid is use to set the parentbe
993*f169c0eaSGlenn Lagasse 	 * property for the new zones datasets.
994*f169c0eaSGlenn Lagasse 	 */
995*f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID &&
996*f169c0eaSGlenn Lagasse 	    be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
997*f169c0eaSGlenn Lagasse 		if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
998*f169c0eaSGlenn Lagasse 		    bt.nbe_root_ds)) != BE_SUCCESS) {
999*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: failed to process "
1000*f169c0eaSGlenn Lagasse 			    "zones\n"));
1001*f169c0eaSGlenn Lagasse 			goto done;
1002*f169c0eaSGlenn Lagasse 		}
1003*f169c0eaSGlenn Lagasse 	}
1004*f169c0eaSGlenn Lagasse 
1005*f169c0eaSGlenn Lagasse 	/*
1006*f169c0eaSGlenn Lagasse 	 * Generate a list of file systems from the original BE that are
1007*f169c0eaSGlenn Lagasse 	 * legacy mounted.  We use this list to determine which entries in
1008*f169c0eaSGlenn Lagasse 	 * vfstab we need to update for the new BE we've just created.
1009*f169c0eaSGlenn Lagasse 	 */
1010*f169c0eaSGlenn Lagasse 	if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL,
1011*f169c0eaSGlenn Lagasse 	    &fld)) != BE_SUCCESS) {
1012*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
1013*f169c0eaSGlenn Lagasse 		    "get legacy mounted file system list for %s\n"),
1014*f169c0eaSGlenn Lagasse 		    bt.obe_name);
1015*f169c0eaSGlenn Lagasse 		goto done;
1016*f169c0eaSGlenn Lagasse 	}
1017*f169c0eaSGlenn Lagasse 
1018*f169c0eaSGlenn Lagasse 	/*
1019*f169c0eaSGlenn Lagasse 	 * Update new BE's vfstab.
1020*f169c0eaSGlenn Lagasse 	 */
1021*f169c0eaSGlenn Lagasse 	if ((ret = be_update_vfstab(bt.nbe_name, bt.obe_zpool, bt.nbe_zpool,
1022*f169c0eaSGlenn Lagasse 	    &fld, new_mp)) != BE_SUCCESS) {
1023*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
1024*f169c0eaSGlenn Lagasse 		    "update new BE's vfstab (%s)\n"), bt.nbe_name);
1025*f169c0eaSGlenn Lagasse 		goto done;
1026*f169c0eaSGlenn Lagasse 	}
1027*f169c0eaSGlenn Lagasse 
1028*f169c0eaSGlenn Lagasse 	/* Unmount the new BE */
1029*f169c0eaSGlenn Lagasse 	if ((ret = _be_unmount(bt.nbe_name, 0)) != BE_SUCCESS) {
1030*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
1031*f169c0eaSGlenn Lagasse 		    "unmount newly created BE\n"));
1032*f169c0eaSGlenn Lagasse 		goto done;
1033*f169c0eaSGlenn Lagasse 	}
1034*f169c0eaSGlenn Lagasse 
1035*f169c0eaSGlenn Lagasse 	/*
1036*f169c0eaSGlenn Lagasse 	 * Add boot menu entry for newly created clone
1037*f169c0eaSGlenn Lagasse 	 */
1038*f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID &&
1039*f169c0eaSGlenn Lagasse 	    (ret = be_append_menu(bt.nbe_name, bt.nbe_zpool,
1040*f169c0eaSGlenn Lagasse 	    NULL, bt.obe_root_ds, bt.nbe_desc)) != BE_SUCCESS) {
1041*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
1042*f169c0eaSGlenn Lagasse 		    "add BE (%s) to boot menu\n"), bt.nbe_name);
1043*f169c0eaSGlenn Lagasse 		goto done;
1044*f169c0eaSGlenn Lagasse 	}
1045*f169c0eaSGlenn Lagasse 
1046*f169c0eaSGlenn Lagasse 	/*
1047*f169c0eaSGlenn Lagasse 	 * If we succeeded in creating an auto named BE, set its policy
1048*f169c0eaSGlenn Lagasse 	 * type and return the auto generated name to the caller by storing
1049*f169c0eaSGlenn Lagasse 	 * it in the nvlist passed in by the caller.
1050*f169c0eaSGlenn Lagasse 	 */
1051*f169c0eaSGlenn Lagasse 	if (autoname) {
1052*f169c0eaSGlenn Lagasse 		/* Get handle to new BE's root dataset. */
1053*f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds,
1054*f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
1055*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: failed to "
1056*f169c0eaSGlenn Lagasse 			    "open BE root dataset (%s): %s\n"), bt.nbe_root_ds,
1057*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1058*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1059*f169c0eaSGlenn Lagasse 			goto done;
1060*f169c0eaSGlenn Lagasse 		}
1061*f169c0eaSGlenn Lagasse 
1062*f169c0eaSGlenn Lagasse 		/*
1063*f169c0eaSGlenn Lagasse 		 * Set the policy type property into the new BE's root dataset
1064*f169c0eaSGlenn Lagasse 		 */
1065*f169c0eaSGlenn Lagasse 		if (bt.policy == NULL) {
1066*f169c0eaSGlenn Lagasse 			/* If no policy type provided, use default type */
1067*f169c0eaSGlenn Lagasse 			bt.policy = be_default_policy();
1068*f169c0eaSGlenn Lagasse 		}
1069*f169c0eaSGlenn Lagasse 
1070*f169c0eaSGlenn Lagasse 		if (zfs_prop_set(zhp, BE_POLICY_PROPERTY, bt.policy) != 0) {
1071*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: failed to "
1072*f169c0eaSGlenn Lagasse 			    "set BE policy for %s: %s\n"), bt.nbe_name,
1073*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1074*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1075*f169c0eaSGlenn Lagasse 			goto done;
1076*f169c0eaSGlenn Lagasse 		}
1077*f169c0eaSGlenn Lagasse 
1078*f169c0eaSGlenn Lagasse 		/*
1079*f169c0eaSGlenn Lagasse 		 * Return the auto generated name to the caller
1080*f169c0eaSGlenn Lagasse 		 */
1081*f169c0eaSGlenn Lagasse 		if (bt.nbe_name) {
1082*f169c0eaSGlenn Lagasse 			if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME,
1083*f169c0eaSGlenn Lagasse 			    bt.nbe_name) != 0) {
1084*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy: failed to "
1085*f169c0eaSGlenn Lagasse 				    "add snap name to be_attrs\n"));
1086*f169c0eaSGlenn Lagasse 			}
1087*f169c0eaSGlenn Lagasse 		}
1088*f169c0eaSGlenn Lagasse 	}
1089*f169c0eaSGlenn Lagasse 
1090*f169c0eaSGlenn Lagasse done:
1091*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1092*f169c0eaSGlenn Lagasse 	be_free_fs_list(&fld);
1093*f169c0eaSGlenn Lagasse 
1094*f169c0eaSGlenn Lagasse 	if (bt.nbe_zfs_props != NULL)
1095*f169c0eaSGlenn Lagasse 		nvlist_free(bt.nbe_zfs_props);
1096*f169c0eaSGlenn Lagasse 
1097*f169c0eaSGlenn Lagasse 	free(bt.obe_altroot);
1098*f169c0eaSGlenn Lagasse 	free(new_mp);
1099*f169c0eaSGlenn Lagasse 
1100*f169c0eaSGlenn Lagasse 	/*
1101*f169c0eaSGlenn Lagasse 	 * If a failure occurred and we already created the datasets for
1102*f169c0eaSGlenn Lagasse 	 * the new boot environment, destroy them.
1103*f169c0eaSGlenn Lagasse 	 */
1104*f169c0eaSGlenn Lagasse 	if (ret != BE_SUCCESS && be_created) {
1105*f169c0eaSGlenn Lagasse 		be_destroy_data_t	cdd = { 0 };
1106*f169c0eaSGlenn Lagasse 
1107*f169c0eaSGlenn Lagasse 		cdd.force_unmount = B_TRUE;
1108*f169c0eaSGlenn Lagasse 
1109*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: "
1110*f169c0eaSGlenn Lagasse 		    "destroying partially created boot environment\n"));
1111*f169c0eaSGlenn Lagasse 
1112*f169c0eaSGlenn Lagasse 		if (getzoneid() == GLOBAL_ZONEID && be_get_uuid(bt.nbe_root_ds,
1113*f169c0eaSGlenn Lagasse 		    &cdd.gz_be_uuid) == 0)
1114*f169c0eaSGlenn Lagasse 			(void) be_destroy_zones(bt.nbe_name, bt.nbe_root_ds,
1115*f169c0eaSGlenn Lagasse 			    &cdd);
1116*f169c0eaSGlenn Lagasse 
1117*f169c0eaSGlenn Lagasse 		(void) _be_destroy(bt.nbe_root_ds, &cdd);
1118*f169c0eaSGlenn Lagasse 	}
1119*f169c0eaSGlenn Lagasse 
1120*f169c0eaSGlenn Lagasse 	be_zfs_fini();
1121*f169c0eaSGlenn Lagasse 
1122*f169c0eaSGlenn Lagasse 	return (ret);
1123*f169c0eaSGlenn Lagasse }
1124*f169c0eaSGlenn Lagasse 
1125*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1126*f169c0eaSGlenn Lagasse /*			Semi-Private Functions				*/
1127*f169c0eaSGlenn Lagasse /* ******************************************************************** */
1128*f169c0eaSGlenn Lagasse 
1129*f169c0eaSGlenn Lagasse /*
1130*f169c0eaSGlenn Lagasse  * Function:	be_find_zpool_callback
1131*f169c0eaSGlenn Lagasse  * Description:	Callback function used to find the pool that a BE lives in.
1132*f169c0eaSGlenn Lagasse  * Parameters:
1133*f169c0eaSGlenn Lagasse  *		zlp - zpool_handle_t pointer for the current pool being
1134*f169c0eaSGlenn Lagasse  *			looked at.
1135*f169c0eaSGlenn Lagasse  *		data - be_transaction_data_t pointer providing information
1136*f169c0eaSGlenn Lagasse  *			about the BE that's being searched for.
1137*f169c0eaSGlenn Lagasse  *			This function uses the obe_name member of this
1138*f169c0eaSGlenn Lagasse  *			parameter to use as the BE name to search for.
1139*f169c0eaSGlenn Lagasse  *			Upon successfully locating the BE, it populates
1140*f169c0eaSGlenn Lagasse  *			obe_zpool with the pool name that the BE is found in.
1141*f169c0eaSGlenn Lagasse  * Returns:
1142*f169c0eaSGlenn Lagasse  *		1 - BE exists in this pool.
1143*f169c0eaSGlenn Lagasse  *		0 - BE does not exist in this pool.
1144*f169c0eaSGlenn Lagasse  * Scope:
1145*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1146*f169c0eaSGlenn Lagasse  */
1147*f169c0eaSGlenn Lagasse int
1148*f169c0eaSGlenn Lagasse be_find_zpool_callback(zpool_handle_t *zlp, void *data)
1149*f169c0eaSGlenn Lagasse {
1150*f169c0eaSGlenn Lagasse 	be_transaction_data_t	*bt = data;
1151*f169c0eaSGlenn Lagasse 	const char		*zpool =  zpool_get_name(zlp);
1152*f169c0eaSGlenn Lagasse 	char			be_root_ds[MAXPATHLEN];
1153*f169c0eaSGlenn Lagasse 
1154*f169c0eaSGlenn Lagasse 	/*
1155*f169c0eaSGlenn Lagasse 	 * Generate string for the BE's root dataset
1156*f169c0eaSGlenn Lagasse 	 */
1157*f169c0eaSGlenn Lagasse 	be_make_root_ds(zpool, bt->obe_name, be_root_ds, sizeof (be_root_ds));
1158*f169c0eaSGlenn Lagasse 
1159*f169c0eaSGlenn Lagasse 	/*
1160*f169c0eaSGlenn Lagasse 	 * Check if dataset exists
1161*f169c0eaSGlenn Lagasse 	 */
1162*f169c0eaSGlenn Lagasse 	if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1163*f169c0eaSGlenn Lagasse 		/* BE's root dataset exists in zpool */
1164*f169c0eaSGlenn Lagasse 		bt->obe_zpool = strdup(zpool);
1165*f169c0eaSGlenn Lagasse 		zpool_close(zlp);
1166*f169c0eaSGlenn Lagasse 		return (1);
1167*f169c0eaSGlenn Lagasse 	}
1168*f169c0eaSGlenn Lagasse 
1169*f169c0eaSGlenn Lagasse 	zpool_close(zlp);
1170*f169c0eaSGlenn Lagasse 	return (0);
1171*f169c0eaSGlenn Lagasse }
1172*f169c0eaSGlenn Lagasse 
1173*f169c0eaSGlenn Lagasse /*
1174*f169c0eaSGlenn Lagasse  * Function:	be_exists_callback
1175*f169c0eaSGlenn Lagasse  * Description:	Callback function used to find out if a BE exists.
1176*f169c0eaSGlenn Lagasse  * Parameters:
1177*f169c0eaSGlenn Lagasse  *		zlp - zpool_handle_t pointer to the current pool being
1178*f169c0eaSGlenn Lagasse  *			looked at.
1179*f169c0eaSGlenn Lagasse  *		data - BE name to look for.
1180*f169c0eaSGlenn Lagasse  * Return:
1181*f169c0eaSGlenn Lagasse  *		1 - BE exists in this pool.
1182*f169c0eaSGlenn Lagasse  *		0 - BE does not exist in this pool.
1183*f169c0eaSGlenn Lagasse  * Scope:
1184*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1185*f169c0eaSGlenn Lagasse  */
1186*f169c0eaSGlenn Lagasse int
1187*f169c0eaSGlenn Lagasse be_exists_callback(zpool_handle_t *zlp, void *data)
1188*f169c0eaSGlenn Lagasse {
1189*f169c0eaSGlenn Lagasse 	const char	*zpool = zpool_get_name(zlp);
1190*f169c0eaSGlenn Lagasse 	char		*be_name = data;
1191*f169c0eaSGlenn Lagasse 	char		be_root_ds[MAXPATHLEN];
1192*f169c0eaSGlenn Lagasse 
1193*f169c0eaSGlenn Lagasse 	/*
1194*f169c0eaSGlenn Lagasse 	 * Generate string for the BE's root dataset
1195*f169c0eaSGlenn Lagasse 	 */
1196*f169c0eaSGlenn Lagasse 	be_make_root_ds(zpool, be_name, be_root_ds, sizeof (be_root_ds));
1197*f169c0eaSGlenn Lagasse 
1198*f169c0eaSGlenn Lagasse 	/*
1199*f169c0eaSGlenn Lagasse 	 * Check if dataset exists
1200*f169c0eaSGlenn Lagasse 	 */
1201*f169c0eaSGlenn Lagasse 	if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1202*f169c0eaSGlenn Lagasse 		/* BE's root dataset exists in zpool */
1203*f169c0eaSGlenn Lagasse 		zpool_close(zlp);
1204*f169c0eaSGlenn Lagasse 		return (1);
1205*f169c0eaSGlenn Lagasse 	}
1206*f169c0eaSGlenn Lagasse 
1207*f169c0eaSGlenn Lagasse 	zpool_close(zlp);
1208*f169c0eaSGlenn Lagasse 	return (0);
1209*f169c0eaSGlenn Lagasse }
1210*f169c0eaSGlenn Lagasse 
1211*f169c0eaSGlenn Lagasse /*
1212*f169c0eaSGlenn Lagasse  * Function:	be_set_uuid
1213*f169c0eaSGlenn Lagasse  * Description:	This function generates a uuid, unparses it into
1214*f169c0eaSGlenn Lagasse  *		string representation, and sets that string into
1215*f169c0eaSGlenn Lagasse  *		a zfs user property for a root dataset of a BE.
1216*f169c0eaSGlenn Lagasse  *		The name of the user property used to store the
1217*f169c0eaSGlenn Lagasse  *		uuid is org.opensolaris.libbe:uuid
1218*f169c0eaSGlenn Lagasse  *
1219*f169c0eaSGlenn Lagasse  * Parameters:
1220*f169c0eaSGlenn Lagasse  *		root_ds - Root dataset of the BE to set a uuid on.
1221*f169c0eaSGlenn Lagasse  * Return:
1222*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1223*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1224*f169c0eaSGlenn Lagasse  * Scope:
1225*f169c0eaSGlenn Lagasse  *		Semi-private (library wide ues only)
1226*f169c0eaSGlenn Lagasse  */
1227*f169c0eaSGlenn Lagasse int
1228*f169c0eaSGlenn Lagasse be_set_uuid(char *root_ds)
1229*f169c0eaSGlenn Lagasse {
1230*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1231*f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
1232*f169c0eaSGlenn Lagasse 	char		uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1233*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1234*f169c0eaSGlenn Lagasse 
1235*f169c0eaSGlenn Lagasse 	/* Generate a UUID and unparse it into string form */
1236*f169c0eaSGlenn Lagasse 	uuid_generate(uu);
1237*f169c0eaSGlenn Lagasse 	if (uuid_is_null(uu) != 0) {
1238*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_set_uuid: failed to "
1239*f169c0eaSGlenn Lagasse 		    "generate uuid\n"));
1240*f169c0eaSGlenn Lagasse 		return (BE_ERR_GEN_UUID);
1241*f169c0eaSGlenn Lagasse 	}
1242*f169c0eaSGlenn Lagasse 	uuid_unparse(uu, uu_string);
1243*f169c0eaSGlenn Lagasse 
1244*f169c0eaSGlenn Lagasse 	/* Get handle to the BE's root dataset. */
1245*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1246*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_set_uuid: failed to "
1247*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), root_ds,
1248*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1249*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1250*f169c0eaSGlenn Lagasse 	}
1251*f169c0eaSGlenn Lagasse 
1252*f169c0eaSGlenn Lagasse 	/* Set uuid property for the BE */
1253*f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, BE_UUID_PROPERTY, uu_string) != 0) {
1254*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_set_uuid: failed to "
1255*f169c0eaSGlenn Lagasse 		    "set uuid property for BE: %s\n"),
1256*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1257*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1258*f169c0eaSGlenn Lagasse 	}
1259*f169c0eaSGlenn Lagasse 
1260*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1261*f169c0eaSGlenn Lagasse 
1262*f169c0eaSGlenn Lagasse 	return (ret);
1263*f169c0eaSGlenn Lagasse }
1264*f169c0eaSGlenn Lagasse 
1265*f169c0eaSGlenn Lagasse /*
1266*f169c0eaSGlenn Lagasse  * Function:	be_get_uuid
1267*f169c0eaSGlenn Lagasse  * Description:	This function gets the uuid string from a BE root
1268*f169c0eaSGlenn Lagasse  *		dataset, parses it into internal format, and returns
1269*f169c0eaSGlenn Lagasse  *		it the caller via a reference pointer passed in.
1270*f169c0eaSGlenn Lagasse  *
1271*f169c0eaSGlenn Lagasse  * Parameters:
1272*f169c0eaSGlenn Lagasse  *		rootds - Root dataset of the BE to get the uuid from.
1273*f169c0eaSGlenn Lagasse  *		uu - reference pointer to a uuid_t to return uuid in.
1274*f169c0eaSGlenn Lagasse  * Return:
1275*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1276*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1277*f169c0eaSGlenn Lagasse  * Scope:
1278*f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1279*f169c0eaSGlenn Lagasse  */
1280*f169c0eaSGlenn Lagasse int
1281*f169c0eaSGlenn Lagasse be_get_uuid(const char *root_ds, uuid_t *uu)
1282*f169c0eaSGlenn Lagasse {
1283*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1284*f169c0eaSGlenn Lagasse 	nvlist_t	*userprops = NULL;
1285*f169c0eaSGlenn Lagasse 	nvlist_t	*propname = NULL;
1286*f169c0eaSGlenn Lagasse 	char		*uu_string = NULL;
1287*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1288*f169c0eaSGlenn Lagasse 
1289*f169c0eaSGlenn Lagasse 	/* Get handle to the BE's root dataset. */
1290*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1291*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_uuid: failed to "
1292*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), root_ds,
1293*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1294*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1295*f169c0eaSGlenn Lagasse 	}
1296*f169c0eaSGlenn Lagasse 
1297*f169c0eaSGlenn Lagasse 	/* Get user properties for BE's root dataset */
1298*f169c0eaSGlenn Lagasse 	if ((userprops = zfs_get_user_props(zhp)) == NULL) {
1299*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_uuid: failed to "
1300*f169c0eaSGlenn Lagasse 		    "get user properties for BE root dataset (%s): %s\n"),
1301*f169c0eaSGlenn Lagasse 		    root_ds, libzfs_error_description(g_zfs));
1302*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1303*f169c0eaSGlenn Lagasse 		goto done;
1304*f169c0eaSGlenn Lagasse 	}
1305*f169c0eaSGlenn Lagasse 
1306*f169c0eaSGlenn Lagasse 	/* Get UUID string from BE's root dataset user properties */
1307*f169c0eaSGlenn Lagasse 	if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propname) != 0 ||
1308*f169c0eaSGlenn Lagasse 	    nvlist_lookup_string(propname, ZPROP_VALUE, &uu_string) != 0) {
1309*f169c0eaSGlenn Lagasse 		/*
1310*f169c0eaSGlenn Lagasse 		 * This probably just means that the BE is simply too old
1311*f169c0eaSGlenn Lagasse 		 * to have a uuid or that we haven't created a uuid for
1312*f169c0eaSGlenn Lagasse 		 * this BE yet.
1313*f169c0eaSGlenn Lagasse 		 */
1314*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_uuid: failed to "
1315*f169c0eaSGlenn Lagasse 		    "get uuid property from BE root dataset user "
1316*f169c0eaSGlenn Lagasse 		    "properties.\n"));
1317*f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_UUID;
1318*f169c0eaSGlenn Lagasse 		goto done;
1319*f169c0eaSGlenn Lagasse 	}
1320*f169c0eaSGlenn Lagasse 	/* Parse uuid string into internal format */
1321*f169c0eaSGlenn Lagasse 	if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) {
1322*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_uuid: failed to "
1323*f169c0eaSGlenn Lagasse 		    "parse uuid\n"));
1324*f169c0eaSGlenn Lagasse 		ret = BE_ERR_PARSE_UUID;
1325*f169c0eaSGlenn Lagasse 		goto done;
1326*f169c0eaSGlenn Lagasse 	}
1327*f169c0eaSGlenn Lagasse 
1328*f169c0eaSGlenn Lagasse done:
1329*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1330*f169c0eaSGlenn Lagasse 	return (ret);
1331*f169c0eaSGlenn Lagasse }
1332*f169c0eaSGlenn Lagasse 
1333*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1334*f169c0eaSGlenn Lagasse /*			Private Functions				*/
1335*f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1336*f169c0eaSGlenn Lagasse 
1337*f169c0eaSGlenn Lagasse /*
1338*f169c0eaSGlenn Lagasse  * Function:	_be_destroy
1339*f169c0eaSGlenn Lagasse  * Description:	Destroy a BE and all of its children datasets and snapshots.
1340*f169c0eaSGlenn Lagasse  *		This function is called for both global BEs and non-global BEs.
1341*f169c0eaSGlenn Lagasse  *		The root dataset of either the global BE or non-global BE to be
1342*f169c0eaSGlenn Lagasse  *		destroyed is passed in.
1343*f169c0eaSGlenn Lagasse  * Parameters:
1344*f169c0eaSGlenn Lagasse  *		root_ds - pointer to the name of the root dataset of the
1345*f169c0eaSGlenn Lagasse  *			BE to destroy.
1346*f169c0eaSGlenn Lagasse  *		dd - pointer to a be_destroy_data_t structure.
1347*f169c0eaSGlenn Lagasse  *
1348*f169c0eaSGlenn Lagasse  * Return:
1349*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1350*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1351*f169c0eaSGlenn Lagasse  * Scope:
1352*f169c0eaSGlenn Lagasse  *		Private
1353*f169c0eaSGlenn Lagasse  */
1354*f169c0eaSGlenn Lagasse static int
1355*f169c0eaSGlenn Lagasse _be_destroy(const char *root_ds, be_destroy_data_t *dd)
1356*f169c0eaSGlenn Lagasse {
1357*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1358*f169c0eaSGlenn Lagasse 	char		origin[MAXPATHLEN];
1359*f169c0eaSGlenn Lagasse 	char		parent[MAXPATHLEN];
1360*f169c0eaSGlenn Lagasse 	char		*snap = NULL;
1361*f169c0eaSGlenn Lagasse 	boolean_t	has_origin = B_FALSE;
1362*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1363*f169c0eaSGlenn Lagasse 
1364*f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
1365*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1366*f169c0eaSGlenn Lagasse 	    NULL) {
1367*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to "
1368*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), root_ds,
1369*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1370*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1371*f169c0eaSGlenn Lagasse 	}
1372*f169c0eaSGlenn Lagasse 
1373*f169c0eaSGlenn Lagasse 	/*
1374*f169c0eaSGlenn Lagasse 	 * Demote this BE in case it has dependent clones.  This call
1375*f169c0eaSGlenn Lagasse 	 * will end up closing the zfs handle passed in whether it
1376*f169c0eaSGlenn Lagasse 	 * succeeds or fails.
1377*f169c0eaSGlenn Lagasse 	 */
1378*f169c0eaSGlenn Lagasse 	if (be_demote_callback(zhp, NULL) != 0) {
1379*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: "
1380*f169c0eaSGlenn Lagasse 		    "failed to demote BE %s\n"), root_ds);
1381*f169c0eaSGlenn Lagasse 		return (BE_ERR_DEMOTE);
1382*f169c0eaSGlenn Lagasse 	}
1383*f169c0eaSGlenn Lagasse 
1384*f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
1385*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1386*f169c0eaSGlenn Lagasse 	    NULL) {
1387*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to "
1388*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), root_ds,
1389*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1390*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1391*f169c0eaSGlenn Lagasse 	}
1392*f169c0eaSGlenn Lagasse 
1393*f169c0eaSGlenn Lagasse 	/*
1394*f169c0eaSGlenn Lagasse 	 * Get the origin of this BE's root dataset.  This will be used
1395*f169c0eaSGlenn Lagasse 	 * later to destroy the snapshots originally used to create this BE.
1396*f169c0eaSGlenn Lagasse 	 */
1397*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
1398*f169c0eaSGlenn Lagasse 	    NULL, 0, B_FALSE) == 0) {
1399*f169c0eaSGlenn Lagasse 		(void) strlcpy(parent, origin, sizeof (parent));
1400*f169c0eaSGlenn Lagasse 		if (be_get_snap(parent, &snap) != BE_SUCCESS) {
1401*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1402*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
1403*f169c0eaSGlenn Lagasse 			    "get snapshot name from origin %s\n"), origin);
1404*f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
1405*f169c0eaSGlenn Lagasse 		}
1406*f169c0eaSGlenn Lagasse 		has_origin = B_TRUE;
1407*f169c0eaSGlenn Lagasse 	}
1408*f169c0eaSGlenn Lagasse 
1409*f169c0eaSGlenn Lagasse 	/*
1410*f169c0eaSGlenn Lagasse 	 * Destroy the BE's root and its hierarchical children.  This call
1411*f169c0eaSGlenn Lagasse 	 * will end up closing the zfs handle passed in whether it succeeds
1412*f169c0eaSGlenn Lagasse 	 * or fails.
1413*f169c0eaSGlenn Lagasse 	 */
1414*f169c0eaSGlenn Lagasse 	if (be_destroy_callback(zhp, dd) != 0) {
1415*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to "
1416*f169c0eaSGlenn Lagasse 		    "destroy BE %s\n"), root_ds);
1417*f169c0eaSGlenn Lagasse 		return (BE_ERR_DESTROY);
1418*f169c0eaSGlenn Lagasse 	}
1419*f169c0eaSGlenn Lagasse 
1420*f169c0eaSGlenn Lagasse 	/* If BE has an origin */
1421*f169c0eaSGlenn Lagasse 	if (has_origin) {
1422*f169c0eaSGlenn Lagasse 
1423*f169c0eaSGlenn Lagasse 		/*
1424*f169c0eaSGlenn Lagasse 		 * If origin snapshot doesn't have any other
1425*f169c0eaSGlenn Lagasse 		 * dependents, delete the origin.
1426*f169c0eaSGlenn Lagasse 		 */
1427*f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, origin, ZFS_TYPE_SNAPSHOT)) ==
1428*f169c0eaSGlenn Lagasse 		    NULL) {
1429*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
1430*f169c0eaSGlenn Lagasse 			    "open BE's origin (%s): %s\n"), origin,
1431*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1432*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1433*f169c0eaSGlenn Lagasse 			return (ret);
1434*f169c0eaSGlenn Lagasse 		}
1435*f169c0eaSGlenn Lagasse 
1436*f169c0eaSGlenn Lagasse 		/* If origin has dependents, don't delete it. */
1437*f169c0eaSGlenn Lagasse 		if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
1438*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1439*f169c0eaSGlenn Lagasse 			return (ret);
1440*f169c0eaSGlenn Lagasse 		}
1441*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1442*f169c0eaSGlenn Lagasse 
1443*f169c0eaSGlenn Lagasse 		/* Get handle to BE's parent's root dataset */
1444*f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, parent, ZFS_TYPE_FILESYSTEM)) ==
1445*f169c0eaSGlenn Lagasse 		    NULL) {
1446*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
1447*f169c0eaSGlenn Lagasse 			    "open BE's parent root dataset (%s): %s\n"), parent,
1448*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1449*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1450*f169c0eaSGlenn Lagasse 			return (ret);
1451*f169c0eaSGlenn Lagasse 		}
1452*f169c0eaSGlenn Lagasse 
1453*f169c0eaSGlenn Lagasse 		/* Destroy the snapshot origin used to create this BE. */
1454*f169c0eaSGlenn Lagasse 		/*
1455*f169c0eaSGlenn Lagasse 		 * The boolean set to B_FALSE and passed to zfs_destroy_snaps()
1456*f169c0eaSGlenn Lagasse 		 * tells zfs to process and destroy the snapshots now.
1457*f169c0eaSGlenn Lagasse 		 * Otherwise the call will potentially return where the
1458*f169c0eaSGlenn Lagasse 		 * snapshot isn't actually destroyed yet, and ZFS is waiting
1459*f169c0eaSGlenn Lagasse 		 * until all the references to the snapshot have been
1460*f169c0eaSGlenn Lagasse 		 * released before actually destroying the snapshot.
1461*f169c0eaSGlenn Lagasse 		 */
1462*f169c0eaSGlenn Lagasse 		if (zfs_destroy_snaps(zhp, snap, B_FALSE) != 0) {
1463*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
1464*f169c0eaSGlenn Lagasse 			    "destroy original snapshots used to create "
1465*f169c0eaSGlenn Lagasse 			    "BE: %s\n"), libzfs_error_description(g_zfs));
1466*f169c0eaSGlenn Lagasse 
1467*f169c0eaSGlenn Lagasse 			/*
1468*f169c0eaSGlenn Lagasse 			 * If a failure happened because a clone exists,
1469*f169c0eaSGlenn Lagasse 			 * don't return a failure to the user.  Above, we're
1470*f169c0eaSGlenn Lagasse 			 * only checking that the root dataset's origin
1471*f169c0eaSGlenn Lagasse 			 * snapshot doesn't have dependent clones, but its
1472*f169c0eaSGlenn Lagasse 			 * possible that a subordinate dataset origin snapshot
1473*f169c0eaSGlenn Lagasse 			 * has a clone.  We really need to check for that
1474*f169c0eaSGlenn Lagasse 			 * before trying to destroy the origin snapshot.
1475*f169c0eaSGlenn Lagasse 			 */
1476*f169c0eaSGlenn Lagasse 			if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1477*f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
1478*f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
1479*f169c0eaSGlenn Lagasse 				return (ret);
1480*f169c0eaSGlenn Lagasse 			}
1481*f169c0eaSGlenn Lagasse 		}
1482*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1483*f169c0eaSGlenn Lagasse 	}
1484*f169c0eaSGlenn Lagasse 
1485*f169c0eaSGlenn Lagasse 	return (ret);
1486*f169c0eaSGlenn Lagasse }
1487*f169c0eaSGlenn Lagasse 
1488*f169c0eaSGlenn Lagasse /*
1489*f169c0eaSGlenn Lagasse  * Function:	be_destroy_zones
1490*f169c0eaSGlenn Lagasse  * Description:	Find valid zone's and call be_destroy_zone_roots to destroy its
1491*f169c0eaSGlenn Lagasse  *		corresponding dataset and all of its children datasets
1492*f169c0eaSGlenn Lagasse  *		and snapshots.
1493*f169c0eaSGlenn Lagasse  * Parameters:
1494*f169c0eaSGlenn Lagasse  *		be_name - name of global boot environment being destroyed
1495*f169c0eaSGlenn Lagasse  *		be_root_ds - root dataset of global boot environment being
1496*f169c0eaSGlenn Lagasse  *			destroyed.
1497*f169c0eaSGlenn Lagasse  *		dd - be_destroy_data_t pointer
1498*f169c0eaSGlenn Lagasse  * Return:
1499*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1500*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1501*f169c0eaSGlenn Lagasse  * Scope:
1502*f169c0eaSGlenn Lagasse  *		Private
1503*f169c0eaSGlenn Lagasse  *
1504*f169c0eaSGlenn Lagasse  * NOTES - Requires that the BE being deleted has no dependent BEs.  If it
1505*f169c0eaSGlenn Lagasse  *	   does, the destroy will fail.
1506*f169c0eaSGlenn Lagasse  */
1507*f169c0eaSGlenn Lagasse static int
1508*f169c0eaSGlenn Lagasse be_destroy_zones(char *be_name, char *be_root_ds, be_destroy_data_t *dd)
1509*f169c0eaSGlenn Lagasse {
1510*f169c0eaSGlenn Lagasse 	int		i;
1511*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1512*f169c0eaSGlenn Lagasse 	int		force_umnt = BE_UNMOUNT_FLAG_NULL;
1513*f169c0eaSGlenn Lagasse 	char		*zonepath = NULL;
1514*f169c0eaSGlenn Lagasse 	char		*zonename = NULL;
1515*f169c0eaSGlenn Lagasse 	char		*zonepath_ds = NULL;
1516*f169c0eaSGlenn Lagasse 	char		*mp = NULL;
1517*f169c0eaSGlenn Lagasse 	zoneList_t	zlist = NULL;
1518*f169c0eaSGlenn Lagasse 	zoneBrandList_t	*brands = NULL;
1519*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1520*f169c0eaSGlenn Lagasse 
1521*f169c0eaSGlenn Lagasse 	/* If zones are not implemented, then get out. */
1522*f169c0eaSGlenn Lagasse 	if (!z_zones_are_implemented()) {
1523*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1524*f169c0eaSGlenn Lagasse 	}
1525*f169c0eaSGlenn Lagasse 
1526*f169c0eaSGlenn Lagasse 	/* Get list of supported brands */
1527*f169c0eaSGlenn Lagasse 	if ((brands = be_get_supported_brandlist()) == NULL) {
1528*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zones: "
1529*f169c0eaSGlenn Lagasse 		    "no supported brands\n"));
1530*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1531*f169c0eaSGlenn Lagasse 	}
1532*f169c0eaSGlenn Lagasse 
1533*f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
1534*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1535*f169c0eaSGlenn Lagasse 	    NULL) {
1536*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zones: failed to "
1537*f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), be_root_ds,
1538*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1539*f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
1540*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1541*f169c0eaSGlenn Lagasse 	}
1542*f169c0eaSGlenn Lagasse 
1543*f169c0eaSGlenn Lagasse 	/*
1544*f169c0eaSGlenn Lagasse 	 * If the global BE is not mounted, we must mount it here to
1545*f169c0eaSGlenn Lagasse 	 * gather data about the non-global zones in it.
1546*f169c0eaSGlenn Lagasse 	 */
1547*f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &mp)) {
1548*f169c0eaSGlenn Lagasse 		if ((ret = _be_mount(be_name, &mp,
1549*f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1550*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zones: failed to "
1551*f169c0eaSGlenn Lagasse 			    "mount the BE (%s) for zones processing.\n"),
1552*f169c0eaSGlenn Lagasse 			    be_name);
1553*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1554*f169c0eaSGlenn Lagasse 			z_free_brand_list(brands);
1555*f169c0eaSGlenn Lagasse 			return (ret);
1556*f169c0eaSGlenn Lagasse 		}
1557*f169c0eaSGlenn Lagasse 	}
1558*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1559*f169c0eaSGlenn Lagasse 
1560*f169c0eaSGlenn Lagasse 	z_set_zone_root(mp);
1561*f169c0eaSGlenn Lagasse 	free(mp);
1562*f169c0eaSGlenn Lagasse 
1563*f169c0eaSGlenn Lagasse 	/* Get list of supported zones. */
1564*f169c0eaSGlenn Lagasse 	if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1565*f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
1566*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1567*f169c0eaSGlenn Lagasse 	}
1568*f169c0eaSGlenn Lagasse 
1569*f169c0eaSGlenn Lagasse 	/* Unmount the BE before destroying the zones in it. */
1570*f169c0eaSGlenn Lagasse 	if (dd->force_unmount)
1571*f169c0eaSGlenn Lagasse 		force_umnt = BE_UNMOUNT_FLAG_FORCE;
1572*f169c0eaSGlenn Lagasse 	if ((ret = _be_unmount(be_name, force_umnt)) != BE_SUCCESS) {
1573*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zones: failed to "
1574*f169c0eaSGlenn Lagasse 		    "unmount the BE (%s)\n"), be_name);
1575*f169c0eaSGlenn Lagasse 		goto done;
1576*f169c0eaSGlenn Lagasse 	}
1577*f169c0eaSGlenn Lagasse 
1578*f169c0eaSGlenn Lagasse 	/* Iterate through the zones and destroy them. */
1579*f169c0eaSGlenn Lagasse 	for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1580*f169c0eaSGlenn Lagasse 
1581*f169c0eaSGlenn Lagasse 		/* Skip zones that aren't at least installed */
1582*f169c0eaSGlenn Lagasse 		if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1583*f169c0eaSGlenn Lagasse 			continue;
1584*f169c0eaSGlenn Lagasse 
1585*f169c0eaSGlenn Lagasse 		zonepath = z_zlist_get_zonepath(zlist, i);
1586*f169c0eaSGlenn Lagasse 
1587*f169c0eaSGlenn Lagasse 		/*
1588*f169c0eaSGlenn Lagasse 		 * Get the dataset of this zonepath.  If its not
1589*f169c0eaSGlenn Lagasse 		 * a dataset, skip it.
1590*f169c0eaSGlenn Lagasse 		 */
1591*f169c0eaSGlenn Lagasse 		if ((zonepath_ds = be_get_ds_from_dir(zonepath)) == NULL)
1592*f169c0eaSGlenn Lagasse 			continue;
1593*f169c0eaSGlenn Lagasse 
1594*f169c0eaSGlenn Lagasse 		/*
1595*f169c0eaSGlenn Lagasse 		 * Check if this zone is supported based on the
1596*f169c0eaSGlenn Lagasse 		 * dataset of its zonepath.
1597*f169c0eaSGlenn Lagasse 		 */
1598*f169c0eaSGlenn Lagasse 		if (!be_zone_supported(zonepath_ds)) {
1599*f169c0eaSGlenn Lagasse 			free(zonepath_ds);
1600*f169c0eaSGlenn Lagasse 			continue;
1601*f169c0eaSGlenn Lagasse 		}
1602*f169c0eaSGlenn Lagasse 
1603*f169c0eaSGlenn Lagasse 		/* Find the zone BE root datasets for this zone. */
1604*f169c0eaSGlenn Lagasse 		if ((ret = be_destroy_zone_roots(zonepath_ds, dd))
1605*f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
1606*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zones: failed to "
1607*f169c0eaSGlenn Lagasse 			    "find and destroy zone roots for zone %s\n"),
1608*f169c0eaSGlenn Lagasse 			    zonename);
1609*f169c0eaSGlenn Lagasse 			free(zonepath_ds);
1610*f169c0eaSGlenn Lagasse 			goto done;
1611*f169c0eaSGlenn Lagasse 		}
1612*f169c0eaSGlenn Lagasse 		free(zonepath_ds);
1613*f169c0eaSGlenn Lagasse 	}
1614*f169c0eaSGlenn Lagasse 
1615*f169c0eaSGlenn Lagasse done:
1616*f169c0eaSGlenn Lagasse 	z_free_brand_list(brands);
1617*f169c0eaSGlenn Lagasse 	z_free_zone_list(zlist);
1618*f169c0eaSGlenn Lagasse 
1619*f169c0eaSGlenn Lagasse 	return (ret);
1620*f169c0eaSGlenn Lagasse }
1621*f169c0eaSGlenn Lagasse 
1622*f169c0eaSGlenn Lagasse /*
1623*f169c0eaSGlenn Lagasse  * Function:	be_destroy_zone_roots
1624*f169c0eaSGlenn Lagasse  * Description:	This function will open the zone's root container dataset
1625*f169c0eaSGlenn Lagasse  *		and iterate the datasets within, looking for roots that
1626*f169c0eaSGlenn Lagasse  *		belong to the given global BE and destroying them.
1627*f169c0eaSGlenn Lagasse  *		If no other zone roots remain in the zone's root container
1628*f169c0eaSGlenn Lagasse  *		dataset, the function will destroy it and the zone's
1629*f169c0eaSGlenn Lagasse  *		zonepath dataset as well.
1630*f169c0eaSGlenn Lagasse  * Parameters:
1631*f169c0eaSGlenn Lagasse  *		zonepath_ds - pointer to zone's zonepath dataset.
1632*f169c0eaSGlenn Lagasse  *		dd - pointer to a linked destroy data.
1633*f169c0eaSGlenn Lagasse  * Returns:
1634*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1635*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1636*f169c0eaSGlenn Lagasse  * Scope:
1637*f169c0eaSGlenn Lagasse  *		Private
1638*f169c0eaSGlenn Lagasse  */
1639*f169c0eaSGlenn Lagasse static int
1640*f169c0eaSGlenn Lagasse be_destroy_zone_roots(char *zonepath_ds, be_destroy_data_t *dd)
1641*f169c0eaSGlenn Lagasse {
1642*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp;
1643*f169c0eaSGlenn Lagasse 	char		zone_container_ds[MAXPATHLEN];
1644*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1645*f169c0eaSGlenn Lagasse 
1646*f169c0eaSGlenn Lagasse 	/* Generate string for the root container dataset for this zone. */
1647*f169c0eaSGlenn Lagasse 	be_make_container_ds(zonepath_ds, zone_container_ds,
1648*f169c0eaSGlenn Lagasse 	    sizeof (zone_container_ds));
1649*f169c0eaSGlenn Lagasse 
1650*f169c0eaSGlenn Lagasse 	/* Get handle to this zone's root container dataset. */
1651*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1652*f169c0eaSGlenn Lagasse 	    == NULL) {
1653*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zone_roots: failed to "
1654*f169c0eaSGlenn Lagasse 		    "open zone root container dataset (%s): %s\n"),
1655*f169c0eaSGlenn Lagasse 		    zone_container_ds, libzfs_error_description(g_zfs));
1656*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1657*f169c0eaSGlenn Lagasse 	}
1658*f169c0eaSGlenn Lagasse 
1659*f169c0eaSGlenn Lagasse 	/*
1660*f169c0eaSGlenn Lagasse 	 * Iterate through all of this zone's BEs, destroying the ones
1661*f169c0eaSGlenn Lagasse 	 * that belong to the parent global BE.
1662*f169c0eaSGlenn Lagasse 	 */
1663*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_destroy_zone_roots_callback,
1664*f169c0eaSGlenn Lagasse 	    dd)) != 0) {
1665*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zone_roots: failed to "
1666*f169c0eaSGlenn Lagasse 		    "destroy zone roots under zonepath dataset %s: %s\n"),
1667*f169c0eaSGlenn Lagasse 		    zonepath_ds, libzfs_error_description(g_zfs));
1668*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1669*f169c0eaSGlenn Lagasse 		return (ret);
1670*f169c0eaSGlenn Lagasse 	}
1671*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1672*f169c0eaSGlenn Lagasse 
1673*f169c0eaSGlenn Lagasse 	/* Get handle to this zone's root container dataset. */
1674*f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1675*f169c0eaSGlenn Lagasse 	    == NULL) {
1676*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zone_roots: failed to "
1677*f169c0eaSGlenn Lagasse 		    "open zone root container dataset (%s): %s\n"),
1678*f169c0eaSGlenn Lagasse 		    zone_container_ds, libzfs_error_description(g_zfs));
1679*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1680*f169c0eaSGlenn Lagasse 	}
1681*f169c0eaSGlenn Lagasse 
1682*f169c0eaSGlenn Lagasse 	/*
1683*f169c0eaSGlenn Lagasse 	 * If there are no more zone roots in this zone's root container,
1684*f169c0eaSGlenn Lagasse 	 * dataset, destroy it and the zonepath dataset as well.
1685*f169c0eaSGlenn Lagasse 	 */
1686*f169c0eaSGlenn Lagasse 	if (zfs_iter_filesystems(zhp, be_zone_root_exists_callback, NULL)
1687*f169c0eaSGlenn Lagasse 	    == 0) {
1688*f169c0eaSGlenn Lagasse 		/* Destroy the zone root container dataset */
1689*f169c0eaSGlenn Lagasse 		if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1690*f169c0eaSGlenn Lagasse 		    zfs_destroy(zhp, B_FALSE) != 0) {
1691*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zone_roots: failed to "
1692*f169c0eaSGlenn Lagasse 			    "destroy zone root container dataset (%s): %s\n"),
1693*f169c0eaSGlenn Lagasse 			    zone_container_ds, libzfs_error_description(g_zfs));
1694*f169c0eaSGlenn Lagasse 			goto done;
1695*f169c0eaSGlenn Lagasse 		}
1696*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1697*f169c0eaSGlenn Lagasse 
1698*f169c0eaSGlenn Lagasse 		/* Get handle to zonepath dataset */
1699*f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, zonepath_ds, ZFS_TYPE_FILESYSTEM))
1700*f169c0eaSGlenn Lagasse 		    == NULL) {
1701*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zone_roots: failed to "
1702*f169c0eaSGlenn Lagasse 			    "open zonepath dataset (%s): %s\n"),
1703*f169c0eaSGlenn Lagasse 			    zonepath_ds, libzfs_error_description(g_zfs));
1704*f169c0eaSGlenn Lagasse 			goto done;
1705*f169c0eaSGlenn Lagasse 		}
1706*f169c0eaSGlenn Lagasse 
1707*f169c0eaSGlenn Lagasse 		/* Destroy zonepath dataset */
1708*f169c0eaSGlenn Lagasse 		if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1709*f169c0eaSGlenn Lagasse 		    zfs_destroy(zhp, B_FALSE) != 0) {
1710*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zone_roots: "
1711*f169c0eaSGlenn Lagasse 			    "failed to destroy zonepath dataest %s: %s\n"),
1712*f169c0eaSGlenn Lagasse 			    zonepath_ds, libzfs_error_description(g_zfs));
1713*f169c0eaSGlenn Lagasse 			goto done;
1714*f169c0eaSGlenn Lagasse 		}
1715*f169c0eaSGlenn Lagasse 	}
1716*f169c0eaSGlenn Lagasse 
1717*f169c0eaSGlenn Lagasse done:
1718*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1719*f169c0eaSGlenn Lagasse 	return (ret);
1720*f169c0eaSGlenn Lagasse }
1721*f169c0eaSGlenn Lagasse 
1722*f169c0eaSGlenn Lagasse /*
1723*f169c0eaSGlenn Lagasse  * Function:	be_destroy_zone_roots_callback
1724*f169c0eaSGlenn Lagasse  * Description: This function is used as a callback to iterate over all of
1725*f169c0eaSGlenn Lagasse  *		a zone's root datasets, finding the one's that
1726*f169c0eaSGlenn Lagasse  *		correspond to the current BE. The name's
1727*f169c0eaSGlenn Lagasse  *		of the zone root datasets are then destroyed by _be_destroy().
1728*f169c0eaSGlenn Lagasse  * Parameters:
1729*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current dataset being processed
1730*f169c0eaSGlenn Lagasse  *		data - be_destroy_data_t pointer
1731*f169c0eaSGlenn Lagasse  * Returns:
1732*f169c0eaSGlenn Lagasse  *		0 - Success
1733*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1734*f169c0eaSGlenn Lagasse  * Scope:
1735*f169c0eaSGlenn Lagasse  *		Private
1736*f169c0eaSGlenn Lagasse  */
1737*f169c0eaSGlenn Lagasse static int
1738*f169c0eaSGlenn Lagasse be_destroy_zone_roots_callback(zfs_handle_t *zhp, void *data)
1739*f169c0eaSGlenn Lagasse {
1740*f169c0eaSGlenn Lagasse 	be_destroy_data_t	*dd = data;
1741*f169c0eaSGlenn Lagasse 	uuid_t			parent_uuid = { 0 };
1742*f169c0eaSGlenn Lagasse 	int			ret = 0;
1743*f169c0eaSGlenn Lagasse 
1744*f169c0eaSGlenn Lagasse 	if (be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid)
1745*f169c0eaSGlenn Lagasse 	    != BE_SUCCESS) {
1746*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zone_roots_callback: "
1747*f169c0eaSGlenn Lagasse 		    "could not get parentuuid for zone root dataset %s\n"),
1748*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp));
1749*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1750*f169c0eaSGlenn Lagasse 		return (0);
1751*f169c0eaSGlenn Lagasse 	}
1752*f169c0eaSGlenn Lagasse 
1753*f169c0eaSGlenn Lagasse 	if (uuid_compare(dd->gz_be_uuid, parent_uuid) == 0) {
1754*f169c0eaSGlenn Lagasse 		/*
1755*f169c0eaSGlenn Lagasse 		 * Found a zone root dataset belonging to the parent
1756*f169c0eaSGlenn Lagasse 		 * BE being destroyed.  Destroy this zone BE.
1757*f169c0eaSGlenn Lagasse 		 */
1758*f169c0eaSGlenn Lagasse 		if ((ret = _be_destroy(zfs_get_name(zhp), dd)) != BE_SUCCESS) {
1759*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zone_root_callback: "
1760*f169c0eaSGlenn Lagasse 			    "failed to destroy zone root %s\n"),
1761*f169c0eaSGlenn Lagasse 			    zfs_get_name(zhp));
1762*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1763*f169c0eaSGlenn Lagasse 			return (ret);
1764*f169c0eaSGlenn Lagasse 		}
1765*f169c0eaSGlenn Lagasse 	}
1766*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1767*f169c0eaSGlenn Lagasse 
1768*f169c0eaSGlenn Lagasse 	return (ret);
1769*f169c0eaSGlenn Lagasse }
1770*f169c0eaSGlenn Lagasse 
1771*f169c0eaSGlenn Lagasse /*
1772*f169c0eaSGlenn Lagasse  * Function:	be_copy_zones
1773*f169c0eaSGlenn Lagasse  * Description:	Find valid zones and clone them to create their
1774*f169c0eaSGlenn Lagasse  *		corresponding datasets for the BE being created.
1775*f169c0eaSGlenn Lagasse  * Parameters:
1776*f169c0eaSGlenn Lagasse  *		obe_name - name of source global BE being copied.
1777*f169c0eaSGlenn Lagasse  *		obe_root_ds - root dataset of source global BE being copied.
1778*f169c0eaSGlenn Lagasse  *		nbe_root_ds - root dataset of target global BE.
1779*f169c0eaSGlenn Lagasse  * Return:
1780*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1781*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1782*f169c0eaSGlenn Lagasse  * Scope:
1783*f169c0eaSGlenn Lagasse  *		Private
1784*f169c0eaSGlenn Lagasse  */
1785*f169c0eaSGlenn Lagasse static int
1786*f169c0eaSGlenn Lagasse be_copy_zones(char *obe_name, char *obe_root_ds, char *nbe_root_ds)
1787*f169c0eaSGlenn Lagasse {
1788*f169c0eaSGlenn Lagasse 	int		i, num_retries;
1789*f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1790*f169c0eaSGlenn Lagasse 	int		iret = 0;
1791*f169c0eaSGlenn Lagasse 	char		*zonename = NULL;
1792*f169c0eaSGlenn Lagasse 	char		*zonepath = NULL;
1793*f169c0eaSGlenn Lagasse 	char		*zone_be_name = NULL;
1794*f169c0eaSGlenn Lagasse 	char		*temp_mntpt = NULL;
1795*f169c0eaSGlenn Lagasse 	char		*new_zone_be_name = NULL;
1796*f169c0eaSGlenn Lagasse 	char		zoneroot[MAXPATHLEN];
1797*f169c0eaSGlenn Lagasse 	char		zoneroot_ds[MAXPATHLEN];
1798*f169c0eaSGlenn Lagasse 	char		zone_container_ds[MAXPATHLEN];
1799*f169c0eaSGlenn Lagasse 	char		new_zoneroot_ds[MAXPATHLEN];
1800*f169c0eaSGlenn Lagasse 	char		ss[MAXPATHLEN];
1801*f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
1802*f169c0eaSGlenn Lagasse 	char		uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1803*f169c0eaSGlenn Lagasse 	be_transaction_data_t bt = { 0 };
1804*f169c0eaSGlenn Lagasse 	zfs_handle_t	*obe_zhp = NULL;
1805*f169c0eaSGlenn Lagasse 	zfs_handle_t	*nbe_zhp = NULL;
1806*f169c0eaSGlenn Lagasse 	zfs_handle_t	*z_zhp = NULL;
1807*f169c0eaSGlenn Lagasse 	zoneList_t	zlist = NULL;
1808*f169c0eaSGlenn Lagasse 	zoneBrandList_t	*brands = NULL;
1809*f169c0eaSGlenn Lagasse 	boolean_t	mounted_here = B_FALSE;
1810*f169c0eaSGlenn Lagasse 	char		*snap_name = NULL;
1811*f169c0eaSGlenn Lagasse 
1812*f169c0eaSGlenn Lagasse 	/* If zones are not implemented, then get out. */
1813*f169c0eaSGlenn Lagasse 	if (!z_zones_are_implemented()) {
1814*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1815*f169c0eaSGlenn Lagasse 	}
1816*f169c0eaSGlenn Lagasse 
1817*f169c0eaSGlenn Lagasse 	/* Get list of supported brands */
1818*f169c0eaSGlenn Lagasse 	if ((brands = be_get_supported_brandlist()) == NULL) {
1819*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy_zones: "
1820*f169c0eaSGlenn Lagasse 		    "no supported brands\n"));
1821*f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1822*f169c0eaSGlenn Lagasse 	}
1823*f169c0eaSGlenn Lagasse 
1824*f169c0eaSGlenn Lagasse 	/* Get handle to origin BE's root dataset */
1825*f169c0eaSGlenn Lagasse 	if ((obe_zhp = zfs_open(g_zfs, obe_root_ds, ZFS_TYPE_FILESYSTEM))
1826*f169c0eaSGlenn Lagasse 	    == NULL) {
1827*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy_zones: failed to open "
1828*f169c0eaSGlenn Lagasse 		    "the origin BE root dataset (%s) for zones processing: "
1829*f169c0eaSGlenn Lagasse 		    "%s\n"), obe_root_ds, libzfs_error_description(g_zfs));
1830*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1831*f169c0eaSGlenn Lagasse 	}
1832*f169c0eaSGlenn Lagasse 
1833*f169c0eaSGlenn Lagasse 	/* Get handle to newly cloned BE's root dataset */
1834*f169c0eaSGlenn Lagasse 	if ((nbe_zhp = zfs_open(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM))
1835*f169c0eaSGlenn Lagasse 	    == NULL) {
1836*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy_zones: failed to open "
1837*f169c0eaSGlenn Lagasse 		    "the new BE root dataset (%s): %s\n"), nbe_root_ds,
1838*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1839*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(obe_zhp);
1840*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1841*f169c0eaSGlenn Lagasse 	}
1842*f169c0eaSGlenn Lagasse 
1843*f169c0eaSGlenn Lagasse 	/* Get the uuid of the newly cloned parent BE. */
1844*f169c0eaSGlenn Lagasse 	if (be_get_uuid(zfs_get_name(nbe_zhp), &uu) != BE_SUCCESS) {
1845*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy_zones: "
1846*f169c0eaSGlenn Lagasse 		    "failed to get uuid for BE root "
1847*f169c0eaSGlenn Lagasse 		    "dataset %s\n"), zfs_get_name(nbe_zhp));
1848*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(nbe_zhp);
1849*f169c0eaSGlenn Lagasse 		goto done;
1850*f169c0eaSGlenn Lagasse 	}
1851*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(nbe_zhp);
1852*f169c0eaSGlenn Lagasse 	uuid_unparse(uu, uu_string);
1853*f169c0eaSGlenn Lagasse 
1854*f169c0eaSGlenn Lagasse 	/*
1855*f169c0eaSGlenn Lagasse 	 * If the origin BE is not mounted, we must mount it here to
1856*f169c0eaSGlenn Lagasse 	 * gather data about the non-global zones in it.
1857*f169c0eaSGlenn Lagasse 	 */
1858*f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(obe_zhp, &temp_mntpt)) {
1859*f169c0eaSGlenn Lagasse 		if ((ret = _be_mount(obe_name, &temp_mntpt,
1860*f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NULL)) != BE_SUCCESS) {
1861*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: failed to "
1862*f169c0eaSGlenn Lagasse 			    "mount the BE (%s) for zones procesing.\n"),
1863*f169c0eaSGlenn Lagasse 			    obe_name);
1864*f169c0eaSGlenn Lagasse 			goto done;
1865*f169c0eaSGlenn Lagasse 		}
1866*f169c0eaSGlenn Lagasse 		mounted_here = B_TRUE;
1867*f169c0eaSGlenn Lagasse 	}
1868*f169c0eaSGlenn Lagasse 
1869*f169c0eaSGlenn Lagasse 	z_set_zone_root(temp_mntpt);
1870*f169c0eaSGlenn Lagasse 
1871*f169c0eaSGlenn Lagasse 	/* Get list of supported zones. */
1872*f169c0eaSGlenn Lagasse 	if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1873*f169c0eaSGlenn Lagasse 		ret = BE_SUCCESS;
1874*f169c0eaSGlenn Lagasse 		goto done;
1875*f169c0eaSGlenn Lagasse 	}
1876*f169c0eaSGlenn Lagasse 
1877*f169c0eaSGlenn Lagasse 	for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1878*f169c0eaSGlenn Lagasse 
1879*f169c0eaSGlenn Lagasse 		be_fs_list_data_t	fld = { 0 };
1880*f169c0eaSGlenn Lagasse 		char			zonepath_ds[MAXPATHLEN];
1881*f169c0eaSGlenn Lagasse 		char			*ds = NULL;
1882*f169c0eaSGlenn Lagasse 
1883*f169c0eaSGlenn Lagasse 		/* Get zonepath of zone */
1884*f169c0eaSGlenn Lagasse 		zonepath = z_zlist_get_zonepath(zlist, i);
1885*f169c0eaSGlenn Lagasse 
1886*f169c0eaSGlenn Lagasse 		/* Skip zones that aren't at least installed */
1887*f169c0eaSGlenn Lagasse 		if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1888*f169c0eaSGlenn Lagasse 			continue;
1889*f169c0eaSGlenn Lagasse 
1890*f169c0eaSGlenn Lagasse 		/*
1891*f169c0eaSGlenn Lagasse 		 * Get the dataset of this zonepath.  If its not
1892*f169c0eaSGlenn Lagasse 		 * a dataset, skip it.
1893*f169c0eaSGlenn Lagasse 		 */
1894*f169c0eaSGlenn Lagasse 		if ((ds = be_get_ds_from_dir(zonepath)) == NULL)
1895*f169c0eaSGlenn Lagasse 			continue;
1896*f169c0eaSGlenn Lagasse 
1897*f169c0eaSGlenn Lagasse 		(void) strlcpy(zonepath_ds, ds, sizeof (zonepath_ds));
1898*f169c0eaSGlenn Lagasse 		free(ds);
1899*f169c0eaSGlenn Lagasse 		ds = NULL;
1900*f169c0eaSGlenn Lagasse 
1901*f169c0eaSGlenn Lagasse 		/* Get zoneroot directory */
1902*f169c0eaSGlenn Lagasse 		be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
1903*f169c0eaSGlenn Lagasse 
1904*f169c0eaSGlenn Lagasse 		/* If zonepath dataset not supported, skip it. */
1905*f169c0eaSGlenn Lagasse 		if (!be_zone_supported(zonepath_ds)) {
1906*f169c0eaSGlenn Lagasse 			continue;
1907*f169c0eaSGlenn Lagasse 		}
1908*f169c0eaSGlenn Lagasse 
1909*f169c0eaSGlenn Lagasse 		if ((ret = be_find_active_zone_root(obe_zhp, zonepath_ds,
1910*f169c0eaSGlenn Lagasse 		    zoneroot_ds, sizeof (zoneroot_ds))) != BE_SUCCESS) {
1911*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
1912*f169c0eaSGlenn Lagasse 			    "failed to find active zone root for zone %s "
1913*f169c0eaSGlenn Lagasse 			    "in BE %s\n"), zonename, obe_name);
1914*f169c0eaSGlenn Lagasse 			goto done;
1915*f169c0eaSGlenn Lagasse 		}
1916*f169c0eaSGlenn Lagasse 
1917*f169c0eaSGlenn Lagasse 		be_make_container_ds(zonepath_ds, zone_container_ds,
1918*f169c0eaSGlenn Lagasse 		    sizeof (zone_container_ds));
1919*f169c0eaSGlenn Lagasse 
1920*f169c0eaSGlenn Lagasse 		if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1921*f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
1922*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
1923*f169c0eaSGlenn Lagasse 			    "failed to open zone root dataset (%s): %s\n"),
1924*f169c0eaSGlenn Lagasse 			    zoneroot_ds, libzfs_error_description(g_zfs));
1925*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1926*f169c0eaSGlenn Lagasse 			goto done;
1927*f169c0eaSGlenn Lagasse 		}
1928*f169c0eaSGlenn Lagasse 
1929*f169c0eaSGlenn Lagasse 		zone_be_name =
1930*f169c0eaSGlenn Lagasse 		    be_get_zone_be_name(zoneroot_ds, zone_container_ds);
1931*f169c0eaSGlenn Lagasse 
1932*f169c0eaSGlenn Lagasse 		if ((new_zone_be_name = be_auto_zone_be_name(zone_container_ds,
1933*f169c0eaSGlenn Lagasse 		    zone_be_name)) == NULL) {
1934*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: failed "
1935*f169c0eaSGlenn Lagasse 			    "to generate auto name for zone BE.\n"));
1936*f169c0eaSGlenn Lagasse 			ret = BE_ERR_AUTONAME;
1937*f169c0eaSGlenn Lagasse 			goto done;
1938*f169c0eaSGlenn Lagasse 		}
1939*f169c0eaSGlenn Lagasse 
1940*f169c0eaSGlenn Lagasse 		if ((snap_name = be_auto_snap_name()) == NULL) {
1941*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: failed to "
1942*f169c0eaSGlenn Lagasse 			    "generate snapshot name for zone BE.\n"));
1943*f169c0eaSGlenn Lagasse 			ret = BE_ERR_AUTONAME;
1944*f169c0eaSGlenn Lagasse 			goto done;
1945*f169c0eaSGlenn Lagasse 		}
1946*f169c0eaSGlenn Lagasse 
1947*f169c0eaSGlenn Lagasse 		(void) snprintf(ss, sizeof (ss), "%s@%s", zoneroot_ds,
1948*f169c0eaSGlenn Lagasse 		    snap_name);
1949*f169c0eaSGlenn Lagasse 
1950*f169c0eaSGlenn Lagasse 		if (zfs_snapshot(g_zfs, ss, B_TRUE, NULL) != 0) {
1951*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
1952*f169c0eaSGlenn Lagasse 			    "failed to snapshot zone BE (%s): %s\n"),
1953*f169c0eaSGlenn Lagasse 			    ss, libzfs_error_description(g_zfs));
1954*f169c0eaSGlenn Lagasse 			if (libzfs_errno(g_zfs) == EZFS_EXISTS)
1955*f169c0eaSGlenn Lagasse 				ret = BE_ERR_ZONE_SS_EXISTS;
1956*f169c0eaSGlenn Lagasse 			else
1957*f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
1958*f169c0eaSGlenn Lagasse 
1959*f169c0eaSGlenn Lagasse 			goto done;
1960*f169c0eaSGlenn Lagasse 		}
1961*f169c0eaSGlenn Lagasse 
1962*f169c0eaSGlenn Lagasse 		(void) snprintf(new_zoneroot_ds, sizeof (new_zoneroot_ds),
1963*f169c0eaSGlenn Lagasse 		    "%s/%s", zone_container_ds, new_zone_be_name);
1964*f169c0eaSGlenn Lagasse 
1965*f169c0eaSGlenn Lagasse 		bt.obe_name = zone_be_name;
1966*f169c0eaSGlenn Lagasse 		bt.obe_root_ds = zoneroot_ds;
1967*f169c0eaSGlenn Lagasse 		bt.obe_snap_name = snap_name;
1968*f169c0eaSGlenn Lagasse 		bt.obe_altroot = temp_mntpt;
1969*f169c0eaSGlenn Lagasse 		bt.nbe_name = new_zone_be_name;
1970*f169c0eaSGlenn Lagasse 		bt.nbe_root_ds = new_zoneroot_ds;
1971*f169c0eaSGlenn Lagasse 
1972*f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
1973*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
1974*f169c0eaSGlenn Lagasse 			    "internal error: out of memory\n"));
1975*f169c0eaSGlenn Lagasse 			ret = BE_ERR_NOMEM;
1976*f169c0eaSGlenn Lagasse 			goto done;
1977*f169c0eaSGlenn Lagasse 		}
1978*f169c0eaSGlenn Lagasse 
1979*f169c0eaSGlenn Lagasse 		/*
1980*f169c0eaSGlenn Lagasse 		 * The call to be_clone_fs_callback always closes the
1981*f169c0eaSGlenn Lagasse 		 * zfs_handle so there's no need to close z_zhp.
1982*f169c0eaSGlenn Lagasse 		 */
1983*f169c0eaSGlenn Lagasse 		if ((iret = be_clone_fs_callback(z_zhp, &bt)) != 0) {
1984*f169c0eaSGlenn Lagasse 			z_zhp = NULL;
1985*f169c0eaSGlenn Lagasse 			if (iret != BE_ERR_BE_EXISTS) {
1986*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy_zones: "
1987*f169c0eaSGlenn Lagasse 				    "failed to create zone BE clone for new "
1988*f169c0eaSGlenn Lagasse 				    "zone BE %s\n"), new_zone_be_name);
1989*f169c0eaSGlenn Lagasse 				ret = iret;
1990*f169c0eaSGlenn Lagasse 				if (bt.nbe_zfs_props != NULL)
1991*f169c0eaSGlenn Lagasse 					nvlist_free(bt.nbe_zfs_props);
1992*f169c0eaSGlenn Lagasse 				goto done;
1993*f169c0eaSGlenn Lagasse 			}
1994*f169c0eaSGlenn Lagasse 			/*
1995*f169c0eaSGlenn Lagasse 			 * We failed to create the new zone BE because a zone
1996*f169c0eaSGlenn Lagasse 			 * BE with the auto-name we generated above has since
1997*f169c0eaSGlenn Lagasse 			 * come into existence. Regenerate a new auto-name
1998*f169c0eaSGlenn Lagasse 			 * and retry.
1999*f169c0eaSGlenn Lagasse 			 */
2000*f169c0eaSGlenn Lagasse 			for (num_retries = 1;
2001*f169c0eaSGlenn Lagasse 			    num_retries < BE_AUTO_NAME_MAX_TRY;
2002*f169c0eaSGlenn Lagasse 			    num_retries++) {
2003*f169c0eaSGlenn Lagasse 
2004*f169c0eaSGlenn Lagasse 				/* Sleep 1 before retrying */
2005*f169c0eaSGlenn Lagasse 				(void) sleep(1);
2006*f169c0eaSGlenn Lagasse 
2007*f169c0eaSGlenn Lagasse 				/* Generate new auto zone BE name */
2008*f169c0eaSGlenn Lagasse 				free(new_zone_be_name);
2009*f169c0eaSGlenn Lagasse 				if ((new_zone_be_name = be_auto_zone_be_name(
2010*f169c0eaSGlenn Lagasse 				    zone_container_ds,
2011*f169c0eaSGlenn Lagasse 				    zone_be_name)) == NULL) {
2012*f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy_zones: "
2013*f169c0eaSGlenn Lagasse 					    "failed to generate auto name "
2014*f169c0eaSGlenn Lagasse 					    "for zone BE.\n"));
2015*f169c0eaSGlenn Lagasse 					ret = BE_ERR_AUTONAME;
2016*f169c0eaSGlenn Lagasse 					if (bt.nbe_zfs_props != NULL)
2017*f169c0eaSGlenn Lagasse 						nvlist_free(bt.nbe_zfs_props);
2018*f169c0eaSGlenn Lagasse 					goto done;
2019*f169c0eaSGlenn Lagasse 				}
2020*f169c0eaSGlenn Lagasse 
2021*f169c0eaSGlenn Lagasse 				(void) snprintf(new_zoneroot_ds,
2022*f169c0eaSGlenn Lagasse 				    sizeof (new_zoneroot_ds),
2023*f169c0eaSGlenn Lagasse 				    "%s/%s", zone_container_ds,
2024*f169c0eaSGlenn Lagasse 				    new_zone_be_name);
2025*f169c0eaSGlenn Lagasse 				bt.nbe_name = new_zone_be_name;
2026*f169c0eaSGlenn Lagasse 				bt.nbe_root_ds = new_zoneroot_ds;
2027*f169c0eaSGlenn Lagasse 
2028*f169c0eaSGlenn Lagasse 				/*
2029*f169c0eaSGlenn Lagasse 				 * Get handle to original zone BE's root
2030*f169c0eaSGlenn Lagasse 				 * dataset.
2031*f169c0eaSGlenn Lagasse 				 */
2032*f169c0eaSGlenn Lagasse 				if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2033*f169c0eaSGlenn Lagasse 				    ZFS_TYPE_FILESYSTEM)) == NULL) {
2034*f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy_zones: "
2035*f169c0eaSGlenn Lagasse 					    "failed to open zone root "
2036*f169c0eaSGlenn Lagasse 					    "dataset (%s): %s\n"),
2037*f169c0eaSGlenn Lagasse 					    zoneroot_ds,
2038*f169c0eaSGlenn Lagasse 					    libzfs_error_description(g_zfs));
2039*f169c0eaSGlenn Lagasse 					ret = zfs_err_to_be_err(g_zfs);
2040*f169c0eaSGlenn Lagasse 					if (bt.nbe_zfs_props != NULL)
2041*f169c0eaSGlenn Lagasse 						nvlist_free(bt.nbe_zfs_props);
2042*f169c0eaSGlenn Lagasse 					goto done;
2043*f169c0eaSGlenn Lagasse 				}
2044*f169c0eaSGlenn Lagasse 
2045*f169c0eaSGlenn Lagasse 				/*
2046*f169c0eaSGlenn Lagasse 				 * Try to clone the zone BE again. This
2047*f169c0eaSGlenn Lagasse 				 * call will end up closing the zfs
2048*f169c0eaSGlenn Lagasse 				 * handle passed in whether it
2049*f169c0eaSGlenn Lagasse 				 * succeeds or fails.
2050*f169c0eaSGlenn Lagasse 				 */
2051*f169c0eaSGlenn Lagasse 				iret = be_clone_fs_callback(z_zhp, &bt);
2052*f169c0eaSGlenn Lagasse 				z_zhp = NULL;
2053*f169c0eaSGlenn Lagasse 				if (iret == 0) {
2054*f169c0eaSGlenn Lagasse 					break;
2055*f169c0eaSGlenn Lagasse 				} else if (iret != BE_ERR_BE_EXISTS) {
2056*f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy_zones: "
2057*f169c0eaSGlenn Lagasse 					    "failed to create zone BE clone "
2058*f169c0eaSGlenn Lagasse 					    "for new zone BE %s\n"),
2059*f169c0eaSGlenn Lagasse 					    new_zone_be_name);
2060*f169c0eaSGlenn Lagasse 					ret = iret;
2061*f169c0eaSGlenn Lagasse 					if (bt.nbe_zfs_props != NULL)
2062*f169c0eaSGlenn Lagasse 						nvlist_free(bt.nbe_zfs_props);
2063*f169c0eaSGlenn Lagasse 					goto done;
2064*f169c0eaSGlenn Lagasse 				}
2065*f169c0eaSGlenn Lagasse 			}
2066*f169c0eaSGlenn Lagasse 			/*
2067*f169c0eaSGlenn Lagasse 			 * If we've exhausted the maximum number of
2068*f169c0eaSGlenn Lagasse 			 * tries, free the auto zone BE name and return
2069*f169c0eaSGlenn Lagasse 			 * error.
2070*f169c0eaSGlenn Lagasse 			 */
2071*f169c0eaSGlenn Lagasse 			if (num_retries == BE_AUTO_NAME_MAX_TRY) {
2072*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy_zones: failed "
2073*f169c0eaSGlenn Lagasse 				    "to create a unique auto zone BE name\n"));
2074*f169c0eaSGlenn Lagasse 				free(bt.nbe_name);
2075*f169c0eaSGlenn Lagasse 				bt.nbe_name = NULL;
2076*f169c0eaSGlenn Lagasse 				ret = BE_ERR_AUTONAME;
2077*f169c0eaSGlenn Lagasse 				if (bt.nbe_zfs_props != NULL)
2078*f169c0eaSGlenn Lagasse 					nvlist_free(bt.nbe_zfs_props);
2079*f169c0eaSGlenn Lagasse 				goto done;
2080*f169c0eaSGlenn Lagasse 			}
2081*f169c0eaSGlenn Lagasse 		}
2082*f169c0eaSGlenn Lagasse 
2083*f169c0eaSGlenn Lagasse 		if (bt.nbe_zfs_props != NULL)
2084*f169c0eaSGlenn Lagasse 			nvlist_free(bt.nbe_zfs_props);
2085*f169c0eaSGlenn Lagasse 
2086*f169c0eaSGlenn Lagasse 		z_zhp = NULL;
2087*f169c0eaSGlenn Lagasse 
2088*f169c0eaSGlenn Lagasse 		if ((z_zhp = zfs_open(g_zfs, new_zoneroot_ds,
2089*f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
2090*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2091*f169c0eaSGlenn Lagasse 			    "failed to open the new zone BE root dataset "
2092*f169c0eaSGlenn Lagasse 			    "(%s): %s\n"), new_zoneroot_ds,
2093*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
2094*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2095*f169c0eaSGlenn Lagasse 			goto done;
2096*f169c0eaSGlenn Lagasse 		}
2097*f169c0eaSGlenn Lagasse 
2098*f169c0eaSGlenn Lagasse 		if (zfs_prop_set(z_zhp, BE_ZONE_PARENTBE_PROPERTY,
2099*f169c0eaSGlenn Lagasse 		    uu_string) != 0) {
2100*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2101*f169c0eaSGlenn Lagasse 			    "failed to set parentbe property\n"));
2102*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(z_zhp);
2103*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2104*f169c0eaSGlenn Lagasse 			goto done;
2105*f169c0eaSGlenn Lagasse 		}
2106*f169c0eaSGlenn Lagasse 
2107*f169c0eaSGlenn Lagasse 		if (zfs_prop_set(z_zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
2108*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2109*f169c0eaSGlenn Lagasse 			    "failed to set active property\n"));
2110*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(z_zhp);
2111*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2112*f169c0eaSGlenn Lagasse 			goto done;
2113*f169c0eaSGlenn Lagasse 		}
2114*f169c0eaSGlenn Lagasse 
2115*f169c0eaSGlenn Lagasse 		/*
2116*f169c0eaSGlenn Lagasse 		 * Generate a list of file systems from the original
2117*f169c0eaSGlenn Lagasse 		 * zone BE that are legacy mounted.  We use this list
2118*f169c0eaSGlenn Lagasse 		 * to determine which entries in the vfstab we need to
2119*f169c0eaSGlenn Lagasse 		 * update for the new zone BE we've just created.
2120*f169c0eaSGlenn Lagasse 		 */
2121*f169c0eaSGlenn Lagasse 		if ((ret = be_get_legacy_fs(obe_name, obe_root_ds,
2122*f169c0eaSGlenn Lagasse 		    zoneroot_ds, zoneroot, &fld)) != BE_SUCCESS) {
2123*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2124*f169c0eaSGlenn Lagasse 			    "failed to get legacy mounted file system "
2125*f169c0eaSGlenn Lagasse 			    "list for zone %s\n"), zonename);
2126*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(z_zhp);
2127*f169c0eaSGlenn Lagasse 			goto done;
2128*f169c0eaSGlenn Lagasse 		}
2129*f169c0eaSGlenn Lagasse 
2130*f169c0eaSGlenn Lagasse 		/*
2131*f169c0eaSGlenn Lagasse 		 * Update new zone BE's vfstab.
2132*f169c0eaSGlenn Lagasse 		 */
2133*f169c0eaSGlenn Lagasse 		if ((ret = be_update_zone_vfstab(z_zhp, bt.nbe_name,
2134*f169c0eaSGlenn Lagasse 		    zonepath_ds, zonepath_ds, &fld)) != BE_SUCCESS) {
2135*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2136*f169c0eaSGlenn Lagasse 			    "failed to update new BE's vfstab (%s)\n"),
2137*f169c0eaSGlenn Lagasse 			    bt.nbe_name);
2138*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(z_zhp);
2139*f169c0eaSGlenn Lagasse 			be_free_fs_list(&fld);
2140*f169c0eaSGlenn Lagasse 			goto done;
2141*f169c0eaSGlenn Lagasse 		}
2142*f169c0eaSGlenn Lagasse 
2143*f169c0eaSGlenn Lagasse 		be_free_fs_list(&fld);
2144*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(z_zhp);
2145*f169c0eaSGlenn Lagasse 	}
2146*f169c0eaSGlenn Lagasse 
2147*f169c0eaSGlenn Lagasse done:
2148*f169c0eaSGlenn Lagasse 	free(snap_name);
2149*f169c0eaSGlenn Lagasse 	if (brands != NULL)
2150*f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
2151*f169c0eaSGlenn Lagasse 	if (zlist != NULL)
2152*f169c0eaSGlenn Lagasse 		z_free_zone_list(zlist);
2153*f169c0eaSGlenn Lagasse 
2154*f169c0eaSGlenn Lagasse 	if (mounted_here)
2155*f169c0eaSGlenn Lagasse 		(void) _be_unmount(obe_name, 0);
2156*f169c0eaSGlenn Lagasse 
2157*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(obe_zhp);
2158*f169c0eaSGlenn Lagasse 	return (ret);
2159*f169c0eaSGlenn Lagasse }
2160*f169c0eaSGlenn Lagasse 
2161*f169c0eaSGlenn Lagasse /*
2162*f169c0eaSGlenn Lagasse  * Function:	be_clone_fs_callback
2163*f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through a BE's filesystems
2164*f169c0eaSGlenn Lagasse  *		to clone them for the new BE.
2165*f169c0eaSGlenn Lagasse  * Parameters:
2166*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer for the filesystem being processed.
2167*f169c0eaSGlenn Lagasse  *		data - be_transaction_data_t pointer providing information
2168*f169c0eaSGlenn Lagasse  *			about original BE and new BE.
2169*f169c0eaSGlenn Lagasse  * Return:
2170*f169c0eaSGlenn Lagasse  *		0 - Success
2171*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2172*f169c0eaSGlenn Lagasse  * Scope:
2173*f169c0eaSGlenn Lagasse  *		Private
2174*f169c0eaSGlenn Lagasse  */
2175*f169c0eaSGlenn Lagasse static int
2176*f169c0eaSGlenn Lagasse be_clone_fs_callback(zfs_handle_t *zhp, void *data)
2177*f169c0eaSGlenn Lagasse {
2178*f169c0eaSGlenn Lagasse 	be_transaction_data_t	*bt = data;
2179*f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp_ss = NULL;
2180*f169c0eaSGlenn Lagasse 	char		prop_buf[MAXPATHLEN];
2181*f169c0eaSGlenn Lagasse 	char		zhp_name[ZFS_MAXNAMELEN];
2182*f169c0eaSGlenn Lagasse 	char		clone_ds[MAXPATHLEN];
2183*f169c0eaSGlenn Lagasse 	char		ss[MAXPATHLEN];
2184*f169c0eaSGlenn Lagasse 	int		ret = 0;
2185*f169c0eaSGlenn Lagasse 
2186*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
2187*f169c0eaSGlenn Lagasse 	    ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) != 0) {
2188*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_clone_fs_callback: "
2189*f169c0eaSGlenn Lagasse 		    "failed to get dataset mountpoint (%s): %s\n"),
2190*f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
2191*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
2192*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2193*f169c0eaSGlenn Lagasse 		return (ret);
2194*f169c0eaSGlenn Lagasse 	}
2195*f169c0eaSGlenn Lagasse 
2196*f169c0eaSGlenn Lagasse 	if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) != 0 &&
2197*f169c0eaSGlenn Lagasse 	    strcmp(prop_buf, "legacy") != 0) {
2198*f169c0eaSGlenn Lagasse 		/*
2199*f169c0eaSGlenn Lagasse 		 * Since zfs can't currently handle setting the
2200*f169c0eaSGlenn Lagasse 		 * mountpoint for a zoned dataset we'll have to skip
2201*f169c0eaSGlenn Lagasse 		 * this dataset. This is because the mountpoint is not
2202*f169c0eaSGlenn Lagasse 		 * set to "legacy".
2203*f169c0eaSGlenn Lagasse 		 */
2204*f169c0eaSGlenn Lagasse 		goto zoned;
2205*f169c0eaSGlenn Lagasse 	}
2206*f169c0eaSGlenn Lagasse 	/*
2207*f169c0eaSGlenn Lagasse 	 * Get a copy of the dataset name from the zfs handle
2208*f169c0eaSGlenn Lagasse 	 */
2209*f169c0eaSGlenn Lagasse 	(void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2210*f169c0eaSGlenn Lagasse 
2211*f169c0eaSGlenn Lagasse 	/*
2212*f169c0eaSGlenn Lagasse 	 * Get the clone dataset name and prepare the zfs properties for it.
2213*f169c0eaSGlenn Lagasse 	 */
2214*f169c0eaSGlenn Lagasse 	if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2215*f169c0eaSGlenn Lagasse 	    sizeof (clone_ds))) != BE_SUCCESS) {
2216*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2217*f169c0eaSGlenn Lagasse 		return (ret);
2218*f169c0eaSGlenn Lagasse 	}
2219*f169c0eaSGlenn Lagasse 
2220*f169c0eaSGlenn Lagasse 	/*
2221*f169c0eaSGlenn Lagasse 	 * Generate the name of the snapshot to use.
2222*f169c0eaSGlenn Lagasse 	 */
2223*f169c0eaSGlenn Lagasse 	(void) snprintf(ss, sizeof (ss), "%s@%s", zhp_name,
2224*f169c0eaSGlenn Lagasse 	    bt->obe_snap_name);
2225*f169c0eaSGlenn Lagasse 
2226*f169c0eaSGlenn Lagasse 	/*
2227*f169c0eaSGlenn Lagasse 	 * Get handle to snapshot.
2228*f169c0eaSGlenn Lagasse 	 */
2229*f169c0eaSGlenn Lagasse 	if ((zhp_ss = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
2230*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_clone_fs_callback: "
2231*f169c0eaSGlenn Lagasse 		    "failed to get handle to snapshot (%s): %s\n"), ss,
2232*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2233*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
2234*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2235*f169c0eaSGlenn Lagasse 		return (ret);
2236*f169c0eaSGlenn Lagasse 	}
2237*f169c0eaSGlenn Lagasse 
2238*f169c0eaSGlenn Lagasse 	/*
2239*f169c0eaSGlenn Lagasse 	 * Clone the dataset.
2240*f169c0eaSGlenn Lagasse 	 */
2241*f169c0eaSGlenn Lagasse 	if (zfs_clone(zhp_ss, clone_ds, bt->nbe_zfs_props) != 0) {
2242*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_clone_fs_callback: "
2243*f169c0eaSGlenn Lagasse 		    "failed to create clone dataset (%s): %s\n"),
2244*f169c0eaSGlenn Lagasse 		    clone_ds, libzfs_error_description(g_zfs));
2245*f169c0eaSGlenn Lagasse 
2246*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp_ss);
2247*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2248*f169c0eaSGlenn Lagasse 
2249*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2250*f169c0eaSGlenn Lagasse 	}
2251*f169c0eaSGlenn Lagasse 
2252*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp_ss);
2253*f169c0eaSGlenn Lagasse 
2254*f169c0eaSGlenn Lagasse zoned:
2255*f169c0eaSGlenn Lagasse 	/*
2256*f169c0eaSGlenn Lagasse 	 * Iterate through zhp's children datasets (if any)
2257*f169c0eaSGlenn Lagasse 	 * and clone them accordingly.
2258*f169c0eaSGlenn Lagasse 	 */
2259*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_clone_fs_callback, bt)) != 0) {
2260*f169c0eaSGlenn Lagasse 		/*
2261*f169c0eaSGlenn Lagasse 		 * Error occurred while processing a child dataset.
2262*f169c0eaSGlenn Lagasse 		 * Destroy this dataset and return error.
2263*f169c0eaSGlenn Lagasse 		 */
2264*f169c0eaSGlenn Lagasse 		zfs_handle_t	*d_zhp = NULL;
2265*f169c0eaSGlenn Lagasse 
2266*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2267*f169c0eaSGlenn Lagasse 
2268*f169c0eaSGlenn Lagasse 		if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2269*f169c0eaSGlenn Lagasse 		    == NULL) {
2270*f169c0eaSGlenn Lagasse 			return (ret);
2271*f169c0eaSGlenn Lagasse 		}
2272*f169c0eaSGlenn Lagasse 
2273*f169c0eaSGlenn Lagasse 		(void) zfs_destroy(d_zhp, B_FALSE);
2274*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(d_zhp);
2275*f169c0eaSGlenn Lagasse 		return (ret);
2276*f169c0eaSGlenn Lagasse 	}
2277*f169c0eaSGlenn Lagasse 
2278*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2279*f169c0eaSGlenn Lagasse 	return (0);
2280*f169c0eaSGlenn Lagasse }
2281*f169c0eaSGlenn Lagasse 
2282*f169c0eaSGlenn Lagasse /*
2283*f169c0eaSGlenn Lagasse  * Function:	be_send_fs_callback
2284*f169c0eaSGlenn Lagasse  * Description: Callback function used to iterate through a BE's filesystems
2285*f169c0eaSGlenn Lagasse  *		to copy them for the new BE.
2286*f169c0eaSGlenn Lagasse  * Parameters:
2287*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer for the filesystem being processed.
2288*f169c0eaSGlenn Lagasse  *		data - be_transaction_data_t pointer providing information
2289*f169c0eaSGlenn Lagasse  *			about original BE and new BE.
2290*f169c0eaSGlenn Lagasse  * Return:
2291*f169c0eaSGlenn Lagasse  *		0 - Success
2292*f169c0eaSGlenn Lagasse  *		be_errnot_t - Failure
2293*f169c0eaSGlenn Lagasse  * Scope:
2294*f169c0eaSGlenn Lagasse  *		Private
2295*f169c0eaSGlenn Lagasse  */
2296*f169c0eaSGlenn Lagasse static int
2297*f169c0eaSGlenn Lagasse be_send_fs_callback(zfs_handle_t *zhp, void *data)
2298*f169c0eaSGlenn Lagasse {
2299*f169c0eaSGlenn Lagasse 	be_transaction_data_t	*bt = data;
2300*f169c0eaSGlenn Lagasse 	recvflags_t	flags = { 0 };
2301*f169c0eaSGlenn Lagasse 	char		zhp_name[ZFS_MAXNAMELEN];
2302*f169c0eaSGlenn Lagasse 	char		clone_ds[MAXPATHLEN];
2303*f169c0eaSGlenn Lagasse 	sendflags_t	send_flags = { 0 };
2304*f169c0eaSGlenn Lagasse 	int		pid, status, retval;
2305*f169c0eaSGlenn Lagasse 	int		srpipe[2];
2306*f169c0eaSGlenn Lagasse 	int		ret = 0;
2307*f169c0eaSGlenn Lagasse 
2308*f169c0eaSGlenn Lagasse 	/*
2309*f169c0eaSGlenn Lagasse 	 * Get a copy of the dataset name from the zfs handle
2310*f169c0eaSGlenn Lagasse 	 */
2311*f169c0eaSGlenn Lagasse 	(void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2312*f169c0eaSGlenn Lagasse 
2313*f169c0eaSGlenn Lagasse 	/*
2314*f169c0eaSGlenn Lagasse 	 * Get the clone dataset name and prepare the zfs properties for it.
2315*f169c0eaSGlenn Lagasse 	 */
2316*f169c0eaSGlenn Lagasse 	if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2317*f169c0eaSGlenn Lagasse 	    sizeof (clone_ds))) != BE_SUCCESS) {
2318*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2319*f169c0eaSGlenn Lagasse 		return (ret);
2320*f169c0eaSGlenn Lagasse 	}
2321*f169c0eaSGlenn Lagasse 
2322*f169c0eaSGlenn Lagasse 	/*
2323*f169c0eaSGlenn Lagasse 	 * Create the new dataset.
2324*f169c0eaSGlenn Lagasse 	 */
2325*f169c0eaSGlenn Lagasse 	if (zfs_create(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM, bt->nbe_zfs_props)
2326*f169c0eaSGlenn Lagasse 	    != 0) {
2327*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: "
2328*f169c0eaSGlenn Lagasse 		    "failed to create new dataset '%s': %s\n"),
2329*f169c0eaSGlenn Lagasse 		    clone_ds, libzfs_error_description(g_zfs));
2330*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
2331*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2332*f169c0eaSGlenn Lagasse 		return (ret);
2333*f169c0eaSGlenn Lagasse 	}
2334*f169c0eaSGlenn Lagasse 
2335*f169c0eaSGlenn Lagasse 	/*
2336*f169c0eaSGlenn Lagasse 	 * Destination file system is already created
2337*f169c0eaSGlenn Lagasse 	 * hence we need to set the force flag on
2338*f169c0eaSGlenn Lagasse 	 */
2339*f169c0eaSGlenn Lagasse 	flags.force = B_TRUE;
2340*f169c0eaSGlenn Lagasse 
2341*f169c0eaSGlenn Lagasse 	/*
2342*f169c0eaSGlenn Lagasse 	 * Initiate the pipe to be used for the send and recv
2343*f169c0eaSGlenn Lagasse 	 */
2344*f169c0eaSGlenn Lagasse 	if (pipe(srpipe) != 0) {
2345*f169c0eaSGlenn Lagasse 		int err = errno;
2346*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: failed to "
2347*f169c0eaSGlenn Lagasse 		    "open pipe\n"));
2348*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2349*f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
2350*f169c0eaSGlenn Lagasse 	}
2351*f169c0eaSGlenn Lagasse 
2352*f169c0eaSGlenn Lagasse 	/*
2353*f169c0eaSGlenn Lagasse 	 * Fork off a child to send the dataset
2354*f169c0eaSGlenn Lagasse 	 */
2355*f169c0eaSGlenn Lagasse 	if ((pid = fork()) == -1) {
2356*f169c0eaSGlenn Lagasse 		int err = errno;
2357*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: failed to fork\n"));
2358*f169c0eaSGlenn Lagasse 		(void) close(srpipe[0]);
2359*f169c0eaSGlenn Lagasse 		(void) close(srpipe[1]);
2360*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2361*f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
2362*f169c0eaSGlenn Lagasse 	} else if (pid == 0) { /* child process */
2363*f169c0eaSGlenn Lagasse 		(void) close(srpipe[0]);
2364*f169c0eaSGlenn Lagasse 
2365*f169c0eaSGlenn Lagasse 		/* Send dataset */
2366*f169c0eaSGlenn Lagasse 		if (zfs_send(zhp, NULL, bt->obe_snap_name, send_flags,
2367*f169c0eaSGlenn Lagasse 		    srpipe[1], NULL, NULL, NULL) != 0) {
2368*f169c0eaSGlenn Lagasse 			_exit(1);
2369*f169c0eaSGlenn Lagasse 		}
2370*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2371*f169c0eaSGlenn Lagasse 
2372*f169c0eaSGlenn Lagasse 		_exit(0);
2373*f169c0eaSGlenn Lagasse 	}
2374*f169c0eaSGlenn Lagasse 
2375*f169c0eaSGlenn Lagasse 	(void) close(srpipe[1]);
2376*f169c0eaSGlenn Lagasse 
2377*f169c0eaSGlenn Lagasse 	/* Receive dataset */
2378*f169c0eaSGlenn Lagasse 	if (zfs_receive(g_zfs, clone_ds, flags, srpipe[0], NULL) != 0) {
2379*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: failed to "
2380*f169c0eaSGlenn Lagasse 		    "recv dataset (%s)\n"), clone_ds);
2381*f169c0eaSGlenn Lagasse 	}
2382*f169c0eaSGlenn Lagasse 	(void) close(srpipe[0]);
2383*f169c0eaSGlenn Lagasse 
2384*f169c0eaSGlenn Lagasse 	/* wait for child to exit */
2385*f169c0eaSGlenn Lagasse 	do {
2386*f169c0eaSGlenn Lagasse 		retval = waitpid(pid, &status, 0);
2387*f169c0eaSGlenn Lagasse 		if (retval == -1) {
2388*f169c0eaSGlenn Lagasse 			status = 0;
2389*f169c0eaSGlenn Lagasse 		}
2390*f169c0eaSGlenn Lagasse 	} while (retval != pid);
2391*f169c0eaSGlenn Lagasse 
2392*f169c0eaSGlenn Lagasse 	if (WEXITSTATUS(status) != 0) {
2393*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: failed to "
2394*f169c0eaSGlenn Lagasse 		    "send dataset (%s)\n"), zhp_name);
2395*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2396*f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
2397*f169c0eaSGlenn Lagasse 	}
2398*f169c0eaSGlenn Lagasse 
2399*f169c0eaSGlenn Lagasse 
2400*f169c0eaSGlenn Lagasse 	/*
2401*f169c0eaSGlenn Lagasse 	 * Iterate through zhp's children datasets (if any)
2402*f169c0eaSGlenn Lagasse 	 * and send them accordingly.
2403*f169c0eaSGlenn Lagasse 	 */
2404*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_send_fs_callback, bt)) != 0) {
2405*f169c0eaSGlenn Lagasse 		/*
2406*f169c0eaSGlenn Lagasse 		 * Error occurred while processing a child dataset.
2407*f169c0eaSGlenn Lagasse 		 * Destroy this dataset and return error.
2408*f169c0eaSGlenn Lagasse 		 */
2409*f169c0eaSGlenn Lagasse 		zfs_handle_t	*d_zhp = NULL;
2410*f169c0eaSGlenn Lagasse 
2411*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2412*f169c0eaSGlenn Lagasse 
2413*f169c0eaSGlenn Lagasse 		if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2414*f169c0eaSGlenn Lagasse 		    == NULL) {
2415*f169c0eaSGlenn Lagasse 			return (ret);
2416*f169c0eaSGlenn Lagasse 		}
2417*f169c0eaSGlenn Lagasse 
2418*f169c0eaSGlenn Lagasse 		(void) zfs_destroy(d_zhp, B_FALSE);
2419*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(d_zhp);
2420*f169c0eaSGlenn Lagasse 		return (ret);
2421*f169c0eaSGlenn Lagasse 	}
2422*f169c0eaSGlenn Lagasse 
2423*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2424*f169c0eaSGlenn Lagasse 	return (0);
2425*f169c0eaSGlenn Lagasse }
2426*f169c0eaSGlenn Lagasse 
2427*f169c0eaSGlenn Lagasse /*
2428*f169c0eaSGlenn Lagasse  * Function:	be_destroy_callback
2429*f169c0eaSGlenn Lagasse  * Description:	Callback function used to destroy a BEs children datasets
2430*f169c0eaSGlenn Lagasse  *		and snapshots.
2431*f169c0eaSGlenn Lagasse  * Parameters:
2432*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to the filesystem being processed.
2433*f169c0eaSGlenn Lagasse  *		data - Not used.
2434*f169c0eaSGlenn Lagasse  * Returns:
2435*f169c0eaSGlenn Lagasse  *		0 - Success
2436*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2437*f169c0eaSGlenn Lagasse  * Scope:
2438*f169c0eaSGlenn Lagasse  *		Private
2439*f169c0eaSGlenn Lagasse  */
2440*f169c0eaSGlenn Lagasse static int
2441*f169c0eaSGlenn Lagasse be_destroy_callback(zfs_handle_t *zhp, void *data)
2442*f169c0eaSGlenn Lagasse {
2443*f169c0eaSGlenn Lagasse 	be_destroy_data_t	*dd = data;
2444*f169c0eaSGlenn Lagasse 	int ret = 0;
2445*f169c0eaSGlenn Lagasse 
2446*f169c0eaSGlenn Lagasse 	/*
2447*f169c0eaSGlenn Lagasse 	 * Iterate down this file system's hierarchical children
2448*f169c0eaSGlenn Lagasse 	 * and destroy them first.
2449*f169c0eaSGlenn Lagasse 	 */
2450*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_destroy_callback, dd)) != 0) {
2451*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2452*f169c0eaSGlenn Lagasse 		return (ret);
2453*f169c0eaSGlenn Lagasse 	}
2454*f169c0eaSGlenn Lagasse 
2455*f169c0eaSGlenn Lagasse 	if (dd->destroy_snaps) {
2456*f169c0eaSGlenn Lagasse 		/*
2457*f169c0eaSGlenn Lagasse 		 * Iterate through this file system's snapshots and
2458*f169c0eaSGlenn Lagasse 		 * destroy them before destroying the file system itself.
2459*f169c0eaSGlenn Lagasse 		 */
2460*f169c0eaSGlenn Lagasse 		if ((ret = zfs_iter_snapshots(zhp, be_destroy_callback, dd))
2461*f169c0eaSGlenn Lagasse 		    != 0) {
2462*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2463*f169c0eaSGlenn Lagasse 			return (ret);
2464*f169c0eaSGlenn Lagasse 		}
2465*f169c0eaSGlenn Lagasse 	}
2466*f169c0eaSGlenn Lagasse 
2467*f169c0eaSGlenn Lagasse 	/* Attempt to unmount the dataset before destroying it */
2468*f169c0eaSGlenn Lagasse 	if (dd->force_unmount) {
2469*f169c0eaSGlenn Lagasse 		if ((ret = zfs_unmount(zhp, NULL, MS_FORCE)) != 0) {
2470*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_callback: "
2471*f169c0eaSGlenn Lagasse 			    "failed to unmount %s: %s\n"), zfs_get_name(zhp),
2472*f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
2473*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2474*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2475*f169c0eaSGlenn Lagasse 			return (ret);
2476*f169c0eaSGlenn Lagasse 		}
2477*f169c0eaSGlenn Lagasse 	}
2478*f169c0eaSGlenn Lagasse 
2479*f169c0eaSGlenn Lagasse 	if (zfs_destroy(zhp, B_FALSE) != 0) {
2480*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_callback: "
2481*f169c0eaSGlenn Lagasse 		    "failed to destroy %s: %s\n"), zfs_get_name(zhp),
2482*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2483*f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
2484*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2485*f169c0eaSGlenn Lagasse 		return (ret);
2486*f169c0eaSGlenn Lagasse 	}
2487*f169c0eaSGlenn Lagasse 
2488*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2489*f169c0eaSGlenn Lagasse 	return (0);
2490*f169c0eaSGlenn Lagasse }
2491*f169c0eaSGlenn Lagasse 
2492*f169c0eaSGlenn Lagasse /*
2493*f169c0eaSGlenn Lagasse  * Function:	be_demote_callback
2494*f169c0eaSGlenn Lagasse  * Description:	This callback function is used to iterate through the file
2495*f169c0eaSGlenn Lagasse  *		systems of a BE, looking for the right clone to promote such
2496*f169c0eaSGlenn Lagasse  *		that this file system is left without any dependent clones.
2497*f169c0eaSGlenn Lagasse  *		If the file system has no dependent clones, it doesn't need
2498*f169c0eaSGlenn Lagasse  *		to get demoted, and the function will return success.
2499*f169c0eaSGlenn Lagasse  *
2500*f169c0eaSGlenn Lagasse  *		The demotion will be done in two passes.  The first pass
2501*f169c0eaSGlenn Lagasse  *		will attempt to find the youngest snapshot that has a clone
2502*f169c0eaSGlenn Lagasse  *		that is part of some other BE.  The second pass will attempt
2503*f169c0eaSGlenn Lagasse  *		to find the youngest snapshot that has a clone that is not
2504*f169c0eaSGlenn Lagasse  *		part of a BE.  Doing this helps ensure the aggregated set of
2505*f169c0eaSGlenn Lagasse  *		file systems that compose a BE stay coordinated wrt BE
2506*f169c0eaSGlenn Lagasse  *		snapshots and BE dependents.  It also prevents a random user
2507*f169c0eaSGlenn Lagasse  *		generated clone of a BE dataset to become the parent of other
2508*f169c0eaSGlenn Lagasse  *		BE datasets after demoting this dataset.
2509*f169c0eaSGlenn Lagasse  *
2510*f169c0eaSGlenn Lagasse  * Parameters:
2511*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to the current file system being
2512*f169c0eaSGlenn Lagasse  *			processed.
2513*f169c0eaSGlenn Lagasse  *		data - not used.
2514*f169c0eaSGlenn Lagasse  * Return:
2515*f169c0eaSGlenn Lagasse  *		0 - Success
2516*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2517*f169c0eaSGlenn Lagasse  * Scope:
2518*f169c0eaSGlenn Lagasse  *		Private
2519*f169c0eaSGlenn Lagasse  */
2520*f169c0eaSGlenn Lagasse static int
2521*f169c0eaSGlenn Lagasse /* LINTED */
2522*f169c0eaSGlenn Lagasse be_demote_callback(zfs_handle_t *zhp, void *data)
2523*f169c0eaSGlenn Lagasse {
2524*f169c0eaSGlenn Lagasse 	be_demote_data_t	dd = { 0 };
2525*f169c0eaSGlenn Lagasse 	int			i, ret = 0;
2526*f169c0eaSGlenn Lagasse 
2527*f169c0eaSGlenn Lagasse 	/*
2528*f169c0eaSGlenn Lagasse 	 * Initialize be_demote_data for the first pass - this will find a
2529*f169c0eaSGlenn Lagasse 	 * clone in another BE, if one exists.
2530*f169c0eaSGlenn Lagasse 	 */
2531*f169c0eaSGlenn Lagasse 	dd.find_in_BE = B_TRUE;
2532*f169c0eaSGlenn Lagasse 
2533*f169c0eaSGlenn Lagasse 	for (i = 0; i < 2; i++) {
2534*f169c0eaSGlenn Lagasse 
2535*f169c0eaSGlenn Lagasse 		if (zfs_iter_snapshots(zhp, be_demote_find_clone_callback, &dd)
2536*f169c0eaSGlenn Lagasse 		    != 0) {
2537*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_demote_callback: "
2538*f169c0eaSGlenn Lagasse 			    "failed to iterate snapshots for %s: %s\n"),
2539*f169c0eaSGlenn Lagasse 			    zfs_get_name(zhp), libzfs_error_description(g_zfs));
2540*f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2541*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2542*f169c0eaSGlenn Lagasse 			return (ret);
2543*f169c0eaSGlenn Lagasse 		}
2544*f169c0eaSGlenn Lagasse 		if (dd.clone_zhp != NULL) {
2545*f169c0eaSGlenn Lagasse 			/* Found the clone to promote.  Promote it. */
2546*f169c0eaSGlenn Lagasse 			if (zfs_promote(dd.clone_zhp) != 0) {
2547*f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_demote_callback: "
2548*f169c0eaSGlenn Lagasse 				    "failed to promote %s: %s\n"),
2549*f169c0eaSGlenn Lagasse 				    zfs_get_name(dd.clone_zhp),
2550*f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
2551*f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
2552*f169c0eaSGlenn Lagasse 				ZFS_CLOSE(dd.clone_zhp);
2553*f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
2554*f169c0eaSGlenn Lagasse 				return (ret);
2555*f169c0eaSGlenn Lagasse 			}
2556*f169c0eaSGlenn Lagasse 
2557*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(dd.clone_zhp);
2558*f169c0eaSGlenn Lagasse 		}
2559*f169c0eaSGlenn Lagasse 
2560*f169c0eaSGlenn Lagasse 		/*
2561*f169c0eaSGlenn Lagasse 		 * Reinitialize be_demote_data for the second pass.
2562*f169c0eaSGlenn Lagasse 		 * This will find a user created clone outside of any BE
2563*f169c0eaSGlenn Lagasse 		 * namespace, if one exists.
2564*f169c0eaSGlenn Lagasse 		 */
2565*f169c0eaSGlenn Lagasse 		dd.clone_zhp = NULL;
2566*f169c0eaSGlenn Lagasse 		dd.origin_creation = 0;
2567*f169c0eaSGlenn Lagasse 		dd.snapshot = NULL;
2568*f169c0eaSGlenn Lagasse 		dd.find_in_BE = B_FALSE;
2569*f169c0eaSGlenn Lagasse 	}
2570*f169c0eaSGlenn Lagasse 
2571*f169c0eaSGlenn Lagasse 	/* Iterate down this file system's children and demote them */
2572*f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_demote_callback, NULL)) != 0) {
2573*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2574*f169c0eaSGlenn Lagasse 		return (ret);
2575*f169c0eaSGlenn Lagasse 	}
2576*f169c0eaSGlenn Lagasse 
2577*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2578*f169c0eaSGlenn Lagasse 	return (0);
2579*f169c0eaSGlenn Lagasse }
2580*f169c0eaSGlenn Lagasse 
2581*f169c0eaSGlenn Lagasse /*
2582*f169c0eaSGlenn Lagasse  * Function:	be_demote_find_clone_callback
2583*f169c0eaSGlenn Lagasse  * Description:	This callback function is used to iterate through the
2584*f169c0eaSGlenn Lagasse  *		snapshots of a dataset, looking for the youngest snapshot
2585*f169c0eaSGlenn Lagasse  *		that has a clone.  If found, it returns a reference to the
2586*f169c0eaSGlenn Lagasse  *		clone back to the caller in the callback data.
2587*f169c0eaSGlenn Lagasse  * Parameters:
2588*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current snapshot being looked at
2589*f169c0eaSGlenn Lagasse  *		data - be_demote_data_t pointer used to store the clone that
2590*f169c0eaSGlenn Lagasse  *			is found.
2591*f169c0eaSGlenn Lagasse  * Returns:
2592*f169c0eaSGlenn Lagasse  *		0 - Successfully iterated through all snapshots.
2593*f169c0eaSGlenn Lagasse  *		1 - Failed to iterate through all snapshots.
2594*f169c0eaSGlenn Lagasse  * Scope:
2595*f169c0eaSGlenn Lagasse  *		Private
2596*f169c0eaSGlenn Lagasse  */
2597*f169c0eaSGlenn Lagasse static int
2598*f169c0eaSGlenn Lagasse be_demote_find_clone_callback(zfs_handle_t *zhp, void *data)
2599*f169c0eaSGlenn Lagasse {
2600*f169c0eaSGlenn Lagasse 	be_demote_data_t	*dd = data;
2601*f169c0eaSGlenn Lagasse 	time_t			snap_creation;
2602*f169c0eaSGlenn Lagasse 	int			zret = 0;
2603*f169c0eaSGlenn Lagasse 
2604*f169c0eaSGlenn Lagasse 	/* If snapshot has no clones, no need to look at it */
2605*f169c0eaSGlenn Lagasse 	if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
2606*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2607*f169c0eaSGlenn Lagasse 		return (0);
2608*f169c0eaSGlenn Lagasse 	}
2609*f169c0eaSGlenn Lagasse 
2610*f169c0eaSGlenn Lagasse 	dd->snapshot = zfs_get_name(zhp);
2611*f169c0eaSGlenn Lagasse 
2612*f169c0eaSGlenn Lagasse 	/* Get the creation time of this snapshot */
2613*f169c0eaSGlenn Lagasse 	snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
2614*f169c0eaSGlenn Lagasse 
2615*f169c0eaSGlenn Lagasse 	/*
2616*f169c0eaSGlenn Lagasse 	 * If this snapshot's creation time is greater than (or younger than)
2617*f169c0eaSGlenn Lagasse 	 * the current youngest snapshot found, iterate this snapshot to
2618*f169c0eaSGlenn Lagasse 	 * check if it has a clone that we're looking for.
2619*f169c0eaSGlenn Lagasse 	 */
2620*f169c0eaSGlenn Lagasse 	if (snap_creation >= dd->origin_creation) {
2621*f169c0eaSGlenn Lagasse 		/*
2622*f169c0eaSGlenn Lagasse 		 * Iterate the dependents of this snapshot to find a
2623*f169c0eaSGlenn Lagasse 		 * a clone that's a direct dependent.
2624*f169c0eaSGlenn Lagasse 		 */
2625*f169c0eaSGlenn Lagasse 		if ((zret = zfs_iter_dependents(zhp, B_FALSE,
2626*f169c0eaSGlenn Lagasse 		    be_demote_get_one_clone, dd)) == -1) {
2627*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_demote_find_clone_callback: "
2628*f169c0eaSGlenn Lagasse 			    "failed to iterate dependents of %s\n"),
2629*f169c0eaSGlenn Lagasse 			    zfs_get_name(zhp));
2630*f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2631*f169c0eaSGlenn Lagasse 			return (1);
2632*f169c0eaSGlenn Lagasse 		} else if (zret == 1) {
2633*f169c0eaSGlenn Lagasse 			/*
2634*f169c0eaSGlenn Lagasse 			 * Found a clone, update the origin_creation time
2635*f169c0eaSGlenn Lagasse 			 * in the callback data.
2636*f169c0eaSGlenn Lagasse 			 */
2637*f169c0eaSGlenn Lagasse 			dd->origin_creation = snap_creation;
2638*f169c0eaSGlenn Lagasse 		}
2639*f169c0eaSGlenn Lagasse 	}
2640*f169c0eaSGlenn Lagasse 
2641*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2642*f169c0eaSGlenn Lagasse 	return (0);
2643*f169c0eaSGlenn Lagasse }
2644*f169c0eaSGlenn Lagasse 
2645*f169c0eaSGlenn Lagasse /*
2646*f169c0eaSGlenn Lagasse  * Function:	be_demote_get_one_clone
2647*f169c0eaSGlenn Lagasse  * Description:	This callback function is used to iterate through a
2648*f169c0eaSGlenn Lagasse  *		snapshot's dependencies to find a filesystem that is a
2649*f169c0eaSGlenn Lagasse  *		direct clone of the snapshot being iterated.
2650*f169c0eaSGlenn Lagasse  * Parameters:
2651*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current dataset being looked at
2652*f169c0eaSGlenn Lagasse  *		data - be_demote_data_t pointer used to store the clone
2653*f169c0eaSGlenn Lagasse  *			that is found, and also provides flag to note
2654*f169c0eaSGlenn Lagasse  *			whether or not the clone filesystem being searched
2655*f169c0eaSGlenn Lagasse  *			for needs to be found in a BE dataset hierarchy.
2656*f169c0eaSGlenn Lagasse  * Return:
2657*f169c0eaSGlenn Lagasse  *		1 - Success, found clone and its also a BE's root dataset.
2658*f169c0eaSGlenn Lagasse  *		0 - Failure, clone not found.
2659*f169c0eaSGlenn Lagasse  * Scope:
2660*f169c0eaSGlenn Lagasse  *		Private
2661*f169c0eaSGlenn Lagasse  */
2662*f169c0eaSGlenn Lagasse static int
2663*f169c0eaSGlenn Lagasse be_demote_get_one_clone(zfs_handle_t *zhp, void *data)
2664*f169c0eaSGlenn Lagasse {
2665*f169c0eaSGlenn Lagasse 	be_demote_data_t	*dd = data;
2666*f169c0eaSGlenn Lagasse 	char			origin[ZFS_MAXNAMELEN];
2667*f169c0eaSGlenn Lagasse 	char			ds_path[ZFS_MAXNAMELEN];
2668*f169c0eaSGlenn Lagasse 
2669*f169c0eaSGlenn Lagasse 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2670*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2671*f169c0eaSGlenn Lagasse 		return (0);
2672*f169c0eaSGlenn Lagasse 	}
2673*f169c0eaSGlenn Lagasse 
2674*f169c0eaSGlenn Lagasse 	(void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
2675*f169c0eaSGlenn Lagasse 
2676*f169c0eaSGlenn Lagasse 	/*
2677*f169c0eaSGlenn Lagasse 	 * Make sure this is a direct clone of the snapshot
2678*f169c0eaSGlenn Lagasse 	 * we're iterating.
2679*f169c0eaSGlenn Lagasse 	 */
2680*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
2681*f169c0eaSGlenn Lagasse 	    NULL, 0, B_FALSE) != 0) {
2682*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_demote_get_one_clone: "
2683*f169c0eaSGlenn Lagasse 		    "failed to get origin of %s: %s\n"), ds_path,
2684*f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2685*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2686*f169c0eaSGlenn Lagasse 		return (0);
2687*f169c0eaSGlenn Lagasse 	}
2688*f169c0eaSGlenn Lagasse 	if (strcmp(origin, dd->snapshot) != 0) {
2689*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2690*f169c0eaSGlenn Lagasse 		return (0);
2691*f169c0eaSGlenn Lagasse 	}
2692*f169c0eaSGlenn Lagasse 
2693*f169c0eaSGlenn Lagasse 	if (dd->find_in_BE) {
2694*f169c0eaSGlenn Lagasse 		if ((zpool_iter(g_zfs, be_check_be_roots_callback, ds_path))
2695*f169c0eaSGlenn Lagasse 		    > 0) {
2696*f169c0eaSGlenn Lagasse 			if (dd->clone_zhp != NULL)
2697*f169c0eaSGlenn Lagasse 				ZFS_CLOSE(dd->clone_zhp);
2698*f169c0eaSGlenn Lagasse 			dd->clone_zhp = zhp;
2699*f169c0eaSGlenn Lagasse 			return (1);
2700*f169c0eaSGlenn Lagasse 		}
2701*f169c0eaSGlenn Lagasse 
2702*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2703*f169c0eaSGlenn Lagasse 		return (0);
2704*f169c0eaSGlenn Lagasse 	}
2705*f169c0eaSGlenn Lagasse 
2706*f169c0eaSGlenn Lagasse 	if (dd->clone_zhp != NULL)
2707*f169c0eaSGlenn Lagasse 		ZFS_CLOSE(dd->clone_zhp);
2708*f169c0eaSGlenn Lagasse 
2709*f169c0eaSGlenn Lagasse 	dd->clone_zhp = zhp;
2710*f169c0eaSGlenn Lagasse 	return (1);
2711*f169c0eaSGlenn Lagasse }
2712*f169c0eaSGlenn Lagasse 
2713*f169c0eaSGlenn Lagasse /*
2714*f169c0eaSGlenn Lagasse  * Function:	be_get_snap
2715*f169c0eaSGlenn Lagasse  * Description:	This function takes a snapshot dataset name and separates
2716*f169c0eaSGlenn Lagasse  *		out the parent dataset portion from the snapshot name.
2717*f169c0eaSGlenn Lagasse  *		I.e. it finds the '@' in the snapshot dataset name and
2718*f169c0eaSGlenn Lagasse  *		replaces it with a '\0'.
2719*f169c0eaSGlenn Lagasse  * Parameters:
2720*f169c0eaSGlenn Lagasse  *		origin - char pointer to a snapshot dataset name.  Its
2721*f169c0eaSGlenn Lagasse  *			contents will be modified by this function.
2722*f169c0eaSGlenn Lagasse  *		*snap - pointer to a char pointer.  Will be set to the
2723*f169c0eaSGlenn Lagasse  *			snapshot name portion upon success.
2724*f169c0eaSGlenn Lagasse  * Return:
2725*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2726*f169c0eaSGlenn Lagasse  *		1 - Failure
2727*f169c0eaSGlenn Lagasse  * Scope:
2728*f169c0eaSGlenn Lagasse  *		Private
2729*f169c0eaSGlenn Lagasse  */
2730*f169c0eaSGlenn Lagasse static int
2731*f169c0eaSGlenn Lagasse be_get_snap(char *origin, char **snap)
2732*f169c0eaSGlenn Lagasse {
2733*f169c0eaSGlenn Lagasse 	char	*cp;
2734*f169c0eaSGlenn Lagasse 
2735*f169c0eaSGlenn Lagasse 	/*
2736*f169c0eaSGlenn Lagasse 	 * Separate out the origin's dataset and snapshot portions by
2737*f169c0eaSGlenn Lagasse 	 * replacing the @ with a '\0'
2738*f169c0eaSGlenn Lagasse 	 */
2739*f169c0eaSGlenn Lagasse 	cp = strrchr(origin, '@');
2740*f169c0eaSGlenn Lagasse 	if (cp != NULL) {
2741*f169c0eaSGlenn Lagasse 		if (cp[1] != NULL && cp[1] != '\0') {
2742*f169c0eaSGlenn Lagasse 			cp[0] = '\0';
2743*f169c0eaSGlenn Lagasse 			*snap = cp+1;
2744*f169c0eaSGlenn Lagasse 		} else {
2745*f169c0eaSGlenn Lagasse 			return (1);
2746*f169c0eaSGlenn Lagasse 		}
2747*f169c0eaSGlenn Lagasse 	} else {
2748*f169c0eaSGlenn Lagasse 		return (1);
2749*f169c0eaSGlenn Lagasse 	}
2750*f169c0eaSGlenn Lagasse 
2751*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
2752*f169c0eaSGlenn Lagasse }
2753*f169c0eaSGlenn Lagasse 
2754*f169c0eaSGlenn Lagasse /*
2755*f169c0eaSGlenn Lagasse  * Function:	be_create_container_ds
2756*f169c0eaSGlenn Lagasse  * Description:	This function checks that the zpool passed has the BE
2757*f169c0eaSGlenn Lagasse  *		container dataset, and if not, then creates it.
2758*f169c0eaSGlenn Lagasse  * Parameters:
2759*f169c0eaSGlenn Lagasse  *		zpool - name of pool to create BE container dataset in.
2760*f169c0eaSGlenn Lagasse  * Return:
2761*f169c0eaSGlenn Lagasse  *		B_TRUE - Successfully created BE container dataset, or it
2762*f169c0eaSGlenn Lagasse  *			already existed.
2763*f169c0eaSGlenn Lagasse  *		B_FALSE - Failed to create container dataset.
2764*f169c0eaSGlenn Lagasse  * Scope:
2765*f169c0eaSGlenn Lagasse  *		Private
2766*f169c0eaSGlenn Lagasse  */
2767*f169c0eaSGlenn Lagasse static boolean_t
2768*f169c0eaSGlenn Lagasse be_create_container_ds(char *zpool)
2769*f169c0eaSGlenn Lagasse {
2770*f169c0eaSGlenn Lagasse 	nvlist_t	*props = NULL;
2771*f169c0eaSGlenn Lagasse 	char		be_container_ds[MAXPATHLEN];
2772*f169c0eaSGlenn Lagasse 
2773*f169c0eaSGlenn Lagasse 	/* Generate string for BE container dataset for this pool */
2774*f169c0eaSGlenn Lagasse 	be_make_container_ds(zpool, be_container_ds,
2775*f169c0eaSGlenn Lagasse 	    sizeof (be_container_ds));
2776*f169c0eaSGlenn Lagasse 
2777*f169c0eaSGlenn Lagasse 	if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2778*f169c0eaSGlenn Lagasse 
2779*f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
2780*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_create_container_ds: "
2781*f169c0eaSGlenn Lagasse 			    "nvlist_alloc failed\n"));
2782*f169c0eaSGlenn Lagasse 			return (B_FALSE);
2783*f169c0eaSGlenn Lagasse 		}
2784*f169c0eaSGlenn Lagasse 
2785*f169c0eaSGlenn Lagasse 		if (nvlist_add_string(props,
2786*f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2787*f169c0eaSGlenn Lagasse 		    ZFS_MOUNTPOINT_LEGACY) != 0) {
2788*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_create_container_ds: "
2789*f169c0eaSGlenn Lagasse 			    "internal error: out of memory\n"));
2790*f169c0eaSGlenn Lagasse 			nvlist_free(props);
2791*f169c0eaSGlenn Lagasse 			return (B_FALSE);
2792*f169c0eaSGlenn Lagasse 		}
2793*f169c0eaSGlenn Lagasse 
2794*f169c0eaSGlenn Lagasse 		if (nvlist_add_string(props,
2795*f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_CANMOUNT), "off") != 0) {
2796*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_create_container_ds: "
2797*f169c0eaSGlenn Lagasse 			    "internal error: out of memory\n"));
2798*f169c0eaSGlenn Lagasse 			nvlist_free(props);
2799*f169c0eaSGlenn Lagasse 			return (B_FALSE);
2800*f169c0eaSGlenn Lagasse 		}
2801*f169c0eaSGlenn Lagasse 
2802*f169c0eaSGlenn Lagasse 		if (zfs_create(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM,
2803*f169c0eaSGlenn Lagasse 		    props) != 0) {
2804*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_create_container_ds: "
2805*f169c0eaSGlenn Lagasse 			    "failed to create container dataset (%s): %s\n"),
2806*f169c0eaSGlenn Lagasse 			    be_container_ds, libzfs_error_description(g_zfs));
2807*f169c0eaSGlenn Lagasse 			nvlist_free(props);
2808*f169c0eaSGlenn Lagasse 			return (B_FALSE);
2809*f169c0eaSGlenn Lagasse 		}
2810*f169c0eaSGlenn Lagasse 
2811*f169c0eaSGlenn Lagasse 		nvlist_free(props);
2812*f169c0eaSGlenn Lagasse 	}
2813*f169c0eaSGlenn Lagasse 
2814*f169c0eaSGlenn Lagasse 	return (B_TRUE);
2815*f169c0eaSGlenn Lagasse }
2816*f169c0eaSGlenn Lagasse 
2817*f169c0eaSGlenn Lagasse /*
2818*f169c0eaSGlenn Lagasse  * Function:	be_prep_clone_send_fs
2819*f169c0eaSGlenn Lagasse  * Description:	This function takes a zfs handle to a dataset from the
2820*f169c0eaSGlenn Lagasse  *		original BE, and generates the name of the clone dataset
2821*f169c0eaSGlenn Lagasse  *		to create for the new BE.  It also prepares the zfs
2822*f169c0eaSGlenn Lagasse  *		properties to be used for the new BE.
2823*f169c0eaSGlenn Lagasse  * Parameters:
2824*f169c0eaSGlenn Lagasse  *		zhp - pointer to zfs_handle_t of the file system being
2825*f169c0eaSGlenn Lagasse  *			cloned/copied.
2826*f169c0eaSGlenn Lagasse  *		bt - be_transaction_data pointer providing information
2827*f169c0eaSGlenn Lagasse  *			about the original BE and new BE.
2828*f169c0eaSGlenn Lagasse  *		clone_ds - buffer to store the name of the dataset
2829*f169c0eaSGlenn Lagasse  *			for the new BE.
2830*f169c0eaSGlenn Lagasse  *		clone_ds_len - length of clone_ds buffer
2831*f169c0eaSGlenn Lagasse  * Return:
2832*f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2833*f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2834*f169c0eaSGlenn Lagasse  * Scope:
2835*f169c0eaSGlenn Lagasse  *		Private
2836*f169c0eaSGlenn Lagasse  */
2837*f169c0eaSGlenn Lagasse static int
2838*f169c0eaSGlenn Lagasse be_prep_clone_send_fs(zfs_handle_t *zhp, be_transaction_data_t *bt,
2839*f169c0eaSGlenn Lagasse     char *clone_ds, int clone_ds_len)
2840*f169c0eaSGlenn Lagasse {
2841*f169c0eaSGlenn Lagasse 	zprop_source_t	sourcetype;
2842*f169c0eaSGlenn Lagasse 	char		source[ZFS_MAXNAMELEN];
2843*f169c0eaSGlenn Lagasse 	char		zhp_name[ZFS_MAXNAMELEN];
2844*f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
2845*f169c0eaSGlenn Lagasse 	char		*child_fs = NULL;
2846*f169c0eaSGlenn Lagasse 	char		*zhp_mountpoint = NULL;
2847*f169c0eaSGlenn Lagasse 	int		err = 0;
2848*f169c0eaSGlenn Lagasse 
2849*f169c0eaSGlenn Lagasse 	/*
2850*f169c0eaSGlenn Lagasse 	 * Get a copy of the dataset name zfs_name from zhp
2851*f169c0eaSGlenn Lagasse 	 */
2852*f169c0eaSGlenn Lagasse 	(void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2853*f169c0eaSGlenn Lagasse 
2854*f169c0eaSGlenn Lagasse 	/*
2855*f169c0eaSGlenn Lagasse 	 * Get file system name relative to the root.
2856*f169c0eaSGlenn Lagasse 	 */
2857*f169c0eaSGlenn Lagasse 	if (strncmp(zhp_name, bt->obe_root_ds, strlen(bt->obe_root_ds))
2858*f169c0eaSGlenn Lagasse 	    == 0) {
2859*f169c0eaSGlenn Lagasse 		child_fs = zhp_name + strlen(bt->obe_root_ds);
2860*f169c0eaSGlenn Lagasse 
2861*f169c0eaSGlenn Lagasse 		/*
2862*f169c0eaSGlenn Lagasse 		 * if child_fs is NULL, this means we're processing the
2863*f169c0eaSGlenn Lagasse 		 * root dataset itself; set child_fs to the empty string.
2864*f169c0eaSGlenn Lagasse 		 */
2865*f169c0eaSGlenn Lagasse 		if (child_fs == NULL)
2866*f169c0eaSGlenn Lagasse 			child_fs = "";
2867*f169c0eaSGlenn Lagasse 	} else {
2868*f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
2869*f169c0eaSGlenn Lagasse 	}
2870*f169c0eaSGlenn Lagasse 
2871*f169c0eaSGlenn Lagasse 	/*
2872*f169c0eaSGlenn Lagasse 	 * Generate the name of the clone file system.
2873*f169c0eaSGlenn Lagasse 	 */
2874*f169c0eaSGlenn Lagasse 	(void) snprintf(clone_ds, clone_ds_len, "%s%s", bt->nbe_root_ds,
2875*f169c0eaSGlenn Lagasse 	    child_fs);
2876*f169c0eaSGlenn Lagasse 
2877*f169c0eaSGlenn Lagasse 	/* Get the mountpoint and source properties of the existing dataset */
2878*f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2879*f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), &sourcetype, source, sizeof (source),
2880*f169c0eaSGlenn Lagasse 	    B_FALSE) != 0) {
2881*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_prep_clone_send_fs: "
2882*f169c0eaSGlenn Lagasse 		    "failed to get mountpoint for (%s): %s\n"),
2883*f169c0eaSGlenn Lagasse 		    zhp_name, libzfs_error_description(g_zfs));
2884*f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2885*f169c0eaSGlenn Lagasse 	}
2886*f169c0eaSGlenn Lagasse 
2887*f169c0eaSGlenn Lagasse 	/*
2888*f169c0eaSGlenn Lagasse 	 * Workaround for 6668667 where a mountpoint property of "/" comes
2889*f169c0eaSGlenn Lagasse 	 * back as "".
2890*f169c0eaSGlenn Lagasse 	 */
2891*f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, "") == 0) {
2892*f169c0eaSGlenn Lagasse 		(void) snprintf(mountpoint, sizeof (mountpoint), "/");
2893*f169c0eaSGlenn Lagasse 	}
2894*f169c0eaSGlenn Lagasse 
2895*f169c0eaSGlenn Lagasse 	/*
2896*f169c0eaSGlenn Lagasse 	 * Figure out what to set as the mountpoint for the new dataset.
2897*f169c0eaSGlenn Lagasse 	 * If the source of the mountpoint property is local, use the
2898*f169c0eaSGlenn Lagasse 	 * mountpoint value itself.  Otherwise, remove it from the
2899*f169c0eaSGlenn Lagasse 	 * zfs properties list so that it gets inherited.
2900*f169c0eaSGlenn Lagasse 	 */
2901*f169c0eaSGlenn Lagasse 	if (sourcetype & ZPROP_SRC_LOCAL) {
2902*f169c0eaSGlenn Lagasse 		/*
2903*f169c0eaSGlenn Lagasse 		 * If the BE that this file system is a part of is
2904*f169c0eaSGlenn Lagasse 		 * currently mounted, strip off the BE altroot portion
2905*f169c0eaSGlenn Lagasse 		 * from the mountpoint.
2906*f169c0eaSGlenn Lagasse 		 */
2907*f169c0eaSGlenn Lagasse 		zhp_mountpoint = mountpoint;
2908*f169c0eaSGlenn Lagasse 
2909*f169c0eaSGlenn Lagasse 		if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
2910*f169c0eaSGlenn Lagasse 		    bt->obe_altroot != NULL && strcmp(bt->obe_altroot,
2911*f169c0eaSGlenn Lagasse 		    "/") != 0 && zfs_is_mounted(zhp, NULL)) {
2912*f169c0eaSGlenn Lagasse 
2913*f169c0eaSGlenn Lagasse 			int altroot_len = strlen(bt->obe_altroot);
2914*f169c0eaSGlenn Lagasse 
2915*f169c0eaSGlenn Lagasse 			if (strncmp(bt->obe_altroot, mountpoint, altroot_len)
2916*f169c0eaSGlenn Lagasse 			    == 0) {
2917*f169c0eaSGlenn Lagasse 				if (mountpoint[altroot_len] == '/')
2918*f169c0eaSGlenn Lagasse 					zhp_mountpoint = mountpoint +
2919*f169c0eaSGlenn Lagasse 					    altroot_len;
2920*f169c0eaSGlenn Lagasse 				else if (mountpoint[altroot_len] == '\0')
2921*f169c0eaSGlenn Lagasse 					(void) snprintf(mountpoint,
2922*f169c0eaSGlenn Lagasse 					    sizeof (mountpoint), "/");
2923*f169c0eaSGlenn Lagasse 			}
2924*f169c0eaSGlenn Lagasse 		}
2925*f169c0eaSGlenn Lagasse 
2926*f169c0eaSGlenn Lagasse 		if (nvlist_add_string(bt->nbe_zfs_props,
2927*f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2928*f169c0eaSGlenn Lagasse 		    zhp_mountpoint) != 0) {
2929*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_prep_clone_send_fs: "
2930*f169c0eaSGlenn Lagasse 			    "internal error: out of memory\n"));
2931*f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
2932*f169c0eaSGlenn Lagasse 		}
2933*f169c0eaSGlenn Lagasse 	} else {
2934*f169c0eaSGlenn Lagasse 		err = nvlist_remove_all(bt->nbe_zfs_props,
2935*f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT));
2936*f169c0eaSGlenn Lagasse 		if (err != 0 && err != ENOENT) {
2937*f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_prep_clone_send_fs: "
2938*f169c0eaSGlenn Lagasse 			    "failed to remove mountpoint from "
2939*f169c0eaSGlenn Lagasse 			    "nvlist\n"));
2940*f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
2941*f169c0eaSGlenn Lagasse 		}
2942*f169c0eaSGlenn Lagasse 	}
2943*f169c0eaSGlenn Lagasse 
2944*f169c0eaSGlenn Lagasse 	/*
2945*f169c0eaSGlenn Lagasse 	 * Set the 'canmount' property
2946*f169c0eaSGlenn Lagasse 	 */
2947*f169c0eaSGlenn Lagasse 	if (nvlist_add_string(bt->nbe_zfs_props,
2948*f169c0eaSGlenn Lagasse 	    zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
2949*f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_prep_clone_send_fs: "
2950*f169c0eaSGlenn Lagasse 		    "internal error: out of memory\n"));
2951*f169c0eaSGlenn Lagasse 		return (BE_ERR_NOMEM);
2952*f169c0eaSGlenn Lagasse 	}
2953*f169c0eaSGlenn Lagasse 
2954*f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
2955*f169c0eaSGlenn Lagasse }
2956*f169c0eaSGlenn Lagasse 
2957*f169c0eaSGlenn Lagasse /*
2958*f169c0eaSGlenn Lagasse  * Function:	be_get_zone_be_name
2959*f169c0eaSGlenn Lagasse  * Description:	This function takes the zones root dataset, the container
2960*f169c0eaSGlenn Lagasse  *		dataset and returns the zones BE name based on the zone
2961*f169c0eaSGlenn Lagasse  *		root dataset.
2962*f169c0eaSGlenn Lagasse  * Parameters:
2963*f169c0eaSGlenn Lagasse  *		root_ds - the zones root dataset.
2964*f169c0eaSGlenn Lagasse  *		container_ds - the container dataset for the zone.
2965*f169c0eaSGlenn Lagasse  * Returns:
2966*f169c0eaSGlenn Lagasse  *		char * - the BE name of this zone based on the root dataset.
2967*f169c0eaSGlenn Lagasse  */
2968*f169c0eaSGlenn Lagasse static char *
2969*f169c0eaSGlenn Lagasse be_get_zone_be_name(char *root_ds, char *container_ds)
2970*f169c0eaSGlenn Lagasse {
2971*f169c0eaSGlenn Lagasse 	return (root_ds + (strlen(container_ds) + 1));
2972*f169c0eaSGlenn Lagasse }
2973*f169c0eaSGlenn Lagasse 
2974*f169c0eaSGlenn Lagasse /*
2975*f169c0eaSGlenn Lagasse  * Function:	be_zone_root_exists_callback
2976*f169c0eaSGlenn Lagasse  * Description:	This callback function is used to determine if a
2977*f169c0eaSGlenn Lagasse  *		zone root container dataset has any children.  It always
2978*f169c0eaSGlenn Lagasse  *		returns 1, signifying a hierarchical child of the zone
2979*f169c0eaSGlenn Lagasse  *		root container dataset has been traversed and therefore
2980*f169c0eaSGlenn Lagasse  *		it has children.
2981*f169c0eaSGlenn Lagasse  * Parameters:
2982*f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current dataset being processed.
2983*f169c0eaSGlenn Lagasse  *		data - not used.
2984*f169c0eaSGlenn Lagasse  * Returns:
2985*f169c0eaSGlenn Lagasse  *		1 - dataset exists
2986*f169c0eaSGlenn Lagasse  * Scope:
2987*f169c0eaSGlenn Lagasse  *		Private
2988*f169c0eaSGlenn Lagasse  */
2989*f169c0eaSGlenn Lagasse static int
2990*f169c0eaSGlenn Lagasse /* LINTED */
2991*f169c0eaSGlenn Lagasse be_zone_root_exists_callback(zfs_handle_t *zhp, void *data)
2992*f169c0eaSGlenn Lagasse {
2993*f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2994*f169c0eaSGlenn Lagasse 	return (1);
2995*f169c0eaSGlenn Lagasse }
2996