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