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