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