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 /* 238536SDavid.Pacheco@Sun.COM * Copyright 2009 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/mount.h> 78789Sahrens #include <sys/stat.h> 79789Sahrens 80789Sahrens #include <libzfs.h> 81789Sahrens 82789Sahrens #include "libzfs_impl.h" 83789Sahrens 844180Sdougm #include <libshare.h> 854180Sdougm #include <sys/systeminfo.h> 864180Sdougm #define MAXISALEN 257 /* based on sysinfo(2) man page */ 874180Sdougm 885331Samw static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *); 895331Samw zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **, 905331Samw zfs_share_proto_t); 915331Samw 923134Sahl static int (*iscsitgt_zfs_share)(const char *); 933134Sahl static int (*iscsitgt_zfs_unshare)(const char *); 943134Sahl static int (*iscsitgt_zfs_is_shared)(const char *); 954543Smarks static int (*iscsitgt_svc_online)(); 963134Sahl 975331Samw /* 985331Samw * The share protocols table must be in the same order as the zfs_share_prot_t 995331Samw * enum in libzfs_impl.h 1005331Samw */ 1015331Samw typedef struct { 1025331Samw zfs_prop_t p_prop; 1035331Samw char *p_name; 1045331Samw int p_share_err; 1055331Samw int p_unshare_err; 1065331Samw } proto_table_t; 1075331Samw 1085331Samw proto_table_t proto_table[PROTO_END] = { 1095331Samw {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED}, 1105331Samw {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED}, 1115331Samw }; 1125331Samw 1135331Samw zfs_share_proto_t nfs_only[] = { 1145331Samw PROTO_NFS, 1155331Samw PROTO_END 1165331Samw }; 1175331Samw 1185331Samw zfs_share_proto_t smb_only[] = { 1195331Samw PROTO_SMB, 1205331Samw PROTO_END 1215331Samw }; 1225331Samw zfs_share_proto_t share_all_proto[] = { 1235331Samw PROTO_NFS, 1245331Samw PROTO_SMB, 1255331Samw PROTO_END 1265331Samw }; 1275331Samw 1283134Sahl #pragma init(zfs_iscsi_init) 1293134Sahl static void 1303134Sahl zfs_iscsi_init(void) 1313134Sahl { 1323134Sahl void *libiscsitgt; 1333134Sahl 1343134Sahl if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1", 1353134Sahl RTLD_LAZY | RTLD_GLOBAL)) == NULL || 1363134Sahl (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt, 1373134Sahl "iscsitgt_zfs_share")) == NULL || 1383134Sahl (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt, 1393134Sahl "iscsitgt_zfs_unshare")) == NULL || 1403134Sahl (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt, 1414543Smarks "iscsitgt_zfs_is_shared")) == NULL || 1424543Smarks (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt, 1434543Smarks "iscsitgt_svc_online")) == NULL) { 1443134Sahl iscsitgt_zfs_share = NULL; 1453134Sahl iscsitgt_zfs_unshare = NULL; 1463134Sahl iscsitgt_zfs_is_shared = NULL; 1474543Smarks iscsitgt_svc_online = NULL; 1483134Sahl } 1493134Sahl } 1503134Sahl 151789Sahrens /* 1525331Samw * Search the sharetab for the given mountpoint and protocol, returning 1535331Samw * a zfs_share_type_t value. 154789Sahrens */ 1555331Samw static zfs_share_type_t 1565331Samw is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto) 157789Sahrens { 158789Sahrens char buf[MAXPATHLEN], *tab; 1595331Samw char *ptr; 160789Sahrens 1612082Seschrock if (hdl->libzfs_sharetab == NULL) 1625331Samw return (SHARED_NOT_SHARED); 163789Sahrens 1642082Seschrock (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); 165789Sahrens 1662082Seschrock while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { 167789Sahrens 168789Sahrens /* the mountpoint is the first entry on each line */ 1695331Samw if ((tab = strchr(buf, '\t')) == NULL) 1705331Samw continue; 1715331Samw 1725331Samw *tab = '\0'; 1735331Samw if (strcmp(buf, mountpoint) == 0) { 1745331Samw /* 1755331Samw * the protocol field is the third field 1765331Samw * skip over second field 1775331Samw */ 1785331Samw ptr = ++tab; 1795331Samw if ((tab = strchr(ptr, '\t')) == NULL) 1805331Samw continue; 1815331Samw ptr = ++tab; 1825331Samw if ((tab = strchr(ptr, '\t')) == NULL) 1835331Samw continue; 184789Sahrens *tab = '\0'; 1855331Samw if (strcmp(ptr, 1865331Samw proto_table[proto].p_name) == 0) { 1875331Samw switch (proto) { 1885331Samw case PROTO_NFS: 1895331Samw return (SHARED_NFS); 1905331Samw case PROTO_SMB: 1915331Samw return (SHARED_SMB); 1925331Samw default: 1935331Samw return (0); 1945331Samw } 1955331Samw } 196789Sahrens } 197789Sahrens } 198789Sahrens 1995331Samw return (SHARED_NOT_SHARED); 200789Sahrens } 201789Sahrens 202789Sahrens /* 2032082Seschrock * Returns true if the specified directory is empty. If we can't open the 2042082Seschrock * directory at all, return true so that the mount can fail with a more 205789Sahrens * informative error message. 206789Sahrens */ 2072082Seschrock static boolean_t 208789Sahrens dir_is_empty(const char *dirname) 209789Sahrens { 210789Sahrens DIR *dirp; 211789Sahrens struct dirent64 *dp; 212789Sahrens 213789Sahrens if ((dirp = opendir(dirname)) == NULL) 2142082Seschrock return (B_TRUE); 215789Sahrens 216789Sahrens while ((dp = readdir64(dirp)) != NULL) { 217789Sahrens 218789Sahrens if (strcmp(dp->d_name, ".") == 0 || 219789Sahrens strcmp(dp->d_name, "..") == 0) 220789Sahrens continue; 221789Sahrens 222789Sahrens (void) closedir(dirp); 2232082Seschrock return (B_FALSE); 224789Sahrens } 225789Sahrens 226789Sahrens (void) closedir(dirp); 2272082Seschrock return (B_TRUE); 228789Sahrens } 229789Sahrens 230789Sahrens /* 231789Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill 232789Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return 233789Sahrens * 0. 234789Sahrens */ 2352082Seschrock boolean_t 2363444Sek110237 is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where) 237789Sahrens { 2388228SEric.Taylor@Sun.COM struct mnttab entry; 239789Sahrens 2408228SEric.Taylor@Sun.COM if (libzfs_mnttab_find(zfs_hdl, special, &entry) != 0) 2412082Seschrock return (B_FALSE); 242789Sahrens 243789Sahrens if (where != NULL) 2443444Sek110237 *where = zfs_strdup(zfs_hdl, entry.mnt_mountp); 245789Sahrens 2462082Seschrock return (B_TRUE); 247789Sahrens } 248789Sahrens 2493444Sek110237 boolean_t 2503444Sek110237 zfs_is_mounted(zfs_handle_t *zhp, char **where) 2513444Sek110237 { 2523444Sek110237 return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where)); 2533444Sek110237 } 2543444Sek110237 255789Sahrens /* 2562676Seschrock * Returns true if the given dataset is mountable, false otherwise. Returns the 2572676Seschrock * mountpoint in 'buf'. 2582676Seschrock */ 2592676Seschrock static boolean_t 2602676Seschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, 2615094Slling zprop_source_t *source) 2622676Seschrock { 2632676Seschrock char sourceloc[ZFS_MAXNAMELEN]; 2645094Slling zprop_source_t sourcetype; 2652676Seschrock 2662676Seschrock if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type)) 2672676Seschrock return (B_FALSE); 2682676Seschrock 2692676Seschrock verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen, 2702676Seschrock &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0); 2712676Seschrock 2722676Seschrock if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 || 2732676Seschrock strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0) 2742676Seschrock return (B_FALSE); 2752676Seschrock 2766168Shs24103 if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF) 2772676Seschrock return (B_FALSE); 2782676Seschrock 2792676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) && 2802676Seschrock getzoneid() == GLOBAL_ZONEID) 2812676Seschrock return (B_FALSE); 2822676Seschrock 2832676Seschrock if (source) 2842676Seschrock *source = sourcetype; 2852676Seschrock 2862676Seschrock return (B_TRUE); 2872676Seschrock } 2882676Seschrock 2892676Seschrock /* 290789Sahrens * Mount the given filesystem. 291789Sahrens */ 292789Sahrens int 293789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 294789Sahrens { 295789Sahrens struct stat buf; 296789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 297789Sahrens char mntopts[MNT_LINE_MAX]; 2982082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 299789Sahrens 300789Sahrens if (options == NULL) 301789Sahrens mntopts[0] = '\0'; 302789Sahrens else 303789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 304789Sahrens 3052676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 3062082Seschrock return (0); 307789Sahrens 308789Sahrens /* Create the directory if it doesn't already exist */ 309789Sahrens if (lstat(mountpoint, &buf) != 0) { 310789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 3112082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3122082Seschrock "failed to create mountpoint")); 3133237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3142082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 3152082Seschrock mountpoint)); 316789Sahrens } 317789Sahrens } 318789Sahrens 319789Sahrens /* 320789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 321789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 322789Sahrens * would defeat the point. We also avoid this check if 'remount' is 323789Sahrens * specified. 324789Sahrens */ 325789Sahrens if ((flags & MS_OVERLAY) == 0 && 326789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 327789Sahrens !dir_is_empty(mountpoint)) { 3282082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3292082Seschrock "directory is not empty")); 3303237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3312082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint)); 332789Sahrens } 333789Sahrens 334789Sahrens /* perform the mount */ 335789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 336789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 337789Sahrens /* 338789Sahrens * Generic errors are nasty, but there are just way too many 339789Sahrens * from mount(), and they're well-understood. We pick a few 340789Sahrens * common ones to improve upon. 341789Sahrens */ 3424302Sdougm if (errno == EBUSY) { 3432082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3442082Seschrock "mountpoint or dataset is busy")); 3454543Smarks } else if (errno == EPERM) { 3464543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3474543Smarks "Insufficient privileges")); 3484302Sdougm } else { 3492082Seschrock zfs_error_aux(hdl, strerror(errno)); 3504302Sdougm } 3513237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3522082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 3532082Seschrock zhp->zfs_name)); 354789Sahrens } 355789Sahrens 3568228SEric.Taylor@Sun.COM /* add the mounted entry into our cache */ 3578228SEric.Taylor@Sun.COM libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint, 3588228SEric.Taylor@Sun.COM mntopts); 359789Sahrens return (0); 360789Sahrens } 361789Sahrens 362789Sahrens /* 3632474Seschrock * Unmount a single filesystem. 3642474Seschrock */ 3652474Seschrock static int 3662474Seschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) 3672474Seschrock { 3682474Seschrock if (umount2(mountpoint, flags) != 0) { 3692474Seschrock zfs_error_aux(hdl, strerror(errno)); 3703237Slling return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED, 3712474Seschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), 3722474Seschrock mountpoint)); 3732474Seschrock } 3742474Seschrock 3752474Seschrock return (0); 3762474Seschrock } 3772474Seschrock 3782474Seschrock /* 379789Sahrens * Unmount the given filesystem. 380789Sahrens */ 381789Sahrens int 382789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 383789Sahrens { 3848228SEric.Taylor@Sun.COM libzfs_handle_t *hdl = zhp->zfs_hdl; 3858228SEric.Taylor@Sun.COM struct mnttab entry; 3864180Sdougm char *mntpt = NULL; 387789Sahrens 3888228SEric.Taylor@Sun.COM /* check to see if we need to unmount the filesystem */ 389789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 3908228SEric.Taylor@Sun.COM libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) { 3914180Sdougm /* 3924180Sdougm * mountpoint may have come from a call to 3934180Sdougm * getmnt/getmntany if it isn't NULL. If it is NULL, 3948228SEric.Taylor@Sun.COM * we know it comes from libzfs_mnttab_find which can 3958228SEric.Taylor@Sun.COM * then get freed later. We strdup it to play it safe. 3964180Sdougm */ 397789Sahrens if (mountpoint == NULL) 3988228SEric.Taylor@Sun.COM mntpt = zfs_strdup(hdl, entry.mnt_mountp); 3994180Sdougm else 4008228SEric.Taylor@Sun.COM mntpt = zfs_strdup(hdl, mountpoint); 401789Sahrens 402789Sahrens /* 4032474Seschrock * Unshare and unmount the filesystem 404789Sahrens */ 4055331Samw if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) 4064331Sth199096 return (-1); 4074331Sth199096 4088228SEric.Taylor@Sun.COM if (unmount_one(hdl, mntpt, flags) != 0) { 4094180Sdougm free(mntpt); 4105331Samw (void) zfs_shareall(zhp); 411789Sahrens return (-1); 4124180Sdougm } 4138228SEric.Taylor@Sun.COM libzfs_mnttab_remove(hdl, zhp->zfs_name); 4144180Sdougm free(mntpt); 415789Sahrens } 416789Sahrens 417789Sahrens return (0); 418789Sahrens } 419789Sahrens 420789Sahrens /* 421789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 422789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 423789Sahrens * remount the filesystems afterwards. 424789Sahrens */ 425789Sahrens int 426789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 427789Sahrens { 428789Sahrens prop_changelist_t *clp; 429789Sahrens int ret; 430789Sahrens 4317366STim.Haley@Sun.COM clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags); 432789Sahrens if (clp == NULL) 433789Sahrens return (-1); 434789Sahrens 435789Sahrens ret = changelist_prefix(clp); 436789Sahrens changelist_free(clp); 437789Sahrens 438789Sahrens return (ret); 439789Sahrens } 440789Sahrens 4413126Sahl boolean_t 4423126Sahl zfs_is_shared(zfs_handle_t *zhp) 4433126Sahl { 4445331Samw zfs_share_type_t rc = 0; 4455331Samw zfs_share_proto_t *curr_proto; 4465331Samw 4473126Sahl if (ZFS_IS_VOLUME(zhp)) 4483126Sahl return (zfs_is_shared_iscsi(zhp)); 4493126Sahl 4505331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 4515331Samw curr_proto++) 4525331Samw rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto); 4535331Samw 4545331Samw return (rc ? B_TRUE : B_FALSE); 4553126Sahl } 4563126Sahl 4573126Sahl int 4583126Sahl zfs_share(zfs_handle_t *zhp) 4593126Sahl { 4603126Sahl if (ZFS_IS_VOLUME(zhp)) 4613126Sahl return (zfs_share_iscsi(zhp)); 4623126Sahl 4635331Samw return (zfs_share_proto(zhp, share_all_proto)); 4643126Sahl } 4653126Sahl 4663126Sahl int 4673126Sahl zfs_unshare(zfs_handle_t *zhp) 4683126Sahl { 4693126Sahl if (ZFS_IS_VOLUME(zhp)) 4703126Sahl return (zfs_unshare_iscsi(zhp)); 4713126Sahl 4725331Samw return (zfs_unshareall(zhp)); 4733126Sahl } 4743126Sahl 475789Sahrens /* 476789Sahrens * Check to see if the filesystem is currently shared. 477789Sahrens */ 4785331Samw zfs_share_type_t 4795331Samw zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto) 480789Sahrens { 481789Sahrens char *mountpoint; 4825331Samw zfs_share_type_t rc; 483789Sahrens 484789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 4855331Samw return (SHARED_NOT_SHARED); 486789Sahrens 4875331Samw if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) { 488789Sahrens if (where != NULL) 489789Sahrens *where = mountpoint; 490789Sahrens else 491789Sahrens free(mountpoint); 4925331Samw return (rc); 493789Sahrens } else { 494789Sahrens free(mountpoint); 4955331Samw return (SHARED_NOT_SHARED); 496789Sahrens } 497789Sahrens } 498789Sahrens 4995331Samw boolean_t 5005331Samw zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) 5015331Samw { 5025331Samw return (zfs_is_shared_proto(zhp, where, 5035331Samw PROTO_NFS) != SHARED_NOT_SHARED); 5045331Samw } 5055331Samw 5065331Samw boolean_t 5075331Samw zfs_is_shared_smb(zfs_handle_t *zhp, char **where) 5085331Samw { 5095331Samw return (zfs_is_shared_proto(zhp, where, 5105331Samw PROTO_SMB) != SHARED_NOT_SHARED); 5115331Samw } 5125331Samw 513789Sahrens /* 5144180Sdougm * Make sure things will work if libshare isn't installed by using 5154180Sdougm * wrapper functions that check to see that the pointers to functions 5164180Sdougm * initialized in _zfs_init_libshare() are actually present. 5174180Sdougm */ 5184180Sdougm 5194180Sdougm static sa_handle_t (*_sa_init)(int); 5204180Sdougm static void (*_sa_fini)(sa_handle_t); 5214180Sdougm static sa_share_t (*_sa_find_share)(sa_handle_t, char *); 5224180Sdougm static int (*_sa_enable_share)(sa_share_t, char *); 5234180Sdougm static int (*_sa_disable_share)(sa_share_t, char *); 5244180Sdougm static char *(*_sa_errorstr)(int); 5254180Sdougm static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *); 5265951Sdougm static boolean_t (*_sa_needs_refresh)(sa_handle_t *); 5275951Sdougm static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t); 5285951Sdougm static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t, 5295951Sdougm char *, char *, zprop_source_t, char *, char *, char *); 5305951Sdougm static void (*_sa_update_sharetab_ts)(sa_handle_t); 5314180Sdougm 5324180Sdougm /* 5334180Sdougm * _zfs_init_libshare() 5344180Sdougm * 5354180Sdougm * Find the libshare.so.1 entry points that we use here and save the 5364180Sdougm * values to be used later. This is triggered by the runtime loader. 5374180Sdougm * Make sure the correct ISA version is loaded. 5384180Sdougm */ 5395951Sdougm 5404180Sdougm #pragma init(_zfs_init_libshare) 5414180Sdougm static void 5424180Sdougm _zfs_init_libshare(void) 5434180Sdougm { 5444180Sdougm void *libshare; 5454180Sdougm char path[MAXPATHLEN]; 5464180Sdougm char isa[MAXISALEN]; 5474180Sdougm 5484180Sdougm #if defined(_LP64) 5494180Sdougm if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1) 5504302Sdougm isa[0] = '\0'; 5514180Sdougm #else 5524180Sdougm isa[0] = '\0'; 5534180Sdougm #endif 5544180Sdougm (void) snprintf(path, MAXPATHLEN, 5554302Sdougm "/usr/lib/%s/libshare.so.1", isa); 5564180Sdougm 5574180Sdougm if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) { 5584302Sdougm _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init"); 5594302Sdougm _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini"); 5604302Sdougm _sa_find_share = (sa_share_t (*)(sa_handle_t, char *)) 5614302Sdougm dlsym(libshare, "sa_find_share"); 5624302Sdougm _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5634302Sdougm "sa_enable_share"); 5644302Sdougm _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5654302Sdougm "sa_disable_share"); 5664302Sdougm _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr"); 5674302Sdougm _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *)) 5684302Sdougm dlsym(libshare, "sa_parse_legacy_options"); 5695951Sdougm _sa_needs_refresh = (boolean_t (*)(sa_handle_t *)) 5705951Sdougm dlsym(libshare, "sa_needs_refresh"); 5715951Sdougm _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t)) 5725951Sdougm dlsym(libshare, "sa_get_zfs_handle"); 5735951Sdougm _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t, 5745951Sdougm sa_share_t, char *, char *, zprop_source_t, char *, 5755951Sdougm char *, char *))dlsym(libshare, "sa_zfs_process_share"); 5765951Sdougm _sa_update_sharetab_ts = (void (*)(sa_handle_t)) 5775951Sdougm dlsym(libshare, "sa_update_sharetab_ts"); 5784327Sdougm if (_sa_init == NULL || _sa_fini == NULL || 5794327Sdougm _sa_find_share == NULL || _sa_enable_share == NULL || 5804327Sdougm _sa_disable_share == NULL || _sa_errorstr == NULL || 5815951Sdougm _sa_parse_legacy_options == NULL || 5825951Sdougm _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL || 5835951Sdougm _sa_zfs_process_share == NULL || 5845951Sdougm _sa_update_sharetab_ts == NULL) { 5854327Sdougm _sa_init = NULL; 5864327Sdougm _sa_fini = NULL; 5874327Sdougm _sa_disable_share = NULL; 5884327Sdougm _sa_enable_share = NULL; 5894327Sdougm _sa_errorstr = NULL; 5904327Sdougm _sa_parse_legacy_options = NULL; 5914327Sdougm (void) dlclose(libshare); 5925951Sdougm _sa_needs_refresh = NULL; 5935951Sdougm _sa_get_zfs_handle = NULL; 5945951Sdougm _sa_zfs_process_share = NULL; 5955951Sdougm _sa_update_sharetab_ts = NULL; 5964327Sdougm } 5974180Sdougm } 5984180Sdougm } 5994180Sdougm 6004180Sdougm /* 6014180Sdougm * zfs_init_libshare(zhandle, service) 6024180Sdougm * 6034180Sdougm * Initialize the libshare API if it hasn't already been initialized. 6044180Sdougm * In all cases it returns 0 if it succeeded and an error if not. The 6054180Sdougm * service value is which part(s) of the API to initialize and is a 6064180Sdougm * direct map to the libshare sa_init(service) interface. 6074180Sdougm */ 6084180Sdougm int 6094180Sdougm zfs_init_libshare(libzfs_handle_t *zhandle, int service) 6104180Sdougm { 6114180Sdougm int ret = SA_OK; 6124180Sdougm 6134302Sdougm if (_sa_init == NULL) 6144302Sdougm ret = SA_CONFIG_ERR; 6154302Sdougm 6165951Sdougm if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) { 6175951Sdougm /* 6185951Sdougm * We had a cache miss. Most likely it is a new ZFS 6195951Sdougm * dataset that was just created. We want to make sure 6205951Sdougm * so check timestamps to see if a different process 6215951Sdougm * has updated any of the configuration. If there was 6225951Sdougm * some non-ZFS change, we need to re-initialize the 6235951Sdougm * internal cache. 6245951Sdougm */ 6255951Sdougm zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS; 6265951Sdougm if (_sa_needs_refresh != NULL && 6275951Sdougm _sa_needs_refresh(zhandle->libzfs_sharehdl)) { 6285951Sdougm zfs_uninit_libshare(zhandle); 6295951Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 6305951Sdougm } 6315951Sdougm } 6325951Sdougm 6334302Sdougm if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL) 6344302Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 6354302Sdougm 6364302Sdougm if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL) 6374302Sdougm ret = SA_NO_MEMORY; 6384302Sdougm 6394180Sdougm return (ret); 6404180Sdougm } 6414180Sdougm 6424180Sdougm /* 6434180Sdougm * zfs_uninit_libshare(zhandle) 6444180Sdougm * 6454180Sdougm * Uninitialize the libshare API if it hasn't already been 6464180Sdougm * uninitialized. It is OK to call multiple times. 6474180Sdougm */ 6484180Sdougm void 6494180Sdougm zfs_uninit_libshare(libzfs_handle_t *zhandle) 6504180Sdougm { 6514180Sdougm if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) { 6524302Sdougm if (_sa_fini != NULL) 6534302Sdougm _sa_fini(zhandle->libzfs_sharehdl); 6544302Sdougm zhandle->libzfs_sharehdl = NULL; 6554180Sdougm } 6564180Sdougm } 6574180Sdougm 6584180Sdougm /* 6594180Sdougm * zfs_parse_options(options, proto) 6604180Sdougm * 6614180Sdougm * Call the legacy parse interface to get the protocol specific 6624180Sdougm * options using the NULL arg to indicate that this is a "parse" only. 6634180Sdougm */ 6644180Sdougm int 6655331Samw zfs_parse_options(char *options, zfs_share_proto_t proto) 6664180Sdougm { 6675367Sahrens if (_sa_parse_legacy_options != NULL) { 6685367Sahrens return (_sa_parse_legacy_options(NULL, options, 6695367Sahrens proto_table[proto].p_name)); 6705367Sahrens } 6715367Sahrens return (SA_CONFIG_ERR); 6724180Sdougm } 6734180Sdougm 6744180Sdougm /* 6754180Sdougm * zfs_sa_find_share(handle, path) 6764180Sdougm * 6774180Sdougm * wrapper around sa_find_share to find a share path in the 6784180Sdougm * configuration. 6794180Sdougm */ 6804180Sdougm static sa_share_t 6814180Sdougm zfs_sa_find_share(sa_handle_t handle, char *path) 6824180Sdougm { 6834180Sdougm if (_sa_find_share != NULL) 6844302Sdougm return (_sa_find_share(handle, path)); 6854180Sdougm return (NULL); 6864180Sdougm } 6874180Sdougm 6884180Sdougm /* 6894180Sdougm * zfs_sa_enable_share(share, proto) 6904180Sdougm * 6914180Sdougm * Wrapper for sa_enable_share which enables a share for a specified 6924180Sdougm * protocol. 6934180Sdougm */ 6944180Sdougm static int 6954180Sdougm zfs_sa_enable_share(sa_share_t share, char *proto) 6964180Sdougm { 6974180Sdougm if (_sa_enable_share != NULL) 6984302Sdougm return (_sa_enable_share(share, proto)); 6994180Sdougm return (SA_CONFIG_ERR); 7004180Sdougm } 7014180Sdougm 7024180Sdougm /* 7034180Sdougm * zfs_sa_disable_share(share, proto) 7044180Sdougm * 7054180Sdougm * Wrapper for sa_enable_share which disables a share for a specified 7064180Sdougm * protocol. 7074180Sdougm */ 7084180Sdougm static int 7094180Sdougm zfs_sa_disable_share(sa_share_t share, char *proto) 7104180Sdougm { 7114180Sdougm if (_sa_disable_share != NULL) 7124302Sdougm return (_sa_disable_share(share, proto)); 7134180Sdougm return (SA_CONFIG_ERR); 7144180Sdougm } 7154180Sdougm 7164180Sdougm /* 7175331Samw * Share the given filesystem according to the options in the specified 7185331Samw * protocol specific properties (sharenfs, sharesmb). We rely 7194180Sdougm * on "libshare" to the dirty work for us. 720789Sahrens */ 7215331Samw static int 7225331Samw zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 723789Sahrens { 724789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 725789Sahrens char shareopts[ZFS_MAXPROPLEN]; 7265951Sdougm char sourcestr[ZFS_MAXPROPLEN]; 7272082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 7284180Sdougm sa_share_t share; 7295331Samw zfs_share_proto_t *curr_proto; 7305951Sdougm zprop_source_t sourcetype; 7314180Sdougm int ret; 732789Sahrens 7332676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 734789Sahrens return (0); 735789Sahrens 7364180Sdougm if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 7374302Sdougm (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 7384302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), 7395951Sdougm zfs_get_name(zhp), _sa_errorstr != NULL ? 7405951Sdougm _sa_errorstr(ret) : ""); 7414302Sdougm return (-1); 7424180Sdougm } 7435331Samw 7445331Samw for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { 7455331Samw /* 7465331Samw * Return success if there are no share options. 7475331Samw */ 7485331Samw if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop, 7495951Sdougm shareopts, sizeof (shareopts), &sourcetype, sourcestr, 7505951Sdougm ZFS_MAXPROPLEN, B_FALSE) != 0 || 7515951Sdougm strcmp(shareopts, "off") == 0) 7525331Samw continue; 7535331Samw 7545331Samw /* 7555331Samw * If the 'zoned' property is set, then zfs_is_mountable() 7565331Samw * will have already bailed out if we are in the global zone. 7575331Samw * But local zones cannot be NFS servers, so we ignore it for 7585331Samw * local zones as well. 7595331Samw */ 7605331Samw if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) 7615331Samw continue; 7625331Samw 7635331Samw share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint); 7645951Sdougm if (share == NULL) { 7655951Sdougm /* 7665951Sdougm * This may be a new file system that was just 7675951Sdougm * created so isn't in the internal cache 7685951Sdougm * (second time through). Rather than 7695951Sdougm * reloading the entire configuration, we can 7705951Sdougm * assume ZFS has done the checking and it is 7715951Sdougm * safe to add this to the internal 7725951Sdougm * configuration. 7735951Sdougm */ 7745951Sdougm if (_sa_zfs_process_share(hdl->libzfs_sharehdl, 7755951Sdougm NULL, NULL, mountpoint, 7765951Sdougm proto_table[*curr_proto].p_name, sourcetype, 7775951Sdougm shareopts, sourcestr, zhp->zfs_name) != SA_OK) { 7785951Sdougm (void) zfs_error_fmt(hdl, 7795951Sdougm proto_table[*curr_proto].p_share_err, 7805951Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 7815951Sdougm zfs_get_name(zhp)); 7825951Sdougm return (-1); 7835951Sdougm } 7845951Sdougm hdl->libzfs_shareflags |= ZFSSHARE_MISS; 7855951Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, 7865951Sdougm mountpoint); 7875951Sdougm } 7885331Samw if (share != NULL) { 7895331Samw int err; 7905331Samw err = zfs_sa_enable_share(share, 7915331Samw proto_table[*curr_proto].p_name); 7925331Samw if (err != SA_OK) { 7935331Samw (void) zfs_error_fmt(hdl, 7945331Samw proto_table[*curr_proto].p_share_err, 7955331Samw dgettext(TEXT_DOMAIN, "cannot share '%s'"), 7965331Samw zfs_get_name(zhp)); 7975331Samw return (-1); 7985331Samw } 7995331Samw } else { 8005331Samw (void) zfs_error_fmt(hdl, 8015331Samw proto_table[*curr_proto].p_share_err, 8024302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 8034302Sdougm zfs_get_name(zhp)); 8044302Sdougm return (-1); 8054302Sdougm } 8065331Samw 807789Sahrens } 8085331Samw return (0); 8095331Samw } 810789Sahrens 8115331Samw 8125331Samw int 8135331Samw zfs_share_nfs(zfs_handle_t *zhp) 8145331Samw { 8155331Samw return (zfs_share_proto(zhp, nfs_only)); 8165331Samw } 8175331Samw 8185331Samw int 8195331Samw zfs_share_smb(zfs_handle_t *zhp) 8205331Samw { 8215331Samw return (zfs_share_proto(zhp, smb_only)); 8225331Samw } 8235331Samw 8245331Samw int 8255331Samw zfs_shareall(zfs_handle_t *zhp) 8265331Samw { 8275331Samw return (zfs_share_proto(zhp, share_all_proto)); 828789Sahrens } 829789Sahrens 830789Sahrens /* 8312474Seschrock * Unshare a filesystem by mountpoint. 8322474Seschrock */ 8332474Seschrock static int 8345331Samw unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, 8355331Samw zfs_share_proto_t proto) 8362474Seschrock { 8374180Sdougm sa_share_t share; 8384180Sdougm int err; 8394180Sdougm char *mntpt; 8402474Seschrock /* 8414180Sdougm * Mountpoint could get trashed if libshare calls getmntany 8428228SEric.Taylor@Sun.COM * which it does during API initialization, so strdup the 8434180Sdougm * value. 8442474Seschrock */ 8454180Sdougm mntpt = zfs_strdup(hdl, mountpoint); 8462474Seschrock 8474180Sdougm /* make sure libshare initialized */ 8484180Sdougm if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 8494180Sdougm free(mntpt); /* don't need the copy anymore */ 8504180Sdougm return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 8514302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 8524302Sdougm name, _sa_errorstr(err))); 8532474Seschrock } 8542474Seschrock 8554180Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt); 8564180Sdougm free(mntpt); /* don't need the copy anymore */ 8572474Seschrock 8584180Sdougm if (share != NULL) { 8595331Samw err = zfs_sa_disable_share(share, proto_table[proto].p_name); 8604180Sdougm if (err != SA_OK) { 8614302Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8624302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 8634302Sdougm name, _sa_errorstr(err))); 8644180Sdougm } 8654180Sdougm } else { 8664180Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8674302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"), 8684302Sdougm name)); 8694180Sdougm } 8702474Seschrock return (0); 8712474Seschrock } 8722474Seschrock 8732474Seschrock /* 874789Sahrens * Unshare the given filesystem. 875789Sahrens */ 876789Sahrens int 8775331Samw zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, 8785331Samw zfs_share_proto_t *proto) 879789Sahrens { 8808228SEric.Taylor@Sun.COM libzfs_handle_t *hdl = zhp->zfs_hdl; 8818228SEric.Taylor@Sun.COM struct mnttab entry; 8824180Sdougm char *mntpt = NULL; 883789Sahrens 884789Sahrens /* check to see if need to unmount the filesystem */ 8852082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 8864302Sdougm if (mountpoint != NULL) 8878228SEric.Taylor@Sun.COM mountpoint = mntpt = zfs_strdup(hdl, mountpoint); 8884302Sdougm 889789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 8908228SEric.Taylor@Sun.COM libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) { 8915331Samw zfs_share_proto_t *curr_proto; 892789Sahrens 893789Sahrens if (mountpoint == NULL) 8945331Samw mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 8955331Samw 8965331Samw for (curr_proto = proto; *curr_proto != PROTO_END; 8975331Samw curr_proto++) { 898789Sahrens 8998228SEric.Taylor@Sun.COM if (is_shared(hdl, mntpt, *curr_proto) && 9008228SEric.Taylor@Sun.COM unshare_one(hdl, zhp->zfs_name, 9015331Samw mntpt, *curr_proto) != 0) { 9025331Samw if (mntpt != NULL) 9035331Samw free(mntpt); 9045331Samw return (-1); 9055331Samw } 9064180Sdougm } 907789Sahrens } 9084180Sdougm if (mntpt != NULL) 9094302Sdougm free(mntpt); 910789Sahrens 911789Sahrens return (0); 912789Sahrens } 913789Sahrens 9145331Samw int 9155331Samw zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) 9165331Samw { 9175331Samw return (zfs_unshare_proto(zhp, mountpoint, nfs_only)); 9185331Samw } 9195331Samw 9205331Samw int 9215331Samw zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint) 9225331Samw { 9235331Samw return (zfs_unshare_proto(zhp, mountpoint, smb_only)); 9245331Samw } 9255331Samw 926789Sahrens /* 9275331Samw * Same as zfs_unmountall(), but for NFS and SMB unshares. 928789Sahrens */ 929789Sahrens int 9305331Samw zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 931789Sahrens { 932789Sahrens prop_changelist_t *clp; 933789Sahrens int ret; 934789Sahrens 9357366STim.Haley@Sun.COM clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0); 936789Sahrens if (clp == NULL) 937789Sahrens return (-1); 938789Sahrens 9395331Samw ret = changelist_unshare(clp, proto); 940789Sahrens changelist_free(clp); 941789Sahrens 942789Sahrens return (ret); 943789Sahrens } 944789Sahrens 9455331Samw int 9465331Samw zfs_unshareall_nfs(zfs_handle_t *zhp) 9475331Samw { 9485331Samw return (zfs_unshareall_proto(zhp, nfs_only)); 9495331Samw } 9505331Samw 9515331Samw int 9525331Samw zfs_unshareall_smb(zfs_handle_t *zhp) 9535331Samw { 9545331Samw return (zfs_unshareall_proto(zhp, smb_only)); 9555331Samw } 9565331Samw 9575331Samw int 9585331Samw zfs_unshareall(zfs_handle_t *zhp) 9595331Samw { 9605331Samw return (zfs_unshareall_proto(zhp, share_all_proto)); 9615331Samw } 9625331Samw 9635331Samw int 9645331Samw zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint) 9655331Samw { 9665331Samw return (zfs_unshare_proto(zhp, mountpoint, share_all_proto)); 9675331Samw } 9685331Samw 969789Sahrens /* 970789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 971789Sahrens * We only remove the underlying directory if: 972789Sahrens * 973789Sahrens * - The mountpoint is not 'none' or 'legacy' 974789Sahrens * - The mountpoint is non-empty 975789Sahrens * - The mountpoint is the default or inherited 976789Sahrens * - The 'zoned' property is set, or we're in a local zone 977789Sahrens * 978789Sahrens * Any other directories we leave alone. 979789Sahrens */ 980789Sahrens void 981789Sahrens remove_mountpoint(zfs_handle_t *zhp) 982789Sahrens { 983789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 9845094Slling zprop_source_t source; 985789Sahrens 9862676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), 9872676Seschrock &source)) 988789Sahrens return; 989789Sahrens 9905094Slling if (source == ZPROP_SRC_DEFAULT || 9915094Slling source == ZPROP_SRC_INHERITED) { 992789Sahrens /* 993789Sahrens * Try to remove the directory, silently ignoring any errors. 994789Sahrens * The filesystem may have since been removed or moved around, 9952676Seschrock * and this error isn't really useful to the administrator in 9962676Seschrock * any way. 997789Sahrens */ 998789Sahrens (void) rmdir(mountpoint); 999789Sahrens } 1000789Sahrens } 10012474Seschrock 10023126Sahl boolean_t 10033126Sahl zfs_is_shared_iscsi(zfs_handle_t *zhp) 10043126Sahl { 10054543Smarks 10064543Smarks /* 10074543Smarks * If iscsi deamon isn't running then we aren't shared 10084543Smarks */ 10094543Smarks if (iscsitgt_svc_online && iscsitgt_svc_online() == 1) 10105331Samw return (B_FALSE); 10114543Smarks else 10124543Smarks return (iscsitgt_zfs_is_shared != NULL && 10134543Smarks iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); 10143126Sahl } 10153126Sahl 10163126Sahl int 10173126Sahl zfs_share_iscsi(zfs_handle_t *zhp) 10183126Sahl { 10193126Sahl char shareopts[ZFS_MAXPROPLEN]; 10203126Sahl const char *dataset = zhp->zfs_name; 10213126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 10223126Sahl 10233126Sahl /* 10243126Sahl * Return success if there are no share options. 10253126Sahl */ 10263126Sahl if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 10273126Sahl sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || 10283126Sahl strcmp(shareopts, "off") == 0) 10293126Sahl return (0); 10303126Sahl 10314543Smarks if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) { 10324543Smarks int error = EZFS_SHAREISCSIFAILED; 10334543Smarks 10344543Smarks /* 10354543Smarks * If service isn't availabele and EPERM was 10364543Smarks * returned then use special error. 10374543Smarks */ 10384543Smarks if (iscsitgt_svc_online && errno == EPERM && 10394543Smarks (iscsitgt_svc_online() != 0)) 10404543Smarks error = EZFS_ISCSISVCUNAVAIL; 10414543Smarks 10424543Smarks return (zfs_error_fmt(hdl, error, 10433126Sahl dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); 10444543Smarks } 10453126Sahl 10463126Sahl return (0); 10473126Sahl } 10483126Sahl 10493126Sahl int 10503126Sahl zfs_unshare_iscsi(zfs_handle_t *zhp) 10513126Sahl { 10523126Sahl const char *dataset = zfs_get_name(zhp); 10533126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 10543126Sahl 10553126Sahl /* 10563380Sgw25295 * Return if the volume is not shared 10573380Sgw25295 */ 10585331Samw if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI) 10593380Sgw25295 return (0); 10603380Sgw25295 10613380Sgw25295 /* 10623126Sahl * If this fails with ENODEV it indicates that zvol wasn't shared so 10633126Sahl * we should return success in that case. 10643126Sahl */ 10653134Sahl if (iscsitgt_zfs_unshare == NULL || 10664543Smarks (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) { 10674543Smarks if (errno == EPERM) 10684543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10694543Smarks "Insufficient privileges to unshare iscsi")); 10703237Slling return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, 10713126Sahl dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); 10724543Smarks } 10733126Sahl 10743126Sahl return (0); 10753126Sahl } 10763126Sahl 10772474Seschrock typedef struct mount_cbdata { 10782474Seschrock zfs_handle_t **cb_datasets; 10792474Seschrock int cb_used; 10802474Seschrock int cb_alloc; 10812474Seschrock } mount_cbdata_t; 10822474Seschrock 10832474Seschrock static int 10842474Seschrock mount_cb(zfs_handle_t *zhp, void *data) 10852474Seschrock { 10862474Seschrock mount_cbdata_t *cbp = data; 10872474Seschrock 10883126Sahl if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { 10892474Seschrock zfs_close(zhp); 10902474Seschrock return (0); 10912474Seschrock } 10922474Seschrock 10936168Shs24103 if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) { 10946168Shs24103 zfs_close(zhp); 10956168Shs24103 return (0); 10966168Shs24103 } 10976168Shs24103 10982474Seschrock if (cbp->cb_alloc == cbp->cb_used) { 10992676Seschrock void *ptr; 11002474Seschrock 11012676Seschrock if ((ptr = zfs_realloc(zhp->zfs_hdl, 11022676Seschrock cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), 11032676Seschrock cbp->cb_alloc * 2 * sizeof (void *))) == NULL) 11042474Seschrock return (-1); 11052676Seschrock cbp->cb_datasets = ptr; 11062474Seschrock 11072676Seschrock cbp->cb_alloc *= 2; 11082474Seschrock } 11092474Seschrock 11102474Seschrock cbp->cb_datasets[cbp->cb_used++] = zhp; 11113126Sahl 11126027Srm160521 return (zfs_iter_filesystems(zhp, mount_cb, cbp)); 11132474Seschrock } 11142474Seschrock 11152474Seschrock static int 11163126Sahl dataset_cmp(const void *a, const void *b) 11172474Seschrock { 11182474Seschrock zfs_handle_t **za = (zfs_handle_t **)a; 11192474Seschrock zfs_handle_t **zb = (zfs_handle_t **)b; 11202474Seschrock char mounta[MAXPATHLEN]; 11212474Seschrock char mountb[MAXPATHLEN]; 11223126Sahl boolean_t gota, gotb; 11232474Seschrock 11243126Sahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 11253126Sahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 11263126Sahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 11273126Sahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 11283126Sahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 11293126Sahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 11302474Seschrock 11313126Sahl if (gota && gotb) 11323126Sahl return (strcmp(mounta, mountb)); 11333126Sahl 11343126Sahl if (gota) 11353126Sahl return (-1); 11363126Sahl if (gotb) 11373126Sahl return (1); 11383126Sahl 11393126Sahl return (strcmp(zfs_get_name(a), zfs_get_name(b))); 11402474Seschrock } 11412474Seschrock 11423126Sahl /* 11433126Sahl * Mount and share all datasets within the given pool. This assumes that no 11443126Sahl * datasets within the pool are currently mounted. Because users can create 11453126Sahl * complicated nested hierarchies of mountpoints, we first gather all the 11463126Sahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once 11473126Sahl * we have the list of all filesystems, we iterate over them in order and mount 11483126Sahl * and/or share each one. 11493126Sahl */ 11503126Sahl #pragma weak zpool_mount_datasets = zpool_enable_datasets 11512474Seschrock int 11523126Sahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) 11532474Seschrock { 11542474Seschrock mount_cbdata_t cb = { 0 }; 11552474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 11562474Seschrock zfs_handle_t *zfsp; 11572474Seschrock int i, ret = -1; 11584180Sdougm int *good; 11592474Seschrock 11602474Seschrock /* 11616027Srm160521 * Gather all non-snap datasets within the pool. 11622474Seschrock */ 11632474Seschrock if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) 11642474Seschrock return (-1); 11652474Seschrock cb.cb_alloc = 4; 11662474Seschrock 11675094Slling if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL) 11682474Seschrock goto out; 11692474Seschrock 11702474Seschrock cb.cb_datasets[0] = zfsp; 11712474Seschrock cb.cb_used = 1; 11722474Seschrock 11736027Srm160521 if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0) 11742474Seschrock goto out; 11752474Seschrock 11762474Seschrock /* 11772474Seschrock * Sort the datasets by mountpoint. 11782474Seschrock */ 11793126Sahl qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); 11802474Seschrock 11812474Seschrock /* 11824180Sdougm * And mount all the datasets, keeping track of which ones 11838536SDavid.Pacheco@Sun.COM * succeeded or failed. 11842474Seschrock */ 11858536SDavid.Pacheco@Sun.COM if ((good = zfs_alloc(zhp->zpool_hdl, 11868536SDavid.Pacheco@Sun.COM cb.cb_used * sizeof (int))) == NULL) 11878536SDavid.Pacheco@Sun.COM goto out; 11888536SDavid.Pacheco@Sun.COM 11892474Seschrock ret = 0; 11902474Seschrock for (i = 0; i < cb.cb_used; i++) { 11914302Sdougm if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0) 11924180Sdougm ret = -1; 11934302Sdougm else 11944180Sdougm good[i] = 1; 11954180Sdougm } 11965951Sdougm 11974180Sdougm /* 11984180Sdougm * Then share all the ones that need to be shared. This needs 11994180Sdougm * to be a separate pass in order to avoid excessive reloading 12004180Sdougm * of the configuration. Good should never be NULL since 12014180Sdougm * zfs_alloc is supposed to exit if memory isn't available. 12024180Sdougm */ 12034180Sdougm for (i = 0; i < cb.cb_used; i++) { 12044180Sdougm if (good[i] && zfs_share(cb.cb_datasets[i]) != 0) 12052474Seschrock ret = -1; 12062474Seschrock } 12072474Seschrock 12084180Sdougm free(good); 12094180Sdougm 12102474Seschrock out: 12112474Seschrock for (i = 0; i < cb.cb_used; i++) 12122474Seschrock zfs_close(cb.cb_datasets[i]); 12132474Seschrock free(cb.cb_datasets); 12142474Seschrock 12152474Seschrock return (ret); 12162474Seschrock } 12172474Seschrock 1218*10588SEric.Taylor@Sun.COM /*ARGSUSED1*/ 12193126Sahl static int 1220*10588SEric.Taylor@Sun.COM zvol_cb(zfs_handle_t *zhp, void *unused) 12213126Sahl { 1222*10588SEric.Taylor@Sun.COM int error = 0; 12233126Sahl 1224*10588SEric.Taylor@Sun.COM if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) 1225*10588SEric.Taylor@Sun.COM (void) zfs_iter_children(zhp, zvol_cb, NULL); 1226*10588SEric.Taylor@Sun.COM if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) 1227*10588SEric.Taylor@Sun.COM error = zfs_unshare_iscsi(zhp); 12283126Sahl zfs_close(zhp); 12293126Sahl 1230*10588SEric.Taylor@Sun.COM return (error); 12313126Sahl } 12323126Sahl 12332474Seschrock static int 12342474Seschrock mountpoint_compare(const void *a, const void *b) 12352474Seschrock { 12362474Seschrock const char *mounta = *((char **)a); 12372474Seschrock const char *mountb = *((char **)b); 12382474Seschrock 12392474Seschrock return (strcmp(mountb, mounta)); 12402474Seschrock } 12412474Seschrock 1242*10588SEric.Taylor@Sun.COM /* alias for 2002/240 */ 1243*10588SEric.Taylor@Sun.COM #pragma weak zpool_unmount_datasets = zpool_disable_datasets 12443126Sahl /* 12453126Sahl * Unshare and unmount all datasets within the given pool. We don't want to 12463126Sahl * rely on traversing the DSL to discover the filesystems within the pool, 12473126Sahl * because this may be expensive (if not all of them are mounted), and can fail 12483126Sahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and 12493126Sahl * gather all the filesystems that are currently mounted. 12503126Sahl */ 12512474Seschrock int 12523126Sahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) 12532474Seschrock { 12542474Seschrock int used, alloc; 12552474Seschrock struct mnttab entry; 12562474Seschrock size_t namelen; 12572474Seschrock char **mountpoints = NULL; 1258*10588SEric.Taylor@Sun.COM zfs_handle_t *zfp; 12592474Seschrock zfs_handle_t **datasets = NULL; 12602474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 12612474Seschrock int i; 12622474Seschrock int ret = -1; 12632474Seschrock int flags = (force ? MS_FORCE : 0); 12642474Seschrock 12653126Sahl /* 12663126Sahl * First unshare all zvols. 12673126Sahl */ 1268*10588SEric.Taylor@Sun.COM zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 1269*10588SEric.Taylor@Sun.COM ZFS_TYPE_FILESYSTEM); 1270*10588SEric.Taylor@Sun.COM if (zfp != NULL) { 1271*10588SEric.Taylor@Sun.COM (void) zfs_iter_children(zfp, zvol_cb, NULL); 1272*10588SEric.Taylor@Sun.COM zfs_close(zfp); 1273*10588SEric.Taylor@Sun.COM } 12743126Sahl 12752474Seschrock namelen = strlen(zhp->zpool_name); 12762474Seschrock 12772474Seschrock rewind(hdl->libzfs_mnttab); 12782474Seschrock used = alloc = 0; 12792474Seschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 12802474Seschrock /* 12812474Seschrock * Ignore non-ZFS entries. 12822474Seschrock */ 12832474Seschrock if (entry.mnt_fstype == NULL || 12842474Seschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 12852474Seschrock continue; 12862474Seschrock 12872474Seschrock /* 12882474Seschrock * Ignore filesystems not within this pool. 12892474Seschrock */ 12902474Seschrock if (entry.mnt_mountp == NULL || 12912474Seschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 || 12922474Seschrock (entry.mnt_special[namelen] != '/' && 12932474Seschrock entry.mnt_special[namelen] != '\0')) 12942474Seschrock continue; 12952474Seschrock 12962474Seschrock /* 12972474Seschrock * At this point we've found a filesystem within our pool. Add 12982474Seschrock * it to our growing list. 12992474Seschrock */ 13002474Seschrock if (used == alloc) { 13012474Seschrock if (alloc == 0) { 13022474Seschrock if ((mountpoints = zfs_alloc(hdl, 13032474Seschrock 8 * sizeof (void *))) == NULL) 13042474Seschrock goto out; 13052474Seschrock 13062474Seschrock if ((datasets = zfs_alloc(hdl, 13072474Seschrock 8 * sizeof (void *))) == NULL) 13082474Seschrock goto out; 13092474Seschrock 13102474Seschrock alloc = 8; 13112474Seschrock } else { 13122676Seschrock void *ptr; 13132474Seschrock 13142676Seschrock if ((ptr = zfs_realloc(hdl, mountpoints, 13152676Seschrock alloc * sizeof (void *), 13162474Seschrock alloc * 2 * sizeof (void *))) == NULL) 13172474Seschrock goto out; 13182676Seschrock mountpoints = ptr; 13192474Seschrock 13202676Seschrock if ((ptr = zfs_realloc(hdl, datasets, 13212676Seschrock alloc * sizeof (void *), 13222474Seschrock alloc * 2 * sizeof (void *))) == NULL) 13232474Seschrock goto out; 13242676Seschrock datasets = ptr; 13252474Seschrock 13262474Seschrock alloc *= 2; 13272474Seschrock } 13282474Seschrock } 13292474Seschrock 13302474Seschrock if ((mountpoints[used] = zfs_strdup(hdl, 13312474Seschrock entry.mnt_mountp)) == NULL) 13322474Seschrock goto out; 13332474Seschrock 13342474Seschrock /* 13352474Seschrock * This is allowed to fail, in case there is some I/O error. It 13362474Seschrock * is only used to determine if we need to remove the underlying 13372474Seschrock * mountpoint, so failure is not fatal. 13382474Seschrock */ 13392474Seschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special); 13402474Seschrock 13412474Seschrock used++; 13422474Seschrock } 13432474Seschrock 13442474Seschrock /* 13452474Seschrock * At this point, we have the entire list of filesystems, so sort it by 13462474Seschrock * mountpoint. 13472474Seschrock */ 13482474Seschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare); 13492474Seschrock 13502474Seschrock /* 13512474Seschrock * Walk through and first unshare everything. 13522474Seschrock */ 13532474Seschrock for (i = 0; i < used; i++) { 13545331Samw zfs_share_proto_t *curr_proto; 13555331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 13565331Samw curr_proto++) { 13575331Samw if (is_shared(hdl, mountpoints[i], *curr_proto) && 13585331Samw unshare_one(hdl, mountpoints[i], 13595331Samw mountpoints[i], *curr_proto) != 0) 13605331Samw goto out; 13615331Samw } 13622474Seschrock } 13632474Seschrock 13642474Seschrock /* 13652474Seschrock * Now unmount everything, removing the underlying directories as 13662474Seschrock * appropriate. 13672474Seschrock */ 13682474Seschrock for (i = 0; i < used; i++) { 13692474Seschrock if (unmount_one(hdl, mountpoints[i], flags) != 0) 13702474Seschrock goto out; 13712676Seschrock } 13722474Seschrock 13732676Seschrock for (i = 0; i < used; i++) { 13742474Seschrock if (datasets[i]) 13752474Seschrock remove_mountpoint(datasets[i]); 13762474Seschrock } 13772474Seschrock 13782474Seschrock ret = 0; 13792474Seschrock out: 13802474Seschrock for (i = 0; i < used; i++) { 13812474Seschrock if (datasets[i]) 13822474Seschrock zfs_close(datasets[i]); 13832474Seschrock free(mountpoints[i]); 13842474Seschrock } 13852474Seschrock free(datasets); 13862474Seschrock free(mountpoints); 13872474Seschrock 13882474Seschrock return (ret); 13892474Seschrock } 1390