xref: /onnv-gate/usr/src/cmd/fs.d/autofs/autod_mount.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  *	autod_mount.c
24*0Sstevel@tonic-gate  *
25*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*0Sstevel@tonic-gate  * Use is subject to license terms.
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #include <stdio.h>
32*0Sstevel@tonic-gate #include <ctype.h>
33*0Sstevel@tonic-gate #include <string.h>
34*0Sstevel@tonic-gate #include <syslog.h>
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <sys/stat.h>
37*0Sstevel@tonic-gate #include <sys/param.h>
38*0Sstevel@tonic-gate #include <errno.h>
39*0Sstevel@tonic-gate #include <pwd.h>
40*0Sstevel@tonic-gate #include <netinet/in.h>
41*0Sstevel@tonic-gate #include <netdb.h>
42*0Sstevel@tonic-gate #include <sys/tiuser.h>
43*0Sstevel@tonic-gate #include <locale.h>
44*0Sstevel@tonic-gate #include <stdlib.h>
45*0Sstevel@tonic-gate #include <unistd.h>
46*0Sstevel@tonic-gate #include <sys/mntent.h>
47*0Sstevel@tonic-gate #include <sys/mnttab.h>
48*0Sstevel@tonic-gate #include <sys/wait.h>
49*0Sstevel@tonic-gate #include <sys/mount.h>
50*0Sstevel@tonic-gate #include <sys/fs/autofs.h>
51*0Sstevel@tonic-gate #include <nfs/nfs.h>
52*0Sstevel@tonic-gate #include <thread.h>
53*0Sstevel@tonic-gate #include <limits.h>
54*0Sstevel@tonic-gate #include <assert.h>
55*0Sstevel@tonic-gate #include <fcntl.h>
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate #include "automount.h"
58*0Sstevel@tonic-gate #include "replica.h"
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate static int unmount_mntpnt(struct mnttab *);
61*0Sstevel@tonic-gate static int fork_exec(char *, char *, char **, int);
62*0Sstevel@tonic-gate static void remove_browse_options(char *);
63*0Sstevel@tonic-gate static int inherit_options(char *, char **);
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate int
66*0Sstevel@tonic-gate do_mount1(mapname, key, subdir, mapopts, path, isdirect, alpp, cred)
67*0Sstevel@tonic-gate 	char *mapname;
68*0Sstevel@tonic-gate 	char *key;
69*0Sstevel@tonic-gate 	char *subdir;
70*0Sstevel@tonic-gate 	char *mapopts;
71*0Sstevel@tonic-gate 	char *path;
72*0Sstevel@tonic-gate 	uint_t isdirect;
73*0Sstevel@tonic-gate 	struct action_list **alpp;
74*0Sstevel@tonic-gate 	struct authunix_parms *cred;
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate 	struct mapline ml;
77*0Sstevel@tonic-gate 	struct mapent *me, *mapents = NULL;
78*0Sstevel@tonic-gate 	char mntpnt[MAXPATHLEN];
79*0Sstevel@tonic-gate 	char spec_mntpnt[MAXPATHLEN];
80*0Sstevel@tonic-gate 	int err = 0;
81*0Sstevel@tonic-gate 	char *private;	/* fs specific data. eg prevhost in case of nfs */
82*0Sstevel@tonic-gate 	int mount_ok = 0;
83*0Sstevel@tonic-gate 	ssize_t len;
84*0Sstevel@tonic-gate 	action_list *alp, *prev, *tmp;
85*0Sstevel@tonic-gate 	char root[MAXPATHLEN];
86*0Sstevel@tonic-gate 	int overlay = 1;
87*0Sstevel@tonic-gate 	char next_subdir[MAXPATHLEN];
88*0Sstevel@tonic-gate 	bool_t mount_access = TRUE;
89*0Sstevel@tonic-gate 	bool_t iswildcard;
90*0Sstevel@tonic-gate 	bool_t isrestricted = hasrestrictopt(mapopts);
91*0Sstevel@tonic-gate 	char *stack[STACKSIZ];
92*0Sstevel@tonic-gate 	char **stkptr = stack;
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate retry:
95*0Sstevel@tonic-gate 	iswildcard = FALSE;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	/* initialize the stack of open files for this thread */
98*0Sstevel@tonic-gate 	stack_op(INIT, NULL, stack, &stkptr);
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	err = getmapent(key, mapname, &ml, stack, &stkptr, &iswildcard,
101*0Sstevel@tonic-gate 		isrestricted);
102*0Sstevel@tonic-gate 	if (err == 0) {
103*0Sstevel@tonic-gate 		mapents = parse_entry(key, mapname, mapopts, &ml,
104*0Sstevel@tonic-gate 				    subdir, isdirect, mount_access);
105*0Sstevel@tonic-gate 	}
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	if (trace > 1) {
108*0Sstevel@tonic-gate 		struct mapfs *mfs;
109*0Sstevel@tonic-gate 		trace_prt(1, "  do_mount1:\n");
110*0Sstevel@tonic-gate 		for (me = mapents; me; me = me->map_next) {
111*0Sstevel@tonic-gate 			trace_prt(1, "  (%s,%s)\t%s%s%s\n",
112*0Sstevel@tonic-gate 			me->map_fstype ? me->map_fstype : "",
113*0Sstevel@tonic-gate 			me->map_mounter ? me->map_mounter : "",
114*0Sstevel@tonic-gate 			path ? path : "",
115*0Sstevel@tonic-gate 			me->map_root  ? me->map_root : "",
116*0Sstevel@tonic-gate 			me->map_mntpnt ? me->map_mntpnt : "");
117*0Sstevel@tonic-gate 			trace_prt(0, "\t\t-%s\n",
118*0Sstevel@tonic-gate 			me->map_mntopts ? me->map_mntopts : "");
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 			for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next)
121*0Sstevel@tonic-gate 				trace_prt(0, "\t\t%s:%s\tpenalty=%d\n",
122*0Sstevel@tonic-gate 					mfs->mfs_host ? mfs->mfs_host: "",
123*0Sstevel@tonic-gate 					mfs->mfs_dir ? mfs->mfs_dir : "",
124*0Sstevel@tonic-gate 					mfs->mfs_penalty);
125*0Sstevel@tonic-gate 		}
126*0Sstevel@tonic-gate 	}
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	*alpp = NULL;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	/*
131*0Sstevel@tonic-gate 	 * Each mapent in the list describes a mount to be done.
132*0Sstevel@tonic-gate 	 * Normally there's just a single entry, though in the
133*0Sstevel@tonic-gate 	 * case of /net mounts there may be many entries, that
134*0Sstevel@tonic-gate 	 * must be mounted as a hierarchy.  For each mount the
135*0Sstevel@tonic-gate 	 * automountd must make sure the required mountpoint
136*0Sstevel@tonic-gate 	 * exists and invoke the appropriate mount command for
137*0Sstevel@tonic-gate 	 * the fstype.
138*0Sstevel@tonic-gate 	 */
139*0Sstevel@tonic-gate 	private = "";
140*0Sstevel@tonic-gate 	for (me = mapents; me && !err; me = me->map_next) {
141*0Sstevel@tonic-gate 		len = snprintf(mntpnt, sizeof (mntpnt), "%s%s%s", path,
142*0Sstevel@tonic-gate 		    mapents->map_root, me->map_mntpnt);
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 		if (len >= sizeof (mntpnt)) {
145*0Sstevel@tonic-gate 			free_mapent(mapents);
146*0Sstevel@tonic-gate 			return (ENAMETOOLONG);
147*0Sstevel@tonic-gate 		}
148*0Sstevel@tonic-gate 		/*
149*0Sstevel@tonic-gate 		 * remove trailing /'s from mountpoint to avoid problems
150*0Sstevel@tonic-gate 		 * stating a directory with two or more trailing slashes.
151*0Sstevel@tonic-gate 		 * This will let us mount directories from machines
152*0Sstevel@tonic-gate 		 * which export with two or more slashes (apollo for instance).
153*0Sstevel@tonic-gate 		 */
154*0Sstevel@tonic-gate 		len -= 1;
155*0Sstevel@tonic-gate 		while (mntpnt[len] == '/')
156*0Sstevel@tonic-gate 			mntpnt[len--] = '\0';
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 		(void) strcpy(spec_mntpnt, mntpnt);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 		if (isrestricted &&
161*0Sstevel@tonic-gate 		    inherit_options(mapopts, &me->map_mntopts) != 0) {
162*0Sstevel@tonic-gate 			syslog(LOG_ERR, "malloc of options failed");
163*0Sstevel@tonic-gate 			free_mapent(mapents);
164*0Sstevel@tonic-gate 			return (EAGAIN);
165*0Sstevel@tonic-gate 		}
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 		if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) {
168*0Sstevel@tonic-gate 			remove_browse_options(me->map_mntopts);
169*0Sstevel@tonic-gate 			err =
170*0Sstevel@tonic-gate 			    mount_nfs(me, spec_mntpnt, private, overlay, cred);
171*0Sstevel@tonic-gate 			/*
172*0Sstevel@tonic-gate 			 * We must retry if we don't have access to the
173*0Sstevel@tonic-gate 			 * root file system and there are other
174*0Sstevel@tonic-gate 			 * following mapents. The reason we can't
175*0Sstevel@tonic-gate 			 * continue because the rest of the mapent list
176*0Sstevel@tonic-gate 			 * depends on whether mount_access is TRUE or FALSE.
177*0Sstevel@tonic-gate 			 */
178*0Sstevel@tonic-gate 			if (err == NFSERR_ACCES && me->map_next != NULL) {
179*0Sstevel@tonic-gate 				/*
180*0Sstevel@tonic-gate 				 * don't expect mount_access to be
181*0Sstevel@tonic-gate 				 * FALSE here, but we do a check
182*0Sstevel@tonic-gate 				 * anyway.
183*0Sstevel@tonic-gate 				 */
184*0Sstevel@tonic-gate 				if (mount_access == TRUE) {
185*0Sstevel@tonic-gate 					mount_access = FALSE;
186*0Sstevel@tonic-gate 					err = 0;
187*0Sstevel@tonic-gate 					free_mapent(mapents);
188*0Sstevel@tonic-gate 					goto retry;
189*0Sstevel@tonic-gate 				}
190*0Sstevel@tonic-gate 			}
191*0Sstevel@tonic-gate 			mount_ok = !err;
192*0Sstevel@tonic-gate 		} else if (strcmp(me->map_fstype, MNTTYPE_AUTOFS) == 0) {
193*0Sstevel@tonic-gate 			if (isdirect) {
194*0Sstevel@tonic-gate 				len = strlcpy(root, path, sizeof (root));
195*0Sstevel@tonic-gate 			} else {
196*0Sstevel@tonic-gate 				len = snprintf(root, sizeof (root), "%s/%s",
197*0Sstevel@tonic-gate 				    path, key);
198*0Sstevel@tonic-gate 			}
199*0Sstevel@tonic-gate 			if (len >= sizeof (root)) {
200*0Sstevel@tonic-gate 				free_mapent(mapents);
201*0Sstevel@tonic-gate 				return (ENAMETOOLONG);
202*0Sstevel@tonic-gate 			}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 			alp = (action_list *)malloc(sizeof (action_list));
205*0Sstevel@tonic-gate 			if (alp == NULL) {
206*0Sstevel@tonic-gate 				syslog(LOG_ERR, "malloc of alp failed");
207*0Sstevel@tonic-gate 				continue;
208*0Sstevel@tonic-gate 			}
209*0Sstevel@tonic-gate 			memset(alp, 0, sizeof (action_list));
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 			/*
212*0Sstevel@tonic-gate 			 * get the next subidr, but only if its a modified
213*0Sstevel@tonic-gate 			 * or faked autofs mount
214*0Sstevel@tonic-gate 			 */
215*0Sstevel@tonic-gate 			if (me->map_modified || me->map_faked) {
216*0Sstevel@tonic-gate 				len = snprintf(next_subdir,
217*0Sstevel@tonic-gate 					sizeof (next_subdir), "%s%s", subdir,
218*0Sstevel@tonic-gate 					me->map_mntpnt);
219*0Sstevel@tonic-gate 			} else {
220*0Sstevel@tonic-gate 				next_subdir[0] = '\0';
221*0Sstevel@tonic-gate 				len = 0;
222*0Sstevel@tonic-gate 			}
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 			if (trace > 2)
225*0Sstevel@tonic-gate 				trace_prt(1, "  root=%s\t next_subdir=%s\n",
226*0Sstevel@tonic-gate 						root, next_subdir);
227*0Sstevel@tonic-gate 			if (len < sizeof (next_subdir)) {
228*0Sstevel@tonic-gate 				err = mount_autofs(me, spec_mntpnt, alp,
229*0Sstevel@tonic-gate 					root, next_subdir, key);
230*0Sstevel@tonic-gate 			} else {
231*0Sstevel@tonic-gate 				err = ENAMETOOLONG;
232*0Sstevel@tonic-gate 			}
233*0Sstevel@tonic-gate 			if (err == 0) {
234*0Sstevel@tonic-gate 				/*
235*0Sstevel@tonic-gate 				 * append to action list
236*0Sstevel@tonic-gate 				 */
237*0Sstevel@tonic-gate 				mount_ok++;
238*0Sstevel@tonic-gate 				if (*alpp == NULL)
239*0Sstevel@tonic-gate 					*alpp = alp;
240*0Sstevel@tonic-gate 				else {
241*0Sstevel@tonic-gate 					for (tmp = *alpp; tmp != NULL;
242*0Sstevel@tonic-gate 					    tmp = tmp->next)
243*0Sstevel@tonic-gate 						prev = tmp;
244*0Sstevel@tonic-gate 					prev->next = alp;
245*0Sstevel@tonic-gate 				}
246*0Sstevel@tonic-gate 			} else {
247*0Sstevel@tonic-gate 				free(alp);
248*0Sstevel@tonic-gate 				mount_ok = 0;
249*0Sstevel@tonic-gate 			}
250*0Sstevel@tonic-gate 		} else if (strcmp(me->map_fstype, MNTTYPE_LOFS) == 0) {
251*0Sstevel@tonic-gate 			remove_browse_options(me->map_mntopts);
252*0Sstevel@tonic-gate 			err = loopbackmount(me->map_fs->mfs_dir, spec_mntpnt,
253*0Sstevel@tonic-gate 					    me->map_mntopts, overlay);
254*0Sstevel@tonic-gate 			mount_ok = !err;
255*0Sstevel@tonic-gate 		} else {
256*0Sstevel@tonic-gate 			remove_browse_options(me->map_mntopts);
257*0Sstevel@tonic-gate 			err = mount_generic(me->map_fs->mfs_dir,
258*0Sstevel@tonic-gate 					    me->map_fstype, me->map_mntopts,
259*0Sstevel@tonic-gate 					    spec_mntpnt, overlay);
260*0Sstevel@tonic-gate 			mount_ok = !err;
261*0Sstevel@tonic-gate 		}
262*0Sstevel@tonic-gate 	}
263*0Sstevel@tonic-gate 	if (mapents)
264*0Sstevel@tonic-gate 		free_mapent(mapents);
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	/*
267*0Sstevel@tonic-gate 	 * If an error occurred,
268*0Sstevel@tonic-gate 	 * the filesystem doesn't exist, or could not be
269*0Sstevel@tonic-gate 	 * mounted.  Return EACCES to autofs indicating that
270*0Sstevel@tonic-gate 	 * the mountpoint can not be accessed if this is not
271*0Sstevel@tonic-gate 	 * a wildcard access.  If it is a wildcard access we
272*0Sstevel@tonic-gate 	 * return ENOENT since the lookup that triggered
273*0Sstevel@tonic-gate 	 * this mount request will fail and the entry will not
274*0Sstevel@tonic-gate 	 * be available.
275*0Sstevel@tonic-gate 	 */
276*0Sstevel@tonic-gate 	if (mount_ok) {
277*0Sstevel@tonic-gate 		/*
278*0Sstevel@tonic-gate 		 * No error occurred, return 0 to indicate success.
279*0Sstevel@tonic-gate 		 */
280*0Sstevel@tonic-gate 		err = 0;
281*0Sstevel@tonic-gate 	} else {
282*0Sstevel@tonic-gate 		/*
283*0Sstevel@tonic-gate 		 * The filesystem does not exist or could not be mounted.
284*0Sstevel@tonic-gate 		 * Return ENOENT if the lookup was triggered by a wildcard
285*0Sstevel@tonic-gate 		 * access.  Wildcard entries only exist if they can be
286*0Sstevel@tonic-gate 		 * mounted.  They can not be listed otherwise (through
287*0Sstevel@tonic-gate 		 * a readdir(2)).
288*0Sstevel@tonic-gate 		 * Return EACCES if the lookup was not triggered by a
289*0Sstevel@tonic-gate 		 * wildcard access.  Map entries that are explicitly defined
290*0Sstevel@tonic-gate 		 * in maps are visible via readdir(2), therefore we return
291*0Sstevel@tonic-gate 		 * EACCES to indicate that the entry exists, but the directory
292*0Sstevel@tonic-gate 		 * can not be opened.  This is the same behavior of a Unix
293*0Sstevel@tonic-gate 		 * directory that exists, but has its execute bit turned off.
294*0Sstevel@tonic-gate 		 * The directory is there, but the user does not have access
295*0Sstevel@tonic-gate 		 * to it.
296*0Sstevel@tonic-gate 		 */
297*0Sstevel@tonic-gate 		if (iswildcard)
298*0Sstevel@tonic-gate 			err = ENOENT;
299*0Sstevel@tonic-gate 		else
300*0Sstevel@tonic-gate 			err = EACCES;
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate 	return (err);
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate #define	ARGV_MAX	16
306*0Sstevel@tonic-gate #define	VFS_PATH	"/usr/lib/fs"
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate int
309*0Sstevel@tonic-gate mount_generic(special, fstype, opts, mntpnt, overlay)
310*0Sstevel@tonic-gate 	char *special, *fstype, *opts, *mntpnt;
311*0Sstevel@tonic-gate 	int overlay;
312*0Sstevel@tonic-gate {
313*0Sstevel@tonic-gate 	struct mnttab m;
314*0Sstevel@tonic-gate 	struct stat stbuf;
315*0Sstevel@tonic-gate 	int i, res;
316*0Sstevel@tonic-gate 	char *newargv[ARGV_MAX];
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	if (trace > 1) {
319*0Sstevel@tonic-gate 		trace_prt(1, "  mount: %s %s %s %s\n",
320*0Sstevel@tonic-gate 			special, mntpnt, fstype, opts);
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	if (stat(mntpnt, &stbuf) < 0) {
324*0Sstevel@tonic-gate 		syslog(LOG_ERR, "Couldn't stat %s: %m", mntpnt);
325*0Sstevel@tonic-gate 		return (ENOENT);
326*0Sstevel@tonic-gate 	}
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	i = 2;
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	if (overlay)
331*0Sstevel@tonic-gate 		newargv[i++] = "-O";
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	/*
334*0Sstevel@tonic-gate 	 *  Use "quiet" option to suppress warnings about unsupported
335*0Sstevel@tonic-gate 	 *  mount options.
336*0Sstevel@tonic-gate 	 */
337*0Sstevel@tonic-gate 	newargv[i++] = "-q";
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 	if (opts && *opts) {
340*0Sstevel@tonic-gate 		m.mnt_mntopts = opts;
341*0Sstevel@tonic-gate 		if (hasmntopt(&m, MNTOPT_RO) != NULL)
342*0Sstevel@tonic-gate 			newargv[i++] = "-r";
343*0Sstevel@tonic-gate 		newargv[i++] = "-o";
344*0Sstevel@tonic-gate 		newargv[i++] = opts;
345*0Sstevel@tonic-gate 	}
346*0Sstevel@tonic-gate 	newargv[i++] = "--";
347*0Sstevel@tonic-gate 	newargv[i++] = special;
348*0Sstevel@tonic-gate 	newargv[i++] = mntpnt;
349*0Sstevel@tonic-gate 	newargv[i] = NULL;
350*0Sstevel@tonic-gate 	res = fork_exec(fstype, "mount", newargv, verbose);
351*0Sstevel@tonic-gate 	if (res == 0 && trace > 1) {
352*0Sstevel@tonic-gate 		if (stat(mntpnt, &stbuf) == 0) {
353*0Sstevel@tonic-gate 			trace_prt(1, "  mount of %s dev=%x rdev=%x OK\n",
354*0Sstevel@tonic-gate 				mntpnt, stbuf.st_dev, stbuf.st_rdev);
355*0Sstevel@tonic-gate 		} else {
356*0Sstevel@tonic-gate 			trace_prt(1, "  failed to stat %s\n", mntpnt);
357*0Sstevel@tonic-gate 		}
358*0Sstevel@tonic-gate 	}
359*0Sstevel@tonic-gate 	return (res);
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate static int
363*0Sstevel@tonic-gate fork_exec(fstype, cmd, newargv, console)
364*0Sstevel@tonic-gate 	char *fstype;
365*0Sstevel@tonic-gate 	char *cmd;
366*0Sstevel@tonic-gate 	char **newargv;
367*0Sstevel@tonic-gate 	int console;
368*0Sstevel@tonic-gate {
369*0Sstevel@tonic-gate 	char path[MAXPATHLEN];
370*0Sstevel@tonic-gate 	int i;
371*0Sstevel@tonic-gate 	int stat_loc;
372*0Sstevel@tonic-gate 	int fd = 0;
373*0Sstevel@tonic-gate 	struct stat stbuf;
374*0Sstevel@tonic-gate 	int res;
375*0Sstevel@tonic-gate 	int child_pid;
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	/* build the full path name of the fstype dependent command */
378*0Sstevel@tonic-gate 	(void) sprintf(path, "%s/%s/%s", VFS_PATH, fstype, cmd);
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 	if (stat(path, &stbuf) != 0) {
381*0Sstevel@tonic-gate 		res = errno;
382*0Sstevel@tonic-gate 		return (res);
383*0Sstevel@tonic-gate 	}
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 	if (trace > 1) {
386*0Sstevel@tonic-gate 		trace_prt(1, "  fork_exec: %s ", path);
387*0Sstevel@tonic-gate 		for (i = 2; newargv[i]; i++)
388*0Sstevel@tonic-gate 			trace_prt(0, "%s ", newargv[i]);
389*0Sstevel@tonic-gate 		trace_prt(0, "\n");
390*0Sstevel@tonic-gate 	}
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	newargv[1] = cmd;
394*0Sstevel@tonic-gate 	switch ((child_pid = fork1())) {
395*0Sstevel@tonic-gate 	case -1:
396*0Sstevel@tonic-gate 		syslog(LOG_ERR, "Cannot fork: %m");
397*0Sstevel@tonic-gate 		return (errno);
398*0Sstevel@tonic-gate 	case 0:
399*0Sstevel@tonic-gate 		/*
400*0Sstevel@tonic-gate 		 * Child
401*0Sstevel@tonic-gate 		 */
402*0Sstevel@tonic-gate 		(void) setsid();
403*0Sstevel@tonic-gate 		fd = open(console ? "/dev/console" : "/dev/null", O_WRONLY);
404*0Sstevel@tonic-gate 		if (fd != -1) {
405*0Sstevel@tonic-gate 			(void) dup2(fd, 1);
406*0Sstevel@tonic-gate 			(void) dup2(fd, 2);
407*0Sstevel@tonic-gate 			(void) close(fd);
408*0Sstevel@tonic-gate 		}
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 		(void) execv(path, &newargv[1]);
411*0Sstevel@tonic-gate 		if (errno == EACCES)
412*0Sstevel@tonic-gate 			syslog(LOG_ERR, "exec %s: %m", path);
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 		_exit(errno);
415*0Sstevel@tonic-gate 	default:
416*0Sstevel@tonic-gate 		/*
417*0Sstevel@tonic-gate 		 * Parent
418*0Sstevel@tonic-gate 		 */
419*0Sstevel@tonic-gate 		(void) waitpid(child_pid, &stat_loc, WUNTRACED);
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 		if (WIFEXITED(stat_loc)) {
422*0Sstevel@tonic-gate 			if (trace > 1) {
423*0Sstevel@tonic-gate 				trace_prt(1,
424*0Sstevel@tonic-gate 				    "  fork_exec: returns exit status %d\n",
425*0Sstevel@tonic-gate 				    WEXITSTATUS(stat_loc));
426*0Sstevel@tonic-gate 			}
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 			return (WEXITSTATUS(stat_loc));
429*0Sstevel@tonic-gate 		} else
430*0Sstevel@tonic-gate 		if (WIFSIGNALED(stat_loc)) {
431*0Sstevel@tonic-gate 			if (trace > 1) {
432*0Sstevel@tonic-gate 				trace_prt(1,
433*0Sstevel@tonic-gate 				    "  fork_exec: returns signal status %d\n",
434*0Sstevel@tonic-gate 				    WTERMSIG(stat_loc));
435*0Sstevel@tonic-gate 			}
436*0Sstevel@tonic-gate 		} else {
437*0Sstevel@tonic-gate 			if (trace > 1)
438*0Sstevel@tonic-gate 				trace_prt(1,
439*0Sstevel@tonic-gate 				    "  fork_exec: returns unknown status\n");
440*0Sstevel@tonic-gate 		}
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 		return (1);
443*0Sstevel@tonic-gate 	}
444*0Sstevel@tonic-gate }
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate int
447*0Sstevel@tonic-gate do_unmount1(ur)
448*0Sstevel@tonic-gate 	umntrequest *ur;
449*0Sstevel@tonic-gate {
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	struct mnttab m;
452*0Sstevel@tonic-gate 	int res = 0;
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	m.mnt_special = ur->mntresource;
455*0Sstevel@tonic-gate 	m.mnt_mountp = ur->mntpnt;
456*0Sstevel@tonic-gate 	m.mnt_fstype = ur->fstype;
457*0Sstevel@tonic-gate 	m.mnt_mntopts = ur->mntopts;
458*0Sstevel@tonic-gate 	/*
459*0Sstevel@tonic-gate 	 * Special case for NFS mounts.
460*0Sstevel@tonic-gate 	 * Don't want to attempt unmounts from
461*0Sstevel@tonic-gate 	 * a dead server.  If any member of a
462*0Sstevel@tonic-gate 	 * hierarchy belongs to a dead server
463*0Sstevel@tonic-gate 	 * give up (try later).
464*0Sstevel@tonic-gate 	 */
465*0Sstevel@tonic-gate 	if (strcmp(ur->fstype, MNTTYPE_NFS) == 0) {
466*0Sstevel@tonic-gate 		struct replica *list;
467*0Sstevel@tonic-gate 		int i, n;
468*0Sstevel@tonic-gate 		bool_t pubopt = FALSE;
469*0Sstevel@tonic-gate 		int nfs_port;
470*0Sstevel@tonic-gate 		int got_port;
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 		/*
473*0Sstevel@tonic-gate 		 * See if a port number was specified.  If one was
474*0Sstevel@tonic-gate 		 * specified that is too large to fit in 16 bits, truncate
475*0Sstevel@tonic-gate 		 * the high-order bits (for historical compatibility).  Use
476*0Sstevel@tonic-gate 		 * zero to indicate "no port specified".
477*0Sstevel@tonic-gate 		 */
478*0Sstevel@tonic-gate 		got_port = nopt(&m, MNTOPT_PORT, &nfs_port);
479*0Sstevel@tonic-gate 		if (!got_port)
480*0Sstevel@tonic-gate 			nfs_port = 0;
481*0Sstevel@tonic-gate 		nfs_port &= USHRT_MAX;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 		if (hasmntopt(&m, MNTOPT_PUBLIC))
484*0Sstevel@tonic-gate 			pubopt = TRUE;
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 		list = parse_replica(ur->mntresource, &n);
487*0Sstevel@tonic-gate 		if (list == NULL) {
488*0Sstevel@tonic-gate 			if (n >= 0)
489*0Sstevel@tonic-gate 				syslog(LOG_ERR, "Memory allocation failed: %m");
490*0Sstevel@tonic-gate 			res = 1;
491*0Sstevel@tonic-gate 			goto done;
492*0Sstevel@tonic-gate 		}
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 		for (i = 0; i < n; i++) {
495*0Sstevel@tonic-gate 			if (pingnfs(list[i].host, 1, NULL, 0, nfs_port,
496*0Sstevel@tonic-gate 			    pubopt, list[i].path, NULL) != RPC_SUCCESS) {
497*0Sstevel@tonic-gate 				res = 1;
498*0Sstevel@tonic-gate 				free_replica(list, n);
499*0Sstevel@tonic-gate 				goto done;
500*0Sstevel@tonic-gate 			}
501*0Sstevel@tonic-gate 		}
502*0Sstevel@tonic-gate 		free_replica(list, n);
503*0Sstevel@tonic-gate 	}
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	res = unmount_mntpnt(&m);
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate done:	return (res);
508*0Sstevel@tonic-gate }
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate static int
511*0Sstevel@tonic-gate unmount_mntpnt(mnt)
512*0Sstevel@tonic-gate 	struct mnttab *mnt;
513*0Sstevel@tonic-gate {
514*0Sstevel@tonic-gate 	char *fstype = mnt->mnt_fstype;
515*0Sstevel@tonic-gate 	char *mountp = mnt->mnt_mountp;
516*0Sstevel@tonic-gate 	char *newargv[ARGV_MAX];
517*0Sstevel@tonic-gate 	int res;
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	if (strcmp(fstype, MNTTYPE_NFS) == 0) {
520*0Sstevel@tonic-gate 		res = nfsunmount(mnt);
521*0Sstevel@tonic-gate 	} else if (strcmp(fstype, MNTTYPE_LOFS) == 0) {
522*0Sstevel@tonic-gate 		if ((res = umount(mountp)) < 0)
523*0Sstevel@tonic-gate 			res = errno;
524*0Sstevel@tonic-gate 	} else {
525*0Sstevel@tonic-gate 		newargv[2] = mountp;
526*0Sstevel@tonic-gate 		newargv[3] = NULL;
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 		res = fork_exec(fstype, "umount", newargv, verbose);
529*0Sstevel@tonic-gate 		if (res == ENOENT) {
530*0Sstevel@tonic-gate 			/*
531*0Sstevel@tonic-gate 			 * filesystem specific unmount command not found
532*0Sstevel@tonic-gate 			 */
533*0Sstevel@tonic-gate 			if ((res = umount(mountp)) < 0)
534*0Sstevel@tonic-gate 				res = errno;
535*0Sstevel@tonic-gate 		}
536*0Sstevel@tonic-gate 	}
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 	if (trace > 1)
539*0Sstevel@tonic-gate 		trace_prt(1, "  unmount %s %s\n",
540*0Sstevel@tonic-gate 			mountp, res ? "failed" : "OK");
541*0Sstevel@tonic-gate 	return (res);
542*0Sstevel@tonic-gate }
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate /*
545*0Sstevel@tonic-gate  * Remove the autofs specific options 'browse', 'nobrowse' and
546*0Sstevel@tonic-gate  * 'restrict' from 'opts'.
547*0Sstevel@tonic-gate  */
548*0Sstevel@tonic-gate static void
549*0Sstevel@tonic-gate remove_browse_options(char *opts)
550*0Sstevel@tonic-gate {
551*0Sstevel@tonic-gate 	char *p, *pb;
552*0Sstevel@tonic-gate 	char buf[MAXOPTSLEN], new[MAXOPTSLEN];
553*0Sstevel@tonic-gate 	char *placeholder;
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 	new[0] = '\0';
556*0Sstevel@tonic-gate 	(void) strcpy(buf, opts);
557*0Sstevel@tonic-gate 	pb = buf;
558*0Sstevel@tonic-gate 	while (p = (char *)strtok_r(pb, ",", &placeholder)) {
559*0Sstevel@tonic-gate 		pb = NULL;
560*0Sstevel@tonic-gate 		if (strcmp(p, MNTOPT_NOBROWSE) != 0 &&
561*0Sstevel@tonic-gate 		    strcmp(p, MNTOPT_BROWSE) != 0 &&
562*0Sstevel@tonic-gate 		    strcmp(p, MNTOPT_RESTRICT) != 0) {
563*0Sstevel@tonic-gate 			if (new[0] != '\0')
564*0Sstevel@tonic-gate 				(void) strcat(new, ",");
565*0Sstevel@tonic-gate 			(void) strcat(new, p);
566*0Sstevel@tonic-gate 		}
567*0Sstevel@tonic-gate 	}
568*0Sstevel@tonic-gate 	(void) strcpy(opts, new);
569*0Sstevel@tonic-gate }
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate static const char *restropts[] = {
572*0Sstevel@tonic-gate 	RESTRICTED_MNTOPTS
573*0Sstevel@tonic-gate };
574*0Sstevel@tonic-gate #define	NROPTS	(sizeof (restropts)/sizeof (restropts[0]))
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate static int
577*0Sstevel@tonic-gate inherit_options(char *opts, char **mapentopts)
578*0Sstevel@tonic-gate {
579*0Sstevel@tonic-gate 	int i;
580*0Sstevel@tonic-gate 	char *new;
581*0Sstevel@tonic-gate 	struct mnttab mtmap;
582*0Sstevel@tonic-gate 	struct mnttab mtopt;
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	size_t len = strlen(*mapentopts);
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	for (i = 0; i < NROPTS; i++)
587*0Sstevel@tonic-gate 		len += strlen(restropts[i]);
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	/* "," for each new option plus the trailing NUL */
590*0Sstevel@tonic-gate 	len += NROPTS + 1;
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 	new = malloc(len);
593*0Sstevel@tonic-gate 	if (new == 0)
594*0Sstevel@tonic-gate 		return (-1);
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	(void) strcpy(new, *mapentopts);
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate 	mtmap.mnt_mntopts = *mapentopts;
599*0Sstevel@tonic-gate 	mtopt.mnt_mntopts = opts;
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	for (i = 0; i < NROPTS; i++) {
602*0Sstevel@tonic-gate 		if (hasmntopt(&mtopt, (char *)restropts[i]) != NULL &&
603*0Sstevel@tonic-gate 		    hasmntopt(&mtmap, (char *)restropts[i]) == NULL) {
604*0Sstevel@tonic-gate 			if (*new != '\0')
605*0Sstevel@tonic-gate 				(void) strcat(new, ",");
606*0Sstevel@tonic-gate 			(void) strcat(new, restropts[i]);
607*0Sstevel@tonic-gate 		}
608*0Sstevel@tonic-gate 	}
609*0Sstevel@tonic-gate 	free(*mapentopts);
610*0Sstevel@tonic-gate 	*mapentopts = new;
611*0Sstevel@tonic-gate 	return (0);
612*0Sstevel@tonic-gate }
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate bool_t
615*0Sstevel@tonic-gate hasrestrictopt(char *opts)
616*0Sstevel@tonic-gate {
617*0Sstevel@tonic-gate 	struct mnttab mt;
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	mt.mnt_mntopts = opts;
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	return (hasmntopt(&mt, MNTOPT_RESTRICT) != NULL);
622*0Sstevel@tonic-gate }
623