1*789Sahrens /*
2*789Sahrens  * CDDL HEADER START
3*789Sahrens  *
4*789Sahrens  * The contents of this file are subject to the terms of the
5*789Sahrens  * Common Development and Distribution License, Version 1.0 only
6*789Sahrens  * (the "License").  You may not use this file except in compliance
7*789Sahrens  * with the License.
8*789Sahrens  *
9*789Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*789Sahrens  * or http://www.opensolaris.org/os/licensing.
11*789Sahrens  * See the License for the specific language governing permissions
12*789Sahrens  * and limitations under the License.
13*789Sahrens  *
14*789Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
15*789Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*789Sahrens  * If applicable, add the following below this CDDL HEADER, with the
17*789Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
18*789Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
19*789Sahrens  *
20*789Sahrens  * CDDL HEADER END
21*789Sahrens  */
22*789Sahrens /*
23*789Sahrens  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*789Sahrens  * Use is subject to license terms.
25*789Sahrens  */
26*789Sahrens 
27*789Sahrens #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*789Sahrens 
29*789Sahrens /*
30*789Sahrens  * Routines to manage ZFS mounts.  We separate all the nasty routines that have
31*789Sahrens  * to deal with the OS.  The main entry points are:
32*789Sahrens  *
33*789Sahrens  * 	zfs_is_mounted()
34*789Sahrens  * 	zfs_mount()
35*789Sahrens  * 	zfs_unmount()
36*789Sahrens  * 	zfs_unmountall()
37*789Sahrens  *
38*789Sahrens  * These functions are used by mount and unmount, and when changing a
39*789Sahrens  * filesystem's mountpoint.  This file also contains the functions used to
40*789Sahrens  * manage sharing filesystems via NFS:
41*789Sahrens  *
42*789Sahrens  * 	zfs_is_shared()
43*789Sahrens  * 	zfs_share()
44*789Sahrens  * 	zfs_unshare()
45*789Sahrens  * 	zfs_unshareall()
46*789Sahrens  */
47*789Sahrens 
48*789Sahrens #include <dirent.h>
49*789Sahrens #include <errno.h>
50*789Sahrens #include <libgen.h>
51*789Sahrens #include <libintl.h>
52*789Sahrens #include <stdio.h>
53*789Sahrens #include <stdlib.h>
54*789Sahrens #include <strings.h>
55*789Sahrens #include <unistd.h>
56*789Sahrens #include <zone.h>
57*789Sahrens #include <sys/mntent.h>
58*789Sahrens #include <sys/mnttab.h>
59*789Sahrens #include <sys/mount.h>
60*789Sahrens #include <sys/stat.h>
61*789Sahrens 
62*789Sahrens #include <libzfs.h>
63*789Sahrens 
64*789Sahrens #include "libzfs_impl.h"
65*789Sahrens 
66*789Sahrens 
67*789Sahrens /*
68*789Sahrens  * The following two files are opened as part of zfs_init().  It's OK to for
69*789Sahrens  * the sharetab to be NULL, but mnttab must always be non-NULL;
70*789Sahrens  */
71*789Sahrens FILE *mnttab_file;
72*789Sahrens FILE *sharetab_file;
73*789Sahrens 
74*789Sahrens /*
75*789Sahrens  * Search the sharetab for the given mountpoint, returning TRUE if it is found.
76*789Sahrens  */
77*789Sahrens static int
78*789Sahrens is_shared(const char *mountpoint)
79*789Sahrens {
80*789Sahrens 	char buf[MAXPATHLEN], *tab;
81*789Sahrens 
82*789Sahrens 	if (sharetab_file == NULL)
83*789Sahrens 		return (0);
84*789Sahrens 
85*789Sahrens 	(void) fseek(sharetab_file, 0, SEEK_SET);
86*789Sahrens 
87*789Sahrens 	while (fgets(buf, sizeof (buf), sharetab_file) != NULL) {
88*789Sahrens 
89*789Sahrens 		/* the mountpoint is the first entry on each line */
90*789Sahrens 		if ((tab = strchr(buf, '\t')) != NULL) {
91*789Sahrens 			*tab = '\0';
92*789Sahrens 			if (strcmp(buf, mountpoint) == 0)
93*789Sahrens 				return (1);
94*789Sahrens 		}
95*789Sahrens 	}
96*789Sahrens 
97*789Sahrens 	return (0);
98*789Sahrens }
99*789Sahrens 
100*789Sahrens /*
101*789Sahrens  * Returns TRUE if the specified directory is empty.  If we can't open the
102*789Sahrens  * directory at all, return TRUE so that the mount can fail with a more
103*789Sahrens  * informative error message.
104*789Sahrens  */
105*789Sahrens static int
106*789Sahrens dir_is_empty(const char *dirname)
107*789Sahrens {
108*789Sahrens 	DIR *dirp;
109*789Sahrens 	struct dirent64 *dp;
110*789Sahrens 
111*789Sahrens 	if ((dirp = opendir(dirname)) == NULL)
112*789Sahrens 		return (TRUE);
113*789Sahrens 
114*789Sahrens 	while ((dp = readdir64(dirp)) != NULL) {
115*789Sahrens 
116*789Sahrens 		if (strcmp(dp->d_name, ".") == 0 ||
117*789Sahrens 		    strcmp(dp->d_name, "..") == 0)
118*789Sahrens 			continue;
119*789Sahrens 
120*789Sahrens 		(void) closedir(dirp);
121*789Sahrens 		return (FALSE);
122*789Sahrens 	}
123*789Sahrens 
124*789Sahrens 	(void) closedir(dirp);
125*789Sahrens 	return (TRUE);
126*789Sahrens }
127*789Sahrens 
128*789Sahrens /*
129*789Sahrens  * Checks to see if the mount is active.  If the filesystem is mounted, we fill
130*789Sahrens  * in 'where' with the current mountpoint, and return 1.  Otherwise, we return
131*789Sahrens  * 0.
132*789Sahrens  */
133*789Sahrens int
134*789Sahrens zfs_is_mounted(zfs_handle_t *zhp, char **where)
135*789Sahrens {
136*789Sahrens 	struct mnttab search = { 0 }, entry;
137*789Sahrens 
138*789Sahrens 	/*
139*789Sahrens 	 * Search for the entry in /etc/mnttab.  We don't bother getting the
140*789Sahrens 	 * mountpoint, as we can just search for the special device.  This will
141*789Sahrens 	 * also let us find mounts when the mountpoint is 'legacy'.
142*789Sahrens 	 */
143*789Sahrens 	search.mnt_special = (char *)zfs_get_name(zhp);
144*789Sahrens 
145*789Sahrens 	rewind(mnttab_file);
146*789Sahrens 	if (getmntany(mnttab_file, &entry, &search) != 0)
147*789Sahrens 		return (FALSE);
148*789Sahrens 
149*789Sahrens 	if (where != NULL)
150*789Sahrens 		*where = zfs_strdup(entry.mnt_mountp);
151*789Sahrens 
152*789Sahrens 	return (TRUE);
153*789Sahrens }
154*789Sahrens 
155*789Sahrens /*
156*789Sahrens  * Mount the given filesystem.
157*789Sahrens  */
158*789Sahrens int
159*789Sahrens zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
160*789Sahrens {
161*789Sahrens 	struct stat buf;
162*789Sahrens 	char mountpoint[ZFS_MAXPROPLEN];
163*789Sahrens 	char mntopts[MNT_LINE_MAX];
164*789Sahrens 
165*789Sahrens 	if (options == NULL)
166*789Sahrens 		mntopts[0] = '\0';
167*789Sahrens 	else
168*789Sahrens 		(void) strlcpy(mntopts, options, sizeof (mntopts));
169*789Sahrens 
170*789Sahrens 	/* ignore non-filesystems */
171*789Sahrens 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
172*789Sahrens 	    sizeof (mountpoint), NULL, NULL, 0, FALSE) != 0)
173*789Sahrens 		return (0);
174*789Sahrens 
175*789Sahrens 	/* return success if there is no mountpoint set */
176*789Sahrens 	if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
177*789Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0)
178*789Sahrens 		return (0);
179*789Sahrens 
180*789Sahrens 	/*
181*789Sahrens 	 * If the 'zoned' property is set, and we're in the global zone, simply
182*789Sahrens 	 * return success.
183*789Sahrens 	 */
184*789Sahrens 	if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
185*789Sahrens 		char zonename[ZONENAME_MAX];
186*789Sahrens 		if (getzonenamebyid(getzoneid(), zonename,
187*789Sahrens 		    sizeof (zonename)) < 0) {
188*789Sahrens 			zfs_error(dgettext(TEXT_DOMAIN, "internal error: "
189*789Sahrens 			    "cannot determine current zone"));
190*789Sahrens 			return (1);
191*789Sahrens 		}
192*789Sahrens 
193*789Sahrens 		if (strcmp(zonename, "global") == 0)
194*789Sahrens 			return (0);
195*789Sahrens 	}
196*789Sahrens 
197*789Sahrens 	/* Create the directory if it doesn't already exist */
198*789Sahrens 	if (lstat(mountpoint, &buf) != 0) {
199*789Sahrens 		if (mkdirp(mountpoint, 0755) != 0) {
200*789Sahrens 			zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': "
201*789Sahrens 			    "unable to create mountpoint"), mountpoint);
202*789Sahrens 			return (1);
203*789Sahrens 		}
204*789Sahrens 	}
205*789Sahrens 
206*789Sahrens 	/*
207*789Sahrens 	 * Determine if the mountpoint is empty.  If so, refuse to perform the
208*789Sahrens 	 * mount.  We don't perform this check if MS_OVERLAY is specified, which
209*789Sahrens 	 * would defeat the point.  We also avoid this check if 'remount' is
210*789Sahrens 	 * specified.
211*789Sahrens 	 */
212*789Sahrens 	if ((flags & MS_OVERLAY) == 0 &&
213*789Sahrens 	    strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
214*789Sahrens 	    !dir_is_empty(mountpoint)) {
215*789Sahrens 		zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': "
216*789Sahrens 		    "directory is not empty"), mountpoint);
217*789Sahrens 		zfs_error(dgettext(TEXT_DOMAIN, "use legacy mountpoint to "
218*789Sahrens 		    "allow this behavior, or use the -O flag"));
219*789Sahrens 		return (1);
220*789Sahrens 	}
221*789Sahrens 
222*789Sahrens 	/* perform the mount */
223*789Sahrens 	if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
224*789Sahrens 	    MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
225*789Sahrens 		/*
226*789Sahrens 		 * Generic errors are nasty, but there are just way too many
227*789Sahrens 		 * from mount(), and they're well-understood.  We pick a few
228*789Sahrens 		 * common ones to improve upon.
229*789Sahrens 		 */
230*789Sahrens 		switch (errno) {
231*789Sahrens 		case EBUSY:
232*789Sahrens 			zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': "
233*789Sahrens 			    "mountpoint '%s' is busy"), zhp->zfs_name,
234*789Sahrens 			    mountpoint);
235*789Sahrens 			break;
236*789Sahrens 		case EPERM:
237*789Sahrens 		case EACCES:
238*789Sahrens 			zfs_error(dgettext(TEXT_DOMAIN, "cannot mount '%s': "
239*789Sahrens 			    "permission denied"), zhp->zfs_name,
240*789Sahrens 			    mountpoint);
241*789Sahrens 			break;
242*789Sahrens 		default:
243*789Sahrens 			zfs_error(dgettext(TEXT_DOMAIN,
244*789Sahrens 			    "cannot mount '%s': %s"),
245*789Sahrens 			    mountpoint, strerror(errno));
246*789Sahrens 			break;
247*789Sahrens 		}
248*789Sahrens 		return (1);
249*789Sahrens 	}
250*789Sahrens 
251*789Sahrens 	return (0);
252*789Sahrens }
253*789Sahrens 
254*789Sahrens /*
255*789Sahrens  * Unmount the given filesystem.
256*789Sahrens  */
257*789Sahrens int
258*789Sahrens zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
259*789Sahrens {
260*789Sahrens 	struct mnttab search = { 0 }, entry;
261*789Sahrens 
262*789Sahrens 	/* check to see if need to unmount the filesystem */
263*789Sahrens 	search.mnt_special = (char *)zfs_get_name(zhp);
264*789Sahrens 	rewind(mnttab_file);
265*789Sahrens 	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
266*789Sahrens 	    getmntany(mnttab_file, &entry, &search) == 0)) {
267*789Sahrens 
268*789Sahrens 		if (mountpoint == NULL)
269*789Sahrens 			mountpoint = entry.mnt_mountp;
270*789Sahrens 
271*789Sahrens 		/*
272*789Sahrens 		 * Always unshare the filesystem first.
273*789Sahrens 		 */
274*789Sahrens 		if (zfs_unshare(zhp, mountpoint) != 0)
275*789Sahrens 			return (-1);
276*789Sahrens 
277*789Sahrens 		/*
278*789Sahrens 		 * Try to unmount the filesystem.  There is no reason to try a
279*789Sahrens 		 * forced unmount because the vnodes will still carry a
280*789Sahrens 		 * reference to the underlying dataset, so we can't destroy it
281*789Sahrens 		 * anyway.
282*789Sahrens 		 *
283*789Sahrens 		 * In the unmount case, we print out a slightly more informative
284*789Sahrens 		 * error message, though we'll be relying on the poor error
285*789Sahrens 		 * semantics from the kernel.
286*789Sahrens 		 */
287*789Sahrens 		if (umount2(mountpoint, flags) != 0) {
288*789Sahrens 			zfs_error(dgettext(TEXT_DOMAIN,
289*789Sahrens 			    "cannot unmount '%s': %s"),
290*789Sahrens 			    mountpoint, strerror(errno));
291*789Sahrens 			return (-1);
292*789Sahrens 		}
293*789Sahrens 
294*789Sahrens 		/*
295*789Sahrens 		 * Don't actually destroy the underlying directory
296*789Sahrens 		 */
297*789Sahrens 	}
298*789Sahrens 
299*789Sahrens 	return (0);
300*789Sahrens }
301*789Sahrens 
302*789Sahrens /*
303*789Sahrens  * Unmount this filesystem and any children inheriting the mountpoint property.
304*789Sahrens  * To do this, just act like we're changing the mountpoint property, but don't
305*789Sahrens  * remount the filesystems afterwards.
306*789Sahrens  */
307*789Sahrens int
308*789Sahrens zfs_unmountall(zfs_handle_t *zhp, int flags)
309*789Sahrens {
310*789Sahrens 	prop_changelist_t *clp;
311*789Sahrens 	int ret;
312*789Sahrens 
313*789Sahrens 	clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, flags);
314*789Sahrens 	if (clp == NULL)
315*789Sahrens 		return (-1);
316*789Sahrens 
317*789Sahrens 	ret = changelist_prefix(clp);
318*789Sahrens 	changelist_free(clp);
319*789Sahrens 
320*789Sahrens 	return (ret);
321*789Sahrens }
322*789Sahrens 
323*789Sahrens /*
324*789Sahrens  * Check to see if the filesystem is currently shared.
325*789Sahrens  */
326*789Sahrens int
327*789Sahrens zfs_is_shared(zfs_handle_t *zhp, char **where)
328*789Sahrens {
329*789Sahrens 	char *mountpoint;
330*789Sahrens 
331*789Sahrens 	if (!zfs_is_mounted(zhp, &mountpoint))
332*789Sahrens 		return (FALSE);
333*789Sahrens 
334*789Sahrens 	if (is_shared(mountpoint)) {
335*789Sahrens 		if (where != NULL)
336*789Sahrens 			*where = mountpoint;
337*789Sahrens 		else
338*789Sahrens 			free(mountpoint);
339*789Sahrens 		return (TRUE);
340*789Sahrens 	} else {
341*789Sahrens 		free(mountpoint);
342*789Sahrens 		return (FALSE);
343*789Sahrens 	}
344*789Sahrens }
345*789Sahrens 
346*789Sahrens /*
347*789Sahrens  * Share the given filesystem according to the options in 'sharenfs'.  We rely
348*789Sahrens  * on share(1M) to the dirty work for us.
349*789Sahrens  */
350*789Sahrens int
351*789Sahrens zfs_share(zfs_handle_t *zhp)
352*789Sahrens {
353*789Sahrens 	char mountpoint[ZFS_MAXPROPLEN];
354*789Sahrens 	char shareopts[ZFS_MAXPROPLEN];
355*789Sahrens 	char buf[MAXPATHLEN];
356*789Sahrens 	FILE *fp;
357*789Sahrens 
358*789Sahrens 	/* ignore non-filesystems */
359*789Sahrens 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM)
360*789Sahrens 		return (0);
361*789Sahrens 
362*789Sahrens 	/* return success if there is no mountpoint set */
363*789Sahrens 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
364*789Sahrens 	    mountpoint, sizeof (mountpoint), NULL, NULL, 0, FALSE) != 0 ||
365*789Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
366*789Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0)
367*789Sahrens 		return (0);
368*789Sahrens 
369*789Sahrens 	/* return success if there are no share options */
370*789Sahrens 	if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts),
371*789Sahrens 	    NULL, NULL, 0, FALSE) != 0 ||
372*789Sahrens 	    strcmp(shareopts, "off") == 0)
373*789Sahrens 		return (0);
374*789Sahrens 
375*789Sahrens 	/*
376*789Sahrens 	 * If the 'zoned' property is set, simply return success since:
377*789Sahrens 	 * 1. in a global zone, a dataset should not be shared if it's
378*789Sahrens 	 *    managed in a local zone.
379*789Sahrens 	 * 2. in a local zone, NFS server is not available.
380*789Sahrens 	 */
381*789Sahrens 	if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
382*789Sahrens 		return (0);
383*789Sahrens 	}
384*789Sahrens 
385*789Sahrens 	/*
386*789Sahrens 	 * Invoke the share(1M) command.  We always do this, even if it's
387*789Sahrens 	 * currently shared, as the options may have changed.
388*789Sahrens 	 */
389*789Sahrens 	if (strcmp(shareopts, "on") == 0)
390*789Sahrens 		(void) snprintf(buf, sizeof (buf), "/usr/sbin/share "
391*789Sahrens 		    "-F nfs \"%s\" 2>&1", mountpoint);
392*789Sahrens 	else
393*789Sahrens 		(void) snprintf(buf, sizeof (buf), "/usr/sbin/share "
394*789Sahrens 		    "-F nfs -o \"%s\" \"%s\" 2>&1", shareopts,
395*789Sahrens 		    mountpoint);
396*789Sahrens 
397*789Sahrens 	if ((fp = popen(buf, "r")) == NULL) {
398*789Sahrens 		zfs_error(dgettext(TEXT_DOMAIN, "cannot share '%s': "
399*789Sahrens 		    "share(1M) failed"), zfs_get_name(zhp));
400*789Sahrens 		return (-1);
401*789Sahrens 	}
402*789Sahrens 
403*789Sahrens 	/*
404*789Sahrens 	 * share(1M) should only produce output if there is some kind
405*789Sahrens 	 * of error.  All output begins with "share_nfs: ", so we trim
406*789Sahrens 	 * this off to get to the real error.
407*789Sahrens 	 */
408*789Sahrens 	if (fgets(buf, sizeof (buf), fp) != NULL) {
409*789Sahrens 		char *colon = strchr(buf, ':');
410*789Sahrens 
411*789Sahrens 		while (buf[strlen(buf) - 1] == '\n')
412*789Sahrens 			buf[strlen(buf) - 1] = '\0';
413*789Sahrens 
414*789Sahrens 		if (colon == NULL)
415*789Sahrens 			zfs_error(dgettext(TEXT_DOMAIN, "cannot share "
416*789Sahrens 			    "'%s': share(1M) failed"),
417*789Sahrens 			    zfs_get_name(zhp));
418*789Sahrens 		else
419*789Sahrens 			zfs_error(dgettext(TEXT_DOMAIN, "cannot share "
420*789Sahrens 			    "'%s': %s"), zfs_get_name(zhp),
421*789Sahrens 			    colon + 2);
422*789Sahrens 
423*789Sahrens 		verify(pclose(fp) != 0);
424*789Sahrens 		return (-1);
425*789Sahrens 	}
426*789Sahrens 
427*789Sahrens 	verify(pclose(fp) == 0);
428*789Sahrens 
429*789Sahrens 	return (0);
430*789Sahrens }
431*789Sahrens 
432*789Sahrens /*
433*789Sahrens  * Unshare the given filesystem.
434*789Sahrens  */
435*789Sahrens int
436*789Sahrens zfs_unshare(zfs_handle_t *zhp, const char *mountpoint)
437*789Sahrens {
438*789Sahrens 	char buf[MAXPATHLEN];
439*789Sahrens 	struct mnttab search = { 0 }, entry;
440*789Sahrens 
441*789Sahrens 	/* check to see if need to unmount the filesystem */
442*789Sahrens 	search.mnt_special = (char *)zfs_get_name(zhp);
443*789Sahrens 	rewind(mnttab_file);
444*789Sahrens 	if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
445*789Sahrens 	    getmntany(mnttab_file, &entry, &search) == 0)) {
446*789Sahrens 
447*789Sahrens 		if (mountpoint == NULL)
448*789Sahrens 			mountpoint = entry.mnt_mountp;
449*789Sahrens 
450*789Sahrens 		if (is_shared(mountpoint)) {
451*789Sahrens 			FILE *fp;
452*789Sahrens 
453*789Sahrens 			(void) snprintf(buf, sizeof (buf),
454*789Sahrens 			    "/usr/sbin/unshare  \"%s\" 2>&1",
455*789Sahrens 			    mountpoint);
456*789Sahrens 
457*789Sahrens 			if ((fp = popen(buf, "r")) == NULL) {
458*789Sahrens 				zfs_error(dgettext(TEXT_DOMAIN, "cannot "
459*789Sahrens 				    "unshare '%s': unshare(1M) failed"),
460*789Sahrens 				    zfs_get_name(zhp));
461*789Sahrens 				return (-1);
462*789Sahrens 			}
463*789Sahrens 
464*789Sahrens 			/*
465*789Sahrens 			 * unshare(1M) should only produce output if there is
466*789Sahrens 			 * some kind of error.  All output begins with "unshare
467*789Sahrens 			 * nfs: ", so we trim this off to get to the real error.
468*789Sahrens 			 */
469*789Sahrens 			if (fgets(buf, sizeof (buf), fp) != NULL) {
470*789Sahrens 				char *colon = strchr(buf, ':');
471*789Sahrens 
472*789Sahrens 				while (buf[strlen(buf) - 1] == '\n')
473*789Sahrens 					buf[strlen(buf) - 1] = '\0';
474*789Sahrens 
475*789Sahrens 				if (colon == NULL)
476*789Sahrens 					zfs_error(dgettext(TEXT_DOMAIN,
477*789Sahrens 					    "cannot unshare '%s': unshare(1M) "
478*789Sahrens 					    "failed"), zfs_get_name(zhp));
479*789Sahrens 				else
480*789Sahrens 					zfs_error(dgettext(TEXT_DOMAIN,
481*789Sahrens 					    "cannot unshare '%s': %s"),
482*789Sahrens 					    zfs_get_name(zhp), colon + 2);
483*789Sahrens 
484*789Sahrens 				verify(pclose(fp) != 0);
485*789Sahrens 				return (-1);
486*789Sahrens 			}
487*789Sahrens 
488*789Sahrens 			verify(pclose(fp) == 0);
489*789Sahrens 		}
490*789Sahrens 	}
491*789Sahrens 
492*789Sahrens 	return (0);
493*789Sahrens }
494*789Sahrens 
495*789Sahrens /*
496*789Sahrens  * Same as zfs_unmountall(), but for unshares.
497*789Sahrens  */
498*789Sahrens int
499*789Sahrens zfs_unshareall(zfs_handle_t *zhp)
500*789Sahrens {
501*789Sahrens 	prop_changelist_t *clp;
502*789Sahrens 	int ret;
503*789Sahrens 
504*789Sahrens 	clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0);
505*789Sahrens 	if (clp == NULL)
506*789Sahrens 		return (-1);
507*789Sahrens 
508*789Sahrens 	ret = changelist_unshare(clp);
509*789Sahrens 	changelist_free(clp);
510*789Sahrens 
511*789Sahrens 	return (ret);
512*789Sahrens }
513*789Sahrens 
514*789Sahrens /*
515*789Sahrens  * Remove the mountpoint associated with the current dataset, if necessary.
516*789Sahrens  * We only remove the underlying directory if:
517*789Sahrens  *
518*789Sahrens  *	- The mountpoint is not 'none' or 'legacy'
519*789Sahrens  *	- The mountpoint is non-empty
520*789Sahrens  *	- The mountpoint is the default or inherited
521*789Sahrens  *	- The 'zoned' property is set, or we're in a local zone
522*789Sahrens  *
523*789Sahrens  * Any other directories we leave alone.
524*789Sahrens  */
525*789Sahrens void
526*789Sahrens remove_mountpoint(zfs_handle_t *zhp)
527*789Sahrens {
528*789Sahrens 	char mountpoint[ZFS_MAXPROPLEN];
529*789Sahrens 	char source[ZFS_MAXNAMELEN];
530*789Sahrens 	zfs_source_t sourcetype;
531*789Sahrens 	char zonename[ZONENAME_MAX];
532*789Sahrens 
533*789Sahrens 	/* ignore non-filesystems */
534*789Sahrens 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
535*789Sahrens 	    sizeof (mountpoint), &sourcetype, source, sizeof (source),
536*789Sahrens 	    FALSE) != 0)
537*789Sahrens 		return;
538*789Sahrens 
539*789Sahrens 	if (getzonenamebyid(getzoneid(), zonename, sizeof (zonename)) < 0)
540*789Sahrens 		zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: "
541*789Sahrens 		    "cannot determine current zone"));
542*789Sahrens 
543*789Sahrens 	if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0 &&
544*789Sahrens 	    strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
545*789Sahrens 	    (sourcetype == ZFS_SRC_DEFAULT ||
546*789Sahrens 	    sourcetype == ZFS_SRC_INHERITED) &&
547*789Sahrens 	    (!zfs_prop_get_int(zhp, ZFS_PROP_ZONED) ||
548*789Sahrens 	    strcmp(zonename, "global") != 0)) {
549*789Sahrens 
550*789Sahrens 		/*
551*789Sahrens 		 * Try to remove the directory, silently ignoring any errors.
552*789Sahrens 		 * The filesystem may have since been removed or moved around,
553*789Sahrens 		 * and this isn't really useful to the administrator in any
554*789Sahrens 		 * way.
555*789Sahrens 		 */
556*789Sahrens 		(void) rmdir(mountpoint);
557*789Sahrens 	}
558*789Sahrens }
559