3608 libbe: Remove duplicate code from be_list
authorEvan Layton <Evan.Layton@Sun.COM>
Wed, 04 Feb 2009 12:39:55 -0700
changeset 431 047edaa3400e
parent 430 358f14cc1af8
child 432 1ac4ba11fa95
3608 libbe: Remove duplicate code from be_list
usr/src/lib/libbe/be_list.c
usr/src/lib/libbe/tbeadm/tbeadm.c
--- a/usr/src/lib/libbe/be_list.c	Tue Feb 03 15:49:13 2009 -0800
+++ b/usr/src/lib/libbe/be_list.c	Wed Feb 04 12:39:55 2009 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -35,6 +35,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <errno.h>
 
 #include "libbe.h"
 #include "libbe_priv.h"
@@ -51,21 +52,26 @@
 } list_callback_data_t;
 
 /*
- * Private callback function prototypes
+ * Private function prototypes
  */
-static int be_get_list_all_callback(zpool_handle_t *zhp, void *data);
+static int be_add_children_callback(zfs_handle_t *zhp, void *data);
 static int be_get_list_callback(zpool_handle_t *, void *);
-static int be_add_children_callback(zfs_handle_t *zhp, void *data);
+static int be_get_node_data(zfs_handle_t *, be_node_list_t *, char *,
+    const char *, char *, char *);
+static int be_get_ds_data(zfs_handle_t *, char *, be_dataset_list_t *,
+    be_node_list_t *);
+static int be_get_ss_data(zfs_handle_t *, char *, be_snapshot_list_t *,
+    be_node_list_t *);
 static void be_sort_list(be_node_list_t **);
 static int be_qsort_compare_BEs(const void *, const void *);
 static int be_qsort_compare_snapshots(const void *x, const void *y);
 static int be_qsort_compare_datasets(const void *x, const void *y);
+static void *be_list_alloc(int *, size_t);
 
 /*
  * Private data.
  */
 static char be_container_ds[MAXPATHLEN];
-const char *rpool;
 
 /* ******************************************************************** */
 /*			Public Functions				*/
@@ -116,8 +122,6 @@
 
 	be_zfs_fini();
 
-	be_sort_list(be_nodes);
-
 	return (ret);
 }
 
@@ -168,40 +172,34 @@
 	 * If be_name is NULL we'll look for all BE's on the system.
 	 * If not then we will only return data for the specified BE.
 	 */
