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