mount.c revision 77577
1214501Srpaulo/*-
2214501Srpaulo * Copyright (c) 1980, 1989, 1993, 1994
3337817Scy *	The Regents of the University of California.  All rights reserved.
4214501Srpaulo *
5252726Srpaulo * Redistribution and use in source and binary forms, with or without
6252726Srpaulo * modification, are permitted provided that the following conditions
7214501Srpaulo * are met:
8214501Srpaulo * 1. Redistributions of source code must retain the above copyright
9214501Srpaulo *    notice, this list of conditions and the following disclaimer.
10214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
11214501Srpaulo *    notice, this list of conditions and the following disclaimer in the
12214501Srpaulo *    documentation and/or other materials provided with the distribution.
13214501Srpaulo * 3. All advertising materials mentioning features or use of this software
14214501Srpaulo *    must display the following acknowledgement:
15214501Srpaulo *	This product includes software developed by the University of
16214501Srpaulo *	California, Berkeley and its contributors.
17214501Srpaulo * 4. Neither the name of the University nor the names of its contributors
18214501Srpaulo *    may be used to endorse or promote products derived from this software
19214501Srpaulo *    without specific prior written permission.
20214501Srpaulo *
21214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22252726Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24214501Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25252726Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31214501Srpaulo * SUCH DAMAGE.
32214501Srpaulo */
33214501Srpaulo
34214501Srpaulo#ifndef lint
35214501Srpaulostatic const char copyright[] =
36214501Srpaulo"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\
37214501Srpaulo	The Regents of the University of California.  All rights reserved.\n";
38252726Srpaulo#endif /* not lint */
39252726Srpaulo
40252726Srpaulo#ifndef lint
41252726Srpaulo#if 0
42214501Srpaulostatic char sccsid[] = "@(#)mount.c	8.25 (Berkeley) 5/8/95";
43281806Srpaulo#endif
44214501Srpaulostatic const char rcsid[] =
45214501Srpaulo  "$FreeBSD: head/sbin/mount/mount.c 77577 2001-06-01 10:57:26Z ru $";
46252726Srpaulo#endif /* not lint */
47252726Srpaulo
48252726Srpaulo#include <sys/param.h>
49281806Srpaulo#include <sys/mount.h>
50252726Srpaulo#include <sys/stat.h>
51252726Srpaulo#include <sys/wait.h>
52252726Srpaulo
53252726Srpaulo#include <err.h>
54252726Srpaulo#include <errno.h>
55252726Srpaulo#include <fstab.h>
56252726Srpaulo#include <pwd.h>
57252726Srpaulo#include <signal.h>
58252726Srpaulo#include <stdio.h>
59252726Srpaulo#include <stdlib.h>
60252726Srpaulo#include <string.h>
61252726Srpaulo#include <unistd.h>
62281806Srpaulo
63281806Srpaulo#include "extern.h"
64281806Srpaulo#include "mntopts.h"
65281806Srpaulo#include "pathnames.h"
66281806Srpaulo
67281806Srpaulo/* `meta' options */
68281806Srpaulo#define MOUNT_META_OPTION_FSTAB		"fstab"
69281806Srpaulo#define MOUNT_META_OPTION_CURRENT	"current"
70252726Srpaulo
71252726Srpauloint debug, fstab_style, verbose;
72252726Srpaulo
73252726Srpaulochar   *catopt __P((char *, const char *));
74252726Srpaulostruct statfs
75252726Srpaulo       *getmntpt __P((const char *));
76252726Srpauloint	hasopt __P((const char *, const char *));
77252726Srpauloint	ismounted __P((struct fstab *, struct statfs *, int));
78252726Srpauloint	isremountable __P((const char *));
79252726Srpaulovoid	mangle __P((char *, int *, const char **));
80252726Srpaulochar   *update_options __P((char *, char *, int));
81252726Srpauloint	mountfs __P((const char *, const char *, const char *,
82252726Srpaulo			int, const char *, const char *));
83252726Srpaulovoid	remopt __P((char *, const char *));
84252726Srpaulovoid	prmount __P((struct statfs *));
85252726Srpaulovoid	putfsent __P((const struct statfs *));
86281806Srpaulovoid	usage __P((void));
87252726Srpaulochar   *flags2opts __P((int));
88252726Srpaulo
89252726Srpaulo/* Map from mount options to printable formats. */
90252726Srpaulostatic struct opt {
91252726Srpaulo	int o_opt;
92252726Srpaulo	const char *o_name;
93252726Srpaulo} optnames[] = {
94252726Srpaulo	{ MNT_ASYNC,		"asynchronous" },
95281806Srpaulo	{ MNT_EXPORTED,		"NFS exported" },
96281806Srpaulo	{ MNT_LOCAL,		"local" },
97214501Srpaulo	{ MNT_NOATIME,		"noatime" },
98214501Srpaulo	{ MNT_NODEV,		"nodev" },
99214501Srpaulo	{ MNT_NOEXEC,		"noexec" },
100214501Srpaulo	{ MNT_NOSUID,		"nosuid" },
101214501Srpaulo	{ MNT_NOSYMFOLLOW,	"nosymfollow" },
102214501Srpaulo	{ MNT_QUOTA,		"with quotas" },
103281806Srpaulo	{ MNT_RDONLY,		"read-only" },
104281806Srpaulo	{ MNT_SYNCHRONOUS,	"synchronous" },
105281806Srpaulo	{ MNT_UNION,		"union" },
106281806Srpaulo	{ MNT_NOCLUSTERR,	"noclusterr" },
107281806Srpaulo	{ MNT_NOCLUSTERW,	"noclusterw" },
108281806Srpaulo	{ MNT_SUIDDIR,		"suiddir" },
109281806Srpaulo	{ MNT_SOFTDEP,		"soft-updates" },
110281806Srpaulo	{ 0, NULL }
111281806Srpaulo};
112281806Srpaulo
113214501Srpaulo/*
114214501Srpaulo * List of VFS types that can be remounted without becoming mounted on top
115214501Srpaulo * of each other.
116214501Srpaulo * XXX Is this list correct?
117214501Srpaulo */
118214501Srpaulostatic const char *
119214501Srpauloremountable_fs_names[] = {
120214501Srpaulo	"ufs", "ffs", "ext2fs",
121214501Srpaulo	0
122214501Srpaulo};
123214501Srpaulo
124214501Srpauloint
125214501Srpaulomain(argc, argv)
126281806Srpaulo	int argc;
127214501Srpaulo	char * const argv[];
128214501Srpaulo{
129281806Srpaulo	const char *mntfromname, **vfslist, *vfstype;
130281806Srpaulo	struct fstab *fs;
131281806Srpaulo	struct statfs *mntbuf;
132281806Srpaulo	FILE *mountdfp;
133281806Srpaulo	pid_t pid;
134214501Srpaulo	int all, ch, i, init_flags, mntsize, rval, have_fstab;
135214501Srpaulo	char *options;
136214501Srpaulo
137214501Srpaulo	all = init_flags = 0;
138214501Srpaulo	options = NULL;
139214501Srpaulo	vfslist = NULL;
140214501Srpaulo	vfstype = "ufs";
141214501Srpaulo	while ((ch = getopt(argc, argv, "adfo:prwt:uv")) != -1)
142214501Srpaulo		switch (ch) {
143214501Srpaulo		case 'a':
144214501Srpaulo			all = 1;
145214501Srpaulo			break;
146214501Srpaulo		case 'd':
147214501Srpaulo			debug = 1;
148214501Srpaulo			break;
149214501Srpaulo		case 'f':
150214501Srpaulo			init_flags |= MNT_FORCE;
151214501Srpaulo			break;
152214501Srpaulo		case 'o':
153214501Srpaulo			if (*optarg)
154214501Srpaulo				options = catopt(options, optarg);
155214501Srpaulo			break;
156214501Srpaulo		case 'p':
157214501Srpaulo			fstab_style = 1;
158214501Srpaulo			verbose = 1;
159214501Srpaulo			break;
160214501Srpaulo		case 'r':
161214501Srpaulo			options = catopt(options, "ro");
162214501Srpaulo			break;
163214501Srpaulo		case 't':
164214501Srpaulo			if (vfslist != NULL)
165252726Srpaulo				errx(1, "only one -t option may be specified");
166252726Srpaulo			vfslist = makevfslist(optarg);
167252726Srpaulo			vfstype = optarg;
168214501Srpaulo			break;
169214501Srpaulo		case 'u':
170214501Srpaulo			init_flags |= MNT_UPDATE;
171214501Srpaulo			break;
172214501Srpaulo		case 'v':
173214501Srpaulo			verbose = 1;
174214501Srpaulo			break;
175214501Srpaulo		case 'w':
176214501Srpaulo			options = catopt(options, "noro");
177214501Srpaulo			break;
178214501Srpaulo		case '?':
179214501Srpaulo		default:
180214501Srpaulo			usage();
181214501Srpaulo			/* NOTREACHED */
182214501Srpaulo		}
183214501Srpaulo	argc -= optind;
184214501Srpaulo	argv += optind;
185214501Srpaulo
186214501Srpaulo#define	BADTYPE(type)							\
187214501Srpaulo	(strcmp(type, FSTAB_RO) &&					\
188281806Srpaulo	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
189214501Srpaulo
190214501Srpaulo	rval = 0;
191214501Srpaulo	switch (argc) {
192214501Srpaulo	case 0:
193214501Srpaulo		if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
194214501Srpaulo			err(1, "getmntinfo");
195214501Srpaulo		if (all) {
196214501Srpaulo			while ((fs = getfsent()) != NULL) {
197214501Srpaulo				if (BADTYPE(fs->fs_type))
198214501Srpaulo					continue;
199214501Srpaulo				if (checkvfsname(fs->fs_vfstype, vfslist))
200214501Srpaulo					continue;
201214501Srpaulo				if (hasopt(fs->fs_mntops, "noauto"))
202214501Srpaulo					continue;
203214501Srpaulo				if (!(init_flags & MNT_UPDATE) &&
204214501Srpaulo				    ismounted(fs, mntbuf, mntsize))
205214501Srpaulo					continue;
206214501Srpaulo				if (mountfs(fs->fs_vfstype, fs->fs_spec,
207214501Srpaulo				    fs->fs_file, init_flags, options,
208214501Srpaulo				    fs->fs_mntops))
209214501Srpaulo					rval = 1;
210252726Srpaulo			}
211252726Srpaulo		} else if (fstab_style) {
212252726Srpaulo			for (i = 0; i < mntsize; i++) {
213252726Srpaulo				if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
214252726Srpaulo					continue;
215252726Srpaulo				putfsent(&mntbuf[i]);
216252726Srpaulo			}
217252726Srpaulo		} else {
218252726Srpaulo			for (i = 0; i < mntsize; i++) {
219252726Srpaulo				if (checkvfsname(mntbuf[i].f_fstypename,
220252726Srpaulo				    vfslist))
221252726Srpaulo					continue;
222252726Srpaulo				prmount(&mntbuf[i]);
223252726Srpaulo			}
224252726Srpaulo		}
225252726Srpaulo		exit(rval);
226252726Srpaulo	case 1:
227214501Srpaulo		if (vfslist != NULL)
228252726Srpaulo			usage();
229252726Srpaulo
230214501Srpaulo		if (init_flags & MNT_UPDATE) {
231214501Srpaulo			mntfromname = NULL;
232214501Srpaulo			have_fstab = 0;
233252726Srpaulo			if ((mntbuf = getmntpt(*argv)) == NULL)
234214501Srpaulo				errx(1, "not currently mounted %s", *argv);
235214501Srpaulo			/*
236214501Srpaulo			 * Only get the mntflags from fstab if both mntpoint
237214501Srpaulo			 * and mntspec are identical. Also handle the special
238214501Srpaulo			 * case where just '/' is mounted and 'spec' is not
239214501Srpaulo			 * identical with the one from fstab ('/dev' is missing
240214501Srpaulo			 * in the spec-string at boot-time).
241252726Srpaulo			 */
242252726Srpaulo			if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) {
243252726Srpaulo				if (strcmp(fs->fs_spec,
244252726Srpaulo				    mntbuf->f_mntfromname) == 0 &&
245252726Srpaulo				    strcmp(fs->fs_file,
246214501Srpaulo				    mntbuf->f_mntonname) == 0) {
247214501Srpaulo					have_fstab = 1;
248214501Srpaulo					mntfromname = mntbuf->f_mntfromname;
249214501Srpaulo				} else if (argv[0][0] == '/' &&
250214501Srpaulo				    argv[0][1] == '\0') {
251214501Srpaulo					fs = getfsfile("/");
252214501Srpaulo					have_fstab = 1;
253214501Srpaulo					mntfromname = fs->fs_spec;
254214501Srpaulo				}
255214501Srpaulo			}
256214501Srpaulo			if (have_fstab) {
257214501Srpaulo				options = update_options(options, fs->fs_mntops,
258214501Srpaulo				    mntbuf->f_flags);
259214501Srpaulo			} else {
260214501Srpaulo				mntfromname = mntbuf->f_mntfromname;
261214501Srpaulo				options = update_options(options, NULL,
262214501Srpaulo				    mntbuf->f_flags);
263214501Srpaulo			}
264214501Srpaulo			rval = mountfs(mntbuf->f_fstypename, mntfromname,
265214501Srpaulo			    mntbuf->f_mntonname, init_flags, options, 0);
266214501Srpaulo			break;
267214501Srpaulo		}
268214501Srpaulo		rmslashes(*argv, *argv);
269214501Srpaulo		if ((fs = getfsfile(*argv)) == NULL &&
270214501Srpaulo		    (fs = getfsspec(*argv)) == NULL)
271214501Srpaulo			errx(1, "%s: unknown special file or file system",
272214501Srpaulo			    *argv);
273214501Srpaulo		if (BADTYPE(fs->fs_type))
274214501Srpaulo			errx(1, "%s has unknown file system type",
275214501Srpaulo			    *argv);
276214501Srpaulo		rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file,
277252726Srpaulo		    init_flags, options, fs->fs_mntops);
278252726Srpaulo		break;
279214501Srpaulo	case 2:
280214501Srpaulo		/*
281214501Srpaulo		 * If -t flag has not been specified, the path cannot be
282214501Srpaulo		 * found, spec contains either a ':' or a '@', and the
283214501Srpaulo		 * spec is not a file with those characters, then assume
284214501Srpaulo		 * that an NFS filesystem is being specified ala Sun.
285281806Srpaulo		 */
286281806Srpaulo		if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL &&
287281806Srpaulo		    access(argv[0], 0) == -1)
288281806Srpaulo			vfstype = "nfs";
289281806Srpaulo		rval = mountfs(vfstype,
290281806Srpaulo		    argv[0], argv[1], init_flags, options, NULL);
291281806Srpaulo		break;
292281806Srpaulo	default:
293281806Srpaulo		usage();
294281806Srpaulo		/* NOTREACHED */
295281806Srpaulo	}
296281806Srpaulo
297281806Srpaulo	/*
298281806Srpaulo	 * If the mount was successfully, and done by root, tell mountd the
299252726Srpaulo	 * good news.  Pid checks are probably unnecessary, but don't hurt.
300252726Srpaulo	 */
301214501Srpaulo	if (rval == 0 && getuid() == 0 &&
302252726Srpaulo	    (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
303252726Srpaulo		if (fscanf(mountdfp, "%d", &pid) == 1 &&
304252726Srpaulo		     pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
305252726Srpaulo			err(1, "signal mountd");
306252726Srpaulo		(void)fclose(mountdfp);
307252726Srpaulo	}
308252726Srpaulo
309252726Srpaulo	exit(rval);
310252726Srpaulo}
311252726Srpaulo
312252726Srpauloint
313281806Srpauloismounted(fs, mntbuf, mntsize)
314281806Srpaulo	struct fstab *fs;
315281806Srpaulo	struct statfs *mntbuf;
316281806Srpaulo	int mntsize;
317281806Srpaulo{
318281806Srpaulo	int i;
319281806Srpaulo
320281806Srpaulo	if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0')
321289549Srpaulo		/* the root file system can always be remounted */
322281806Srpaulo		return (0);
323281806Srpaulo
324281806Srpaulo	for (i = mntsize - 1; i >= 0; --i)
325281806Srpaulo		if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 &&
326281806Srpaulo		    (!isremountable(fs->fs_vfstype) ||
327281806Srpaulo		     strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0))
328281806Srpaulo			return (1);
329281806Srpaulo	return (0);
330281806Srpaulo}
331281806Srpaulo
332281806Srpauloint
333281806Srpauloisremountable(vfsname)
334281806Srpaulo	const char *vfsname;
335281806Srpaulo{
336281806Srpaulo	const char **cp;
337281806Srpaulo
338281806Srpaulo	for (cp = remountable_fs_names; *cp; cp++)
339281806Srpaulo		if (strcmp(*cp, vfsname) == 0)
340281806Srpaulo			return (1);
341281806Srpaulo	return (0);
342281806Srpaulo}
343281806Srpaulo
344289549Srpauloint
345289549Srpaulohasopt(mntopts, option)
346289549Srpaulo	const char *mntopts, *option;
347289549Srpaulo{
348289549Srpaulo	int negative, found;
349289549Srpaulo	char *opt, *optbuf;
350281806Srpaulo
351281806Srpaulo	if (option[0] == 'n' && option[1] == 'o') {
352281806Srpaulo		negative = 1;
353281806Srpaulo		option += 2;
354281806Srpaulo	} else
355281806Srpaulo		negative = 0;
356281806Srpaulo	optbuf = strdup(mntopts);
357346981Scy	found = 0;
358346981Scy	for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
359346981Scy		if (opt[0] == 'n' && opt[1] == 'o') {
360346981Scy			if (!strcasecmp(opt + 2, option))
361346981Scy				found = negative;
362346981Scy		} else if (!strcasecmp(opt, option))
363346981Scy			found = !negative;
364346981Scy	}
365346981Scy	free(optbuf);
366346981Scy	return (found);
367346981Scy}
368346981Scy
369281806Srpauloint
370281806Srpaulomountfs(vfstype, spec, name, flags, options, mntopts)
371281806Srpaulo	const char *vfstype, *spec, *name, *options, *mntopts;
372281806Srpaulo	int flags;
373281806Srpaulo{
374281806Srpaulo	/* List of directories containing mount_xxx subcommands. */
375281806Srpaulo	static const char *edirs[] = {
376281806Srpaulo		_PATH_SBIN,
377281806Srpaulo		_PATH_USRSBIN,
378281806Srpaulo		NULL
379281806Srpaulo	};
380281806Srpaulo	const char *argv[100], **edir;
381281806Srpaulo	struct statfs sf;
382281806Srpaulo	pid_t pid;
383281806Srpaulo	int argc, i, status;
384281806Srpaulo	char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
385281806Srpaulo
386281806Srpaulo#if __GNUC__
387281806Srpaulo	(void)&optbuf;
388281806Srpaulo	(void)&name;
389281806Srpaulo#endif
390281806Srpaulo
391281806Srpaulo	/* resolve the mountpoint with realpath(3) */
392281806Srpaulo	(void)checkpath(name, mntpath);
393281806Srpaulo	name = mntpath;
394281806Srpaulo
395281806Srpaulo	if (mntopts == NULL)
396281806Srpaulo		mntopts = "";
397281806Srpaulo	if (options == NULL) {
398281806Srpaulo		if (*mntopts == '\0') {
399281806Srpaulo			options = "rw";
400281806Srpaulo		} else {
401281806Srpaulo			options = mntopts;
402281806Srpaulo			mntopts = "";
403281806Srpaulo		}
404281806Srpaulo	}
405281806Srpaulo	optbuf = catopt(strdup(mntopts), options);
406281806Srpaulo
407252726Srpaulo	if (strcmp(name, "/") == 0)
408252726Srpaulo		flags |= MNT_UPDATE;
409252726Srpaulo	if (flags & MNT_FORCE)
410214501Srpaulo		optbuf = catopt(optbuf, "force");
411214501Srpaulo	if (flags & MNT_RDONLY)
412214501Srpaulo		optbuf = catopt(optbuf, "ro");
413214501Srpaulo	/*
414214501Srpaulo	 * XXX
415214501Srpaulo	 * The mount_mfs (newfs) command uses -o to select the
416346981Scy	 * optimization mode.  We don't pass the default "-o rw"
417214501Srpaulo	 * for that reason.
418252726Srpaulo	 */
419252726Srpaulo	if (flags & MNT_UPDATE)
420252726Srpaulo		optbuf = catopt(optbuf, "update");
421214501Srpaulo
422214501Srpaulo	/* Compatibility glue. */
423214501Srpaulo	if (strcmp(vfstype, "msdos") == 0)
424214501Srpaulo		vfstype = "msdosfs";
425214501Srpaulo
426214501Srpaulo	argc = 0;
427214501Srpaulo	argv[argc++] = vfstype;
428214501Srpaulo	mangle(optbuf, &argc, argv);
429214501Srpaulo	argv[argc++] = spec;
430214501Srpaulo	argv[argc++] = name;
431214501Srpaulo	argv[argc] = NULL;
432214501Srpaulo
433214501Srpaulo	if (debug) {
434214501Srpaulo		(void)printf("exec: mount_%s", vfstype);
435214501Srpaulo		for (i = 1; i < argc; i++)
436214501Srpaulo			(void)printf(" %s", argv[i]);
437252726Srpaulo		(void)printf("\n");
438252726Srpaulo		return (0);
439252726Srpaulo	}
440252726Srpaulo
441252726Srpaulo	switch (pid = fork()) {
442252726Srpaulo	case -1:				/* Error. */
443252726Srpaulo		warn("fork");
444252726Srpaulo		free(optbuf);
445252726Srpaulo		return (1);
446214501Srpaulo	case 0:					/* Child. */
447214501Srpaulo		if (strcmp(vfstype, "ufs") == 0)
448214501Srpaulo			exit(mount_ufs(argc, (char * const *) argv));
449214501Srpaulo
450214501Srpaulo		/* Go find an executable. */
451214501Srpaulo		for (edir = edirs; *edir; edir++) {
452214501Srpaulo			(void)snprintf(execname,
453214501Srpaulo			    sizeof(execname), "%s/mount_%s", *edir, vfstype);
454214501Srpaulo			execv(execname, (char * const *)argv);
455337817Scy		}
456337817Scy		if (errno == ENOENT) {
457214501Srpaulo			int len = 0;
458281806Srpaulo			char *cp;
459281806Srpaulo			for (edir = edirs; *edir; edir++)
460214501Srpaulo				len += strlen(*edir) + 2;	/* ", " */
461214501Srpaulo			if ((cp = malloc(len)) == NULL)
462214501Srpaulo				errx(1, "malloc failed");
463214501Srpaulo			cp[0] = '\0';
464289549Srpaulo			for (edir = edirs; *edir; edir++) {
465289549Srpaulo				strcat(cp, *edir);
466289549Srpaulo				if (edir[1] != NULL)
467289549Srpaulo					strcat(cp, ", ");
468289549Srpaulo			}
469214501Srpaulo			warn("exec mount_%s not found in %s", vfstype, cp);
470214501Srpaulo		}
471214501Srpaulo		exit(1);
472214501Srpaulo		/* NOTREACHED */
473214501Srpaulo	default:				/* Parent. */
474214501Srpaulo		free(optbuf);
475214501Srpaulo
476214501Srpaulo		if (waitpid(pid, &status, 0) < 0) {
477214501Srpaulo			warn("waitpid");
478214501Srpaulo			return (1);
479214501Srpaulo		}
480214501Srpaulo
481214501Srpaulo		if (WIFEXITED(status)) {
482214501Srpaulo			if (WEXITSTATUS(status) != 0)
483252726Srpaulo				return (WEXITSTATUS(status));
484281806Srpaulo		} else if (WIFSIGNALED(status)) {
485214501Srpaulo			warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
486214501Srpaulo			return (1);
487214501Srpaulo		}
488214501Srpaulo
489214501Srpaulo		if (verbose) {
490214501Srpaulo			if (statfs(name, &sf) < 0) {
491214501Srpaulo				warn("statfs %s", name);
492214501Srpaulo				return (1);
493214501Srpaulo			}
494214501Srpaulo			if (fstab_style)
495214501Srpaulo				putfsent(&sf);
496214501Srpaulo			else
497214501Srpaulo				prmount(&sf);
498214501Srpaulo		}
499214501Srpaulo		break;
500214501Srpaulo	}
501214501Srpaulo
502214501Srpaulo	return (0);
503214501Srpaulo}
504214501Srpaulo
505214501Srpaulovoid
506214501Srpauloprmount(sfp)
507214501Srpaulo	struct statfs *sfp;
508214501Srpaulo{
509214501Srpaulo	int flags;
510214501Srpaulo	struct opt *o;
511214501Srpaulo	struct passwd *pw;
512252726Srpaulo
513252726Srpaulo	(void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname,
514252726Srpaulo	    sfp->f_fstypename);
515252726Srpaulo
516252726Srpaulo	flags = sfp->f_flags & MNT_VISFLAGMASK;
517252726Srpaulo	for (o = optnames; flags && o->o_opt; o++)
518252726Srpaulo		if (flags & o->o_opt) {
519252726Srpaulo			(void)printf(", %s", o->o_name);
520252726Srpaulo			flags &= ~o->o_opt;
521252726Srpaulo		}
522252726Srpaulo	if (sfp->f_owner) {
523214501Srpaulo		(void)printf(", mounted by ");
524214501Srpaulo		if ((pw = getpwuid(sfp->f_owner)) != NULL)
525214501Srpaulo			(void)printf("%s", pw->pw_name);
526214501Srpaulo		else
527214501Srpaulo			(void)printf("%d", sfp->f_owner);
528214501Srpaulo	}
529214501Srpaulo	if (verbose) {
530214501Srpaulo		if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0)
531214501Srpaulo			(void)printf(", writes: sync %ld async %ld",
532214501Srpaulo			    sfp->f_syncwrites, sfp->f_asyncwrites);
533214501Srpaulo		if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0)
534214501Srpaulo			(void)printf(", reads: sync %ld async %ld",
535214501Srpaulo			    sfp->f_syncreads, sfp->f_asyncreads);
536346981Scy	}
537346981Scy	(void)printf(")\n");
538346981Scy}
539346981Scy
540214501Srpaulostruct statfs *
541214501Srpaulogetmntpt(name)
542214501Srpaulo	const char *name;
543214501Srpaulo{
544214501Srpaulo	struct statfs *mntbuf;
545214501Srpaulo	int i, mntsize;
546214501Srpaulo
547214501Srpaulo	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
548346981Scy	for (i = mntsize - 1; i >= 0; i--) {
549214501Srpaulo		if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
550346981Scy		    strcmp(mntbuf[i].f_mntonname, name) == 0)
551346981Scy			return (&mntbuf[i]);
552346981Scy	}
553346981Scy	return (NULL);
554346981Scy}
555346981Scy
556346981Scychar *
557346981Scycatopt(s0, s1)
558346981Scy	char *s0;
559346981Scy	const char *s1;
560214501Srpaulo{
561214501Srpaulo	size_t i;
562346981Scy	char *cp;
563346981Scy
564346981Scy	if (s1 == NULL || *s1 == '\0')
565346981Scy		return s0;
566346981Scy
567346981Scy	if (s0 && *s0) {
568346981Scy		i = strlen(s0) + strlen(s1) + 1 + 1;
569346981Scy		if ((cp = malloc(i)) == NULL)
570346981Scy			errx(1, "malloc failed");
571346981Scy		(void)snprintf(cp, i, "%s,%s", s0, s1);
572214501Srpaulo	} else
573214501Srpaulo		cp = strdup(s1);
574214501Srpaulo
575289549Srpaulo	if (s0)
576289549Srpaulo		free(s0);
577289549Srpaulo	return (cp);
578289549Srpaulo}
579289549Srpaulo
580214501Srpaulovoid
581214501Srpaulomangle(options, argcp, argv)
582214501Srpaulo	char *options;
583214501Srpaulo	int *argcp;
584214501Srpaulo	const char **argv;
585214501Srpaulo{
586214501Srpaulo	char *p, *s;
587214501Srpaulo	int argc;
588214501Srpaulo
589214501Srpaulo	argc = *argcp;
590214501Srpaulo	for (s = options; (p = strsep(&s, ",")) != NULL;)
591214501Srpaulo		if (*p != '\0') {
592214501Srpaulo			if (*p == '-') {
593214501Srpaulo				argv[argc++] = p;
594214501Srpaulo				p = strchr(p, '=');
595214501Srpaulo				if (p) {
596214501Srpaulo					*p = '\0';
597214501Srpaulo					argv[argc++] = p+1;
598214501Srpaulo				}
599214501Srpaulo			} else if (strcmp(p, "rw") != 0) {
600214501Srpaulo				argv[argc++] = "-o";
601214501Srpaulo				argv[argc++] = p;
602214501Srpaulo			}
603214501Srpaulo		}
604214501Srpaulo
605281806Srpaulo	*argcp = argc;
606281806Srpaulo}
607281806Srpaulo
608281806Srpaulo
609281806Srpaulochar *
610214501Srpauloupdate_options(opts, fstab, curflags)
611214501Srpaulo	char *opts;
612214501Srpaulo	char *fstab;
613214501Srpaulo	int curflags;
614214501Srpaulo{
615214501Srpaulo	char *o, *p;
616214501Srpaulo	char *cur;
617214501Srpaulo	char *expopt, *newopt, *tmpopt;
618214501Srpaulo
619214501Srpaulo	if (opts == NULL)
620252726Srpaulo		return strdup("");
621214501Srpaulo
622252726Srpaulo	/* remove meta options from list */
623252726Srpaulo	remopt(fstab, MOUNT_META_OPTION_FSTAB);
624214501Srpaulo	remopt(fstab, MOUNT_META_OPTION_CURRENT);
625346981Scy	cur = flags2opts(curflags);
626214501Srpaulo
627214501Srpaulo	/*
628214501Srpaulo	 * Expand all meta-options passed to us first.
629214501Srpaulo	 */
630214501Srpaulo	expopt = NULL;
631214501Srpaulo	for (p = opts; (o = strsep(&p, ",")) != NULL;) {
632214501Srpaulo		if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0)
633214501Srpaulo			expopt = catopt(expopt, fstab);
634214501Srpaulo		else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0)
635214501Srpaulo			expopt = catopt(expopt, cur);
636214501Srpaulo		else
637214501Srpaulo			expopt = catopt(expopt, o);
638214501Srpaulo	}
639214501Srpaulo	free(cur);
640214501Srpaulo	free(opts);
641214501Srpaulo
642214501Srpaulo	/*
643214501Srpaulo	 * Remove previous contradictory arguments. Given option "foo" we
644214501Srpaulo	 * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo"
645214501Srpaulo	 * and "foo" - so we can deal with possible options like "notice".
646214501Srpaulo	 */
647214501Srpaulo	newopt = NULL;
648214501Srpaulo	for (p = expopt; (o = strsep(&p, ",")) != NULL;) {
649214501Srpaulo		if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL)
650214501Srpaulo			errx(1, "malloc failed");
651214501Srpaulo
652214501Srpaulo		strcpy(tmpopt, "no");
653214501Srpaulo		strcat(tmpopt, o);
654214501Srpaulo		remopt(newopt, tmpopt);
655214501Srpaulo		free(tmpopt);
656214501Srpaulo
657214501Srpaulo		if (strncmp("no", o, 2) == 0)
658214501Srpaulo			remopt(newopt, o+2);
659214501Srpaulo
660214501Srpaulo		newopt = catopt(newopt, o);
661252726Srpaulo	}
662252726Srpaulo	free(expopt);
663252726Srpaulo
664252726Srpaulo	return newopt;
665252726Srpaulo}
666252726Srpaulo
667252726Srpaulovoid
668214501Srpauloremopt(string, opt)
669214501Srpaulo	char *string;
670214501Srpaulo 	const char *opt;
671214501Srpaulo{
672214501Srpaulo	char *o, *p, *r;
673214501Srpaulo
674252726Srpaulo	if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0')
675252726Srpaulo		return;
676214501Srpaulo
677214501Srpaulo	r = string;
678214501Srpaulo
679214501Srpaulo	for (p = string; (o = strsep(&p, ",")) != NULL;) {
680214501Srpaulo		if (strcmp(opt, o) != 0) {
681214501Srpaulo			if (*r == ',' && *o != '\0')
682214501Srpaulo				r++;
683214501Srpaulo			while ((*r++ = *o++) != '\0')
684252726Srpaulo			    ;
685214501Srpaulo			*--r = ',';
686252726Srpaulo		}
687214501Srpaulo	}
688252726Srpaulo	*r = '\0';
689252726Srpaulo}
690252726Srpaulo
691214501Srpaulovoid
692214501Srpaulousage()
693214501Srpaulo{
694214501Srpaulo
695214501Srpaulo	(void)fprintf(stderr, "%s\n%s\n%s\n",
696214501Srpaulo"usage: mount [-dfpruvw] [-o options] [-t ufs | external_type] special node",
697252726Srpaulo"       mount [-adfpruvw] [-t ufs | external_type]",
698252726Srpaulo"       mount [-dfpruvw] special | node");
699252726Srpaulo	exit(1);
700252726Srpaulo}
701214501Srpaulo
702252726Srpaulovoid
703214501Srpauloputfsent(ent)
704214501Srpaulo	const struct statfs *ent;
705214501Srpaulo{
706214501Srpaulo	struct fstab *fst;
707214501Srpaulo	char *opts;
708214501Srpaulo
709252726Srpaulo	opts = flags2opts(ent->f_flags);
710252726Srpaulo	printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname,
711252726Srpaulo	    ent->f_fstypename, opts);
712252726Srpaulo	free(opts);
713252726Srpaulo
714252726Srpaulo	if ((fst = getfsspec(ent->f_mntfromname)))
715252726Srpaulo		printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
716252726Srpaulo	else if ((fst = getfsfile(ent->f_mntonname)))
717252726Srpaulo		printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
718214501Srpaulo	else if (strcmp(ent->f_fstypename, "ufs") == 0) {
719214501Srpaulo		if (strcmp(ent->f_mntonname, "/") == 0)
720214501Srpaulo			printf("\t1 1\n");
721214501Srpaulo		else
722214501Srpaulo			printf("\t2 2\n");
723214501Srpaulo	} else
724214501Srpaulo		printf("\t0 0\n");
725214501Srpaulo}
726214501Srpaulo
727214501Srpaulo
728214501Srpaulochar *
729214501Srpauloflags2opts(flags)
730214501Srpaulo	int flags;
731214501Srpaulo{
732252726Srpaulo	char *res;
733214501Srpaulo
734214501Srpaulo	res = NULL;
735214501Srpaulo
736252726Srpaulo	res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw");
737252726Srpaulo
738252726Srpaulo	if (flags & MNT_SYNCHRONOUS)	res = catopt(res, "sync");
739281806Srpaulo	if (flags & MNT_NOEXEC)		res = catopt(res, "noexec");
740281806Srpaulo	if (flags & MNT_NOSUID)		res = catopt(res, "nosuid");
741281806Srpaulo	if (flags & MNT_NODEV)		res = catopt(res, "nodev");
742281806Srpaulo	if (flags & MNT_UNION)		res = catopt(res, "union");
743281806Srpaulo	if (flags & MNT_ASYNC)		res = catopt(res, "async");
744281806Srpaulo	if (flags & MNT_NOATIME)	res = catopt(res, "noatime");
745252726Srpaulo	if (flags & MNT_NOCLUSTERR)	res = catopt(res, "noclusterr");
746252726Srpaulo	if (flags & MNT_NOCLUSTERW)	res = catopt(res, "noclusterw");
747252726Srpaulo	if (flags & MNT_NOSYMFOLLOW)	res = catopt(res, "nosymfollow");
748252726Srpaulo	if (flags & MNT_SUIDDIR)	res = catopt(res, "suiddir");
749252726Srpaulo
750252726Srpaulo	return res;
751252726Srpaulo}
752252726Srpaulo