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