-	if (be_name == NULL) {
-		err = zpool_iter(g_zfs, be_get_list_all_callback, &cb);
-		if (err != 0) {
-			if (cb.be_nodes_head != NULL) {
-				be_free_list(cb.be_nodes_head);
-				cb.be_nodes_head = NULL;
-				cb.be_nodes = NULL;
-			}
-			err = BE_ERR_BE_NOENT;
-		} else if (cb.be_nodes_head == NULL) {
-			be_print_err(gettext("be_list: "
-			    "No BE's found\n"));
-			err = BE_ERR_BE_NOENT;
+	if (be_name != NULL)
+		cb.be_name = strdup(be_name);
+
+	err = zpool_iter(g_zfs, be_get_list_callback, &cb);
+	if (err != 0) {
+		if (cb.be_nodes_head != NULL) {
+			be_free_list(cb.be_nodes_head);
+			cb.be_nodes_head = NULL;
+			cb.be_nodes = NULL;
 		}
-	} else {
-		cb.be_name = be_name;
-		err = zpool_iter(g_zfs, be_get_list_callback, &cb);
-		if (err != 0) {
-			if (cb.be_nodes_head != NULL) {
-				be_free_list(cb.be_nodes_head);
-				cb.be_nodes_head = NULL;
-				cb.be_nodes = NULL;
-			}
-			err = BE_ERR_BE_NOENT;
-		} else if (cb.be_nodes_head == NULL) {
-			be_print_err(gettext("be_list: "
-			    "BE (%s) does not exist\n"),
-			    be_name);
-			err = BE_ERR_BE_NOENT;
-		}
+		err = BE_ERR_BE_NOENT;
+	}
+
+	if (cb.be_nodes_head == NULL) {
+		if (be_name != NULL)
+			be_print_err(gettext("be_list: BE (%s) does not "
+			    "exist\n"), be_name);
+		else
+			be_print_err(gettext("be_list: No BE's found\n"));
+		err = BE_ERR_BE_NOENT;
 	}
 
 	*be_nodes = cb.be_nodes_head;
 
+	free(cb.be_name);
+
+	be_sort_list(be_nodes);
+
 	return (err);
 }
 
@@ -260,88 +258,11 @@
 /* ******************************************************************** */
 
 /*
- * Function:	be_get_list_all_callback
- * Description:	Callback function used by zpool_iter to look through all
- *		the pools on the system looking for BEs. This function is
- *		used when no BE is specified and we want to return a list
- *		of all BEs on the system.
- * Parameters:
- *		zlp - handle to the first zpool. (provided by the
- *		      zpool_iter call)
- *		data - pointer to the callback data and where we'll pass
- *		       the list of BE back.
- * Returns:
- *		0 - Success
- *		be_errno_t - Failure
- * Scope:
- *		Private
- */
-static int
-be_get_list_all_callback(zpool_handle_t *zlp, void *data)
-{
-	list_callback_data_t *cb = (list_callback_data_t *)data;
-	zfs_handle_t *zhp = NULL;
-	int err = 0;
-
-	rpool = zpool_get_name(zlp);
-
-	/*
-	 * Generate string for the BE container dataset
-	 */
-	be_make_container_ds(rpool, be_container_ds,
-	    sizeof (be_container_ds));
-
-	/*
-	 * Check if main BE container dataset exists
-	 */
-	if (!zfs_dataset_exists(g_zfs, be_container_ds,
-	    ZFS_TYPE_FILESYSTEM)) {
-		/*
-		 * No BE container dataset exists in this pool,
-		 * no valid BE's in this pool, try the next pool.
-		 */
-		zpool_close(zlp);
-		return (0);
-	}
-
-	if ((zhp = zfs_open(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) ==
-	    NULL) {
-		be_print_err(gettext("be_get_list_all_callback: failed to "
-		    "open BE container dataset %s: %s\n"),
-		    be_container_ds, libzfs_error_description(g_zfs));
-		err = zfs_err_to_be_err(g_zfs);
-		zpool_close(zlp);
-		return (err);
-	}
-
-	if (cb->be_nodes_head == NULL) {
-		cb->be_nodes_head = cb->be_nodes =
-		    calloc(1, sizeof (be_node_list_t));
-		if (cb->be_nodes == NULL) {
-			ZFS_CLOSE(zhp);
-			zpool_close(zlp);
-			be_print_err(gettext("be_get_list_all_callback: memory "
-			    "allocation failed\n"));
-			return (BE_ERR_NOMEM);
-		}
-	}
-
-	/*
-	 * iterate through the next level of datasets to find the BE's
-	 * within the pool
-	 */
-	err = zfs_iter_filesystems(zhp, be_add_children_callback, cb);
-	ZFS_CLOSE(zhp);
-	zpool_close(zlp);
-
-	return (err);
-}
-
-/*
  * Function:	be_get_list_callback
  * Description:	Callback function used by zfs_iter to look through all
- *		the datasets and snapshots for the named BE. This function
- *		is used when a BE name has been specified.
+ *		the pools on the system looking for BEs. If a BE name was
+ *		specified only that BE's information will be collected and
+ *		returned.
  * Parameters:
  *		zlp - handle to the first zfs dataset. (provided by the
  *		      zfs_iter_* call)
@@ -358,140 +279,85 @@
 {
 	list_callback_data_t *cb = (list_callback_data_t *)data;
 	char be_ds[MAXPATHLEN];
-	char prop_buf[MAXPATHLEN];
-	nvlist_t *userprops;
-	nvlist_t *propval;
-	char *prop_str = NULL;
-	char *grub_default_bootfs = NULL;
+	char *open_ds = NULL;
+	char *rpool = NULL;
 	zfs_handle_t *zhp = NULL;
-	zpool_handle_t *zphp = NULL;
 	int err = 0;
 
-	rpool =  zpool_get_name(zlp);
+	cb->zpool_name = rpool =  (char *)zpool_get_name(zlp);
 
 	/*
 	 * Generate string for the BE container dataset
 	 */
 	be_make_container_ds(rpool, be_container_ds,
 	    sizeof (be_container_ds));
-	be_make_root_ds(rpool, cb->be_name, be_ds, sizeof (be_ds));
 
 	/*
-	 * Check if main BE dataset exists
+	 * If a BE name was specified we use it's root dataset in place of
+	 * the container dataset. This is because we only want to collect
+	 * the information for the specified BE.
 	 */
-	if (!zfs_dataset_exists(g_zfs, be_ds,
+	if (cb->be_name != NULL) {
+		/*
+		 * Generate string for the BE root dataset
+		 */
+		be_make_root_ds(rpool, cb->be_name, be_ds, sizeof (be_ds));
+		open_ds = be_ds;
+	} else {
+		open_ds = be_container_ds;
+	}
+
+	/*
+	 * Check if the dataset exists
+	 */
+	if (!zfs_dataset_exists(g_zfs, open_ds,
 	    ZFS_TYPE_FILESYSTEM)) {
 		/*
-		 * No BE root dataset exists in this pool,
-		 * no valid BE's in this pool. Try the
-		 * next zpool.
+		 * The specified dataset does not exist in this pool or
+		 * there are no valid BE's in this pool. Try the next zpool.
 		 */
 		zpool_close(zlp);
 		return (BE_SUCCESS);
 	}
 
-	if ((zhp = zfs_open(g_zfs, be_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
+	if ((zhp = zfs_open(g_zfs, open_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
 		be_print_err(gettext("be_get_list_callback: failed to open "
-		    "BE root dataset %s: %s\n"), be_ds,
+		    "the BE dataset %s: %s\n"), open_ds,
 		    libzfs_error_description(g_zfs));
 		err = zfs_err_to_be_err(g_zfs);
 		zpool_close(zlp);
 		return (err);
 	}
 
-	cb->be_nodes_head = cb->be_nodes = calloc(1, sizeof (be_node_list_t));
-	if (cb->be_nodes == NULL) {
-		ZFS_CLOSE(zhp);
-		zpool_close(zlp);
-		be_print_err(gettext("be_get_list_callback: memory allocation "
-		    "failed\n"));
-		return (BE_ERR_NOMEM);
+	if (cb->be_nodes_head == NULL) {
+		if ((cb->be_nodes_head = be_list_alloc(&err,
+		    sizeof (be_node_list_t))) == NULL) {
+			ZFS_CLOSE(zhp);
+			zpool_close(zlp);
+			return (err);
+		}
+		cb->be_nodes = cb->be_nodes_head;
 	}
 
-	cb->be_nodes->be_root_ds = strdup(be_ds);
-
-	cb->be_nodes->be_node_name = strdup(cb->be_name);
-	if (strncmp(cb->be_name, cb->current_be, MAXPATHLEN) == 0)
-		cb->be_nodes->be_active = B_TRUE;
-	else
-		cb->be_nodes->be_active = B_FALSE;
-
-	cb->be_nodes->be_rpool = strdup(rpool);
-
-	zphp = zpool_open(g_zfs, rpool);
-	cb->be_nodes->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED);
-	zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf, ZFS_MAXPROPLEN,
-	    NULL);
-	if (be_has_grub() &&
-	    (be_default_grub_bootfs(rpool, &grub_default_bootfs) == 0) &&
-	    grub_default_bootfs != NULL)
-		if (strcmp(grub_default_bootfs, be_ds) == 0)
-			cb->be_nodes->be_active_on_boot = B_TRUE;
-		else
-			cb->be_nodes->be_active_on_boot = B_FALSE;
-	else if (prop_buf != NULL && strcmp(prop_buf, be_ds) == 0)
-		cb->be_nodes->be_active_on_boot = B_TRUE;
-	else
-		cb->be_nodes->be_active_on_boot = B_FALSE;
-	free(grub_default_bootfs);
 	/*
-	 * If the dataset is mounted use the mount point
-	 * returned from the zfs_is_mounted call. If the
-	 * dataset is not mounted then pull the mount
-	 * point information out of the zfs properties.
+	 * If a BE name was specified we iterate through the datasets
+	 * and snapshots for this BE only. Otherwise we will iterate
+	 * through the next level of datasets to find all the BE's
+	 * within the pool
 	 */
-	cb->be_nodes->be_mounted = zfs_is_mounted(zhp,
-	    &(cb->be_nodes->be_mntpt));
-	if (!cb->be_nodes->be_mounted) {
-		err = zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
-		    ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE);
-		if (err)
-			cb->be_nodes->be_mntpt = NULL;
-		else
-			cb->be_nodes->be_mntpt = strdup(prop_buf);
-	}
-	cb->be_nodes->be_node_creation = (time_t)zfs_prop_get_int(zhp,
-	    ZFS_PROP_CREATION);
-
-	/* Get all user properties used for libbe */
-	if ((userprops = zfs_get_user_props(zhp)) == NULL) {
-		cb->be_nodes->be_policy_type = strdup(be_default_policy());
-	} else {
-		if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
-		    &propval) != 0 || propval == NULL) {
-			cb->be_nodes->be_policy_type =
-			    strdup(be_default_policy());
-		} else {
-			verify(nvlist_lookup_string(propval, ZPROP_VALUE,
-			    &prop_str) == 0);
-			if (prop_str == NULL || strcmp(prop_str, "-") == 0 ||
-			    strcmp(prop_str, "") == 0)
-				cb->be_nodes->be_policy_type =
-				    strdup(be_default_policy());
-			else
-				cb->be_nodes->be_policy_type = strdup(prop_str);
+	if (cb->be_name != NULL) {
+		if ((err = be_get_node_data(zhp, cb->be_nodes, cb->be_name,
+		    rpool, cb->current_be, be_ds)) != 0) {
+			ZFS_CLOSE(zhp);
+			zpool_close(zlp);
+			return (err);
 		}
-
-		if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propval)
-		    == 0 && nvlist_lookup_string(propval, ZPROP_VALUE,
-		    &prop_str) == 0) {
-			cb->be_nodes->be_uuid_str = strdup(prop_str);
-		}
+		err = zfs_iter_snapshots(zhp, be_add_children_callback, cb);
 	}
 
-	zpool_close(zphp);
 
-	/*
-	 * Increment the dataset counter to include the root dataset
-	 * of the BE.
-	 */
-	cb->be_nodes->be_node_num_datasets++;
-
-	/*
-	 * iterate through the next level of datasets to find the BE's
-	 * within the pool
-	 */
-	err = zfs_iter_children(zhp, be_add_children_callback, cb);
+	if (err == 0)
+		err = zfs_iter_filesystems(zhp, be_add_children_callback, cb);
 	ZFS_CLOSE(zhp);
 	zpool_close(zlp);
 	return (err);
@@ -517,539 +383,108 @@
 be_add_children_callback(zfs_handle_t *zhp, void *data)
 {
 	list_callback_data_t	*cb = (list_callback_data_t *)data;
-	char			prop_buf[ZFS_MAXPROPLEN];
 	char			*str = NULL, *ds_path = NULL;
-	nvlist_t		*propval;
-	nvlist_t		*userprops;
-	char			*prop_str = NULL;
-	char			*grub_default_bootfs = NULL;
 	int			err = 0;
 
 	ds_path = str = strdup(zfs_get_name(zhp));
 
-	if (strncmp(str + strlen(be_container_ds), "@", 1) == 0) {
-		/*
-		 * This is a snapshot created by the installer and not a BE.
-		 */
-		ZFS_CLOSE(zhp);
-		return (BE_SUCCESS);
-	}
 	/*
 	 * get past the end of the container dataset plus the trailing "/"
 	 */
 	str = str + (strlen(be_container_ds) + 1);
-	if (strchr(str, '/') == NULL && strchr(str, '@') == NULL) {
-		if (cb->be_nodes->be_node_name == NULL) {
-			zpool_handle_t *zphp = zpool_open(g_zfs, rpool);
-			zfs_handle_t *zfshp = zfs_open(g_zfs, ds_path,
-			    ZFS_TYPE_DATASET);
-			cb->be_nodes->be_node_name = strdup(str);
-			if (strncmp(str, cb->current_be, MAXPATHLEN) == 0)
-				cb->be_nodes->be_active = B_TRUE;
-			else
-				cb->be_nodes->be_active = B_FALSE;
-			cb->be_nodes->be_root_ds = strdup(ds_path);
-			cb->be_nodes->be_rpool = strdup(rpool);
-			cb->be_nodes->be_space_used = zfs_prop_get_int(zfshp,
-			    ZFS_PROP_USED);
-			zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf,
-			    ZFS_MAXPROPLEN, NULL);
-			if (be_has_grub() &&
-			    (be_default_grub_bootfs(rpool,
-			    &grub_default_bootfs) == 0) &&
-			    grub_default_bootfs != NULL) {
-				if (strcmp(grub_default_bootfs, ds_path) == 0)
-					cb->be_nodes->be_active_on_boot =
-					    B_TRUE;
-				else
-					cb->be_nodes->be_active_on_boot =
-					    B_FALSE;
-			} else if (prop_buf != NULL &&
-			    strcmp(prop_buf, ds_path) == 0)
-				cb->be_nodes->be_active_on_boot = B_TRUE;
-			else
-				cb->be_nodes->be_active_on_boot =
-				    B_FALSE;
-			free(grub_default_bootfs);
-			/*
-			 * If the dataset is mounted use the mount point
-			 * returned from the zfs_is_mounted call. If the
-			 * dataset is not mounted then pull the mount
-			 * point information out of the zfs properties.
-			 */
-			cb->be_nodes->be_mounted = zfs_is_mounted(zfshp,
-			    &(cb->be_nodes->be_mntpt));
-			if (!cb->be_nodes->be_mounted) {
-				err = zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
-				    prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
-				    B_FALSE);
-				if (err)
-					cb->be_nodes->be_mntpt = NULL;
-				else
-					cb->be_nodes->be_mntpt =
-					    strdup(prop_buf);
+	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
+		be_snapshot_list_t *snapshots = NULL;
+		if (cb->be_nodes->be_node_snapshots == NULL) {
+			if ((cb->be_nodes->be_node_snapshots =
+			    be_list_alloc(&err, sizeof (be_snapshot_list_t)))
+			    == NULL || err != 0) {
+				ZFS_CLOSE(zhp);
+				return (err);
 			}
-			cb->be_nodes->be_node_creation =
-			    (time_t)zfs_prop_get_int(zfshp,
-			    ZFS_PROP_CREATION);
-
-			/* Get all user properties used for libbe */
-			if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
-				cb->be_nodes->be_policy_type =
-				    strdup(be_default_policy());
-			} else {
-				if (nvlist_lookup_nvlist(userprops,
-				    BE_POLICY_PROPERTY, &propval) != 0 ||
-				    propval == NULL) {
-					cb->be_nodes->be_policy_type =
-					    strdup(be_default_policy());
-				} else {
-					verify(nvlist_lookup_string(propval,
-					    ZPROP_VALUE, &prop_str) == 0);
-					if (prop_str == NULL ||
-					    strcmp(prop_str, "-") == 0 ||
-					    strcmp(prop_str, "") == 0)
-						cb->be_nodes->be_policy_type =
-						    strdup(be_default_policy());
-					else
-						cb->be_nodes->be_policy_type =
-						    strdup(prop_str);
+			cb->be_nodes->be_node_snapshots->be_next_snapshot =
+			    NULL;
+			snapshots = cb->be_nodes->be_node_snapshots;
+		} else {
+			for (snapshots = cb->be_nodes->be_node_snapshots;
+			    snapshots != NULL;
+			    snapshots = snapshots->be_next_snapshot) {
+				if (snapshots->be_next_snapshot != NULL)
+					continue;
+				/*
+				 * We're at the end of the list add the
+				 * new snapshot.
+				 */
+				if ((snapshots->be_next_snapshot =
+				    be_list_alloc(&err,
+				    sizeof (be_snapshot_list_t))) == NULL ||
+				    err != 0) {
+					ZFS_CLOSE(zhp);
+					return (err);
 				}
-
-				if (nvlist_lookup_nvlist(userprops,
-				    BE_UUID_PROPERTY, &propval) == 0 &&
-				    nvlist_lookup_string(propval,
-				    ZPROP_VALUE, &prop_str) == 0) {
-					cb->be_nodes->be_uuid_str =
-					    strdup(prop_str);
-				}
-
+				snapshots = snapshots->be_next_snapshot;
+				snapshots->be_next_snapshot = NULL;
+				break;
 			}
-
-			cb->be_nodes->be_node_num_datasets++;
-			ZFS_CLOSE(zfshp);
-			zpool_close(zphp);
-		} else {
-			zpool_handle_t *zphp = zpool_open(g_zfs, rpool);
-			zfs_handle_t *zfshp = zfs_open(g_zfs, ds_path,
-			    ZFS_TYPE_DATASET);
-			cb->be_nodes->be_next_node = calloc(1,
-			    sizeof (be_node_list_t));
-			if (cb->be_nodes->be_next_node == NULL) {
+		}
+		if ((err = be_get_ss_data(zhp, str, snapshots,
+		    cb->be_nodes)) != 0) {
+			ZFS_CLOSE(zhp);
+			return (err);
+		}
+	} else if (strchr(str, '/') == NULL) {
+		if (cb->be_nodes->be_node_name != NULL) {
+			if ((cb->be_nodes->be_next_node =
+			    be_list_alloc(&err, sizeof (be_node_list_t))) ==
+			    NULL || err != 0) {
 				ZFS_CLOSE(zhp);
-				ZFS_CLOSE(zfshp);
-				zpool_close(zphp);
-				be_print_err(gettext(
-				    "be_add_children_callback: memory "
-				    "allocation failed\n"));
-				return (BE_ERR_NOMEM);
+				return (err);
 			}
 			cb->be_nodes = cb->be_nodes->be_next_node;
 			cb->be_nodes->be_next_node = NULL;
-			cb->be_nodes->be_node_name = strdup(str);
-			if (strncmp(str, cb->current_be, MAXPATHLEN) == 0)
-				cb->be_nodes->be_active = B_TRUE;
-			else
-				cb->be_nodes->be_active = B_FALSE;
-			cb->be_nodes->be_root_ds = strdup(ds_path);
-			cb->be_nodes->be_rpool = strdup(rpool);
-			cb->be_nodes->be_space_used = zfs_prop_get_int(zfshp,
-			    ZFS_PROP_USED);
-			zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf,
-			    ZFS_MAXPROPLEN, NULL);
-			if (be_has_grub() &&
-			    (be_default_grub_bootfs(rpool,
-			    &grub_default_bootfs) == 0) &&
-			    grub_default_bootfs != NULL) {
-				if (strcmp(grub_default_bootfs, ds_path) == 0)
-					cb->be_nodes->be_active_on_boot
-					    = B_TRUE;
-				else
-					cb->be_nodes->be_active_on_boot
-					    = B_FALSE;
-			} else if (prop_buf != NULL &&
-			    strcmp(prop_buf, ds_path) == 0)
-				cb->be_nodes->be_active_on_boot =
-				    B_TRUE;
-			else
-				cb->be_nodes->be_active_on_boot =
-				    B_FALSE;
-			free(grub_default_bootfs);
-			/*
-			 * If the dataset is mounted use the mount point
-			 * returned from the zfs_is_mounted call. If the
-			 * dataset is not mounted then pull the mount
-			 * point information out of the zfs properties.
-			 */
-			cb->be_nodes->be_mounted = zfs_is_mounted(zfshp,
-			    &(cb->be_nodes->be_mntpt));
-			if (!cb->be_nodes->be_mounted) {
-				err = zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
-				    prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
-				    B_FALSE);
-				if (err)
-					cb->be_nodes->be_mntpt = NULL;
-				else
-					cb->be_nodes->be_mntpt =
-					    strdup(prop_buf);
-			}
-			cb->be_nodes->be_node_creation =
-			    (time_t)zfs_prop_get_int(zfshp,
-			    ZFS_PROP_CREATION);
-
-			/* Get all user properties used for libbe */
-			if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
-				cb->be_nodes->be_policy_type =
-				    strdup(be_default_policy());
-			} else {
-				if (nvlist_lookup_nvlist(userprops,
-				    BE_POLICY_PROPERTY, &propval) != 0 ||
-				    propval == NULL) {
-					cb->be_nodes->be_policy_type =
-					    strdup(be_default_policy());
-				} else {
-					verify(nvlist_lookup_string(propval,
-					    ZPROP_VALUE, &prop_str) == 0);
-					if (prop_str == NULL || strcmp(prop_str,
-					    "-") == 0 || strcmp(prop_str,
-					    "") == 0)
-						cb->be_nodes->be_policy_type =
-						    strdup(be_default_policy());
-					else
-						cb->be_nodes->be_policy_type =
-						    strdup(prop_str);
-				}
-
-				if (nvlist_lookup_nvlist(userprops,
-				    BE_UUID_PROPERTY, &propval) == 0 &&
-				    nvlist_lookup_string(propval,
-				    ZPROP_VALUE, &prop_str) == 0) {
-					cb->be_nodes->be_uuid_str =
-					    strdup(prop_str);
-				}
-
-			}
-
-			cb->be_nodes->be_node_num_datasets++;
-			ZFS_CLOSE(zfshp);
-			zpool_close(zphp);
+		}
+		if ((err = be_get_node_data(zhp, cb->be_nodes, str,
+		    cb->zpool_name, cb->current_be, ds_path)) != 0) {
+			ZFS_CLOSE(zhp);
+			return (err);
 		}
-	} else if (strchr(str, '/') != NULL && strchr(str, '@') == NULL) {
+	} else if (strchr(str, '/') != NULL) {
+		be_dataset_list_t *datasets = NULL;
 		if (cb->be_nodes->be_node_datasets == NULL) {
-			zfs_handle_t *zfshp = zfs_open(g_zfs, ds_path,
-			    ZFS_TYPE_DATASET);
-			cb->be_nodes->be_node_datasets = calloc(1,
-			    sizeof (be_dataset_list_t));
-			if (cb->be_nodes->be_node_datasets == NULL) {
+			if ((cb->be_nodes->be_node_datasets =
+			    be_list_alloc(&err, sizeof (be_dataset_list_t)))
+			    == NULL || err != 0) {
 				ZFS_CLOSE(zhp);
-				ZFS_CLOSE(zfshp);
-				be_print_err(gettext(
-				    "be_add_children_callback: memory "
-				    "allocation failed\n"));
-				return (BE_ERR_NOMEM);
-			}
-			cb->be_nodes->be_node_datasets->be_dataset_name =
-			    strdup(str);
-			cb->be_nodes->be_node_datasets->be_ds_space_used =
-			    zfs_prop_get_int(zfshp, ZFS_PROP_USED);
-			/*
-			 * If the dataset is mounted use the mount point
-			 * returned from the zfs_is_mounted call. If the
-			 * dataset is not mounted then pull the mount
-			 * point information out of the zfs properties.
-			 */
-			cb->be_nodes->be_node_datasets->be_ds_mounted =
-			    zfs_is_mounted(zfshp,
-			    &(cb->be_nodes->be_node_datasets->be_ds_mntpt));
-			if (!cb->be_nodes->be_node_datasets->be_ds_mounted) {
-				err = zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
-				    prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
-				    B_FALSE);
-				if (err)
-				cb->be_nodes->be_node_datasets->be_ds_mntpt =
-				    NULL;
-				else
-				cb->be_nodes->be_node_datasets->be_ds_mntpt =
-				    strdup(prop_buf);
+				return (err);
 			}
-			cb->be_nodes->be_node_datasets->be_ds_creation =
-			    (time_t)zfs_prop_get_int(zfshp, ZFS_PROP_CREATION);
-
-			/*
-			 * Get the user property used for the libbe
-			 * cleaup policy
-			 */
-			if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
-			cb->be_nodes->be_node_datasets->be_ds_plcy_type =
-			    strdup(cb->be_nodes->be_policy_type);
-			} else {
-				if (nvlist_lookup_nvlist(userprops,
-				    BE_POLICY_PROPERTY, &propval) != 0 ||
-				    propval == NULL) {
-			cb->be_nodes->be_node_datasets->be_ds_plcy_type =
-			    strdup(cb->be_nodes->be_policy_type);
-				} else {
-					verify(nvlist_lookup_string(propval,
-					    ZPROP_VALUE, &prop_str) == 0);
-					if (prop_str == NULL ||
-					    strcmp(prop_str, "-") == 0 ||
-					    strcmp(prop_str, "") == 0)
-				cb->be_nodes->be_node_datasets->be_ds_plcy_type
-				    = strdup(cb->be_nodes->be_policy_type);
-					else
-				cb->be_nodes->be_node_datasets->be_ds_plcy_type
-				    = strdup(prop_str);
-				}
-			}
-
-			cb->be_nodes->be_node_datasets->be_next_dataset =
-			    NULL;
-			cb->be_nodes->be_node_num_datasets++;
-			ZFS_CLOSE(zfshp);
-		} else if (strcmp(
-		    cb->be_nodes->be_node_datasets->be_dataset_name,
-		    str) != 0) {
-			be_dataset_list_t *datasets =
-			    cb->be_nodes->be_node_datasets;
-			while (datasets != NULL) {
-				if (strcmp(datasets->be_dataset_name, str) ==
-				    0) {
-					/*
-					 * We already have this dataset, move
-					 * on to the next one.
-					 */
-					datasets = datasets->be_next_dataset;
+			cb->be_nodes->be_node_datasets->be_next_dataset = NULL;
+			datasets = cb->be_nodes->be_node_datasets;
+		} else {
+			for (datasets = cb->be_nodes->be_node_datasets;
+			    datasets != NULL;
+			    datasets = datasets->be_next_dataset) {
+				if (datasets->be_next_dataset != NULL)
 					continue;
-				} else if (datasets->be_next_dataset == NULL) {
-					/*
-					 * We're at the end of the list add
-					 * the new dataset.
-					 */
-					zfs_handle_t *zfshp = zfs_open(g_zfs,
-					    ds_path, ZFS_TYPE_DATASET);
-					datasets->be_next_dataset = calloc(1,
-					    sizeof (be_dataset_list_t));
-					if (datasets->be_next_dataset ==
-					    NULL) {
-						ZFS_CLOSE(zhp);
-						ZFS_CLOSE(zfshp);
-						be_print_err(gettext(
-						    "be_add_children_callback: "
-						    "memory allocation "
-						    "failed\n"));
-						return (BE_ERR_NOMEM);
-					}
-					datasets = datasets->be_next_dataset;
-					datasets->be_dataset_name = strdup(str);
-					datasets->be_ds_space_used =
-					    zfs_prop_get_int(zfshp,
-					    ZFS_PROP_USED);
-					/*
-					 * If the dataset is mounted use
-					 * the mount point returned from the
-					 * zfs_is_mounted call. If the
-					 * dataset is not mounted then pull
-					 * the mount point information out
-					 * of the zfs properties.
-					 */
-					datasets->be_ds_mounted =
-					    zfs_is_mounted(zfshp,
-					    &(datasets->be_ds_mntpt));
-					if (!datasets->be_ds_mounted) {
-						err = zfs_prop_get(zfshp,
-						    ZFS_PROP_MOUNTPOINT,
-						    prop_buf, ZFS_MAXPROPLEN,
-						    NULL, NULL, 0, B_FALSE);
-						if (err)
-							datasets->be_ds_mntpt =
-							    NULL;
-						else
-							datasets->be_ds_mntpt =
-							    strdup(prop_buf);
-					}
-					datasets->be_ds_creation =
-					    (time_t)zfs_prop_get_int(zfshp,
-					    ZFS_PROP_CREATION);
-
-					/*
-					 * Get the user properties used for
-					 * the libbe cleanup policy.
-					 */
-					if ((userprops = zfs_get_user_props(
-					    zfshp)) == NULL) {
-					datasets->be_ds_plcy_type =
-					    strdup(
-					    cb->be_nodes->be_policy_type);
-					} else {
-						if (nvlist_lookup_nvlist(
-						    userprops,
-						    BE_POLICY_PROPERTY,
-						    &propval) != 0 ||
-						    propval == NULL) {
-					datasets->be_ds_plcy_type =
-					    strdup(
-					    cb->be_nodes->be_policy_type);
-						} else {
-						verify(nvlist_lookup_string(
-						    propval, ZPROP_VALUE,
-						    &prop_str) == 0);
-						if (prop_str == NULL ||
-						    strcmp(prop_str, "-")
-						    == 0 || strcmp(prop_str,
-						    "") == 0)
-					datasets->be_ds_plcy_type =
-					    strdup(
-					    cb->be_nodes->be_policy_type);
-						else
-						datasets->be_ds_plcy_type =
-						    strdup(prop_str);
-						}
-					}
-					cb->be_nodes->be_node_num_datasets++;
-					datasets->be_next_dataset = NULL;
-					ZFS_CLOSE(zfshp);
+				/*
+				 * We're at the end of the list add
+				 * the new dataset.
+				 */
+				if ((datasets->be_next_dataset =
+				    be_list_alloc(&err,
+				    sizeof (be_dataset_list_t)))
+				    == NULL || err != 0) {
+					ZFS_CLOSE(zhp);
+					return (err);
 				}
 				datasets = datasets->be_next_dataset;
+				datasets->be_next_dataset = NULL;
+				break;
 			}
 		}
-	} else {
-		if (cb->be_nodes->be_node_snapshots == NULL) {
-			uint64_t space_used;
-			zfs_handle_t *zfshp;
 
-			zfshp = zfs_open(g_zfs, ds_path, ZFS_TYPE_SNAPSHOT);
-			cb->be_nodes->be_node_snapshots =
-			    calloc(1, sizeof (be_snapshot_list_t));
-			if (cb->be_nodes->be_node_snapshots == NULL) {
-				ZFS_CLOSE(zhp);
-				ZFS_CLOSE(zfshp);
-				be_print_err(gettext(
-				    "be_add_children_callback: memory "
-				    "allocation failed\n"));
-				return (BE_ERR_NOMEM);
-			}
-			cb->be_nodes->be_node_snapshots->be_snapshot_name =
-			    strdup(str);
-			cb->be_nodes->be_node_snapshots->be_snapshot_creation
-			    = (time_t)zfs_prop_get_int(zfshp,
-			    ZFS_PROP_CREATION);
-
-			/*
-			 * Try to get this snapshot's cleanup policy from its
-			 * user properties first.  If not there, use default
-			 * cleanup policy.
-			 */
-			if ((userprops = zfs_get_user_props(zfshp)) != NULL &&
-			    nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
-			    &propval) == 0 && nvlist_lookup_string(propval,
-			    ZPROP_VALUE, &prop_str) == 0) {
-			cb->be_nodes->be_node_snapshots->be_snapshot_type =
-			    strdup(prop_str);
-			} else {
-			cb->be_nodes->be_node_snapshots->be_snapshot_type =
-			    strdup(be_default_policy());
-			}
-
-			space_used = zfs_prop_get_int(zfshp, ZFS_PROP_USED);
-			if ((err = zfs_err_to_be_err(g_zfs)) != 0) {
-				ZFS_CLOSE(zhp);
-				ZFS_CLOSE(zfshp);
-				be_print_err(gettext(
-				    "be_add_children_callback: get space "
-				    "used failed (%d)\n"), err);
-				return (err);
-			}
-			cb->be_nodes->be_node_snapshots->be_snapshot_space_used
-			    = space_used;
-			cb->be_nodes->be_node_snapshots->be_next_snapshot =
-			    NULL;
-			cb->be_nodes->be_node_num_snapshots++;
-			ZFS_CLOSE(zfshp);
-		} else if (
-		    strcmp(cb->be_nodes->be_node_snapshots->be_snapshot_name,
-		    str) != 0) {
-			be_snapshot_list_t *snapshots =
-			    cb->be_nodes->be_node_snapshots;
-			while (snapshots != NULL) {
-				if (strcmp(snapshots->be_snapshot_name,
-				    str) == 0) {
-					/*
-					 * We already have this snapshot
-					 * move on
-					 */
-					snapshots = snapshots->be_next_snapshot;
-					continue;
-				} else if (snapshots->be_next_snapshot ==
-				    NULL) {
-					uint64_t space_used;
-					zfs_handle_t *zfshp;
-
-					/*
-					 * We're at the end of the list add the
-					 * new snapshot.
-					 */
-					zfshp = zfs_open(g_zfs, ds_path,
-					    ZFS_TYPE_SNAPSHOT);
-					snapshots->be_next_snapshot = calloc(1,
-					    sizeof (be_snapshot_list_t));
-					if (snapshots->be_next_snapshot ==
-					    NULL) {
-						ZFS_CLOSE(zhp);
-						ZFS_CLOSE(zfshp);
-						be_print_err(gettext(
-						    "be_add_children_callback: "
-						    "memory allocation "
-						    "failed\n"));
-						return (BE_ERR_NOMEM);
-					}
-					snapshots = snapshots->be_next_snapshot;
-					snapshots->be_snapshot_name =
-					    strdup(str);
-					snapshots->be_snapshot_creation =
-					    (time_t)zfs_prop_get_int(zfshp,
-					    ZFS_PROP_CREATION);
-
-					/*
-					 * Try to get this snapshot's cleanup
-					 * policy from its user properties
-					 * first.  If not there, use default
-					 * cleanup policy.
-					 */
-					if ((userprops =
-					    zfs_get_user_props(zfshp))
-					    != NULL &&
-					    nvlist_lookup_nvlist(userprops,
-					    BE_POLICY_PROPERTY, &propval)
-					    == 0 &&
-					    nvlist_lookup_string(propval,
-					    ZPROP_VALUE, &prop_str) == 0) {
-						snapshots->be_snapshot_type =
-						    strdup(prop_str);
-					} else {
-						snapshots->be_snapshot_type =
-						    strdup(be_default_policy());
-					}
-
-					space_used = zfs_prop_get_int(zfshp,
-					    ZFS_PROP_USED);
-					if ((err = zfs_err_to_be_err(g_zfs)) !=
-					    BE_SUCCESS) {
-						ZFS_CLOSE(zhp);
-						ZFS_CLOSE(zfshp);
-						be_print_err(gettext(
-						    "be_add_children_callback: "
-						    "get space used failed "
-						    "(%d)\n"), err);
-						return (err);
-					}
-					snapshots->be_snapshot_space_used =
-					    space_used;
-					cb->be_nodes->be_node_num_snapshots++;
-					snapshots->be_next_snapshot = NULL;
-					ZFS_CLOSE(zfshp);
-				}
-				snapshots = snapshots->be_next_snapshot;
-			}
+		if ((err = be_get_ds_data(zhp, str,
+		    datasets, cb->be_nodes)) != 0) {
+			ZFS_CLOSE(zhp);
+			return (err);
 		}
 	}
 	err = zfs_iter_children(zhp, be_add_children_callback, cb);
@@ -1234,3 +669,381 @@
 		return (-1);
 	return (strcmp(p->be_dataset_name, q->be_dataset_name));
 }
+
+/*
+ * Function:	be_get_node_data
+ * Description:	Helper function used to collect all the information to fill
+ *		in the be_node_list structure to be returned by be_list.
+ * Parameters:
+ *		zhp - Handle to the root dataset for the BE whose information
+ *		      we're collecting.
+ *		be_node - a pointer to the node structure we're filling in.
+ *		be_name - The BE name of the node whose information we're
+ *		          collecting.
+ *		current_be - the name of the currently active BE.
+ *		be_ds - The dataset name for the BE.
+ *
+ * Returns:
+ *		0 - Success
+ *		be_errno_t - Failure
+ * Scope:
+ *		Private
+ */
+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)
+{
+	char prop_buf[MAXPATHLEN];
+	nvlist_t *userprops = NULL;
+	nvlist_t *propval = NULL;
+	char *prop_str = NULL;
+	char *grub_default_bootfs = NULL;
+	zpool_handle_t *zphp = NULL;
+	int err = 0;
+
+	if (be_node == NULL || be_name == NULL || current_be == NULL ||
+	    be_ds == NULL) {
+		be_print_err(gettext("be_get_node_data: invalid arguments, "
+		    "can not be NULL\n"));
+		return (BE_ERR_INVAL);
+	}
+
+	errno = 0;
+
+	be_node->be_root_ds = strdup(be_ds);
+	if ((err = errno) != 0 || be_node->be_root_ds == NULL) {
+		be_print_err(gettext("be_get_node_data: failed to "
+		    "copy root dataset name\n"));
+		return (errno_to_be_err(err));
+	}
+
+	be_node->be_node_name = strdup(be_name);
+	if ((err = errno) != 0 || be_node->be_node_name == NULL) {
+		be_print_err(gettext("be_get_node_data: failed to "
+		    "copy BE name\n"));
+		return (errno_to_be_err(err));
+	}
+	if (strncmp(be_name, current_be, MAXPATHLEN) == 0)
+		be_node->be_active = B_TRUE;
+	else
+		be_node->be_active = B_FALSE;
+
+	be_node->be_rpool = strdup(rpool);
+	if ((err = errno) != 0 || be_node->be_rpool == NULL) {
+		be_print_err(gettext("be_get_node_data: failed to "
+		    "copy root pool name\n"));
+		return (errno_to_be_err(err));
+	}
+
+	be_node->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED);
+	if ((err = zfs_err_to_be_err(g_zfs)) != 0) {
+		be_print_err(gettext(
+		    "be_get_node_data: get space used failed (%d)\n"), err);
+		return (err);
+	}
+
+	if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
+		be_print_err(gettext("be_get_node_data: failed to open pool "
+		    "(%s): %s\n"), rpool, libzfs_error_description(g_zfs));
+		err = zfs_err_to_be_err(g_zfs);
+		return (err);
+	}
+
+	zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf, ZFS_MAXPROPLEN,
+	    NULL);
+	if (be_has_grub() &&
+	    (be_default_grub_bootfs(rpool, &grub_default_bootfs) == 0) &&
+	    grub_default_bootfs != NULL)
+		if (strcmp(grub_default_bootfs, be_ds) == 0)
+			be_node->be_active_on_boot = B_TRUE;
+		else
+			be_node->be_active_on_boot = B_FALSE;
+	else if (prop_buf != NULL && strcmp(prop_buf, be_ds) == 0)
+		be_node->be_active_on_boot = B_TRUE;
+	else
+		be_node->be_active_on_boot = B_FALSE;
+	free(grub_default_bootfs);
+	zpool_close(zphp);
+
+	/*
+	 * If the dataset is mounted use the mount point
+	 * returned from the zfs_is_mounted call. If the
+	 * dataset is not mounted then pull the mount
+	 * point information out of the zfs properties.
+	 */
+	be_node->be_mounted = zfs_is_mounted(zhp,
+	    &(be_node->be_mntpt));
+	if (!be_node->be_mounted) {
+		err = zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
+		    ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE);
+		if (err)
+			be_node->be_mntpt = NULL;
+		else
+			be_node->be_mntpt = strdup(prop_buf);
+	}
+
+	be_node->be_node_creation = (time_t)zfs_prop_get_int(zhp,
+	    ZFS_PROP_CREATION);
+	if ((err = zfs_err_to_be_err(g_zfs)) != 0) {
+		be_print_err(gettext(
+		    "be_get_node_data: get creation time failed (%d)\n"), err);
+		return (err);
+	}
+
+	/* Get all user properties used for libbe */
+	if ((userprops = zfs_get_user_props(zhp)) == NULL) {
+		be_node->be_policy_type = strdup(be_default_policy());
+	} else {
+		if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
+		    &propval) != 0 || propval == NULL) {
+			be_node->be_policy_type =
+			    strdup(be_default_policy());
+		} else {
+			verify(nvlist_lookup_string(propval, ZPROP_VALUE,
+			    &prop_str) == 0);
+			if (prop_str == NULL || strcmp(prop_str, "-") == 0 ||
+			    strcmp(prop_str, "") == 0)
+				be_node->be_policy_type =
+				    strdup(be_default_policy());
+			else
+				be_node->be_policy_type = strdup(prop_str);
+		}
+
+		if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propval)
+		    == 0 && nvlist_lookup_string(propval, ZPROP_VALUE,
+		    &prop_str) == 0) {
+			be_node->be_uuid_str = strdup(prop_str);
+		}
+	}
+
+	/*
+	 * Increment the dataset counter to include the root dataset
+	 * of the BE.
+	 */
+	be_node->be_node_num_datasets++;
+
+	return (err);
+}
+
+/*
+ * Function:	be_get_ds_data
+ * Description:	Helper function used by be_add_children_callback to collect
+ *		the dataset related information that will be returned by
+ *		be_list.
+ * Parameters:
+ *		zhp - Handle to the zfs dataset whose information we're
+ *		      collecting.
+ *		name - The name of the dataset we're processing.
+ *		dataset - A pointer to the be_dataset_list structure
+ *			  we're filling in.
+ *		node - The node structure that this dataset belongs to.
+ * Return:
+ *		0 - Success
+ *		be_errno_t - Failure
+ * Scope:
+ *		Private
+ */
+static int
+be_get_ds_data(
+	zfs_handle_t *zfshp,
+	char *name,
+	be_dataset_list_t *dataset,
+	be_node_list_t *node)
+{
+	char			prop_buf[ZFS_MAXPROPLEN];
+	nvlist_t		*propval = NULL;
+	nvlist_t		*userprops = NULL;
+	char			*prop_str = NULL;
+	int			err = 0;
+
+	if (zfshp == NULL || name == NULL || dataset == NULL || node == NULL) {
+		be_print_err(gettext("be_get_ds_data: invalid arguments, "
+		    "can not be NULL\n"));
+		return (BE_ERR_INVAL);
+	}
+
+	errno = 0;
+
+	dataset->be_dataset_name = strdup(name);
+	if ((err = errno) != 0) {
+		be_print_err(gettext("be_get_ds_data: failed to copy "
+		    "dataset name\n"));
+		return (errno_to_be_err(err));
+	}
+
+	dataset->be_ds_space_used = zfs_prop_get_int(zfshp, ZFS_PROP_USED);
+	if ((err = zfs_err_to_be_err(g_zfs)) != 0) {
+		be_print_err(gettext(
+		    "be_get_ds_data: get space used failed (%d)\n"), err);
+		return (err);
+	}
+
+	/*
+	 * If the dataset is mounted use the mount point
+	 * returned from the zfs_is_mounted call. If the
+	 * dataset is not mounted then pull the mount
+	 * point information out of the zfs properties.
+	 */
+	if (!(dataset->be_ds_mounted = zfs_is_mounted(zfshp,
+	    &(dataset->be_ds_mntpt)))) {
+		err = zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
+		    prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
+		    B_FALSE);
+		if (err != 0)
+			dataset->be_ds_mntpt = NULL;
+		else
+			dataset->be_ds_mntpt = strdup(prop_buf);
+	}
+	dataset->be_ds_creation =
+	    (time_t)zfs_prop_get_int(zfshp, ZFS_PROP_CREATION);
+	if ((err = zfs_err_to_be_err(g_zfs)) != 0) {
+		be_print_err(gettext(
+		    "be_get_ds_data: get creation time failed (%d)\n"), err);
+		return (err);
+	}
+
+	/*
+	 * Get the user property used for the libbe
+	 * cleaup policy
+	 */
+	if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
+		dataset->be_ds_plcy_type =
+		    strdup(node->be_policy_type);
+	} else {
+		if (nvlist_lookup_nvlist(userprops,
+		    BE_POLICY_PROPERTY, &propval) != 0 ||
+		    propval == NULL) {
+			dataset->be_ds_plcy_type =
+			    strdup(node->be_policy_type);
+		} else {
+			verify(nvlist_lookup_string(propval,
+			    ZPROP_VALUE, &prop_str) == 0);
+			if (prop_str == NULL ||
+			    strcmp(prop_str, "-") == 0 ||
+			    strcmp(prop_str, "") == 0)
+				dataset->be_ds_plcy_type
+				    = strdup(node->be_policy_type);
+			else
+				dataset->be_ds_plcy_type = strdup(prop_str);
+		}
+	}
+
+	node->be_node_num_datasets++;
+	return (err);
+}
+
+/*
+ * Function:	be_get_ss_data
+ * Description: Helper function used by be_add_children_callback to collect
+ *		the dataset related information that will be returned by
+ *		be_list.
+ * Parameters:
+ *		zhp - Handle to the zfs snapshot whose information we're
+ *		      collecting.
+ *		name - The name of the snapshot we're processing.
+ *		shapshot - A pointer to the be_snapshot_list structure
+ *			   we're filling in.
+ *		node - The node structure that this snapshot belongs to.
+ * Returns:
+ *		0 - Success
+ *		be_errno_t - Failure
+ * Scope:
+ *		Private
+ */
+static int
+be_get_ss_data(
+	zfs_handle_t *zfshp,
+	char *name,
+	be_snapshot_list_t *snapshot,
+	be_node_list_t *node)
+{
+	nvlist_t	*propval = NULL;
+	nvlist_t	*userprops = NULL;
+	char		*prop_str = NULL;
+	int		err = 0;
+
+	if (zfshp == NULL || name == NULL || snapshot == NULL || node == NULL) {
+		be_print_err(gettext("be_get_ss_data: invalid arguments, "
+		    "can not be NULL\n"));
+		return (BE_ERR_INVAL);
+	}
+
+	errno = 0;
+
+	snapshot->be_snapshot_name = strdup(name);
+	if ((err = errno) != 0) {
+		be_print_err(gettext("be_get_ss_data: failed to copy name\n"));
+		return (errno_to_be_err(err));
+	}
+
+	snapshot->be_snapshot_creation = (time_t)zfs_prop_get_int(zfshp,
+	    ZFS_PROP_CREATION);
+	if ((err = zfs_err_to_be_err(g_zfs)) != 0) {
+		be_print_err(gettext(
+		    "be_get_ss_data: get creation "
+		    "time failed (%d)\n"), err);
+		return (err);
+	}
+
+	/*
+	 * Try to get this snapshot's cleanup policy from its
+	 * user properties first.  If not there, use default
+	 * cleanup policy.
+	 */
+	if ((userprops = zfs_get_user_props(zfshp)) != NULL &&
+	    nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
+	    &propval) == 0 && nvlist_lookup_string(propval,
+	    ZPROP_VALUE, &prop_str) == 0) {
+		snapshot->be_snapshot_type =
+		    strdup(prop_str);
+	} else {
+		snapshot->be_snapshot_type =
+		    strdup(be_default_policy());
+	}
+
+	snapshot->be_snapshot_space_used = zfs_prop_get_int(zfshp,
+	    ZFS_PROP_USED);
+	if ((err = zfs_err_to_be_err(g_zfs)) != 0) {
+		be_print_err(gettext(
+		    "be_get_ss_data: get space "
+		    "used failed (%d)\n"), err);
+		return (err);
+	}
+	node->be_node_num_snapshots++;
+	return (err);
+}
+
+/*
+ * Function:	be_list_alloc
+ * Description: Helper function used to allocate memory for the various
+ *		sructures that make up a BE node.
+ * Parameters:
+ *		err - Used to return any errors encountered.
+ *			BE_SUCCESS - Success
+ *			BE_ERR_NOMEM - Allocation failure
+ *		size - The size of memory to allocate.
+ * Returns:
+ *		Success - A pointer to the allocated memory
+ * 		Failure - NULL
+ * Scope:
+ *		Private
+ */
+static void*
+be_list_alloc(int *err, size_t size)
+{
+	void *bep = NULL;
+
+	bep = calloc(1, size);
+	if (bep == NULL) {
+		be_print_err(gettext("be_list_alloc: memory "
+		    "allocation failed\n"));
+		*err = BE_ERR_NOMEM;
+	}
+	*err = BE_SUCCESS;
+	return (bep);
+}
--- a/usr/src/lib/libbe/tbeadm/tbeadm.c	Tue Feb 03 15:49:13 2009 -0800
+++ b/usr/src/lib/libbe/tbeadm/tbeadm.c	Wed Feb 04 12:39:55 2009 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -78,7 +78,7 @@
 	    "\ttbeadm destroy [-fs] beName\n"
 	    "\ttbeadm create_snap [-p policy] beName [snapshot]\n"
 	    "\ttbeadm destroy_snap beName snapshot\n"
