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