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 /*
2312070SMark.Shellenbaum@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24789Sahrens */
25789Sahrens
26789Sahrens /*
27789Sahrens * Routines to manage ZFS mounts. We separate all the nasty routines that have
283126Sahl * to deal with the OS. The following functions are the main entry points --
293126Sahl * they are used by mount and unmount and when changing a filesystem's
303126Sahl * mountpoint.
31789Sahrens *
32789Sahrens * zfs_is_mounted()
33789Sahrens * zfs_mount()
34789Sahrens * zfs_unmount()
35789Sahrens * zfs_unmountall()
36789Sahrens *
373126Sahl * This file also contains the functions used to manage sharing filesystems via
383126Sahl * NFS and iSCSI:
39789Sahrens *
40789Sahrens * zfs_is_shared()
41789Sahrens * zfs_share()
42789Sahrens * zfs_unshare()
433126Sahl *
443126Sahl * zfs_is_shared_nfs()
455331Samw * zfs_is_shared_smb()
465331Samw * zfs_share_proto()
475331Samw * zfs_shareall();
483126Sahl * zfs_unshare_nfs()
495331Samw * zfs_unshare_smb()
503126Sahl * zfs_unshareall_nfs()
515331Samw * zfs_unshareall_smb()
525331Samw * zfs_unshareall()
535331Samw * zfs_unshareall_bypath()
542474Seschrock *
552474Seschrock * The following functions are available for pool consumers, and will
563126Sahl * mount/unmount and share/unshare all datasets within pool:
572474Seschrock *
583126Sahl * zpool_enable_datasets()
593126Sahl * zpool_disable_datasets()
60789Sahrens */
61789Sahrens
62789Sahrens #include <dirent.h>
633134Sahl #include <dlfcn.h>
64789Sahrens #include <errno.h>
65789Sahrens #include <libgen.h>
66789Sahrens #include <libintl.h>
67789Sahrens #include <stdio.h>
68789Sahrens #include <stdlib.h>
69789Sahrens #include <strings.h>
70789Sahrens #include <unistd.h>
71789Sahrens #include <zone.h>
72789Sahrens #include <sys/mntent.h>
73789Sahrens #include <sys/mount.h>
74789Sahrens #include <sys/stat.h>
75789Sahrens
76789Sahrens #include <libzfs.h>
77789Sahrens
78789Sahrens #include "libzfs_impl.h"
79789Sahrens
804180Sdougm #include <libshare.h>
814180Sdougm #include <sys/systeminfo.h>
824180Sdougm #define MAXISALEN 257 /* based on sysinfo(2) man page */
834180Sdougm
845331Samw static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
855331Samw zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
865331Samw zfs_share_proto_t);
875331Samw
885331Samw /*
895331Samw * The share protocols table must be in the same order as the zfs_share_prot_t
905331Samw * enum in libzfs_impl.h
915331Samw */
925331Samw typedef struct {
935331Samw zfs_prop_t p_prop;
945331Samw char *p_name;
955331Samw int p_share_err;
965331Samw int p_unshare_err;
975331Samw } proto_table_t;
985331Samw
995331Samw proto_table_t proto_table[PROTO_END] = {
1005331Samw {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
1015331Samw {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
1025331Samw };
1035331Samw
1045331Samw zfs_share_proto_t nfs_only[] = {
1055331Samw PROTO_NFS,
1065331Samw PROTO_END
1075331Samw };
1085331Samw
1095331Samw zfs_share_proto_t smb_only[] = {
1105331Samw PROTO_SMB,
1115331Samw PROTO_END
1125331Samw };
1135331Samw zfs_share_proto_t share_all_proto[] = {
1145331Samw PROTO_NFS,
1155331Samw PROTO_SMB,
1165331Samw PROTO_END
1175331Samw };
1185331Samw
119789Sahrens /*
1205331Samw * Search the sharetab for the given mountpoint and protocol, returning
1215331Samw * a zfs_share_type_t value.
122789Sahrens */
1235331Samw static zfs_share_type_t
is_shared(libzfs_handle_t * hdl,const char * mountpoint,zfs_share_proto_t proto)1245331Samw is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
125789Sahrens {
126789Sahrens char buf[MAXPATHLEN], *tab;
1275331Samw char *ptr;
128789Sahrens
1292082Seschrock if (hdl->libzfs_sharetab == NULL)
1305331Samw return (SHARED_NOT_SHARED);
131789Sahrens
1322082Seschrock (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
133789Sahrens
1342082Seschrock while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
135789Sahrens
136789Sahrens /* the mountpoint is the first entry on each line */
1375331Samw if ((tab = strchr(buf, '\t')) == NULL)
1385331Samw continue;
1395331Samw
1405331Samw *tab = '\0';
1415331Samw if (strcmp(buf, mountpoint) == 0) {
1425331Samw /*
1435331Samw * the protocol field is the third field
1445331Samw * skip over second field
1455331Samw */
1465331Samw ptr = ++tab;
1475331Samw if ((tab = strchr(ptr, '\t')) == NULL)
1485331Samw continue;
1495331Samw ptr = ++tab;
1505331Samw if ((tab = strchr(ptr, '\t')) == NULL)
1515331Samw continue;
152789Sahrens *tab = '\0';
1535331Samw if (strcmp(ptr,
1545331Samw proto_table[proto].p_name) == 0) {
1555331Samw switch (proto) {
1565331Samw case PROTO_NFS:
1575331Samw return (SHARED_NFS);
1585331Samw case PROTO_SMB:
1595331Samw return (SHARED_SMB);
1605331Samw default:
1615331Samw return (0);
1625331Samw }
1635331Samw }
164789Sahrens }
165789Sahrens }
166789Sahrens
1675331Samw return (SHARED_NOT_SHARED);
168789Sahrens }
169789Sahrens
170789Sahrens /*
1712082Seschrock * Returns true if the specified directory is empty. If we can't open the
1722082Seschrock * directory at all, return true so that the mount can fail with a more
173789Sahrens * informative error message.
174789Sahrens */
1752082Seschrock static boolean_t
dir_is_empty(const char * dirname)176789Sahrens dir_is_empty(const char *dirname)
177789Sahrens {
178789Sahrens DIR *dirp;
179789Sahrens struct dirent64 *dp;
180789Sahrens
181789Sahrens if ((dirp = opendir(dirname)) == NULL)
1822082Seschrock return (B_TRUE);
183789Sahrens
184789Sahrens while ((dp = readdir64(dirp)) != NULL) {
185789Sahrens
186789Sahrens if (strcmp(dp->d_name, ".") == 0 ||
187789Sahrens strcmp(dp->d_name, "..") == 0)
188789Sahrens continue;
189789Sahrens
190789Sahrens (void) closedir(dirp);
1912082Seschrock return (B_FALSE);
192789Sahrens }
193789Sahrens
194789Sahrens (void) closedir(dirp);
1952082Seschrock return (B_TRUE);
196789Sahrens }
197789Sahrens
198789Sahrens /*
199789Sahrens * Checks to see if the mount is active. If the filesystem is mounted, we fill
200789Sahrens * in 'where' with the current mountpoint, and return 1. Otherwise, we return
201789Sahrens * 0.
202789Sahrens */
2032082Seschrock boolean_t
is_mounted(libzfs_handle_t * zfs_hdl,const char * special,char ** where)2043444Sek110237 is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where)
205789Sahrens {
2068228SEric.Taylor@Sun.COM struct mnttab entry;
207789Sahrens
2088228SEric.Taylor@Sun.COM if (libzfs_mnttab_find(zfs_hdl, special, &entry) != 0)
2092082Seschrock return (B_FALSE);
210789Sahrens
211789Sahrens if (where != NULL)
2123444Sek110237 *where = zfs_strdup(zfs_hdl, entry.mnt_mountp);
213789Sahrens
2142082Seschrock return (B_TRUE);
215789Sahrens }
216789Sahrens
2173444Sek110237 boolean_t
zfs_is_mounted(zfs_handle_t * zhp,char ** where)2183444Sek110237 zfs_is_mounted(zfs_handle_t *zhp, char **where)
2193444Sek110237 {
2203444Sek110237 return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where));
2213444Sek110237 }
2223444Sek110237
223789Sahrens /*
2242676Seschrock * Returns true if the given dataset is mountable, false otherwise. Returns the
2252676Seschrock * mountpoint in 'buf'.
2262676Seschrock */
2272676Seschrock static boolean_t
zfs_is_mountable(zfs_handle_t * zhp,char * buf,size_t buflen,zprop_source_t * source)2282676Seschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
2295094Slling zprop_source_t *source)
2302676Seschrock {
2312676Seschrock char sourceloc[ZFS_MAXNAMELEN];
2325094Slling zprop_source_t sourcetype;
2332676Seschrock
2342676Seschrock if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type))
2352676Seschrock return (B_FALSE);
2362676Seschrock
2372676Seschrock verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen,
2382676Seschrock &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0);
2392676Seschrock
2402676Seschrock if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 ||
2412676Seschrock strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0)
2422676Seschrock return (B_FALSE);
2432676Seschrock
2446168Shs24103 if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF)
2452676Seschrock return (B_FALSE);
2462676Seschrock
2472676Seschrock if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
2482676Seschrock getzoneid() == GLOBAL_ZONEID)
2492676Seschrock return (B_FALSE);
2502676Seschrock
2512676Seschrock if (source)
2522676Seschrock *source = sourcetype;
2532676Seschrock
2542676Seschrock return (B_TRUE);
2552676Seschrock }
2562676Seschrock
2572676Seschrock /*
258789Sahrens * Mount the given filesystem.
259789Sahrens */
260789Sahrens int
zfs_mount(zfs_handle_t * zhp,const char * options,int flags)261789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
262789Sahrens {
263789Sahrens struct stat buf;
264789Sahrens char mountpoint[ZFS_MAXPROPLEN];
265789Sahrens char mntopts[MNT_LINE_MAX];
2662082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl;
267789Sahrens
268789Sahrens if (options == NULL)
269789Sahrens mntopts[0] = '\0';
270789Sahrens else
271789Sahrens (void) strlcpy(mntopts, options, sizeof (mntopts));
272789Sahrens
273*13049SGeorge.Wilson@Sun.COM /*
274*13049SGeorge.Wilson@Sun.COM * If the pool is imported read-only then all mounts must be read-only
275*13049SGeorge.Wilson@Sun.COM */
276*13049SGeorge.Wilson@Sun.COM if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
277*13049SGeorge.Wilson@Sun.COM flags |= MS_RDONLY;
278*13049SGeorge.Wilson@Sun.COM
2792676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
2802082Seschrock return (0);
281789Sahrens
282789Sahrens /* Create the directory if it doesn't already exist */
283789Sahrens if (lstat(mountpoint, &buf) != 0) {
284789Sahrens if (mkdirp(mountpoint, 0755) != 0) {
2852082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2862082Seschrock "failed to create mountpoint"));
2873237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
2882082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
2892082Seschrock mountpoint));
290789Sahrens }
291789Sahrens }
292789Sahrens
293789Sahrens /*
294789Sahrens * Determine if the mountpoint is empty. If so, refuse to perform the
295789Sahrens * mount. We don't perform this check if MS_OVERLAY is specified, which
296789Sahrens * would defeat the point. We also avoid this check if 'remount' is
297789Sahrens * specified.
298789Sahrens */
299789Sahrens if ((flags & MS_OVERLAY) == 0 &&
300789Sahrens strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
301789Sahrens !dir_is_empty(mountpoint)) {
3022082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3032082Seschrock "directory is not empty"));
3043237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
3052082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
306789Sahrens }
307789Sahrens
308789Sahrens /* perform the mount */
309789Sahrens if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
310789Sahrens MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
311789Sahrens /*
312789Sahrens * Generic errors are nasty, but there are just way too many
313789Sahrens * from mount(), and they're well-understood. We pick a few
314789Sahrens * common ones to improve upon.
315789Sahrens */
3164302Sdougm if (errno == EBUSY) {
3172082Seschrock zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3182082Seschrock "mountpoint or dataset is busy"));
3194543Smarks } else if (errno == EPERM) {
3204543Smarks zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3214543Smarks "Insufficient privileges"));
32211814SChris.Kirby@sun.com } else if (errno == ENOTSUP) {
32311814SChris.Kirby@sun.com char buf[256];
32412070SMark.Shellenbaum@Sun.COM int spa_version;
32511814SChris.Kirby@sun.com
32612070SMark.Shellenbaum@Sun.COM VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
32711814SChris.Kirby@sun.com (void) snprintf(buf, sizeof (buf),
32812070SMark.Shellenbaum@Sun.COM dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
32912070SMark.Shellenbaum@Sun.COM "file system on a version %d pool. Pool must be"
33012070SMark.Shellenbaum@Sun.COM " upgraded to mount this file system."),
33111814SChris.Kirby@sun.com (u_longlong_t)zfs_prop_get_int(zhp,
33212070SMark.Shellenbaum@Sun.COM ZFS_PROP_VERSION), spa_version);
33311814SChris.Kirby@sun.com zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
3344302Sdougm } else {
3352082Seschrock zfs_error_aux(hdl, strerror(errno));
3364302Sdougm }
3373237Slling return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
3382082Seschrock dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
3392082Seschrock zhp->zfs_name));
340789Sahrens }
341789Sahrens
3428228SEric.Taylor@Sun.COM /* add the mounted entry into our cache */
3438228SEric.Taylor@Sun.COM libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint,
3448228SEric.Taylor@Sun.COM mntopts);
345789Sahrens return (0);
346789Sahrens }
347789Sahrens
348789Sahrens /*
3492474Seschrock * Unmount a single filesystem.
3502474Seschrock */
3512474Seschrock static int
unmount_one(libzfs_handle_t * hdl,const char * mountpoint,int flags)3522474Seschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
3532474Seschrock {
3542474Seschrock if (umount2(mountpoint, flags) != 0) {
3552474Seschrock zfs_error_aux(hdl, strerror(errno));
3563237Slling return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
3572474Seschrock dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
3582474Seschrock mountpoint));
3592474Seschrock }
3602474Seschrock
3612474Seschrock return (0);
3622474Seschrock }
3632474Seschrock
3642474Seschrock /*
365789Sahrens * Unmount the given filesystem.
366789Sahrens */
367789Sahrens int
zfs_unmount(zfs_handle_t * zhp,const char * mountpoint,int flags)368789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
369789Sahrens {
3708228SEric.Taylor@Sun.COM libzfs_handle_t *hdl = zhp->zfs_hdl;
3718228SEric.Taylor@Sun.COM struct mnttab entry;
3724180Sdougm char *mntpt = NULL;
373789Sahrens
3748228SEric.Taylor@Sun.COM /* check to see if we need to unmount the filesystem */
375789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
3768228SEric.Taylor@Sun.COM libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) {
3774180Sdougm /*
3784180Sdougm * mountpoint may have come from a call to
3794180Sdougm * getmnt/getmntany if it isn't NULL. If it is NULL,
3808228SEric.Taylor@Sun.COM * we know it comes from libzfs_mnttab_find which can
3818228SEric.Taylor@Sun.COM * then get freed later. We strdup it to play it safe.
3824180Sdougm */
383789Sahrens if (mountpoint == NULL)
3848228SEric.Taylor@Sun.COM mntpt = zfs_strdup(hdl, entry.mnt_mountp);
3854180Sdougm else
3868228SEric.Taylor@Sun.COM mntpt = zfs_strdup(hdl, mountpoint);
387789Sahrens
388789Sahrens /*
3892474Seschrock * Unshare and unmount the filesystem
390789Sahrens */
3915331Samw if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
3924331Sth199096 return (-1);
3934331Sth199096
3948228SEric.Taylor@Sun.COM if (unmount_one(hdl, mntpt, flags) != 0) {
3954180Sdougm free(mntpt);
3965331Samw (void) zfs_shareall(zhp);
397789Sahrens return (-1);
3984180Sdougm }
3998228SEric.Taylor@Sun.COM libzfs_mnttab_remove(hdl, zhp->zfs_name);
4004180Sdougm free(mntpt);
401789Sahrens }
402789Sahrens
403789Sahrens return (0);
404789Sahrens }
405789Sahrens
406789Sahrens /*
407789Sahrens * Unmount this filesystem and any children inheriting the mountpoint property.
408789Sahrens * To do this, just act like we're changing the mountpoint property, but don't
409789Sahrens * remount the filesystems afterwards.
410789Sahrens */
411789Sahrens int
zfs_unmountall(zfs_handle_t * zhp,int flags)412789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags)
413789Sahrens {
414789Sahrens prop_changelist_t *clp;
415789Sahrens int ret;
416789Sahrens
4177366STim.Haley@Sun.COM clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags);
418789Sahrens if (clp == NULL)
419789Sahrens return (-1);
420789Sahrens
421789Sahrens ret = changelist_prefix(clp);
422789Sahrens changelist_free(clp);
423789Sahrens
424789Sahrens return (ret);
425789Sahrens }
426789Sahrens
4273126Sahl boolean_t
zfs_is_shared(zfs_handle_t * zhp)4283126Sahl zfs_is_shared(zfs_handle_t *zhp)
4293126Sahl {
4305331Samw zfs_share_type_t rc = 0;
4315331Samw zfs_share_proto_t *curr_proto;
4325331Samw
4333126Sahl if (ZFS_IS_VOLUME(zhp))
43411876SJames.Dunham@Sun.COM return (B_FALSE);
4353126Sahl
4365331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
4375331Samw curr_proto++)
4385331Samw rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto);
4395331Samw
4405331Samw return (rc ? B_TRUE : B_FALSE);
4413126Sahl }
4423126Sahl
4433126Sahl int
zfs_share(zfs_handle_t * zhp)4443126Sahl zfs_share(zfs_handle_t *zhp)
4453126Sahl {
44613025SEric.Taylor@oracle.com assert(!ZFS_IS_VOLUME(zhp));
4475331Samw return (zfs_share_proto(zhp, share_all_proto));
4483126Sahl }
4493126Sahl
4503126Sahl int
zfs_unshare(zfs_handle_t * zhp)4513126Sahl zfs_unshare(zfs_handle_t *zhp)
4523126Sahl {
45313025SEric.Taylor@oracle.com assert(!ZFS_IS_VOLUME(zhp));
4545331Samw return (zfs_unshareall(zhp));
4553126Sahl }
4563126Sahl
457789Sahrens /*
458789Sahrens * Check to see if the filesystem is currently shared.
459789Sahrens */
4605331Samw zfs_share_type_t
zfs_is_shared_proto(zfs_handle_t * zhp,char ** where,zfs_share_proto_t proto)4615331Samw zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
462789Sahrens {
463789Sahrens char *mountpoint;
4645331Samw zfs_share_type_t rc;
465789Sahrens
466789Sahrens if (!zfs_is_mounted(zhp, &mountpoint))
4675331Samw return (SHARED_NOT_SHARED);
468789Sahrens
4695331Samw if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) {
470789Sahrens if (where != NULL)
471789Sahrens *where = mountpoint;
472789Sahrens else
473789Sahrens free(mountpoint);
4745331Samw return (rc);
475789Sahrens } else {
476789Sahrens free(mountpoint);
4775331Samw return (SHARED_NOT_SHARED);
478789Sahrens }
479789Sahrens }
480789Sahrens
4815331Samw boolean_t
zfs_is_shared_nfs(zfs_handle_t * zhp,char ** where)4825331Samw zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
4835331Samw {
4845331Samw return (zfs_is_shared_proto(zhp, where,
4855331Samw PROTO_NFS) != SHARED_NOT_SHARED);
4865331Samw }
4875331Samw
4885331Samw boolean_t
zfs_is_shared_smb(zfs_handle_t * zhp,char ** where)4895331Samw zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
4905331Samw {
4915331Samw return (zfs_is_shared_proto(zhp, where,
4925331Samw PROTO_SMB) != SHARED_NOT_SHARED);
4935331Samw }
4945331Samw
495789Sahrens /*
4964180Sdougm * Make sure things will work if libshare isn't installed by using
4974180Sdougm * wrapper functions that check to see that the pointers to functions
4984180Sdougm * initialized in _zfs_init_libshare() are actually present.
4994180Sdougm */
5004180Sdougm
5014180Sdougm static sa_handle_t (*_sa_init)(int);
5024180Sdougm static void (*_sa_fini)(sa_handle_t);
5034180Sdougm static sa_share_t (*_sa_find_share)(sa_handle_t, char *);
5044180Sdougm static int (*_sa_enable_share)(sa_share_t, char *);
5054180Sdougm static int (*_sa_disable_share)(sa_share_t, char *);
5064180Sdougm static char *(*_sa_errorstr)(int);
5074180Sdougm static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *);
5085951Sdougm static boolean_t (*_sa_needs_refresh)(sa_handle_t *);
5095951Sdougm static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t);
5105951Sdougm static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t,
5115951Sdougm char *, char *, zprop_source_t, char *, char *, char *);
5125951Sdougm static void (*_sa_update_sharetab_ts)(sa_handle_t);
5134180Sdougm
5144180Sdougm /*
5154180Sdougm * _zfs_init_libshare()
5164180Sdougm *
5174180Sdougm * Find the libshare.so.1 entry points that we use here and save the
5184180Sdougm * values to be used later. This is triggered by the runtime loader.
5194180Sdougm * Make sure the correct ISA version is loaded.
5204180Sdougm */
5215951Sdougm
5224180Sdougm #pragma init(_zfs_init_libshare)
5234180Sdougm static void
_zfs_init_libshare(void)5244180Sdougm _zfs_init_libshare(void)
5254180Sdougm {
5264180Sdougm void *libshare;
5274180Sdougm char path[MAXPATHLEN];
5284180Sdougm char isa[MAXISALEN];
5294180Sdougm
5304180Sdougm #if defined(_LP64)
5314180Sdougm if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
5324302Sdougm isa[0] = '\0';
5334180Sdougm #else
5344180Sdougm isa[0] = '\0';
5354180Sdougm #endif
5364180Sdougm (void) snprintf(path, MAXPATHLEN,
5374302Sdougm "/usr/lib/%s/libshare.so.1", isa);
5384180Sdougm
5394180Sdougm if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) {
5404302Sdougm _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init");
5414302Sdougm _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini");
5424302Sdougm _sa_find_share = (sa_share_t (*)(sa_handle_t, char *))
5434302Sdougm dlsym(libshare, "sa_find_share");
5444302Sdougm _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
5454302Sdougm "sa_enable_share");
5464302Sdougm _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
5474302Sdougm "sa_disable_share");
5484302Sdougm _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr");
5494302Sdougm _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *))
5504302Sdougm dlsym(libshare, "sa_parse_legacy_options");
5515951Sdougm _sa_needs_refresh = (boolean_t (*)(sa_handle_t *))
5525951Sdougm dlsym(libshare, "sa_needs_refresh");
5535951Sdougm _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t))
5545951Sdougm dlsym(libshare, "sa_get_zfs_handle");
5555951Sdougm _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t,
5565951Sdougm sa_share_t, char *, char *, zprop_source_t, char *,
5575951Sdougm char *, char *))dlsym(libshare, "sa_zfs_process_share");
5585951Sdougm _sa_update_sharetab_ts = (void (*)(sa_handle_t))
5595951Sdougm dlsym(libshare, "sa_update_sharetab_ts");
5604327Sdougm if (_sa_init == NULL || _sa_fini == NULL ||
5614327Sdougm _sa_find_share == NULL || _sa_enable_share == NULL ||
5624327Sdougm _sa_disable_share == NULL || _sa_errorstr == NULL ||
5635951Sdougm _sa_parse_legacy_options == NULL ||
5645951Sdougm _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL ||
5655951Sdougm _sa_zfs_process_share == NULL ||
5665951Sdougm _sa_update_sharetab_ts == NULL) {
5674327Sdougm _sa_init = NULL;
5684327Sdougm _sa_fini = NULL;
5694327Sdougm _sa_disable_share = NULL;
5704327Sdougm _sa_enable_share = NULL;
5714327Sdougm _sa_errorstr = NULL;
5724327Sdougm _sa_parse_legacy_options = NULL;
5734327Sdougm (void) dlclose(libshare);
5745951Sdougm _sa_needs_refresh = NULL;
5755951Sdougm _sa_get_zfs_handle = NULL;
5765951Sdougm _sa_zfs_process_share = NULL;
5775951Sdougm _sa_update_sharetab_ts = NULL;
5784327Sdougm }
5794180Sdougm }
5804180Sdougm }
5814180Sdougm
5824180Sdougm /*
5834180Sdougm * zfs_init_libshare(zhandle, service)
5844180Sdougm *
5854180Sdougm * Initialize the libshare API if it hasn't already been initialized.
5864180Sdougm * In all cases it returns 0 if it succeeded and an error if not. The
5874180Sdougm * service value is which part(s) of the API to initialize and is a
5884180Sdougm * direct map to the libshare sa_init(service) interface.
5894180Sdougm */
5904180Sdougm int
zfs_init_libshare(libzfs_handle_t * zhandle,int service)5914180Sdougm zfs_init_libshare(libzfs_handle_t *zhandle, int service)
5924180Sdougm {
5934180Sdougm int ret = SA_OK;
5944180Sdougm
5954302Sdougm if (_sa_init == NULL)
5964302Sdougm ret = SA_CONFIG_ERR;
5974302Sdougm
5985951Sdougm if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) {
5995951Sdougm /*
6005951Sdougm * We had a cache miss. Most likely it is a new ZFS
6015951Sdougm * dataset that was just created. We want to make sure
6025951Sdougm * so check timestamps to see if a different process
6035951Sdougm * has updated any of the configuration. If there was
6045951Sdougm * some non-ZFS change, we need to re-initialize the
6055951Sdougm * internal cache.
6065951Sdougm */
6075951Sdougm zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS;
6085951Sdougm if (_sa_needs_refresh != NULL &&
6095951Sdougm _sa_needs_refresh(zhandle->libzfs_sharehdl)) {
6105951Sdougm zfs_uninit_libshare(zhandle);
6115951Sdougm zhandle->libzfs_sharehdl = _sa_init(service);
6125951Sdougm }
6135951Sdougm }
6145951Sdougm
6154302Sdougm if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL)
6164302Sdougm zhandle->libzfs_sharehdl = _sa_init(service);
6174302Sdougm
6184302Sdougm if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL)
6194302Sdougm ret = SA_NO_MEMORY;
6204302Sdougm
6214180Sdougm return (ret);
6224180Sdougm }
6234180Sdougm
6244180Sdougm /*
6254180Sdougm * zfs_uninit_libshare(zhandle)
6264180Sdougm *
6274180Sdougm * Uninitialize the libshare API if it hasn't already been
6284180Sdougm * uninitialized. It is OK to call multiple times.
6294180Sdougm */
6304180Sdougm void
zfs_uninit_libshare(libzfs_handle_t * zhandle)6314180Sdougm zfs_uninit_libshare(libzfs_handle_t *zhandle)
6324180Sdougm {
6334180Sdougm if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
6344302Sdougm if (_sa_fini != NULL)
6354302Sdougm _sa_fini(zhandle->libzfs_sharehdl);
6364302Sdougm zhandle->libzfs_sharehdl = NULL;
6374180Sdougm }
6384180Sdougm }
6394180Sdougm
6404180Sdougm /*
6414180Sdougm * zfs_parse_options(options, proto)
6424180Sdougm *
6434180Sdougm * Call the legacy parse interface to get the protocol specific
6444180Sdougm * options using the NULL arg to indicate that this is a "parse" only.
6454180Sdougm */
6464180Sdougm int
zfs_parse_options(char * options,zfs_share_proto_t proto)6475331Samw zfs_parse_options(char *options, zfs_share_proto_t proto)
6484180Sdougm {
6495367Sahrens if (_sa_parse_legacy_options != NULL) {
6505367Sahrens return (_sa_parse_legacy_options(NULL, options,
6515367Sahrens proto_table[proto].p_name));
6525367Sahrens }
6535367Sahrens return (SA_CONFIG_ERR);
6544180Sdougm }
6554180Sdougm
6564180Sdougm /*
6574180Sdougm * zfs_sa_find_share(handle, path)
6584180Sdougm *
6594180Sdougm * wrapper around sa_find_share to find a share path in the
6604180Sdougm * configuration.
6614180Sdougm */
6624180Sdougm static sa_share_t
zfs_sa_find_share(sa_handle_t handle,char * path)6634180Sdougm zfs_sa_find_share(sa_handle_t handle, char *path)
6644180Sdougm {
6654180Sdougm if (_sa_find_share != NULL)
6664302Sdougm return (_sa_find_share(handle, path));
6674180Sdougm return (NULL);
6684180Sdougm }
6694180Sdougm
6704180Sdougm /*
6714180Sdougm * zfs_sa_enable_share(share, proto)
6724180Sdougm *
6734180Sdougm * Wrapper for sa_enable_share which enables a share for a specified
6744180Sdougm * protocol.
6754180Sdougm */
6764180Sdougm static int
zfs_sa_enable_share(sa_share_t share,char * proto)6774180Sdougm zfs_sa_enable_share(sa_share_t share, char *proto)
6784180Sdougm {
6794180Sdougm if (_sa_enable_share != NULL)
6804302Sdougm return (_sa_enable_share(share, proto));
6814180Sdougm return (SA_CONFIG_ERR);
6824180Sdougm }
6834180Sdougm
6844180Sdougm /*
6854180Sdougm * zfs_sa_disable_share(share, proto)
6864180Sdougm *
6874180Sdougm * Wrapper for sa_enable_share which disables a share for a specified
6884180Sdougm * protocol.
6894180Sdougm */
6904180Sdougm static int
zfs_sa_disable_share(sa_share_t share,char * proto)6914180Sdougm zfs_sa_disable_share(sa_share_t share, char *proto)
6924180Sdougm {
6934180Sdougm if (_sa_disable_share != NULL)
6944302Sdougm return (_sa_disable_share(share, proto));
6954180Sdougm return (SA_CONFIG_ERR);
6964180Sdougm }
6974180Sdougm
6984180Sdougm /*
6995331Samw * Share the given filesystem according to the options in the specified
7005331Samw * protocol specific properties (sharenfs, sharesmb). We rely
7014180Sdougm * on "libshare" to the dirty work for us.
702789Sahrens */
7035331Samw static int
zfs_share_proto(zfs_handle_t * zhp,zfs_share_proto_t * proto)7045331Samw zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
705789Sahrens {
706789Sahrens char mountpoint[ZFS_MAXPROPLEN];
707789Sahrens char shareopts[ZFS_MAXPROPLEN];
7085951Sdougm char sourcestr[ZFS_MAXPROPLEN];
7092082Seschrock libzfs_handle_t *hdl = zhp->zfs_hdl;
7104180Sdougm sa_share_t share;
7115331Samw zfs_share_proto_t *curr_proto;
7125951Sdougm zprop_source_t sourcetype;
7134180Sdougm int ret;
714789Sahrens
7152676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
716789Sahrens return (0);
717789Sahrens
7184180Sdougm if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
7194302Sdougm (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
7204302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
7215951Sdougm zfs_get_name(zhp), _sa_errorstr != NULL ?
7225951Sdougm _sa_errorstr(ret) : "");
7234302Sdougm return (-1);
7244180Sdougm }
7255331Samw
7265331Samw for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
7275331Samw /*
7285331Samw * Return success if there are no share options.
7295331Samw */
7305331Samw if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
7315951Sdougm shareopts, sizeof (shareopts), &sourcetype, sourcestr,
7325951Sdougm ZFS_MAXPROPLEN, B_FALSE) != 0 ||
7335951Sdougm strcmp(shareopts, "off") == 0)
7345331Samw continue;
7355331Samw
7365331Samw /*
7375331Samw * If the 'zoned' property is set, then zfs_is_mountable()
7385331Samw * will have already bailed out if we are in the global zone.
7395331Samw * But local zones cannot be NFS servers, so we ignore it for
7405331Samw * local zones as well.
7415331Samw */
7425331Samw if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
7435331Samw continue;
7445331Samw
7455331Samw share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
7465951Sdougm if (share == NULL) {
7475951Sdougm /*
7485951Sdougm * This may be a new file system that was just
7495951Sdougm * created so isn't in the internal cache
7505951Sdougm * (second time through). Rather than
7515951Sdougm * reloading the entire configuration, we can
7525951Sdougm * assume ZFS has done the checking and it is
7535951Sdougm * safe to add this to the internal
7545951Sdougm * configuration.
7555951Sdougm */
7565951Sdougm if (_sa_zfs_process_share(hdl->libzfs_sharehdl,
7575951Sdougm NULL, NULL, mountpoint,
7585951Sdougm proto_table[*curr_proto].p_name, sourcetype,
7595951Sdougm shareopts, sourcestr, zhp->zfs_name) != SA_OK) {
7605951Sdougm (void) zfs_error_fmt(hdl,
7615951Sdougm proto_table[*curr_proto].p_share_err,
7625951Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"),
7635951Sdougm zfs_get_name(zhp));
7645951Sdougm return (-1);
7655951Sdougm }
7665951Sdougm hdl->libzfs_shareflags |= ZFSSHARE_MISS;
7675951Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl,
7685951Sdougm mountpoint);
7695951Sdougm }
7705331Samw if (share != NULL) {
7715331Samw int err;
7725331Samw err = zfs_sa_enable_share(share,
7735331Samw proto_table[*curr_proto].p_name);
7745331Samw if (err != SA_OK) {
7755331Samw (void) zfs_error_fmt(hdl,
7765331Samw proto_table[*curr_proto].p_share_err,
7775331Samw dgettext(TEXT_DOMAIN, "cannot share '%s'"),
7785331Samw zfs_get_name(zhp));
7795331Samw return (-1);
7805331Samw }
7815331Samw } else {
7825331Samw (void) zfs_error_fmt(hdl,
7835331Samw proto_table[*curr_proto].p_share_err,
7844302Sdougm dgettext(TEXT_DOMAIN, "cannot share '%s'"),
7854302Sdougm zfs_get_name(zhp));
7864302Sdougm return (-1);
7874302Sdougm }
7885331Samw
789789Sahrens }
7905331Samw return (0);
7915331Samw }
792789Sahrens
7935331Samw
7945331Samw int
zfs_share_nfs(zfs_handle_t * zhp)7955331Samw zfs_share_nfs(zfs_handle_t *zhp)
7965331Samw {
7975331Samw return (zfs_share_proto(zhp, nfs_only));
7985331Samw }
7995331Samw
8005331Samw int
zfs_share_smb(zfs_handle_t * zhp)8015331Samw zfs_share_smb(zfs_handle_t *zhp)
8025331Samw {
8035331Samw return (zfs_share_proto(zhp, smb_only));
8045331Samw }
8055331Samw
8065331Samw int
zfs_shareall(zfs_handle_t * zhp)8075331Samw zfs_shareall(zfs_handle_t *zhp)
8085331Samw {
8095331Samw return (zfs_share_proto(zhp, share_all_proto));
810789Sahrens }
811789Sahrens
812789Sahrens /*
8132474Seschrock * Unshare a filesystem by mountpoint.
8142474Seschrock */
8152474Seschrock static int
unshare_one(libzfs_handle_t * hdl,const char * name,const char * mountpoint,zfs_share_proto_t proto)8165331Samw unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
8175331Samw zfs_share_proto_t proto)
8182474Seschrock {
8194180Sdougm sa_share_t share;
8204180Sdougm int err;
8214180Sdougm char *mntpt;
8222474Seschrock /*
8234180Sdougm * Mountpoint could get trashed if libshare calls getmntany
8248228SEric.Taylor@Sun.COM * which it does during API initialization, so strdup the
8254180Sdougm * value.
8262474Seschrock */
8274180Sdougm mntpt = zfs_strdup(hdl, mountpoint);
8282474Seschrock
8294180Sdougm /* make sure libshare initialized */
8304180Sdougm if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
8314180Sdougm free(mntpt); /* don't need the copy anymore */
8324180Sdougm return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
8334302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
8344302Sdougm name, _sa_errorstr(err)));
8352474Seschrock }
8362474Seschrock
8374180Sdougm share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt);
8384180Sdougm free(mntpt); /* don't need the copy anymore */
8392474Seschrock
8404180Sdougm if (share != NULL) {
8415331Samw err = zfs_sa_disable_share(share, proto_table[proto].p_name);
8424180Sdougm if (err != SA_OK) {
8434302Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
8444302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
8454302Sdougm name, _sa_errorstr(err)));
8464180Sdougm }
8474180Sdougm } else {
8484180Sdougm return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
8494302Sdougm dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"),
8504302Sdougm name));
8514180Sdougm }
8522474Seschrock return (0);
8532474Seschrock }
8542474Seschrock
8552474Seschrock /*
856789Sahrens * Unshare the given filesystem.
857789Sahrens */
858789Sahrens int
zfs_unshare_proto(zfs_handle_t * zhp,const char * mountpoint,zfs_share_proto_t * proto)8595331Samw zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
8605331Samw zfs_share_proto_t *proto)
861789Sahrens {
8628228SEric.Taylor@Sun.COM libzfs_handle_t *hdl = zhp->zfs_hdl;
8638228SEric.Taylor@Sun.COM struct mnttab entry;
8644180Sdougm char *mntpt = NULL;
865789Sahrens
866789Sahrens /* check to see if need to unmount the filesystem */
8672082Seschrock rewind(zhp->zfs_hdl->libzfs_mnttab);
8684302Sdougm if (mountpoint != NULL)
8698228SEric.Taylor@Sun.COM mountpoint = mntpt = zfs_strdup(hdl, mountpoint);
8704302Sdougm
871789Sahrens if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
8728228SEric.Taylor@Sun.COM libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) {
8735331Samw zfs_share_proto_t *curr_proto;
874789Sahrens
875789Sahrens if (mountpoint == NULL)
8765331Samw mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
8775331Samw
8785331Samw for (curr_proto = proto; *curr_proto != PROTO_END;
8795331Samw curr_proto++) {
880789Sahrens
8818228SEric.Taylor@Sun.COM if (is_shared(hdl, mntpt, *curr_proto) &&
8828228SEric.Taylor@Sun.COM unshare_one(hdl, zhp->zfs_name,
8835331Samw mntpt, *curr_proto) != 0) {
8845331Samw if (mntpt != NULL)
8855331Samw free(mntpt);
8865331Samw return (-1);
8875331Samw }
8884180Sdougm }
889789Sahrens }
8904180Sdougm if (mntpt != NULL)
8914302Sdougm free(mntpt);
892789Sahrens
893789Sahrens return (0);
894789Sahrens }
895789Sahrens
8965331Samw int
zfs_unshare_nfs(zfs_handle_t * zhp,const char * mountpoint)8975331Samw zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
8985331Samw {
8995331Samw return (zfs_unshare_proto(zhp, mountpoint, nfs_only));
9005331Samw }
9015331Samw
9025331Samw int
zfs_unshare_smb(zfs_handle_t * zhp,const char * mountpoint)9035331Samw zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint)
9045331Samw {
9055331Samw return (zfs_unshare_proto(zhp, mountpoint, smb_only));
9065331Samw }
9075331Samw
908789Sahrens /*
9095331Samw * Same as zfs_unmountall(), but for NFS and SMB unshares.
910789Sahrens */
911789Sahrens int
zfs_unshareall_proto(zfs_handle_t * zhp,zfs_share_proto_t * proto)9125331Samw zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
913789Sahrens {
914789Sahrens prop_changelist_t *clp;
915789Sahrens int ret;
916789Sahrens
9177366STim.Haley@Sun.COM clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0);
918789Sahrens if (clp == NULL)
919789Sahrens return (-1);
920789Sahrens
9215331Samw ret = changelist_unshare(clp, proto);
922789Sahrens changelist_free(clp);
923789Sahrens
924789Sahrens return (ret);
925789Sahrens }
926789Sahrens
9275331Samw int
zfs_unshareall_nfs(zfs_handle_t * zhp)9285331Samw zfs_unshareall_nfs(zfs_handle_t *zhp)
9295331Samw {
9305331Samw return (zfs_unshareall_proto(zhp, nfs_only));
9315331Samw }
9325331Samw
9335331Samw int
zfs_unshareall_smb(zfs_handle_t * zhp)9345331Samw zfs_unshareall_smb(zfs_handle_t *zhp)
9355331Samw {
9365331Samw return (zfs_unshareall_proto(zhp, smb_only));
9375331Samw }
9385331Samw
9395331Samw int
zfs_unshareall(zfs_handle_t * zhp)9405331Samw zfs_unshareall(zfs_handle_t *zhp)
9415331Samw {
9425331Samw return (zfs_unshareall_proto(zhp, share_all_proto));
9435331Samw }
9445331Samw
9455331Samw int
zfs_unshareall_bypath(zfs_handle_t * zhp,const char * mountpoint)9465331Samw zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint)
9475331Samw {
9485331Samw return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
9495331Samw }
9505331Samw
951789Sahrens /*
952789Sahrens * Remove the mountpoint associated with the current dataset, if necessary.
953789Sahrens * We only remove the underlying directory if:
954789Sahrens *
955789Sahrens * - The mountpoint is not 'none' or 'legacy'
956789Sahrens * - The mountpoint is non-empty
957789Sahrens * - The mountpoint is the default or inherited
958789Sahrens * - The 'zoned' property is set, or we're in a local zone
959789Sahrens *
960789Sahrens * Any other directories we leave alone.
961789Sahrens */
962789Sahrens void
remove_mountpoint(zfs_handle_t * zhp)963789Sahrens remove_mountpoint(zfs_handle_t *zhp)
964789Sahrens {
965789Sahrens char mountpoint[ZFS_MAXPROPLEN];
9665094Slling zprop_source_t source;
967789Sahrens
9682676Seschrock if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
9692676Seschrock &source))
970789Sahrens return;
971789Sahrens
9725094Slling if (source == ZPROP_SRC_DEFAULT ||
9735094Slling source == ZPROP_SRC_INHERITED) {
974789Sahrens /*
975789Sahrens * Try to remove the directory, silently ignoring any errors.
976789Sahrens * The filesystem may have since been removed or moved around,
9772676Seschrock * and this error isn't really useful to the administrator in
9782676Seschrock * any way.
979789Sahrens */
980789Sahrens (void) rmdir(mountpoint);
981789Sahrens }
982789Sahrens }
9832474Seschrock
98413025SEric.Taylor@oracle.com void
libzfs_add_handle(get_all_cb_t * cbp,zfs_handle_t * zhp)98513025SEric.Taylor@oracle.com libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp)
98613025SEric.Taylor@oracle.com {
98713025SEric.Taylor@oracle.com if (cbp->cb_alloc == cbp->cb_used) {
98813025SEric.Taylor@oracle.com size_t newsz;
98913025SEric.Taylor@oracle.com void *ptr;
99013025SEric.Taylor@oracle.com
99113025SEric.Taylor@oracle.com newsz = cbp->cb_alloc ? cbp->cb_alloc * 2 : 64;
99213025SEric.Taylor@oracle.com ptr = zfs_realloc(zhp->zfs_hdl,
99313025SEric.Taylor@oracle.com cbp->cb_handles, cbp->cb_alloc * sizeof (void *),
99413025SEric.Taylor@oracle.com newsz * sizeof (void *));
99513025SEric.Taylor@oracle.com cbp->cb_handles = ptr;
99613025SEric.Taylor@oracle.com cbp->cb_alloc = newsz;
99713025SEric.Taylor@oracle.com }
99813025SEric.Taylor@oracle.com cbp->cb_handles[cbp->cb_used++] = zhp;
99913025SEric.Taylor@oracle.com }
10002474Seschrock
10012474Seschrock static int
mount_cb(zfs_handle_t * zhp,void * data)10022474Seschrock mount_cb(zfs_handle_t *zhp, void *data)
10032474Seschrock {
100413025SEric.Taylor@oracle.com get_all_cb_t *cbp = data;
10052474Seschrock
100613025SEric.Taylor@oracle.com if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
10072474Seschrock zfs_close(zhp);
10082474Seschrock return (0);
10092474Seschrock }
10102474Seschrock
10116168Shs24103 if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
10126168Shs24103 zfs_close(zhp);
10136168Shs24103 return (0);
10146168Shs24103 }
10156168Shs24103
101613025SEric.Taylor@oracle.com libzfs_add_handle(cbp, zhp);
101713025SEric.Taylor@oracle.com if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
101813025SEric.Taylor@oracle.com zfs_close(zhp);
101913025SEric.Taylor@oracle.com return (-1);
10202474Seschrock }
102113025SEric.Taylor@oracle.com return (0);
10222474Seschrock }
10232474Seschrock
102413025SEric.Taylor@oracle.com int
libzfs_dataset_cmp(const void * a,const void * b)102513025SEric.Taylor@oracle.com libzfs_dataset_cmp(const void *a, const void *b)
10262474Seschrock {
10272474Seschrock zfs_handle_t **za = (zfs_handle_t **)a;
10282474Seschrock zfs_handle_t **zb = (zfs_handle_t **)b;
10292474Seschrock char mounta[MAXPATHLEN];
10302474Seschrock char mountb[MAXPATHLEN];
10313126Sahl boolean_t gota, gotb;
10322474Seschrock
10333126Sahl if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0)
10343126Sahl verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
10353126Sahl sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
10363126Sahl if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0)
10373126Sahl verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
10383126Sahl sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
10392474Seschrock
10403126Sahl if (gota && gotb)
10413126Sahl return (strcmp(mounta, mountb));
10423126Sahl
10433126Sahl if (gota)
10443126Sahl return (-1);
10453126Sahl if (gotb)
10463126Sahl return (1);
10473126Sahl
10483126Sahl return (strcmp(zfs_get_name(a), zfs_get_name(b)));
10492474Seschrock }
10502474Seschrock
10513126Sahl /*
10523126Sahl * Mount and share all datasets within the given pool. This assumes that no
10533126Sahl * datasets within the pool are currently mounted. Because users can create
10543126Sahl * complicated nested hierarchies of mountpoints, we first gather all the
10553126Sahl * datasets and mountpoints within the pool, and sort them by mountpoint. Once
10563126Sahl * we have the list of all filesystems, we iterate over them in order and mount
10573126Sahl * and/or share each one.
10583126Sahl */
10593126Sahl #pragma weak zpool_mount_datasets = zpool_enable_datasets
10602474Seschrock int
zpool_enable_datasets(zpool_handle_t * zhp,const char * mntopts,int flags)10613126Sahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
10622474Seschrock {
106313025SEric.Taylor@oracle.com get_all_cb_t cb = { 0 };
10642474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl;
10652474Seschrock zfs_handle_t *zfsp;
10662474Seschrock int i, ret = -1;
10674180Sdougm int *good;
10682474Seschrock
10692474Seschrock /*
10706027Srm160521 * Gather all non-snap datasets within the pool.
10712474Seschrock */
10725094Slling if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL)
10732474Seschrock goto out;
10742474Seschrock
107513025SEric.Taylor@oracle.com libzfs_add_handle(&cb, zfsp);
10766027Srm160521 if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0)
10772474Seschrock goto out;
10782474Seschrock /*
10792474Seschrock * Sort the datasets by mountpoint.
10802474Seschrock */
108113025SEric.Taylor@oracle.com qsort(cb.cb_handles, cb.cb_used, sizeof (void *),
108213025SEric.Taylor@oracle.com libzfs_dataset_cmp);
10832474Seschrock
10842474Seschrock /*
10854180Sdougm * And mount all the datasets, keeping track of which ones
10868536SDavid.Pacheco@Sun.COM * succeeded or failed.
10872474Seschrock */
10888536SDavid.Pacheco@Sun.COM if ((good = zfs_alloc(zhp->zpool_hdl,
10898536SDavid.Pacheco@Sun.COM cb.cb_used * sizeof (int))) == NULL)
10908536SDavid.Pacheco@Sun.COM goto out;
10918536SDavid.Pacheco@Sun.COM
10922474Seschrock ret = 0;
10932474Seschrock for (i = 0; i < cb.cb_used; i++) {
109413025SEric.Taylor@oracle.com if (zfs_mount(cb.cb_handles[i], mntopts, flags) != 0)
10954180Sdougm ret = -1;
10964302Sdougm else
10974180Sdougm good[i] = 1;
10984180Sdougm }
10995951Sdougm
11004180Sdougm /*
11014180Sdougm * Then share all the ones that need to be shared. This needs
11024180Sdougm * to be a separate pass in order to avoid excessive reloading
11034180Sdougm * of the configuration. Good should never be NULL since
11044180Sdougm * zfs_alloc is supposed to exit if memory isn't available.
11054180Sdougm */
11064180Sdougm for (i = 0; i < cb.cb_used; i++) {
110713025SEric.Taylor@oracle.com if (good[i] && zfs_share(cb.cb_handles[i]) != 0)
11082474Seschrock ret = -1;
11092474Seschrock }
11102474Seschrock
11114180Sdougm free(good);
11124180Sdougm
11132474Seschrock out:
11142474Seschrock for (i = 0; i < cb.cb_used; i++)
111513025SEric.Taylor@oracle.com zfs_close(cb.cb_handles[i]);
111613025SEric.Taylor@oracle.com free(cb.cb_handles);
11172474Seschrock
11182474Seschrock return (ret);
11192474Seschrock }
11202474Seschrock
11212474Seschrock static int
mountpoint_compare(const void * a,const void * b)11222474Seschrock mountpoint_compare(const void *a, const void *b)
11232474Seschrock {
11242474Seschrock const char *mounta = *((char **)a);
11252474Seschrock const char *mountb = *((char **)b);
11262474Seschrock
11272474Seschrock return (strcmp(mountb, mounta));
11282474Seschrock }
11292474Seschrock
113010588SEric.Taylor@Sun.COM /* alias for 2002/240 */
113110588SEric.Taylor@Sun.COM #pragma weak zpool_unmount_datasets = zpool_disable_datasets
11323126Sahl /*
11333126Sahl * Unshare and unmount all datasets within the given pool. We don't want to
11343126Sahl * rely on traversing the DSL to discover the filesystems within the pool,
11353126Sahl * because this may be expensive (if not all of them are mounted), and can fail
11363126Sahl * arbitrarily (on I/O error, for example). Instead, we walk /etc/mnttab and
11373126Sahl * gather all the filesystems that are currently mounted.
11383126Sahl */
11392474Seschrock int
zpool_disable_datasets(zpool_handle_t * zhp,boolean_t force)11403126Sahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
11412474Seschrock {
11422474Seschrock int used, alloc;
11432474Seschrock struct mnttab entry;
11442474Seschrock size_t namelen;
11452474Seschrock char **mountpoints = NULL;
11462474Seschrock zfs_handle_t **datasets = NULL;
11472474Seschrock libzfs_handle_t *hdl = zhp->zpool_hdl;
11482474Seschrock int i;
11492474Seschrock int ret = -1;
11502474Seschrock int flags = (force ? MS_FORCE : 0);
11512474Seschrock
11522474Seschrock namelen = strlen(zhp->zpool_name);
11532474Seschrock
11542474Seschrock rewind(hdl->libzfs_mnttab);
11552474Seschrock used = alloc = 0;
11562474Seschrock while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
11572474Seschrock /*
11582474Seschrock * Ignore non-ZFS entries.
11592474Seschrock */
11602474Seschrock if (entry.mnt_fstype == NULL ||
11612474Seschrock strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
11622474Seschrock continue;
11632474Seschrock
11642474Seschrock /*
11652474Seschrock * Ignore filesystems not within this pool.
11662474Seschrock */
11672474Seschrock if (entry.mnt_mountp == NULL ||
11682474Seschrock strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 ||
11692474Seschrock (entry.mnt_special[namelen] != '/' &&
11702474Seschrock entry.mnt_special[namelen] != '\0'))
11712474Seschrock continue;
11722474Seschrock
11732474Seschrock /*
11742474Seschrock * At this point we've found a filesystem within our pool. Add
11752474Seschrock * it to our growing list.
11762474Seschrock */
11772474Seschrock if (used == alloc) {
11782474Seschrock if (alloc == 0) {
11792474Seschrock if ((mountpoints = zfs_alloc(hdl,
11802474Seschrock 8 * sizeof (void *))) == NULL)
11812474Seschrock goto out;
11822474Seschrock
11832474Seschrock if ((datasets = zfs_alloc(hdl,
11842474Seschrock 8 * sizeof (void *))) == NULL)
11852474Seschrock goto out;
11862474Seschrock
11872474Seschrock alloc = 8;
11882474Seschrock } else {
11892676Seschrock void *ptr;
11902474Seschrock
11912676Seschrock if ((ptr = zfs_realloc(hdl, mountpoints,
11922676Seschrock alloc * sizeof (void *),
11932474Seschrock alloc * 2 * sizeof (void *))) == NULL)
11942474Seschrock goto out;
11952676Seschrock mountpoints = ptr;
11962474Seschrock
11972676Seschrock if ((ptr = zfs_realloc(hdl, datasets,
11982676Seschrock alloc * sizeof (void *),
11992474Seschrock alloc * 2 * sizeof (void *))) == NULL)
12002474Seschrock goto out;
12012676Seschrock datasets = ptr;
12022474Seschrock
12032474Seschrock alloc *= 2;
12042474Seschrock }
12052474Seschrock }
12062474Seschrock
12072474Seschrock if ((mountpoints[used] = zfs_strdup(hdl,
12082474Seschrock entry.mnt_mountp)) == NULL)
12092474Seschrock goto out;
12102474Seschrock
12112474Seschrock /*
12122474Seschrock * This is allowed to fail, in case there is some I/O error. It
12132474Seschrock * is only used to determine if we need to remove the underlying
12142474Seschrock * mountpoint, so failure is not fatal.
12152474Seschrock */
12162474Seschrock datasets[used] = make_dataset_handle(hdl, entry.mnt_special);
12172474Seschrock
12182474Seschrock used++;
12192474Seschrock }
12202474Seschrock
12212474Seschrock /*
12222474Seschrock * At this point, we have the entire list of filesystems, so sort it by
12232474Seschrock * mountpoint.
12242474Seschrock */
12252474Seschrock qsort(mountpoints, used, sizeof (char *), mountpoint_compare);
12262474Seschrock
12272474Seschrock /*
12282474Seschrock * Walk through and first unshare everything.
12292474Seschrock */
12302474Seschrock for (i = 0; i < used; i++) {
12315331Samw zfs_share_proto_t *curr_proto;
12325331Samw for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
12335331Samw curr_proto++) {
12345331Samw if (is_shared(hdl, mountpoints[i], *curr_proto) &&
12355331Samw unshare_one(hdl, mountpoints[i],
12365331Samw mountpoints[i], *curr_proto) != 0)
12375331Samw goto out;
12385331Samw }
12392474Seschrock }
12402474Seschrock
12412474Seschrock /*
12422474Seschrock * Now unmount everything, removing the underlying directories as
12432474Seschrock * appropriate.
12442474Seschrock */
12452474Seschrock for (i = 0; i < used; i++) {
12462474Seschrock if (unmount_one(hdl, mountpoints[i], flags) != 0)
12472474Seschrock goto out;
12482676Seschrock }
12492474Seschrock
12502676Seschrock for (i = 0; i < used; i++) {
12512474Seschrock if (datasets[i])
12522474Seschrock remove_mountpoint(datasets[i]);
12532474Seschrock }
12542474Seschrock
12552474Seschrock ret = 0;
12562474Seschrock out:
12572474Seschrock for (i = 0; i < used; i++) {
12582474Seschrock if (datasets[i])
12592474Seschrock zfs_close(datasets[i]);
12602474Seschrock free(mountpoints[i]);
12612474Seschrock }
12622474Seschrock free(datasets);
12632474Seschrock free(mountpoints);
12642474Seschrock
12652474Seschrock return (ret);
12662474Seschrock }
1267