1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5789Sahrens * Common Development and Distribution License, Version 1.0 only 6789Sahrens * (the "License"). You may not use this file except in compliance 7789Sahrens * with the License. 8789Sahrens * 9789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10789Sahrens * or http://www.opensolaris.org/os/licensing. 11789Sahrens * See the License for the specific language governing permissions 12789Sahrens * and limitations under the License. 13789Sahrens * 14789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16789Sahrens * If applicable, add the following below this CDDL HEADER, with the 17789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19789Sahrens * 20789Sahrens * CDDL HEADER END 21789Sahrens */ 22789Sahrens /* 23*1371Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28789Sahrens 29789Sahrens /* 30789Sahrens * Routines to manage ZFS mounts. We separate all the nasty routines that have 31789Sahrens * to deal with the OS. The main entry points are: 32789Sahrens * 33789Sahrens * zfs_is_mounted() 34789Sahrens * zfs_mount() 35789Sahrens * zfs_unmount() 36789Sahrens * zfs_unmountall() 37789Sahrens * 38789Sahrens * These functions are used by mount and unmount, and when changing a 39789Sahrens * filesystem's mountpoint. This file also contains the functions used to 40789Sahrens * manage sharing filesystems via NFS: 41789Sahrens * 42789Sahrens * zfs_is_shared() 43789Sahrens * zfs_share() 44789Sahrens * zfs_unshare() 45789Sahrens * zfs_unshareall() 46789Sahrens */ 47789Sahrens 48789Sahrens #include <dirent.h> 49789Sahrens #include <errno.h> 50789Sahrens #include <libgen.h> 51789Sahrens #include <libintl.h> 52789Sahrens #include <stdio.h> 53789Sahrens #include <stdlib.h> 54789Sahrens #include <strings.h> 55789Sahrens #include <unistd.h> 56789Sahrens #include <zone.h> 57789Sahrens #include <sys/mntent.h> 58789Sahrens #include <sys/mnttab.h> 59789Sahrens #include <sys/mount.h> 60789Sahrens #include <sys/stat.h> 61789Sahrens 62789Sahrens #include <libzfs.h> 63789Sahrens 64789Sahrens #include "libzfs_impl.h" 65789Sahrens 66789Sahrens 67789Sahrens /* 68789Sahrens * The following two files are opened as part of zfs_init(). It's OK to for 69789Sahrens * the sharetab to be NULL, but mnttab must always be non-NULL; 70789Sahrens */ 71789Sahrens FILE *mnttab_file; 72789Sahrens FILE *sharetab_file; 73789Sahrens 74789Sahrens /* 75789Sahrens * Search the sharetab for the given mountpoint, returning TRUE if it is found. 76789Sahrens */ 77789Sahrens static int 78789Sahrens is_shared(const char *mountpoint) 79789Sahrens { 80789Sahrens char buf[MAXPATHLEN], *tab; 81789Sahrens 82789Sahrens if (sharetab_file == NULL) 83789Sahrens return (0); 84789Sahrens 85789Sahrens (void) fseek(sharetab_file, 0, SEEK_SET); 86789Sahrens 87789Sahrens while (fgets(buf, sizeof (buf), sharetab_file) != NULL) { 88789Sahrens 89789Sahrens /* the mountpoint is the first entry on each line */ 90789Sahrens if ((tab = strchr(buf, '\t')) != NULL) { 91789Sahrens *tab = '\0'; 92789Sahrens if (strcmp(buf, mountpoint) == 0) 93789Sahrens return (1); 94789Sahrens } 95789Sahrens } 96789Sahrens 97789Sahrens return (0); 98789Sahrens } 99789Sahrens 100789Sahrens /* 101789Sahrens * Returns TRUE if the specified directory is empty. If we can't open the 102789Sahrens * directory at all, return TRUE so that the mount can fail with a more 103789Sahrens * informative error message. 104789Sahrens */ 105789Sahrens static int 106789Sahrens dir_is_empty(const char *dirname) 107789Sahrens { 108789Sahrens DIR *dirp; 109789Sahrens struct dirent64 *dp; 110789Sahrens 111789Sahrens if ((dirp = opendir(dirname)) == NULL) 112789Sahrens return (TRUE); 113789Sahrens 114789Sahrens while ((dp = readdir64(dirp)) != NULL) { 115789Sahrens 116789Sahrens if (strcmp(dp->d_name, ".") == 0 || 117789Sahrens strcmp(dp->d_name, "..") == 0) 118789Sahrens continue; 119789Sahrens 120789Sahrens (void) closedir(dirp); 121789Sahrens return (FALSE); 122789Sahrens } 123789Sahrens 124789Sahrens (void) closedir(dirp); 125789Sahrens return (TRUE); 126789Sahrens } 127789Sahrens 128789Sahrens /* 129789Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill 130789Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return 131789Sahrens * 0. 132789Sahrens */ 133789Sahrens int 134789Sahrens zfs_is_mounted(zfs_handle_t *zhp, char **where) 135789Sahrens { 136789Sahrens struct mnttab search = { 0 }, entry; 137789Sahrens 138789Sahrens /* 139789Sahrens * Search for the entry in /etc/mnttab. We don't bother getting the 140789Sahrens * mountpoint, as we can just search for the special device. This will 141789Sahrens * also let us find mounts when the mountpoint is 'legacy'. 142789Sahrens */ 143789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 144789Sahrens 145789Sahrens rewind(mnttab_file); 146789Sahrens if (getmntany(mnttab_file, &entry, &search) != 0) 147789Sahrens return (FALSE); 148789Sahrens 149789Sahrens if (where != NULL) 150789Sahrens *where = zfs_strdup(entry.mnt_mountp); 151789Sahrens 152789Sahrens return (TRUE); 153789Sahrens } 154789Sahrens 155789Sahrens /* 156789Sahrens * Mount the given filesystem. 157789Sahrens */ 158789Sahrens int 159789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 160789Sahrens { 161789Sahrens struct stat buf; 162789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 163789Sahrens char mntopts[MNT_LINE_MAX]; 164789Sahrens 165789Sahrens if (options == NULL) 166789Sahrens mntopts[0] = '\0'; 167789Sahrens else 168789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 169789Sahrens 170789Sahrens /* ignore non-filesystems */ 171789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 172789Sahrens sizeof (mountpoint), NULL, NULL, 0, FALSE) != 0) 173789Sahrens return (0); 174789Sahrens 175789Sahrens /* return success if there is no mountpoint set */ 176789Sahrens if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 177789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 178789Sahrens return (0); 179789Sahrens 180789Sahrens /* 181789Sahrens * If the 'zoned' property is set, and we're in the global zone, simply 182789Sahrens * return success. 183789Sahrens */ 184789Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 185789Sahrens char zonename[ZONENAME_MAX]; 186789Sahrens if (getzonenamebyid(getzoneid(), zonename, 187789Sahrens sizeof (zonename)) < 0) { 188789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "internal error: " 189789Sahrens "cannot determine current zone")); 190789Sahrens return (1); 191789Sahrens } 192789Sahrens 193789Sahrens if (strcmp(zonename, "global") == 0) 194789Sahrens return (0); 195789Sahrens } 196789Sahrens 197789Sahrens /* Create the directory if it doesn't already exist */ 198789Sahrens if (lstat(mountpoint, &buf) != 0) { 199789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 200789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': " 201789Sahrens "unable to create mountpoint"), mountpoint); 202789Sahrens return (1); 203789Sahrens } 204789Sahrens } 205789Sahrens 206789Sahrens /* 207789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 208789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 209789Sahrens * would defeat the point. We also avoid this check if 'remount' is 210789Sahrens * specified. 211789Sahrens */ 212789Sahrens if ((flags & MS_OVERLAY) == 0 && 213789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 214789Sahrens !dir_is_empty(mountpoint)) { 215789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': " 216789Sahrens "directory is not empty"), mountpoint); 217789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "use legacy mountpoint to " 218789Sahrens "allow this behavior, or use the -O flag")); 219789Sahrens return (1); 220789Sahrens } 221789Sahrens 222789Sahrens /* perform the mount */ 223789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 224789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 225789Sahrens /* 226789Sahrens * Generic errors are nasty, but there are just way too many 227789Sahrens * from mount(), and they're well-understood. We pick a few 228789Sahrens * common ones to improve upon. 229789Sahrens */ 230789Sahrens switch (errno) { 231789Sahrens case EBUSY: 232789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': " 233*1371Seschrock "mountpoint or dataset is busy"), zhp->zfs_name); 234789Sahrens break; 235789Sahrens case EPERM: 236789Sahrens case EACCES: 237789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': " 238789Sahrens "permission denied"), zhp->zfs_name, 239789Sahrens mountpoint); 240789Sahrens break; 241789Sahrens default: 242789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 243789Sahrens "cannot mount '%s': %s"), 244789Sahrens mountpoint, strerror(errno)); 245789Sahrens break; 246789Sahrens } 247789Sahrens return (1); 248789Sahrens } 249789Sahrens 250789Sahrens return (0); 251789Sahrens } 252789Sahrens 253789Sahrens /* 254789Sahrens * Unmount the given filesystem. 255789Sahrens */ 256789Sahrens int 257789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 258789Sahrens { 259789Sahrens struct mnttab search = { 0 }, entry; 260789Sahrens 261789Sahrens /* check to see if need to unmount the filesystem */ 262789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 263789Sahrens rewind(mnttab_file); 264789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 265789Sahrens getmntany(mnttab_file, &entry, &search) == 0)) { 266789Sahrens 267789Sahrens if (mountpoint == NULL) 268789Sahrens mountpoint = entry.mnt_mountp; 269789Sahrens 270789Sahrens /* 271789Sahrens * Always unshare the filesystem first. 272789Sahrens */ 273789Sahrens if (zfs_unshare(zhp, mountpoint) != 0) 274789Sahrens return (-1); 275789Sahrens 276789Sahrens /* 277789Sahrens * Try to unmount the filesystem. There is no reason to try a 278789Sahrens * forced unmount because the vnodes will still carry a 279789Sahrens * reference to the underlying dataset, so we can't destroy it 280789Sahrens * anyway. 281789Sahrens * 282789Sahrens * In the unmount case, we print out a slightly more informative 283789Sahrens * error message, though we'll be relying on the poor error 284789Sahrens * semantics from the kernel. 285789Sahrens */ 286789Sahrens if (umount2(mountpoint, flags) != 0) { 287789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 288789Sahrens "cannot unmount '%s': %s"), 289789Sahrens mountpoint, strerror(errno)); 290789Sahrens return (-1); 291789Sahrens } 292789Sahrens 293789Sahrens /* 294789Sahrens * Don't actually destroy the underlying directory 295789Sahrens */ 296789Sahrens } 297789Sahrens 298789Sahrens return (0); 299789Sahrens } 300789Sahrens 301789Sahrens /* 302789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 303789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 304789Sahrens * remount the filesystems afterwards. 305789Sahrens */ 306789Sahrens int 307789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 308789Sahrens { 309789Sahrens prop_changelist_t *clp; 310789Sahrens int ret; 311789Sahrens 312789Sahrens clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags); 313789Sahrens if (clp == NULL) 314789Sahrens return (-1); 315789Sahrens 316789Sahrens ret = changelist_prefix(clp); 317789Sahrens changelist_free(clp); 318789Sahrens 319789Sahrens return (ret); 320789Sahrens } 321789Sahrens 322789Sahrens /* 323789Sahrens * Check to see if the filesystem is currently shared. 324789Sahrens */ 325789Sahrens int 326789Sahrens zfs_is_shared(zfs_handle_t *zhp, char **where) 327789Sahrens { 328789Sahrens char *mountpoint; 329789Sahrens 330789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 331789Sahrens return (FALSE); 332789Sahrens 333789Sahrens if (is_shared(mountpoint)) { 334789Sahrens if (where != NULL) 335789Sahrens *where = mountpoint; 336789Sahrens else 337789Sahrens free(mountpoint); 338789Sahrens return (TRUE); 339789Sahrens } else { 340789Sahrens free(mountpoint); 341789Sahrens return (FALSE); 342789Sahrens } 343789Sahrens } 344789Sahrens 345789Sahrens /* 346789Sahrens * Share the given filesystem according to the options in 'sharenfs'. We rely 347789Sahrens * on share(1M) to the dirty work for us. 348789Sahrens */ 349789Sahrens int 350789Sahrens zfs_share(zfs_handle_t *zhp) 351789Sahrens { 352789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 353789Sahrens char shareopts[ZFS_MAXPROPLEN]; 354789Sahrens char buf[MAXPATHLEN]; 355789Sahrens FILE *fp; 356789Sahrens 357789Sahrens /* ignore non-filesystems */ 358789Sahrens if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) 359789Sahrens return (0); 360789Sahrens 361789Sahrens /* return success if there is no mountpoint set */ 362789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, 363789Sahrens mountpoint, sizeof (mountpoint), NULL, NULL, 0, FALSE) != 0 || 364789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 365789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 366789Sahrens return (0); 367789Sahrens 368789Sahrens /* return success if there are no share options */ 369789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts), 370789Sahrens NULL, NULL, 0, FALSE) != 0 || 371789Sahrens strcmp(shareopts, "off") == 0) 372789Sahrens return (0); 373789Sahrens 374789Sahrens /* 375789Sahrens * If the 'zoned' property is set, simply return success since: 376789Sahrens * 1. in a global zone, a dataset should not be shared if it's 377789Sahrens * managed in a local zone. 378789Sahrens * 2. in a local zone, NFS server is not available. 379789Sahrens */ 380789Sahrens if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) { 381789Sahrens return (0); 382789Sahrens } 383789Sahrens 384789Sahrens /* 385789Sahrens * Invoke the share(1M) command. We always do this, even if it's 386789Sahrens * currently shared, as the options may have changed. 387789Sahrens */ 388789Sahrens if (strcmp(shareopts, "on") == 0) 389789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 390789Sahrens "-F nfs \"%s\" 2>&1", mountpoint); 391789Sahrens else 392789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 393789Sahrens "-F nfs -o \"%s\" \"%s\" 2>&1", shareopts, 394789Sahrens mountpoint); 395789Sahrens 396789Sahrens if ((fp = popen(buf, "r")) == NULL) { 397789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot share '%s': " 398789Sahrens "share(1M) failed"), zfs_get_name(zhp)); 399789Sahrens return (-1); 400789Sahrens } 401789Sahrens 402789Sahrens /* 403789Sahrens * share(1M) should only produce output if there is some kind 404789Sahrens * of error. All output begins with "share_nfs: ", so we trim 405789Sahrens * this off to get to the real error. 406789Sahrens */ 407789Sahrens if (fgets(buf, sizeof (buf), fp) != NULL) { 408789Sahrens char *colon = strchr(buf, ':'); 409789Sahrens 410789Sahrens while (buf[strlen(buf) - 1] == '\n') 411789Sahrens buf[strlen(buf) - 1] = '\0'; 412789Sahrens 413789Sahrens if (colon == NULL) 414789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot share " 415789Sahrens "'%s': share(1M) failed"), 416789Sahrens zfs_get_name(zhp)); 417789Sahrens else 418789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot share " 419789Sahrens "'%s': %s"), zfs_get_name(zhp), 420789Sahrens colon + 2); 421789Sahrens 422789Sahrens verify(pclose(fp) != 0); 423789Sahrens return (-1); 424789Sahrens } 425789Sahrens 426789Sahrens verify(pclose(fp) == 0); 427789Sahrens 428789Sahrens return (0); 429789Sahrens } 430789Sahrens 431789Sahrens /* 432789Sahrens * Unshare the given filesystem. 433789Sahrens */ 434789Sahrens int 435789Sahrens zfs_unshare(zfs_handle_t *zhp, const char *mountpoint) 436789Sahrens { 437789Sahrens char buf[MAXPATHLEN]; 438789Sahrens struct mnttab search = { 0 }, entry; 439789Sahrens 440789Sahrens /* check to see if need to unmount the filesystem */ 441789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 442789Sahrens rewind(mnttab_file); 443789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 444789Sahrens getmntany(mnttab_file, &entry, &search) == 0)) { 445789Sahrens 446789Sahrens if (mountpoint == NULL) 447789Sahrens mountpoint = entry.mnt_mountp; 448789Sahrens 449789Sahrens if (is_shared(mountpoint)) { 450789Sahrens FILE *fp; 451789Sahrens 452789Sahrens (void) snprintf(buf, sizeof (buf), 453789Sahrens "/usr/sbin/unshare \"%s\" 2>&1", 454789Sahrens mountpoint); 455789Sahrens 456789Sahrens if ((fp = popen(buf, "r")) == NULL) { 457789Sahrens zfs_error(dgettext(TEXT_DOMAIN, "cannot " 458789Sahrens "unshare '%s': unshare(1M) failed"), 459789Sahrens zfs_get_name(zhp)); 460789Sahrens return (-1); 461789Sahrens } 462789Sahrens 463789Sahrens /* 464789Sahrens * unshare(1M) should only produce output if there is 465789Sahrens * some kind of error. All output begins with "unshare 466789Sahrens * nfs: ", so we trim this off to get to the real error. 467789Sahrens */ 468789Sahrens if (fgets(buf, sizeof (buf), fp) != NULL) { 469789Sahrens char *colon = strchr(buf, ':'); 470789Sahrens 471789Sahrens while (buf[strlen(buf) - 1] == '\n') 472789Sahrens buf[strlen(buf) - 1] = '\0'; 473789Sahrens 474789Sahrens if (colon == NULL) 475789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 476789Sahrens "cannot unshare '%s': unshare(1M) " 477789Sahrens "failed"), zfs_get_name(zhp)); 478789Sahrens else 479789Sahrens zfs_error(dgettext(TEXT_DOMAIN, 480789Sahrens "cannot unshare '%s': %s"), 481789Sahrens zfs_get_name(zhp), colon + 2); 482789Sahrens 483789Sahrens verify(pclose(fp) != 0); 484789Sahrens return (-1); 485789Sahrens } 486789Sahrens 487789Sahrens verify(pclose(fp) == 0); 488789Sahrens } 489789Sahrens } 490789Sahrens 491789Sahrens return (0); 492789Sahrens } 493789Sahrens 494789Sahrens /* 495789Sahrens * Same as zfs_unmountall(), but for unshares. 496789Sahrens */ 497789Sahrens int 498789Sahrens zfs_unshareall(zfs_handle_t *zhp) 499789Sahrens { 500789Sahrens prop_changelist_t *clp; 501789Sahrens int ret; 502789Sahrens 503789Sahrens clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0); 504789Sahrens if (clp == NULL) 505789Sahrens return (-1); 506789Sahrens 507789Sahrens ret = changelist_unshare(clp); 508789Sahrens changelist_free(clp); 509789Sahrens 510789Sahrens return (ret); 511789Sahrens } 512789Sahrens 513789Sahrens /* 514789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 515789Sahrens * We only remove the underlying directory if: 516789Sahrens * 517789Sahrens * - The mountpoint is not 'none' or 'legacy' 518789Sahrens * - The mountpoint is non-empty 519789Sahrens * - The mountpoint is the default or inherited 520789Sahrens * - The 'zoned' property is set, or we're in a local zone 521789Sahrens * 522789Sahrens * Any other directories we leave alone. 523789Sahrens */ 524789Sahrens void 525789Sahrens remove_mountpoint(zfs_handle_t *zhp) 526789Sahrens { 527789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 528789Sahrens char source[ZFS_MAXNAMELEN]; 529789Sahrens zfs_source_t sourcetype; 530789Sahrens char zonename[ZONENAME_MAX]; 531789Sahrens 532789Sahrens /* ignore non-filesystems */ 533789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 534789Sahrens sizeof (mountpoint), &sourcetype, source, sizeof (source), 535789Sahrens FALSE) != 0) 536789Sahrens return; 537789Sahrens 538789Sahrens if (getzonenamebyid(getzoneid(), zonename, sizeof (zonename)) < 0) 539789Sahrens zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: " 540789Sahrens "cannot determine current zone")); 541789Sahrens 542789Sahrens if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0 && 543789Sahrens strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 544789Sahrens (sourcetype == ZFS_SRC_DEFAULT || 545789Sahrens sourcetype == ZFS_SRC_INHERITED) && 546789Sahrens (!zfs_prop_get_int(zhp, ZFS_PROP_ZONED) || 547789Sahrens strcmp(zonename, "global") != 0)) { 548789Sahrens 549789Sahrens /* 550789Sahrens * Try to remove the directory, silently ignoring any errors. 551789Sahrens * The filesystem may have since been removed or moved around, 552789Sahrens * and this isn't really useful to the administrator in any 553789Sahrens * way. 554789Sahrens */ 555789Sahrens (void) rmdir(mountpoint); 556789Sahrens } 557789Sahrens } 558