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