17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
539d3e169Sevanl  * Common Development and Distribution License (the "License").
639d3e169Sevanl  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  *	autod_mount.c
237c478bd9Sstevel@tonic-gate  *
243bfb48feSsemery  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <syslog.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <pwd.h>
377c478bd9Sstevel@tonic-gate #include <netinet/in.h>
387c478bd9Sstevel@tonic-gate #include <netdb.h>
397c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
407c478bd9Sstevel@tonic-gate #include <locale.h>
417c478bd9Sstevel@tonic-gate #include <stdlib.h>
427c478bd9Sstevel@tonic-gate #include <unistd.h>
437c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
447c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
457c478bd9Sstevel@tonic-gate #include <sys/wait.h>
467c478bd9Sstevel@tonic-gate #include <sys/mount.h>
477c478bd9Sstevel@tonic-gate #include <sys/fs/autofs.h>
487c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
497c478bd9Sstevel@tonic-gate #include <thread.h>
507c478bd9Sstevel@tonic-gate #include <limits.h>
517c478bd9Sstevel@tonic-gate #include <assert.h>
527c478bd9Sstevel@tonic-gate #include <fcntl.h>
53*8548bf79Snr #include <strings.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include "automount.h"
567c478bd9Sstevel@tonic-gate #include "replica.h"
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static int unmount_mntpnt(struct mnttab *);
59*8548bf79Snr static int call_fork_exec(char *, char *, char **, int);
607c478bd9Sstevel@tonic-gate static void remove_browse_options(char *);
617c478bd9Sstevel@tonic-gate static int inherit_options(char *, char **);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@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)6439d3e169Sevanl do_mount1(
6539d3e169Sevanl 	char *mapname,
6639d3e169Sevanl 	char *key,
6739d3e169Sevanl 	char *subdir,
6839d3e169Sevanl 	char *mapopts,
6939d3e169Sevanl 	char *path,
7039d3e169Sevanl 	uint_t isdirect,
713bfb48feSsemery 	uid_t uid,
7239d3e169Sevanl 	action_list **alpp,
7339d3e169Sevanl 	int flags)
747c478bd9Sstevel@tonic-gate {
757c478bd9Sstevel@tonic-gate 	struct mapline ml;
767c478bd9Sstevel@tonic-gate 	struct mapent *me, *mapents = NULL;
777c478bd9Sstevel@tonic-gate 	char mntpnt[MAXPATHLEN];
787c478bd9Sstevel@tonic-gate 	char spec_mntpnt[MAXPATHLEN];
797c478bd9Sstevel@tonic-gate 	int err = 0;
807c478bd9Sstevel@tonic-gate 	char *private;	/* fs specific data. eg prevhost in case of nfs */
817c478bd9Sstevel@tonic-gate 	int mount_ok = 0;
827c478bd9Sstevel@tonic-gate 	ssize_t len;
837c478bd9Sstevel@tonic-gate 	action_list *alp, *prev, *tmp;
847c478bd9Sstevel@tonic-gate 	char root[MAXPATHLEN];
857c478bd9Sstevel@tonic-gate 	int overlay = 1;
867c478bd9Sstevel@tonic-gate 	char next_subdir[MAXPATHLEN];
877c478bd9Sstevel@tonic-gate 	bool_t mount_access = TRUE;
887c478bd9Sstevel@tonic-gate 	bool_t iswildcard;
897c478bd9Sstevel@tonic-gate 	bool_t isrestricted = hasrestrictopt(mapopts);
907c478bd9Sstevel@tonic-gate 	char *stack[STACKSIZ];
917c478bd9Sstevel@tonic-gate 	char **stkptr = stack;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate retry:
947c478bd9Sstevel@tonic-gate 	iswildcard = FALSE;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	/* initialize the stack of open files for this thread */
977c478bd9Sstevel@tonic-gate 	stack_op(INIT, NULL, stack, &stkptr);
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	err = getmapent(key, mapname, &ml, stack, &stkptr, &iswildcard,
1007c478bd9Sstevel@tonic-gate 		isrestricted);
1017c478bd9Sstevel@tonic-gate 	if (err == 0) {
1027c478bd9Sstevel@tonic-gate 		mapents = parse_entry(key, mapname, mapopts, &ml,
1037c478bd9Sstevel@tonic-gate 				    subdir, isdirect, mount_access);
1047c478bd9Sstevel@tonic-gate 	}
1057c478bd9Sstevel@tonic-gate 
10639d3e169Sevanl 	if (trace) {
1077c478bd9Sstevel@tonic-gate 		struct mapfs *mfs;
1087c478bd9Sstevel@tonic-gate 		trace_prt(1, "  do_mount1:\n");
1097c478bd9Sstevel@tonic-gate 		for (me = mapents; me; me = me->map_next) {
1107c478bd9Sstevel@tonic-gate 			trace_prt(1, "  (%s,%s)\t%s%s%s\n",
1117c478bd9Sstevel@tonic-gate 			me->map_fstype ? me->map_fstype : "",
1127c478bd9Sstevel@tonic-gate 			me->map_mounter ? me->map_mounter : "",
1137c478bd9Sstevel@tonic-gate 			path ? path : "",
1147c478bd9Sstevel@tonic-gate 			me->map_root  ? me->map_root : "",
1157c478bd9Sstevel@tonic-gate 			me->map_mntpnt ? me->map_mntpnt : "");
1167c478bd9Sstevel@tonic-gate 			trace_prt(0, "\t\t-%s\n",
1177c478bd9Sstevel@tonic-gate 			me->map_mntopts ? me->map_mntopts : "");
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 			for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next)
1207c478bd9Sstevel@tonic-gate 				trace_prt(0, "\t\t%s:%s\tpenalty=%d\n",
1217c478bd9Sstevel@tonic-gate 					mfs->mfs_host ? mfs->mfs_host: "",
1227c478bd9Sstevel@tonic-gate 					mfs->mfs_dir ? mfs->mfs_dir : "",
1237c478bd9Sstevel@tonic-gate 					mfs->mfs_penalty);
1247c478bd9Sstevel@tonic-gate 		}
1257c478bd9Sstevel@tonic-gate 	}
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	*alpp = NULL;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	/*
1307c478bd9Sstevel@tonic-gate 	 * Each mapent in the list describes a mount to be done.
1317c478bd9Sstevel@tonic-gate 	 * Normally there's just a single entry, though in the
1327c478bd9Sstevel@tonic-gate 	 * case of /net mounts there may be many entries, that
1337c478bd9Sstevel@tonic-gate 	 * must be mounted as a hierarchy.  For each mount the
1347c478bd9Sstevel@tonic-gate 	 * automountd must make sure the required mountpoint
1357c478bd9Sstevel@tonic-gate 	 * exists and invoke the appropriate mount command for
1367c478bd9Sstevel@tonic-gate 	 * the fstype.
1377c478bd9Sstevel@tonic-gate 	 */
1387c478bd9Sstevel@tonic-gate 	private = "";
1397c478bd9Sstevel@tonic-gate 	for (me = mapents; me && !err; me = me->map_next) {
1407c478bd9Sstevel@tonic-gate 		len = snprintf(mntpnt, sizeof (mntpnt), "%s%s%s", path,
1417c478bd9Sstevel@tonic-gate 		    mapents->map_root, me->map_mntpnt);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 		if (len >= sizeof (mntpnt)) {
1447c478bd9Sstevel@tonic-gate 			free_mapent(mapents);
1457c478bd9Sstevel@tonic-gate 			return (ENAMETOOLONG);
1467c478bd9Sstevel@tonic-gate 		}
1477c478bd9Sstevel@tonic-gate 		/*
1487c478bd9Sstevel@tonic-gate 		 * remove trailing /'s from mountpoint to avoid problems
1497c478bd9Sstevel@tonic-gate 		 * stating a directory with two or more trailing slashes.
1507c478bd9Sstevel@tonic-gate 		 * This will let us mount directories from machines
1517c478bd9Sstevel@tonic-gate 		 * which export with two or more slashes (apollo for instance).
1527c478bd9Sstevel@tonic-gate 		 */
1537c478bd9Sstevel@tonic-gate 		len -= 1;
1547c478bd9Sstevel@tonic-gate 		while (mntpnt[len] == '/')
1557c478bd9Sstevel@tonic-gate 			mntpnt[len--] = '\0';
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 		(void) strcpy(spec_mntpnt, mntpnt);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 		if (isrestricted &&
1607c478bd9Sstevel@tonic-gate 		    inherit_options(mapopts, &me->map_mntopts) != 0) {
1617c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "malloc of options failed");
1627c478bd9Sstevel@tonic-gate 			free_mapent(mapents);
1637c478bd9Sstevel@tonic-gate 			return (EAGAIN);
1647c478bd9Sstevel@tonic-gate 		}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 		if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) {
1677c478bd9Sstevel@tonic-gate 			remove_browse_options(me->map_mntopts);
16839d3e169Sevanl 			if (flags == DOMOUNT_KERNEL) {
16939d3e169Sevanl 				alp = (action_list *)malloc(
17039d3e169Sevanl 					sizeof (action_list));
17139d3e169Sevanl 				if (alp == NULL) {
17239d3e169Sevanl 					syslog(LOG_ERR,
17339d3e169Sevanl 						"malloc of alp failed");
17439d3e169Sevanl 					continue;
17539d3e169Sevanl 				}
17639d3e169Sevanl 				memset(alp, 0, sizeof (action_list));
17739d3e169Sevanl 			} else
17839d3e169Sevanl 				alp = NULL;
1797c478bd9Sstevel@tonic-gate 			err =
1803bfb48feSsemery 			    mount_nfs(me, spec_mntpnt, private, overlay, uid,
18139d3e169Sevanl 				    &alp);
1827c478bd9Sstevel@tonic-gate 			/*
1837c478bd9Sstevel@tonic-gate 			 * We must retry if we don't have access to the
1847c478bd9Sstevel@tonic-gate 			 * root file system and there are other
1857c478bd9Sstevel@tonic-gate 			 * following mapents. The reason we can't
1867c478bd9Sstevel@tonic-gate 			 * continue because the rest of the mapent list
1877c478bd9Sstevel@tonic-gate 			 * depends on whether mount_access is TRUE or FALSE.
1887c478bd9Sstevel@tonic-gate 			 */
1897c478bd9Sstevel@tonic-gate 			if (err == NFSERR_ACCES && me->map_next != NULL) {
1907c478bd9Sstevel@tonic-gate 				/*
1917c478bd9Sstevel@tonic-gate 				 * don't expect mount_access to be
1927c478bd9Sstevel@tonic-gate 				 * FALSE here, but we do a check
1937c478bd9Sstevel@tonic-gate 				 * anyway.
1947c478bd9Sstevel@tonic-gate 				 */
1957c478bd9Sstevel@tonic-gate 				if (mount_access == TRUE) {
1967c478bd9Sstevel@tonic-gate 					mount_access = FALSE;
1977c478bd9Sstevel@tonic-gate 					err = 0;
1987c478bd9Sstevel@tonic-gate 					free_mapent(mapents);
19939d3e169Sevanl 					if (alp) {
20039d3e169Sevanl 						free(alp);
20139d3e169Sevanl 						alp = NULL;
20239d3e169Sevanl 					}
2037c478bd9Sstevel@tonic-gate 					goto retry;
2047c478bd9Sstevel@tonic-gate 				}
2057c478bd9Sstevel@tonic-gate 			}
20639d3e169Sevanl 			if (alp) {
20739d3e169Sevanl 				if (*alpp == NULL)
20839d3e169Sevanl 					*alpp = alp;
20939d3e169Sevanl 				else {
21039d3e169Sevanl 					for (tmp = *alpp; tmp != NULL;
21139d3e169Sevanl 						tmp = tmp->next)
21239d3e169Sevanl 						prev = tmp;
21339d3e169Sevanl 					prev->next = alp;
21439d3e169Sevanl 				}
21539d3e169Sevanl 			}
2167c478bd9Sstevel@tonic-gate 			mount_ok = !err;
2177c478bd9Sstevel@tonic-gate 		} else if (strcmp(me->map_fstype, MNTTYPE_AUTOFS) == 0) {
2187c478bd9Sstevel@tonic-gate 			if (isdirect) {
2197c478bd9Sstevel@tonic-gate 				len = strlcpy(root, path, sizeof (root));
2207c478bd9Sstevel@tonic-gate 			} else {
2217c478bd9Sstevel@tonic-gate 				len = snprintf(root, sizeof (root), "%s/%s",
2227c478bd9Sstevel@tonic-gate 				    path, key);
2237c478bd9Sstevel@tonic-gate 			}
2247c478bd9Sstevel@tonic-gate 			if (len >= sizeof (root)) {
2257c478bd9Sstevel@tonic-gate 				free_mapent(mapents);
2267c478bd9Sstevel@tonic-gate 				return (ENAMETOOLONG);
2277c478bd9Sstevel@tonic-gate 			}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 			alp = (action_list *)malloc(sizeof (action_list));
2307c478bd9Sstevel@tonic-gate 			if (alp == NULL) {
2317c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "malloc of alp failed");
2327c478bd9Sstevel@tonic-gate 				continue;
2337c478bd9Sstevel@tonic-gate 			}
2347c478bd9Sstevel@tonic-gate 			memset(alp, 0, sizeof (action_list));
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 			/*
2377c478bd9Sstevel@tonic-gate 			 * get the next subidr, but only if its a modified
2387c478bd9Sstevel@tonic-gate 			 * or faked autofs mount
2397c478bd9Sstevel@tonic-gate 			 */
2407c478bd9Sstevel@tonic-gate 			if (me->map_modified || me->map_faked) {
2417c478bd9Sstevel@tonic-gate 				len = snprintf(next_subdir,
2427c478bd9Sstevel@tonic-gate 					sizeof (next_subdir), "%s%s", subdir,
2437c478bd9Sstevel@tonic-gate 					me->map_mntpnt);
2447c478bd9Sstevel@tonic-gate 			} else {
2457c478bd9Sstevel@tonic-gate 				next_subdir[0] = '\0';
2467c478bd9Sstevel@tonic-gate 				len = 0;
2477c478bd9Sstevel@tonic-gate 			}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 			if (trace > 2)
2507c478bd9Sstevel@tonic-gate 				trace_prt(1, "  root=%s\t next_subdir=%s\n",
2517c478bd9Sstevel@tonic-gate 						root, next_subdir);
2527c478bd9Sstevel@tonic-gate 			if (len < sizeof (next_subdir)) {
2537c478bd9Sstevel@tonic-gate 				err = mount_autofs(me, spec_mntpnt, alp,
2547c478bd9Sstevel@tonic-gate 					root, next_subdir, key);
2557c478bd9Sstevel@tonic-gate 			} else {
2567c478bd9Sstevel@tonic-gate 				err = ENAMETOOLONG;
2577c478bd9Sstevel@tonic-gate 			}
2587c478bd9Sstevel@tonic-gate 			if (err == 0) {
2597c478bd9Sstevel@tonic-gate 				/*
2607c478bd9Sstevel@tonic-gate 				 * append to action list
2617c478bd9Sstevel@tonic-gate 				 */
2627c478bd9Sstevel@tonic-gate 				mount_ok++;
2637c478bd9Sstevel@tonic-gate 				if (*alpp == NULL)
2647c478bd9Sstevel@tonic-gate 					*alpp = alp;
2657c478bd9Sstevel@tonic-gate 				else {
2667c478bd9Sstevel@tonic-gate 					for (tmp = *alpp; tmp != NULL;
2677c478bd9Sstevel@tonic-gate 					    tmp = tmp->next)
2687c478bd9Sstevel@tonic-gate 						prev = tmp;
2697c478bd9Sstevel@tonic-gate 					prev->next = alp;
2707c478bd9Sstevel@tonic-gate 				}
2717c478bd9Sstevel@tonic-gate 			} else {
2727c478bd9Sstevel@tonic-gate 				free(alp);
2737c478bd9Sstevel@tonic-gate 				mount_ok = 0;
2747c478bd9Sstevel@tonic-gate 			}
2757c478bd9Sstevel@tonic-gate 		} else if (strcmp(me->map_fstype, MNTTYPE_LOFS) == 0) {
2767c478bd9Sstevel@tonic-gate 			remove_browse_options(me->map_mntopts);
2777c478bd9Sstevel@tonic-gate 			err = loopbackmount(me->map_fs->mfs_dir, spec_mntpnt,
2787c478bd9Sstevel@tonic-gate 					    me->map_mntopts, overlay);
2797c478bd9Sstevel@tonic-gate 			mount_ok = !err;
2807c478bd9Sstevel@tonic-gate 		} else {
2817c478bd9Sstevel@tonic-gate 			remove_browse_options(me->map_mntopts);
2827c478bd9Sstevel@tonic-gate 			err = mount_generic(me->map_fs->mfs_dir,
2837c478bd9Sstevel@tonic-gate 					    me->map_fstype, me->map_mntopts,
2847c478bd9Sstevel@tonic-gate 					    spec_mntpnt, overlay);
2857c478bd9Sstevel@tonic-gate 			mount_ok = !err;
2867c478bd9Sstevel@tonic-gate 		}
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 	if (mapents)
2897c478bd9Sstevel@tonic-gate 		free_mapent(mapents);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	/*
2927c478bd9Sstevel@tonic-gate 	 * If an error occurred,
2937c478bd9Sstevel@tonic-gate 	 * the filesystem doesn't exist, or could not be
2947c478bd9Sstevel@tonic-gate 	 * mounted.  Return EACCES to autofs indicating that
2957c478bd9Sstevel@tonic-gate 	 * the mountpoint can not be accessed if this is not
2967c478bd9Sstevel@tonic-gate 	 * a wildcard access.  If it is a wildcard access we
2977c478bd9Sstevel@tonic-gate 	 * return ENOENT since the lookup that triggered
2987c478bd9Sstevel@tonic-gate 	 * this mount request will fail and the entry will not
2997c478bd9Sstevel@tonic-gate 	 * be available.
3007c478bd9Sstevel@tonic-gate 	 */
3017c478bd9Sstevel@tonic-gate 	if (mount_ok) {
3027c478bd9Sstevel@tonic-gate 		/*
3037c478bd9Sstevel@tonic-gate 		 * No error occurred, return 0 to indicate success.
3047c478bd9Sstevel@tonic-gate 		 */
3057c478bd9Sstevel@tonic-gate 		err = 0;
3067c478bd9Sstevel@tonic-gate 	} else {
3077c478bd9Sstevel@tonic-gate 		/*
3087c478bd9Sstevel@tonic-gate 		 * The filesystem does not exist or could not be mounted.
3097c478bd9Sstevel@tonic-gate 		 * Return ENOENT if the lookup was triggered by a wildcard
3107c478bd9Sstevel@tonic-gate 		 * access.  Wildcard entries only exist if they can be
3117c478bd9Sstevel@tonic-gate 		 * mounted.  They can not be listed otherwise (through
3127c478bd9Sstevel@tonic-gate 		 * a readdir(2)).
3137c478bd9Sstevel@tonic-gate 		 * Return EACCES if the lookup was not triggered by a
3147c478bd9Sstevel@tonic-gate 		 * wildcard access.  Map entries that are explicitly defined
3157c478bd9Sstevel@tonic-gate 		 * in maps are visible via readdir(2), therefore we return
3167c478bd9Sstevel@tonic-gate 		 * EACCES to indicate that the entry exists, but the directory
3177c478bd9Sstevel@tonic-gate 		 * can not be opened.  This is the same behavior of a Unix
3187c478bd9Sstevel@tonic-gate 		 * directory that exists, but has its execute bit turned off.
3197c478bd9Sstevel@tonic-gate 		 * The directory is there, but the user does not have access
3207c478bd9Sstevel@tonic-gate 		 * to it.
3217c478bd9Sstevel@tonic-gate 		 */
3227c478bd9Sstevel@tonic-gate 		if (iswildcard)
3237c478bd9Sstevel@tonic-gate 			err = ENOENT;
3247c478bd9Sstevel@tonic-gate 		else
3257c478bd9Sstevel@tonic-gate 			err = EACCES;
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 	return (err);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate #define	ARGV_MAX	16
3317c478bd9Sstevel@tonic-gate #define	VFS_PATH	"/usr/lib/fs"
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate int
mount_generic(special,fstype,opts,mntpnt,overlay)3347c478bd9Sstevel@tonic-gate mount_generic(special, fstype, opts, mntpnt, overlay)
3357c478bd9Sstevel@tonic-gate 	char *special, *fstype, *opts, *mntpnt;
3367c478bd9Sstevel@tonic-gate 	int overlay;
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate 	struct mnttab m;
3397c478bd9Sstevel@tonic-gate 	struct stat stbuf;
3407c478bd9Sstevel@tonic-gate 	int i, res;
3417c478bd9Sstevel@tonic-gate 	char *newargv[ARGV_MAX];
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	if (trace > 1) {
3447c478bd9Sstevel@tonic-gate 		trace_prt(1, "  mount: %s %s %s %s\n",
3457c478bd9Sstevel@tonic-gate 			special, mntpnt, fstype, opts);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	if (stat(mntpnt, &stbuf) < 0) {
3497c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Couldn't stat %s: %m", mntpnt);
3507c478bd9Sstevel@tonic-gate 		return (ENOENT);
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	i = 2;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	if (overlay)
3567c478bd9Sstevel@tonic-gate 		newargv[i++] = "-O";
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/*
3597c478bd9Sstevel@tonic-gate 	 *  Use "quiet" option to suppress warnings about unsupported
3607c478bd9Sstevel@tonic-gate 	 *  mount options.
3617c478bd9Sstevel@tonic-gate 	 */
3627c478bd9Sstevel@tonic-gate 	newargv[i++] = "-q";
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	if (opts && *opts) {
3657c478bd9Sstevel@tonic-gate 		m.mnt_mntopts = opts;
3667c478bd9Sstevel@tonic-gate 		if (hasmntopt(&m, MNTOPT_RO) != NULL)
3677c478bd9Sstevel@tonic-gate 			newargv[i++] = "-r";
3687c478bd9Sstevel@tonic-gate 		newargv[i++] = "-o";
3697c478bd9Sstevel@tonic-gate 		newargv[i++] = opts;
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 	newargv[i++] = "--";
3727c478bd9Sstevel@tonic-gate 	newargv[i++] = special;
3737c478bd9Sstevel@tonic-gate 	newargv[i++] = mntpnt;
3747c478bd9Sstevel@tonic-gate 	newargv[i] = NULL;
375*8548bf79Snr 	res = call_fork_exec(fstype, "mount", newargv, verbose);
3767c478bd9Sstevel@tonic-gate 	if (res == 0 && trace > 1) {
3777c478bd9Sstevel@tonic-gate 		if (stat(mntpnt, &stbuf) == 0) {
3787c478bd9Sstevel@tonic-gate 			trace_prt(1, "  mount of %s dev=%x rdev=%x OK\n",
3797c478bd9Sstevel@tonic-gate 				mntpnt, stbuf.st_dev, stbuf.st_rdev);
3807c478bd9Sstevel@tonic-gate 		} else {
3817c478bd9Sstevel@tonic-gate 			trace_prt(1, "  failed to stat %s\n", mntpnt);
3827c478bd9Sstevel@tonic-gate 		}
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 	return (res);
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate 
387*8548bf79Snr void
automountd_do_fork_exec(void * cookie,char * argp,size_t arg_size,door_desc_t * dfd,uint_t n_desc)388*8548bf79Snr automountd_do_fork_exec(void *cookie, char *argp, size_t arg_size,
389*8548bf79Snr 		door_desc_t *dfd, uint_t n_desc)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	int stat_loc;
3927c478bd9Sstevel@tonic-gate 	int fd = 0;
3937c478bd9Sstevel@tonic-gate 	struct stat stbuf;
3947c478bd9Sstevel@tonic-gate 	int res;
3957c478bd9Sstevel@tonic-gate 	int child_pid;
396*8548bf79Snr 	command_t *command;
397*8548bf79Snr 	char *newargv[ARGV_MAX];
398*8548bf79Snr 	int i;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 
401*8548bf79Snr 	command = (command_t *)argp;
402*8548bf79Snr 	if (sizeof (*command) != arg_size) {
403*8548bf79Snr 		res = EINVAL;
404*8548bf79Snr 		door_return((char *)&res, sizeof (res), NULL, 0);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	switch ((child_pid = fork1())) {
4087c478bd9Sstevel@tonic-gate 	case -1:
4097c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "Cannot fork: %m");
410*8548bf79Snr 		res = errno;
411*8548bf79Snr 		break;
4127c478bd9Sstevel@tonic-gate 	case 0:
4137c478bd9Sstevel@tonic-gate 		/*
4147c478bd9Sstevel@tonic-gate 		 * Child
4157c478bd9Sstevel@tonic-gate 		 */
4167c478bd9Sstevel@tonic-gate 		(void) setsid();
417*8548bf79Snr 		fd = open(command->console ? "/dev/console" : "/dev/null",
418*8548bf79Snr 			    O_WRONLY);
4197c478bd9Sstevel@tonic-gate 		if (fd != -1) {
4207c478bd9Sstevel@tonic-gate 			(void) dup2(fd, 1);
4217c478bd9Sstevel@tonic-gate 			(void) dup2(fd, 2);
4227c478bd9Sstevel@tonic-gate 			(void) close(fd);
4237c478bd9Sstevel@tonic-gate 		}
4247c478bd9Sstevel@tonic-gate 
425*8548bf79Snr 		for (i = 0; *command->argv[i]; i++) {
426*8548bf79Snr 			newargv[i] = strdup(command->argv[i]);
427*8548bf79Snr 			if (newargv[i] == (char *)NULL) {
428*8548bf79Snr 				syslog(LOG_ERR, "failed to copy argument '%s'"
429*8548bf79Snr 				    " of %s: %m", command->argv[i],
430*8548bf79Snr 				    command->file);
431*8548bf79Snr 				_exit(errno);
432*8548bf79Snr 			}
433*8548bf79Snr 		}
434*8548bf79Snr 		newargv[i] = NULL;
435*8548bf79Snr 
436*8548bf79Snr 		(void) execv(command->file, newargv);
4377c478bd9Sstevel@tonic-gate 		if (errno == EACCES)
438*8548bf79Snr 			syslog(LOG_ERR, "exec %s: %m", command->file);
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 		_exit(errno);
4417c478bd9Sstevel@tonic-gate 	default:
4427c478bd9Sstevel@tonic-gate 		/*
4437c478bd9Sstevel@tonic-gate 		 * Parent
4447c478bd9Sstevel@tonic-gate 		 */
4457c478bd9Sstevel@tonic-gate 		(void) waitpid(child_pid, &stat_loc, WUNTRACED);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 		if (WIFEXITED(stat_loc)) {
4487c478bd9Sstevel@tonic-gate 			if (trace > 1) {
4497c478bd9Sstevel@tonic-gate 				trace_prt(1,
4507c478bd9Sstevel@tonic-gate 				    "  fork_exec: returns exit status %d\n",
4517c478bd9Sstevel@tonic-gate 				    WEXITSTATUS(stat_loc));
4527c478bd9Sstevel@tonic-gate 			}
4537c478bd9Sstevel@tonic-gate 
454*8548bf79Snr 			res = WEXITSTATUS(stat_loc);
455*8548bf79Snr 		} else if (WIFSIGNALED(stat_loc)) {
456*8548bf79Snr 			if (trace > 1)
4577c478bd9Sstevel@tonic-gate 				trace_prt(1,
4587c478bd9Sstevel@tonic-gate 				    "  fork_exec: returns signal status %d\n",
4597c478bd9Sstevel@tonic-gate 				    WTERMSIG(stat_loc));
460*8548bf79Snr 			res = 1;
4617c478bd9Sstevel@tonic-gate 		} else {
4627c478bd9Sstevel@tonic-gate 			if (trace > 1)
4637c478bd9Sstevel@tonic-gate 				trace_prt(1,
4647c478bd9Sstevel@tonic-gate 				    "  fork_exec: returns unknown status\n");
465*8548bf79Snr 			res = 1;
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	}
469*8548bf79Snr 	door_return((char *)&res, sizeof (res), NULL, 0);
470*8548bf79Snr 	trace_prt(1, "automountd_do_fork_exec, door return failed %s, %s\n",
471*8548bf79Snr 	    command->file, strerror(errno));
472*8548bf79Snr 	door_return(NULL, 0, NULL, 0);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate int
do_unmount1(ur)4767c478bd9Sstevel@tonic-gate do_unmount1(ur)
4777c478bd9Sstevel@tonic-gate 	umntrequest *ur;
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	struct mnttab m;
4817c478bd9Sstevel@tonic-gate 	int res = 0;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	m.mnt_special = ur->mntresource;
4847c478bd9Sstevel@tonic-gate 	m.mnt_mountp = ur->mntpnt;
4857c478bd9Sstevel@tonic-gate 	m.mnt_fstype = ur->fstype;
4867c478bd9Sstevel@tonic-gate 	m.mnt_mntopts = ur->mntopts;
4877c478bd9Sstevel@tonic-gate 	/*
4887c478bd9Sstevel@tonic-gate 	 * Special case for NFS mounts.
4897c478bd9Sstevel@tonic-gate 	 * Don't want to attempt unmounts from
4907c478bd9Sstevel@tonic-gate 	 * a dead server.  If any member of a
4917c478bd9Sstevel@tonic-gate 	 * hierarchy belongs to a dead server
4927c478bd9Sstevel@tonic-gate 	 * give up (try later).
4937c478bd9Sstevel@tonic-gate 	 */
4947c478bd9Sstevel@tonic-gate 	if (strcmp(ur->fstype, MNTTYPE_NFS) == 0) {
4957c478bd9Sstevel@tonic-gate 		struct replica *list;
4967c478bd9Sstevel@tonic-gate 		int i, n;
4977c478bd9Sstevel@tonic-gate 		bool_t pubopt = FALSE;
4987c478bd9Sstevel@tonic-gate 		int nfs_port;
4997c478bd9Sstevel@tonic-gate 		int got_port;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		/*
5027c478bd9Sstevel@tonic-gate 		 * See if a port number was specified.  If one was
5037c478bd9Sstevel@tonic-gate 		 * specified that is too large to fit in 16 bits, truncate
5047c478bd9Sstevel@tonic-gate 		 * the high-order bits (for historical compatibility).  Use
5057c478bd9Sstevel@tonic-gate 		 * zero to indicate "no port specified".
5067c478bd9Sstevel@tonic-gate 		 */
5077c478bd9Sstevel@tonic-gate 		got_port = nopt(&m, MNTOPT_PORT, &nfs_port);
5087c478bd9Sstevel@tonic-gate 		if (!got_port)
5097c478bd9Sstevel@tonic-gate 			nfs_port = 0;
5107c478bd9Sstevel@tonic-gate 		nfs_port &= USHRT_MAX;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		if (hasmntopt(&m, MNTOPT_PUBLIC))
5137c478bd9Sstevel@tonic-gate 			pubopt = TRUE;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 		list = parse_replica(ur->mntresource, &n);
5167c478bd9Sstevel@tonic-gate 		if (list == NULL) {
5177c478bd9Sstevel@tonic-gate 			if (n >= 0)
5187c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, "Memory allocation failed: %m");
5197c478bd9Sstevel@tonic-gate 			res = 1;
5207c478bd9Sstevel@tonic-gate 			goto done;
5217c478bd9Sstevel@tonic-gate 		}
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 		for (i = 0; i < n; i++) {
5247c478bd9Sstevel@tonic-gate 			if (pingnfs(list[i].host, 1, NULL, 0, nfs_port,
5257c478bd9Sstevel@tonic-gate 			    pubopt, list[i].path, NULL) != RPC_SUCCESS) {
5267c478bd9Sstevel@tonic-gate 				res = 1;
5277c478bd9Sstevel@tonic-gate 				free_replica(list, n);
5287c478bd9Sstevel@tonic-gate 				goto done;
5297c478bd9Sstevel@tonic-gate 			}
5307c478bd9Sstevel@tonic-gate 		}
5317c478bd9Sstevel@tonic-gate 		free_replica(list, n);
5327c478bd9Sstevel@tonic-gate 	}
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	res = unmount_mntpnt(&m);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate done:	return (res);
5377c478bd9Sstevel@tonic-gate }
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate static int
unmount_mntpnt(mnt)5407c478bd9Sstevel@tonic-gate unmount_mntpnt(mnt)
5417c478bd9Sstevel@tonic-gate 	struct mnttab *mnt;
5427c478bd9Sstevel@tonic-gate {
5437c478bd9Sstevel@tonic-gate 	char *fstype = mnt->mnt_fstype;
5447c478bd9Sstevel@tonic-gate 	char *mountp = mnt->mnt_mountp;
5457c478bd9Sstevel@tonic-gate 	char *newargv[ARGV_MAX];
5467c478bd9Sstevel@tonic-gate 	int res;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	if (strcmp(fstype, MNTTYPE_NFS) == 0) {
5497c478bd9Sstevel@tonic-gate 		res = nfsunmount(mnt);
5507c478bd9Sstevel@tonic-gate 	} else if (strcmp(fstype, MNTTYPE_LOFS) == 0) {
5517c478bd9Sstevel@tonic-gate 		if ((res = umount(mountp)) < 0)
5527c478bd9Sstevel@tonic-gate 			res = errno;
5537c478bd9Sstevel@tonic-gate 	} else {
5547c478bd9Sstevel@tonic-gate 		newargv[2] = mountp;
5557c478bd9Sstevel@tonic-gate 		newargv[3] = NULL;
5567c478bd9Sstevel@tonic-gate 
557*8548bf79Snr 		res = call_fork_exec(fstype, "umount", newargv, verbose);
5587c478bd9Sstevel@tonic-gate 		if (res == ENOENT) {
5597c478bd9Sstevel@tonic-gate 			/*
5607c478bd9Sstevel@tonic-gate 			 * filesystem specific unmount command not found
5617c478bd9Sstevel@tonic-gate 			 */
5627c478bd9Sstevel@tonic-gate 			if ((res = umount(mountp)) < 0)
5637c478bd9Sstevel@tonic-gate 				res = errno;
5647c478bd9Sstevel@tonic-gate 		}
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	if (trace > 1)
5687c478bd9Sstevel@tonic-gate 		trace_prt(1, "  unmount %s %s\n",
5697c478bd9Sstevel@tonic-gate 			mountp, res ? "failed" : "OK");
5707c478bd9Sstevel@tonic-gate 	return (res);
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate /*
5747c478bd9Sstevel@tonic-gate  * Remove the autofs specific options 'browse', 'nobrowse' and
5757c478bd9Sstevel@tonic-gate  * 'restrict' from 'opts'.
5767c478bd9Sstevel@tonic-gate  */
5777c478bd9Sstevel@tonic-gate static void
remove_browse_options(char * opts)5787c478bd9Sstevel@tonic-gate remove_browse_options(char *opts)
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate 	char *p, *pb;
5817c478bd9Sstevel@tonic-gate 	char buf[MAXOPTSLEN], new[MAXOPTSLEN];
5827c478bd9Sstevel@tonic-gate 	char *placeholder;
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	new[0] = '\0';
5857c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, opts);
5867c478bd9Sstevel@tonic-gate 	pb = buf;
5877c478bd9Sstevel@tonic-gate 	while (p = (char *)strtok_r(pb, ",", &placeholder)) {
5887c478bd9Sstevel@tonic-gate 		pb = NULL;
5897c478bd9Sstevel@tonic-gate 		if (strcmp(p, MNTOPT_NOBROWSE) != 0 &&
5907c478bd9Sstevel@tonic-gate 		    strcmp(p, MNTOPT_BROWSE) != 0 &&
5917c478bd9Sstevel@tonic-gate 		    strcmp(p, MNTOPT_RESTRICT) != 0) {
5927c478bd9Sstevel@tonic-gate 			if (new[0] != '\0')
5937c478bd9Sstevel@tonic-gate 				(void) strcat(new, ",");
5947c478bd9Sstevel@tonic-gate 			(void) strcat(new, p);
5957c478bd9Sstevel@tonic-gate 		}
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 	(void) strcpy(opts, new);
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate static const char *restropts[] = {
6017c478bd9Sstevel@tonic-gate 	RESTRICTED_MNTOPTS
6027c478bd9Sstevel@tonic-gate };
6037c478bd9Sstevel@tonic-gate #define	NROPTS	(sizeof (restropts)/sizeof (restropts[0]))
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate static int
inherit_options(char * opts,char ** mapentopts)6067c478bd9Sstevel@tonic-gate inherit_options(char *opts, char **mapentopts)
6077c478bd9Sstevel@tonic-gate {
6087c478bd9Sstevel@tonic-gate 	int i;
6097c478bd9Sstevel@tonic-gate 	char *new;
6107c478bd9Sstevel@tonic-gate 	struct mnttab mtmap;
6117c478bd9Sstevel@tonic-gate 	struct mnttab mtopt;
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	size_t len = strlen(*mapentopts);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	for (i = 0; i < NROPTS; i++)
6167c478bd9Sstevel@tonic-gate 		len += strlen(restropts[i]);
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	/* "," for each new option plus the trailing NUL */
6197c478bd9Sstevel@tonic-gate 	len += NROPTS + 1;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	new = malloc(len);
6227c478bd9Sstevel@tonic-gate 	if (new == 0)
6237c478bd9Sstevel@tonic-gate 		return (-1);
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	(void) strcpy(new, *mapentopts);
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	mtmap.mnt_mntopts = *mapentopts;
6287c478bd9Sstevel@tonic-gate 	mtopt.mnt_mntopts = opts;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	for (i = 0; i < NROPTS; i++) {
6317c478bd9Sstevel@tonic-gate 		if (hasmntopt(&mtopt, (char *)restropts[i]) != NULL &&
6327c478bd9Sstevel@tonic-gate 		    hasmntopt(&mtmap, (char *)restropts[i]) == NULL) {
6337c478bd9Sstevel@tonic-gate 			if (*new != '\0')
6347c478bd9Sstevel@tonic-gate 				(void) strcat(new, ",");
6357c478bd9Sstevel@tonic-gate 			(void) strcat(new, restropts[i]);
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 	free(*mapentopts);
6397c478bd9Sstevel@tonic-gate 	*mapentopts = new;
6407c478bd9Sstevel@tonic-gate 	return (0);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate bool_t
hasrestrictopt(char * opts)6447c478bd9Sstevel@tonic-gate hasrestrictopt(char *opts)
6457c478bd9Sstevel@tonic-gate {
6467c478bd9Sstevel@tonic-gate 	struct mnttab mt;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	mt.mnt_mntopts = opts;
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	return (hasmntopt(&mt, MNTOPT_RESTRICT) != NULL);
6517c478bd9Sstevel@tonic-gate }
652*8548bf79Snr 
653*8548bf79Snr static int
call_fork_exec(fstype,cmd,newargv,console)654*8548bf79Snr call_fork_exec(fstype, cmd, newargv, console)
655*8548bf79Snr 	char *fstype;
656*8548bf79Snr 	char *cmd;
657*8548bf79Snr 	char **newargv;
658*8548bf79Snr 	int console;
659*8548bf79Snr {
660*8548bf79Snr 	command_t command;
661*8548bf79Snr 	door_arg_t darg;
662*8548bf79Snr 	char path[MAXPATHLEN];
663*8548bf79Snr 	struct stat stbuf;
664*8548bf79Snr 	int ret;
665*8548bf79Snr 	int sz;
666*8548bf79Snr 	int status;
667*8548bf79Snr 	int i;
668*8548bf79Snr 
669*8548bf79Snr 	bzero(&command, sizeof (command));
670*8548bf79Snr 	/* build the full path name of the fstype dependent command */
671*8548bf79Snr 	(void) snprintf(path, MAXPATHLEN, "%s/%s/%s", VFS_PATH, fstype, cmd);
672*8548bf79Snr 
673*8548bf79Snr 	if (stat(path, &stbuf) != 0) {
674*8548bf79Snr 		ret = errno;
675*8548bf79Snr 		return (ret);
676*8548bf79Snr 	}
677*8548bf79Snr 
678*8548bf79Snr 	strlcpy(command.file, path, MAXPATHLEN);
679*8548bf79Snr 	strlcpy(command.argv[0], path, MAXOPTSLEN);
680*8548bf79Snr 	for (i = 2; newargv[i]; i++) {
681*8548bf79Snr 		strlcpy(command.argv[i-1], newargv[i], MAXOPTSLEN);
682*8548bf79Snr 	}
683*8548bf79Snr 	if (trace > 1) {
684*8548bf79Snr 		trace_prt(1, "  call_fork_exec: %s ", command.file);
685*8548bf79Snr 		for (i = 0; *command.argv[i]; i++)
686*8548bf79Snr 			trace_prt(0, "%s ", command.argv[i]);
687*8548bf79Snr 		trace_prt(0, "\n");
688*8548bf79Snr 	}
689*8548bf79Snr 
690*8548bf79Snr 	command.console = console;
691*8548bf79Snr 
692*8548bf79Snr 	darg.data_ptr = (char *)&command;
693*8548bf79Snr 	darg.data_size = sizeof (command);
694*8548bf79Snr 	darg.desc_ptr = NULL;
695*8548bf79Snr 	darg.desc_num = 0;
696*8548bf79Snr 	darg.rbuf = (char *)&status;
697*8548bf79Snr 	darg.rsize = sizeof (status);
698*8548bf79Snr 
699*8548bf79Snr 	ret = door_call(did_fork_exec, &darg);
700*8548bf79Snr 	if (trace > 1) {
701*8548bf79Snr 		trace_prt(1, "  call_fork_exec: door_call failed %d\n", ret);
702*8548bf79Snr 	}
703*8548bf79Snr 
704*8548bf79Snr 	return (status);
705*8548bf79Snr }
706