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*11814SChris.Kirby@sun.com * Copyright 2010 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")); 348*11814SChris.Kirby@sun.com } else if (errno == ENOTSUP) { 349*11814SChris.Kirby@sun.com char buf[256]; 350*11814SChris.Kirby@sun.com 351*11814SChris.Kirby@sun.com (void) snprintf(buf, sizeof (buf), 352*11814SChris.Kirby@sun.com dgettext(TEXT_DOMAIN, "Mismatched versions: File " 353*11814SChris.Kirby@sun.com "system is version %llu on-disk format, which is " 354*11814SChris.Kirby@sun.com "incompatible with this software version %lld!"), 355*11814SChris.Kirby@sun.com (u_longlong_t)zfs_prop_get_int(zhp, 356*11814SChris.Kirby@sun.com ZFS_PROP_VERSION), ZPL_VERSION); 357*11814SChris.Kirby@sun.com zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf)); 3584302Sdougm } else { 3592082Seschrock zfs_error_aux(hdl, strerror(errno)); 3604302Sdougm } 3613237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3622082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 3632082Seschrock zhp->zfs_name)); 364789Sahrens } 365789Sahrens 3668228SEric.Taylor@Sun.COM /* add the mounted entry into our cache */ 3678228SEric.Taylor@Sun.COM libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint, 3688228SEric.Taylor@Sun.COM mntopts); 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 { 3948228SEric.Taylor@Sun.COM libzfs_handle_t *hdl = zhp->zfs_hdl; 3958228SEric.Taylor@Sun.COM struct mnttab entry; 3964180Sdougm char *mntpt = NULL; 397789Sahrens 3988228SEric.Taylor@Sun.COM /* check to see if we need to unmount the filesystem */ 399789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 4008228SEric.Taylor@Sun.COM libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) { 4014180Sdougm /* 4024180Sdougm * mountpoint may have come from a call to 4034180Sdougm * getmnt/getmntany if it isn't NULL. If it is NULL, 4048228SEric.Taylor@Sun.COM * we know it comes from libzfs_mnttab_find which can 4058228SEric.Taylor@Sun.COM * then get freed later. We strdup it to play it safe. 4064180Sdougm */ 407789Sahrens if (mountpoint == NULL) 4088228SEric.Taylor@Sun.COM mntpt = zfs_strdup(hdl, entry.mnt_mountp); 4094180Sdougm else 4108228SEric.Taylor@Sun.COM mntpt = zfs_strdup(hdl, mountpoint); 411789Sahrens 412789Sahrens /* 4132474Seschrock * Unshare and unmount the filesystem 414789Sahrens */ 4155331Samw if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) 4164331Sth199096 return (-1); 4174331Sth199096 4188228SEric.Taylor@Sun.COM if (unmount_one(hdl, mntpt, flags) != 0) { 4194180Sdougm free(mntpt); 4205331Samw (void) zfs_shareall(zhp); 421789Sahrens return (-1); 4224180Sdougm } 4238228SEric.Taylor@Sun.COM libzfs_mnttab_remove(hdl, zhp->zfs_name); 4244180Sdougm free(mntpt); 425789Sahrens } 426789Sahrens 427789Sahrens return (0); 428789Sahrens } 429789Sahrens 430789Sahrens /* 431789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 432789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 433789Sahrens * remount the filesystems afterwards. 434789Sahrens */ 435789Sahrens int 436789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 437789Sahrens { 438789Sahrens prop_changelist_t *clp; 439789Sahrens int ret; 440789Sahrens 4417366STim.Haley@Sun.COM clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags); 442789Sahrens if (clp == NULL) 443789Sahrens return (-1); 444789Sahrens 445789Sahrens ret = changelist_prefix(clp); 446789Sahrens changelist_free(clp); 447789Sahrens 448789Sahrens return (ret); 449789Sahrens } 450789Sahrens 4513126Sahl boolean_t 4523126Sahl zfs_is_shared(zfs_handle_t *zhp) 4533126Sahl { 4545331Samw zfs_share_type_t rc = 0; 4555331Samw zfs_share_proto_t *curr_proto; 4565331Samw 4573126Sahl if (ZFS_IS_VOLUME(zhp)) 4583126Sahl return (zfs_is_shared_iscsi(zhp)); 4593126Sahl 4605331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 4615331Samw curr_proto++) 4625331Samw rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto); 4635331Samw 4645331Samw return (rc ? B_TRUE : B_FALSE); 4653126Sahl } 4663126Sahl 4673126Sahl int 4683126Sahl zfs_share(zfs_handle_t *zhp) 4693126Sahl { 4703126Sahl if (ZFS_IS_VOLUME(zhp)) 4713126Sahl return (zfs_share_iscsi(zhp)); 4723126Sahl 4735331Samw return (zfs_share_proto(zhp, share_all_proto)); 4743126Sahl } 4753126Sahl 4763126Sahl int 4773126Sahl zfs_unshare(zfs_handle_t *zhp) 4783126Sahl { 4793126Sahl if (ZFS_IS_VOLUME(zhp)) 4803126Sahl return (zfs_unshare_iscsi(zhp)); 4813126Sahl 4825331Samw return (zfs_unshareall(zhp)); 4833126Sahl } 4843126Sahl 485789Sahrens /* 486789Sahrens * Check to see if the filesystem is currently shared. 487789Sahrens */ 4885331Samw zfs_share_type_t 4895331Samw zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto) 490789Sahrens { 491789Sahrens char *mountpoint; 4925331Samw zfs_share_type_t rc; 493789Sahrens 494789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 4955331Samw return (SHARED_NOT_SHARED); 496789Sahrens 4975331Samw if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) { 498789Sahrens if (where != NULL) 499789Sahrens *where = mountpoint; 500789Sahrens else 501789Sahrens free(mountpoint); 5025331Samw return (rc); 503789Sahrens } else { 504789Sahrens free(mountpoint); 5055331Samw return (SHARED_NOT_SHARED); 506789Sahrens } 507789Sahrens } 508789Sahrens 5095331Samw boolean_t 5105331Samw zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) 5115331Samw { 5125331Samw return (zfs_is_shared_proto(zhp, where, 5135331Samw PROTO_NFS) != SHARED_NOT_SHARED); 5145331Samw } 5155331Samw 5165331Samw boolean_t 5175331Samw zfs_is_shared_smb(zfs_handle_t *zhp, char **where) 5185331Samw { 5195331Samw return (zfs_is_shared_proto(zhp, where, 5205331Samw PROTO_SMB) != SHARED_NOT_SHARED); 5215331Samw } 5225331Samw 523789Sahrens /* 5244180Sdougm * Make sure things will work if libshare isn't installed by using 5254180Sdougm * wrapper functions that check to see that the pointers to functions 5264180Sdougm * initialized in _zfs_init_libshare() are actually present. 5274180Sdougm */ 5284180Sdougm 5294180Sdougm static sa_handle_t (*_sa_init)(int); 5304180Sdougm static void (*_sa_fini)(sa_handle_t); 5314180Sdougm static sa_share_t (*_sa_find_share)(sa_handle_t, char *); 5324180Sdougm static int (*_sa_enable_share)(sa_share_t, char *); 5334180Sdougm static int (*_sa_disable_share)(sa_share_t, char *); 5344180Sdougm static char *(*_sa_errorstr)(int); 5354180Sdougm static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *); 5365951Sdougm static boolean_t (*_sa_needs_refresh)(sa_handle_t *); 5375951Sdougm static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t); 5385951Sdougm static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t, 5395951Sdougm char *, char *, zprop_source_t, char *, char *, char *); 5405951Sdougm static void (*_sa_update_sharetab_ts)(sa_handle_t); 5414180Sdougm 5424180Sdougm /* 5434180Sdougm * _zfs_init_libshare() 5444180Sdougm * 5454180Sdougm * Find the libshare.so.1 entry points that we use here and save the 5464180Sdougm * values to be used later. This is triggered by the runtime loader. 5474180Sdougm * Make sure the correct ISA version is loaded. 5484180Sdougm */ 5495951Sdougm 5504180Sdougm #pragma init(_zfs_init_libshare) 5514180Sdougm static void 5524180Sdougm _zfs_init_libshare(void) 5534180Sdougm { 5544180Sdougm void *libshare; 5554180Sdougm char path[MAXPATHLEN]; 5564180Sdougm char isa[MAXISALEN]; 5574180Sdougm 5584180Sdougm #if defined(_LP64) 5594180Sdougm if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1) 5604302Sdougm isa[0] = '\0'; 5614180Sdougm #else 5624180Sdougm isa[0] = '\0'; 5634180Sdougm #endif 5644180Sdougm (void) snprintf(path, MAXPATHLEN, 5654302Sdougm "/usr/lib/%s/libshare.so.1", isa); 5664180Sdougm 5674180Sdougm if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) { 5684302Sdougm _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init"); 5694302Sdougm _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini"); 5704302Sdougm _sa_find_share = (sa_share_t (*)(sa_handle_t, char *)) 5714302Sdougm dlsym(libshare, "sa_find_share"); 5724302Sdougm _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5734302Sdougm "sa_enable_share"); 5744302Sdougm _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5754302Sdougm "sa_disable_share"); 5764302Sdougm _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr"); 5774302Sdougm _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *)) 5784302Sdougm dlsym(libshare, "sa_parse_legacy_options"); 5795951Sdougm _sa_needs_refresh = (boolean_t (*)(sa_handle_t *)) 5805951Sdougm dlsym(libshare, "sa_needs_refresh"); 5815951Sdougm _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t)) 5825951Sdougm dlsym(libshare, "sa_get_zfs_handle"); 5835951Sdougm _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t, 5845951Sdougm sa_share_t, char *, char *, zprop_source_t, char *, 5855951Sdougm char *, char *))dlsym(libshare, "sa_zfs_process_share"); 5865951Sdougm _sa_update_sharetab_ts = (void (*)(sa_handle_t)) 5875951Sdougm dlsym(libshare, "sa_update_sharetab_ts"); 5884327Sdougm if (_sa_init == NULL || _sa_fini == NULL || 5894327Sdougm _sa_find_share == NULL || _sa_enable_share == NULL || 5904327Sdougm _sa_disable_share == NULL || _sa_errorstr == NULL || 5915951Sdougm _sa_parse_legacy_options == NULL || 5925951Sdougm _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL || 5935951Sdougm _sa_zfs_process_share == NULL || 5945951Sdougm _sa_update_sharetab_ts == NULL) { 5954327Sdougm _sa_init = NULL; 5964327Sdougm _sa_fini = NULL; 5974327Sdougm _sa_disable_share = NULL; 5984327Sdougm _sa_enable_share = NULL; 5994327Sdougm _sa_errorstr = NULL; 6004327Sdougm _sa_parse_legacy_options = NULL; 6014327Sdougm (void) dlclose(libshare); 6025951Sdougm _sa_needs_refresh = NULL; 6035951Sdougm _sa_get_zfs_handle = NULL; 6045951Sdougm _sa_zfs_process_share = NULL; 6055951Sdougm _sa_update_sharetab_ts = NULL; 6064327Sdougm } 6074180Sdougm } 6084180Sdougm } 6094180Sdougm 6104180Sdougm /* 6114180Sdougm * zfs_init_libshare(zhandle, service) 6124180Sdougm * 6134180Sdougm * Initialize the libshare API if it hasn't already been initialized. 6144180Sdougm * In all cases it returns 0 if it succeeded and an error if not. The 6154180Sdougm * service value is which part(s) of the API to initialize and is a 6164180Sdougm * direct map to the libshare sa_init(service) interface. 6174180Sdougm */ 6184180Sdougm int 6194180Sdougm zfs_init_libshare(libzfs_handle_t *zhandle, int service) 6204180Sdougm { 6214180Sdougm int ret = SA_OK; 6224180Sdougm 6234302Sdougm if (_sa_init == NULL) 6244302Sdougm ret = SA_CONFIG_ERR; 6254302Sdougm 6265951Sdougm if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) { 6275951Sdougm /* 6285951Sdougm * We had a cache miss. Most likely it is a new ZFS 6295951Sdougm * dataset that was just created. We want to make sure 6305951Sdougm * so check timestamps to see if a different process 6315951Sdougm * has updated any of the configuration. If there was 6325951Sdougm * some non-ZFS change, we need to re-initialize the 6335951Sdougm * internal cache. 6345951Sdougm */ 6355951Sdougm zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS; 6365951Sdougm if (_sa_needs_refresh != NULL && 6375951Sdougm _sa_needs_refresh(zhandle->libzfs_sharehdl)) { 6385951Sdougm zfs_uninit_libshare(zhandle); 6395951Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 6405951Sdougm } 6415951Sdougm } 6425951Sdougm 6434302Sdougm if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL) 6444302Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 6454302Sdougm 6464302Sdougm if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL) 6474302Sdougm ret = SA_NO_MEMORY; 6484302Sdougm 6494180Sdougm return (ret); 6504180Sdougm } 6514180Sdougm 6524180Sdougm /* 6534180Sdougm * zfs_uninit_libshare(zhandle) 6544180Sdougm * 6554180Sdougm * Uninitialize the libshare API if it hasn't already been 6564180Sdougm * uninitialized. It is OK to call multiple times. 6574180Sdougm */ 6584180Sdougm void 6594180Sdougm zfs_uninit_libshare(libzfs_handle_t *zhandle) 6604180Sdougm { 6614180Sdougm if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) { 6624302Sdougm if (_sa_fini != NULL) 6634302Sdougm _sa_fini(zhandle->libzfs_sharehdl); 6644302Sdougm zhandle->libzfs_sharehdl = NULL; 6654180Sdougm } 6664180Sdougm } 6674180Sdougm 6684180Sdougm /* 6694180Sdougm * zfs_parse_options(options, proto) 6704180Sdougm * 6714180Sdougm * Call the legacy parse interface to get the protocol specific 6724180Sdougm * options using the NULL arg to indicate that this is a "parse" only. 6734180Sdougm */ 6744180Sdougm int 6755331Samw zfs_parse_options(char *options, zfs_share_proto_t proto) 6764180Sdougm { 6775367Sahrens if (_sa_parse_legacy_options != NULL) { 6785367Sahrens return (_sa_parse_legacy_options(NULL, options, 6795367Sahrens proto_table[proto].p_name)); 6805367Sahrens } 6815367Sahrens return (SA_CONFIG_ERR); 6824180Sdougm } 6834180Sdougm 6844180Sdougm /* 6854180Sdougm * zfs_sa_find_share(handle, path) 6864180Sdougm * 6874180Sdougm * wrapper around sa_find_share to find a share path in the 6884180Sdougm * configuration. 6894180Sdougm */ 6904180Sdougm static sa_share_t 6914180Sdougm zfs_sa_find_share(sa_handle_t handle, char *path) 6924180Sdougm { 6934180Sdougm if (_sa_find_share != NULL) 6944302Sdougm return (_sa_find_share(handle, path)); 6954180Sdougm return (NULL); 6964180Sdougm } 6974180Sdougm 6984180Sdougm /* 6994180Sdougm * zfs_sa_enable_share(share, proto) 7004180Sdougm * 7014180Sdougm * Wrapper for sa_enable_share which enables a share for a specified 7024180Sdougm * protocol. 7034180Sdougm */ 7044180Sdougm static int 7054180Sdougm zfs_sa_enable_share(sa_share_t share, char *proto) 7064180Sdougm { 7074180Sdougm if (_sa_enable_share != NULL) 7084302Sdougm return (_sa_enable_share(share, proto)); 7094180Sdougm return (SA_CONFIG_ERR); 7104180Sdougm } 7114180Sdougm 7124180Sdougm /* 7134180Sdougm * zfs_sa_disable_share(share, proto) 7144180Sdougm * 7154180Sdougm * Wrapper for sa_enable_share which disables a share for a specified 7164180Sdougm * protocol. 7174180Sdougm */ 7184180Sdougm static int 7194180Sdougm zfs_sa_disable_share(sa_share_t share, char *proto) 7204180Sdougm { 7214180Sdougm if (_sa_disable_share != NULL) 7224302Sdougm return (_sa_disable_share(share, proto)); 7234180Sdougm return (SA_CONFIG_ERR); 7244180Sdougm } 7254180Sdougm 7264180Sdougm /* 7275331Samw * Share the given filesystem according to the options in the specified 7285331Samw * protocol specific properties (sharenfs, sharesmb). We rely 7294180Sdougm * on "libshare" to the dirty work for us. 730789Sahrens */ 7315331Samw static int 7325331Samw zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 733789Sahrens { 734789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 735789Sahrens char shareopts[ZFS_MAXPROPLEN]; 7365951Sdougm char sourcestr[ZFS_MAXPROPLEN]; 7372082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 7384180Sdougm sa_share_t share; 7395331Samw zfs_share_proto_t *curr_proto; 7405951Sdougm zprop_source_t sourcetype; 7414180Sdougm int ret; 742789Sahrens 7432676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 744789Sahrens return (0); 745789Sahrens 7464180Sdougm if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 7474302Sdougm (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 7484302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), 7495951Sdougm zfs_get_name(zhp), _sa_errorstr != NULL ? 7505951Sdougm _sa_errorstr(ret) : ""); 7514302Sdougm return (-1); 7524180Sdougm } 7535331Samw 7545331Samw for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { 7555331Samw /* 7565331Samw * Return success if there are no share options. 7575331Samw */ 7585331Samw if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop, 7595951Sdougm shareopts, sizeof (shareopts), &sourcetype, sourcestr, 7605951Sdougm ZFS_MAXPROPLEN, B_FALSE) != 0 || 7615951Sdougm strcmp(shareopts, "off") == 0) 7625331Samw continue; 7635331Samw 7645331Samw /* 7655331Samw * If the 'zoned' property is set, then zfs_is_mountable() 7665331Samw * will have already bailed out if we are in the global zone. 7675331Samw * But local zones cannot be NFS servers, so we ignore it for 7685331Samw * local zones as well. 7695331Samw */ 7705331Samw if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) 7715331Samw continue; 7725331Samw 7735331Samw share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint); 7745951Sdougm if (share == NULL) { 7755951Sdougm /* 7765951Sdougm * This may be a new file system that was just 7775951Sdougm * created so isn't in the internal cache 7785951Sdougm * (second time through). Rather than 7795951Sdougm * reloading the entire configuration, we can 7805951Sdougm * assume ZFS has done the checking and it is 7815951Sdougm * safe to add this to the internal 7825951Sdougm * configuration. 7835951Sdougm */ 7845951Sdougm if (_sa_zfs_process_share(hdl->libzfs_sharehdl, 7855951Sdougm NULL, NULL, mountpoint, 7865951Sdougm proto_table[*curr_proto].p_name, sourcetype, 7875951Sdougm shareopts, sourcestr, zhp->zfs_name) != SA_OK) { 7885951Sdougm (void) zfs_error_fmt(hdl, 7895951Sdougm proto_table[*curr_proto].p_share_err, 7905951Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 7915951Sdougm zfs_get_name(zhp)); 7925951Sdougm return (-1); 7935951Sdougm } 7945951Sdougm hdl->libzfs_shareflags |= ZFSSHARE_MISS; 7955951Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, 7965951Sdougm mountpoint); 7975951Sdougm } 7985331Samw if (share != NULL) { 7995331Samw int err; 8005331Samw err = zfs_sa_enable_share(share, 8015331Samw proto_table[*curr_proto].p_name); 8025331Samw if (err != SA_OK) { 8035331Samw (void) zfs_error_fmt(hdl, 8045331Samw proto_table[*curr_proto].p_share_err, 8055331Samw dgettext(TEXT_DOMAIN, "cannot share '%s'"), 8065331Samw zfs_get_name(zhp)); 8075331Samw return (-1); 8085331Samw } 8095331Samw } else { 8105331Samw (void) zfs_error_fmt(hdl, 8115331Samw proto_table[*curr_proto].p_share_err, 8124302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 8134302Sdougm zfs_get_name(zhp)); 8144302Sdougm return (-1); 8154302Sdougm } 8165331Samw 817789Sahrens } 8185331Samw return (0); 8195331Samw } 820789Sahrens 8215331Samw 8225331Samw int 8235331Samw zfs_share_nfs(zfs_handle_t *zhp) 8245331Samw { 8255331Samw return (zfs_share_proto(zhp, nfs_only)); 8265331Samw } 8275331Samw 8285331Samw int 8295331Samw zfs_share_smb(zfs_handle_t *zhp) 8305331Samw { 8315331Samw return (zfs_share_proto(zhp, smb_only)); 8325331Samw } 8335331Samw 8345331Samw int 8355331Samw zfs_shareall(zfs_handle_t *zhp) 8365331Samw { 8375331Samw return (zfs_share_proto(zhp, share_all_proto)); 838789Sahrens } 839789Sahrens 840789Sahrens /* 8412474Seschrock * Unshare a filesystem by mountpoint. 8422474Seschrock */ 8432474Seschrock static int 8445331Samw unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, 8455331Samw zfs_share_proto_t proto) 8462474Seschrock { 8474180Sdougm sa_share_t share; 8484180Sdougm int err; 8494180Sdougm char *mntpt; 8502474Seschrock /* 8514180Sdougm * Mountpoint could get trashed if libshare calls getmntany 8528228SEric.Taylor@Sun.COM * which it does during API initialization, so strdup the 8534180Sdougm * value. 8542474Seschrock */ 8554180Sdougm mntpt = zfs_strdup(hdl, mountpoint); 8562474Seschrock 8574180Sdougm /* make sure libshare initialized */ 8584180Sdougm if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 8594180Sdougm free(mntpt); /* don't need the copy anymore */ 8604180Sdougm return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 8614302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 8624302Sdougm name, _sa_errorstr(err))); 8632474Seschrock } 8642474Seschrock 8654180Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt); 8664180Sdougm free(mntpt); /* don't need the copy anymore */ 8672474Seschrock 8684180Sdougm if (share != NULL) { 8695331Samw err = zfs_sa_disable_share(share, proto_table[proto].p_name); 8704180Sdougm if (err != SA_OK) { 8714302Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8724302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 8734302Sdougm name, _sa_errorstr(err))); 8744180Sdougm } 8754180Sdougm } else { 8764180Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8774302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"), 8784302Sdougm name)); 8794180Sdougm } 8802474Seschrock return (0); 8812474Seschrock } 8822474Seschrock 8832474Seschrock /* 884789Sahrens * Unshare the given filesystem. 885789Sahrens */ 886789Sahrens int 8875331Samw zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, 8885331Samw zfs_share_proto_t *proto) 889789Sahrens { 8908228SEric.Taylor@Sun.COM libzfs_handle_t *hdl = zhp->zfs_hdl; 8918228SEric.Taylor@Sun.COM struct mnttab entry; 8924180Sdougm char *mntpt = NULL; 893789Sahrens 894789Sahrens /* check to see if need to unmount the filesystem */ 8952082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 8964302Sdougm if (mountpoint != NULL) 8978228SEric.Taylor@Sun.COM mountpoint = mntpt = zfs_strdup(hdl, mountpoint); 8984302Sdougm 899789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 9008228SEric.Taylor@Sun.COM libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) { 9015331Samw zfs_share_proto_t *curr_proto; 902789Sahrens 903789Sahrens if (mountpoint == NULL) 9045331Samw mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 9055331Samw 9065331Samw for (curr_proto = proto; *curr_proto != PROTO_END; 9075331Samw curr_proto++) { 908789Sahrens 9098228SEric.Taylor@Sun.COM if (is_shared(hdl, mntpt, *curr_proto) && 9108228SEric.Taylor@Sun.COM unshare_one(hdl, zhp->zfs_name, 9115331Samw mntpt, *curr_proto) != 0) { 9125331Samw if (mntpt != NULL) 9135331Samw free(mntpt); 9145331Samw return (-1); 9155331Samw } 9164180Sdougm } 917789Sahrens } 9184180Sdougm if (mntpt != NULL) 9194302Sdougm free(mntpt); 920789Sahrens 921789Sahrens return (0); 922789Sahrens } 923789Sahrens 9245331Samw int 9255331Samw zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) 9265331Samw { 9275331Samw return (zfs_unshare_proto(zhp, mountpoint, nfs_only)); 9285331Samw } 9295331Samw 9305331Samw int 9315331Samw zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint) 9325331Samw { 9335331Samw return (zfs_unshare_proto(zhp, mountpoint, smb_only)); 9345331Samw } 9355331Samw 936789Sahrens /* 9375331Samw * Same as zfs_unmountall(), but for NFS and SMB unshares. 938789Sahrens */ 939789Sahrens int 9405331Samw zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 941789Sahrens { 942789Sahrens prop_changelist_t *clp; 943789Sahrens int ret; 944789Sahrens 9457366STim.Haley@Sun.COM clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0); 946789Sahrens if (clp == NULL) 947789Sahrens return (-1); 948789Sahrens 9495331Samw ret = changelist_unshare(clp, proto); 950789Sahrens changelist_free(clp); 951789Sahrens 952789Sahrens return (ret); 953789Sahrens } 954789Sahrens 9555331Samw int 9565331Samw zfs_unshareall_nfs(zfs_handle_t *zhp) 9575331Samw { 9585331Samw return (zfs_unshareall_proto(zhp, nfs_only)); 9595331Samw } 9605331Samw 9615331Samw int 9625331Samw zfs_unshareall_smb(zfs_handle_t *zhp) 9635331Samw { 9645331Samw return (zfs_unshareall_proto(zhp, smb_only)); 9655331Samw } 9665331Samw 9675331Samw int 9685331Samw zfs_unshareall(zfs_handle_t *zhp) 9695331Samw { 9705331Samw return (zfs_unshareall_proto(zhp, share_all_proto)); 9715331Samw } 9725331Samw 9735331Samw int 9745331Samw zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint) 9755331Samw { 9765331Samw return (zfs_unshare_proto(zhp, mountpoint, share_all_proto)); 9775331Samw } 9785331Samw 979789Sahrens /* 980789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 981789Sahrens * We only remove the underlying directory if: 982789Sahrens * 983789Sahrens * - The mountpoint is not 'none' or 'legacy' 984789Sahrens * - The mountpoint is non-empty 985789Sahrens * - The mountpoint is the default or inherited 986789Sahrens * - The 'zoned' property is set, or we're in a local zone 987789Sahrens * 988789Sahrens * Any other directories we leave alone. 989789Sahrens */ 990789Sahrens void 991789Sahrens remove_mountpoint(zfs_handle_t *zhp) 992789Sahrens { 993789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 9945094Slling zprop_source_t source; 995789Sahrens 9962676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), 9972676Seschrock &source)) 998789Sahrens return; 999789Sahrens 10005094Slling if (source == ZPROP_SRC_DEFAULT || 10015094Slling source == ZPROP_SRC_INHERITED) { 1002789Sahrens /* 1003789Sahrens * Try to remove the directory, silently ignoring any errors. 1004789Sahrens * The filesystem may have since been removed or moved around, 10052676Seschrock * and this error isn't really useful to the administrator in 10062676Seschrock * any way. 1007789Sahrens */ 1008789Sahrens (void) rmdir(mountpoint); 1009789Sahrens } 1010789Sahrens } 10112474Seschrock 10123126Sahl boolean_t 10133126Sahl zfs_is_shared_iscsi(zfs_handle_t *zhp) 10143126Sahl { 10154543Smarks 10164543Smarks /* 10174543Smarks * If iscsi deamon isn't running then we aren't shared 10184543Smarks */ 10194543Smarks if (iscsitgt_svc_online && iscsitgt_svc_online() == 1) 10205331Samw return (B_FALSE); 10214543Smarks else 10224543Smarks return (iscsitgt_zfs_is_shared != NULL && 10234543Smarks iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); 10243126Sahl } 10253126Sahl 10263126Sahl int 10273126Sahl zfs_share_iscsi(zfs_handle_t *zhp) 10283126Sahl { 10293126Sahl char shareopts[ZFS_MAXPROPLEN]; 10303126Sahl const char *dataset = zhp->zfs_name; 10313126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 10323126Sahl 10333126Sahl /* 10343126Sahl * Return success if there are no share options. 10353126Sahl */ 10363126Sahl if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 10373126Sahl sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || 10383126Sahl strcmp(shareopts, "off") == 0) 10393126Sahl return (0); 10403126Sahl 10414543Smarks if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) { 10424543Smarks int error = EZFS_SHAREISCSIFAILED; 10434543Smarks 10444543Smarks /* 10454543Smarks * If service isn't availabele and EPERM was 10464543Smarks * returned then use special error. 10474543Smarks */ 10484543Smarks if (iscsitgt_svc_online && errno == EPERM && 10494543Smarks (iscsitgt_svc_online() != 0)) 10504543Smarks error = EZFS_ISCSISVCUNAVAIL; 10514543Smarks 10524543Smarks return (zfs_error_fmt(hdl, error, 10533126Sahl dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); 10544543Smarks } 10553126Sahl 10563126Sahl return (0); 10573126Sahl } 10583126Sahl 10593126Sahl int 10603126Sahl zfs_unshare_iscsi(zfs_handle_t *zhp) 10613126Sahl { 10623126Sahl const char *dataset = zfs_get_name(zhp); 10633126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 10643126Sahl 10653126Sahl /* 10663380Sgw25295 * Return if the volume is not shared 10673380Sgw25295 */ 10685331Samw if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI) 10693380Sgw25295 return (0); 10703380Sgw25295 10713380Sgw25295 /* 10723126Sahl * If this fails with ENODEV it indicates that zvol wasn't shared so 10733126Sahl * we should return success in that case. 10743126Sahl */ 10753134Sahl if (iscsitgt_zfs_unshare == NULL || 10764543Smarks (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) { 10774543Smarks if (errno == EPERM) 10784543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10794543Smarks "Insufficient privileges to unshare iscsi")); 10803237Slling return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, 10813126Sahl dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); 10824543Smarks } 10833126Sahl 10843126Sahl return (0); 10853126Sahl } 10863126Sahl 10872474Seschrock typedef struct mount_cbdata { 10882474Seschrock zfs_handle_t **cb_datasets; 10892474Seschrock int cb_used; 10902474Seschrock int cb_alloc; 10912474Seschrock } mount_cbdata_t; 10922474Seschrock 10932474Seschrock static int 10942474Seschrock mount_cb(zfs_handle_t *zhp, void *data) 10952474Seschrock { 10962474Seschrock mount_cbdata_t *cbp = data; 10972474Seschrock 10983126Sahl if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { 10992474Seschrock zfs_close(zhp); 11002474Seschrock return (0); 11012474Seschrock } 11022474Seschrock 11036168Shs24103 if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) { 11046168Shs24103 zfs_close(zhp); 11056168Shs24103 return (0); 11066168Shs24103 } 11076168Shs24103 11082474Seschrock if (cbp->cb_alloc == cbp->cb_used) { 11092676Seschrock void *ptr; 11102474Seschrock 11112676Seschrock if ((ptr = zfs_realloc(zhp->zfs_hdl, 11122676Seschrock cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), 11132676Seschrock cbp->cb_alloc * 2 * sizeof (void *))) == NULL) 11142474Seschrock return (-1); 11152676Seschrock cbp->cb_datasets = ptr; 11162474Seschrock 11172676Seschrock cbp->cb_alloc *= 2; 11182474Seschrock } 11192474Seschrock 11202474Seschrock cbp->cb_datasets[cbp->cb_used++] = zhp; 11213126Sahl 11226027Srm160521 return (zfs_iter_filesystems(zhp, mount_cb, cbp)); 11232474Seschrock } 11242474Seschrock 11252474Seschrock static int 11263126Sahl dataset_cmp(const void *a, const void *b) 11272474Seschrock { 11282474Seschrock zfs_handle_t **za = (zfs_handle_t **)a; 11292474Seschrock zfs_handle_t **zb = (zfs_handle_t **)b; 11302474Seschrock char mounta[MAXPATHLEN]; 11312474Seschrock char mountb[MAXPATHLEN]; 11323126Sahl boolean_t gota, gotb; 11332474Seschrock 11343126Sahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 11353126Sahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 11363126Sahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 11373126Sahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 11383126Sahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 11393126Sahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 11402474Seschrock 11413126Sahl if (gota && gotb) 11423126Sahl return (strcmp(mounta, mountb)); 11433126Sahl 11443126Sahl if (gota) 11453126Sahl return (-1); 11463126Sahl if (gotb) 11473126Sahl return (1); 11483126Sahl 11493126Sahl return (strcmp(zfs_get_name(a), zfs_get_name(b))); 11502474Seschrock } 11512474Seschrock 11523126Sahl /* 11533126Sahl * Mount and share all datasets within the given pool. This assumes that no 11543126Sahl * datasets within the pool are currently mounted. Because users can create 11553126Sahl * complicated nested hierarchies of mountpoints, we first gather all the 11563126Sahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once 11573126Sahl * we have the list of all filesystems, we iterate over them in order and mount 11583126Sahl * and/or share each one. 11593126Sahl */ 11603126Sahl #pragma weak zpool_mount_datasets = zpool_enable_datasets 11612474Seschrock int 11623126Sahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) 11632474Seschrock { 11642474Seschrock mount_cbdata_t cb = { 0 }; 11652474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 11662474Seschrock zfs_handle_t *zfsp; 11672474Seschrock int i, ret = -1; 11684180Sdougm int *good; 11692474Seschrock 11702474Seschrock /* 11716027Srm160521 * Gather all non-snap datasets within the pool. 11722474Seschrock */ 11732474Seschrock if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) 11742474Seschrock return (-1); 11752474Seschrock cb.cb_alloc = 4; 11762474Seschrock 11775094Slling if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL) 11782474Seschrock goto out; 11792474Seschrock 11802474Seschrock cb.cb_datasets[0] = zfsp; 11812474Seschrock cb.cb_used = 1; 11822474Seschrock 11836027Srm160521 if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0) 11842474Seschrock goto out; 11852474Seschrock 11862474Seschrock /* 11872474Seschrock * Sort the datasets by mountpoint. 11882474Seschrock */ 11893126Sahl qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); 11902474Seschrock 11912474Seschrock /* 11924180Sdougm * And mount all the datasets, keeping track of which ones 11938536SDavid.Pacheco@Sun.COM * succeeded or failed. 11942474Seschrock */ 11958536SDavid.Pacheco@Sun.COM if ((good = zfs_alloc(zhp->zpool_hdl, 11968536SDavid.Pacheco@Sun.COM cb.cb_used * sizeof (int))) == NULL) 11978536SDavid.Pacheco@Sun.COM goto out; 11988536SDavid.Pacheco@Sun.COM 11992474Seschrock ret = 0; 12002474Seschrock for (i = 0; i < cb.cb_used; i++) { 12014302Sdougm if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0) 12024180Sdougm ret = -1; 12034302Sdougm else 12044180Sdougm good[i] = 1; 12054180Sdougm } 12065951Sdougm 12074180Sdougm /* 12084180Sdougm * Then share all the ones that need to be shared. This needs 12094180Sdougm * to be a separate pass in order to avoid excessive reloading 12104180Sdougm * of the configuration. Good should never be NULL since 12114180Sdougm * zfs_alloc is supposed to exit if memory isn't available. 12124180Sdougm */ 12134180Sdougm for (i = 0; i < cb.cb_used; i++) { 12144180Sdougm if (good[i] && zfs_share(cb.cb_datasets[i]) != 0) 12152474Seschrock ret = -1; 12162474Seschrock } 12172474Seschrock 12184180Sdougm free(good); 12194180Sdougm 12202474Seschrock out: 12212474Seschrock for (i = 0; i < cb.cb_used; i++) 12222474Seschrock zfs_close(cb.cb_datasets[i]); 12232474Seschrock free(cb.cb_datasets); 12242474Seschrock 12252474Seschrock return (ret); 12262474Seschrock } 12272474Seschrock 122810588SEric.Taylor@Sun.COM /*ARGSUSED1*/ 12293126Sahl static int 123010588SEric.Taylor@Sun.COM zvol_cb(zfs_handle_t *zhp, void *unused) 12313126Sahl { 123210588SEric.Taylor@Sun.COM int error = 0; 12333126Sahl 123410588SEric.Taylor@Sun.COM if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) 123510588SEric.Taylor@Sun.COM (void) zfs_iter_children(zhp, zvol_cb, NULL); 123610588SEric.Taylor@Sun.COM if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) 123710588SEric.Taylor@Sun.COM error = zfs_unshare_iscsi(zhp); 12383126Sahl zfs_close(zhp); 12393126Sahl 124010588SEric.Taylor@Sun.COM return (error); 12413126Sahl } 12423126Sahl 12432474Seschrock static int 12442474Seschrock mountpoint_compare(const void *a, const void *b) 12452474Seschrock { 12462474Seschrock const char *mounta = *((char **)a); 12472474Seschrock const char *mountb = *((char **)b); 12482474Seschrock 12492474Seschrock return (strcmp(mountb, mounta)); 12502474Seschrock } 12512474Seschrock 125210588SEric.Taylor@Sun.COM /* alias for 2002/240 */ 125310588SEric.Taylor@Sun.COM #pragma weak zpool_unmount_datasets = zpool_disable_datasets 12543126Sahl /* 12553126Sahl * Unshare and unmount all datasets within the given pool. We don't want to 12563126Sahl * rely on traversing the DSL to discover the filesystems within the pool, 12573126Sahl * because this may be expensive (if not all of them are mounted), and can fail 12583126Sahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and 12593126Sahl * gather all the filesystems that are currently mounted. 12603126Sahl */ 12612474Seschrock int 12623126Sahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) 12632474Seschrock { 12642474Seschrock int used, alloc; 12652474Seschrock struct mnttab entry; 12662474Seschrock size_t namelen; 12672474Seschrock char **mountpoints = NULL; 126810588SEric.Taylor@Sun.COM zfs_handle_t *zfp; 12692474Seschrock zfs_handle_t **datasets = NULL; 12702474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 12712474Seschrock int i; 12722474Seschrock int ret = -1; 12732474Seschrock int flags = (force ? MS_FORCE : 0); 12742474Seschrock 12753126Sahl /* 12763126Sahl * First unshare all zvols. 12773126Sahl */ 127810588SEric.Taylor@Sun.COM zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name, 127910588SEric.Taylor@Sun.COM ZFS_TYPE_FILESYSTEM); 128010588SEric.Taylor@Sun.COM if (zfp != NULL) { 128110588SEric.Taylor@Sun.COM (void) zfs_iter_children(zfp, zvol_cb, NULL); 128210588SEric.Taylor@Sun.COM zfs_close(zfp); 128310588SEric.Taylor@Sun.COM } 12843126Sahl 12852474Seschrock namelen = strlen(zhp->zpool_name); 12862474Seschrock 12872474Seschrock rewind(hdl->libzfs_mnttab); 12882474Seschrock used = alloc = 0; 12892474Seschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 12902474Seschrock /* 12912474Seschrock * Ignore non-ZFS entries. 12922474Seschrock */ 12932474Seschrock if (entry.mnt_fstype == NULL || 12942474Seschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 12952474Seschrock continue; 12962474Seschrock 12972474Seschrock /* 12982474Seschrock * Ignore filesystems not within this pool. 12992474Seschrock */ 13002474Seschrock if (entry.mnt_mountp == NULL || 13012474Seschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 || 13022474Seschrock (entry.mnt_special[namelen] != '/' && 13032474Seschrock entry.mnt_special[namelen] != '\0')) 13042474Seschrock continue; 13052474Seschrock 13062474Seschrock /* 13072474Seschrock * At this point we've found a filesystem within our pool. Add 13082474Seschrock * it to our growing list. 13092474Seschrock */ 13102474Seschrock if (used == alloc) { 13112474Seschrock if (alloc == 0) { 13122474Seschrock if ((mountpoints = zfs_alloc(hdl, 13132474Seschrock 8 * sizeof (void *))) == NULL) 13142474Seschrock goto out; 13152474Seschrock 13162474Seschrock if ((datasets = zfs_alloc(hdl, 13172474Seschrock 8 * sizeof (void *))) == NULL) 13182474Seschrock goto out; 13192474Seschrock 13202474Seschrock alloc = 8; 13212474Seschrock } else { 13222676Seschrock void *ptr; 13232474Seschrock 13242676Seschrock if ((ptr = zfs_realloc(hdl, mountpoints, 13252676Seschrock alloc * sizeof (void *), 13262474Seschrock alloc * 2 * sizeof (void *))) == NULL) 13272474Seschrock goto out; 13282676Seschrock mountpoints = ptr; 13292474Seschrock 13302676Seschrock if ((ptr = zfs_realloc(hdl, datasets, 13312676Seschrock alloc * sizeof (void *), 13322474Seschrock alloc * 2 * sizeof (void *))) == NULL) 13332474Seschrock goto out; 13342676Seschrock datasets = ptr; 13352474Seschrock 13362474Seschrock alloc *= 2; 13372474Seschrock } 13382474Seschrock } 13392474Seschrock 13402474Seschrock if ((mountpoints[used] = zfs_strdup(hdl, 13412474Seschrock entry.mnt_mountp)) == NULL) 13422474Seschrock goto out; 13432474Seschrock 13442474Seschrock /* 13452474Seschrock * This is allowed to fail, in case there is some I/O error. It 13462474Seschrock * is only used to determine if we need to remove the underlying 13472474Seschrock * mountpoint, so failure is not fatal. 13482474Seschrock */ 13492474Seschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special); 13502474Seschrock 13512474Seschrock used++; 13522474Seschrock } 13532474Seschrock 13542474Seschrock /* 13552474Seschrock * At this point, we have the entire list of filesystems, so sort it by 13562474Seschrock * mountpoint. 13572474Seschrock */ 13582474Seschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare); 13592474Seschrock 13602474Seschrock /* 13612474Seschrock * Walk through and first unshare everything. 13622474Seschrock */ 13632474Seschrock for (i = 0; i < used; i++) { 13645331Samw zfs_share_proto_t *curr_proto; 13655331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 13665331Samw curr_proto++) { 13675331Samw if (is_shared(hdl, mountpoints[i], *curr_proto) && 13685331Samw unshare_one(hdl, mountpoints[i], 13695331Samw mountpoints[i], *curr_proto) != 0) 13705331Samw goto out; 13715331Samw } 13722474Seschrock } 13732474Seschrock 13742474Seschrock /* 13752474Seschrock * Now unmount everything, removing the underlying directories as 13762474Seschrock * appropriate. 13772474Seschrock */ 13782474Seschrock for (i = 0; i < used; i++) { 13792474Seschrock if (unmount_one(hdl, mountpoints[i], flags) != 0) 13802474Seschrock goto out; 13812676Seschrock } 13822474Seschrock 13832676Seschrock for (i = 0; i < used; i++) { 13842474Seschrock if (datasets[i]) 13852474Seschrock remove_mountpoint(datasets[i]); 13862474Seschrock } 13872474Seschrock 13882474Seschrock ret = 0; 13892474Seschrock out: 13902474Seschrock for (i = 0; i < used; i++) { 13912474Seschrock if (datasets[i]) 13922474Seschrock zfs_close(datasets[i]); 13932474Seschrock free(mountpoints[i]); 13942474Seschrock } 13952474Seschrock free(datasets); 13962474Seschrock free(mountpoints); 13972474Seschrock 13982474Seschrock return (ret); 13992474Seschrock } 1400