xref: /illumos-gate/usr/src/lib/libbe/common/be_list.c (revision 8c69cc8fbe729fa7b091e901c4b50508ccc6bb33)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28  * Copyright 2015 Toomas Soome <tsoome@me.com>
29  * Copyright 2015 Gary Mills
30  * Copyright (c) 2016 Martin Matuska. All rights reserved.
31  */
32 
33 #include <assert.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 <strings.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 #include <errno.h>
45 
46 #include <libbe.h>
47 #include <libbe_priv.h>
48 
49 /*
50  * Callback data used for zfs_iter calls.
51  */
52 typedef struct list_callback_data {
53 	char *zpool_name;
54 	char *be_name;
55 	be_node_list_t *be_nodes_head;
56 	be_node_list_t *be_nodes;
57 	char current_be[MAXPATHLEN];
58 } list_callback_data_t;
59 
60 /*
61  * Private function prototypes
62  */
63 static int be_add_children_callback(zfs_handle_t *zhp, void *data);
64 static int be_get_list_callback(zpool_handle_t *, void *);
65 static int be_get_node_data(zfs_handle_t *, be_node_list_t *, char *,
66     const char *, char *, char *);
67 static int be_get_zone_node_data(be_node_list_t *, char *);
68 static int be_get_ds_data(zfs_handle_t *, char *, be_dataset_list_t *,
69     be_node_list_t *);
70 static int be_get_ss_data(zfs_handle_t *, char *, be_snapshot_list_t *,
71     be_node_list_t *);
72 static int be_sort_list(be_node_list_t **,
73     int (*)(const void *, const void *));
74 static int be_qsort_compare_BEs_name(const void *, const void *);
75 static int be_qsort_compare_BEs_name_rev(const void *, const void *);
76 static int be_qsort_compare_BEs_date(const void *, const void *);
77 static int be_qsort_compare_BEs_date_rev(const void *, const void *);
78 static int be_qsort_compare_BEs_space(const void *, const void *);
79 static int be_qsort_compare_BEs_space_rev(const void *, const void *);
80 static int be_qsort_compare_snapshots(const void *x, const void *y);
81 static int be_qsort_compare_datasets(const void *x, const void *y);
82 static void *be_list_alloc(int *, size_t);
83 
84 /*
85  * Private data.
86  */
87 static char be_container_ds[MAXPATHLEN];
88 static boolean_t zone_be = B_FALSE;
89 
90 /* ******************************************************************** */
91 /*			Public Functions				*/
92 /* ******************************************************************** */
93 
94 /*
95  * Function:	be_list
96  * Description:	Calls _be_list which finds all the BEs on the system and
97  *		returns the datasets and snapshots belonging to each BE.
98  *		Also data, such as dataset and snapshot properties,
99  *		for each BE and their snapshots and datasets is
100  *		returned. The data returned is as described in the
101  *		be_dataset_list_t, be_snapshot_list_t and be_node_list_t
102  *		structures.
103  * Parameters:
104  *		be_name - The name of the BE to look up.
105  *			  If NULL a list of all BEs will be returned.
106  *		be_nodes - A reference pointer to the list of BEs. The list
107  *			   structure will be allocated by _be_list and must
108  *			   be freed by a call to be_free_list. If there are no
109  *			   BEs found on the system this reference will be
110  *			   set to NULL.
111  * Return:
112  *		BE_SUCCESS - Success
113  *		be_errno_t - Failure
114  * Scope:
115  *		Public
116  */
117 int
118 be_list(char *be_name, be_node_list_t **be_nodes)
119 {
120 	int	ret = BE_SUCCESS;
121 
122 	/* Initialize libzfs handle */
123 	if (!be_zfs_init())
124 		return (BE_ERR_INIT);
125 
126 	/* Validate be_name if its not NULL */
127 	if (be_name != NULL) {
128 		if (!be_valid_be_name(be_name)) {
129 			be_print_err(gettext("be_list: "
130 			    "invalid BE name %s\n"), be_name);
131 			return (BE_ERR_INVAL);
132 		}
133 	}
134 
135 	ret = _be_list(be_name, be_nodes);
136 
137 	be_zfs_fini();
138 
139 	return (ret);
140 }
141 
142 /*
143  * Function:	be_sort
144  * Description:	Sort BE node list
145  * Parameters:
146  *		pointer to address of list head
147  *		sort order type
148  * Return:
149  *              BE_SUCCESS - Success
150  *              be_errno_t - Failure
151  * Side effect:
152  *		node list sorted by name
153  * Scope:
154  *		Public
155  */
156 int
157 be_sort(be_node_list_t **be_nodes, int order)
158 {
159 	int (*compar)(const void *, const void *) = be_qsort_compare_BEs_date;
160 
161 	if (be_nodes == NULL)
162 		return (BE_ERR_INVAL);
163 
164 	switch (order) {
165 	case BE_SORT_UNSPECIFIED:
166 	case BE_SORT_DATE:
167 		compar = be_qsort_compare_BEs_date;
168 		break;
169 	case BE_SORT_DATE_REV:
170 		compar = be_qsort_compare_BEs_date_rev;
171 		break;
172 	case BE_SORT_NAME:
173 		compar = be_qsort_compare_BEs_name;
174 		break;
175 	case BE_SORT_NAME_REV:
176 		compar = be_qsort_compare_BEs_name_rev;
177 		break;
178 	case BE_SORT_SPACE:
179 		compar = be_qsort_compare_BEs_space;
180 		break;
181 	case BE_SORT_SPACE_REV:
182 		compar = be_qsort_compare_BEs_space_rev;
183 		break;
184 	default:
185 		be_print_err(gettext("be_sort: invalid sort order %d\n"),
186 		    order);
187 		return (BE_ERR_INVAL);
188 	}
189 
190 	return (be_sort_list(be_nodes, compar));
191 }
192 
193 /* ******************************************************************** */
194 /*			Semi-Private Functions				*/
195 /* ******************************************************************** */
196 
197 /*
198  * Function:	_be_list
199  * Description:	This does the actual work described in be_list.
200  * Parameters:
201  *		be_name - The name of the BE to look up.
202  *			  If NULL a list of all BEs will be returned.
203  *		be_nodes - A reference pointer to the list of BEs. The list
204  *			   structure will be allocated here and must
205  *			   be freed by a call to be_free_list. If there are no
206  *			   BEs found on the system this reference will be
207  *			   set to NULL.
208  * Return:
209  *		BE_SUCCESS - Success
210  *		be_errno_t - Failure
211  * Scope:
212  *		Semi-private (library wide use only)
213  */
214 int
215 _be_list(char *be_name, be_node_list_t **be_nodes)
216 {
217 	list_callback_data_t cb = { 0 };
218 	be_transaction_data_t bt = { 0 };
219 	int ret = BE_SUCCESS;
220 	int sret;
221 	zpool_handle_t *zphp;
222 	char *rpool = NULL;
223 	struct be_defaults be_defaults;
224 
225 	if (be_nodes == NULL)
226 		return (BE_ERR_INVAL);
227 
228 	be_get_defaults(&be_defaults);
229 
230 	if (be_find_current_be(&bt) != BE_SUCCESS) {
231 		/*
232 		 * We were unable to find a currently booted BE which
233 		 * probably means that we're not booted in a BE envoronment.
234 		 * None of the BE's will be marked as the active BE.
235 		 */
236 		(void) strcpy(cb.current_be, "-");
237 	} else {
238 		(void) strncpy(cb.current_be, bt.obe_name,
239 		    sizeof (cb.current_be));
240 		rpool = bt.obe_zpool;
241 	}
242 
243 	/*
244 	 * If be_name is NULL we'll look for all BE's on the system.
245 	 * If not then we will only return data for the specified BE.
246 	 */
247 	if (be_name != NULL)
248 		cb.be_name = strdup(be_name);
249 
250 	if (be_defaults.be_deflt_rpool_container && rpool != NULL) {
251 		if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
252 			be_print_err(gettext("be_list: failed to "
253 			    "open rpool (%s): %s\n"), rpool,
254 			    libzfs_error_description(g_zfs));
255 			free(cb.be_name);
256 			return (zfs_err_to_be_err(g_zfs));
257 		}
258 
259 		ret = be_get_list_callback(zphp, &cb);
260 	} else {
261 		if ((zpool_iter(g_zfs, be_get_list_callback, &cb)) != 0) {
262 			if (cb.be_nodes_head != NULL) {
263 				be_free_list(cb.be_nodes_head);
264 				cb.be_nodes_head = NULL;
265 				cb.be_nodes = NULL;
266 			}
267 			ret = BE_ERR_BE_NOENT;
268 		}
269 	}
270 
271 	if (cb.be_nodes_head == NULL) {
272 		if (be_name != NULL)
273 			be_print_err(gettext("be_list: BE (%s) does not "
274 			    "exist\n"), be_name);
275 		else
276 			be_print_err(gettext("be_list: No BE's found\n"));
277 		ret = BE_ERR_BE_NOENT;
278 	}
279 
280 	*be_nodes = cb.be_nodes_head;
281 
282 	free(cb.be_name);
283 
284 	sret = be_sort(be_nodes, BE_SORT_DATE);
285 
286 	return ((ret == BE_SUCCESS) ? sret : ret);
287 }
288 
289 /*
290  * Function:	be_free_list
291  * Description:	Frees up all the data allocated for the list of BEs,
292  *		datasets and snapshots returned by be_list.
293  * Parameters:
294  *		be_node - be_nodes_t structure returned from call to be_list.
295  * Returns:
296  *		none
297  * Scope:
298  *		Semi-private (library wide use only)
299  */
300 void
301 be_free_list(be_node_list_t *be_nodes)
302 {
303 	be_node_list_t *temp_node = NULL;
304 	be_node_list_t *list = be_nodes;
305 
306 	while (list != NULL) {
307 		be_dataset_list_t *datasets = list->be_node_datasets;
308 		be_snapshot_list_t *snapshots = list->be_node_snapshots;
309 
310 		while (datasets != NULL) {
311 			be_dataset_list_t *temp_ds = datasets;
312 			datasets = datasets->be_next_dataset;
313 			free(temp_ds->be_dataset_name);
314 			free(temp_ds->be_ds_mntpt);
315 			free(temp_ds->be_ds_plcy_type);
316 			free(temp_ds);
317 		}
318 
319 		while (snapshots != NULL) {
320 			be_snapshot_list_t *temp_ss = snapshots;
321 			snapshots = snapshots->be_next_snapshot;
322 			free(temp_ss->be_snapshot_name);
323 			free(temp_ss->be_snapshot_type);
324 			free(temp_ss);
325 		}
326 
327 		temp_node = list;
328 		list = list->be_next_node;
329 		free(temp_node->be_node_name);
330 		free(temp_node->be_root_ds);
331 		free(temp_node->be_rpool);
332 		free(temp_node->be_mntpt);
333 		free(temp_node->be_policy_type);
334 		free(temp_node->be_uuid_str);
335 		free(temp_node);
336 	}
337 }
338 
339 /*
340  * Function:	be_get_zone_be_list
341  * Description:	Finds all the BEs for this zone on the system.
342  * Parameters:
343  *		zone_be_name - The name of the BE to look up.
344  *              zone_be_container_ds - The dataset for the zone.
345  *		zbe_nodes - A reference pointer to the list of BEs. The list
346  *			   structure will be allocated here and must
347  *			   be freed by a call to be_free_list. If there are no
348  *			   BEs found on the system this reference will be
349  *			   set to NULL.
350  * Return:
351  *		BE_SUCCESS - Success
352  *		be_errno_t - Failure
353  * Scope:
354  *		Semi-private (library wide use only)
355  */
356 int
357 /* LINTED */
358 be_get_zone_be_list(char *zone_be_name, char *zone_be_container_ds,
359     be_node_list_t **zbe_nodes)
360 {
361 	zfs_handle_t *zhp = NULL;
362 	list_callback_data_t cb = { 0 };
363 	int ret = BE_SUCCESS;
364 
365 	if (zbe_nodes == NULL)
366 		return (BE_ERR_INVAL);
367 
368 	if (!zfs_dataset_exists(g_zfs, zone_be_container_ds,
369 	    ZFS_TYPE_FILESYSTEM)) {
370 		return (BE_ERR_BE_NOENT);
371 	}
372 
373 	zone_be = B_TRUE;
374 
375 	if ((zhp = zfs_open(g_zfs, zone_be_container_ds,
376 	    ZFS_TYPE_FILESYSTEM)) == NULL) {
377 		be_print_err(gettext("be_get_zone_be_list: failed to open "
378 		    "the zone BE dataset %s: %s\n"), zone_be_container_ds,
379 		    libzfs_error_description(g_zfs));
380 		ret = zfs_err_to_be_err(g_zfs);
381 		goto cleanup;
382 	}
383 
384 	(void) strcpy(be_container_ds, zone_be_container_ds);
385 
386 	if (cb.be_nodes_head == NULL) {
387 		if ((cb.be_nodes_head = be_list_alloc(&ret,
388 		    sizeof (be_node_list_t))) == NULL) {
389 			ZFS_CLOSE(zhp);
390 			goto cleanup;
391 		}
392 		cb.be_nodes = cb.be_nodes_head;
393 	}
394 	if (ret == 0)
395 		ret = zfs_iter_filesystems(zhp, be_add_children_callback, &cb);
396 	ZFS_CLOSE(zhp);
397 
398 	*zbe_nodes = cb.be_nodes_head;
399 
400 cleanup:
401 	zone_be = B_FALSE;
402 
403 	return (ret);
404 }
405 
406 /* ******************************************************************** */
407 /*			Private Functions				*/
408 /* ******************************************************************** */
409 
410 /*
411  * Function:	be_get_list_callback
412  * Description:	Callback function used by zfs_iter to look through all
413  *		the pools on the system looking for BEs. If a BE name was
414  *		specified only that BE's information will be collected and
415  *		returned.
416  * Parameters:
417  *		zlp - handle to the first zfs dataset. (provided by the
418  *		      zfs_iter_* call)
419  *		data - pointer to the callback data and where we'll pass
420  *		       the BE information back.
421  * Returns:
422  *		0 - Success
423  *		be_errno_t - Failure
424  * Scope:
425  *		Private
426  */
427 static int
428 be_get_list_callback(zpool_handle_t *zlp, void *data)
429 {
430 	list_callback_data_t *cb = (list_callback_data_t *)data;
431 	char be_ds[MAXPATHLEN];
432 	char *open_ds = NULL;
433 	char *rpool = NULL;
434 	zfs_handle_t *zhp = NULL;
435 	int ret = 0;
436 
437 	cb->zpool_name = rpool =  (char *)zpool_get_name(zlp);
438 
439 	/*
440 	 * Generate string for the BE container dataset
441 	 */
442 	be_make_container_ds(rpool, be_container_ds,
443 	    sizeof (be_container_ds));
444 
445 	/*
446 	 * If a BE name was specified we use it's root dataset in place of
447 	 * the container dataset. This is because we only want to collect
448 	 * the information for the specified BE.
449 	 */
450 	if (cb->be_name != NULL) {
451 		if (!be_valid_be_name(cb->be_name))
452 			return (BE_ERR_INVAL);
453 		/*
454 		 * Generate string for the BE root dataset
455 		 */
456 		be_make_root_ds(rpool, cb->be_name, be_ds, sizeof (be_ds));
457 		open_ds = be_ds;
458 	} else {
459 		open_ds = be_container_ds;
460 	}
461 
462 	/*
463 	 * Check if the dataset exists
464 	 */
465 	if (!zfs_dataset_exists(g_zfs, open_ds,
466 	    ZFS_TYPE_FILESYSTEM)) {
467 		/*
468 		 * The specified dataset does not exist in this pool or
469 		 * there are no valid BE's in this pool. Try the next zpool.
470 		 */
471 		zpool_close(zlp);
472 		return (0);
473 	}
474 
475 	if ((zhp = zfs_open(g_zfs, open_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
476 		be_print_err(gettext("be_get_list_callback: failed to open "
477 		    "the BE dataset %s: %s\n"), open_ds,
478 		    libzfs_error_description(g_zfs));
479 		ret = zfs_err_to_be_err(g_zfs);
480 		zpool_close(zlp);
481 		return (ret);
482 	}
483 
484 	/*
485 	 * If a BE name was specified we iterate through the datasets
486 	 * and snapshots for this BE only. Otherwise we will iterate
487 	 * through the next level of datasets to find all the BE's
488 	 * within the pool
489 	 */
490 	if (cb->be_name != NULL) {
491 		if (cb->be_nodes_head == NULL) {
492 			if ((cb->be_nodes_head = be_list_alloc(&ret,
493 			    sizeof (be_node_list_t))) == NULL) {
494 				ZFS_CLOSE(zhp);
495 				zpool_close(zlp);
496 				return (ret);
497 			}
498 			cb->be_nodes = cb->be_nodes_head;
499 		}
500 
501 		if ((ret = be_get_node_data(zhp, cb->be_nodes, cb->be_name,
502 		    rpool, cb->current_be, be_ds)) != BE_SUCCESS) {
503 			ZFS_CLOSE(zhp);
504 			zpool_close(zlp);
505 			return (ret);
506 		}
507 		ret = zfs_iter_snapshots(zhp, B_FALSE, be_add_children_callback,
508 		    cb);
509 	}
510 
511 	if (ret == 0)
512 		ret = zfs_iter_filesystems(zhp, be_add_children_callback, cb);
513 	ZFS_CLOSE(zhp);
514 
515 	zpool_close(zlp);
516 	return (ret);
517 }
518 
519 /*
520  * Function:	be_add_children_callback
521  * Description:	Callback function used by zfs_iter to look through all
522  *		the datasets and snapshots for each BE and add them to
523  *		the lists of information to be passed back.
524  * Parameters:
525  *		zhp - handle to the first zfs dataset. (provided by the
526  *		      zfs_iter_* call)
527  *		data - pointer to the callback data and where we'll pass
528  *		       the BE information back.
529  * Returns:
530  *		0 - Success
531  *		be_errno_t - Failure
532  * Scope:
533  *		Private
534  */
535 static int
536 be_add_children_callback(zfs_handle_t *zhp, void *data)
537 {
538 	list_callback_data_t	*cb = (list_callback_data_t *)data;
539 	char			*str = NULL, *ds_path = NULL;
540 	int			ret = 0;
541 	struct be_defaults be_defaults;
542 
543 	be_get_defaults(&be_defaults);
544 
545 	ds_path = str = strdup(zfs_get_name(zhp));
546 
547 	/*
548 	 * get past the end of the container dataset plus the trailing "/"
549 	 */
550 	str = str + (strlen(be_container_ds) + 1);
551 	if (be_defaults.be_deflt_rpool_container) {
552 		/* just skip if invalid */
553 		if (!be_valid_be_name(str))
554 			return (BE_SUCCESS);
555 	}
556 
557 	if (cb->be_nodes_head == NULL) {
558 		if ((cb->be_nodes_head = be_list_alloc(&ret,
559 		    sizeof (be_node_list_t))) == NULL) {
560 			ZFS_CLOSE(zhp);
561 			return (ret);
562 		}
563 		cb->be_nodes = cb->be_nodes_head;
564 	}
565 
566 	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && !zone_be) {
567 		be_snapshot_list_t *snapshots = NULL;
568 		if (cb->be_nodes->be_node_snapshots == NULL) {
569 			if ((cb->be_nodes->be_node_snapshots =
570 			    be_list_alloc(&ret, sizeof (be_snapshot_list_t)))
571 			    == NULL || ret != BE_SUCCESS) {
572 				ZFS_CLOSE(zhp);
573 				return (ret);
574 			}
575 			cb->be_nodes->be_node_snapshots->be_next_snapshot =
576 			    NULL;
577 			snapshots = cb->be_nodes->be_node_snapshots;
578 		} else {
579 			for (snapshots = cb->be_nodes->be_node_snapshots;
580 			    snapshots != NULL;
581 			    snapshots = snapshots->be_next_snapshot) {
582 				if (snapshots->be_next_snapshot != NULL)
583 					continue;
584 				/*
585 				 * We're at the end of the list add the
586 				 * new snapshot.
587 				 */
588 				if ((snapshots->be_next_snapshot =
589 				    be_list_alloc(&ret,
590 				    sizeof (be_snapshot_list_t))) == NULL ||
591 				    ret != BE_SUCCESS) {
592 					ZFS_CLOSE(zhp);
593 					return (ret);
594 				}
595 				snapshots = snapshots->be_next_snapshot;
596 				snapshots->be_next_snapshot = NULL;
597 				break;
598 			}
599 		}
600 		if ((ret = be_get_ss_data(zhp, str, snapshots,
601 		    cb->be_nodes)) != BE_SUCCESS) {
602 			ZFS_CLOSE(zhp);
603 			return (ret);
604 		}
605 	} else if (strchr(str, '/') == NULL) {
606 		if (cb->be_nodes->be_node_name != NULL) {
607 			if ((cb->be_nodes->be_next_node =
608 			    be_list_alloc(&ret, sizeof (be_node_list_t))) ==
609 			    NULL || ret != BE_SUCCESS) {
610 				ZFS_CLOSE(zhp);
611 				return (ret);
612 			}
613 			cb->be_nodes = cb->be_nodes->be_next_node;
614 			cb->be_nodes->be_next_node = NULL;
615 		}
616 
617 		/*
618 		 * If this is a zone root dataset then we only need
619 		 * the name of the zone BE at this point. We grab that
620 		 * and return.
621 		 */
622 		if (zone_be) {
623 			ret = be_get_zone_node_data(cb->be_nodes, str);
624 			ZFS_CLOSE(zhp);
625 			return (ret);
626 		}
627 
628 		if ((ret = be_get_node_data(zhp, cb->be_nodes, str,
629 		    cb->zpool_name, cb->current_be, ds_path)) != BE_SUCCESS) {
630 			ZFS_CLOSE(zhp);
631 			return (ret);
632 		}
633 	} else if (strchr(str, '/') != NULL && !zone_be) {
634 		be_dataset_list_t *datasets = NULL;
635 		if (cb->be_nodes->be_node_datasets == NULL) {
636 			if ((cb->be_nodes->be_node_datasets =
637 			    be_list_alloc(&ret, sizeof (be_dataset_list_t)))
638 			    == NULL || ret != BE_SUCCESS) {
639 				ZFS_CLOSE(zhp);
640 				return (ret);
641 			}
642 			cb->be_nodes->be_node_datasets->be_next_dataset = NULL;
643 			datasets = cb->be_nodes->be_node_datasets;
644 		} else {
645 			for (datasets = cb->be_nodes->be_node_datasets;
646 			    datasets != NULL;
647 			    datasets = datasets->be_next_dataset) {
648 				if (datasets->be_next_dataset != NULL)
649 					continue;
650 				/*
651 				 * We're at the end of the list add
652 				 * the new dataset.
653 				 */
654 				if ((datasets->be_next_dataset =
655 				    be_list_alloc(&ret,
656 				    sizeof (be_dataset_list_t)))
657 				    == NULL || ret != BE_SUCCESS) {
658 					ZFS_CLOSE(zhp);
659 					return (ret);
660 				}
661 				datasets = datasets->be_next_dataset;
662 				datasets->be_next_dataset = NULL;
663 				break;
664 			}
665 		}
666 
667 		if ((ret = be_get_ds_data(zhp, str,
668 		    datasets, cb->be_nodes)) != BE_SUCCESS) {
669 			ZFS_CLOSE(zhp);
670 			return (ret);
671 		}
672 	}
673 	ret = zfs_iter_children(zhp, be_add_children_callback, cb);
674 	if (ret != 0) {
675 		be_print_err(gettext("be_add_children_callback: "
676 		    "encountered error: %s\n"),
677 		    libzfs_error_description(g_zfs));
678 		ret = zfs_err_to_be_err(g_zfs);
679 	}
680 	ZFS_CLOSE(zhp);
681 	return (ret);
682 }
683 
684 /*
685  * Function:	be_sort_list
686  * Description:	Sort BE node list
687  * Parameters:
688  *		pointer to address of list head
689  *		compare function
690  * Return:
691  *              BE_SUCCESS - Success
692  *              be_errno_t - Failure
693  * Side effect:
694  *		node list sorted by name
695  * Scope:
696  *		Private
697  */
698 static int
699 be_sort_list(be_node_list_t **pstart, int (*compar)(const void *, const void *))
700 {
701 	int ret = BE_SUCCESS;
702 	size_t ibe, nbe;
703 	be_node_list_t *p = NULL;
704 	be_node_list_t **ptrlist = NULL;
705 	be_node_list_t **ptrtmp;
706 
707 	if (pstart == NULL) /* Nothing to sort */
708 		return (BE_SUCCESS);
709 	/* build array of linked list BE struct pointers */
710 	for (p = *pstart, nbe = 0; p != NULL; nbe++, p = p->be_next_node) {
711 		ptrtmp = realloc(ptrlist,
712 		    sizeof (be_node_list_t *) * (nbe + 2));
713 		if (ptrtmp == NULL) { /* out of memory */
714 			be_print_err(gettext("be_sort_list: memory "
715 			    "allocation failed\n"));
716 			ret = BE_ERR_NOMEM;
717 			goto free;
718 		}
719 		ptrlist = ptrtmp;
720 		ptrlist[nbe] = p;
721 	}
722 	if (nbe == 0) /* Nothing to sort */
723 		return (BE_SUCCESS);
724 	/* in-place list quicksort using qsort(3C) */
725 	if (nbe > 1)	/* no sort if less than 2 BEs */
726 		qsort(ptrlist, nbe, sizeof (be_node_list_t *), compar);
727 
728 	ptrlist[nbe] = NULL; /* add linked list terminator */
729 	*pstart = ptrlist[0]; /* set new linked list header */
730 	/* for each BE in list */
731 	for (ibe = 0; ibe < nbe; ibe++) {
732 		size_t k, ns;	/* subordinate index, count */
733 
734 		/* rewrite list pointer chain, including terminator */
735 		ptrlist[ibe]->be_next_node = ptrlist[ibe + 1];
736 		/* sort subordinate snapshots */
737 		if (ptrlist[ibe]->be_node_num_snapshots > 1) {
738 			const size_t nmax = ptrlist[ibe]->be_node_num_snapshots;
739 			be_snapshot_list_t ** const slist =
740 			    malloc(sizeof (be_snapshot_list_t *) * (nmax + 1));
741 			be_snapshot_list_t *p;
742 
743 			if (slist == NULL) {
744 				ret = BE_ERR_NOMEM;
745 				continue;
746 			}
747 			/* build array of linked list snapshot struct ptrs */
748 			for (ns = 0, p = ptrlist[ibe]->be_node_snapshots;
749 			    ns < nmax && p != NULL;
750 			    ns++, p = p->be_next_snapshot) {
751 				slist[ns] = p;
752 			}
753 			if (ns < 2)
754 				goto end_snapshot;
755 			slist[ns] = NULL; /* add terminator */
756 			/* in-place list quicksort using qsort(3C) */
757 			qsort(slist, ns, sizeof (be_snapshot_list_t *),
758 			    be_qsort_compare_snapshots);
759 			/* rewrite list pointer chain, including terminator */
760 			ptrlist[ibe]->be_node_snapshots = slist[0];
761 			for (k = 0; k < ns; k++)
762 				slist[k]->be_next_snapshot = slist[k + 1];
763 end_snapshot:
764 			free(slist);
765 		}
766 		/* sort subordinate datasets */
767 		if (ptrlist[ibe]->be_node_num_datasets > 1) {
768 			const size_t nmax = ptrlist[ibe]->be_node_num_datasets;
769 			be_dataset_list_t ** const slist =
770 			    malloc(sizeof (be_dataset_list_t *) * (nmax + 1));
771 			be_dataset_list_t *p;
772 
773 			if (slist == NULL) {
774 				ret = BE_ERR_NOMEM;
775 				continue;
776 			}
777 			/* build array of linked list dataset struct ptrs */
778 			for (ns = 0, p = ptrlist[ibe]->be_node_datasets;
779 			    ns < nmax && p != NULL;
780 			    ns++, p = p->be_next_dataset) {
781 				slist[ns] = p;
782 			}
783 			if (ns < 2) /* subordinate datasets < 2 - no sort */
784 				goto end_dataset;
785 			slist[ns] = NULL; /* add terminator */
786 			/* in-place list quicksort using qsort(3C) */
787 			qsort(slist, ns, sizeof (be_dataset_list_t *),
788 			    be_qsort_compare_datasets);
789 			/* rewrite list pointer chain, including terminator */
790 			ptrlist[ibe]->be_node_datasets = slist[0];
791 			for (k = 0; k < ns; k++)
792 				slist[k]->be_next_dataset = slist[k + 1];
793 end_dataset:
794 			free(slist);
795 		}
796 	}
797 free:
798 	free(ptrlist);
799 	return (ret);
800 }
801 
802 /*
803  * Function:	be_qsort_compare_BEs_date
804  * Description:	compare BE creation times for qsort(3C)
805  *		will sort BE list from oldest to most recent
806  * Parameters:
807  *		x,y - BEs with names to compare
808  * Returns:
809  *		positive if x>y, negative if y>x, 0 if equal
810  * Scope:
811  *		Private
812  */
813 static int
814 be_qsort_compare_BEs_date(const void *x, const void *y)
815 {
816 	be_node_list_t *p = *(be_node_list_t **)x;
817 	be_node_list_t *q = *(be_node_list_t **)y;
818 
819 	assert(p != NULL);
820 	assert(q != NULL);
821 
822 	if (p->be_node_creation > q->be_node_creation)
823 		return (1);
824 	if (p->be_node_creation < q->be_node_creation)
825 		return (-1);
826 	return (0);
827 }
828 
829 /*
830  * Function:	be_qsort_compare_BEs_date_rev
831  * Description:	compare BE creation times for qsort(3C)
832  *		will sort BE list from recent to oldest
833  * Parameters:
834  *		x,y - BEs with names to compare
835  * Returns:
836  *		positive if y>x, negative if x>y, 0 if equal
837  * Scope:
838  *		Private
839  */
840 static int
841 be_qsort_compare_BEs_date_rev(const void *x, const void *y)
842 {
843 	return (be_qsort_compare_BEs_date(y, x));
844 }
845 
846 /*
847  * Function:	be_qsort_compare_BEs_name
848  * Description:	lexical compare of BE names for qsort(3C)
849  * Parameters:
850  *		x,y - BEs with names to compare
851  * Returns:
852  *		positive if x>y, negative if y>x, 0 if equal
853  * Scope:
854  *		Private
855  */
856 static int
857 be_qsort_compare_BEs_name(const void *x, const void *y)
858 {
859 	be_node_list_t *p = *(be_node_list_t **)x;
860 	be_node_list_t *q = *(be_node_list_t **)y;
861 
862 	assert(p != NULL);
863 	assert(p->be_node_name != NULL);
864 	assert(q != NULL);
865 	assert(q->be_node_name != NULL);
866 
867 	return (strcmp(p->be_node_name, q->be_node_name));
868 }
869 
870 /*
871  * Function:	be_qsort_compare_BEs_name_rev
872  * Description:	reverse lexical compare of BE names for qsort(3C)
873  * Parameters:
874  *		x,y - BEs with names to compare
875  * Returns:
876  *		positive if y>x, negative if x>y, 0 if equal
877  * Scope:
878  *		Private
879  */
880 static int
881 be_qsort_compare_BEs_name_rev(const void *x, const void *y)
882 {
883 	return (be_qsort_compare_BEs_name(y, x));
884 }
885 
886 /*
887  * Function:	be_qsort_compare_BEs_space
888  * Description:	compare BE sizes for qsort(3C)
889  *		will sort BE list in growing order
890  * Parameters:
891  *		x,y - BEs with names to compare
892  * Returns:
893  *		positive if x>y, negative if y>x, 0 if equal
894  * Scope:
895  *		Private
896  */
897 static int
898 be_qsort_compare_BEs_space(const void *x, const void *y)
899 {
900 	be_node_list_t *p = *(be_node_list_t **)x;
901 	be_node_list_t *q = *(be_node_list_t **)y;
902 
903 	assert(p != NULL);
904 	assert(q != NULL);
905 
906 	if (p->be_space_used > q->be_space_used)
907 		return (1);
908 	if (p->be_space_used < q->be_space_used)
909 		return (-1);
910 	return (0);
911 }
912 
913 /*
914  * Function:	be_qsort_compare_BEs_space_rev
915  * Description:	compare BE sizes for qsort(3C)
916  *		will sort BE list in shrinking
917  * Parameters:
918  *		x,y - BEs with names to compare
919  * Returns:
920  *		positive if y>x, negative if x>y, 0 if equal
921  * Scope:
922  *		Private
923  */
924 static int
925 be_qsort_compare_BEs_space_rev(const void *x, const void *y)
926 {
927 	return (be_qsort_compare_BEs_space(y, x));
928 }
929 
930 /*
931  * Function:	be_qsort_compare_snapshots
932  * Description:	lexical compare of BE names for qsort(3C)
933  * Parameters:
934  *		x,y - BE snapshots with names to compare
935  * Returns:
936  *		positive if y>x, negative if x>y, 0 if equal
937  * Scope:
938  *		Private
939  */
940 static int
941 be_qsort_compare_snapshots(const void *x, const void *y)
942 {
943 	be_snapshot_list_t *p = *(be_snapshot_list_t **)x;
944 	be_snapshot_list_t *q = *(be_snapshot_list_t **)y;
945 
946 	if (p == NULL || p->be_snapshot_name == NULL)
947 		return (1);
948 	if (q == NULL || q->be_snapshot_name == NULL)
949 		return (-1);
950 	return (strcmp(p->be_snapshot_name, q->be_snapshot_name));
951 }
952 
953 /*
954  * Function:	be_qsort_compare_datasets
955  * Description:	lexical compare of dataset names for qsort(3C)
956  * Parameters:
957  *		x,y - BE snapshots with names to compare
958  * Returns:
959  *		positive if y>x, negative if x>y, 0 if equal
960  * Scope:
961  *		Private
962  */
963 static int
964 be_qsort_compare_datasets(const void *x, const void *y)
965 {
966 	be_dataset_list_t *p = *(be_dataset_list_t **)x;
967 	be_dataset_list_t *q = *(be_dataset_list_t **)y;
968 
969 	if (p == NULL || p->be_dataset_name == NULL)
970 		return (1);
971 	if (q == NULL || q->be_dataset_name == NULL)
972 		return (-1);
973 	return (strcmp(p->be_dataset_name, q->be_dataset_name));
974 }
975 
976 /*
977  * Function:	be_get_node_data
978  * Description:	Helper function used to collect all the information to fill
979  *		in the be_node_list structure to be returned by be_list.
980  * Parameters:
981  *		zhp - Handle to the root dataset for the BE whose information
982  *		      we're collecting.
983  *		be_node - a pointer to the node structure we're filling in.
984  *		be_name - The BE name of the node whose information we're
985  *		          collecting.
986  *		current_be - the name of the currently active BE.
987  *		be_ds - The dataset name for the BE.
988  *
989  * Returns:
990  *		BE_SUCCESS - Success
991  *		be_errno_t - Failure
992  * Scope:
993  *		Private
994  */
995 static int
996 be_get_node_data(
997 	zfs_handle_t *zhp,
998 	be_node_list_t *be_node,
999 	char *be_name,
1000 	const char *rpool,
1001 	char *current_be,
1002 	char *be_ds)
1003 {
1004 	char prop_buf[MAXPATHLEN];
1005 	nvlist_t *userprops = NULL;
1006 	nvlist_t *propval = NULL;
1007 	nvlist_t *zone_propval = NULL;
1008 	char *prop_str = NULL;
1009 	char *zone_prop_str = NULL;
1010 	char *grub_default_bootfs = NULL;
1011 	zpool_handle_t *zphp = NULL;
1012 	int err = 0;
1013 
1014 	if (be_node == NULL || be_name == NULL || current_be == NULL ||
1015 	    be_ds == NULL) {
1016 		be_print_err(gettext("be_get_node_data: invalid arguments, "
1017 		    "can not be NULL\n"));
1018 		return (BE_ERR_INVAL);
1019 	}
1020 
1021 	errno = 0;
1022 
1023 	be_node->be_root_ds = strdup(be_ds);
1024 	if ((err = errno) != 0 || be_node->be_root_ds == NULL) {
1025 		be_print_err(gettext("be_get_node_data: failed to "
1026 		    "copy root dataset name\n"));
1027 		return (errno_to_be_err(err));
1028 	}
1029 
1030 	be_node->be_node_name = strdup(be_name);
1031 	if ((err = errno) != 0 || be_node->be_node_name == NULL) {
1032 		be_print_err(gettext("be_get_node_data: failed to "
1033 		    "copy BE name\n"));
1034 		return (errno_to_be_err(err));
1035 	}
1036 	if (strncmp(be_name, current_be, MAXPATHLEN) == 0)
1037 		be_node->be_active = B_TRUE;
1038 	else
1039 		be_node->be_active = B_FALSE;
1040 
1041 	be_node->be_rpool = strdup(rpool);
1042 	if (be_node->be_rpool == NULL || (err = errno) != 0) {
1043 		be_print_err(gettext("be_get_node_data: failed to "
1044 		    "copy root pool name\n"));
1045 		return (errno_to_be_err(err));
1046 	}
1047 
1048 	be_node->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED);
1049 
1050 	if (getzoneid() == GLOBAL_ZONEID) {
1051 		if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
1052 			be_print_err(gettext("be_get_node_data: failed to open "
1053 			    "pool (%s): %s\n"), rpool,
1054 			    libzfs_error_description(g_zfs));
1055 			return (zfs_err_to_be_err(g_zfs));
1056 		}
1057 
1058 		(void) zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf,
1059 		    ZFS_MAXPROPLEN, NULL, B_FALSE);
1060 		if (be_has_grub() && (be_default_grub_bootfs(rpool,
1061 		    &grub_default_bootfs) == BE_SUCCESS) &&
1062 		    grub_default_bootfs != NULL)
1063 			if (strcmp(grub_default_bootfs, be_ds) == 0)
1064 				be_node->be_active_on_boot = B_TRUE;
1065 			else
1066 				be_node->be_active_on_boot = B_FALSE;
1067 		else if (strcmp(prop_buf, be_ds) == 0)
1068 			be_node->be_active_on_boot = B_TRUE;
1069 		else
1070 			be_node->be_active_on_boot = B_FALSE;
1071 
1072 		be_node->be_global_active = B_TRUE;
1073 
1074 		free(grub_default_bootfs);
1075 		zpool_close(zphp);
1076 	} else {
1077 		if (be_zone_compare_uuids(be_node->be_root_ds))
1078 			be_node->be_global_active = B_TRUE;
1079 		else
1080 			be_node->be_global_active = B_FALSE;
1081 	}
1082 
1083 	/*
1084 	 * If the dataset is mounted use the mount point
1085 	 * returned from the zfs_is_mounted call. If the
1086 	 * dataset is not mounted then pull the mount
1087 	 * point information out of the zfs properties.
1088 	 */
1089 	be_node->be_mounted = zfs_is_mounted(zhp,
1090 	    &(be_node->be_mntpt));
1091 	if (!be_node->be_mounted) {
1092 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
1093 		    ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) == 0)
1094 			be_node->be_mntpt = strdup(prop_buf);
1095 		else
1096 			return (zfs_err_to_be_err(g_zfs));
1097 	}
1098 
1099 	be_node->be_node_creation = (time_t)zfs_prop_get_int(zhp,
1100 	    ZFS_PROP_CREATION);
1101 
1102 	/* Get all user properties used for libbe */
1103 	if ((userprops = zfs_get_user_props(zhp)) == NULL) {
1104 		be_node->be_policy_type = strdup(be_default_policy());
1105 	} else {
1106 		if (getzoneid() != GLOBAL_ZONEID) {
1107 			if (nvlist_lookup_nvlist(userprops,
1108 			    BE_ZONE_ACTIVE_PROPERTY, &zone_propval) != 0 ||
1109 			    zone_propval == NULL) {
1110 				be_node->be_active_on_boot = B_FALSE;
1111 			} else {
1112 				verify(nvlist_lookup_string(zone_propval,
1113 				    ZPROP_VALUE, &zone_prop_str) == 0);
1114 				if (strcmp(zone_prop_str, "on") == 0) {
1115 					be_node->be_active_on_boot = B_TRUE;
1116 				} else {
1117 					be_node->be_active_on_boot = B_FALSE;
1118 				}
1119 			}
1120 		}
1121 
1122 		if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
1123 		    &propval) != 0 || propval == NULL) {
1124 			be_node->be_policy_type =
1125 			    strdup(be_default_policy());
1126 		} else {
1127 			verify(nvlist_lookup_string(propval, ZPROP_VALUE,
1128 			    &prop_str) == 0);
1129 			if (prop_str == NULL || strcmp(prop_str, "-") == 0 ||
1130 			    strcmp(prop_str, "") == 0)
1131 				be_node->be_policy_type =
1132 				    strdup(be_default_policy());
1133 			else
1134 				be_node->be_policy_type = strdup(prop_str);
1135 		}
1136 		if (getzoneid() != GLOBAL_ZONEID) {
1137 			if (nvlist_lookup_nvlist(userprops,
1138 			    BE_ZONE_PARENTBE_PROPERTY, &propval) != 0 &&
1139 			    nvlist_lookup_string(propval, ZPROP_VALUE,
1140 			    &prop_str) == 0) {
1141 				be_node->be_uuid_str = strdup(prop_str);
1142 			}
1143 		} else {
1144 			if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY,
1145 			    &propval) == 0 && nvlist_lookup_string(propval,
1146 			    ZPROP_VALUE, &prop_str) == 0) {
1147 				be_node->be_uuid_str = strdup(prop_str);
1148 			}
1149 		}
1150 	}
1151 
1152 	/*
1153 	 * Increment the dataset counter to include the root dataset
1154 	 * of the BE.
1155 	 */
1156 	be_node->be_node_num_datasets++;
1157 
1158 	return (BE_SUCCESS);
1159 }
1160 
1161 /*
1162  * Function:	be_get_ds_data
1163  * Description:	Helper function used by be_add_children_callback to collect
1164  *		the dataset related information that will be returned by
1165  *		be_list.
1166  * Parameters:
1167  *		zhp - Handle to the zfs dataset whose information we're
1168  *		      collecting.
1169  *		name - The name of the dataset we're processing.
1170  *		dataset - A pointer to the be_dataset_list structure
1171  *			  we're filling in.
1172  *		node - The node structure that this dataset belongs to.
1173  * Return:
1174  *		BE_SUCCESS - Success
1175  *		be_errno_t - Failure
1176  * Scope:
1177  *		Private
1178  */
1179 static int
1180 be_get_ds_data(
1181 	zfs_handle_t *zfshp,
1182 	char *name,
1183 	be_dataset_list_t *dataset,
1184 	be_node_list_t *node)
1185 {
1186 	char			prop_buf[ZFS_MAXPROPLEN];
1187 	nvlist_t		*propval = NULL;
1188 	nvlist_t		*userprops = NULL;
1189 	char			*prop_str = NULL;
1190 	int			err = 0;
1191 
1192 	if (zfshp == NULL || name == NULL || dataset == NULL || node == NULL) {
1193 		be_print_err(gettext("be_get_ds_data: invalid arguments, "
1194 		    "can not be NULL\n"));
1195 		return (BE_ERR_INVAL);
1196 	}
1197 
1198 	errno = 0;
1199 
1200 	dataset->be_dataset_name = strdup(name);
1201 	if ((err = errno) != 0) {
1202 		be_print_err(gettext("be_get_ds_data: failed to copy "
1203 		    "dataset name\n"));
1204 		return (errno_to_be_err(err));
1205 	}
1206 
1207 	dataset->be_ds_space_used = zfs_prop_get_int(zfshp, ZFS_PROP_USED);
1208 
1209 	/*
1210 	 * If the dataset is mounted use the mount point
1211 	 * returned from the zfs_is_mounted call. If the
1212 	 * dataset is not mounted then pull the mount
1213 	 * point information out of the zfs properties.
1214 	 */
1215 	if (!(dataset->be_ds_mounted = zfs_is_mounted(zfshp,
1216 	    &(dataset->be_ds_mntpt)))) {
1217 		if (zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
1218 		    prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
1219 		    B_FALSE) == 0)
1220 			dataset->be_ds_mntpt = strdup(prop_buf);
1221 		else
1222 			return (zfs_err_to_be_err(g_zfs));
1223 	}
1224 	dataset->be_ds_creation =
1225 	    (time_t)zfs_prop_get_int(zfshp, ZFS_PROP_CREATION);
1226 
1227 	/*
1228 	 * Get the user property used for the libbe
1229 	 * cleaup policy
1230 	 */
1231 	if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
1232 		dataset->be_ds_plcy_type =
1233 		    strdup(node->be_policy_type);
1234 	} else {
1235 		if (nvlist_lookup_nvlist(userprops,
1236 		    BE_POLICY_PROPERTY, &propval) != 0 ||
1237 		    propval == NULL) {
1238 			dataset->be_ds_plcy_type =
1239 			    strdup(node->be_policy_type);
1240 		} else {
1241 			verify(nvlist_lookup_string(propval,
1242 			    ZPROP_VALUE, &prop_str) == 0);
1243 			if (prop_str == NULL ||
1244 			    strcmp(prop_str, "-") == 0 ||
1245 			    strcmp(prop_str, "") == 0)
1246 				dataset->be_ds_plcy_type
1247 				    = strdup(node->be_policy_type);
1248 			else
1249 				dataset->be_ds_plcy_type = strdup(prop_str);
1250 		}
1251 	}
1252 
1253 	node->be_node_num_datasets++;
1254 	return (BE_SUCCESS);
1255 }
1256 
1257 /*
1258  * Function:	be_get_ss_data
1259  * Description: Helper function used by be_add_children_callback to collect
1260  *		the dataset related information that will be returned by
1261  *		be_list.
1262  * Parameters:
1263  *		zhp - Handle to the zfs snapshot whose information we're
1264  *		      collecting.
1265  *		name - The name of the snapshot we're processing.
1266  *		shapshot - A pointer to the be_snapshot_list structure
1267  *			   we're filling in.
1268  *		node - The node structure that this snapshot belongs to.
1269  * Returns:
1270  *		BE_SUCCESS - Success
1271  *		be_errno_t - Failure
1272  * Scope:
1273  *		Private
1274  */
1275 static int
1276 be_get_ss_data(
1277 	zfs_handle_t *zfshp,
1278 	char *name,
1279 	be_snapshot_list_t *snapshot,
1280 	be_node_list_t *node)
1281 {
1282 	nvlist_t	*propval = NULL;
1283 	nvlist_t	*userprops = NULL;
1284 	char		*prop_str = NULL;
1285 	int		err = 0;
1286 
1287 	if (zfshp == NULL || name == NULL || snapshot == NULL || node == NULL) {
1288 		be_print_err(gettext("be_get_ss_data: invalid arguments, "
1289 		    "can not be NULL\n"));
1290 		return (BE_ERR_INVAL);
1291 	}
1292 
1293 	errno = 0;
1294 
1295 	snapshot->be_snapshot_name = strdup(name);
1296 	if ((err = errno) != 0) {
1297 		be_print_err(gettext("be_get_ss_data: failed to copy name\n"));
1298 		return (errno_to_be_err(err));
1299 	}
1300 
1301 	snapshot->be_snapshot_creation = (time_t)zfs_prop_get_int(zfshp,
1302 	    ZFS_PROP_CREATION);
1303 
1304 	/*
1305 	 * Try to get this snapshot's cleanup policy from its
1306 	 * user properties first.  If not there, use default
1307 	 * cleanup policy.
1308 	 */
1309 	if ((userprops = zfs_get_user_props(zfshp)) != NULL &&
1310 	    nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
1311 	    &propval) == 0 && nvlist_lookup_string(propval,
1312 	    ZPROP_VALUE, &prop_str) == 0) {
1313 		snapshot->be_snapshot_type =
1314 		    strdup(prop_str);
1315 	} else {
1316 		snapshot->be_snapshot_type =
1317 		    strdup(be_default_policy());
1318 	}
1319 
1320 	snapshot->be_snapshot_space_used = zfs_prop_get_int(zfshp,
1321 	    ZFS_PROP_USED);
1322 
1323 	node->be_node_num_snapshots++;
1324 	return (BE_SUCCESS);
1325 }
1326 
1327 /*
1328  * Function:	be_list_alloc
1329  * Description: Helper function used to allocate memory for the various
1330  *		sructures that make up a BE node.
1331  * Parameters:
1332  *		err - Used to return any errors encountered.
1333  *			BE_SUCCESS - Success
1334  *			BE_ERR_NOMEM - Allocation failure
1335  *		size - The size of memory to allocate.
1336  * Returns:
1337  *		Success - A pointer to the allocated memory
1338  * 		Failure - NULL
1339  * Scope:
1340  *		Private
1341  */
1342 static void*
1343 be_list_alloc(int *err, size_t size)
1344 {
1345 	void *bep = NULL;
1346 
1347 	bep = calloc(1, size);
1348 	if (bep == NULL) {
1349 		be_print_err(gettext("be_list_alloc: memory "
1350 		    "allocation failed\n"));
1351 		*err = BE_ERR_NOMEM;
1352 	}
1353 	*err = BE_SUCCESS;
1354 	return (bep);
1355 }
1356 
1357 /*
1358  * Function:	be_get_zone_node_data
1359  * Description:	Helper function used to collect all the information to
1360  *		fill in the be_node_list structure to be returned by
1361  *              be_get_zone_list.
1362  * Parameters:
1363  *		be_node - a pointer to the node structure we're filling in.
1364  *		be_name - The BE name of the node whose information we're
1365  * Returns:
1366  *		BE_SUCCESS - Success
1367  *		be_errno_t - Failure
1368  * Scope:
1369  *		Private
1370  *
1371  * NOTE: This function currently only collects the zone BE name but when
1372  *       support for beadm/libbe in a zone is provided it will need to fill
1373  *       in the rest of the information needed for a zone BE.
1374  */
1375 static int
1376 be_get_zone_node_data(be_node_list_t *be_node, char *be_name)
1377 {
1378 	if ((be_node->be_node_name = strdup(be_name)) != NULL)
1379 		return (BE_SUCCESS);
1380 	return (BE_ERR_NOMEM);
1381 }
1382