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