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 /* 235951Sdougm * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens /* 28789Sahrens * Routines to manage ZFS mounts. We separate all the nasty routines that have 293126Sahl * to deal with the OS. The following functions are the main entry points -- 303126Sahl * they are used by mount and unmount and when changing a filesystem's 313126Sahl * mountpoint. 32789Sahrens * 33789Sahrens * zfs_is_mounted() 34789Sahrens * zfs_mount() 35789Sahrens * zfs_unmount() 36789Sahrens * zfs_unmountall() 37789Sahrens * 383126Sahl * This file also contains the functions used to manage sharing filesystems via 393126Sahl * NFS and iSCSI: 40789Sahrens * 41789Sahrens * zfs_is_shared() 42789Sahrens * zfs_share() 43789Sahrens * zfs_unshare() 443126Sahl * 453126Sahl * zfs_is_shared_nfs() 465331Samw * zfs_is_shared_smb() 475331Samw * zfs_is_shared_iscsi() 485331Samw * zfs_share_proto() 495331Samw * zfs_shareall(); 505331Samw * zfs_share_iscsi() 513126Sahl * zfs_unshare_nfs() 525331Samw * zfs_unshare_smb() 533126Sahl * zfs_unshareall_nfs() 545331Samw * zfs_unshareall_smb() 555331Samw * zfs_unshareall() 565331Samw * zfs_unshareall_bypath() 573126Sahl * zfs_unshare_iscsi() 582474Seschrock * 592474Seschrock * The following functions are available for pool consumers, and will 603126Sahl * mount/unmount and share/unshare all datasets within pool: 612474Seschrock * 623126Sahl * zpool_enable_datasets() 633126Sahl * zpool_disable_datasets() 64789Sahrens */ 65789Sahrens 66789Sahrens #include <dirent.h> 673134Sahl #include <dlfcn.h> 68789Sahrens #include <errno.h> 69789Sahrens #include <libgen.h> 70789Sahrens #include <libintl.h> 71789Sahrens #include <stdio.h> 72789Sahrens #include <stdlib.h> 73789Sahrens #include <strings.h> 74789Sahrens #include <unistd.h> 75789Sahrens #include <zone.h> 76789Sahrens #include <sys/mntent.h> 77789Sahrens #include <sys/mnttab.h> 78789Sahrens #include <sys/mount.h> 79789Sahrens #include <sys/stat.h> 80789Sahrens 81789Sahrens #include <libzfs.h> 82789Sahrens 83789Sahrens #include "libzfs_impl.h" 84789Sahrens 854180Sdougm #include <libshare.h> 864180Sdougm #include <sys/systeminfo.h> 874180Sdougm #define MAXISALEN 257 /* based on sysinfo(2) man page */ 884180Sdougm 895331Samw static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *); 905331Samw zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **, 915331Samw zfs_share_proto_t); 925331Samw 933134Sahl static int (*iscsitgt_zfs_share)(const char *); 943134Sahl static int (*iscsitgt_zfs_unshare)(const char *); 953134Sahl static int (*iscsitgt_zfs_is_shared)(const char *); 964543Smarks static int (*iscsitgt_svc_online)(); 973134Sahl 985331Samw /* 995331Samw * The share protocols table must be in the same order as the zfs_share_prot_t 1005331Samw * enum in libzfs_impl.h 1015331Samw */ 1025331Samw typedef struct { 1035331Samw zfs_prop_t p_prop; 1045331Samw char *p_name; 1055331Samw int p_share_err; 1065331Samw int p_unshare_err; 1075331Samw } proto_table_t; 1085331Samw 1095331Samw proto_table_t proto_table[PROTO_END] = { 1105331Samw {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED}, 1115331Samw {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED}, 1125331Samw }; 1135331Samw 1145331Samw zfs_share_proto_t nfs_only[] = { 1155331Samw PROTO_NFS, 1165331Samw PROTO_END 1175331Samw }; 1185331Samw 1195331Samw zfs_share_proto_t smb_only[] = { 1205331Samw PROTO_SMB, 1215331Samw PROTO_END 1225331Samw }; 1235331Samw zfs_share_proto_t share_all_proto[] = { 1245331Samw PROTO_NFS, 1255331Samw PROTO_SMB, 1265331Samw PROTO_END 1275331Samw }; 1285331Samw 1293134Sahl #pragma init(zfs_iscsi_init) 1303134Sahl static void 1313134Sahl zfs_iscsi_init(void) 1323134Sahl { 1333134Sahl void *libiscsitgt; 1343134Sahl 1353134Sahl if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1", 1363134Sahl RTLD_LAZY | RTLD_GLOBAL)) == NULL || 1373134Sahl (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt, 1383134Sahl "iscsitgt_zfs_share")) == NULL || 1393134Sahl (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt, 1403134Sahl "iscsitgt_zfs_unshare")) == NULL || 1413134Sahl (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt, 1424543Smarks "iscsitgt_zfs_is_shared")) == NULL || 1434543Smarks (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt, 1444543Smarks "iscsitgt_svc_online")) == NULL) { 1453134Sahl iscsitgt_zfs_share = NULL; 1463134Sahl iscsitgt_zfs_unshare = NULL; 1473134Sahl iscsitgt_zfs_is_shared = NULL; 1484543Smarks iscsitgt_svc_online = NULL; 1493134Sahl } 1503134Sahl } 1513134Sahl 152789Sahrens /* 1535331Samw * Search the sharetab for the given mountpoint and protocol, returning 1545331Samw * a zfs_share_type_t value. 155789Sahrens */ 1565331Samw static zfs_share_type_t 1575331Samw is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto) 158789Sahrens { 159789Sahrens char buf[MAXPATHLEN], *tab; 1605331Samw char *ptr; 161789Sahrens 1622082Seschrock if (hdl->libzfs_sharetab == NULL) 1635331Samw return (SHARED_NOT_SHARED); 164789Sahrens 1652082Seschrock (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); 166789Sahrens 1672082Seschrock while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { 168789Sahrens 169789Sahrens /* the mountpoint is the first entry on each line */ 1705331Samw if ((tab = strchr(buf, '\t')) == NULL) 1715331Samw continue; 1725331Samw 1735331Samw *tab = '\0'; 1745331Samw if (strcmp(buf, mountpoint) == 0) { 1755331Samw /* 1765331Samw * the protocol field is the third field 1775331Samw * skip over second field 1785331Samw */ 1795331Samw ptr = ++tab; 1805331Samw if ((tab = strchr(ptr, '\t')) == NULL) 1815331Samw continue; 1825331Samw ptr = ++tab; 1835331Samw if ((tab = strchr(ptr, '\t')) == NULL) 1845331Samw continue; 185789Sahrens *tab = '\0'; 1865331Samw if (strcmp(ptr, 1875331Samw proto_table[proto].p_name) == 0) { 1885331Samw switch (proto) { 1895331Samw case PROTO_NFS: 1905331Samw return (SHARED_NFS); 1915331Samw case PROTO_SMB: 1925331Samw return (SHARED_SMB); 1935331Samw default: 1945331Samw return (0); 1955331Samw } 1965331Samw } 197789Sahrens } 198789Sahrens } 199789Sahrens 2005331Samw return (SHARED_NOT_SHARED); 201789Sahrens } 202789Sahrens 203789Sahrens /* 2042082Seschrock * Returns true if the specified directory is empty. If we can't open the 2052082Seschrock * directory at all, return true so that the mount can fail with a more 206789Sahrens * informative error message. 207789Sahrens */ 2082082Seschrock static boolean_t 209789Sahrens dir_is_empty(const char *dirname) 210789Sahrens { 211789Sahrens DIR *dirp; 212789Sahrens struct dirent64 *dp; 213789Sahrens 214789Sahrens if ((dirp = opendir(dirname)) == NULL) 2152082Seschrock return (B_TRUE); 216789Sahrens 217789Sahrens while ((dp = readdir64(dirp)) != NULL) { 218789Sahrens 219789Sahrens if (strcmp(dp->d_name, ".") == 0 || 220789Sahrens strcmp(dp->d_name, "..") == 0) 221789Sahrens continue; 222789Sahrens 223789Sahrens (void) closedir(dirp); 2242082Seschrock return (B_FALSE); 225789Sahrens } 226789Sahrens 227789Sahrens (void) closedir(dirp); 2282082Seschrock return (B_TRUE); 229789Sahrens } 230789Sahrens 231789Sahrens /* 232789Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill 233789Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return 234789Sahrens * 0. 235789Sahrens */ 2362082Seschrock boolean_t 2373444Sek110237 is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where) 238789Sahrens { 239789Sahrens struct mnttab search = { 0 }, entry; 240789Sahrens 241789Sahrens /* 242789Sahrens * Search for the entry in /etc/mnttab. We don't bother getting the 243789Sahrens * mountpoint, as we can just search for the special device. This will 244789Sahrens * also let us find mounts when the mountpoint is 'legacy'. 245789Sahrens */ 2463444Sek110237 search.mnt_special = (char *)special; 2471407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 248789Sahrens 2493444Sek110237 rewind(zfs_hdl->libzfs_mnttab); 2503444Sek110237 if (getmntany(zfs_hdl->libzfs_mnttab, &entry, &search) != 0) 2512082Seschrock return (B_FALSE); 252789Sahrens 253789Sahrens if (where != NULL) 2543444Sek110237 *where = zfs_strdup(zfs_hdl, entry.mnt_mountp); 255789Sahrens 2562082Seschrock return (B_TRUE); 257789Sahrens } 258789Sahrens 2593444Sek110237 boolean_t 2603444Sek110237 zfs_is_mounted(zfs_handle_t *zhp, char **where) 2613444Sek110237 { 2623444Sek110237 return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where)); 2633444Sek110237 } 2643444Sek110237 265789Sahrens /* 2662676Seschrock * Returns true if the given dataset is mountable, false otherwise. Returns the 2672676Seschrock * mountpoint in 'buf'. 2682676Seschrock */ 2692676Seschrock static boolean_t 2702676Seschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, 2715094Slling zprop_source_t *source) 2722676Seschrock { 2732676Seschrock char sourceloc[ZFS_MAXNAMELEN]; 2745094Slling zprop_source_t sourcetype; 2752676Seschrock 2762676Seschrock if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type)) 2772676Seschrock return (B_FALSE); 2782676Seschrock 2792676Seschrock verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen, 2802676Seschrock &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0); 2812676Seschrock 2822676Seschrock if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 || 2832676Seschrock strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0) 2842676Seschrock return (B_FALSE); 2852676Seschrock 2866168Shs24103 if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF) 2872676Seschrock return (B_FALSE); 2882676Seschrock 2892676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) && 2902676Seschrock getzoneid() == GLOBAL_ZONEID) 2912676Seschrock return (B_FALSE); 2922676Seschrock 2932676Seschrock if (source) 2942676Seschrock *source = sourcetype; 2952676Seschrock 2962676Seschrock return (B_TRUE); 2972676Seschrock } 2982676Seschrock 2992676Seschrock /* 300789Sahrens * Mount the given filesystem. 301789Sahrens */ 302789Sahrens int 303789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 304789Sahrens { 305789Sahrens struct stat buf; 306789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 307789Sahrens char mntopts[MNT_LINE_MAX]; 3082082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 309789Sahrens 310789Sahrens if (options == NULL) 311789Sahrens mntopts[0] = '\0'; 312789Sahrens else 313789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 314789Sahrens 3152676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 3162082Seschrock return (0); 317789Sahrens 318789Sahrens /* Create the directory if it doesn't already exist */ 319789Sahrens if (lstat(mountpoint, &buf) != 0) { 320789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 3212082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3222082Seschrock "failed to create mountpoint")); 3233237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3242082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 3252082Seschrock mountpoint)); 326789Sahrens } 327789Sahrens } 328789Sahrens 329789Sahrens /* 330789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 331789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 332789Sahrens * would defeat the point. We also avoid this check if 'remount' is 333789Sahrens * specified. 334789Sahrens */ 335789Sahrens if ((flags & MS_OVERLAY) == 0 && 336789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 337789Sahrens !dir_is_empty(mountpoint)) { 3382082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3392082Seschrock "directory is not empty")); 3403237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3412082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint)); 342789Sahrens } 343789Sahrens 344789Sahrens /* perform the mount */ 345789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 346789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 347789Sahrens /* 348789Sahrens * Generic errors are nasty, but there are just way too many 349789Sahrens * from mount(), and they're well-understood. We pick a few 350789Sahrens * common ones to improve upon. 351789Sahrens */ 3524302Sdougm if (errno == EBUSY) { 3532082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3542082Seschrock "mountpoint or dataset is busy")); 3554543Smarks } else if (errno == EPERM) { 3564543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3574543Smarks "Insufficient privileges")); 3584302Sdougm } else { 3592082Seschrock zfs_error_aux(hdl, strerror(errno)); 3604302Sdougm } 3612082Seschrock 3623237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3632082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 3642082Seschrock zhp->zfs_name)); 365789Sahrens } 366789Sahrens 367789Sahrens return (0); 368789Sahrens } 369789Sahrens 370789Sahrens /* 3712474Seschrock * Unmount a single filesystem. 3722474Seschrock */ 3732474Seschrock static int 3742474Seschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) 3752474Seschrock { 3762474Seschrock if (umount2(mountpoint, flags) != 0) { 3772474Seschrock zfs_error_aux(hdl, strerror(errno)); 3783237Slling return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED, 3792474Seschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), 3802474Seschrock mountpoint)); 3812474Seschrock } 3822474Seschrock 3832474Seschrock return (0); 3842474Seschrock } 3852474Seschrock 3862474Seschrock /* 387789Sahrens * Unmount the given filesystem. 388789Sahrens */ 389789Sahrens int 390789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 391789Sahrens { 392789Sahrens struct mnttab search = { 0 }, entry; 3934180Sdougm char *mntpt = NULL; 394789Sahrens 395789Sahrens /* check to see if need to unmount the filesystem */ 3962474Seschrock search.mnt_special = zhp->zfs_name; 3971407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 3982082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 399789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 4002082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 401789Sahrens 4024180Sdougm /* 4034180Sdougm * mountpoint may have come from a call to 4044180Sdougm * getmnt/getmntany if it isn't NULL. If it is NULL, 4054180Sdougm * we know it comes from getmntany which can then get 4064180Sdougm * overwritten later. We strdup it to play it safe. 4074180Sdougm */ 408789Sahrens if (mountpoint == NULL) 4094302Sdougm mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 4104180Sdougm else 4114302Sdougm mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); 412789Sahrens 413789Sahrens /* 4142474Seschrock * Unshare and unmount the filesystem 415789Sahrens */ 4165331Samw if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) 4174331Sth199096 return (-1); 4184331Sth199096 4194331Sth199096 if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) { 4204180Sdougm free(mntpt); 4215331Samw (void) zfs_shareall(zhp); 422789Sahrens return (-1); 4234180Sdougm } 4244180Sdougm free(mntpt); 425789Sahrens } 426789Sahrens 427789Sahrens return (0); 428789Sahrens } 429789Sahrens 430789Sahrens /* 431789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 432789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 433789Sahrens * remount the filesystems afterwards. 434789Sahrens */ 435789Sahrens int 436789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 437789Sahrens { 438789Sahrens prop_changelist_t *clp; 439789Sahrens int ret; 440789Sahrens 441*7366STim.Haley@Sun.COM clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags); 442789Sahrens if (clp == NULL) 443789Sahrens return (-1); 444789Sahrens 445789Sahrens ret = changelist_prefix(clp); 446789Sahrens changelist_free(clp); 447789Sahrens 448789Sahrens return (ret); 449789Sahrens } 450789Sahrens 4513126Sahl boolean_t 4523126Sahl zfs_is_shared(zfs_handle_t *zhp) 4533126Sahl { 4545331Samw zfs_share_type_t rc = 0; 4555331Samw zfs_share_proto_t *curr_proto; 4565331Samw 4573126Sahl if (ZFS_IS_VOLUME(zhp)) 4583126Sahl return (zfs_is_shared_iscsi(zhp)); 4593126Sahl 4605331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 4615331Samw curr_proto++) 4625331Samw rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto); 4635331Samw 4645331Samw return (rc ? B_TRUE : B_FALSE); 4653126Sahl } 4663126Sahl 4673126Sahl int 4683126Sahl zfs_share(zfs_handle_t *zhp) 4693126Sahl { 4703126Sahl if (ZFS_IS_VOLUME(zhp)) 4713126Sahl return (zfs_share_iscsi(zhp)); 4723126Sahl 4735331Samw return (zfs_share_proto(zhp, share_all_proto)); 4743126Sahl } 4753126Sahl 4763126Sahl int 4773126Sahl zfs_unshare(zfs_handle_t *zhp) 4783126Sahl { 4793126Sahl if (ZFS_IS_VOLUME(zhp)) 4803126Sahl return (zfs_unshare_iscsi(zhp)); 4813126Sahl 4825331Samw return (zfs_unshareall(zhp)); 4833126Sahl } 4843126Sahl 485789Sahrens /* 486789Sahrens * Check to see if the filesystem is currently shared. 487789Sahrens */ 4885331Samw zfs_share_type_t 4895331Samw zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto) 490789Sahrens { 491789Sahrens char *mountpoint; 4925331Samw zfs_share_type_t rc; 493789Sahrens 494789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 4955331Samw return (SHARED_NOT_SHARED); 496789Sahrens 4975331Samw if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) { 498789Sahrens if (where != NULL) 499789Sahrens *where = mountpoint; 500789Sahrens else 501789Sahrens free(mountpoint); 5025331Samw return (rc); 503789Sahrens } else { 504789Sahrens free(mountpoint); 5055331Samw return (SHARED_NOT_SHARED); 506789Sahrens } 507789Sahrens } 508789Sahrens 5095331Samw boolean_t 5105331Samw zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) 5115331Samw { 5125331Samw return (zfs_is_shared_proto(zhp, where, 5135331Samw PROTO_NFS) != SHARED_NOT_SHARED); 5145331Samw } 5155331Samw 5165331Samw boolean_t 5175331Samw zfs_is_shared_smb(zfs_handle_t *zhp, char **where) 5185331Samw { 5195331Samw return (zfs_is_shared_proto(zhp, where, 5205331Samw PROTO_SMB) != SHARED_NOT_SHARED); 5215331Samw } 5225331Samw 523789Sahrens /* 5244180Sdougm * Make sure things will work if libshare isn't installed by using 5254180Sdougm * wrapper functions that check to see that the pointers to functions 5264180Sdougm * initialized in _zfs_init_libshare() are actually present. 5274180Sdougm */ 5284180Sdougm 5294180Sdougm static sa_handle_t (*_sa_init)(int); 5304180Sdougm static void (*_sa_fini)(sa_handle_t); 5314180Sdougm static sa_share_t (*_sa_find_share)(sa_handle_t, char *); 5324180Sdougm static int (*_sa_enable_share)(sa_share_t, char *); 5334180Sdougm static int (*_sa_disable_share)(sa_share_t, char *); 5344180Sdougm static char *(*_sa_errorstr)(int); 5354180Sdougm static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *); 5365951Sdougm static boolean_t (*_sa_needs_refresh)(sa_handle_t *); 5375951Sdougm static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t); 5385951Sdougm static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t, 5395951Sdougm char *, char *, zprop_source_t, char *, char *, char *); 5405951Sdougm static void (*_sa_update_sharetab_ts)(sa_handle_t); 5414180Sdougm 5424180Sdougm /* 5434180Sdougm * _zfs_init_libshare() 5444180Sdougm * 5454180Sdougm * Find the libshare.so.1 entry points that we use here and save the 5464180Sdougm * values to be used later. This is triggered by the runtime loader. 5474180Sdougm * Make sure the correct ISA version is loaded. 5484180Sdougm */ 5495951Sdougm 5504180Sdougm #pragma init(_zfs_init_libshare) 5514180Sdougm static void 5524180Sdougm _zfs_init_libshare(void) 5534180Sdougm { 5544180Sdougm void *libshare; 5554180Sdougm char path[MAXPATHLEN]; 5564180Sdougm char isa[MAXISALEN]; 5574180Sdougm 5584180Sdougm #if defined(_LP64) 5594180Sdougm if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1) 5604302Sdougm isa[0] = '\0'; 5614180Sdougm #else 5624180Sdougm isa[0] = '\0'; 5634180Sdougm #endif 5644180Sdougm (void) snprintf(path, MAXPATHLEN, 5654302Sdougm "/usr/lib/%s/libshare.so.1", isa); 5664180Sdougm 5674180Sdougm if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) { 5684302Sdougm _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init"); 5694302Sdougm _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini"); 5704302Sdougm _sa_find_share = (sa_share_t (*)(sa_handle_t, char *)) 5714302Sdougm dlsym(libshare, "sa_find_share"); 5724302Sdougm _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5734302Sdougm "sa_enable_share"); 5744302Sdougm _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5754302Sdougm "sa_disable_share"); 5764302Sdougm _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr"); 5774302Sdougm _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *)) 5784302Sdougm dlsym(libshare, "sa_parse_legacy_options"); 5795951Sdougm _sa_needs_refresh = (boolean_t (*)(sa_handle_t *)) 5805951Sdougm dlsym(libshare, "sa_needs_refresh"); 5815951Sdougm _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t)) 5825951Sdougm dlsym(libshare, "sa_get_zfs_handle"); 5835951Sdougm _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t, 5845951Sdougm sa_share_t, char *, char *, zprop_source_t, char *, 5855951Sdougm char *, char *))dlsym(libshare, "sa_zfs_process_share"); 5865951Sdougm _sa_update_sharetab_ts = (void (*)(sa_handle_t)) 5875951Sdougm dlsym(libshare, "sa_update_sharetab_ts"); 5884327Sdougm if (_sa_init == NULL || _sa_fini == NULL || 5894327Sdougm _sa_find_share == NULL || _sa_enable_share == NULL || 5904327Sdougm _sa_disable_share == NULL || _sa_errorstr == NULL || 5915951Sdougm _sa_parse_legacy_options == NULL || 5925951Sdougm _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL || 5935951Sdougm _sa_zfs_process_share == NULL || 5945951Sdougm _sa_update_sharetab_ts == NULL) { 5954327Sdougm _sa_init = NULL; 5964327Sdougm _sa_fini = NULL; 5974327Sdougm _sa_disable_share = NULL; 5984327Sdougm _sa_enable_share = NULL; 5994327Sdougm _sa_errorstr = NULL; 6004327Sdougm _sa_parse_legacy_options = NULL; 6014327Sdougm (void) dlclose(libshare); 6025951Sdougm _sa_needs_refresh = NULL; 6035951Sdougm _sa_get_zfs_handle = NULL; 6045951Sdougm _sa_zfs_process_share = NULL; 6055951Sdougm _sa_update_sharetab_ts = NULL; 6064327Sdougm } 6074180Sdougm } 6084180Sdougm } 6094180Sdougm 6104180Sdougm /* 6114180Sdougm * zfs_init_libshare(zhandle, service) 6124180Sdougm * 6134180Sdougm * Initialize the libshare API if it hasn't already been initialized. 6144180Sdougm * In all cases it returns 0 if it succeeded and an error if not. The 6154180Sdougm * service value is which part(s) of the API to initialize and is a 6164180Sdougm * direct map to the libshare sa_init(service) interface. 6174180Sdougm */ 6184180Sdougm int 6194180Sdougm zfs_init_libshare(libzfs_handle_t *zhandle, int service) 6204180Sdougm { 6214180Sdougm int ret = SA_OK; 6224180Sdougm 6234302Sdougm if (_sa_init == NULL) 6244302Sdougm ret = SA_CONFIG_ERR; 6254302Sdougm 6265951Sdougm if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) { 6275951Sdougm /* 6285951Sdougm * We had a cache miss. Most likely it is a new ZFS 6295951Sdougm * dataset that was just created. We want to make sure 6305951Sdougm * so check timestamps to see if a different process 6315951Sdougm * has updated any of the configuration. If there was 6325951Sdougm * some non-ZFS change, we need to re-initialize the 6335951Sdougm * internal cache. 6345951Sdougm */ 6355951Sdougm zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS; 6365951Sdougm if (_sa_needs_refresh != NULL && 6375951Sdougm _sa_needs_refresh(zhandle->libzfs_sharehdl)) { 6385951Sdougm zfs_uninit_libshare(zhandle); 6395951Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 6405951Sdougm } 6415951Sdougm } 6425951Sdougm 6434302Sdougm if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL) 6444302Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 6454302Sdougm 6464302Sdougm if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL) 6474302Sdougm ret = SA_NO_MEMORY; 6484302Sdougm 6494180Sdougm return (ret); 6504180Sdougm } 6514180Sdougm 6524180Sdougm /* 6534180Sdougm * zfs_uninit_libshare(zhandle) 6544180Sdougm * 6554180Sdougm * Uninitialize the libshare API if it hasn't already been 6564180Sdougm * uninitialized. It is OK to call multiple times. 6574180Sdougm */ 6584180Sdougm void 6594180Sdougm zfs_uninit_libshare(libzfs_handle_t *zhandle) 6604180Sdougm { 6614180Sdougm if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) { 6624302Sdougm if (_sa_fini != NULL) 6634302Sdougm _sa_fini(zhandle->libzfs_sharehdl); 6644302Sdougm zhandle->libzfs_sharehdl = NULL; 6654180Sdougm } 6664180Sdougm } 6674180Sdougm 6684180Sdougm /* 6694180Sdougm * zfs_parse_options(options, proto) 6704180Sdougm * 6714180Sdougm * Call the legacy parse interface to get the protocol specific 6724180Sdougm * options using the NULL arg to indicate that this is a "parse" only. 6734180Sdougm */ 6744180Sdougm int 6755331Samw zfs_parse_options(char *options, zfs_share_proto_t proto) 6764180Sdougm { 6775367Sahrens if (_sa_parse_legacy_options != NULL) { 6785367Sahrens return (_sa_parse_legacy_options(NULL, options, 6795367Sahrens proto_table[proto].p_name)); 6805367Sahrens } 6815367Sahrens return (SA_CONFIG_ERR); 6824180Sdougm } 6834180Sdougm 6844180Sdougm /* 6854180Sdougm * zfs_sa_find_share(handle, path) 6864180Sdougm * 6874180Sdougm * wrapper around sa_find_share to find a share path in the 6884180Sdougm * configuration. 6894180Sdougm */ 6904180Sdougm static sa_share_t 6914180Sdougm zfs_sa_find_share(sa_handle_t handle, char *path) 6924180Sdougm { 6934180Sdougm if (_sa_find_share != NULL) 6944302Sdougm return (_sa_find_share(handle, path)); 6954180Sdougm return (NULL); 6964180Sdougm } 6974180Sdougm 6984180Sdougm /* 6994180Sdougm * zfs_sa_enable_share(share, proto) 7004180Sdougm * 7014180Sdougm * Wrapper for sa_enable_share which enables a share for a specified 7024180Sdougm * protocol. 7034180Sdougm */ 7044180Sdougm static int 7054180Sdougm zfs_sa_enable_share(sa_share_t share, char *proto) 7064180Sdougm { 7074180Sdougm if (_sa_enable_share != NULL) 7084302Sdougm return (_sa_enable_share(share, proto)); 7094180Sdougm return (SA_CONFIG_ERR); 7104180Sdougm } 7114180Sdougm 7124180Sdougm /* 7134180Sdougm * zfs_sa_disable_share(share, proto) 7144180Sdougm * 7154180Sdougm * Wrapper for sa_enable_share which disables a share for a specified 7164180Sdougm * protocol. 7174180Sdougm */ 7184180Sdougm static int 7194180Sdougm zfs_sa_disable_share(sa_share_t share, char *proto) 7204180Sdougm { 7214180Sdougm if (_sa_disable_share != NULL) 7224302Sdougm return (_sa_disable_share(share, proto)); 7234180Sdougm return (SA_CONFIG_ERR); 7244180Sdougm } 7254180Sdougm 7264180Sdougm /* 7275331Samw * Share the given filesystem according to the options in the specified 7285331Samw * protocol specific properties (sharenfs, sharesmb). We rely 7294180Sdougm * on "libshare" to the dirty work for us. 730789Sahrens */ 7315331Samw static int 7325331Samw zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 733789Sahrens { 734789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 735789Sahrens char shareopts[ZFS_MAXPROPLEN]; 7365951Sdougm char sourcestr[ZFS_MAXPROPLEN]; 7372082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 7384180Sdougm sa_share_t share; 7395331Samw zfs_share_proto_t *curr_proto; 7405951Sdougm zprop_source_t sourcetype; 7414180Sdougm int ret; 742789Sahrens 7432676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 744789Sahrens return (0); 745789Sahrens 7464180Sdougm if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 7474302Sdougm (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 7484302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), 7495951Sdougm zfs_get_name(zhp), _sa_errorstr != NULL ? 7505951Sdougm _sa_errorstr(ret) : ""); 7514302Sdougm return (-1); 7524180Sdougm } 7535331Samw 7545331Samw for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { 7555331Samw /* 7565331Samw * Return success if there are no share options. 7575331Samw */ 7585331Samw if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop, 7595951Sdougm shareopts, sizeof (shareopts), &sourcetype, sourcestr, 7605951Sdougm ZFS_MAXPROPLEN, B_FALSE) != 0 || 7615951Sdougm strcmp(shareopts, "off") == 0) 7625331Samw continue; 7635331Samw 7645331Samw /* 7655331Samw * If the 'zoned' property is set, then zfs_is_mountable() 7665331Samw * will have already bailed out if we are in the global zone. 7675331Samw * But local zones cannot be NFS servers, so we ignore it for 7685331Samw * local zones as well. 7695331Samw */ 7705331Samw if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) 7715331Samw continue; 7725331Samw 7735331Samw share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint); 7745951Sdougm if (share == NULL) { 7755951Sdougm /* 7765951Sdougm * This may be a new file system that was just 7775951Sdougm * created so isn't in the internal cache 7785951Sdougm * (second time through). Rather than 7795951Sdougm * reloading the entire configuration, we can 7805951Sdougm * assume ZFS has done the checking and it is 7815951Sdougm * safe to add this to the internal 7825951Sdougm * configuration. 7835951Sdougm */ 7845951Sdougm if (_sa_zfs_process_share(hdl->libzfs_sharehdl, 7855951Sdougm NULL, NULL, mountpoint, 7865951Sdougm proto_table[*curr_proto].p_name, sourcetype, 7875951Sdougm shareopts, sourcestr, zhp->zfs_name) != SA_OK) { 7885951Sdougm (void) zfs_error_fmt(hdl, 7895951Sdougm proto_table[*curr_proto].p_share_err, 7905951Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 7915951Sdougm zfs_get_name(zhp)); 7925951Sdougm return (-1); 7935951Sdougm } 7945951Sdougm hdl->libzfs_shareflags |= ZFSSHARE_MISS; 7955951Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, 7965951Sdougm mountpoint); 7975951Sdougm } 7985331Samw if (share != NULL) { 7995331Samw int err; 8005331Samw err = zfs_sa_enable_share(share, 8015331Samw proto_table[*curr_proto].p_name); 8025331Samw if (err != SA_OK) { 8035331Samw (void) zfs_error_fmt(hdl, 8045331Samw proto_table[*curr_proto].p_share_err, 8055331Samw dgettext(TEXT_DOMAIN, "cannot share '%s'"), 8065331Samw zfs_get_name(zhp)); 8075331Samw return (-1); 8085331Samw } 8095331Samw } else { 8105331Samw (void) zfs_error_fmt(hdl, 8115331Samw proto_table[*curr_proto].p_share_err, 8124302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 8134302Sdougm zfs_get_name(zhp)); 8144302Sdougm return (-1); 8154302Sdougm } 8165331Samw 817789Sahrens } 8185331Samw return (0); 8195331Samw } 820789Sahrens 8215331Samw 8225331Samw int 8235331Samw zfs_share_nfs(zfs_handle_t *zhp) 8245331Samw { 8255331Samw return (zfs_share_proto(zhp, nfs_only)); 8265331Samw } 8275331Samw 8285331Samw int 8295331Samw zfs_share_smb(zfs_handle_t *zhp) 8305331Samw { 8315331Samw return (zfs_share_proto(zhp, smb_only)); 8325331Samw } 8335331Samw 8345331Samw int 8355331Samw zfs_shareall(zfs_handle_t *zhp) 8365331Samw { 8375331Samw return (zfs_share_proto(zhp, share_all_proto)); 838789Sahrens } 839789Sahrens 840789Sahrens /* 8412474Seschrock * Unshare a filesystem by mountpoint. 8422474Seschrock */ 8432474Seschrock static int 8445331Samw unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, 8455331Samw zfs_share_proto_t proto) 8462474Seschrock { 8474180Sdougm sa_share_t share; 8484180Sdougm int err; 8494180Sdougm char *mntpt; 8502474Seschrock /* 8514180Sdougm * Mountpoint could get trashed if libshare calls getmntany 8524180Sdougm * which id does during API initialization, so strdup the 8534180Sdougm * value. 8542474Seschrock */ 8554180Sdougm mntpt = zfs_strdup(hdl, mountpoint); 8562474Seschrock 8574180Sdougm /* make sure libshare initialized */ 8584180Sdougm if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 8594180Sdougm free(mntpt); /* don't need the copy anymore */ 8604180Sdougm return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 8614302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 8624302Sdougm name, _sa_errorstr(err))); 8632474Seschrock } 8642474Seschrock 8654180Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt); 8664180Sdougm free(mntpt); /* don't need the copy anymore */ 8672474Seschrock 8684180Sdougm if (share != NULL) { 8695331Samw err = zfs_sa_disable_share(share, proto_table[proto].p_name); 8704180Sdougm if (err != SA_OK) { 8714302Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8724302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 8734302Sdougm name, _sa_errorstr(err))); 8744180Sdougm } 8754180Sdougm } else { 8764180Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8774302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"), 8784302Sdougm name)); 8794180Sdougm } 8802474Seschrock return (0); 8812474Seschrock } 8822474Seschrock 8832474Seschrock /* 884789Sahrens * Unshare the given filesystem. 885789Sahrens */ 886789Sahrens int 8875331Samw zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, 8885331Samw zfs_share_proto_t *proto) 889789Sahrens { 890789Sahrens struct mnttab search = { 0 }, entry; 8914180Sdougm char *mntpt = NULL; 892789Sahrens 893789Sahrens /* check to see if need to unmount the filesystem */ 894789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 8951407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 8962082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 8974302Sdougm if (mountpoint != NULL) 8985331Samw mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); 8994302Sdougm 900789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 9012082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 9025331Samw zfs_share_proto_t *curr_proto; 903789Sahrens 904789Sahrens if (mountpoint == NULL) 9055331Samw mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 9065331Samw 9075331Samw for (curr_proto = proto; *curr_proto != PROTO_END; 9085331Samw curr_proto++) { 909789Sahrens 9105331Samw if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) && 9115331Samw unshare_one(zhp->zfs_hdl, zhp->zfs_name, 9125331Samw mntpt, *curr_proto) != 0) { 9135331Samw if (mntpt != NULL) 9145331Samw free(mntpt); 9155331Samw return (-1); 9165331Samw } 9174180Sdougm } 918789Sahrens } 9194180Sdougm if (mntpt != NULL) 9204302Sdougm free(mntpt); 921789Sahrens 922789Sahrens return (0); 923789Sahrens } 924789Sahrens 9255331Samw int 9265331Samw zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) 9275331Samw { 9285331Samw return (zfs_unshare_proto(zhp, mountpoint, nfs_only)); 9295331Samw } 9305331Samw 9315331Samw int 9325331Samw zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint) 9335331Samw { 9345331Samw return (zfs_unshare_proto(zhp, mountpoint, smb_only)); 9355331Samw } 9365331Samw 937789Sahrens /* 9385331Samw * Same as zfs_unmountall(), but for NFS and SMB unshares. 939789Sahrens */ 940789Sahrens int 9415331Samw zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 942789Sahrens { 943789Sahrens prop_changelist_t *clp; 944789Sahrens int ret; 945789Sahrens 946*7366STim.Haley@Sun.COM clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0); 947789Sahrens if (clp == NULL) 948789Sahrens return (-1); 949789Sahrens 9505331Samw ret = changelist_unshare(clp, proto); 951789Sahrens changelist_free(clp); 952789Sahrens 953789Sahrens return (ret); 954789Sahrens } 955789Sahrens 9565331Samw int 9575331Samw zfs_unshareall_nfs(zfs_handle_t *zhp) 9585331Samw { 9595331Samw return (zfs_unshareall_proto(zhp, nfs_only)); 9605331Samw } 9615331Samw 9625331Samw int 9635331Samw zfs_unshareall_smb(zfs_handle_t *zhp) 9645331Samw { 9655331Samw return (zfs_unshareall_proto(zhp, smb_only)); 9665331Samw } 9675331Samw 9685331Samw int 9695331Samw zfs_unshareall(zfs_handle_t *zhp) 9705331Samw { 9715331Samw return (zfs_unshareall_proto(zhp, share_all_proto)); 9725331Samw } 9735331Samw 9745331Samw int 9755331Samw zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint) 9765331Samw { 9775331Samw return (zfs_unshare_proto(zhp, mountpoint, share_all_proto)); 9785331Samw } 9795331Samw 980789Sahrens /* 981789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 982789Sahrens * We only remove the underlying directory if: 983789Sahrens * 984789Sahrens * - The mountpoint is not 'none' or 'legacy' 985789Sahrens * - The mountpoint is non-empty 986789Sahrens * - The mountpoint is the default or inherited 987789Sahrens * - The 'zoned' property is set, or we're in a local zone 988789Sahrens * 989789Sahrens * Any other directories we leave alone. 990789Sahrens */ 991789Sahrens void 992789Sahrens remove_mountpoint(zfs_handle_t *zhp) 993789Sahrens { 994789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 9955094Slling zprop_source_t source; 996789Sahrens 9972676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), 9982676Seschrock &source)) 999789Sahrens return; 1000789Sahrens 10015094Slling if (source == ZPROP_SRC_DEFAULT || 10025094Slling source == ZPROP_SRC_INHERITED) { 1003789Sahrens /* 1004789Sahrens * Try to remove the directory, silently ignoring any errors. 1005789Sahrens * The filesystem may have since been removed or moved around, 10062676Seschrock * and this error isn't really useful to the administrator in 10072676Seschrock * any way. 1008789Sahrens */ 1009789Sahrens (void) rmdir(mountpoint); 1010789Sahrens } 1011789Sahrens } 10122474Seschrock 10133126Sahl boolean_t 10143126Sahl zfs_is_shared_iscsi(zfs_handle_t *zhp) 10153126Sahl { 10164543Smarks 10174543Smarks /* 10184543Smarks * If iscsi deamon isn't running then we aren't shared 10194543Smarks */ 10204543Smarks if (iscsitgt_svc_online && iscsitgt_svc_online() == 1) 10215331Samw return (B_FALSE); 10224543Smarks else 10234543Smarks return (iscsitgt_zfs_is_shared != NULL && 10244543Smarks iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); 10253126Sahl } 10263126Sahl 10273126Sahl int 10283126Sahl zfs_share_iscsi(zfs_handle_t *zhp) 10293126Sahl { 10303126Sahl char shareopts[ZFS_MAXPROPLEN]; 10313126Sahl const char *dataset = zhp->zfs_name; 10323126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 10333126Sahl 10343126Sahl /* 10353126Sahl * Return success if there are no share options. 10363126Sahl */ 10373126Sahl if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 10383126Sahl sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || 10393126Sahl strcmp(shareopts, "off") == 0) 10403126Sahl return (0); 10413126Sahl 10424543Smarks if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) { 10434543Smarks int error = EZFS_SHAREISCSIFAILED; 10444543Smarks 10454543Smarks /* 10464543Smarks * If service isn't availabele and EPERM was 10474543Smarks * returned then use special error. 10484543Smarks */ 10494543Smarks if (iscsitgt_svc_online && errno == EPERM && 10504543Smarks (iscsitgt_svc_online() != 0)) 10514543Smarks error = EZFS_ISCSISVCUNAVAIL; 10524543Smarks 10534543Smarks return (zfs_error_fmt(hdl, error, 10543126Sahl dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); 10554543Smarks } 10563126Sahl 10573126Sahl return (0); 10583126Sahl } 10593126Sahl 10603126Sahl int 10613126Sahl zfs_unshare_iscsi(zfs_handle_t *zhp) 10623126Sahl { 10633126Sahl const char *dataset = zfs_get_name(zhp); 10643126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 10653126Sahl 10663126Sahl /* 10673380Sgw25295 * Return if the volume is not shared 10683380Sgw25295 */ 10695331Samw if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI) 10703380Sgw25295 return (0); 10713380Sgw25295 10723380Sgw25295 /* 10733126Sahl * If this fails with ENODEV it indicates that zvol wasn't shared so 10743126Sahl * we should return success in that case. 10753126Sahl */ 10763134Sahl if (iscsitgt_zfs_unshare == NULL || 10774543Smarks (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) { 10784543Smarks if (errno == EPERM) 10794543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10804543Smarks "Insufficient privileges to unshare iscsi")); 10813237Slling return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, 10823126Sahl dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); 10834543Smarks } 10843126Sahl 10853126Sahl return (0); 10863126Sahl } 10873126Sahl 10882474Seschrock typedef struct mount_cbdata { 10892474Seschrock zfs_handle_t **cb_datasets; 10902474Seschrock int cb_used; 10912474Seschrock int cb_alloc; 10922474Seschrock } mount_cbdata_t; 10932474Seschrock 10942474Seschrock static int 10952474Seschrock mount_cb(zfs_handle_t *zhp, void *data) 10962474Seschrock { 10972474Seschrock mount_cbdata_t *cbp = data; 10982474Seschrock 10993126Sahl if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { 11002474Seschrock zfs_close(zhp); 11012474Seschrock return (0); 11022474Seschrock } 11032474Seschrock 11046168Shs24103 if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) { 11056168Shs24103 zfs_close(zhp); 11066168Shs24103 return (0); 11076168Shs24103 } 11086168Shs24103 11092474Seschrock if (cbp->cb_alloc == cbp->cb_used) { 11102676Seschrock void *ptr; 11112474Seschrock 11122676Seschrock if ((ptr = zfs_realloc(zhp->zfs_hdl, 11132676Seschrock cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), 11142676Seschrock cbp->cb_alloc * 2 * sizeof (void *))) == NULL) 11152474Seschrock return (-1); 11162676Seschrock cbp->cb_datasets = ptr; 11172474Seschrock 11182676Seschrock cbp->cb_alloc *= 2; 11192474Seschrock } 11202474Seschrock 11212474Seschrock cbp->cb_datasets[cbp->cb_used++] = zhp; 11223126Sahl 11236027Srm160521 return (zfs_iter_filesystems(zhp, mount_cb, cbp)); 11242474Seschrock } 11252474Seschrock 11262474Seschrock static int 11273126Sahl dataset_cmp(const void *a, const void *b) 11282474Seschrock { 11292474Seschrock zfs_handle_t **za = (zfs_handle_t **)a; 11302474Seschrock zfs_handle_t **zb = (zfs_handle_t **)b; 11312474Seschrock char mounta[MAXPATHLEN]; 11322474Seschrock char mountb[MAXPATHLEN]; 11333126Sahl boolean_t gota, gotb; 11342474Seschrock 11353126Sahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 11363126Sahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 11373126Sahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 11383126Sahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 11393126Sahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 11403126Sahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 11412474Seschrock 11423126Sahl if (gota && gotb) 11433126Sahl return (strcmp(mounta, mountb)); 11443126Sahl 11453126Sahl if (gota) 11463126Sahl return (-1); 11473126Sahl if (gotb) 11483126Sahl return (1); 11493126Sahl 11503126Sahl return (strcmp(zfs_get_name(a), zfs_get_name(b))); 11512474Seschrock } 11522474Seschrock 11533126Sahl /* 11543126Sahl * Mount and share all datasets within the given pool. This assumes that no 11553126Sahl * datasets within the pool are currently mounted. Because users can create 11563126Sahl * complicated nested hierarchies of mountpoints, we first gather all the 11573126Sahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once 11583126Sahl * we have the list of all filesystems, we iterate over them in order and mount 11593126Sahl * and/or share each one. 11603126Sahl */ 11613126Sahl #pragma weak zpool_mount_datasets = zpool_enable_datasets 11622474Seschrock int 11633126Sahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) 11642474Seschrock { 11652474Seschrock mount_cbdata_t cb = { 0 }; 11662474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 11672474Seschrock zfs_handle_t *zfsp; 11682474Seschrock int i, ret = -1; 11694180Sdougm int *good; 11702474Seschrock 11712474Seschrock /* 11726027Srm160521 * Gather all non-snap datasets within the pool. 11732474Seschrock */ 11742474Seschrock if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) 11752474Seschrock return (-1); 11762474Seschrock cb.cb_alloc = 4; 11772474Seschrock 11785094Slling if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL) 11792474Seschrock goto out; 11802474Seschrock 11812474Seschrock cb.cb_datasets[0] = zfsp; 11822474Seschrock cb.cb_used = 1; 11832474Seschrock 11846027Srm160521 if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0) 11852474Seschrock goto out; 11862474Seschrock 11872474Seschrock /* 11882474Seschrock * Sort the datasets by mountpoint. 11892474Seschrock */ 11903126Sahl qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); 11912474Seschrock 11922474Seschrock /* 11934180Sdougm * And mount all the datasets, keeping track of which ones 11944180Sdougm * succeeded or failed. By using zfs_alloc(), the good pointer 11954180Sdougm * will always be non-NULL. 11962474Seschrock */ 11974180Sdougm good = zfs_alloc(zhp->zpool_hdl, cb.cb_used * sizeof (int)); 11982474Seschrock ret = 0; 11992474Seschrock for (i = 0; i < cb.cb_used; i++) { 12004302Sdougm if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0) 12014180Sdougm ret = -1; 12024302Sdougm else 12034180Sdougm good[i] = 1; 12044180Sdougm } 12055951Sdougm 12064180Sdougm /* 12074180Sdougm * Then share all the ones that need to be shared. This needs 12084180Sdougm * to be a separate pass in order to avoid excessive reloading 12094180Sdougm * of the configuration. Good should never be NULL since 12104180Sdougm * zfs_alloc is supposed to exit if memory isn't available. 12114180Sdougm */ 12124180Sdougm for (i = 0; i < cb.cb_used; i++) { 12134180Sdougm if (good[i] && zfs_share(cb.cb_datasets[i]) != 0) 12142474Seschrock ret = -1; 12152474Seschrock } 12162474Seschrock 12174180Sdougm free(good); 12184180Sdougm 12192474Seschrock out: 12202474Seschrock for (i = 0; i < cb.cb_used; i++) 12212474Seschrock zfs_close(cb.cb_datasets[i]); 12222474Seschrock free(cb.cb_datasets); 12232474Seschrock 12242474Seschrock return (ret); 12252474Seschrock } 12262474Seschrock 12273126Sahl 12283126Sahl static int 12293126Sahl zvol_cb(const char *dataset, void *data) 12303126Sahl { 12313126Sahl libzfs_handle_t *hdl = data; 12323126Sahl zfs_handle_t *zhp; 12333126Sahl 12343126Sahl /* 12353126Sahl * Ignore snapshots and ignore failures from non-existant datasets. 12363126Sahl */ 12373126Sahl if (strchr(dataset, '@') != NULL || 12383126Sahl (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL) 12393126Sahl return (0); 12403126Sahl 12414543Smarks if (zfs_unshare_iscsi(zhp) != 0) 12424543Smarks return (-1); 12433126Sahl 12443126Sahl zfs_close(zhp); 12453126Sahl 12463126Sahl return (0); 12473126Sahl } 12483126Sahl 12492474Seschrock static int 12502474Seschrock mountpoint_compare(const void *a, const void *b) 12512474Seschrock { 12522474Seschrock const char *mounta = *((char **)a); 12532474Seschrock const char *mountb = *((char **)b); 12542474Seschrock 12552474Seschrock return (strcmp(mountb, mounta)); 12562474Seschrock } 12572474Seschrock 12583126Sahl /* 12593126Sahl * Unshare and unmount all datasets within the given pool. We don't want to 12603126Sahl * rely on traversing the DSL to discover the filesystems within the pool, 12613126Sahl * because this may be expensive (if not all of them are mounted), and can fail 12623126Sahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and 12633126Sahl * gather all the filesystems that are currently mounted. 12643126Sahl */ 12653126Sahl #pragma weak zpool_unmount_datasets = zpool_disable_datasets 12662474Seschrock int 12673126Sahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) 12682474Seschrock { 12692474Seschrock int used, alloc; 12702474Seschrock struct mnttab entry; 12712474Seschrock size_t namelen; 12722474Seschrock char **mountpoints = NULL; 12732474Seschrock zfs_handle_t **datasets = NULL; 12742474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 12752474Seschrock int i; 12762474Seschrock int ret = -1; 12772474Seschrock int flags = (force ? MS_FORCE : 0); 12782474Seschrock 12793126Sahl /* 12803126Sahl * First unshare all zvols. 12813126Sahl */ 12823126Sahl if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0) 12833126Sahl return (-1); 12843126Sahl 12852474Seschrock namelen = strlen(zhp->zpool_name); 12862474Seschrock 12872474Seschrock rewind(hdl->libzfs_mnttab); 12882474Seschrock used = alloc = 0; 12892474Seschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 12902474Seschrock /* 12912474Seschrock * Ignore non-ZFS entries. 12922474Seschrock */ 12932474Seschrock if (entry.mnt_fstype == NULL || 12942474Seschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 12952474Seschrock continue; 12962474Seschrock 12972474Seschrock /* 12982474Seschrock * Ignore filesystems not within this pool. 12992474Seschrock */ 13002474Seschrock if (entry.mnt_mountp == NULL || 13012474Seschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 || 13022474Seschrock (entry.mnt_special[namelen] != '/' && 13032474Seschrock entry.mnt_special[namelen] != '\0')) 13042474Seschrock continue; 13052474Seschrock 13062474Seschrock /* 13072474Seschrock * At this point we've found a filesystem within our pool. Add 13082474Seschrock * it to our growing list. 13092474Seschrock */ 13102474Seschrock if (used == alloc) { 13112474Seschrock if (alloc == 0) { 13122474Seschrock if ((mountpoints = zfs_alloc(hdl, 13132474Seschrock 8 * sizeof (void *))) == NULL) 13142474Seschrock goto out; 13152474Seschrock 13162474Seschrock if ((datasets = zfs_alloc(hdl, 13172474Seschrock 8 * sizeof (void *))) == NULL) 13182474Seschrock goto out; 13192474Seschrock 13202474Seschrock alloc = 8; 13212474Seschrock } else { 13222676Seschrock void *ptr; 13232474Seschrock 13242676Seschrock if ((ptr = zfs_realloc(hdl, mountpoints, 13252676Seschrock alloc * sizeof (void *), 13262474Seschrock alloc * 2 * sizeof (void *))) == NULL) 13272474Seschrock goto out; 13282676Seschrock mountpoints = ptr; 13292474Seschrock 13302676Seschrock if ((ptr = zfs_realloc(hdl, datasets, 13312676Seschrock alloc * sizeof (void *), 13322474Seschrock alloc * 2 * sizeof (void *))) == NULL) 13332474Seschrock goto out; 13342676Seschrock datasets = ptr; 13352474Seschrock 13362474Seschrock alloc *= 2; 13372474Seschrock } 13382474Seschrock } 13392474Seschrock 13402474Seschrock if ((mountpoints[used] = zfs_strdup(hdl, 13412474Seschrock entry.mnt_mountp)) == NULL) 13422474Seschrock goto out; 13432474Seschrock 13442474Seschrock /* 13452474Seschrock * This is allowed to fail, in case there is some I/O error. It 13462474Seschrock * is only used to determine if we need to remove the underlying 13472474Seschrock * mountpoint, so failure is not fatal. 13482474Seschrock */ 13492474Seschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special); 13502474Seschrock 13512474Seschrock used++; 13522474Seschrock } 13532474Seschrock 13542474Seschrock /* 13552474Seschrock * At this point, we have the entire list of filesystems, so sort it by 13562474Seschrock * mountpoint. 13572474Seschrock */ 13582474Seschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare); 13592474Seschrock 13602474Seschrock /* 13612474Seschrock * Walk through and first unshare everything. 13622474Seschrock */ 13632474Seschrock for (i = 0; i < used; i++) { 13645331Samw zfs_share_proto_t *curr_proto; 13655331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 13665331Samw curr_proto++) { 13675331Samw if (is_shared(hdl, mountpoints[i], *curr_proto) && 13685331Samw unshare_one(hdl, mountpoints[i], 13695331Samw mountpoints[i], *curr_proto) != 0) 13705331Samw goto out; 13715331Samw } 13722474Seschrock } 13732474Seschrock 13742474Seschrock /* 13752474Seschrock * Now unmount everything, removing the underlying directories as 13762474Seschrock * appropriate. 13772474Seschrock */ 13782474Seschrock for (i = 0; i < used; i++) { 13792474Seschrock if (unmount_one(hdl, mountpoints[i], flags) != 0) 13802474Seschrock goto out; 13812676Seschrock } 13822474Seschrock 13832676Seschrock for (i = 0; i < used; i++) { 13842474Seschrock if (datasets[i]) 13852474Seschrock remove_mountpoint(datasets[i]); 13862474Seschrock } 13872474Seschrock 13882474Seschrock ret = 0; 13892474Seschrock out: 13902474Seschrock for (i = 0; i < used; i++) { 13912474Seschrock if (datasets[i]) 13922474Seschrock zfs_close(datasets[i]); 13932474Seschrock free(mountpoints[i]); 13942474Seschrock } 13952474Seschrock free(datasets); 13962474Seschrock free(mountpoints); 13972474Seschrock 13982474Seschrock return (ret); 13992474Seschrock } 1400