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