1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 213126Sahl 22789Sahrens /* 23*5951Sdougm * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28789Sahrens 29789Sahrens /* 30789Sahrens * Routines to manage ZFS mounts. We separate all the nasty routines that have 313126Sahl * to deal with the OS. The following functions are the main entry points -- 323126Sahl * they are used by mount and unmount and when changing a filesystem's 333126Sahl * mountpoint. 34789Sahrens * 35789Sahrens * zfs_is_mounted() 36789Sahrens * zfs_mount() 37789Sahrens * zfs_unmount() 38789Sahrens * zfs_unmountall() 39789Sahrens * 403126Sahl * This file also contains the functions used to manage sharing filesystems via 413126Sahl * NFS and iSCSI: 42789Sahrens * 43789Sahrens * zfs_is_shared() 44789Sahrens * zfs_share() 45789Sahrens * zfs_unshare() 463126Sahl * 473126Sahl * zfs_is_shared_nfs() 485331Samw * zfs_is_shared_smb() 495331Samw * zfs_is_shared_iscsi() 505331Samw * zfs_share_proto() 515331Samw * zfs_shareall(); 525331Samw * zfs_share_iscsi() 533126Sahl * zfs_unshare_nfs() 545331Samw * zfs_unshare_smb() 553126Sahl * zfs_unshareall_nfs() 565331Samw * zfs_unshareall_smb() 575331Samw * zfs_unshareall() 585331Samw * zfs_unshareall_bypath() 593126Sahl * zfs_unshare_iscsi() 602474Seschrock * 612474Seschrock * The following functions are available for pool consumers, and will 623126Sahl * mount/unmount and share/unshare all datasets within pool: 632474Seschrock * 643126Sahl * zpool_enable_datasets() 653126Sahl * zpool_disable_datasets() 66789Sahrens */ 67789Sahrens 68789Sahrens #include <dirent.h> 693134Sahl #include <dlfcn.h> 70789Sahrens #include <errno.h> 71789Sahrens #include <libgen.h> 72789Sahrens #include <libintl.h> 73789Sahrens #include <stdio.h> 74789Sahrens #include <stdlib.h> 75789Sahrens #include <strings.h> 76789Sahrens #include <unistd.h> 77789Sahrens #include <zone.h> 78789Sahrens #include <sys/mntent.h> 79789Sahrens #include <sys/mnttab.h> 80789Sahrens #include <sys/mount.h> 81789Sahrens #include <sys/stat.h> 82789Sahrens 83789Sahrens #include <libzfs.h> 84789Sahrens 85789Sahrens #include "libzfs_impl.h" 86789Sahrens 874180Sdougm #include <libshare.h> 884180Sdougm #include <sys/systeminfo.h> 894180Sdougm #define MAXISALEN 257 /* based on sysinfo(2) man page */ 904180Sdougm 915331Samw static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *); 925331Samw zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **, 935331Samw zfs_share_proto_t); 945331Samw 953134Sahl static int (*iscsitgt_zfs_share)(const char *); 963134Sahl static int (*iscsitgt_zfs_unshare)(const char *); 973134Sahl static int (*iscsitgt_zfs_is_shared)(const char *); 984543Smarks static int (*iscsitgt_svc_online)(); 993134Sahl 1005331Samw /* 1015331Samw * The share protocols table must be in the same order as the zfs_share_prot_t 1025331Samw * enum in libzfs_impl.h 1035331Samw */ 1045331Samw typedef struct { 1055331Samw zfs_prop_t p_prop; 1065331Samw char *p_name; 1075331Samw int p_share_err; 1085331Samw int p_unshare_err; 1095331Samw } proto_table_t; 1105331Samw 1115331Samw proto_table_t proto_table[PROTO_END] = { 1125331Samw {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED}, 1135331Samw {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED}, 1145331Samw }; 1155331Samw 1165331Samw zfs_share_proto_t nfs_only[] = { 1175331Samw PROTO_NFS, 1185331Samw PROTO_END 1195331Samw }; 1205331Samw 1215331Samw zfs_share_proto_t smb_only[] = { 1225331Samw PROTO_SMB, 1235331Samw PROTO_END 1245331Samw }; 1255331Samw zfs_share_proto_t share_all_proto[] = { 1265331Samw PROTO_NFS, 1275331Samw PROTO_SMB, 1285331Samw PROTO_END 1295331Samw }; 1305331Samw 1313134Sahl #pragma init(zfs_iscsi_init) 1323134Sahl static void 1333134Sahl zfs_iscsi_init(void) 1343134Sahl { 1353134Sahl void *libiscsitgt; 1363134Sahl 1373134Sahl if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1", 1383134Sahl RTLD_LAZY | RTLD_GLOBAL)) == NULL || 1393134Sahl (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt, 1403134Sahl "iscsitgt_zfs_share")) == NULL || 1413134Sahl (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt, 1423134Sahl "iscsitgt_zfs_unshare")) == NULL || 1433134Sahl (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt, 1444543Smarks "iscsitgt_zfs_is_shared")) == NULL || 1454543Smarks (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt, 1464543Smarks "iscsitgt_svc_online")) == NULL) { 1473134Sahl iscsitgt_zfs_share = NULL; 1483134Sahl iscsitgt_zfs_unshare = NULL; 1493134Sahl iscsitgt_zfs_is_shared = NULL; 1504543Smarks iscsitgt_svc_online = NULL; 1513134Sahl } 1523134Sahl } 1533134Sahl 154789Sahrens /* 1555331Samw * Search the sharetab for the given mountpoint and protocol, returning 1565331Samw * a zfs_share_type_t value. 157789Sahrens */ 1585331Samw static zfs_share_type_t 1595331Samw is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto) 160789Sahrens { 161789Sahrens char buf[MAXPATHLEN], *tab; 1625331Samw char *ptr; 163789Sahrens 1642082Seschrock if (hdl->libzfs_sharetab == NULL) 1655331Samw return (SHARED_NOT_SHARED); 166789Sahrens 1672082Seschrock (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); 168789Sahrens 1692082Seschrock while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { 170789Sahrens 171789Sahrens /* the mountpoint is the first entry on each line */ 1725331Samw if ((tab = strchr(buf, '\t')) == NULL) 1735331Samw continue; 1745331Samw 1755331Samw *tab = '\0'; 1765331Samw if (strcmp(buf, mountpoint) == 0) { 1775331Samw /* 1785331Samw * the protocol field is the third field 1795331Samw * skip over second field 1805331Samw */ 1815331Samw ptr = ++tab; 1825331Samw if ((tab = strchr(ptr, '\t')) == NULL) 1835331Samw continue; 1845331Samw ptr = ++tab; 1855331Samw if ((tab = strchr(ptr, '\t')) == NULL) 1865331Samw continue; 187789Sahrens *tab = '\0'; 1885331Samw if (strcmp(ptr, 1895331Samw proto_table[proto].p_name) == 0) { 1905331Samw switch (proto) { 1915331Samw case PROTO_NFS: 1925331Samw return (SHARED_NFS); 1935331Samw case PROTO_SMB: 1945331Samw return (SHARED_SMB); 1955331Samw default: 1965331Samw return (0); 1975331Samw } 1985331Samw } 199789Sahrens } 200789Sahrens } 201789Sahrens 2025331Samw return (SHARED_NOT_SHARED); 203789Sahrens } 204789Sahrens 205789Sahrens /* 2062082Seschrock * Returns true if the specified directory is empty. If we can't open the 2072082Seschrock * directory at all, return true so that the mount can fail with a more 208789Sahrens * informative error message. 209789Sahrens */ 2102082Seschrock static boolean_t 211789Sahrens dir_is_empty(const char *dirname) 212789Sahrens { 213789Sahrens DIR *dirp; 214789Sahrens struct dirent64 *dp; 215789Sahrens 216789Sahrens if ((dirp = opendir(dirname)) == NULL) 2172082Seschrock return (B_TRUE); 218789Sahrens 219789Sahrens while ((dp = readdir64(dirp)) != NULL) { 220789Sahrens 221789Sahrens if (strcmp(dp->d_name, ".") == 0 || 222789Sahrens strcmp(dp->d_name, "..") == 0) 223789Sahrens continue; 224789Sahrens 225789Sahrens (void) closedir(dirp); 2262082Seschrock return (B_FALSE); 227789Sahrens } 228789Sahrens 229789Sahrens (void) closedir(dirp); 2302082Seschrock return (B_TRUE); 231789Sahrens } 232789Sahrens 233789Sahrens /* 234789Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill 235789Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return 236789Sahrens * 0. 237789Sahrens */ 2382082Seschrock boolean_t 2393444Sek110237 is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where) 240789Sahrens { 241789Sahrens struct mnttab search = { 0 }, entry; 242789Sahrens 243789Sahrens /* 244789Sahrens * Search for the entry in /etc/mnttab. We don't bother getting the 245789Sahrens * mountpoint, as we can just search for the special device. This will 246789Sahrens * also let us find mounts when the mountpoint is 'legacy'. 247789Sahrens */ 2483444Sek110237 search.mnt_special = (char *)special; 2491407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 250789Sahrens 2513444Sek110237 rewind(zfs_hdl->libzfs_mnttab); 2523444Sek110237 if (getmntany(zfs_hdl->libzfs_mnttab, &entry, &search) != 0) 2532082Seschrock return (B_FALSE); 254789Sahrens 255789Sahrens if (where != NULL) 2563444Sek110237 *where = zfs_strdup(zfs_hdl, entry.mnt_mountp); 257789Sahrens 2582082Seschrock return (B_TRUE); 259789Sahrens } 260789Sahrens 2613444Sek110237 boolean_t 2623444Sek110237 zfs_is_mounted(zfs_handle_t *zhp, char **where) 2633444Sek110237 { 2643444Sek110237 return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where)); 2653444Sek110237 } 2663444Sek110237 267789Sahrens /* 2682676Seschrock * Returns true if the given dataset is mountable, false otherwise. Returns the 2692676Seschrock * mountpoint in 'buf'. 2702676Seschrock */ 2712676Seschrock static boolean_t 2722676Seschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, 2735094Slling zprop_source_t *source) 2742676Seschrock { 2752676Seschrock char sourceloc[ZFS_MAXNAMELEN]; 2765094Slling zprop_source_t sourcetype; 2772676Seschrock 2782676Seschrock if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type)) 2792676Seschrock return (B_FALSE); 2802676Seschrock 2812676Seschrock verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen, 2822676Seschrock &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0); 2832676Seschrock 2842676Seschrock if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 || 2852676Seschrock strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0) 2862676Seschrock return (B_FALSE); 2872676Seschrock 2882676Seschrock if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT)) 2892676Seschrock return (B_FALSE); 2902676Seschrock 2912676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) && 2922676Seschrock getzoneid() == GLOBAL_ZONEID) 2932676Seschrock return (B_FALSE); 2942676Seschrock 2952676Seschrock if (source) 2962676Seschrock *source = sourcetype; 2972676Seschrock 2982676Seschrock return (B_TRUE); 2992676Seschrock } 3002676Seschrock 3012676Seschrock /* 302789Sahrens * Mount the given filesystem. 303789Sahrens */ 304789Sahrens int 305789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 306789Sahrens { 307789Sahrens struct stat buf; 308789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 309789Sahrens char mntopts[MNT_LINE_MAX]; 3102082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 311789Sahrens 312789Sahrens if (options == NULL) 313789Sahrens mntopts[0] = '\0'; 314789Sahrens else 315789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 316789Sahrens 3172676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 3182082Seschrock return (0); 319789Sahrens 320789Sahrens /* Create the directory if it doesn't already exist */ 321789Sahrens if (lstat(mountpoint, &buf) != 0) { 322789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 3232082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3242082Seschrock "failed to create mountpoint")); 3253237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3262082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 3272082Seschrock mountpoint)); 328789Sahrens } 329789Sahrens } 330789Sahrens 331789Sahrens /* 332789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 333789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 334789Sahrens * would defeat the point. We also avoid this check if 'remount' is 335789Sahrens * specified. 336789Sahrens */ 337789Sahrens if ((flags & MS_OVERLAY) == 0 && 338789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 339789Sahrens !dir_is_empty(mountpoint)) { 3402082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3412082Seschrock "directory is not empty")); 3423237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3432082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint)); 344789Sahrens } 345789Sahrens 346789Sahrens /* perform the mount */ 347789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 348789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 349789Sahrens /* 350789Sahrens * Generic errors are nasty, but there are just way too many 351789Sahrens * from mount(), and they're well-understood. We pick a few 352789Sahrens * common ones to improve upon. 353789Sahrens */ 3544302Sdougm if (errno == EBUSY) { 3552082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3562082Seschrock "mountpoint or dataset is busy")); 3574543Smarks } else if (errno == EPERM) { 3584543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3594543Smarks "Insufficient privileges")); 3604302Sdougm } else { 3612082Seschrock zfs_error_aux(hdl, strerror(errno)); 3624302Sdougm } 3632082Seschrock 3643237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3652082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 3662082Seschrock zhp->zfs_name)); 367789Sahrens } 368789Sahrens 369789Sahrens return (0); 370789Sahrens } 371789Sahrens 372789Sahrens /* 3732474Seschrock * Unmount a single filesystem. 3742474Seschrock */ 3752474Seschrock static int 3762474Seschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) 3772474Seschrock { 3782474Seschrock if (umount2(mountpoint, flags) != 0) { 3792474Seschrock zfs_error_aux(hdl, strerror(errno)); 3803237Slling return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED, 3812474Seschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), 3822474Seschrock mountpoint)); 3832474Seschrock } 3842474Seschrock 3852474Seschrock return (0); 3862474Seschrock } 3872474Seschrock 3882474Seschrock /* 389789Sahrens * Unmount the given filesystem. 390789Sahrens */ 391789Sahrens int 392789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 393789Sahrens { 394789Sahrens struct mnttab search = { 0 }, entry; 3954180Sdougm char *mntpt = NULL; 396789Sahrens 397789Sahrens /* check to see if need to unmount the filesystem */ 3982474Seschrock search.mnt_special = zhp->zfs_name; 3991407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 4002082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 401789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 4022082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 403789Sahrens 4044180Sdougm /* 4054180Sdougm * mountpoint may have come from a call to 4064180Sdougm * getmnt/getmntany if it isn't NULL. If it is NULL, 4074180Sdougm * we know it comes from getmntany which can then get 4084180Sdougm * overwritten later. We strdup it to play it safe. 4094180Sdougm */ 410789Sahrens if (mountpoint == NULL) 4114302Sdougm mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 4124180Sdougm else 4134302Sdougm mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); 414789Sahrens 415789Sahrens /* 4162474Seschrock * Unshare and unmount the filesystem 417789Sahrens */ 4185331Samw if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) 4194331Sth199096 return (-1); 4204331Sth199096 4214331Sth199096 if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) { 4224180Sdougm free(mntpt); 4235331Samw (void) zfs_shareall(zhp); 424789Sahrens return (-1); 4254180Sdougm } 4264180Sdougm free(mntpt); 427789Sahrens } 428789Sahrens 429789Sahrens return (0); 430789Sahrens } 431789Sahrens 432789Sahrens /* 433789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 434789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 435789Sahrens * remount the filesystems afterwards. 436789Sahrens */ 437789Sahrens int 438789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 439789Sahrens { 440789Sahrens prop_changelist_t *clp; 441789Sahrens int ret; 442789Sahrens 443789Sahrens clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags); 444789Sahrens if (clp == NULL) 445789Sahrens return (-1); 446789Sahrens 447789Sahrens ret = changelist_prefix(clp); 448789Sahrens changelist_free(clp); 449789Sahrens 450789Sahrens return (ret); 451789Sahrens } 452789Sahrens 4533126Sahl boolean_t 4543126Sahl zfs_is_shared(zfs_handle_t *zhp) 4553126Sahl { 4565331Samw zfs_share_type_t rc = 0; 4575331Samw zfs_share_proto_t *curr_proto; 4585331Samw 4593126Sahl if (ZFS_IS_VOLUME(zhp)) 4603126Sahl return (zfs_is_shared_iscsi(zhp)); 4613126Sahl 4625331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 4635331Samw curr_proto++) 4645331Samw rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto); 4655331Samw 4665331Samw return (rc ? B_TRUE : B_FALSE); 4673126Sahl } 4683126Sahl 4693126Sahl int 4703126Sahl zfs_share(zfs_handle_t *zhp) 4713126Sahl { 4723126Sahl if (ZFS_IS_VOLUME(zhp)) 4733126Sahl return (zfs_share_iscsi(zhp)); 4743126Sahl 4755331Samw return (zfs_share_proto(zhp, share_all_proto)); 4763126Sahl } 4773126Sahl 4783126Sahl int 4793126Sahl zfs_unshare(zfs_handle_t *zhp) 4803126Sahl { 4813126Sahl if (ZFS_IS_VOLUME(zhp)) 4823126Sahl return (zfs_unshare_iscsi(zhp)); 4833126Sahl 4845331Samw return (zfs_unshareall(zhp)); 4853126Sahl } 4863126Sahl 487789Sahrens /* 488789Sahrens * Check to see if the filesystem is currently shared. 489789Sahrens */ 4905331Samw zfs_share_type_t 4915331Samw zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto) 492789Sahrens { 493789Sahrens char *mountpoint; 4945331Samw zfs_share_type_t rc; 495789Sahrens 496789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 4975331Samw return (SHARED_NOT_SHARED); 498789Sahrens 4995331Samw if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) { 500789Sahrens if (where != NULL) 501789Sahrens *where = mountpoint; 502789Sahrens else 503789Sahrens free(mountpoint); 5045331Samw return (rc); 505789Sahrens } else { 506789Sahrens free(mountpoint); 5075331Samw return (SHARED_NOT_SHARED); 508789Sahrens } 509789Sahrens } 510789Sahrens 5115331Samw boolean_t 5125331Samw zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) 5135331Samw { 5145331Samw return (zfs_is_shared_proto(zhp, where, 5155331Samw PROTO_NFS) != SHARED_NOT_SHARED); 5165331Samw } 5175331Samw 5185331Samw boolean_t 5195331Samw zfs_is_shared_smb(zfs_handle_t *zhp, char **where) 5205331Samw { 5215331Samw return (zfs_is_shared_proto(zhp, where, 5225331Samw PROTO_SMB) != SHARED_NOT_SHARED); 5235331Samw } 5245331Samw 525789Sahrens /* 5264180Sdougm * Make sure things will work if libshare isn't installed by using 5274180Sdougm * wrapper functions that check to see that the pointers to functions 5284180Sdougm * initialized in _zfs_init_libshare() are actually present. 5294180Sdougm */ 5304180Sdougm 5314180Sdougm static sa_handle_t (*_sa_init)(int); 5324180Sdougm static void (*_sa_fini)(sa_handle_t); 5334180Sdougm static sa_share_t (*_sa_find_share)(sa_handle_t, char *); 5344180Sdougm static int (*_sa_enable_share)(sa_share_t, char *); 5354180Sdougm static int (*_sa_disable_share)(sa_share_t, char *); 5364180Sdougm static char *(*_sa_errorstr)(int); 5374180Sdougm static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *); 538*5951Sdougm static boolean_t (*_sa_needs_refresh)(sa_handle_t *); 539*5951Sdougm static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t); 540*5951Sdougm static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t, 541*5951Sdougm char *, char *, zprop_source_t, char *, char *, char *); 542*5951Sdougm static void (*_sa_update_sharetab_ts)(sa_handle_t); 5434180Sdougm 5444180Sdougm /* 5454180Sdougm * _zfs_init_libshare() 5464180Sdougm * 5474180Sdougm * Find the libshare.so.1 entry points that we use here and save the 5484180Sdougm * values to be used later. This is triggered by the runtime loader. 5494180Sdougm * Make sure the correct ISA version is loaded. 5504180Sdougm */ 551*5951Sdougm 5524180Sdougm #pragma init(_zfs_init_libshare) 5534180Sdougm static void 5544180Sdougm _zfs_init_libshare(void) 5554180Sdougm { 5564180Sdougm void *libshare; 5574180Sdougm char path[MAXPATHLEN]; 5584180Sdougm char isa[MAXISALEN]; 5594180Sdougm 5604180Sdougm #if defined(_LP64) 5614180Sdougm if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1) 5624302Sdougm isa[0] = '\0'; 5634180Sdougm #else 5644180Sdougm isa[0] = '\0'; 5654180Sdougm #endif 5664180Sdougm (void) snprintf(path, MAXPATHLEN, 5674302Sdougm "/usr/lib/%s/libshare.so.1", isa); 5684180Sdougm 5694180Sdougm if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) { 5704302Sdougm _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init"); 5714302Sdougm _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini"); 5724302Sdougm _sa_find_share = (sa_share_t (*)(sa_handle_t, char *)) 5734302Sdougm dlsym(libshare, "sa_find_share"); 5744302Sdougm _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5754302Sdougm "sa_enable_share"); 5764302Sdougm _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5774302Sdougm "sa_disable_share"); 5784302Sdougm _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr"); 5794302Sdougm _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *)) 5804302Sdougm dlsym(libshare, "sa_parse_legacy_options"); 581*5951Sdougm _sa_needs_refresh = (boolean_t (*)(sa_handle_t *)) 582*5951Sdougm dlsym(libshare, "sa_needs_refresh"); 583*5951Sdougm _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t)) 584*5951Sdougm dlsym(libshare, "sa_get_zfs_handle"); 585*5951Sdougm _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t, 586*5951Sdougm sa_share_t, char *, char *, zprop_source_t, char *, 587*5951Sdougm char *, char *))dlsym(libshare, "sa_zfs_process_share"); 588*5951Sdougm _sa_update_sharetab_ts = (void (*)(sa_handle_t)) 589*5951Sdougm dlsym(libshare, "sa_update_sharetab_ts"); 5904327Sdougm if (_sa_init == NULL || _sa_fini == NULL || 5914327Sdougm _sa_find_share == NULL || _sa_enable_share == NULL || 5924327Sdougm _sa_disable_share == NULL || _sa_errorstr == NULL || 593*5951Sdougm _sa_parse_legacy_options == NULL || 594*5951Sdougm _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL || 595*5951Sdougm _sa_zfs_process_share == NULL || 596*5951Sdougm _sa_update_sharetab_ts == NULL) { 5974327Sdougm _sa_init = NULL; 5984327Sdougm _sa_fini = NULL; 5994327Sdougm _sa_disable_share = NULL; 6004327Sdougm _sa_enable_share = NULL; 6014327Sdougm _sa_errorstr = NULL; 6024327Sdougm _sa_parse_legacy_options = NULL; 6034327Sdougm (void) dlclose(libshare); 604*5951Sdougm _sa_needs_refresh = NULL; 605*5951Sdougm _sa_get_zfs_handle = NULL; 606*5951Sdougm _sa_zfs_process_share = NULL; 607*5951Sdougm _sa_update_sharetab_ts = NULL; 6084327Sdougm } 6094180Sdougm } 6104180Sdougm } 6114180Sdougm 6124180Sdougm /* 6134180Sdougm * zfs_init_libshare(zhandle, service) 6144180Sdougm * 6154180Sdougm * Initialize the libshare API if it hasn't already been initialized. 6164180Sdougm * In all cases it returns 0 if it succeeded and an error if not. The 6174180Sdougm * service value is which part(s) of the API to initialize and is a 6184180Sdougm * direct map to the libshare sa_init(service) interface. 6194180Sdougm */ 6204180Sdougm int 6214180Sdougm zfs_init_libshare(libzfs_handle_t *zhandle, int service) 6224180Sdougm { 6234180Sdougm int ret = SA_OK; 6244180Sdougm 6254302Sdougm if (_sa_init == NULL) 6264302Sdougm ret = SA_CONFIG_ERR; 6274302Sdougm 628*5951Sdougm if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) { 629*5951Sdougm /* 630*5951Sdougm * We had a cache miss. Most likely it is a new ZFS 631*5951Sdougm * dataset that was just created. We want to make sure 632*5951Sdougm * so check timestamps to see if a different process 633*5951Sdougm * has updated any of the configuration. If there was 634*5951Sdougm * some non-ZFS change, we need to re-initialize the 635*5951Sdougm * internal cache. 636*5951Sdougm */ 637*5951Sdougm zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS; 638*5951Sdougm if (_sa_needs_refresh != NULL && 639*5951Sdougm _sa_needs_refresh(zhandle->libzfs_sharehdl)) { 640*5951Sdougm zfs_uninit_libshare(zhandle); 641*5951Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 642*5951Sdougm } 643*5951Sdougm } 644*5951Sdougm 6454302Sdougm if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL) 6464302Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 6474302Sdougm 6484302Sdougm if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL) 6494302Sdougm ret = SA_NO_MEMORY; 6504302Sdougm 6514180Sdougm return (ret); 6524180Sdougm } 6534180Sdougm 6544180Sdougm /* 6554180Sdougm * zfs_uninit_libshare(zhandle) 6564180Sdougm * 6574180Sdougm * Uninitialize the libshare API if it hasn't already been 6584180Sdougm * uninitialized. It is OK to call multiple times. 6594180Sdougm */ 6604180Sdougm void 6614180Sdougm zfs_uninit_libshare(libzfs_handle_t *zhandle) 6624180Sdougm { 6634180Sdougm if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) { 6644302Sdougm if (_sa_fini != NULL) 6654302Sdougm _sa_fini(zhandle->libzfs_sharehdl); 6664302Sdougm zhandle->libzfs_sharehdl = NULL; 6674180Sdougm } 6684180Sdougm } 6694180Sdougm 6704180Sdougm /* 6714180Sdougm * zfs_parse_options(options, proto) 6724180Sdougm * 6734180Sdougm * Call the legacy parse interface to get the protocol specific 6744180Sdougm * options using the NULL arg to indicate that this is a "parse" only. 6754180Sdougm */ 6764180Sdougm int 6775331Samw zfs_parse_options(char *options, zfs_share_proto_t proto) 6784180Sdougm { 6795367Sahrens if (_sa_parse_legacy_options != NULL) { 6805367Sahrens return (_sa_parse_legacy_options(NULL, options, 6815367Sahrens proto_table[proto].p_name)); 6825367Sahrens } 6835367Sahrens return (SA_CONFIG_ERR); 6844180Sdougm } 6854180Sdougm 6864180Sdougm /* 6874180Sdougm * zfs_sa_find_share(handle, path) 6884180Sdougm * 6894180Sdougm * wrapper around sa_find_share to find a share path in the 6904180Sdougm * configuration. 6914180Sdougm */ 6924180Sdougm static sa_share_t 6934180Sdougm zfs_sa_find_share(sa_handle_t handle, char *path) 6944180Sdougm { 6954180Sdougm if (_sa_find_share != NULL) 6964302Sdougm return (_sa_find_share(handle, path)); 6974180Sdougm return (NULL); 6984180Sdougm } 6994180Sdougm 7004180Sdougm /* 7014180Sdougm * zfs_sa_enable_share(share, proto) 7024180Sdougm * 7034180Sdougm * Wrapper for sa_enable_share which enables a share for a specified 7044180Sdougm * protocol. 7054180Sdougm */ 7064180Sdougm static int 7074180Sdougm zfs_sa_enable_share(sa_share_t share, char *proto) 7084180Sdougm { 7094180Sdougm if (_sa_enable_share != NULL) 7104302Sdougm return (_sa_enable_share(share, proto)); 7114180Sdougm return (SA_CONFIG_ERR); 7124180Sdougm } 7134180Sdougm 7144180Sdougm /* 7154180Sdougm * zfs_sa_disable_share(share, proto) 7164180Sdougm * 7174180Sdougm * Wrapper for sa_enable_share which disables a share for a specified 7184180Sdougm * protocol. 7194180Sdougm */ 7204180Sdougm static int 7214180Sdougm zfs_sa_disable_share(sa_share_t share, char *proto) 7224180Sdougm { 7234180Sdougm if (_sa_disable_share != NULL) 7244302Sdougm return (_sa_disable_share(share, proto)); 7254180Sdougm return (SA_CONFIG_ERR); 7264180Sdougm } 7274180Sdougm 7284180Sdougm /* 7295331Samw * Share the given filesystem according to the options in the specified 7305331Samw * protocol specific properties (sharenfs, sharesmb). We rely 7314180Sdougm * on "libshare" to the dirty work for us. 732789Sahrens */ 7335331Samw static int 7345331Samw zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 735789Sahrens { 736789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 737789Sahrens char shareopts[ZFS_MAXPROPLEN]; 738*5951Sdougm char sourcestr[ZFS_MAXPROPLEN]; 7392082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 7404180Sdougm sa_share_t share; 7415331Samw zfs_share_proto_t *curr_proto; 742*5951Sdougm zprop_source_t sourcetype; 7434180Sdougm int ret; 744789Sahrens 7452676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 746789Sahrens return (0); 747789Sahrens 7484180Sdougm if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 7494302Sdougm (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 7504302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), 751*5951Sdougm zfs_get_name(zhp), _sa_errorstr != NULL ? 752*5951Sdougm _sa_errorstr(ret) : ""); 7534302Sdougm return (-1); 7544180Sdougm } 7555331Samw 7565331Samw for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { 7575331Samw /* 7585331Samw * Return success if there are no share options. 7595331Samw */ 7605331Samw if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop, 761*5951Sdougm shareopts, sizeof (shareopts), &sourcetype, sourcestr, 762*5951Sdougm ZFS_MAXPROPLEN, B_FALSE) != 0 || 763*5951Sdougm strcmp(shareopts, "off") == 0) 7645331Samw continue; 7655331Samw 7665331Samw /* 7675331Samw * If the 'zoned' property is set, then zfs_is_mountable() 7685331Samw * will have already bailed out if we are in the global zone. 7695331Samw * But local zones cannot be NFS servers, so we ignore it for 7705331Samw * local zones as well. 7715331Samw */ 7725331Samw if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) 7735331Samw continue; 7745331Samw 7755331Samw share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint); 776*5951Sdougm if (share == NULL) { 777*5951Sdougm /* 778*5951Sdougm * This may be a new file system that was just 779*5951Sdougm * created so isn't in the internal cache 780*5951Sdougm * (second time through). Rather than 781*5951Sdougm * reloading the entire configuration, we can 782*5951Sdougm * assume ZFS has done the checking and it is 783*5951Sdougm * safe to add this to the internal 784*5951Sdougm * configuration. 785*5951Sdougm */ 786*5951Sdougm if (_sa_zfs_process_share(hdl->libzfs_sharehdl, 787*5951Sdougm NULL, NULL, mountpoint, 788*5951Sdougm proto_table[*curr_proto].p_name, sourcetype, 789*5951Sdougm shareopts, sourcestr, zhp->zfs_name) != SA_OK) { 790*5951Sdougm (void) zfs_error_fmt(hdl, 791*5951Sdougm proto_table[*curr_proto].p_share_err, 792*5951Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 793*5951Sdougm zfs_get_name(zhp)); 794*5951Sdougm return (-1); 795*5951Sdougm } 796*5951Sdougm hdl->libzfs_shareflags |= ZFSSHARE_MISS; 797*5951Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, 798*5951Sdougm mountpoint); 799*5951Sdougm } 8005331Samw if (share != NULL) { 8015331Samw int err; 8025331Samw err = zfs_sa_enable_share(share, 8035331Samw proto_table[*curr_proto].p_name); 8045331Samw if (err != SA_OK) { 8055331Samw (void) zfs_error_fmt(hdl, 8065331Samw proto_table[*curr_proto].p_share_err, 8075331Samw dgettext(TEXT_DOMAIN, "cannot share '%s'"), 8085331Samw zfs_get_name(zhp)); 8095331Samw return (-1); 8105331Samw } 8115331Samw } else { 8125331Samw (void) zfs_error_fmt(hdl, 8135331Samw proto_table[*curr_proto].p_share_err, 8144302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 8154302Sdougm zfs_get_name(zhp)); 8164302Sdougm return (-1); 8174302Sdougm } 8185331Samw 819789Sahrens } 8205331Samw return (0); 8215331Samw } 822789Sahrens 8235331Samw 8245331Samw int 8255331Samw zfs_share_nfs(zfs_handle_t *zhp) 8265331Samw { 8275331Samw return (zfs_share_proto(zhp, nfs_only)); 8285331Samw } 8295331Samw 8305331Samw int 8315331Samw zfs_share_smb(zfs_handle_t *zhp) 8325331Samw { 8335331Samw return (zfs_share_proto(zhp, smb_only)); 8345331Samw } 8355331Samw 8365331Samw int 8375331Samw zfs_shareall(zfs_handle_t *zhp) 8385331Samw { 8395331Samw return (zfs_share_proto(zhp, share_all_proto)); 840789Sahrens } 841789Sahrens 842789Sahrens /* 8432474Seschrock * Unshare a filesystem by mountpoint. 8442474Seschrock */ 8452474Seschrock static int 8465331Samw unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, 8475331Samw zfs_share_proto_t proto) 8482474Seschrock { 8494180Sdougm sa_share_t share; 8504180Sdougm int err; 8514180Sdougm char *mntpt; 8522474Seschrock /* 8534180Sdougm * Mountpoint could get trashed if libshare calls getmntany 8544180Sdougm * which id does during API initialization, so strdup the 8554180Sdougm * value. 8562474Seschrock */ 8574180Sdougm mntpt = zfs_strdup(hdl, mountpoint); 8582474Seschrock 8594180Sdougm /* make sure libshare initialized */ 8604180Sdougm if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 8614180Sdougm free(mntpt); /* don't need the copy anymore */ 8624180Sdougm return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 8634302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 8644302Sdougm name, _sa_errorstr(err))); 8652474Seschrock } 8662474Seschrock 8674180Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt); 8684180Sdougm free(mntpt); /* don't need the copy anymore */ 8692474Seschrock 8704180Sdougm if (share != NULL) { 8715331Samw err = zfs_sa_disable_share(share, proto_table[proto].p_name); 8724180Sdougm if (err != SA_OK) { 8734302Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8744302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 8754302Sdougm name, _sa_errorstr(err))); 8764180Sdougm } 8774180Sdougm } else { 8784180Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8794302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"), 8804302Sdougm name)); 8814180Sdougm } 8822474Seschrock return (0); 8832474Seschrock } 8842474Seschrock 8852474Seschrock /* 886789Sahrens * Unshare the given filesystem. 887789Sahrens */ 888789Sahrens int 8895331Samw zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, 8905331Samw zfs_share_proto_t *proto) 891789Sahrens { 892789Sahrens struct mnttab search = { 0 }, entry; 8934180Sdougm char *mntpt = NULL; 894789Sahrens 895789Sahrens /* check to see if need to unmount the filesystem */ 896789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 8971407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 8982082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 8994302Sdougm if (mountpoint != NULL) 9005331Samw mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); 9014302Sdougm 902789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 9032082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 9045331Samw zfs_share_proto_t *curr_proto; 905789Sahrens 906789Sahrens if (mountpoint == NULL) 9075331Samw mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 9085331Samw 9095331Samw for (curr_proto = proto; *curr_proto != PROTO_END; 9105331Samw curr_proto++) { 911789Sahrens 9125331Samw if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) && 9135331Samw unshare_one(zhp->zfs_hdl, zhp->zfs_name, 9145331Samw mntpt, *curr_proto) != 0) { 9155331Samw if (mntpt != NULL) 9165331Samw free(mntpt); 9175331Samw return (-1); 9185331Samw } 9194180Sdougm } 920789Sahrens } 9214180Sdougm if (mntpt != NULL) 9224302Sdougm free(mntpt); 923789Sahrens 924789Sahrens return (0); 925789Sahrens } 926789Sahrens 9275331Samw int 9285331Samw zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) 9295331Samw { 9305331Samw return (zfs_unshare_proto(zhp, mountpoint, nfs_only)); 9315331Samw } 9325331Samw 9335331Samw int 9345331Samw zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint) 9355331Samw { 9365331Samw return (zfs_unshare_proto(zhp, mountpoint, smb_only)); 9375331Samw } 9385331Samw 939789Sahrens /* 9405331Samw * Same as zfs_unmountall(), but for NFS and SMB unshares. 941789Sahrens */ 942789Sahrens int 9435331Samw zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 944789Sahrens { 945789Sahrens prop_changelist_t *clp; 946789Sahrens int ret; 947789Sahrens 948789Sahrens clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0); 949789Sahrens if (clp == NULL) 950789Sahrens return (-1); 951789Sahrens 9525331Samw ret = changelist_unshare(clp, proto); 953789Sahrens changelist_free(clp); 954789Sahrens 955789Sahrens return (ret); 956789Sahrens } 957789Sahrens 9585331Samw int 9595331Samw zfs_unshareall_nfs(zfs_handle_t *zhp) 9605331Samw { 9615331Samw return (zfs_unshareall_proto(zhp, nfs_only)); 9625331Samw } 9635331Samw 9645331Samw int 9655331Samw zfs_unshareall_smb(zfs_handle_t *zhp) 9665331Samw { 9675331Samw return (zfs_unshareall_proto(zhp, smb_only)); 9685331Samw } 9695331Samw 9705331Samw int 9715331Samw zfs_unshareall(zfs_handle_t *zhp) 9725331Samw { 9735331Samw return (zfs_unshareall_proto(zhp, share_all_proto)); 9745331Samw } 9755331Samw 9765331Samw int 9775331Samw zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint) 9785331Samw { 9795331Samw return (zfs_unshare_proto(zhp, mountpoint, share_all_proto)); 9805331Samw } 9815331Samw 982789Sahrens /* 983789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 984789Sahrens * We only remove the underlying directory if: 985789Sahrens * 986789Sahrens * - The mountpoint is not 'none' or 'legacy' 987789Sahrens * - The mountpoint is non-empty 988789Sahrens * - The mountpoint is the default or inherited 989789Sahrens * - The 'zoned' property is set, or we're in a local zone 990789Sahrens * 991789Sahrens * Any other directories we leave alone. 992789Sahrens */ 993789Sahrens void 994789Sahrens remove_mountpoint(zfs_handle_t *zhp) 995789Sahrens { 996789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 9975094Slling zprop_source_t source; 998789Sahrens 9992676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), 10002676Seschrock &source)) 1001789Sahrens return; 1002789Sahrens 10035094Slling if (source == ZPROP_SRC_DEFAULT || 10045094Slling source == ZPROP_SRC_INHERITED) { 1005789Sahrens /* 1006789Sahrens * Try to remove the directory, silently ignoring any errors. 1007789Sahrens * The filesystem may have since been removed or moved around, 10082676Seschrock * and this error isn't really useful to the administrator in 10092676Seschrock * any way. 1010789Sahrens */ 1011789Sahrens (void) rmdir(mountpoint); 1012789Sahrens } 1013789Sahrens } 10142474Seschrock 10153126Sahl boolean_t 10163126Sahl zfs_is_shared_iscsi(zfs_handle_t *zhp) 10173126Sahl { 10184543Smarks 10194543Smarks /* 10204543Smarks * If iscsi deamon isn't running then we aren't shared 10214543Smarks */ 10224543Smarks if (iscsitgt_svc_online && iscsitgt_svc_online() == 1) 10235331Samw return (B_FALSE); 10244543Smarks else 10254543Smarks return (iscsitgt_zfs_is_shared != NULL && 10264543Smarks iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); 10273126Sahl } 10283126Sahl 10293126Sahl int 10303126Sahl zfs_share_iscsi(zfs_handle_t *zhp) 10313126Sahl { 10323126Sahl char shareopts[ZFS_MAXPROPLEN]; 10333126Sahl const char *dataset = zhp->zfs_name; 10343126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 10353126Sahl 10363126Sahl /* 10373126Sahl * Return success if there are no share options. 10383126Sahl */ 10393126Sahl if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 10403126Sahl sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || 10413126Sahl strcmp(shareopts, "off") == 0) 10423126Sahl return (0); 10433126Sahl 10444543Smarks if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) { 10454543Smarks int error = EZFS_SHAREISCSIFAILED; 10464543Smarks 10474543Smarks /* 10484543Smarks * If service isn't availabele and EPERM was 10494543Smarks * returned then use special error. 10504543Smarks */ 10514543Smarks if (iscsitgt_svc_online && errno == EPERM && 10524543Smarks (iscsitgt_svc_online() != 0)) 10534543Smarks error = EZFS_ISCSISVCUNAVAIL; 10544543Smarks 10554543Smarks return (zfs_error_fmt(hdl, error, 10563126Sahl dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); 10574543Smarks } 10583126Sahl 10593126Sahl return (0); 10603126Sahl } 10613126Sahl 10623126Sahl int 10633126Sahl zfs_unshare_iscsi(zfs_handle_t *zhp) 10643126Sahl { 10653126Sahl const char *dataset = zfs_get_name(zhp); 10663126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 10673126Sahl 10683126Sahl /* 10693380Sgw25295 * Return if the volume is not shared 10703380Sgw25295 */ 10715331Samw if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI) 10723380Sgw25295 return (0); 10733380Sgw25295 10743380Sgw25295 /* 10753126Sahl * If this fails with ENODEV it indicates that zvol wasn't shared so 10763126Sahl * we should return success in that case. 10773126Sahl */ 10783134Sahl if (iscsitgt_zfs_unshare == NULL || 10794543Smarks (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) { 10804543Smarks if (errno == EPERM) 10814543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10824543Smarks "Insufficient privileges to unshare iscsi")); 10833237Slling return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, 10843126Sahl dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); 10854543Smarks } 10863126Sahl 10873126Sahl return (0); 10883126Sahl } 10893126Sahl 10902474Seschrock typedef struct mount_cbdata { 10912474Seschrock zfs_handle_t **cb_datasets; 10922474Seschrock int cb_used; 10932474Seschrock int cb_alloc; 10942474Seschrock } mount_cbdata_t; 10952474Seschrock 10962474Seschrock static int 10972474Seschrock mount_cb(zfs_handle_t *zhp, void *data) 10982474Seschrock { 10992474Seschrock mount_cbdata_t *cbp = data; 11002474Seschrock 11013126Sahl if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { 11022474Seschrock zfs_close(zhp); 11032474Seschrock return (0); 11042474Seschrock } 11052474Seschrock 11062474Seschrock if (cbp->cb_alloc == cbp->cb_used) { 11072676Seschrock void *ptr; 11082474Seschrock 11092676Seschrock if ((ptr = zfs_realloc(zhp->zfs_hdl, 11102676Seschrock cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), 11112676Seschrock cbp->cb_alloc * 2 * sizeof (void *))) == NULL) 11122474Seschrock return (-1); 11132676Seschrock cbp->cb_datasets = ptr; 11142474Seschrock 11152676Seschrock cbp->cb_alloc *= 2; 11162474Seschrock } 11172474Seschrock 11182474Seschrock cbp->cb_datasets[cbp->cb_used++] = zhp; 11193126Sahl 11203126Sahl return (zfs_iter_children(zhp, mount_cb, cbp)); 11212474Seschrock } 11222474Seschrock 11232474Seschrock static int 11243126Sahl dataset_cmp(const void *a, const void *b) 11252474Seschrock { 11262474Seschrock zfs_handle_t **za = (zfs_handle_t **)a; 11272474Seschrock zfs_handle_t **zb = (zfs_handle_t **)b; 11282474Seschrock char mounta[MAXPATHLEN]; 11292474Seschrock char mountb[MAXPATHLEN]; 11303126Sahl boolean_t gota, gotb; 11312474Seschrock 11323126Sahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 11333126Sahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 11343126Sahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 11353126Sahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 11363126Sahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 11373126Sahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 11382474Seschrock 11393126Sahl if (gota && gotb) 11403126Sahl return (strcmp(mounta, mountb)); 11413126Sahl 11423126Sahl if (gota) 11433126Sahl return (-1); 11443126Sahl if (gotb) 11453126Sahl return (1); 11463126Sahl 11473126Sahl return (strcmp(zfs_get_name(a), zfs_get_name(b))); 11482474Seschrock } 11492474Seschrock 11503126Sahl /* 11513126Sahl * Mount and share all datasets within the given pool. This assumes that no 11523126Sahl * datasets within the pool are currently mounted. Because users can create 11533126Sahl * complicated nested hierarchies of mountpoints, we first gather all the 11543126Sahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once 11553126Sahl * we have the list of all filesystems, we iterate over them in order and mount 11563126Sahl * and/or share each one. 11573126Sahl */ 11583126Sahl #pragma weak zpool_mount_datasets = zpool_enable_datasets 11592474Seschrock int 11603126Sahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) 11612474Seschrock { 11622474Seschrock mount_cbdata_t cb = { 0 }; 11632474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 11642474Seschrock zfs_handle_t *zfsp; 11652474Seschrock int i, ret = -1; 11664180Sdougm int *good; 11672474Seschrock 11682474Seschrock /* 11692474Seschrock * Gather all datasets within the pool. 11702474Seschrock */ 11712474Seschrock if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) 11722474Seschrock return (-1); 11732474Seschrock cb.cb_alloc = 4; 11742474Seschrock 11755094Slling if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL) 11762474Seschrock goto out; 11772474Seschrock 11782474Seschrock cb.cb_datasets[0] = zfsp; 11792474Seschrock cb.cb_used = 1; 11802474Seschrock 11812474Seschrock if (zfs_iter_children(zfsp, mount_cb, &cb) != 0) 11822474Seschrock goto out; 11832474Seschrock 11842474Seschrock /* 11852474Seschrock * Sort the datasets by mountpoint. 11862474Seschrock */ 11873126Sahl qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); 11882474Seschrock 11892474Seschrock /* 11904180Sdougm * And mount all the datasets, keeping track of which ones 11914180Sdougm * succeeded or failed. By using zfs_alloc(), the good pointer 11924180Sdougm * will always be non-NULL. 11932474Seschrock */ 11944180Sdougm good = zfs_alloc(zhp->zpool_hdl, cb.cb_used * sizeof (int)); 11952474Seschrock ret = 0; 11962474Seschrock for (i = 0; i < cb.cb_used; i++) { 11974302Sdougm if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0) 11984180Sdougm ret = -1; 11994302Sdougm else 12004180Sdougm good[i] = 1; 12014180Sdougm } 1202*5951Sdougm 12034180Sdougm /* 12044180Sdougm * Then share all the ones that need to be shared. This needs 12054180Sdougm * to be a separate pass in order to avoid excessive reloading 12064180Sdougm * of the configuration. Good should never be NULL since 12074180Sdougm * zfs_alloc is supposed to exit if memory isn't available. 12084180Sdougm */ 12094180Sdougm for (i = 0; i < cb.cb_used; i++) { 12104180Sdougm if (good[i] && zfs_share(cb.cb_datasets[i]) != 0) 12112474Seschrock ret = -1; 12122474Seschrock } 12132474Seschrock 12144180Sdougm free(good); 12154180Sdougm 12162474Seschrock out: 12172474Seschrock for (i = 0; i < cb.cb_used; i++) 12182474Seschrock zfs_close(cb.cb_datasets[i]); 12192474Seschrock free(cb.cb_datasets); 12202474Seschrock 12212474Seschrock return (ret); 12222474Seschrock } 12232474Seschrock 12243126Sahl 12253126Sahl static int 12263126Sahl zvol_cb(const char *dataset, void *data) 12273126Sahl { 12283126Sahl libzfs_handle_t *hdl = data; 12293126Sahl zfs_handle_t *zhp; 12303126Sahl 12313126Sahl /* 12323126Sahl * Ignore snapshots and ignore failures from non-existant datasets. 12333126Sahl */ 12343126Sahl if (strchr(dataset, '@') != NULL || 12353126Sahl (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL) 12363126Sahl return (0); 12373126Sahl 12384543Smarks if (zfs_unshare_iscsi(zhp) != 0) 12394543Smarks return (-1); 12403126Sahl 12413126Sahl zfs_close(zhp); 12423126Sahl 12433126Sahl return (0); 12443126Sahl } 12453126Sahl 12462474Seschrock static int 12472474Seschrock mountpoint_compare(const void *a, const void *b) 12482474Seschrock { 12492474Seschrock const char *mounta = *((char **)a); 12502474Seschrock const char *mountb = *((char **)b); 12512474Seschrock 12522474Seschrock return (strcmp(mountb, mounta)); 12532474Seschrock } 12542474Seschrock 12553126Sahl /* 12563126Sahl * Unshare and unmount all datasets within the given pool. We don't want to 12573126Sahl * rely on traversing the DSL to discover the filesystems within the pool, 12583126Sahl * because this may be expensive (if not all of them are mounted), and can fail 12593126Sahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and 12603126Sahl * gather all the filesystems that are currently mounted. 12613126Sahl */ 12623126Sahl #pragma weak zpool_unmount_datasets = zpool_disable_datasets 12632474Seschrock int 12643126Sahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) 12652474Seschrock { 12662474Seschrock int used, alloc; 12672474Seschrock struct mnttab entry; 12682474Seschrock size_t namelen; 12692474Seschrock char **mountpoints = NULL; 12702474Seschrock zfs_handle_t **datasets = NULL; 12712474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 12722474Seschrock int i; 12732474Seschrock int ret = -1; 12742474Seschrock int flags = (force ? MS_FORCE : 0); 12752474Seschrock 12763126Sahl /* 12773126Sahl * First unshare all zvols. 12783126Sahl */ 12793126Sahl if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0) 12803126Sahl return (-1); 12813126Sahl 12822474Seschrock namelen = strlen(zhp->zpool_name); 12832474Seschrock 12842474Seschrock rewind(hdl->libzfs_mnttab); 12852474Seschrock used = alloc = 0; 12862474Seschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 12872474Seschrock /* 12882474Seschrock * Ignore non-ZFS entries. 12892474Seschrock */ 12902474Seschrock if (entry.mnt_fstype == NULL || 12912474Seschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 12922474Seschrock continue; 12932474Seschrock 12942474Seschrock /* 12952474Seschrock * Ignore filesystems not within this pool. 12962474Seschrock */ 12972474Seschrock if (entry.mnt_mountp == NULL || 12982474Seschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 || 12992474Seschrock (entry.mnt_special[namelen] != '/' && 13002474Seschrock entry.mnt_special[namelen] != '\0')) 13012474Seschrock continue; 13022474Seschrock 13032474Seschrock /* 13042474Seschrock * At this point we've found a filesystem within our pool. Add 13052474Seschrock * it to our growing list. 13062474Seschrock */ 13072474Seschrock if (used == alloc) { 13082474Seschrock if (alloc == 0) { 13092474Seschrock if ((mountpoints = zfs_alloc(hdl, 13102474Seschrock 8 * sizeof (void *))) == NULL) 13112474Seschrock goto out; 13122474Seschrock 13132474Seschrock if ((datasets = zfs_alloc(hdl, 13142474Seschrock 8 * sizeof (void *))) == NULL) 13152474Seschrock goto out; 13162474Seschrock 13172474Seschrock alloc = 8; 13182474Seschrock } else { 13192676Seschrock void *ptr; 13202474Seschrock 13212676Seschrock if ((ptr = zfs_realloc(hdl, mountpoints, 13222676Seschrock alloc * sizeof (void *), 13232474Seschrock alloc * 2 * sizeof (void *))) == NULL) 13242474Seschrock goto out; 13252676Seschrock mountpoints = ptr; 13262474Seschrock 13272676Seschrock if ((ptr = zfs_realloc(hdl, datasets, 13282676Seschrock alloc * sizeof (void *), 13292474Seschrock alloc * 2 * sizeof (void *))) == NULL) 13302474Seschrock goto out; 13312676Seschrock datasets = ptr; 13322474Seschrock 13332474Seschrock alloc *= 2; 13342474Seschrock } 13352474Seschrock } 13362474Seschrock 13372474Seschrock if ((mountpoints[used] = zfs_strdup(hdl, 13382474Seschrock entry.mnt_mountp)) == NULL) 13392474Seschrock goto out; 13402474Seschrock 13412474Seschrock /* 13422474Seschrock * This is allowed to fail, in case there is some I/O error. It 13432474Seschrock * is only used to determine if we need to remove the underlying 13442474Seschrock * mountpoint, so failure is not fatal. 13452474Seschrock */ 13462474Seschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special); 13472474Seschrock 13482474Seschrock used++; 13492474Seschrock } 13502474Seschrock 13512474Seschrock /* 13522474Seschrock * At this point, we have the entire list of filesystems, so sort it by 13532474Seschrock * mountpoint. 13542474Seschrock */ 13552474Seschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare); 13562474Seschrock 13572474Seschrock /* 13582474Seschrock * Walk through and first unshare everything. 13592474Seschrock */ 13602474Seschrock for (i = 0; i < used; i++) { 13615331Samw zfs_share_proto_t *curr_proto; 13625331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 13635331Samw curr_proto++) { 13645331Samw if (is_shared(hdl, mountpoints[i], *curr_proto) && 13655331Samw unshare_one(hdl, mountpoints[i], 13665331Samw mountpoints[i], *curr_proto) != 0) 13675331Samw goto out; 13685331Samw } 13692474Seschrock } 13702474Seschrock 13712474Seschrock /* 13722474Seschrock * Now unmount everything, removing the underlying directories as 13732474Seschrock * appropriate. 13742474Seschrock */ 13752474Seschrock for (i = 0; i < used; i++) { 13762474Seschrock if (unmount_one(hdl, mountpoints[i], flags) != 0) 13772474Seschrock goto out; 13782676Seschrock } 13792474Seschrock 13802676Seschrock for (i = 0; i < used; i++) { 13812474Seschrock if (datasets[i]) 13822474Seschrock remove_mountpoint(datasets[i]); 13832474Seschrock } 13842474Seschrock 13852474Seschrock ret = 0; 13862474Seschrock out: 13872474Seschrock for (i = 0; i < used; i++) { 13882474Seschrock if (datasets[i]) 13892474Seschrock zfs_close(datasets[i]); 13902474Seschrock free(mountpoints[i]); 13912474Seschrock } 13922474Seschrock free(datasets); 13932474Seschrock free(mountpoints); 13942474Seschrock 13952474Seschrock return (ret); 13962474Seschrock } 1397