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  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  27  * Copyright 2015 EveryCity Ltd.
  28  * Copyright 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  29  */
  30 
  31 /*
  32  * System includes
  33  */
  34 #include <assert.h>
  35 #include <errno.h>
  36 #include <libgen.h>
  37 #include <libintl.h>
  38 #include <libnvpair.h>
  39 #include <libzfs.h>
  40 #include <stdio.h>
  41 #include <stdlib.h>
  42 #include <string.h>
  43 #include <sys/mntent.h>
  44 #include <sys/mnttab.h>
  45 #include <sys/mount.h>
  46 #include <sys/stat.h>
  47 #include <sys/types.h>
  48 #include <sys/vfstab.h>
  49 #include <sys/zone.h>
  50 #include <sys/mkdev.h>
  51 #include <unistd.h>
  52 
  53 #include <libbe.h>
  54 #include <libbe_priv.h>
  55 
  56 #define BE_TMP_MNTPNT           "/tmp/.be.XXXXXX"
  57 
  58 typedef struct dir_data {
  59         char *dir;
  60         char *ds;
  61 } dir_data_t;
  62 
  63 /* Private function prototypes */
  64 static int be_mount_callback(zfs_handle_t *, void *);
  65 static int be_unmount_callback(zfs_handle_t *, void *);
  66 static int be_get_legacy_fs_callback(zfs_handle_t *, void *);
  67 static int fix_mountpoint(zfs_handle_t *);
  68 static int fix_mountpoint_callback(zfs_handle_t *, void *);
  69 static int get_mountpoint_from_vfstab(char *, const char *, char *, size_t,
  70     boolean_t);
  71 static int loopback_mount_shared_fs(zfs_handle_t *, be_mount_data_t *);
  72 static int loopback_mount_zonepath(const char *, be_mount_data_t *);
  73 static int iter_shared_fs_callback(zfs_handle_t *, void *);
  74 static int zpool_shared_fs_callback(zpool_handle_t *, void *);
  75 static int unmount_shared_fs(be_unmount_data_t *);
  76 static int add_to_fs_list(be_fs_list_data_t *, const char *);
  77 static int be_mount_root(zfs_handle_t *, char *);
  78 static int be_unmount_root(zfs_handle_t *, be_unmount_data_t *);
  79 static int be_mount_zones(zfs_handle_t *, be_mount_data_t *);
  80 static int be_unmount_zones(be_unmount_data_t *);
  81 static int be_mount_one_zone(zfs_handle_t *, be_mount_data_t *, char *, char *,
  82     char *);
  83 static int be_unmount_one_zone(be_unmount_data_t *, char *, char *, char *);
  84 static int be_get_ds_from_dir_callback(zfs_handle_t *, void *);
  85 
  86 
  87 /* ******************************************************************** */
  88 /*                      Public Functions                                */
  89 /* ******************************************************************** */
  90 
  91 /*
  92  * Function:    be_mount
  93  * Description: Mounts a BE and its subordinate datasets at a given mountpoint.
  94  * Parameters:
  95  *              be_attrs - pointer to nvlist_t of attributes being passed in.
  96  *                      The following attributes are used by this function:
  97  *
  98  *                      BE_ATTR_ORIG_BE_NAME            *required
  99  *                      BE_ATTR_MOUNTPOINT              *required
 100  *                      BE_ATTR_MOUNT_FLAGS             *optional
 101  * Return:
 102  *              BE_SUCCESS - Success
 103  *              be_errno_t - Failure
 104  * Scope:
 105  *              Public
 106  */
 107 int
 108 be_mount(nvlist_t *be_attrs)
 109 {
 110         char            *be_name = NULL;
 111         char            *mountpoint = NULL;
 112         uint16_t        flags = 0;
 113         int             ret = BE_SUCCESS;
 114 
 115         /* Initialize libzfs handle */
 116         if (!be_zfs_init())
 117                 return (BE_ERR_INIT);
 118 
 119         /* Get original BE name */
 120         if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
 121             != 0) {
 122                 be_print_err(gettext("be_mount: failed to lookup "
 123                     "BE_ATTR_ORIG_BE_NAME attribute\n"));
 124                 return (BE_ERR_INVAL);
 125         }
 126 
 127         /* Validate original BE name */
 128         if (!be_valid_be_name(be_name)) {
 129                 be_print_err(gettext("be_mount: invalid BE name %s\n"),
 130                     be_name);
 131                 return (BE_ERR_INVAL);
 132         }
 133 
 134         /* Get mountpoint */
 135         if (nvlist_lookup_string(be_attrs, BE_ATTR_MOUNTPOINT, &mountpoint)
 136             != 0) {
 137                 be_print_err(gettext("be_mount: failed to lookup "
 138                     "BE_ATTR_MOUNTPOINT attribute\n"));
 139                 return (BE_ERR_INVAL);
 140         }
 141 
 142         /* Get flags */
 143         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 144             BE_ATTR_MOUNT_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
 145                 be_print_err(gettext("be_mount: failed to lookup "
 146                     "BE_ATTR_MOUNT_FLAGS attribute\n"));
 147                 return (BE_ERR_INVAL);
 148         }
 149 
 150         ret = _be_mount(be_name, &mountpoint, flags);
 151 
 152         be_zfs_fini();
 153 
 154         return (ret);
 155 }
 156 
 157 /*
 158  * Function:    be_unmount
 159  * Description: Unmounts a BE and its subordinate datasets.
 160  * Parameters:
 161  *              be_attrs - pointer to nvlist_t of attributes being passed in.
 162  *                      The following attributes are used by this function:
 163  *
 164  *                      BE_ATTR_ORIG_BE_NAME            *required
 165  *                      BE_ATTR_UNMOUNT_FLAGS           *optional
 166  * Return:
 167  *              BE_SUCCESS - Success
 168  *              be_errno_t - Failure
 169  * Scope:
 170  *              Public
 171  */
 172 int
 173 be_unmount(nvlist_t *be_attrs)
 174 {
 175         char            *be_name = NULL;
 176         char            *be_name_mnt = NULL;
 177         char            *ds = NULL;
 178         uint16_t        flags = 0;
 179         int             ret = BE_SUCCESS;
 180 
 181         /* Initialize libzfs handle */
 182         if (!be_zfs_init())
 183                 return (BE_ERR_INIT);
 184 
 185         /* Get original BE name */
 186         if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
 187             != 0) {
 188                 be_print_err(gettext("be_unmount: failed to lookup "
 189                     "BE_ATTR_ORIG_BE_NAME attribute\n"));
 190                 return (BE_ERR_INVAL);
 191         }
 192 
 193         /* Check if we have mountpoint argument instead of BE name */
 194         if (be_name[0] == '/') {
 195                 if ((ds = be_get_ds_from_dir(be_name)) != NULL) {
 196                         if ((be_name_mnt = strrchr(ds, '/')) != NULL) {
 197                                 be_name = be_name_mnt + 1;
 198                         }
 199                 } else {
 200                         be_print_err(gettext("be_unmount: no datasets mounted "
 201                             "at '%s'\n"), be_name);
 202                         return (BE_ERR_INVAL);
 203                 }
 204         }
 205 
 206         /* Validate original BE name */
 207         if (!be_valid_be_name(be_name)) {
 208                 be_print_err(gettext("be_unmount: invalid BE name %s\n"),
 209                     be_name);
 210                 return (BE_ERR_INVAL);
 211         }
 212 
 213         /* Get unmount flags */
 214         if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
 215             BE_ATTR_UNMOUNT_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
 216                 be_print_err(gettext("be_unmount: failed to loookup "
 217                     "BE_ATTR_UNMOUNT_FLAGS attribute\n"));
 218                 return (BE_ERR_INVAL);
 219         }
 220 
 221         ret = _be_unmount(be_name, flags);
 222 
 223         be_zfs_fini();
 224 
 225         return (ret);
 226 }
 227 
 228 /* ******************************************************************** */
 229 /*                      Semi-Private Functions                          */
 230 /* ******************************************************************** */
 231 
 232 /*
 233  * Function:    _be_mount
 234  * Description: Mounts a BE.  If the altroot is not provided, this function
 235  *              will generate a temporary mountpoint to mount the BE at.  It
 236  *              will return this temporary mountpoint to the caller via the
 237  *              altroot reference pointer passed in.  This returned value is
 238  *              allocated on heap storage and is the repsonsibility of the
 239  *              caller to free.
 240  * Parameters:
 241  *              be_name - pointer to name of BE to mount.
 242  *              altroot - reference pointer to altroot of where to mount BE.
 243  *              flags - flag indicating special handling for mounting the BE
 244  * Return:
 245  *              BE_SUCCESS - Success
 246  *              be_errno_t - Failure
 247  * Scope:
 248  *              Semi-private (library wide use only)
 249  */
 250 int
 251 _be_mount(char *be_name, char **altroot, int flags)
 252 {
 253         be_transaction_data_t   bt = { 0 };
 254         be_mount_data_t md = { 0 };
 255         zfs_handle_t    *zhp;
 256         char            obe_root_ds[MAXPATHLEN];
 257         char            *mp = NULL;
 258         char            *tmp_altroot = NULL;
 259         int             ret = BE_SUCCESS, err = 0;
 260         uuid_t          uu = { 0 };
 261         boolean_t       gen_tmp_altroot = B_FALSE;
 262 
 263         if (be_name == NULL || altroot == NULL)
 264                 return (BE_ERR_INVAL);
 265 
 266         /* Set be_name as obe_name in bt structure */
 267         bt.obe_name = be_name;
 268 
 269         /* Find which zpool obe_name lives in */
 270         if ((err = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
 271                 be_print_err(gettext("be_mount: failed to "
 272                     "find zpool for BE (%s)\n"), bt.obe_name);
 273                 return (BE_ERR_BE_NOENT);
 274         } else if (err < 0) {
 275                 be_print_err(gettext("be_mount: zpool_iter failed: %s\n"),
 276                     libzfs_error_description(g_zfs));
 277                 return (zfs_err_to_be_err(g_zfs));
 278         }
 279 
 280         /* Generate string for obe_name's root dataset */
 281         be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
 282             sizeof (obe_root_ds));
 283         bt.obe_root_ds = obe_root_ds;
 284 
 285         /* Get handle to BE's root dataset */
 286         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
 287             NULL) {
 288                 be_print_err(gettext("be_mount: failed to "
 289                     "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
 290                     libzfs_error_description(g_zfs));
 291                 return (zfs_err_to_be_err(g_zfs));
 292         }
 293 
 294         /* Make sure BE's root dataset isn't already mounted somewhere */
 295         if (zfs_is_mounted(zhp, &mp)) {
 296                 ZFS_CLOSE(zhp);
 297                 be_print_err(gettext("be_mount: %s is already mounted "
 298                     "at %s\n"), bt.obe_name, mp != NULL ? mp : "");
 299                 free(mp);
 300                 return (BE_ERR_MOUNTED);
 301         }
 302 
 303         /*
 304          * Fix this BE's mountpoint if its root dataset isn't set to
 305          * either 'legacy' or '/'.
 306          */
 307         if ((ret = fix_mountpoint(zhp)) != BE_SUCCESS) {
 308                 be_print_err(gettext("be_mount: mountpoint check "
 309                     "failed for %s\n"), bt.obe_root_ds);
 310                 ZFS_CLOSE(zhp);
 311                 return (ret);
 312         }
 313 
 314         /*
 315          * If altroot not provided, create a temporary alternate root
 316          * to mount on
 317          */
 318         if (*altroot == NULL) {
 319                 if ((ret = be_make_tmp_mountpoint(&tmp_altroot))
 320                     != BE_SUCCESS) {
 321                         be_print_err(gettext("be_mount: failed to "
 322                             "make temporary mountpoint\n"));
 323                         ZFS_CLOSE(zhp);
 324                         return (ret);
 325                 }
 326                 gen_tmp_altroot = B_TRUE;
 327         } else {
 328                 tmp_altroot = *altroot;
 329         }
 330 
 331         md.altroot = tmp_altroot;
 332         md.shared_fs = flags & BE_MOUNT_FLAG_SHARED_FS;
 333         md.shared_rw = flags & BE_MOUNT_FLAG_SHARED_RW;
 334 
 335         /* Mount the BE's root file system */
 336         if (getzoneid() == GLOBAL_ZONEID) {
 337                 if ((ret = be_mount_root(zhp, tmp_altroot)) != BE_SUCCESS) {
 338                         be_print_err(gettext("be_mount: failed to "
 339                             "mount BE root file system\n"));
 340                         if (gen_tmp_altroot)
 341                                 free(tmp_altroot);
 342                         ZFS_CLOSE(zhp);
 343                         return (ret);
 344                 }
 345         } else {
 346                 /* Legacy mount the zone root dataset */
 347                 if ((ret = be_mount_zone_root(zhp, &md)) != BE_SUCCESS) {
 348                         be_print_err(gettext("be_mount: failed to "
 349                             "mount BE zone root file system\n"));
 350                         free(md.altroot);
 351                         ZFS_CLOSE(zhp);
 352                         return (ret);
 353                 }
 354         }
 355 
 356         /* Iterate through BE's children filesystems */
 357         if ((err = zfs_iter_filesystems(zhp, be_mount_callback,
 358             tmp_altroot)) != 0) {
 359                 be_print_err(gettext("be_mount: failed to "
 360                     "mount BE (%s) on %s\n"), bt.obe_name, tmp_altroot);
 361                 if (gen_tmp_altroot)
 362                         free(tmp_altroot);
 363                 ZFS_CLOSE(zhp);
 364                 return (err);
 365         }
 366 
 367         /*
 368          * Mount shared file systems if mount flag says so.
 369          */
 370         if (md.shared_fs) {
 371                 /*
 372                  * Mount all ZFS file systems not under the BE's root dataset
 373                  */
 374                 (void) zpool_iter(g_zfs, zpool_shared_fs_callback, &md);
 375 
 376                 /* TODO: Mount all non-ZFS file systems - Not supported yet */
 377         }
 378 
 379         /*
 380          * If we're in the global zone and the global zone has a valid uuid,
 381          * mount all supported non-global zones.
 382          */
 383         if (getzoneid() == GLOBAL_ZONEID &&
 384             !(flags & BE_MOUNT_FLAG_NO_ZONES) &&
 385             be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
 386                 if (be_mount_zones(zhp, &md) != BE_SUCCESS) {
 387                         ret = BE_ERR_NO_MOUNTED_ZONE;
 388                 }
 389         }
 390 
 391         ZFS_CLOSE(zhp);
 392 
 393         /*
 394          * If a NULL altroot was passed in, pass the generated altroot
 395          * back to the caller in altroot.
 396          */
 397         if (gen_tmp_altroot) {
 398                 if (ret == BE_SUCCESS || ret == BE_ERR_NO_MOUNTED_ZONE)
 399                         *altroot = tmp_altroot;
 400                 else
 401                         free(tmp_altroot);
 402         }
 403 
 404         return (ret);
 405 }
 406 
 407 /*
 408  * Function:    _be_unmount
 409  * Description: Unmount a BE.
 410  * Parameters:
 411  *              be_name - pointer to name of BE to unmount.
 412  *              flags - flags for unmounting the BE.
 413  * Returns:
 414  *              BE_SUCCESS - Success
 415  *              be_errno_t - Failure
 416  * Scope:
 417  *              Semi-private (library wide use only)
 418  */
 419 int
 420 _be_unmount(char *be_name, int flags)
 421 {
 422         be_transaction_data_t   bt = { 0 };
 423         be_unmount_data_t       ud = { 0 };
 424         zfs_handle_t    *zhp;
 425         uuid_t          uu = { 0 };
 426         char            obe_root_ds[MAXPATHLEN];
 427         char            mountpoint[MAXPATHLEN];
 428         char            *mp = NULL;
 429         int             ret = BE_SUCCESS;
 430         int             zret = 0;
 431 
 432         if (be_name == NULL)
 433                 return (BE_ERR_INVAL);
 434 
 435         /* Set be_name as obe_name in bt structure */
 436         bt.obe_name = be_name;
 437 
 438         /* Find which zpool obe_name lives in */
 439         if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
 440                 be_print_err(gettext("be_unmount: failed to "
 441                     "find zpool for BE (%s)\n"), bt.obe_name);
 442                 return (BE_ERR_BE_NOENT);
 443         } else if (zret < 0) {
 444                 be_print_err(gettext("be_unmount: "
 445                     "zpool_iter failed: %s\n"),
 446                     libzfs_error_description(g_zfs));
 447                 ret = zfs_err_to_be_err(g_zfs);
 448                 return (ret);
 449         }
 450 
 451         /* Generate string for obe_name's root dataset */
 452         be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
 453             sizeof (obe_root_ds));
 454         bt.obe_root_ds = obe_root_ds;
 455 
 456         /* Get handle to BE's root dataset */
 457         if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
 458             NULL) {
 459                 be_print_err(gettext("be_unmount: failed to "
 460                     "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
 461                     libzfs_error_description(g_zfs));
 462                 ret = zfs_err_to_be_err(g_zfs);
 463                 return (ret);
 464         }
 465 
 466         /* Make sure BE's root dataset is mounted somewhere */
 467         if (!zfs_is_mounted(zhp, &mp)) {
 468 
 469                 be_print_err(gettext("be_unmount: "
 470                     "(%s) not mounted\n"), bt.obe_name);
 471 
 472                 /*
 473                  * BE is not mounted, fix this BE's mountpoint if its root
 474                  * dataset isn't set to either 'legacy' or '/'.
 475                  */
 476                 if ((ret = fix_mountpoint(zhp)) != BE_SUCCESS) {
 477                         be_print_err(gettext("be_unmount: mountpoint check "
 478                             "failed for %s\n"), bt.obe_root_ds);
 479                         ZFS_CLOSE(zhp);
 480                         return (ret);
 481                 }
 482 
 483                 ZFS_CLOSE(zhp);
 484                 return (BE_ERR_NOTMOUNTED);
 485         }
 486 
 487         /*
 488          * If we didn't get a mountpoint from the zfs_is_mounted call,
 489          * try and get it from its property.
 490          */
 491         if (mp == NULL) {
 492                 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
 493                     sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
 494                         be_print_err(gettext("be_unmount: failed to "
 495                             "get mountpoint of (%s)\n"), bt.obe_name);
 496                         ZFS_CLOSE(zhp);
 497                         return (BE_ERR_ZFS);
 498                 }
 499         } else {
 500                 (void) strlcpy(mountpoint, mp, sizeof (mountpoint));
 501                 free(mp);
 502         }
 503 
 504         /* If BE mounted as current root, fail */
 505         if (strcmp(mountpoint, "/") == 0) {
 506                 be_print_err(gettext("be_unmount: "
 507                     "cannot unmount currently running BE\n"));
 508                 ZFS_CLOSE(zhp);
 509                 return (BE_ERR_UMOUNT_CURR_BE);
 510         }
 511 
 512         ud.altroot = mountpoint;
 513         ud.force = flags & BE_UNMOUNT_FLAG_FORCE;
 514 
 515         /* Unmount all supported non-global zones if we're in the global zone */
 516         if (getzoneid() == GLOBAL_ZONEID &&
 517             be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
 518                 if ((ret = be_unmount_zones(&ud)) != BE_SUCCESS) {
 519                         ZFS_CLOSE(zhp);
 520                         return (ret);
 521                 }
 522         }
 523 
 524         /* TODO: Unmount all non-ZFS file systems - Not supported yet */
 525 
 526         /* Unmount all ZFS file systems not under the BE root dataset */
 527         if ((ret = unmount_shared_fs(&ud)) != BE_SUCCESS) {
 528                 be_print_err(gettext("be_unmount: failed to "
 529                     "unmount shared file systems\n"));
 530                 ZFS_CLOSE(zhp);
 531                 return (ret);
 532         }
 533 
 534         /* Unmount all children datasets under the BE's root dataset */
 535         if ((zret = zfs_iter_filesystems(zhp, be_unmount_callback,
 536             &ud)) != 0) {
 537                 be_print_err(gettext("be_unmount: failed to "
 538                     "unmount BE (%s)\n"), bt.obe_name);
 539                 ZFS_CLOSE(zhp);
 540                 return (zret);
 541         }
 542 
 543         /* Unmount this BE's root filesystem */
 544         if (getzoneid() == GLOBAL_ZONEID) {
 545                 if ((ret = be_unmount_root(zhp, &ud)) != BE_SUCCESS) {
 546                         ZFS_CLOSE(zhp);
 547                         return (ret);
 548                 }
 549         } else {
 550                 if ((ret = be_unmount_zone_root(zhp, &ud)) != BE_SUCCESS) {
 551                         ZFS_CLOSE(zhp);
 552                         return (ret);
 553                 }
 554         }
 555 
 556         ZFS_CLOSE(zhp);
 557 
 558         return (BE_SUCCESS);
 559 }
 560 
 561 /*
 562  * Function:    be_mount_zone_root
 563  * Description: Mounts the zone root dataset for a zone.
 564  * Parameters:
 565  *              zfs - zfs_handle_t pointer to zone root dataset
 566  *              md - be_mount_data_t pointer to data for zone to be mounted
 567  * Returns:
 568  *              BE_SUCCESS - Success
 569  *              be_errno_t - Failure
 570  * Scope:
 571  *              Semi-private (library wide use only)
 572  */
 573 int
 574 be_mount_zone_root(zfs_handle_t *zhp, be_mount_data_t *md)
 575 {
 576         struct stat buf;
 577         char    mountpoint[MAXPATHLEN];
 578         int     err = 0;
 579 
 580         /* Get mountpoint property of dataset */
 581         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
 582             sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
 583                 be_print_err(gettext("be_mount_zone_root: failed to "
 584                     "get mountpoint property for %s: %s\n"), zfs_get_name(zhp),
 585                     libzfs_error_description(g_zfs));
 586                 return (zfs_err_to_be_err(g_zfs));
 587         }
 588 
 589         /*
 590          * Make sure zone's root dataset is set to 'legacy'.  This is
 591          * currently a requirement in this implementation of zones
 592          * support.
 593          */
 594         if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
 595                 be_print_err(gettext("be_mount_zone_root: "
 596                     "zone root dataset mountpoint is not 'legacy'\n"));
 597                 return (BE_ERR_ZONE_ROOT_NOT_LEGACY);
 598         }
 599 
 600         /* Create the mountpoint if it doesn't exist */
 601         if (lstat(md->altroot, &buf) != 0) {
 602                 if (mkdirp(md->altroot, 0755) != 0) {
 603                         err = errno;
 604                         be_print_err(gettext("be_mount_zone_root: failed "
 605                             "to create mountpoint %s\n"), md->altroot);
 606                         return (errno_to_be_err(err));
 607                 }
 608         }
 609 
 610         /*
 611          * Legacy mount the zone root dataset.
 612          *
 613          * As a workaround for 6176743, we mount the zone's root with the
 614          * MS_OVERLAY option in case an alternate BE is mounted, and we're
 615          * mounting the root for the zone from the current BE here.  When an
 616          * alternate BE is mounted, it ties up the zone's zoneroot directory
 617          * for the current BE since the zone's zonepath is loopback mounted
 618          * from the current BE.
 619          *
 620          * TODO: The MS_OVERLAY option needs to be removed when 6176743
 621          * is fixed.
 622          */
 623         if (mount(zfs_get_name(zhp), md->altroot, MS_OVERLAY, MNTTYPE_ZFS,
 624             NULL, 0, NULL, 0) != 0) {
 625                 err = errno;
 626                 be_print_err(gettext("be_mount_zone_root: failed to "
 627                     "legacy mount zone root dataset (%s) at %s\n"),
 628                     zfs_get_name(zhp), md->altroot);
 629                 return (errno_to_be_err(err));
 630         }
 631 
 632         return (BE_SUCCESS);
 633 }
 634 
 635 /*
 636  * Function:    be_unmount_zone_root
 637  * Description: Unmounts the zone root dataset for a zone.
 638  * Parameters:
 639  *              zhp - zfs_handle_t pointer to zone root dataset
 640  *              ud - be_unmount_data_t pointer to data for zone to be unmounted
 641  * Returns:
 642  *              BE_SUCCESS - Success
 643  *              be_errno_t - Failure
 644  * Scope:
 645  *              Semi-private (library wise use only)
 646  */
 647 int
 648 be_unmount_zone_root(zfs_handle_t *zhp, be_unmount_data_t *ud)
 649 {
 650         char    mountpoint[MAXPATHLEN];
 651 
 652         /* Unmount the dataset */
 653         if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) {
 654                 be_print_err(gettext("be_unmount_zone_root: failed to "
 655                     "unmount zone root dataset %s: %s\n"), zfs_get_name(zhp),
 656                     libzfs_error_description(g_zfs));
 657                 return (zfs_err_to_be_err(g_zfs));
 658         }
 659 
 660         /* Get the current mountpoint property for the zone root dataset */
 661         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
 662             sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
 663                 be_print_err(gettext("be_unmount_zone_root: failed to "
 664                     "get mountpoint property for zone root dataset (%s): %s\n"),
 665                     zfs_get_name(zhp), libzfs_error_description(g_zfs));
 666                 return (zfs_err_to_be_err(g_zfs));
 667         }
 668 
 669         /* If mountpoint not already set to 'legacy', set it to 'legacy' */
 670         if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
 671                 if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
 672                     ZFS_MOUNTPOINT_LEGACY) != 0) {
 673                         be_print_err(gettext("be_unmount_zone_root: "
 674                             "failed to set mountpoint of zone root dataset "
 675                             "%s to 'legacy': %s\n"), zfs_get_name(zhp),
 676                             libzfs_error_description(g_zfs));
 677                         return (zfs_err_to_be_err(g_zfs));
 678                 }
 679         }
 680 
 681         return (BE_SUCCESS);
 682 }
 683 
 684 /*
 685  * Function:    be_get_legacy_fs
 686  * Description: This function iterates through all non-shared file systems
 687  *              of a BE and finds the ones with a legacy mountpoint.  For
 688  *              those file systems, it reads the BE's vfstab to get the
 689  *              mountpoint.  If found, it adds that file system to the
 690  *              be_fs_list_data_t passed in.
 691  *
 692  *              This function can be used to gather legacy mounted file systems
 693  *              for both global BEs and non-global zone BEs.  To get data for
 694  *              a non-global zone BE, the zoneroot_ds and zoneroot parameters
 695  *              will be specified, otherwise they should be set to NULL.
 696  * Parameters:
 697  *              be_name - global BE name from which to get legacy file
 698  *                      system list.
 699  *              be_root_ds - root dataset of global BE.
 700  *              zoneroot_ds - root dataset of zone.
 701  *              zoneroot - zoneroot path of zone.
 702  *              fld - be_fs_list_data_t pointer.
 703  * Returns:
 704  *              BE_SUCCESS - Success
 705  *              be_errno_t - Failure
 706  * Scope:
 707  *              Semi-private (library wide use only)
 708  */
 709 int
 710 be_get_legacy_fs(char *be_name, char *be_root_ds, char *zoneroot_ds,
 711     char *zoneroot, be_fs_list_data_t *fld)
 712 {
 713         zfs_handle_t            *zhp = NULL;
 714         char                    mountpoint[MAXPATHLEN];
 715         boolean_t               mounted_here = B_FALSE;
 716         boolean_t               zone_mounted_here = B_FALSE;
 717         int                     ret = BE_SUCCESS, err = 0;
 718 
 719         if (be_name == NULL || be_root_ds == NULL || fld == NULL)
 720                 return (BE_ERR_INVAL);
 721 
 722         /* Get handle to BE's root dataset */
 723         if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM))
 724             == NULL) {
 725                 be_print_err(gettext("be_get_legacy_fs: failed to "
 726                     "open BE root dataset (%s): %s\n"), be_root_ds,
 727                     libzfs_error_description(g_zfs));
 728                 ret = zfs_err_to_be_err(g_zfs);
 729                 return (ret);
 730         }
 731 
 732         /* If BE is not already mounted, mount it. */
 733         if (!zfs_is_mounted(zhp, &fld->altroot)) {
 734                 if ((ret = _be_mount(be_name, &fld->altroot,
 735                     zoneroot_ds ? BE_MOUNT_FLAG_NULL :
 736                     BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
 737                         be_print_err(gettext("be_get_legacy_fs: "
 738                             "failed to mount BE %s\n"), be_name);
 739                         goto cleanup;
 740                 }
 741 
 742                 mounted_here = B_TRUE;
 743         } else if (fld->altroot == NULL) {
 744                 be_print_err(gettext("be_get_legacy_fs: failed to "
 745                     "get altroot of mounted BE %s: %s\n"),
 746                     be_name, libzfs_error_description(g_zfs));
 747                 ret = zfs_err_to_be_err(g_zfs);
 748                 goto cleanup;
 749         }
 750 
 751         /*
 752          * If a zone root dataset was passed in, we're wanting to get
 753          * legacy mounted file systems for that zone, not the global
 754          * BE.
 755          */
 756         if (zoneroot_ds != NULL) {
 757                 be_mount_data_t         zone_md = { 0 };
 758 
 759                 /* Close off handle to global BE's root dataset */
 760                 ZFS_CLOSE(zhp);
 761 
 762                 /* Get handle to zone's root dataset */
 763                 if ((zhp = zfs_open(g_zfs, zoneroot_ds,
 764                     ZFS_TYPE_FILESYSTEM)) == NULL) {
 765                         be_print_err(gettext("be_get_legacy_fs: failed to "
 766                             "open zone BE root dataset (%s): %s\n"),
 767                             zoneroot_ds, libzfs_error_description(g_zfs));
 768                         ret = zfs_err_to_be_err(g_zfs);
 769                         goto cleanup;
 770                 }
 771 
 772                 /* Make sure the zone we're looking for is mounted */
 773                 if (!zfs_is_mounted(zhp, &zone_md.altroot)) {
 774                         char    zone_altroot[MAXPATHLEN];
 775 
 776                         /* Generate alternate root path for zone */
 777                         (void) snprintf(zone_altroot, sizeof (zone_altroot),
 778                             "%s%s", fld->altroot, zoneroot);
 779                         if ((zone_md.altroot = strdup(zone_altroot)) == NULL) {
 780                                 be_print_err(gettext("be_get_legacy_fs: "
 781                                     "memory allocation failed\n"));
 782                                 ret = BE_ERR_NOMEM;
 783                                 goto cleanup;
 784                         }
 785 
 786                         if ((ret = be_mount_zone_root(zhp, &zone_md))
 787                             != BE_SUCCESS) {
 788                                 be_print_err(gettext("be_get_legacy_fs: "
 789                                     "failed to mount zone root %s\n"),
 790                                     zoneroot_ds);
 791                                 free(zone_md.altroot);
 792                                 zone_md.altroot = NULL;
 793                                 goto cleanup;
 794                         }
 795                         zone_mounted_here = B_TRUE;
 796                 }
 797 
 798                 free(fld->altroot);
 799                 fld->altroot = zone_md.altroot;
 800         }
 801 
 802         /*
 803          * If the root dataset is in the vfstab with a mountpoint of "/",
 804          * add it to the list
 805          */
 806         if (get_mountpoint_from_vfstab(fld->altroot, zfs_get_name(zhp),
 807             mountpoint, sizeof (mountpoint), B_FALSE) == BE_SUCCESS) {
 808                 if (strcmp(mountpoint, "/") == 0) {
 809                         if (add_to_fs_list(fld, zfs_get_name(zhp))
 810                             != BE_SUCCESS) {
 811                                 be_print_err(gettext("be_get_legacy_fs: "
 812                                     "failed to add %s to fs list\n"),
 813                                     zfs_get_name(zhp));
 814                                 ret = BE_ERR_INVAL;
 815                                 goto cleanup;
 816                         }
 817                 }
 818         }
 819 
 820         /* Iterate subordinate file systems looking for legacy mounts */
 821         if ((ret = zfs_iter_filesystems(zhp, be_get_legacy_fs_callback,
 822             fld)) != 0) {
 823                 be_print_err(gettext("be_get_legacy_fs: "
 824                     "failed to iterate  %s to get legacy mounts\n"),
 825                     zfs_get_name(zhp));
 826         }
 827 
 828 cleanup:
 829         /* If we mounted the zone BE, unmount it */
 830         if (zone_mounted_here) {
 831                 be_unmount_data_t       zone_ud = { 0 };
 832 
 833                 zone_ud.altroot = fld->altroot;
 834                 zone_ud.force = B_TRUE;
 835                 if ((err = be_unmount_zone_root(zhp, &zone_ud)) != BE_SUCCESS) {
 836                         be_print_err(gettext("be_get_legacy_fs: "
 837                             "failed to unmount zone root %s\n"),
 838                             zoneroot_ds);
 839                         if (ret == BE_SUCCESS)
 840                                 ret = err;
 841                 }
 842         }
 843 
 844         /* If we mounted this BE, unmount it */
 845         if (mounted_here) {
 846                 if ((err = _be_unmount(be_name, 0)) != BE_SUCCESS) {
 847                         be_print_err(gettext("be_get_legacy_fs: "
 848                             "failed to unmount %s\n"), be_name);
 849                         if (ret == BE_SUCCESS)
 850                                 ret = err;
 851                 }
 852         }
 853 
 854         ZFS_CLOSE(zhp);
 855 
 856         free(fld->altroot);
 857         fld->altroot = NULL;
 858 
 859         return (ret);
 860 }
 861 
 862 /*
 863  * Function:    be_free_fs_list
 864  * Description: Function used to free the members of a be_fs_list_data_t
 865  *                      structure.
 866  * Parameters:
 867  *              fld - be_fs_list_data_t pointer to free.
 868  * Returns:
 869  *              None
 870  * Scope:
 871  *              Semi-private (library wide use only)
 872  */
 873 void
 874 be_free_fs_list(be_fs_list_data_t *fld)
 875 {
 876         int     i;
 877 
 878         if (fld == NULL)
 879                 return;
 880 
 881         free(fld->altroot);
 882 
 883         if (fld->fs_list == NULL)
 884                 return;
 885 
 886         for (i = 0; i < fld->fs_num; i++)
 887                 free(fld->fs_list[i]);
 888 
 889         free(fld->fs_list);
 890 }
 891 
 892 /*
 893  * Function:    be_get_ds_from_dir(char *dir)
 894  * Description: Given a directory path, find the underlying dataset mounted
 895  *              at that directory path if there is one.   The returned name
 896  *              is allocated in heap storage, so the caller is responsible
 897  *              for freeing it.
 898  * Parameters:
 899  *              dir - char pointer of directory to find.
 900  * Returns:
 901  *              NULL - if directory is not mounted from a dataset.
 902  *              name of dataset mounted at dir.
 903  * Scope:
 904  *              Semi-private (library wide use only)
 905  */
 906 char *
 907 be_get_ds_from_dir(char *dir)
 908 {
 909         dir_data_t      dd = { 0 };
 910         char            resolved_dir[MAXPATHLEN];
 911 
 912         /* Make sure length of dir is within the max length */
 913         if (dir == NULL || strlen(dir) >= MAXPATHLEN)
 914                 return (NULL);
 915 
 916         /* Resolve dir in case its lofs mounted */
 917         (void) strlcpy(resolved_dir, dir, sizeof (resolved_dir));
 918         z_resolve_lofs(resolved_dir, sizeof (resolved_dir));
 919 
 920         dd.dir = resolved_dir;
 921 
 922         (void) zfs_iter_root(g_zfs, be_get_ds_from_dir_callback, &dd);
 923 
 924         return (dd.ds);
 925 }
 926 
 927 /*
 928  * Function:    be_make_tmp_mountpoint
 929  * Description: This function generates a random temporary mountpoint
 930  *              and creates that mountpoint directory.  It returns the
 931  *              mountpoint in heap storage, so the caller is responsible
 932  *              for freeing it.
 933  * Parameters:
 934  *              tmp_mp - reference to pointer of where to store generated
 935  *                      temporary mountpoint.
 936  * Returns:
 937  *              BE_SUCCESS - Success
 938  *              be_errno_t - Failure
 939  * Scope:
 940  *              Semi-private (library wide use only)
 941  */
 942 int
 943 be_make_tmp_mountpoint(char **tmp_mp)
 944 {
 945         int     err = 0;
 946 
 947         if ((*tmp_mp = (char *)calloc(1, sizeof (BE_TMP_MNTPNT) + 1)) == NULL) {
 948                 be_print_err(gettext("be_make_tmp_mountpoint: "
 949                     "malloc failed\n"));
 950                 return (BE_ERR_NOMEM);
 951         }
 952         (void) strlcpy(*tmp_mp, BE_TMP_MNTPNT, sizeof (BE_TMP_MNTPNT) + 1);
 953         if (mkdtemp(*tmp_mp) == NULL) {
 954                 err = errno;
 955                 be_print_err(gettext("be_make_tmp_mountpoint: mkdtemp() failed "
 956                     "for %s: %s\n"), *tmp_mp, strerror(err));
 957                 free(*tmp_mp);
 958                 *tmp_mp = NULL;
 959                 return (errno_to_be_err(err));
 960         }
 961 
 962         return (BE_SUCCESS);
 963 }
 964 
 965 /*
 966  * Function:    be_mount_pool
 967  * Description: This function determines if the pool's datase is mounted
 968  *              and if not it is used to mount the pool's dataset. The
 969  *              function returns the current mountpoint if we are able
 970  *              to mount the dataset.
 971  * Parameters:
 972  *              zhp - handle to the pool's dataset
 973  *              tmp_mntpnt - The temporary mountpoint that the pool's
 974  *                            dataset is mounted on. This is set only
 975  *                            if the attempt to mount the dataset at it's
 976  *                            set mountpoint fails, and we've used a
 977  *                            temporary mount point for this dataset. It
 978  *                            is expected that the caller will free this
 979  *                            memory.
 980  *              orig_mntpnt - The original mountpoint for the pool. If a
 981  *                            temporary mount point was needed this will
 982  *                            be used to reset the mountpoint property to
 983  *                            it's original mountpoint. It is expected that
 984  *                            the caller will free this memory.
 985  *              pool_mounted - This flag indicates that the pool was mounted
 986  *                             in this function.
 987  * Returns:
 988  *              BE_SUCCESS - Success
 989  *              be_errno_t - Failure
 990  * Scope:
 991  *              Semi-private (library wide use only)
 992  */
 993 int
 994 be_mount_pool(
 995         zfs_handle_t *zhp,
 996         char **tmp_mntpnt,
 997         char **orig_mntpnt,
 998         boolean_t *pool_mounted)
 999 {
1000 
1001         char            mountpoint[MAXPATHLEN];
1002         int             ret = 0;
1003 
1004         *tmp_mntpnt = NULL;
1005         *orig_mntpnt = NULL;
1006         *pool_mounted = B_FALSE;
1007 
1008         if (!zfs_is_mounted(zhp, NULL)) {
1009                 if (zfs_mount(zhp, NULL, 0) != 0) {
1010                         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
1011                             sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
1012                                 be_print_err(gettext("be_mount_pool: failed to "
1013                                     "get mountpoint of (%s): %s\n"),
1014                                     zfs_get_name(zhp),
1015                                     libzfs_error_description(g_zfs));
1016                                 return (zfs_err_to_be_err(g_zfs));
1017                         }
1018                         if ((*orig_mntpnt = strdup(mountpoint)) == NULL) {
1019                                 be_print_err(gettext("be_mount_pool: memory "
1020                                     "allocation failed\n"));
1021                                 return (BE_ERR_NOMEM);
1022                         }
1023                         /*
1024                          * attempt to mount on a temp mountpoint
1025                          */
1026                         if ((ret = be_make_tmp_mountpoint(tmp_mntpnt))
1027                             != BE_SUCCESS) {
1028                                 be_print_err(gettext("be_mount_pool: failed "
1029                                     "to make temporary mountpoint\n"));
1030                                 free(*orig_mntpnt);
1031                                 *orig_mntpnt = NULL;
1032                                 return (ret);
1033                         }
1034 
1035                         if (zfs_prop_set(zhp,
1036                             zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1037                             *tmp_mntpnt) != 0) {
1038                                 be_print_err(gettext("be_mount_pool: failed "
1039                                     "to set mountpoint of pool dataset %s to "
1040                                     "%s: %s\n"), zfs_get_name(zhp),
1041                                     *orig_mntpnt,
1042                                     libzfs_error_description(g_zfs));
1043                                 free(*tmp_mntpnt);
1044                                 free(*orig_mntpnt);
1045                                 *orig_mntpnt = NULL;
1046                                 *tmp_mntpnt = NULL;
1047                                 return (zfs_err_to_be_err(g_zfs));
1048                         }
1049 
1050                         if (zfs_mount(zhp, NULL, 0) != 0) {
1051                                 be_print_err(gettext("be_mount_pool: failed "
1052                                     "to mount dataset %s at %s: %s\n"),
1053                                     zfs_get_name(zhp), *tmp_mntpnt,
1054                                     libzfs_error_description(g_zfs));
1055                                 ret = zfs_err_to_be_err(g_zfs);
1056                                 if (zfs_prop_set(zhp,
1057                                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1058                                     mountpoint) != 0) {
1059                                         be_print_err(gettext("be_mount_pool: "
1060                                             "failed to set mountpoint of pool "
1061                                             "dataset %s to %s: %s\n"),
1062                                             zfs_get_name(zhp), *tmp_mntpnt,
1063                                             libzfs_error_description(g_zfs));
1064                                 }
1065                                 free(*tmp_mntpnt);
1066                                 free(*orig_mntpnt);
1067                                 *orig_mntpnt = NULL;
1068                                 *tmp_mntpnt = NULL;
1069                                 return (ret);
1070                         }
1071                 }
1072                 *pool_mounted = B_TRUE;
1073         }
1074 
1075         return (BE_SUCCESS);
1076 }
1077 
1078 /*
1079  * Function:    be_unmount_pool
1080  * Description: This function is used to unmount the pool's dataset if we
1081  *              mounted it previously using be_mount_pool().
1082  * Parameters:
1083  *              zhp - handle to the pool's dataset
1084  *              tmp_mntpnt - If a temprary mount point was used this will
1085  *                           be set. Since this was created in be_mount_pool
1086  *                           we will need to clean it up here.
1087  *              orig_mntpnt - The original mountpoint for the pool. This is
1088  *                            used to set the dataset mountpoint property
1089  *                            back to it's original value in the case where a
1090  *                            temporary mountpoint was used.
1091  * Returns:
1092  *              BE_SUCCESS - Success
1093  *              be_errno_t - Failure
1094  * Scope:
1095  *              Semi-private (library wide use only)
1096  */
1097 int
1098 be_unmount_pool(
1099         zfs_handle_t *zhp,
1100         char *tmp_mntpnt,
1101         char *orig_mntpnt)
1102 {
1103         if (zfs_unmount(zhp, NULL, 0) != 0) {
1104                 be_print_err(gettext("be_unmount_pool: failed to "
1105                     "unmount pool (%s): %s\n"), zfs_get_name(zhp),
1106                     libzfs_error_description(g_zfs));
1107                 return (zfs_err_to_be_err(g_zfs));
1108         }
1109         if (orig_mntpnt != NULL) {
1110                 if (tmp_mntpnt != NULL &&
1111                     strcmp(orig_mntpnt, tmp_mntpnt) != 0) {
1112                         (void) rmdir(tmp_mntpnt);
1113                 }
1114                 if (zfs_prop_set(zhp,
1115                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1116                     orig_mntpnt) != 0) {
1117                         be_print_err(gettext("be_unmount_pool: failed "
1118                             "to set the mountpoint for dataset (%s) to "
1119                             "%s: %s\n"), zfs_get_name(zhp), orig_mntpnt,
1120                             libzfs_error_description(g_zfs));
1121                         return (zfs_err_to_be_err(g_zfs));
1122                 }
1123         }
1124 
1125         return (BE_SUCCESS);
1126 }
1127 
1128 /* ******************************************************************** */
1129 /*                      Private Functions                               */
1130 /* ******************************************************************** */
1131 
1132 /*
1133  * Function:    be_mount_callback
1134  * Description: Callback function used to iterate through all of a BE's
1135  *              subordinate file systems and to mount them accordingly.
1136  * Parameters:
1137  *              zhp - zfs_handle_t pointer to current file system being
1138  *                      processed.
1139  *              data - pointer to the altroot of where to mount BE.
1140  * Returns:
1141  *              0 - Success
1142  *              be_errno_t - Failure
1143  * Scope:
1144  *              Private
1145  */
1146 static int
1147 be_mount_callback(zfs_handle_t *zhp, void *data)
1148 {
1149         zprop_source_t  sourcetype;
1150         const char      *fs_name = zfs_get_name(zhp);
1151         char            source[ZFS_MAXNAMELEN];
1152         char            *altroot = data;
1153         char            zhp_mountpoint[MAXPATHLEN];
1154         char            mountpoint[MAXPATHLEN];
1155         int             ret = 0;
1156 
1157         /* Get dataset's mountpoint and source values */
1158         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, zhp_mountpoint,
1159             sizeof (zhp_mountpoint), &sourcetype, source, sizeof (source),
1160             B_FALSE) != 0) {
1161                 be_print_err(gettext("be_mount_callback: failed to "
1162                     "get mountpoint and sourcetype for %s\n"),
1163                     fs_name);
1164                 ZFS_CLOSE(zhp);
1165                 return (BE_ERR_ZFS);
1166         }
1167 
1168         /*
1169          * Set this filesystem's 'canmount' property to 'noauto' just incase
1170          * it's been set 'on'.  We do this so that when we change its
1171          * mountpoint zfs won't immediately try to mount it.
1172          */
1173         if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")) {
1174                 be_print_err(gettext("be_mount_callback: failed to "
1175                     "set canmount to 'noauto' (%s)\n"), fs_name);
1176                 ZFS_CLOSE(zhp);
1177                 return (BE_ERR_ZFS);
1178         }
1179 
1180         /*
1181          * If the mountpoint is none, there's nothing to do, goto next.
1182          * If the mountpoint is legacy, legacy mount it with mount(2).
1183          * If the mountpoint is inherited, its mountpoint should
1184          * already be set.  If it's not, then explicitly fix-up
1185          * the mountpoint now by appending its explicitly set
1186          * mountpoint value to the BE mountpoint.
1187          */
1188         if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_NONE) == 0) {
1189                 goto next;
1190         } else if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1191                 /*
1192                  * If the mountpoint is set to 'legacy', we need to
1193                  * dig into this BE's vfstab to figure out where to
1194                  * mount it, and just mount it via mount(2).
1195                  */
1196                 if (get_mountpoint_from_vfstab(altroot, fs_name,
1197                     mountpoint, sizeof (mountpoint), B_TRUE) == BE_SUCCESS) {
1198 
1199                         /* Legacy mount the file system */
1200                         if (mount(fs_name, mountpoint, MS_DATA,
1201                             MNTTYPE_ZFS, NULL, 0, NULL, 0) != 0) {
1202                                 be_print_err(
1203                                     gettext("be_mount_callback: "
1204                                     "failed to mount %s on %s\n"),
1205                                     fs_name, mountpoint);
1206                         }
1207                 } else {
1208                         be_print_err(
1209                             gettext("be_mount_callback: "
1210                             "no entry for %s in vfstab, "
1211                             "skipping ...\n"), fs_name);
1212                 }
1213 
1214                 goto next;
1215 
1216         } else if (sourcetype & ZPROP_SRC_INHERITED) {
1217                 /*
1218                  * If the mountpoint is inherited, its parent should have
1219                  * already been processed so its current mountpoint value
1220                  * is what its mountpoint ought to be.
1221                  */
1222                 (void) strlcpy(mountpoint, zhp_mountpoint, sizeof (mountpoint));
1223         } else if (sourcetype & ZPROP_SRC_LOCAL) {
1224                 /*
1225                  * Else process dataset with explicitly set mountpoint.
1226                  */
1227                 (void) snprintf(mountpoint, sizeof (mountpoint),
1228                     "%s%s", altroot, zhp_mountpoint);
1229 
1230                 /* Set the new mountpoint for the dataset */
1231                 if (zfs_prop_set(zhp,
1232                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1233                     mountpoint)) {
1234                         be_print_err(gettext("be_mount_callback: "
1235                             "failed to set mountpoint for %s to "
1236                             "%s\n"), fs_name, mountpoint);
1237                         ZFS_CLOSE(zhp);
1238                         return (BE_ERR_ZFS);
1239                 }
1240         } else {
1241                 be_print_err(gettext("be_mount_callback: "
1242                     "mountpoint sourcetype of %s is %d, skipping ...\n"),
1243                     fs_name, sourcetype);
1244 
1245                 goto next;
1246         }
1247 
1248         /* Mount this filesystem */
1249         if (zfs_mount(zhp, NULL, 0) != 0) {
1250                 be_print_err(gettext("be_mount_callback: failed to "
1251                     "mount dataset %s at %s: %s\n"), fs_name, mountpoint,
1252                     libzfs_error_description(g_zfs));
1253                 /*
1254                  * Set this filesystem's 'mountpoint' property back to what
1255                  * it was
1256                  */
1257                 if (sourcetype & ZPROP_SRC_LOCAL &&
1258                     strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
1259                         (void) zfs_prop_set(zhp,
1260                             zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1261                             zhp_mountpoint);
1262                 }
1263 
1264                 ZFS_CLOSE(zhp);
1265                 return (BE_ERR_MOUNT);
1266         }
1267 
1268 next:
1269         /* Iterate through this dataset's children and mount them */
1270         if ((ret = zfs_iter_filesystems(zhp, be_mount_callback,
1271             altroot)) != 0) {
1272                 ZFS_CLOSE(zhp);
1273                 return (ret);
1274         }
1275 
1276 
1277         ZFS_CLOSE(zhp);
1278         return (0);
1279 }
1280 
1281 /*
1282  * Function:    be_unmount_callback
1283  * Description: Callback function used to iterate through all of a BE's
1284  *              subordinate file systems and to unmount them.
1285  * Parameters:
1286  *              zhp - zfs_handle_t pointer to current file system being
1287  *                      processed.
1288  *              data - pointer to the mountpoint of where BE is mounted.
1289  * Returns:
1290  *              0 - Success
1291  *              be_errno_t - Failure
1292  * Scope:
1293  *              Private
1294  */
1295 static int
1296 be_unmount_callback(zfs_handle_t *zhp, void *data)
1297 {
1298         be_unmount_data_t       *ud = data;
1299         zprop_source_t  sourcetype;
1300         const char      *fs_name = zfs_get_name(zhp);
1301         char            source[ZFS_MAXNAMELEN];
1302         char            mountpoint[MAXPATHLEN];
1303         char            *zhp_mountpoint;
1304         int             ret = 0;
1305 
1306         /* Iterate down this dataset's children first */
1307         if (zfs_iter_filesystems(zhp, be_unmount_callback, ud)) {
1308                 ret = BE_ERR_UMOUNT;
1309                 goto done;
1310         }
1311 
1312         /* Is dataset even mounted ? */
1313         if (!zfs_is_mounted(zhp, NULL))
1314                 goto done;
1315 
1316         /* Unmount this file system */
1317         if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) {
1318                 be_print_err(gettext("be_unmount_callback: "
1319                     "failed to unmount %s: %s\n"), fs_name,
1320                     libzfs_error_description(g_zfs));
1321                 ret = zfs_err_to_be_err(g_zfs);
1322                 goto done;
1323         }
1324 
1325         /* Get dataset's current mountpoint and source value */
1326         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
1327             sizeof (mountpoint), &sourcetype, source, sizeof (source),
1328             B_FALSE) != 0) {
1329                 be_print_err(gettext("be_unmount_callback: "
1330                     "failed to get mountpoint and sourcetype for %s: %s\n"),
1331                     fs_name, libzfs_error_description(g_zfs));
1332                 ret = zfs_err_to_be_err(g_zfs);
1333                 goto done;
1334         }
1335 
1336         if (sourcetype & ZPROP_SRC_INHERITED) {
1337                 /*
1338                  * If the mountpoint is inherited we don't need to
1339                  * do anything.  When its parent gets processed
1340                  * its mountpoint will be set accordingly.
1341                  */
1342                 goto done;
1343         } else if (sourcetype & ZPROP_SRC_LOCAL) {
1344 
1345                 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1346                         /*
1347                          * If the mountpoint is set to 'legacy', its already
1348                          * been unmounted (from above call to zfs_unmount), and
1349                          * we don't need to do anything else with it.
1350                          */
1351                         goto done;
1352 
1353                 } else {
1354                         /*
1355                          * Else process dataset with explicitly set mountpoint.
1356                          */
1357 
1358                         /*
1359                          * Get this dataset's mountpoint relative to
1360                          * the BE's mountpoint.
1361                          */
1362                         if ((strncmp(mountpoint, ud->altroot,
1363                             strlen(ud->altroot)) == 0) &&
1364                             (mountpoint[strlen(ud->altroot)] == '/')) {
1365 
1366                                 zhp_mountpoint = mountpoint +
1367                                     strlen(ud->altroot);
1368 
1369                                 /* Set this dataset's mountpoint value */
1370                                 if (zfs_prop_set(zhp,
1371                                     zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1372                                     zhp_mountpoint)) {
1373                                         be_print_err(
1374                                             gettext("be_unmount_callback: "
1375                                             "failed to set mountpoint for "
1376                                             "%s to %s: %s\n"), fs_name,
1377                                             zhp_mountpoint,
1378                                             libzfs_error_description(g_zfs));
1379                                         ret = zfs_err_to_be_err(g_zfs);
1380                                 }
1381                         } else {
1382                                 be_print_err(
1383                                     gettext("be_unmount_callback: "
1384                                     "%s not mounted under BE's altroot %s, "
1385                                     "skipping ...\n"), fs_name, ud->altroot);
1386                                 /*
1387                                  * fs_name is mounted but not under the
1388                                  * root for this BE.
1389                                  */
1390                                 ret = BE_ERR_INVALMOUNTPOINT;
1391                         }
1392                 }
1393         } else {
1394                 be_print_err(gettext("be_unmount_callback: "
1395                     "mountpoint sourcetype of %s is %d, skipping ...\n"),
1396                     fs_name, sourcetype);
1397                 ret = BE_ERR_ZFS;
1398         }
1399 
1400 done:
1401         /* Set this filesystem's 'canmount' property to 'noauto' */
1402         if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")) {
1403                 be_print_err(gettext("be_unmount_callback: "
1404                     "failed to set canmount to 'noauto' (%s)\n"), fs_name);
1405                 if (ret == 0)
1406                         ret = BE_ERR_ZFS;
1407         }
1408 
1409         ZFS_CLOSE(zhp);
1410         return (ret);
1411 }
1412 
1413 /*
1414  * Function:    be_get_legacy_fs_callback
1415  * Description: The callback function is used to iterate through all
1416  *              non-shared file systems of a BE, finding ones that have
1417  *              a legacy mountpoint and an entry in the BE's vfstab.
1418  *              It adds these file systems to the callback data.
1419  * Parameters:
1420  *              zhp - zfs_handle_t pointer to current file system being
1421  *                      processed.
1422  *              data - be_fs_list_data_t pointer
1423  * Returns:
1424  *              0 - Success
1425  *              be_errno_t - Failure
1426  * Scope:
1427  *              Private
1428  */
1429 static int
1430 be_get_legacy_fs_callback(zfs_handle_t *zhp, void *data)
1431 {
1432         be_fs_list_data_t       *fld = data;
1433         const char              *fs_name = zfs_get_name(zhp);
1434         char                    zhp_mountpoint[MAXPATHLEN];
1435         char                    mountpoint[MAXPATHLEN];
1436         int                     ret = 0;
1437 
1438         /* Get this dataset's mountpoint property */
1439         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, zhp_mountpoint,
1440             sizeof (zhp_mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
1441                 be_print_err(gettext("be_get_legacy_fs_callback: "
1442                     "failed to get mountpoint for %s: %s\n"),
1443                     fs_name, libzfs_error_description(g_zfs));
1444                 ret = zfs_err_to_be_err(g_zfs);
1445                 ZFS_CLOSE(zhp);
1446                 return (ret);
1447         }
1448 
1449         /*
1450          * If mountpoint is legacy, try to get its mountpoint from this BE's
1451          * vfstab.  If it exists in the vfstab, add this file system to the
1452          * callback data.
1453          */
1454         if (strcmp(zhp_mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1455                 if (get_mountpoint_from_vfstab(fld->altroot, fs_name,
1456                     mountpoint, sizeof (mountpoint), B_FALSE) != BE_SUCCESS) {
1457                         be_print_err(gettext("be_get_legacy_fs_callback: "
1458                             "no entry for %s in vfstab, "
1459                             "skipping ...\n"), fs_name);
1460 
1461                         goto next;
1462                 }
1463 
1464                 /* Record file system into the callback data. */
1465                 if (add_to_fs_list(fld, zfs_get_name(zhp)) != BE_SUCCESS) {
1466                         be_print_err(gettext("be_get_legacy_fs_callback: "
1467                             "failed to add %s to fs list\n"), mountpoint);
1468                         ZFS_CLOSE(zhp);
1469                         return (BE_ERR_NOMEM);
1470                 }
1471         }
1472 
1473 next:
1474         /* Iterate through this dataset's children file systems */
1475         if ((ret = zfs_iter_filesystems(zhp, be_get_legacy_fs_callback,
1476             fld)) != 0) {
1477                 ZFS_CLOSE(zhp);
1478                 return (ret);
1479         }
1480         ZFS_CLOSE(zhp);
1481         return (0);
1482 }
1483 
1484 /*
1485  * Function:    add_to_fs_list
1486  * Description: Function used to add a file system to the fs_list array in
1487  *                      a be_fs_list_data_t structure.
1488  * Parameters:
1489  *              fld - be_fs_list_data_t pointer
1490  *              fs - file system to add
1491  * Returns:
1492  *              BE_SUCCESS - Success
1493  *              1 - Failure
1494  * Scope:
1495  *              Private
1496  */
1497 static int
1498 add_to_fs_list(be_fs_list_data_t *fld, const char *fs)
1499 {
1500         if (fld == NULL || fs == NULL)
1501                 return (1);
1502 
1503         if ((fld->fs_list = (char **)realloc(fld->fs_list,
1504             sizeof (char *)*(fld->fs_num + 1))) == NULL) {
1505                 be_print_err(gettext("add_to_fs_list: "
1506                     "memory allocation failed\n"));
1507                 return (1);
1508         }
1509 
1510         if ((fld->fs_list[fld->fs_num++] = strdup(fs)) == NULL) {
1511                 be_print_err(gettext("add_to_fs_list: "
1512                     "memory allocation failed\n"));
1513                 return (1);
1514         }
1515 
1516         return (BE_SUCCESS);
1517 }
1518 
1519 /*
1520  * Function:    zpool_shared_fs_callback
1521  * Description: Callback function used to iterate through all existing pools
1522  *              to find and mount all shared filesystems.  This function
1523  *              processes the pool's "pool data" dataset, then uses
1524  *              iter_shared_fs_callback to iterate through the pool's
1525  *              datasets.
1526  * Parameters:
1527  *              zlp - zpool_handle_t pointer to the current pool being
1528  *                      looked at.
1529  *              data - be_mount_data_t pointer
1530  * Returns:
1531  *              0 - Success
1532  *              be_errno_t - Failure
1533  * Scope:
1534  *              Private
1535  */
1536 static int
1537 zpool_shared_fs_callback(zpool_handle_t *zlp, void *data)
1538 {
1539         be_mount_data_t *md = data;
1540         zfs_handle_t    *zhp = NULL;
1541         const char      *zpool = zpool_get_name(zlp);
1542         int             ret = 0;
1543 
1544         /*
1545          * Get handle to pool's "pool data" dataset
1546          */
1547         if ((zhp = zfs_open(g_zfs, zpool, ZFS_TYPE_FILESYSTEM)) == NULL) {
1548                 be_print_err(gettext("zpool_shared_fs: "
1549                     "failed to open pool dataset %s: %s\n"), zpool,
1550                     libzfs_error_description(g_zfs));
1551                 ret = zfs_err_to_be_err(g_zfs);
1552                 zpool_close(zlp);
1553                 return (ret);
1554         }
1555 
1556         /* Process this pool's "pool data" dataset */
1557         (void) loopback_mount_shared_fs(zhp, md);
1558 
1559         /* Interate through this pool's children */
1560         (void) zfs_iter_filesystems(zhp, iter_shared_fs_callback, md);
1561 
1562         ZFS_CLOSE(zhp);
1563         zpool_close(zlp);
1564 
1565         return (0);
1566 }
1567 
1568 /*
1569  * Function:    iter_shared_fs_callback
1570  * Description: Callback function used to iterate through a pool's datasets
1571  *              to find and mount all shared filesystems.  It makes sure to
1572  *              find the BE container dataset of the pool, if it exists, and
1573  *              does not process and iterate down that path.
1574  *
1575  *              Note - This function iterates linearly down the
1576  *              hierarchical dataset paths and mounts things as it goes
1577  *              along.  It does not make sure that something deeper down
1578  *              a dataset path has an interim mountpoint for something
1579  *              processed earlier.
1580  *
1581  * Parameters:
1582  *              zhp - zfs_handle_t pointer to the current dataset being
1583  *                      processed.
1584  *              data - be_mount_data_t pointer
1585  * Returns:
1586  *              0 - Success
1587  *              be_errno_t - Failure
1588  * Scope:
1589  *              Private
1590  */
1591 static int
1592 iter_shared_fs_callback(zfs_handle_t *zhp, void *data)
1593 {
1594         be_mount_data_t *md = data;
1595         const char      *name = zfs_get_name(zhp);
1596         char            container_ds[MAXPATHLEN];
1597         char            tmp_name[MAXPATHLEN];
1598         char            *pool;
1599 
1600         /* Get the pool's name */
1601         (void) strlcpy(tmp_name, name, sizeof (tmp_name));
1602         pool = strtok(tmp_name, "/");
1603 
1604         if (pool) {
1605                 /* Get the name of this pool's container dataset */
1606                 be_make_container_ds(pool, container_ds,
1607                     sizeof (container_ds));
1608 
1609                 /*
1610                  * If what we're processing is this pool's BE container
1611                  * dataset, skip it.
1612                  */
1613                 if (strcmp(name, container_ds) == 0) {
1614                         ZFS_CLOSE(zhp);
1615                         return (0);
1616                 }
1617         } else {
1618                 /* Getting the pool name failed, return error */
1619                 be_print_err(gettext("iter_shared_fs_callback: "
1620                     "failed to get pool name from %s\n"), name);
1621                 ZFS_CLOSE(zhp);
1622                 return (BE_ERR_POOL_NOENT);
1623         }
1624 
1625         /* Mount this shared filesystem */
1626         (void) loopback_mount_shared_fs(zhp, md);
1627 
1628         /* Iterate this dataset's children file systems */
1629         (void) zfs_iter_filesystems(zhp, iter_shared_fs_callback, md);
1630         ZFS_CLOSE(zhp);
1631 
1632         return (0);
1633 }
1634 
1635 /*
1636  * Function:    loopback_mount_shared_fs
1637  * Description: This function loopback mounts a file system into the altroot
1638  *              area of the BE being mounted.  Since these are shared file
1639  *              systems, they are expected to be already mounted for the
1640  *              current BE, and this function just loopback mounts them into
1641  *              the BE mountpoint.  If they are not mounted for the current
1642  *              live system, they are skipped and not mounted into the BE
1643  *              we're mounting.
1644  * Parameters:
1645  *              zhp - zfs_handle_t pointer to the dataset to loopback mount
1646  *              md - be_mount_data_t pointer
1647  * Returns:
1648  *              BE_SUCCESS - Success
1649  *              be_errno_t - Failure
1650  * Scope:
1651  *              Private
1652  */
1653 static int
1654 loopback_mount_shared_fs(zfs_handle_t *zhp, be_mount_data_t *md)
1655 {
1656         char            zhp_mountpoint[MAXPATHLEN];
1657         char            mountpoint[MAXPATHLEN];
1658         char            *mp = NULL;
1659         char            optstr[MAX_MNTOPT_STR];
1660         int             mflag = MS_OPTIONSTR;
1661         int             err;
1662 
1663         /*
1664          * Check if file system is currently mounted and not delegated
1665          * to a non-global zone (if we're in the global zone)
1666          */
1667         if (zfs_is_mounted(zhp, &mp) && (getzoneid() != GLOBAL_ZONEID ||
1668             !zfs_prop_get_int(zhp, ZFS_PROP_ZONED))) {
1669                 /*
1670                  * If we didn't get a mountpoint from the zfs_is_mounted call,
1671                  * get it from the mountpoint property.
1672                  */
1673                 if (mp == NULL) {
1674                         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
1675                             zhp_mountpoint, sizeof (zhp_mountpoint), NULL,
1676                             NULL, 0, B_FALSE) != 0) {
1677                                 be_print_err(
1678                                     gettext("loopback_mount_shared_fs: "
1679                                     "failed to get mountpoint property\n"));
1680                                 return (BE_ERR_ZFS);
1681                         }
1682                 } else {
1683                         (void) strlcpy(zhp_mountpoint, mp,
1684                             sizeof (zhp_mountpoint));
1685                         free(mp);
1686                 }
1687 
1688                 (void) snprintf(mountpoint, sizeof (mountpoint), "%s%s",
1689                     md->altroot, zhp_mountpoint);
1690 
1691                 /* Mount it read-only if read-write was not requested */
1692                 if (!md->shared_rw) {
1693                         mflag |= MS_RDONLY;
1694                 }
1695 
1696                 /* Add the "nosub" option to the mount options string */
1697                 (void) strlcpy(optstr, MNTOPT_NOSUB, sizeof (optstr));
1698 
1699                 /* Loopback mount this dataset at the altroot */
1700                 if (mount(zhp_mountpoint, mountpoint, mflag, MNTTYPE_LOFS,
1701                     NULL, 0, optstr, sizeof (optstr)) != 0) {
1702                         err = errno;
1703                         be_print_err(gettext("loopback_mount_shared_fs: "
1704                             "failed to loopback mount %s at %s: %s\n"),
1705                             zhp_mountpoint, mountpoint, strerror(err));
1706                         return (BE_ERR_MOUNT);
1707                 }
1708         }
1709 
1710         return (BE_SUCCESS);
1711 }
1712 
1713 /*
1714  * Function:    loopback_mount_zonepath
1715  * Description: This function loopback mounts a zonepath into the altroot
1716  *              area of the BE being mounted.
1717  * Parameters:
1718  *              zonepath - pointer to zone path in the current BE
1719  *              md - be_mount_data_t pointer
1720  * Returns:
1721  *              BE_SUCCESS - Success
1722  *              be_errno_t - Failure
1723  * Scope:
1724  *              Private
1725  */
1726 static int
1727 loopback_mount_zonepath(const char *zonepath, be_mount_data_t *md)
1728 {
1729         FILE            *fp = (FILE *)NULL;
1730         struct stat     st;
1731         char            *p;
1732         char            *p1;
1733         char            *parent_dir;
1734         struct extmnttab        extmtab;
1735         dev_t           dev = NODEV;
1736         char            *parentmnt;
1737         char            alt_parentmnt[MAXPATHLEN];
1738         struct mnttab   mntref;
1739         char            altzonepath[MAXPATHLEN];
1740         char            optstr[MAX_MNTOPT_STR];
1741         int             mflag = MS_OPTIONSTR;
1742         int             ret;
1743         int             err;
1744 
1745         fp = fopen(MNTTAB, "r");
1746         if (fp == NULL) {
1747                 err = errno;
1748                 be_print_err(gettext("loopback_mount_zonepath: "
1749                     "failed to open /etc/mnttab\n"));
1750                 return (errno_to_be_err(err));
1751         }
1752 
1753         /*
1754          * before attempting the loopback mount of zonepath under altroot,
1755          * we need to make sure that all intermediate file systems in the
1756          * zone path are also mounted under altroot
1757          */
1758 
1759         /* get the parent directory for zonepath */
1760         p = strrchr(zonepath, '/');
1761         if (p != NULL && p != zonepath) {
1762                 if ((parent_dir = (char *)calloc(sizeof (char),
1763                     p - zonepath + 1)) == NULL) {
1764                         ret = BE_ERR_NOMEM;
1765                         goto done;
1766                 }
1767                 (void) strlcpy(parent_dir, zonepath, p - zonepath + 1);
1768                 if (stat(parent_dir, &st) < 0) {
1769                         ret = errno_to_be_err(errno);
1770                         be_print_err(gettext("loopback_mount_zonepath: "
1771                             "failed to stat %s"),
1772                             parent_dir);
1773                         free(parent_dir);
1774                         goto done;
1775                 }
1776                 free(parent_dir);
1777 
1778                 /*
1779                  * After the above stat call, st.st_dev contains ID of the
1780                  * device over which parent dir resides.
1781                  * Now, search mnttab and find mount point of parent dir device.
1782                  */
1783 
1784                 resetmnttab(fp);
1785                 while (getextmntent(fp, &extmtab, sizeof (extmtab)) == 0) {
1786                         dev = makedev(extmtab.mnt_major, extmtab.mnt_minor);
1787                         if (st.st_dev == dev && strcmp(extmtab.mnt_fstype,
1788                             MNTTYPE_ZFS) == 0) {
1789                                 p1 = strchr(extmtab.mnt_special, '/');
1790                                 if (p1 == NULL || strncmp(p1 + 1,
1791                                     BE_CONTAINER_DS_NAME, 4) != 0 ||
1792                                     (*(p1 + 5) != '/' && *(p1 + 5) != '\0')) {
1793                                         /*
1794                                          * if parent dir is in a shared file
1795                                          * system, check whether it is already
1796                                          * loopback mounted under altroot or
1797                                          * not.  It would have been mounted
1798                                          * already under altroot if it is in
1799                                          * a non-shared filesystem.
1800                                          */
1801                                         parentmnt = strdup(extmtab.mnt_mountp);
1802                                         (void) snprintf(alt_parentmnt,
1803                                             sizeof (alt_parentmnt), "%s%s",
1804                                             md->altroot, parentmnt);
1805                                         mntref.mnt_mountp = alt_parentmnt;
1806                                         mntref.mnt_special = parentmnt;
1807                                         mntref.mnt_fstype = MNTTYPE_LOFS;
1808                                         mntref.mnt_mntopts = NULL;
1809                                         mntref.mnt_time = NULL;
1810                                         resetmnttab(fp);
1811                                         if (getmntany(fp, (struct mnttab *)
1812                                             &extmtab, &mntref) != 0) {
1813                                                 ret = loopback_mount_zonepath(
1814                                                     parentmnt, md);
1815                                                 if (ret != BE_SUCCESS) {
1816                                                         free(parentmnt);
1817                                                         goto done;
1818                                                 }
1819                                         }
1820                                         free(parentmnt);
1821                                 }
1822                                 break;
1823                         }
1824                 }
1825         }
1826 
1827 
1828         if (!md->shared_rw) {
1829                 mflag |= MS_RDONLY;
1830         }
1831 
1832         (void) snprintf(altzonepath, sizeof (altzonepath), "%s%s",
1833             md->altroot, zonepath);
1834 
1835         /* Add the "nosub" option to the mount options string */
1836         (void) strlcpy(optstr, MNTOPT_NOSUB, sizeof (optstr));
1837 
1838         /* Loopback mount this dataset at the altroot */
1839         if (mount(zonepath, altzonepath, mflag, MNTTYPE_LOFS,
1840             NULL, 0, optstr, sizeof (optstr)) != 0) {
1841                 err = errno;
1842                 be_print_err(gettext("loopback_mount_zonepath: "
1843                     "failed to loopback mount %s at %s: %s\n"),
1844                     zonepath, altzonepath, strerror(err));
1845                 ret = BE_ERR_MOUNT;
1846                 goto done;
1847         }
1848         ret = BE_SUCCESS;
1849 
1850 done :
1851         (void) fclose(fp);
1852         return (ret);
1853 }
1854 
1855 /*
1856  * Function:    unmount_shared_fs
1857  * Description: This function iterates through the mnttab and finds all
1858  *              loopback mount entries that reside within the altroot of
1859  *              where the BE is mounted, and unmounts it.
1860  * Parameters:
1861  *              ud - be_unmount_data_t pointer
1862  * Returns:
1863  *              BE_SUCCESS - Success
1864  *              be_errno_t - Failure
1865  * Scope:
1866  *              Private
1867  */
1868 static int
1869 unmount_shared_fs(be_unmount_data_t *ud)
1870 {
1871         FILE            *fp = NULL;
1872         struct mnttab   *table = NULL;
1873         struct mnttab   ent;
1874         struct mnttab   *entp = NULL;
1875         size_t          size = 0;
1876         int             read_chunk = 32;
1877         int             i;
1878         int             altroot_len;
1879         int             err = 0;
1880 
1881         errno = 0;
1882 
1883         /* Read in the mnttab into a table */
1884         if ((fp = fopen(MNTTAB, "r")) == NULL) {
1885                 err = errno;
1886                 be_print_err(gettext("unmount_shared_fs: "
1887                     "failed to open mnttab\n"));
1888                 return (errno_to_be_err(err));
1889         }
1890 
1891         while (getmntent(fp, &ent) == 0) {
1892                 if (size % read_chunk == 0) {
1893                         table = (struct mnttab *)realloc(table,
1894                             (size + read_chunk) * sizeof (ent));
1895                 }
1896                 entp = &table[size++];
1897 
1898                 /*
1899                  * Copy over the current mnttab entry into our table,
1900                  * copying only the fields that we care about.
1901                  */
1902                 (void) memset(entp, 0, sizeof (*entp));
1903                 if ((entp->mnt_mountp = strdup(ent.mnt_mountp)) == NULL ||
1904                     (entp->mnt_fstype = strdup(ent.mnt_fstype)) == NULL) {
1905                         be_print_err(gettext("unmount_shared_fs: "
1906                             "memory allocation failed\n"));
1907                         return (BE_ERR_NOMEM);
1908                 }
1909         }
1910         (void) fclose(fp);
1911 
1912         /*
1913          * Process the mnttab entries in reverse order, looking for
1914          * loopback mount entries mounted under our altroot.
1915          */
1916         altroot_len = strlen(ud->altroot);
1917         for (i = size; i > 0; i--) {
1918                 entp = &table[i - 1];
1919 
1920                 /* If not of type lofs, skip */
1921                 if (strcmp(entp->mnt_fstype, MNTTYPE_LOFS) != 0)
1922                         continue;
1923 
1924                 /* If inside the altroot, unmount it */
1925                 if (strncmp(entp->mnt_mountp, ud->altroot, altroot_len) == 0 &&
1926                     entp->mnt_mountp[altroot_len] == '/') {
1927                         if (umount(entp->mnt_mountp) != 0) {
1928                                 err = errno;
1929                                 if (err == EBUSY) {
1930                                         (void) sleep(1);
1931                                         err = errno = 0;
1932                                         if (umount(entp->mnt_mountp) != 0)
1933                                                 err = errno;
1934                                 }
1935                                 if (err != 0) {
1936                                         be_print_err(gettext(
1937                                             "unmount_shared_fs: "
1938                                             "failed to unmount shared file "
1939                                             "system %s: %s\n"),
1940                                             entp->mnt_mountp, strerror(err));
1941                                         return (errno_to_be_err(err));
1942                                 }
1943                         }
1944                 }
1945         }
1946 
1947         return (BE_SUCCESS);
1948 }
1949 
1950 /*
1951  * Function:    get_mountpoint_from_vfstab
1952  * Description: This function digs into the vfstab in the given altroot,
1953  *              and searches for an entry for the fs passed in.  If found,
1954  *              it returns the mountpoint of that fs in the mountpoint
1955  *              buffer passed in.  If the get_alt_mountpoint flag is set,
1956  *              it returns the mountpoint with the altroot prepended.
1957  * Parameters:
1958  *              altroot - pointer to the alternate root location
1959  *              fs - pointer to the file system name to look for in the
1960  *                      vfstab in altroot
1961  *              mountpoint - pointer to buffer of where the mountpoint of
1962  *                      fs will be returned.
1963  *              size_mp - size of mountpoint argument
1964  *              get_alt_mountpoint - flag to indicate whether or not the
1965  *                      mountpoint should be populated with the altroot
1966  *                      prepended.
1967  * Returns:
1968  *              BE_SUCCESS - Success
1969  *              1 - Failure
1970  * Scope:
1971  *              Private
1972  */
1973 static int
1974 get_mountpoint_from_vfstab(char *altroot, const char *fs, char *mountpoint,
1975     size_t size_mp, boolean_t get_alt_mountpoint)
1976 {
1977         struct vfstab   vp;
1978         FILE            *fp = NULL;
1979         char            alt_vfstab[MAXPATHLEN];
1980 
1981         /* Generate path to alternate root vfstab */
1982         (void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
1983             altroot);
1984 
1985         /* Open alternate root vfstab */
1986         if ((fp = fopen(alt_vfstab, "r")) == NULL) {
1987                 be_print_err(gettext("get_mountpoint_from_vfstab: "
1988                     "failed to open vfstab (%s)\n"), alt_vfstab);
1989                 return (1);
1990         }
1991 
1992         if (getvfsspec(fp, &vp, (char *)fs) == 0) {
1993                 /*
1994                  * Found entry for fs, grab its mountpoint.
1995                  * If the flag to prepend the altroot into the mountpoint
1996                  * is set, prepend it.  Otherwise, just return the mountpoint.
1997                  */
1998                 if (get_alt_mountpoint) {
1999                         (void) snprintf(mountpoint, size_mp, "%s%s", altroot,
2000                             vp.vfs_mountp);
2001                 } else {
2002                         (void) strlcpy(mountpoint, vp.vfs_mountp, size_mp);
2003                 }
2004         } else {
2005                 (void) fclose(fp);
2006                 return (1);
2007         }
2008 
2009         (void) fclose(fp);
2010 
2011         return (BE_SUCCESS);
2012 }
2013 
2014 /*
2015  * Function:    fix_mountpoint_callback
2016  * Description: This callback function is used to iterate through a BE's
2017  *              children filesystems to check if its mountpoint is currently
2018  *              set to be mounted at some specified altroot.  If so, fix it by
2019  *              removing altroot from the beginning of its mountpoint.
2020  *
2021  *              Note - There's no way to tell if a child filesystem's
2022  *              mountpoint isn't broken, and just happens to begin with
2023  *              the altroot we're looking for.  In this case, this function
2024  *              will errantly remove the altroot portion from the beginning
2025  *              of this filesystem's mountpoint.
2026  *
2027  * Parameters:
2028  *              zhp - zfs_handle_t pointer to filesystem being processed.
2029  *              data - altroot of where BE is to be mounted.
2030  * Returns:
2031  *              0 - Success
2032  *              be_errno_t - Failure
2033  * Scope:
2034  *              Private
2035  */
2036 static int
2037 fix_mountpoint_callback(zfs_handle_t *zhp, void *data)
2038 {
2039         zprop_source_t  sourcetype;
2040         char            source[ZFS_MAXNAMELEN];
2041         char            mountpoint[MAXPATHLEN];
2042         char            *zhp_mountpoint = NULL;
2043         char            *altroot = data;
2044         int             ret = 0;
2045 
2046         /* Get dataset's mountpoint and source values */
2047         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2048             sizeof (mountpoint), &sourcetype, source, sizeof (source),
2049             B_FALSE) != 0) {
2050                 be_print_err(gettext("fix_mountpoint_callback: "
2051                     "failed to get mountpoint and sourcetype for %s\n"),
2052                     zfs_get_name(zhp));
2053                 ZFS_CLOSE(zhp);
2054                 return (BE_ERR_ZFS);
2055         }
2056 
2057         /*
2058          * If the mountpoint is not inherited and the mountpoint is not
2059          * 'legacy', this file system potentially needs its mountpoint
2060          * fixed.
2061          */
2062         if (!(sourcetype & ZPROP_SRC_INHERITED) &&
2063             strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0) {
2064 
2065                 /*
2066                  * Check if this file system's current mountpoint is
2067                  * under the altroot we're fixing it against.
2068                  */
2069                 if (strncmp(mountpoint, altroot, strlen(altroot)) == 0 &&
2070                     mountpoint[strlen(altroot)] == '/') {
2071 
2072                         /*
2073                          * Get this dataset's mountpoint relative to the
2074                          * altroot.
2075                          */
2076                         zhp_mountpoint = mountpoint + strlen(altroot);
2077 
2078                         /* Fix this dataset's mountpoint value */
2079                         if (zfs_prop_set(zhp,
2080                             zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2081                             zhp_mountpoint)) {
2082                                 be_print_err(gettext("fix_mountpoint_callback: "
2083                                     "failed to set mountpoint for %s to "
2084                                     "%s: %s\n"), zfs_get_name(zhp),
2085                                     zhp_mountpoint,
2086                                     libzfs_error_description(g_zfs));
2087                                 ret = zfs_err_to_be_err(g_zfs);
2088                                 ZFS_CLOSE(zhp);
2089                                 return (ret);
2090                         }
2091                 }
2092         }
2093 
2094         /* Iterate through this dataset's children and fix them */
2095         if ((ret = zfs_iter_filesystems(zhp, fix_mountpoint_callback,
2096             altroot)) != 0) {
2097                 ZFS_CLOSE(zhp);
2098                 return (ret);
2099         }
2100 
2101 
2102         ZFS_CLOSE(zhp);
2103         return (0);
2104 }
2105 
2106 /*
2107  * Function:    be_mount_root
2108  * Description: This function mounts the root dataset of a BE at the
2109  *              specified altroot.
2110  * Parameters:
2111  *              zhp - zfs_handle_t pointer to root dataset of a BE that is
2112  *              to be mounted at altroot.
2113  *              altroot - location of where to mount the BE root.
2114  * Return:
2115  *              BE_SUCCESS - Success
2116  *              be_errno_t - Failure
2117  * Scope:
2118  *              Private
2119  */
2120 static int
2121 be_mount_root(zfs_handle_t *zhp, char *altroot)
2122 {
2123         char            mountpoint[MAXPATHLEN];
2124 
2125         /* Get mountpoint property of dataset */
2126         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2127             sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
2128                 be_print_err(gettext("be_mount_root: failed to "
2129                     "get mountpoint property for %s: %s\n"), zfs_get_name(zhp),
2130                     libzfs_error_description(g_zfs));
2131                 return (zfs_err_to_be_err(g_zfs));
2132         }
2133 
2134         /*
2135          * Set the canmount property for the BE's root dataset to 'noauto' just
2136          * in case it's been set to 'on'.  We do this so that when we change its
2137          * mountpoint, zfs won't immediately try to mount it.
2138          */
2139         if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")
2140             != 0) {
2141                 be_print_err(gettext("be_mount_root: failed to "
2142                     "set canmount property to 'noauto' (%s): %s\n"),
2143                     zfs_get_name(zhp), libzfs_error_description(g_zfs));
2144                 return (zfs_err_to_be_err(g_zfs));
2145         }
2146 
2147         /* Set mountpoint for BE's root filesystem */
2148         if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), altroot)
2149             != 0) {
2150                 be_print_err(gettext("be_mount_root: failed to "
2151                     "set mountpoint of %s to %s: %s\n"),
2152                     zfs_get_name(zhp), altroot,
2153                     libzfs_error_description(g_zfs));
2154                 return (zfs_err_to_be_err(g_zfs));
2155         }
2156 
2157         /* Mount the BE's root filesystem */
2158         if (zfs_mount(zhp, NULL, 0) != 0) {
2159                 be_print_err(gettext("be_mount_root: failed to "
2160                     "mount dataset %s at %s: %s\n"), zfs_get_name(zhp),
2161                     altroot, libzfs_error_description(g_zfs));
2162                 /*
2163                  * Set this BE's root filesystem 'mountpoint' property
2164                  * back to what it was before.
2165                  */
2166                 (void) zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2167                     mountpoint);
2168                 return (zfs_err_to_be_err(g_zfs));
2169         }
2170 
2171         return (BE_SUCCESS);
2172 }
2173 
2174 /*
2175  * Function:    be_unmount_root
2176  * Description: This function unmounts the root dataset of a BE, but before
2177  *              unmounting, it looks at the BE's vfstab to determine
2178  *              if the root dataset mountpoint should be left as 'legacy'
2179  *              or '/'.  If the vfstab contains an entry for this root
2180  *              dataset with a mountpoint of '/', it sets the mountpoint
2181  *              property to 'legacy'.
2182  *
2183  * Parameters:
2184  *              zhp - zfs_handle_t pointer of the BE root dataset that
2185  *              is currently mounted.
2186  *              ud - be_unmount_data_t pointer providing unmount data
2187  *              for the given BE root dataset.
2188  * Returns:
2189  *              BE_SUCCESS - Success
2190  *              be_errno_t - Failure
2191  * Scope:
2192  *              Private
2193  */
2194 static int
2195 be_unmount_root(zfs_handle_t *zhp, be_unmount_data_t *ud)
2196 {
2197         char            mountpoint[MAXPATHLEN];
2198         boolean_t       is_legacy = B_FALSE;
2199 
2200         /* See if this is a legacy mounted root */
2201         if (get_mountpoint_from_vfstab(ud->altroot, zfs_get_name(zhp),
2202             mountpoint, sizeof (mountpoint), B_FALSE) == BE_SUCCESS &&
2203             strcmp(mountpoint, "/") == 0) {
2204                 is_legacy = B_TRUE;
2205         }
2206 
2207         /* Unmount the dataset */
2208         if (zfs_unmount(zhp, NULL, ud->force ? MS_FORCE : 0) != 0) {
2209                 be_print_err(gettext("be_unmount_root: failed to "
2210                     "unmount BE root dataset %s: %s\n"), zfs_get_name(zhp),
2211                     libzfs_error_description(g_zfs));
2212                 return (zfs_err_to_be_err(g_zfs));
2213         }
2214 
2215         /* Set canmount property for this BE's root filesystem to noauto */
2216         if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto")
2217             != 0) {
2218                 be_print_err(gettext("be_unmount_root: failed to "
2219                     "set canmount property for %s to 'noauto': %s\n"),
2220                     zfs_get_name(zhp), libzfs_error_description(g_zfs));
2221                 return (zfs_err_to_be_err(g_zfs));
2222         }
2223 
2224         /*
2225          * Set mountpoint for BE's root dataset back to '/', or 'legacy'
2226          * if its a legacy mounted root.
2227          */
2228         if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2229             is_legacy ? ZFS_MOUNTPOINT_LEGACY : "/") != 0) {
2230                 be_print_err(gettext("be_unmount_root: failed to "
2231                     "set mountpoint of %s to %s\n"), zfs_get_name(zhp),
2232                     is_legacy ? ZFS_MOUNTPOINT_LEGACY : "/");
2233                 return (zfs_err_to_be_err(g_zfs));
2234         }
2235 
2236         return (BE_SUCCESS);
2237 }
2238 
2239 /*
2240  * Function:    fix_mountpoint
2241  * Description: This function checks the mountpoint of an unmounted BE to make
2242  *              sure that it is set to either 'legacy' or '/'.  If it's not,
2243  *              then we're in a situation where an unmounted BE has some random
2244  *              mountpoint set for it.  (This could happen if the system was
2245  *              rebooted while an inactive BE was mounted).  This function
2246  *              attempts to fix its mountpoints.
2247  * Parameters:
2248  *              zhp - zfs_handle_t pointer to root dataset of the BE
2249  *              whose mountpoint needs to be checked.
2250  * Return:
2251  *              BE_SUCCESS - Success
2252  *              be_errno_t - Failure
2253  * Scope:
2254  *              Private
2255  */
2256 static int
2257 fix_mountpoint(zfs_handle_t *zhp)
2258 {
2259         be_unmount_data_t       ud = { 0 };
2260         char    *altroot = NULL;
2261         char    mountpoint[MAXPATHLEN];
2262         int     ret = BE_SUCCESS;
2263 
2264         /*
2265          * Record what this BE's root dataset mountpoint property is currently
2266          * set to.
2267          */
2268         if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2269             sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
2270                 be_print_err(gettext("fix_mountpoint: failed to get "
2271                     "mountpoint property of (%s): %s\n"), zfs_get_name(zhp),
2272                     libzfs_error_description(g_zfs));
2273                 return (BE_ERR_ZFS);
2274         }
2275 
2276         /*
2277          * If the root dataset mountpoint is set to 'legacy' or '/', we're okay.
2278          */
2279         if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0 ||
2280             strcmp(mountpoint, "/") == 0) {
2281                 return (BE_SUCCESS);
2282         }
2283 
2284         /*
2285          * Iterate through this BE's children datasets and fix
2286          * them if they need fixing.
2287          */
2288         if (zfs_iter_filesystems(zhp, fix_mountpoint_callback, mountpoint)
2289             != 0) {
2290                 return (BE_ERR_ZFS);
2291         }
2292 
2293         /*
2294          * The process of mounting and unmounting the root file system
2295          * will fix its mountpoint to correctly be either 'legacy' or '/'
2296          * since be_unmount_root will do the right thing by looking at
2297          * its vfstab.
2298          */
2299 
2300         /* Generate temporary altroot to mount the root file system */
2301         if ((ret = be_make_tmp_mountpoint(&altroot)) != BE_SUCCESS) {
2302                 be_print_err(gettext("fix_mountpoint: failed to "
2303                     "make temporary mountpoint\n"));
2304                 return (ret);
2305         }
2306 
2307         /* Mount and unmount the root. */
2308         if ((ret = be_mount_root(zhp, altroot)) != BE_SUCCESS) {
2309                 be_print_err(gettext("fix_mountpoint: failed to "
2310                     "mount BE root file system\n"));
2311                 goto cleanup;
2312         }
2313         ud.altroot = altroot;
2314         if ((ret = be_unmount_root(zhp, &ud)) != BE_SUCCESS) {
2315                 be_print_err(gettext("fix_mountpoint: failed to "
2316                     "unmount BE root file system\n"));
2317                 goto cleanup;
2318         }
2319 
2320 cleanup:
2321         free(altroot);
2322 
2323         return (ret);
2324 }
2325 
2326 /*
2327  * Function:    be_mount_zones
2328  * Description: This function finds all supported non-global zones in the
2329  *              given global BE and mounts them with respect to where the
2330  *              global BE is currently mounted.  The global BE datasets
2331  *              (including its shared datasets) are expected to already
2332  *              be mounted.
2333  * Parameters:
2334  *              be_zhp - zfs_handle_t pointer to the root dataset of the
2335  *                      global BE.
2336  *              md - be_mount_data_t pointer to data for global BE.
2337  * Returns:
2338  *              BE_SUCCESS - Success
2339  *              be_errno_t - Failure
2340  * Scope:
2341  *              Private
2342  */
2343 static int
2344 be_mount_zones(zfs_handle_t *be_zhp, be_mount_data_t *md)
2345 {
2346         zoneList_t      zlst = NULL;
2347         char            *zonename = NULL;
2348         char            *zonepath = NULL;
2349         char            *zonepath_ds = NULL;
2350         int             k;
2351         int             ret = BE_SUCCESS;
2352         boolean_t       auto_create;
2353 
2354         z_set_zone_root(md->altroot);
2355 
2356         zlst = z_get_nonglobal_branded_zone_list();
2357         if (zlst == NULL)
2358                 return (BE_SUCCESS);
2359 
2360         for (k = 0; (zonename = z_zlist_get_zonename(zlst, k)) != NULL; k++) {
2361                 if (z_zlist_is_zone_auto_create_be(zlst, k, &auto_create) != 0) {
2362                         be_print_err(gettext("be_mount_zones: failed to"
2363                             " get auto-create-be brand property\n"));
2364                         goto done;
2365                 }
2366 
2367                 if (!auto_create)
2368                         continue;
2369 
2370                 if (z_zlist_get_current_state(zlst, k) ==
2371                     ZONE_STATE_INSTALLED) {
2372                         zonepath = z_zlist_get_zonepath(zlst, k);
2373 
2374                         /*
2375                          * Get the dataset of this zonepath in current BE.
2376                          * If its not a dataset, skip it.
2377                          */
2378                         if ((zonepath_ds = be_get_ds_from_dir(zonepath))
2379                             == NULL)
2380                                 continue;
2381 
2382                         /*
2383                          * Check if this zone is supported based on
2384                          * the dataset of its zonepath
2385                          */
2386                         if (!be_zone_supported(zonepath_ds)) {
2387                                 free(zonepath_ds);
2388                                 zonepath_ds = NULL;
2389                                 continue;
2390                         }
2391 
2392                         /*
2393                          * if BE's shared file systems are already mounted,
2394                          * zone path dataset would have already been lofs
2395                          * mounted under altroot. Otherwise, we need to do
2396                          * it here.
2397                          */
2398                         if (!md->shared_fs) {
2399                                 ret = loopback_mount_zonepath(zonepath, md);
2400                                 if (ret != BE_SUCCESS)
2401                                         goto done;
2402                         }
2403 
2404 
2405                         /* Mount this zone */
2406                         ret = be_mount_one_zone(be_zhp, md, zonename,
2407                             zonepath, zonepath_ds);
2408 
2409                         free(zonepath_ds);
2410                         zonepath_ds = NULL;
2411 
2412                         if (ret != BE_SUCCESS) {
2413                                 be_print_err(gettext("be_mount_zones: "
2414                                     "failed to mount zone %s under "
2415                                     "altroot %s\n"), zonename, md->altroot);
2416                                 goto done;
2417                         }
2418                 }
2419         }
2420 
2421 done:
2422         z_free_zone_list(zlst);
2423         /*
2424          * libinstzones caches mnttab and uses cached version for resolving lofs
2425          * mounts when we call z_resolve_lofs. It creates the cached version
2426          * when the first call to z_resolve_lofs happens. So, library's cached
2427          * mnttab doesn't contain entries for lofs mounts created in the above
2428          * loop. Because of this, subsequent calls to z_resolve_lofs would fail
2429          * to resolve these lofs mounts. So, here we destroy library's cached
2430          * mnttab to force its recreation when the next call to z_resolve_lofs
2431          * happens.
2432          */
2433         z_destroyMountTable();
2434         return (ret);
2435 }
2436 
2437 /*
2438  * Function:    be_unmount_zones
2439  * Description: This function finds all supported non-global zones in the
2440  *              given mounted global BE and unmounts them.
2441  * Parameters:
2442  *              ud - unmount_data_t pointer data for the global BE.
2443  * Returns:
2444  *              BE_SUCCESS - Success
2445  *              be_errno_t - Failure
2446  * Scope:
2447  *              Private
2448  */
2449 static int
2450 be_unmount_zones(be_unmount_data_t *ud)
2451 {
2452         zoneList_t              zlst = NULL;
2453         char                    *zonename = NULL;
2454         char                    *zonepath = NULL;
2455         char                    alt_zonepath[MAXPATHLEN];
2456         char                    *zonepath_ds = NULL;
2457         int                     k;
2458         int                     ret = BE_SUCCESS;
2459         boolean_t               auto_create;
2460 
2461         z_set_zone_root(ud->altroot);
2462 
2463         zlst = z_get_nonglobal_branded_zone_list();
2464         if (zlst == NULL)
2465                 return (BE_SUCCESS);
2466 
2467         for (k = 0; (zonename = z_zlist_get_zonename(zlst, k)) != NULL; k++) {
2468                 if (z_zlist_is_zone_auto_create_be(zlst, k, &auto_create) != 0) {
2469                         be_print_err(gettext("be_unmount_zones: failed to"
2470                             " get auto-create-be brand property\n"));
2471                         goto done;
2472                 }
2473 
2474                 if (!auto_create)
2475                         continue;
2476 
2477                 if (z_zlist_get_current_state(zlst, k) ==
2478                     ZONE_STATE_INSTALLED) {
2479                         zonepath = z_zlist_get_zonepath(zlst, k);
2480 
2481                         /* Build zone's zonepath wrt the global BE altroot */
2482                         (void) snprintf(alt_zonepath, sizeof (alt_zonepath),
2483                             "%s%s", ud->altroot, zonepath);
2484 
2485                         /*
2486                          * Get the dataset of this zonepath.  If its not
2487                          * a dataset, skip it.
2488                          */
2489                         if ((zonepath_ds = be_get_ds_from_dir(alt_zonepath))
2490                             == NULL)
2491                                 continue;
2492 
2493                         /*
2494                          * Check if this zone is supported based on the
2495                          * dataset of its zonepath.
2496                          */
2497                         if (!be_zone_supported(zonepath_ds)) {
2498                                 free(zonepath_ds);
2499                                 zonepath_ds = NULL;
2500                                 continue;
2501                         }
2502 
2503                         /* Unmount this zone */
2504                         ret = be_unmount_one_zone(ud, zonename, zonepath,
2505                             zonepath_ds);
2506 
2507                         free(zonepath_ds);
2508                         zonepath_ds = NULL;
2509 
2510                         if (ret != BE_SUCCESS) {
2511                                 be_print_err(gettext("be_unmount_zones:"
2512                                     " failed to unmount zone %s from "
2513                                     "altroot %s\n"), zonename, ud->altroot);
2514                                 goto done;
2515                         }
2516                 }
2517         }
2518 
2519 done:
2520         z_free_zone_list(zlst);
2521         return (ret);
2522 }
2523 
2524 /*
2525  * Function:    be_mount_one_zone
2526  * Description: This function is called to mount one zone for a given
2527  *              global BE.
2528  * Parameters:
2529  *              be_zhp - zfs_handle_t pointer to the root dataset of the
2530  *                      global BE
2531  *              md - be_mount_data_t pointer to data for global BE
2532  *              zonename - name of zone to mount
2533  *              zonepath - zonepath of zone to mount
2534  *              zonepath_ds - dataset for the zonepath
2535  * Returns:
2536  *              BE_SUCCESS - Success
2537  *              be_errno_t - Failure
2538  * Scope:
2539  *              Private
2540  */
2541 static int
2542 be_mount_one_zone(zfs_handle_t *be_zhp, be_mount_data_t *md, char *zonename,
2543     char *zonepath, char *zonepath_ds)
2544 {
2545         be_mount_data_t zone_md = { 0 };
2546         zfs_handle_t    *zone_zhp = NULL;
2547         char            zone_altroot[MAXPATHLEN];
2548         char            zoneroot[MAXPATHLEN];
2549         char            zoneroot_ds[MAXPATHLEN];
2550         int             ret = BE_SUCCESS;
2551 
2552         /* Find the active zone root dataset for this zone for this BE */
2553         if ((ret = be_find_active_zone_root(be_zhp, zonepath_ds, zoneroot_ds,
2554             sizeof (zoneroot_ds))) == BE_ERR_ZONE_NO_ACTIVE_ROOT) {
2555                 be_print_err(gettext("be_mount_one_zone: did not "
2556                     "find active zone root for zone %s, skipping ...\n"),
2557                     zonename);
2558                 return (BE_SUCCESS);
2559         } else if (ret != BE_SUCCESS) {
2560                 be_print_err(gettext("be_mount_one_zone: failed to "
2561                     "find active zone root for zone %s\n"), zonename);
2562                 return (ret);
2563         }
2564 
2565         /* Get handle to active zoneroot dataset */
2566         if ((zone_zhp = zfs_open(g_zfs, zoneroot_ds, ZFS_TYPE_FILESYSTEM))
2567             == NULL) {
2568                 be_print_err(gettext("be_mount_one_zone: failed to "
2569                     "open zone root dataset (%s): %s\n"), zoneroot_ds,
2570                     libzfs_error_description(g_zfs));
2571                 return (zfs_err_to_be_err(g_zfs));
2572         }
2573 
2574         /* Generate string for zone's altroot path */
2575         be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2576         (void) strlcpy(zone_altroot, md->altroot, sizeof (zone_altroot));
2577         (void) strlcat(zone_altroot, zoneroot, sizeof (zone_altroot));
2578 
2579         /* Build mount_data for the zone */
2580         zone_md.altroot = zone_altroot;
2581         zone_md.shared_fs = md->shared_fs;
2582         zone_md.shared_rw = md->shared_rw;
2583 
2584         /* Mount the zone's root file system */
2585         if ((ret = be_mount_zone_root(zone_zhp, &zone_md)) != BE_SUCCESS) {
2586                 be_print_err(gettext("be_mount_one_zone: failed to "
2587                     "mount zone root file system at %s\n"), zone_altroot);
2588                 goto done;
2589         }
2590 
2591         /* Iterate through zone's children filesystems */
2592         if ((ret = zfs_iter_filesystems(zone_zhp, be_mount_callback,
2593             zone_altroot)) != 0) {
2594                 be_print_err(gettext("be_mount_one_zone: failed to "
2595                     "mount zone subordinate file systems at %s\n"),
2596                     zone_altroot);
2597                 goto done;
2598         }
2599 
2600         /* TODO: Mount all shared file systems for this zone */
2601 
2602 done:
2603         ZFS_CLOSE(zone_zhp);
2604         return (ret);
2605 }
2606 
2607 /*
2608  * Function:    be_unmount_one_zone
2609  * Description: This function unmount one zone for a give global BE.
2610  * Parameters:
2611  *              ud - be_unmount_data_t pointer to data for global BE
2612  *              zonename - name of zone to unmount
2613  *              zonepath - zonepath of the zone to unmount
2614  *              zonepath_ds - dataset for the zonepath
2615  * Returns:
2616  *              BE_SUCCESS - Success
2617  *              be_errno_t - Failure
2618  * Scope:
2619  *              Private
2620  */
2621 static int
2622 be_unmount_one_zone(be_unmount_data_t *ud, char *zonename, char *zonepath,
2623     char *zonepath_ds)
2624 {
2625         be_unmount_data_t       zone_ud = { 0 };
2626         zfs_handle_t    *zone_zhp = NULL;
2627         char            zone_altroot[MAXPATHLEN];
2628         char            zoneroot[MAXPATHLEN];
2629         char            zoneroot_ds[MAXPATHLEN];
2630         int             ret = BE_SUCCESS;
2631 
2632         /* Generate string for zone's alternate root path */
2633         be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2634         (void) strlcpy(zone_altroot, ud->altroot, sizeof (zone_altroot));
2635         (void) strlcat(zone_altroot, zoneroot, sizeof (zone_altroot));
2636 
2637         /* Build be_unmount_data for zone */
2638         zone_ud.altroot = zone_altroot;
2639         zone_ud.force = ud->force;
2640 
2641         /* Find the mounted zone root dataset for this zone for this BE */
2642         if ((ret = be_find_mounted_zone_root(zone_altroot, zonepath_ds,
2643             zoneroot_ds, sizeof (zoneroot_ds))) == BE_ERR_NO_MOUNTED_ZONE) {
2644                 be_print_err(gettext("be_unmount_one_zone: did not "
2645                     "find any zone root mounted for zone %s\n"), zonename);
2646                 return (BE_SUCCESS);
2647         } else if (ret != BE_SUCCESS) {
2648                 be_print_err(gettext("be_unmount_one_zone: failed to "
2649                     "find mounted zone root for zone %s\n"), zonename);
2650                 return (ret);
2651         }
2652 
2653         /* Get handle to zoneroot dataset mounted for this BE */
2654         if ((zone_zhp = zfs_open(g_zfs, zoneroot_ds, ZFS_TYPE_FILESYSTEM))
2655             == NULL) {
2656                 be_print_err(gettext("be_unmount_one_zone: failed to "
2657                     "open mounted zone root dataset (%s): %s\n"), zoneroot_ds,
2658                     libzfs_error_description(g_zfs));
2659                 return (zfs_err_to_be_err(g_zfs));
2660         }
2661 
2662         /* TODO: Unmount all shared file systems for this zone */
2663 
2664         /* Iterate through zone's children filesystems and unmount them */
2665         if ((ret = zfs_iter_filesystems(zone_zhp, be_unmount_callback,
2666             &zone_ud)) != 0) {
2667                 be_print_err(gettext("be_unmount_one_zone: failed to "
2668                     "unmount zone subordinate file systems at %s\n"),
2669                     zone_altroot);
2670                 goto done;
2671         }
2672 
2673         /* Unmount the zone's root filesystem */
2674         if ((ret = be_unmount_zone_root(zone_zhp, &zone_ud)) != BE_SUCCESS) {
2675                 be_print_err(gettext("be_unmount_one_zone: failed to "
2676                     "unmount zone root file system at %s\n"), zone_altroot);
2677                 goto done;
2678         }
2679 
2680 done:
2681         ZFS_CLOSE(zone_zhp);
2682         return (ret);
2683 }
2684 
2685 /*
2686  * Function:    be_get_ds_from_dir_callback
2687  * Description: This is a callback function used to iterate all datasets
2688  *              to find the one that is currently mounted at the directory
2689  *              being searched for.  If matched, the name of the dataset is
2690  *              returned in heap storage, so the caller is responsible for
2691  *              freeing it.
2692  * Parameters:
2693  *              zhp - zfs_handle_t pointer to current dataset being processed.
2694  *              data - dir_data_t pointer providing name of directory being
2695  *                      searched for.
2696  * Returns:
2697  *              1 - This dataset is mounted at directory being searched for.
2698  *              0 - This dataset is not mounted at directory being searched for.
2699  * Scope:
2700  *              Private
2701  */
2702 static int
2703 be_get_ds_from_dir_callback(zfs_handle_t *zhp, void *data)
2704 {
2705         dir_data_t      *dd = data;
2706         char            *mp = NULL;
2707         int             zret = 0;
2708 
2709         if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2710                 ZFS_CLOSE(zhp);
2711                 return (0);
2712         }
2713 
2714         if (zfs_is_mounted(zhp, &mp) && mp != NULL &&
2715             strcmp(mp, dd->dir) == 0) {
2716                 if ((dd->ds = strdup(zfs_get_name(zhp))) == NULL) {
2717                         be_print_err(gettext("be_get_ds_from_dir_callback: "
2718                             "memory allocation failed\n"));
2719                         ZFS_CLOSE(zhp);
2720                         return (0);
2721                 }
2722                 ZFS_CLOSE(zhp);
2723                 return (1);
2724         }
2725 
2726         zret = zfs_iter_filesystems(zhp, be_get_ds_from_dir_callback, dd);
2727 
2728         ZFS_CLOSE(zhp);
2729 
2730         return (zret);
2731 }