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