1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 221371Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens /* 29789Sahrens * Routines to manage ZFS mounts. We separate all the nasty routines that have 30789Sahrens * to deal with the OS. The main entry points are: 31789Sahrens * 32789Sahrens * zfs_is_mounted() 33789Sahrens * zfs_mount() 34789Sahrens * zfs_unmount() 35789Sahrens * zfs_unmountall() 36789Sahrens * 37789Sahrens * These functions are used by mount and unmount, and when changing a 38789Sahrens * filesystem's mountpoint. This file also contains the functions used to 39789Sahrens * manage sharing filesystems via NFS: 40789Sahrens * 41789Sahrens * zfs_is_shared() 42789Sahrens * zfs_share() 43789Sahrens * zfs_unshare() 44789Sahrens * zfs_unshareall() 45789Sahrens */ 46789Sahrens 47789Sahrens #include <dirent.h> 48789Sahrens #include <errno.h> 49789Sahrens #include <libgen.h> 50789Sahrens #include <libintl.h> 51789Sahrens #include <stdio.h> 52789Sahrens #include <stdlib.h> 53789Sahrens #include <strings.h> 54789Sahrens #include <unistd.h> 55789Sahrens #include <zone.h> 56789Sahrens #include <sys/mntent.h> 57789Sahrens #include <sys/mnttab.h> 58789Sahrens #include <sys/mount.h> 59789Sahrens #include <sys/stat.h> 60789Sahrens 61789Sahrens #include <libzfs.h> 62789Sahrens 63789Sahrens #include "libzfs_impl.h" 64789Sahrens 65789Sahrens /* 66*2082Seschrock * Search the sharetab for the given mountpoint, returning true if it is found. 67789Sahrens */ 68*2082Seschrock static boolean_t 69*2082Seschrock is_shared(libzfs_handle_t *hdl, const char *mountpoint) 70789Sahrens { 71789Sahrens char buf[MAXPATHLEN], *tab; 72789Sahrens 73*2082Seschrock if (hdl->libzfs_sharetab == NULL) 74789Sahrens return (0); 75789Sahrens 76*2082Seschrock (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); 77789Sahrens 78*2082Seschrock while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { 79789Sahrens 80789Sahrens /* the mountpoint is the first entry on each line */ 81789Sahrens if ((tab = strchr(buf, '\t')) != NULL) { 82789Sahrens *tab = '\0'; 83789Sahrens if (strcmp(buf, mountpoint) == 0) 84*2082Seschrock return (B_TRUE); 85789Sahrens } 86789Sahrens } 87789Sahrens 88*2082Seschrock return (B_FALSE); 89789Sahrens } 90789Sahrens 91789Sahrens /* 92*2082Seschrock * Returns true if the specified directory is empty. If we can't open the 93*2082Seschrock * directory at all, return true so that the mount can fail with a more 94789Sahrens * informative error message. 95789Sahrens */ 96*2082Seschrock static boolean_t 97789Sahrens dir_is_empty(const char *dirname) 98789Sahrens { 99789Sahrens DIR *dirp; 100789Sahrens struct dirent64 *dp; 101789Sahrens 102789Sahrens if ((dirp = opendir(dirname)) == NULL) 103*2082Seschrock return (B_TRUE); 104789Sahrens 105789Sahrens while ((dp = readdir64(dirp)) != NULL) { 106789Sahrens 107789Sahrens if (strcmp(dp->d_name, ".") == 0 || 108789Sahrens strcmp(dp->d_name, "..") == 0) 109789Sahrens continue; 110789Sahrens 111789Sahrens (void) closedir(dirp); 112*2082Seschrock return (B_FALSE); 113789Sahrens } 114789Sahrens 115789Sahrens (void) closedir(dirp); 116*2082Seschrock return (B_TRUE); 117789Sahrens } 118789Sahrens 119789Sahrens /* 120789Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill 121789Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return 122789Sahrens * 0. 123789Sahrens */ 124*2082Seschrock boolean_t 125789Sahrens zfs_is_mounted(zfs_handle_t *zhp, char **where) 126789Sahrens { 127789Sahrens struct mnttab search = { 0 }, entry; 128789Sahrens 129789Sahrens /* 130789Sahrens * Search for the entry in /etc/mnttab. We don't bother getting the 131789Sahrens * mountpoint, as we can just search for the special device. This will 132789Sahrens * also let us find mounts when the mountpoint is 'legacy'. 133789Sahrens */ 134789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 1351407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 136789Sahrens 137*2082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 138*2082Seschrock if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) != 0) 139*2082Seschrock return (B_FALSE); 140789Sahrens 141789Sahrens if (where != NULL) 142*2082Seschrock *where = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 143789Sahrens 144*2082Seschrock return (B_TRUE); 145789Sahrens } 146789Sahrens 147789Sahrens /* 148789Sahrens * Mount the given filesystem. 149789Sahrens */ 150789Sahrens int 151789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 152789Sahrens { 153789Sahrens struct stat buf; 154789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 155789Sahrens char mntopts[MNT_LINE_MAX]; 156*2082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 157789Sahrens 158789Sahrens if (options == NULL) 159789Sahrens mntopts[0] = '\0'; 160789Sahrens else 161789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 162789Sahrens 163789Sahrens /* ignore non-filesystems */ 164789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 165*2082Seschrock sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) 166789Sahrens return (0); 167789Sahrens 168789Sahrens /* return success if there is no mountpoint set */ 169789Sahrens if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 170789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 171789Sahrens return (0); 172789Sahrens 173789Sahrens /* 174789Sahrens * If the 'zoned' property is set, and we're in the global zone, simply 175789Sahrens * return success. 176789Sahrens */ 177*2082Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) && 178*2082Seschrock getzoneid() == GLOBAL_ZONEID) 179*2082Seschrock return (0); 180789Sahrens 181789Sahrens /* Create the directory if it doesn't already exist */ 182789Sahrens if (lstat(mountpoint, &buf) != 0) { 183789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 184*2082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 185*2082Seschrock "failed to create mountpoint")); 186*2082Seschrock return (zfs_error(hdl, EZFS_MOUNTFAILED, 187*2082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 188*2082Seschrock mountpoint)); 189789Sahrens } 190789Sahrens } 191789Sahrens 192789Sahrens /* 193789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 194789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 195789Sahrens * would defeat the point. We also avoid this check if 'remount' is 196789Sahrens * specified. 197789Sahrens */ 198789Sahrens if ((flags & MS_OVERLAY) == 0 && 199789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 200789Sahrens !dir_is_empty(mountpoint)) { 201*2082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 202*2082Seschrock "directory is not empty")); 203*2082Seschrock return (zfs_error(hdl, EZFS_MOUNTFAILED, 204*2082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint)); 205789Sahrens } 206789Sahrens 207789Sahrens /* perform the mount */ 208789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 209789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 210789Sahrens /* 211789Sahrens * Generic errors are nasty, but there are just way too many 212789Sahrens * from mount(), and they're well-understood. We pick a few 213789Sahrens * common ones to improve upon. 214789Sahrens */ 215*2082Seschrock if (errno == EBUSY) 216*2082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 217*2082Seschrock "mountpoint or dataset is busy")); 218*2082Seschrock else 219*2082Seschrock zfs_error_aux(hdl, strerror(errno)); 220*2082Seschrock 221*2082Seschrock return (zfs_error(hdl, EZFS_MOUNTFAILED, 222*2082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 223*2082Seschrock zhp->zfs_name)); 224789Sahrens } 225789Sahrens 226789Sahrens return (0); 227789Sahrens } 228789Sahrens 229789Sahrens /* 230789Sahrens * Unmount the given filesystem. 231789Sahrens */ 232789Sahrens int 233789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 234789Sahrens { 235789Sahrens struct mnttab search = { 0 }, entry; 236789Sahrens 237789Sahrens /* check to see if need to unmount the filesystem */ 238789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 2391407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 240*2082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 241789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 242*2082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 243789Sahrens 244789Sahrens if (mountpoint == NULL) 245789Sahrens mountpoint = entry.mnt_mountp; 246789Sahrens 247789Sahrens /* 248789Sahrens * Always unshare the filesystem first. 249789Sahrens */ 250789Sahrens if (zfs_unshare(zhp, mountpoint) != 0) 251789Sahrens return (-1); 252789Sahrens 253789Sahrens /* 254789Sahrens * Try to unmount the filesystem. There is no reason to try a 255789Sahrens * forced unmount because the vnodes will still carry a 256789Sahrens * reference to the underlying dataset, so we can't destroy it 257789Sahrens * anyway. 258789Sahrens * 259789Sahrens * In the unmount case, we print out a slightly more informative 260789Sahrens * error message, though we'll be relying on the poor error 261789Sahrens * semantics from the kernel. 262789Sahrens */ 263789Sahrens if (umount2(mountpoint, flags) != 0) { 264*2082Seschrock zfs_error_aux(zhp->zfs_hdl, strerror(errno)); 265*2082Seschrock return (zfs_error(zhp->zfs_hdl, EZFS_UMOUNTFAILED, 266*2082Seschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), 267*2082Seschrock mountpoint)); 268789Sahrens } 269789Sahrens 270789Sahrens /* 271789Sahrens * Don't actually destroy the underlying directory 272789Sahrens */ 273789Sahrens } 274789Sahrens 275789Sahrens return (0); 276789Sahrens } 277789Sahrens 278789Sahrens /* 279789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 280789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 281789Sahrens * remount the filesystems afterwards. 282789Sahrens */ 283789Sahrens int 284789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 285789Sahrens { 286789Sahrens prop_changelist_t *clp; 287789Sahrens int ret; 288789Sahrens 289789Sahrens clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags); 290789Sahrens if (clp == NULL) 291789Sahrens return (-1); 292789Sahrens 293789Sahrens ret = changelist_prefix(clp); 294789Sahrens changelist_free(clp); 295789Sahrens 296789Sahrens return (ret); 297789Sahrens } 298789Sahrens 299789Sahrens /* 300789Sahrens * Check to see if the filesystem is currently shared. 301789Sahrens */ 302*2082Seschrock boolean_t 303789Sahrens zfs_is_shared(zfs_handle_t *zhp, char **where) 304789Sahrens { 305789Sahrens char *mountpoint; 306789Sahrens 307789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 308*2082Seschrock return (B_FALSE); 309789Sahrens 310*2082Seschrock if (is_shared(zhp->zfs_hdl, mountpoint)) { 311789Sahrens if (where != NULL) 312789Sahrens *where = mountpoint; 313789Sahrens else 314789Sahrens free(mountpoint); 315*2082Seschrock return (B_TRUE); 316789Sahrens } else { 317789Sahrens free(mountpoint); 318*2082Seschrock return (B_FALSE); 319789Sahrens } 320789Sahrens } 321789Sahrens 322789Sahrens /* 323789Sahrens * Share the given filesystem according to the options in 'sharenfs'. We rely 324789Sahrens * on share(1M) to the dirty work for us. 325789Sahrens */ 326789Sahrens int 327789Sahrens zfs_share(zfs_handle_t *zhp) 328789Sahrens { 329789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 330789Sahrens char shareopts[ZFS_MAXPROPLEN]; 331789Sahrens char buf[MAXPATHLEN]; 332789Sahrens FILE *fp; 333*2082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 334789Sahrens 335789Sahrens /* ignore non-filesystems */ 336789Sahrens if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) 337789Sahrens return (0); 338789Sahrens 339789Sahrens /* return success if there is no mountpoint set */ 340789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, 341*2082Seschrock mountpoint, sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0 || 342789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 343789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 344789Sahrens return (0); 345789Sahrens 346789Sahrens /* return success if there are no share options */ 347789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts), 348*2082Seschrock NULL, NULL, 0, B_FALSE) != 0 || 349789Sahrens strcmp(shareopts, "off") == 0) 350789Sahrens return (0); 351789Sahrens 352789Sahrens /* 353789Sahrens * If the 'zoned' property is set, simply return success since: 354789Sahrens * 1. in a global zone, a dataset should not be shared if it's 355789Sahrens * managed in a local zone. 356789Sahrens * 2. in a local zone, NFS server is not available. 357789Sahrens */ 358789Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 359789Sahrens return (0); 360789Sahrens } 361789Sahrens 362789Sahrens /* 363789Sahrens * Invoke the share(1M) command. We always do this, even if it's 364789Sahrens * currently shared, as the options may have changed. 365789Sahrens */ 366789Sahrens if (strcmp(shareopts, "on") == 0) 367789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 368789Sahrens "-F nfs \"%s\" 2>&1", mountpoint); 369789Sahrens else 370789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 371789Sahrens "-F nfs -o \"%s\" \"%s\" 2>&1", shareopts, 372789Sahrens mountpoint); 373789Sahrens 374*2082Seschrock if ((fp = popen(buf, "r")) == NULL) 375*2082Seschrock return (zfs_error(hdl, EZFS_SHAREFAILED, 376*2082Seschrock dgettext(TEXT_DOMAIN, "cannot share '%s'"), 377*2082Seschrock zfs_get_name(zhp))); 378789Sahrens 379789Sahrens /* 380789Sahrens * share(1M) should only produce output if there is some kind 381789Sahrens * of error. All output begins with "share_nfs: ", so we trim 382789Sahrens * this off to get to the real error. 383789Sahrens */ 384789Sahrens if (fgets(buf, sizeof (buf), fp) != NULL) { 385789Sahrens char *colon = strchr(buf, ':'); 386789Sahrens 387789Sahrens while (buf[strlen(buf) - 1] == '\n') 388789Sahrens buf[strlen(buf) - 1] = '\0'; 389789Sahrens 390*2082Seschrock if (colon != NULL) 391*2082Seschrock zfs_error_aux(hdl, colon + 2); 392*2082Seschrock 393*2082Seschrock (void) zfs_error(hdl, EZFS_SHAREFAILED, 394*2082Seschrock dgettext(TEXT_DOMAIN, "cannot share '%s'")); 395789Sahrens 396789Sahrens verify(pclose(fp) != 0); 397789Sahrens return (-1); 398789Sahrens } 399789Sahrens 400789Sahrens verify(pclose(fp) == 0); 401789Sahrens 402789Sahrens return (0); 403789Sahrens } 404789Sahrens 405789Sahrens /* 406789Sahrens * Unshare the given filesystem. 407789Sahrens */ 408789Sahrens int 409789Sahrens zfs_unshare(zfs_handle_t *zhp, const char *mountpoint) 410789Sahrens { 411789Sahrens char buf[MAXPATHLEN]; 412789Sahrens struct mnttab search = { 0 }, entry; 413*2082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 414789Sahrens 415789Sahrens /* check to see if need to unmount the filesystem */ 416789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 4171407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 418*2082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 419789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 420*2082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 421789Sahrens 422789Sahrens if (mountpoint == NULL) 423789Sahrens mountpoint = entry.mnt_mountp; 424789Sahrens 425*2082Seschrock if (is_shared(zhp->zfs_hdl, mountpoint)) { 426789Sahrens FILE *fp; 427789Sahrens 428789Sahrens (void) snprintf(buf, sizeof (buf), 429789Sahrens "/usr/sbin/unshare \"%s\" 2>&1", 430789Sahrens mountpoint); 431789Sahrens 432*2082Seschrock if ((fp = popen(buf, "r")) == NULL) 433*2082Seschrock return (zfs_error(hdl, EZFS_UNSHAREFAILED, 434*2082Seschrock dgettext(TEXT_DOMAIN, 435*2082Seschrock "cannot unshare '%s'"), zfs_get_name(zhp))); 436789Sahrens 437789Sahrens /* 438789Sahrens * unshare(1M) should only produce output if there is 439789Sahrens * some kind of error. All output begins with "unshare 440789Sahrens * nfs: ", so we trim this off to get to the real error. 441789Sahrens */ 442789Sahrens if (fgets(buf, sizeof (buf), fp) != NULL) { 443789Sahrens char *colon = strchr(buf, ':'); 444789Sahrens 445789Sahrens while (buf[strlen(buf) - 1] == '\n') 446789Sahrens buf[strlen(buf) - 1] = '\0'; 447789Sahrens 448*2082Seschrock if (colon != NULL) 449*2082Seschrock zfs_error_aux(hdl, colon + 2); 450789Sahrens 451789Sahrens verify(pclose(fp) != 0); 452*2082Seschrock 453*2082Seschrock return (zfs_error(hdl, EZFS_UNSHAREFAILED, 454*2082Seschrock dgettext(TEXT_DOMAIN, 455*2082Seschrock "cannot unshare '%s'"), zfs_get_name(zhp))); 456789Sahrens } 457789Sahrens 458789Sahrens verify(pclose(fp) == 0); 459789Sahrens } 460789Sahrens } 461789Sahrens 462789Sahrens return (0); 463789Sahrens } 464789Sahrens 465789Sahrens /* 466789Sahrens * Same as zfs_unmountall(), but for unshares. 467789Sahrens */ 468789Sahrens int 469789Sahrens zfs_unshareall(zfs_handle_t *zhp) 470789Sahrens { 471789Sahrens prop_changelist_t *clp; 472789Sahrens int ret; 473789Sahrens 474789Sahrens clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0); 475789Sahrens if (clp == NULL) 476789Sahrens return (-1); 477789Sahrens 478789Sahrens ret = changelist_unshare(clp); 479789Sahrens changelist_free(clp); 480789Sahrens 481789Sahrens return (ret); 482789Sahrens } 483789Sahrens 484789Sahrens /* 485789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 486789Sahrens * We only remove the underlying directory if: 487789Sahrens * 488789Sahrens * - The mountpoint is not 'none' or 'legacy' 489789Sahrens * - The mountpoint is non-empty 490789Sahrens * - The mountpoint is the default or inherited 491789Sahrens * - The 'zoned' property is set, or we're in a local zone 492789Sahrens * 493789Sahrens * Any other directories we leave alone. 494789Sahrens */ 495789Sahrens void 496789Sahrens remove_mountpoint(zfs_handle_t *zhp) 497789Sahrens { 498789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 499789Sahrens char source[ZFS_MAXNAMELEN]; 500789Sahrens zfs_source_t sourcetype; 501*2082Seschrock int zoneid = getzoneid(); 502789Sahrens 503789Sahrens /* ignore non-filesystems */ 504789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 505789Sahrens sizeof (mountpoint), &sourcetype, source, sizeof (source), 506*2082Seschrock B_FALSE) != 0) 507789Sahrens return; 508789Sahrens 509789Sahrens if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0 && 510789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 511789Sahrens (sourcetype == ZFS_SRC_DEFAULT || 512789Sahrens sourcetype == ZFS_SRC_INHERITED) && 513789Sahrens (!zfs_prop_get_int(zhp, ZFS_PROP_ZONED) || 514*2082Seschrock zoneid != GLOBAL_ZONEID)) { 515789Sahrens 516789Sahrens /* 517789Sahrens * Try to remove the directory, silently ignoring any errors. 518789Sahrens * The filesystem may have since been removed or moved around, 519789Sahrens * and this isn't really useful to the administrator in any 520789Sahrens * way. 521789Sahrens */ 522789Sahrens (void) rmdir(mountpoint); 523789Sahrens } 524789Sahrens } 525