1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5*1544Seschrock * Common Development and Distribution License (the "License"). 6*1544Seschrock * 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 /* 66789Sahrens * Search the sharetab for the given mountpoint, returning TRUE if it is found. 67789Sahrens */ 68789Sahrens static int 69789Sahrens is_shared(const char *mountpoint) 70789Sahrens { 71789Sahrens char buf[MAXPATHLEN], *tab; 72789Sahrens 73*1544Seschrock if (zfs_sharetab() == NULL) 74789Sahrens return (0); 75789Sahrens 76*1544Seschrock (void) fseek(zfs_sharetab(), 0, SEEK_SET); 77789Sahrens 78*1544Seschrock while (fgets(buf, sizeof (buf), zfs_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) 84789Sahrens return (1); 85789Sahrens } 86789Sahrens } 87789Sahrens 88789Sahrens return (0); 89789Sahrens } 90789Sahrens 91789Sahrens /* 92789Sahrens * Returns TRUE if the specified directory is empty. If we can't open the 93789Sahrens * directory at all, return TRUE so that the mount can fail with a more 94789Sahrens * informative error message. 95789Sahrens */ 96789Sahrens static int 97789Sahrens dir_is_empty(const char *dirname) 98789Sahrens { 99789Sahrens DIR *dirp; 100789Sahrens struct dirent64 *dp; 101789Sahrens 102789Sahrens if ((dirp = opendir(dirname)) == NULL) 103789Sahrens return (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); 112789Sahrens return (FALSE); 113789Sahrens } 114789Sahrens 115789Sahrens (void) closedir(dirp); 116789Sahrens return (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 */ 124789Sahrens int 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*1544Seschrock rewind(zfs_mnttab()); 138*1544Seschrock if (getmntany(zfs_mnttab(), &entry, &search) != 0) 139789Sahrens return (FALSE); 140789Sahrens 141789Sahrens if (where != NULL) 142789Sahrens *where = zfs_strdup(entry.mnt_mountp); 143789Sahrens 144789Sahrens return (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]; 156789Sahrens 157789Sahrens if (options == NULL) 158789Sahrens mntopts[0] = '\0'; 159789Sahrens else 160789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 161789Sahrens 162789Sahrens /* ignore non-filesystems */ 163789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 164789Sahrens sizeof (mountpoint), NULL, NULL, 0, FALSE) != 0) 165789Sahrens return (0); 166789Sahrens 167789Sahrens /* return success if there is no mountpoint set */ 168789Sahrens if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 169789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 170789Sahrens return (0); 171789Sahrens 172789Sahrens /* 173789Sahrens * If the 'zoned' property is set, and we're in the global zone, simply 174789Sahrens * return success. 175789Sahrens */ 176789Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 177789Sahrens char zonename[ZONENAME_MAX]; 178789Sahrens if (getzonenamebyid(getzoneid(), zonename, 179789Sahrens sizeof (zonename)) < 0) { 180789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "internal error: " 181789Sahrens "cannot determine current zone")); 182789Sahrens return (1); 183789Sahrens } 184789Sahrens 185789Sahrens if (strcmp(zonename, "global") == 0) 186789Sahrens return (0); 187789Sahrens } 188789Sahrens 189789Sahrens /* Create the directory if it doesn't already exist */ 190789Sahrens if (lstat(mountpoint, &buf) != 0) { 191789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 192789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': " 193789Sahrens "unable to create mountpoint"), mountpoint); 194789Sahrens return (1); 195789Sahrens } 196789Sahrens } 197789Sahrens 198789Sahrens /* 199789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 200789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 201789Sahrens * would defeat the point. We also avoid this check if 'remount' is 202789Sahrens * specified. 203789Sahrens */ 204789Sahrens if ((flags & MS_OVERLAY) == 0 && 205789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 206789Sahrens !dir_is_empty(mountpoint)) { 207789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': " 208789Sahrens "directory is not empty"), mountpoint); 209789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "use legacy mountpoint to " 210789Sahrens "allow this behavior, or use the -O flag")); 211789Sahrens return (1); 212789Sahrens } 213789Sahrens 214789Sahrens /* perform the mount */ 215789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 216789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 217789Sahrens /* 218789Sahrens * Generic errors are nasty, but there are just way too many 219789Sahrens * from mount(), and they're well-understood. We pick a few 220789Sahrens * common ones to improve upon. 221789Sahrens */ 222789Sahrens switch (errno) { 223789Sahrens case EBUSY: 224789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': " 2251371Seschrock "mountpoint or dataset is busy"), zhp->zfs_name); 226789Sahrens break; 227789Sahrens case EPERM: 228789Sahrens case EACCES: 229789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': " 230789Sahrens "permission denied"), zhp->zfs_name, 231789Sahrens mountpoint); 232789Sahrens break; 233789Sahrens default: 234789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 235789Sahrens "cannot mount '%s': %s"), 236789Sahrens mountpoint, strerror(errno)); 237789Sahrens break; 238789Sahrens } 239789Sahrens return (1); 240789Sahrens } 241789Sahrens 242789Sahrens return (0); 243789Sahrens } 244789Sahrens 245789Sahrens /* 246789Sahrens * Unmount the given filesystem. 247789Sahrens */ 248789Sahrens int 249789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 250789Sahrens { 251789Sahrens struct mnttab search = { 0 }, entry; 252789Sahrens 253789Sahrens /* check to see if need to unmount the filesystem */ 254789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 2551407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 256*1544Seschrock rewind(zfs_mnttab()); 257789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 258*1544Seschrock getmntany(zfs_mnttab(), &entry, &search) == 0)) { 259789Sahrens 260789Sahrens if (mountpoint == NULL) 261789Sahrens mountpoint = entry.mnt_mountp; 262789Sahrens 263789Sahrens /* 264789Sahrens * Always unshare the filesystem first. 265789Sahrens */ 266789Sahrens if (zfs_unshare(zhp, mountpoint) != 0) 267789Sahrens return (-1); 268789Sahrens 269789Sahrens /* 270789Sahrens * Try to unmount the filesystem. There is no reason to try a 271789Sahrens * forced unmount because the vnodes will still carry a 272789Sahrens * reference to the underlying dataset, so we can't destroy it 273789Sahrens * anyway. 274789Sahrens * 275789Sahrens * In the unmount case, we print out a slightly more informative 276789Sahrens * error message, though we'll be relying on the poor error 277789Sahrens * semantics from the kernel. 278789Sahrens */ 279789Sahrens if (umount2(mountpoint, flags) != 0) { 280789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 281789Sahrens "cannot unmount '%s': %s"), 282789Sahrens mountpoint, strerror(errno)); 283789Sahrens return (-1); 284789Sahrens } 285789Sahrens 286789Sahrens /* 287789Sahrens * Don't actually destroy the underlying directory 288789Sahrens */ 289789Sahrens } 290789Sahrens 291789Sahrens return (0); 292789Sahrens } 293789Sahrens 294789Sahrens /* 295789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 296789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 297789Sahrens * remount the filesystems afterwards. 298789Sahrens */ 299789Sahrens int 300789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 301789Sahrens { 302789Sahrens prop_changelist_t *clp; 303789Sahrens int ret; 304789Sahrens 305789Sahrens clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags); 306789Sahrens if (clp == NULL) 307789Sahrens return (-1); 308789Sahrens 309789Sahrens ret = changelist_prefix(clp); 310789Sahrens changelist_free(clp); 311789Sahrens 312789Sahrens return (ret); 313789Sahrens } 314789Sahrens 315789Sahrens /* 316789Sahrens * Check to see if the filesystem is currently shared. 317789Sahrens */ 318789Sahrens int 319789Sahrens zfs_is_shared(zfs_handle_t *zhp, char **where) 320789Sahrens { 321789Sahrens char *mountpoint; 322789Sahrens 323789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 324789Sahrens return (FALSE); 325789Sahrens 326789Sahrens if (is_shared(mountpoint)) { 327789Sahrens if (where != NULL) 328789Sahrens *where = mountpoint; 329789Sahrens else 330789Sahrens free(mountpoint); 331789Sahrens return (TRUE); 332789Sahrens } else { 333789Sahrens free(mountpoint); 334789Sahrens return (FALSE); 335789Sahrens } 336789Sahrens } 337789Sahrens 338789Sahrens /* 339789Sahrens * Share the given filesystem according to the options in 'sharenfs'. We rely 340789Sahrens * on share(1M) to the dirty work for us. 341789Sahrens */ 342789Sahrens int 343789Sahrens zfs_share(zfs_handle_t *zhp) 344789Sahrens { 345789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 346789Sahrens char shareopts[ZFS_MAXPROPLEN]; 347789Sahrens char buf[MAXPATHLEN]; 348789Sahrens FILE *fp; 349789Sahrens 350789Sahrens /* ignore non-filesystems */ 351789Sahrens if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) 352789Sahrens return (0); 353789Sahrens 354789Sahrens /* return success if there is no mountpoint set */ 355789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, 356789Sahrens mountpoint, sizeof (mountpoint), NULL, NULL, 0, FALSE) != 0 || 357789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 358789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 359789Sahrens return (0); 360789Sahrens 361789Sahrens /* return success if there are no share options */ 362789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts), 363789Sahrens NULL, NULL, 0, FALSE) != 0 || 364789Sahrens strcmp(shareopts, "off") == 0) 365789Sahrens return (0); 366789Sahrens 367789Sahrens /* 368789Sahrens * If the 'zoned' property is set, simply return success since: 369789Sahrens * 1. in a global zone, a dataset should not be shared if it's 370789Sahrens * managed in a local zone. 371789Sahrens * 2. in a local zone, NFS server is not available. 372789Sahrens */ 373789Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 374789Sahrens return (0); 375789Sahrens } 376789Sahrens 377789Sahrens /* 378789Sahrens * Invoke the share(1M) command. We always do this, even if it's 379789Sahrens * currently shared, as the options may have changed. 380789Sahrens */ 381789Sahrens if (strcmp(shareopts, "on") == 0) 382789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 383789Sahrens "-F nfs \"%s\" 2>&1", mountpoint); 384789Sahrens else 385789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 386789Sahrens "-F nfs -o \"%s\" \"%s\" 2>&1", shareopts, 387789Sahrens mountpoint); 388789Sahrens 389789Sahrens if ((fp = popen(buf, "r")) == NULL) { 390789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot share '%s': " 391789Sahrens "share(1M) failed"), zfs_get_name(zhp)); 392789Sahrens return (-1); 393789Sahrens } 394789Sahrens 395789Sahrens /* 396789Sahrens * share(1M) should only produce output if there is some kind 397789Sahrens * of error. All output begins with "share_nfs: ", so we trim 398789Sahrens * this off to get to the real error. 399789Sahrens */ 400789Sahrens if (fgets(buf, sizeof (buf), fp) != NULL) { 401789Sahrens char *colon = strchr(buf, ':'); 402789Sahrens 403789Sahrens while (buf[strlen(buf) - 1] == '\n') 404789Sahrens buf[strlen(buf) - 1] = '\0'; 405789Sahrens 406789Sahrens if (colon == NULL) 407789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot share " 408789Sahrens "'%s': share(1M) failed"), 409789Sahrens zfs_get_name(zhp)); 410789Sahrens else 411789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot share " 412789Sahrens "'%s': %s"), zfs_get_name(zhp), 413789Sahrens colon + 2); 414789Sahrens 415789Sahrens verify(pclose(fp) != 0); 416789Sahrens return (-1); 417789Sahrens } 418789Sahrens 419789Sahrens verify(pclose(fp) == 0); 420789Sahrens 421789Sahrens return (0); 422789Sahrens } 423789Sahrens 424789Sahrens /* 425789Sahrens * Unshare the given filesystem. 426789Sahrens */ 427789Sahrens int 428789Sahrens zfs_unshare(zfs_handle_t *zhp, const char *mountpoint) 429789Sahrens { 430789Sahrens char buf[MAXPATHLEN]; 431789Sahrens struct mnttab search = { 0 }, entry; 432789Sahrens 433789Sahrens /* check to see if need to unmount the filesystem */ 434789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 4351407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 436*1544Seschrock rewind(zfs_mnttab()); 437789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 438*1544Seschrock getmntany(zfs_mnttab(), &entry, &search) == 0)) { 439789Sahrens 440789Sahrens if (mountpoint == NULL) 441789Sahrens mountpoint = entry.mnt_mountp; 442789Sahrens 443789Sahrens if (is_shared(mountpoint)) { 444789Sahrens FILE *fp; 445789Sahrens 446789Sahrens (void) snprintf(buf, sizeof (buf), 447789Sahrens "/usr/sbin/unshare \"%s\" 2>&1", 448789Sahrens mountpoint); 449789Sahrens 450789Sahrens if ((fp = popen(buf, "r")) == NULL) { 451789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot " 452789Sahrens "unshare '%s': unshare(1M) failed"), 453789Sahrens zfs_get_name(zhp)); 454789Sahrens return (-1); 455789Sahrens } 456789Sahrens 457789Sahrens /* 458789Sahrens * unshare(1M) should only produce output if there is 459789Sahrens * some kind of error. All output begins with "unshare 460789Sahrens * nfs: ", so we trim this off to get to the real error. 461789Sahrens */ 462789Sahrens if (fgets(buf, sizeof (buf), fp) != NULL) { 463789Sahrens char *colon = strchr(buf, ':'); 464789Sahrens 465789Sahrens while (buf[strlen(buf) - 1] == '\n') 466789Sahrens buf[strlen(buf) - 1] = '\0'; 467789Sahrens 468789Sahrens if (colon == NULL) 469789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 470789Sahrens "cannot unshare '%s': unshare(1M) " 471789Sahrens "failed"), zfs_get_name(zhp)); 472789Sahrens else 473789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 474789Sahrens "cannot unshare '%s': %s"), 475789Sahrens zfs_get_name(zhp), colon + 2); 476789Sahrens 477789Sahrens verify(pclose(fp) != 0); 478789Sahrens return (-1); 479789Sahrens } 480789Sahrens 481789Sahrens verify(pclose(fp) == 0); 482789Sahrens } 483789Sahrens } 484789Sahrens 485789Sahrens return (0); 486789Sahrens } 487789Sahrens 488789Sahrens /* 489789Sahrens * Same as zfs_unmountall(), but for unshares. 490789Sahrens */ 491789Sahrens int 492789Sahrens zfs_unshareall(zfs_handle_t *zhp) 493789Sahrens { 494789Sahrens prop_changelist_t *clp; 495789Sahrens int ret; 496789Sahrens 497789Sahrens clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0); 498789Sahrens if (clp == NULL) 499789Sahrens return (-1); 500789Sahrens 501789Sahrens ret = changelist_unshare(clp); 502789Sahrens changelist_free(clp); 503789Sahrens 504789Sahrens return (ret); 505789Sahrens } 506789Sahrens 507789Sahrens /* 508789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 509789Sahrens * We only remove the underlying directory if: 510789Sahrens * 511789Sahrens * - The mountpoint is not 'none' or 'legacy' 512789Sahrens * - The mountpoint is non-empty 513789Sahrens * - The mountpoint is the default or inherited 514789Sahrens * - The 'zoned' property is set, or we're in a local zone 515789Sahrens * 516789Sahrens * Any other directories we leave alone. 517789Sahrens */ 518789Sahrens void 519789Sahrens remove_mountpoint(zfs_handle_t *zhp) 520789Sahrens { 521789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 522789Sahrens char source[ZFS_MAXNAMELEN]; 523789Sahrens zfs_source_t sourcetype; 524789Sahrens char zonename[ZONENAME_MAX]; 525789Sahrens 526789Sahrens /* ignore non-filesystems */ 527789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 528789Sahrens sizeof (mountpoint), &sourcetype, source, sizeof (source), 529789Sahrens FALSE) != 0) 530789Sahrens return; 531789Sahrens 532789Sahrens if (getzonenamebyid(getzoneid(), zonename, sizeof (zonename)) < 0) 533789Sahrens zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: " 534789Sahrens "cannot determine current zone")); 535789Sahrens 536789Sahrens if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0 && 537789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 538789Sahrens (sourcetype == ZFS_SRC_DEFAULT || 539789Sahrens sourcetype == ZFS_SRC_INHERITED) && 540789Sahrens (!zfs_prop_get_int(zhp, ZFS_PROP_ZONED) || 541789Sahrens strcmp(zonename, "global") != 0)) { 542789Sahrens 543789Sahrens /* 544789Sahrens * Try to remove the directory, silently ignoring any errors. 545789Sahrens * The filesystem may have since been removed or moved around, 546789Sahrens * and this isn't really useful to the administrator in any 547789Sahrens * way. 548789Sahrens */ 549789Sahrens (void) rmdir(mountpoint); 550789Sahrens } 551789Sahrens } 552