xref: /original-bsd/sbin/mount/mount.c (revision f737e041)
1 /*
2  * Copyright (c) 1980, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1989, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)mount.c	8.15 (Berkeley) 02/21/94";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/wait.h>
20 #include <sys/mount.h>
21 
22 #include <err.h>
23 #include <errno.h>
24 #include <fstab.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "pathnames.h"
32 
33 
34 int debug, force, verbose, mnttype, skipvfs;
35 char *mntname;
36 
37 int    badvfsname __P((char *, char **));
38 int    badvfstype __P((int, char **));
39 int    getexecopts __P((char *, char **));
40 struct statfs
41       *getmntpt __P((char *));
42 int    getmnttype __P((char *));
43 void   getstdopts __P((char *, int *));
44 void   getufsopts __P((char *, int *));
45 char **makevfslist __P((char *));
46 int    mountfs __P((char *, char *, int, char *, char *, char *));
47 void   prmount __P((char *, char *, int));
48 void   usage __P((void));
49 
50 int
51 main(argc, argv)
52 	int argc;
53 	char *argv[];
54 {
55 	struct fstab *fs;
56 	struct statfs *mntbuf;
57 	FILE *mountdfp;
58 	pid_t pid;
59 	long mntsize;
60 	int all, ch, i, rval, updateflg;
61 	char *cp, *type, *options, **vfslist;
62 
63 	mntname = "ufs";
64 	mnttype = MOUNT_UFS;
65 
66 	all = updateflg = 0;
67 	options = type = NULL;
68 	vfslist = NULL;
69 	while ((ch = getopt(argc, argv, "adfo:rwt:uv")) != EOF)
70 		switch(ch) {
71 		case 'a':
72 			all = 1;
73 			break;
74 		case 'd':
75 			debug = 1;
76 			break;
77 		case 'f':
78 			force = 1;
79 			break;
80 		case 'o':
81 			options = optarg;
82 			break;
83 		case 'r':
84 			type = FSTAB_RO;
85 			break;
86 		case 't':
87 			vfslist = makevfslist(optarg);
88 			mnttype = getmnttype(optarg);
89 			break;
90 		case 'u':
91 			updateflg = MNT_UPDATE;
92 			break;
93 		case 'v':
94 			verbose = 1;
95 			break;
96 		case 'w':
97 			type = FSTAB_RW;
98 			break;
99 		case '?':
100 		default:
101 			usage();
102 			/* NOTREACHED */
103 		}
104 	argc -= optind;
105 	argv += optind;
106 
107 #define	BADTYPE(type)							\
108 	(strcmp(type, FSTAB_RO) &&					\
109 	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
110 
111 	rval = 0;
112 	if (all) {
113 		while ((fs = getfsent()) != NULL) {
114 			if (BADTYPE(fs->fs_type))
115 				continue;
116 			if (badvfsname(fs->fs_vfstype, vfslist))
117 				continue;
118 			/* `/' is special, it's always mounted. */
119 			mnttype = getmnttype(fs->fs_vfstype);
120 			if (mountfs(fs->fs_spec, fs->fs_file, updateflg,
121 			    type, options, fs->fs_mntops))
122 				rval = 1;
123 		}
124 		exit(rval);
125 	}
126 
127 	if (argc == 0) {
128 		if (verbose || debug || type)
129 			usage();
130 		if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
131 			err(1, "getmntinfo");
132 		for (i = 0; i < mntsize; i++) {
133 			if (badvfstype(mntbuf[i].f_type, vfslist))
134 				continue;
135 			prmount(mntbuf[i].f_mntfromname,
136 			     mntbuf[i].f_mntonname, mntbuf[i].f_flags);
137 		}
138 		exit(0);
139 	}
140 
141 	if (argc == 1 && vfslist != NULL) {
142 		usage();
143 		/* NOTREACHED */
144 	}
145 
146 	if (argc == 1 && updateflg) {
147 		if ((mntbuf = getmntpt(*argv)) == NULL)
148 			errx(1,
149 			    "unknown special file or file system %s.", *argv);
150 		mnttype = mntbuf->f_type;
151 		if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL)
152 			errx(1, "can't find fstab entry for %s.", *argv);
153 		mntname = fs->fs_vfstype;
154 
155 		/*
156 		 * Default type to fstab version if none specified on the
157 		 * command line.
158 		 */
159 		if (type == NULL)
160 			type = fs->fs_type;
161 
162 		/*
163 		 * Default options to fstab version if none specified on the
164 		 * command line.
165 		 */
166 		if (options == NULL)
167 			options = fs->fs_mntops;
168 		else {
169 			/*
170 			 * Concat the two strings with the command line
171 			 * options last so that they will override the
172 			 * fstab options.
173 			 */
174 			i = strlen(fs->fs_mntops) + strlen(options) + 2;
175 			if ((cp = malloc((size_t)i)) == NULL)
176 				err(1, NULL);
177 			(void)snprintf(cp, i, "%s,%s", fs->fs_mntops, options);
178 			options = cp;
179 		}
180 		rval = mountfs(fs->fs_spec,
181 		    mntbuf->f_mntonname, updateflg, type, options, NULL);
182 	} else if (argc == 1) {
183 		if ((fs = getfsfile(*argv)) == NULL &&
184 		    (fs = getfsspec(*argv)) == NULL)
185 			errx(1,
186 			    "%s: unknown special file or file system.", *argv);
187 		if (BADTYPE(fs->fs_type))
188 			errx(1, "%s has unknown file system type.", *argv);
189 		mnttype = getmnttype(fs->fs_vfstype);
190 		rval = mountfs(fs->fs_spec,
191 		    fs->fs_file, updateflg, type, options, fs->fs_mntops);
192 	} else if (argc != 2) {
193 		usage();
194 		/* NOTREACHED */
195 	} else {
196 		/*
197 		 * If -t flag has not been specified, and spec contains either
198 		 * a ':' or a '@' then assume that an NFS filesystem is being
199 		 * specified ala Sun.
200 		 */
201 		if (vfslist == NULL &&
202 		    (strchr(argv[0], ':') || strchr(argv[0], '@'))) {
203 			mnttype = MOUNT_NFS;
204 			mntname = "nfs";
205 		}
206 		rval =
207 		    mountfs(argv[0], argv[1], updateflg, type, options, NULL);
208 	}
209 	/*
210 	 * If the mount succeeded, and root did the mount, then tell
211 	 * mountd the good news.  Pid checks are probably unnecessary,
212 	 * but don't hurt.
213 	 */
214 	if (rval == 0 && getuid() == 0 &&
215 	    (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
216 		if (fscanf(mountdfp, "%ld", &pid) == 1 &&
217 		    pid > 0 && kill(pid, SIGHUP))
218 			err(1, "signal mountd");
219 		(void)fclose(mountdfp);
220 	}
221 
222 	exit(rval);
223 }
224 
225 int
226 mountfs(spec, name, flags, type, options, mntopts)
227 	char *spec, *name, *type, *options, *mntopts;
228 	int flags;
229 {
230 	struct ufs_args args;
231 	pid_t pid;
232 	int argc, i, status;
233 	char *argp, *argv[50];
234 	char execname[MAXPATHLEN + 1], flagval[12], mntpath[MAXPATHLEN];
235 
236 	if (mntopts)
237 		getstdopts(mntopts, &flags);
238 	if (options)
239 		getstdopts(options, &flags);
240 	if (type)
241 		getstdopts(type, &flags);
242 	if (force)
243 		flags |= MNT_FORCE;
244 
245 	if (realpath(name, mntpath) == 0) {
246 		warn("%s", mntpath);
247 		return (1);
248 	}
249 
250 	name = mntpath;
251 
252 	if (strcmp(name, "/") == 0)
253 		flags |= MNT_UPDATE;
254 
255 	switch (mnttype) {
256 	case MOUNT_UFS:
257 		if (mntopts)
258 			getufsopts(mntopts, &flags);
259 		if (options)
260 			getufsopts(options, &flags);
261 		args.fspec = spec;
262 #define	DEFAULT_ROOTUID	-2
263 		args.export.ex_root = DEFAULT_ROOTUID;
264 		if (flags & MNT_RDONLY)
265 			args.export.ex_flags = MNT_EXRDONLY;
266 		else
267 			args.export.ex_flags = 0;
268 		argp = (caddr_t)&args;
269 		break;
270 	case MOUNT_MFS:
271 	case MOUNT_NFS:
272 	default:
273 		argv[0] = mntname;
274 		argc = 1;
275 		if (flags) {
276 			argv[argc++] = "-F";
277 			(void)snprintf(flagval, sizeof(flagval), "%d", flags);
278 			argv[argc++] = flagval;
279 		}
280 		if (mntopts)
281 			argc += getexecopts(mntopts, &argv[argc]);
282 		if (options)
283 			argc += getexecopts(options, &argv[argc]);
284 		argv[argc++] = spec;
285 		argv[argc++] = name;
286 		argv[argc++] = NULL;
287 		snprintf(execname, sizeof(execname),
288 		    "%s/mount_%s", _PATH_EXECDIR, mntname);
289 		if (verbose) {
290 			(void)printf("exec: %s", execname);
291 			for (i = 1; i < argc - 1; i++)
292 				(void)printf(" %s", argv[i]);
293 			(void)printf("\n");
294 		}
295 		if (debug)
296 			break;
297 		if (pid = vfork()) {
298 			if (pid == -1) {
299 				warn("vfork starting file system");
300 				return (1);
301 			}
302 			if (waitpid(pid, &status, 0) != -1 &&
303 			    WIFEXITED(status) &&
304 			    WEXITSTATUS(status) != 0)
305 				return (WEXITSTATUS(status));
306 			spec = mntname;
307 			goto out;
308 		}
309 		execv(execname, argv);
310 		err(1, "cannot exec %s for %s", execname, name);
311 		/* NOTREACHED */
312 
313 	}
314 	if (!debug && mount(mnttype, name, flags, argp)) {
315 		(void)fprintf(stderr, "%s on %s: ", spec, name);
316 		switch (errno) {
317 		case EMFILE:
318 			(void)fprintf(stderr, "Mount table full.\n");
319 			break;
320 		case EINVAL:
321 			if (flags & MNT_UPDATE)
322 				(void)fprintf(stderr, "Specified device %s\n",
323 					"does not match mounted device");
324 			else if (mnttype == MOUNT_UFS)
325 				(void)fprintf(stderr, "Bogus super block\n");
326 			else
327 				perror(NULL);
328 			break;
329 		default:
330 			perror(NULL);
331 			break;
332 		}
333 		return (1);
334 	}
335 
336 out:	if (verbose)
337 		prmount(spec, name, flags);
338 	return (0);
339 }
340 
341 void
342 prmount(spec, name, flags)
343 	char *spec, *name;
344 	int flags;
345 {
346 	int first;
347 
348 	(void)printf("%s on %s", spec, name);
349 	if (!(flags & MNT_VISFLAGMASK)) {
350 		(void)printf("\n");
351 		return;
352 	}
353 	first = 0;
354 #define	PR(msg)	(void)printf("%s%s", !first++ ? " (" : ", ", msg)
355 	if (flags & MNT_RDONLY)
356 		PR("read-only");
357 	if (flags & MNT_NOEXEC)
358 		PR("noexec");
359 	if (flags & MNT_NOSUID)
360 		PR("nosuid");
361 	if (flags & MNT_NODEV)
362 		PR("nodev");
363 	if (flags & MNT_SYNCHRONOUS)
364 		PR("synchronous");
365 	if (flags & MNT_ASYNC)
366 		PR("asynchronous");
367 	if (flags & MNT_QUOTA)
368 		PR("with quotas");
369 	if (flags & MNT_LOCAL)
370 		PR("local");
371 	if (flags & MNT_USER)
372 		PR("user mount");
373 	if (flags & MNT_UNION)
374 		PR("union");
375 	if (flags & MNT_EXPORTED)
376 		PR("NFS exported");
377 	(void)printf(")\n");
378 }
379 
380 int
381 getmnttype(fstype)
382 	char *fstype;
383 {
384 
385 	mntname = fstype;
386 	return (strcmp(fstype, "ufs") == 0 ? MOUNT_UFS : 0);
387 }
388 
389 void
390 getstdopts(options, flagp)
391 	char *options;
392 	int *flagp;
393 {
394 	int negative;
395 	char *opt, optbuf[BUFSIZ];
396 
397 	(void)strcpy(optbuf, options);
398 	for (opt = strtok(optbuf, ","); opt; opt = strtok(NULL, ",")) {
399 		if (opt[0] == '-')
400 			continue;
401 		if (opt[0] == 'n' && opt[1] == 'o') {
402 			negative++;
403 			opt += 2;
404 		} else
405 			negative = 0;
406 		if (!negative && !strcasecmp(opt, FSTAB_RO)) {
407 			*flagp |= MNT_RDONLY;
408 			continue;
409 		}
410 		if (!negative && !strcasecmp(opt, FSTAB_RW)) {
411 			*flagp &= ~MNT_RDONLY;
412 			continue;
413 		}
414 		if (!strcasecmp(opt, "exec")) {
415 			if (negative)
416 				*flagp |= MNT_NOEXEC;
417 			else
418 				*flagp &= ~MNT_NOEXEC;
419 			continue;
420 		}
421 		if (!strcasecmp(opt, "suid")) {
422 			if (negative)
423 				*flagp |= MNT_NOSUID;
424 			else
425 				*flagp &= ~MNT_NOSUID;
426 			continue;
427 		}
428 		if (!strcasecmp(opt, "dev")) {
429 			if (negative)
430 				*flagp |= MNT_NODEV;
431 			else
432 				*flagp &= ~MNT_NODEV;
433 			continue;
434 		}
435 		if (!strcasecmp(opt, "synchronous")) {
436 			if (!negative)
437 				*flagp |= MNT_SYNCHRONOUS;
438 			else
439 				*flagp &= ~MNT_SYNCHRONOUS;
440 			continue;
441 		}
442 		if (!strcasecmp(opt, "asynchronous")) {
443 			if (!negative)
444 				*flagp |= MNT_ASYNC;
445 			else
446 				*flagp &= ~MNT_ASYNC;
447 			continue;
448 		}
449 		if (!strcasecmp(opt, "union")) {
450 			if (!negative)
451 				*flagp |= MNT_UNION;
452 			else
453 				*flagp &= ~MNT_UNION;
454 			continue;
455 		}
456 		(void)fprintf(stderr, "mount: %s: unknown option\n", opt);
457 	}
458 }
459 
460 /* ARGSUSED */
461 void
462 getufsopts(options, flagp)
463 	char *options;
464 	int *flagp;
465 {
466 
467 	return;
468 }
469 
470 int
471 getexecopts(options, argv)
472 	char *options, **argv;
473 {
474 	int argc;
475 	char *opt;
476 
477 	argc = 0;
478 	for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
479 		if (opt[0] != '-')
480 			continue;
481 		argv[argc++] = opt;
482 		if (opt[2] == '\0' || opt[2] != '=')
483 			continue;
484 		opt[2] = '\0';
485 		argv[argc++] = &opt[3];
486 	}
487 	return (argc);
488 }
489 
490 struct statfs *
491 getmntpt(name)
492 	char *name;
493 {
494 	struct statfs *mntbuf;
495 	long i, mntsize;
496 
497 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
498 	for (i = 0; i < mntsize; i++) {
499 		if (!strcmp(mntbuf[i].f_mntfromname, name) ||
500 		    !strcmp(mntbuf[i].f_mntonname, name))
501 			return (&mntbuf[i]);
502 	}
503 	return (NULL);
504 }
505 
506 int
507 badvfstype(vfstype, vfslist)
508 	int vfstype;
509 	char **vfslist;
510 {
511 
512 	if (vfslist == NULL)
513 		return (0);
514 	while (*vfslist != NULL) {
515 		if (vfstype == getmnttype(*vfslist))
516 			return (skipvfs);
517 		vfslist++;
518 	}
519 	return (!skipvfs);
520 }
521 
522 int
523 badvfsname(vfsname, vfslist)
524 	char *vfsname;
525 	char **vfslist;
526 {
527 
528 	if (vfslist == NULL)
529 		return (0);
530 	while (*vfslist != NULL) {
531 		if (strcmp(vfsname, *vfslist) == 0)
532 			return (skipvfs);
533 		vfslist++;
534 	}
535 	return (!skipvfs);
536 }
537 
538 char **
539 makevfslist(fslist)
540 	char *fslist;
541 {
542 	int i;
543 	char **av, *nextcp;
544 
545 	if (fslist == NULL)
546 		return (NULL);
547 	if (fslist[0] == 'n' && fslist[1] == 'o') {
548 		fslist += 2;
549 		skipvfs = 1;
550 	}
551 	for (i = 0, nextcp = fslist; *nextcp; nextcp++)
552 		if (*nextcp == ',')
553 			i++;
554 	av = malloc((size_t)(i + 2) * sizeof(char *));
555 	if (av == NULL)
556 		return (NULL);
557 	nextcp = fslist;
558 	i = 0;
559 	av[i++] = nextcp;
560 	while ((nextcp = index(nextcp, ',')) != NULL) {
561 		*nextcp++ = '\0';
562 		av[i++] = nextcp;
563 	}
564 	av[i++] = NULL;
565 	return (av);
566 }
567 
568 void
569 usage()
570 {
571 
572 	(void)fprintf(stderr,
573 		"usage: %s %s\n       %s\n       %s\n",
574 		"mount [-dfruvw] [-t ufs | external_type]",
575 			"[-o options] special node",
576 		"mount [-adfruvw] [-t ufs | external_type]",
577 		"mount [-dfruvw] special | node");
578 	exit(1);
579 }
580