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