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 /* 233380Sgw25295 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24789Sahrens * Use is subject to license terms. 25789Sahrens */ 26789Sahrens 27789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28789Sahrens 29789Sahrens /* 30789Sahrens * Routines to manage ZFS mounts. We separate all the nasty routines that have 313126Sahl * to deal with the OS. The following functions are the main entry points -- 323126Sahl * they are used by mount and unmount and when changing a filesystem's 333126Sahl * mountpoint. 34789Sahrens * 35789Sahrens * zfs_is_mounted() 36789Sahrens * zfs_mount() 37789Sahrens * zfs_unmount() 38789Sahrens * zfs_unmountall() 39789Sahrens * 403126Sahl * This file also contains the functions used to manage sharing filesystems via 413126Sahl * NFS and iSCSI: 42789Sahrens * 43789Sahrens * zfs_is_shared() 44789Sahrens * zfs_share() 45789Sahrens * zfs_unshare() 463126Sahl * 473126Sahl * zfs_is_shared_nfs() 485331Samw * zfs_is_shared_smb() 495331Samw * zfs_is_shared_iscsi() 505331Samw * zfs_share_proto() 515331Samw * zfs_shareall(); 525331Samw * zfs_share_iscsi() 533126Sahl * zfs_unshare_nfs() 545331Samw * zfs_unshare_smb() 553126Sahl * zfs_unshareall_nfs() 565331Samw * zfs_unshareall_smb() 575331Samw * zfs_unshareall() 585331Samw * zfs_unshareall_bypath() 593126Sahl * zfs_unshare_iscsi() 602474Seschrock * 612474Seschrock * The following functions are available for pool consumers, and will 623126Sahl * mount/unmount and share/unshare all datasets within pool: 632474Seschrock * 643126Sahl * zpool_enable_datasets() 653126Sahl * zpool_disable_datasets() 66789Sahrens */ 67789Sahrens 68789Sahrens #include <dirent.h> 693134Sahl #include <dlfcn.h> 70789Sahrens #include <errno.h> 71789Sahrens #include <libgen.h> 72789Sahrens #include <libintl.h> 73789Sahrens #include <stdio.h> 74789Sahrens #include <stdlib.h> 75789Sahrens #include <strings.h> 76789Sahrens #include <unistd.h> 77789Sahrens #include <zone.h> 78789Sahrens #include <sys/mntent.h> 79789Sahrens #include <sys/mnttab.h> 80789Sahrens #include <sys/mount.h> 81789Sahrens #include <sys/stat.h> 82789Sahrens 83789Sahrens #include <libzfs.h> 84789Sahrens 85789Sahrens #include "libzfs_impl.h" 86789Sahrens 874180Sdougm #include <libshare.h> 884180Sdougm #include <sys/systeminfo.h> 894180Sdougm #define MAXISALEN 257 /* based on sysinfo(2) man page */ 904180Sdougm 915331Samw static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *); 925331Samw zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **, 935331Samw zfs_share_proto_t); 945331Samw 953134Sahl static int (*iscsitgt_zfs_share)(const char *); 963134Sahl static int (*iscsitgt_zfs_unshare)(const char *); 973134Sahl static int (*iscsitgt_zfs_is_shared)(const char *); 984543Smarks static int (*iscsitgt_svc_online)(); 993134Sahl 1005331Samw /* 1015331Samw * The share protocols table must be in the same order as the zfs_share_prot_t 1025331Samw * enum in libzfs_impl.h 1035331Samw */ 1045331Samw typedef struct { 1055331Samw zfs_prop_t p_prop; 1065331Samw char *p_name; 1075331Samw int p_share_err; 1085331Samw int p_unshare_err; 1095331Samw } proto_table_t; 1105331Samw 1115331Samw proto_table_t proto_table[PROTO_END] = { 1125331Samw {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED}, 1135331Samw {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED}, 1145331Samw }; 1155331Samw 1165331Samw zfs_share_proto_t nfs_only[] = { 1175331Samw PROTO_NFS, 1185331Samw PROTO_END 1195331Samw }; 1205331Samw 1215331Samw zfs_share_proto_t smb_only[] = { 1225331Samw PROTO_SMB, 1235331Samw PROTO_END 1245331Samw }; 1255331Samw zfs_share_proto_t share_all_proto[] = { 1265331Samw PROTO_NFS, 1275331Samw PROTO_SMB, 1285331Samw PROTO_END 1295331Samw }; 1305331Samw 1313134Sahl #pragma init(zfs_iscsi_init) 1323134Sahl static void 1333134Sahl zfs_iscsi_init(void) 1343134Sahl { 1353134Sahl void *libiscsitgt; 1363134Sahl 1373134Sahl if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1", 1383134Sahl RTLD_LAZY | RTLD_GLOBAL)) == NULL || 1393134Sahl (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt, 1403134Sahl "iscsitgt_zfs_share")) == NULL || 1413134Sahl (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt, 1423134Sahl "iscsitgt_zfs_unshare")) == NULL || 1433134Sahl (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt, 1444543Smarks "iscsitgt_zfs_is_shared")) == NULL || 1454543Smarks (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt, 1464543Smarks "iscsitgt_svc_online")) == NULL) { 1473134Sahl iscsitgt_zfs_share = NULL; 1483134Sahl iscsitgt_zfs_unshare = NULL; 1493134Sahl iscsitgt_zfs_is_shared = NULL; 1504543Smarks iscsitgt_svc_online = NULL; 1513134Sahl } 1523134Sahl } 1533134Sahl 154789Sahrens /* 1555331Samw * Search the sharetab for the given mountpoint and protocol, returning 1565331Samw * a zfs_share_type_t value. 157789Sahrens */ 1585331Samw static zfs_share_type_t 1595331Samw is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto) 160789Sahrens { 161789Sahrens char buf[MAXPATHLEN], *tab; 1625331Samw char *ptr; 163789Sahrens 1642082Seschrock if (hdl->libzfs_sharetab == NULL) 1655331Samw return (SHARED_NOT_SHARED); 166789Sahrens 1672082Seschrock (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET); 168789Sahrens 1692082Seschrock while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) { 170789Sahrens 171789Sahrens /* the mountpoint is the first entry on each line */ 1725331Samw if ((tab = strchr(buf, '\t')) == NULL) 1735331Samw continue; 1745331Samw 1755331Samw *tab = '\0'; 1765331Samw if (strcmp(buf, mountpoint) == 0) { 1775331Samw /* 1785331Samw * the protocol field is the third field 1795331Samw * skip over second field 1805331Samw */ 1815331Samw ptr = ++tab; 1825331Samw if ((tab = strchr(ptr, '\t')) == NULL) 1835331Samw continue; 1845331Samw ptr = ++tab; 1855331Samw if ((tab = strchr(ptr, '\t')) == NULL) 1865331Samw continue; 187789Sahrens *tab = '\0'; 1885331Samw if (strcmp(ptr, 1895331Samw proto_table[proto].p_name) == 0) { 1905331Samw switch (proto) { 1915331Samw case PROTO_NFS: 1925331Samw return (SHARED_NFS); 1935331Samw case PROTO_SMB: 1945331Samw return (SHARED_SMB); 1955331Samw default: 1965331Samw return (0); 1975331Samw } 1985331Samw } 199789Sahrens } 200789Sahrens } 201789Sahrens 2025331Samw return (SHARED_NOT_SHARED); 203789Sahrens } 204789Sahrens 205789Sahrens /* 2062082Seschrock * Returns true if the specified directory is empty. If we can't open the 2072082Seschrock * directory at all, return true so that the mount can fail with a more 208789Sahrens * informative error message. 209789Sahrens */ 2102082Seschrock static boolean_t 211789Sahrens dir_is_empty(const char *dirname) 212789Sahrens { 213789Sahrens DIR *dirp; 214789Sahrens struct dirent64 *dp; 215789Sahrens 216789Sahrens if ((dirp = opendir(dirname)) == NULL) 2172082Seschrock return (B_TRUE); 218789Sahrens 219789Sahrens while ((dp = readdir64(dirp)) != NULL) { 220789Sahrens 221789Sahrens if (strcmp(dp->d_name, ".") == 0 || 222789Sahrens strcmp(dp->d_name, "..") == 0) 223789Sahrens continue; 224789Sahrens 225789Sahrens (void) closedir(dirp); 2262082Seschrock return (B_FALSE); 227789Sahrens } 228789Sahrens 229789Sahrens (void) closedir(dirp); 2302082Seschrock return (B_TRUE); 231789Sahrens } 232789Sahrens 233789Sahrens /* 234789Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill 235789Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return 236789Sahrens * 0. 237789Sahrens */ 2382082Seschrock boolean_t 2393444Sek110237 is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where) 240789Sahrens { 241789Sahrens struct mnttab search = { 0 }, entry; 242789Sahrens 243789Sahrens /* 244789Sahrens * Search for the entry in /etc/mnttab. We don't bother getting the 245789Sahrens * mountpoint, as we can just search for the special device. This will 246789Sahrens * also let us find mounts when the mountpoint is 'legacy'. 247789Sahrens */ 2483444Sek110237 search.mnt_special = (char *)special; 2491407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 250789Sahrens 2513444Sek110237 rewind(zfs_hdl->libzfs_mnttab); 2523444Sek110237 if (getmntany(zfs_hdl->libzfs_mnttab, &entry, &search) != 0) 2532082Seschrock return (B_FALSE); 254789Sahrens 255789Sahrens if (where != NULL) 2563444Sek110237 *where = zfs_strdup(zfs_hdl, entry.mnt_mountp); 257789Sahrens 2582082Seschrock return (B_TRUE); 259789Sahrens } 260789Sahrens 2613444Sek110237 boolean_t 2623444Sek110237 zfs_is_mounted(zfs_handle_t *zhp, char **where) 2633444Sek110237 { 2643444Sek110237 return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where)); 2653444Sek110237 } 2663444Sek110237 267789Sahrens /* 2682676Seschrock * Returns true if the given dataset is mountable, false otherwise. Returns the 2692676Seschrock * mountpoint in 'buf'. 2702676Seschrock */ 2712676Seschrock static boolean_t 2722676Seschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, 2735094Slling zprop_source_t *source) 2742676Seschrock { 2752676Seschrock char sourceloc[ZFS_MAXNAMELEN]; 2765094Slling zprop_source_t sourcetype; 2772676Seschrock 2782676Seschrock if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type)) 2792676Seschrock return (B_FALSE); 2802676Seschrock 2812676Seschrock verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen, 2822676Seschrock &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0); 2832676Seschrock 2842676Seschrock if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 || 2852676Seschrock strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0) 2862676Seschrock return (B_FALSE); 2872676Seschrock 2882676Seschrock if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT)) 2892676Seschrock return (B_FALSE); 2902676Seschrock 2912676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) && 2922676Seschrock getzoneid() == GLOBAL_ZONEID) 2932676Seschrock return (B_FALSE); 2942676Seschrock 2952676Seschrock if (source) 2962676Seschrock *source = sourcetype; 2972676Seschrock 2982676Seschrock return (B_TRUE); 2992676Seschrock } 3002676Seschrock 3012676Seschrock /* 302789Sahrens * Mount the given filesystem. 303789Sahrens */ 304789Sahrens int 305789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags) 306789Sahrens { 307789Sahrens struct stat buf; 308789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 309789Sahrens char mntopts[MNT_LINE_MAX]; 3102082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 311789Sahrens 312789Sahrens if (options == NULL) 313789Sahrens mntopts[0] = '\0'; 314789Sahrens else 315789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts)); 316789Sahrens 3172676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 3182082Seschrock return (0); 319789Sahrens 320789Sahrens /* Create the directory if it doesn't already exist */ 321789Sahrens if (lstat(mountpoint, &buf) != 0) { 322789Sahrens if (mkdirp(mountpoint, 0755) != 0) { 3232082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3242082Seschrock "failed to create mountpoint")); 3253237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3262082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 3272082Seschrock mountpoint)); 328789Sahrens } 329789Sahrens } 330789Sahrens 331789Sahrens /* 332789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the 333789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which 334789Sahrens * would defeat the point. We also avoid this check if 'remount' is 335789Sahrens * specified. 336789Sahrens */ 337789Sahrens if ((flags & MS_OVERLAY) == 0 && 338789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL && 339789Sahrens !dir_is_empty(mountpoint)) { 3402082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3412082Seschrock "directory is not empty")); 3423237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3432082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint)); 344789Sahrens } 345789Sahrens 346789Sahrens /* perform the mount */ 347789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags, 348789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) { 349789Sahrens /* 350789Sahrens * Generic errors are nasty, but there are just way too many 351789Sahrens * from mount(), and they're well-understood. We pick a few 352789Sahrens * common ones to improve upon. 353789Sahrens */ 3544302Sdougm if (errno == EBUSY) { 3552082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3562082Seschrock "mountpoint or dataset is busy")); 3574543Smarks } else if (errno == EPERM) { 3584543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 3594543Smarks "Insufficient privileges")); 3604302Sdougm } else { 3612082Seschrock zfs_error_aux(hdl, strerror(errno)); 3624302Sdougm } 3632082Seschrock 3643237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED, 3652082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), 3662082Seschrock zhp->zfs_name)); 367789Sahrens } 368789Sahrens 369789Sahrens return (0); 370789Sahrens } 371789Sahrens 372789Sahrens /* 3732474Seschrock * Unmount a single filesystem. 3742474Seschrock */ 3752474Seschrock static int 3762474Seschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags) 3772474Seschrock { 3782474Seschrock if (umount2(mountpoint, flags) != 0) { 3792474Seschrock zfs_error_aux(hdl, strerror(errno)); 3803237Slling return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED, 3812474Seschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"), 3822474Seschrock mountpoint)); 3832474Seschrock } 3842474Seschrock 3852474Seschrock return (0); 3862474Seschrock } 3872474Seschrock 3882474Seschrock /* 389789Sahrens * Unmount the given filesystem. 390789Sahrens */ 391789Sahrens int 392789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags) 393789Sahrens { 394789Sahrens struct mnttab search = { 0 }, entry; 3954180Sdougm char *mntpt = NULL; 396789Sahrens 397789Sahrens /* check to see if need to unmount the filesystem */ 3982474Seschrock search.mnt_special = zhp->zfs_name; 3991407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 4002082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 401789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 4022082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 403789Sahrens 4044180Sdougm /* 4054180Sdougm * mountpoint may have come from a call to 4064180Sdougm * getmnt/getmntany if it isn't NULL. If it is NULL, 4074180Sdougm * we know it comes from getmntany which can then get 4084180Sdougm * overwritten later. We strdup it to play it safe. 4094180Sdougm */ 410789Sahrens if (mountpoint == NULL) 4114302Sdougm mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 4124180Sdougm else 4134302Sdougm mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); 414789Sahrens 415789Sahrens /* 4162474Seschrock * Unshare and unmount the filesystem 417789Sahrens */ 4185331Samw if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) 4194331Sth199096 return (-1); 4204331Sth199096 4214331Sth199096 if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) { 4224180Sdougm free(mntpt); 4235331Samw (void) zfs_shareall(zhp); 424789Sahrens return (-1); 4254180Sdougm } 4264180Sdougm free(mntpt); 427789Sahrens } 428789Sahrens 429789Sahrens return (0); 430789Sahrens } 431789Sahrens 432789Sahrens /* 433789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property. 434789Sahrens * To do this, just act like we're changing the mountpoint property, but don't 435789Sahrens * remount the filesystems afterwards. 436789Sahrens */ 437789Sahrens int 438789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags) 439789Sahrens { 440789Sahrens prop_changelist_t *clp; 441789Sahrens int ret; 442789Sahrens 443789Sahrens clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags); 444789Sahrens if (clp == NULL) 445789Sahrens return (-1); 446789Sahrens 447789Sahrens ret = changelist_prefix(clp); 448789Sahrens changelist_free(clp); 449789Sahrens 450789Sahrens return (ret); 451789Sahrens } 452789Sahrens 4533126Sahl boolean_t 4543126Sahl zfs_is_shared(zfs_handle_t *zhp) 4553126Sahl { 4565331Samw zfs_share_type_t rc = 0; 4575331Samw zfs_share_proto_t *curr_proto; 4585331Samw 4593126Sahl if (ZFS_IS_VOLUME(zhp)) 4603126Sahl return (zfs_is_shared_iscsi(zhp)); 4613126Sahl 4625331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 4635331Samw curr_proto++) 4645331Samw rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto); 4655331Samw 4665331Samw return (rc ? B_TRUE : B_FALSE); 4673126Sahl } 4683126Sahl 4693126Sahl int 4703126Sahl zfs_share(zfs_handle_t *zhp) 4713126Sahl { 4723126Sahl if (ZFS_IS_VOLUME(zhp)) 4733126Sahl return (zfs_share_iscsi(zhp)); 4743126Sahl 4755331Samw return (zfs_share_proto(zhp, share_all_proto)); 4763126Sahl } 4773126Sahl 4783126Sahl int 4793126Sahl zfs_unshare(zfs_handle_t *zhp) 4803126Sahl { 4813126Sahl if (ZFS_IS_VOLUME(zhp)) 4823126Sahl return (zfs_unshare_iscsi(zhp)); 4833126Sahl 4845331Samw return (zfs_unshareall(zhp)); 4853126Sahl } 4863126Sahl 487789Sahrens /* 488789Sahrens * Check to see if the filesystem is currently shared. 489789Sahrens */ 4905331Samw zfs_share_type_t 4915331Samw zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto) 492789Sahrens { 493789Sahrens char *mountpoint; 4945331Samw zfs_share_type_t rc; 495789Sahrens 496789Sahrens if (!zfs_is_mounted(zhp, &mountpoint)) 4975331Samw return (SHARED_NOT_SHARED); 498789Sahrens 4995331Samw if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) { 500789Sahrens if (where != NULL) 501789Sahrens *where = mountpoint; 502789Sahrens else 503789Sahrens free(mountpoint); 5045331Samw return (rc); 505789Sahrens } else { 506789Sahrens free(mountpoint); 5075331Samw return (SHARED_NOT_SHARED); 508789Sahrens } 509789Sahrens } 510789Sahrens 5115331Samw boolean_t 5125331Samw zfs_is_shared_nfs(zfs_handle_t *zhp, char **where) 5135331Samw { 5145331Samw return (zfs_is_shared_proto(zhp, where, 5155331Samw PROTO_NFS) != SHARED_NOT_SHARED); 5165331Samw } 5175331Samw 5185331Samw boolean_t 5195331Samw zfs_is_shared_smb(zfs_handle_t *zhp, char **where) 5205331Samw { 5215331Samw return (zfs_is_shared_proto(zhp, where, 5225331Samw PROTO_SMB) != SHARED_NOT_SHARED); 5235331Samw } 5245331Samw 525789Sahrens /* 5264180Sdougm * Make sure things will work if libshare isn't installed by using 5274180Sdougm * wrapper functions that check to see that the pointers to functions 5284180Sdougm * initialized in _zfs_init_libshare() are actually present. 5294180Sdougm */ 5304180Sdougm 5314180Sdougm static sa_handle_t (*_sa_init)(int); 5324180Sdougm static void (*_sa_fini)(sa_handle_t); 5334180Sdougm static sa_share_t (*_sa_find_share)(sa_handle_t, char *); 5344180Sdougm static int (*_sa_enable_share)(sa_share_t, char *); 5354180Sdougm static int (*_sa_disable_share)(sa_share_t, char *); 5364180Sdougm static char *(*_sa_errorstr)(int); 5374180Sdougm static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *); 5384180Sdougm 5394180Sdougm /* 5404180Sdougm * _zfs_init_libshare() 5414180Sdougm * 5424180Sdougm * Find the libshare.so.1 entry points that we use here and save the 5434180Sdougm * values to be used later. This is triggered by the runtime loader. 5444180Sdougm * Make sure the correct ISA version is loaded. 5454180Sdougm */ 5464180Sdougm #pragma init(_zfs_init_libshare) 5474180Sdougm static void 5484180Sdougm _zfs_init_libshare(void) 5494180Sdougm { 5504180Sdougm void *libshare; 5514180Sdougm char path[MAXPATHLEN]; 5524180Sdougm char isa[MAXISALEN]; 5534180Sdougm 5544180Sdougm #if defined(_LP64) 5554180Sdougm if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1) 5564302Sdougm isa[0] = '\0'; 5574180Sdougm #else 5584180Sdougm isa[0] = '\0'; 5594180Sdougm #endif 5604180Sdougm (void) snprintf(path, MAXPATHLEN, 5614302Sdougm "/usr/lib/%s/libshare.so.1", isa); 5624180Sdougm 5634180Sdougm if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) { 5644302Sdougm _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init"); 5654302Sdougm _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini"); 5664302Sdougm _sa_find_share = (sa_share_t (*)(sa_handle_t, char *)) 5674302Sdougm dlsym(libshare, "sa_find_share"); 5684302Sdougm _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5694302Sdougm "sa_enable_share"); 5704302Sdougm _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare, 5714302Sdougm "sa_disable_share"); 5724302Sdougm _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr"); 5734302Sdougm _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *)) 5744302Sdougm dlsym(libshare, "sa_parse_legacy_options"); 5754327Sdougm if (_sa_init == NULL || _sa_fini == NULL || 5764327Sdougm _sa_find_share == NULL || _sa_enable_share == NULL || 5774327Sdougm _sa_disable_share == NULL || _sa_errorstr == NULL || 5784327Sdougm _sa_parse_legacy_options == NULL) { 5794327Sdougm _sa_init = NULL; 5804327Sdougm _sa_fini = NULL; 5814327Sdougm _sa_disable_share = NULL; 5824327Sdougm _sa_enable_share = NULL; 5834327Sdougm _sa_errorstr = NULL; 5844327Sdougm _sa_parse_legacy_options = NULL; 5854327Sdougm (void) dlclose(libshare); 5864327Sdougm } 5874180Sdougm } 5884180Sdougm } 5894180Sdougm 5904180Sdougm /* 5914180Sdougm * zfs_init_libshare(zhandle, service) 5924180Sdougm * 5934180Sdougm * Initialize the libshare API if it hasn't already been initialized. 5944180Sdougm * In all cases it returns 0 if it succeeded and an error if not. The 5954180Sdougm * service value is which part(s) of the API to initialize and is a 5964180Sdougm * direct map to the libshare sa_init(service) interface. 5974180Sdougm */ 5984180Sdougm int 5994180Sdougm zfs_init_libshare(libzfs_handle_t *zhandle, int service) 6004180Sdougm { 6014180Sdougm int ret = SA_OK; 6024180Sdougm 6034302Sdougm if (_sa_init == NULL) 6044302Sdougm ret = SA_CONFIG_ERR; 6054302Sdougm 6064302Sdougm if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL) 6074302Sdougm zhandle->libzfs_sharehdl = _sa_init(service); 6084302Sdougm 6094302Sdougm if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL) 6104302Sdougm ret = SA_NO_MEMORY; 6114302Sdougm 6124180Sdougm return (ret); 6134180Sdougm } 6144180Sdougm 6154180Sdougm /* 6164180Sdougm * zfs_uninit_libshare(zhandle) 6174180Sdougm * 6184180Sdougm * Uninitialize the libshare API if it hasn't already been 6194180Sdougm * uninitialized. It is OK to call multiple times. 6204180Sdougm */ 6214180Sdougm void 6224180Sdougm zfs_uninit_libshare(libzfs_handle_t *zhandle) 6234180Sdougm { 6244180Sdougm if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) { 6254302Sdougm if (_sa_fini != NULL) 6264302Sdougm _sa_fini(zhandle->libzfs_sharehdl); 6274302Sdougm zhandle->libzfs_sharehdl = NULL; 6284180Sdougm } 6294180Sdougm } 6304180Sdougm 6314180Sdougm /* 6324180Sdougm * zfs_parse_options(options, proto) 6334180Sdougm * 6344180Sdougm * Call the legacy parse interface to get the protocol specific 6354180Sdougm * options using the NULL arg to indicate that this is a "parse" only. 6364180Sdougm */ 6374180Sdougm int 6385331Samw zfs_parse_options(char *options, zfs_share_proto_t proto) 6394180Sdougm { 640*5367Sahrens if (_sa_parse_legacy_options != NULL) { 641*5367Sahrens return (_sa_parse_legacy_options(NULL, options, 642*5367Sahrens proto_table[proto].p_name)); 643*5367Sahrens } 644*5367Sahrens return (SA_CONFIG_ERR); 6454180Sdougm } 6464180Sdougm 6474180Sdougm /* 6484180Sdougm * zfs_sa_find_share(handle, path) 6494180Sdougm * 6504180Sdougm * wrapper around sa_find_share to find a share path in the 6514180Sdougm * configuration. 6524180Sdougm */ 6534180Sdougm static sa_share_t 6544180Sdougm zfs_sa_find_share(sa_handle_t handle, char *path) 6554180Sdougm { 6564180Sdougm if (_sa_find_share != NULL) 6574302Sdougm return (_sa_find_share(handle, path)); 6584180Sdougm return (NULL); 6594180Sdougm } 6604180Sdougm 6614180Sdougm /* 6624180Sdougm * zfs_sa_enable_share(share, proto) 6634180Sdougm * 6644180Sdougm * Wrapper for sa_enable_share which enables a share for a specified 6654180Sdougm * protocol. 6664180Sdougm */ 6674180Sdougm static int 6684180Sdougm zfs_sa_enable_share(sa_share_t share, char *proto) 6694180Sdougm { 6704180Sdougm if (_sa_enable_share != NULL) 6714302Sdougm return (_sa_enable_share(share, proto)); 6724180Sdougm return (SA_CONFIG_ERR); 6734180Sdougm } 6744180Sdougm 6754180Sdougm /* 6764180Sdougm * zfs_sa_disable_share(share, proto) 6774180Sdougm * 6784180Sdougm * Wrapper for sa_enable_share which disables a share for a specified 6794180Sdougm * protocol. 6804180Sdougm */ 6814180Sdougm static int 6824180Sdougm zfs_sa_disable_share(sa_share_t share, char *proto) 6834180Sdougm { 6844180Sdougm if (_sa_disable_share != NULL) 6854302Sdougm return (_sa_disable_share(share, proto)); 6864180Sdougm return (SA_CONFIG_ERR); 6874180Sdougm } 6884180Sdougm 6894180Sdougm /* 6905331Samw * Share the given filesystem according to the options in the specified 6915331Samw * protocol specific properties (sharenfs, sharesmb). We rely 6924180Sdougm * on "libshare" to the dirty work for us. 693789Sahrens */ 6945331Samw static int 6955331Samw zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 696789Sahrens { 697789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 698789Sahrens char shareopts[ZFS_MAXPROPLEN]; 6992082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl; 7004180Sdougm sa_share_t share; 7015331Samw zfs_share_proto_t *curr_proto; 7024180Sdougm int ret; 703789Sahrens 7042676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL)) 705789Sahrens return (0); 706789Sahrens 7074180Sdougm if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 7084302Sdougm (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 7094302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s': %s"), 7104302Sdougm zfs_get_name(zhp), _sa_errorstr(ret)); 7114302Sdougm return (-1); 7124180Sdougm } 7135331Samw 7145331Samw for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) { 7155331Samw /* 7165331Samw * Return success if there are no share options. 7175331Samw */ 7185331Samw if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop, 7195331Samw shareopts, sizeof (shareopts), NULL, NULL, 7205331Samw 0, B_FALSE) != 0 || strcmp(shareopts, "off") == 0) 7215331Samw continue; 7225331Samw 7235331Samw /* 7245331Samw * If the 'zoned' property is set, then zfs_is_mountable() 7255331Samw * will have already bailed out if we are in the global zone. 7265331Samw * But local zones cannot be NFS servers, so we ignore it for 7275331Samw * local zones as well. 7285331Samw */ 7295331Samw if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) 7305331Samw continue; 7315331Samw 7325331Samw share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint); 7335331Samw if (share != NULL) { 7345331Samw int err; 7355331Samw err = zfs_sa_enable_share(share, 7365331Samw proto_table[*curr_proto].p_name); 7375331Samw if (err != SA_OK) { 7385331Samw (void) zfs_error_fmt(hdl, 7395331Samw proto_table[*curr_proto].p_share_err, 7405331Samw dgettext(TEXT_DOMAIN, "cannot share '%s'"), 7415331Samw zfs_get_name(zhp)); 7425331Samw return (-1); 7435331Samw } 7445331Samw } else { 7455331Samw (void) zfs_error_fmt(hdl, 7465331Samw proto_table[*curr_proto].p_share_err, 7474302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"), 7484302Sdougm zfs_get_name(zhp)); 7494302Sdougm return (-1); 7504302Sdougm } 7515331Samw 752789Sahrens } 7535331Samw return (0); 7545331Samw } 755789Sahrens 7565331Samw 7575331Samw int 7585331Samw zfs_share_nfs(zfs_handle_t *zhp) 7595331Samw { 7605331Samw return (zfs_share_proto(zhp, nfs_only)); 7615331Samw } 7625331Samw 7635331Samw int 7645331Samw zfs_share_smb(zfs_handle_t *zhp) 7655331Samw { 7665331Samw return (zfs_share_proto(zhp, smb_only)); 7675331Samw } 7685331Samw 7695331Samw int 7705331Samw zfs_shareall(zfs_handle_t *zhp) 7715331Samw { 7725331Samw return (zfs_share_proto(zhp, share_all_proto)); 773789Sahrens } 774789Sahrens 775789Sahrens /* 7762474Seschrock * Unshare a filesystem by mountpoint. 7772474Seschrock */ 7782474Seschrock static int 7795331Samw unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint, 7805331Samw zfs_share_proto_t proto) 7812474Seschrock { 7824180Sdougm sa_share_t share; 7834180Sdougm int err; 7844180Sdougm char *mntpt; 7852474Seschrock /* 7864180Sdougm * Mountpoint could get trashed if libshare calls getmntany 7874180Sdougm * which id does during API initialization, so strdup the 7884180Sdougm * value. 7892474Seschrock */ 7904180Sdougm mntpt = zfs_strdup(hdl, mountpoint); 7912474Seschrock 7924180Sdougm /* make sure libshare initialized */ 7934180Sdougm if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) { 7944180Sdougm free(mntpt); /* don't need the copy anymore */ 7954180Sdougm return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED, 7964302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 7974302Sdougm name, _sa_errorstr(err))); 7982474Seschrock } 7992474Seschrock 8004180Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt); 8014180Sdougm free(mntpt); /* don't need the copy anymore */ 8022474Seschrock 8034180Sdougm if (share != NULL) { 8045331Samw err = zfs_sa_disable_share(share, proto_table[proto].p_name); 8054180Sdougm if (err != SA_OK) { 8064302Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8074302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"), 8084302Sdougm name, _sa_errorstr(err))); 8094180Sdougm } 8104180Sdougm } else { 8114180Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED, 8124302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"), 8134302Sdougm name)); 8144180Sdougm } 8152474Seschrock return (0); 8162474Seschrock } 8172474Seschrock 8182474Seschrock /* 819789Sahrens * Unshare the given filesystem. 820789Sahrens */ 821789Sahrens int 8225331Samw zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint, 8235331Samw zfs_share_proto_t *proto) 824789Sahrens { 825789Sahrens struct mnttab search = { 0 }, entry; 8264180Sdougm char *mntpt = NULL; 827789Sahrens 828789Sahrens /* check to see if need to unmount the filesystem */ 829789Sahrens search.mnt_special = (char *)zfs_get_name(zhp); 8301407Snd150628 search.mnt_fstype = MNTTYPE_ZFS; 8312082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab); 8324302Sdougm if (mountpoint != NULL) 8335331Samw mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint); 8344302Sdougm 835789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) && 8362082Seschrock getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) { 8375331Samw zfs_share_proto_t *curr_proto; 838789Sahrens 839789Sahrens if (mountpoint == NULL) 8405331Samw mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp); 8415331Samw 8425331Samw for (curr_proto = proto; *curr_proto != PROTO_END; 8435331Samw curr_proto++) { 844789Sahrens 8455331Samw if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) && 8465331Samw unshare_one(zhp->zfs_hdl, zhp->zfs_name, 8475331Samw mntpt, *curr_proto) != 0) { 8485331Samw if (mntpt != NULL) 8495331Samw free(mntpt); 8505331Samw return (-1); 8515331Samw } 8524180Sdougm } 853789Sahrens } 8544180Sdougm if (mntpt != NULL) 8554302Sdougm free(mntpt); 856789Sahrens 857789Sahrens return (0); 858789Sahrens } 859789Sahrens 8605331Samw int 8615331Samw zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint) 8625331Samw { 8635331Samw return (zfs_unshare_proto(zhp, mountpoint, nfs_only)); 8645331Samw } 8655331Samw 8665331Samw int 8675331Samw zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint) 8685331Samw { 8695331Samw return (zfs_unshare_proto(zhp, mountpoint, smb_only)); 8705331Samw } 8715331Samw 872789Sahrens /* 8735331Samw * Same as zfs_unmountall(), but for NFS and SMB unshares. 874789Sahrens */ 875789Sahrens int 8765331Samw zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto) 877789Sahrens { 878789Sahrens prop_changelist_t *clp; 879789Sahrens int ret; 880789Sahrens 881789Sahrens clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0); 882789Sahrens if (clp == NULL) 883789Sahrens return (-1); 884789Sahrens 8855331Samw ret = changelist_unshare(clp, proto); 886789Sahrens changelist_free(clp); 887789Sahrens 888789Sahrens return (ret); 889789Sahrens } 890789Sahrens 8915331Samw int 8925331Samw zfs_unshareall_nfs(zfs_handle_t *zhp) 8935331Samw { 8945331Samw return (zfs_unshareall_proto(zhp, nfs_only)); 8955331Samw } 8965331Samw 8975331Samw int 8985331Samw zfs_unshareall_smb(zfs_handle_t *zhp) 8995331Samw { 9005331Samw return (zfs_unshareall_proto(zhp, smb_only)); 9015331Samw } 9025331Samw 9035331Samw int 9045331Samw zfs_unshareall(zfs_handle_t *zhp) 9055331Samw { 9065331Samw return (zfs_unshareall_proto(zhp, share_all_proto)); 9075331Samw } 9085331Samw 9095331Samw int 9105331Samw zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint) 9115331Samw { 9125331Samw return (zfs_unshare_proto(zhp, mountpoint, share_all_proto)); 9135331Samw } 9145331Samw 915789Sahrens /* 916789Sahrens * Remove the mountpoint associated with the current dataset, if necessary. 917789Sahrens * We only remove the underlying directory if: 918789Sahrens * 919789Sahrens * - The mountpoint is not 'none' or 'legacy' 920789Sahrens * - The mountpoint is non-empty 921789Sahrens * - The mountpoint is the default or inherited 922789Sahrens * - The 'zoned' property is set, or we're in a local zone 923789Sahrens * 924789Sahrens * Any other directories we leave alone. 925789Sahrens */ 926789Sahrens void 927789Sahrens remove_mountpoint(zfs_handle_t *zhp) 928789Sahrens { 929789Sahrens char mountpoint[ZFS_MAXPROPLEN]; 9305094Slling zprop_source_t source; 931789Sahrens 9322676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), 9332676Seschrock &source)) 934789Sahrens return; 935789Sahrens 9365094Slling if (source == ZPROP_SRC_DEFAULT || 9375094Slling source == ZPROP_SRC_INHERITED) { 938789Sahrens /* 939789Sahrens * Try to remove the directory, silently ignoring any errors. 940789Sahrens * The filesystem may have since been removed or moved around, 9412676Seschrock * and this error isn't really useful to the administrator in 9422676Seschrock * any way. 943789Sahrens */ 944789Sahrens (void) rmdir(mountpoint); 945789Sahrens } 946789Sahrens } 9472474Seschrock 9483126Sahl boolean_t 9493126Sahl zfs_is_shared_iscsi(zfs_handle_t *zhp) 9503126Sahl { 9514543Smarks 9524543Smarks /* 9534543Smarks * If iscsi deamon isn't running then we aren't shared 9544543Smarks */ 9554543Smarks if (iscsitgt_svc_online && iscsitgt_svc_online() == 1) 9565331Samw return (B_FALSE); 9574543Smarks else 9584543Smarks return (iscsitgt_zfs_is_shared != NULL && 9594543Smarks iscsitgt_zfs_is_shared(zhp->zfs_name) != 0); 9603126Sahl } 9613126Sahl 9623126Sahl int 9633126Sahl zfs_share_iscsi(zfs_handle_t *zhp) 9643126Sahl { 9653126Sahl char shareopts[ZFS_MAXPROPLEN]; 9663126Sahl const char *dataset = zhp->zfs_name; 9673126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 9683126Sahl 9693126Sahl /* 9703126Sahl * Return success if there are no share options. 9713126Sahl */ 9723126Sahl if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts, 9733126Sahl sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 || 9743126Sahl strcmp(shareopts, "off") == 0) 9753126Sahl return (0); 9763126Sahl 9774543Smarks if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) { 9784543Smarks int error = EZFS_SHAREISCSIFAILED; 9794543Smarks 9804543Smarks /* 9814543Smarks * If service isn't availabele and EPERM was 9824543Smarks * returned then use special error. 9834543Smarks */ 9844543Smarks if (iscsitgt_svc_online && errno == EPERM && 9854543Smarks (iscsitgt_svc_online() != 0)) 9864543Smarks error = EZFS_ISCSISVCUNAVAIL; 9874543Smarks 9884543Smarks return (zfs_error_fmt(hdl, error, 9893126Sahl dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset)); 9904543Smarks } 9913126Sahl 9923126Sahl return (0); 9933126Sahl } 9943126Sahl 9953126Sahl int 9963126Sahl zfs_unshare_iscsi(zfs_handle_t *zhp) 9973126Sahl { 9983126Sahl const char *dataset = zfs_get_name(zhp); 9993126Sahl libzfs_handle_t *hdl = zhp->zfs_hdl; 10003126Sahl 10013126Sahl /* 10023380Sgw25295 * Return if the volume is not shared 10033380Sgw25295 */ 10045331Samw if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI) 10053380Sgw25295 return (0); 10063380Sgw25295 10073380Sgw25295 /* 10083126Sahl * If this fails with ENODEV it indicates that zvol wasn't shared so 10093126Sahl * we should return success in that case. 10103126Sahl */ 10113134Sahl if (iscsitgt_zfs_unshare == NULL || 10124543Smarks (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) { 10134543Smarks if (errno == EPERM) 10144543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 10154543Smarks "Insufficient privileges to unshare iscsi")); 10163237Slling return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED, 10173126Sahl dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset)); 10184543Smarks } 10193126Sahl 10203126Sahl return (0); 10213126Sahl } 10223126Sahl 10232474Seschrock typedef struct mount_cbdata { 10242474Seschrock zfs_handle_t **cb_datasets; 10252474Seschrock int cb_used; 10262474Seschrock int cb_alloc; 10272474Seschrock } mount_cbdata_t; 10282474Seschrock 10292474Seschrock static int 10302474Seschrock mount_cb(zfs_handle_t *zhp, void *data) 10312474Seschrock { 10322474Seschrock mount_cbdata_t *cbp = data; 10332474Seschrock 10343126Sahl if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) { 10352474Seschrock zfs_close(zhp); 10362474Seschrock return (0); 10372474Seschrock } 10382474Seschrock 10392474Seschrock if (cbp->cb_alloc == cbp->cb_used) { 10402676Seschrock void *ptr; 10412474Seschrock 10422676Seschrock if ((ptr = zfs_realloc(zhp->zfs_hdl, 10432676Seschrock cbp->cb_datasets, cbp->cb_alloc * sizeof (void *), 10442676Seschrock cbp->cb_alloc * 2 * sizeof (void *))) == NULL) 10452474Seschrock return (-1); 10462676Seschrock cbp->cb_datasets = ptr; 10472474Seschrock 10482676Seschrock cbp->cb_alloc *= 2; 10492474Seschrock } 10502474Seschrock 10512474Seschrock cbp->cb_datasets[cbp->cb_used++] = zhp; 10523126Sahl 10533126Sahl return (zfs_iter_children(zhp, mount_cb, cbp)); 10542474Seschrock } 10552474Seschrock 10562474Seschrock static int 10573126Sahl dataset_cmp(const void *a, const void *b) 10582474Seschrock { 10592474Seschrock zfs_handle_t **za = (zfs_handle_t **)a; 10602474Seschrock zfs_handle_t **zb = (zfs_handle_t **)b; 10612474Seschrock char mounta[MAXPATHLEN]; 10622474Seschrock char mountb[MAXPATHLEN]; 10633126Sahl boolean_t gota, gotb; 10642474Seschrock 10653126Sahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0) 10663126Sahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 10673126Sahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 10683126Sahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0) 10693126Sahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 10703126Sahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 10712474Seschrock 10723126Sahl if (gota && gotb) 10733126Sahl return (strcmp(mounta, mountb)); 10743126Sahl 10753126Sahl if (gota) 10763126Sahl return (-1); 10773126Sahl if (gotb) 10783126Sahl return (1); 10793126Sahl 10803126Sahl return (strcmp(zfs_get_name(a), zfs_get_name(b))); 10812474Seschrock } 10822474Seschrock 10833126Sahl /* 10843126Sahl * Mount and share all datasets within the given pool. This assumes that no 10853126Sahl * datasets within the pool are currently mounted. Because users can create 10863126Sahl * complicated nested hierarchies of mountpoints, we first gather all the 10873126Sahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once 10883126Sahl * we have the list of all filesystems, we iterate over them in order and mount 10893126Sahl * and/or share each one. 10903126Sahl */ 10913126Sahl #pragma weak zpool_mount_datasets = zpool_enable_datasets 10922474Seschrock int 10933126Sahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags) 10942474Seschrock { 10952474Seschrock mount_cbdata_t cb = { 0 }; 10962474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 10972474Seschrock zfs_handle_t *zfsp; 10982474Seschrock int i, ret = -1; 10994180Sdougm int *good; 11002474Seschrock 11012474Seschrock /* 11022474Seschrock * Gather all datasets within the pool. 11032474Seschrock */ 11042474Seschrock if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL) 11052474Seschrock return (-1); 11062474Seschrock cb.cb_alloc = 4; 11072474Seschrock 11085094Slling if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL) 11092474Seschrock goto out; 11102474Seschrock 11112474Seschrock cb.cb_datasets[0] = zfsp; 11122474Seschrock cb.cb_used = 1; 11132474Seschrock 11142474Seschrock if (zfs_iter_children(zfsp, mount_cb, &cb) != 0) 11152474Seschrock goto out; 11162474Seschrock 11172474Seschrock /* 11182474Seschrock * Sort the datasets by mountpoint. 11192474Seschrock */ 11203126Sahl qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp); 11212474Seschrock 11222474Seschrock /* 11234180Sdougm * And mount all the datasets, keeping track of which ones 11244180Sdougm * succeeded or failed. By using zfs_alloc(), the good pointer 11254180Sdougm * will always be non-NULL. 11262474Seschrock */ 11274180Sdougm good = zfs_alloc(zhp->zpool_hdl, cb.cb_used * sizeof (int)); 11282474Seschrock ret = 0; 11292474Seschrock for (i = 0; i < cb.cb_used; i++) { 11304302Sdougm if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0) 11314180Sdougm ret = -1; 11324302Sdougm else 11334180Sdougm good[i] = 1; 11344180Sdougm } 11354180Sdougm /* 11364180Sdougm * Then share all the ones that need to be shared. This needs 11374180Sdougm * to be a separate pass in order to avoid excessive reloading 11384180Sdougm * of the configuration. Good should never be NULL since 11394180Sdougm * zfs_alloc is supposed to exit if memory isn't available. 11404180Sdougm */ 11414180Sdougm zfs_uninit_libshare(hdl); 11424180Sdougm for (i = 0; i < cb.cb_used; i++) { 11434180Sdougm if (good[i] && zfs_share(cb.cb_datasets[i]) != 0) 11442474Seschrock ret = -1; 11452474Seschrock } 11462474Seschrock 11474180Sdougm free(good); 11484180Sdougm 11492474Seschrock out: 11502474Seschrock for (i = 0; i < cb.cb_used; i++) 11512474Seschrock zfs_close(cb.cb_datasets[i]); 11522474Seschrock free(cb.cb_datasets); 11532474Seschrock 11542474Seschrock return (ret); 11552474Seschrock } 11562474Seschrock 11573126Sahl 11583126Sahl static int 11593126Sahl zvol_cb(const char *dataset, void *data) 11603126Sahl { 11613126Sahl libzfs_handle_t *hdl = data; 11623126Sahl zfs_handle_t *zhp; 11633126Sahl 11643126Sahl /* 11653126Sahl * Ignore snapshots and ignore failures from non-existant datasets. 11663126Sahl */ 11673126Sahl if (strchr(dataset, '@') != NULL || 11683126Sahl (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL) 11693126Sahl return (0); 11703126Sahl 11714543Smarks if (zfs_unshare_iscsi(zhp) != 0) 11724543Smarks return (-1); 11733126Sahl 11743126Sahl zfs_close(zhp); 11753126Sahl 11763126Sahl return (0); 11773126Sahl } 11783126Sahl 11792474Seschrock static int 11802474Seschrock mountpoint_compare(const void *a, const void *b) 11812474Seschrock { 11822474Seschrock const char *mounta = *((char **)a); 11832474Seschrock const char *mountb = *((char **)b); 11842474Seschrock 11852474Seschrock return (strcmp(mountb, mounta)); 11862474Seschrock } 11872474Seschrock 11883126Sahl /* 11893126Sahl * Unshare and unmount all datasets within the given pool. We don't want to 11903126Sahl * rely on traversing the DSL to discover the filesystems within the pool, 11913126Sahl * because this may be expensive (if not all of them are mounted), and can fail 11923126Sahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and 11933126Sahl * gather all the filesystems that are currently mounted. 11943126Sahl */ 11953126Sahl #pragma weak zpool_unmount_datasets = zpool_disable_datasets 11962474Seschrock int 11973126Sahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force) 11982474Seschrock { 11992474Seschrock int used, alloc; 12002474Seschrock struct mnttab entry; 12012474Seschrock size_t namelen; 12022474Seschrock char **mountpoints = NULL; 12032474Seschrock zfs_handle_t **datasets = NULL; 12042474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl; 12052474Seschrock int i; 12062474Seschrock int ret = -1; 12072474Seschrock int flags = (force ? MS_FORCE : 0); 12082474Seschrock 12093126Sahl /* 12103126Sahl * First unshare all zvols. 12113126Sahl */ 12123126Sahl if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0) 12133126Sahl return (-1); 12143126Sahl 12152474Seschrock namelen = strlen(zhp->zpool_name); 12162474Seschrock 12172474Seschrock rewind(hdl->libzfs_mnttab); 12182474Seschrock used = alloc = 0; 12192474Seschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) { 12202474Seschrock /* 12212474Seschrock * Ignore non-ZFS entries. 12222474Seschrock */ 12232474Seschrock if (entry.mnt_fstype == NULL || 12242474Seschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 12252474Seschrock continue; 12262474Seschrock 12272474Seschrock /* 12282474Seschrock * Ignore filesystems not within this pool. 12292474Seschrock */ 12302474Seschrock if (entry.mnt_mountp == NULL || 12312474Seschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 || 12322474Seschrock (entry.mnt_special[namelen] != '/' && 12332474Seschrock entry.mnt_special[namelen] != '\0')) 12342474Seschrock continue; 12352474Seschrock 12362474Seschrock /* 12372474Seschrock * At this point we've found a filesystem within our pool. Add 12382474Seschrock * it to our growing list. 12392474Seschrock */ 12402474Seschrock if (used == alloc) { 12412474Seschrock if (alloc == 0) { 12422474Seschrock if ((mountpoints = zfs_alloc(hdl, 12432474Seschrock 8 * sizeof (void *))) == NULL) 12442474Seschrock goto out; 12452474Seschrock 12462474Seschrock if ((datasets = zfs_alloc(hdl, 12472474Seschrock 8 * sizeof (void *))) == NULL) 12482474Seschrock goto out; 12492474Seschrock 12502474Seschrock alloc = 8; 12512474Seschrock } else { 12522676Seschrock void *ptr; 12532474Seschrock 12542676Seschrock if ((ptr = zfs_realloc(hdl, mountpoints, 12552676Seschrock alloc * sizeof (void *), 12562474Seschrock alloc * 2 * sizeof (void *))) == NULL) 12572474Seschrock goto out; 12582676Seschrock mountpoints = ptr; 12592474Seschrock 12602676Seschrock if ((ptr = zfs_realloc(hdl, datasets, 12612676Seschrock alloc * sizeof (void *), 12622474Seschrock alloc * 2 * sizeof (void *))) == NULL) 12632474Seschrock goto out; 12642676Seschrock datasets = ptr; 12652474Seschrock 12662474Seschrock alloc *= 2; 12672474Seschrock } 12682474Seschrock } 12692474Seschrock 12702474Seschrock if ((mountpoints[used] = zfs_strdup(hdl, 12712474Seschrock entry.mnt_mountp)) == NULL) 12722474Seschrock goto out; 12732474Seschrock 12742474Seschrock /* 12752474Seschrock * This is allowed to fail, in case there is some I/O error. It 12762474Seschrock * is only used to determine if we need to remove the underlying 12772474Seschrock * mountpoint, so failure is not fatal. 12782474Seschrock */ 12792474Seschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special); 12802474Seschrock 12812474Seschrock used++; 12822474Seschrock } 12832474Seschrock 12842474Seschrock /* 12852474Seschrock * At this point, we have the entire list of filesystems, so sort it by 12862474Seschrock * mountpoint. 12872474Seschrock */ 12882474Seschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare); 12892474Seschrock 12902474Seschrock /* 12912474Seschrock * Walk through and first unshare everything. 12922474Seschrock */ 12932474Seschrock for (i = 0; i < used; i++) { 12945331Samw zfs_share_proto_t *curr_proto; 12955331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END; 12965331Samw curr_proto++) { 12975331Samw if (is_shared(hdl, mountpoints[i], *curr_proto) && 12985331Samw unshare_one(hdl, mountpoints[i], 12995331Samw mountpoints[i], *curr_proto) != 0) 13005331Samw goto out; 13015331Samw } 13022474Seschrock } 13032474Seschrock 13042474Seschrock /* 13052474Seschrock * Now unmount everything, removing the underlying directories as 13062474Seschrock * appropriate. 13072474Seschrock */ 13082474Seschrock for (i = 0; i < used; i++) { 13092474Seschrock if (unmount_one(hdl, mountpoints[i], flags) != 0) 13102474Seschrock goto out; 13112676Seschrock } 13122474Seschrock 13132676Seschrock for (i = 0; i < used; i++) { 13142474Seschrock if (datasets[i]) 13152474Seschrock remove_mountpoint(datasets[i]); 13162474Seschrock } 13172474Seschrock 13182474Seschrock ret = 0; 13192474Seschrock out: 13202474Seschrock for (i = 0; i < used; i++) { 13212474Seschrock if (datasets[i]) 13222474Seschrock zfs_close(datasets[i]); 13232474Seschrock free(mountpoints[i]); 13242474Seschrock } 13252474Seschrock free(datasets); 13262474Seschrock free(mountpoints); 13272474Seschrock 13282474Seschrock return (ret); 13292474Seschrock } 1330