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