1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21f3861e1aSahl 22fa9e4066Sahrens /* 235b6e0c46Sdougm * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24fa9e4066Sahrens * Use is subject to license terms. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens /* 28fa9e4066Sahrens * Routines to manage ZFS mounts. We separate all the nasty routines that have 29f3861e1aSahl * to deal with the OS. The following functions are the main entry points -- 30f3861e1aSahl * they are used by mount and unmount and when changing a filesystem's 31f3861e1aSahl * mountpoint. 32fa9e4066Sahrens * 33fa9e4066Sahrens * zfs_is_mounted() 34fa9e4066Sahrens * zfs_mount() 35fa9e4066Sahrens * zfs_unmount() 36fa9e4066Sahrens * zfs_unmountall() 37fa9e4066Sahrens * 38f3861e1aSahl * This file also contains the functions used to manage sharing filesystems via 39f3861e1aSahl * NFS and iSCSI: 40fa9e4066Sahrens * 41fa9e4066Sahrens * zfs_is_shared() 42fa9e4066Sahrens * zfs_share() 43fa9e4066Sahrens * zfs_unshare() 44f3861e1aSahl * 45f3861e1aSahl * zfs_is_shared_nfs() 46da6c28aaSamw * zfs_is_shared_smb() 47f3861e1aSahl * zfs_is_shared_iscsi() 48da6c28aaSamw * zfs_share_proto() 49da6c28aaSamw * zfs_shareall(); 50f3861e1aSahl * zfs_share_iscsi() 51da6c28aaSamw * zfs_unshare_nfs() 52da6c28aaSamw * zfs_unshare_smb() 53da6c28aaSamw * zfs_unshareall_nfs() 54da6c28aaSamw * zfs_unshareall_smb() 55da6c28aaSamw * zfs_unshareall() 56da6c28aaSamw * zfs_unshareall_bypath() 57f3861e1aSahl * zfs_unshare_iscsi() 583bb79becSeschrock * 593bb79becSeschrock * The following functions are available for pool consumers, and will 60f3861e1aSahl * mount/unmount and share/unshare all datasets within pool: 613bb79becSeschrock * 62f3861e1aSahl * zpool_enable_datasets() 63f3861e1aSahl * zpool_disable_datasets() 64fa9e4066Sahrens */ 65fa9e4066Sahrens 66fa9e4066Sahrens #include <dirent.h> 67d8d59944Sahl #include <dlfcn.h> 68fa9e4066Sahrens #include <errno.h> 69fa9e4066Sahrens #include <libgen.h> 70fa9e4066Sahrens #include <libintl.h> 71fa9e4066Sahrens #include <stdio.h> 72fa9e4066Sahrens #include <stdlib.h> 73fa9e4066Sahrens #include <strings.h> 74fa9e4066Sahrens #include <unistd.h> 75fa9e4066Sahrens #include <zone.h> 76fa9e4066Sahrens #include <sys/mntent.h> 77fa9e4066Sahrens #include <sys/mount.h> 78fa9e4066Sahrens #include <sys/stat.h> 79fa9e4066Sahrens 80fa9e4066Sahrens #include <libzfs.h> 81fa9e4066Sahrens 82fa9e4066Sahrens #include "libzfs_impl.h" 83fa9e4066Sahrens 8467331909Sdougm #include <libshare.h> 8567331909Sdougm #include <sys/systeminfo.h> 8667331909Sdougm #define MAXISALEN 257 /* based on sysinfo(2) man page */ 8767331909Sdougm 88da6c28aaSamw static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *); 89da6c28aaSamw zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **, 90da6c28aaSamw zfs_share_proto_t); 91da6c28aaSamw 92d8d59944Sahl static int (*iscsitgt_zfs_share)(const char *); 93d8d59944Sahl static int (*iscsitgt_zfs_unshare)(const char *); 94d8d59944Sahl static int (*iscsitgt_zfs_is_shared)(const char *); 95ecd6cf80Smarks static int (*iscsitgt_svc_online)(); 96d8d59944Sahl 97da6c28aaSamw /* 98da6c28aaSamw * The share protocols table must be in the same order as the zfs_share_prot_t 99da6c28aaSamw * enum in libzfs_impl.h 100da6c28aaSamw */ 101da6c28aaSamw typedef struct { 102da6c28aaSamw zfs_prop_t p_prop; 103da6c28aaSamw char *p_name; 104da6c28aaSamw int p_share_err; 105da6c28aaSamw int p_unshare_err; 106da6c28aaSamw } proto_table_t; 107da6c28aaSamw 108da6c28aaSamw proto_table_t proto_table[PROTO_END] = { 109da6c28aaSamw {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED}, 110da6c28aaSamw {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED}, 111da6c28aaSamw }; 112da6c28aaSamw 113da6c28aaSamw zfs_share_proto_t nfs_only[] = { 114da6c28aaSamw PROTO_NFS, 115da6c28aaSamw PROTO_END 116da6c28aaSamw }; 117da6c28aaSamw 118da6c28aaSamw zfs_share_proto_t smb_only[] = { 119da6c28aaSamw PROTO_SMB, 120da6c28aaSamw PROTO_END 121da6c28aaSamw }; 122da6c28aaSamw zfs_share_proto_t share_all_proto[] = { 123da6c28aaSamw PROTO_NFS, 124da6c28aaSamw PROTO_SMB, 125da6c28aaSamw PROTO_END 126da6c28aaSamw }; 127da6c28aaSamw 128d8d59944Sahl #pragma init(zfs_iscsi_init) 129d8d59944Sahl static void 130d8d59944Sahl zfs_iscsi_init(void) 131d8d59944Sahl { 132d8d59944Sahl void *libiscsitgt; 133d8d59944Sahl 134d8d59944Sahl if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1", 135d8d59944Sahl RTLD_LAZY | RTLD_GLOBAL)) == NULL || 136d8d59944Sahl (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt, 137d8d59944Sahl "iscsitgt_zfs_share")) == NULL || 138d8d59944Sahl (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt, 139d8d59944Sahl "iscsitgt_zfs_unshare")) == NULL || 140d8d59944Sahl (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt, 141ecd6cf80Smarks "iscsitgt_zfs_is_shared")) == NULL || 142ecd6cf80Smarks (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt, 143ecd6cf80Smarks "iscsitgt_svc_online")) == NULL) { 144d8d59944Sahl iscsitgt_zfs_share = NULL; 145d8d59944Sahl iscsitgt_zfs_unshare = NULL; 146d8d59944Sahl iscsitgt_zfs_is_shared = NULL; 147ecd6cf80Smarks iscsitgt_svc_online = NULL; 148d8d59944Sahl } 149d8d59944Sahl } 150d8d59944Sahl 151fa9e4066Sahrens /* 152da6c28aaSamw * Search the sharetab for the given mountpoint and protocol, returning 153da6c28aaSamw * a zfs_share_type_t value. 154fa9e4066Sahrens */ 155da6c28aaSamw static zfs_share_type_t 156da6c28aaSamw is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto) 157fa9e4066Sahrens { 158fa9e4066Sahrens char buf[MAXPATHLEN], *tab; 159da6c28aaSamw char *ptr; 160fa9e4066Sahrens 16199653d4eSeschrock if (hdl->libzfs_sharetab == NULL) 162da6c28aaSamw return (SHARED_NOT_SHARED); 163fa9e4066Sahrens 16499653d4eSeschrock (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); 165fa9e4066Sahrens 16699653d4eSeschrock while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { 167fa9e4066Sahrens 168fa9e4066Sahrens /* the mountpoint is the first entry on each line */ 169da6c28aaSamw if ((tab = strchr(buf, '\t')) == NULL) 170da6c28aaSamw continue; 171da6c28aaSamw 172da6c28aaSamw *tab = '\0'; 173da6c28aaSamw if (strcmp(buf, mountpoint) == 0) { 174da6c28aaSamw /* 175da6c28aaSamw * the protocol field is the third field 176da6c28aaSamw * skip over second field 177da6c28aaSamw */ 178da6c28aaSamw ptr = ++tab; 179da6c28aaSamw if ((tab = strchr(ptr, '\t')) == NULL) 180da6c28aaSamw continue; 181da6c28aaSamw ptr = ++tab; 182da6c28aaSamw if ((tab = strchr(ptr, '\t')) == NULL) 183da6c28aaSamw continue; 184fa9e4066Sahrens *tab = '\0'; 185da6c28aaSamw if (strcmp(ptr, 186da6c28aaSamw proto_table[proto].p_name) == 0) { 187da6c28aaSamw switch (proto) { 188da6c28aaSamw case PROTO_NFS: 189da6c28aaSamw return (SHARED_NFS); 190da6c28aaSamw case PROTO_SMB: 191da6c28aaSamw return (SHARED_SMB); 192da6c28aaSamw default: 193da6c28aaSamw return (0); 194da6c28aaSamw } 195da6c28aaSamw } 196fa9e4066Sahrens } 197fa9e4066Sahrens } 198fa9e4066Sahrens 199da6c28aaSamw return (SHARED_NOT_SHARED); 200fa9e4066Sahrens } 201fa9e4066Sahrens 202fa9e4066Sahrens /* 20399653d4eSeschrock * Returns true if the specified directory is empty. If we can't open the 20499653d4eSeschrock * directory at all, return true so that the mount can fail with a more 205fa9e4066Sahrens * informative error message. 206fa9e4066Sahrens */ 20799653d4eSeschrock static boolean_t 208fa9e4066Sahrens dir_is_empty(const char *dirname) 209fa9e4066Sahrens { 210fa9e4066Sahrens DIR *dirp; 211fa9e4066Sahrens struct dirent64 *dp; 212fa9e4066Sahrens 213fa9e4066Sahrens if ((dirp = opendir(dirname)) == NULL) 21499653d4eSeschrock return (B_TRUE); 215fa9e4066Sahrens 216fa9e4066Sahrens while ((dp = readdir64(dirp)) != NULL) { 217fa9e4066Sahrens 218fa9e4066Sahrens if (strcmp(dp->d_name, ".") == 0 || 219fa9e4066Sahrens strcmp(dp->d_name, "..") == 0) 220fa9e4066Sahrens continue; 221fa9e4066Sahrens 222fa9e4066Sahrens (void) closedir(dirp); 22399653d4eSeschrock return (B_FALSE); 224fa9e4066Sahrens } 225fa9e4066Sahrens 226fa9e4066Sahrens (void) closedir(dirp); 22799653d4eSeschrock return (B_TRUE); 228fa9e4066Sahrens } 229fa9e4066Sahrens 230fa9e4066Sahrens /* 231fa9e4066Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill 232fa9e4066Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return 233fa9e4066Sahrens * 0. 234fa9e4066Sahrens */ 23599653d4eSeschrock boolean_t 23655434c77Sek is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where) 237fa9e4066Sahrens { 238*ebedde84SEric Taylor struct mnttab entry; 239fa9e4066Sahrens 240*ebedde84SEric Taylor if (libzfs_mnttab_find(zfs_hdl, special, &entry) != 0) 24199653d4eSeschrock return (B_FALSE); 242fa9e4066Sahrens 243fa9e4066Sahrens if (where != NULL) 24455434c77Sek *where = zfs_strdup(zfs_hdl, entry.mnt_mountp); 245fa9e4066Sahrens 24699653d4eSeschrock return (B_TRUE); 247fa9e4066Sahrens } 248fa9e4066Sahrens 24955434c77Sek boolean_t 25055434c77Sek zfs_is_mounted(zfs_handle_t *zhp, char **where) 25155434c77Sek { 25255434c77Sek return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where)); 25355434c77Sek } 25455434c77Sek 255e9dbad6fSeschrock /* 256e9dbad6fSeschrock * Returns true if the given dataset is mountable, false otherwise. Returns the 257e9dbad6fSeschrock * mountpoint in 'buf'. 258e9dbad6fSeschrock */ 259e9dbad6fSeschrock static boolean_t 260e9dbad6fSeschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, 261990b4856Slling zprop_source_t *source) 262e9dbad6fSeschrock { 263e9dbad6fSeschrock char sourceloc[ZFS_MAXNAMELEN]; 264990b4856Slling zprop_source_t sourcetype; 265e9dbad6fSeschrock 266e9dbad6fSeschrock if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type)) 267e9dbad6fSeschrock return (B_FALSE); 268e9dbad6fSeschrock 269e9dbad6fSeschrock verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen, 270e9dbad6fSeschrock &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0); 271e9dbad6fSeschrock 272e9dbad6fSeschrock if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 || 273e9dbad6fSeschrock strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0) 274e9dbad6fSeschrock return (B_FALSE); 275e9dbad6fSeschrock 276a227b7f4Shs if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF) 277e9dbad6fSeschrock return (B_FALSE); 278e9dbad6fSeschrock 279e9dbad6fSeschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) && 280e9dbad6fSeschrock getzoneid() == GLOBAL_ZONEID) 281e9dbad6fSeschrock return (B_FALSE); 282e9dbad6fSeschrock 283e9dbad6fSeschrock if (source) 284e9dbad6fSeschrock *source = sourcetype; 285e9dbad6fSeschrock 286e9dbad6fSeschrock return (B_TRUE); 287e9dbad6fSeschrock } 288e9dbad6fSeschrock 289fa9e4066Sahrens /* 290fa9e4066Sahrens * Mount the given filesystem. 291fa9e4066Sahrens */ 292fa9e4066Sahrens int 293fa9e4066Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 294fa9e4066Sahrens { 295fa9e4066Sahrens struct stat buf; 296fa9e4066Sahrens char mountpoint[ZFS_MAXPROPLEN]; 297fa9e4066Sahrens char mntopts[MNT_LINE_MAX]; 29899653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 299fa9e4066Sahrens 300fa9e4066Sahrens if (options == NULL) 301fa9e4066Sahrens mntopts[0] = '\0'; 302fa9e4066Sahrens else 303fa9e4066Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 304fa9e4066Sahrens 305e9dbad6fSeschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 30699653d4eSeschrock return (0); 307fa9e4066Sahrens 308fa9e4066Sahrens /* Create the directory if it doesn't already exist */ 309fa9e4066Sahrens if (lstat(mountpoint, &buf) != 0) { 310fa9e4066Sahrens if (mkdirp(mountpoint, 0755) != 0) { 31199653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 31299653d4eSeschrock "failed to create mountpoint")); 313ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 31499653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 31599653d4eSeschrock mountpoint)); 316fa9e4066Sahrens } 317fa9e4066Sahrens } 318fa9e4066Sahrens 319fa9e4066Sahrens /* 320fa9e4066Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 321fa9e4066Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 322fa9e4066Sahrens * would defeat the point. We also avoid this check if 'remount' is 323fa9e4066Sahrens * specified. 324fa9e4066Sahrens */ 325fa9e4066Sahrens if ((flags & MS_OVERLAY) == 0 && 326fa9e4066Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 327fa9e4066Sahrens !dir_is_empty(mountpoint)) { 32899653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 32999653d4eSeschrock "directory is not empty")); 330ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 33199653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint)); 332fa9e4066Sahrens } 333fa9e4066Sahrens 334fa9e4066Sahrens /* perform the mount */ 335fa9e4066Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 336fa9e4066Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 337fa9e4066Sahrens /* 338fa9e4066Sahrens * Generic errors are nasty, but there are just way too many 339fa9e4066Sahrens * from mount(), and they're well-understood. We pick a few 340fa9e4066Sahrens * common ones to improve upon. 341fa9e4066Sahrens */ 342d8689a57Sdougm if (errno == EBUSY) { 34399653d4eSeschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 34499653d4eSeschrock "mountpoint or dataset is busy")); 345ecd6cf80Smarks } else if (errno == EPERM) { 346ecd6cf80Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 347ecd6cf80Smarks "Insufficient privileges")); 348d8689a57Sdougm } else { 34999653d4eSeschrock zfs_error_aux(hdl, strerror(errno)); 350d8689a57Sdougm } 351ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 35299653d4eSeschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 35399653d4eSeschrock zhp->zfs_name)); 354fa9e4066Sahrens } 355fa9e4066Sahrens 356*ebedde84SEric Taylor /* add the mounted entry into our cache */ 357*ebedde84SEric Taylor libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint, 358*ebedde84SEric Taylor mntopts); 359fa9e4066Sahrens return (0); 360fa9e4066Sahrens } 361fa9e4066Sahrens 3623bb79becSeschrock /* 3633bb79becSeschrock * Unmount a single filesystem. 3643bb79becSeschrock */ 3653bb79becSeschrock static int 3663bb79becSeschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) 3673bb79becSeschrock { 3683bb79becSeschrock if (umount2(mountpoint, flags) != 0) { 3693bb79becSeschrock zfs_error_aux(hdl, strerror(errno)); 370ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED, 3713bb79becSeschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), 3723bb79becSeschrock mountpoint)); 3733bb79becSeschrock } 3743bb79becSeschrock 3753bb79becSeschrock return (0); 3763bb79becSeschrock } 3773bb79becSeschrock 378fa9e4066Sahrens /* 379fa9e4066Sahrens * Unmount the given filesystem. 380fa9e4066Sahrens */ 381fa9e4066Sahrens int 382fa9e4066Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 383fa9e4066Sahrens { 384*ebedde84SEric Taylor libzfs_handle_t *hdl = zhp->zfs_hdl; 385*ebedde84SEric Taylor struct mnttab entry; 38667331909Sdougm char *mntpt = NULL; 387fa9e4066Sahrens 388*ebedde84SEric Taylor /* check to see if we need to unmount the filesystem */ 389fa9e4066Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 390*ebedde84SEric Taylor libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) { 39167331909Sdougm /* 39267331909Sdougm * mountpoint may have come from a call to 39367331909Sdougm * getmnt/getmntany if it isn't NULL. If it is NULL, 394*ebedde84SEric Taylor * we know it comes from libzfs_mnttab_find which can 395*ebedde84SEric Taylor * then get freed later. We strdup it to play it safe. 39667331909Sdougm */ 397fa9e4066Sahrens if (mountpoint == NULL) 398*ebedde84SEric Taylor mntpt = zfs_strdup(hdl, entry.mnt_mountp); 39967331909Sdougm else 400*ebedde84SEric Taylor mntpt = zfs_strdup(hdl, mountpoint); 401fa9e4066Sahrens 402fa9e4066Sahrens /* 4033bb79becSeschrock * Unshare and unmount the filesystem 404fa9e4066Sahrens */ 405da6c28aaSamw if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) 406eb66cf86Sth return (-1); 407eb66cf86Sth 408*ebedde84SEric Taylor if (unmount_one(hdl, mntpt, flags) != 0) { 40967331909Sdougm free(mntpt); 410da6c28aaSamw (void) zfs_shareall(zhp); 411fa9e4066Sahrens return (-1); 41267331909Sdougm } 413*ebedde84SEric Taylor libzfs_mnttab_remove(hdl, zhp->zfs_name); 41467331909Sdougm free(mntpt); 415fa9e4066Sahrens } 416fa9e4066Sahrens 417fa9e4066Sahrens return (0); 418fa9e4066Sahrens } 419fa9e4066Sahrens 420fa9e4066Sahrens /* 421fa9e4066Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 422fa9e4066Sahrens * To do this, just act like we're changing the mountpoint property, but don't 423fa9e4066Sahrens * remount the filesystems afterwards. 424fa9e4066Sahrens */ 425fa9e4066Sahrens int 426fa9e4066Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 427fa9e4066Sahrens { 428fa9e4066Sahrens prop_changelist_t *clp; 429fa9e4066Sahrens int ret; 430fa9e4066Sahrens 4310069fd67STim Haley clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags); 432fa9e4066Sahrens if (clp == NULL) 433fa9e4066Sahrens return (-1); 434fa9e4066Sahrens 435fa9e4066Sahrens ret = changelist_prefix(clp); 436fa9e4066Sahrens changelist_free(clp); 437fa9e4066Sahrens 438fa9e4066Sahrens return (ret); 439fa9e4066Sahrens } 440fa9e4066Sahrens 441f3861e1aSahl boolean_t 442f3861e1aSahl zfs_is_shared(zfs_handle_t *zhp) 443f3861e1aSahl { 444da6c28aaSamw zfs_share_type_t rc = 0; 445da6c28aaSamw zfs_share_proto_t *curr_proto; 446da6c28aaSamw 447f3861e1aSahl if (ZFS_IS_VOLUME(zhp)) 448f3861e1aSahl return (zfs_is_shared_iscsi(zhp)); 449f3861e1aSahl 450da6c28aaSamw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 451da6c28aaSamw curr_proto++) 452da6c28aaSamw rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto); 453da6c28aaSamw 454da6c28aaSamw return (rc ? B_TRUE : B_FALSE); 455f3861e1aSahl } 456f3861e1aSahl 457f3861e1aSahl int 458f3861e1aSahl zfs_share(zfs_handle_t *zhp) 459f3861e1aSahl { 460f3861e1aSahl if (ZFS_IS_VOLUME(zhp)) 461f3861e1aSahl return (zfs_share_iscsi(zhp)); 462f3861e1aSahl 463da6c28aaSamw return (zfs_share_proto(zhp, share_all_proto)); 464f3861e1aSahl } 465f3861e1aSahl 466f3861e1aSahl int 467f3861e1aSahl zfs_unshare(zfs_handle_t *zhp) 468f3861e1aSahl { 469f3861e1aSahl if (ZFS_IS_VOLUME(zhp)) 470f3861e1aSahl return (zfs_unshare_iscsi(zhp)); 471f3861e1aSahl 472da6c28aaSamw return (zfs_unshareall(zhp)); 473f3861e1aSahl } 474f3861e1aSahl 475fa9e4066Sahrens /* 476fa9e4066Sahrens * Check to see if the filesystem is currently shared. 477fa9e4066Sahrens */ 478da6c28aaSamw zfs_share_type_t 479da6c28aaSamw zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto) 480fa9e4066Sahrens { 481fa9e4066Sahrens char *mountpoint; 482da6c28aaSamw zfs_share_type_t rc; 483fa9e4066Sahrens 484fa9e4066Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 485da6c28aaSamw return (SHARED_NOT_SHARED); 486fa9e4066Sahrens 487da6c28aaSamw if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) { 488fa9e4066Sahrens if (where != NULL) 489fa9e4066Sahrens *where = mountpoint; 490fa9e4066Sahrens else 491fa9e4066Sahrens free(mountpoint); 492da6c28aaSamw return (rc); 493fa9e4066Sahrens } else { 494fa9e4066Sahrens free(mountpoint); 495da6c28aaSamw return (SHARED_NOT_SHARED); 496fa9e4066Sahrens } 497fa9e4066Sahrens } 498fa9e4066Sahrens 499da6c28aaSamw boolean_t 500da6c28aaSamw zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) 501da6c28aaSamw { 502da6c28aaSamw return (zfs_is_shared_proto(zhp, where, 503da6c28aaSamw PROTO_NFS) != SHARED_NOT_SHARED); 504da6c28aaSamw } 505da6c28aaSamw 506da6c28aaSamw boolean_t 507da6c28aaSamw zfs_is_shared_smb(zfs_handle_t *zhp, char **where) 508da6c28aaSamw { 509da6c28aaSamw return (zfs_is_shared_proto(zhp, where, 510da6c28aaSamw PROTO_SMB) != SHARED_NOT_SHARED); 511da6c28aaSamw } 512da6c28aaSamw 51367331909Sdougm /* 51467331909Sdougm * Make sure things will work if libshare isn't installed by using 51567331909Sdougm * wrapper functions that check to see that the pointers to functions 51667331909Sdougm * initialized in _zfs_init_libshare() are actually present. 51767331909Sdougm */ 51867331909Sdougm 51967331909Sdougm static sa_handle_t (*_sa_init)(int); 52067331909Sdougm static void (*_sa_fini)(sa_handle_t); 52167331909Sdougm static sa_share_t (*_sa_find_share)(sa_handle_t, char *); 52267331909Sdougm static int (*_sa_enable_share)(sa_share_t, char *); 52367331909Sdougm static int (*_sa_disable_share)(sa_share_t, char *); 52467331909Sdougm static char *(*_sa_errorstr)(int); 52567331909Sdougm static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *); 5265b6e0c46Sdougm static boolean_t (*_sa_needs_refresh)(sa_handle_t *); 5275b6e0c46Sdougm static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t); 5285b6e0c46Sdougm static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t, 5295b6e0c46Sdougm char *, char *, zprop_source_t, char *, char *, char *); 5305b6e0c46Sdougm static void (*_sa_update_sharetab_ts)(sa_handle_t); 53167331909Sdougm 53267331909Sdougm /* 53367331909Sdougm * _zfs_init_libshare() 53467331909Sdougm * 53567331909Sdougm * Find the libshare.so.1 entry points that we use here and save the 53667331909Sdougm * values to be used later. This is triggered by the runtime loader. 53767331909Sdougm * Make sure the correct ISA version is loaded. 53867331909Sdougm */ 5395b6e0c46Sdougm 54067331909Sdougm #pragma init(_zfs_init_libshare) 54167331909Sdougm static void 54267331909Sdougm _zfs_init_libshare(void) 54367331909Sdougm { 54467331909Sdougm void *libshare; 54567331909Sdougm char path[MAXPATHLEN]; 54667331909Sdougm char isa[MAXISALEN]; 54767331909Sdougm 54867331909Sdougm #if defined(_LP64) 54967331909Sdougm if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1) 550d8689a57Sdougm isa[0] = '\0'; 55167331909Sdougm #else 55267331909Sdougm isa[0] = '\0'; 55367331909Sdougm #endif 55467331909Sdougm (void) snprintf(path, MAXPATHLEN, 555d8689a57Sdougm "/usr/lib/%s/libshare.so.1", isa); 55667331909Sdougm 55767331909Sdougm if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) { 558d8689a57Sdougm _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init"); 559d8689a57Sdougm _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini"); 560d8689a57Sdougm _sa_find_share = (sa_share_t (*)(sa_handle_t, char *)) 561d8689a57Sdougm dlsym(libshare, "sa_find_share"); 562d8689a57Sdougm _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 563d8689a57Sdougm "sa_enable_share"); 564d8689a57Sdougm _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 565d8689a57Sdougm "sa_disable_share"); 566d8689a57Sdougm _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr"); 567d8689a57Sdougm _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *)) 568d8689a57Sdougm dlsym(libshare, "sa_parse_legacy_options"); 5695b6e0c46Sdougm _sa_needs_refresh = (boolean_t (*)(sa_handle_t *)) 5705b6e0c46Sdougm dlsym(libshare, "sa_needs_refresh"); 5715b6e0c46Sdougm _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t)) 5725b6e0c46Sdougm dlsym(libshare, "sa_get_zfs_handle"); 5735b6e0c46Sdougm _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t, 5745b6e0c46Sdougm sa_share_t, char *, char *, zprop_source_t, char *, 5755b6e0c46Sdougm char *, char *))dlsym(libshare, "sa_zfs_process_share"); 5765b6e0c46Sdougm _sa_update_sharetab_ts = (void (*)(sa_handle_t)) 5775b6e0c46Sdougm dlsym(libshare, "sa_update_sharetab_ts"); 57857b448deSdougm if (_sa_init == NULL || _sa_fini == NULL || 57957b448deSdougm _sa_find_share == NULL || _sa_enable_share == NULL || 58057b448deSdougm _sa_disable_share == NULL || _sa_errorstr == NULL || 5815b6e0c46Sdougm _sa_parse_legacy_options == NULL || 5825b6e0c46Sdougm _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL || 5835b6e0c46Sdougm _sa_zfs_process_share == NULL || 5845b6e0c46Sdougm _sa_update_sharetab_ts == NULL) { 58557b448deSdougm _sa_init = NULL; 58657b448deSdougm _sa_fini = NULL; 58757b448deSdougm _sa_disable_share = NULL; 58857b448deSdougm _sa_enable_share = NULL; 58957b448deSdougm _sa_errorstr = NULL; 59057b448deSdougm _sa_parse_legacy_options = NULL; 59157b448deSdougm (void) dlclose(libshare); 5925b6e0c46Sdougm _sa_needs_refresh = NULL; 5935b6e0c46Sdougm _sa_get_zfs_handle = NULL; 5945b6e0c46Sdougm _sa_zfs_process_share = NULL; 5955b6e0c46Sdougm _sa_update_sharetab_ts = NULL; 59657b448deSdougm } 59767331909Sdougm } 59867331909Sdougm } 59967331909Sdougm 60067331909Sdougm /* 60167331909Sdougm * zfs_init_libshare(zhandle, service) 60267331909Sdougm * 60367331909Sdougm * Initialize the libshare API if it hasn't already been initialized. 60467331909Sdougm * In all cases it returns 0 if it succeeded and an error if not. The 60567331909Sdougm * service value is which part(s) of the API to initialize and is a 60667331909Sdougm * direct map to the libshare sa_init(service) interface. 60767331909Sdougm */ 60867331909Sdougm int 60967331909Sdougm zfs_init_libshare(libzfs_handle_t *zhandle, int service) 61067331909Sdougm { 61167331909Sdougm int ret = SA_OK; 61267331909Sdougm 613d8689a57Sdougm if (_sa_init == NULL) 614d8689a57Sdougm ret = SA_CONFIG_ERR; 615d8689a57Sdougm 6165b6e0c46Sdougm if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) { 6175b6e0c46Sdougm /* 6185b6e0c46Sdougm * We had a cache miss. Most likely it is a new ZFS 6195b6e0c46Sdougm * dataset that was just created. We want to make sure 6205b6e0c46Sdougm * so check timestamps to see if a different process 6215b6e0c46Sdougm * has updated any of the configuration. If there was 6225b6e0c46Sdougm * some non-ZFS change, we need to re-initialize the 6235b6e0c46Sdougm * internal cache. 6245b6e0c46Sdougm */ 6255b6e0c46Sdougm zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS; 6265b6e0c46Sdougm if (_sa_needs_refresh != NULL && 6275b6e0c46Sdougm _sa_needs_refresh(zhandle->libzfs_sharehdl)) { 6285b6e0c46Sdougm zfs_uninit_libshare(zhandle); 6295b6e0c46Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 6305b6e0c46Sdougm } 6315b6e0c46Sdougm } 6325b6e0c46Sdougm 633d8689a57Sdougm if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL) 634d8689a57Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 635d8689a57Sdougm 636d8689a57Sdougm if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL) 637d8689a57Sdougm ret = SA_NO_MEMORY; 638d8689a57Sdougm 63967331909Sdougm return (ret); 64067331909Sdougm } 64167331909Sdougm 64267331909Sdougm /* 64367331909Sdougm * zfs_uninit_libshare(zhandle) 64467331909Sdougm * 64567331909Sdougm * Uninitialize the libshare API if it hasn't already been 64667331909Sdougm * uninitialized. It is OK to call multiple times. 64767331909Sdougm */ 64867331909Sdougm void 64967331909Sdougm zfs_uninit_libshare(libzfs_handle_t *zhandle) 65067331909Sdougm { 65167331909Sdougm if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) { 652d8689a57Sdougm if (_sa_fini != NULL) 653d8689a57Sdougm _sa_fini(zhandle->libzfs_sharehdl); 654d8689a57Sdougm zhandle->libzfs_sharehdl = NULL; 65567331909Sdougm } 65667331909Sdougm } 65767331909Sdougm 65867331909Sdougm /* 65967331909Sdougm * zfs_parse_options(options, proto) 66067331909Sdougm * 66167331909Sdougm * Call the legacy parse interface to get the protocol specific 66267331909Sdougm * options using the NULL arg to indicate that this is a "parse" only. 66367331909Sdougm */ 66467331909Sdougm int 665da6c28aaSamw zfs_parse_options(char *options, zfs_share_proto_t proto) 66667331909Sdougm { 6673cb34c60Sahrens if (_sa_parse_legacy_options != NULL) { 6683cb34c60Sahrens return (_sa_parse_legacy_options(NULL, options, 6693cb34c60Sahrens proto_table[proto].p_name)); 6703cb34c60Sahrens } 6713cb34c60Sahrens return (SA_CONFIG_ERR); 67267331909Sdougm } 67367331909Sdougm 67467331909Sdougm /* 67567331909Sdougm * zfs_sa_find_share(handle, path) 67667331909Sdougm * 67767331909Sdougm * wrapper around sa_find_share to find a share path in the 67867331909Sdougm * configuration. 67967331909Sdougm */ 68067331909Sdougm static sa_share_t 68167331909Sdougm zfs_sa_find_share(sa_handle_t handle, char *path) 68267331909Sdougm { 68367331909Sdougm if (_sa_find_share != NULL) 684d8689a57Sdougm return (_sa_find_share(handle, path)); 68567331909Sdougm return (NULL); 68667331909Sdougm } 68767331909Sdougm 68867331909Sdougm /* 68967331909Sdougm * zfs_sa_enable_share(share, proto) 69067331909Sdougm * 69167331909Sdougm * Wrapper for sa_enable_share which enables a share for a specified 69267331909Sdougm * protocol. 69367331909Sdougm */ 69467331909Sdougm static int 69567331909Sdougm zfs_sa_enable_share(sa_share_t share, char *proto) 69667331909Sdougm { 69767331909Sdougm if (_sa_enable_share != NULL) 698d8689a57Sdougm return (_sa_enable_share(share, proto)); 69967331909Sdougm return (SA_CONFIG_ERR); 70067331909Sdougm } 70167331909Sdougm 70267331909Sdougm /* 70367331909Sdougm * zfs_sa_disable_share(share, proto) 70467331909Sdougm * 70567331909Sdougm * Wrapper for sa_enable_share which disables a share for a specified 70667331909Sdougm * protocol. 70767331909Sdougm */ 70867331909Sdougm static int 70967331909Sdougm zfs_sa_disable_share(sa_share_t share, char *proto) 71067331909Sdougm { 71167331909Sdougm if (_sa_disable_share != NULL) 712d8689a57Sdougm return (_sa_disable_share(share, proto)); 71367331909Sdougm return (SA_CONFIG_ERR); 71467331909Sdougm } 71567331909Sdougm 716fa9e4066Sahrens /* 717da6c28aaSamw * Share the given filesystem according to the options in the specified 718da6c28aaSamw * protocol specific properties (sharenfs, sharesmb). We rely 71967331909Sdougm * on "libshare" to the dirty work for us. 720fa9e4066Sahrens */ 721da6c28aaSamw static int 722da6c28aaSamw zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 723fa9e4066Sahrens { 724fa9e4066Sahrens char mountpoint[ZFS_MAXPROPLEN]; 725fa9e4066Sahrens char shareopts[ZFS_MAXPROPLEN]; 7265b6e0c46Sdougm char sourcestr[ZFS_MAXPROPLEN]; 72799653d4eSeschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 72867331909Sdougm sa_share_t share; 729da6c28aaSamw zfs_share_proto_t *curr_proto; 7305b6e0c46Sdougm zprop_source_t sourcetype; 73167331909Sdougm int ret; 732fa9e4066Sahrens 733e9dbad6fSeschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 734fa9e4066Sahrens return (0); 735fa9e4066Sahrens 73667331909Sdougm if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 737d8689a57Sdougm (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 738d8689a57Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), 7395b6e0c46Sdougm zfs_get_name(zhp), _sa_errorstr != NULL ? 7405b6e0c46Sdougm _sa_errorstr(ret) : ""); 741d8689a57Sdougm return (-1); 74267331909Sdougm } 743da6c28aaSamw 744da6c28aaSamw for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { 745da6c28aaSamw /* 746da6c28aaSamw * Return success if there are no share options. 747da6c28aaSamw */ 748da6c28aaSamw if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop, 7495b6e0c46Sdougm shareopts, sizeof (shareopts), &sourcetype, sourcestr, 7505b6e0c46Sdougm ZFS_MAXPROPLEN, B_FALSE) != 0 || 7515b6e0c46Sdougm strcmp(shareopts, "off") == 0) 752da6c28aaSamw continue; 753da6c28aaSamw 754da6c28aaSamw /* 755da6c28aaSamw * If the 'zoned' property is set, then zfs_is_mountable() 756da6c28aaSamw * will have already bailed out if we are in the global zone. 757da6c28aaSamw * But local zones cannot be NFS servers, so we ignore it for 758da6c28aaSamw * local zones as well. 759da6c28aaSamw */ 760da6c28aaSamw if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) 761da6c28aaSamw continue; 762da6c28aaSamw 763da6c28aaSamw share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint); 7645b6e0c46Sdougm if (share == NULL) { 7655b6e0c46Sdougm /* 7665b6e0c46Sdougm * This may be a new file system that was just 7675b6e0c46Sdougm * created so isn't in the internal cache 7685b6e0c46Sdougm * (second time through). Rather than 7695b6e0c46Sdougm * reloading the entire configuration, we can 7705b6e0c46Sdougm * assume ZFS has done the checking and it is 7715b6e0c46Sdougm * safe to add this to the internal 7725b6e0c46Sdougm * configuration. 7735b6e0c46Sdougm */ 7745b6e0c46Sdougm if (_sa_zfs_process_share(hdl->libzfs_sharehdl, 7755b6e0c46Sdougm NULL, NULL, mountpoint, 7765b6e0c46Sdougm proto_table[*curr_proto].p_name, sourcetype, 7775b6e0c46Sdougm shareopts, sourcestr, zhp->zfs_name) != SA_OK) { 7785b6e0c46Sdougm (void) zfs_error_fmt(hdl, 7795b6e0c46Sdougm proto_table[*curr_proto].p_share_err, 7805b6e0c46Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 7815b6e0c46Sdougm zfs_get_name(zhp)); 7825b6e0c46Sdougm return (-1); 7835b6e0c46Sdougm } 7845b6e0c46Sdougm hdl->libzfs_shareflags |= ZFSSHARE_MISS; 7855b6e0c46Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, 7865b6e0c46Sdougm mountpoint); 7875b6e0c46Sdougm } 788da6c28aaSamw if (share != NULL) { 789da6c28aaSamw int err; 790da6c28aaSamw err = zfs_sa_enable_share(share, 791da6c28aaSamw proto_table[*curr_proto].p_name); 792da6c28aaSamw if (err != SA_OK) { 793da6c28aaSamw (void) zfs_error_fmt(hdl, 794da6c28aaSamw proto_table[*curr_proto].p_share_err, 795da6c28aaSamw dgettext(TEXT_DOMAIN, "cannot share '%s'"), 796da6c28aaSamw zfs_get_name(zhp)); 797da6c28aaSamw return (-1); 798da6c28aaSamw } 799da6c28aaSamw } else { 800da6c28aaSamw (void) zfs_error_fmt(hdl, 801da6c28aaSamw proto_table[*curr_proto].p_share_err, 802d8689a57Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 803d8689a57Sdougm zfs_get_name(zhp)); 804d8689a57Sdougm return (-1); 805d8689a57Sdougm } 806fa9e4066Sahrens 807da6c28aaSamw } 808fa9e4066Sahrens return (0); 809fa9e4066Sahrens } 810fa9e4066Sahrens 811da6c28aaSamw 812da6c28aaSamw int 813da6c28aaSamw zfs_share_nfs(zfs_handle_t *zhp) 814da6c28aaSamw { 815da6c28aaSamw return (zfs_share_proto(zhp, nfs_only)); 816da6c28aaSamw } 817da6c28aaSamw 818da6c28aaSamw int 819da6c28aaSamw zfs_share_smb(zfs_handle_t *zhp) 820da6c28aaSamw { 821da6c28aaSamw return (zfs_share_proto(zhp, smb_only)); 822da6c28aaSamw } 823da6c28aaSamw 824da6c28aaSamw int 825da6c28aaSamw zfs_shareall(zfs_handle_t *zhp) 826da6c28aaSamw { 827da6c28aaSamw return (zfs_share_proto(zhp, share_all_proto)); 828da6c28aaSamw } 829da6c28aaSamw 8303bb79becSeschrock /* 8313bb79becSeschrock * Unshare a filesystem by mountpoint. 8323bb79becSeschrock */ 8333bb79becSeschrock static int 834da6c28aaSamw unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, 835da6c28aaSamw zfs_share_proto_t proto) 8363bb79becSeschrock { 83767331909Sdougm sa_share_t share; 83867331909Sdougm int err; 83967331909Sdougm char *mntpt; 8403bb79becSeschrock /* 84167331909Sdougm * Mountpoint could get trashed if libshare calls getmntany 842*ebedde84SEric Taylor * which it does during API initialization, so strdup the 84367331909Sdougm * value. 8443bb79becSeschrock */ 84567331909Sdougm mntpt = zfs_strdup(hdl, mountpoint); 8463bb79becSeschrock 84767331909Sdougm /* make sure libshare initialized */ 84867331909Sdougm if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 84967331909Sdougm free(mntpt); /* don't need the copy anymore */ 85067331909Sdougm return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 851d8689a57Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 852d8689a57Sdougm name, _sa_errorstr(err))); 85367331909Sdougm } 8543bb79becSeschrock 85567331909Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt); 85667331909Sdougm free(mntpt); /* don't need the copy anymore */ 8573bb79becSeschrock 85867331909Sdougm if (share != NULL) { 859da6c28aaSamw err = zfs_sa_disable_share(share, proto_table[proto].p_name); 86067331909Sdougm if (err != SA_OK) { 861d8689a57Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 862d8689a57Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 863d8689a57Sdougm name, _sa_errorstr(err))); 86467331909Sdougm } 86567331909Sdougm } else { 866ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 867d8689a57Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"), 868d8689a57Sdougm name)); 8693bb79becSeschrock } 8703bb79becSeschrock return (0); 8713bb79becSeschrock } 8723bb79becSeschrock 873fa9e4066Sahrens /* 874fa9e4066Sahrens * Unshare the given filesystem. 875fa9e4066Sahrens */ 876fa9e4066Sahrens int 877da6c28aaSamw zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, 878da6c28aaSamw zfs_share_proto_t *proto) 879fa9e4066Sahrens { 880*ebedde84SEric Taylor libzfs_handle_t *hdl = zhp->zfs_hdl; 881*ebedde84SEric Taylor struct mnttab entry; 88267331909Sdougm char *mntpt = NULL; 883fa9e4066Sahrens 884fa9e4066Sahrens /* check to see if need to unmount the filesystem */ 88599653d4eSeschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 886d8689a57Sdougm if (mountpoint != NULL) 887*ebedde84SEric Taylor mountpoint = mntpt = zfs_strdup(hdl, mountpoint); 888d8689a57Sdougm 889fa9e4066Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 890*ebedde84SEric Taylor libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) { 891da6c28aaSamw zfs_share_proto_t *curr_proto; 892fa9e4066Sahrens 893fa9e4066Sahrens if (mountpoint == NULL) 894da6c28aaSamw mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 895fa9e4066Sahrens 896da6c28aaSamw for (curr_proto = proto; *curr_proto != PROTO_END; 897da6c28aaSamw curr_proto++) { 898da6c28aaSamw 899*ebedde84SEric Taylor if (is_shared(hdl, mntpt, *curr_proto) && 900*ebedde84SEric Taylor unshare_one(hdl, zhp->zfs_name, 901da6c28aaSamw mntpt, *curr_proto) != 0) { 902da6c28aaSamw if (mntpt != NULL) 903da6c28aaSamw free(mntpt); 904da6c28aaSamw return (-1); 905da6c28aaSamw } 90667331909Sdougm } 907fa9e4066Sahrens } 90867331909Sdougm if (mntpt != NULL) 909d8689a57Sdougm free(mntpt); 910fa9e4066Sahrens 911fa9e4066Sahrens return (0); 912fa9e4066Sahrens } 913fa9e4066Sahrens 914da6c28aaSamw int 915da6c28aaSamw zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) 916da6c28aaSamw { 917da6c28aaSamw return (zfs_unshare_proto(zhp, mountpoint, nfs_only)); 918da6c28aaSamw } 919da6c28aaSamw 920da6c28aaSamw int 921da6c28aaSamw zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint) 922da6c28aaSamw { 923da6c28aaSamw return (zfs_unshare_proto(zhp, mountpoint, smb_only)); 924da6c28aaSamw } 925da6c28aaSamw 926fa9e4066Sahrens /* 927da6c28aaSamw * Same as zfs_unmountall(), but for NFS and SMB unshares. 928fa9e4066Sahrens */ 929fa9e4066Sahrens int 930da6c28aaSamw zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 931fa9e4066Sahrens { 932fa9e4066Sahrens prop_changelist_t *clp; 933fa9e4066Sahrens int ret; 934fa9e4066Sahrens 9350069fd67STim Haley clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0); 936fa9e4066Sahrens if (clp == NULL) 937fa9e4066Sahrens return (-1); 938fa9e4066Sahrens 939da6c28aaSamw ret = changelist_unshare(clp, proto); 940fa9e4066Sahrens changelist_free(clp); 941fa9e4066Sahrens 942fa9e4066Sahrens return (ret); 943fa9e4066Sahrens } 944fa9e4066Sahrens 945da6c28aaSamw int 946da6c28aaSamw zfs_unshareall_nfs(zfs_handle_t *zhp) 947da6c28aaSamw { 948da6c28aaSamw return (zfs_unshareall_proto(zhp, nfs_only)); 949da6c28aaSamw } 950da6c28aaSamw 951da6c28aaSamw int 952da6c28aaSamw zfs_unshareall_smb(zfs_handle_t *zhp) 953da6c28aaSamw { 954da6c28aaSamw return (zfs_unshareall_proto(zhp, smb_only)); 955da6c28aaSamw } 956da6c28aaSamw 957da6c28aaSamw int 958da6c28aaSamw zfs_unshareall(zfs_handle_t *zhp) 959da6c28aaSamw { 960da6c28aaSamw return (zfs_unshareall_proto(zhp, share_all_proto)); 961da6c28aaSamw } 962da6c28aaSamw 963da6c28aaSamw int 964da6c28aaSamw zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint) 965da6c28aaSamw { 966da6c28aaSamw return (zfs_unshare_proto(zhp, mountpoint, share_all_proto)); 967da6c28aaSamw } 968da6c28aaSamw 969fa9e4066Sahrens /* 970fa9e4066Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 971fa9e4066Sahrens * We only remove the underlying directory if: 972fa9e4066Sahrens * 973fa9e4066Sahrens * - The mountpoint is not 'none' or 'legacy' 974fa9e4066Sahrens * - The mountpoint is non-empty 975fa9e4066Sahrens * - The mountpoint is the default or inherited 976fa9e4066Sahrens * - The 'zoned' property is set, or we're in a local zone 977fa9e4066Sahrens * 978fa9e4066Sahrens * Any other directories we leave alone. 979fa9e4066Sahrens */ 980fa9e4066Sahrens void 981fa9e4066Sahrens remove_mountpoint(zfs_handle_t *zhp) 982fa9e4066Sahrens { 983fa9e4066Sahrens char mountpoint[ZFS_MAXPROPLEN]; 984990b4856Slling zprop_source_t source; 985fa9e4066Sahrens 986e9dbad6fSeschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), 987e9dbad6fSeschrock &source)) 988fa9e4066Sahrens return; 989fa9e4066Sahrens 990990b4856Slling if (source == ZPROP_SRC_DEFAULT || 991990b4856Slling source == ZPROP_SRC_INHERITED) { 992fa9e4066Sahrens /* 993fa9e4066Sahrens * Try to remove the directory, silently ignoring any errors. 994fa9e4066Sahrens * The filesystem may have since been removed or moved around, 995e9dbad6fSeschrock * and this error isn't really useful to the administrator in 996e9dbad6fSeschrock * any way. 997fa9e4066Sahrens */ 998fa9e4066Sahrens (void) rmdir(mountpoint); 999fa9e4066Sahrens } 1000fa9e4066Sahrens } 10013bb79becSeschrock 1002f3861e1aSahl boolean_t 1003f3861e1aSahl zfs_is_shared_iscsi(zfs_handle_t *zhp) 1004f3861e1aSahl { 1005ecd6cf80Smarks 1006ecd6cf80Smarks /* 1007ecd6cf80Smarks * If iscsi deamon isn't running then we aren't shared 1008ecd6cf80Smarks */ 1009ecd6cf80Smarks if (iscsitgt_svc_online && iscsitgt_svc_online() == 1) 1010da6c28aaSamw return (B_FALSE); 1011ecd6cf80Smarks else 1012ecd6cf80Smarks return (iscsitgt_zfs_is_shared != NULL && 1013ecd6cf80Smarks iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); 1014f3861e1aSahl } 1015f3861e1aSahl 1016f3861e1aSahl int 1017f3861e1aSahl zfs_share_iscsi(zfs_handle_t *zhp) 1018f3861e1aSahl { 1019f3861e1aSahl char shareopts[ZFS_MAXPROPLEN]; 1020f3861e1aSahl const char *dataset = zhp->zfs_name; 1021f3861e1aSahl libzfs_handle_t *hdl = zhp->zfs_hdl; 1022f3861e1aSahl 1023f3861e1aSahl /* 1024f3861e1aSahl * Return success if there are no share options. 1025f3861e1aSahl */ 1026f3861e1aSahl if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 1027f3861e1aSahl sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || 1028f3861e1aSahl strcmp(shareopts, "off") == 0) 1029f3861e1aSahl return (0); 1030f3861e1aSahl 1031ecd6cf80Smarks if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) { 1032ecd6cf80Smarks int error = EZFS_SHAREISCSIFAILED; 1033ecd6cf80Smarks 1034ecd6cf80Smarks /* 1035ecd6cf80Smarks * If service isn't availabele and EPERM was 1036ecd6cf80Smarks * returned then use special error. 1037ecd6cf80Smarks */ 1038ecd6cf80Smarks if (iscsitgt_svc_online && errno == EPERM && 1039ecd6cf80Smarks (iscsitgt_svc_online() != 0)) 1040ecd6cf80Smarks error = EZFS_ISCSISVCUNAVAIL; 1041ecd6cf80Smarks 1042ecd6cf80Smarks return (zfs_error_fmt(hdl, error, 1043f3861e1aSahl dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); 1044ecd6cf80Smarks } 1045f3861e1aSahl 1046f3861e1aSahl return (0); 1047f3861e1aSahl } 1048f3861e1aSahl 1049f3861e1aSahl int 1050f3861e1aSahl zfs_unshare_iscsi(zfs_handle_t *zhp) 1051f3861e1aSahl { 1052f3861e1aSahl const char *dataset = zfs_get_name(zhp); 1053f3861e1aSahl libzfs_handle_t *hdl = zhp->zfs_hdl; 1054f3861e1aSahl 105511d2789dSgw /* 105611d2789dSgw * Return if the volume is not shared 105711d2789dSgw */ 1058da6c28aaSamw if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI) 105911d2789dSgw return (0); 106011d2789dSgw 1061f3861e1aSahl /* 1062f3861e1aSahl * If this fails with ENODEV it indicates that zvol wasn't shared so 1063f3861e1aSahl * we should return success in that case. 1064f3861e1aSahl */ 1065d8d59944Sahl if (iscsitgt_zfs_unshare == NULL || 1066ecd6cf80Smarks (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) { 1067ecd6cf80Smarks if (errno == EPERM) 1068ecd6cf80Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1069ecd6cf80Smarks "Insufficient privileges to unshare iscsi")); 1070ece3d9b3Slling return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, 1071f3861e1aSahl dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); 1072ecd6cf80Smarks } 1073f3861e1aSahl 1074f3861e1aSahl return (0); 1075f3861e1aSahl } 1076f3861e1aSahl 10773bb79becSeschrock typedef struct mount_cbdata { 10783bb79becSeschrock zfs_handle_t **cb_datasets; 10793bb79becSeschrock int cb_used; 10803bb79becSeschrock int cb_alloc; 10813bb79becSeschrock } mount_cbdata_t; 10823bb79becSeschrock 10833bb79becSeschrock static int 10843bb79becSeschrock mount_cb(zfs_handle_t *zhp, void *data) 10853bb79becSeschrock { 10863bb79becSeschrock mount_cbdata_t *cbp = data; 10873bb79becSeschrock 1088f3861e1aSahl if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { 10893bb79becSeschrock zfs_close(zhp); 10903bb79becSeschrock return (0); 10913bb79becSeschrock } 10923bb79becSeschrock 1093a227b7f4Shs if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) { 1094a227b7f4Shs zfs_close(zhp); 1095a227b7f4Shs return (0); 1096a227b7f4Shs } 1097a227b7f4Shs 10983bb79becSeschrock if (cbp->cb_alloc == cbp->cb_used) { 1099e9dbad6fSeschrock void *ptr; 11003bb79becSeschrock 1101e9dbad6fSeschrock if ((ptr = zfs_realloc(zhp->zfs_hdl, 1102e9dbad6fSeschrock cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), 1103e9dbad6fSeschrock cbp->cb_alloc * 2 * sizeof (void *))) == NULL) 11043bb79becSeschrock return (-1); 1105e9dbad6fSeschrock cbp->cb_datasets = ptr; 11063bb79becSeschrock 1107e9dbad6fSeschrock cbp->cb_alloc *= 2; 11083bb79becSeschrock } 11093bb79becSeschrock 11103bb79becSeschrock cbp->cb_datasets[cbp->cb_used++] = zhp; 1111f3861e1aSahl 1112d87468daSrm return (zfs_iter_filesystems(zhp, mount_cb, cbp)); 11133bb79becSeschrock } 11143bb79becSeschrock 11153bb79becSeschrock static int 1116f3861e1aSahl dataset_cmp(const void *a, const void *b) 11173bb79becSeschrock { 11183bb79becSeschrock zfs_handle_t **za = (zfs_handle_t **)a; 11193bb79becSeschrock zfs_handle_t **zb = (zfs_handle_t **)b; 11203bb79becSeschrock char mounta[MAXPATHLEN]; 11213bb79becSeschrock char mountb[MAXPATHLEN]; 1122f3861e1aSahl boolean_t gota, gotb; 1123f3861e1aSahl 1124f3861e1aSahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 1125f3861e1aSahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 1126f3861e1aSahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 1127f3861e1aSahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 1128f3861e1aSahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 1129f3861e1aSahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 1130f3861e1aSahl 1131f3861e1aSahl if (gota && gotb) 1132f3861e1aSahl return (strcmp(mounta, mountb)); 11333bb79becSeschrock 1134f3861e1aSahl if (gota) 1135f3861e1aSahl return (-1); 1136f3861e1aSahl if (gotb) 1137f3861e1aSahl return (1); 11383bb79becSeschrock 1139f3861e1aSahl return (strcmp(zfs_get_name(a), zfs_get_name(b))); 11403bb79becSeschrock } 11413bb79becSeschrock 1142f3861e1aSahl /* 1143f3861e1aSahl * Mount and share all datasets within the given pool. This assumes that no 1144f3861e1aSahl * datasets within the pool are currently mounted. Because users can create 1145f3861e1aSahl * complicated nested hierarchies of mountpoints, we first gather all the 1146f3861e1aSahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once 1147f3861e1aSahl * we have the list of all filesystems, we iterate over them in order and mount 1148f3861e1aSahl * and/or share each one. 1149f3861e1aSahl */ 1150f3861e1aSahl #pragma weak zpool_mount_datasets = zpool_enable_datasets 11513bb79becSeschrock int 1152f3861e1aSahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) 11533bb79becSeschrock { 11543bb79becSeschrock mount_cbdata_t cb = { 0 }; 11553bb79becSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 11563bb79becSeschrock zfs_handle_t *zfsp; 11573bb79becSeschrock int i, ret = -1; 115867331909Sdougm int *good; 11593bb79becSeschrock 11603bb79becSeschrock /* 1161d87468daSrm * Gather all non-snap datasets within the pool. 11623bb79becSeschrock */ 11633bb79becSeschrock if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) 11643bb79becSeschrock return (-1); 11653bb79becSeschrock cb.cb_alloc = 4; 11663bb79becSeschrock 1167990b4856Slling if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL) 11683bb79becSeschrock goto out; 11693bb79becSeschrock 11703bb79becSeschrock cb.cb_datasets[0] = zfsp; 11713bb79becSeschrock cb.cb_used = 1; 11723bb79becSeschrock 1173d87468daSrm if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0) 11743bb79becSeschrock goto out; 11753bb79becSeschrock 11763bb79becSeschrock /* 11773bb79becSeschrock * Sort the datasets by mountpoint. 11783bb79becSeschrock */ 1179f3861e1aSahl qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); 11803bb79becSeschrock 11813bb79becSeschrock /* 118267331909Sdougm * And mount all the datasets, keeping track of which ones 118367331909Sdougm * succeeded or failed. By using zfs_alloc(), the good pointer 118467331909Sdougm * will always be non-NULL. 11853bb79becSeschrock */ 118667331909Sdougm good = zfs_alloc(zhp->zpool_hdl, cb.cb_used * sizeof (int)); 11873bb79becSeschrock ret = 0; 11883bb79becSeschrock for (i = 0; i < cb.cb_used; i++) { 1189d8689a57Sdougm if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0) 11903bb79becSeschrock ret = -1; 1191d8689a57Sdougm else 119267331909Sdougm good[i] = 1; 11933bb79becSeschrock } 11945b6e0c46Sdougm 119567331909Sdougm /* 119667331909Sdougm * Then share all the ones that need to be shared. This needs 119767331909Sdougm * to be a separate pass in order to avoid excessive reloading 119867331909Sdougm * of the configuration. Good should never be NULL since 119967331909Sdougm * zfs_alloc is supposed to exit if memory isn't available. 120067331909Sdougm */ 120167331909Sdougm for (i = 0; i < cb.cb_used; i++) { 120267331909Sdougm if (good[i] && zfs_share(cb.cb_datasets[i]) != 0) 120367331909Sdougm ret = -1; 120467331909Sdougm } 120567331909Sdougm 120667331909Sdougm free(good); 12073bb79becSeschrock 12083bb79becSeschrock out: 12093bb79becSeschrock for (i = 0; i < cb.cb_used; i++) 12103bb79becSeschrock zfs_close(cb.cb_datasets[i]); 12113bb79becSeschrock free(cb.cb_datasets); 12123bb79becSeschrock 12133bb79becSeschrock return (ret); 12143bb79becSeschrock } 12153bb79becSeschrock 1216f3861e1aSahl 1217f3861e1aSahl static int 1218f3861e1aSahl zvol_cb(const char *dataset, void *data) 1219f3861e1aSahl { 1220f3861e1aSahl libzfs_handle_t *hdl = data; 1221f3861e1aSahl zfs_handle_t *zhp; 1222f3861e1aSahl 1223f3861e1aSahl /* 1224f3861e1aSahl * Ignore snapshots and ignore failures from non-existant datasets. 1225f3861e1aSahl */ 1226f3861e1aSahl if (strchr(dataset, '@') != NULL || 1227f3861e1aSahl (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL) 1228f3861e1aSahl return (0); 1229f3861e1aSahl 1230ecd6cf80Smarks if (zfs_unshare_iscsi(zhp) != 0) 1231ecd6cf80Smarks return (-1); 1232f3861e1aSahl 1233f3861e1aSahl zfs_close(zhp); 1234f3861e1aSahl 1235f3861e1aSahl return (0); 1236f3861e1aSahl } 1237f3861e1aSahl 12383bb79becSeschrock static int 12393bb79becSeschrock mountpoint_compare(const void *a, const void *b) 12403bb79becSeschrock { 12413bb79becSeschrock const char *mounta = *((char **)a); 12423bb79becSeschrock const char *mountb = *((char **)b); 12433bb79becSeschrock 12443bb79becSeschrock return (strcmp(mountb, mounta)); 12453bb79becSeschrock } 12463bb79becSeschrock 1247f3861e1aSahl /* 1248f3861e1aSahl * Unshare and unmount all datasets within the given pool. We don't want to 1249f3861e1aSahl * rely on traversing the DSL to discover the filesystems within the pool, 1250f3861e1aSahl * because this may be expensive (if not all of them are mounted), and can fail 1251f3861e1aSahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and 1252f3861e1aSahl * gather all the filesystems that are currently mounted. 1253f3861e1aSahl */ 1254f3861e1aSahl #pragma weak zpool_unmount_datasets = zpool_disable_datasets 12553bb79becSeschrock int 1256f3861e1aSahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) 12573bb79becSeschrock { 12583bb79becSeschrock int used, alloc; 12593bb79becSeschrock struct mnttab entry; 12603bb79becSeschrock size_t namelen; 12613bb79becSeschrock char **mountpoints = NULL; 12623bb79becSeschrock zfs_handle_t **datasets = NULL; 12633bb79becSeschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 12643bb79becSeschrock int i; 12653bb79becSeschrock int ret = -1; 12663bb79becSeschrock int flags = (force ? MS_FORCE : 0); 12673bb79becSeschrock 1268f3861e1aSahl /* 1269f3861e1aSahl * First unshare all zvols. 1270f3861e1aSahl */ 1271f3861e1aSahl if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0) 1272f3861e1aSahl return (-1); 1273f3861e1aSahl 12743bb79becSeschrock namelen = strlen(zhp->zpool_name); 12753bb79becSeschrock 12763bb79becSeschrock rewind(hdl->libzfs_mnttab); 12773bb79becSeschrock used = alloc = 0; 12783bb79becSeschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 12793bb79becSeschrock /* 12803bb79becSeschrock * Ignore non-ZFS entries. 12813bb79becSeschrock */ 12823bb79becSeschrock if (entry.mnt_fstype == NULL || 12833bb79becSeschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 12843bb79becSeschrock continue; 12853bb79becSeschrock 12863bb79becSeschrock /* 12873bb79becSeschrock * Ignore filesystems not within this pool. 12883bb79becSeschrock */ 12893bb79becSeschrock if (entry.mnt_mountp == NULL || 12903bb79becSeschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 || 12913bb79becSeschrock (entry.mnt_special[namelen] != '/' && 12923bb79becSeschrock entry.mnt_special[namelen] != '\0')) 12933bb79becSeschrock continue; 12943bb79becSeschrock 12953bb79becSeschrock /* 12963bb79becSeschrock * At this point we've found a filesystem within our pool. Add 12973bb79becSeschrock * it to our growing list. 12983bb79becSeschrock */ 12993bb79becSeschrock if (used == alloc) { 13003bb79becSeschrock if (alloc == 0) { 13013bb79becSeschrock if ((mountpoints = zfs_alloc(hdl, 13023bb79becSeschrock 8 * sizeof (void *))) == NULL) 13033bb79becSeschrock goto out; 13043bb79becSeschrock 13053bb79becSeschrock if ((datasets = zfs_alloc(hdl, 13063bb79becSeschrock 8 * sizeof (void *))) == NULL) 13073bb79becSeschrock goto out; 13083bb79becSeschrock 13093bb79becSeschrock alloc = 8; 13103bb79becSeschrock } else { 1311e9dbad6fSeschrock void *ptr; 13123bb79becSeschrock 1313e9dbad6fSeschrock if ((ptr = zfs_realloc(hdl, mountpoints, 1314e9dbad6fSeschrock alloc * sizeof (void *), 13153bb79becSeschrock alloc * 2 * sizeof (void *))) == NULL) 13163bb79becSeschrock goto out; 1317e9dbad6fSeschrock mountpoints = ptr; 13183bb79becSeschrock 1319e9dbad6fSeschrock if ((ptr = zfs_realloc(hdl, datasets, 1320e9dbad6fSeschrock alloc * sizeof (void *), 13213bb79becSeschrock alloc * 2 * sizeof (void *))) == NULL) 13223bb79becSeschrock goto out; 1323e9dbad6fSeschrock datasets = ptr; 13243bb79becSeschrock 13253bb79becSeschrock alloc *= 2; 13263bb79becSeschrock } 13273bb79becSeschrock } 13283bb79becSeschrock 13293bb79becSeschrock if ((mountpoints[used] = zfs_strdup(hdl, 13303bb79becSeschrock entry.mnt_mountp)) == NULL) 13313bb79becSeschrock goto out; 13323bb79becSeschrock 13333bb79becSeschrock /* 13343bb79becSeschrock * This is allowed to fail, in case there is some I/O error. It 13353bb79becSeschrock * is only used to determine if we need to remove the underlying 13363bb79becSeschrock * mountpoint, so failure is not fatal. 13373bb79becSeschrock */ 13383bb79becSeschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special); 13393bb79becSeschrock 13403bb79becSeschrock used++; 13413bb79becSeschrock } 13423bb79becSeschrock 13433bb79becSeschrock /* 13443bb79becSeschrock * At this point, we have the entire list of filesystems, so sort it by 13453bb79becSeschrock * mountpoint. 13463bb79becSeschrock */ 13473bb79becSeschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare); 13483bb79becSeschrock 13493bb79becSeschrock /* 13503bb79becSeschrock * Walk through and first unshare everything. 13513bb79becSeschrock */ 13523bb79becSeschrock for (i = 0; i < used; i++) { 1353da6c28aaSamw zfs_share_proto_t *curr_proto; 1354da6c28aaSamw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 1355da6c28aaSamw curr_proto++) { 1356da6c28aaSamw if (is_shared(hdl, mountpoints[i], *curr_proto) && 1357da6c28aaSamw unshare_one(hdl, mountpoints[i], 1358da6c28aaSamw mountpoints[i], *curr_proto) != 0) 1359da6c28aaSamw goto out; 1360da6c28aaSamw } 13613bb79becSeschrock } 13623bb79becSeschrock 13633bb79becSeschrock /* 13643bb79becSeschrock * Now unmount everything, removing the underlying directories as 13653bb79becSeschrock * appropriate. 13663bb79becSeschrock */ 13673bb79becSeschrock for (i = 0; i < used; i++) { 13683bb79becSeschrock if (unmount_one(hdl, mountpoints[i], flags) != 0) 13693bb79becSeschrock goto out; 1370e9dbad6fSeschrock } 13713bb79becSeschrock 1372e9dbad6fSeschrock for (i = 0; i < used; i++) { 13733bb79becSeschrock if (datasets[i]) 13743bb79becSeschrock remove_mountpoint(datasets[i]); 13753bb79becSeschrock } 13763bb79becSeschrock 13773bb79becSeschrock ret = 0; 13783bb79becSeschrock out: 13793bb79becSeschrock for (i = 0; i < used; i++) { 13803bb79becSeschrock if (datasets[i]) 13813bb79becSeschrock zfs_close(datasets[i]); 13823bb79becSeschrock free(mountpoints[i]); 13833bb79becSeschrock } 13843bb79becSeschrock free(datasets); 13853bb79becSeschrock free(mountpoints); 13863bb79becSeschrock 13873bb79becSeschrock return (ret); 13883bb79becSeschrock } 1389