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