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