-	    "\ttbeadm list\n"
+	    "\ttbeadm list [-s] [beName]\n"
 	    "\ttbeadm mount [-s ro|rw] beName mountpoint\n"
 	    "\ttbeadm unmount [-f] beName\n"
 	    "\ttbeadm rename origBeName newBeName\n"
@@ -409,9 +409,26 @@
 	int		err = 0;
 	be_node_list_t	*be_nodes;
 	be_node_list_t	*cur_be;
+	boolean_t	snaps = B_FALSE;
+	int		c = 0;
 
-	if (argc > 1) {
-		err = be_list(argv[1], &be_nodes);
+	while ((c = getopt(argc, argv, "s")) != -1) {
+		switch (c) {
+		case 's':
+			snaps = B_TRUE;
+			break;
+		default:
+			usage();
+			return (1);
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+
+
+	if (argc == 1) {
+		err = be_list(argv[0], &be_nodes);
 	} else {
 		err = be_list(NULL, &be_nodes);
 	}
@@ -441,6 +458,17 @@
 			    (ds_len < 16 ? "\t\t" : "\t"),
 			    cur_be->be_policy_type,
 			    cur_be->be_uuid_str ? cur_be->be_uuid_str : "-");
+			if (snaps) {
+				be_snapshot_list_t *snapshots = NULL;
+				printf("Snapshot Name\n");
+				printf("--------------\n");
+				for (snapshots = cur_be->be_node_snapshots;
+				    snapshots != NULL; snapshots =
+				    snapshots->be_next_snapshot) {
+					printf("%s\n",
+					    snapshots->be_snapshot_name);
+				}
+			}
 		}
 	}
 
@@ -459,7 +487,6 @@
 		usage();
 		return (1);
 	}
-printf("argc is %d and argv is %s\n", argc, argv[0]);
 
 	obe_name = argv[0];
 	nbe_name = argv[1];