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 2011 Nexenta Systems, Inc. All rights reserved.
  28  */
  29 
  30 /*
  31  * System includes
  32  */
  33 #include <assert.h>
  34 #include <libintl.h>
  35 #include <libnvpair.h>
  36 #include <libzfs.h>
  37 #include <stdio.h>
  38 #include <stdlib.h>
  39 #include <string.h>
  40 #include <sys/types.h>
  41 #include <sys/stat.h>
  42 #include <unistd.h>
  43 
  44 #include <libbe.h>
  45 #include <libbe_priv.h>
  46 
  47 /* Private function prototypes */
  48 static int be_rollback_check_callback(zfs_handle_t *, void *);
  49 static int be_rollback_callback(zfs_handle_t *, void *);
  50 
  51 
  52 /* ******************************************************************** */
  53 /*                      Public Functions                                */
  54 /* ******************************************************************** */
  55 
  56 /*
  57  * Function:    be_create_snapshot
  58  * Description: Creates a recursive snapshot of all the datasets within a BE.
  59  *              If the name of the BE to snapshot is not provided, it assumes
  60  *              we're snapshotting the currently running BE.  If the snapshot
  61  *              name is not provided it creates an auto named snapshot, which
  62  *              will be returned to the caller upon success.
  63  * Parameters:
  64  *              be_attrs - pointer to nvlist_t of attributes being passed in.
  65  *                      The following attributes are used by this function:
  66  *
  67  *                      BE_ATTR_ORIG_BE_NAME            *optional
  68  *                      BE_ATTR_SNAP_NAME               *optional
  69  *                      BE_ATTR_POLICY                  *optional
  70  *
  71  *                      If the BE_ATTR_SNAP_NAME was not passed in, upon
  72  *                      successful BE snapshot creation, the following
  73  *                      attribute value will be returned to the caller by
  74  *                      setting it in the be_attrs parameter passed in:
  75  *
  76  *                      BE_ATTR_SNAP_NAME
  77  *
  78  * Return:
  79  *              BE_SUCCESS - Success
  80  *              be_errno_t - Failure
  81  * Scope:
  82  *              Public
  83  */
  84 int
  85 be_create_snapshot(nvlist_t *be_attrs)
  86 {
  87         char            *be_name = NULL;
  88         char            *snap_name = NULL;
  89         char            *policy = NULL;
  90         boolean_t       autoname = B_FALSE;
  91         int             ret = BE_SUCCESS;
  92 
  93         /* Initialize libzfs handle */
  94         if (!be_zfs_init())
  95                 return (BE_ERR_INIT);
  96 
  97         /* Get original BE name if one was provided */
  98         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
  99             BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &be_name, NULL) != 0) {
 100                 be_print_err(gettext("be_create_snapshot: failed to "
 101                     "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
 102                 be_zfs_fini();
 103                 return (BE_ERR_INVAL);
 104         }
 105 
 106         /* Validate original BE name if one was provided */
 107         if (be_name != NULL && !be_valid_be_name(be_name)) {
 108                 be_print_err(gettext("be_create_snapshot: "
 109                     "invalid BE name %s\n"), be_name);
 110                 be_zfs_fini();
 111                 return (BE_ERR_INVAL);
 112         }
 113 
 114         /* Get snapshot name to create if one was provided */
 115         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 116             BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &snap_name, NULL) != 0) {
 117                 be_print_err(gettext("be_create_snapshot: "
 118                     "failed to lookup BE_ATTR_SNAP_NAME attribute\n"));
 119                 be_zfs_fini();
 120                 return (BE_ERR_INVAL);
 121         }
 122 
 123         /* Get BE policy to create this snapshot under */
 124         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 125             BE_ATTR_POLICY, DATA_TYPE_STRING, &policy, NULL) != 0) {
 126                 be_print_err(gettext("be_create_snapshot: "
 127                     "failed to lookup BE_ATTR_POLICY attribute\n"));
 128                 be_zfs_fini();
 129                 return (BE_ERR_INVAL);
 130         }
 131 
 132         /*
 133          * If no snap_name ws provided, we're going to create an
 134          * auto named snapshot.  Set flag so that we know to pass
 135          * the auto named snapshot to the caller later.
 136          */
 137         if (snap_name == NULL)
 138                 autoname = B_TRUE;
 139 
 140         if ((ret = _be_create_snapshot(be_name, &snap_name, policy))
 141             == BE_SUCCESS) {
 142                 if (autoname == B_TRUE) {
 143                         /*
 144                          * Set auto named snapshot name in the
 145                          * nvlist passed in by the caller.
 146                          */
 147                         if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME,
 148                             snap_name) != 0) {
 149                                 be_print_err(gettext("be_create_snapshot: "
 150                                     "failed to add auto snap name (%s) to "
 151                                     "be_attrs\n"), snap_name);
 152                                 ret = BE_ERR_NOMEM;
 153                         }
 154                 }
 155         }
 156 
 157         be_zfs_fini();
 158 
 159         return (ret);
 160 }
 161 
 162 /*
 163  * Function:    be_destroy_snapshot
 164  * Description: Iterates through all the datasets of the BE and deletes
 165  *              the snapshots of each one with the specified name.  If the
 166  *              BE name is not provided, it assumes we're operating on the
 167  *              currently running BE.  The name of the snapshot name to
 168  *              destroy must be provided.
 169  * Parameters:
 170  *              be_attrs - pointer to nvlist_t of attributes being passed in.
 171  *                         The following attribute values are used by this
 172  *                         function:
 173  *
 174  *                         BE_ATTR_ORIG_BE_NAME         *optional
 175  *                         BE_ATTR_SNAP_NAME            *required
 176  * Return:
 177  *              BE_SUCCESS - Success
 178  *              be_errno_t - Failure
 179  * Scope:
 180  *              Public
 181  */
 182 int
 183 be_destroy_snapshot(nvlist_t *be_attrs)
 184 {
 185         char    *be_name = NULL;
 186         char    *snap_name = NULL;
 187         int     ret = BE_SUCCESS;
 188 
 189         /* Initialize libzfs handle */
 190         if (!be_zfs_init())
 191                 return (BE_ERR_INIT);
 192 
 193         /* Get original BE name if one was provided */
 194         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 195             BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &be_name, NULL) != 0) {
 196                 be_print_err(gettext("be_destroy_snapshot: "
 197                     "failed to lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
 198                 return (BE_ERR_INVAL);
 199         }
 200 
 201         /* Validate original BE name if one was provided */
 202         if (be_name != NULL && !be_valid_be_name(be_name)) {
 203                 be_print_err(gettext("be_destroy_snapshot: "
 204                     "invalid BE name %s\n"), be_name);
 205                 return (BE_ERR_INVAL);
 206         }
 207 
 208         /* Get snapshot name to destroy */
 209         if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, &snap_name)
 210             != 0) {
 211                 be_print_err(gettext("be_destroy_snapshot: "
 212                     "failed to lookup BE_ATTR_SNAP_NAME attribute.\n"));
 213                 return (BE_ERR_INVAL);
 214         }
 215 
 216         ret = _be_destroy_snapshot(be_name, snap_name);
 217 
 218         be_zfs_fini();
 219 
 220         return (ret);
 221 }
 222 
 223 /*
 224  * Function:    be_rollback
 225  * Description: Rolls back a BE and all of its children datasets to the
 226  *              named snapshot.  All of the BE's datasets must have the
 227  *              named snapshot for this function to succeed.  If the name
 228  *              of the BE is not passed in, this function assumes we're
 229  *              operating on the currently booted live BE.
 230  *
 231  *              Note - This function does not check if the BE has any
 232  *              younger snapshots than the one we're trying to rollback to.
 233  *              If it does, then those younger snapshots and their dependent
 234  *              clone file systems will get destroyed in the process of
 235  *              rolling back.
 236  *
 237  * Parameters:
 238  *              be_attrs - pointer to nvlist_t of attributes being passed in.
 239  *                         The following attributes are used by this function:
 240  *
 241  *                         BE_ATTR_ORIG_BE_NAME         *optional
 242  *                         BE_ATTR_SNAP_NAME            *required
 243  *
 244  * Returns:
 245  *              BE_SUCCESS - Success
 246  *              be_errno_t - Failure
 247  * Scope:
 248  *              Public
 249  */
 250 int
 251 be_rollback(nvlist_t *be_attrs)
 252 {
 253         be_transaction_data_t   bt = { 0 };
 254         zfs_handle_t            *zhp = NULL;
 255         zpool_handle_t          *zphp;
 256         char                    obe_root_ds[MAXPATHLEN];
 257         char                    *obe_name = NULL;
 258         int                     zret = 0, ret = BE_SUCCESS;
 259         struct be_defaults be_defaults;
 260 
 261         /* Initialize libzfs handle */
 262         if (!be_zfs_init())
 263                 return (BE_ERR_INIT);
 264 
 265         if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
 266                 return (ret);
 267         }
 268 
 269         /* Get original BE name if one was provided */
 270         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 271             BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
 272                 be_print_err(gettext("be_rollback: "
 273                     "failed to lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
 274                 return (BE_ERR_INVAL);
 275         }
 276 
 277         be_get_defaults(&be_defaults);
 278 
 279         /* If original BE name not provided, use current BE */
 280         if (obe_name != NULL) {
 281                 bt.obe_name = obe_name;
 282                 /* Validate original BE name  */
 283                 if (!be_valid_be_name(bt.obe_name)) {
 284                         be_print_err(gettext("be_rollback: "
 285                             "invalid BE name %s\n"), bt.obe_name);
 286                         return (BE_ERR_INVAL);
 287                 }
 288         }
 289 
 290         /* Get snapshot name to rollback to */
 291         if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, &bt.obe_snap_name)
 292             != 0) {
 293                 be_print_err(gettext("be_rollback: "
 294                     "failed to lookup BE_ATTR_SNAP_NAME attribute.\n"));
 295                 return (BE_ERR_INVAL);
 296         }
 297 
 298         if (be_defaults.be_deflt_rpool_container) {
 299                 if ((zphp = zpool_open(g_zfs, bt.obe_zpool)) == NULL) {
 300                         be_print_err(gettext("be_rollback: failed to "
 301                             "open rpool (%s): %s\n"), bt.obe_zpool,
 302                             libzfs_error_description(g_zfs));
 303                         return (zfs_err_to_be_err(g_zfs));
 304                 }
 305                 zret = be_find_zpool_callback(zphp, &bt);
 306         } else {
 307                 /* Find which zpool obe_name lives in */
 308                 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) ==
 309                     0) {
 310                         be_print_err(gettext("be_rollback: "
 311                             "failed to find zpool for BE (%s)\n"), bt.obe_name);
 312                         return (BE_ERR_BE_NOENT);
 313                 } else if (zret < 0) {
 314                         be_print_err(gettext("be_rollback: "
 315                             "zpool_iter failed: %s\n"),
 316                             libzfs_error_description(g_zfs));
 317                         return (zfs_err_to_be_err(g_zfs));
 318                 }
 319         }
 320 
 321         /* Generate string for BE's root dataset */
 322         be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
 323             sizeof (obe_root_ds));
 324         bt.obe_root_ds = obe_root_ds;
 325 
 326         /* Get handle to BE's root dataset */
 327         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) {
 328                 be_print_err(gettext("be_rollback: "
 329                     "failed to open BE root dataset (%s): %s\n"),
 330                     bt.obe_root_ds, libzfs_error_description(g_zfs));
 331                 return (zfs_err_to_be_err(g_zfs));
 332         }
 333 
 334         /*
 335          * Check that snapshot name exists for this BE and all of its
 336          * children file systems.  This call will end up closing the
 337          * zfs handle passed in whether it succeeds or fails.
 338          */
 339         if ((ret = be_rollback_check_callback(zhp, bt.obe_snap_name)) != 0) {
 340                 zhp = NULL;
 341                 return (ret);
 342         }
 343 
 344         /* Get handle to BE's root dataset */
 345         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) {
 346                 be_print_err(gettext("be_rollback: "
 347                     "failed to open BE root dataset (%s): %s\n"),
 348                     bt.obe_root_ds, libzfs_error_description(g_zfs));
 349                 return (zfs_err_to_be_err(g_zfs));
 350         }
 351 
 352         /*
 353          * Iterate through a BE's datasets and roll them all back to
 354          * the specified snapshot.  This call will end up closing the
 355          * zfs handle passed in whether it succeeds or fails.
 356          */
 357         if ((ret = be_rollback_callback(zhp, bt.obe_snap_name)) != 0) {
 358                 zhp = NULL;
 359                 be_print_err(gettext("be_rollback: "
 360                     "failed to rollback BE %s to %s\n"), bt.obe_name,
 361                     bt.obe_snap_name);
 362                 return (ret);
 363         }
 364         zhp = NULL;
 365         be_zfs_fini();
 366         return (BE_SUCCESS);
 367 }
 368 
 369 
 370 /* ******************************************************************** */
 371 /*                      Semi-Private Functions                          */
 372 /* ******************************************************************** */
 373 
 374 /*
 375  * Function:    _be_create_snapshot
 376  * Description: see be_create_snapshot
 377  * Parameters:
 378  *              be_name - The name of the BE that we're taking a snapshot of.
 379  *              snap_name - The name of the snapshot we're creating. If
 380  *                      snap_name is NULL an auto generated name will be used,
 381  *                      and upon success, will return that name via this
 382  *                      reference pointer.  The caller is responsible for
 383  *                      freeing the returned name.
 384  *              policy - The clean-up policy type. (library wide use only)
 385  * Return:
 386  *              BE_SUCCESS - Success
 387  *              be_errno_t - Failure
 388  * Scope:
 389  *              Semi-private (library wide use only)
 390  */
 391 int
 392 _be_create_snapshot(char *be_name, char **snap_name, char *policy)
 393 {
 394         be_transaction_data_t   bt = { 0 };
 395         zfs_handle_t            *zhp = NULL;
 396         nvlist_t                *ss_props = NULL;
 397         char                    ss[MAXPATHLEN];
 398         char                    root_ds[MAXPATHLEN];
 399         int                     pool_version = 0;
 400         int                     i = 0;
 401         int                     zret = 0, ret = BE_SUCCESS;
 402         boolean_t               autoname = B_FALSE;
 403 
 404         /* Set parameters in bt structure */
 405         bt.obe_name = be_name;
 406         bt.obe_snap_name = *snap_name;
 407         bt.policy = policy;
 408 
 409         /* If original BE name not supplied, use current BE */
 410         if (bt.obe_name == NULL) {
 411                 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
 412                         return (ret);
 413                 }
 414         }
 415 
 416         /* Find which zpool obe_name lives in */
 417         if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
 418                 be_print_err(gettext("be_create_snapshot: failed to "
 419                     "find zpool for BE (%s)\n"), bt.obe_name);
 420                 return (BE_ERR_BE_NOENT);
 421         } else if (zret < 0) {
 422                 be_print_err(gettext("be_create_snapshot: "
 423                     "zpool_iter failed: %s\n"),
 424                     libzfs_error_description(g_zfs));
 425                 return (zfs_err_to_be_err(g_zfs));
 426         }
 427 
 428         be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds,
 429             sizeof (root_ds));
 430         bt.obe_root_ds = root_ds;
 431 
 432         /* If BE policy not specified, use the default policy */
 433         if (bt.policy == NULL) {
 434                 bt.policy = be_default_policy();
 435         } else {
 436                 /* Validate policy type */
 437                 if (!valid_be_policy(bt.policy)) {
 438                         be_print_err(gettext("be_create_snapshot: "
 439                             "invalid BE policy type (%s)\n"), bt.policy);
 440                         return (BE_ERR_INVAL);
 441                 }
 442         }
 443 
 444         /*
 445          * If snapshot name not specified, set auto name flag and
 446          * generate auto snapshot name.
 447          */
 448         if (bt.obe_snap_name == NULL) {
 449                 autoname = B_TRUE;
 450                 if ((bt.obe_snap_name = be_auto_snap_name())
 451                     == NULL) {
 452                         be_print_err(gettext("be_create_snapshot: "
 453                             "failed to create auto snapshot name\n"));
 454                         ret =  BE_ERR_AUTONAME;
 455                         goto done;
 456                 }
 457         }
 458 
 459         /* Generate the name of the snapshot to take. */
 460         (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds,
 461             bt.obe_snap_name);
 462 
 463         /* Get handle to BE's root dataset */
 464         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET))
 465             == NULL) {
 466                 be_print_err(gettext("be_create_snapshot: "
 467                     "failed to open BE root dataset (%s): %s\n"),
 468                     bt.obe_root_ds, libzfs_error_description(g_zfs));
 469                 ret = zfs_err_to_be_err(g_zfs);
 470                 goto done;
 471         }
 472 
 473         /* Get the ZFS pool version of the pool where this dataset resides */
 474         if (zfs_spa_version(zhp, &pool_version) != 0) {
 475                 be_print_err(gettext("be_create_snapshot: failed to "
 476                     "get ZFS pool version for %s: %s\n"), zfs_get_name(zhp),
 477                     libzfs_error_description(g_zfs));
 478         }
 479 
 480         /*
 481          * If ZFS pool version supports snapshot user properties, store
 482          * cleanup policy there.  Otherwise don't set one - this snapshot
 483          * will always inherit the cleanup policy from its parent.
 484          */
 485         if (pool_version >= SPA_VERSION_SNAP_PROPS) {
 486                 if (nvlist_alloc(&ss_props, NV_UNIQUE_NAME, 0) != 0) {
 487                         be_print_err(gettext("be_create_snapshot: internal "
 488                             "error: out of memory\n"));
 489                         return (BE_ERR_NOMEM);
 490                 }
 491                 if (nvlist_add_string(ss_props, BE_POLICY_PROPERTY, bt.policy)
 492                     != 0) {
 493                         be_print_err(gettext("be_create_snapshot: internal "
 494                             "error: out of memory\n"));
 495                         nvlist_free(ss_props);
 496                         return (BE_ERR_NOMEM);
 497                 }
 498         } else if (policy != NULL) {
 499                 /*
 500                  * If an explicit cleanup policy was requested
 501                  * by the caller and we don't support it, error out.
 502                  */
 503                 be_print_err(gettext("be_create_snapshot: cannot set "
 504                     "cleanup policy: ZFS pool version is %d\n"), pool_version);
 505                 return (BE_ERR_NOTSUP);
 506         }
 507 
 508         /* Create the snapshots recursively */
 509         if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props) != 0) {
 510                 if (!autoname || libzfs_errno(g_zfs) != EZFS_EXISTS) {
 511                         be_print_err(gettext("be_create_snapshot: "
 512                             "recursive snapshot of %s failed: %s\n"),
 513                             ss, libzfs_error_description(g_zfs));
 514 
 515                         if (libzfs_errno(g_zfs) == EZFS_EXISTS)
 516                                 ret = BE_ERR_SS_EXISTS;
 517                         else
 518                                 ret = zfs_err_to_be_err(g_zfs);
 519 
 520                         goto done;
 521                 } else {
 522                         for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) {
 523 
 524                                 /* Sleep 1 before retrying */
 525                                 (void) sleep(1);
 526 
 527                                 /* Generate new auto snapshot name. */
 528                                 free(bt.obe_snap_name);
 529                                 if ((bt.obe_snap_name =
 530                                     be_auto_snap_name()) == NULL) {
 531                                         be_print_err(gettext(
 532                                             "be_create_snapshot: failed to "
 533                                             "create auto snapshot name\n"));
 534                                         ret = BE_ERR_AUTONAME;
 535                                         goto done;
 536                                 }
 537 
 538                                 /* Generate string of the snapshot to take. */
 539                                 (void) snprintf(ss, sizeof (ss), "%s@%s",
 540                                     bt.obe_root_ds, bt.obe_snap_name);
 541 
 542                                 /* Create the snapshots recursively */
 543                                 if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props)
 544                                     != 0) {
 545                                         if (libzfs_errno(g_zfs) !=
 546                                             EZFS_EXISTS) {
 547                                                 be_print_err(gettext(
 548                                                     "be_create_snapshot: "
 549                                                     "recursive snapshot of %s "
 550                                                     "failed: %s\n"), ss,
 551                                                     libzfs_error_description(
 552                                                     g_zfs));
 553                                                 ret = zfs_err_to_be_err(g_zfs);
 554                                                 goto done;
 555                                         }
 556                                 } else {
 557                                         break;
 558                                 }
 559                         }
 560 
 561                         /*
 562                          * If we exhausted the maximum number of tries,
 563                          * free the auto snap name and set error.
 564                          */
 565                         if (i == BE_AUTO_NAME_MAX_TRY) {
 566                                 be_print_err(gettext("be_create_snapshot: "
 567                                     "failed to create unique auto snapshot "
 568                                     "name\n"));
 569                                 free(bt.obe_snap_name);
 570                                 bt.obe_snap_name = NULL;
 571                                 ret = BE_ERR_AUTONAME;
 572                         }
 573                 }
 574         }
 575 
 576         /*
 577          * If we succeeded in creating an auto named snapshot, store
 578          * the name in the nvlist passed in by the caller.
 579          */
 580         if (autoname && bt.obe_snap_name) {
 581                 *snap_name = bt.obe_snap_name;
 582         }
 583 
 584 done:
 585         ZFS_CLOSE(zhp);
 586 
 587         if (ss_props != NULL)
 588                 nvlist_free(ss_props);
 589 
 590         return (ret);
 591 }
 592 
 593 /*
 594  * Function:    _be_destroy_snapshot
 595  * Description: see be_destroy_snapshot
 596  * Parameters:
 597  *              be_name - The name of the BE that the snapshot belongs to.
 598  *              snap_name - The name of the snapshot we're destroying.
 599  * Return:
 600  *              BE_SUCCESS - Success
 601  *              be_errno_t - Failure
 602  * Scope:
 603  *              Semi-private (library wide use only)
 604  */
 605 int
 606 _be_destroy_snapshot(char *be_name, char *snap_name)
 607 {
 608         be_transaction_data_t   bt = { 0 };
 609         zfs_handle_t            *zhp;
 610         char                    ss[MAXPATHLEN];
 611         char                    root_ds[MAXPATHLEN];
 612         int                     err = BE_SUCCESS, ret = BE_SUCCESS;
 613 
 614         /* Make sure we actaully have a snapshot name */
 615         if (snap_name == NULL) {
 616                 be_print_err(gettext("be_destroy_snapshot: "
 617                     "invalid snapshot name\n"));
 618                 return (BE_ERR_INVAL);
 619         }
 620 
 621         /* Set parameters in bt structure */
 622         bt.obe_name = be_name;
 623         bt.obe_snap_name = snap_name;
 624 
 625         /* If original BE name not supplied, use current BE */
 626         if (bt.obe_name == NULL) {
 627                 if ((err = be_find_current_be(&bt)) != BE_SUCCESS) {
 628                         return (err);
 629                 }
 630         }
 631 
 632         /* Find which zpool be_name lives in */
 633         if ((ret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
 634                 be_print_err(gettext("be_destroy_snapshot: "
 635                     "failed to find zpool for BE (%s)\n"), bt.obe_name);
 636                 return (BE_ERR_BE_NOENT);
 637         } else if (ret < 0) {
 638                 be_print_err(gettext("be_destroy_snapshot: "
 639                     "zpool_iter failed: %s\n"),
 640                     libzfs_error_description(g_zfs));
 641                 return (zfs_err_to_be_err(g_zfs));
 642         }
 643 
 644         be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds,
 645             sizeof (root_ds));
 646         bt.obe_root_ds = root_ds;
 647 
 648         zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET);
 649         if (zhp == NULL) {
 650                 /*
 651                  * The zfs_open failed, return an error.
 652                  */
 653                 be_print_err(gettext("be_destroy_snapshot: "
 654                     "failed to open BE root dataset (%s): %s\n"),
 655                     bt.obe_root_ds, libzfs_error_description(g_zfs));
 656                 err = zfs_err_to_be_err(g_zfs);
 657         } else {
 658                 /*
 659                  * Generate the name of the snapshot to take.
 660                  */
 661                 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_name,
 662                     bt.obe_snap_name);
 663 
 664                 /*
 665                  * destroy the snapshot.
 666                  */
 667                 /*
 668                  * The boolean set to B_FALSE and passed to zfs_destroy_snaps()
 669                  * tells zfs to process and destroy the snapshots now.
 670                  * Otherwise the call will potentially return where the
 671                  * snapshot isn't actually destroyed yet, and ZFS is waiting
 672                  * until all the references to the snapshot have been
 673                  * released before actually destroying the snapshot.
 674                  */
 675                 if (zfs_destroy_snaps(zhp, bt.obe_snap_name, B_FALSE) != 0) {
 676                         err = zfs_err_to_be_err(g_zfs);
 677                         be_print_err(gettext("be_destroy_snapshot: "
 678                             "failed to destroy snapshot %s: %s\n"), ss,
 679                             libzfs_error_description(g_zfs));
 680                 }
 681         }
 682 
 683         ZFS_CLOSE(zhp);
 684 
 685         return (err);
 686 }
 687 
 688 /* ******************************************************************** */
 689 /*                      Private Functions                               */
 690 /* ******************************************************************** */
 691 
 692 /*
 693  * Function:    be_rollback_check_callback
 694  * Description: Callback function used to iterate through a BE's filesystems
 695  *              to check if a given snapshot name exists.
 696  * Parameters:
 697  *              zhp - zfs_handle_t pointer to filesystem being processed.
 698  *              data - name of the snapshot to check for.
 699  * Returns:
 700  *              0 - Success, snapshot name exists for all filesystems.
 701  *              be_errno_t - Failure, snapshot name does not exist for all
 702  *              filesystems.
 703  * Scope:
 704  *              Private
 705  */
 706 static int
 707 be_rollback_check_callback(zfs_handle_t *zhp, void *data)
 708 {
 709         char            *snap_name = data;
 710         char            ss[MAXPATHLEN];
 711         int             ret = BE_SUCCESS;
 712 
 713         /* Generate string for this filesystem's snapshot name */
 714         (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name);
 715 
 716         /* Check if snapshot exists */
 717         if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) {
 718                 be_print_err(gettext("be_rollback_check_callback: "
 719                     "snapshot does not exist %s\n"), ss);
 720                 ZFS_CLOSE(zhp);
 721                 return (BE_ERR_SS_NOENT);
 722         }
 723 
 724         /* Iterate this dataset's children and check them */
 725         if ((ret = zfs_iter_filesystems(zhp, be_rollback_check_callback,
 726             snap_name)) != 0) {
 727                 ZFS_CLOSE(zhp);
 728                 return (ret);
 729         }
 730 
 731         ZFS_CLOSE(zhp);
 732         return (0);
 733 }
 734 
 735 /*
 736  * Function:    be_rollback_callback
 737  * Description: Callback function used to iterate through a BE's filesystems
 738  *              and roll them all back to the specified snapshot name.
 739  * Parameters:
 740  *              zhp - zfs_handle_t pointer to filesystem being processed.
 741  *              data - name of snapshot to rollback to.
 742  * Returns:
 743  *              0 - Success
 744  *              be_errno_t - Failure
 745  * Scope:
 746  *              Private
 747  */
 748 static int
 749 be_rollback_callback(zfs_handle_t *zhp, void *data)
 750 {
 751         zfs_handle_t    *zhp_snap = NULL;
 752         char            *snap_name = data;
 753         char            ss[MAXPATHLEN];
 754         int             ret = 0;
 755 
 756         /* Generate string for this filesystem's snapshot name */
 757         (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name);
 758 
 759         /* Get handle to this filesystem's snapshot */
 760         if ((zhp_snap = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
 761                 be_print_err(gettext("be_rollback_callback: "
 762                     "failed to open snapshot %s: %s\n"), zfs_get_name(zhp),
 763                     libzfs_error_description(g_zfs));
 764                 ret = zfs_err_to_be_err(g_zfs);
 765                 ZFS_CLOSE(zhp);
 766                 return (ret);
 767         }
 768 
 769         /* Rollback dataset */
 770         if (zfs_rollback(zhp, zhp_snap, B_FALSE) != 0) {
 771                 be_print_err(gettext("be_rollback_callback: "
 772                     "failed to rollback BE dataset %s to snapshot %s: %s\n"),
 773                     zfs_get_name(zhp), ss, libzfs_error_description(g_zfs));
 774                 ret = zfs_err_to_be_err(g_zfs);
 775                 ZFS_CLOSE(zhp_snap);
 776                 ZFS_CLOSE(zhp);
 777                 return (ret);
 778         }
 779 
 780         ZFS_CLOSE(zhp_snap);
 781         /* Iterate this dataset's children and roll them back */
 782         if ((ret = zfs_iter_filesystems(zhp, be_rollback_callback,
 783             snap_name)) != 0) {
 784                 ZFS_CLOSE(zhp);
 785                 return (ret);
 786         }
 787 
 788         ZFS_CLOSE(zhp);
 789         return (0);
 790 }