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