xref: /onnv-gate/usr/src/cmd/fs.d/autofs/autod_mount.c (revision 3930:59477feabc54)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52170Sevanl  * Common Development and Distribution License (the "License").
62170Sevanl  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
220Sstevel@tonic-gate  *	autod_mount.c
230Sstevel@tonic-gate  *
243391Ssemery  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
250Sstevel@tonic-gate  * Use is subject to license terms.
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <ctype.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <syslog.h>
340Sstevel@tonic-gate #include <sys/types.h>
350Sstevel@tonic-gate #include <sys/stat.h>
360Sstevel@tonic-gate #include <sys/param.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate #include <pwd.h>
390Sstevel@tonic-gate #include <netinet/in.h>
400Sstevel@tonic-gate #include <netdb.h>
410Sstevel@tonic-gate #include <sys/tiuser.h>
420Sstevel@tonic-gate #include <locale.h>
430Sstevel@tonic-gate #include <stdlib.h>
440Sstevel@tonic-gate #include <unistd.h>
450Sstevel@tonic-gate #include <sys/mntent.h>
460Sstevel@tonic-gate #include <sys/mnttab.h>
470Sstevel@tonic-gate #include <sys/wait.h>
480Sstevel@tonic-gate #include <sys/mount.h>
490Sstevel@tonic-gate #include <sys/fs/autofs.h>
500Sstevel@tonic-gate #include <nfs/nfs.h>
510Sstevel@tonic-gate #include <thread.h>
520Sstevel@tonic-gate #include <limits.h>
530Sstevel@tonic-gate #include <assert.h>
540Sstevel@tonic-gate #include <fcntl.h>
55*3930Snr123932 #include <strings.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #include "automount.h"
580Sstevel@tonic-gate #include "replica.h"
590Sstevel@tonic-gate 
600Sstevel@tonic-gate static int unmount_mntpnt(struct mnttab *);
61*3930Snr123932 static int call_fork_exec(char *, char *, char **, int);
620Sstevel@tonic-gate static void remove_browse_options(char *);
630Sstevel@tonic-gate static int inherit_options(char *, char **);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate int
do_mount1(char * mapname,char * key,char * subdir,char * mapopts,char * path,uint_t isdirect,uid_t uid,action_list ** alpp,int flags)662170Sevanl do_mount1(
672170Sevanl 	char *mapname,
682170Sevanl 	char *key,
692170Sevanl 	char *subdir,
702170Sevanl 	char *mapopts,
712170Sevanl 	char *path,
722170Sevanl 	uint_t isdirect,
733391Ssemery 	uid_t uid,
742170Sevanl 	action_list **alpp,
752170Sevanl 	int flags)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	struct mapline ml;
780Sstevel@tonic-gate 	struct mapent *me, *mapents = NULL;
790Sstevel@tonic-gate 	char mntpnt[MAXPATHLEN];
800Sstevel@tonic-gate 	char spec_mntpnt[MAXPATHLEN];
810Sstevel@tonic-gate 	int err = 0;
820Sstevel@tonic-gate 	char *private;	/* fs specific data. eg prevhost in case of nfs */
830Sstevel@tonic-gate 	int mount_ok = 0;
840Sstevel@tonic-gate 	ssize_t len;
850Sstevel@tonic-gate 	action_list *alp, *prev, *tmp;
860Sstevel@tonic-gate 	char root[MAXPATHLEN];
870Sstevel@tonic-gate 	int overlay = 1;
880Sstevel@tonic-gate 	char next_subdir[MAXPATHLEN];
890Sstevel@tonic-gate 	bool_t mount_access = TRUE;
900Sstevel@tonic-gate 	bool_t iswildcard;
910Sstevel@tonic-gate 	bool_t isrestricted = hasrestrictopt(mapopts);
920Sstevel@tonic-gate 	char *stack[STACKSIZ];
930Sstevel@tonic-gate 	char **stkptr = stack;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate retry:
960Sstevel@tonic-gate 	iswildcard = FALSE;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	/* initialize the stack of open files for this thread */
990Sstevel@tonic-gate 	stack_op(INIT, NULL, stack, &stkptr);
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	err = getmapent(key, mapname, &ml, stack, &stkptr, &iswildcard,
1020Sstevel@tonic-gate 		isrestricted);
1030Sstevel@tonic-gate 	if (err == 0) {
1040Sstevel@tonic-gate 		mapents = parse_entry(key, mapname, mapopts, &ml,
1050Sstevel@tonic-gate 				    subdir, isdirect, mount_access);
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 
1082170Sevanl 	if (trace) {
1090Sstevel@tonic-gate 		struct mapfs *mfs;
1100Sstevel@tonic-gate 		trace_prt(1, "  do_mount1:\n");
1110Sstevel@tonic-gate 		for (me = mapents; me; me = me->map_next) {
1120Sstevel@tonic-gate 			trace_prt(1, "  (%s,%s)\t%s%s%s\n",
1130Sstevel@tonic-gate 			me->map_fstype ? me->map_fstype : "",
1140Sstevel@tonic-gate 			me->map_mounter ? me->map_mounter : "",
1150Sstevel@tonic-gate 			path ? path : "",
1160Sstevel@tonic-gate 			me->map_root  ? me->map_root : "",
1170Sstevel@tonic-gate 			me->map_mntpnt ? me->map_mntpnt : "");
1180Sstevel@tonic-gate 			trace_prt(0, "\t\t-%s\n",
1190Sstevel@tonic-gate 			me->map_mntopts ? me->map_mntopts : "");
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 			for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next)
1220Sstevel@tonic-gate 				trace_prt(0, "\t\t%s:%s\tpenalty=%d\n",
1230Sstevel@tonic-gate 					mfs->mfs_host ? mfs->mfs_host: "",
1240Sstevel@tonic-gate 					mfs->mfs_dir ? mfs->mfs_dir : "",
1250Sstevel@tonic-gate 					mfs->mfs_penalty);
1260Sstevel@tonic-gate 		}
1270Sstevel@tonic-gate 	}
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	*alpp = NULL;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	/*
1320Sstevel@tonic-gate 	 * Each mapent in the list describes a mount to be done.
1330Sstevel@tonic-gate 	 * Normally there's just a single entry, though in the
1340Sstevel@tonic-gate 	 * case of /net mounts there may be many entries, that
1350Sstevel@tonic-gate 	 * must be mounted as a hierarchy.  For each mount the
1360Sstevel@tonic-gate 	 * automountd must make sure the required mountpoint
1370Sstevel@tonic-gate 	 * exists and invoke the appropriate mount command for
1380Sstevel@tonic-gate 	 * the fstype.
1390Sstevel@tonic-gate 	 */
1400Sstevel@tonic-gate 	private = "";
1410Sstevel@tonic-gate 	for (me = mapents; me && !err; me = me->map_next) {
1420Sstevel@tonic-gate 		len = snprintf(mntpnt, sizeof (mntpnt), "%s%s%s", path,
1430Sstevel@tonic-gate 		    mapents->map_root, me->map_mntpnt);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 		if (len >= sizeof (mntpnt)) {
1460Sstevel@tonic-gate 			free_mapent(mapents);
1470Sstevel@tonic-gate 			return (ENAMETOOLONG);
1480Sstevel@tonic-gate 		}
1490Sstevel@tonic-gate 		/*
1500Sstevel@tonic-gate 		 * remove trailing /'s from mountpoint to avoid problems
1510Sstevel@tonic-gate 		 * stating a directory with two or more trailing slashes.
1520Sstevel@tonic-gate 		 * This will let us mount directories from machines
1530Sstevel@tonic-gate 		 * which export with two or more slashes (apollo for instance).
1540Sstevel@tonic-gate 		 */
1550Sstevel@tonic-gate 		len -= 1;
1560Sstevel@tonic-gate 		while (mntpnt[len] == '/')
1570Sstevel@tonic-gate 			mntpnt[len--] = '\0';
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 		(void) strcpy(spec_mntpnt, mntpnt);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 		if (isrestricted &&
1620Sstevel@tonic-gate 		    inherit_options(mapopts, &me->map_mntopts) != 0) {
1630Sstevel@tonic-gate 			syslog(LOG_ERR, "malloc of options failed");
1640Sstevel@tonic-gate 			free_mapent(mapents);
1650Sstevel@tonic-gate 			return (EAGAIN);
1660Sstevel@tonic-gate 		}
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 		if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) {
1690Sstevel@tonic-gate 			remove_browse_options(me->map_mntopts);
1702170Sevanl 			if (flags == DOMOUNT_KERNEL) {
1712170Sevanl 				alp = (action_list *)malloc(
1722170Sevanl 					sizeof (action_list));
1732170Sevanl 				if (alp == NULL) {
1742170Sevanl 					syslog(LOG_ERR,
1752170Sevanl 						"malloc of alp failed");
1762170Sevanl 					continue;
1772170Sevanl 				}
1782170Sevanl 				memset(alp, 0, sizeof (action_list));
1792170Sevanl 			} else
1802170Sevanl 				alp = NULL;
1810Sstevel@tonic-gate 			err =
1823391Ssemery 			    mount_nfs(me, spec_mntpnt, private, overlay, uid,
1832170Sevanl 				    &alp);
1840Sstevel@tonic-gate 			/*
1850Sstevel@tonic-gate 			 * We must retry if we don't have access to the
1860Sstevel@tonic-gate 			 * root file system and there are other
1870Sstevel@tonic-gate 			 * following mapents. The reason we can't
1880Sstevel@tonic-gate 			 * continue because the rest of the mapent list
1890Sstevel@tonic-gate 			 * depends on whether mount_access is TRUE or FALSE.
1900Sstevel@tonic-gate 			 */
1910Sstevel@tonic-gate 			if (err == NFSERR_ACCES && me->map_next != NULL) {
1920Sstevel@tonic-gate 				/*
1930Sstevel@tonic-gate 				 * don't expect mount_access to be
1940Sstevel@tonic-gate 				 * FALSE here, but we do a check
1950Sstevel@tonic-gate 				 * anyway.
1960Sstevel@tonic-gate 				 */
1970Sstevel@tonic-gate 				if (mount_access == TRUE) {
1980Sstevel@tonic-gate 					mount_access = FALSE;
1990Sstevel@tonic-gate 					err = 0;
2000Sstevel@tonic-gate 					free_mapent(mapents);
2012170Sevanl 					if (alp) {
2022170Sevanl 						free(alp);
2032170Sevanl 						alp = NULL;
2042170Sevanl 					}
2050Sstevel@tonic-gate 					goto retry;
2060Sstevel@tonic-gate 				}
2070Sstevel@tonic-gate 			}
2082170Sevanl 			if (alp) {
2092170Sevanl 				if (*alpp == NULL)
2102170Sevanl 					*alpp = alp;
2112170Sevanl 				else {
2122170Sevanl 					for (tmp = *alpp; tmp != NULL;
2132170Sevanl 						tmp = tmp->next)
2142170Sevanl 						prev = tmp;
2152170Sevanl 					prev->next = alp;
2162170Sevanl 				}
2172170Sevanl 			}
2180Sstevel@tonic-gate 			mount_ok = !err;
2190Sstevel@tonic-gate 		} else if (strcmp(me->map_fstype, MNTTYPE_AUTOFS) == 0) {
2200Sstevel@tonic-gate 			if (isdirect) {
2210Sstevel@tonic-gate 				len = strlcpy(root, path, sizeof (root));
2220Sstevel@tonic-gate 			} else {
2230Sstevel@tonic-gate 				len = snprintf(root, sizeof (root), "%s/%s",
2240Sstevel@tonic-gate 				    path, key);
2250Sstevel@tonic-gate 			}
2260Sstevel@tonic-gate 			if (len >= sizeof (root)) {
2270Sstevel@tonic-gate 				free_mapent(mapents);
2280Sstevel@tonic-gate 				return (ENAMETOOLONG);
2290Sstevel@tonic-gate 			}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 			alp = (action_list *)malloc(sizeof (action_list));
2320Sstevel@tonic-gate 			if (alp == NULL) {
2330Sstevel@tonic-gate 				syslog(LOG_ERR, "malloc of alp failed");
2340Sstevel@tonic-gate 				continue;
2350Sstevel@tonic-gate 			}
2360Sstevel@tonic-gate 			memset(alp, 0, sizeof (action_list));
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 			/*
2390Sstevel@tonic-gate 			 * get the next subidr, but only if its a modified
2400Sstevel@tonic-gate 			 * or faked autofs mount
2410Sstevel@tonic-gate 			 */
2420Sstevel@tonic-gate 			if (me->map_modified || me->map_faked) {
2430Sstevel@tonic-gate 				len = snprintf(next_subdir,
2440Sstevel@tonic-gate 					sizeof (next_subdir), "%s%s", subdir,
2450Sstevel@tonic-gate 					me->map_mntpnt);
2460Sstevel@tonic-gate 			} else {
2470Sstevel@tonic-gate 				next_subdir[0] = '\0';
2480Sstevel@tonic-gate 				len = 0;
2490Sstevel@tonic-gate 			}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 			if (trace > 2)
2520Sstevel@tonic-gate 				trace_prt(1, "  root=%s\t next_subdir=%s\n",
2530Sstevel@tonic-gate 						root, next_subdir);
2540Sstevel@tonic-gate 			if (len < sizeof (next_subdir)) {
2550Sstevel@tonic-gate 				err = mount_autofs(me, spec_mntpnt, alp,
2560Sstevel@tonic-gate 					root, next_subdir, key);
2570Sstevel@tonic-gate 			} else {
2580Sstevel@tonic-gate 				err = ENAMETOOLONG;
2590Sstevel@tonic-gate 			}
2600Sstevel@tonic-gate 			if (err == 0) {
2610Sstevel@tonic-gate 				/*
2620Sstevel@tonic-gate 				 * append to action list
2630Sstevel@tonic-gate 				 */
2640Sstevel@tonic-gate 				mount_ok++;
2650Sstevel@tonic-gate 				if (*alpp == NULL)
2660Sstevel@tonic-gate 					*alpp = alp;
2670Sstevel@tonic-gate 				else {
2680Sstevel@tonic-gate 					for (tmp = *alpp; tmp != NULL;
2690Sstevel@tonic-gate 					    tmp = tmp->next)
2700Sstevel@tonic-gate 						prev = tmp;
2710Sstevel@tonic-gate 					prev->next = alp;
2720Sstevel@tonic-gate 				}
2730Sstevel@tonic-gate 			} else {
2740Sstevel@tonic-gate 				free(alp);
2750Sstevel@tonic-gate 				mount_ok = 0;
2760Sstevel@tonic-gate 			}
2770Sstevel@tonic-gate 		} else if (strcmp(me->map_fstype, MNTTYPE_LOFS) == 0) {
2780Sstevel@tonic-gate 			remove_browse_options(me->map_mntopts);
2790Sstevel@tonic-gate 			err = loopbackmount(me->map_fs->mfs_dir, spec_mntpnt,
2800Sstevel@tonic-gate 					    me->map_mntopts, overlay);
2810Sstevel@tonic-gate 			mount_ok = !err;
2820Sstevel@tonic-gate 		} else {
2830Sstevel@tonic-gate 			remove_browse_options(me->map_mntopts);
2840Sstevel@tonic-gate 			err = mount_generic(me->map_fs->mfs_dir,
2850Sstevel@tonic-gate 					    me->map_fstype, me->map_mntopts,
2860Sstevel@tonic-gate 					    spec_mntpnt, overlay);
2870Sstevel@tonic-gate 			mount_ok = !err;
2880Sstevel@tonic-gate 		}
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 	if (mapents)
2910Sstevel@tonic-gate 		free_mapent(mapents);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	/*
2940Sstevel@tonic-gate 	 * If an error occurred,
2950Sstevel@tonic-gate 	 * the filesystem doesn't exist, or could not be
2960Sstevel@tonic-gate 	 * mounted.  Return EACCES to autofs indicating that
2970Sstevel@tonic-gate 	 * the mountpoint can not be accessed if this is not
2980Sstevel@tonic-gate 	 * a wildcard access.  If it is a wildcard access we
2990Sstevel@tonic-gate 	 * return ENOENT since the lookup that triggered
3000Sstevel@tonic-gate 	 * this mount request will fail and the entry will not
3010Sstevel@tonic-gate 	 * be available.
3020Sstevel@tonic-gate 	 */
3030Sstevel@tonic-gate 	if (mount_ok) {
3040Sstevel@tonic-gate 		/*
3050Sstevel@tonic-gate 		 * No error occurred, return 0 to indicate success.
3060Sstevel@tonic-gate 		 */
3070Sstevel@tonic-gate 		err = 0;
3080Sstevel@tonic-gate 	} else {
3090Sstevel@tonic-gate 		/*
3100Sstevel@tonic-gate 		 * The filesystem does not exist or could not be mounted.
3110Sstevel@tonic-gate 		 * Return ENOENT if the lookup was triggered by a wildcard
3120Sstevel@tonic-gate 		 * access.  Wildcard entries only exist if they can be
3130Sstevel@tonic-gate 		 * mounted.  They can not be listed otherwise (through
3140Sstevel@tonic-gate 		 * a readdir(2)).
3150Sstevel@tonic-gate 		 * Return EACCES if the lookup was not triggered by a
3160Sstevel@tonic-gate 		 * wildcard access.  Map entries that are explicitly defined
3170Sstevel@tonic-gate 		 * in maps are visible via readdir(2), therefore we return
3180Sstevel@tonic-gate 		 * EACCES to indicate that the entry exists, but the directory
3190Sstevel@tonic-gate 		 * can not be opened.  This is the same behavior of a Unix
3200Sstevel@tonic-gate 		 * directory that exists, but has its execute bit turned off.
3210Sstevel@tonic-gate 		 * The directory is there, but the user does not have access
3220Sstevel@tonic-gate 		 * to it.
3230Sstevel@tonic-gate 		 */
3240Sstevel@tonic-gate 		if (iswildcard)
3250Sstevel@tonic-gate 			err = ENOENT;
3260Sstevel@tonic-gate 		else
3270Sstevel@tonic-gate 			err = EACCES;
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 	return (err);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate #define	ARGV_MAX	16
3330Sstevel@tonic-gate #define	VFS_PATH	"/usr/lib/fs"
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate int
mount_generic(special,fstype,opts,mntpnt,overlay)3360Sstevel@tonic-gate mount_generic(special, fstype, opts, mntpnt, overlay)
3370Sstevel@tonic-gate 	char *special, *fstype, *opts, *mntpnt;
3380Sstevel@tonic-gate 	int overlay;
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 	struct mnttab m;
3410Sstevel@tonic-gate 	struct stat stbuf;
3420Sstevel@tonic-gate 	int i, res;
3430Sstevel@tonic-gate 	char *newargv[ARGV_MAX];
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	if (trace > 1) {
3460Sstevel@tonic-gate 		trace_prt(1, "  mount: %s %s %s %s\n",
3470Sstevel@tonic-gate 			special, mntpnt, fstype, opts);
3480Sstevel@tonic-gate 	}
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	if (stat(mntpnt, &stbuf) < 0) {
3510Sstevel@tonic-gate 		syslog(LOG_ERR, "Couldn't stat %s: %m", mntpnt);
3520Sstevel@tonic-gate 		return (ENOENT);
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	i = 2;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	if (overlay)
3580Sstevel@tonic-gate 		newargv[i++] = "-O";
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/*
3610Sstevel@tonic-gate 	 *  Use "quiet" option to suppress warnings about unsupported
3620Sstevel@tonic-gate 	 *  mount options.
3630Sstevel@tonic-gate 	 */
3640Sstevel@tonic-gate 	newargv[i++] = "-q";
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	if (opts && *opts) {
3670Sstevel@tonic-gate 		m.mnt_mntopts = opts;
3680Sstevel@tonic-gate 		if (hasmntopt(&m, MNTOPT_RO) != NULL)
3690Sstevel@tonic-gate 			newargv[i++] = "-r";
3700Sstevel@tonic-gate 		newargv[i++] = "-o";
3710Sstevel@tonic-gate 		newargv[i++] = opts;
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 	newargv[i++] = "--";
3740Sstevel@tonic-gate 	newargv[i++] = special;
3750Sstevel@tonic-gate 	newargv[i++] = mntpnt;
3760Sstevel@tonic-gate 	newargv[i] = NULL;
377*3930Snr123932 	res = call_fork_exec(fstype, "mount", newargv, verbose);
3780Sstevel@tonic-gate 	if (res == 0 && trace > 1) {
3790Sstevel@tonic-gate 		if (stat(mntpnt, &stbuf) == 0) {
3800Sstevel@tonic-gate 			trace_prt(1, "  mount of %s dev=%x rdev=%x OK\n",
3810Sstevel@tonic-gate 				mntpnt, stbuf.st_dev, stbuf.st_rdev);
3820Sstevel@tonic-gate 		} else {
3830Sstevel@tonic-gate 			trace_prt(1, "  failed to stat %s\n", mntpnt);
3840Sstevel@tonic-gate 		}
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 	return (res);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate 
389*3930Snr123932 void
automountd_do_fork_exec(void * cookie,char * argp,size_t arg_size,door_desc_t * dfd,uint_t n_desc)390*3930Snr123932 automountd_do_fork_exec(void *cookie, char *argp, size_t arg_size,
391*3930Snr123932 		door_desc_t *dfd, uint_t n_desc)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	int stat_loc;
3940Sstevel@tonic-gate 	int fd = 0;
3950Sstevel@tonic-gate 	struct stat stbuf;
3960Sstevel@tonic-gate 	int res;
3970Sstevel@tonic-gate 	int child_pid;
398*3930Snr123932 	command_t *command;
399*3930Snr123932 	char *newargv[ARGV_MAX];
400*3930Snr123932 	int i;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 
403*3930Snr123932 	command = (command_t *)argp;
404*3930Snr123932 	if (sizeof (*command) != arg_size) {
405*3930Snr123932 		res = EINVAL;
406*3930Snr123932 		door_return((char *)&res, sizeof (res), NULL, 0);
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	switch ((child_pid = fork1())) {
4100Sstevel@tonic-gate 	case -1:
4110Sstevel@tonic-gate 		syslog(LOG_ERR, "Cannot fork: %m");
412*3930Snr123932 		res = errno;
413*3930Snr123932 		break;
4140Sstevel@tonic-gate 	case 0:
4150Sstevel@tonic-gate 		/*
4160Sstevel@tonic-gate 		 * Child
4170Sstevel@tonic-gate 		 */
4180Sstevel@tonic-gate 		(void) setsid();
419*3930Snr123932 		fd = open(command->console ? "/dev/console" : "/dev/null",
420*3930Snr123932 			    O_WRONLY);
4210Sstevel@tonic-gate 		if (fd != -1) {
4220Sstevel@tonic-gate 			(void) dup2(fd, 1);
4230Sstevel@tonic-gate 			(void) dup2(fd, 2);
4240Sstevel@tonic-gate 			(void) close(fd);
4250Sstevel@tonic-gate 		}
4260Sstevel@tonic-gate 
427*3930Snr123932 		for (i = 0; *command->argv[i]; i++) {
428*3930Snr123932 			newargv[i] = strdup(command->argv[i]);
429*3930Snr123932 			if (newargv[i] == (char *)NULL) {
430*3930Snr123932 				syslog(LOG_ERR, "failed to copy argument '%s'"
431*3930Snr123932 				    " of %s: %m", command->argv[i],
432*3930Snr123932 				    command->file);
433*3930Snr123932 				_exit(errno);
434*3930Snr123932 			}
435*3930Snr123932 		}
436*3930Snr123932 		newargv[i] = NULL;
437*3930Snr123932 
438*3930Snr123932 		(void) execv(command->file, newargv);
4390Sstevel@tonic-gate 		if (errno == EACCES)
440*3930Snr123932 			syslog(LOG_ERR, "exec %s: %m", command->file);
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 		_exit(errno);
4430Sstevel@tonic-gate 	default:
4440Sstevel@tonic-gate 		/*
4450Sstevel@tonic-gate 		 * Parent
4460Sstevel@tonic-gate 		 */
4470Sstevel@tonic-gate 		(void) waitpid(child_pid, &stat_loc, WUNTRACED);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 		if (WIFEXITED(stat_loc)) {
4500Sstevel@tonic-gate 			if (trace > 1) {
4510Sstevel@tonic-gate 				trace_prt(1,
4520Sstevel@tonic-gate 				    "  fork_exec: returns exit status %d\n",
4530Sstevel@tonic-gate 				    WEXITSTATUS(stat_loc));
4540Sstevel@tonic-gate 			}
4550Sstevel@tonic-gate 
456*3930Snr123932 			res = WEXITSTATUS(stat_loc);
457*3930Snr123932 		} else if (WIFSIGNALED(stat_loc)) {
458*3930Snr123932 			if (trace > 1)
4590Sstevel@tonic-gate 				trace_prt(1,
4600Sstevel@tonic-gate 				    "  fork_exec: returns signal status %d\n",
4610Sstevel@tonic-gate 				    WTERMSIG(stat_loc));
462*3930Snr123932 			res = 1;
4630Sstevel@tonic-gate 		} else {
4640Sstevel@tonic-gate 			if (trace > 1)
4650Sstevel@tonic-gate 				trace_prt(1,
4660Sstevel@tonic-gate 				    "  fork_exec: returns unknown status\n");
467*3930Snr123932 			res = 1;
4680Sstevel@tonic-gate 		}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	}
471*3930Snr123932 	door_return((char *)&res, sizeof (res), NULL, 0);
472*3930Snr123932 	trace_prt(1, "automountd_do_fork_exec, door return failed %s, %s\n",
473*3930Snr123932 	    command->file, strerror(errno));
474*3930Snr123932 	door_return(NULL, 0, NULL, 0);
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate int
do_unmount1(ur)4780Sstevel@tonic-gate do_unmount1(ur)
4790Sstevel@tonic-gate 	umntrequest *ur;
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	struct mnttab m;
4830Sstevel@tonic-gate 	int res = 0;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	m.mnt_special = ur->mntresource;
4860Sstevel@tonic-gate 	m.mnt_mountp = ur->mntpnt;
4870Sstevel@tonic-gate 	m.mnt_fstype = ur->fstype;
4880Sstevel@tonic-gate 	m.mnt_mntopts = ur->mntopts;
4890Sstevel@tonic-gate 	/*
4900Sstevel@tonic-gate 	 * Special case for NFS mounts.
4910Sstevel@tonic-gate 	 * Don't want to attempt unmounts from
4920Sstevel@tonic-gate 	 * a dead server.  If any member of a
4930Sstevel@tonic-gate 	 * hierarchy belongs to a dead server
4940Sstevel@tonic-gate 	 * give up (try later).
4950Sstevel@tonic-gate 	 */
4960Sstevel@tonic-gate 	if (strcmp(ur->fstype, MNTTYPE_NFS) == 0) {
4970Sstevel@tonic-gate 		struct replica *list;
4980Sstevel@tonic-gate 		int i, n;
4990Sstevel@tonic-gate 		bool_t pubopt = FALSE;
5000Sstevel@tonic-gate 		int nfs_port;
5010Sstevel@tonic-gate 		int got_port;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 		/*
5040Sstevel@tonic-gate 		 * See if a port number was specified.  If one was
5050Sstevel@tonic-gate 		 * specified that is too large to fit in 16 bits, truncate
5060Sstevel@tonic-gate 		 * the high-order bits (for historical compatibility).  Use
5070Sstevel@tonic-gate 		 * zero to indicate "no port specified".
5080Sstevel@tonic-gate 		 */
5090Sstevel@tonic-gate 		got_port = nopt(&m, MNTOPT_PORT, &nfs_port);
5100Sstevel@tonic-gate 		if (!got_port)
5110Sstevel@tonic-gate 			nfs_port = 0;
5120Sstevel@tonic-gate 		nfs_port &= USHRT_MAX;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 		if (hasmntopt(&m, MNTOPT_PUBLIC))
5150Sstevel@tonic-gate 			pubopt = TRUE;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		list = parse_replica(ur->mntresource, &n);
5180Sstevel@tonic-gate 		if (list == NULL) {
5190Sstevel@tonic-gate 			if (n >= 0)
5200Sstevel@tonic-gate 				syslog(LOG_ERR, "Memory allocation failed: %m");
5210Sstevel@tonic-gate 			res = 1;
5220Sstevel@tonic-gate 			goto done;
5230Sstevel@tonic-gate 		}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		for (i = 0; i < n; i++) {
5260Sstevel@tonic-gate 			if (pingnfs(list[i].host, 1, NULL, 0, nfs_port,
5270Sstevel@tonic-gate 			    pubopt, list[i].path, NULL) != RPC_SUCCESS) {
5280Sstevel@tonic-gate 				res = 1;
5290Sstevel@tonic-gate 				free_replica(list, n);
5300Sstevel@tonic-gate 				goto done;
5310Sstevel@tonic-gate 			}
5320Sstevel@tonic-gate 		}
5330Sstevel@tonic-gate 		free_replica(list, n);
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	res = unmount_mntpnt(&m);
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate done:	return (res);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate static int
unmount_mntpnt(mnt)5420Sstevel@tonic-gate unmount_mntpnt(mnt)
5430Sstevel@tonic-gate 	struct mnttab *mnt;
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate 	char *fstype = mnt->mnt_fstype;
5460Sstevel@tonic-gate 	char *mountp = mnt->mnt_mountp;
5470Sstevel@tonic-gate 	char *newargv[ARGV_MAX];
5480Sstevel@tonic-gate 	int res;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	if (strcmp(fstype, MNTTYPE_NFS) == 0) {
5510Sstevel@tonic-gate 		res = nfsunmount(mnt);
5520Sstevel@tonic-gate 	} else if (strcmp(fstype, MNTTYPE_LOFS) == 0) {
5530Sstevel@tonic-gate 		if ((res = umount(mountp)) < 0)
5540Sstevel@tonic-gate 			res = errno;
5550Sstevel@tonic-gate 	} else {
5560Sstevel@tonic-gate 		newargv[2] = mountp;
5570Sstevel@tonic-gate 		newargv[3] = NULL;
5580Sstevel@tonic-gate 
559*3930Snr123932 		res = call_fork_exec(fstype, "umount", newargv, verbose);
5600Sstevel@tonic-gate 		if (res == ENOENT) {
5610Sstevel@tonic-gate 			/*
5620Sstevel@tonic-gate 			 * filesystem specific unmount command not found
5630Sstevel@tonic-gate 			 */
5640Sstevel@tonic-gate 			if ((res = umount(mountp)) < 0)
5650Sstevel@tonic-gate 				res = errno;
5660Sstevel@tonic-gate 		}
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	if (trace > 1)
5700Sstevel@tonic-gate 		trace_prt(1, "  unmount %s %s\n",
5710Sstevel@tonic-gate 			mountp, res ? "failed" : "OK");
5720Sstevel@tonic-gate 	return (res);
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate /*
5760Sstevel@tonic-gate  * Remove the autofs specific options 'browse', 'nobrowse' and
5770Sstevel@tonic-gate  * 'restrict' from 'opts'.
5780Sstevel@tonic-gate  */
5790Sstevel@tonic-gate static void
remove_browse_options(char * opts)5800Sstevel@tonic-gate remove_browse_options(char *opts)
5810Sstevel@tonic-gate {
5820Sstevel@tonic-gate 	char *p, *pb;
5830Sstevel@tonic-gate 	char buf[MAXOPTSLEN], new[MAXOPTSLEN];
5840Sstevel@tonic-gate 	char *placeholder;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	new[0] = '\0';
5870Sstevel@tonic-gate 	(void) strcpy(buf, opts);
5880Sstevel@tonic-gate 	pb = buf;
5890Sstevel@tonic-gate 	while (p = (char *)strtok_r(pb, ",", &placeholder)) {
5900Sstevel@tonic-gate 		pb = NULL;
5910Sstevel@tonic-gate 		if (strcmp(p, MNTOPT_NOBROWSE) != 0 &&
5920Sstevel@tonic-gate 		    strcmp(p, MNTOPT_BROWSE) != 0 &&
5930Sstevel@tonic-gate 		    strcmp(p, MNTOPT_RESTRICT) != 0) {
5940Sstevel@tonic-gate 			if (new[0] != '\0')
5950Sstevel@tonic-gate 				(void) strcat(new, ",");
5960Sstevel@tonic-gate 			(void) strcat(new, p);
5970Sstevel@tonic-gate 		}
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 	(void) strcpy(opts, new);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate static const char *restropts[] = {
6030Sstevel@tonic-gate 	RESTRICTED_MNTOPTS
6040Sstevel@tonic-gate };
6050Sstevel@tonic-gate #define	NROPTS	(sizeof (restropts)/sizeof (restropts[0]))
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate static int
inherit_options(char * opts,char ** mapentopts)6080Sstevel@tonic-gate inherit_options(char *opts, char **mapentopts)
6090Sstevel@tonic-gate {
6100Sstevel@tonic-gate 	int i;
6110Sstevel@tonic-gate 	char *new;
6120Sstevel@tonic-gate 	struct mnttab mtmap;
6130Sstevel@tonic-gate 	struct mnttab mtopt;
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	size_t len = strlen(*mapentopts);
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	for (i = 0; i < NROPTS; i++)
6180Sstevel@tonic-gate 		len += strlen(restropts[i]);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	/* "," for each new option plus the trailing NUL */
6210Sstevel@tonic-gate 	len += NROPTS + 1;
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	new = malloc(len);
6240Sstevel@tonic-gate 	if (new == 0)
6250Sstevel@tonic-gate 		return (-1);
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	(void) strcpy(new, *mapentopts);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	mtmap.mnt_mntopts = *mapentopts;
6300Sstevel@tonic-gate 	mtopt.mnt_mntopts = opts;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	for (i = 0; i < NROPTS; i++) {
6330Sstevel@tonic-gate 		if (hasmntopt(&mtopt, (char *)restropts[i]) != NULL &&
6340Sstevel@tonic-gate 		    hasmntopt(&mtmap, (char *)restropts[i]) == NULL) {
6350Sstevel@tonic-gate 			if (*new != '\0')
6360Sstevel@tonic-gate 				(void) strcat(new, ",");
6370Sstevel@tonic-gate 			(void) strcat(new, restropts[i]);
6380Sstevel@tonic-gate 		}
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 	free(*mapentopts);
6410Sstevel@tonic-gate 	*mapentopts = new;
6420Sstevel@tonic-gate 	return (0);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate bool_t
hasrestrictopt(char * opts)6460Sstevel@tonic-gate hasrestrictopt(char *opts)
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate 	struct mnttab mt;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	mt.mnt_mntopts = opts;
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	return (hasmntopt(&mt, MNTOPT_RESTRICT) != NULL);
6530Sstevel@tonic-gate }
654*3930Snr123932 
655*3930Snr123932 static int
call_fork_exec(fstype,cmd,newargv,console)656*3930Snr123932 call_fork_exec(fstype, cmd, newargv, console)
657*3930Snr123932 	char *fstype;
658*3930Snr123932 	char *cmd;
659*3930Snr123932 	char **newargv;
660*3930Snr123932 	int console;
661*3930Snr123932 {
662*3930Snr123932 	command_t command;
663*3930Snr123932 	door_arg_t darg;
664*3930Snr123932 	char path[MAXPATHLEN];
665*3930Snr123932 	struct stat stbuf;
666*3930Snr123932 	int ret;
667*3930Snr123932 	int sz;
668*3930Snr123932 	int status;
669*3930Snr123932 	int i;
670*3930Snr123932 
671*3930Snr123932 	bzero(&command, sizeof (command));
672*3930Snr123932 	/* build the full path name of the fstype dependent command */
673*3930Snr123932 	(void) snprintf(path, MAXPATHLEN, "%s/%s/%s", VFS_PATH, fstype, cmd);
674*3930Snr123932 
675*3930Snr123932 	if (stat(path, &stbuf) != 0) {
676*3930Snr123932 		ret = errno;
677*3930Snr123932 		return (ret);
678*3930Snr123932 	}
679*3930Snr123932 
680*3930Snr123932 	strlcpy(command.file, path, MAXPATHLEN);
681*3930Snr123932 	strlcpy(command.argv[0], path, MAXOPTSLEN);
682*3930Snr123932 	for (i = 2; newargv[i]; i++) {
683*3930Snr123932 		strlcpy(command.argv[i-1], newargv[i], MAXOPTSLEN);
684*3930Snr123932 	}
685*3930Snr123932 	if (trace > 1) {
686*3930Snr123932 		trace_prt(1, "  call_fork_exec: %s ", command.file);
687*3930Snr123932 		for (i = 0; *command.argv[i]; i++)
688*3930Snr123932 			trace_prt(0, "%s ", command.argv[i]);
689*3930Snr123932 		trace_prt(0, "\n");
690*3930Snr123932 	}
691*3930Snr123932 
692*3930Snr123932 	command.console = console;
693*3930Snr123932 
694*3930Snr123932 	darg.data_ptr = (char *)&command;
695*3930Snr123932 	darg.data_size = sizeof (command);
696*3930Snr123932 	darg.desc_ptr = NULL;
697*3930Snr123932 	darg.desc_num = 0;
698*3930Snr123932 	darg.rbuf = (char *)&status;
699*3930Snr123932 	darg.rsize = sizeof (status);
700*3930Snr123932 
701*3930Snr123932 	ret = door_call(did_fork_exec, &darg);
702*3930Snr123932 	if (trace > 1) {
703*3930Snr123932 		trace_prt(1, "  call_fork_exec: door_call failed %d\n", ret);
704*3930Snr123932 	}
705*3930Snr123932 
706*3930Snr123932 	return (status);
707*3930Snr123932 }
708