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