mount.c revision 23678
1/*
2 * Copyright (c) 1980, 1989, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)mount.c	8.25 (Berkeley) 5/8/95";
42#endif /* not lint */
43
44#include <sys/param.h>
45#include <sys/mount.h>
46#include <sys/wait.h>
47#include <sys/types.h>
48#include <sys/stat.h>
49
50#include <err.h>
51#include <errno.h>
52#include <fstab.h>
53#include <pwd.h>
54#include <signal.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <unistd.h>
59
60#include "pathnames.h"
61
62int debug, verbose;
63int fstab_style = 0;
64
65int	checkvfsname __P((const char *, const char **));
66char   *catopt __P((char *, const char *));
67struct statfs
68       *getmntpt __P((const char *));
69int	hasopt __P((const char *, const char *));
70const char
71      **makevfslist __P((char *));
72void	mangle __P((char *, int *, const char **));
73int	mountfs __P((const char *, const char *, const char *,
74			int, const char *, const char *));
75void	prmount __P((struct statfs *));
76void	usage __P((void));
77void	putfsent __P((const struct statfs *));
78
79/* From mount_ufs.c. */
80int	mount_ufs __P((int, char * const *));
81
82/* Map from mount otions to printable formats. */
83static struct opt {
84	int o_opt;
85	const char *o_name;
86} optnames[] = {
87	{ MNT_ASYNC,		"asynchronous" },
88	{ MNT_EXPORTED,		"NFS exported" },
89	{ MNT_LOCAL,		"local" },
90	{ MNT_NOATIME,		"noatime" },
91	{ MNT_NODEV,		"nodev" },
92	{ MNT_NOEXEC,		"noexec" },
93	{ MNT_NOSUID,		"nosuid" },
94	{ MNT_QUOTA,		"with quotas" },
95	{ MNT_RDONLY,		"read-only" },
96	{ MNT_SYNCHRONOUS,	"synchronous" },
97	{ MNT_UNION,		"union" },
98	{ MNT_NOATIME,		"noatime" },
99	{ NULL }
100};
101
102int
103main(argc, argv)
104	int argc;
105	char * const argv[];
106{
107	const char *mntfromname, **vfslist, *vfstype;
108	struct fstab *fs;
109	struct statfs *mntbuf;
110	FILE *mountdfp;
111	pid_t pid;
112	int all, ch, i, init_flags, mntsize, rval;
113	char *options;
114
115	all = init_flags = 0;
116	options = NULL;
117	vfslist = NULL;
118	vfstype = "ufs";
119	while ((ch = getopt(argc, argv, "padfo:rwt:uv")) != EOF)
120		switch (ch) {
121		case 'p':
122			fstab_style = 1;
123			verbose = 1;
124			break;
125		case 'a':
126			all = 1;
127			break;
128		case 'd':
129			debug = 1;
130			break;
131		case 'f':
132			init_flags |= MNT_FORCE;
133			break;
134		case 'o':
135			if (*optarg)
136				options = catopt(options, optarg);
137			break;
138		case 'r':
139			init_flags |= MNT_RDONLY;
140			break;
141		case 't':
142			if (vfslist != NULL)
143				errx(1, "only one -t option may be specified.");
144			vfslist = makevfslist(optarg);
145			vfstype = optarg;
146			break;
147		case 'u':
148			init_flags |= MNT_UPDATE;
149			break;
150		case 'v':
151			verbose = 1;
152			break;
153		case 'w':
154			init_flags &= ~MNT_RDONLY;
155			break;
156		case '?':
157		default:
158			usage();
159			/* NOTREACHED */
160		}
161	argc -= optind;
162	argv += optind;
163
164#define	BADTYPE(type)							\
165	(strcmp(type, FSTAB_RO) &&					\
166	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
167
168	rval = 0;
169	switch (argc) {
170	case 0:
171		if (all)
172			while ((fs = getfsent()) != NULL) {
173				if (BADTYPE(fs->fs_type))
174					continue;
175				if (checkvfsname(fs->fs_vfstype, vfslist))
176					continue;
177				if (hasopt(fs->fs_mntops, "noauto"))
178					continue;
179				if (mountfs(fs->fs_vfstype, fs->fs_spec,
180		    			fs->fs_file, init_flags, options,
181			    		fs->fs_mntops))
182						rval = 1;
183			}
184		else if (fstab_style) {
185			if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
186				err(1, "getmntinfo");
187			for (i = 0; i < mntsize; i++) {
188				if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
189					continue;
190				putfsent (&mntbuf[i]);
191			}
192		}
193		else {
194			if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
195				err(1, "getmntinfo");
196			for (i = 0; i < mntsize; i++) {
197				if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
198					continue;
199				prmount(&mntbuf[i]);
200			}
201		}
202		exit(rval);
203	case 1:
204		if (vfslist != NULL)
205			usage();
206
207		if (init_flags & MNT_UPDATE) {
208			if ((mntbuf = getmntpt(*argv)) == NULL)
209				errx(1,
210				    "unknown special file or file system %s.",
211				    *argv);
212			if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL)
213				mntfromname = fs->fs_spec;
214			else
215				mntfromname = mntbuf->f_mntfromname;
216			rval = mountfs(mntbuf->f_fstypename, mntfromname,
217			    mntbuf->f_mntonname, init_flags, options, 0);
218			break;
219		}
220		if ((fs = getfsfile(*argv)) == NULL &&
221		    (fs = getfsspec(*argv)) == NULL)
222			errx(1, "%s: unknown special file or file system.",
223			    *argv);
224		if (BADTYPE(fs->fs_type))
225			errx(1, "%s has unknown file system type.",
226			    *argv);
227		rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file,
228		    init_flags, options, fs->fs_mntops);
229		break;
230	case 2:
231		/*
232		 * If -t flag has not been specified, and spec contains either
233		 * a ':' or a '@' then assume that an NFS filesystem is being
234		 * specified ala Sun.
235		 */
236		if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL)
237			vfstype = "nfs";
238		rval = mountfs(vfstype,
239		    argv[0], argv[1], init_flags, options, NULL);
240		break;
241	default:
242		usage();
243		/* NOTREACHED */
244	}
245
246	/*
247	 * If the mount was successfully, and done by root, tell mountd the
248	 * good news.  Pid checks are probably unnecessary, but don't hurt.
249	 */
250	if (rval == 0 && getuid() == 0 &&
251	    (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
252		if (fscanf(mountdfp, "%ld", &pid) == 1 &&
253		     pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
254			err(1, "signal mountd");
255		(void)fclose(mountdfp);
256	}
257
258	exit(rval);
259}
260
261int
262hasopt(mntopts, option)
263	const char *mntopts, *option;
264{
265	int negative, found;
266	char *opt, *optbuf;
267
268	if (option[0] == 'n' && option[1] == 'o') {
269		negative = 1;
270		option += 2;
271	} else
272		negative = 0;
273	optbuf = strdup(mntopts);
274	found = 0;
275	for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
276		if (opt[0] == 'n' && opt[1] == 'o') {
277			if (!strcasecmp(opt + 2, option))
278				found = negative;
279		} else if (!strcasecmp(opt, option))
280			found = !negative;
281	}
282	free(optbuf);
283	return (found);
284}
285
286int
287mountfs(vfstype, spec, name, flags, options, mntopts)
288	const char *vfstype, *spec, *name, *options, *mntopts;
289	int flags;
290{
291	struct stat sb;
292
293	/* List of directories containing mount_xxx subcommands. */
294	static const char *edirs[] = {
295		_PATH_SBIN,
296		_PATH_USRSBIN,
297		NULL
298	};
299	const char *argv[100], **edir;
300	struct statfs sf;
301	pid_t pid;
302	int argc, i, status;
303	char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
304
305	if (realpath(name, mntpath) != NULL && stat(mntpath, &sb) == 0) {
306		if (!S_ISDIR(sb.st_mode)) {
307			warnx("%s: Not a directory", mntpath);
308			return (1);
309		}
310	} else {
311		warn("%s", mntpath);
312		return (1);
313	}
314
315	if (mntopts == NULL)
316		mntopts = "";
317
318	name = mntpath;
319
320	if (mntopts == NULL)
321		mntopts = "";
322	if (options == NULL) {
323		if (*mntopts == '\0') {
324			options = "rw";
325		} else {
326			options = mntopts;
327			mntopts = "";
328		}
329	}
330	optbuf = catopt(strdup(mntopts), options);
331
332	if (strcmp(name, "/") == 0)
333		flags |= MNT_UPDATE;
334	if (flags & MNT_FORCE)
335		optbuf = catopt(optbuf, "force");
336	if (flags & MNT_RDONLY)
337		optbuf = catopt(optbuf, "ro");
338	/*
339	 * XXX
340	 * The mount_mfs (newfs) command uses -o to select the
341	 * optimisation mode.  We don't pass the default "-o rw"
342	 * for that reason.
343	 */
344	if (flags & MNT_UPDATE)
345		optbuf = catopt(optbuf, "update");
346
347	argc = 0;
348	argv[argc++] = vfstype;
349	mangle(optbuf, &argc, argv);
350	argv[argc++] = spec;
351	argv[argc++] = name;
352	argv[argc] = NULL;
353
354	if (debug) {
355		(void)printf("exec: mount_%s", vfstype);
356		for (i = 1; i < argc; i++)
357			(void)printf(" %s", argv[i]);
358		(void)printf("\n");
359		return (0);
360	}
361
362	switch (pid = vfork()) {
363	case -1:				/* Error. */
364		warn("vfork");
365		free(optbuf);
366		return (1);
367	case 0:					/* Child. */
368		if (strcmp(vfstype, "ufs") == 0)
369			exit(mount_ufs(argc, (char * const *) argv));
370
371		/* Go find an executable. */
372		for (edir = edirs; *edir; edir++) {
373			(void)snprintf(execname,
374			    sizeof(execname), "%s/mount_%s", *edir, vfstype);
375			execv(execname, (char * const *)argv);
376		}
377		if (errno == ENOENT) {
378			int len = 0;
379			char *cp;
380			for (edir = edirs; *edir; edir++)
381				len += strlen(*edir) + 2;	/* ", " */
382			if ((cp = malloc(len)) == NULL) {
383				warn(NULL);
384				exit(1);
385			}
386			cp[0] = '\0';
387			for (edir = edirs; *edir; edir++) {
388				strcat(cp, *edir);
389				if (edir[1] != NULL)
390					strcat(cp, ", ");
391			}
392			warn("exec mount_%s not found in %s", vfstype, cp);
393		}
394		exit(1);
395		/* NOTREACHED */
396	default:				/* Parent. */
397		free(optbuf);
398
399		if (waitpid(pid, &status, 0) < 0) {
400			warn("waitpid");
401			return (1);
402		}
403
404		if (WIFEXITED(status)) {
405			if (WEXITSTATUS(status) != 0)
406				return (WEXITSTATUS(status));
407		} else if (WIFSIGNALED(status)) {
408			warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
409			return (1);
410		}
411
412		if (verbose) {
413			if (statfs(name, &sf) < 0) {
414				warn("statfs %s", name);
415				return (1);
416			}
417			if (fstab_style)
418				putfsent (&sf);
419			else
420				prmount(&sf);
421		}
422		break;
423	}
424
425	return (0);
426}
427
428void
429prmount(sfp)
430	struct statfs *sfp;
431{
432	int flags;
433	struct opt *o;
434	struct passwd *pw;
435	int f;
436
437	(void)printf("%s on %s", sfp->f_mntfromname, sfp->f_mntonname);
438
439	flags = sfp->f_flags & MNT_VISFLAGMASK;
440	for (f = 0, o = optnames; flags && o->o_opt; o++)
441		if (flags & o->o_opt) {
442			(void)printf("%s%s", !f++ ? " (" : ", ", o->o_name);
443			flags &= ~o->o_opt;
444		}
445	if (sfp->f_owner) {
446		(void)printf("%smounted by ", !f++ ? " (" : ", ");
447		if ((pw = getpwuid(sfp->f_owner)) != NULL)
448			(void)printf("%s", pw->pw_name);
449		else
450			(void)printf("%d", sfp->f_owner);
451	}
452	(void)printf(f ? ")\n" : "\n");
453}
454
455struct statfs *
456getmntpt(name)
457	const char *name;
458{
459	struct statfs *mntbuf;
460	int i, mntsize;
461
462	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
463	for (i = 0; i < mntsize; i++)
464		if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
465		    strcmp(mntbuf[i].f_mntonname, name) == 0)
466			return (&mntbuf[i]);
467	return (NULL);
468}
469
470char *
471catopt(s0, s1)
472	char *s0;
473	const char *s1;
474{
475	size_t i;
476	char *cp;
477
478	if (s0 && *s0) {
479		i = strlen(s0) + strlen(s1) + 1 + 1;
480		if ((cp = malloc(i)) == NULL)
481			err(1, NULL);
482		(void)snprintf(cp, i, "%s,%s", s0, s1);
483	} else
484		cp = strdup(s1);
485
486	if (s0)
487		free(s0);
488	return (cp);
489}
490
491void
492mangle(options, argcp, argv)
493	char *options;
494	int *argcp;
495	const char **argv;
496{
497	char *p, *s;
498	int argc;
499
500	argc = *argcp;
501	for (s = options; (p = strsep(&s, ",")) != NULL;)
502		if (*p != '\0')
503			if (*p == '-') {
504				argv[argc++] = p;
505				p = strchr(p, '=');
506				if (p) {
507					*p = '\0';
508					argv[argc++] = p+1;
509				}
510			} else if (strcmp(p, "rw") != 0) {
511				argv[argc++] = "-o";
512				argv[argc++] = p;
513			}
514
515	*argcp = argc;
516}
517
518void
519usage()
520{
521
522	(void)fprintf(stderr,
523		"usage: mount %s %s\n       mount %s\n       mount %s\n",
524		"[-dfpruvw] [-o options] [-t ufs | external_type]",
525			"special node",
526		"[-adfpruvw] [-t ufs | external_type]",
527		"[-dfpruvw] special | node");
528	exit(1);
529}
530
531void
532putfsent (ent)
533    const struct statfs	    *ent;
534{
535    struct fstab    *fst;
536
537    printf ("%s\t%s\t%s %s",
538	    ent->f_mntfromname, ent->f_mntonname,
539	    ent->f_fstypename,
540	    (ent->f_flags & MNT_RDONLY) ? "ro" : "rw");
541
542    if (ent->f_flags & MNT_SYNCHRONOUS)
543	printf (",sync");
544
545    if (ent->f_flags & MNT_NOEXEC)
546	printf (",noexec");
547
548    if (ent->f_flags & MNT_NOSUID)
549	printf (",nosuid");
550
551    if (ent->f_flags & MNT_NODEV)
552	printf (",nodev");
553
554    if (ent->f_flags & MNT_UNION)
555	printf (",union");
556
557    if (ent->f_flags & MNT_ASYNC)
558	printf (",async");
559
560    if (ent->f_flags & MNT_NOATIME)
561	printf (",noatime");
562
563    if (fst = getfsspec (ent->f_mntfromname))
564	printf ("\t%u %u\n", fst->fs_freq, fst->fs_passno);
565    else if (fst = getfsfile (ent->f_mntonname))
566	printf ("\t%u %u\n", fst->fs_freq, fst->fs_passno);
567    else if (ent->f_type == MOUNT_UFS)
568	printf ("\t1 1\n");
569    else
570	printf ("\t0 0\n");
571}
572