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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     22 /*	  All Rights Reserved  	*/
     23 
     24 
     25 /*
     26  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     27  * Use is subject to license terms.
     28  */
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.82	*/
     31 
     32 #include	<stdio.h>
     33 #include	<stdio_ext.h>
     34 #include 	<limits.h>
     35 #include 	<fcntl.h>
     36 #include 	<unistd.h>
     37 #include	<stdlib.h>
     38 #include	<string.h>
     39 #include	<stdarg.h>
     40 #include	<sys/types.h>
     41 #include	<sys/stat.h>
     42 #include	<sys/statvfs.h>
     43 #include	<errno.h>
     44 #include	<sys/mnttab.h>
     45 #include	<sys/mntent.h>
     46 #include	<sys/mount.h>
     47 #include	<sys/vfstab.h>
     48 #include	<sys/param.h>
     49 #include	<sys/wait.h>
     50 #include	<sys/signal.h>
     51 #include	<sys/resource.h>
     52 #include	<stropts.h>
     53 #include	<sys/conf.h>
     54 #include	<locale.h>
     55 #include	"fslib.h"
     56 
     57 #define	VFS_PATH	"/usr/lib/fs"
     58 #define	ALT_PATH	"/etc/fs"
     59 #define	REMOTE		"/etc/dfs/fstypes"
     60 
     61 #define	ARGV_MAX	16
     62 #define	TIME_MAX	50
     63 #define	FSTYPE_MAX	8
     64 #define	REMOTE_MAX	64
     65 
     66 #define	OLD	0
     67 #define	NEW	1
     68 
     69 #define	READONLY	0
     70 #define	READWRITE	1
     71 #define	SUID 		2
     72 #define	NOSUID		3
     73 #define	SETUID 		4
     74 #define	NOSETUID	5
     75 #define	DEVICES		6
     76 #define	NODEVICES	7
     77 
     78 #define	FORMAT	"%a %b %e %H:%M:%S %Y\n"	/* date time format */
     79 				/* a - abbreviated weekday name */
     80 				/* b - abbreviated month name */
     81 				/* e - day of month */
     82 				/* H - hour */
     83 				/* M - minute */
     84 				/* S - second */
     85 				/* Y - Year */
     86 				/* n - newline */
     87 
     88 extern int	optind;
     89 extern char	*optarg;
     90 
     91 extern void	usage(void);
     92 extern char	*flags(char *, int);
     93 extern char	*remote(char *, FILE *);
     94 extern char	*default_fstype(char *);
     95 
     96 char	*myopts[] = {
     97 	MNTOPT_RO,
     98 	MNTOPT_RW,
     99 	MNTOPT_SUID,
    100 	MNTOPT_NOSUID,
    101 	MNTOPT_SETUID,
    102 	MNTOPT_NOSETUID,
    103 	MNTOPT_DEVICES,
    104 	MNTOPT_NODEVICES,
    105 	NULL
    106 };
    107 
    108 static char	*myname;		/* point to argv[0] */
    109 
    110 /*
    111  * Set the limit to double the number of characters a user should be allowed to
    112  * type in one line.
    113  * This should cover the different shells, which don't use POSIX_MAX_INPUT,
    114  * and should cover the case where a long option string can be in
    115  * the /etc/vfstab file.
    116  */
    117 char	mntflags[(_POSIX_MAX_INPUT+1) * 2];
    118 
    119 char	realdir[MAXPATHLEN];	/* buffer for realpath() calls */
    120 char	*vfstab = VFSTAB;
    121 char	*mnttab = MNTTAB;
    122 char	*specific_opts;		/* holds specific mount options */
    123 char	*generic_opts;		/* holds generic mount options */
    124 int	maxrun;
    125 int	nrun;
    126 int	lofscnt;		/* presence of lofs prohibits parallel */
    127 				/* mounting */
    128 int	exitcode;
    129 int	aflg, cflg, fflg, Fflg, gflg, oflg, pflg, rflg, vflg, Vflg, mflg, Oflg,
    130 	dashflg, questflg, dflg, qflg;
    131 
    132 /*
    133  * Currently, mounting cachefs instances simultaneously uncovers various
    134  * problems.  For the short term, we serialize cachefs activity while we fix
    135  * these cachefs bugs.
    136  */
    137 #define	CACHEFS_BUG
    138 #ifdef	CACHEFS_BUG
    139 int	cachefs_running;	/* parallel cachefs not supported yet */
    140 #endif
    141 
    142 /*
    143  * Each vfsent_t describes a vfstab entry.  It is used to manage and cleanup
    144  * each child that performs the particular mount for the entry.
    145  */
    146 
    147 typedef struct vfsent {
    148 	struct vfstab	v;		/* the vfstab entry */
    149 	char		*rpath;		/* resolved pathname so far */
    150 	int		mlevel;		/* how deep is this mount point */
    151 	int		order;		/* vfstab serial order of this vfs */
    152 	int		flag;
    153 	pid_t		pid;		/* the pid of this mount process */
    154 	int		exitcode;	/* process's exitcode */
    155 #define	RDPIPE		0
    156 #define	WRPIPE		1
    157 	int		sopipe[2];	/* pipe attached to child's stdout */
    158 	int		sepipe[2];	/* pipe attached to child's stderr */
    159 	struct vfsent	*next;		/* used when in linked list */
    160 } vfsent_t;
    161 
    162 #define	VRPFAILED	0x01		/* most recent realpath failed on */
    163 					/* this mount point */
    164 #define	VNOTMOUNTED	0x02		/* mount point could not be mounted */
    165 
    166 vfsent_t	*vfsll, *vfslltail;	/* head and tail of the global */
    167 					/* linked list of vfstab entries */
    168 vfsent_t	**vfsarray;		/* global array of vfsent_t's */
    169 int		vfsarraysize;		/* length of the list */
    170 
    171 /*
    172  * This structure is used to build a linked list of
    173  * mnttab structures from /etc/mnttab.
    174  */
    175 typedef struct mountent {
    176 	struct extmnttab	*ment;
    177 	int		flag;
    178 	struct mountent	*next;
    179 } mountent_t;
    180 
    181 #define	MSORTED		0x1
    182 
    183 static vfsent_t **make_vfsarray(char **, int);
    184 static vfsent_t	*new_vfsent(struct vfstab *, int);
    185 static vfsent_t *getvfsall(char *, int);
    186 
    187 static void	doexec(char *, char **);
    188 static void	nomem();
    189 static void	cleanup(int);
    190 static char	*setrpath(vfsent_t *);
    191 static int	dowait();
    192 static int	setup_iopipe(vfsent_t *);
    193 static void	setup_output(vfsent_t *);
    194 static void	doio(vfsent_t *);
    195 static void	do_mounts();
    196 static int	parmount(char **, int, char *);
    197 static int	mlevelcmp(const void *, const void *);
    198 static int	mordercmp(const void *, const void *);
    199 static int	check_fields(char *, char *);
    200 static int	cleanupkid(pid_t, int);
    201 static void	print_mnttab(int, int);
    202 static void	vfserror(int, char *);
    203 static void	mnterror(int);
    204 static int	ignore(char *);
    205 
    206 /*
    207  * This is /usr/sbin/mount: the generic command that in turn
    208  * execs the appropriate /usr/lib/fs/{fstype}/mount.
    209  * The -F flag and argument are NOT passed.
    210  * If the usr file system is not mounted a duplicate copy
    211  * can be found in /sbin and this version execs the
    212  * appropriate /etc/fs/{fstype}/mount
    213  *
    214  * If the -F fstype, special or directory are missing,
    215  * /etc/vfstab is searched to fill in the missing arguments.
    216  *
    217  * -V will print the built command on the stdout.
    218  * It isn't passed either.
    219  */
    220 int
    221 main(int argc, char *argv[])
    222 {
    223 	char	*special,	/* argument of special/resource */
    224 	    *mountp,		/* argument of mount directory */
    225 	    *fstype,		/* wherein the fstype name is filled */
    226 	    *newargv[ARGV_MAX],	/* arg list for specific command */
    227 	    *farg = NULL, *Farg = NULL;
    228 	int	ii, ret, cc, fscnt;
    229 	struct stat64	stbuf;
    230 	struct vfstab	vget, vref;
    231 	mode_t mode;
    232 	FILE	*fd;
    233 
    234 	(void) setlocale(LC_ALL, "");
    235 
    236 #if !defined(TEXT_DOMAIN)
    237 #define	TEXT_DOMAIN "SYS_TEST"
    238 #endif
    239 	(void) textdomain(TEXT_DOMAIN);
    240 
    241 	myname = strrchr(argv[0], '/');
    242 	if (myname)
    243 		myname++;
    244 	else
    245 		myname = argv[0];
    246 	if (myname == 0) myname = "path unknown";
    247 
    248 	/* Process the args.  */
    249 
    250 	while ((cc = getopt(argc, argv, "?acd:f:F:gmno:pqrvVO")) != -1)
    251 		switch (cc) {
    252 			case 'a':
    253 				aflg++;
    254 				break;
    255 			case 'c':
    256 				cflg++;
    257 				break;
    258 
    259 #ifdef DEBUG
    260 			case 'd':
    261 				dflg = atoi(optarg);
    262 				break;
    263 #endif
    264 
    265 			case 'f':
    266 				fflg++;
    267 				farg = optarg;
    268 				break;
    269 			case 'F':
    270 				Fflg++;
    271 				Farg = optarg;
    272 				break;
    273 			case 'g':
    274 				gflg++;
    275 				break;
    276 			case 'm':
    277 				mflg++;
    278 				break; /* do not update /etc/mnttab */
    279 			case 'o':
    280 				oflg++;
    281 				if ((specific_opts = strdup(optarg)) == NULL)
    282 					nomem();
    283 				break; /* fstype dependent options */
    284 			case 'O':
    285 				Oflg++;
    286 				break;
    287 			case 'p':
    288 				pflg++;
    289 				break;
    290 			case 'q':
    291 				qflg++;
    292 				break;
    293 			case 'r':
    294 				rflg++;
    295 				generic_opts = "ro";
    296 				break;
    297 			case 'v':
    298 				vflg++;
    299 				break;
    300 			case 'V':
    301 				Vflg++;
    302 				break;
    303 			case '?':
    304 				questflg++;
    305 				break;
    306 		}
    307 
    308 	/* copy '--' to specific */
    309 	if (strcmp(argv[optind-1], "--") == 0)
    310 		dashflg++;
    311 
    312 	/* option checking */
    313 	/* more than two args not allowed if !aflg */
    314 	if (!aflg && (argc - optind > 2))
    315 		usage();
    316 
    317 	/* pv mututally exclusive */
    318 	if (pflg + vflg + aflg > 1) {
    319 		fprintf(stderr, gettext
    320 		    ("%s: -a, -p, and -v are mutually exclusive\n"),
    321 		    myname);
    322 		usage();
    323 	}
    324 
    325 	/*
    326 	 * Can't have overlaying mounts on the same mount point during
    327 	 * a parallel mount.
    328 	 */
    329 	if (aflg && Oflg) {
    330 		fprintf(stderr, gettext
    331 		    ("%s: -a and -O are mutually exclusive\n"), myname);
    332 		usage();
    333 	}
    334 
    335 	/* dfF mutually exclusive */
    336 	if (fflg + Fflg > 1) {
    337 		fprintf(stderr, gettext
    338 		    ("%s: More than one FSType specified\n"), myname);
    339 		usage();
    340 	}
    341 
    342 	/* no arguments, only allow p,v,V or [F]? */
    343 	if (!aflg && optind == argc) {
    344 		if (cflg || fflg || mflg || oflg || rflg || qflg)
    345 			usage();
    346 
    347 		if (Fflg && !questflg)
    348 			usage();
    349 
    350 		if (questflg) {
    351 			if (Fflg) {
    352 				newargv[2] = "-?";
    353 				newargv[3] = NULL;
    354 				doexec(Farg, newargv);
    355 			}
    356 			usage();
    357 		}
    358 	}
    359 
    360 	if (questflg)
    361 		usage();
    362 
    363 	/* one or two args, allow any but p,v */
    364 	if (optind != argc && (pflg || vflg)) {
    365 		fprintf(stderr,
    366 gettext("%s: Cannot use -p and -v with arguments\n"), myname);
    367 		usage();
    368 	}
    369 
    370 
    371 	/* if only reporting mnttab, generic prints mnttab and exits */
    372 	if (!aflg && optind == argc) {
    373 		if (Vflg) {
    374 			printf("%s", myname);
    375 			if (pflg)
    376 				printf(" -p");
    377 			if (vflg)
    378 				printf(" -v");
    379 			printf("\n");
    380 			exit(0);
    381 		}
    382 
    383 		print_mnttab(vflg, pflg);
    384 		exit(0);
    385 	}
    386 
    387 	/*
    388 	 * Get filesystem type here.  If "-F FStype" is specified, use
    389 	 * that fs type.  Otherwise, determine the fs type from /etc/vfstab
    390 	 * if the entry exists.  Otherwise, determine the local or remote
    391 	 * fs type from /etc/default/df or /etc/dfs/fstypes respectively.
    392 	 */
    393 	if (fflg) {
    394 		if ((strcmp(farg, "S51K") != 0) &&
    395 		    (strcmp(farg, "S52K") != 0)) {
    396 			fstype = farg;
    397 		}
    398 		else
    399 			fstype = "ufs";
    400 	} else /* if (Fflg) */
    401 		fstype = Farg;
    402 
    403 	fscnt = argc - optind;
    404 	if (aflg && (fscnt != 1))
    405 		exit(parmount(argv + optind, fscnt, fstype));
    406 
    407 	/*
    408 	 * Then don't bother with the parallel over head.  Everything
    409 	 * from this point is simple/normal single execution.
    410 	 */
    411 	aflg = 0;
    412 
    413 	/* get special and/or mount-point from arg(s) */
    414 	if (fscnt == 2)
    415 		special = argv[optind++];
    416 	else
    417 		special = NULL;
    418 	if (optind < argc)
    419 		mountp = argv[optind++];
    420 	else
    421 		mountp = NULL;
    422 
    423 	/* lookup only if we need to */
    424 	if (fstype == NULL || specific_opts == NULL || special == NULL ||
    425 	    mountp == NULL) {
    426 		if ((fd = fopen(vfstab, "r")) == NULL) {
    427 			if (fstype == NULL || special == NULL ||
    428 			    mountp == NULL) {
    429 				fprintf(stderr, gettext(
    430 				    "%s: Cannot open %s\n"),
    431 				    myname, vfstab);
    432 				exit(1);
    433 			} else {
    434 				/*
    435 				 * No vfstab, but we know what we want
    436 				 * to mount.
    437 				 */
    438 				goto out;
    439 			}
    440 		}
    441 		vfsnull(&vref);
    442 		vref.vfs_special = special;
    443 		vref.vfs_mountp = mountp;
    444 		vref.vfs_fstype = fstype;
    445 
    446 		/* get a vfstab entry matching mountp or special */
    447 		while ((ret = getvfsany(fd, &vget, &vref)) > 0)
    448 			vfserror(ret, vget.vfs_special);
    449 
    450 		/* if no entry and there was only one argument */
    451 		/* then the argument could be the special */
    452 		/* and not mount point as we thought earlier */
    453 		if (ret == -1 && special == NULL) {
    454 			rewind(fd);
    455 			special = vref.vfs_special = mountp;
    456 			mountp = vref.vfs_mountp = NULL;
    457 			/* skip erroneous lines; they were reported above */
    458 			while ((ret = getvfsany(fd, &vget, &vref)) > 0)
    459 				;
    460 		}
    461 
    462 		fclose(fd);
    463 
    464 		if (ret == 0) {
    465 			if (fstype == NULL)
    466 				fstype = vget.vfs_fstype;
    467 			if (special == NULL)
    468 				special = vget.vfs_special;
    469 			if (mountp == NULL)
    470 				mountp = vget.vfs_mountp;
    471 			if (oflg == 0 && vget.vfs_mntopts) {
    472 				oflg++;
    473 				specific_opts = vget.vfs_mntopts;
    474 			}
    475 		} else if (special == NULL) {
    476 			if (stat64(mountp, &stbuf) == -1) {
    477 				fprintf(stderr, gettext("%s: cannot stat %s\n"),
    478 				    myname, mountp);
    479 				exit(2);
    480 			}
    481 			if (((mode = (stbuf.st_mode & S_IFMT)) == S_IFBLK) ||
    482 			    (mode == S_IFCHR)) {
    483 				fprintf(stderr,
    484 gettext("%s: mount point cannot be determined\n"),
    485 				    myname);
    486 				exit(1);
    487 			} else
    488 				{
    489 				fprintf(stderr,
    490 gettext("%s: special cannot be determined\n"),
    491 				    myname);
    492 				exit(1);
    493 			}
    494 		} else if (fstype == NULL)
    495 			fstype = default_fstype(special);
    496 	}
    497 
    498 out:
    499 	if (check_fields(fstype, mountp))
    500 		exit(1);
    501 
    502 	if (realpath(mountp, realdir) == NULL) {
    503 		(void) fprintf(stderr, "mount: ");
    504 		perror(mountp);
    505 		exit(1);
    506 	}
    507 
    508 	if ((mountp = strdup(realdir)) == NULL)
    509 		nomem();
    510 
    511 	/* create the new arg list, and end the list with a null pointer */
    512 	ii = 2;
    513 	if (cflg)
    514 		newargv[ii++] = "-c";
    515 	if (gflg)
    516 		newargv[ii++] = "-g";
    517 	if (mflg)
    518 		newargv[ii++] = "-m";
    519 	/*
    520 	 * The q option needs to go before the -o option as some
    521 	 * filesystems complain during first pass option parsing.
    522 	 */
    523 	if (qflg)
    524 		newargv[ii++] = "-q";
    525 	if (oflg) {
    526 		newargv[ii++] = "-o";
    527 		newargv[ii++] = specific_opts;
    528 	}
    529 	if (Oflg)
    530 		newargv[ii++] = "-O";
    531 	if (rflg)
    532 		newargv[ii++] = "-r";
    533 	if (dashflg)
    534 		newargv[ii++] = "--";
    535 	newargv[ii++] = special;
    536 	newargv[ii++] = mountp;
    537 	newargv[ii] = NULL;
    538 
    539 	doexec(fstype, newargv);
    540 	return (0);
    541 }
    542 
    543 void
    544 usage(void)
    545 {
    546 	fprintf(stderr,	gettext("Usage:\n%s [-v | -p]\n"), myname);
    547 	fprintf(stderr, gettext(
    548 	    "%s [-F FSType] [-V] [current_options] [-o specific_options]"),
    549 	    myname);
    550 	fprintf(stderr, gettext("\n\t{special | mount_point}\n"));
    551 
    552 	fprintf(stderr, gettext(
    553 	    "%s [-F FSType] [-V] [current_options] [-o specific_options]"),
    554 	    myname);
    555 	fprintf(stderr, gettext("\n\tspecial mount_point\n"));
    556 
    557 	fprintf(stderr, gettext(
    558 	"%s -a [-F FSType ] [-V] [current_options] [-o specific_options]\n"),
    559 	    myname);
    560 	fprintf(stderr, gettext("\t[mount_point ...]\n"));
    561 
    562 	exit(1);
    563 }
    564 
    565 /*
    566  * Get rid of "dev=[hex string]" clause, if any.  It's not legal
    567  * when printing in vfstab format.
    568  */
    569 void
    570 elide_dev(char *mntopts)
    571 {
    572 	char *dev, *other;
    573 
    574 	if (mntopts != NULL) {
    575 		dev = strstr(mntopts, "dev=");
    576 		if (dev != NULL) {
    577 			other = strpbrk(dev, ",");
    578 			if (other == NULL) {
    579 				/* last option */
    580 				if (dev != mntopts) {
    581 					*--dev = '\0';
    582 				} else {
    583 					*dev = '\0';
    584 				}
    585 			} else {
    586 				/* first or intermediate option */
    587 				memmove(dev, other+1, strlen(other+1)+1);
    588 			}
    589 		}
    590 	}
    591 }
    592 
    593 void
    594 print_mnttab(int vflg, int pflg)
    595 {
    596 	FILE	*fd;
    597 	FILE	*rfp;			/* this will be NULL if fopen fails */
    598 	int	ret;
    599 	char	time_buf[TIME_MAX];	/* array to hold date and time */
    600 	struct extmnttab	mget;
    601 	time_t	ltime;
    602 
    603 	if ((fd = fopen(mnttab, "r")) == NULL) {
    604 		fprintf(stderr, gettext("%s: Cannot open mnttab\n"), myname);
    605 		exit(1);
    606 	}
    607 	rfp = fopen(REMOTE, "r");
    608 	while ((ret = getextmntent(fd, &mget, sizeof (struct extmnttab)))
    609 	    == 0) {
    610 		if (ignore(mget.mnt_mntopts))
    611 			continue;
    612 		if (mget.mnt_special && mget.mnt_mountp &&
    613 		    mget.mnt_fstype && mget.mnt_time) {
    614 			ltime = atol(mget.mnt_time);
    615 			cftime(time_buf, FORMAT, &ltime);
    616 			if (pflg) {
    617 				elide_dev(mget.mnt_mntopts);
    618 				printf("%s - %s %s - no %s\n",
    619 				    mget.mnt_special,
    620 				    mget.mnt_mountp,
    621 				    mget.mnt_fstype,
    622 				    mget.mnt_mntopts != NULL ?
    623 				    mget.mnt_mntopts : "-");
    624 			} else if (vflg) {
    625 				printf("%s on %s type %s %s%s on %s",
    626 				    mget.mnt_special,
    627 				    mget.mnt_mountp,
    628 				    mget.mnt_fstype,
    629 				    remote(mget.mnt_fstype, rfp),
    630 				    flags(mget.mnt_mntopts, NEW),
    631 				    time_buf);
    632 			} else
    633 				printf("%s on %s %s%s on %s",
    634 				    mget.mnt_mountp,
    635 				    mget.mnt_special,
    636 				    remote(mget.mnt_fstype, rfp),
    637 				    flags(mget.mnt_mntopts, OLD),
    638 				    time_buf);
    639 		}
    640 	}
    641 	if (ret > 0)
    642 		mnterror(ret);
    643 }
    644 
    645 char	*
    646 flags(char *mntopts, int flag)
    647 {
    648 	char	opts[sizeof (mntflags)];
    649 	char	*value;
    650 	int	rdwr = 1;
    651 	int	suid = 1;
    652 	int	devices = 1;
    653 	int	setuid = 1;
    654 
    655 	if (mntopts == NULL || *mntopts == '\0')
    656 		return ("read/write/setuid/devices");
    657 
    658 	strcpy(opts, "");
    659 	while (*mntopts != '\0')  {
    660 		switch (getsubopt(&mntopts, myopts, &value)) {
    661 		case READONLY:
    662 			rdwr = 0;
    663 			break;
    664 		case READWRITE:
    665 			rdwr = 1;
    666 			break;
    667 		case SUID:
    668 			suid = 1;
    669 			break;
    670 		case NOSUID:
    671 			suid = 0;
    672 			break;
    673 		case SETUID:
    674 			setuid = 1;
    675 			break;
    676 		case NOSETUID:
    677 			setuid = 0;
    678 			break;
    679 		case DEVICES:
    680 			devices = 1;
    681 			break;
    682 		case NODEVICES:
    683 			devices = 0;
    684 			break;
    685 		default:
    686 			/* cat '/' separator to mntflags */
    687 			if (*opts != '\0' && value != NULL)
    688 				strcat(opts, "/");
    689 			strcat(opts, value);
    690 			break;
    691 		}
    692 	}
    693 
    694 	strcpy(mntflags, "");
    695 	if (rdwr)
    696 		strcat(mntflags, "read/write");
    697 	else if (flag == OLD)
    698 		strcat(mntflags, "read only");
    699 	else
    700 		strcat(mntflags, "read-only");
    701 	if (suid) {
    702 		if (setuid)
    703 			strcat(mntflags, "/setuid");
    704 		else
    705 			strcat(mntflags, "/nosetuid");
    706 		if (devices)
    707 			strcat(mntflags, "/devices");
    708 		else
    709 			strcat(mntflags, "/nodevices");
    710 	} else {
    711 		strcat(mntflags, "/nosetuid/nodevices");
    712 	}
    713 	if (*opts != '\0') {
    714 		strcat(mntflags, "/");
    715 		strcat(mntflags, opts);
    716 	}
    717 
    718 	/*
    719 	 * The assumed assertion
    720 	 * 	assert (strlen(mntflags) < sizeof mntflags);
    721 	 * is valid at this point in the code. Note that a call to "assert"
    722 	 * is not appropriate in production code since it halts the program.
    723 	 */
    724 	return (mntflags);
    725 }
    726 
    727 char	*
    728 remote(char *fstype, FILE *rfp)
    729 {
    730 	char	buf[BUFSIZ];
    731 	char	*fs;
    732 	extern char *strtok();
    733 
    734 	if (rfp == NULL || fstype == NULL ||
    735 	    strlen(fstype) > (size_t)FSTYPE_MAX)
    736 		return ("");	/* not a remote */
    737 	rewind(rfp);
    738 	while (fgets(buf, sizeof (buf), rfp) != NULL) {
    739 		fs = strtok(buf, " \t\n");
    740 		if (strcmp(fstype, fs) == 0)
    741 			return ("remote/");	/* is a remote fs */
    742 	}
    743 	return ("");	/* not a remote */
    744 }
    745 
    746 
    747 void
    748 vfserror(int flag, char *special)
    749 {
    750 	if (special == NULL)
    751 		special = "<null>";
    752 	switch (flag) {
    753 	case VFS_TOOLONG:
    754 		fprintf(stderr,
    755 gettext("%s: Warning: Line in vfstab for \"%s\" exceeds %d characters\n"),
    756 		    myname, special, VFS_LINE_MAX-1);
    757 		break;
    758 	case VFS_TOOFEW:
    759 		fprintf(stderr,
    760 gettext("%s: Warning: Line for \"%s\" in vfstab has too few entries\n"),
    761 		    myname, special);
    762 		break;
    763 	case VFS_TOOMANY:
    764 		fprintf(stderr,
    765 gettext("%s: Warning: Line for \"%s\" in vfstab has too many entries\n"),
    766 		    myname, special);
    767 		break;
    768 	default:
    769 		fprintf(stderr, gettext(
    770 		    "%s: Warning: Error in line for \"%s\" in vfstab\n"),
    771 		    myname, special);
    772 	}
    773 }
    774 
    775 void
    776 mnterror(int flag)
    777 {
    778 	switch (flag) {
    779 	case MNT_TOOLONG:
    780 		fprintf(stderr,
    781 		    gettext("%s: Line in mnttab exceeds %d characters\n"),
    782 		    myname, MNT_LINE_MAX-2);
    783 		break;
    784 	case MNT_TOOFEW:
    785 		fprintf(stderr,
    786 		    gettext("%s: Line in mnttab has too few entries\n"),
    787 		    myname);
    788 		break;
    789 	case MNT_TOOMANY:
    790 		fprintf(stderr,
    791 		    gettext("%s: Line in mnttab has too many entries\n"),
    792 		    myname);
    793 		break;
    794 	}
    795 	exit(1);
    796 }
    797 
    798 void
    799 doexec(char *fstype, char *newargv[])
    800 {
    801 	char	full_path[PATH_MAX];
    802 	char	alter_path[PATH_MAX];
    803 	char	*vfs_path = VFS_PATH;
    804 	char	*alt_path = ALT_PATH;
    805 	int	i;
    806 	int	smbfs;
    807 
    808 	/*
    809 	 * Special case smbfs file system.
    810 	 * Execute command in profile if possible.
    811 	 */
    812 	smbfs = strcmp(fstype, "smbfs") == 0;
    813 
    814 	/* build the full pathname of the fstype dependent command. */
    815 	sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname);
    816 	sprintf(alter_path, "%s/%s/%s", alt_path, fstype, myname);
    817 	newargv[1] = myname;
    818 
    819 	if (Vflg) {
    820 		printf("%s -F %s", newargv[1], fstype);
    821 		for (i = 2; newargv[i]; i++)
    822 			printf(" %s", newargv[i]);
    823 		printf("\n");
    824 		fflush(stdout);
    825 		exit(0);
    826 	}
    827 
    828 	/*
    829 	 * Try to exec the fstype dependent portion of the mount.
    830 	 * See if the directory is there before trying to exec dependent
    831 	 * portion.  This is only useful for eliminating the
    832 	 * '..mount: not found' message when '/usr' is mounted
    833 	 */
    834 	if (access(full_path, 0) == 0) {
    835 		if (smbfs) {
    836 			/*
    837 			 * Run mount_smbfs(1m) with pfexec so that we can
    838 			 * add sys_mount privilege, (via exec_attr, etc.)
    839 			 * allowing normal users to mount on any directory
    840 			 * they own.
    841 			 */
    842 			newargv[0] = "pfexec";
    843 			newargv[1] = full_path;
    844 			execv("/usr/bin/pfexec", &newargv[0]);
    845 			newargv[1] = myname;
    846 		}
    847 		execv(full_path, &newargv[1]);
    848 		if (errno == EACCES) {
    849 			fprintf(stderr,
    850 			gettext("%s: Cannot execute %s - permission denied\n"),
    851 			    myname, full_path);
    852 		}
    853 		if (errno == ENOEXEC) {
    854 			newargv[0] = "sh";
    855 			newargv[1] = full_path;
    856 			execv("/sbin/sh", &newargv[0]);
    857 		}
    858 	}
    859 	if (smbfs) {
    860 		newargv[0] = "pfexec";
    861 		newargv[1] = alter_path;
    862 		execv("/usr/bin/pfexec", &newargv[0]);
    863 		newargv[1] = myname;
    864 	}
    865 	execv(alter_path, &newargv[1]);
    866 	if (errno == EACCES) {
    867 		fprintf(stderr, gettext(
    868 		    "%s: Cannot execute %s - permission denied\n"),
    869 		    myname, alter_path);
    870 		exit(1);
    871 	}
    872 	if (errno == ENOEXEC) {
    873 		newargv[0] = "sh";
    874 		newargv[1] = alter_path;
    875 		execv("/sbin/sh", &newargv[0]);
    876 	}
    877 	fprintf(stderr,
    878 	    gettext("%s: Operation not applicable to FSType %s\n"),
    879 	    myname, fstype);
    880 	exit(1);
    881 }
    882 
    883 char *mntopts[] = { MNTOPT_IGNORE, NULL };
    884 #define	IGNORE    0
    885 
    886 /*
    887  * Return 1 if "ignore" appears in the options string
    888  */
    889 int
    890 ignore(char *opts)
    891 {
    892 	char *value;
    893 	char *saveptr, *my_opts;
    894 	int rval = 0;
    895 
    896 	if (opts == NULL || *opts == NULL)
    897 		return (0);
    898 
    899 	/*
    900 	 * we make a copy of the option string to pass to getsubopt(),
    901 	 * because getsubopt() modifies the string.  We also save
    902 	 * the original pointer returned by strdup, because getsubopt
    903 	 * changes the pointer passed into it.  If strdup fails (unlikely),
    904 	 * we act as if the "ignore" option isn't set rather than fail.
    905 	 */
    906 
    907 	if ((saveptr = my_opts = strdup(opts)) == NULL)
    908 		nomem();
    909 
    910 	while (*my_opts != '\0') {
    911 		if (getsubopt(&my_opts, mntopts, &value) == IGNORE)
    912 			rval = 1;
    913 	}
    914 
    915 	free(saveptr);
    916 
    917 	return (rval);
    918 }
    919 
    920 /*
    921  * Perform the parallel version of mount.  If count == 0, mount all
    922  * vfstab filesystems with the automnt field == "yes".  Use fstype if
    923  * supplied.  If mntlist supplied, then attempt to only mount those.
    924  */
    925 
    926 int
    927 parmount(char **mntlist, int count, char *fstype)
    928 {
    929 	int 		maxfd =	OPEN_MAX;
    930 	struct 		rlimit rl;
    931 	vfsent_t	**vl, *vp;
    932 
    933 	/*
    934 	 * Process scaling.  After running a series
    935 	 * of tests based on the number of simultaneous processes and
    936 	 * processors available, optimum performance was achieved near or
    937 	 * at (PROCN * 2).
    938 	 */
    939 	if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1)
    940 		maxrun = 4;
    941 	else
    942 		maxrun = maxrun * 2 + 1;
    943 
    944 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
    945 		rl.rlim_cur = rl.rlim_max;
    946 		if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
    947 			maxfd = (int)rl.rlim_cur;
    948 	}
    949 	(void) enable_extended_FILE_stdio(-1, -1);
    950 
    951 	/*
    952 	 * The parent needs to maintain 3 of its own fd's, plus 2 for
    953 	 * each child (the stdout and stderr pipes).
    954 	 */
    955 	maxfd = (maxfd / 2) - 6;	/* 6 takes care of temporary  */
    956 					/* periods of open fds */
    957 	if (maxfd < maxrun)
    958 		maxrun = maxfd;
    959 	if (maxrun < 4)
    960 		maxrun = 4;		/* sanity check */
    961 
    962 	if (count == 0)
    963 		mntlist = NULL;		/* used as a flag later */
    964 	else
    965 		fstype = NULL;		/* mount points supplied: */
    966 					/* ignore fstype */
    967 	/*
    968 	 * Read the whole vfstab into a linked list for quick processing.
    969 	 * On average, this is the most efficient way to collect and
    970 	 * manipulate the vfstab data.
    971 	 */
    972 	vfsll = getvfsall(fstype, mntlist == NULL);
    973 
    974 	/*
    975 	 * Make an array out of the vfs linked list for sorting purposes.
    976 	 */
    977 	if (vfsll == NULL ||
    978 	    (vfsarray = make_vfsarray(mntlist, count)) == NULL) {
    979 		if (mntlist == NULL)	/* not an error - just none found */
    980 			return (0);
    981 
    982 		fprintf(stderr, gettext("%s: No valid entries found in %s\n"),
    983 		    myname, vfstab);
    984 		return (1);
    985 	}
    986 
    987 	/*
    988 	 * Sort the entries based on their resolved path names
    989 	 *
    990 	 * If an lofs is encountered, then the original order of the vfstab
    991 	 * file needs to be maintained until we are done mounting lofs's.
    992 	 */
    993 	if (!lofscnt)
    994 		qsort((void *)vfsarray, vfsarraysize, sizeof (vfsent_t *),
    995 		    mlevelcmp);
    996 
    997 	/*
    998 	 * Shrink the vfsll linked list down to the new list.  This will
    999 	 * speed up the pid search in cleanupkid() later.
   1000 	 */
   1001 	vfsll = vfsarray[0];
   1002 	for (vl = vfsarray; vp = *vl; )
   1003 		vp->next = *++vl;
   1004 
   1005 	/*
   1006 	 * Try to handle interrupts in a reasonable way.
   1007 	 */
   1008 	sigset(SIGHUP, cleanup);
   1009 	sigset(SIGQUIT, cleanup);
   1010 	sigset(SIGINT, cleanup);
   1011 
   1012 	do_mounts();		/* do the mounts */
   1013 	return (exitcode);
   1014 }
   1015 
   1016 /*
   1017  * Read all vstab (fp) entries into memory if fstype == NULL.
   1018  * If fstype is specified, than read all those that match it.
   1019  *
   1020  * Returns a linked list.
   1021  */
   1022 vfsent_t *
   1023 getvfsall(char *fstype, int takeall)
   1024 {
   1025 	vfsent_t	*vhead, *vtail;
   1026 	struct vfstab 	vget;
   1027 	FILE		*fp;
   1028 	int		cnt = 0, ret;
   1029 
   1030 	if ((fp = fopen(vfstab, "r")) == NULL) {
   1031 		fprintf(stderr, gettext("%s: Cannot open %s\n"),
   1032 		    myname, vfstab);
   1033 		exit(1);
   1034 	}
   1035 
   1036 	vhead = vtail = NULL;
   1037 
   1038 	while ((ret = getvfsent(fp, &vget)) != -1) {
   1039 		vfsent_t *vp;
   1040 
   1041 		if (ret > 0) {
   1042 			vfserror(ret, vget.vfs_mountp);
   1043 			continue;
   1044 		}
   1045 
   1046 		/*
   1047 		 * If mount points were not specified, then we ignore
   1048 		 * entries that aren't marked "yes".
   1049 		 */
   1050 		if (takeall &&
   1051 		    (vget.vfs_automnt == NULL ||
   1052 		    strcmp(vget.vfs_automnt, "yes")))
   1053 			continue;
   1054 
   1055 		if (fstype && vget.vfs_fstype &&
   1056 		    strcmp(fstype, vget.vfs_fstype))
   1057 			continue;
   1058 
   1059 		if (vget.vfs_mountp == NULL ||
   1060 		    (vget.vfs_fstype && (strcmp(vget.vfs_fstype, "swap") == 0)))
   1061 			continue;
   1062 
   1063 		if (check_fields(vget.vfs_fstype, vget.vfs_mountp)) {
   1064 			exitcode = 1;
   1065 			continue;
   1066 		}
   1067 
   1068 		vp = new_vfsent(&vget, cnt);	/* create new vfs entry */
   1069 		if (vhead == NULL)
   1070 			vhead = vp;
   1071 		else
   1072 			vtail->next = vp;
   1073 		vtail = vp;
   1074 		cnt++;
   1075 	}
   1076 	fclose(fp);
   1077 	if (vtail == NULL) {
   1078 		vfsarraysize = 0;
   1079 		vfslltail = NULL;
   1080 		return (NULL);
   1081 	}
   1082 	vtail->next = NULL;
   1083 	vfslltail = vtail;	/* save it in the global variable */
   1084 	vfsarraysize = cnt;
   1085 	return (vhead);
   1086 }
   1087 
   1088 
   1089 /*
   1090  * Returns an array of vfsent_t's based on vfsll & mntlist.
   1091  */
   1092 vfsent_t **
   1093 make_vfsarray(char **mntlist, int count)
   1094 {
   1095 	vfsent_t 	*vp, *vmark, *vpprev, **vpp;
   1096 	int		ndx, found;
   1097 
   1098 	if (vfsll == NULL)
   1099 		return (NULL);
   1100 
   1101 	if (count > 0)
   1102 		vfsarraysize = count;
   1103 
   1104 	vpp = (vfsent_t **)malloc(sizeof (*vpp) * (vfsarraysize + 1));
   1105 	if (vpp == NULL)
   1106 		nomem();
   1107 
   1108 	if (mntlist == NULL) {
   1109 		/*
   1110 		 * No mount list specified: take all vfstab mount points.
   1111 		 */
   1112 		for (ndx = 0, vp = vfsll; vp; vp = vp->next) {
   1113 			(void) setrpath(vp);
   1114 			/*
   1115 			 * Sigh. lofs entries can complicate matters so much
   1116 			 * that the best way to avoid problems is to
   1117 			 * stop parallel mounting when an lofs is
   1118 			 * encountered, so we keep a count of how many
   1119 			 * there are.
   1120 			 * Fortunately this is rare.
   1121 			 */
   1122 			if (vp->v.vfs_fstype &&
   1123 			    (strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0))
   1124 				lofscnt++;
   1125 
   1126 			vpp[ndx++] = vp;
   1127 		}
   1128 		vpp[ndx] = NULL;
   1129 		return (vpp);
   1130 	}
   1131 
   1132 	/*
   1133 	 * A list of mount points was specified on the command line
   1134 	 * and we need to search for each one.
   1135 	 */
   1136 	vpprev = vfslltail;
   1137 	vpprev</