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  */
21789Sahrens /*
221371Seschrock  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23789Sahrens  * Use is subject to license terms.
24789Sahrens  */
25789Sahrens 
26789Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
27789Sahrens 
28789Sahrens /*
29789Sahrens  * Routines to manage ZFS mounts.  We separate all the nasty routines that have
30789Sahrens  * to deal with the OS.  The main entry points are:
31789Sahrens  *
32789Sahrens  * 	zfs_is_mounted()
33789Sahrens  * 	zfs_mount()
34789Sahrens  * 	zfs_unmount()
35789Sahrens  * 	zfs_unmountall()
36789Sahrens  *
37789Sahrens  * These functions are used by mount and unmount, and when changing a
38789Sahrens  * filesystem's mountpoint.  This file also contains the functions used to
39789Sahrens  * manage sharing filesystems via NFS:
40789Sahrens  *
41789Sahrens  * 	zfs_is_shared()
42789Sahrens  * 	zfs_share()
43789Sahrens  * 	zfs_unshare()
44789Sahrens  * 	zfs_unshareall()
452474Seschrock  *
462474Seschrock  * The following functions are available for pool consumers, and will
472474Seschrock  * mount/unmount (and share/unshare) all datasets within pool:
482474Seschrock  *
492474Seschrock  * 	zpool_mount_datasets()
502474Seschrock  * 	zpool_unmount_datasets()
51789Sahrens  */
52789Sahrens 
53789Sahrens #include <dirent.h>
54789Sahrens #include <errno.h>
55789Sahrens #include <libgen.h>
56789Sahrens #include <libintl.h>
57789Sahrens #include <stdio.h>
58789Sahrens #include <stdlib.h>
59789Sahrens #include <strings.h>
60789Sahrens #include <unistd.h>
61789Sahrens #include <zone.h>
62789Sahrens #include <sys/mntent.h>
63789Sahrens #include <sys/mnttab.h>
64789Sahrens #include <sys/mount.h>
65789Sahrens #include <sys/stat.h>
66789Sahrens 
67789Sahrens #include <libzfs.h>
68789Sahrens 
69789Sahrens #include "libzfs_impl.h"
70789Sahrens 
71789Sahrens /*
722082Seschrock  * Search the sharetab for the given mountpoint, returning true if it is found.
73789Sahrens  */
742082Seschrock static boolean_t
752082Seschrock is_shared(libzfs_handle_t *hdl, const char *mountpoint)
76789Sahrens {
77789Sahrens 	char buf[MAXPATHLEN], *tab;
78789Sahrens 
792082Seschrock 	if (hdl->libzfs_sharetab == NULL)
80789Sahrens 		return (0);
81789Sahrens 
822082Seschrock 	(void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
83789Sahrens 
842082Seschrock 	while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
85789Sahrens 
86789Sahrens 		/* the mountpoint is the first entry on each line */
87789Sahrens 		if ((tab = strchr(buf, '\t')) != NULL) {
88789Sahrens 			*tab = '\0';
89789Sahrens 			if (strcmp(buf, mountpoint) == 0)
902082Seschrock 				return (B_TRUE);
91789Sahrens 		}
92789Sahrens 	}
93789Sahrens 
942082Seschrock 	return (B_FALSE);
95789Sahrens }
96789Sahrens 
97789Sahrens /*
982082Seschrock  * Returns true if the specified directory is empty.  If we can't open the
992082Seschrock  * directory at all, return true so that the mount can fail with a more
100789Sahrens  * informative error message.
101789Sahrens  */
1022082Seschrock static boolean_t
103789Sahrens dir_is_empty(const char *dirname)
104789Sahrens {
105789Sahrens 	DIR *dirp;
106789Sahrens 	struct dirent64 *dp;
107789Sahrens 
108789Sahrens 	if ((dirp = opendir(dirname)) == NULL)
1092082Seschrock 		return (B_TRUE);
110789Sahrens 
111789Sahrens 	while ((dp = readdir64(dirp)) != NULL) {
112789Sahrens 
113789Sahrens 		if (strcmp(dp->d_name, ".") == 0 ||
114789Sahrens 		    strcmp(dp->d_name, "..") == 0)
115789Sahrens 			continue;
116789Sahrens 
117789Sahrens 		(void) closedir(dirp);
1182082Seschrock 		return (B_FALSE);
119789Sahrens 	}
120789Sahrens 
121789Sahrens 	(void) closedir(dirp);
1222082Seschrock 	return (B_TRUE);
123789Sahrens }
124789Sahrens 
125789Sahrens /*
126789Sahrens  * Checks to see if the mount is active.  If the filesystem is mounted, we fill
127789Sahrens  * in 'where' with the current mountpoint, and return 1.  Otherwise, we return
128789Sahrens  * 0.
129789Sahrens  */
1302082Seschrock boolean_t
131789Sahrens zfs_is_mounted(zfs_handle_t *zhp, char **where)
132789Sahrens {
133789Sahrens 	struct mnttab search = { 0 }, entry;
134789Sahrens 
135789Sahrens 	/*
136789Sahrens 	 * Search for the entry in /etc/mnttab.  We don't bother getting the
137789Sahrens 	 * mountpoint, as we can just search for the special device.  This will
138789Sahrens 	 * also let us find mounts when the mountpoint is 'legacy'.
139789Sahrens 	 */
140789Sahrens 	search.mnt_special = (char *)zfs_get_name(zhp);
1411407Snd150628 	search.mnt_fstype = MNTTYPE_ZFS;
142789Sahrens 
1432082Seschrock 	rewind(zhp->zfs_hdl->libzfs_mnttab);
1442082Seschrock 	if (getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) != 0)
1452082Seschrock 		return (B_FALSE);
146789Sahrens 
147789Sahrens 	if (where != NULL)
1482082Seschrock 		*where = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
149789Sahrens 
1502082Seschrock 	return (B_TRUE);
151789Sahrens }
152789Sahrens 
153789Sahrens /*
154*2676Seschrock  * Returns true if the given dataset is mountable, false otherwise.  Returns the
155*2676Seschrock  * mountpoint in 'buf'.
156*2676Seschrock  */
157*2676Seschrock static boolean_t
158*2676Seschrock zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
159*2676Seschrock     zfs_source_t *source)
160*2676Seschrock {
161*2676Seschrock 	char sourceloc[ZFS_MAXNAMELEN];
162*2676Seschrock 	zfs_source_t sourcetype;
163*2676Seschrock 
164*2676Seschrock 	if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type))
165*2676Seschrock 		return (B_FALSE);
166*2676Seschrock 
167*2676Seschrock 	verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen,
168*2676Seschrock 	    &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0);
169*2676Seschrock 
170*2676Seschrock 	if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 ||
171*2676Seschrock 	    strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0)
172*2676Seschrock 		return (B_FALSE);
173*2676Seschrock 
174*2676Seschrock 	if (!zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT))
175*2676Seschrock 		return (B_FALSE);
176*2676Seschrock 
177*2676Seschrock 	if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
178*2676Seschrock 	    getzoneid() == GLOBAL_ZONEID)
179*2676Seschrock 		return (B_FALSE);
180*2676Seschrock 
181*2676Seschrock 	if (source)
182*2676Seschrock 		*source = sourcetype;
183*2676Seschrock 
184*2676Seschrock 	return (B_TRUE);
185*2676Seschrock }
186*2676Seschrock 
187*2676Seschrock /*
188789Sahrens  * Mount the given filesystem.
189789Sahrens  */
190789Sahrens int
191789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
192789Sahrens {
193789Sahrens 	struct stat buf;
194789Sahrens 	char mountpoint[ZFS_MAXPROPLEN];
195789Sahrens 	char mntopts[MNT_LINE_MAX];
1962082Seschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
197789Sahrens 
198789Sahrens 	if (options == NULL)
199789Sahrens 		mntopts[0] = '\0';
200789Sahrens 	else
201789Sahrens 		(void) strlcpy(mntopts, options, sizeof (mntopts));
202789Sahrens 
203*2676Seschrock 	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
2042082Seschrock 		return (0);
205789Sahrens 
206789Sahrens 	/* Create the directory if it doesn't already exist */
207789Sahrens 	if (lstat(mountpoint, &buf) != 0) {
208789Sahrens 		if (mkdirp(mountpoint, 0755) != 0) {
2092082Seschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2102082Seschrock 			    "failed to create mountpoint"));
2112082Seschrock 			return (zfs_error(hdl, EZFS_MOUNTFAILED,
2122082Seschrock 			    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
2132082Seschrock 			    mountpoint));
214789Sahrens 		}
215789Sahrens 	}
216789Sahrens 
217789Sahrens 	/*
218789Sahrens 	 * Determine if the mountpoint is empty.  If so, refuse to perform the
219789Sahrens 	 * mount.  We don't perform this check if MS_OVERLAY is specified, which
220789Sahrens 	 * would defeat the point.  We also avoid this check if 'remount' is
221789Sahrens 	 * specified.
222789Sahrens 	 */
223789Sahrens 	if ((flags & MS_OVERLAY) == 0 &&
224789Sahrens 	    strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
225789Sahrens 	    !dir_is_empty(mountpoint)) {
2262082Seschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2272082Seschrock 		    "directory is not empty"));
2282082Seschrock 		return (zfs_error(hdl, EZFS_MOUNTFAILED,
2292082Seschrock 		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
230789Sahrens 	}
231789Sahrens 
232789Sahrens 	/* perform the mount */
233789Sahrens 	if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
234789Sahrens 	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
235789Sahrens 		/*
236789Sahrens 		 * Generic errors are nasty, but there are just way too many
237789Sahrens 		 * from mount(), and they're well-understood.  We pick a few
238789Sahrens 		 * common ones to improve upon.
239789Sahrens 		 */
2402082Seschrock 		if (errno == EBUSY)
2412082Seschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2422082Seschrock 			    "mountpoint or dataset is busy"));
2432082Seschrock 		else
2442082Seschrock 			zfs_error_aux(hdl, strerror(errno));
2452082Seschrock 
2462082Seschrock 		return (zfs_error(hdl, EZFS_MOUNTFAILED,
2472082Seschrock 		    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
2482082Seschrock 		    zhp->zfs_name));
249789Sahrens 	}
250789Sahrens 
251789Sahrens 	return (0);
252789Sahrens }
253789Sahrens 
254789Sahrens /*
2552474Seschrock  * Unmount a single filesystem.
2562474Seschrock  */
2572474Seschrock static int
2582474Seschrock unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
2592474Seschrock {
2602474Seschrock 	if (umount2(mountpoint, flags) != 0) {
2612474Seschrock 		zfs_error_aux(hdl, strerror(errno));
2622474Seschrock 		return (zfs_error(hdl, EZFS_UMOUNTFAILED,
2632474Seschrock 		    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
2642474Seschrock 		    mountpoint));
2652474Seschrock 	}
2662474Seschrock 
2672474Seschrock 	return (0);
2682474Seschrock }
2692474Seschrock 
2702474Seschrock /*
271789Sahrens  * Unmount the given filesystem.
272789Sahrens  */
273789Sahrens int
274789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
275789Sahrens {
276789Sahrens 	struct mnttab search = { 0 }, entry;
277789Sahrens 
278789Sahrens 	/* check to see if need to unmount the filesystem */
2792474Seschrock 	search.mnt_special = zhp->zfs_name;
2801407Snd150628 	search.mnt_fstype = MNTTYPE_ZFS;
2812082Seschrock 	rewind(zhp->zfs_hdl->libzfs_mnttab);
282789Sahrens 	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
2832082Seschrock 	    getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
284789Sahrens 
285789Sahrens 		if (mountpoint == NULL)
286789Sahrens 			mountpoint = entry.mnt_mountp;
287789Sahrens 
288789Sahrens 		/*
2892474Seschrock 		 * Unshare and unmount the filesystem
290789Sahrens 		 */
2912474Seschrock 		if (zfs_unshare(zhp, mountpoint) != 0 ||
2922474Seschrock 		    unmount_one(zhp->zfs_hdl, mountpoint, flags) != 0)
293789Sahrens 			return (-1);
294789Sahrens 	}
295789Sahrens 
296789Sahrens 	return (0);
297789Sahrens }
298789Sahrens 
299789Sahrens /*
300789Sahrens  * Unmount this filesystem and any children inheriting the mountpoint property.
301789Sahrens  * To do this, just act like we're changing the mountpoint property, but don't
302789Sahrens  * remount the filesystems afterwards.
303789Sahrens  */
304789Sahrens int
305789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags)
306789Sahrens {
307789Sahrens 	prop_changelist_t *clp;
308789Sahrens 	int ret;
309789Sahrens 
310789Sahrens 	clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags);
311789Sahrens 	if (clp == NULL)
312789Sahrens 		return (-1);
313789Sahrens 
314789Sahrens 	ret = changelist_prefix(clp);
315789Sahrens 	changelist_free(clp);
316789Sahrens 
317789Sahrens 	return (ret);
318789Sahrens }
319789Sahrens 
320789Sahrens /*
321789Sahrens  * Check to see if the filesystem is currently shared.
322789Sahrens  */
3232082Seschrock boolean_t
324789Sahrens zfs_is_shared(zfs_handle_t *zhp, char **where)
325789Sahrens {
326789Sahrens 	char *mountpoint;
327789Sahrens 
328789Sahrens 	if (!zfs_is_mounted(zhp, &mountpoint))
3292082Seschrock 		return (B_FALSE);
330789Sahrens 
3312082Seschrock 	if (is_shared(zhp->zfs_hdl, mountpoint)) {
332789Sahrens 		if (where != NULL)
333789Sahrens 			*where = mountpoint;
334789Sahrens 		else
335789Sahrens 			free(mountpoint);
3362082Seschrock 		return (B_TRUE);
337789Sahrens 	} else {
338789Sahrens 		free(mountpoint);
3392082Seschrock 		return (B_FALSE);
340789Sahrens 	}
341789Sahrens }
342789Sahrens 
343789Sahrens /*
344789Sahrens  * Share the given filesystem according to the options in 'sharenfs'.  We rely
345789Sahrens  * on share(1M) to the dirty work for us.
346789Sahrens  */
347789Sahrens int
348789Sahrens zfs_share(zfs_handle_t *zhp)
349789Sahrens {
350789Sahrens 	char mountpoint[ZFS_MAXPROPLEN];
351789Sahrens 	char shareopts[ZFS_MAXPROPLEN];
352789Sahrens 	char buf[MAXPATHLEN];
353789Sahrens 	FILE *fp;
3542082Seschrock 	libzfs_handle_t *hdl = zhp->zfs_hdl;
355789Sahrens 
356*2676Seschrock 	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
357789Sahrens 		return (0);
358789Sahrens 
359789Sahrens 	/* return success if there are no share options */
360789Sahrens 	if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts),
3612082Seschrock 	    NULL, NULL, 0, B_FALSE) != 0 ||
362789Sahrens 	    strcmp(shareopts, "off") == 0)
363789Sahrens 		return (0);
364789Sahrens 
365789Sahrens 	/*
366*2676Seschrock 	 * If the 'zoned' property is set, then zfs_is_mountable() will have
367*2676Seschrock 	 * already bailed out if we are in the global zone.  But local
368*2676Seschrock 	 * zones cannot be NFS servers, so we ignore it for local zones as well.
369789Sahrens 	 */
370*2676Seschrock 	if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
371789Sahrens 		return (0);
372789Sahrens 
373789Sahrens 	/*
374789Sahrens 	 * Invoke the share(1M) command.  We always do this, even if it's
375789Sahrens 	 * currently shared, as the options may have changed.
376789Sahrens 	 */
377789Sahrens 	if (strcmp(shareopts, "on") == 0)
378789Sahrens 		(void) snprintf(buf, sizeof (buf), "/usr/sbin/share "
379789Sahrens 		    "-F nfs \"%s\" 2>&1", mountpoint);
380789Sahrens 	else
381789Sahrens 		(void) snprintf(buf, sizeof (buf), "/usr/sbin/share "
382789Sahrens 		    "-F nfs -o \"%s\" \"%s\" 2>&1", shareopts,
383789Sahrens 		    mountpoint);
384789Sahrens 
3852082Seschrock 	if ((fp = popen(buf, "r")) == NULL)
3862082Seschrock 		return (zfs_error(hdl, EZFS_SHAREFAILED,
3872082Seschrock 		    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
3882082Seschrock 		    zfs_get_name(zhp)));
389789Sahrens 
390789Sahrens 	/*
391789Sahrens 	 * share(1M) should only produce output if there is some kind
392789Sahrens 	 * of error.  All output begins with "share_nfs: ", so we trim
393789Sahrens 	 * this off to get to the real error.
394789Sahrens 	 */
395789Sahrens 	if (fgets(buf, sizeof (buf), fp) != NULL) {
396789Sahrens 		char *colon = strchr(buf, ':');
397789Sahrens 
398789Sahrens 		while (buf[strlen(buf) - 1] == '\n')
399789Sahrens 			buf[strlen(buf) - 1] = '\0';
400789Sahrens 
4012082Seschrock 		if (colon != NULL)
4022082Seschrock 			zfs_error_aux(hdl, colon + 2);
4032082Seschrock 
4042082Seschrock 		(void) zfs_error(hdl, EZFS_SHAREFAILED,
4052474Seschrock 		    dgettext(TEXT_DOMAIN, "cannot share '%s'"),
4062474Seschrock 		    zfs_get_name(zhp));
407789Sahrens 
408789Sahrens 		verify(pclose(fp) != 0);
409789Sahrens 		return (-1);
410789Sahrens 	}
411789Sahrens 
412789Sahrens 	verify(pclose(fp) == 0);
413789Sahrens 
414789Sahrens 	return (0);
415789Sahrens }
416789Sahrens 
417789Sahrens /*
4182474Seschrock  * Unshare a filesystem by mountpoint.
4192474Seschrock  */
4202474Seschrock static int
4212474Seschrock unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
4222474Seschrock {
4232474Seschrock 	char buf[MAXPATHLEN];
4242474Seschrock 	FILE *fp;
4252474Seschrock 
4262474Seschrock 	(void) snprintf(buf, sizeof (buf),
4272474Seschrock 	    "/usr/sbin/unshare  \"%s\" 2>&1",
4282474Seschrock 	    mountpoint);
4292474Seschrock 
4302474Seschrock 	if ((fp = popen(buf, "r")) == NULL)
4312474Seschrock 		return (zfs_error(hdl, EZFS_UNSHAREFAILED,
4322474Seschrock 		    dgettext(TEXT_DOMAIN,
4332474Seschrock 		    "cannot unshare '%s'"), name));
4342474Seschrock 
4352474Seschrock 	/*
4362474Seschrock 	 * unshare(1M) should only produce output if there is
4372474Seschrock 	 * some kind of error.  All output begins with "unshare
4382474Seschrock 	 * nfs: ", so we trim this off to get to the real error.
4392474Seschrock 	 */
4402474Seschrock 	if (fgets(buf, sizeof (buf), fp) != NULL) {
4412474Seschrock 		char *colon = strchr(buf, ':');
4422474Seschrock 
4432474Seschrock 		while (buf[strlen(buf) - 1] == '\n')
4442474Seschrock 			buf[strlen(buf) - 1] = '\0';
4452474Seschrock 
4462474Seschrock 		if (colon != NULL)
4472474Seschrock 			zfs_error_aux(hdl, colon + 2);
4482474Seschrock 
4492474Seschrock 		verify(pclose(fp) != 0);
4502474Seschrock 
4512474Seschrock 		return (zfs_error(hdl, EZFS_UNSHAREFAILED,
4522474Seschrock 		    dgettext(TEXT_DOMAIN,
4532474Seschrock 		    "cannot unshare '%s'"), name));
4542474Seschrock 	}
4552474Seschrock 
4562474Seschrock 	verify(pclose(fp) == 0);
4572474Seschrock 
4582474Seschrock 	return (0);
4592474Seschrock }
4602474Seschrock 
4612474Seschrock /*
462789Sahrens  * Unshare the given filesystem.
463789Sahrens  */
464789Sahrens int
465789Sahrens zfs_unshare(zfs_handle_t *zhp, const char *mountpoint)
466789Sahrens {
467789Sahrens 	struct mnttab search = { 0 }, entry;
468789Sahrens 
469789Sahrens 	/* check to see if need to unmount the filesystem */
470789Sahrens 	search.mnt_special = (char *)zfs_get_name(zhp);
4711407Snd150628 	search.mnt_fstype = MNTTYPE_ZFS;
4722082Seschrock 	rewind(zhp->zfs_hdl->libzfs_mnttab);
473789Sahrens 	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
4742082Seschrock 	    getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
475789Sahrens 
476789Sahrens 		if (mountpoint == NULL)
477789Sahrens 			mountpoint = entry.mnt_mountp;
478789Sahrens 
4792474Seschrock 		if (is_shared(zhp->zfs_hdl, mountpoint) &&
4802474Seschrock 		    unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0)
4812474Seschrock 			return (-1);
482789Sahrens 	}
483789Sahrens 
484789Sahrens 	return (0);
485789Sahrens }
486789Sahrens 
487789Sahrens /*
488789Sahrens  * Same as zfs_unmountall(), but for unshares.
489789Sahrens  */
490789Sahrens int
491789Sahrens zfs_unshareall(zfs_handle_t *zhp)
492789Sahrens {
493789Sahrens 	prop_changelist_t *clp;
494789Sahrens 	int ret;
495789Sahrens 
496789Sahrens 	clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0);
497789Sahrens 	if (clp == NULL)
498789Sahrens 		return (-1);
499789Sahrens 
500789Sahrens 	ret = changelist_unshare(clp);
501789Sahrens 	changelist_free(clp);
502789Sahrens 
503789Sahrens 	return (ret);
504789Sahrens }
505789Sahrens 
506789Sahrens /*
507789Sahrens  * Remove the mountpoint associated with the current dataset, if necessary.
508789Sahrens  * We only remove the underlying directory if:
509789Sahrens  *
510789Sahrens  *	- The mountpoint is not 'none' or 'legacy'
511789Sahrens  *	- The mountpoint is non-empty
512789Sahrens  *	- The mountpoint is the default or inherited
513789Sahrens  *	- The 'zoned' property is set, or we're in a local zone
514789Sahrens  *
515789Sahrens  * Any other directories we leave alone.
516789Sahrens  */
517789Sahrens void
518789Sahrens remove_mountpoint(zfs_handle_t *zhp)
519789Sahrens {
520789Sahrens 	char mountpoint[ZFS_MAXPROPLEN];
521*2676Seschrock 	zfs_source_t source;
522789Sahrens 
523*2676Seschrock 	if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
524*2676Seschrock 	    &source))
525789Sahrens 		return;
526789Sahrens 
527*2676Seschrock 	if (source == ZFS_SRC_DEFAULT ||
528*2676Seschrock 	    source == ZFS_SRC_INHERITED) {
529789Sahrens 		/*
530789Sahrens 		 * Try to remove the directory, silently ignoring any errors.
531789Sahrens 		 * The filesystem may have since been removed or moved around,
532*2676Seschrock 		 * and this error isn't really useful to the administrator in
533*2676Seschrock 		 * any way.
534789Sahrens 		 */
535789Sahrens 		(void) rmdir(mountpoint);
536789Sahrens 	}
537789Sahrens }
5382474Seschrock 
5392474Seschrock /*
5402474Seschrock  * Mount and share all datasets within the given pool.  This assumes that no
5412474Seschrock  * datasets within the pool are currently mounted.  Because users can create
5422474Seschrock  * complicated nested hierarchies of mountpoints, we first gather all the
5432474Seschrock  * datasets and mountpoints within the pool, and sort them by mountpoint.  Once
5442474Seschrock  * we have the list of all filesystems, we iterate over them in order and mount
5452474Seschrock  * and/or share each one.
5462474Seschrock  */
5472474Seschrock typedef struct mount_cbdata {
5482474Seschrock 	zfs_handle_t	**cb_datasets;
5492474Seschrock 	int 		cb_used;
5502474Seschrock 	int		cb_alloc;
5512474Seschrock } mount_cbdata_t;
5522474Seschrock 
5532474Seschrock static int
5542474Seschrock mount_cb(zfs_handle_t *zhp, void *data)
5552474Seschrock {
5562474Seschrock 	mount_cbdata_t *cbp = data;
5572474Seschrock 
5582474Seschrock 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
5592474Seschrock 		zfs_close(zhp);
5602474Seschrock 		return (0);
5612474Seschrock 	}
5622474Seschrock 
5632474Seschrock 	if (cbp->cb_alloc == cbp->cb_used) {
564*2676Seschrock 		void *ptr;
5652474Seschrock 
566*2676Seschrock 		if ((ptr = zfs_realloc(zhp->zfs_hdl,
567*2676Seschrock 		    cbp->cb_datasets, cbp->cb_alloc * sizeof (void *),
568*2676Seschrock 		    cbp->cb_alloc * 2 * sizeof (void *))) == NULL)
5692474Seschrock 			return (-1);
570*2676Seschrock 		cbp->cb_datasets = ptr;
5712474Seschrock 
572*2676Seschrock 		cbp->cb_alloc *= 2;
5732474Seschrock 	}
5742474Seschrock 
5752474Seschrock 	cbp->cb_datasets[cbp->cb_used++] = zhp;
5762474Seschrock 	return (0);
5772474Seschrock }
5782474Seschrock 
5792474Seschrock static int
5802474Seschrock dataset_compare(const void *a, const void *b)
5812474Seschrock {
5822474Seschrock 	zfs_handle_t **za = (zfs_handle_t **)a;
5832474Seschrock 	zfs_handle_t **zb = (zfs_handle_t **)b;
5842474Seschrock 	char mounta[MAXPATHLEN];
5852474Seschrock 	char mountb[MAXPATHLEN];
5862474Seschrock 
5872474Seschrock 	verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
5882474Seschrock 	    sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
5892474Seschrock 	verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
5902474Seschrock 	    sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
5912474Seschrock 
5922474Seschrock 	return (strcmp(mounta, mountb));
5932474Seschrock }
5942474Seschrock 
5952474Seschrock int
5962500Seschrock zpool_mount_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
5972474Seschrock {
5982474Seschrock 	mount_cbdata_t cb = { 0 };
5992474Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
6002474Seschrock 	zfs_handle_t *zfsp;
6012474Seschrock 	int i, ret = -1;
6022474Seschrock 
6032474Seschrock 	/*
6042474Seschrock 	 * Gather all datasets within the pool.
6052474Seschrock 	 */
6062474Seschrock 	if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL)
6072474Seschrock 		return (-1);
6082474Seschrock 	cb.cb_alloc = 4;
6092474Seschrock 
6102474Seschrock 	if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_ANY)) == NULL)
6112474Seschrock 		goto out;
6122474Seschrock 
6132474Seschrock 	cb.cb_datasets[0] = zfsp;
6142474Seschrock 	cb.cb_used = 1;
6152474Seschrock 
6162474Seschrock 	if (zfs_iter_children(zfsp, mount_cb, &cb) != 0)
6172474Seschrock 		goto out;
6182474Seschrock 
6192474Seschrock 	/*
6202474Seschrock 	 * Sort the datasets by mountpoint.
6212474Seschrock 	 */
6222474Seschrock 	qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_compare);
6232474Seschrock 
6242474Seschrock 	/*
6252474Seschrock 	 * And mount all the datasets.
6262474Seschrock 	 */
6272474Seschrock 	ret = 0;
6282474Seschrock 	for (i = 0; i < cb.cb_used; i++) {
6292500Seschrock 		if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0 ||
6302474Seschrock 		    zfs_share(cb.cb_datasets[i]) != 0)
6312474Seschrock 			ret = -1;
6322474Seschrock 	}
6332474Seschrock 
6342474Seschrock out:
6352474Seschrock 	for (i = 0; i < cb.cb_used; i++)
6362474Seschrock 		zfs_close(cb.cb_datasets[i]);
6372474Seschrock 	free(cb.cb_datasets);
6382474Seschrock 
6392474Seschrock 	return (ret);
6402474Seschrock }
6412474Seschrock 
6422474Seschrock /*
6432474Seschrock  * Unshare and unmount all datasets within the given pool.  We don't want to
6442474Seschrock  * rely on traversing the DSL to discover the filesystems within the pool,
6452474Seschrock  * because this may be expensive (if not all of them are mounted), and can fail
6462474Seschrock  * arbitrarily (on I/O error, for example).  Instead, we walk /etc/mnttab and
6472474Seschrock  * gather all the filesystems that are currently mounted.
6482474Seschrock  */
6492474Seschrock static int
6502474Seschrock mountpoint_compare(const void *a, const void *b)
6512474Seschrock {
6522474Seschrock 	const char *mounta = *((char **)a);
6532474Seschrock 	const char *mountb = *((char **)b);
6542474Seschrock 
6552474Seschrock 	return (strcmp(mountb, mounta));
6562474Seschrock }
6572474Seschrock 
6582474Seschrock int
6592474Seschrock zpool_unmount_datasets(zpool_handle_t *zhp, boolean_t force)
6602474Seschrock {
6612474Seschrock 	int used, alloc;
6622474Seschrock 	struct mnttab entry;
6632474Seschrock 	size_t namelen;
6642474Seschrock 	char **mountpoints = NULL;
6652474Seschrock 	zfs_handle_t **datasets = NULL;
6662474Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
6672474Seschrock 	int i;
6682474Seschrock 	int ret = -1;
6692474Seschrock 	int flags = (force ? MS_FORCE : 0);
6702474Seschrock 
6712474Seschrock 	namelen = strlen(zhp->zpool_name);
6722474Seschrock 
6732474Seschrock 	rewind(hdl->libzfs_mnttab);
6742474Seschrock 	used = alloc = 0;
6752474Seschrock 	while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
6762474Seschrock 		/*
6772474Seschrock 		 * Ignore non-ZFS entries.
6782474Seschrock 		 */
6792474Seschrock 		if (entry.mnt_fstype == NULL ||
6802474Seschrock 		    strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
6812474Seschrock 			continue;
6822474Seschrock 
6832474Seschrock 		/*
6842474Seschrock 		 * Ignore filesystems not within this pool.
6852474Seschrock 		 */
6862474Seschrock 		if (entry.mnt_mountp == NULL ||
6872474Seschrock 		    strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 ||
6882474Seschrock 		    (entry.mnt_special[namelen] != '/' &&
6892474Seschrock 		    entry.mnt_special[namelen] != '\0'))
6902474Seschrock 			continue;
6912474Seschrock 
6922474Seschrock 		/*
6932474Seschrock 		 * At this point we've found a filesystem within our pool.  Add
6942474Seschrock 		 * it to our growing list.
6952474Seschrock 		 */
6962474Seschrock 		if (used == alloc) {
6972474Seschrock 			if (alloc == 0) {
6982474Seschrock 				if ((mountpoints = zfs_alloc(hdl,
6992474Seschrock 				    8 * sizeof (void *))) == NULL)
7002474Seschrock 					goto out;
7012474Seschrock 
7022474Seschrock 				if ((datasets = zfs_alloc(hdl,
7032474Seschrock 				    8 * sizeof (void *))) == NULL)
7042474Seschrock 					goto out;
7052474Seschrock 
7062474Seschrock 				alloc = 8;
7072474Seschrock 			} else {
708*2676Seschrock 				void *ptr;
7092474Seschrock 
710*2676Seschrock 				if ((ptr = zfs_realloc(hdl, mountpoints,
711*2676Seschrock 				    alloc * sizeof (void *),
7122474Seschrock 				    alloc * 2 * sizeof (void *))) == NULL)
7132474Seschrock 					goto out;
714*2676Seschrock 				mountpoints = ptr;
7152474Seschrock 
716*2676Seschrock 				if ((ptr = zfs_realloc(hdl, datasets,
717*2676Seschrock 				    alloc * sizeof (void *),
7182474Seschrock 				    alloc * 2 * sizeof (void *))) == NULL)
7192474Seschrock 					goto out;
720*2676Seschrock 				datasets = ptr;
7212474Seschrock 
7222474Seschrock 				alloc *= 2;
7232474Seschrock 			}
7242474Seschrock 		}
7252474Seschrock 
7262474Seschrock 		if ((mountpoints[used] = zfs_strdup(hdl,
7272474Seschrock 		    entry.mnt_mountp)) == NULL)
7282474Seschrock 			goto out;
7292474Seschrock 
7302474Seschrock 		/*
7312474Seschrock 		 * This is allowed to fail, in case there is some I/O error.  It
7322474Seschrock 		 * is only used to determine if we need to remove the underlying
7332474Seschrock 		 * mountpoint, so failure is not fatal.
7342474Seschrock 		 */
7352474Seschrock 		datasets[used] = make_dataset_handle(hdl, entry.mnt_special);
7362474Seschrock 
7372474Seschrock 		used++;
7382474Seschrock 	}
7392474Seschrock 
7402474Seschrock 	/*
7412474Seschrock 	 * At this point, we have the entire list of filesystems, so sort it by
7422474Seschrock 	 * mountpoint.
7432474Seschrock 	 */
7442474Seschrock 	qsort(mountpoints, used, sizeof (char *), mountpoint_compare);
7452474Seschrock 
7462474Seschrock 	/*
7472474Seschrock 	 * Walk through and first unshare everything.
7482474Seschrock 	 */
7492474Seschrock 	for (i = 0; i < used; i++) {
7502474Seschrock 		if (is_shared(hdl, mountpoints[i]) &&
751*2676Seschrock 		    unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0)
7522474Seschrock 			goto out;
7532474Seschrock 	}
7542474Seschrock 
7552474Seschrock 	/*
7562474Seschrock 	 * Now unmount everything, removing the underlying directories as
7572474Seschrock 	 * appropriate.
7582474Seschrock 	 */
7592474Seschrock 	for (i = 0; i < used; i++) {
7602474Seschrock 		if (unmount_one(hdl, mountpoints[i], flags) != 0)
7612474Seschrock 			goto out;
762*2676Seschrock 	}
7632474Seschrock 
764*2676Seschrock 	for (i = 0; i < used; i++) {
7652474Seschrock 		if (datasets[i])
7662474Seschrock 			remove_mountpoint(datasets[i]);
7672474Seschrock 	}
7682474Seschrock 
7692474Seschrock 	ret = 0;
7702474Seschrock out:
7712474Seschrock 	for (i = 0; i < used; i++) {
7722474Seschrock 		if (datasets[i])
7732474Seschrock 			zfs_close(datasets[i]);
7742474Seschrock 		free(mountpoints[i]);
7752474Seschrock 	}
7762474Seschrock 	free(datasets);
7772474Seschrock 	free(mountpoints);
7782474Seschrock 
7792474Seschrock 	return (ret);
7802474Seschrock }
781