nfsd(8) wasn't dealing with the death of a child correctly.
[unix-history] / usr / src / sbin / mount / mount.c
CommitLineData
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 9static 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 15static 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 34int debug, verbose, skipvfs;
9dc9fb3d 35
093824e5
KB
36int badvfsname __P((const char *, const char **));
37int badvfstype __P((int, const char **));
38char *catopt __P((char *, const char *));
18852d2d 39struct statfs
093824e5 40 *getmntpt __P((const char *));
32c19d8b 41int hasopt __P((const char *, const char *));
093824e5
KB
42const char
43 **makevfslist __P((char *));
44void mangle __P((char *, int *, const char **));
45int mountfs __P((const char *, const char *, const char *,
46 int, const char *, const char *));
ebbd1d0f 47void prmount __P((struct statfs *));
093824e5
KB
48void usage __P((void));
49
50/* From mount_ufs.c. */
51int mount_ufs __P((int, char * const *));
52
53/* Map from mount otions to printable formats. */
54static 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
71int
72main(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
217int
218hasopt(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 242int
093824e5
KB
243mountfs(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 360void
ebbd1d0f
KM
361prmount(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 387struct statfs *
9965791c 388getmntpt(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 402int
093824e5
KB
403badvfsname(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 418const char **
59931427
KM
419makevfslist(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
450char *
451catopt(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
471void
472mangle(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
498void
499usage()
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}