mount.c revision 1.1.1.2 1 /*
2 * Copyright (c) 1980, 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char copyright[] =
36 "@(#) Copyright (c) 1980, 1989, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 static char sccsid[] = "@(#)mount.c 8.19 (Berkeley) 4/19/94";
42 #endif /* not lint */
43
44 #include <sys/param.h>
45 #include <sys/mount.h>
46 #include <sys/wait.h>
47
48 #include <err.h>
49 #include <errno.h>
50 #include <fstab.h>
51 #include <signal.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56
57 #include "pathnames.h"
58
59 int debug, verbose, skipvfs;
60
61 int badvfsname __P((const char *, const char **));
62 int badvfstype __P((int, const char **));
63 char *catopt __P((char *, const char *));
64 struct statfs
65 *getmntpt __P((const char *));
66 const char
67 **makevfslist __P((char *));
68 void mangle __P((char *, int *, const char **));
69 int mountfs __P((const char *, const char *, const char *,
70 int, const char *, const char *));
71 void prmount __P((const char *, const char *, int));
72 void usage __P((void));
73
74 /* From mount_ufs.c. */
75 int mount_ufs __P((int, char * const *));
76
77 /* Map from mount otions to printable formats. */
78 static struct opt {
79 int o_opt;
80 const char *o_name;
81 } optnames[] = {
82 { MNT_ASYNC, "asynchronous" },
83 { MNT_EXPORTED, "NFS exported" },
84 { MNT_LOCAL, "local" },
85 { MNT_NODEV, "nodev" },
86 { MNT_NOEXEC, "noexec" },
87 { MNT_NOSUID, "nosuid" },
88 { MNT_QUOTA, "with quotas" },
89 { MNT_RDONLY, "read-only" },
90 { MNT_SYNCHRONOUS, "synchronous" },
91 { MNT_UNION, "union" },
92 { MNT_USER, "user mount" },
93 { NULL }
94 };
95
96 int
97 main(argc, argv)
98 int argc;
99 char * const argv[];
100 {
101 const char *mntonname, **vfslist, *vfstype;
102 struct fstab *fs;
103 struct statfs *mntbuf;
104 FILE *mountdfp;
105 pid_t pid;
106 int all, ch, i, init_flags, mntsize, rval;
107 char *options;
108
109 all = init_flags = 0;
110 options = NULL;
111 vfslist = NULL;
112 vfstype = "ufs";
113 while ((ch = getopt(argc, argv, "adfo:rwt:uv")) != EOF)
114 switch (ch) {
115 case 'a':
116 all = 1;
117 break;
118 case 'd':
119 debug = 1;
120 break;
121 case 'f':
122 init_flags |= MNT_FORCE;
123 break;
124 case 'o':
125 if (*optarg)
126 options = catopt(options, optarg);
127 break;
128 case 'r':
129 init_flags |= MNT_RDONLY;
130 break;
131 case 't':
132 if (vfslist != NULL)
133 errx(1, "only one -t option may be specified.");
134 vfslist = makevfslist(optarg);
135 vfstype = optarg;
136 break;
137 case 'u':
138 init_flags |= MNT_UPDATE;
139 break;
140 case 'v':
141 verbose = 1;
142 break;
143 case 'w':
144 init_flags &= ~MNT_RDONLY;
145 break;
146 case '?':
147 default:
148 usage();
149 /* NOTREACHED */
150 }
151 argc -= optind;
152 argv += optind;
153
154 #define BADTYPE(type) \
155 (strcmp(type, FSTAB_RO) && \
156 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
157
158 rval = 0;
159 switch (argc) {
160 case 0:
161 if (all)
162 while ((fs = getfsent()) != NULL) {
163 if (BADTYPE(fs->fs_type))
164 continue;
165 if (badvfsname(fs->fs_vfstype, vfslist))
166 continue;
167 if (mountfs(fs->fs_vfstype, fs->fs_spec,
168 fs->fs_file, init_flags, options,
169 fs->fs_mntops))
170 rval = 1;
171 }
172 else {
173 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
174 err(1, "getmntinfo");
175 for (i = 0; i < mntsize; i++) {
176 if (badvfstype(mntbuf[i].f_type, vfslist))
177 continue;
178 prmount(mntbuf[i].f_mntfromname,
179 mntbuf[i].f_mntonname, mntbuf[i].f_flags);
180 }
181 }
182 exit(rval);
183 case 1:
184 if (vfslist != NULL)
185 usage();
186
187 if (init_flags & MNT_UPDATE) {
188 if ((mntbuf = getmntpt(*argv)) == NULL)
189 errx(1,
190 "unknown special file or file system %s.",
191 *argv);
192 if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL)
193 errx(1, "can't find fstab entry for %s.",
194 *argv);
195 /* If it's an update, ignore the fstab file options. */
196 fs->fs_mntops = NULL;
197 mntonname = mntbuf->f_mntonname;
198 } else {
199 if ((fs = getfsfile(*argv)) == NULL &&
200 (fs = getfsspec(*argv)) == NULL)
201 errx(1,
202 "%s: unknown special file or file system.",
203 *argv);
204 if (BADTYPE(fs->fs_type))
205 errx(1, "%s has unknown file system type.",
206 *argv);
207 mntonname = fs->fs_file;
208 }
209 rval = mountfs(fs->fs_vfstype, fs->fs_spec,
210 mntonname, init_flags, options, fs->fs_mntops);
211 break;
212 case 2:
213 /*
214 * If -t flag has not been specified, and spec contains either
215 * a ':' or a '@' then assume that an NFS filesystem is being
216 * specified ala Sun.
217 */
218 if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL)
219 vfstype = "nfs";
220 rval = mountfs(vfstype,
221 argv[0], argv[1], init_flags, options, NULL);
222 break;
223 default:
224 usage();
225 /* NOTREACHED */
226 }
227
228 /*
229 * If the mount was successfully, and done by root, tell mountd the
230 * good news. Pid checks are probably unnecessary, but don't hurt.
231 */
232 if (rval == 0 && getuid() == 0 &&
233 (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
234 if (fscanf(mountdfp, "%ld", &pid) == 1 &&
235 pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
236 err(1, "signal mountd");
237 (void)fclose(mountdfp);
238 }
239
240 exit(rval);
241 }
242
243 int
244 mountfs(vfstype, spec, name, flags, options, mntopts)
245 const char *vfstype, *spec, *name, *options, *mntopts;
246 int flags;
247 {
248 /* List of directories containing mount_xxx subcommands. */
249 static const char *edirs[] = {
250 _PATH_SBIN,
251 _PATH_USRSBIN,
252 NULL
253 };
254 const char *argv[100], **edir;
255 struct statfs sf;
256 pid_t pid;
257 int argc, i, status;
258 char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
259
260 if (realpath(name, mntpath) == NULL) {
261 warn("%s", mntpath);
262 return (1);
263 }
264
265 name = mntpath;
266
267 if (options == NULL) {
268 if (mntopts == NULL || *mntopts == '\0')
269 options = "rw";
270 else
271 options = mntopts;
272 mntopts = "";
273 }
274 optbuf = catopt(strdup(mntopts), options);
275
276 if (strcmp(name, "/") == 0)
277 flags |= MNT_UPDATE;
278 if (flags & MNT_FORCE)
279 optbuf = catopt(optbuf, "force");
280 if (flags & MNT_RDONLY)
281 optbuf = catopt(optbuf, "ro");
282 /*
283 * XXX
284 * The mount_mfs (newfs) command uses -o to select the
285 * optimisation mode. We don't pass the default "-o rw"
286 * for that reason.
287 */
288 if (flags & MNT_UPDATE)
289 optbuf = catopt(optbuf, "update");
290
291 argc = 0;
292 argv[argc++] = vfstype;
293 mangle(optbuf, &argc, argv);
294 argv[argc++] = spec;
295 argv[argc++] = name;
296 argv[argc] = NULL;
297
298 if (debug) {
299 (void)printf("exec: mount_%s", vfstype);
300 for (i = 1; i < argc; i++)
301 (void)printf(" %s", argv[i]);
302 (void)printf("\n");
303 return (0);
304 }
305
306 switch (pid = vfork()) {
307 case -1: /* Error. */
308 warn("vfork");
309 free(optbuf);
310 return (1);
311 case 0: /* Child. */
312 if (strcmp(vfstype, "ufs") == 0)
313 exit(mount_ufs(argc, (char * const *) argv));
314
315 /* Go find an executable. */
316 edir = edirs;
317 do {
318 (void)snprintf(execname,
319 sizeof(execname), "%s/mount_%s", *edir, vfstype);
320 execv(execname, (char * const *)argv);
321 if (errno != ENOENT)
322 warn("exec %s for %s", execname, name);
323 } while (*++edir != NULL);
324
325 if (errno == ENOENT)
326 warn("exec %s for %s", execname, name);
327 exit(1);
328 /* NOTREACHED */
329 default: /* Parent. */
330 free(optbuf);
331
332 if (waitpid(pid, &status, 0) < 0) {
333 warn("waitpid");
334 return (1);
335 }
336
337 if (WIFEXITED(status)) {
338 if (WEXITSTATUS(status) != 0)
339 return (WEXITSTATUS(status));
340 } else if (WIFSIGNALED(status)) {
341 warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
342 return (1);
343 }
344
345 if (verbose) {
346 if (statfs(name, &sf) < 0) {
347 warn("%s", name);
348 return (1);
349 }
350 prmount(sf.f_mntfromname, sf.f_mntonname, sf.f_flags);
351 }
352 break;
353 }
354
355 return (0);
356 }
357
358 void
359 prmount(spec, name, flags)
360 const char *spec, *name;
361 int flags;
362 {
363 struct opt *o;
364 int f;
365
366 (void)printf("%s on %s", spec, name);
367
368 flags &= MNT_VISFLAGMASK;
369 for (f = 0, o = optnames; flags && o->o_opt; o++)
370 if (flags & o->o_opt) {
371 (void)printf("%s%s", !f++ ? " (" : ", ", o->o_name);
372 flags &= ~o->o_opt;
373 }
374 (void)printf(f ? ")\n" : "\n");
375 }
376
377 struct statfs *
378 getmntpt(name)
379 const char *name;
380 {
381 struct statfs *mntbuf;
382 int i, mntsize;
383
384 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
385 for (i = 0; i < mntsize; i++)
386 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
387 strcmp(mntbuf[i].f_mntonname, name) == 0)
388 return (&mntbuf[i]);
389 return (NULL);
390 }
391
392 int
393 badvfsname(vfsname, vfslist)
394 const char *vfsname;
395 const char **vfslist;
396 {
397
398 if (vfslist == NULL)
399 return (0);
400 while (*vfslist != NULL) {
401 if (strcmp(vfsname, *vfslist) == 0)
402 return (skipvfs);
403 ++vfslist;
404 }
405 return (!skipvfs);
406 }
407
408 int
409 badvfstype(vfstype, vfslist)
410 int vfstype;
411 const char **vfslist;
412 {
413 static const char *vfsnames[] = INITMOUNTNAMES;
414
415 if ((vfstype < 0) || (vfstype > MOUNT_MAXTYPE))
416 return (0);
417
418 return (badvfsname(vfsnames[vfstype], vfslist));
419 }
420
421 const char **
422 makevfslist(fslist)
423 char *fslist;
424 {
425 const char **av;
426 int i;
427 char *nextcp;
428
429 if (fslist == NULL)
430 return (NULL);
431 if (fslist[0] == 'n' && fslist[1] == 'o') {
432 fslist += 2;
433 skipvfs = 1;
434 }
435 for (i = 0, nextcp = fslist; *nextcp; nextcp++)
436 if (*nextcp == ',')
437 i++;
438 if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) {
439 warn(NULL);
440 return (NULL);
441 }
442 nextcp = fslist;
443 i = 0;
444 av[i++] = nextcp;
445 while ((nextcp = strchr(nextcp, ',')) != NULL) {
446 *nextcp++ = '\0';
447 av[i++] = nextcp;
448 }
449 av[i++] = NULL;
450 return (av);
451 }
452
453 char *
454 catopt(s0, s1)
455 char *s0;
456 const char *s1;
457 {
458 size_t i;
459 char *cp;
460
461 if (s0 && *s0) {
462 i = strlen(s0) + strlen(s1) + 1 + 1;
463 if ((cp = malloc(i)) == NULL)
464 err(1, NULL);
465 (void)snprintf(cp, i, "%s,%s", s0, s1);
466 } else
467 cp = strdup(s1);
468
469 if (s0)
470 free(s0);
471 return (cp);
472 }
473
474 void
475 mangle(options, argcp, argv)
476 char *options;
477 int *argcp;
478 const char **argv;
479 {
480 char *p, *s;
481 int argc;
482
483 argc = *argcp;
484 for (s = options; (p = strsep(&s, ",")) != NULL;)
485 if (*p != '\0')
486 if (*p == '-') {
487 argv[argc++] = p;
488 p = strchr(p, '=');
489 if (p) {
490 *p = '\0';
491 argv[argc++] = p+1;
492 }
493 } else if (strcmp(p, "rw") != 0) {
494 argv[argc++] = "-o";
495 argv[argc++] = p;
496 }
497
498 *argcp = argc;
499 }
500
501 void
502 usage()
503 {
504
505 (void)fprintf(stderr,
506 "usage: mount %s %s\n mount %s\n mount %s\n",
507 "[-dfruvw] [-o options] [-t ufs | external_type]",
508 "special node",
509 "[-adfruvw] [-t ufs | external_type]",
510 "[-dfruvw] special | node");
511 exit(1);
512 }
513