xref: /illumos-gate/usr/src/cmd/fs.d/umount.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include	<stdio.h>
34*7c478bd9Sstevel@tonic-gate #include	<limits.h>
35*7c478bd9Sstevel@tonic-gate #include	<unistd.h>
36*7c478bd9Sstevel@tonic-gate #include	<stdlib.h>
37*7c478bd9Sstevel@tonic-gate #include	<string.h>
38*7c478bd9Sstevel@tonic-gate #include	<sys/signal.h>
39*7c478bd9Sstevel@tonic-gate #include	<sys/mnttab.h>
40*7c478bd9Sstevel@tonic-gate #include	<errno.h>
41*7c478bd9Sstevel@tonic-gate #include	<sys/types.h>
42*7c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
43*7c478bd9Sstevel@tonic-gate #include	<sys/param.h>
44*7c478bd9Sstevel@tonic-gate #include	<sys/wait.h>
45*7c478bd9Sstevel@tonic-gate #include	<sys/vfstab.h>
46*7c478bd9Sstevel@tonic-gate #include	<sys/fcntl.h>
47*7c478bd9Sstevel@tonic-gate #include	<sys/resource.h>
48*7c478bd9Sstevel@tonic-gate #include	<sys/mntent.h>
49*7c478bd9Sstevel@tonic-gate #include	<sys/ctfs.h>
50*7c478bd9Sstevel@tonic-gate #include	<locale.h>
51*7c478bd9Sstevel@tonic-gate #include	<stdarg.h>
52*7c478bd9Sstevel@tonic-gate #include	<sys/mount.h>
53*7c478bd9Sstevel@tonic-gate #include	<sys/objfs.h>
54*7c478bd9Sstevel@tonic-gate #include	"fslib.h"
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #define	FS_PATH		"/usr/lib/fs"
57*7c478bd9Sstevel@tonic-gate #define	ALT_PATH	"/etc/fs"
58*7c478bd9Sstevel@tonic-gate #define	FULLPATH_MAX	32
59*7c478bd9Sstevel@tonic-gate #define	FSTYPE_MAX	8
60*7c478bd9Sstevel@tonic-gate #define	ARGV_MAX	16
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate int	aflg, oflg, Vflg, dashflg, dflg, fflg;
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate extern void	rpterr(), usage(), mnterror();
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate extern	char	*optarg;	/* used by getopt */
67*7c478bd9Sstevel@tonic-gate extern	int	optind, opterr;
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate static char	*myname;
70*7c478bd9Sstevel@tonic-gate char	fs_path[] = FS_PATH;
71*7c478bd9Sstevel@tonic-gate char	alt_path[] = ALT_PATH;
72*7c478bd9Sstevel@tonic-gate char	mnttab[MAXPATHLEN + 1];
73*7c478bd9Sstevel@tonic-gate char	*oarg, *farg;
74*7c478bd9Sstevel@tonic-gate int	maxrun, nrun;
75*7c478bd9Sstevel@tonic-gate int	no_mnttab;
76*7c478bd9Sstevel@tonic-gate int	lofscnt;		/* presence of lofs prohibits parallel */
77*7c478bd9Sstevel@tonic-gate 				/* umounting */
78*7c478bd9Sstevel@tonic-gate int	exitcode;
79*7c478bd9Sstevel@tonic-gate char	resolve[MAXPATHLEN];
80*7c478bd9Sstevel@tonic-gate static  char ibuf[BUFSIZ];
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate /*
83*7c478bd9Sstevel@tonic-gate  * Currently, mounting cachefs's simultaneous uncovers various problems.
84*7c478bd9Sstevel@tonic-gate  * For the short term, we serialize cachefs activity while we fix
85*7c478bd9Sstevel@tonic-gate  * these cachefs bugs.
86*7c478bd9Sstevel@tonic-gate  */
87*7c478bd9Sstevel@tonic-gate #define	CACHEFS_BUG
88*7c478bd9Sstevel@tonic-gate #ifdef	CACHEFS_BUG
89*7c478bd9Sstevel@tonic-gate #include	<sys/fs/cachefs_fs.h>	/* for BACKMNT_NAME */
90*7c478bd9Sstevel@tonic-gate int	cachefs_running;	/* parallel cachefs not supported yet */
91*7c478bd9Sstevel@tonic-gate #endif
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate /*
94*7c478bd9Sstevel@tonic-gate  * The basic mount struct that describes an mnttab entry.
95*7c478bd9Sstevel@tonic-gate  * It is used both in an array and as a linked list elem.
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate typedef struct mountent {
99*7c478bd9Sstevel@tonic-gate 	struct mnttab	ment;		/* the mnttab data */
100*7c478bd9Sstevel@tonic-gate 	int		mlevel;		/* mount level of the mount pt */
101*7c478bd9Sstevel@tonic-gate 	pid_t		pid;		/* the pid of this mount process */
102*7c478bd9Sstevel@tonic-gate #define	RDPIPE		0
103*7c478bd9Sstevel@tonic-gate #define	WRPIPE		1
104*7c478bd9Sstevel@tonic-gate 	int		sopipe[2];	/* pipe attached to child's stdout */
105*7c478bd9Sstevel@tonic-gate 	int		sepipe[2];	/* pipe attached to child's stderr */
106*7c478bd9Sstevel@tonic-gate 	struct mountent *link;		/* used when in linked list */
107*7c478bd9Sstevel@tonic-gate } mountent_t;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static mountent_t	*mntll;		/* head of global linked list of */
110*7c478bd9Sstevel@tonic-gate 					/* mountents */
111*7c478bd9Sstevel@tonic-gate int			listlength;	/* # of elems in this list */
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate /*
114*7c478bd9Sstevel@tonic-gate  * If the automatic flag (-a) is given and mount points are not specified
115*7c478bd9Sstevel@tonic-gate  * on the command line, then do not attempt to umount these.  These
116*7c478bd9Sstevel@tonic-gate  * generally need to be kept mounted until system shutdown.
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate static const char   *keeplist[] = {
119*7c478bd9Sstevel@tonic-gate 	"/",
120*7c478bd9Sstevel@tonic-gate 	"/dev",
121*7c478bd9Sstevel@tonic-gate 	"/dev/fd",
122*7c478bd9Sstevel@tonic-gate 	"/devices",
123*7c478bd9Sstevel@tonic-gate 	"/etc/mnttab",
124*7c478bd9Sstevel@tonic-gate 	"/etc/svc/volatile",
125*7c478bd9Sstevel@tonic-gate 	"/lib",
126*7c478bd9Sstevel@tonic-gate 	"/proc",
127*7c478bd9Sstevel@tonic-gate 	"/sbin",
128*7c478bd9Sstevel@tonic-gate 	CTFS_ROOT,
129*7c478bd9Sstevel@tonic-gate 	OBJFS_ROOT,
130*7c478bd9Sstevel@tonic-gate 	"/tmp",
131*7c478bd9Sstevel@tonic-gate 	"/usr",
132*7c478bd9Sstevel@tonic-gate 	"/var",
133*7c478bd9Sstevel@tonic-gate 	"/var/adm",
134*7c478bd9Sstevel@tonic-gate 	"/var/run",
135*7c478bd9Sstevel@tonic-gate 	NULL
136*7c478bd9Sstevel@tonic-gate };
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate static void	nomem();
139*7c478bd9Sstevel@tonic-gate static void	doexec(struct mnttab *);
140*7c478bd9Sstevel@tonic-gate static int	setup_iopipe(mountent_t *);
141*7c478bd9Sstevel@tonic-gate static void	setup_output(mountent_t *);
142*7c478bd9Sstevel@tonic-gate static void	doio(mountent_t *);
143*7c478bd9Sstevel@tonic-gate static void	do_umounts(mountent_t **);
144*7c478bd9Sstevel@tonic-gate static int	dowait();
145*7c478bd9Sstevel@tonic-gate static int	parumount();
146*7c478bd9Sstevel@tonic-gate static int	mcompar(const void *, const void *);
147*7c478bd9Sstevel@tonic-gate static void	cleanup(int);
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate static mountent_t	**make_mntarray(char **, int);
150*7c478bd9Sstevel@tonic-gate static mountent_t	*getmntall();
151*7c478bd9Sstevel@tonic-gate static mountent_t 	*new_mountent(struct mnttab *);
152*7c478bd9Sstevel@tonic-gate static mountent_t	*getmntlast(mountent_t *, char *, char *);
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate main(argc, argv)
155*7c478bd9Sstevel@tonic-gate 	int	argc;
156*7c478bd9Sstevel@tonic-gate 	char	**argv;
157*7c478bd9Sstevel@tonic-gate {
158*7c478bd9Sstevel@tonic-gate 	int 	cc;
159*7c478bd9Sstevel@tonic-gate 	struct mnttab  mget;
160*7c478bd9Sstevel@tonic-gate 	char 	*mname, *is_special;
161*7c478bd9Sstevel@tonic-gate 	int	fscnt;
162*7c478bd9Sstevel@tonic-gate 	mountent_t	*mp;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
167*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
168*7c478bd9Sstevel@tonic-gate #endif
169*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	myname = strrchr(argv[0], '/');
172*7c478bd9Sstevel@tonic-gate 	if (myname)
173*7c478bd9Sstevel@tonic-gate 		myname++;
174*7c478bd9Sstevel@tonic-gate 	else
175*7c478bd9Sstevel@tonic-gate 		myname = argv[0];
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	/*
178*7c478bd9Sstevel@tonic-gate 	 * Process the args.
179*7c478bd9Sstevel@tonic-gate 	 * "-d" for compatibility
180*7c478bd9Sstevel@tonic-gate 	 */
181*7c478bd9Sstevel@tonic-gate 	while ((cc = getopt(argc, argv, "ado:Vf?")) != -1)
182*7c478bd9Sstevel@tonic-gate 		switch (cc) {
183*7c478bd9Sstevel@tonic-gate 		case 'a':
184*7c478bd9Sstevel@tonic-gate 			aflg++;
185*7c478bd9Sstevel@tonic-gate 			break;
186*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
187*7c478bd9Sstevel@tonic-gate 		case 'd':
188*7c478bd9Sstevel@tonic-gate 			dflg++;
189*7c478bd9Sstevel@tonic-gate 			break;
190*7c478bd9Sstevel@tonic-gate #endif
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 		case '?':
193*7c478bd9Sstevel@tonic-gate 			usage();
194*7c478bd9Sstevel@tonic-gate 			break;
195*7c478bd9Sstevel@tonic-gate 		case 'o':
196*7c478bd9Sstevel@tonic-gate 			if (oflg)
197*7c478bd9Sstevel@tonic-gate 				usage();
198*7c478bd9Sstevel@tonic-gate 			else {
199*7c478bd9Sstevel@tonic-gate 				oflg++;
200*7c478bd9Sstevel@tonic-gate 				oarg = optarg;
201*7c478bd9Sstevel@tonic-gate 			}
202*7c478bd9Sstevel@tonic-gate 			break;
203*7c478bd9Sstevel@tonic-gate 		case 'f':
204*7c478bd9Sstevel@tonic-gate 			fflg++;
205*7c478bd9Sstevel@tonic-gate 			break;
206*7c478bd9Sstevel@tonic-gate 		case 'V':
207*7c478bd9Sstevel@tonic-gate 			if (Vflg)
208*7c478bd9Sstevel@tonic-gate 				usage();
209*7c478bd9Sstevel@tonic-gate 			else
210*7c478bd9Sstevel@tonic-gate 				Vflg++;
211*7c478bd9Sstevel@tonic-gate 			break;
212*7c478bd9Sstevel@tonic-gate 		default:
213*7c478bd9Sstevel@tonic-gate 			usage();
214*7c478bd9Sstevel@tonic-gate 			break;
215*7c478bd9Sstevel@tonic-gate 		}
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	fscnt = argc - optind;
218*7c478bd9Sstevel@tonic-gate 	if (!aflg && fscnt != 1)
219*7c478bd9Sstevel@tonic-gate 		usage();
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	/* copy '--' to specific */
222*7c478bd9Sstevel@tonic-gate 	if (strcmp(argv[optind-1], "--") == 0)
223*7c478bd9Sstevel@tonic-gate 		dashflg++;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	/*
226*7c478bd9Sstevel@tonic-gate 	 * mnttab may be a symlink to a file in another file system.
227*7c478bd9Sstevel@tonic-gate 	 * This happens during install when / is mounted read-only
228*7c478bd9Sstevel@tonic-gate 	 * and /etc/mnttab is symlinked to a file in /tmp.
229*7c478bd9Sstevel@tonic-gate 	 * If this is the case, we need to follow the symlink to the
230*7c478bd9Sstevel@tonic-gate 	 * read-write file itself so that the subsequent mnttab.temp
231*7c478bd9Sstevel@tonic-gate 	 * open and rename will work.
232*7c478bd9Sstevel@tonic-gate 	 */
233*7c478bd9Sstevel@tonic-gate 	if (realpath(MNTTAB, mnttab) == NULL) {
234*7c478bd9Sstevel@tonic-gate 		strcpy(mnttab, MNTTAB);
235*7c478bd9Sstevel@tonic-gate 	}
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	/*
238*7c478bd9Sstevel@tonic-gate 	 * bugid 1205242
239*7c478bd9Sstevel@tonic-gate 	 * call the realpath() here, so that if the user is
240*7c478bd9Sstevel@tonic-gate 	 * trying to umount an autofs directory, the directory
241*7c478bd9Sstevel@tonic-gate 	 * is forced to mount.
242*7c478bd9Sstevel@tonic-gate 	 */
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	mname = argv[optind];
245*7c478bd9Sstevel@tonic-gate 	is_special = realpath(mname, resolve);
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	/*
248*7c478bd9Sstevel@tonic-gate 	 * Read the whole mnttab into memory.
249*7c478bd9Sstevel@tonic-gate 	 */
250*7c478bd9Sstevel@tonic-gate 	mntll = getmntall();
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	if (aflg && fscnt != 1)
253*7c478bd9Sstevel@tonic-gate 		exit(parumount(argv + optind, fscnt));
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	aflg = 0;
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	mntnull(&mget);
258*7c478bd9Sstevel@tonic-gate 	if (listlength == 0) {
259*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(
260*7c478bd9Sstevel@tonic-gate 			"%s: warning: no entries found in %s\n"),
261*7c478bd9Sstevel@tonic-gate 				myname, mnttab);
262*7c478bd9Sstevel@tonic-gate 		mget.mnt_mountp = mname;	/* assume mount point */
263*7c478bd9Sstevel@tonic-gate 		no_mnttab++;
264*7c478bd9Sstevel@tonic-gate 		doexec(&mget);
265*7c478bd9Sstevel@tonic-gate 		exit(0);
266*7c478bd9Sstevel@tonic-gate 	}
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	mp = NULL;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	/*
271*7c478bd9Sstevel@tonic-gate 	 * if realpath fails, it can't be a mount point, so we'll
272*7c478bd9Sstevel@tonic-gate 	 * go straight to the code that treats the arg as a special.
273*7c478bd9Sstevel@tonic-gate 	 * if realpath succeeds, it could be a special or a mount point;
274*7c478bd9Sstevel@tonic-gate 	 * we'll start by assuming it's a mount point, and if it's not,
275*7c478bd9Sstevel@tonic-gate 	 * try to treat it as a special.
276*7c478bd9Sstevel@tonic-gate 	 */
277*7c478bd9Sstevel@tonic-gate 	if (is_special != NULL) {
278*7c478bd9Sstevel@tonic-gate 		/*
279*7c478bd9Sstevel@tonic-gate 		 * if this succeeds,
280*7c478bd9Sstevel@tonic-gate 		 * we'll have the appropriate record; if it fails
281*7c478bd9Sstevel@tonic-gate 		 * we'll assume the arg is a special of some sort
282*7c478bd9Sstevel@tonic-gate 		 */
283*7c478bd9Sstevel@tonic-gate 		mp = getmntlast(mntll, NULL, resolve);
284*7c478bd9Sstevel@tonic-gate 	}
285*7c478bd9Sstevel@tonic-gate 	/*
286*7c478bd9Sstevel@tonic-gate 	 * Since stackable mount is allowed (RFE 2001535),
287*7c478bd9Sstevel@tonic-gate 	 * we will un-mount the last entry in the MNTTAB that matches.
288*7c478bd9Sstevel@tonic-gate 	 */
289*7c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
290*7c478bd9Sstevel@tonic-gate 		/*
291*7c478bd9Sstevel@tonic-gate 		 * Perhaps there is a bogus mnttab entry that
292*7c478bd9Sstevel@tonic-gate 		 * can't be resolved:
293*7c478bd9Sstevel@tonic-gate 		 */
294*7c478bd9Sstevel@tonic-gate 		if ((mp = getmntlast(mntll, NULL, mname)) == NULL)
295*7c478bd9Sstevel@tonic-gate 			/*
296*7c478bd9Sstevel@tonic-gate 			 * assume it's a device (special) now
297*7c478bd9Sstevel@tonic-gate 			 */
298*7c478bd9Sstevel@tonic-gate 			mp = getmntlast(mntll, mname, NULL);
299*7c478bd9Sstevel@tonic-gate 		if (mp) {
300*7c478bd9Sstevel@tonic-gate 			/*
301*7c478bd9Sstevel@tonic-gate 			 * Found it.
302*7c478bd9Sstevel@tonic-gate 			 * This is a device. Now we want to know if
303*7c478bd9Sstevel@tonic-gate 			 * it stackmounted on by something else.
304*7c478bd9Sstevel@tonic-gate 			 * The original fix for bug 1103850 has a
305*7c478bd9Sstevel@tonic-gate 			 * problem with lockfs (bug 1119731). This
306*7c478bd9Sstevel@tonic-gate 			 * is a revised method.
307*7c478bd9Sstevel@tonic-gate 			 */
308*7c478bd9Sstevel@tonic-gate 			mountent_t *lmp;
309*7c478bd9Sstevel@tonic-gate 			lmp = getmntlast(mntll, NULL, mp->ment.mnt_mountp);
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 			if (lmp && strcmp(lmp->ment.mnt_special,
312*7c478bd9Sstevel@tonic-gate 					mp->ment.mnt_special)) {
313*7c478bd9Sstevel@tonic-gate 				errno = EBUSY;
314*7c478bd9Sstevel@tonic-gate 				rpterr(mname);
315*7c478bd9Sstevel@tonic-gate 				exit(1);
316*7c478bd9Sstevel@tonic-gate 			}
317*7c478bd9Sstevel@tonic-gate 		} else {
318*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext(
319*7c478bd9Sstevel@tonic-gate 				"%s: warning: %s not in mnttab\n"),
320*7c478bd9Sstevel@tonic-gate 				myname, mname);
321*7c478bd9Sstevel@tonic-gate 			if (Vflg)
322*7c478bd9Sstevel@tonic-gate 				exit(1);
323*7c478bd9Sstevel@tonic-gate 				/*
324*7c478bd9Sstevel@tonic-gate 				 * same error as mount -V
325*7c478bd9Sstevel@tonic-gate 				 * would give for unknown
326*7c478bd9Sstevel@tonic-gate 				 * mount point
327*7c478bd9Sstevel@tonic-gate 				 */
328*7c478bd9Sstevel@tonic-gate 			mget.mnt_special = mget.mnt_mountp = mname;
329*7c478bd9Sstevel@tonic-gate 		}
330*7c478bd9Sstevel@tonic-gate 	}
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	if (mp)
333*7c478bd9Sstevel@tonic-gate 		doexec(&mp->ment);
334*7c478bd9Sstevel@tonic-gate 	else
335*7c478bd9Sstevel@tonic-gate 		doexec(&mget);
336*7c478bd9Sstevel@tonic-gate 
337*7c478bd9Sstevel@tonic-gate 	exit(0);
338*7c478bd9Sstevel@tonic-gate }
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate void
341*7c478bd9Sstevel@tonic-gate doexec(struct mnttab *ment)
342*7c478bd9Sstevel@tonic-gate {
343*7c478bd9Sstevel@tonic-gate 	int 	ret;
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
346*7c478bd9Sstevel@tonic-gate 	if (dflg)
347*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "%d: umounting %s\n",
348*7c478bd9Sstevel@tonic-gate 			getpid(), ment->mnt_mountp);
349*7c478bd9Sstevel@tonic-gate #endif
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	/* try to exec the dependent portion */
352*7c478bd9Sstevel@tonic-gate 	if ((ment->mnt_fstype != NULL) || Vflg) {
353*7c478bd9Sstevel@tonic-gate 		char	full_path[FULLPATH_MAX];
354*7c478bd9Sstevel@tonic-gate 		char	alter_path[FULLPATH_MAX];
355*7c478bd9Sstevel@tonic-gate 		char	*newargv[ARGV_MAX];
356*7c478bd9Sstevel@tonic-gate 		int 	ii;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 		if (strlen(ment->mnt_fstype) > (size_t)FSTYPE_MAX) {
359*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext(
360*7c478bd9Sstevel@tonic-gate 				"%s: FSType %s exceeds %d characters\n"),
361*7c478bd9Sstevel@tonic-gate 				myname, ment->mnt_fstype, FSTYPE_MAX);
362*7c478bd9Sstevel@tonic-gate 			exit(1);
363*7c478bd9Sstevel@tonic-gate 		}
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 		/* build the full pathname of the fstype dependent command. */
366*7c478bd9Sstevel@tonic-gate 		sprintf(full_path, "%s/%s/%s", fs_path, ment->mnt_fstype,
367*7c478bd9Sstevel@tonic-gate 					myname);
368*7c478bd9Sstevel@tonic-gate 		sprintf(alter_path, "%s/%s/%s", alt_path, ment->mnt_fstype,
369*7c478bd9Sstevel@tonic-gate 					myname);
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 		/*
372*7c478bd9Sstevel@tonic-gate 		 * create the new arg list, and end the list with a
373*7c478bd9Sstevel@tonic-gate 		 * null pointer
374*7c478bd9Sstevel@tonic-gate 		 */
375*7c478bd9Sstevel@tonic-gate 		ii = 2;
376*7c478bd9Sstevel@tonic-gate 		if (oflg) {
377*7c478bd9Sstevel@tonic-gate 			newargv[ii++] = "-o";
378*7c478bd9Sstevel@tonic-gate 			newargv[ii++] = oarg;
379*7c478bd9Sstevel@tonic-gate 		}
380*7c478bd9Sstevel@tonic-gate 		if (dashflg) {
381*7c478bd9Sstevel@tonic-gate 			newargv[ii++] = "--";
382*7c478bd9Sstevel@tonic-gate 		}
383*7c478bd9Sstevel@tonic-gate 		if (fflg) {
384*7c478bd9Sstevel@tonic-gate 			newargv[ii++] = "-f";
385*7c478bd9Sstevel@tonic-gate 		}
386*7c478bd9Sstevel@tonic-gate 		newargv[ii++] = (ment->mnt_mountp)
387*7c478bd9Sstevel@tonic-gate 				? ment->mnt_mountp : ment->mnt_special;
388*7c478bd9Sstevel@tonic-gate 		newargv[ii] = NULL;
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 		/* set the new argv[0] to the filename */
391*7c478bd9Sstevel@tonic-gate 		newargv[1] = myname;
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 		if (Vflg) {
394*7c478bd9Sstevel@tonic-gate 			printf("%s", myname);
395*7c478bd9Sstevel@tonic-gate 			for (ii = 2; newargv[ii]; ii++)
396*7c478bd9Sstevel@tonic-gate 				printf(" %s", newargv[ii]);
397*7c478bd9Sstevel@tonic-gate 			printf("\n");
398*7c478bd9Sstevel@tonic-gate 			fflush(stdout);
399*7c478bd9Sstevel@tonic-gate 			exit(0);
400*7c478bd9Sstevel@tonic-gate 		}
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 		/* Try to exec the fstype dependent umount. */
403*7c478bd9Sstevel@tonic-gate 		execv(full_path, &newargv[1]);
404*7c478bd9Sstevel@tonic-gate 		if (errno == ENOEXEC) {
405*7c478bd9Sstevel@tonic-gate 			newargv[0] = "sh";
406*7c478bd9Sstevel@tonic-gate 			newargv[1] = full_path;
407*7c478bd9Sstevel@tonic-gate 			execv("/sbin/sh", &newargv[0]);
408*7c478bd9Sstevel@tonic-gate 		}
409*7c478bd9Sstevel@tonic-gate 		newargv[1] = myname;
410*7c478bd9Sstevel@tonic-gate 		execv(alter_path, &newargv[1]);
411*7c478bd9Sstevel@tonic-gate 		if (errno == ENOEXEC) {
412*7c478bd9Sstevel@tonic-gate 			newargv[0] = "sh";
413*7c478bd9Sstevel@tonic-gate 			newargv[1] = alter_path;
414*7c478bd9Sstevel@tonic-gate 			execv("/sbin/sh", &newargv[0]);
415*7c478bd9Sstevel@tonic-gate 		}
416*7c478bd9Sstevel@tonic-gate 		/* exec failed */
417*7c478bd9Sstevel@tonic-gate 		if (errno != ENOENT) {
418*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext("umount: cannot execute %s\n"),
419*7c478bd9Sstevel@tonic-gate 					full_path);
420*7c478bd9Sstevel@tonic-gate 			exit(1);
421*7c478bd9Sstevel@tonic-gate 		}
422*7c478bd9Sstevel@tonic-gate 	}
423*7c478bd9Sstevel@tonic-gate 	/*
424*7c478bd9Sstevel@tonic-gate 	 * No fstype independent executable then.  We'll go generic
425*7c478bd9Sstevel@tonic-gate 	 * from here.
426*7c478bd9Sstevel@tonic-gate 	 */
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	/* don't use -o with generic */
429*7c478bd9Sstevel@tonic-gate 	if (oflg) {
430*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(
431*7c478bd9Sstevel@tonic-gate 	"%s: %s specific umount does not exist; -o suboption ignored\n"),
432*7c478bd9Sstevel@tonic-gate 		myname, ment->mnt_fstype ? ment->mnt_fstype : "<null>");
433*7c478bd9Sstevel@tonic-gate 	}
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	signal(SIGHUP,  SIG_IGN);
436*7c478bd9Sstevel@tonic-gate 	signal(SIGQUIT, SIG_IGN);
437*7c478bd9Sstevel@tonic-gate 	signal(SIGINT,  SIG_IGN);
438*7c478bd9Sstevel@tonic-gate 	/*
439*7c478bd9Sstevel@tonic-gate 	 * Try to umount the mountpoint.
440*7c478bd9Sstevel@tonic-gate 	 * If that fails, try the corresponding special.
441*7c478bd9Sstevel@tonic-gate 	 * (This ordering is necessary for nfs umounts.)
442*7c478bd9Sstevel@tonic-gate 	 * (for remote resources:  if the first umount returns EBUSY
443*7c478bd9Sstevel@tonic-gate 	 * don't call umount again - umount() with a resource name
444*7c478bd9Sstevel@tonic-gate 	 * will return a misleading error to the user
445*7c478bd9Sstevel@tonic-gate 	 */
446*7c478bd9Sstevel@tonic-gate 	if (fflg) {
447*7c478bd9Sstevel@tonic-gate 		if (((ret = umount2(ment->mnt_mountp, MS_FORCE)) < 0) &&
448*7c478bd9Sstevel@tonic-gate 				(errno != EBUSY && errno != ENOTSUP &&
449*7c478bd9Sstevel@tonic-gate 				errno != EPERM))
450*7c478bd9Sstevel@tonic-gate 			ret = umount2(ment->mnt_special, MS_FORCE);
451*7c478bd9Sstevel@tonic-gate 	} else {
452*7c478bd9Sstevel@tonic-gate 		if (((ret = umount2(ment->mnt_mountp, 0)) < 0) &&
453*7c478bd9Sstevel@tonic-gate 				(errno != EBUSY) && (errno != EPERM))
454*7c478bd9Sstevel@tonic-gate 			ret = umount2(ment->mnt_special, 0);
455*7c478bd9Sstevel@tonic-gate 	}
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	if (ret < 0) {
458*7c478bd9Sstevel@tonic-gate 		rpterr(ment->mnt_mountp);
459*7c478bd9Sstevel@tonic-gate 		if (errno != EINVAL && errno != EFAULT)
460*7c478bd9Sstevel@tonic-gate 			exit(1);
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 		exitcode = 1;
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	exit(exitcode);
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate void
469*7c478bd9Sstevel@tonic-gate rpterr(sp)
470*7c478bd9Sstevel@tonic-gate 	char	*sp;
471*7c478bd9Sstevel@tonic-gate {
472*7c478bd9Sstevel@tonic-gate 	switch (errno) {
473*7c478bd9Sstevel@tonic-gate 	case EPERM:
474*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: permission denied\n"), myname);
475*7c478bd9Sstevel@tonic-gate 		break;
476*7c478bd9Sstevel@tonic-gate 	case ENXIO:
477*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: %s no device\n"), myname, sp);
478*7c478bd9Sstevel@tonic-gate 		break;
479*7c478bd9Sstevel@tonic-gate 	case ENOENT:
480*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
481*7c478bd9Sstevel@tonic-gate 			gettext("%s: %s no such file or directory\n"),
482*7c478bd9Sstevel@tonic-gate 			myname, sp);
483*7c478bd9Sstevel@tonic-gate 		break;
484*7c478bd9Sstevel@tonic-gate 	case EINVAL:
485*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: %s not mounted\n"), myname, sp);
486*7c478bd9Sstevel@tonic-gate 		break;
487*7c478bd9Sstevel@tonic-gate 	case EBUSY:
488*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: %s busy\n"), myname, sp);
489*7c478bd9Sstevel@tonic-gate 		break;
490*7c478bd9Sstevel@tonic-gate 	case ENOTBLK:
491*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
492*7c478bd9Sstevel@tonic-gate 			gettext("%s: %s block device required\n"), myname, sp);
493*7c478bd9Sstevel@tonic-gate 		break;
494*7c478bd9Sstevel@tonic-gate 	case ECOMM:
495*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
496*7c478bd9Sstevel@tonic-gate 			gettext("%s: warning: broken link detected\n"), myname);
497*7c478bd9Sstevel@tonic-gate 		break;
498*7c478bd9Sstevel@tonic-gate 	default:
499*7c478bd9Sstevel@tonic-gate 		perror(myname);
500*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: cannot unmount %s\n"), myname, sp);
501*7c478bd9Sstevel@tonic-gate 	}
502*7c478bd9Sstevel@tonic-gate }
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate void
505*7c478bd9Sstevel@tonic-gate usage()
506*7c478bd9Sstevel@tonic-gate {
507*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, gettext(
508*7c478bd9Sstevel@tonic-gate "Usage:\n%s [-f] [-V] [-o specific_options] {special | mount-point}\n"),
509*7c478bd9Sstevel@tonic-gate 		myname);
510*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, gettext(
511*7c478bd9Sstevel@tonic-gate "%s -a [-f] [-V] [-o specific_options] [mount_point ...]\n"), myname);
512*7c478bd9Sstevel@tonic-gate 	exit(1);
513*7c478bd9Sstevel@tonic-gate }
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate void
516*7c478bd9Sstevel@tonic-gate mnterror(flag)
517*7c478bd9Sstevel@tonic-gate 	int	flag;
518*7c478bd9Sstevel@tonic-gate {
519*7c478bd9Sstevel@tonic-gate 	switch (flag) {
520*7c478bd9Sstevel@tonic-gate 	case MNT_TOOLONG:
521*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
522*7c478bd9Sstevel@tonic-gate 			gettext("%s: line in mnttab exceeds %d characters\n"),
523*7c478bd9Sstevel@tonic-gate 			myname, MNT_LINE_MAX-2);
524*7c478bd9Sstevel@tonic-gate 		break;
525*7c478bd9Sstevel@tonic-gate 	case MNT_TOOFEW:
526*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
527*7c478bd9Sstevel@tonic-gate 			gettext("%s: line in mnttab has too few entries\n"),
528*7c478bd9Sstevel@tonic-gate 			myname);
529*7c478bd9Sstevel@tonic-gate 		break;
530*7c478bd9Sstevel@tonic-gate 	default:
531*7c478bd9Sstevel@tonic-gate 		break;
532*7c478bd9Sstevel@tonic-gate 	}
533*7c478bd9Sstevel@tonic-gate }
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate /*
536*7c478bd9Sstevel@tonic-gate  * Search the mlist linked list for the
537*7c478bd9Sstevel@tonic-gate  * first match of specp or mntp.  The list is expected to be in reverse
538*7c478bd9Sstevel@tonic-gate  * order of /etc/mnttab.
539*7c478bd9Sstevel@tonic-gate  * If both are specified, then both have to match.
540*7c478bd9Sstevel@tonic-gate  * Returns the (mountent_t *) of the match, otherwise returns NULL.
541*7c478bd9Sstevel@tonic-gate  */
542*7c478bd9Sstevel@tonic-gate mountent_t *
543*7c478bd9Sstevel@tonic-gate getmntlast(mountent_t *mlist, char *specp, char *mntp)
544*7c478bd9Sstevel@tonic-gate {
545*7c478bd9Sstevel@tonic-gate 	int		mfound, sfound;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	for (/* */; mlist; mlist = mlist->link) {
548*7c478bd9Sstevel@tonic-gate 		mfound = sfound = 0;
549*7c478bd9Sstevel@tonic-gate 		if (mntp && (strcmp(mlist->ment.mnt_mountp, mntp) == 0)) {
550*7c478bd9Sstevel@tonic-gate 			if (specp == NULL)
551*7c478bd9Sstevel@tonic-gate 				return (mlist);
552*7c478bd9Sstevel@tonic-gate 			mfound++;
553*7c478bd9Sstevel@tonic-gate 		}
554*7c478bd9Sstevel@tonic-gate 		if (specp && (strcmp(mlist->ment.mnt_special, specp) == 0)) {
555*7c478bd9Sstevel@tonic-gate 			if (mntp == NULL)
556*7c478bd9Sstevel@tonic-gate 				return (mlist);
557*7c478bd9Sstevel@tonic-gate 			sfound++;
558*7c478bd9Sstevel@tonic-gate 		}
559*7c478bd9Sstevel@tonic-gate 		if (mfound && sfound)
560*7c478bd9Sstevel@tonic-gate 			return (mlist);
561*7c478bd9Sstevel@tonic-gate 	}
562*7c478bd9Sstevel@tonic-gate 	return (NULL);
563*7c478bd9Sstevel@tonic-gate }
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate /*
568*7c478bd9Sstevel@tonic-gate  * Perform the parallel version of umount.  Returns 0 if no errors occurred,
569*7c478bd9Sstevel@tonic-gate  * non zero otherwise.
570*7c478bd9Sstevel@tonic-gate  */
571*7c478bd9Sstevel@tonic-gate int
572*7c478bd9Sstevel@tonic-gate parumount(char **mntlist, int count)
573*7c478bd9Sstevel@tonic-gate {
574*7c478bd9Sstevel@tonic-gate 	int 		maxfd = OPEN_MAX;
575*7c478bd9Sstevel@tonic-gate 	struct rlimit 	rl;
576*7c478bd9Sstevel@tonic-gate 	mountent_t	**mntarray, **ml, *mp;
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	/*
579*7c478bd9Sstevel@tonic-gate 	 * If no mount points are specified and none were found in mnttab,
580*7c478bd9Sstevel@tonic-gate 	 * then end it all here.
581*7c478bd9Sstevel@tonic-gate 	 */
582*7c478bd9Sstevel@tonic-gate 	if (count == 0 && mntll == NULL)
583*7c478bd9Sstevel@tonic-gate 		return (0);
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	/*
586*7c478bd9Sstevel@tonic-gate 	 * This is the process scaling section.  After running a series
587*7c478bd9Sstevel@tonic-gate 	 * of tests based on the number of simultaneous processes and
588*7c478bd9Sstevel@tonic-gate 	 * processors available, optimum performance was achieved near or
589*7c478bd9Sstevel@tonic-gate 	 * at (PROCN * 2).
590*7c478bd9Sstevel@tonic-gate 	 */
591*7c478bd9Sstevel@tonic-gate 	if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1)
592*7c478bd9Sstevel@tonic-gate 		maxrun = 4;
593*7c478bd9Sstevel@tonic-gate 	else
594*7c478bd9Sstevel@tonic-gate 		maxrun = maxrun * 2 + 1;
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
597*7c478bd9Sstevel@tonic-gate 		rl.rlim_cur = rl.rlim_max;
598*7c478bd9Sstevel@tonic-gate 		if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
599*7c478bd9Sstevel@tonic-gate 			maxfd = (int)rl.rlim_cur;
600*7c478bd9Sstevel@tonic-gate 	}
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	/*
603*7c478bd9Sstevel@tonic-gate 	 * The parent needs to maintain 3 of its own fd's, plus 2 for
604*7c478bd9Sstevel@tonic-gate 	 * each child (the stdout and stderr pipes).
605*7c478bd9Sstevel@tonic-gate 	 */
606*7c478bd9Sstevel@tonic-gate 	maxfd = (maxfd / 2) - 6;	/* 6 takes care of temporary  */
607*7c478bd9Sstevel@tonic-gate 					/* periods of open fds */
608*7c478bd9Sstevel@tonic-gate 	if (maxfd < maxrun)
609*7c478bd9Sstevel@tonic-gate 		maxrun = maxfd;
610*7c478bd9Sstevel@tonic-gate 	if (maxrun < 4)
611*7c478bd9Sstevel@tonic-gate 		maxrun = 4;		/* sanity check */
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	mntarray = make_mntarray(mntlist, count);
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	if (listlength == 0) {
616*7c478bd9Sstevel@tonic-gate 		if (count == 0)		/* not an error, just none found */
617*7c478bd9Sstevel@tonic-gate 			return (0);
618*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: no valid entries found in %s\n"),
619*7c478bd9Sstevel@tonic-gate 				myname, mnttab);
620*7c478bd9Sstevel@tonic-gate 		return (1);
621*7c478bd9Sstevel@tonic-gate 	}
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 	/*
624*7c478bd9Sstevel@tonic-gate 	 * Sort the entries based on their mount level only if lofs's are
625*7c478bd9Sstevel@tonic-gate 	 * not present.
626*7c478bd9Sstevel@tonic-gate 	 */
627*7c478bd9Sstevel@tonic-gate 	if (lofscnt == 0) {
628*7c478bd9Sstevel@tonic-gate 		qsort((void *)mntarray, listlength, sizeof (mountent_t *),
629*7c478bd9Sstevel@tonic-gate 			mcompar);
630*7c478bd9Sstevel@tonic-gate 		/*
631*7c478bd9Sstevel@tonic-gate 		 * If we do not detect a lofs by now, we never will.
632*7c478bd9Sstevel@tonic-gate 		 */
633*7c478bd9Sstevel@tonic-gate 		lofscnt = -1;
634*7c478bd9Sstevel@tonic-gate 	}
635*7c478bd9Sstevel@tonic-gate 	/*
636*7c478bd9Sstevel@tonic-gate 	 * Now link them up so that a given pid is easier to find when
637*7c478bd9Sstevel@tonic-gate 	 * we go to clean up after they are done.
638*7c478bd9Sstevel@tonic-gate 	 */
639*7c478bd9Sstevel@tonic-gate 	mntll = mntarray[0];
640*7c478bd9Sstevel@tonic-gate 	for (ml = mntarray; mp = *ml; /* */)
641*7c478bd9Sstevel@tonic-gate 		mp->link = *++ml;
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 	/*
644*7c478bd9Sstevel@tonic-gate 	 * Try to handle interrupts in a reasonable way.
645*7c478bd9Sstevel@tonic-gate 	 */
646*7c478bd9Sstevel@tonic-gate 	sigset(SIGHUP, cleanup);
647*7c478bd9Sstevel@tonic-gate 	sigset(SIGQUIT, cleanup);
648*7c478bd9Sstevel@tonic-gate 	sigset(SIGINT, cleanup);
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 	do_umounts(mntarray);	/* do the umounts */
651*7c478bd9Sstevel@tonic-gate 	return (exitcode);
652*7c478bd9Sstevel@tonic-gate }
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate /*
655*7c478bd9Sstevel@tonic-gate  * Returns a mountent_t array based on mntlist.  If mntlist is NULL, then
656*7c478bd9Sstevel@tonic-gate  * it returns all mnttab entries with a few exceptions.  Sets the global
657*7c478bd9Sstevel@tonic-gate  * variable listlength to the number of entries in the array.
658*7c478bd9Sstevel@tonic-gate  */
659*7c478bd9Sstevel@tonic-gate mountent_t **
660*7c478bd9Sstevel@tonic-gate make_mntarray(char **mntlist, int count)
661*7c478bd9Sstevel@tonic-gate {
662*7c478bd9Sstevel@tonic-gate 	mountent_t 	*mp, **mpp;
663*7c478bd9Sstevel@tonic-gate 	int 		ndx;
664*7c478bd9Sstevel@tonic-gate 	char		*cp;
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	if (count > 0)
667*7c478bd9Sstevel@tonic-gate 		listlength = count;
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 	mpp = (mountent_t **)malloc(sizeof (*mp) * (listlength + 1));
670*7c478bd9Sstevel@tonic-gate 	if (mpp == NULL)
671*7c478bd9Sstevel@tonic-gate 		nomem();
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 	if (count == 0) {
674*7c478bd9Sstevel@tonic-gate 		if (mntll == NULL) {	/* no entries? */
675*7c478bd9Sstevel@tonic-gate 			listlength = 0;
676*7c478bd9Sstevel@tonic-gate 			return (NULL);
677*7c478bd9Sstevel@tonic-gate 		}
678*7c478bd9Sstevel@tonic-gate 		/*
679*7c478bd9Sstevel@tonic-gate 		 * No mount list specified: take all mnttab mount points
680*7c478bd9Sstevel@tonic-gate 		 * except for a few cases.
681*7c478bd9Sstevel@tonic-gate 		 */
682*7c478bd9Sstevel@tonic-gate 		for (ndx = 0, mp = mntll; mp; mp = mp->link) {
683*7c478bd9Sstevel@tonic-gate 			if (fsstrinlist(mp->ment.mnt_mountp, keeplist))
684*7c478bd9Sstevel@tonic-gate 				continue;
685*7c478bd9Sstevel@tonic-gate 			mp->mlevel = fsgetmlevel(mp->ment.mnt_mountp);
686*7c478bd9Sstevel@tonic-gate 			if (mp->ment.mnt_fstype &&
687*7c478bd9Sstevel@tonic-gate 			    (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0))
688*7c478bd9Sstevel@tonic-gate 				lofscnt++;
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 			mpp[ndx++] = mp;
691*7c478bd9Sstevel@tonic-gate 		}
692*7c478bd9Sstevel@tonic-gate 		mpp[ndx] = NULL;
693*7c478bd9Sstevel@tonic-gate 		listlength = ndx;
694*7c478bd9Sstevel@tonic-gate 		return (mpp);
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	/*
698*7c478bd9Sstevel@tonic-gate 	 * A list of mount points was specified on the command line.
699*7c478bd9Sstevel@tonic-gate 	 * Build an array out of these.
700*7c478bd9Sstevel@tonic-gate 	 */
701*7c478bd9Sstevel@tonic-gate 	for (ndx = 0; count--; ) {
702*7c478bd9Sstevel@tonic-gate 		cp = *mntlist++;
703*7c478bd9Sstevel@tonic-gate 		if (realpath(cp, resolve) == NULL) {
704*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
705*7c478bd9Sstevel@tonic-gate 				gettext("%s: warning: can't resolve %s\n"),
706*7c478bd9Sstevel@tonic-gate 				myname, cp);
707*7c478bd9Sstevel@tonic-gate 			exitcode = 1;
708*7c478bd9Sstevel@tonic-gate 			mp = getmntlast(mntll, NULL, cp); /* try anyways */
709*7c478bd9Sstevel@tonic-gate 		} else
710*7c478bd9Sstevel@tonic-gate 			mp = getmntlast(mntll, NULL, resolve);
711*7c478bd9Sstevel@tonic-gate 		if (mp == NULL) {
712*7c478bd9Sstevel@tonic-gate 			struct mnttab mnew;
713*7c478bd9Sstevel@tonic-gate 			/*
714*7c478bd9Sstevel@tonic-gate 			 * Then we've reached the end without finding
715*7c478bd9Sstevel@tonic-gate 			 * what we are looking for, but we still have to
716*7c478bd9Sstevel@tonic-gate 			 * try to umount it: append it to mntarray.
717*7c478bd9Sstevel@tonic-gate 			 */
718*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext(
719*7c478bd9Sstevel@tonic-gate 				"%s: warning: %s not found in %s\n"),
720*7c478bd9Sstevel@tonic-gate 				myname, resolve, mnttab);
721*7c478bd9Sstevel@tonic-gate 			exitcode = 1;
722*7c478bd9Sstevel@tonic-gate 			mntnull(&mnew);
723*7c478bd9Sstevel@tonic-gate 			mnew.mnt_special = mnew.mnt_mountp = strdup(resolve);
724*7c478bd9Sstevel@tonic-gate 			if (mnew.mnt_special == NULL)
725*7c478bd9Sstevel@tonic-gate 				nomem();
726*7c478bd9Sstevel@tonic-gate 			mp = new_mountent(&mnew);
727*7c478bd9Sstevel@tonic-gate 		}
728*7c478bd9Sstevel@tonic-gate 		if (mp->ment.mnt_fstype &&
729*7c478bd9Sstevel@tonic-gate 		    (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0))
730*7c478bd9Sstevel@tonic-gate 			lofscnt++;
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 		mp->mlevel = fsgetmlevel(mp->ment.mnt_mountp);
733*7c478bd9Sstevel@tonic-gate 		mpp[ndx++] = mp;
734*7c478bd9Sstevel@tonic-gate 	}
735*7c478bd9Sstevel@tonic-gate 	mpp[ndx] = NULL;
736*7c478bd9Sstevel@tonic-gate 	listlength = ndx;
737*7c478bd9Sstevel@tonic-gate 	return (mpp);
738*7c478bd9Sstevel@tonic-gate }
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate /*
741*7c478bd9Sstevel@tonic-gate  * Returns the tail of a linked list of all mnttab entries.  I.e, it's faster
742*7c478bd9Sstevel@tonic-gate  * to return the mnttab in reverse order.
743*7c478bd9Sstevel@tonic-gate  * Sets listlength to the number of entries in the list.
744*7c478bd9Sstevel@tonic-gate  * Returns NULL if none are found.
745*7c478bd9Sstevel@tonic-gate  */
746*7c478bd9Sstevel@tonic-gate mountent_t *
747*7c478bd9Sstevel@tonic-gate getmntall()
748*7c478bd9Sstevel@tonic-gate {
749*7c478bd9Sstevel@tonic-gate 	FILE		*fp;
750*7c478bd9Sstevel@tonic-gate 	mountent_t	*mtail;
751*7c478bd9Sstevel@tonic-gate 	int		cnt = 0, ret;
752*7c478bd9Sstevel@tonic-gate 	struct mnttab	mget;
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(mnttab, "r")) == NULL) {
755*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("%s: warning cannot open %s\n"),
756*7c478bd9Sstevel@tonic-gate 				myname, mnttab);
757*7c478bd9Sstevel@tonic-gate 		return (0);
758*7c478bd9Sstevel@tonic-gate 	}
759*7c478bd9Sstevel@tonic-gate 	mtail = NULL;
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	while ((ret = getmntent(fp, &mget)) != -1) {
762*7c478bd9Sstevel@tonic-gate 		mountent_t	*mp;
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 		if (ret > 0) {
765*7c478bd9Sstevel@tonic-gate 			mnterror(ret);
766*7c478bd9Sstevel@tonic-gate 			continue;
767*7c478bd9Sstevel@tonic-gate 		}
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 		mp = new_mountent(&mget);
770*7c478bd9Sstevel@tonic-gate 		mp->link = mtail;
771*7c478bd9Sstevel@tonic-gate 		mtail = mp;
772*7c478bd9Sstevel@tonic-gate 		cnt++;
773*7c478bd9Sstevel@tonic-gate 	}
774*7c478bd9Sstevel@tonic-gate 	fclose(fp);
775*7c478bd9Sstevel@tonic-gate 	if (mtail == NULL) {
776*7c478bd9Sstevel@tonic-gate 		listlength = 0;
777*7c478bd9Sstevel@tonic-gate 		return (NULL);
778*7c478bd9Sstevel@tonic-gate 	}
779*7c478bd9Sstevel@tonic-gate 	listlength = cnt;
780*7c478bd9Sstevel@tonic-gate 	return (mtail);
781*7c478bd9Sstevel@tonic-gate }
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate void
784*7c478bd9Sstevel@tonic-gate do_umounts(mountent_t **mntarray)
785*7c478bd9Sstevel@tonic-gate {
786*7c478bd9Sstevel@tonic-gate 	mountent_t *mp, *mpprev, **ml = mntarray;
787*7c478bd9Sstevel@tonic-gate 	int	cnt = listlength;
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	/*
790*7c478bd9Sstevel@tonic-gate 	 * Main loop for the forked children:
791*7c478bd9Sstevel@tonic-gate 	 */
792*7c478bd9Sstevel@tonic-gate 	for (mpprev = *ml; mp = *ml; mpprev = mp, ml++, cnt--) {
793*7c478bd9Sstevel@tonic-gate 		pid_t	pid;
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 		/*
796*7c478bd9Sstevel@tonic-gate 		 * Check to see if we cross a mount level: e.g.,
797*7c478bd9Sstevel@tonic-gate 		 * /a/b/c -> /a/b.  If so, we need to wait for all current
798*7c478bd9Sstevel@tonic-gate 		 * umounts to finish before umounting the rest.
799*7c478bd9Sstevel@tonic-gate 		 *
800*7c478bd9Sstevel@tonic-gate 		 * Also, we unmount serially as long as there are lofs's
801*7c478bd9Sstevel@tonic-gate 		 * to mount to avoid improper umount ordering.
802*7c478bd9Sstevel@tonic-gate 		 */
803*7c478bd9Sstevel@tonic-gate 		if (mp->mlevel < mpprev->mlevel || lofscnt > 0)
804*7c478bd9Sstevel@tonic-gate 			while (nrun > 0 && (dowait() != -1))
805*7c478bd9Sstevel@tonic-gate 				;
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 		if (lofscnt == 0) {
808*7c478bd9Sstevel@tonic-gate 			/*
809*7c478bd9Sstevel@tonic-gate 			 * We can now go to parallel umounting.
810*7c478bd9Sstevel@tonic-gate 			 */
811*7c478bd9Sstevel@tonic-gate 			qsort((void *)ml, cnt, sizeof (mountent_t *), mcompar);
812*7c478bd9Sstevel@tonic-gate 			mp = *ml;	/* possible first entry */
813*7c478bd9Sstevel@tonic-gate 			lofscnt--;	/* so we don't do this again */
814*7c478bd9Sstevel@tonic-gate 		}
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 		while (setup_iopipe(mp) == -1 && (dowait() != -1))
817*7c478bd9Sstevel@tonic-gate 			;
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 		while (nrun >= maxrun && (dowait() != -1))	/* throttle */
820*7c478bd9Sstevel@tonic-gate 			;
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate #ifdef CACHEFS_BUG
823*7c478bd9Sstevel@tonic-gate 		/*
824*7c478bd9Sstevel@tonic-gate 		 * If this is the back file system, then let cachefs/umount
825*7c478bd9Sstevel@tonic-gate 		 * unmount it.
826*7c478bd9Sstevel@tonic-gate 		 */
827*7c478bd9Sstevel@tonic-gate 		if (strstr(mp->ment.mnt_mountp, BACKMNT_NAME))
828*7c478bd9Sstevel@tonic-gate 			continue;
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 		if (mp->ment.mnt_fstype &&
832*7c478bd9Sstevel@tonic-gate 		    (strcmp(mp->ment.mnt_fstype, "cachefs") == 0)) {
833*7c478bd9Sstevel@tonic-gate 			while (cachefs_running && (dowait() != -1))
834*7c478bd9Sstevel@tonic-gate 					;
835*7c478bd9Sstevel@tonic-gate 			cachefs_running = 1;
836*7c478bd9Sstevel@tonic-gate 		}
837*7c478bd9Sstevel@tonic-gate #endif
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 		if ((pid = fork()) == -1) {
840*7c478bd9Sstevel@tonic-gate 			perror("fork");
841*7c478bd9Sstevel@tonic-gate 			cleanup(-1);
842*7c478bd9Sstevel@tonic-gate 			/* not reached */
843*7c478bd9Sstevel@tonic-gate 		}
844*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
845*7c478bd9Sstevel@tonic-gate 		if (dflg && pid > 0) {
846*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "parent %d: umounting %d %s\n",
847*7c478bd9Sstevel@tonic-gate 				getpid(), pid, mp->ment.mnt_mountp);
848*7c478bd9Sstevel@tonic-gate 		}
849*7c478bd9Sstevel@tonic-gate #endif
850*7c478bd9Sstevel@tonic-gate 		if (pid == 0) {		/* child */
851*7c478bd9Sstevel@tonic-gate 			signal(SIGHUP, SIG_IGN);
852*7c478bd9Sstevel@tonic-gate 			signal(SIGQUIT, SIG_IGN);
853*7c478bd9Sstevel@tonic-gate 			signal(SIGINT, SIG_IGN);
854*7c478bd9Sstevel@tonic-gate 			setup_output(mp);
855*7c478bd9Sstevel@tonic-gate 			doexec(&mp->ment);
856*7c478bd9Sstevel@tonic-gate 			perror("exec");
857*7c478bd9Sstevel@tonic-gate 			exit(1);
858*7c478bd9Sstevel@tonic-gate 		}
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 		/* parent */
861*7c478bd9Sstevel@tonic-gate 		(void) close(mp->sopipe[WRPIPE]);
862*7c478bd9Sstevel@tonic-gate 		(void) close(mp->sepipe[WRPIPE]);
863*7c478bd9Sstevel@tonic-gate 		mp->pid = pid;
864*7c478bd9Sstevel@tonic-gate 		nrun++;
865*7c478bd9Sstevel@tonic-gate 	}
866*7c478bd9Sstevel@tonic-gate 	cleanup(0);
867*7c478bd9Sstevel@tonic-gate }
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate /*
870*7c478bd9Sstevel@tonic-gate  * cleanup the existing children and exit with an error
871*7c478bd9Sstevel@tonic-gate  * if asig != 0.
872*7c478bd9Sstevel@tonic-gate  */
873*7c478bd9Sstevel@tonic-gate void
874*7c478bd9Sstevel@tonic-gate cleanup(int asig)
875*7c478bd9Sstevel@tonic-gate {
876*7c478bd9Sstevel@tonic-gate 	/*
877*7c478bd9Sstevel@tonic-gate 	 * Let the stragglers finish.
878*7c478bd9Sstevel@tonic-gate 	 */
879*7c478bd9Sstevel@tonic-gate 	while (nrun > 0 && (dowait() != -1))
880*7c478bd9Sstevel@tonic-gate 		;
881*7c478bd9Sstevel@tonic-gate 	if (asig != 0)
882*7c478bd9Sstevel@tonic-gate 		exit(1);
883*7c478bd9Sstevel@tonic-gate }
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate /*
887*7c478bd9Sstevel@tonic-gate  * Waits for 1 child to die.
888*7c478bd9Sstevel@tonic-gate  *
889*7c478bd9Sstevel@tonic-gate  * Returns -1 if no children are left to wait for.
890*7c478bd9Sstevel@tonic-gate  * Returns 0 if a child died without an error.
891*7c478bd9Sstevel@tonic-gate  * Returns 1 if a child died with an error.
892*7c478bd9Sstevel@tonic-gate  * Sets the global exitcode if an error occurred.
893*7c478bd9Sstevel@tonic-gate  */
894*7c478bd9Sstevel@tonic-gate int
895*7c478bd9Sstevel@tonic-gate dowait()
896*7c478bd9Sstevel@tonic-gate {
897*7c478bd9Sstevel@tonic-gate 	int		wstat, child, ret;
898*7c478bd9Sstevel@tonic-gate 	mountent_t 	*mp, *prevp;
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 	if ((child = wait(&wstat)) == -1)
901*7c478bd9Sstevel@tonic-gate 		return (-1);
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	if (WIFEXITED(wstat))		/* this should always be true */
904*7c478bd9Sstevel@tonic-gate 		ret = WEXITSTATUS(wstat);
905*7c478bd9Sstevel@tonic-gate 	else
906*7c478bd9Sstevel@tonic-gate 		ret = 1;		/* assume some kind of error */
907*7c478bd9Sstevel@tonic-gate 	nrun--;
908*7c478bd9Sstevel@tonic-gate 	if (ret)
909*7c478bd9Sstevel@tonic-gate 		exitcode = 1;
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate 	/*
912*7c478bd9Sstevel@tonic-gate 	 * Find our child so we can process its std output, if any.
913*7c478bd9Sstevel@tonic-gate 	 * This search gets smaller and smaller as children are cleaned
914*7c478bd9Sstevel@tonic-gate 	 * up.
915*7c478bd9Sstevel@tonic-gate 	 */
916*7c478bd9Sstevel@tonic-gate 	for (prevp = NULL, mp = mntll; mp; mp = mp->link) {
917*7c478bd9Sstevel@tonic-gate 		if (mp->pid != child) {
918*7c478bd9Sstevel@tonic-gate 			prevp = mp;
919*7c478bd9Sstevel@tonic-gate 			continue;
920*7c478bd9Sstevel@tonic-gate 		}
921*7c478bd9Sstevel@tonic-gate 		/*
922*7c478bd9Sstevel@tonic-gate 		 * Found: let's remove it from this list.
923*7c478bd9Sstevel@tonic-gate 		 */
924*7c478bd9Sstevel@tonic-gate 		if (prevp) {
925*7c478bd9Sstevel@tonic-gate 			prevp->link = mp->link;
926*7c478bd9Sstevel@tonic-gate 			mp->link = NULL;
927*7c478bd9Sstevel@tonic-gate 		}
928*7c478bd9Sstevel@tonic-gate 		break;
929*7c478bd9Sstevel@tonic-gate 	}
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 	if (mp == NULL) {
932*7c478bd9Sstevel@tonic-gate 		/*
933*7c478bd9Sstevel@tonic-gate 		 * This should never happen.
934*7c478bd9Sstevel@tonic-gate 		 */
935*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
936*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(
937*7c478bd9Sstevel@tonic-gate 			"%s: unknown child %d\n"), myname, child);
938*7c478bd9Sstevel@tonic-gate #endif
939*7c478bd9Sstevel@tonic-gate 		exitcode = 1;
940*7c478bd9Sstevel@tonic-gate 		return (1);
941*7c478bd9Sstevel@tonic-gate 	}
942*7c478bd9Sstevel@tonic-gate 	doio(mp);	/* Any output? */
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	if (mp->ment.mnt_fstype &&
945*7c478bd9Sstevel@tonic-gate 	    (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0))
946*7c478bd9Sstevel@tonic-gate 		lofscnt--;
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate #ifdef CACHEFS_BUG
949*7c478bd9Sstevel@tonic-gate 	if (mp->ment.mnt_fstype &&
950*7c478bd9Sstevel@tonic-gate 	    (strcmp(mp->ment.mnt_fstype, "cachefs") == 0))
951*7c478bd9Sstevel@tonic-gate 		cachefs_running = 0;
952*7c478bd9Sstevel@tonic-gate #endif
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate 	return (ret);
955*7c478bd9Sstevel@tonic-gate }
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate static const mountent_t zmount = { 0 };
958*7c478bd9Sstevel@tonic-gate 
959*7c478bd9Sstevel@tonic-gate mountent_t *
960*7c478bd9Sstevel@tonic-gate new_mountent(struct mnttab *ment)
961*7c478bd9Sstevel@tonic-gate {
962*7c478bd9Sstevel@tonic-gate 	mountent_t *new;
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	new = (mountent_t *)malloc(sizeof (*new));
965*7c478bd9Sstevel@tonic-gate 	if (new == NULL)
966*7c478bd9Sstevel@tonic-gate 		nomem();
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 	*new = zmount;
969*7c478bd9Sstevel@tonic-gate 	if (ment->mnt_special &&
970*7c478bd9Sstevel@tonic-gate 	    (new->ment.mnt_special = strdup(ment->mnt_special)) == NULL)
971*7c478bd9Sstevel@tonic-gate 		nomem();
972*7c478bd9Sstevel@tonic-gate 	if (ment->mnt_mountp &&
973*7c478bd9Sstevel@tonic-gate 	    (new->ment.mnt_mountp = strdup(ment->mnt_mountp)) == NULL)
974*7c478bd9Sstevel@tonic-gate 		nomem();
975*7c478bd9Sstevel@tonic-gate 	if (ment->mnt_fstype &&
976*7c478bd9Sstevel@tonic-gate 	    (new->ment.mnt_fstype = strdup(ment->mnt_fstype)) == NULL)
977*7c478bd9Sstevel@tonic-gate 		nomem();
978*7c478bd9Sstevel@tonic-gate 	return (new);
979*7c478bd9Sstevel@tonic-gate }
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate /*
983*7c478bd9Sstevel@tonic-gate  * Sort in descending order of "mount level".  For example, /a/b/c is
984*7c478bd9Sstevel@tonic-gate  * placed before /a/b .
985*7c478bd9Sstevel@tonic-gate  */
986*7c478bd9Sstevel@tonic-gate int
987*7c478bd9Sstevel@tonic-gate mcompar(const void *a, const void *b)
988*7c478bd9Sstevel@tonic-gate {
989*7c478bd9Sstevel@tonic-gate 	mountent_t *a1, *b1;
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 	a1 = *(mountent_t **)a;
992*7c478bd9Sstevel@tonic-gate 	b1 = *(mountent_t **)b;
993*7c478bd9Sstevel@tonic-gate 	return (b1->mlevel - a1->mlevel);
994*7c478bd9Sstevel@tonic-gate }
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate /*
997*7c478bd9Sstevel@tonic-gate  * The purpose of this routine is to form stdout and stderr
998*7c478bd9Sstevel@tonic-gate  * pipes for the children's output.  The parent then reads and writes it
999*7c478bd9Sstevel@tonic-gate  * out it serially in order to ensure that the output is
1000*7c478bd9Sstevel@tonic-gate  * not garbled.
1001*7c478bd9Sstevel@tonic-gate  */
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate int
1004*7c478bd9Sstevel@tonic-gate setup_iopipe(mountent_t *mp)
1005*7c478bd9Sstevel@tonic-gate {
1006*7c478bd9Sstevel@tonic-gate 	/*
1007*7c478bd9Sstevel@tonic-gate 	 * Make a stdout and stderr pipe.  This should never fail.
1008*7c478bd9Sstevel@tonic-gate 	 */
1009*7c478bd9Sstevel@tonic-gate 	if (pipe(mp->sopipe) == -1)
1010*7c478bd9Sstevel@tonic-gate 		return (-1);
1011*7c478bd9Sstevel@tonic-gate 	if (pipe(mp->sepipe) == -1) {
1012*7c478bd9Sstevel@tonic-gate 		(void) close(mp->sopipe[RDPIPE]);
1013*7c478bd9Sstevel@tonic-gate 		(void) close(mp->sopipe[WRPIPE]);
1014*7c478bd9Sstevel@tonic-gate 		return (-1);
1015*7c478bd9Sstevel@tonic-gate 	}
1016*7c478bd9Sstevel@tonic-gate 	/*
1017*7c478bd9Sstevel@tonic-gate 	 * Don't block on an empty pipe.
1018*7c478bd9Sstevel@tonic-gate 	 */
1019*7c478bd9Sstevel@tonic-gate 	(void) fcntl(mp->sopipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
1020*7c478bd9Sstevel@tonic-gate 	(void) fcntl(mp->sepipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
1021*7c478bd9Sstevel@tonic-gate 	return (0);
1022*7c478bd9Sstevel@tonic-gate }
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate /*
1025*7c478bd9Sstevel@tonic-gate  * Called by a child to attach its stdout and stderr to the write side of
1026*7c478bd9Sstevel@tonic-gate  * the pipes.
1027*7c478bd9Sstevel@tonic-gate  */
1028*7c478bd9Sstevel@tonic-gate void
1029*7c478bd9Sstevel@tonic-gate setup_output(mountent_t *mp)
1030*7c478bd9Sstevel@tonic-gate {
1031*7c478bd9Sstevel@tonic-gate 	(void) close(fileno(stdout));
1032*7c478bd9Sstevel@tonic-gate 	(void) dup(mp->sopipe[WRPIPE]);
1033*7c478bd9Sstevel@tonic-gate 	(void) close(mp->sopipe[WRPIPE]);
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	(void) close(fileno(stderr));
1036*7c478bd9Sstevel@tonic-gate 	(void) dup(mp->sepipe[WRPIPE]);
1037*7c478bd9Sstevel@tonic-gate 	(void) close(mp->sepipe[WRPIPE]);
1038*7c478bd9Sstevel@tonic-gate }
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate /*
1041*7c478bd9Sstevel@tonic-gate  * Parent uses this to print any stdout or stderr output issued by
1042*7c478bd9Sstevel@tonic-gate  * the child.
1043*7c478bd9Sstevel@tonic-gate  */
1044*7c478bd9Sstevel@tonic-gate static void
1045*7c478bd9Sstevel@tonic-gate doio(mountent_t *mp)
1046*7c478bd9Sstevel@tonic-gate {
1047*7c478bd9Sstevel@tonic-gate 	int bytes;
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 	while ((bytes = read(mp->sepipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
1050*7c478bd9Sstevel@tonic-gate 		write(fileno(stderr), ibuf, bytes);
1051*7c478bd9Sstevel@tonic-gate 	while ((bytes = read(mp->sopipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
1052*7c478bd9Sstevel@tonic-gate 		write(fileno(stdout), ibuf, bytes);
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 	(void) close(mp->sopipe[RDPIPE]);
1055*7c478bd9Sstevel@tonic-gate 	(void) close(mp->sepipe[RDPIPE]);
1056*7c478bd9Sstevel@tonic-gate }
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate void
1059*7c478bd9Sstevel@tonic-gate nomem()
1060*7c478bd9Sstevel@tonic-gate {
1061*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, gettext("%s: out of memory\n"), myname);
1062*7c478bd9Sstevel@tonic-gate 	/*
1063*7c478bd9Sstevel@tonic-gate 	 * Let the stragglers finish.
1064*7c478bd9Sstevel@tonic-gate 	 */
1065*7c478bd9Sstevel@tonic-gate 	while (nrun > 0 && (dowait() != -1))
1066*7c478bd9Sstevel@tonic-gate 		;
1067*7c478bd9Sstevel@tonic-gate 	exit(1);
1068*7c478bd9Sstevel@tonic-gate }
1069