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