xref: /original-bsd/sbin/mount/mount.c (revision 68549010)
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.48 (Berkeley) 01/13/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 (!strcmp(mntbuf->f_mntfromname, "root_device")) {
146 			fs = getfsfile("/");
147 			strcpy(mntbuf->f_mntfromname, fs->fs_spec);
148 		}
149 		ret = mountfs(mntbuf->f_mntfromname, mntbuf->f_mntonname,
150 		    updateflg, type, options, (char *)NULL);
151 	} else if (argc == 1) {
152 		if (!(fs = getfsfile(*argv)) && !(fs = getfsspec(*argv))) {
153 			(void) fprintf(stderr,
154 			    "mount: unknown special file or file system %s.\n",
155 			    *argv);
156 			exit(1);
157 		}
158 		if (BADTYPE(fs->fs_type)) {
159 			(void) fprintf(stderr,
160 			    "mount: %s has unknown file system type.\n", *argv);
161 			exit(1);
162 		}
163 		mnttype = getmnttype(fs->fs_vfstype);
164 		ret = mountfs(fs->fs_spec, fs->fs_file, updateflg,
165 		    type, options, fs->fs_mntops);
166 	} else if (argc != 2) {
167 		usage();
168 		ret = 1;
169 	} else {
170 		/*
171 		 * If -t flag has not been specified, and spec
172 		 * contains either a ':' or a '@' then assume that
173 		 * an NFS filesystem is being specified ala Sun.
174 		 */
175 		if (vfslist == (char **)0 &&
176 		    (index(argv[0], ':') || index(argv[0], '@'))) {
177 			mnttype = MOUNT_NFS;
178 			mntname = "nfs";
179 		}
180 		ret = mountfs(argv[0], argv[1], updateflg, type, options,
181 		    (char *)NULL);
182 	}
183 	if ((pidfile = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
184 		pid = 0;
185 		fscanf(pidfile, "%d", &pid);
186 		fclose(pidfile);
187 		if (pid > 0)
188 			kill(pid, SIGHUP);
189 	}
190 	exit (ret);
191 }
192 
193 mountfs(spec, name, flags, type, options, mntopts)
194 	char *spec, *name, *type, *options, *mntopts;
195 	int flags;
196 {
197 	union wait status;
198 	pid_t pid;
199 	int argc, i;
200 	struct ufs_args args;
201 	char *argp, *argv[50];
202 	char execname[MAXPATHLEN + 1], flagval[12];
203 
204 	if (mntopts)
205 		getstdopts(mntopts, &flags);
206 	if (options)
207 		getstdopts(options, &flags);
208 	if (type)
209 		getstdopts(type, &flags);
210 	switch (mnttype) {
211 	case MOUNT_LFS:
212 	case MOUNT_UFS:
213 		if (mntopts)
214 			getufsopts(mntopts, &flags);
215 		if (options)
216 			getufsopts(options, &flags);
217 		args.fspec = spec;
218 		args.exroot = DEFAULT_ROOTUID;
219 		if (flags & MNT_RDONLY)
220 			args.exflags = MNT_EXRDONLY;
221 		else
222 			args.exflags = 0;
223 		argp = (caddr_t)&args;
224 		break;
225 
226 	case MOUNT_MFS:
227 	case MOUNT_NFS:
228 	default:
229 		argv[0] = mntname;
230 		argc = 1;
231 		if (flags) {
232 			argv[argc++] = "-F";
233 			sprintf(flagval, "%d", flags);
234 			argv[argc++] = flagval;
235 		}
236 		if (mntopts)
237 			argc += getexecopts(mntopts, &argv[argc]);
238 		if (options)
239 			argc += getexecopts(options, &argv[argc]);
240 		argv[argc++] = spec;
241 		argv[argc++] = name;
242 		argv[argc++] = NULL;
243 		sprintf(execname, "%s/mount_%s", _PATH_EXECDIR, mntname);
244 		if (verbose) {
245 			(void)printf("exec: %s", execname);
246 			for (i = 1; i < argc - 1; i++)
247 				(void)printf(" %s", argv[i]);
248 			(void)printf("\n");
249 		}
250 		if (fake)
251 			break;
252 		if (pid = vfork()) {
253 			if (pid == -1) {
254 				perror("mount: vfork starting file system");
255 				return (1);
256 			}
257 			if (waitpid(pid, (int *)&status, 0) != -1 &&
258 			    WIFEXITED(status) &&
259 			    WEXITSTATUS(status) != 0)
260 				return (WEXITSTATUS(status));
261 			spec = mntname;
262 			goto out;
263 		}
264 		execve(execname, argv, envp);
265 		(void) fprintf(stderr, "mount: cannot exec %s for %s: ",
266 			execname, name);
267 		perror((char *)NULL);
268 		exit (1);
269 		/* NOTREACHED */
270 
271 	}
272 	if (!fake && mount(mnttype, name, flags, argp)) {
273 		(void) fprintf(stderr, "%s on %s: ", spec, name);
274 		switch (errno) {
275 		case EMFILE:
276 			(void) fprintf(stderr, "Mount table full\n");
277 			break;
278 		case EINVAL:
279 			if (flags & MNT_UPDATE)
280 				(void) fprintf(stderr, "Specified device %s\n",
281 					"does not match mounted device");
282 			else if (mnttype == MOUNT_UFS)
283 				(void) fprintf(stderr, "Bogus super block\n");
284 			else
285 				perror((char *)NULL);
286 			break;
287 		default:
288 			perror((char *)NULL);
289 			break;
290 		}
291 		return(1);
292 	}
293 
294 out:
295 	if (verbose)
296 		prmount(spec, name, flags);
297 
298 	return(0);
299 }
300 
301 static void
302 prmount(spec, name, flags)
303 	char *spec, *name;
304 	register short flags;
305 {
306 	register int first;
307 
308 	(void)printf("%s on %s", spec, name);
309 	if (!(flags & MNT_VISFLAGMASK)) {
310 		(void)printf("\n");
311 		return;
312 	}
313 	first = 0;
314 #define	PR(msg)	(void)printf("%s%s", !first++ ? " (" : ", ", msg)
315 	if (flags & MNT_RDONLY)
316 		PR("read-only");
317 	if (flags & MNT_NOEXEC)
318 		PR("noexec");
319 	if (flags & MNT_NOSUID)
320 		PR("nosuid");
321 	if (flags & MNT_NODEV)
322 		PR("nodev");
323 	if (flags & MNT_SYNCHRONOUS)
324 		PR("synchronous");
325 	if (flags & MNT_QUOTA)
326 		PR("with quotas");
327 	if (flags & MNT_LOCAL)
328 		PR("local");
329 	if (flags & MNT_EXPORTED)
330 		PR("NFS exported");
331 	(void)printf(")\n");
332 }
333 
334 getmnttype(fstype)
335 	char *fstype;
336 {
337 
338 	mntname = fstype;
339 	if (!strcmp(fstype, "ufs"))
340 		return (MOUNT_UFS);
341 	if (!strcmp(fstype, "nfs"))
342 		return (MOUNT_NFS);
343 	if (!strcmp(fstype, "mfs"))
344 		return (MOUNT_MFS);
345 	if (!strcmp(fstype, "lfs"))
346 		return (MOUNT_LFS);
347 	return (0);
348 }
349 
350 usage()
351 {
352 
353 	(void) fprintf(stderr,
354 		"usage:\n  mount %s %s\n  mount %s\n  mount %s\n",
355 		"[ -frwu ] [ -t ufs | external_type ]",
356 		"[ -o options ] special node",
357 		"[ -afrwu ] [ -t ufs | external_type ]",
358 		"[ -frwu ] special | node");
359 	exit(1);
360 }
361 
362 getstdopts(options, flagp)
363 	char *options;
364 	int *flagp;
365 {
366 	register char *opt;
367 	int negative;
368 	char optbuf[BUFSIZ];
369 
370 	(void)strcpy(optbuf, options);
371 	for (opt = strtok(optbuf, ","); opt; opt = strtok((char *)NULL, ",")) {
372 		if (opt[0] == 'n' && opt[1] == 'o') {
373 			negative++;
374 			opt += 2;
375 		} else {
376 			negative = 0;
377 		}
378 		if (!negative && !strcasecmp(opt, FSTAB_RO)) {
379 			*flagp |= MNT_RDONLY;
380 			continue;
381 		}
382 		if (!negative && !strcasecmp(opt, FSTAB_RW)) {
383 			*flagp &= ~MNT_RDONLY;
384 			continue;
385 		}
386 		if (!strcasecmp(opt, "exec")) {
387 			if (negative)
388 				*flagp |= MNT_NOEXEC;
389 			else
390 				*flagp &= ~MNT_NOEXEC;
391 			continue;
392 		}
393 		if (!strcasecmp(opt, "suid")) {
394 			if (negative)
395 				*flagp |= MNT_NOSUID;
396 			else
397 				*flagp &= ~MNT_NOSUID;
398 			continue;
399 		}
400 		if (!strcasecmp(opt, "dev")) {
401 			if (negative)
402 				*flagp |= MNT_NODEV;
403 			else
404 				*flagp &= ~MNT_NODEV;
405 			continue;
406 		}
407 		if (!strcasecmp(opt, "synchronous")) {
408 			if (!negative)
409 				*flagp |= MNT_SYNCHRONOUS;
410 			else
411 				*flagp &= ~MNT_SYNCHRONOUS;
412 			continue;
413 		}
414 	}
415 }
416 
417 /* ARGSUSED */
418 getufsopts(options, flagp)
419 	char *options;
420 	int *flagp;
421 {
422 	return;
423 }
424 
425 getexecopts(options, argv)
426 	char *options;
427 	char **argv;
428 {
429 	register int argc = 0;
430 	register char *opt;
431 
432 	for (opt = strtok(options, ","); opt; opt = strtok((char *)NULL, ",")) {
433 		if (opt[0] != '-')
434 			continue;
435 		argv[argc++] = opt;
436 		if (opt[2] == '\0' || opt[2] != '=')
437 			continue;
438 		opt[2] = '\0';
439 		argv[argc++] = &opt[3];
440 	}
441 	return (argc);
442 }
443 
444 struct statfs *
445 getmntpt(name)
446 	char *name;
447 {
448 	long mntsize;
449 	register long i;
450 	struct statfs *mntbuf;
451 
452 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
453 	for (i = 0; i < mntsize; i++) {
454 		if (!strcmp(mntbuf[i].f_mntfromname, name) ||
455 		    !strcmp(mntbuf[i].f_mntonname, name))
456 			return (&mntbuf[i]);
457 	}
458 	return ((struct statfs *)0);
459 }
460 
461 static int skipvfs;
462 
463 badvfstype(vfstype, vfslist)
464 	short vfstype;
465 	char **vfslist;
466 {
467 
468 	if (vfslist == 0)
469 		return(0);
470 	while (*vfslist) {
471 		if (vfstype == getmnttype(*vfslist))
472 			return(skipvfs);
473 		vfslist++;
474 	}
475 	return (!skipvfs);
476 }
477 
478 badvfsname(vfsname, vfslist)
479 	char *vfsname;
480 	char **vfslist;
481 {
482 
483 	if (vfslist == 0)
484 		return(0);
485 	while (*vfslist) {
486 		if (strcmp(vfsname, *vfslist) == 0)
487 			return(skipvfs);
488 		vfslist++;
489 	}
490 	return (!skipvfs);
491 }
492 
493 char **
494 makevfslist(fslist)
495 	char *fslist;
496 {
497 	register char **av, *nextcp;
498 	register int i;
499 
500 	if (fslist == NULL)
501 		return (NULL);
502 	if (fslist[0] == 'n' && fslist[1] == 'o') {
503 		fslist += 2;
504 		skipvfs = 1;
505 	}
506 	for (i = 0, nextcp = fslist; *nextcp; nextcp++)
507 		if (*nextcp == ',')
508 			i++;
509 	av = (char **)malloc((size_t)(i+2) * sizeof(char *));
510 	if (av == NULL)
511 		return (NULL);
512 	nextcp = fslist;
513 	i = 0;
514 	av[i++] = nextcp;
515 	while (nextcp = index(nextcp, ',')) {
516 		*nextcp++ = '\0';
517 		av[i++] = nextcp;
518 	}
519 	av[i++] = 0;
520 	return (av);
521 }
522