mount.c revision 17243
11558Srgrimes/*
21558Srgrimes * Copyright (c) 1980, 1989, 1993, 1994
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
131558Srgrimes * 3. All advertising materials mentioning features or use of this software
141558Srgrimes *    must display the following acknowledgement:
151558Srgrimes *	This product includes software developed by the University of
161558Srgrimes *	California, Berkeley and its contributors.
171558Srgrimes * 4. Neither the name of the University nor the names of its contributors
181558Srgrimes *    may be used to endorse or promote products derived from this software
191558Srgrimes *    without specific prior written permission.
201558Srgrimes *
211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311558Srgrimes * SUCH DAMAGE.
321558Srgrimes */
331558Srgrimes
341558Srgrimes#ifndef lint
351558Srgrimesstatic char copyright[] =
361558Srgrimes"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\
371558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381558Srgrimes#endif /* not lint */
391558Srgrimes
401558Srgrimes#ifndef lint
411558Srgrimesstatic char sccsid[] = "@(#)mount.c	8.19 (Berkeley) 4/19/94";
421558Srgrimes#endif /* not lint */
431558Srgrimes
441558Srgrimes#include <sys/param.h>
451558Srgrimes#include <sys/mount.h>
461558Srgrimes#include <sys/wait.h>
476441Sdg#include <sys/types.h>
486441Sdg#include <sys/stat.h>
491558Srgrimes
501558Srgrimes#include <err.h>
511558Srgrimes#include <errno.h>
521558Srgrimes#include <fstab.h>
531558Srgrimes#include <signal.h>
541558Srgrimes#include <stdio.h>
551558Srgrimes#include <stdlib.h>
561558Srgrimes#include <string.h>
571558Srgrimes#include <unistd.h>
581558Srgrimes
591558Srgrimes#include "pathnames.h"
601558Srgrimes
611558Srgrimesint debug, verbose, skipvfs;
6217243Sjkhint fstab_style = 0;
631558Srgrimes
6417243Sjkhstatic char	*mnttype[] = INITMOUNTNAMES;
6517243Sjkh
661558Srgrimesint	badvfsname __P((const char *, const char **));
671558Srgrimesint	badvfstype __P((int, const char **));
681558Srgrimeschar   *catopt __P((char *, const char *));
691558Srgrimesstruct statfs
701558Srgrimes       *getmntpt __P((const char *));
711558Srgrimesconst char
721558Srgrimes      **makevfslist __P((char *));
731558Srgrimesvoid	mangle __P((char *, int *, const char **));
741558Srgrimesint	mountfs __P((const char *, const char *, const char *,
751558Srgrimes			int, const char *, const char *));
761558Srgrimesvoid	prmount __P((const char *, const char *, int));
771558Srgrimesvoid	usage __P((void));
7817243Sjkhvoid	putfsent __P((const struct statfs *));
791558Srgrimes
801558Srgrimes/* From mount_ufs.c. */
811558Srgrimesint	mount_ufs __P((int, char * const *));
821558Srgrimes
831558Srgrimes/* Map from mount otions to printable formats. */
841558Srgrimesstatic struct opt {
851558Srgrimes	int o_opt;
861558Srgrimes	const char *o_name;
871558Srgrimes} optnames[] = {
881558Srgrimes	{ MNT_ASYNC,		"asynchronous" },
891558Srgrimes	{ MNT_EXPORTED,		"NFS exported" },
901558Srgrimes	{ MNT_LOCAL,		"local" },
911558Srgrimes	{ MNT_NODEV,		"nodev" },
921558Srgrimes	{ MNT_NOEXEC,		"noexec" },
931558Srgrimes	{ MNT_NOSUID,		"nosuid" },
941558Srgrimes	{ MNT_QUOTA,		"with quotas" },
951558Srgrimes	{ MNT_RDONLY,		"read-only" },
961558Srgrimes	{ MNT_SYNCHRONOUS,	"synchronous" },
971558Srgrimes	{ MNT_UNION,		"union" },
981558Srgrimes	{ MNT_USER,		"user mount" },
991558Srgrimes	{ NULL }
1001558Srgrimes};
1011558Srgrimes
1021558Srgrimesint
1031558Srgrimesmain(argc, argv)
1041558Srgrimes	int argc;
1051558Srgrimes	char * const argv[];
1061558Srgrimes{
1071558Srgrimes	const char *mntonname, **vfslist, *vfstype;
1081558Srgrimes	struct fstab *fs;
1091558Srgrimes	struct statfs *mntbuf;
1101558Srgrimes	FILE *mountdfp;
1111558Srgrimes	pid_t pid;
1121558Srgrimes	int all, ch, i, init_flags, mntsize, rval;
1131558Srgrimes	char *options;
1141558Srgrimes
1151558Srgrimes	all = init_flags = 0;
1161558Srgrimes	options = NULL;
1171558Srgrimes	vfslist = NULL;
1181558Srgrimes	vfstype = "ufs";
11917243Sjkh	while ((ch = getopt(argc, argv, "padfo:rwt:uv")) != EOF)
1201558Srgrimes		switch (ch) {
12117243Sjkh		case 'p':
12217243Sjkh			fstab_style = 1;
12317243Sjkh			verbose = 1;
12417243Sjkh			break;
1251558Srgrimes		case 'a':
1261558Srgrimes			all = 1;
1271558Srgrimes			break;
1281558Srgrimes		case 'd':
1291558Srgrimes			debug = 1;
1301558Srgrimes			break;
1311558Srgrimes		case 'f':
1321558Srgrimes			init_flags |= MNT_FORCE;
1331558Srgrimes			break;
1341558Srgrimes		case 'o':
1351558Srgrimes			if (*optarg)
1361558Srgrimes				options = catopt(options, optarg);
1371558Srgrimes			break;
1381558Srgrimes		case 'r':
1391558Srgrimes			init_flags |= MNT_RDONLY;
1401558Srgrimes			break;
1411558Srgrimes		case 't':
1421558Srgrimes			if (vfslist != NULL)
1431558Srgrimes				errx(1, "only one -t option may be specified.");
1441558Srgrimes			vfslist = makevfslist(optarg);
1451558Srgrimes			vfstype = optarg;
1461558Srgrimes			break;
1471558Srgrimes		case 'u':
1481558Srgrimes			init_flags |= MNT_UPDATE;
1491558Srgrimes			break;
1501558Srgrimes		case 'v':
1511558Srgrimes			verbose = 1;
1521558Srgrimes			break;
1531558Srgrimes		case 'w':
1541558Srgrimes			init_flags &= ~MNT_RDONLY;
1551558Srgrimes			break;
1561558Srgrimes		case '?':
1571558Srgrimes		default:
1581558Srgrimes			usage();
1591558Srgrimes			/* NOTREACHED */
1601558Srgrimes		}
1611558Srgrimes	argc -= optind;
1621558Srgrimes	argv += optind;
1631558Srgrimes
1641558Srgrimes#define	BADTYPE(type)							\
1651558Srgrimes	(strcmp(type, FSTAB_RO) &&					\
1661558Srgrimes	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
1671558Srgrimes
1681558Srgrimes	rval = 0;
1691558Srgrimes	switch (argc) {
1701558Srgrimes	case 0:
1711558Srgrimes		if (all)
1721558Srgrimes			while ((fs = getfsent()) != NULL) {
1731558Srgrimes				if (BADTYPE(fs->fs_type))
1741558Srgrimes					continue;
1751558Srgrimes				if (badvfsname(fs->fs_vfstype, vfslist))
1761558Srgrimes					continue;
17710288Sdg				if (strstr(fs->fs_mntops, "noauto"))
17810288Sdg					continue;
1791558Srgrimes				if (mountfs(fs->fs_vfstype, fs->fs_spec,
18010288Sdg		    			fs->fs_file, init_flags, options,
18110288Sdg			    		fs->fs_mntops))
18210199Sjkh						rval = 1;
1831558Srgrimes			}
18417243Sjkh		else if (fstab_style) {
18517243Sjkh			if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
18617243Sjkh				err(1, "getmntinfo");
18717243Sjkh			for (i = 0; i < mntsize; i++) {
18817243Sjkh				if (badvfstype(mntbuf[i].f_type, vfslist))
18917243Sjkh					continue;
19017243Sjkh				putfsent (&mntbuf[i]);
19117243Sjkh			}
19217243Sjkh		}
1931558Srgrimes		else {
1941558Srgrimes			if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
1951558Srgrimes				err(1, "getmntinfo");
1961558Srgrimes			for (i = 0; i < mntsize; i++) {
1971558Srgrimes				if (badvfstype(mntbuf[i].f_type, vfslist))
1981558Srgrimes					continue;
1991558Srgrimes				prmount(mntbuf[i].f_mntfromname,
2001558Srgrimes				    mntbuf[i].f_mntonname, mntbuf[i].f_flags);
2011558Srgrimes			}
2021558Srgrimes		}
2031558Srgrimes		exit(rval);
2041558Srgrimes	case 1:
2051558Srgrimes		if (vfslist != NULL)
2061558Srgrimes			usage();
2071558Srgrimes
2081558Srgrimes		if (init_flags & MNT_UPDATE) {
2091558Srgrimes			if ((mntbuf = getmntpt(*argv)) == NULL)
2101558Srgrimes				errx(1,
2111558Srgrimes				    "unknown special file or file system %s.",
2121558Srgrimes				    *argv);
2131558Srgrimes			if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL)
2141558Srgrimes				errx(1, "can't find fstab entry for %s.",
2151558Srgrimes				    *argv);
2161558Srgrimes			/* If it's an update, ignore the fstab file options. */
2171558Srgrimes			fs->fs_mntops = NULL;
2181558Srgrimes			mntonname = mntbuf->f_mntonname;
2191558Srgrimes		} else {
2201558Srgrimes			if ((fs = getfsfile(*argv)) == NULL &&
2211558Srgrimes			    (fs = getfsspec(*argv)) == NULL)
2221558Srgrimes				errx(1,
2231558Srgrimes				    "%s: unknown special file or file system.",
2241558Srgrimes				    *argv);
2251558Srgrimes			if (BADTYPE(fs->fs_type))
2261558Srgrimes				errx(1, "%s has unknown file system type.",
2271558Srgrimes				    *argv);
2281558Srgrimes			mntonname = fs->fs_file;
2291558Srgrimes		}
2301558Srgrimes		rval = mountfs(fs->fs_vfstype, fs->fs_spec,
2311558Srgrimes		    mntonname, init_flags, options, fs->fs_mntops);
2321558Srgrimes		break;
2331558Srgrimes	case 2:
2341558Srgrimes		/*
2351558Srgrimes		 * If -t flag has not been specified, and spec contains either
2361558Srgrimes		 * a ':' or a '@' then assume that an NFS filesystem is being
2371558Srgrimes		 * specified ala Sun.
2381558Srgrimes		 */
2391558Srgrimes		if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL)
2401558Srgrimes			vfstype = "nfs";
2411558Srgrimes		rval = mountfs(vfstype,
2421558Srgrimes		    argv[0], argv[1], init_flags, options, NULL);
2431558Srgrimes		break;
2441558Srgrimes	default:
2451558Srgrimes		usage();
2461558Srgrimes		/* NOTREACHED */
2471558Srgrimes	}
2481558Srgrimes
2491558Srgrimes	/*
2501558Srgrimes	 * If the mount was successfully, and done by root, tell mountd the
2511558Srgrimes	 * good news.  Pid checks are probably unnecessary, but don't hurt.
2521558Srgrimes	 */
2531558Srgrimes	if (rval == 0 && getuid() == 0 &&
2541558Srgrimes	    (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
2551558Srgrimes		if (fscanf(mountdfp, "%ld", &pid) == 1 &&
2561558Srgrimes		     pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
2571558Srgrimes			err(1, "signal mountd");
2581558Srgrimes		(void)fclose(mountdfp);
2591558Srgrimes	}
2601558Srgrimes
2611558Srgrimes	exit(rval);
2621558Srgrimes}
2631558Srgrimes
2641558Srgrimesint
2651558Srgrimesmountfs(vfstype, spec, name, flags, options, mntopts)
2661558Srgrimes	const char *vfstype, *spec, *name, *options, *mntopts;
2671558Srgrimes	int flags;
2681558Srgrimes{
2696441Sdg	struct stat sb;
2706441Sdg
2711558Srgrimes	/* List of directories containing mount_xxx subcommands. */
2721558Srgrimes	static const char *edirs[] = {
2731558Srgrimes		_PATH_SBIN,
2741558Srgrimes		_PATH_USRSBIN,
2751558Srgrimes		NULL
2761558Srgrimes	};
2771558Srgrimes	const char *argv[100], **edir;
2781558Srgrimes	struct statfs sf;
2791558Srgrimes	pid_t pid;
2801558Srgrimes	int argc, i, status;
2811558Srgrimes	char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
2821558Srgrimes
2836491Sbde	if (realpath(name, mntpath) != NULL && stat(mntpath, &sb) == 0) {
2846444Sdg		if (!S_ISDIR(sb.st_mode)) {
2856441Sdg			warnx("%s: Not a directory", mntpath);
2866441Sdg			return (1);
2876441Sdg		}
2886441Sdg	} else {
2891558Srgrimes		warn("%s", mntpath);
2901558Srgrimes		return (1);
2911558Srgrimes	}
2926441Sdg
2931818Sdg	if (mntopts == NULL)
2941818Sdg		mntopts = "";
2951558Srgrimes
2961558Srgrimes	name = mntpath;
2971558Srgrimes
2981558Srgrimes	if (options == NULL) {
2991818Sdg		if (*mntopts == '\0')
3001558Srgrimes			options = "rw";
3011558Srgrimes		else
3021558Srgrimes			options = mntopts;
3031558Srgrimes		mntopts = "";
3041558Srgrimes	}
3051558Srgrimes	optbuf = catopt(strdup(mntopts), options);
3061558Srgrimes
3071558Srgrimes	if (strcmp(name, "/") == 0)
3081558Srgrimes		flags |= MNT_UPDATE;
3091558Srgrimes	if (flags & MNT_FORCE)
3101558Srgrimes		optbuf = catopt(optbuf, "force");
3111558Srgrimes	if (flags & MNT_RDONLY)
3121558Srgrimes		optbuf = catopt(optbuf, "ro");
3131558Srgrimes	/*
3141558Srgrimes	 * XXX
3151558Srgrimes	 * The mount_mfs (newfs) command uses -o to select the
3161558Srgrimes	 * optimisation mode.  We don't pass the default "-o rw"
3171558Srgrimes	 * for that reason.
3181558Srgrimes	 */
3191558Srgrimes	if (flags & MNT_UPDATE)
3201558Srgrimes		optbuf = catopt(optbuf, "update");
3211558Srgrimes
3221558Srgrimes	argc = 0;
3231558Srgrimes	argv[argc++] = vfstype;
3241558Srgrimes	mangle(optbuf, &argc, argv);
3251558Srgrimes	argv[argc++] = spec;
3261558Srgrimes	argv[argc++] = name;
3271558Srgrimes	argv[argc] = NULL;
3281558Srgrimes
3291558Srgrimes	if (debug) {
3301558Srgrimes		(void)printf("exec: mount_%s", vfstype);
3311558Srgrimes		for (i = 1; i < argc; i++)
3321558Srgrimes			(void)printf(" %s", argv[i]);
3331558Srgrimes		(void)printf("\n");
3341558Srgrimes		return (0);
3351558Srgrimes	}
3361558Srgrimes
3371558Srgrimes	switch (pid = vfork()) {
3381558Srgrimes	case -1:				/* Error. */
3391558Srgrimes		warn("vfork");
3401558Srgrimes		free(optbuf);
3411558Srgrimes		return (1);
3421558Srgrimes	case 0:					/* Child. */
3431558Srgrimes		if (strcmp(vfstype, "ufs") == 0)
3441558Srgrimes			exit(mount_ufs(argc, (char * const *) argv));
3451558Srgrimes
3461558Srgrimes		/* Go find an executable. */
34714626Sasami		for (edir = edirs; *edir; edir++) {
3481558Srgrimes			(void)snprintf(execname,
3491558Srgrimes			    sizeof(execname), "%s/mount_%s", *edir, vfstype);
3501558Srgrimes			execv(execname, (char * const *)argv);
35114626Sasami		}
35214626Sasami		if (errno == ENOENT) {
35314626Sasami			int len = 0;
35414626Sasami			char *cp;
35514626Sasami			for (edir = edirs; *edir; edir++)
35614626Sasami				len += strlen(*edir) + 2;	/* ", " */
35714626Sasami			if ((cp = malloc(len)) == NULL) {
35814626Sasami				warn(NULL);
35914626Sasami				exit(1);
36014626Sasami			}
36114626Sasami			cp[0] = '\0';
36214626Sasami			for (edir = edirs; *edir; edir++) {
36314626Sasami				strcat(cp, *edir);
36414626Sasami				if (edir[1] != NULL)
36514626Sasami					strcat(cp, ", ");
36614626Sasami			}
36714626Sasami			warn("exec mount_%s not found in %s", vfstype, cp);
36814626Sasami		}
3691558Srgrimes		exit(1);
3701558Srgrimes		/* NOTREACHED */
3711558Srgrimes	default:				/* Parent. */
3721558Srgrimes		free(optbuf);
3731558Srgrimes
3741558Srgrimes		if (waitpid(pid, &status, 0) < 0) {
3751558Srgrimes			warn("waitpid");
3761558Srgrimes			return (1);
3771558Srgrimes		}
3781558Srgrimes
3791558Srgrimes		if (WIFEXITED(status)) {
3801558Srgrimes			if (WEXITSTATUS(status) != 0)
3811558Srgrimes				return (WEXITSTATUS(status));
3821558Srgrimes		} else if (WIFSIGNALED(status)) {
3831558Srgrimes			warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
3841558Srgrimes			return (1);
3851558Srgrimes		}
3861558Srgrimes
3871558Srgrimes		if (verbose) {
3881558Srgrimes			if (statfs(name, &sf) < 0) {
3891558Srgrimes				warn("%s", name);
3901558Srgrimes				return (1);
3911558Srgrimes			}
39217243Sjkh
39317243Sjkh			if (fstab_style)
39417243Sjkh			    putfsent (&sf);
39517243Sjkh			else
39617243Sjkh			    prmount (sf.f_mntfromname,
39717243Sjkh				     sf.f_mntonname, sf.f_flags);
3981558Srgrimes		}
3991558Srgrimes		break;
4001558Srgrimes	}
4011558Srgrimes
4021558Srgrimes	return (0);
4031558Srgrimes}
4041558Srgrimes
4051558Srgrimesvoid
4061558Srgrimesprmount(spec, name, flags)
4071558Srgrimes	const char *spec, *name;
4081558Srgrimes	int flags;
4091558Srgrimes{
4101558Srgrimes	struct opt *o;
4111558Srgrimes	int f;
4121558Srgrimes
4131558Srgrimes	(void)printf("%s on %s", spec, name);
4141558Srgrimes
4151558Srgrimes	flags &= MNT_VISFLAGMASK;
4161558Srgrimes	for (f = 0, o = optnames; flags && o->o_opt; o++)
4171558Srgrimes		if (flags & o->o_opt) {
4181558Srgrimes			(void)printf("%s%s", !f++ ? " (" : ", ", o->o_name);
4191558Srgrimes			flags &= ~o->o_opt;
4201558Srgrimes		}
4211558Srgrimes	(void)printf(f ? ")\n" : "\n");
4221558Srgrimes}
4231558Srgrimes
4241558Srgrimesstruct statfs *
4251558Srgrimesgetmntpt(name)
4261558Srgrimes	const char *name;
4271558Srgrimes{
4281558Srgrimes	struct statfs *mntbuf;
4291558Srgrimes	int i, mntsize;
4301558Srgrimes
4311558Srgrimes	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
4321558Srgrimes	for (i = 0; i < mntsize; i++)
4331558Srgrimes		if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
4341558Srgrimes		    strcmp(mntbuf[i].f_mntonname, name) == 0)
4351558Srgrimes			return (&mntbuf[i]);
4361558Srgrimes	return (NULL);
4371558Srgrimes}
4381558Srgrimes
4391558Srgrimesint
4401558Srgrimesbadvfsname(vfsname, vfslist)
4411558Srgrimes	const char *vfsname;
4421558Srgrimes	const char **vfslist;
4431558Srgrimes{
4441558Srgrimes
4451558Srgrimes	if (vfslist == NULL)
4461558Srgrimes		return (0);
4471558Srgrimes	while (*vfslist != NULL) {
4481558Srgrimes		if (strcmp(vfsname, *vfslist) == 0)
4491558Srgrimes			return (skipvfs);
4501558Srgrimes		++vfslist;
4511558Srgrimes	}
4521558Srgrimes	return (!skipvfs);
4531558Srgrimes}
4541558Srgrimes
4551558Srgrimesint
4561558Srgrimesbadvfstype(vfstype, vfslist)
4571558Srgrimes	int vfstype;
4581558Srgrimes	const char **vfslist;
4591558Srgrimes{
4602968Swollman	struct vfsconf *vfc;
4612968Swollman	vfc = getvfsbytype(vfstype);
4621558Srgrimes
4632968Swollman	if ( ! vfc )
4641558Srgrimes		return (0);
4651558Srgrimes
4662968Swollman	return (badvfsname(vfc->vfc_name, vfslist));
4671558Srgrimes}
4681558Srgrimes
4691558Srgrimesconst char **
4701558Srgrimesmakevfslist(fslist)
4711558Srgrimes	char *fslist;
4721558Srgrimes{
4731558Srgrimes	const char **av;
4741558Srgrimes	int i;
4751558Srgrimes	char *nextcp;
4761558Srgrimes
4771558Srgrimes	if (fslist == NULL)
4781558Srgrimes		return (NULL);
4791558Srgrimes	if (fslist[0] == 'n' && fslist[1] == 'o') {
4801558Srgrimes		fslist += 2;
4811558Srgrimes		skipvfs = 1;
4821558Srgrimes	}
4831558Srgrimes	for (i = 0, nextcp = fslist; *nextcp; nextcp++)
4841558Srgrimes		if (*nextcp == ',')
4851558Srgrimes			i++;
4861558Srgrimes	if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) {
4871558Srgrimes		warn(NULL);
4881558Srgrimes		return (NULL);
4891558Srgrimes	}
4901558Srgrimes	nextcp = fslist;
4911558Srgrimes	i = 0;
4921558Srgrimes	av[i++] = nextcp;
4931558Srgrimes	while ((nextcp = strchr(nextcp, ',')) != NULL) {
4941558Srgrimes		*nextcp++ = '\0';
4951558Srgrimes		av[i++] = nextcp;
4961558Srgrimes	}
4971558Srgrimes	av[i++] = NULL;
4981558Srgrimes	return (av);
4991558Srgrimes}
5001558Srgrimes
5011558Srgrimeschar *
5021558Srgrimescatopt(s0, s1)
5031558Srgrimes	char *s0;
5041558Srgrimes	const char *s1;
5051558Srgrimes{
5061558Srgrimes	size_t i;
5071558Srgrimes	char *cp;
5081558Srgrimes
5091558Srgrimes	if (s0 && *s0) {
5101558Srgrimes		i = strlen(s0) + strlen(s1) + 1 + 1;
5111558Srgrimes		if ((cp = malloc(i)) == NULL)
5121558Srgrimes			err(1, NULL);
5131558Srgrimes		(void)snprintf(cp, i, "%s,%s", s0, s1);
5141558Srgrimes	} else
5151558Srgrimes		cp = strdup(s1);
5161558Srgrimes
5171558Srgrimes	if (s0)
5181558Srgrimes		free(s0);
5191558Srgrimes	return (cp);
5201558Srgrimes}
5211558Srgrimes
5221558Srgrimesvoid
5231558Srgrimesmangle(options, argcp, argv)
5241558Srgrimes	char *options;
5251558Srgrimes	int *argcp;
5261558Srgrimes	const char **argv;
5271558Srgrimes{
5281558Srgrimes	char *p, *s;
5291558Srgrimes	int argc;
5301558Srgrimes
5311558Srgrimes	argc = *argcp;
5321558Srgrimes	for (s = options; (p = strsep(&s, ",")) != NULL;)
5331558Srgrimes		if (*p != '\0')
5341558Srgrimes			if (*p == '-') {
5351558Srgrimes				argv[argc++] = p;
5361558Srgrimes				p = strchr(p, '=');
5371558Srgrimes				if (p) {
5381558Srgrimes					*p = '\0';
5391558Srgrimes					argv[argc++] = p+1;
5401558Srgrimes				}
5411558Srgrimes			} else if (strcmp(p, "rw") != 0) {
5421558Srgrimes				argv[argc++] = "-o";
5431558Srgrimes				argv[argc++] = p;
5441558Srgrimes			}
5451558Srgrimes
5461558Srgrimes	*argcp = argc;
5471558Srgrimes}
5481558Srgrimes
5491558Srgrimesvoid
5501558Srgrimesusage()
5511558Srgrimes{
5521558Srgrimes
5531558Srgrimes	(void)fprintf(stderr,
5541558Srgrimes		"usage: mount %s %s\n       mount %s\n       mount %s\n",
55517243Sjkh		"[-dfpruvw] [-o options] [-t ufs | external_type]",
5561558Srgrimes			"special node",
55717243Sjkh		"[-adfpruvw] [-t ufs | external_type]",
55817243Sjkh		"[-dfpruvw] special | node");
5591558Srgrimes	exit(1);
5601558Srgrimes}
56117243Sjkh
56217243Sjkhvoid
56317243Sjkhputfsent (ent)
56417243Sjkh    const struct statfs	    *ent;
56517243Sjkh{
56617243Sjkh    struct fstab    *fst;
56717243Sjkh
56817243Sjkh    printf ("%s\t%s\t%s %s",
56917243Sjkh	    ent->f_mntfromname, ent->f_mntonname,
57017243Sjkh	    mnttype[ent->f_type],
57117243Sjkh	    (ent->f_flags & MNT_RDONLY) ? "ro" : "rw");
57217243Sjkh
57317243Sjkh    if (ent->f_flags & MNT_SYNCHRONOUS)
57417243Sjkh	printf (",sync");
57517243Sjkh
57617243Sjkh    if (ent->f_flags & MNT_NOEXEC)
57717243Sjkh	printf (",noexec");
57817243Sjkh
57917243Sjkh    if (ent->f_flags & MNT_NOSUID)
58017243Sjkh	printf (",nosuid");
58117243Sjkh
58217243Sjkh    if (ent->f_flags & MNT_NODEV)
58317243Sjkh	printf (",nodev");
58417243Sjkh
58517243Sjkh    if (ent->f_flags & MNT_UNION)
58617243Sjkh	printf (",union");
58717243Sjkh
58817243Sjkh    if (ent->f_flags & MNT_ASYNC)
58917243Sjkh	printf (",async");
59017243Sjkh
59117243Sjkh    if (fst = getfsspec (ent->f_mntfromname))
59217243Sjkh	printf ("\t%u %u\n", fst->fs_freq, fst->fs_passno);
59317243Sjkh    else if (fst = getfsfile (ent->f_mntonname))
59417243Sjkh	printf ("\t%u %u\n", fst->fs_freq, fst->fs_passno);
59517243Sjkh    else if (ent->f_type == MOUNT_UFS)
59617243Sjkh	printf ("\t1 1\n");
59717243Sjkh    else
59817243Sjkh	printf ("\t0 0\n");
59917243Sjkh}
600