xref: /original-bsd/sbin/mount/mount.c (revision 9756c099)
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.11 (Berkeley) 02/17/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, pid, 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 	if ((pidfile = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
205 		pid = 0;
206 		(void)fscanf(pidfile, "%ld", &pid);
207 		(void)fclose(pidfile);
208 		if (pid > 0 && kill(pid, SIGHUP))
209 			err(1, "signal mountd");
210 	}
211 
212 	exit(ret);
213 }
214 
215 int
216 mountfs(spec, name, flags, type, options, mntopts)
217 	char *spec, *name, *type, *options, *mntopts;
218 	int flags;
219 {
220 	struct ufs_args args;
221 	pid_t pid;
222 	int argc, i, status;
223 	char *argp, *argv[50];
224 	char execname[MAXPATHLEN + 1], flagval[12], mntpath[MAXPATHLEN];
225 
226 	if (mntopts)
227 		getstdopts(mntopts, &flags);
228 	if (options)
229 		getstdopts(options, &flags);
230 	if (type)
231 		getstdopts(type, &flags);
232 	if (force)
233 		flags |= MNT_FORCE;
234 
235 	if (realpath(name, mntpath) == 0) {
236 		warn("%s", mntpath);
237 		return (1);
238 	}
239 
240 	name = mntpath;
241 
242 	if (strcmp(name, "/") == 0)
243 		flags |= MNT_UPDATE;
244 
245 	switch (mnttype) {
246 	case MOUNT_UFS:
247 		if (mntopts)
248 			getufsopts(mntopts, &flags);
249 		if (options)
250 			getufsopts(options, &flags);
251 		args.fspec = spec;
252 #define	DEFAULT_ROOTUID	-2
253 		args.export.ex_root = DEFAULT_ROOTUID;
254 		if (flags & MNT_RDONLY)
255 			args.export.ex_flags = MNT_EXRDONLY;
256 		else
257 			args.export.ex_flags = 0;
258 		argp = (caddr_t)&args;
259 		break;
260 	case MOUNT_MFS:
261 	case MOUNT_NFS:
262 	default:
263 		argv[0] = mntname;
264 		argc = 1;
265 		if (flags) {
266 			argv[argc++] = "-F";
267 			(void)snprintf(flagval, sizeof(flagval), "%d", flags);
268 			argv[argc++] = flagval;
269 		}
270 		if (mntopts)
271 			argc += getexecopts(mntopts, &argv[argc]);
272 		if (options)
273 			argc += getexecopts(options, &argv[argc]);
274 		argv[argc++] = spec;
275 		argv[argc++] = name;
276 		argv[argc++] = NULL;
277 		snprintf(execname, sizeof(execname),
278 		    "%s/mount_%s", _PATH_EXECDIR, mntname);
279 		if (verbose) {
280 			(void)printf("exec: %s", execname);
281 			for (i = 1; i < argc - 1; i++)
282 				(void)printf(" %s", argv[i]);
283 			(void)printf("\n");
284 		}
285 		if (debug)
286 			break;
287 		if (pid = vfork()) {
288 			if (pid == -1) {
289 				warn("vfork starting file system");
290 				return (1);
291 			}
292 			if (waitpid(pid, &status, 0) != -1 &&
293 			    WIFEXITED(status) &&
294 			    WEXITSTATUS(status) != 0)
295 				return (WEXITSTATUS(status));
296 			spec = mntname;
297 			goto out;
298 		}
299 		execv(execname, argv);
300 		err(1, "cannot exec %s for %s", execname, name);
301 		/* NOTREACHED */
302 
303 	}
304 	if (!debug && mount(mnttype, name, flags, argp)) {
305 		(void)fprintf(stderr, "%s on %s: ", spec, name);
306 		switch (errno) {
307 		case EMFILE:
308 			(void)fprintf(stderr, "Mount table full.\n");
309 			break;
310 		case EINVAL:
311 			if (flags & MNT_UPDATE)
312 				(void)fprintf(stderr, "Specified device %s\n",
313 					"does not match mounted device");
314 			else if (mnttype == MOUNT_UFS)
315 				(void)fprintf(stderr, "Bogus super block\n");
316 			else
317 				perror(NULL);
318 			break;
319 		default:
320 			perror(NULL);
321 			break;
322 		}
323 		return (1);
324 	}
325 
326 out:	if (verbose)
327 		prmount(spec, name, flags);
328 	return (0);
329 }
330 
331 void
332 prmount(spec, name, flags)
333 	char *spec, *name;
334 	int flags;
335 {
336 	int first;
337 
338 	(void)printf("%s on %s", spec, name);
339 	if (!(flags & MNT_VISFLAGMASK)) {
340 		(void)printf("\n");
341 		return;
342 	}
343 	first = 0;
344 #define	PR(msg)	(void)printf("%s%s", !first++ ? " (" : ", ", msg)
345 	if (flags & MNT_RDONLY)
346 		PR("read-only");
347 	if (flags & MNT_NOEXEC)
348 		PR("noexec");
349 	if (flags & MNT_NOSUID)
350 		PR("nosuid");
351 	if (flags & MNT_NODEV)
352 		PR("nodev");
353 	if (flags & MNT_SYNCHRONOUS)
354 		PR("synchronous");
355 	if (flags & MNT_ASYNC)
356 		PR("asynchronous");
357 	if (flags & MNT_QUOTA)
358 		PR("with quotas");
359 	if (flags & MNT_LOCAL)
360 		PR("local");
361 	if (flags & MNT_UNION)
362 		PR("union");
363 	if (flags & MNT_EXPORTED)
364 		PR("NFS exported");
365 	(void)printf(")\n");
366 }
367 
368 int
369 getmnttype(fstype)
370 	char *fstype;
371 {
372 
373 	mntname = fstype;
374 	return (strcmp(fstype, "ufs") == 0 ? MOUNT_UFS : 0);
375 }
376 
377 void
378 getstdopts(options, flagp)
379 	char *options;
380 	int *flagp;
381 {
382 	int negative;
383 	char *opt, optbuf[BUFSIZ];
384 
385 	(void)strcpy(optbuf, options);
386 	for (opt = strtok(optbuf, ","); opt; opt = strtok(NULL, ",")) {
387 		if (opt[0] == '-')
388 			continue;
389 		if (opt[0] == 'n' && opt[1] == 'o') {
390 			negative++;
391 			opt += 2;
392 		} else
393 			negative = 0;
394 		if (!negative && !strcasecmp(opt, FSTAB_RO)) {
395 			*flagp |= MNT_RDONLY;
396 			continue;
397 		}
398 		if (!negative && !strcasecmp(opt, FSTAB_RW)) {
399 			*flagp &= ~MNT_RDONLY;
400 			continue;
401 		}
402 		if (!strcasecmp(opt, "exec")) {
403 			if (negative)
404 				*flagp |= MNT_NOEXEC;
405 			else
406 				*flagp &= ~MNT_NOEXEC;
407 			continue;
408 		}
409 		if (!strcasecmp(opt, "suid")) {
410 			if (negative)
411 				*flagp |= MNT_NOSUID;
412 			else
413 				*flagp &= ~MNT_NOSUID;
414 			continue;
415 		}
416 		if (!strcasecmp(opt, "dev")) {
417 			if (negative)
418 				*flagp |= MNT_NODEV;
419 			else
420 				*flagp &= ~MNT_NODEV;
421 			continue;
422 		}
423 		if (!strcasecmp(opt, "synchronous")) {
424 			if (!negative)
425 				*flagp |= MNT_SYNCHRONOUS;
426 			else
427 				*flagp &= ~MNT_SYNCHRONOUS;
428 			continue;
429 		}
430 		if (!strcasecmp(opt, "asynchronous")) {
431 			if (!negative)
432 				*flagp |= MNT_ASYNC;
433 			else
434 				*flagp &= ~MNT_ASYNC;
435 			continue;
436 		}
437 		if (!strcasecmp(opt, "union")) {
438 			if (!negative)
439 				*flagp |= MNT_UNION;
440 			else
441 				*flagp &= ~MNT_UNION;
442 			continue;
443 		}
444 		(void)fprintf(stderr, "mount: %s: unknown option\n", opt);
445 	}
446 }
447 
448 /* ARGSUSED */
449 void
450 getufsopts(options, flagp)
451 	char *options;
452 	int *flagp;
453 {
454 
455 	return;
456 }
457 
458 int
459 getexecopts(options, argv)
460 	char *options, **argv;
461 {
462 	int argc;
463 	char *opt;
464 
465 	argc = 0;
466 	for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
467 		if (opt[0] != '-')
468 			continue;
469 		argv[argc++] = opt;
470 		if (opt[2] == '\0' || opt[2] != '=')
471 			continue;
472 		opt[2] = '\0';
473 		argv[argc++] = &opt[3];
474 	}
475 	return (argc);
476 }
477 
478 struct statfs *
479 getmntpt(name)
480 	char *name;
481 {
482 	struct statfs *mntbuf;
483 	long i, mntsize;
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 (NULL);
492 }
493 
494 int
495 badvfstype(vfstype, vfslist)
496 	int vfstype;
497 	char **vfslist;
498 {
499 
500 	if (vfslist == NULL)
501 		return (0);
502 	while (*vfslist != NULL) {
503 		if (vfstype == getmnttype(*vfslist))
504 			return (skipvfs);
505 		vfslist++;
506 	}
507 	return (!skipvfs);
508 }
509 
510 int
511 badvfsname(vfsname, vfslist)
512 	char *vfsname;
513 	char **vfslist;
514 {
515 
516 	if (vfslist == NULL)
517 		return (0);
518 	while (*vfslist != NULL) {
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 	int i;
531 	char **av, *nextcp;
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 = 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, ',')) != NULL) {
549 		*nextcp++ = '\0';
550 		av[i++] = nextcp;
551 	}
552 	av[i++] = NULL;
553 	return (av);
554 }
555 
556 void
557 usage()
558 {
559 
560 	(void)fprintf(stderr,
561 		"usage:\n  mount %s %s\n  mount %s\n  mount %s\n",
562 		"[ -frwu ] [ -t ufs | external_type ]",
563 		"[ -o options ] special node",
564 		"[ -afrwu ] [ -t ufs | external_type ]",
565 		"[ -frwu ] special | node");
566 	exit(1);
567 }
568