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