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