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