xref: /illumos-gate/usr/src/lib/libbe/common/be_list.c (revision dcbf3bd6a1f1360fc1afcee9e22c6dcff7844bf2)
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 be_get_zone_be_list(
358 /* LINTED */
359 	char *zone_be_name,
360 	char *zone_be_container_ds,
361 	be_node_list_t **zbe_nodes)
362 {
363 	zfs_handle_t *zhp = NULL;
364 	list_callback_data_t cb = { 0 };
365 	int ret = BE_SUCCESS;
366 
367 	if (zbe_nodes == NULL)
368 		return (BE_ERR_INVAL);
369 
370 	if (!zfs_dataset_exists(g_zfs, zone_be_container_ds,
371 	    ZFS_TYPE_FILESYSTEM)) {
372 		return (BE_ERR_BE_NOENT);
373 	}
374 
375 	zone_be = B_TRUE;
376 
377 	if ((zhp = zfs_open(g_zfs, zone_be_container_ds,
378 	    ZFS_TYPE_FILESYSTEM)) == NULL) {
379 		be_print_err(gettext("be_get_zone_be_list: failed to open "
380 		    "the zone BE dataset %s: %s\n"), zone_be_container_ds,
381 		    libzfs_error_description(g_zfs));
382 		ret = zfs_err_to_be_err(g_zfs);
383 		goto cleanup;
384 	}
385 
386 	(void) strcpy(be_container_ds, zone_be_container_ds);
387 
388 	if (cb.be_nodes_head == NULL) {
389 		if ((cb.be_nodes_head = be_list_alloc(&ret,
390 		    sizeof (be_node_list_t))) == NULL) {
391 			ZFS_CLOSE(zhp);
392 			goto cleanup;
393 		}
394 		cb.be_nodes = cb.be_nodes_head;
395 	}
396 	if (ret == 0)
397 		ret = zfs_iter_filesystems(zhp, be_add_children_callback, &cb);
398 	ZFS_CLOSE(zhp);
399 
400 	*zbe_nodes = cb.be_nodes_head;
401 
402 cleanup:
403 	zone_be = B_FALSE;
404 
405 	return (ret);
406 }
407 
408 /* ******************************************************************** */
409 /*			Private Functions				*/
410 /* ******************************************************************** */
411 
412 /*
413  * Function:	be_get_list_callback
414  * Description:	Callback function used by zfs_iter to look through all
415  *		the pools on the system looking for BEs. If a BE name was
416  *		specified only that BE's information will be collected and
417  *		returned.
418  * Parameters:
419  *		zlp - handle to the first zfs dataset. (provided by the
420  *		      zfs_iter_* call)
421  *		data - pointer to the callback data and where we'll pass
422  *		       the BE information back.
423  * Returns:
424  *		0 - Success
425  *		be_errno_t - Failure
426  * Scope:
427  *		Private
428  */
429 static int
430 be_get_list_callback(zpool_handle_t *zlp, void *data)
431 {
432 	list_callback_data_t *cb = (list_callback_data_t *)data;
433 	char be_ds[MAXPATHLEN];
434 	char *open_ds = NULL;
435 	char *rpool = NULL;
436 	zfs_handle_t *zhp = NULL;
437 	int ret = 0;
438 
439 	cb->zpool_name = rpool =  (char *)zpool_get_name(zlp);
440 
441 	/*
442 	 * Generate string for the BE container dataset
443 	 */
444 	be_make_container_ds(rpool, be_container_ds,
445 	    sizeof (be_container_ds));
446 
447 	/*
448 	 * If a BE name was specified we use it's root dataset in place of
449 	 * the container dataset. This is because we only want to collect
450 	 * the information for the specified BE.
451 	 */
452 	if (cb->be_name != NULL) {
453 		if (!be_valid_be_name(cb->be_name))
454 			return (BE_ERR_INVAL);
455 		/*
456 		 * Generate string for the BE root dataset
457 		 */
458 		be_make_root_ds(rpool, cb->be_name, be_ds, sizeof (be_ds));
459 		open_ds = be_ds;
460 	} else {
461 		open_ds = be_container_ds;
462 	}
463 
464 	/*
465 	 * Check if the dataset exists
466 	 */
467 	if (!zfs_dataset_exists(g_zfs, open_ds,
468 	    ZFS_TYPE_FILESYSTEM)) {
469 		/*
470 		 * The specified dataset does not exist in this pool or
471 		 * there are no valid BE's in this pool. Try the next zpool.
472 		 */
473 		zpool_close(zlp);
474 		return (0);
475 	}
476 
477 	if ((zhp = zfs_open(g_zfs, open_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
478 		be_print_err(gettext("be_get_list_callback: failed to open "
479 		    "the BE dataset %s: %s\n"), open_ds,
480 		    libzfs_error_description(g_zfs));
481 		ret = zfs_err_to_be_err(g_zfs);
482 		zpool_close(zlp);
483 		return (ret);
484 	}
485 
486 	/*
487 	 * If a BE name was specified we iterate through the datasets
488 	 * and snapshots for this BE only. Otherwise we will iterate
489 	 * through the next level of datasets to find all the BE's
490 	 * within the pool
491 	 */
492 	if (cb->be_name != NULL) {
493 		if (cb->be_nodes_head == NULL) {
494 			if ((cb->be_nodes_head = be_list_alloc(&ret,
495 			    sizeof (be_node_list_t))) == NULL) {
496 				ZFS_CLOSE(zhp);
497 				zpool_close(zlp);
498 				return (ret);
499 			}
500 			cb->be_nodes = cb->be_nodes_head;
501 		}
502 
503 		if ((ret = be_get_node_data(zhp, cb->be_nodes, cb->be_name,
504 		    rpool, cb->current_be, be_ds)) != BE_SUCCESS) {
505 			ZFS_CLOSE(zhp);
506 			zpool_close(zlp);
507 			return (ret);
508 		}
509 		ret = zfs_iter_snapshots(zhp, B_FALSE, be_add_children_callback,
510 		    cb);
511 	}
512 
513 	if (ret == 0)
514 		ret = zfs_iter_filesystems(zhp, be_add_children_callback, cb);
515 	ZFS_CLOSE(zhp);
516 
517 	zpool_close(zlp);
518 	return (ret);
519 }
520 
521 /*
522  * Function:	be_add_children_callback
523  * Description:	Callback function used by zfs_iter to look through all
524  *		the datasets and snapshots for each BE and add them to
525  *		the lists of information to be passed back.
526  * Parameters:
527  *		zhp - handle to the first zfs dataset. (provided by the
528  *		      zfs_iter_* call)
529  *		data - pointer to the callback data and where we'll pass
530  *		       the BE information back.
531  * Returns:
532  *		0 - Success
533  *		be_errno_t - Failure
534  * Scope:
535  *		Private
536  */
537 static int
538 be_add_children_callback(zfs_handle_t *zhp, void *data)
539 {
540 	list_callback_data_t	*cb = (list_callback_data_t *)data;
541 	char			*str = NULL, *ds_path = NULL;
542 	int			ret = 0;
543 	struct be_defaults be_defaults;
544 
545 	be_get_defaults(&be_defaults);
546 
547 	ds_path = str = strdup(zfs_get_name(zhp));
548 
549 	/*
550 	 * get past the end of the container dataset plus the trailing "/"
551 	 */
552 	str = str + (strlen(be_container_ds) + 1);
553 	if (be_defaults.be_deflt_rpool_container) {
554 		/* just skip if invalid */
555 		if (!be_valid_be_name(str))
556 			return (BE_SUCCESS);
557 	}
558 
559 	if (cb->be_nodes_head == NULL) {
560 		if ((cb->be_nodes_head = be_list_alloc(&ret,
561 		    sizeof (be_node_list_t))) == NULL) {
562 			ZFS_CLOSE(zhp);
563 			return (ret);
564 		}
565 		cb->be_nodes = cb->be_nodes_head;
566 	}
567 
568 	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && !zone_be) {
569 		be_snapshot_list_t *snapshots = NULL;
570 		if (cb->be_nodes->be_node_snapshots == NULL) {
571 			if ((cb->be_nodes->be_node_snapshots =
572 			    be_list_alloc(&ret, sizeof (be_snapshot_list_t)))
573 			    == NULL || ret != BE_SUCCESS) {
574 				ZFS_CLOSE(zhp);
575 				return (ret);
576 			}
577 			cb->be_nodes->be_node_snapshots->be_next_snapshot =
578 			    NULL;
579 			snapshots = cb->be_nodes->be_node_snapshots;
580 		} else {
581 			for (snapshots = cb->be_nodes->be_node_snapshots;
582 			    snapshots != NULL;
583 			    snapshots = snapshots->be_next_snapshot) {
584 				if (snapshots->be_next_snapshot != NULL)
585 					continue;
586 				/*
587 				 * We're at the end of the list add the
588 				 * new snapshot.
589 				 */
590 				if ((snapshots->be_next_snapshot =
591 				    be_list_alloc(&ret,
592 				    sizeof (be_snapshot_list_t))) == NULL ||
593 				    ret != BE_SUCCESS) {
594 					ZFS_CLOSE(zhp);
595 					return (ret);
596 				}
597 				snapshots = snapshots->be_next_snapshot;
598 				snapshots->be_next_snapshot = NULL;
599 				break;
600 			}
601 		}
602 		if ((ret = be_get_ss_data(zhp, str, snapshots,
603 		    cb->be_nodes)) != BE_SUCCESS) {
604 			ZFS_CLOSE(zhp);
605 			return (ret);
606 		}
607 	} else if (strchr(str, '/') == NULL) {
608 		if (cb->be_nodes->be_node_name != NULL) {
609 			if ((cb->be_nodes->be_next_node =
610 			    be_list_alloc(&ret, sizeof (be_node_list_t))) ==
611 			    NULL || ret != BE_SUCCESS) {
612 				ZFS_CLOSE(zhp);
613 				return (ret);
614 			}
615 			cb->be_nodes = cb->be_nodes->be_next_node;
616 			cb->be_nodes->be_next_node = NULL;
617 		}
618 
619 		/*
620 		 * If this is a zone root dataset then we only need
621 		 * the name of the zone BE at this point. We grab that
622 		 * and return.
623 		 */
624 		if (zone_be) {
625 			ret = be_get_zone_node_data(cb->be_nodes, str);
626 			ZFS_CLOSE(zhp);
627 			return (ret);
628 		}
629 
630 		if ((ret = be_get_node_data(zhp, cb->be_nodes, str,
631 		    cb->zpool_name, cb->current_be, ds_path)) != BE_SUCCESS) {
632 			ZFS_CLOSE(zhp);
633 			return (ret);
634 		}
635 	} else if (strchr(str, '/') != NULL && !zone_be) {
636 		be_dataset_list_t *datasets = NULL;
637 		if (cb->be_nodes->be_node_datasets == NULL) {
638 			if ((cb->be_nodes->be_node_datasets =
639 			    be_list_alloc(&ret, sizeof (be_dataset_list_t)))
640 			    == NULL || ret != BE_SUCCESS) {
641 				ZFS_CLOSE(zhp);
642 				return (ret);
643 			}
644 			cb->be_nodes->be_node_datasets->be_next_dataset = NULL;
645 			datasets = cb->be_nodes->be_node_datasets;
646 		} else {
647 			for (datasets = cb->be_nodes->be_node_datasets;
648 			    datasets != NULL;
649 			    datasets = datasets->be_next_dataset) {
650 				if (datasets->be_next_dataset != NULL)
651 					continue;
652 				/*
653 				 * We're at the end of the list add
654 				 * the new dataset.
655 				 */
656 				if ((datasets->be_next_dataset =
657 				    be_list_alloc(&ret,
658 				    sizeof (be_dataset_list_t)))
659 				    == NULL || ret != BE_SUCCESS) {
660 					ZFS_CLOSE(zhp);
661 					return (ret);
662 				}
663 				datasets = datasets->be_next_dataset;
664 				datasets->be_next_dataset = NULL;
665 				break;
666 			}
667 		}
668 
669 		if ((ret = be_get_ds_data(zhp, str,
670 		    datasets, cb->be_nodes)) != BE_SUCCESS) {
671 			ZFS_CLOSE(zhp);
672 			return (ret);
673 		}
674 	}
675 	ret = zfs_iter_children(zhp, be_add_children_callback, cb);
676 	if (ret != 0) {
677 		be_print_err(gettext("be_add_children_callback: "
678 		    "encountered error: %s\n"),
679 		    libzfs_error_description(g_zfs));
680 		ret = zfs_err_to_be_err(g_zfs);
681 	}
682 	ZFS_CLOSE(zhp);
683 	return (ret);
684 }
685 
686 /*
687  * Function:	be_sort_list
688  * Description:	Sort BE node list
689  * Parameters:
690  *		pointer to address of list head
691  *		compare function
692  * Return:
693  *              BE_SUCCESS - Success
694  *              be_errno_t - Failure
695  * Side effect:
696  *		node list sorted by name
697  * Scope:
698  *		Private
699  */
700 static int
701 be_sort_list(be_node_list_t **pstart, int (*compar)(const void *, const void *))
702 {
703 	int ret = BE_SUCCESS;
704 	size_t ibe, nbe;
705 	be_node_list_t *p = NULL;
706 	be_node_list_t **ptrlist = NULL;
707 	be_node_list_t **ptrtmp;
708 
709 	if (pstart == NULL) /* Nothing to sort */
710 		return (BE_SUCCESS);
711 	/* build array of linked list BE struct pointers */
712 	for (p = *pstart, nbe = 0; p != NULL; nbe++, p = p->be_next_node) {
713 		ptrtmp = realloc(ptrlist,
714 		    sizeof (be_node_list_t *) * (nbe + 2));
715 		if (ptrtmp == NULL) { /* out of memory */
716 			be_print_err(gettext("be_sort_list: memory "
717 			    "allocation failed\n"));
718 			ret = BE_ERR_NOMEM;
719 			goto free;
720 		}
721 		ptrlist = ptrtmp;
722 		ptrlist[nbe] = p;
723 	}
724 	if (nbe == 0) /* Nothing to sort */
725 		return (BE_SUCCESS);
726 	/* in-place list quicksort using qsort(3C) */
727 	if (nbe > 1)	/* no sort if less than 2 BEs */
728 		qsort(ptrlist, nbe, sizeof (be_node_list_t *), compar);
729 
730 	ptrlist[nbe] = NULL; /* add linked list terminator */
731 	*pstart = ptrlist[0]; /* set new linked list header */
732 	/* for each BE in list */
733 	for (ibe = 0; ibe < nbe; ibe++) {
734 		size_t k, ns;	/* subordinate index, count */
735 
736 		/* rewrite list pointer chain, including terminator */
737 		ptrlist[ibe]->be_next_node = ptrlist[ibe + 1];
738 		/* sort subordinate snapshots */
739 		if (ptrlist[ibe]->be_node_num_snapshots > 1) {
740 			const size_t nmax = ptrlist[ibe]->be_node_num_snapshots;
741 			be_snapshot_list_t ** const slist =
742 			    malloc(sizeof (be_snapshot_list_t *) * (nmax + 1));
743 			be_snapshot_list_t *p;
744 
745 			if (slist == NULL) {
746 				ret = BE_ERR_NOMEM;
747 				continue;
748 			}
749 			/* build array of linked list snapshot struct ptrs */
750 			for (ns = 0, p = ptrlist[ibe]->be_node_snapshots;
751 			    ns < nmax && p != NULL;
752 			    ns++, p = p->be_next_snapshot) {
753 				slist[ns] = p;
754 			}
755 			if (ns < 2)
756 				goto end_snapshot;
757 			slist[ns] = NULL; /* add terminator */
758 			/* in-place list quicksort using qsort(3C) */
759 			qsort(slist, ns, sizeof (be_snapshot_list_t *),
760 			    be_qsort_compare_snapshots);
761 			/* rewrite list pointer chain, including terminator */
762 			ptrlist[ibe]->be_node_snapshots = slist[0];
763 			for (k = 0; k < ns; k++)
764 				slist[k]->be_next_snapshot = slist[k + 1];
765 end_snapshot:
766 			free(slist);
767 		}
768 		/* sort subordinate datasets */
769 		if (ptrlist[ibe]->be_node_num_datasets > 1) {
770 			const size_t nmax = ptrlist[ibe]->be_node_num_datasets;
771 			be_dataset_list_t ** const slist =
772 			    malloc(sizeof (be_dataset_list_t *) * (nmax + 1));
773 			be_dataset_list_t *p;
774 
775 			if (slist == NULL) {
776 				ret = BE_ERR_NOMEM;
777 				continue;
778 			}
779 			/* build array of linked list dataset struct ptrs */
780 			for (ns = 0, p = ptrlist[ibe]->be_node_datasets;
781 			    ns < nmax && p != NULL;
782 			    ns++, p = p->be_next_dataset) {
783 				slist[ns] = p;
784 			}
785 			if (ns < 2) /* subordinate datasets < 2 - no sort */
786 				goto end_dataset;
787 			slist[ns] = NULL; /* add terminator */
788 			/* in-place list quicksort using qsort(3C) */
789 			qsort(slist, ns, sizeof (be_dataset_list_t *),
790 			    be_qsort_compare_datasets);
791 			/* rewrite list pointer chain, including terminator */
792 			ptrlist[ibe]->be_node_datasets = slist[0];
793 			for (k = 0; k < ns; k++)
794 				slist[k]->be_next_dataset = slist[k + 1];
795 end_dataset:
796 			free(slist);
797 		}
798 	}
799 free:
800 	free(ptrlist);
801 	return (ret);
802 }
803 
804 /*
805  * Function:	be_qsort_compare_BEs_date
806  * Description:	compare BE creation times for qsort(3C)
807  *		will sort BE list from oldest to most recent
808  * Parameters:
809  *		x,y - BEs with names to compare
810  * Returns:
811  *		positive if x>y, negative if y>x, 0 if equal
812  * Scope:
813  *		Private
814  */
815 static int
816 be_qsort_compare_BEs_date(const void *x, const void *y)
817 {
818 	be_node_list_t *p = *(be_node_list_t **)x;
819 	be_node_list_t *q = *(be_node_list_t **)y;
820 
821 	assert(p != NULL);
822 	assert(q != NULL);
823 
824 	if (p->be_node_creation > q->be_node_creation)
825 		return (1);
826 	if (p->be_node_creation < q->be_node_creation)
827 		return (-1);
828 	return (0);
829 }
830 
831 /*
832  * Function:	be_qsort_compare_BEs_date_rev
833  * Description:	compare BE creation times for qsort(3C)
834  *		will sort BE list from recent to oldest
835  * Parameters:
836  *		x,y - BEs with names to compare
837  * Returns:
838  *		positive if y>x, negative if x>y, 0 if equal
839  * Scope:
840  *		Private
841  */
842 static int
843 be_qsort_compare_BEs_date_rev(const void *x, const void *y)
844 {
845 	return (be_qsort_compare_BEs_date(y, x));
846 }
847 
848 /*
849  * Function:	be_qsort_compare_BEs_name
850  * Description:	lexical compare of BE names for qsort(3C)
851  * Parameters:
852  *		x,y - BEs with names to compare
853  * Returns:
854  *		positive if x>y, negative if y>x, 0 if equal
855  * Scope:
856  *		Private
857  */
858 static int
859 be_qsort_compare_BEs_name(const void *x, const void *y)
860 {
861 	be_node_list_t *p = *(be_node_list_t **)x;
862 	be_node_list_t *q = *(be_node_list_t **)y;
863 
864 	assert(p != NULL);
865 	assert(p->be_node_name != NULL);
866 	assert(q != NULL);
867 	assert(q->be_node_name != NULL);
868 
869 	return (strcmp(p->be_node_name, q->be_node_name));
870 }
871 
872 /*
873  * Function:	be_qsort_compare_BEs_name_rev
874  * Description:	reverse lexical compare of BE names for qsort(3C)
875  * Parameters:
876  *		x,y - BEs with names to compare
877  * Returns:
878  *		positive if y>x, negative if x>y, 0 if equal
879  * Scope:
880  *		Private
881  */
882 static int
883 be_qsort_compare_BEs_name_rev(const void *x, const void *y)
884 {
885 	return (be_qsort_compare_BEs_name(y, x));
886 }
887 
888 /*
889  * Function:	be_qsort_compare_BEs_space
890  * Description:	compare BE sizes for qsort(3C)
891  *		will sort BE list in growing order
892  * Parameters:
893  *		x,y - BEs with names to compare
894  * Returns:
895  *		positive if x>y, negative if y>x, 0 if equal
896  * Scope:
897  *		Private
898  */
899 static int
900 be_qsort_compare_BEs_space(const void *x, const void *y)
901 {
902 	be_node_list_t *p = *(be_node_list_t **)x;
903 	be_node_list_t *q = *(be_node_list_t **)y;
904 
905 	assert(p != NULL);
906 	assert(q != NULL);
907 
908 	if (p->be_space_used > q->be_space_used)
909 		return (1);
910 	if (p->be_space_used < q->be_space_used)
911 		return (-1);
912 	return (0);
913 }
914 
915 /*
916  * Function:	be_qsort_compare_BEs_space_rev
917  * Description:	compare BE sizes for qsort(3C)
918  *		will sort BE list in shrinking
919  * Parameters:
920  *		x,y - BEs with names to compare
921  * Returns:
922  *		positive if y>x, negative if x>y, 0 if equal
923  * Scope:
924  *		Private
925  */
926 static int
927 be_qsort_compare_BEs_space_rev(const void *x, const void *y)
928 {
929 	return (be_qsort_compare_BEs_space(y, x));
930 }
931 
932 /*
933  * Function:	be_qsort_compare_snapshots
934  * Description:	lexical compare of BE names for qsort(3C)
935  * Parameters:
936  *		x,y - BE snapshots with names to compare
937  * Returns:
938  *		positive if y>x, negative if x>y, 0 if equal
939  * Scope:
940  *		Private
941  */
942 static int
943 be_qsort_compare_snapshots(const void *x, const void *y)
944 {
945 	be_snapshot_list_t *p = *(be_snapshot_list_t **)x;
946 	be_snapshot_list_t *q = *(be_snapshot_list_t **)y;
947 
948 	if (p == NULL || p->be_snapshot_name == NULL)
949 		return (1);
950 	if (q == NULL || q->be_snapshot_name == NULL)
951 		return (-1);
952 	return (strcmp(p->be_snapshot_name, q->be_snapshot_name));
953 }
954 
955 /*
956  * Function:	be_qsort_compare_datasets
957  * Description:	lexical compare of dataset names for qsort(3C)
958  * Parameters:
959  *		x,y - BE snapshots with names to compare
960  * Returns:
961  *		positive if y>x, negative if x>y, 0 if equal
962  * Scope:
963  *		Private
964  */
965 static int
966 be_qsort_compare_datasets(const void *x, const void *y)
967 {
968 	be_dataset_list_t *p = *(be_dataset_list_t **)x;
969 	be_dataset_list_t *q = *(be_dataset_list_t **)y;
970 
971 	if (p == NULL || p->be_dataset_name == NULL)
972 		return (1);
973 	if (q == NULL || q->be_dataset_name == NULL)
974 		return (-1);
975 	return (strcmp(p->be_dataset_name, q->be_dataset_name));
976 }
977 
978 /*
979  * Function:	be_get_node_data
980  * Description:	Helper function used to collect all the information to fill
981  *		in the be_node_list structure to be returned by be_list.
982  * Parameters:
983  *		zhp - Handle to the root dataset for the BE whose information
984  *		      we're collecting.
985  *		be_node - a pointer to the node structure we're filling in.
986  *		be_name - The BE name of the node whose information we're
987  *		          collecting.
988  *		current_be - the name of the currently active BE.
989  *		be_ds - The dataset name for the BE.
990  *
991  * Returns:
992  *		BE_SUCCESS - Success
993  *		be_errno_t - Failure
994  * Scope:
995  *		Private
996  */
997 static int
998 be_get_node_data(
999 	zfs_handle_t *zhp,
1000 	be_node_list_t *be_node,
1001 	char *be_name,
1002 	const char *rpool,
1003 	char *current_be,
1004 	char *be_ds)
1005 {
1006 	char prop_buf[MAXPATHLEN];
1007 	nvlist_t *userprops = NULL;
1008 	nvlist_t *propval = NULL;
1009 	nvlist_t *zone_propval = NULL;
1010 	char *prop_str = NULL;
1011 	char *zone_prop_str = NULL;
1012 	char *grub_default_bootfs = NULL;
1013 	zpool_handle_t *zphp = NULL;
1014 	int err = 0;
1015 
1016 	if (be_node == NULL || be_name == NULL || current_be == NULL ||
1017 	    be_ds == NULL) {
1018 		be_print_err(gettext("be_get_node_data: invalid arguments, "
1019 		    "can not be NULL\n"));
1020 		return (BE_ERR_INVAL);
1021 	}
1022 
1023 	errno = 0;
1024 
1025 	be_node->be_root_ds = strdup(be_ds);
1026 	if ((err = errno) != 0 || be_node->be_root_ds == NULL) {
1027 		be_print_err(gettext("be_get_node_data: failed to "
1028 		    "copy root dataset name\n"));
1029 		return (errno_to_be_err(err));
1030 	}
1031 
1032 	be_node->be_node_name = strdup(be_name);
1033 	if ((err = errno) != 0 || be_node->be_node_name == NULL) {
1034 		be_print_err(gettext("be_get_node_data: failed to "
1035 		    "copy BE name\n"));
1036 		return (errno_to_be_err(err));
1037 	}
1038 	if (strncmp(be_name, current_be, MAXPATHLEN) == 0)
1039 		be_node->be_active = B_TRUE;
1040 	else
1041 		be_node->be_active = B_FALSE;
1042 
1043 	be_node->be_rpool = strdup(rpool);
1044 	if (be_node->be_rpool == NULL || (err = errno) != 0) {
1045 		be_print_err(gettext("be_get_node_data: failed to "
1046 		    "copy root pool name\n"));
1047 		return (errno_to_be_err(err));
1048 	}
1049 
1050 	be_node->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED);
1051 
1052 	if (getzoneid() == GLOBAL_ZONEID) {
1053 		if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
1054 			be_print_err(gettext("be_get_node_data: failed to open "
1055 			    "pool (%s): %s\n"), rpool,
1056 			    libzfs_error_description(g_zfs));
1057 			return (zfs_err_to_be_err(g_zfs));
1058 		}
1059 
1060 		(void) zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf,
1061 		    ZFS_MAXPROPLEN, NULL, B_FALSE);
1062 		if (be_has_grub() && (be_default_grub_bootfs(rpool,
1063 		    &grub_default_bootfs) == BE_SUCCESS) &&
1064 		    grub_default_bootfs != NULL)
1065 			if (strcmp(grub_default_bootfs, be_ds) == 0)
1066 				be_node->be_active_on_boot = B_TRUE;
1067 			else
1068 				be_node->be_active_on_boot = B_FALSE;
1069 		else if (prop_buf != NULL && strcmp(prop_buf, be_ds) == 0)
1070 			be_node->be_active_on_boot = B_TRUE;
1071 		else
1072 			be_node->be_active_on_boot = B_FALSE;
1073 
1074 		be_node->be_global_active = B_TRUE;
1075 
1076 		free(grub_default_bootfs);
1077 		zpool_close(zphp);
1078 	} else {
1079 		if (be_zone_compare_uuids(be_node->be_root_ds))
1080 			be_node->be_global_active = B_TRUE;
1081 		else
1082 			be_node->be_global_active = B_FALSE;
1083 	}
1084 
1085 	/*
1086 	 * If the dataset is mounted use the mount point
1087 	 * returned from the zfs_is_mounted call. If the
1088 	 * dataset is not mounted then pull the mount
1089 	 * point information out of the zfs properties.
1090 	 */
1091 	be_node->be_mounted = zfs_is_mounted(zhp,
1092 	    &(be_node->be_mntpt));
1093 	if (!be_node->be_mounted) {
1094 		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
1095 		    ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) == 0)
1096 			be_node->be_mntpt = strdup(prop_buf);
1097 		else
1098 			return (zfs_err_to_be_err(g_zfs));
1099 	}
1100 
1101 	be_node->be_node_creation = (time_t)zfs_prop_get_int(zhp,
1102 	    ZFS_PROP_CREATION);
1103 
1104 	/* Get all user properties used for libbe */
1105 	if ((userprops = zfs_get_user_props(zhp)) == NULL) {
1106 		be_node->be_policy_type = strdup(be_default_policy());
1107 	} else {
1108 		if (getzoneid() != GLOBAL_ZONEID) {
1109 			if (nvlist_lookup_nvlist(userprops,
1110 			    BE_ZONE_ACTIVE_PROPERTY, &zone_propval) != 0 ||
1111 			    zone_propval == NULL) {
1112 				be_node->be_active_on_boot = B_FALSE;
1113 			} else {
1114 				verify(nvlist_lookup_string(zone_propval,
1115 				    ZPROP_VALUE, &zone_prop_str) == 0);
1116 				if (strcmp(zone_prop_str, "on") == 0) {
1117 					be_node->be_active_on_boot = B_TRUE;
1118 				} else {
1119 					be_node->be_active_on_boot = B_FALSE;
1120 				}
1121 			}
1122 		}
1123 
1124 		if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
1125 		    &propval) != 0 || propval == NULL) {
1126 			be_node->be_policy_type =
1127 			    strdup(be_default_policy());
1128 		} else {
1129 			verify(nvlist_lookup_string(propval, ZPROP_VALUE,
1130 			    &prop_str) == 0);
1131 			if (prop_str == NULL || strcmp(prop_str, "-") == 0 ||
1132 			    strcmp(prop_str, "") == 0)
1133 				be_node->be_policy_type =
1134 				    strdup(be_default_policy());
1135 			else
1136 				be_node->be_policy_type = strdup(prop_str);
1137 		}
1138 		if (getzoneid() != GLOBAL_ZONEID) {
1139 			if (nvlist_lookup_nvlist(userprops,
1140 			    BE_ZONE_PARENTBE_PROPERTY, &propval) != 0 &&
1141 			    nvlist_lookup_string(propval, ZPROP_VALUE,
1142 			    &prop_str) == 0) {
1143 				be_node->be_uuid_str = strdup(prop_str);
1144 			}
1145 		} else {
1146 			if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY,
1147 			    &propval) == 0 && nvlist_lookup_string(propval,
1148 			    ZPROP_VALUE, &prop_str) == 0) {
1149 				be_node->be_uuid_str = strdup(prop_str);
1150 			}
1151 		}
1152 	}
1153 
1154 	/*
1155 	 * Increment the dataset counter to include the root dataset
1156 	 * of the BE.
1157 	 */
1158 	be_node->be_node_num_datasets++;
1159 
1160 	return (BE_SUCCESS);
1161 }
1162 
1163 /*
1164  * Function:	be_get_ds_data
1165  * Description:	Helper function used by be_add_children_callback to collect
1166  *		the dataset related information that will be returned by
1167  *		be_list.
1168  * Parameters:
1169  *		zhp - Handle to the zfs dataset whose information we're
1170  *		      collecting.
1171  *		name - The name of the dataset we're processing.
1172  *		dataset - A pointer to the be_dataset_list structure
1173  *			  we're filling in.
1174  *		node - The node structure that this dataset belongs to.
1175  * Return:
1176  *		BE_SUCCESS - Success
1177  *		be_errno_t - Failure
1178  * Scope:
1179  *		Private
1180  */
1181 static int
1182 be_get_ds_data(
1183 	zfs_handle_t *zfshp,
1184 	char *name,
1185 	be_dataset_list_t *dataset,
1186 	be_node_list_t *node)
1187 {
1188 	char			prop_buf[ZFS_MAXPROPLEN];
1189 	nvlist_t		*propval = NULL;
1190 	nvlist_t		*userprops = NULL;
1191 	char			*prop_str = NULL;
1192 	int			err = 0;
1193 
1194 	if (zfshp == NULL || name == NULL || dataset == NULL || node == NULL) {
1195 		be_print_err(gettext("be_get_ds_data: invalid arguments, "
1196 		    "can not be NULL\n"));
1197 		return (BE_ERR_INVAL);
1198 	}
1199 
1200 	errno = 0;
1201 
1202 	dataset->be_dataset_name = strdup(name);
1203 	if ((err = errno) != 0) {
1204 		be_print_err(gettext("be_get_ds_data: failed to copy "
1205 		    "dataset name\n"));
1206 		return (errno_to_be_err(err));
1207 	}
1208 
1209 	dataset->be_ds_space_used = zfs_prop_get_int(zfshp, ZFS_PROP_USED);
1210 
1211 	/*
1212 	 * If the dataset is mounted use the mount point
1213 	 * returned from the zfs_is_mounted call. If the
1214 	 * dataset is not mounted then pull the mount
1215 	 * point information out of the zfs properties.
1216 	 */
1217 	if (!(dataset->be_ds_mounted = zfs_is_mounted(zfshp,
1218 	    &(dataset->be_ds_mntpt)))) {
1219 		if (zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
1220 		    prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
1221 		    B_FALSE) == 0)
1222 			dataset->be_ds_mntpt = strdup(prop_buf);
1223 		else
1224 			return (zfs_err_to_be_err(g_zfs));
1225 	}
1226 	dataset->be_ds_creation =
1227 	    (time_t)zfs_prop_get_int(zfshp, ZFS_PROP_CREATION);
1228 
1229 	/*
1230 	 * Get the user property used for the libbe
1231 	 * cleaup policy
1232 	 */
1233 	if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
1234 		dataset->be_ds_plcy_type =
1235 		    strdup(node->be_policy_type);
1236 	} else {
1237 		if (nvlist_lookup_nvlist(userprops,
1238 		    BE_POLICY_PROPERTY, &propval) != 0 ||
1239 		    propval == NULL) {
1240 			dataset->be_ds_plcy_type =
1241 			    strdup(node->be_policy_type);
1242 		} else {
1243 			verify(nvlist_lookup_string(propval,
1244 			    ZPROP_VALUE, &prop_str) == 0);
1245 			if (prop_str == NULL ||
1246 			    strcmp(prop_str, "-") == 0 ||
1247 			    strcmp(prop_str, "") == 0)
1248 				dataset->be_ds_plcy_type
1249 				    = strdup(node->be_policy_type);
1250 			else
1251 				dataset->be_ds_plcy_type = strdup(prop_str);
1252 		}
1253 	}
1254 
1255 	node->be_node_num_datasets++;
1256 	return (BE_SUCCESS);
1257 }
1258 
1259 /*
1260  * Function:	be_get_ss_data
1261  * Description: Helper function used by be_add_children_callback to collect
1262  *		the dataset related information that will be returned by
1263  *		be_list.
1264  * Parameters:
1265  *		zhp - Handle to the zfs snapshot whose information we're
1266  *		      collecting.
1267  *		name - The name of the snapshot we're processing.
1268  *		shapshot - A pointer to the be_snapshot_list structure
1269  *			   we're filling in.
1270  *		node - The node structure that this snapshot belongs to.
1271  * Returns:
1272  *		BE_SUCCESS - Success
1273  *		be_errno_t - Failure
1274  * Scope:
1275  *		Private
1276  */
1277 static int
1278 be_get_ss_data(
1279 	zfs_handle_t *zfshp,
1280 	char *name,
1281 	be_snapshot_list_t *snapshot,
1282 	be_node_list_t *node)
1283 {
1284 	nvlist_t	*propval = NULL;
1285 	nvlist_t	*userprops = NULL;
1286 	char		*prop_str = NULL;
1287 	int		err = 0;
1288 
1289 	if (zfshp == NULL || name == NULL || snapshot == NULL || node == NULL) {
1290 		be_print_err(gettext("be_get_ss_data: invalid arguments, "
1291 		    "can not be NULL\n"));
1292 		return (BE_ERR_INVAL);
1293 	}
1294 
1295 	errno = 0;
1296 
1297 	snapshot->be_snapshot_name = strdup(name);
1298 	if ((err = errno) != 0) {
1299 		be_print_err(gettext("be_get_ss_data: failed to copy name\n"));
1300 		return (errno_to_be_err(err));
1301 	}
1302 
1303 	snapshot->be_snapshot_creation = (time_t)zfs_prop_get_int(zfshp,
1304 	    ZFS_PROP_CREATION);
1305 
1306 	/*
1307 	 * Try to get this snapshot's cleanup policy from its
1308 	 * user properties first.  If not there, use default
1309 	 * cleanup policy.
1310 	 */
1311 	if ((userprops = zfs_get_user_props(zfshp)) != NULL &&
1312 	    nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
1313 	    &propval) == 0 && nvlist_lookup_string(propval,
1314 	    ZPROP_VALUE, &prop_str) == 0) {
1315 		snapshot->be_snapshot_type =
1316 		    strdup(prop_str);
1317 	} else {
1318 		snapshot->be_snapshot_type =
1319 		    strdup(be_default_policy());
1320 	}
1321 
1322 	snapshot->be_snapshot_space_used = zfs_prop_get_int(zfshp,
1323 	    ZFS_PROP_USED);
1324 
1325 	node->be_node_num_snapshots++;
1326 	return (BE_SUCCESS);
1327 }
1328 
1329 /*
1330  * Function:	be_list_alloc
1331  * Description: Helper function used to allocate memory for the various
1332  *		sructures that make up a BE node.
1333  * Parameters:
1334  *		err - Used to return any errors encountered.
1335  *			BE_SUCCESS - Success
1336  *			BE_ERR_NOMEM - Allocation failure
1337  *		size - The size of memory to allocate.
1338  * Returns:
1339  *		Success - A pointer to the allocated memory
1340  * 		Failure - NULL
1341  * Scope:
1342  *		Private
1343  */
1344 static void*
1345 be_list_alloc(int *err, size_t size)
1346 {
1347 	void *bep = NULL;
1348 
1349 	bep = calloc(1, size);
1350 	if (bep == NULL) {
1351 		be_print_err(gettext("be_list_alloc: memory "
1352 		    "allocation failed\n"));
1353 		*err = BE_ERR_NOMEM;
1354 	}
1355 	*err = BE_SUCCESS;
1356 	return (bep);
1357 }
1358 
1359 /*
1360  * Function:	be_get_zone_node_data
1361  * Description:	Helper function used to collect all the information to
1362  *		fill in the be_node_list structure to be returned by
1363  *              be_get_zone_list.
1364  * Parameters:
1365  *		be_node - a pointer to the node structure we're filling in.
1366  *		be_name - The BE name of the node whose information we're
1367  * Returns:
1368  *		BE_SUCCESS - Success
1369  *		be_errno_t - Failure
1370  * Scope:
1371  *		Private
1372  *
1373  * NOTE: This function currently only collects the zone BE name but when
1374  *       support for beadm/libbe in a zone is provided it will need to fill
1375  *       in the rest of the information needed for a zone BE.
1376  */
1377 static int
1378 be_get_zone_node_data(be_node_list_t *be_node, char *be_name)
1379 {
1380 	if ((be_node->be_node_name = strdup(be_name)) != NULL)
1381 		return (BE_SUCCESS);
1382 	return (BE_ERR_NOMEM);
1383 }
1384