Commit | Line | Data |
---|---|---|
4ba29bcc | 1 | /* |
093824e5 | 2 | * Copyright (c) 1980, 1989, 1993, 1994 |
bf65886c | 3 | * The Regents of the University of California. All rights reserved. |
f58c02bf | 4 | * |
70ab3c27 | 5 | * %sccs.include.redist.c% |
4ba29bcc DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
bf65886c | 9 | static char copyright[] = |
093824e5 | 10 | "@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ |
bf65886c | 11 | The Regents of the University of California. All rights reserved.\n"; |
f58c02bf | 12 | #endif /* not lint */ |
4ba29bcc | 13 | |
a3c5c1bf | 14 | #ifndef lint |
d7749b89 | 15 | static char sccsid[] = "@(#)mount.c 8.19 (Berkeley) %G%"; |
f58c02bf | 16 | #endif /* not lint */ |
9dc9fb3d | 17 | |
18852d2d | 18 | #include <sys/param.h> |
18852d2d | 19 | #include <sys/mount.h> |
093824e5 | 20 | #include <sys/wait.h> |
9798e8ed | 21 | |
18852d2d KB |
22 | #include <err.h> |
23 | #include <errno.h> | |
24 | #include <fstab.h> | |
25 | #include <signal.h> | |
c67c2855 KB |
26 | #include <stdio.h> |
27 | #include <stdlib.h> | |
9798e8ed | 28 | #include <string.h> |
18852d2d | 29 | #include <unistd.h> |
9dc9fb3d | 30 | |
18852d2d | 31 | #include "pathnames.h" |
8b5369dd | 32 | |
093824e5 | 33 | int debug, verbose, skipvfs; |
9dc9fb3d | 34 | |
093824e5 KB |
35 | int badvfsname __P((const char *, const char **)); |
36 | int badvfstype __P((int, const char **)); | |
37 | char *catopt __P((char *, const char *)); | |
18852d2d | 38 | struct statfs |
093824e5 KB |
39 | *getmntpt __P((const char *)); |
40 | const char | |
41 | **makevfslist __P((char *)); | |
42 | void mangle __P((char *, int *, const char **)); | |
43 | int mountfs __P((const char *, const char *, const char *, | |
44 | int, const char *, const char *)); | |
45 | void prmount __P((const char *, const char *, int)); | |
46 | void usage __P((void)); | |
47 | ||
48 | /* From mount_ufs.c. */ | |
49 | int mount_ufs __P((int, char * const *)); | |
50 | ||
51 | /* Map from mount otions to printable formats. */ | |
52 | static struct opt { | |
53 | int o_opt; | |
54 | const char *o_name; | |
55 | } optnames[] = { | |
56 | { MNT_ASYNC, "asynchronous" }, | |
57 | { MNT_EXPORTED, "NFS exported" }, | |
58 | { MNT_LOCAL, "local" }, | |
59 | { MNT_NODEV, "nodev" }, | |
60 | { MNT_NOEXEC, "noexec" }, | |
61 | { MNT_NOSUID, "nosuid" }, | |
62 | { MNT_QUOTA, "with quotas" }, | |
63 | { MNT_RDONLY, "read-only" }, | |
64 | { MNT_SYNCHRONOUS, "synchronous" }, | |
65 | { MNT_UNION, "union" }, | |
66 | { MNT_USER, "user mount" }, | |
67 | { NULL } | |
68 | }; | |
e3e6f1da JSP |
69 | |
70 | int | |
71 | main(argc, argv) | |
62c2bd36 | 72 | int argc; |
093824e5 | 73 | char * const argv[]; |
9dc9fb3d | 74 | { |
093824e5 | 75 | const char *mntonname, **vfslist, *vfstype; |
e3e6f1da | 76 | struct fstab *fs; |
e3e6f1da | 77 | struct statfs *mntbuf; |
c9cd6add KB |
78 | FILE *mountdfp; |
79 | pid_t pid; | |
093824e5 KB |
80 | int all, ch, i, init_flags, mntsize, rval; |
81 | char *options; | |
18852d2d | 82 | |
093824e5 KB |
83 | all = init_flags = 0; |
84 | options = NULL; | |
18852d2d | 85 | vfslist = NULL; |
093824e5 | 86 | vfstype = "ufs"; |
18852d2d | 87 | while ((ch = getopt(argc, argv, "adfo:rwt:uv")) != EOF) |
093824e5 | 88 | switch (ch) { |
f8836a3c KB |
89 | case 'a': |
90 | all = 1; | |
91 | break; | |
1d7f54a0 KM |
92 | case 'd': |
93 | debug = 1; | |
94 | break; | |
f8836a3c | 95 | case 'f': |
093824e5 | 96 | init_flags |= MNT_FORCE; |
f8836a3c | 97 | break; |
18852d2d | 98 | case 'o': |
093824e5 KB |
99 | if (*optarg) |
100 | options = catopt(options, optarg); | |
18852d2d | 101 | break; |
f8836a3c | 102 | case 'r': |
093824e5 | 103 | init_flags |= MNT_RDONLY; |
f8836a3c | 104 | break; |
18852d2d | 105 | case 't': |
093824e5 KB |
106 | if (vfslist != NULL) |
107 | errx(1, "only one -t option may be specified."); | |
18852d2d | 108 | vfslist = makevfslist(optarg); |
093824e5 | 109 | vfstype = optarg; |
18852d2d | 110 | break; |
169158fc | 111 | case 'u': |
093824e5 | 112 | init_flags |= MNT_UPDATE; |
169158fc | 113 | break; |
f8836a3c KB |
114 | case 'v': |
115 | verbose = 1; | |
116 | break; | |
117 | case 'w': | |
093824e5 | 118 | init_flags &= ~MNT_RDONLY; |
f8836a3c KB |
119 | break; |
120 | case '?': | |
121 | default: | |
122 | usage(); | |
c6534479 | 123 | /* NOTREACHED */ |
df611cb9 | 124 | } |
f8836a3c KB |
125 | argc -= optind; |
126 | argv += optind; | |
127 | ||
18852d2d KB |
128 | #define BADTYPE(type) \ |
129 | (strcmp(type, FSTAB_RO) && \ | |
130 | strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) | |
f8836a3c | 131 | |
c9cd6add | 132 | rval = 0; |
093824e5 KB |
133 | switch (argc) { |
134 | case 0: | |
135 | if (all) | |
136 | while ((fs = getfsent()) != NULL) { | |
137 | if (BADTYPE(fs->fs_type)) | |
138 | continue; | |
139 | if (badvfsname(fs->fs_vfstype, vfslist)) | |
140 | continue; | |
141 | if (mountfs(fs->fs_vfstype, fs->fs_spec, | |
142 | fs->fs_file, init_flags, options, | |
143 | fs->fs_mntops)) | |
144 | rval = 1; | |
145 | } | |
146 | else { | |
093824e5 KB |
147 | if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) |
148 | err(1, "getmntinfo"); | |
149 | for (i = 0; i < mntsize; i++) { | |
150 | if (badvfstype(mntbuf[i].f_type, vfslist)) | |
151 | continue; | |
152 | prmount(mntbuf[i].f_mntfromname, | |
2b33ac40 | 153 | mntbuf[i].f_mntonname, mntbuf[i].f_flags); |
093824e5 | 154 | } |
499c04f5 | 155 | } |
5ad3e76c | 156 | exit(rval); |
093824e5 | 157 | case 1: |
2b33ac40 | 158 | if (vfslist != NULL) |
f8836a3c | 159 | usage(); |
543787ae | 160 | |
093824e5 KB |
161 | if (init_flags & MNT_UPDATE) { |
162 | if ((mntbuf = getmntpt(*argv)) == NULL) | |
163 | errx(1, | |
164 | "unknown special file or file system %s.", | |
165 | *argv); | |
166 | if ((fs = getfsfile(mntbuf->f_mntonname)) == NULL) | |
167 | errx(1, "can't find fstab entry for %s.", | |
168 | *argv); | |
2b33ac40 KB |
169 | /* If it's an update, ignore the fstab file options. */ |
170 | fs->fs_mntops = NULL; | |
093824e5 KB |
171 | mntonname = mntbuf->f_mntonname; |
172 | } else { | |
173 | if ((fs = getfsfile(*argv)) == NULL && | |
174 | (fs = getfsspec(*argv)) == NULL) | |
175 | errx(1, | |
176 | "%s: unknown special file or file system.", | |
177 | *argv); | |
178 | if (BADTYPE(fs->fs_type)) | |
179 | errx(1, "%s has unknown file system type.", | |
180 | *argv); | |
181 | mntonname = fs->fs_file; | |
cc93e56b | 182 | } |
093824e5 KB |
183 | rval = mountfs(fs->fs_vfstype, fs->fs_spec, |
184 | mntonname, init_flags, options, fs->fs_mntops); | |
185 | break; | |
186 | case 2: | |
0ddf9625 | 187 | /* |
18852d2d KB |
188 | * If -t flag has not been specified, and spec contains either |
189 | * a ':' or a '@' then assume that an NFS filesystem is being | |
190 | * specified ala Sun. | |
0ddf9625 | 191 | */ |
2b33ac40 | 192 | if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL) |
093824e5 KB |
193 | vfstype = "nfs"; |
194 | rval = mountfs(vfstype, | |
195 | argv[0], argv[1], init_flags, options, NULL); | |
196 | break; | |
197 | default: | |
198 | usage(); | |
199 | /* NOTREACHED */ | |
053dae05 | 200 | } |
093824e5 | 201 | |
49d36311 | 202 | /* |
093824e5 KB |
203 | * If the mount was successfully, and done by root, tell mountd the |
204 | * good news. Pid checks are probably unnecessary, but don't hurt. | |
49d36311 | 205 | */ |
c9cd6add KB |
206 | if (rval == 0 && getuid() == 0 && |
207 | (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { | |
208 | if (fscanf(mountdfp, "%ld", &pid) == 1 && | |
d7749b89 | 209 | pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) |
c9cd6add KB |
210 | err(1, "signal mountd"); |
211 | (void)fclose(mountdfp); | |
053dae05 | 212 | } |
18852d2d | 213 | |
c9cd6add | 214 | exit(rval); |
7a6d69cb SL |
215 | } |
216 | ||
18852d2d | 217 | int |
093824e5 KB |
218 | mountfs(vfstype, spec, name, flags, options, mntopts) |
219 | const char *vfstype, *spec, *name, *options, *mntopts; | |
169158fc | 220 | int flags; |
9dc9fb3d | 221 | { |
093824e5 KB |
222 | /* List of directories containing mount_xxx subcommands. */ |
223 | static const char *edirs[] = { | |
224 | _PATH_SBIN, | |
225 | _PATH_USRSBIN, | |
226 | NULL | |
227 | }; | |
228 | const char *argv[100], **edir; | |
229 | struct statfs sf; | |
18852d2d KB |
230 | pid_t pid; |
231 | int argc, i, status; | |
093824e5 KB |
232 | char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN]; |
233 | ||
234 | if (realpath(name, mntpath) == NULL) { | |
eacd18b3 JSP |
235 | warn("%s", mntpath); |
236 | return (1); | |
237 | } | |
238 | ||
239 | name = mntpath; | |
240 | ||
2b33ac40 KB |
241 | if (options == NULL) { |
242 | if (mntopts == NULL || *mntopts == '\0') | |
093824e5 KB |
243 | options = "rw"; |
244 | else | |
245 | options = mntopts; | |
246 | mntopts = ""; | |
093824e5 KB |
247 | } |
248 | optbuf = catopt(strdup(mntopts), options); | |
249 | ||
9798e8ed JSP |
250 | if (strcmp(name, "/") == 0) |
251 | flags |= MNT_UPDATE; | |
093824e5 KB |
252 | if (flags & MNT_FORCE) |
253 | optbuf = catopt(optbuf, "force"); | |
254 | if (flags & MNT_RDONLY) | |
255 | optbuf = catopt(optbuf, "ro"); | |
256 | /* | |
257 | * XXX | |
258 | * The mount_mfs (newfs) command uses -o to select the | |
259 | * optimisation mode. We don't pass the default "-o rw" | |
260 | * for that reason. | |
261 | */ | |
262 | if (flags & MNT_UPDATE) | |
263 | optbuf = catopt(optbuf, "update"); | |
9798e8ed | 264 | |
093824e5 KB |
265 | argc = 0; |
266 | argv[argc++] = vfstype; | |
267 | mangle(optbuf, &argc, argv); | |
268 | argv[argc++] = spec; | |
269 | argv[argc++] = name; | |
270 | argv[argc] = NULL; | |
271 | ||
272 | if (debug) { | |
273 | (void)printf("exec: mount_%s", vfstype); | |
274 | for (i = 1; i < argc; i++) | |
275 | (void)printf(" %s", argv[i]); | |
276 | (void)printf("\n"); | |
277 | return (0); | |
278 | } | |
279 | ||
280 | switch (pid = vfork()) { | |
281 | case -1: /* Error. */ | |
282 | warn("vfork"); | |
283 | free(optbuf); | |
284 | return (1); | |
285 | case 0: /* Child. */ | |
9e076302 JSP |
286 | if (strcmp(vfstype, "ufs") == 0) |
287 | exit(mount_ufs(argc, (char * const *) argv)); | |
288 | ||
093824e5 KB |
289 | /* Go find an executable. */ |
290 | edir = edirs; | |
291 | do { | |
292 | (void)snprintf(execname, | |
293 | sizeof(execname), "%s/mount_%s", *edir, vfstype); | |
294 | execv(execname, (char * const *)argv); | |
295 | if (errno != ENOENT) | |
296 | warn("exec %s for %s", execname, name); | |
297 | } while (*++edir != NULL); | |
298 | ||
299 | if (errno == ENOENT) | |
300 | warn("exec %s for %s", execname, name); | |
301 | exit(1); | |
302 | /* NOTREACHED */ | |
303 | default: /* Parent. */ | |
304 | free(optbuf); | |
305 | ||
306 | if (waitpid(pid, &status, 0) < 0) { | |
307 | warn("waitpid"); | |
308 | return (1); | |
b5ce7fc9 | 309 | } |
093824e5 KB |
310 | |
311 | if (WIFEXITED(status)) { | |
312 | if (WEXITSTATUS(status) != 0) | |
b5ce7fc9 | 313 | return (WEXITSTATUS(status)); |
093824e5 KB |
314 | } else if (WIFSIGNALED(status)) { |
315 | warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); | |
316 | return (1); | |
b5ce7fc9 | 317 | } |
edac6b76 | 318 | |
093824e5 KB |
319 | if (verbose) { |
320 | if (statfs(name, &sf) < 0) { | |
321 | warn("%s", name); | |
322 | return (1); | |
323 | } | |
324 | prmount(sf.f_mntfromname, sf.f_mntonname, sf.f_flags); | |
df611cb9 | 325 | } |
093824e5 | 326 | break; |
7a6d69cb | 327 | } |
f8836a3c | 328 | |
e3e6f1da | 329 | return (0); |
f8836a3c KB |
330 | } |
331 | ||
18852d2d | 332 | void |
b5ce7fc9 | 333 | prmount(spec, name, flags) |
093824e5 | 334 | const char *spec, *name; |
e3e6f1da | 335 | int flags; |
f8836a3c | 336 | { |
093824e5 KB |
337 | struct opt *o; |
338 | int f; | |
edac6b76 | 339 | |
0e2d72b2 | 340 | (void)printf("%s on %s", spec, name); |
f8836a3c | 341 | |
093824e5 KB |
342 | flags &= MNT_VISFLAGMASK; |
343 | for (f = 0, o = optnames; flags && o->o_opt; o++) | |
344 | if (flags & o->o_opt) { | |
345 | (void)printf("%s%s", !f++ ? " (" : ", ", o->o_name); | |
346 | flags &= ~o->o_opt; | |
169158fc | 347 | } |
093824e5 | 348 | (void)printf(f ? ")\n" : "\n"); |
c6534479 | 349 | } |
c6534479 | 350 | |
18852d2d | 351 | struct statfs * |
9965791c | 352 | getmntpt(name) |
093824e5 | 353 | const char *name; |
9965791c | 354 | { |
9965791c | 355 | struct statfs *mntbuf; |
093824e5 | 356 | int i, mntsize; |
9965791c | 357 | |
f1d59f64 | 358 | mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); |
093824e5 KB |
359 | for (i = 0; i < mntsize; i++) |
360 | if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || | |
361 | strcmp(mntbuf[i].f_mntonname, name) == 0) | |
9965791c | 362 | return (&mntbuf[i]); |
18852d2d | 363 | return (NULL); |
9965791c KM |
364 | } |
365 | ||
18852d2d | 366 | int |
093824e5 KB |
367 | badvfsname(vfsname, vfslist) |
368 | const char *vfsname; | |
369 | const char **vfslist; | |
fd8bfbc5 KM |
370 | { |
371 | ||
18852d2d | 372 | if (vfslist == NULL) |
e3e6f1da | 373 | return (0); |
18852d2d | 374 | while (*vfslist != NULL) { |
093824e5 | 375 | if (strcmp(vfsname, *vfslist) == 0) |
e3e6f1da | 376 | return (skipvfs); |
093824e5 | 377 | ++vfslist; |
fd8bfbc5 KM |
378 | } |
379 | return (!skipvfs); | |
380 | } | |
381 | ||
18852d2d | 382 | int |
093824e5 KB |
383 | badvfstype(vfstype, vfslist) |
384 | int vfstype; | |
385 | const char **vfslist; | |
59931427 | 386 | { |
093824e5 | 387 | static const char *vfsnames[] = INITMOUNTNAMES; |
59931427 | 388 | |
093824e5 | 389 | if ((vfstype < 0) || (vfstype > MOUNT_MAXTYPE)) |
e3e6f1da | 390 | return (0); |
093824e5 KB |
391 | |
392 | return (badvfsname(vfsnames[vfstype], vfslist)); | |
59931427 KM |
393 | } |
394 | ||
093824e5 | 395 | const char ** |
59931427 KM |
396 | makevfslist(fslist) |
397 | char *fslist; | |
398 | { | |
093824e5 | 399 | const char **av; |
e3e6f1da | 400 | int i; |
093824e5 | 401 | char *nextcp; |
59931427 KM |
402 | |
403 | if (fslist == NULL) | |
404 | return (NULL); | |
405 | if (fslist[0] == 'n' && fslist[1] == 'o') { | |
406 | fslist += 2; | |
407 | skipvfs = 1; | |
408 | } | |
409 | for (i = 0, nextcp = fslist; *nextcp; nextcp++) | |
410 | if (*nextcp == ',') | |
411 | i++; | |
093824e5 KB |
412 | if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) { |
413 | warn(NULL); | |
59931427 | 414 | return (NULL); |
093824e5 | 415 | } |
59931427 KM |
416 | nextcp = fslist; |
417 | i = 0; | |
418 | av[i++] = nextcp; | |
093824e5 | 419 | while ((nextcp = strchr(nextcp, ',')) != NULL) { |
59931427 KM |
420 | *nextcp++ = '\0'; |
421 | av[i++] = nextcp; | |
422 | } | |
18852d2d | 423 | av[i++] = NULL; |
59931427 KM |
424 | return (av); |
425 | } | |
18852d2d | 426 | |
093824e5 KB |
427 | char * |
428 | catopt(s0, s1) | |
429 | char *s0; | |
430 | const char *s1; | |
431 | { | |
432 | size_t i; | |
433 | char *cp; | |
434 | ||
435 | if (s0 && *s0) { | |
436 | i = strlen(s0) + strlen(s1) + 1 + 1; | |
437 | if ((cp = malloc(i)) == NULL) | |
438 | err(1, NULL); | |
439 | (void)snprintf(cp, i, "%s,%s", s0, s1); | |
440 | } else | |
441 | cp = strdup(s1); | |
442 | ||
443 | if (s0) | |
444 | free(s0); | |
445 | return (cp); | |
446 | } | |
447 | ||
448 | void | |
449 | mangle(options, argcp, argv) | |
450 | char *options; | |
451 | int *argcp; | |
452 | const char **argv; | |
453 | { | |
454 | char *p, *s; | |
455 | int argc; | |
456 | ||
457 | argc = *argcp; | |
458 | for (s = options; (p = strsep(&s, ",")) != NULL;) | |
459 | if (*p != '\0') | |
460 | if (*p == '-') { | |
461 | argv[argc++] = p; | |
462 | p = strchr(p, '='); | |
463 | if (p) { | |
464 | *p = '\0'; | |
465 | argv[argc++] = p+1; | |
466 | } | |
467 | } else if (strcmp(p, "rw") != 0) { | |
468 | argv[argc++] = "-o"; | |
469 | argv[argc++] = p; | |
470 | } | |
471 | ||
472 | *argcp = argc; | |
473 | } | |
474 | ||
18852d2d KB |
475 | void |
476 | usage() | |
477 | { | |
478 | ||
479 | (void)fprintf(stderr, | |
093824e5 KB |
480 | "usage: mount %s %s\n mount %s\n mount %s\n", |
481 | "[-dfruvw] [-o options] [-t ufs | external_type]", | |
482 | "special node", | |
483 | "[-adfruvw] [-t ufs | external_type]", | |
484 | "[-dfruvw] special | node"); | |
18852d2d KB |
485 | exit(1); |
486 | } |