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