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 /* 233380Sgw25295 * 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 165*3444Sek110237 is_mounted(libzfs_handle_t *zfs_hdl, const char *special, 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 */ 174*3444Sek110237 search.mnt_special = (char *)special; 1751407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 176789Sahrens 177*3444Sek110237 rewind(zfs_hdl->libzfs_mnttab); 178*3444Sek110237 if (getmntany(zfs_hdl->libzfs_mnttab, &entry, &search) != 0) 1792082Seschrock return (B_FALSE); 180789Sahrens 181789Sahrens if (where != NULL) 182*3444Sek110237 *where = zfs_strdup(zfs_hdl, entry.mnt_mountp); 183789Sahrens 1842082Seschrock return (B_TRUE); 185789Sahrens } 186789Sahrens 187*3444Sek110237 boolean_t 188*3444Sek110237 zfs_is_mounted(zfs_handle_t *zhp, char **where) 189*3444Sek110237 { 190*3444Sek110237 return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where)); 191*3444Sek110237 } 192*3444Sek110237 193789Sahrens /* 1942676Seschrock * Returns true if the given dataset is mountable, false otherwise. Returns the 1952676Seschrock * mountpoint in 'buf'. 1962676Seschrock */ 1972676Seschrock static boolean_t 1982676Seschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, 1992676Seschrock zfs_source_t *source) 2002676Seschrock { 2012676Seschrock char sourceloc[ZFS_MAXNAMELEN]; 2022676Seschrock zfs_source_t sourcetype; 2032676Seschrock 2042676Seschrock if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type)) 2052676Seschrock return (B_FALSE); 2062676Seschrock 2072676Seschrock verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen, 2082676Seschrock &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0); 2092676Seschrock 2102676Seschrock if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 || 2112676Seschrock strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0) 2122676Seschrock return (B_FALSE); 2132676Seschrock 2142676Seschrock if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT)) 2152676Seschrock return (B_FALSE); 2162676Seschrock 2172676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) && 2182676Seschrock getzoneid() == GLOBAL_ZONEID) 2192676Seschrock return (B_FALSE); 2202676Seschrock 2212676Seschrock if (source) 2222676Seschrock *source = sourcetype; 2232676Seschrock 2242676Seschrock return (B_TRUE); 2252676Seschrock } 2262676Seschrock 2272676Seschrock /* 228789Sahrens * Mount the given filesystem. 229789Sahrens */ 230789Sahrens int 231789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 232789Sahrens { 233789Sahrens struct stat buf; 234789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 235789Sahrens char mntopts[MNT_LINE_MAX]; 2362082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 237789Sahrens 238789Sahrens if (options == NULL) 239789Sahrens mntopts[0] = '\0'; 240789Sahrens else 241789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 242789Sahrens 2432676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 2442082Seschrock return (0); 245789Sahrens 246789Sahrens /* Create the directory if it doesn't already exist */ 247789Sahrens if (lstat(mountpoint, &buf) != 0) { 248789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 2492082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2502082Seschrock "failed to create mountpoint")); 2513237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 2522082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 2532082Seschrock mountpoint)); 254789Sahrens } 255789Sahrens } 256789Sahrens 257789Sahrens /* 258789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 259789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 260789Sahrens * would defeat the point. We also avoid this check if 'remount' is 261789Sahrens * specified. 262789Sahrens */ 263789Sahrens if ((flags & MS_OVERLAY) == 0 && 264789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 265789Sahrens !dir_is_empty(mountpoint)) { 2662082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2672082Seschrock "directory is not empty")); 2683237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 2692082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint)); 270789Sahrens } 271789Sahrens 272789Sahrens /* perform the mount */ 273789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 274789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 275789Sahrens /* 276789Sahrens * Generic errors are nasty, but there are just way too many 277789Sahrens * from mount(), and they're well-understood. We pick a few 278789Sahrens * common ones to improve upon. 279789Sahrens */ 2802082Seschrock if (errno == EBUSY) 2812082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 2822082Seschrock "mountpoint or dataset is busy")); 2832082Seschrock else 2842082Seschrock zfs_error_aux(hdl, strerror(errno)); 2852082Seschrock 2863237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 2872082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 2882082Seschrock zhp->zfs_name)); 289789Sahrens } 290789Sahrens 291789Sahrens return (0); 292789Sahrens } 293789Sahrens 294789Sahrens /* 2952474Seschrock * Unmount a single filesystem. 2962474Seschrock */ 2972474Seschrock static int 2982474Seschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) 2992474Seschrock { 3002474Seschrock if (umount2(mountpoint, flags) != 0) { 3012474Seschrock zfs_error_aux(hdl, strerror(errno)); 3023237Slling return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED, 3032474Seschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), 3042474Seschrock mountpoint)); 3052474Seschrock } 3062474Seschrock 3072474Seschrock return (0); 3082474Seschrock } 3092474Seschrock 3102474Seschrock /* 311789Sahrens * Unmount the given filesystem. 312789Sahrens */ 313789Sahrens int 314789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 315789Sahrens { 316789Sahrens struct mnttab search = { 0 }, entry; 317789Sahrens 318789Sahrens /* check to see if need to unmount the filesystem */ 3192474Seschrock search.mnt_special = zhp->zfs_name; 3201407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 3212082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 322789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 3232082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 324789Sahrens 325789Sahrens if (mountpoint == NULL) 326789Sahrens mountpoint = entry.mnt_mountp; 327789Sahrens 328789Sahrens /* 3292474Seschrock * Unshare and unmount the filesystem 330789Sahrens */ 3313126Sahl if (zfs_unshare_nfs(zhp, mountpoint) != 0 || 3322474Seschrock unmount_one(zhp->zfs_hdl, mountpoint, flags) != 0) 333789Sahrens return (-1); 334789Sahrens } 335789Sahrens 336789Sahrens return (0); 337789Sahrens } 338789Sahrens 339789Sahrens /* 340789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 341789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 342789Sahrens * remount the filesystems afterwards. 343789Sahrens */ 344789Sahrens int 345789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 346789Sahrens { 347789Sahrens prop_changelist_t *clp; 348789Sahrens int ret; 349789Sahrens 350789Sahrens clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags); 351789Sahrens if (clp == NULL) 352789Sahrens return (-1); 353789Sahrens 354789Sahrens ret = changelist_prefix(clp); 355789Sahrens changelist_free(clp); 356789Sahrens 357789Sahrens return (ret); 358789Sahrens } 359789Sahrens 3603126Sahl boolean_t 3613126Sahl zfs_is_shared(zfs_handle_t *zhp) 3623126Sahl { 3633126Sahl if (ZFS_IS_VOLUME(zhp)) 3643126Sahl return (zfs_is_shared_iscsi(zhp)); 3653126Sahl 3663126Sahl return (zfs_is_shared_nfs(zhp, NULL)); 3673126Sahl } 3683126Sahl 3693126Sahl int 3703126Sahl zfs_share(zfs_handle_t *zhp) 3713126Sahl { 3723126Sahl if (ZFS_IS_VOLUME(zhp)) 3733126Sahl return (zfs_share_iscsi(zhp)); 3743126Sahl 3753126Sahl return (zfs_share_nfs(zhp)); 3763126Sahl } 3773126Sahl 3783126Sahl int 3793126Sahl zfs_unshare(zfs_handle_t *zhp) 3803126Sahl { 3813126Sahl if (ZFS_IS_VOLUME(zhp)) 3823126Sahl return (zfs_unshare_iscsi(zhp)); 3833126Sahl 3843126Sahl return (zfs_unshare_nfs(zhp, NULL)); 3853126Sahl } 3863126Sahl 387789Sahrens /* 388789Sahrens * Check to see if the filesystem is currently shared. 389789Sahrens */ 3902082Seschrock boolean_t 3913126Sahl zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) 392789Sahrens { 393789Sahrens char *mountpoint; 394789Sahrens 395789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 3962082Seschrock return (B_FALSE); 397789Sahrens 3982082Seschrock if (is_shared(zhp->zfs_hdl, mountpoint)) { 399789Sahrens if (where != NULL) 400789Sahrens *where = mountpoint; 401789Sahrens else 402789Sahrens free(mountpoint); 4032082Seschrock return (B_TRUE); 404789Sahrens } else { 405789Sahrens free(mountpoint); 4062082Seschrock return (B_FALSE); 407789Sahrens } 408789Sahrens } 409789Sahrens 410789Sahrens /* 411789Sahrens * Share the given filesystem according to the options in 'sharenfs'. We rely 412789Sahrens * on share(1M) to the dirty work for us. 413789Sahrens */ 414789Sahrens int 4153126Sahl zfs_share_nfs(zfs_handle_t *zhp) 416789Sahrens { 417789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 418789Sahrens char shareopts[ZFS_MAXPROPLEN]; 419789Sahrens char buf[MAXPATHLEN]; 420789Sahrens FILE *fp; 4212082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 422789Sahrens 4232676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 424789Sahrens return (0); 425789Sahrens 4263126Sahl /* 4273126Sahl * Return success if there are no share options. 4283126Sahl */ 429789Sahrens if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts), 4302082Seschrock NULL, NULL, 0, B_FALSE) != 0 || 431789Sahrens strcmp(shareopts, "off") == 0) 432789Sahrens return (0); 433789Sahrens 434789Sahrens /* 4352676Seschrock * If the 'zoned' property is set, then zfs_is_mountable() will have 4362676Seschrock * already bailed out if we are in the global zone. But local 4372676Seschrock * zones cannot be NFS servers, so we ignore it for local zones as well. 438789Sahrens */ 4392676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) 440789Sahrens return (0); 441789Sahrens 442789Sahrens /* 443789Sahrens * Invoke the share(1M) command. We always do this, even if it's 444789Sahrens * currently shared, as the options may have changed. 445789Sahrens */ 446789Sahrens if (strcmp(shareopts, "on") == 0) 447789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 448789Sahrens "-F nfs \"%s\" 2>&1", mountpoint); 449789Sahrens else 450789Sahrens (void) snprintf(buf, sizeof (buf), "/usr/sbin/share " 451789Sahrens "-F nfs -o \"%s\" \"%s\" 2>&1", shareopts, 452789Sahrens mountpoint); 453789Sahrens 4542082Seschrock if ((fp = popen(buf, "r")) == NULL) 4553237Slling return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 4562082Seschrock dgettext(TEXT_DOMAIN, "cannot share '%s'"), 4572082Seschrock zfs_get_name(zhp))); 458789Sahrens 459789Sahrens /* 460789Sahrens * share(1M) should only produce output if there is some kind 461789Sahrens * of error. All output begins with "share_nfs: ", so we trim 462789Sahrens * this off to get to the real error. 463789Sahrens */ 464789Sahrens if (fgets(buf, sizeof (buf), fp) != NULL) { 465789Sahrens char *colon = strchr(buf, ':'); 466789Sahrens 467789Sahrens while (buf[strlen(buf) - 1] == '\n') 468789Sahrens buf[strlen(buf) - 1] = '\0'; 469789Sahrens 4702082Seschrock if (colon != NULL) 4712082Seschrock zfs_error_aux(hdl, colon + 2); 4722082Seschrock 4733237Slling (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 4742474Seschrock dgettext(TEXT_DOMAIN, "cannot share '%s'"), 4752474Seschrock zfs_get_name(zhp)); 476789Sahrens 477789Sahrens verify(pclose(fp) != 0); 478789Sahrens return (-1); 479789Sahrens } 480789Sahrens 481789Sahrens verify(pclose(fp) == 0); 482789Sahrens 483789Sahrens return (0); 484789Sahrens } 485789Sahrens 486789Sahrens /* 4872474Seschrock * Unshare a filesystem by mountpoint. 4882474Seschrock */ 4892474Seschrock static int 4902474Seschrock unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint) 4912474Seschrock { 4922474Seschrock char buf[MAXPATHLEN]; 4932474Seschrock FILE *fp; 4942474Seschrock 4952474Seschrock (void) snprintf(buf, sizeof (buf), 4962474Seschrock "/usr/sbin/unshare \"%s\" 2>&1", 4972474Seschrock mountpoint); 4982474Seschrock 4992474Seschrock if ((fp = popen(buf, "r")) == NULL) 5003237Slling return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 5012474Seschrock dgettext(TEXT_DOMAIN, 5022474Seschrock "cannot unshare '%s'"), name)); 5032474Seschrock 5042474Seschrock /* 5052474Seschrock * unshare(1M) should only produce output if there is 5062474Seschrock * some kind of error. All output begins with "unshare 5072474Seschrock * nfs: ", so we trim this off to get to the real error. 5082474Seschrock */ 5092474Seschrock if (fgets(buf, sizeof (buf), fp) != NULL) { 5102474Seschrock char *colon = strchr(buf, ':'); 5112474Seschrock 5122474Seschrock while (buf[strlen(buf) - 1] == '\n') 5132474Seschrock buf[strlen(buf) - 1] = '\0'; 5142474Seschrock 5152474Seschrock if (colon != NULL) 5162474Seschrock zfs_error_aux(hdl, colon + 2); 5172474Seschrock 5182474Seschrock verify(pclose(fp) != 0); 5192474Seschrock 5203237Slling return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 5212474Seschrock dgettext(TEXT_DOMAIN, 5222474Seschrock "cannot unshare '%s'"), name)); 5232474Seschrock } 5242474Seschrock 5252474Seschrock verify(pclose(fp) == 0); 5262474Seschrock 5272474Seschrock return (0); 5282474Seschrock } 5292474Seschrock 5302474Seschrock /* 531789Sahrens * Unshare the given filesystem. 532789Sahrens */ 533789Sahrens int 5343126Sahl zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) 535789Sahrens { 536789Sahrens struct mnttab search = { 0 }, entry; 537789Sahrens 538789Sahrens /* check to see if need to unmount the filesystem */ 539789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 5401407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 5412082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 542789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 5432082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 544789Sahrens 545789Sahrens if (mountpoint == NULL) 546789Sahrens mountpoint = entry.mnt_mountp; 547789Sahrens 5482474Seschrock if (is_shared(zhp->zfs_hdl, mountpoint) && 5492474Seschrock unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0) 5502474Seschrock return (-1); 551789Sahrens } 552789Sahrens 553789Sahrens return (0); 554789Sahrens } 555789Sahrens 556789Sahrens /* 5573126Sahl * Same as zfs_unmountall(), but for NFS unshares. 558789Sahrens */ 559789Sahrens int 5603126Sahl zfs_unshareall_nfs(zfs_handle_t *zhp) 561789Sahrens { 562789Sahrens prop_changelist_t *clp; 563789Sahrens int ret; 564789Sahrens 565789Sahrens clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0); 566789Sahrens if (clp == NULL) 567789Sahrens return (-1); 568789Sahrens 569789Sahrens ret = changelist_unshare(clp); 570789Sahrens changelist_free(clp); 571789Sahrens 572789Sahrens return (ret); 573789Sahrens } 574789Sahrens 575789Sahrens /* 576789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 577789Sahrens * We only remove the underlying directory if: 578789Sahrens * 579789Sahrens * - The mountpoint is not 'none' or 'legacy' 580789Sahrens * - The mountpoint is non-empty 581789Sahrens * - The mountpoint is the default or inherited 582789Sahrens * - The 'zoned' property is set, or we're in a local zone 583789Sahrens * 584789Sahrens * Any other directories we leave alone. 585789Sahrens */ 586789Sahrens void 587789Sahrens remove_mountpoint(zfs_handle_t *zhp) 588789Sahrens { 589789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 5902676Seschrock zfs_source_t source; 591789Sahrens 5922676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), 5932676Seschrock &source)) 594789Sahrens return; 595789Sahrens 5962676Seschrock if (source == ZFS_SRC_DEFAULT || 5972676Seschrock source == ZFS_SRC_INHERITED) { 598789Sahrens /* 599789Sahrens * Try to remove the directory, silently ignoring any errors. 600789Sahrens * The filesystem may have since been removed or moved around, 6012676Seschrock * and this error isn't really useful to the administrator in 6022676Seschrock * any way. 603789Sahrens */ 604789Sahrens (void) rmdir(mountpoint); 605789Sahrens } 606789Sahrens } 6072474Seschrock 6083126Sahl boolean_t 6093126Sahl zfs_is_shared_iscsi(zfs_handle_t *zhp) 6103126Sahl { 6113134Sahl return (iscsitgt_zfs_is_shared != NULL && 6123134Sahl iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); 6133126Sahl } 6143126Sahl 6153126Sahl int 6163126Sahl zfs_share_iscsi(zfs_handle_t *zhp) 6173126Sahl { 6183126Sahl char shareopts[ZFS_MAXPROPLEN]; 6193126Sahl const char *dataset = zhp->zfs_name; 6203126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 6213126Sahl 6223126Sahl /* 6233126Sahl * Return success if there are no share options. 6243126Sahl */ 6253126Sahl if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 6263126Sahl sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || 6273126Sahl strcmp(shareopts, "off") == 0) 6283126Sahl return (0); 6293126Sahl 6303134Sahl if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) 6313237Slling return (zfs_error_fmt(hdl, EZFS_SHAREISCSIFAILED, 6323126Sahl dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); 6333126Sahl 6343126Sahl return (0); 6353126Sahl } 6363126Sahl 6373126Sahl int 6383126Sahl zfs_unshare_iscsi(zfs_handle_t *zhp) 6393126Sahl { 6403126Sahl const char *dataset = zfs_get_name(zhp); 6413126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 6423126Sahl 6433126Sahl /* 6443380Sgw25295 * Return if the volume is not shared 6453380Sgw25295 */ 6463380Sgw25295 if (!zfs_is_shared_iscsi(zhp)) 6473380Sgw25295 return (0); 6483380Sgw25295 6493380Sgw25295 /* 6503126Sahl * If this fails with ENODEV it indicates that zvol wasn't shared so 6513126Sahl * we should return success in that case. 6523126Sahl */ 6533134Sahl if (iscsitgt_zfs_unshare == NULL || 6543134Sahl (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) 6553237Slling return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, 6563126Sahl dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); 6573126Sahl 6583126Sahl return (0); 6593126Sahl } 6603126Sahl 6612474Seschrock typedef struct mount_cbdata { 6622474Seschrock zfs_handle_t **cb_datasets; 6632474Seschrock int cb_used; 6642474Seschrock int cb_alloc; 6652474Seschrock } mount_cbdata_t; 6662474Seschrock 6672474Seschrock static int 6682474Seschrock mount_cb(zfs_handle_t *zhp, void *data) 6692474Seschrock { 6702474Seschrock mount_cbdata_t *cbp = data; 6712474Seschrock 6723126Sahl if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { 6732474Seschrock zfs_close(zhp); 6742474Seschrock return (0); 6752474Seschrock } 6762474Seschrock 6772474Seschrock if (cbp->cb_alloc == cbp->cb_used) { 6782676Seschrock void *ptr; 6792474Seschrock 6802676Seschrock if ((ptr = zfs_realloc(zhp->zfs_hdl, 6812676Seschrock cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), 6822676Seschrock cbp->cb_alloc * 2 * sizeof (void *))) == NULL) 6832474Seschrock return (-1); 6842676Seschrock cbp->cb_datasets = ptr; 6852474Seschrock 6862676Seschrock cbp->cb_alloc *= 2; 6872474Seschrock } 6882474Seschrock 6892474Seschrock cbp->cb_datasets[cbp->cb_used++] = zhp; 6903126Sahl 6913126Sahl return (zfs_iter_children(zhp, mount_cb, cbp)); 6922474Seschrock } 6932474Seschrock 6942474Seschrock static int 6953126Sahl dataset_cmp(const void *a, const void *b) 6962474Seschrock { 6972474Seschrock zfs_handle_t **za = (zfs_handle_t **)a; 6982474Seschrock zfs_handle_t **zb = (zfs_handle_t **)b; 6992474Seschrock char mounta[MAXPATHLEN]; 7002474Seschrock char mountb[MAXPATHLEN]; 7013126Sahl boolean_t gota, gotb; 7022474Seschrock 7033126Sahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 7043126Sahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 7053126Sahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 7063126Sahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 7073126Sahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 7083126Sahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 7092474Seschrock 7103126Sahl if (gota && gotb) 7113126Sahl return (strcmp(mounta, mountb)); 7123126Sahl 7133126Sahl if (gota) 7143126Sahl return (-1); 7153126Sahl if (gotb) 7163126Sahl return (1); 7173126Sahl 7183126Sahl return (strcmp(zfs_get_name(a), zfs_get_name(b))); 7192474Seschrock } 7202474Seschrock 7213126Sahl /* 7223126Sahl * Mount and share all datasets within the given pool. This assumes that no 7233126Sahl * datasets within the pool are currently mounted. Because users can create 7243126Sahl * complicated nested hierarchies of mountpoints, we first gather all the 7253126Sahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once 7263126Sahl * we have the list of all filesystems, we iterate over them in order and mount 7273126Sahl * and/or share each one. 7283126Sahl */ 7293126Sahl #pragma weak zpool_mount_datasets = zpool_enable_datasets 7302474Seschrock int 7313126Sahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) 7322474Seschrock { 7332474Seschrock mount_cbdata_t cb = { 0 }; 7342474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 7352474Seschrock zfs_handle_t *zfsp; 7362474Seschrock int i, ret = -1; 7372474Seschrock 7382474Seschrock /* 7392474Seschrock * Gather all datasets within the pool. 7402474Seschrock */ 7412474Seschrock if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) 7422474Seschrock return (-1); 7432474Seschrock cb.cb_alloc = 4; 7442474Seschrock 7452474Seschrock if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_ANY)) == NULL) 7462474Seschrock goto out; 7472474Seschrock 7482474Seschrock cb.cb_datasets[0] = zfsp; 7492474Seschrock cb.cb_used = 1; 7502474Seschrock 7512474Seschrock if (zfs_iter_children(zfsp, mount_cb, &cb) != 0) 7522474Seschrock goto out; 7532474Seschrock 7542474Seschrock /* 7552474Seschrock * Sort the datasets by mountpoint. 7562474Seschrock */ 7573126Sahl qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); 7582474Seschrock 7592474Seschrock /* 7602474Seschrock * And mount all the datasets. 7612474Seschrock */ 7622474Seschrock ret = 0; 7632474Seschrock for (i = 0; i < cb.cb_used; i++) { 7642500Seschrock if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0 || 7652474Seschrock zfs_share(cb.cb_datasets[i]) != 0) 7662474Seschrock ret = -1; 7672474Seschrock } 7682474Seschrock 7692474Seschrock out: 7702474Seschrock for (i = 0; i < cb.cb_used; i++) 7712474Seschrock zfs_close(cb.cb_datasets[i]); 7722474Seschrock free(cb.cb_datasets); 7732474Seschrock 7742474Seschrock return (ret); 7752474Seschrock } 7762474Seschrock 7773126Sahl 7783126Sahl static int 7793126Sahl zvol_cb(const char *dataset, void *data) 7803126Sahl { 7813126Sahl libzfs_handle_t *hdl = data; 7823126Sahl zfs_handle_t *zhp; 7833126Sahl 7843126Sahl /* 7853126Sahl * Ignore snapshots and ignore failures from non-existant datasets. 7863126Sahl */ 7873126Sahl if (strchr(dataset, '@') != NULL || 7883126Sahl (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL) 7893126Sahl return (0); 7903126Sahl 7913126Sahl (void) zfs_unshare_iscsi(zhp); 7923126Sahl 7933126Sahl zfs_close(zhp); 7943126Sahl 7953126Sahl return (0); 7963126Sahl } 7973126Sahl 7982474Seschrock static int 7992474Seschrock mountpoint_compare(const void *a, const void *b) 8002474Seschrock { 8012474Seschrock const char *mounta = *((char **)a); 8022474Seschrock const char *mountb = *((char **)b); 8032474Seschrock 8042474Seschrock return (strcmp(mountb, mounta)); 8052474Seschrock } 8062474Seschrock 8073126Sahl /* 8083126Sahl * Unshare and unmount all datasets within the given pool. We don't want to 8093126Sahl * rely on traversing the DSL to discover the filesystems within the pool, 8103126Sahl * because this may be expensive (if not all of them are mounted), and can fail 8113126Sahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and 8123126Sahl * gather all the filesystems that are currently mounted. 8133126Sahl */ 8143126Sahl #pragma weak zpool_unmount_datasets = zpool_disable_datasets 8152474Seschrock int 8163126Sahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) 8172474Seschrock { 8182474Seschrock int used, alloc; 8192474Seschrock struct mnttab entry; 8202474Seschrock size_t namelen; 8212474Seschrock char **mountpoints = NULL; 8222474Seschrock zfs_handle_t **datasets = NULL; 8232474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 8242474Seschrock int i; 8252474Seschrock int ret = -1; 8262474Seschrock int flags = (force ? MS_FORCE : 0); 8272474Seschrock 8283126Sahl /* 8293126Sahl * First unshare all zvols. 8303126Sahl */ 8313126Sahl if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0) 8323126Sahl return (-1); 8333126Sahl 8342474Seschrock namelen = strlen(zhp->zpool_name); 8352474Seschrock 8362474Seschrock rewind(hdl->libzfs_mnttab); 8372474Seschrock used = alloc = 0; 8382474Seschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 8392474Seschrock /* 8402474Seschrock * Ignore non-ZFS entries. 8412474Seschrock */ 8422474Seschrock if (entry.mnt_fstype == NULL || 8432474Seschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 8442474Seschrock continue; 8452474Seschrock 8462474Seschrock /* 8472474Seschrock * Ignore filesystems not within this pool. 8482474Seschrock */ 8492474Seschrock if (entry.mnt_mountp == NULL || 8502474Seschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 || 8512474Seschrock (entry.mnt_special[namelen] != '/' && 8522474Seschrock entry.mnt_special[namelen] != '\0')) 8532474Seschrock continue; 8542474Seschrock 8552474Seschrock /* 8562474Seschrock * At this point we've found a filesystem within our pool. Add 8572474Seschrock * it to our growing list. 8582474Seschrock */ 8592474Seschrock if (used == alloc) { 8602474Seschrock if (alloc == 0) { 8612474Seschrock if ((mountpoints = zfs_alloc(hdl, 8622474Seschrock 8 * sizeof (void *))) == NULL) 8632474Seschrock goto out; 8642474Seschrock 8652474Seschrock if ((datasets = zfs_alloc(hdl, 8662474Seschrock 8 * sizeof (void *))) == NULL) 8672474Seschrock goto out; 8682474Seschrock 8692474Seschrock alloc = 8; 8702474Seschrock } else { 8712676Seschrock void *ptr; 8722474Seschrock 8732676Seschrock if ((ptr = zfs_realloc(hdl, mountpoints, 8742676Seschrock alloc * sizeof (void *), 8752474Seschrock alloc * 2 * sizeof (void *))) == NULL) 8762474Seschrock goto out; 8772676Seschrock mountpoints = ptr; 8782474Seschrock 8792676Seschrock if ((ptr = zfs_realloc(hdl, datasets, 8802676Seschrock alloc * sizeof (void *), 8812474Seschrock alloc * 2 * sizeof (void *))) == NULL) 8822474Seschrock goto out; 8832676Seschrock datasets = ptr; 8842474Seschrock 8852474Seschrock alloc *= 2; 8862474Seschrock } 8872474Seschrock } 8882474Seschrock 8892474Seschrock if ((mountpoints[used] = zfs_strdup(hdl, 8902474Seschrock entry.mnt_mountp)) == NULL) 8912474Seschrock goto out; 8922474Seschrock 8932474Seschrock /* 8942474Seschrock * This is allowed to fail, in case there is some I/O error. It 8952474Seschrock * is only used to determine if we need to remove the underlying 8962474Seschrock * mountpoint, so failure is not fatal. 8972474Seschrock */ 8982474Seschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special); 8992474Seschrock 9002474Seschrock used++; 9012474Seschrock } 9022474Seschrock 9032474Seschrock /* 9042474Seschrock * At this point, we have the entire list of filesystems, so sort it by 9052474Seschrock * mountpoint. 9062474Seschrock */ 9072474Seschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare); 9082474Seschrock 9092474Seschrock /* 9102474Seschrock * Walk through and first unshare everything. 9112474Seschrock */ 9122474Seschrock for (i = 0; i < used; i++) { 9132474Seschrock if (is_shared(hdl, mountpoints[i]) && 9142676Seschrock unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0) 9152474Seschrock goto out; 9162474Seschrock } 9172474Seschrock 9182474Seschrock /* 9192474Seschrock * Now unmount everything, removing the underlying directories as 9202474Seschrock * appropriate. 9212474Seschrock */ 9222474Seschrock for (i = 0; i < used; i++) { 9232474Seschrock if (unmount_one(hdl, mountpoints[i], flags) != 0) 9242474Seschrock goto out; 9252676Seschrock } 9262474Seschrock 9272676Seschrock for (i = 0; i < used; i++) { 9282474Seschrock if (datasets[i]) 9292474Seschrock remove_mountpoint(datasets[i]); 9302474Seschrock } 9312474Seschrock 9322474Seschrock ret = 0; 9332474Seschrock out: 9342474Seschrock for (i = 0; i < used; i++) { 9352474Seschrock if (datasets[i]) 9362474Seschrock zfs_close(datasets[i]); 9372474Seschrock free(mountpoints[i]); 9382474Seschrock } 9392474Seschrock free(datasets); 9402474Seschrock free(mountpoints); 9412474Seschrock 9422474Seschrock return (ret); 9432474Seschrock } 944