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 */ 213126Sahl 22789Sahrens /* 23*3380Sgw25295 * Copyright 2007 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 313126Sahl * to deal with the OS. The following functions are the main entry points -- 323126Sahl * they are used by mount and unmount and when changing a filesystem's 333126Sahl * mountpoint. 34789Sahrens * 35789Sahrens * zfs_is_mounted() 36789Sahrens * zfs_mount() 37789Sahrens * zfs_unmount() 38789Sahrens * zfs_unmountall() 39789Sahrens * 403126Sahl * This file also contains the functions used to manage sharing filesystems via 413126Sahl * NFS and iSCSI: 42789Sahrens * 43789Sahrens * zfs_is_shared() 44789Sahrens * zfs_share() 45789Sahrens * zfs_unshare() 463126Sahl * 473126Sahl * zfs_is_shared_nfs() 483126Sahl * zfs_share_nfs() 493126Sahl * zfs_unshare_nfs() 503126Sahl * zfs_unshareall_nfs() 513126Sahl * zfs_is_shared_iscsi() 523126Sahl * zfs_share_iscsi() 533126Sahl * zfs_unshare_iscsi() 542474Seschrock * 552474Seschrock * The following functions are available for pool consumers, and will 563126Sahl * mount/unmount and share/unshare all datasets within pool: 572474Seschrock * 583126Sahl * zpool_enable_datasets() 593126Sahl * zpool_disable_datasets() 60789Sahrens */ 61789Sahrens 62789Sahrens #include <dirent.h> 633134Sahl #include <dlfcn.h> 64789Sahrens #include <errno.h> 65789Sahrens #include <libgen.h> 66789Sahrens #include <libintl.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 813134Sahl static int (*iscsitgt_zfs_share)(const char *); 823134Sahl static int (*iscsitgt_zfs_unshare)(const char *); 833134Sahl static int (*iscsitgt_zfs_is_shared)(const char *); 843134Sahl 853134Sahl #pragma init(zfs_iscsi_init) 863134Sahl static void 873134Sahl zfs_iscsi_init(void) 883134Sahl { 893134Sahl void *libiscsitgt; 903134Sahl 913134Sahl if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1", 923134Sahl RTLD_LAZY | RTLD_GLOBAL)) == NULL || 933134Sahl (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt, 943134Sahl "iscsitgt_zfs_share")) == NULL || 953134Sahl (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt, 963134Sahl "iscsitgt_zfs_unshare")) == NULL || 973134Sahl (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt, 983134Sahl "iscsitgt_zfs_is_shared")) == NULL) { 993134Sahl iscsitgt_zfs_share = NULL; 1003134Sahl iscsitgt_zfs_unshare = NULL; 1013134Sahl iscsitgt_zfs_is_shared = NULL; 1023134Sahl } 1033134Sahl } 1043134Sahl 105789Sahrens /* 1062082Seschrock * Search the sharetab for the given mountpoint, returning true if it is found. 107789Sahrens */ 1082082Seschrock static boolean_t 1092082Seschrock is_shared(libzfs_handle_t *hdl, const char *mountpoint) 110789Sahrens { 111789Sahrens char buf[MAXPATHLEN], *tab; 112789Sahrens 1132082Seschrock if (hdl->libzfs_sharetab == NULL) 114789Sahrens return (0); 115789Sahrens 1162082Seschrock (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); 117789Sahrens 1182082Seschrock while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { 119789Sahrens 120789Sahrens /* the mountpoint is the first entry on each line */ 121789Sahrens if ((tab = strchr(buf, '\t')) != NULL) { 122789Sahrens *tab = '\0'; 123789Sahrens if (strcmp(buf, mountpoint) == 0) 1242082Seschrock return (B_TRUE); 125789Sahrens } 126789Sahrens } 127789Sahrens 1282082Seschrock return (B_FALSE); 129789Sahrens } 130789Sahrens 131789Sahrens /* 1322082Seschrock * Returns true if the specified directory is empty. If we can't open the 1332082Seschrock * directory at all, return true so that the mount can fail with a more 134789Sahrens * informative error message. 135789Sahrens */ 1362082Seschrock static boolean_t 137789Sahrens dir_is_empty(const char *dirname) 138789Sahrens { 139789Sahrens DIR *dirp; 140789Sahrens struct dirent64 *dp; 141789Sahrens 142789Sahrens if ((dirp = opendir(dirname)) == NULL) 1432082Seschrock return (B_TRUE); 144789Sahrens 145789Sahrens while ((dp = readdir64(dirp)) != NULL) { 146789Sahrens 147789Sahrens if (strcmp(dp->d_name, ".") == 0 || 148789Sahrens strcmp(dp->d_name, "..") == 0) 149789Sahrens continue; 150789Sahrens 151789Sahrens (void) closedir(dirp); 1522082Seschrock return (B_FALSE); 153789Sahrens } 154789Sahrens 155789Sahrens (void) closedir(dirp); 1562082Seschrock return (B_TRUE); 157789Sahrens } 158789Sahrens 159789Sahrens /* 160789Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill 161789Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return 162789Sahrens * 0. 163789Sahrens */ 1642082Seschrock boolean_t 165789Sahrens zfs_is_mounted(zfs_handle_t *zhp, char **where) 166789Sahrens { 167789Sahrens struct mnttab search = { 0 }, entry; 168789Sahrens 169789Sahrens /* 170789Sahrens * Search for the entry in /etc/mnttab. We don't bother getting the 171789Sahrens * mountpoint, as we can just search for the special device. This will 172789Sahrens * also let us find mounts when the mountpoint is 'legacy'. 173789Sahrens */ 174789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 1751407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 176789Sahrens 1772082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 1782082Seschrock if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) != 0) 1792082Seschrock return (B_FALSE); 180789Sahrens 181789Sahrens if (where != NULL) 1822082Seschrock *where = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 183789Sahrens 1842082Seschrock return (B_TRUE); 185789Sahrens } 186789Sahrens 187789Sahrens /* 1882676Seschrock * Returns true if the given dataset is mountable, false otherwise. Returns the 1892676Seschrock * mountpoint in 'buf'. 1902676Seschrock */ 1912676Seschrock static boolean_t 1922676Seschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, 1932676Seschrock zfs_source_t *source) 1942676Seschrock { 1952676Seschrock char sourceloc[ZFS_MAXNAMELEN]; 1962676Seschrock zfs_source_t sourcetype; 1972676Seschrock 1982676Seschrock if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type)) 1992676Seschrock return (B_FALSE); 2002676Seschrock 2012676Seschrock verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen, 2022676Seschrock &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0); 2032676Seschrock 2042676Seschrock if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 || 2052676Seschrock strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0) 2062676Seschrock return (B_FALSE); 2072676Seschrock 2082676Seschrock if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT)) 2092676Seschrock return (B_FALSE); 2102676Seschrock 2112676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) && 2122676Seschrock getzoneid() == GLOBAL_ZONEID) 2132676Seschrock return (B_FALSE); 2142676Seschrock 2152676Seschrock if (source) 2162676Seschrock *source = sourcetype; 2172676Seschrock 2182676Seschrock return (B_TRUE); 2192676Seschrock } 2202676Seschrock 2212676Seschrock /* 222789Sahrens * Mount the given filesystem. 223789Sahrens */ 224789Sahrens int 225789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 226789Sahrens { 227789Sahrens struct stat buf; 228789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 229789Sahrens char mntopts[MNT_LINE_MAX]; 2302082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 231789Sahrens 232789Sahrens if (options == NULL) 233789Sahrens mntopts[0] = '\0'; 234789Sahrens else 235789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 236789Sahrens 2372676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 2382082Seschrock return (0); 239789Sahrens 240789Sahrens /* Create the directory if it doesn't already exist */ 241789Sahrens if (lstat(mountpoint, &buf) != 0) { 242789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 2432082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2442082Seschrock "failed to create mountpoint")); 2453237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 2462082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 2472082Seschrock mountpoint)); 248789Sahrens } 249789Sahrens } 250789Sahrens 251789Sahrens /* 252789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 253789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 254789Sahrens * would defeat the point. We also avoid this check if 'remount' is 255789Sahrens * specified. 256789Sahrens */ 257789Sahrens if ((flags & MS_OVERLAY) == 0 && 258789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 259789Sahrens !dir_is_empty(mountpoint)) { 2602082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2612082Seschrock "directory is not empty")); 2623237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 2632082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint)); 264789Sahrens } 265789Sahrens 266789Sahrens /* perform the mount */ 267789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 268789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 269789Sahrens /* 270789Sahrens * Generic errors are nasty, but there are just way too many 271789Sahrens * from mount(), and they're well-understood. We pick a few 272789Sahrens * common ones to improve upon. 273789Sahrens */ 2742082Seschrock if (errno == EBUSY) 2752082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2762082Seschrock "mountpoint or dataset is busy")); 2772082Seschrock else 2782082Seschrock zfs_error_aux(hdl, strerror(errno)); 2792082Seschrock 2803237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 2812082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 2822082Seschrock zhp->zfs_name)); 283789Sahrens } 284789Sahrens 285789Sahrens return (0); 286789Sahrens } 287789Sahrens 288789Sahrens /* 2892474Seschrock * Unmount a single filesystem. 2902474Seschrock */ 2912474Seschrock static int 2922474Seschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) 2932474Seschrock { 2942474Seschrock if (umount2(mountpoint, flags) != 0) { 2952474Seschrock zfs_error_aux(hdl, strerror(errno)); 2963237Slling return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED, 2972474Seschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), 2982474Seschrock mountpoint)); 2992474Seschrock } 3002474Seschrock 3012474Seschrock return (0); 3022474Seschrock } 3032474Seschrock 3042474Seschrock /* 305789Sahrens * Unmount the given filesystem. 306789Sahrens */ 307789Sahrens int 308789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 309789Sahrens { 310789Sahrens struct mnttab search = { 0 }, entry; 311789Sahrens 312789Sahrens /* check to see if need to unmount the filesystem */ 3132474Seschrock search.mnt_special = zhp->zfs_name; 3141407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 3152082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 316789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 3172082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 318789Sahrens 319789Sahrens if (mountpoint == NULL) 320789Sahrens mountpoint = entry.mnt_mountp; 321789Sahrens 322789Sahrens /* 3232474Seschrock * Unshare and unmount the filesystem 324789Sahrens */ 3253126Sahl if (zfs_unshare_nfs(zhp, mountpoint) != 0 || 3262474Seschrock unmount_one(zhp->zfs_hdl, mountpoint, flags) != 0) 327789Sahrens return (-1); 328789Sahrens } 329789Sahrens 330789Sahrens return (0); 331789Sahrens } 332789Sahrens 333789Sahrens /* 334789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 335789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 336789Sahrens * remount the filesystems afterwards. 337789Sahrens */ 338789Sahrens int 339789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 340789Sahrens { 341789Sahrens prop_changelist_t *clp; 342789Sahrens int ret; 343789Sahrens 344789Sahrens clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags); 345789Sahrens if (clp == NULL) 346789Sahrens return (-1); 347789Sahrens 348789Sahrens ret = changelist_prefix(clp); 349789Sahrens changelist_free(clp); 350789Sahrens 351789Sahrens return (ret); 352789Sahrens } 353789Sahrens 3543126Sahl boolean_t 3553126Sahl zfs_is_shared(zfs_handle_t *zhp) 3563126Sahl { 3573126Sahl if (ZFS_IS_VOLUME(zhp)) 3583126Sahl return (zfs_is_shared_iscsi(zhp)); 3593126Sahl 3603126Sahl return (zfs_is_shared_nfs(zhp, NULL)); 3613126Sahl } 3623126Sahl 3633126Sahl int 3643126Sahl zfs_share(zfs_handle_t *zhp) 3653126Sahl { 3663126Sahl if (ZFS_IS_VOLUME(zhp)) 3673126Sahl return (zfs_share_iscsi(zhp)); 3683126Sahl 3693126Sahl return (zfs_share_nfs(zhp)); 3703126Sahl } 3713126Sahl 3723126Sahl int 3733126Sahl zfs_unshare(zfs_handle_t *zhp) 3743126Sahl { 3753126Sahl if (ZFS_IS_VOLUME(zhp)) 3763126Sahl return (zfs_unshare_iscsi(zhp)); 3773126Sahl 3783126Sahl return (zfs_unshare_nfs(zhp, NULL)); 3793126Sahl } 3803126Sahl 381789Sahrens /* 382789Sahrens * Check to see if the filesystem is currently shared. 383789Sahrens */ 3842082Seschrock boolean_t 3853126Sahl zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) 386789Sahrens { 387789Sahrens char *mountpoint; 388789Sahrens 389789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 3902082Seschrock return (B_FALSE); 391789Sahrens 3922082Seschrock if (is_shared(zhp->zfs_hdl, mountpoint)) { 393789Sahrens if (where != NULL) 394789Sahrens *where = mountpoint; 395789Sahrens else 396789Sahrens free(mountpoint); 3972082Seschrock return (B_TRUE); 398789Sahrens } else { 399789Sahrens free(mountpoint); 4002082Seschrock return (B_FALSE); 401789Sahrens } 402789Sahrens } 403789Sahrens 404789Sahrens /* 405789Sahrens * Share the given filesystem according to the options in 'sharenfs'. We rely 406789Sahrens * on share(1M) to the dirty work for us. 407789Sahrens */ 408789Sahrens int 4093126Sahl zfs_share_nfs(zfs_handle_t *zhp) 410789Sahrens { 411789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 412789Sahrens char shareopts[ZFS_MAXPROPLEN]; 413789Sahrens char buf[MAXPATHLEN]; 414789Sahrens FILE *fp; 4152082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 416789Sahrens 4172676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 418789Sahrens return (0); 419789Sahrens 4203126Sahl /* 4213126Sahl * Return success if there are no share options. 4223126Sahl */ 423789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts), 4242082Seschrock NULL, NULL, 0, B_FALSE) != 0 || 425789Sahrens strcmp(shareopts, "off") == 0) 426789Sahrens return (0); 427789Sahrens 428789Sahrens /* 4292676Seschrock * If the 'zoned' property is set, then zfs_is_mountable() will have 4302676Seschrock * already bailed out if we are in the global zone. But local 4312676Seschrock * zones cannot be NFS servers, so we ignore it for local zones as well. 432789Sahrens */ 4332676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) 434789Sahrens return (0); 435789Sahrens 436789Sahrens /* 437789Sahrens * Invoke the share(1M) command. We always do this, even if it's 438789Sahrens * currently shared, as the options may have changed. 439789Sahrens */ 440789Sahrens if (strcmp(shareopts, "on") == 0) 441789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 442789Sahrens "-F nfs \"%s\" 2>&1", mountpoint); 443789Sahrens else 444789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 445789Sahrens "-F nfs -o \"%s\" \"%s\" 2>&1", shareopts, 446789Sahrens mountpoint); 447789Sahrens 4482082Seschrock if ((fp = popen(buf, "r")) == NULL) 4493237Slling return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 4502082Seschrock dgettext(TEXT_DOMAIN, "cannot share '%s'"), 4512082Seschrock zfs_get_name(zhp))); 452789Sahrens 453789Sahrens /* 454789Sahrens * share(1M) should only produce output if there is some kind 455789Sahrens * of error. All output begins with "share_nfs: ", so we trim 456789Sahrens * this off to get to the real error. 457789Sahrens */ 458789Sahrens if (fgets(buf, sizeof (buf), fp) != NULL) { 459789Sahrens char *colon = strchr(buf, ':'); 460789Sahrens 461789Sahrens while (buf[strlen(buf) - 1] == '\n') 462789Sahrens buf[strlen(buf) - 1] = '\0'; 463789Sahrens 4642082Seschrock if (colon != NULL) 4652082Seschrock zfs_error_aux(hdl, colon + 2); 4662082Seschrock 4673237Slling (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 4682474Seschrock dgettext(TEXT_DOMAIN, "cannot share '%s'"), 4692474Seschrock zfs_get_name(zhp)); 470789Sahrens 471789Sahrens verify(pclose(fp) != 0); 472789Sahrens return (-1); 473789Sahrens } 474789Sahrens 475789Sahrens verify(pclose(fp) == 0); 476789Sahrens 477789Sahrens return (0); 478789Sahrens } 479789Sahrens 480789Sahrens /* 4812474Seschrock * Unshare a filesystem by mountpoint. 4822474Seschrock */ 4832474Seschrock static int 4842474Seschrock unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint) 4852474Seschrock { 4862474Seschrock char buf[MAXPATHLEN]; 4872474Seschrock FILE *fp; 4882474Seschrock 4892474Seschrock (void) snprintf(buf, sizeof (buf), 4902474Seschrock "/usr/sbin/unshare \"%s\" 2>&1", 4912474Seschrock mountpoint); 4922474Seschrock 4932474Seschrock if ((fp = popen(buf, "r")) == NULL) 4943237Slling return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 4952474Seschrock dgettext(TEXT_DOMAIN, 4962474Seschrock "cannot unshare '%s'"), name)); 4972474Seschrock 4982474Seschrock /* 4992474Seschrock * unshare(1M) should only produce output if there is 5002474Seschrock * some kind of error. All output begins with "unshare 5012474Seschrock * nfs: ", so we trim this off to get to the real error. 5022474Seschrock */ 5032474Seschrock if (fgets(buf, sizeof (buf), fp) != NULL) { 5042474Seschrock char *colon = strchr(buf, ':'); 5052474Seschrock 5062474Seschrock while (buf[strlen(buf) - 1] == '\n') 5072474Seschrock buf[strlen(buf) - 1] = '\0'; 5082474Seschrock 5092474Seschrock if (colon != NULL) 5102474Seschrock zfs_error_aux(hdl, colon + 2); 5112474Seschrock 5122474Seschrock verify(pclose(fp) != 0); 5132474Seschrock 5143237Slling return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 5152474Seschrock dgettext(TEXT_DOMAIN, 5162474Seschrock "cannot unshare '%s'"), name)); 5172474Seschrock } 5182474Seschrock 5192474Seschrock verify(pclose(fp) == 0); 5202474Seschrock 5212474Seschrock return (0); 5222474Seschrock } 5232474Seschrock 5242474Seschrock /* 525789Sahrens * Unshare the given filesystem. 526789Sahrens */ 527789Sahrens int 5283126Sahl zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) 529789Sahrens { 530789Sahrens struct mnttab search = { 0 }, entry; 531789Sahrens 532789Sahrens /* check to see if need to unmount the filesystem */ 533789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 5341407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 5352082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 536789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 5372082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 538789Sahrens 539789Sahrens if (mountpoint == NULL) 540789Sahrens mountpoint = entry.mnt_mountp; 541789Sahrens 5422474Seschrock if (is_shared(zhp->zfs_hdl, mountpoint) && 5432474Seschrock unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0) 5442474Seschrock return (-1); 545789Sahrens } 546789Sahrens 547789Sahrens return (0); 548789Sahrens } 549789Sahrens 550789Sahrens /* 5513126Sahl * Same as zfs_unmountall(), but for NFS unshares. 552789Sahrens */ 553789Sahrens int 5543126Sahl zfs_unshareall_nfs(zfs_handle_t *zhp) 555789Sahrens { 556789Sahrens prop_changelist_t *clp; 557789Sahrens int ret; 558789Sahrens 559789Sahrens clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0); 560789Sahrens if (clp == NULL) 561789Sahrens return (-1); 562789Sahrens 563789Sahrens ret = changelist_unshare(clp); 564789Sahrens changelist_free(clp); 565789Sahrens 566789Sahrens return (ret); 567789Sahrens } 568789Sahrens 569789Sahrens /* 570789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 571789Sahrens * We only remove the underlying directory if: 572789Sahrens * 573789Sahrens * - The mountpoint is not 'none' or 'legacy' 574789Sahrens * - The mountpoint is non-empty 575789Sahrens * - The mountpoint is the default or inherited 576789Sahrens * - The 'zoned' property is set, or we're in a local zone 577789Sahrens * 578789Sahrens * Any other directories we leave alone. 579789Sahrens */ 580789Sahrens void 581789Sahrens remove_mountpoint(zfs_handle_t *zhp) 582789Sahrens { 583789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 5842676Seschrock zfs_source_t source; 585789Sahrens 5862676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), 5872676Seschrock &source)) 588789Sahrens return; 589789Sahrens 5902676Seschrock if (source == ZFS_SRC_DEFAULT || 5912676Seschrock source == ZFS_SRC_INHERITED) { 592789Sahrens /* 593789Sahrens * Try to remove the directory, silently ignoring any errors. 594789Sahrens * The filesystem may have since been removed or moved around, 5952676Seschrock * and this error isn't really useful to the administrator in 5962676Seschrock * any way. 597789Sahrens */ 598789Sahrens (void) rmdir(mountpoint); 599789Sahrens } 600789Sahrens } 6012474Seschrock 6023126Sahl boolean_t 6033126Sahl zfs_is_shared_iscsi(zfs_handle_t *zhp) 6043126Sahl { 6053134Sahl return (iscsitgt_zfs_is_shared != NULL && 6063134Sahl iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); 6073126Sahl } 6083126Sahl 6093126Sahl int 6103126Sahl zfs_share_iscsi(zfs_handle_t *zhp) 6113126Sahl { 6123126Sahl char shareopts[ZFS_MAXPROPLEN]; 6133126Sahl const char *dataset = zhp->zfs_name; 6143126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 6153126Sahl 6163126Sahl /* 6173126Sahl * Return success if there are no share options. 6183126Sahl */ 6193126Sahl if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 6203126Sahl sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || 6213126Sahl strcmp(shareopts, "off") == 0) 6223126Sahl return (0); 6233126Sahl 6243134Sahl if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) 6253237Slling return (zfs_error_fmt(hdl, EZFS_SHAREISCSIFAILED, 6263126Sahl dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); 6273126Sahl 6283126Sahl return (0); 6293126Sahl } 6303126Sahl 6313126Sahl int 6323126Sahl zfs_unshare_iscsi(zfs_handle_t *zhp) 6333126Sahl { 6343126Sahl const char *dataset = zfs_get_name(zhp); 6353126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 6363126Sahl 6373126Sahl /* 638*3380Sgw25295 * Return if the volume is not shared 639*3380Sgw25295 */ 640*3380Sgw25295 if (!zfs_is_shared_iscsi(zhp)) 641*3380Sgw25295 return (0); 642*3380Sgw25295 643*3380Sgw25295 /* 6443126Sahl * If this fails with ENODEV it indicates that zvol wasn't shared so 6453126Sahl * we should return success in that case. 6463126Sahl */ 6473134Sahl if (iscsitgt_zfs_unshare == NULL || 6483134Sahl (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) 6493237Slling return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, 6503126Sahl dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); 6513126Sahl 6523126Sahl return (0); 6533126Sahl } 6543126Sahl 6552474Seschrock typedef struct mount_cbdata { 6562474Seschrock zfs_handle_t **cb_datasets; 6572474Seschrock int cb_used; 6582474Seschrock int cb_alloc; 6592474Seschrock } mount_cbdata_t; 6602474Seschrock 6612474Seschrock static int 6622474Seschrock mount_cb(zfs_handle_t *zhp, void *data) 6632474Seschrock { 6642474Seschrock mount_cbdata_t *cbp = data; 6652474Seschrock 6663126Sahl if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { 6672474Seschrock zfs_close(zhp); 6682474Seschrock return (0); 6692474Seschrock } 6702474Seschrock 6712474Seschrock if (cbp->cb_alloc == cbp->cb_used) { 6722676Seschrock void *ptr; 6732474Seschrock 6742676Seschrock if ((ptr = zfs_realloc(zhp->zfs_hdl, 6752676Seschrock cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), 6762676Seschrock cbp->cb_alloc * 2 * sizeof (void *))) == NULL) 6772474Seschrock return (-1); 6782676Seschrock cbp->cb_datasets = ptr; 6792474Seschrock 6802676Seschrock cbp->cb_alloc *= 2; 6812474Seschrock } 6822474Seschrock 6832474Seschrock cbp->cb_datasets[cbp->cb_used++] = zhp; 6843126Sahl 6853126Sahl return (zfs_iter_children(zhp, mount_cb, cbp)); 6862474Seschrock } 6872474Seschrock 6882474Seschrock static int 6893126Sahl dataset_cmp(const void *a, const void *b) 6902474Seschrock { 6912474Seschrock zfs_handle_t **za = (zfs_handle_t **)a; 6922474Seschrock zfs_handle_t **zb = (zfs_handle_t **)b; 6932474Seschrock char mounta[MAXPATHLEN]; 6942474Seschrock char mountb[MAXPATHLEN]; 6953126Sahl boolean_t gota, gotb; 6962474Seschrock 6973126Sahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 6983126Sahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 6993126Sahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 7003126Sahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 7013126Sahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 7023126Sahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 7032474Seschrock 7043126Sahl if (gota && gotb) 7053126Sahl return (strcmp(mounta, mountb)); 7063126Sahl 7073126Sahl if (gota) 7083126Sahl return (-1); 7093126Sahl if (gotb) 7103126Sahl return (1); 7113126Sahl 7123126Sahl return (strcmp(zfs_get_name(a), zfs_get_name(b))); 7132474Seschrock } 7142474Seschrock 7153126Sahl /* 7163126Sahl * Mount and share all datasets within the given pool. This assumes that no 7173126Sahl * datasets within the pool are currently mounted. Because users can create 7183126Sahl * complicated nested hierarchies of mountpoints, we first gather all the 7193126Sahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once 7203126Sahl * we have the list of all filesystems, we iterate over them in order and mount 7213126Sahl * and/or share each one. 7223126Sahl */ 7233126Sahl #pragma weak zpool_mount_datasets = zpool_enable_datasets 7242474Seschrock int 7253126Sahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) 7262474Seschrock { 7272474Seschrock mount_cbdata_t cb = { 0 }; 7282474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 7292474Seschrock zfs_handle_t *zfsp; 7302474Seschrock int i, ret = -1; 7312474Seschrock 7322474Seschrock /* 7332474Seschrock * Gather all datasets within the pool. 7342474Seschrock */ 7352474Seschrock if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) 7362474Seschrock return (-1); 7372474Seschrock cb.cb_alloc = 4; 7382474Seschrock 7392474Seschrock if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_ANY)) == NULL) 7402474Seschrock goto out; 7412474Seschrock 7422474Seschrock cb.cb_datasets[0] = zfsp; 7432474Seschrock cb.cb_used = 1; 7442474Seschrock 7452474Seschrock if (zfs_iter_children(zfsp, mount_cb, &cb) != 0) 7462474Seschrock goto out; 7472474Seschrock 7482474Seschrock /* 7492474Seschrock * Sort the datasets by mountpoint. 7502474Seschrock */ 7513126Sahl qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); 7522474Seschrock 7532474Seschrock /* 7542474Seschrock * And mount all the datasets. 7552474Seschrock */ 7562474Seschrock ret = 0; 7572474Seschrock for (i = 0; i < cb.cb_used; i++) { 7582500Seschrock if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0 || 7592474Seschrock zfs_share(cb.cb_datasets[i]) != 0) 7602474Seschrock ret = -1; 7612474Seschrock } 7622474Seschrock 7632474Seschrock out: 7642474Seschrock for (i = 0; i < cb.cb_used; i++) 7652474Seschrock zfs_close(cb.cb_datasets[i]); 7662474Seschrock free(cb.cb_datasets); 7672474Seschrock 7682474Seschrock return (ret); 7692474Seschrock } 7702474Seschrock 7713126Sahl 7723126Sahl static int 7733126Sahl zvol_cb(const char *dataset, void *data) 7743126Sahl { 7753126Sahl libzfs_handle_t *hdl = data; 7763126Sahl zfs_handle_t *zhp; 7773126Sahl 7783126Sahl /* 7793126Sahl * Ignore snapshots and ignore failures from non-existant datasets. 7803126Sahl */ 7813126Sahl if (strchr(dataset, '@') != NULL || 7823126Sahl (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL) 7833126Sahl return (0); 7843126Sahl 7853126Sahl (void) zfs_unshare_iscsi(zhp); 7863126Sahl 7873126Sahl zfs_close(zhp); 7883126Sahl 7893126Sahl return (0); 7903126Sahl } 7913126Sahl 7922474Seschrock static int 7932474Seschrock mountpoint_compare(const void *a, const void *b) 7942474Seschrock { 7952474Seschrock const char *mounta = *((char **)a); 7962474Seschrock const char *mountb = *((char **)b); 7972474Seschrock 7982474Seschrock return (strcmp(mountb, mounta)); 7992474Seschrock } 8002474Seschrock 8013126Sahl /* 8023126Sahl * Unshare and unmount all datasets within the given pool. We don't want to 8033126Sahl * rely on traversing the DSL to discover the filesystems within the pool, 8043126Sahl * because this may be expensive (if not all of them are mounted), and can fail 8053126Sahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and 8063126Sahl * gather all the filesystems that are currently mounted. 8073126Sahl */ 8083126Sahl #pragma weak zpool_unmount_datasets = zpool_disable_datasets 8092474Seschrock int 8103126Sahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) 8112474Seschrock { 8122474Seschrock int used, alloc; 8132474Seschrock struct mnttab entry; 8142474Seschrock size_t namelen; 8152474Seschrock char **mountpoints = NULL; 8162474Seschrock zfs_handle_t **datasets = NULL; 8172474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 8182474Seschrock int i; 8192474Seschrock int ret = -1; 8202474Seschrock int flags = (force ? MS_FORCE : 0); 8212474Seschrock 8223126Sahl /* 8233126Sahl * First unshare all zvols. 8243126Sahl */ 8253126Sahl if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0) 8263126Sahl return (-1); 8273126Sahl 8282474Seschrock namelen = strlen(zhp->zpool_name); 8292474Seschrock 8302474Seschrock rewind(hdl->libzfs_mnttab); 8312474Seschrock used = alloc = 0; 8322474Seschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 8332474Seschrock /* 8342474Seschrock * Ignore non-ZFS entries. 8352474Seschrock */ 8362474Seschrock if (entry.mnt_fstype == NULL || 8372474Seschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 8382474Seschrock continue; 8392474Seschrock 8402474Seschrock /* 8412474Seschrock * Ignore filesystems not within this pool. 8422474Seschrock */ 8432474Seschrock if (entry.mnt_mountp == NULL || 8442474Seschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 || 8452474Seschrock (entry.mnt_special[namelen] != '/' && 8462474Seschrock entry.mnt_special[namelen] != '\0')) 8472474Seschrock continue; 8482474Seschrock 8492474Seschrock /* 8502474Seschrock * At this point we've found a filesystem within our pool. Add 8512474Seschrock * it to our growing list. 8522474Seschrock */ 8532474Seschrock if (used == alloc) { 8542474Seschrock if (alloc == 0) { 8552474Seschrock if ((mountpoints = zfs_alloc(hdl, 8562474Seschrock 8 * sizeof (void *))) == NULL) 8572474Seschrock goto out; 8582474Seschrock 8592474Seschrock if ((datasets = zfs_alloc(hdl, 8602474Seschrock 8 * sizeof (void *))) == NULL) 8612474Seschrock goto out; 8622474Seschrock 8632474Seschrock alloc = 8; 8642474Seschrock } else { 8652676Seschrock void *ptr; 8662474Seschrock 8672676Seschrock if ((ptr = zfs_realloc(hdl, mountpoints, 8682676Seschrock alloc * sizeof (void *), 8692474Seschrock alloc * 2 * sizeof (void *))) == NULL) 8702474Seschrock goto out; 8712676Seschrock mountpoints = ptr; 8722474Seschrock 8732676Seschrock if ((ptr = zfs_realloc(hdl, datasets, 8742676Seschrock alloc * sizeof (void *), 8752474Seschrock alloc * 2 * sizeof (void *))) == NULL) 8762474Seschrock goto out; 8772676Seschrock datasets = ptr; 8782474Seschrock 8792474Seschrock alloc *= 2; 8802474Seschrock } 8812474Seschrock } 8822474Seschrock 8832474Seschrock if ((mountpoints[used] = zfs_strdup(hdl, 8842474Seschrock entry.mnt_mountp)) == NULL) 8852474Seschrock goto out; 8862474Seschrock 8872474Seschrock /* 8882474Seschrock * This is allowed to fail, in case there is some I/O error. It 8892474Seschrock * is only used to determine if we need to remove the underlying 8902474Seschrock * mountpoint, so failure is not fatal. 8912474Seschrock */ 8922474Seschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special); 8932474Seschrock 8942474Seschrock used++; 8952474Seschrock } 8962474Seschrock 8972474Seschrock /* 8982474Seschrock * At this point, we have the entire list of filesystems, so sort it by 8992474Seschrock * mountpoint. 9002474Seschrock */ 9012474Seschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare); 9022474Seschrock 9032474Seschrock /* 9042474Seschrock * Walk through and first unshare everything. 9052474Seschrock */ 9062474Seschrock for (i = 0; i < used; i++) { 9072474Seschrock if (is_shared(hdl, mountpoints[i]) && 9082676Seschrock unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0) 9092474Seschrock goto out; 9102474Seschrock } 9112474Seschrock 9122474Seschrock /* 9132474Seschrock * Now unmount everything, removing the underlying directories as 9142474Seschrock * appropriate. 9152474Seschrock */ 9162474Seschrock for (i = 0; i < used; i++) { 9172474Seschrock if (unmount_one(hdl, mountpoints[i], flags) != 0) 9182474Seschrock goto out; 9192676Seschrock } 9202474Seschrock 9212676Seschrock for (i = 0; i < used; i++) { 9222474Seschrock if (datasets[i]) 9232474Seschrock remove_mountpoint(datasets[i]); 9242474Seschrock } 9252474Seschrock 9262474Seschrock ret = 0; 9272474Seschrock out: 9282474Seschrock for (i = 0; i < used; i++) { 9292474Seschrock if (datasets[i]) 9302474Seschrock zfs_close(datasets[i]); 9312474Seschrock free(mountpoints[i]); 9322474Seschrock } 9332474Seschrock free(datasets); 9342474Seschrock free(mountpoints); 9352474Seschrock 9362474Seschrock return (ret); 9372474Seschrock } 938