xref: /illumos-gate/usr/src/lib/libzfs/common/libzfs_mount.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21f3861e1aSahl 
22fa9e4066Sahrens /*
2311d2789dSgw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28fa9e4066Sahrens 
29fa9e4066Sahrens /*
30fa9e4066Sahrens  * Routines to manage ZFS mounts.  We separate all the nasty routines that have
31f3861e1aSahl  * to deal with the OS.  The following functions are the main entry points --
32f3861e1aSahl  * they are used by mount and unmount and when changing a filesystem's
33f3861e1aSahl  * mountpoint.
34fa9e4066Sahrens  *
35fa9e4066Sahrens  * 	zfs_is_mounted()
36fa9e4066Sahrens  * 	zfs_mount()
37fa9e4066Sahrens  * 	zfs_unmount()
38fa9e4066Sahrens  * 	zfs_unmountall()
39fa9e4066Sahrens  *
40f3861e1aSahl  * This file also contains the functions used to manage sharing filesystems via
41f3861e1aSahl  * NFS and iSCSI:
42fa9e4066Sahrens  *
43fa9e4066Sahrens  * 	zfs_is_shared()
44fa9e4066Sahrens  * 	zfs_share()
45fa9e4066Sahrens  * 	zfs_unshare()
46f3861e1aSahl  *
47f3861e1aSahl  * 	zfs_is_shared_nfs()
48*da6c28aaSamw  * 	zfs_is_shared_smb()
49f3861e1aSahl  * 	zfs_is_shared_iscsi()
50*da6c28aaSamw  * 	zfs_share_proto()
51*da6c28aaSamw  * 	zfs_shareall();
52f3861e1aSahl  * 	zfs_share_iscsi()
53*da6c28aaSamw  * 	zfs_unshare_nfs()
54*da6c28aaSamw  * 	zfs_unshare_smb()
55*da6c28aaSamw  * 	zfs_unshareall_nfs()
56*da6c28aaSamw  *	zfs_unshareall_smb()
57*da6c28aaSamw  *	zfs_unshareall()
58*da6c28aaSamw  *	zfs_unshareall_bypath()
59f3861e1aSahl  * 	zfs_unshare_iscsi()
603bb79becSeschrock  *
613bb79becSeschrock  * The following functions are available for pool consumers, and will
62f3861e1aSahl  * mount/unmount and share/unshare all datasets within pool:
633bb79becSeschrock  *
64f3861e1aSahl  * 	zpool_enable_datasets()
65f3861e1aSahl  * 	zpool_disable_datasets()
66fa9e4066Sahrens  */
67fa9e4066Sahrens 
68fa9e4066Sahrens #include <dirent.h>
69d8d59944Sahl #include <dlfcn.h>
70fa9e4066Sahrens #include <errno.h>
71fa9e4066Sahrens #include <libgen.h>
72fa9e4066Sahrens #include <libintl.h>
73fa9e4066Sahrens #include <stdio.h>
74fa9e4066Sahrens #include <stdlib.h>
75fa9e4066Sahrens #include <strings.h>
76fa9e4066Sahrens #include <unistd.h>
77fa9e4066Sahrens #include <zone.h>
78fa9e4066Sahrens #include <sys/mntent.h>
79fa9e4066Sahrens #include <sys/mnttab.h>
80fa9e4066Sahrens #include <sys/mount.h>
81fa9e4066Sahrens #include <sys/stat.h>
82fa9e4066Sahrens 
83fa9e4066Sahrens #include <libzfs.h>
84fa9e4066Sahrens 
85fa9e4066Sahrens #include "libzfs_impl.h"
86fa9e4066Sahrens 
8767331909Sdougm #include <libshare.h>
8867331909Sdougm #include <sys/systeminfo.h>
8967331909Sdougm #define	MAXISALEN	257	/* based on sysinfo(2) man page */
9067331909Sdougm 
91*da6c28aaSamw static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
92*da6c28aaSamw zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
93*da6c28aaSamw     zfs_share_proto_t);
94*da6c28aaSamw 
95d8d59944Sahl static int (*iscsitgt_zfs_share)(const char *);
96d8d59944Sahl static int (*iscsitgt_zfs_unshare)(const char *);
97d8d59944Sahl static int (*iscsitgt_zfs_is_shared)(const char *);
98ecd6cf80Smarks static int (*iscsitgt_svc_online)();
99d8d59944Sahl 
100*da6c28aaSamw /*
101*da6c28aaSamw  * The share protocols table must be in the same order as the zfs_share_prot_t
102*da6c28aaSamw  * enum in libzfs_impl.h
103*da6c28aaSamw  */
104*da6c28aaSamw typedef struct {
105*da6c28aaSamw 	zfs_prop_t p_prop;
106*da6c28aaSamw 	char *p_name;
107*da6c28aaSamw 	int p_share_err;
108*da6c28aaSamw 	int p_unshare_err;
109*da6c28aaSamw } proto_table_t;
110*da6c28aaSamw 
111*da6c28aaSamw proto_table_t proto_table[PROTO_END] = {
112*da6c28aaSamw 	{ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
113*da6c28aaSamw 	{ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
114*da6c28aaSamw };
115*da6c28aaSamw 
116*da6c28aaSamw zfs_share_proto_t nfs_only[] = {
117*da6c28aaSamw 	PROTO_NFS,
118*da6c28aaSamw 	PROTO_END
119*da6c28aaSamw };
120*da6c28aaSamw 
121*da6c28aaSamw zfs_share_proto_t smb_only[] = {
122*da6c28aaSamw 	PROTO_SMB,
123*da6c28aaSamw 	PROTO_END
124*da6c28aaSamw };
125*da6c28aaSamw zfs_share_proto_t share_all_proto[] = {
126*da6c28aaSamw 	PROTO_NFS,
127*da6c28aaSamw 	PROTO_SMB,
128*da6c28aaSamw 	PROTO_END
129*da6c28aaSamw };
130*da6c28aaSamw 
131d8d59944Sahl #pragma init(zfs_iscsi_init)
132d8d59944Sahl static void
133d8d59944Sahl zfs_iscsi_init(void)
134d8d59944Sahl {
135d8d59944Sahl 	void *libiscsitgt;
136d8d59944Sahl 
137d8d59944Sahl 	if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1",
138d8d59944Sahl 	    RTLD_LAZY | RTLD_GLOBAL)) == NULL ||
139d8d59944Sahl 	    (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt,
140d8d59944Sahl 	    "iscsitgt_zfs_share")) == NULL ||
141d8d59944Sahl 	    (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt,
142d8d59944Sahl 	    "iscsitgt_zfs_unshare")) == NULL ||
143d8d59944Sahl 	    (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt,
144ecd6cf80Smarks 	    "iscsitgt_zfs_is_shared")) == NULL ||
145ecd6cf80Smarks 	    (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt,
146ecd6cf80Smarks 	    "iscsitgt_svc_online")) == NULL) {
147d8d59944Sahl 		iscsitgt_zfs_share = NULL;
148d8d59944Sahl 		iscsitgt_zfs_unshare = NULL;
149d8d59944Sahl 		iscsitgt_zfs_is_shared = NULL;
150ecd6cf80Smarks 		iscsitgt_svc_online = NULL;
151d8d59944Sahl 	}
152d8d59944Sahl }
153d8d59944Sahl 
154fa9e4066Sahrens /*
155*da6c28aaSamw  * Search the sharetab for the given mountpoint and protocol, returning
156*da6c28aaSamw  * a zfs_share_type_t value.
157fa9e4066Sahrens  */
158*da6c28aaSamw static zfs_share_type_t
159*da6c28aaSamw is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
160fa9e4066Sahrens {
161fa9e4066Sahrens 	char buf[MAXPATHLEN], *tab;
162*da6c28aaSamw 	char *ptr;
163fa9e4066Sahrens 
16499653d4eSeschrock 	if (hdl->libzfs_sharetab == NULL)
165*da6c28aaSamw 		return (SHARED_NOT_SHARED);
166fa9e4066Sahrens 
16799653d4eSeschrock 	(void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
168fa9e4066Sahrens 
16999653d4eSeschrock 	while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
170fa9e4066Sahrens 
171fa9e4066Sahrens 		/* the mountpoint is the first entry on each line */
172*da6c28aaSamw 		if ((tab = strchr(buf, '\t')) == NULL)
173*da6c28aaSamw 			continue;
174*da6c28aaSamw 
175*da6c28aaSamw 		*tab = '\0';
176*da6c28aaSamw 		if (strcmp(buf, mountpoint) == 0) {
177*da6c28aaSamw 			/*
178*da6c28aaSamw 			 * the protocol field is the third field
179*da6c28aaSamw 			 * skip over second field
180*da6c28aaSamw 			 */
181*da6c28aaSamw 			ptr = ++tab;
182*da6c28aaSamw 			if ((tab = strchr(ptr, '\t')) == NULL)
183*da6c28aaSamw 				continue;
184*da6c28aaSamw 			ptr = ++tab;
185*da6c28aaSamw 			if ((tab = strchr(ptr, '\t')) == NULL)
186*da6c28aaSamw 				continue;
187fa9e4066Sahrens 			*tab = '\0';
188*da6c28aaSamw 			if (strcmp(ptr,
189*da6c28aaSamw 			    proto_table[proto].p_name) == 0) {
190*da6c28aaSamw 				switch (proto) {
191*da6c28aaSamw 				case PROTO_NFS:
192*da6c28aaSamw 					return (SHARED_NFS);
193*da6c28aaSamw 				case PROTO_SMB:
194*da6c28aaSamw 					return (SHARED_SMB);
195*da6c28aaSamw 				default:
196*da6c28aaSamw 					return (0);
197*da6c28aaSamw 				}
198*da6c28aaSamw 			}
199fa9e4066Sahrens 		}
200fa9e4066Sahrens 	}
201fa9e4066Sahrens 
202*da6c28aaSamw 	return (SHARED_NOT_SHARED);
203fa9e4066Sahrens }
204fa9e4066Sahrens 
205fa9e4066Sahrens /*
20699653d4eSeschrock  * Returns true if the specified directory is empty.  If we can't open the
20799653d4eSeschrock  * directory at all, return true so that the mount can fail with a more
208fa9e4066Sahrens  * informative error message.
209fa9e4066Sahrens  */
21099653d4eSeschrock static boolean_t
211fa9e4066Sahrens dir_is_empty(const char *dirname)
212fa9e4066Sahrens {
213fa9e4066Sahrens 	DIR *dirp;
214fa9e4066Sahrens 	struct dirent64 *dp;
215fa9e4066Sahrens 
216fa9e4066Sahrens 	if ((dirp = opendir(dirname)) == NULL)
21799653d4eSeschrock 		return (B_TRUE);
218fa9e4066Sahrens 
219fa9e4066Sahrens 	while ((dp = readdir64(dirp)) != NULL) {
220fa9e4066Sahrens 
221fa9e4066Sahrens 		if (strcmp(dp->d_name, ".") == 0 ||
222fa9e4066Sahrens 		    strcmp(dp->d_name, "..") == 0)
223fa9e4066Sahrens 			continue;
224fa9e4066Sahrens 
225fa9e4066Sahrens 		(void) closedir(dirp);
22699653d4eSeschrock 		return (B_FALSE);
227fa9e4066Sahrens 	}
228fa9e4066Sahrens 
229fa9e4066Sahrens 	(void) closedir(dirp);
23099653d4eSeschrock 	return (B_TRUE);
231fa9e4066Sahrens }
232fa9e4066Sahrens 
233fa9e4066Sahrens /*
234fa9e4066Sahrens  * Checks to see if the mount is active.  If the filesystem is mounted, we fill
235fa9e4066Sahrens  * in 'where' with the current mountpoint, and return 1.  Otherwise, we return
236fa9e4066Sahrens  * 0.
237fa9e4066Sahrens  */
23899653d4eSeschrock boolean_t
23955434c77Sek is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where)
240fa9e4066Sahrens {
241fa9e4066Sahrens 	struct mnttab search = { 0 }, entry;
242fa9e4066Sahrens 
243fa9e4066Sahrens 	/*
244fa9e4066Sahrens 	 * Search for the entry in /etc/mnttab.  We don't bother getting the
245fa9e4066Sahrens 	 * mountpoint, as we can just search for the special device.  This will
246fa9e4066Sahrens 	 * also let us find mounts when the mountpoint is 'legacy'.
247fa9e4066Sahrens 	 */
24855434c77Sek 	search.mnt_special = (char *)special;
24996dedd18Snd 	search.mnt_fstype = MNTTYPE_ZFS;
250fa9e4066Sahrens 
25155434c77Sek 	rewind(zfs_hdl->libzfs_mnttab);
25255434c77Sek 	if (getmntany(zfs_hdl->libzfs_mnttab, &entry, &search) != 0)
25399653d4eSeschrock 		return (B_FALSE);
254fa9e4066Sahrens 
255fa9e4066Sahrens 	if (where != NULL)
25655434c77Sek 		*where = zfs_strdup(zfs_hdl, entry.mnt_mountp);
257fa9e4066Sahrens 
25899653d4eSeschrock 	return (B_TRUE);
259fa9e4066Sahrens }
260fa9e4066Sahrens 
26155434c77Sek boolean_t
26255434c77Sek zfs_is_mounted(zfs_handle_t *zhp, char **where)
26355434c77Sek {
26455434c77Sek 	return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where));
26555434c77Sek }
26655434c77Sek 
267e9dbad6fSeschrock /*
268e9dbad6fSeschrock  * Returns true if the given dataset is mountable, false otherwise.  Returns the
269e9dbad6fSeschrock  * mountpoint in 'buf'.
270e9dbad6fSeschrock  */
271e9dbad6fSeschrock static boolean_t
272e9dbad6fSeschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
273990b4856Slling     zprop_source_t *source)
274e9dbad6fSeschrock {
275e9dbad6fSeschrock 	char sourceloc[ZFS_MAXNAMELEN];
276990b4856Slling 	zprop_source_t sourcetype;
277e9dbad6fSeschrock 
278e9dbad6fSeschrock 	if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type))
279e9dbad6fSeschrock 		return (B_FALSE);
280e9dbad6fSeschrock 
281e9dbad6fSeschrock 	verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen,
282e9dbad6fSeschrock 	    &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0);
283e9dbad6fSeschrock 
284e9dbad6fSeschrock 	if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 ||
285e9dbad6fSeschrock 	    strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0)
286e9dbad6fSeschrock 		return (B_FALSE);
287e9dbad6fSeschrock 
288e9dbad6fSeschrock 	if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT))
289e9dbad6fSeschrock 		return (B_FALSE);
290e9dbad6fSeschrock 
291e9dbad6fSeschrock 	if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
292e9dbad6fSeschrock 	    getzoneid() == GLOBAL_ZONEID)
293e9dbad6fSeschrock 		return (B_FALSE);
294e9dbad6fSeschrock 
295e9dbad6fSeschrock 	if (source)
296e9dbad6fSeschrock 		*source = sourcetype;
297e9dbad6fSeschrock 
298e9dbad6fSeschrock 	return (B_TRUE);
299e9dbad6fSeschrock }
300e9dbad6fSeschrock 
301fa9e4066Sahrens /*
302fa9e4066Sahrens  * Mount the given filesystem.
303fa9e4066Sahrens  */
304fa9e4066Sahrens int
305fa9e4066Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
306fa9e4066Sahrens {
307fa9e4066Sahrens 	struct stat buf;
308fa9e4066Sahrens 	char mountpoint[ZFS_MAXPROPLEN];
309fa9e4066Sahrens 	char mntopts[MNT_LINE_MAX];
31099653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
311fa9e4066Sahrens 
312fa9e4066Sahrens 	if (options == NULL)
313fa9e4066Sahrens 		mntopts[0] = '\0';
314fa9e4066Sahrens 	else
315fa9e4066Sahrens 		(void) strlcpy(mntopts, options, sizeof (mntopts));
316fa9e4066Sahrens 
317e9dbad6fSeschrock 	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
31899653d4eSeschrock 		return (0);
319fa9e4066Sahrens 
320fa9e4066Sahrens 	/* Create the directory if it doesn't already exist */
321fa9e4066Sahrens 	if (lstat(mountpoint, &buf) != 0) {
322fa9e4066Sahrens 		if (mkdirp(mountpoint, 0755) != 0) {
32399653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
32499653d4eSeschrock 			    "failed to create mountpoint"));
325ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
32699653d4eSeschrock 			    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
32799653d4eSeschrock 			    mountpoint));
328fa9e4066Sahrens 		}
329fa9e4066Sahrens 	}
330fa9e4066Sahrens 
331fa9e4066Sahrens 	/*
332fa9e4066Sahrens 	 * Determine if the mountpoint is empty.  If so, refuse to perform the
333fa9e4066Sahrens 	 * mount.  We don't perform this check if MS_OVERLAY is specified, which
334fa9e4066Sahrens 	 * would defeat the point.  We also avoid this check if 'remount' is
335fa9e4066Sahrens 	 * specified.
336fa9e4066Sahrens 	 */
337fa9e4066Sahrens 	if ((flags & MS_OVERLAY) == 0 &&
338fa9e4066Sahrens 	    strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
339fa9e4066Sahrens 	    !dir_is_empty(mountpoint)) {
34099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
34199653d4eSeschrock 		    "directory is not empty"));
342ece3d9b3Slling 		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
34399653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
344fa9e4066Sahrens 	}
345fa9e4066Sahrens 
346fa9e4066Sahrens 	/* perform the mount */
347fa9e4066Sahrens 	if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
348fa9e4066Sahrens 	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
349fa9e4066Sahrens 		/*
350fa9e4066Sahrens 		 * Generic errors are nasty, but there are just way too many
351fa9e4066Sahrens 		 * from mount(), and they're well-understood.  We pick a few
352fa9e4066Sahrens 		 * common ones to improve upon.
353fa9e4066Sahrens 		 */
354d8689a57Sdougm 		if (errno == EBUSY) {
35599653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
35699653d4eSeschrock 			    "mountpoint or dataset is busy"));
357ecd6cf80Smarks 		} else if (errno == EPERM) {
358ecd6cf80Smarks 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
359ecd6cf80Smarks 			    "Insufficient privileges"));
360d8689a57Sdougm 		} else {
36199653d4eSeschrock 			zfs_error_aux(hdl, strerror(errno));
362d8689a57Sdougm 		}
36399653d4eSeschrock 
364ece3d9b3Slling 		return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
36599653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
36699653d4eSeschrock 		    zhp->zfs_name));
367fa9e4066Sahrens 	}
368fa9e4066Sahrens 
369fa9e4066Sahrens 	return (0);
370fa9e4066Sahrens }
371fa9e4066Sahrens 
3723bb79becSeschrock /*
3733bb79becSeschrock  * Unmount a single filesystem.
3743bb79becSeschrock  */
3753bb79becSeschrock static int
3763bb79becSeschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
3773bb79becSeschrock {
3783bb79becSeschrock 	if (umount2(mountpoint, flags) != 0) {
3793bb79becSeschrock 		zfs_error_aux(hdl, strerror(errno));
380ece3d9b3Slling 		return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
3813bb79becSeschrock 		    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
3823bb79becSeschrock 		    mountpoint));
3833bb79becSeschrock 	}
3843bb79becSeschrock 
3853bb79becSeschrock 	return (0);
3863bb79becSeschrock }
3873bb79becSeschrock 
388fa9e4066Sahrens /*
389fa9e4066Sahrens  * Unmount the given filesystem.
390fa9e4066Sahrens  */
391fa9e4066Sahrens int
392fa9e4066Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
393fa9e4066Sahrens {
394fa9e4066Sahrens 	struct mnttab search = { 0 }, entry;
39567331909Sdougm 	char *mntpt = NULL;
396fa9e4066Sahrens 
397fa9e4066Sahrens 	/* check to see if need to unmount the filesystem */
3983bb79becSeschrock 	search.mnt_special = zhp->zfs_name;
39996dedd18Snd 	search.mnt_fstype = MNTTYPE_ZFS;
40099653d4eSeschrock 	rewind(zhp->zfs_hdl->libzfs_mnttab);
401fa9e4066Sahrens 	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
40299653d4eSeschrock 	    getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
403fa9e4066Sahrens 
40467331909Sdougm 		/*
40567331909Sdougm 		 * mountpoint may have come from a call to
40667331909Sdougm 		 * getmnt/getmntany if it isn't NULL. If it is NULL,
40767331909Sdougm 		 * we know it comes from getmntany which can then get
40867331909Sdougm 		 * overwritten later. We strdup it to play it safe.
40967331909Sdougm 		 */
410fa9e4066Sahrens 		if (mountpoint == NULL)
411d8689a57Sdougm 			mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
41267331909Sdougm 		else
413d8689a57Sdougm 			mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);
414fa9e4066Sahrens 
415fa9e4066Sahrens 		/*
4163bb79becSeschrock 		 * Unshare and unmount the filesystem
417fa9e4066Sahrens 		 */
418*da6c28aaSamw 		if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
419eb66cf86Sth 			return (-1);
420eb66cf86Sth 
421eb66cf86Sth 		if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) {
42267331909Sdougm 			free(mntpt);
423*da6c28aaSamw 			(void) zfs_shareall(zhp);
424fa9e4066Sahrens 			return (-1);
42567331909Sdougm 		}
42667331909Sdougm 		free(mntpt);
427fa9e4066Sahrens 	}
428fa9e4066Sahrens 
429fa9e4066Sahrens 	return (0);
430fa9e4066Sahrens }
431fa9e4066Sahrens 
432fa9e4066Sahrens /*
433fa9e4066Sahrens  * Unmount this filesystem and any children inheriting the mountpoint property.
434fa9e4066Sahrens  * To do this, just act like we're changing the mountpoint property, but don't
435fa9e4066Sahrens  * remount the filesystems afterwards.
436fa9e4066Sahrens  */
437fa9e4066Sahrens int
438fa9e4066Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags)
439fa9e4066Sahrens {
440fa9e4066Sahrens 	prop_changelist_t *clp;
441fa9e4066Sahrens 	int ret;
442fa9e4066Sahrens 
443fa9e4066Sahrens 	clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags);
444fa9e4066Sahrens 	if (clp == NULL)
445fa9e4066Sahrens 		return (-1);
446fa9e4066Sahrens 
447fa9e4066Sahrens 	ret = changelist_prefix(clp);
448fa9e4066Sahrens 	changelist_free(clp);
449fa9e4066Sahrens 
450fa9e4066Sahrens 	return (ret);
451fa9e4066Sahrens }
452fa9e4066Sahrens 
453f3861e1aSahl boolean_t
454f3861e1aSahl zfs_is_shared(zfs_handle_t *zhp)
455f3861e1aSahl {
456*da6c28aaSamw 	zfs_share_type_t rc = 0;
457*da6c28aaSamw 	zfs_share_proto_t *curr_proto;
458*da6c28aaSamw 
459f3861e1aSahl 	if (ZFS_IS_VOLUME(zhp))
460f3861e1aSahl 		return (zfs_is_shared_iscsi(zhp));
461f3861e1aSahl 
462*da6c28aaSamw 	for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
463*da6c28aaSamw 	    curr_proto++)
464*da6c28aaSamw 		rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto);
465*da6c28aaSamw 
466*da6c28aaSamw 	return (rc ? B_TRUE : B_FALSE);
467f3861e1aSahl }
468f3861e1aSahl 
469f3861e1aSahl int
470f3861e1aSahl zfs_share(zfs_handle_t *zhp)
471f3861e1aSahl {
472f3861e1aSahl 	if (ZFS_IS_VOLUME(zhp))
473f3861e1aSahl 		return (zfs_share_iscsi(zhp));
474f3861e1aSahl 
475*da6c28aaSamw 	return (zfs_share_proto(zhp, share_all_proto));
476f3861e1aSahl }
477f3861e1aSahl 
478f3861e1aSahl int
479f3861e1aSahl zfs_unshare(zfs_handle_t *zhp)
480f3861e1aSahl {
481f3861e1aSahl 	if (ZFS_IS_VOLUME(zhp))
482f3861e1aSahl 		return (zfs_unshare_iscsi(zhp));
483f3861e1aSahl 
484*da6c28aaSamw 	return (zfs_unshareall(zhp));
485f3861e1aSahl }
486f3861e1aSahl 
487fa9e4066Sahrens /*
488fa9e4066Sahrens  * Check to see if the filesystem is currently shared.
489fa9e4066Sahrens  */
490*da6c28aaSamw zfs_share_type_t
491*da6c28aaSamw zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
492fa9e4066Sahrens {
493fa9e4066Sahrens 	char *mountpoint;
494*da6c28aaSamw 	zfs_share_type_t rc;
495fa9e4066Sahrens 
496fa9e4066Sahrens 	if (!zfs_is_mounted(zhp, &mountpoint))
497*da6c28aaSamw 		return (SHARED_NOT_SHARED);
498fa9e4066Sahrens 
499*da6c28aaSamw 	if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) {
500fa9e4066Sahrens 		if (where != NULL)
501fa9e4066Sahrens 			*where = mountpoint;
502fa9e4066Sahrens 		else
503fa9e4066Sahrens 			free(mountpoint);
504*da6c28aaSamw 		return (rc);
505fa9e4066Sahrens 	} else {
506fa9e4066Sahrens 		free(mountpoint);
507*da6c28aaSamw 		return (SHARED_NOT_SHARED);
508fa9e4066Sahrens 	}
509fa9e4066Sahrens }
510fa9e4066Sahrens 
511*da6c28aaSamw boolean_t
512*da6c28aaSamw zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
513*da6c28aaSamw {
514*da6c28aaSamw 	return (zfs_is_shared_proto(zhp, where,
515*da6c28aaSamw 	    PROTO_NFS) != SHARED_NOT_SHARED);
516*da6c28aaSamw }
517*da6c28aaSamw 
518*da6c28aaSamw boolean_t
519*da6c28aaSamw zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
520*da6c28aaSamw {
521*da6c28aaSamw 	return (zfs_is_shared_proto(zhp, where,
522*da6c28aaSamw 	    PROTO_SMB) != SHARED_NOT_SHARED);
523*da6c28aaSamw }
524*da6c28aaSamw 
52567331909Sdougm /*
52667331909Sdougm  * Make sure things will work if libshare isn't installed by using
52767331909Sdougm  * wrapper functions that check to see that the pointers to functions
52867331909Sdougm  * initialized in _zfs_init_libshare() are actually present.
52967331909Sdougm  */
53067331909Sdougm 
53167331909Sdougm static sa_handle_t (*_sa_init)(int);
53267331909Sdougm static void (*_sa_fini)(sa_handle_t);
53367331909Sdougm static sa_share_t (*_sa_find_share)(sa_handle_t, char *);
53467331909Sdougm static int (*_sa_enable_share)(sa_share_t, char *);
53567331909Sdougm static int (*_sa_disable_share)(sa_share_t, char *);
53667331909Sdougm static char *(*_sa_errorstr)(int);
53767331909Sdougm static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *);
53867331909Sdougm 
53967331909Sdougm /*
54067331909Sdougm  * _zfs_init_libshare()
54167331909Sdougm  *
54267331909Sdougm  * Find the libshare.so.1 entry points that we use here and save the
54367331909Sdougm  * values to be used later. This is triggered by the runtime loader.
54467331909Sdougm  * Make sure the correct ISA version is loaded.
54567331909Sdougm  */
54667331909Sdougm 
54767331909Sdougm #pragma init(_zfs_init_libshare)
54867331909Sdougm static void
54967331909Sdougm _zfs_init_libshare(void)
55067331909Sdougm {
55167331909Sdougm 	void *libshare;
55267331909Sdougm 	char path[MAXPATHLEN];
55367331909Sdougm 	char isa[MAXISALEN];
55467331909Sdougm 
55567331909Sdougm #if defined(_LP64)
55667331909Sdougm 	if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
557d8689a57Sdougm 		isa[0] = '\0';
55867331909Sdougm #else
55967331909Sdougm 	isa[0] = '\0';
56067331909Sdougm #endif
56167331909Sdougm 	(void) snprintf(path, MAXPATHLEN,
562d8689a57Sdougm 	    "/usr/lib/%s/libshare.so.1", isa);
56367331909Sdougm 
56467331909Sdougm 	if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) {
565d8689a57Sdougm 		_sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init");
566d8689a57Sdougm 		_sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini");
567d8689a57Sdougm 		_sa_find_share = (sa_share_t (*)(sa_handle_t, char *))
568d8689a57Sdougm 		    dlsym(libshare, "sa_find_share");
569d8689a57Sdougm 		_sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
570d8689a57Sdougm 		    "sa_enable_share");
571d8689a57Sdougm 		_sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
572d8689a57Sdougm 		    "sa_disable_share");
573d8689a57Sdougm 		_sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr");
574d8689a57Sdougm 		_sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *))
575d8689a57Sdougm 		    dlsym(libshare, "sa_parse_legacy_options");
57657b448deSdougm 		if (_sa_init == NULL || _sa_fini == NULL ||
57757b448deSdougm 		    _sa_find_share == NULL || _sa_enable_share == NULL ||
57857b448deSdougm 		    _sa_disable_share == NULL || _sa_errorstr == NULL ||
57957b448deSdougm 		    _sa_parse_legacy_options == NULL) {
58057b448deSdougm 			_sa_init = NULL;
58157b448deSdougm 			_sa_fini = NULL;
58257b448deSdougm 			_sa_disable_share = NULL;
58357b448deSdougm 			_sa_enable_share = NULL;
58457b448deSdougm 			_sa_errorstr = NULL;
58557b448deSdougm 			_sa_parse_legacy_options = NULL;
58657b448deSdougm 			(void) dlclose(libshare);
58757b448deSdougm 		}
58867331909Sdougm 	}
58967331909Sdougm }
59067331909Sdougm 
59167331909Sdougm /*
59267331909Sdougm  * zfs_init_libshare(zhandle, service)
59367331909Sdougm  *
59467331909Sdougm  * Initialize the libshare API if it hasn't already been initialized.
59567331909Sdougm  * In all cases it returns 0 if it succeeded and an error if not. The
59667331909Sdougm  * service value is which part(s) of the API to initialize and is a
59767331909Sdougm  * direct map to the libshare sa_init(service) interface.
59867331909Sdougm  */
59967331909Sdougm 
60067331909Sdougm int
60167331909Sdougm zfs_init_libshare(libzfs_handle_t *zhandle, int service)
60267331909Sdougm {
60367331909Sdougm 	int ret = SA_OK;
60467331909Sdougm 
605d8689a57Sdougm 	if (_sa_init == NULL)
606d8689a57Sdougm 		ret = SA_CONFIG_ERR;
607d8689a57Sdougm 
608d8689a57Sdougm 	if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL)
609d8689a57Sdougm 		zhandle->libzfs_sharehdl = _sa_init(service);
610d8689a57Sdougm 
611d8689a57Sdougm 	if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL)
612d8689a57Sdougm 		ret = SA_NO_MEMORY;
613d8689a57Sdougm 
61467331909Sdougm 	return (ret);
61567331909Sdougm }
61667331909Sdougm 
61767331909Sdougm /*
61867331909Sdougm  * zfs_uninit_libshare(zhandle)
61967331909Sdougm  *
62067331909Sdougm  * Uninitialize the libshare API if it hasn't already been
62167331909Sdougm  * uninitialized. It is OK to call multiple times.
62267331909Sdougm  */
62367331909Sdougm 
62467331909Sdougm void
62567331909Sdougm zfs_uninit_libshare(libzfs_handle_t *zhandle)
62667331909Sdougm {
62767331909Sdougm 
62867331909Sdougm 	if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
629d8689a57Sdougm 		if (_sa_fini != NULL)
630d8689a57Sdougm 			_sa_fini(zhandle->libzfs_sharehdl);
631d8689a57Sdougm 		zhandle->libzfs_sharehdl = NULL;
63267331909Sdougm 	}
63367331909Sdougm }
63467331909Sdougm 
63567331909Sdougm /*
63667331909Sdougm  * zfs_parse_options(options, proto)
63767331909Sdougm  *
63867331909Sdougm  * Call the legacy parse interface to get the protocol specific
63967331909Sdougm  * options using the NULL arg to indicate that this is a "parse" only.
64067331909Sdougm  */
64167331909Sdougm 
64267331909Sdougm int
643*da6c28aaSamw zfs_parse_options(char *options, zfs_share_proto_t proto)
64467331909Sdougm {
64567331909Sdougm 	int ret;
64667331909Sdougm 
64767331909Sdougm 	if (_sa_parse_legacy_options != NULL)
648*da6c28aaSamw 		ret = _sa_parse_legacy_options(NULL, options,
649*da6c28aaSamw 		    proto_table[proto].p_name);
65067331909Sdougm 	else
651d8689a57Sdougm 		ret = SA_CONFIG_ERR;
65267331909Sdougm 	return (ret);
65367331909Sdougm }
65467331909Sdougm 
65567331909Sdougm /*
65667331909Sdougm  * zfs_sa_find_share(handle, path)
65767331909Sdougm  *
65867331909Sdougm  * wrapper around sa_find_share to find a share path in the
65967331909Sdougm  * configuration.
66067331909Sdougm  */
66167331909Sdougm 
66267331909Sdougm static sa_share_t
66367331909Sdougm zfs_sa_find_share(sa_handle_t handle, char *path)
66467331909Sdougm {
66567331909Sdougm 	if (_sa_find_share != NULL)
666d8689a57Sdougm 		return (_sa_find_share(handle, path));
66767331909Sdougm 	return (NULL);
66867331909Sdougm }
66967331909Sdougm 
67067331909Sdougm /*
67167331909Sdougm  * zfs_sa_enable_share(share, proto)
67267331909Sdougm  *
67367331909Sdougm  * Wrapper for sa_enable_share which enables a share for a specified
67467331909Sdougm  * protocol.
67567331909Sdougm  */
67667331909Sdougm 
67767331909Sdougm static int
67867331909Sdougm zfs_sa_enable_share(sa_share_t share, char *proto)
67967331909Sdougm {
68067331909Sdougm 	if (_sa_enable_share != NULL)
681d8689a57Sdougm 		return (_sa_enable_share(share, proto));
68267331909Sdougm 	return (SA_CONFIG_ERR);
68367331909Sdougm }
68467331909Sdougm 
68567331909Sdougm /*
68667331909Sdougm  * zfs_sa_disable_share(share, proto)
68767331909Sdougm  *
68867331909Sdougm  * Wrapper for sa_enable_share which disables a share for a specified
68967331909Sdougm  * protocol.
69067331909Sdougm  */
69167331909Sdougm 
69267331909Sdougm static int
69367331909Sdougm zfs_sa_disable_share(sa_share_t share, char *proto)
69467331909Sdougm {
69567331909Sdougm 	if (_sa_disable_share != NULL)
696d8689a57Sdougm 		return (_sa_disable_share(share, proto));
69767331909Sdougm 	return (SA_CONFIG_ERR);
69867331909Sdougm }
69967331909Sdougm 
700fa9e4066Sahrens /*
701*da6c28aaSamw  * Share the given filesystem according to the options in the specified
702*da6c28aaSamw  * protocol specific properties (sharenfs, sharesmb).  We rely
70367331909Sdougm  * on "libshare" to the dirty work for us.
704fa9e4066Sahrens  */
70567331909Sdougm 
706*da6c28aaSamw static int
707*da6c28aaSamw zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
708fa9e4066Sahrens {
709fa9e4066Sahrens 	char mountpoint[ZFS_MAXPROPLEN];
710fa9e4066Sahrens 	char shareopts[ZFS_MAXPROPLEN];
71199653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
71267331909Sdougm 	sa_share_t share;
713*da6c28aaSamw 	zfs_share_proto_t *curr_proto;
71467331909Sdougm 	int ret;
715fa9e4066Sahrens 
716e9dbad6fSeschrock 	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
717fa9e4066Sahrens 		return (0);
718fa9e4066Sahrens 
71967331909Sdougm 	if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
720d8689a57Sdougm 		(void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
721d8689a57Sdougm 		    dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
722d8689a57Sdougm 		    zfs_get_name(zhp), _sa_errorstr(ret));
723d8689a57Sdougm 		return (-1);
72467331909Sdougm 	}
725*da6c28aaSamw 
726*da6c28aaSamw 	for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
727*da6c28aaSamw 		/*
728*da6c28aaSamw 		 * Return success if there are no share options.
729*da6c28aaSamw 		 */
730*da6c28aaSamw 		if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
731*da6c28aaSamw 		    shareopts, sizeof (shareopts), NULL, NULL,
732*da6c28aaSamw 		    0, B_FALSE) != 0 || strcmp(shareopts, "off") == 0)
733*da6c28aaSamw 			continue;
734*da6c28aaSamw 
735*da6c28aaSamw 		/*
736*da6c28aaSamw 		 * If the 'zoned' property is set, then zfs_is_mountable()
737*da6c28aaSamw 		 * will have already bailed out if we are in the global zone.
738*da6c28aaSamw 		 * But local zones cannot be NFS servers, so we ignore it for
739*da6c28aaSamw 		 * local zones as well.
740*da6c28aaSamw 		 */
741*da6c28aaSamw 		if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
742*da6c28aaSamw 			continue;
743*da6c28aaSamw 
744*da6c28aaSamw 		share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
745*da6c28aaSamw 		if (share != NULL) {
746*da6c28aaSamw 			int err;
747*da6c28aaSamw 			err = zfs_sa_enable_share(share,
748*da6c28aaSamw 			    proto_table[*curr_proto].p_name);
749*da6c28aaSamw 			if (err != SA_OK) {
750*da6c28aaSamw 				(void) zfs_error_fmt(hdl,
751*da6c28aaSamw 				    proto_table[*curr_proto].p_share_err,
752*da6c28aaSamw 				    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
753*da6c28aaSamw 				    zfs_get_name(zhp));
754*da6c28aaSamw 				return (-1);
755*da6c28aaSamw 			}
756*da6c28aaSamw 		} else {
757*da6c28aaSamw 			(void) zfs_error_fmt(hdl,
758*da6c28aaSamw 			    proto_table[*curr_proto].p_share_err,
759d8689a57Sdougm 			    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
760d8689a57Sdougm 			    zfs_get_name(zhp));
761d8689a57Sdougm 			return (-1);
762d8689a57Sdougm 		}
763fa9e4066Sahrens 
764*da6c28aaSamw 	}
765fa9e4066Sahrens 	return (0);
766fa9e4066Sahrens }
767fa9e4066Sahrens 
768*da6c28aaSamw 
769*da6c28aaSamw int
770*da6c28aaSamw zfs_share_nfs(zfs_handle_t *zhp)
771*da6c28aaSamw {
772*da6c28aaSamw 	return (zfs_share_proto(zhp, nfs_only));
773*da6c28aaSamw }
774*da6c28aaSamw 
775*da6c28aaSamw int
776*da6c28aaSamw zfs_share_smb(zfs_handle_t *zhp)
777*da6c28aaSamw {
778*da6c28aaSamw 	return (zfs_share_proto(zhp, smb_only));
779*da6c28aaSamw }
780*da6c28aaSamw 
781*da6c28aaSamw int
782*da6c28aaSamw zfs_shareall(zfs_handle_t *zhp)
783*da6c28aaSamw {
784*da6c28aaSamw 	return (zfs_share_proto(zhp, share_all_proto));
785*da6c28aaSamw }
786*da6c28aaSamw 
7873bb79becSeschrock /*
7883bb79becSeschrock  * Unshare a filesystem by mountpoint.
7893bb79becSeschrock  */
7903bb79becSeschrock static int
791*da6c28aaSamw unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
792*da6c28aaSamw     zfs_share_proto_t proto)
7933bb79becSeschrock {
79467331909Sdougm 	sa_share_t share;
79567331909Sdougm 	int err;
79667331909Sdougm 	char *mntpt;
7973bb79becSeschrock 	/*
79867331909Sdougm 	 * Mountpoint could get trashed if libshare calls getmntany
79967331909Sdougm 	 * which id does during API initialization, so strdup the
80067331909Sdougm 	 * value.
8013bb79becSeschrock 	 */
80267331909Sdougm 	mntpt = zfs_strdup(hdl, mountpoint);
8033bb79becSeschrock 
80467331909Sdougm 	/* make sure libshare initialized */
80567331909Sdougm 	if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
80667331909Sdougm 		free(mntpt);	/* don't need the copy anymore */
80767331909Sdougm 		return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
808d8689a57Sdougm 		    dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
809d8689a57Sdougm 		    name, _sa_errorstr(err)));
81067331909Sdougm 	}
8113bb79becSeschrock 
81267331909Sdougm 	share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt);
81367331909Sdougm 	free(mntpt);	/* don't need the copy anymore */
8143bb79becSeschrock 
81567331909Sdougm 	if (share != NULL) {
816*da6c28aaSamw 		err = zfs_sa_disable_share(share, proto_table[proto].p_name);
81767331909Sdougm 		if (err != SA_OK) {
818d8689a57Sdougm 			return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
819d8689a57Sdougm 			    dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
820d8689a57Sdougm 			    name, _sa_errorstr(err)));
82167331909Sdougm 		}
82267331909Sdougm 	} else {
823ece3d9b3Slling 		return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
824d8689a57Sdougm 		    dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"),
825d8689a57Sdougm 		    name));
8263bb79becSeschrock 	}
8273bb79becSeschrock 	return (0);
8283bb79becSeschrock }
8293bb79becSeschrock 
830fa9e4066Sahrens /*
831fa9e4066Sahrens  * Unshare the given filesystem.
832fa9e4066Sahrens  */
833fa9e4066Sahrens int
834*da6c28aaSamw zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
835*da6c28aaSamw     zfs_share_proto_t *proto)
836fa9e4066Sahrens {
837fa9e4066Sahrens 	struct mnttab search = { 0 }, entry;
83867331909Sdougm 	char *mntpt = NULL;
839fa9e4066Sahrens 
840fa9e4066Sahrens 	/* check to see if need to unmount the filesystem */
841fa9e4066Sahrens 	search.mnt_special = (char *)zfs_get_name(zhp);
84296dedd18Snd 	search.mnt_fstype = MNTTYPE_ZFS;
84399653d4eSeschrock 	rewind(zhp->zfs_hdl->libzfs_mnttab);
844d8689a57Sdougm 	if (mountpoint != NULL)
845*da6c28aaSamw 		mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);
846d8689a57Sdougm 
847fa9e4066Sahrens 	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
84899653d4eSeschrock 	    getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
849*da6c28aaSamw 		zfs_share_proto_t *curr_proto;
850fa9e4066Sahrens 
851fa9e4066Sahrens 		if (mountpoint == NULL)
852*da6c28aaSamw 			mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
853fa9e4066Sahrens 
854*da6c28aaSamw 		for (curr_proto = proto; *curr_proto != PROTO_END;
855*da6c28aaSamw 		    curr_proto++) {
856*da6c28aaSamw 
857*da6c28aaSamw 			if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) &&
858*da6c28aaSamw 			    unshare_one(zhp->zfs_hdl, zhp->zfs_name,
859*da6c28aaSamw 			    mntpt, *curr_proto) != 0) {
860*da6c28aaSamw 				if (mntpt != NULL)
861*da6c28aaSamw 					free(mntpt);
862*da6c28aaSamw 				return (-1);
863*da6c28aaSamw 			}
86467331909Sdougm 		}
865fa9e4066Sahrens 	}
86667331909Sdougm 	if (mntpt != NULL)
867d8689a57Sdougm 		free(mntpt);
868fa9e4066Sahrens 
869fa9e4066Sahrens 	return (0);
870fa9e4066Sahrens }
871fa9e4066Sahrens 
872*da6c28aaSamw int
873*da6c28aaSamw zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
874*da6c28aaSamw {
875*da6c28aaSamw 	return (zfs_unshare_proto(zhp, mountpoint, nfs_only));
876*da6c28aaSamw }
877*da6c28aaSamw 
878*da6c28aaSamw int
879*da6c28aaSamw zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint)
880*da6c28aaSamw {
881*da6c28aaSamw 	return (zfs_unshare_proto(zhp, mountpoint, smb_only));
882*da6c28aaSamw }
883*da6c28aaSamw 
884fa9e4066Sahrens /*
885*da6c28aaSamw  * Same as zfs_unmountall(), but for NFS and SMB unshares.
886fa9e4066Sahrens  */
887fa9e4066Sahrens int
888*da6c28aaSamw zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
889fa9e4066Sahrens {
890fa9e4066Sahrens 	prop_changelist_t *clp;
891fa9e4066Sahrens 	int ret;
892fa9e4066Sahrens 
893fa9e4066Sahrens 	clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0);
894fa9e4066Sahrens 	if (clp == NULL)
895fa9e4066Sahrens 		return (-1);
896fa9e4066Sahrens 
897*da6c28aaSamw 	ret = changelist_unshare(clp, proto);
898fa9e4066Sahrens 	changelist_free(clp);
899fa9e4066Sahrens 
900fa9e4066Sahrens 	return (ret);
901fa9e4066Sahrens }
902fa9e4066Sahrens 
903*da6c28aaSamw int
904*da6c28aaSamw zfs_unshareall_nfs(zfs_handle_t *zhp)
905*da6c28aaSamw {
906*da6c28aaSamw 	return (zfs_unshareall_proto(zhp, nfs_only));
907*da6c28aaSamw }
908*da6c28aaSamw 
909*da6c28aaSamw int
910*da6c28aaSamw zfs_unshareall_smb(zfs_handle_t *zhp)
911*da6c28aaSamw {
912*da6c28aaSamw 	return (zfs_unshareall_proto(zhp, smb_only));
913*da6c28aaSamw }
914*da6c28aaSamw 
915*da6c28aaSamw int
916*da6c28aaSamw zfs_unshareall(zfs_handle_t *zhp)
917*da6c28aaSamw {
918*da6c28aaSamw 	return (zfs_unshareall_proto(zhp, share_all_proto));
919*da6c28aaSamw }
920*da6c28aaSamw 
921*da6c28aaSamw int
922*da6c28aaSamw zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint)
923*da6c28aaSamw {
924*da6c28aaSamw 	return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
925*da6c28aaSamw }
926*da6c28aaSamw 
927fa9e4066Sahrens /*
928fa9e4066Sahrens  * Remove the mountpoint associated with the current dataset, if necessary.
929fa9e4066Sahrens  * We only remove the underlying directory if:
930fa9e4066Sahrens  *
931fa9e4066Sahrens  *	- The mountpoint is not 'none' or 'legacy'
932fa9e4066Sahrens  *	- The mountpoint is non-empty
933fa9e4066Sahrens  *	- The mountpoint is the default or inherited
934fa9e4066Sahrens  *	- The 'zoned' property is set, or we're in a local zone
935fa9e4066Sahrens  *
936fa9e4066Sahrens  * Any other directories we leave alone.
937fa9e4066Sahrens  */
938fa9e4066Sahrens void
939fa9e4066Sahrens remove_mountpoint(zfs_handle_t *zhp)
940fa9e4066Sahrens {
941fa9e4066Sahrens 	char mountpoint[ZFS_MAXPROPLEN];
942990b4856Slling 	zprop_source_t source;
943fa9e4066Sahrens 
944e9dbad6fSeschrock 	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
945e9dbad6fSeschrock 	    &source))
946fa9e4066Sahrens 		return;
947fa9e4066Sahrens 
948990b4856Slling 	if (source == ZPROP_SRC_DEFAULT ||
949990b4856Slling 	    source == ZPROP_SRC_INHERITED) {
950fa9e4066Sahrens 		/*
951fa9e4066Sahrens 		 * Try to remove the directory, silently ignoring any errors.
952fa9e4066Sahrens 		 * The filesystem may have since been removed or moved around,
953e9dbad6fSeschrock 		 * and this error isn't really useful to the administrator in
954e9dbad6fSeschrock 		 * any way.
955fa9e4066Sahrens 		 */
956fa9e4066Sahrens 		(void) rmdir(mountpoint);
957fa9e4066Sahrens 	}
958fa9e4066Sahrens }
9593bb79becSeschrock 
960f3861e1aSahl boolean_t
961f3861e1aSahl zfs_is_shared_iscsi(zfs_handle_t *zhp)
962f3861e1aSahl {
963ecd6cf80Smarks 
964ecd6cf80Smarks 	/*
965ecd6cf80Smarks 	 * If iscsi deamon isn't running then we aren't shared
966ecd6cf80Smarks 	 */
967ecd6cf80Smarks 	if (iscsitgt_svc_online && iscsitgt_svc_online() == 1)
968*da6c28aaSamw 		return (B_FALSE);
969ecd6cf80Smarks 	else
970ecd6cf80Smarks 		return (iscsitgt_zfs_is_shared != NULL &&
971ecd6cf80Smarks 		    iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
972f3861e1aSahl }
973f3861e1aSahl 
974f3861e1aSahl int
975f3861e1aSahl zfs_share_iscsi(zfs_handle_t *zhp)
976f3861e1aSahl {
977f3861e1aSahl 	char shareopts[ZFS_MAXPROPLEN];
978f3861e1aSahl 	const char *dataset = zhp->zfs_name;
979f3861e1aSahl 	libzfs_handle_t *hdl = zhp->zfs_hdl;
980f3861e1aSahl 
981f3861e1aSahl 	/*
982f3861e1aSahl 	 * Return success if there are no share options.
983f3861e1aSahl 	 */
984f3861e1aSahl 	if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts,
985f3861e1aSahl 	    sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 ||
986f3861e1aSahl 	    strcmp(shareopts, "off") == 0)
987f3861e1aSahl 		return (0);
988f3861e1aSahl 
989ecd6cf80Smarks 	if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) {
990ecd6cf80Smarks 		int error = EZFS_SHAREISCSIFAILED;
991ecd6cf80Smarks 
992ecd6cf80Smarks 		/*
993ecd6cf80Smarks 		 * If service isn't availabele and EPERM was
994ecd6cf80Smarks 		 * returned then use special error.
995ecd6cf80Smarks 		 */
996ecd6cf80Smarks 		if (iscsitgt_svc_online && errno == EPERM &&
997ecd6cf80Smarks 		    (iscsitgt_svc_online() != 0))
998ecd6cf80Smarks 			error = EZFS_ISCSISVCUNAVAIL;
999ecd6cf80Smarks 
1000ecd6cf80Smarks 		return (zfs_error_fmt(hdl, error,
1001f3861e1aSahl 		    dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset));
1002ecd6cf80Smarks 	}
1003f3861e1aSahl 
1004f3861e1aSahl 	return (0);
1005f3861e1aSahl }
1006f3861e1aSahl 
1007f3861e1aSahl int
1008f3861e1aSahl zfs_unshare_iscsi(zfs_handle_t *zhp)
1009f3861e1aSahl {
1010f3861e1aSahl 	const char *dataset = zfs_get_name(zhp);
1011f3861e1aSahl 	libzfs_handle_t *hdl = zhp->zfs_hdl;
1012f3861e1aSahl 
101311d2789dSgw 	/*
101411d2789dSgw 	 * Return if the volume is not shared
101511d2789dSgw 	 */
1016*da6c28aaSamw 	if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI)
101711d2789dSgw 		return (0);
101811d2789dSgw 
1019f3861e1aSahl 	/*
1020f3861e1aSahl 	 * If this fails with ENODEV it indicates that zvol wasn't shared so
1021f3861e1aSahl 	 * we should return success in that case.
1022f3861e1aSahl 	 */
1023d8d59944Sahl 	if (iscsitgt_zfs_unshare == NULL ||
1024ecd6cf80Smarks 	    (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) {
1025ecd6cf80Smarks 		if (errno == EPERM)
1026ecd6cf80Smarks 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1027ecd6cf80Smarks 			    "Insufficient privileges to unshare iscsi"));
1028ece3d9b3Slling 		return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED,
1029f3861e1aSahl 		    dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset));
1030ecd6cf80Smarks 	}
1031f3861e1aSahl 
1032f3861e1aSahl 	return (0);
1033f3861e1aSahl }
1034f3861e1aSahl 
10353bb79becSeschrock typedef struct mount_cbdata {
10363bb79becSeschrock 	zfs_handle_t	**cb_datasets;
10373bb79becSeschrock 	int 		cb_used;
10383bb79becSeschrock 	int		cb_alloc;
10393bb79becSeschrock } mount_cbdata_t;
10403bb79becSeschrock 
10413bb79becSeschrock static int
10423bb79becSeschrock mount_cb(zfs_handle_t *zhp, void *data)
10433bb79becSeschrock {
10443bb79becSeschrock 	mount_cbdata_t *cbp = data;
10453bb79becSeschrock 
1046f3861e1aSahl 	if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) {
10473bb79becSeschrock 		zfs_close(zhp);
10483bb79becSeschrock 		return (0);
10493bb79becSeschrock 	}
10503bb79becSeschrock 
10513bb79becSeschrock 	if (cbp->cb_alloc == cbp->cb_used) {
1052e9dbad6fSeschrock 		void *ptr;
10533bb79becSeschrock 
1054e9dbad6fSeschrock 		if ((ptr = zfs_realloc(zhp->zfs_hdl,
1055e9dbad6fSeschrock 		    cbp->cb_datasets, cbp->cb_alloc * sizeof (void *),
1056e9dbad6fSeschrock 		    cbp->cb_alloc * 2 * sizeof (void *))) == NULL)
10573bb79becSeschrock 			return (-1);
1058e9dbad6fSeschrock 		cbp->cb_datasets = ptr;
10593bb79becSeschrock 
1060e9dbad6fSeschrock 		cbp->cb_alloc *= 2;
10613bb79becSeschrock 	}
10623bb79becSeschrock 
10633bb79becSeschrock 	cbp->cb_datasets[cbp->cb_used++] = zhp;
1064f3861e1aSahl 
1065f3861e1aSahl 	return (zfs_iter_children(zhp, mount_cb, cbp));
10663bb79becSeschrock }
10673bb79becSeschrock 
10683bb79becSeschrock static int
1069f3861e1aSahl dataset_cmp(const void *a, const void *b)
10703bb79becSeschrock {
10713bb79becSeschrock 	zfs_handle_t **za = (zfs_handle_t **)a;
10723bb79becSeschrock 	zfs_handle_t **zb = (zfs_handle_t **)b;
10733bb79becSeschrock 	char mounta[MAXPATHLEN];
10743bb79becSeschrock 	char mountb[MAXPATHLEN];
1075f3861e1aSahl 	boolean_t gota, gotb;
1076f3861e1aSahl 
1077f3861e1aSahl 	if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0)
1078f3861e1aSahl 		verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
1079f3861e1aSahl 		    sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
1080f3861e1aSahl 	if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0)
1081f3861e1aSahl 		verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
1082f3861e1aSahl 		    sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
1083f3861e1aSahl 
1084f3861e1aSahl 	if (gota && gotb)
1085f3861e1aSahl 		return (strcmp(mounta, mountb));
10863bb79becSeschrock 
1087f3861e1aSahl 	if (gota)
1088f3861e1aSahl 		return (-1);
1089f3861e1aSahl 	if (gotb)
1090f3861e1aSahl 		return (1);
10913bb79becSeschrock 
1092f3861e1aSahl 	return (strcmp(zfs_get_name(a), zfs_get_name(b)));
10933bb79becSeschrock }
10943bb79becSeschrock 
1095f3861e1aSahl /*
1096f3861e1aSahl  * Mount and share all datasets within the given pool.  This assumes that no
1097f3861e1aSahl  * datasets within the pool are currently mounted.  Because users can create
1098f3861e1aSahl  * complicated nested hierarchies of mountpoints, we first gather all the
1099f3861e1aSahl  * datasets and mountpoints within the pool, and sort them by mountpoint.  Once
1100f3861e1aSahl  * we have the list of all filesystems, we iterate over them in order and mount
1101f3861e1aSahl  * and/or share each one.
1102f3861e1aSahl  */
1103f3861e1aSahl #pragma weak zpool_mount_datasets = zpool_enable_datasets
11043bb79becSeschrock int
1105f3861e1aSahl zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
11063bb79becSeschrock {
11073bb79becSeschrock 	mount_cbdata_t cb = { 0 };
11083bb79becSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
11093bb79becSeschrock 	zfs_handle_t *zfsp;
11103bb79becSeschrock 	int i, ret = -1;
111167331909Sdougm 	int *good;
11123bb79becSeschrock 
11133bb79becSeschrock 	/*
11143bb79becSeschrock 	 * Gather all datasets within the pool.
11153bb79becSeschrock 	 */
11163bb79becSeschrock 	if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL)
11173bb79becSeschrock 		return (-1);
11183bb79becSeschrock 	cb.cb_alloc = 4;
11193bb79becSeschrock 
1120990b4856Slling 	if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL)
11213bb79becSeschrock 		goto out;
11223bb79becSeschrock 
11233bb79becSeschrock 	cb.cb_datasets[0] = zfsp;
11243bb79becSeschrock 	cb.cb_used = 1;
11253bb79becSeschrock 
11263bb79becSeschrock 	if (zfs_iter_children(zfsp, mount_cb, &cb) != 0)
11273bb79becSeschrock 		goto out;
11283bb79becSeschrock 
11293bb79becSeschrock 	/*
11303bb79becSeschrock 	 * Sort the datasets by mountpoint.
11313bb79becSeschrock 	 */
1132f3861e1aSahl 	qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp);
11333bb79becSeschrock 
11343bb79becSeschrock 	/*
113567331909Sdougm 	 * And mount all the datasets, keeping track of which ones
113667331909Sdougm 	 * succeeded or failed. By using zfs_alloc(), the good pointer
113767331909Sdougm 	 * will always be non-NULL.
11383bb79becSeschrock 	 */
113967331909Sdougm 	good = zfs_alloc(zhp->zpool_hdl, cb.cb_used * sizeof (int));
11403bb79becSeschrock 	ret = 0;
11413bb79becSeschrock 	for (i = 0; i < cb.cb_used; i++) {
1142d8689a57Sdougm 		if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0)
11433bb79becSeschrock 			ret = -1;
1144d8689a57Sdougm 		else
114567331909Sdougm 			good[i] = 1;
11463bb79becSeschrock 	}
114767331909Sdougm 	/*
114867331909Sdougm 	 * Then share all the ones that need to be shared. This needs
114967331909Sdougm 	 * to be a separate pass in order to avoid excessive reloading
115067331909Sdougm 	 * of the configuration. Good should never be NULL since
115167331909Sdougm 	 * zfs_alloc is supposed to exit if memory isn't available.
115267331909Sdougm 	 */
115367331909Sdougm 	zfs_uninit_libshare(hdl);
115467331909Sdougm 	for (i = 0; i < cb.cb_used; i++) {
115567331909Sdougm 		if (good[i] && zfs_share(cb.cb_datasets[i]) != 0)
115667331909Sdougm 			ret = -1;
115767331909Sdougm 	}
115867331909Sdougm 
115967331909Sdougm 	free(good);
11603bb79becSeschrock 
11613bb79becSeschrock out:
11623bb79becSeschrock 	for (i = 0; i < cb.cb_used; i++)
11633bb79becSeschrock 		zfs_close(cb.cb_datasets[i]);
11643bb79becSeschrock 	free(cb.cb_datasets);
11653bb79becSeschrock 
11663bb79becSeschrock 	return (ret);
11673bb79becSeschrock }
11683bb79becSeschrock 
1169f3861e1aSahl 
1170f3861e1aSahl static int
1171f3861e1aSahl zvol_cb(const char *dataset, void *data)
1172f3861e1aSahl {
1173f3861e1aSahl 	libzfs_handle_t *hdl = data;
1174f3861e1aSahl 	zfs_handle_t *zhp;
1175f3861e1aSahl 
1176f3861e1aSahl 	/*
1177f3861e1aSahl 	 * Ignore snapshots and ignore failures from non-existant datasets.
1178f3861e1aSahl 	 */
1179f3861e1aSahl 	if (strchr(dataset, '@') != NULL ||
1180f3861e1aSahl 	    (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL)
1181f3861e1aSahl 		return (0);
1182f3861e1aSahl 
1183ecd6cf80Smarks 	if (zfs_unshare_iscsi(zhp) != 0)
1184ecd6cf80Smarks 		return (-1);
1185f3861e1aSahl 
1186f3861e1aSahl 	zfs_close(zhp);
1187f3861e1aSahl 
1188f3861e1aSahl 	return (0);
1189f3861e1aSahl }
1190f3861e1aSahl 
11913bb79becSeschrock static int
11923bb79becSeschrock mountpoint_compare(const void *a, const void *b)
11933bb79becSeschrock {
11943bb79becSeschrock 	const char *mounta = *((char **)a);
11953bb79becSeschrock 	const char *mountb = *((char **)b);
11963bb79becSeschrock 
11973bb79becSeschrock 	return (strcmp(mountb, mounta));
11983bb79becSeschrock }
11993bb79becSeschrock 
1200f3861e1aSahl /*
1201f3861e1aSahl  * Unshare and unmount all datasets within the given pool.  We don't want to
1202f3861e1aSahl  * rely on traversing the DSL to discover the filesystems within the pool,
1203f3861e1aSahl  * because this may be expensive (if not all of them are mounted), and can fail
1204f3861e1aSahl  * arbitrarily (on I/O error, for example).  Instead, we walk /etc/mnttab and
1205f3861e1aSahl  * gather all the filesystems that are currently mounted.
1206f3861e1aSahl  */
1207f3861e1aSahl #pragma weak zpool_unmount_datasets = zpool_disable_datasets
12083bb79becSeschrock int
1209f3861e1aSahl zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
12103bb79becSeschrock {
12113bb79becSeschrock 	int used, alloc;
12123bb79becSeschrock 	struct mnttab entry;
12133bb79becSeschrock 	size_t namelen;
12143bb79becSeschrock 	char **mountpoints = NULL;
12153bb79becSeschrock 	zfs_handle_t **datasets = NULL;
12163bb79becSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
12173bb79becSeschrock 	int i;
12183bb79becSeschrock 	int ret = -1;
12193bb79becSeschrock 	int flags = (force ? MS_FORCE : 0);
12203bb79becSeschrock 
1221f3861e1aSahl 	/*
1222f3861e1aSahl 	 * First unshare all zvols.
1223f3861e1aSahl 	 */
1224f3861e1aSahl 	if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0)
1225f3861e1aSahl 		return (-1);
1226f3861e1aSahl 
12273bb79becSeschrock 	namelen = strlen(zhp->zpool_name);
12283bb79becSeschrock 
12293bb79becSeschrock 	rewind(hdl->libzfs_mnttab);
12303bb79becSeschrock 	used = alloc = 0;
12313bb79becSeschrock 	while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
12323bb79becSeschrock 		/*
12333bb79becSeschrock 		 * Ignore non-ZFS entries.
12343bb79becSeschrock 		 */
12353bb79becSeschrock 		if (entry.mnt_fstype == NULL ||
12363bb79becSeschrock 		    strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
12373bb79becSeschrock 			continue;
12383bb79becSeschrock 
12393bb79becSeschrock 		/*
12403bb79becSeschrock 		 * Ignore filesystems not within this pool.
12413bb79becSeschrock 		 */
12423bb79becSeschrock 		if (entry.mnt_mountp == NULL ||
12433bb79becSeschrock 		    strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 ||
12443bb79becSeschrock 		    (entry.mnt_special[namelen] != '/' &&
12453bb79becSeschrock 		    entry.mnt_special[namelen] != '\0'))
12463bb79becSeschrock 			continue;
12473bb79becSeschrock 
12483bb79becSeschrock 		/*
12493bb79becSeschrock 		 * At this point we've found a filesystem within our pool.  Add
12503bb79becSeschrock 		 * it to our growing list.
12513bb79becSeschrock 		 */
12523bb79becSeschrock 		if (used == alloc) {
12533bb79becSeschrock 			if (alloc == 0) {
12543bb79becSeschrock 				if ((mountpoints = zfs_alloc(hdl,
12553bb79becSeschrock 				    8 * sizeof (void *))) == NULL)
12563bb79becSeschrock 					goto out;
12573bb79becSeschrock 
12583bb79becSeschrock 				if ((datasets = zfs_alloc(hdl,
12593bb79becSeschrock 				    8 * sizeof (void *))) == NULL)
12603bb79becSeschrock 					goto out;
12613bb79becSeschrock 
12623bb79becSeschrock 				alloc = 8;
12633bb79becSeschrock 			} else {
1264e9dbad6fSeschrock 				void *ptr;
12653bb79becSeschrock 
1266e9dbad6fSeschrock 				if ((ptr = zfs_realloc(hdl, mountpoints,
1267e9dbad6fSeschrock 				    alloc * sizeof (void *),
12683bb79becSeschrock 				    alloc * 2 * sizeof (void *))) == NULL)
12693bb79becSeschrock 					goto out;
1270e9dbad6fSeschrock 				mountpoints = ptr;
12713bb79becSeschrock 
1272e9dbad6fSeschrock 				if ((ptr = zfs_realloc(hdl, datasets,
1273e9dbad6fSeschrock 				    alloc * sizeof (void *),
12743bb79becSeschrock 				    alloc * 2 * sizeof (void *))) == NULL)
12753bb79becSeschrock 					goto out;
1276e9dbad6fSeschrock 				datasets = ptr;
12773bb79becSeschrock 
12783bb79becSeschrock 				alloc *= 2;
12793bb79becSeschrock 			}
12803bb79becSeschrock 		}
12813bb79becSeschrock 
12823bb79becSeschrock 		if ((mountpoints[used] = zfs_strdup(hdl,
12833bb79becSeschrock 		    entry.mnt_mountp)) == NULL)
12843bb79becSeschrock 			goto out;
12853bb79becSeschrock 
12863bb79becSeschrock 		/*
12873bb79becSeschrock 		 * This is allowed to fail, in case there is some I/O error.  It
12883bb79becSeschrock 		 * is only used to determine if we need to remove the underlying
12893bb79becSeschrock 		 * mountpoint, so failure is not fatal.
12903bb79becSeschrock 		 */
12913bb79becSeschrock 		datasets[used] = make_dataset_handle(hdl, entry.mnt_special);
12923bb79becSeschrock 
12933bb79becSeschrock 		used++;
12943bb79becSeschrock 	}
12953bb79becSeschrock 
12963bb79becSeschrock 	/*
12973bb79becSeschrock 	 * At this point, we have the entire list of filesystems, so sort it by
12983bb79becSeschrock 	 * mountpoint.
12993bb79becSeschrock 	 */
13003bb79becSeschrock 	qsort(mountpoints, used, sizeof (char *), mountpoint_compare);
13013bb79becSeschrock 
13023bb79becSeschrock 	/*
13033bb79becSeschrock 	 * Walk through and first unshare everything.
13043bb79becSeschrock 	 */
13053bb79becSeschrock 	for (i = 0; i < used; i++) {
1306*da6c28aaSamw 		zfs_share_proto_t *curr_proto;
1307*da6c28aaSamw 		for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
1308*da6c28aaSamw 		    curr_proto++) {
1309*da6c28aaSamw 			if (is_shared(hdl, mountpoints[i], *curr_proto) &&
1310*da6c28aaSamw 			    unshare_one(hdl, mountpoints[i],
1311*da6c28aaSamw 			    mountpoints[i], *curr_proto) != 0)
1312*da6c28aaSamw 				goto out;
1313*da6c28aaSamw 		}
13143bb79becSeschrock 	}
13153bb79becSeschrock 
13163bb79becSeschrock 	/*
13173bb79becSeschrock 	 * Now unmount everything, removing the underlying directories as
13183bb79becSeschrock 	 * appropriate.
13193bb79becSeschrock 	 */
13203bb79becSeschrock 	for (i = 0; i < used; i++) {
13213bb79becSeschrock 		if (unmount_one(hdl, mountpoints[i], flags) != 0)
13223bb79becSeschrock 			goto out;
1323e9dbad6fSeschrock 	}
13243bb79becSeschrock 
1325e9dbad6fSeschrock 	for (i = 0; i < used; i++) {
13263bb79becSeschrock 		if (datasets[i])
13273bb79becSeschrock 			remove_mountpoint(datasets[i]);
13283bb79becSeschrock 	}
13293bb79becSeschrock 
13303bb79becSeschrock 	ret = 0;
13313bb79becSeschrock out:
13323bb79becSeschrock 	for (i = 0; i < used; i++) {
13333bb79becSeschrock 		if (datasets[i])
13343bb79becSeschrock 			zfs_close(datasets[i]);
13353bb79becSeschrock 		free(mountpoints[i]);
13363bb79becSeschrock 	}
13373bb79becSeschrock 	free(datasets);
13383bb79becSeschrock 	free(mountpoints);
13393bb79becSeschrock 
13403bb79becSeschrock 	return (ret);
13413bb79becSeschrock }
1342