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 */ 21*3126Sahl 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 31*3126Sahl * to deal with the OS. The following functions are the main entry points -- 32*3126Sahl * they are used by mount and unmount and when changing a filesystem's 33*3126Sahl * mountpoint. 34789Sahrens * 35789Sahrens * zfs_is_mounted() 36789Sahrens * zfs_mount() 37789Sahrens * zfs_unmount() 38789Sahrens * zfs_unmountall() 39789Sahrens * 40*3126Sahl * This file also contains the functions used to manage sharing filesystems via 41*3126Sahl * NFS and iSCSI: 42789Sahrens * 43789Sahrens * zfs_is_shared() 44789Sahrens * zfs_share() 45789Sahrens * zfs_unshare() 46*3126Sahl * 47*3126Sahl * zfs_is_shared_nfs() 48*3126Sahl * zfs_share_nfs() 49*3126Sahl * zfs_unshare_nfs() 50*3126Sahl * zfs_unshareall_nfs() 51*3126Sahl * zfs_is_shared_iscsi() 52*3126Sahl * zfs_share_iscsi() 53*3126Sahl * zfs_unshare_iscsi() 542474Seschrock * 552474Seschrock * The following functions are available for pool consumers, and will 56*3126Sahl * mount/unmount and share/unshare all datasets within pool: 572474Seschrock * 58*3126Sahl * zpool_enable_datasets() 59*3126Sahl * zpool_disable_datasets() 60789Sahrens */ 61789Sahrens 62789Sahrens #include <dirent.h> 63789Sahrens #include <errno.h> 64789Sahrens #include <libgen.h> 65789Sahrens #include <libintl.h> 66*3126Sahl #include <libiscsitgt.h> 67789Sahrens #include <stdio.h> 68789Sahrens #include <stdlib.h> 69789Sahrens #include <strings.h> 70789Sahrens #include <unistd.h> 71789Sahrens #include <zone.h> 72789Sahrens #include <sys/mntent.h> 73789Sahrens #include <sys/mnttab.h> 74789Sahrens #include <sys/mount.h> 75789Sahrens #include <sys/stat.h> 76789Sahrens 77789Sahrens #include <libzfs.h> 78789Sahrens 79789Sahrens #include "libzfs_impl.h" 80789Sahrens 81789Sahrens /* 822082Seschrock * Search the sharetab for the given mountpoint, returning true if it is found. 83789Sahrens */ 842082Seschrock static boolean_t 852082Seschrock is_shared(libzfs_handle_t *hdl, const char *mountpoint) 86789Sahrens { 87789Sahrens char buf[MAXPATHLEN], *tab; 88789Sahrens 892082Seschrock if (hdl->libzfs_sharetab == NULL) 90789Sahrens return (0); 91789Sahrens 922082Seschrock (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); 93789Sahrens 942082Seschrock while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { 95789Sahrens 96789Sahrens /* the mountpoint is the first entry on each line */ 97789Sahrens if ((tab = strchr(buf, '\t')) != NULL) { 98789Sahrens *tab = '\0'; 99789Sahrens if (strcmp(buf, mountpoint) == 0) 1002082Seschrock return (B_TRUE); 101789Sahrens } 102789Sahrens } 103789Sahrens 1042082Seschrock return (B_FALSE); 105789Sahrens } 106789Sahrens 107789Sahrens /* 1082082Seschrock * Returns true if the specified directory is empty. If we can't open the 1092082Seschrock * directory at all, return true so that the mount can fail with a more 110789Sahrens * informative error message. 111789Sahrens */ 1122082Seschrock static boolean_t 113789Sahrens dir_is_empty(const char *dirname) 114789Sahrens { 115789Sahrens DIR *dirp; 116789Sahrens struct dirent64 *dp; 117789Sahrens 118789Sahrens if ((dirp = opendir(dirname)) == NULL) 1192082Seschrock return (B_TRUE); 120789Sahrens 121789Sahrens while ((dp = readdir64(dirp)) != NULL) { 122789Sahrens 123789Sahrens if (strcmp(dp->d_name, ".") == 0 || 124789Sahrens strcmp(dp->d_name, "..") == 0) 125789Sahrens continue; 126789Sahrens 127789Sahrens (void) closedir(dirp); 1282082Seschrock return (B_FALSE); 129789Sahrens } 130789Sahrens 131789Sahrens (void) closedir(dirp); 1322082Seschrock return (B_TRUE); 133789Sahrens } 134789Sahrens 135789Sahrens /* 136789Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill 137789Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return 138789Sahrens * 0. 139789Sahrens */ 1402082Seschrock boolean_t 141789Sahrens zfs_is_mounted(zfs_handle_t *zhp, char **where) 142789Sahrens { 143789Sahrens struct mnttab search = { 0 }, entry; 144789Sahrens 145789Sahrens /* 146789Sahrens * Search for the entry in /etc/mnttab. We don't bother getting the 147789Sahrens * mountpoint, as we can just search for the special device. This will 148789Sahrens * also let us find mounts when the mountpoint is 'legacy'. 149789Sahrens */ 150789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 1511407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 152789Sahrens 1532082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 1542082Seschrock if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) != 0) 1552082Seschrock return (B_FALSE); 156789Sahrens 157789Sahrens if (where != NULL) 1582082Seschrock *where = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 159789Sahrens 1602082Seschrock return (B_TRUE); 161789Sahrens } 162789Sahrens 163789Sahrens /* 1642676Seschrock * Returns true if the given dataset is mountable, false otherwise. Returns the 1652676Seschrock * mountpoint in 'buf'. 1662676Seschrock */ 1672676Seschrock static boolean_t 1682676Seschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, 1692676Seschrock zfs_source_t *source) 1702676Seschrock { 1712676Seschrock char sourceloc[ZFS_MAXNAMELEN]; 1722676Seschrock zfs_source_t sourcetype; 1732676Seschrock 1742676Seschrock if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type)) 1752676Seschrock return (B_FALSE); 1762676Seschrock 1772676Seschrock verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen, 1782676Seschrock &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0); 1792676Seschrock 1802676Seschrock if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 || 1812676Seschrock strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0) 1822676Seschrock return (B_FALSE); 1832676Seschrock 1842676Seschrock if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT)) 1852676Seschrock return (B_FALSE); 1862676Seschrock 1872676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) && 1882676Seschrock getzoneid() == GLOBAL_ZONEID) 1892676Seschrock return (B_FALSE); 1902676Seschrock 1912676Seschrock if (source) 1922676Seschrock *source = sourcetype; 1932676Seschrock 1942676Seschrock return (B_TRUE); 1952676Seschrock } 1962676Seschrock 1972676Seschrock /* 198789Sahrens * Mount the given filesystem. 199789Sahrens */ 200789Sahrens int 201789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 202789Sahrens { 203789Sahrens struct stat buf; 204789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 205789Sahrens char mntopts[MNT_LINE_MAX]; 2062082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 207789Sahrens 208789Sahrens if (options == NULL) 209789Sahrens mntopts[0] = '\0'; 210789Sahrens else 211789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 212789Sahrens 2132676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 2142082Seschrock return (0); 215789Sahrens 216789Sahrens /* Create the directory if it doesn't already exist */ 217789Sahrens if (lstat(mountpoint, &buf) != 0) { 218789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 2192082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2202082Seschrock "failed to create mountpoint")); 2212082Seschrock return (zfs_error(hdl, EZFS_MOUNTFAILED, 2222082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 2232082Seschrock mountpoint)); 224789Sahrens } 225789Sahrens } 226789Sahrens 227789Sahrens /* 228789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 229789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 230789Sahrens * would defeat the point. We also avoid this check if 'remount' is 231789Sahrens * specified. 232789Sahrens */ 233789Sahrens if ((flags & MS_OVERLAY) == 0 && 234789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 235789Sahrens !dir_is_empty(mountpoint)) { 2362082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2372082Seschrock "directory is not empty")); 2382082Seschrock return (zfs_error(hdl, EZFS_MOUNTFAILED, 2392082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint)); 240789Sahrens } 241789Sahrens 242789Sahrens /* perform the mount */ 243789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 244789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 245789Sahrens /* 246789Sahrens * Generic errors are nasty, but there are just way too many 247789Sahrens * from mount(), and they're well-understood. We pick a few 248789Sahrens * common ones to improve upon. 249789Sahrens */ 2502082Seschrock if (errno == EBUSY) 2512082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2522082Seschrock "mountpoint or dataset is busy")); 2532082Seschrock else 2542082Seschrock zfs_error_aux(hdl, strerror(errno)); 2552082Seschrock 2562082Seschrock return (zfs_error(hdl, EZFS_MOUNTFAILED, 2572082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 2582082Seschrock zhp->zfs_name)); 259789Sahrens } 260789Sahrens 261789Sahrens return (0); 262789Sahrens } 263789Sahrens 264789Sahrens /* 2652474Seschrock * Unmount a single filesystem. 2662474Seschrock */ 2672474Seschrock static int 2682474Seschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) 2692474Seschrock { 2702474Seschrock if (umount2(mountpoint, flags) != 0) { 2712474Seschrock zfs_error_aux(hdl, strerror(errno)); 2722474Seschrock return (zfs_error(hdl, EZFS_UMOUNTFAILED, 2732474Seschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), 2742474Seschrock mountpoint)); 2752474Seschrock } 2762474Seschrock 2772474Seschrock return (0); 2782474Seschrock } 2792474Seschrock 2802474Seschrock /* 281789Sahrens * Unmount the given filesystem. 282789Sahrens */ 283789Sahrens int 284789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 285789Sahrens { 286789Sahrens struct mnttab search = { 0 }, entry; 287789Sahrens 288789Sahrens /* check to see if need to unmount the filesystem */ 2892474Seschrock search.mnt_special = zhp->zfs_name; 2901407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 2912082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 292789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 2932082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 294789Sahrens 295789Sahrens if (mountpoint == NULL) 296789Sahrens mountpoint = entry.mnt_mountp; 297789Sahrens 298789Sahrens /* 2992474Seschrock * Unshare and unmount the filesystem 300789Sahrens */ 301*3126Sahl if (zfs_unshare_nfs(zhp, mountpoint) != 0 || 3022474Seschrock unmount_one(zhp->zfs_hdl, mountpoint, flags) != 0) 303789Sahrens return (-1); 304789Sahrens } 305789Sahrens 306789Sahrens return (0); 307789Sahrens } 308789Sahrens 309789Sahrens /* 310789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 311789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 312789Sahrens * remount the filesystems afterwards. 313789Sahrens */ 314789Sahrens int 315789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 316789Sahrens { 317789Sahrens prop_changelist_t *clp; 318789Sahrens int ret; 319789Sahrens 320789Sahrens clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags); 321789Sahrens if (clp == NULL) 322789Sahrens return (-1); 323789Sahrens 324789Sahrens ret = changelist_prefix(clp); 325789Sahrens changelist_free(clp); 326789Sahrens 327789Sahrens return (ret); 328789Sahrens } 329789Sahrens 330*3126Sahl boolean_t 331*3126Sahl zfs_is_shared(zfs_handle_t *zhp) 332*3126Sahl { 333*3126Sahl if (ZFS_IS_VOLUME(zhp)) 334*3126Sahl return (zfs_is_shared_iscsi(zhp)); 335*3126Sahl 336*3126Sahl return (zfs_is_shared_nfs(zhp, NULL)); 337*3126Sahl } 338*3126Sahl 339*3126Sahl int 340*3126Sahl zfs_share(zfs_handle_t *zhp) 341*3126Sahl { 342*3126Sahl if (ZFS_IS_VOLUME(zhp)) 343*3126Sahl return (zfs_share_iscsi(zhp)); 344*3126Sahl 345*3126Sahl return (zfs_share_nfs(zhp)); 346*3126Sahl } 347*3126Sahl 348*3126Sahl int 349*3126Sahl zfs_unshare(zfs_handle_t *zhp) 350*3126Sahl { 351*3126Sahl if (ZFS_IS_VOLUME(zhp)) 352*3126Sahl return (zfs_unshare_iscsi(zhp)); 353*3126Sahl 354*3126Sahl return (zfs_unshare_nfs(zhp, NULL)); 355*3126Sahl } 356*3126Sahl 357789Sahrens /* 358789Sahrens * Check to see if the filesystem is currently shared. 359789Sahrens */ 3602082Seschrock boolean_t 361*3126Sahl zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) 362789Sahrens { 363789Sahrens char *mountpoint; 364789Sahrens 365789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 3662082Seschrock return (B_FALSE); 367789Sahrens 3682082Seschrock if (is_shared(zhp->zfs_hdl, mountpoint)) { 369789Sahrens if (where != NULL) 370789Sahrens *where = mountpoint; 371789Sahrens else 372789Sahrens free(mountpoint); 3732082Seschrock return (B_TRUE); 374789Sahrens } else { 375789Sahrens free(mountpoint); 3762082Seschrock return (B_FALSE); 377789Sahrens } 378789Sahrens } 379789Sahrens 380789Sahrens /* 381789Sahrens * Share the given filesystem according to the options in 'sharenfs'. We rely 382789Sahrens * on share(1M) to the dirty work for us. 383789Sahrens */ 384789Sahrens int 385*3126Sahl zfs_share_nfs(zfs_handle_t *zhp) 386789Sahrens { 387789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 388789Sahrens char shareopts[ZFS_MAXPROPLEN]; 389789Sahrens char buf[MAXPATHLEN]; 390789Sahrens FILE *fp; 3912082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 392789Sahrens 3932676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 394789Sahrens return (0); 395789Sahrens 396*3126Sahl /* 397*3126Sahl * Return success if there are no share options. 398*3126Sahl */ 399789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts), 4002082Seschrock NULL, NULL, 0, B_FALSE) != 0 || 401789Sahrens strcmp(shareopts, "off") == 0) 402789Sahrens return (0); 403789Sahrens 404789Sahrens /* 4052676Seschrock * If the 'zoned' property is set, then zfs_is_mountable() will have 4062676Seschrock * already bailed out if we are in the global zone. But local 4072676Seschrock * zones cannot be NFS servers, so we ignore it for local zones as well. 408789Sahrens */ 4092676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) 410789Sahrens return (0); 411789Sahrens 412789Sahrens /* 413789Sahrens * Invoke the share(1M) command. We always do this, even if it's 414789Sahrens * currently shared, as the options may have changed. 415789Sahrens */ 416789Sahrens if (strcmp(shareopts, "on") == 0) 417789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 418789Sahrens "-F nfs \"%s\" 2>&1", mountpoint); 419789Sahrens else 420789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 421789Sahrens "-F nfs -o \"%s\" \"%s\" 2>&1", shareopts, 422789Sahrens mountpoint); 423789Sahrens 4242082Seschrock if ((fp = popen(buf, "r")) == NULL) 425*3126Sahl return (zfs_error(hdl, EZFS_SHARENFSFAILED, 4262082Seschrock dgettext(TEXT_DOMAIN, "cannot share '%s'"), 4272082Seschrock zfs_get_name(zhp))); 428789Sahrens 429789Sahrens /* 430789Sahrens * share(1M) should only produce output if there is some kind 431789Sahrens * of error. All output begins with "share_nfs: ", so we trim 432789Sahrens * this off to get to the real error. 433789Sahrens */ 434789Sahrens if (fgets(buf, sizeof (buf), fp) != NULL) { 435789Sahrens char *colon = strchr(buf, ':'); 436789Sahrens 437789Sahrens while (buf[strlen(buf) - 1] == '\n') 438789Sahrens buf[strlen(buf) - 1] = '\0'; 439789Sahrens 4402082Seschrock if (colon != NULL) 4412082Seschrock zfs_error_aux(hdl, colon + 2); 4422082Seschrock 443*3126Sahl (void) zfs_error(hdl, EZFS_SHARENFSFAILED, 4442474Seschrock dgettext(TEXT_DOMAIN, "cannot share '%s'"), 4452474Seschrock zfs_get_name(zhp)); 446789Sahrens 447789Sahrens verify(pclose(fp) != 0); 448789Sahrens return (-1); 449789Sahrens } 450789Sahrens 451789Sahrens verify(pclose(fp) == 0); 452789Sahrens 453789Sahrens return (0); 454789Sahrens } 455789Sahrens 456789Sahrens /* 4572474Seschrock * Unshare a filesystem by mountpoint. 4582474Seschrock */ 4592474Seschrock static int 4602474Seschrock unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint) 4612474Seschrock { 4622474Seschrock char buf[MAXPATHLEN]; 4632474Seschrock FILE *fp; 4642474Seschrock 4652474Seschrock (void) snprintf(buf, sizeof (buf), 4662474Seschrock "/usr/sbin/unshare \"%s\" 2>&1", 4672474Seschrock mountpoint); 4682474Seschrock 4692474Seschrock if ((fp = popen(buf, "r")) == NULL) 470*3126Sahl return (zfs_error(hdl, EZFS_UNSHARENFSFAILED, 4712474Seschrock dgettext(TEXT_DOMAIN, 4722474Seschrock "cannot unshare '%s'"), name)); 4732474Seschrock 4742474Seschrock /* 4752474Seschrock * unshare(1M) should only produce output if there is 4762474Seschrock * some kind of error. All output begins with "unshare 4772474Seschrock * nfs: ", so we trim this off to get to the real error. 4782474Seschrock */ 4792474Seschrock if (fgets(buf, sizeof (buf), fp) != NULL) { 4802474Seschrock char *colon = strchr(buf, ':'); 4812474Seschrock 4822474Seschrock while (buf[strlen(buf) - 1] == '\n') 4832474Seschrock buf[strlen(buf) - 1] = '\0'; 4842474Seschrock 4852474Seschrock if (colon != NULL) 4862474Seschrock zfs_error_aux(hdl, colon + 2); 4872474Seschrock 4882474Seschrock verify(pclose(fp) != 0); 4892474Seschrock 490*3126Sahl return (zfs_error(hdl, EZFS_UNSHARENFSFAILED, 4912474Seschrock dgettext(TEXT_DOMAIN, 4922474Seschrock "cannot unshare '%s'"), name)); 4932474Seschrock } 4942474Seschrock 4952474Seschrock verify(pclose(fp) == 0); 4962474Seschrock 4972474Seschrock return (0); 4982474Seschrock } 4992474Seschrock 5002474Seschrock /* 501789Sahrens * Unshare the given filesystem. 502789Sahrens */ 503789Sahrens int 504*3126Sahl zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) 505789Sahrens { 506789Sahrens struct mnttab search = { 0 }, entry; 507789Sahrens 508789Sahrens /* check to see if need to unmount the filesystem */ 509789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 5101407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 5112082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 512789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 5132082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 514789Sahrens 515789Sahrens if (mountpoint == NULL) 516789Sahrens mountpoint = entry.mnt_mountp; 517789Sahrens 5182474Seschrock if (is_shared(zhp->zfs_hdl, mountpoint) && 5192474Seschrock unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0) 5202474Seschrock return (-1); 521789Sahrens } 522789Sahrens 523789Sahrens return (0); 524789Sahrens } 525789Sahrens 526789Sahrens /* 527*3126Sahl * Same as zfs_unmountall(), but for NFS unshares. 528789Sahrens */ 529789Sahrens int 530*3126Sahl zfs_unshareall_nfs(zfs_handle_t *zhp) 531789Sahrens { 532789Sahrens prop_changelist_t *clp; 533789Sahrens int ret; 534789Sahrens 535789Sahrens clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0); 536789Sahrens if (clp == NULL) 537789Sahrens return (-1); 538789Sahrens 539789Sahrens ret = changelist_unshare(clp); 540789Sahrens changelist_free(clp); 541789Sahrens 542789Sahrens return (ret); 543789Sahrens } 544789Sahrens 545789Sahrens /* 546789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 547789Sahrens * We only remove the underlying directory if: 548789Sahrens * 549789Sahrens * - The mountpoint is not 'none' or 'legacy' 550789Sahrens * - The mountpoint is non-empty 551789Sahrens * - The mountpoint is the default or inherited 552789Sahrens * - The 'zoned' property is set, or we're in a local zone 553789Sahrens * 554789Sahrens * Any other directories we leave alone. 555789Sahrens */ 556789Sahrens void 557789Sahrens remove_mountpoint(zfs_handle_t *zhp) 558789Sahrens { 559789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 5602676Seschrock zfs_source_t source; 561789Sahrens 5622676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), 5632676Seschrock &source)) 564789Sahrens return; 565789Sahrens 5662676Seschrock if (source == ZFS_SRC_DEFAULT || 5672676Seschrock source == ZFS_SRC_INHERITED) { 568789Sahrens /* 569789Sahrens * Try to remove the directory, silently ignoring any errors. 570789Sahrens * The filesystem may have since been removed or moved around, 5712676Seschrock * and this error isn't really useful to the administrator in 5722676Seschrock * any way. 573789Sahrens */ 574789Sahrens (void) rmdir(mountpoint); 575789Sahrens } 576789Sahrens } 5772474Seschrock 578*3126Sahl boolean_t 579*3126Sahl zfs_is_shared_iscsi(zfs_handle_t *zhp) 580*3126Sahl { 581*3126Sahl return (iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); 582*3126Sahl } 583*3126Sahl 584*3126Sahl int 585*3126Sahl zfs_share_iscsi(zfs_handle_t *zhp) 586*3126Sahl { 587*3126Sahl char shareopts[ZFS_MAXPROPLEN]; 588*3126Sahl const char *dataset = zhp->zfs_name; 589*3126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 590*3126Sahl 591*3126Sahl /* 592*3126Sahl * Return success if there are no share options. 593*3126Sahl */ 594*3126Sahl if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 595*3126Sahl sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || 596*3126Sahl strcmp(shareopts, "off") == 0) 597*3126Sahl return (0); 598*3126Sahl 599*3126Sahl if (iscsitgt_zfs_share(dataset) != 0) 600*3126Sahl return (zfs_error(hdl, EZFS_SHAREISCSIFAILED, 601*3126Sahl dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); 602*3126Sahl 603*3126Sahl return (0); 604*3126Sahl } 605*3126Sahl 606*3126Sahl int 607*3126Sahl zfs_unshare_iscsi(zfs_handle_t *zhp) 608*3126Sahl { 609*3126Sahl const char *dataset = zfs_get_name(zhp); 610*3126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 611*3126Sahl 612*3126Sahl /* 613*3126Sahl * If this fails with ENODEV it indicates that zvol wasn't shared so 614*3126Sahl * we should return success in that case. 615*3126Sahl */ 616*3126Sahl if (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV) 617*3126Sahl return (zfs_error(hdl, EZFS_UNSHAREISCSIFAILED, 618*3126Sahl dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); 619*3126Sahl 620*3126Sahl return (0); 621*3126Sahl } 622*3126Sahl 6232474Seschrock typedef struct mount_cbdata { 6242474Seschrock zfs_handle_t **cb_datasets; 6252474Seschrock int cb_used; 6262474Seschrock int cb_alloc; 6272474Seschrock } mount_cbdata_t; 6282474Seschrock 6292474Seschrock static int 6302474Seschrock mount_cb(zfs_handle_t *zhp, void *data) 6312474Seschrock { 6322474Seschrock mount_cbdata_t *cbp = data; 6332474Seschrock 634*3126Sahl if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { 6352474Seschrock zfs_close(zhp); 6362474Seschrock return (0); 6372474Seschrock } 6382474Seschrock 6392474Seschrock if (cbp->cb_alloc == cbp->cb_used) { 6402676Seschrock void *ptr; 6412474Seschrock 6422676Seschrock if ((ptr = zfs_realloc(zhp->zfs_hdl, 6432676Seschrock cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), 6442676Seschrock cbp->cb_alloc * 2 * sizeof (void *))) == NULL) 6452474Seschrock return (-1); 6462676Seschrock cbp->cb_datasets = ptr; 6472474Seschrock 6482676Seschrock cbp->cb_alloc *= 2; 6492474Seschrock } 6502474Seschrock 6512474Seschrock cbp->cb_datasets[cbp->cb_used++] = zhp; 652*3126Sahl 653*3126Sahl return (zfs_iter_children(zhp, mount_cb, cbp)); 6542474Seschrock } 6552474Seschrock 6562474Seschrock static int 657*3126Sahl dataset_cmp(const void *a, const void *b) 6582474Seschrock { 6592474Seschrock zfs_handle_t **za = (zfs_handle_t **)a; 6602474Seschrock zfs_handle_t **zb = (zfs_handle_t **)b; 6612474Seschrock char mounta[MAXPATHLEN]; 6622474Seschrock char mountb[MAXPATHLEN]; 663*3126Sahl boolean_t gota, gotb; 6642474Seschrock 665*3126Sahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 666*3126Sahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 667*3126Sahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 668*3126Sahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 669*3126Sahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 670*3126Sahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 6712474Seschrock 672*3126Sahl if (gota && gotb) 673*3126Sahl return (strcmp(mounta, mountb)); 674*3126Sahl 675*3126Sahl if (gota) 676*3126Sahl return (-1); 677*3126Sahl if (gotb) 678*3126Sahl return (1); 679*3126Sahl 680*3126Sahl return (strcmp(zfs_get_name(a), zfs_get_name(b))); 6812474Seschrock } 6822474Seschrock 683*3126Sahl /* 684*3126Sahl * Mount and share all datasets within the given pool. This assumes that no 685*3126Sahl * datasets within the pool are currently mounted. Because users can create 686*3126Sahl * complicated nested hierarchies of mountpoints, we first gather all the 687*3126Sahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once 688*3126Sahl * we have the list of all filesystems, we iterate over them in order and mount 689*3126Sahl * and/or share each one. 690*3126Sahl */ 691*3126Sahl #pragma weak zpool_mount_datasets = zpool_enable_datasets 6922474Seschrock int 693*3126Sahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) 6942474Seschrock { 6952474Seschrock mount_cbdata_t cb = { 0 }; 6962474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 6972474Seschrock zfs_handle_t *zfsp; 6982474Seschrock int i, ret = -1; 6992474Seschrock 7002474Seschrock /* 7012474Seschrock * Gather all datasets within the pool. 7022474Seschrock */ 7032474Seschrock if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) 7042474Seschrock return (-1); 7052474Seschrock cb.cb_alloc = 4; 7062474Seschrock 7072474Seschrock if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_ANY)) == NULL) 7082474Seschrock goto out; 7092474Seschrock 7102474Seschrock cb.cb_datasets[0] = zfsp; 7112474Seschrock cb.cb_used = 1; 7122474Seschrock 7132474Seschrock if (zfs_iter_children(zfsp, mount_cb, &cb) != 0) 7142474Seschrock goto out; 7152474Seschrock 7162474Seschrock /* 7172474Seschrock * Sort the datasets by mountpoint. 7182474Seschrock */ 719*3126Sahl qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); 7202474Seschrock 7212474Seschrock /* 7222474Seschrock * And mount all the datasets. 7232474Seschrock */ 7242474Seschrock ret = 0; 7252474Seschrock for (i = 0; i < cb.cb_used; i++) { 7262500Seschrock if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0 || 7272474Seschrock zfs_share(cb.cb_datasets[i]) != 0) 7282474Seschrock ret = -1; 7292474Seschrock } 7302474Seschrock 7312474Seschrock out: 7322474Seschrock for (i = 0; i < cb.cb_used; i++) 7332474Seschrock zfs_close(cb.cb_datasets[i]); 7342474Seschrock free(cb.cb_datasets); 7352474Seschrock 7362474Seschrock return (ret); 7372474Seschrock } 7382474Seschrock 739*3126Sahl 740*3126Sahl static int 741*3126Sahl zvol_cb(const char *dataset, void *data) 742*3126Sahl { 743*3126Sahl libzfs_handle_t *hdl = data; 744*3126Sahl zfs_handle_t *zhp; 745*3126Sahl 746*3126Sahl /* 747*3126Sahl * Ignore snapshots and ignore failures from non-existant datasets. 748*3126Sahl */ 749*3126Sahl if (strchr(dataset, '@') != NULL || 750*3126Sahl (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL) 751*3126Sahl return (0); 752*3126Sahl 753*3126Sahl (void) zfs_unshare_iscsi(zhp); 754*3126Sahl 755*3126Sahl zfs_close(zhp); 756*3126Sahl 757*3126Sahl return (0); 758*3126Sahl } 759*3126Sahl 7602474Seschrock static int 7612474Seschrock mountpoint_compare(const void *a, const void *b) 7622474Seschrock { 7632474Seschrock const char *mounta = *((char **)a); 7642474Seschrock const char *mountb = *((char **)b); 7652474Seschrock 7662474Seschrock return (strcmp(mountb, mounta)); 7672474Seschrock } 7682474Seschrock 769*3126Sahl /* 770*3126Sahl * Unshare and unmount all datasets within the given pool. We don't want to 771*3126Sahl * rely on traversing the DSL to discover the filesystems within the pool, 772*3126Sahl * because this may be expensive (if not all of them are mounted), and can fail 773*3126Sahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and 774*3126Sahl * gather all the filesystems that are currently mounted. 775*3126Sahl */ 776*3126Sahl #pragma weak zpool_unmount_datasets = zpool_disable_datasets 7772474Seschrock int 778*3126Sahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) 7792474Seschrock { 7802474Seschrock int used, alloc; 7812474Seschrock struct mnttab entry; 7822474Seschrock size_t namelen; 7832474Seschrock char **mountpoints = NULL; 7842474Seschrock zfs_handle_t **datasets = NULL; 7852474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 7862474Seschrock int i; 7872474Seschrock int ret = -1; 7882474Seschrock int flags = (force ? MS_FORCE : 0); 7892474Seschrock 790*3126Sahl /* 791*3126Sahl * First unshare all zvols. 792*3126Sahl */ 793*3126Sahl if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0) 794*3126Sahl return (-1); 795*3126Sahl 7962474Seschrock namelen = strlen(zhp->zpool_name); 7972474Seschrock 7982474Seschrock rewind(hdl->libzfs_mnttab); 7992474Seschrock used = alloc = 0; 8002474Seschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 8012474Seschrock /* 8022474Seschrock * Ignore non-ZFS entries. 8032474Seschrock */ 8042474Seschrock if (entry.mnt_fstype == NULL || 8052474Seschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 8062474Seschrock continue; 8072474Seschrock 8082474Seschrock /* 8092474Seschrock * Ignore filesystems not within this pool. 8102474Seschrock */ 8112474Seschrock if (entry.mnt_mountp == NULL || 8122474Seschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 || 8132474Seschrock (entry.mnt_special[namelen] != '/' && 8142474Seschrock entry.mnt_special[namelen] != '\0')) 8152474Seschrock continue; 8162474Seschrock 8172474Seschrock /* 8182474Seschrock * At this point we've found a filesystem within our pool. Add 8192474Seschrock * it to our growing list. 8202474Seschrock */ 8212474Seschrock if (used == alloc) { 8222474Seschrock if (alloc == 0) { 8232474Seschrock if ((mountpoints = zfs_alloc(hdl, 8242474Seschrock 8 * sizeof (void *))) == NULL) 8252474Seschrock goto out; 8262474Seschrock 8272474Seschrock if ((datasets = zfs_alloc(hdl, 8282474Seschrock 8 * sizeof (void *))) == NULL) 8292474Seschrock goto out; 8302474Seschrock 8312474Seschrock alloc = 8; 8322474Seschrock } else { 8332676Seschrock void *ptr; 8342474Seschrock 8352676Seschrock if ((ptr = zfs_realloc(hdl, mountpoints, 8362676Seschrock alloc * sizeof (void *), 8372474Seschrock alloc * 2 * sizeof (void *))) == NULL) 8382474Seschrock goto out; 8392676Seschrock mountpoints = ptr; 8402474Seschrock 8412676Seschrock if ((ptr = zfs_realloc(hdl, datasets, 8422676Seschrock alloc * sizeof (void *), 8432474Seschrock alloc * 2 * sizeof (void *))) == NULL) 8442474Seschrock goto out; 8452676Seschrock datasets = ptr; 8462474Seschrock 8472474Seschrock alloc *= 2; 8482474Seschrock } 8492474Seschrock } 8502474Seschrock 8512474Seschrock if ((mountpoints[used] = zfs_strdup(hdl, 8522474Seschrock entry.mnt_mountp)) == NULL) 8532474Seschrock goto out; 8542474Seschrock 8552474Seschrock /* 8562474Seschrock * This is allowed to fail, in case there is some I/O error. It 8572474Seschrock * is only used to determine if we need to remove the underlying 8582474Seschrock * mountpoint, so failure is not fatal. 8592474Seschrock */ 8602474Seschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special); 8612474Seschrock 8622474Seschrock used++; 8632474Seschrock } 8642474Seschrock 8652474Seschrock /* 8662474Seschrock * At this point, we have the entire list of filesystems, so sort it by 8672474Seschrock * mountpoint. 8682474Seschrock */ 8692474Seschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare); 8702474Seschrock 8712474Seschrock /* 8722474Seschrock * Walk through and first unshare everything. 8732474Seschrock */ 8742474Seschrock for (i = 0; i < used; i++) { 8752474Seschrock if (is_shared(hdl, mountpoints[i]) && 8762676Seschrock unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0) 8772474Seschrock goto out; 8782474Seschrock } 8792474Seschrock 8802474Seschrock /* 8812474Seschrock * Now unmount everything, removing the underlying directories as 8822474Seschrock * appropriate. 8832474Seschrock */ 8842474Seschrock for (i = 0; i < used; i++) { 8852474Seschrock if (unmount_one(hdl, mountpoints[i], flags) != 0) 8862474Seschrock goto out; 8872676Seschrock } 8882474Seschrock 8892676Seschrock for (i = 0; i < used; i++) { 8902474Seschrock if (datasets[i]) 8912474Seschrock remove_mountpoint(datasets[i]); 8922474Seschrock } 8932474Seschrock 8942474Seschrock ret = 0; 8952474Seschrock out: 8962474Seschrock for (i = 0; i < used; i++) { 8972474Seschrock if (datasets[i]) 8982474Seschrock zfs_close(datasets[i]); 8992474Seschrock free(mountpoints[i]); 9002474Seschrock } 9012474Seschrock free(datasets); 9022474Seschrock free(mountpoints); 9032474Seschrock 9042474Seschrock return (ret); 9052474Seschrock } 906