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