mount.c revision 1.1.1.3 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.25 (Berkeley) 5/8/95";
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 <pwd.h>
52 #include <signal.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57
58 #include "pathnames.h"
59
60 int debug, verbose;
61
62 int checkvfsname __P((const char *, const char **));
63 char *catopt __P((char *, const char *));
64 struct statfs
65 *getmntpt __P((const char *));
66 int hasopt __P((const char *, const char *));
67 const char
68 **makevfslist __P((char *));
69 void mangle __P((char *, int *, const char **));
70 int mountfs __P((const char *, const char *, const char *,
71 int, const char *, const char *));
72 void prmount __P((struct statfs *));
73 void usage __P((void));
74
75 /* From mount_ufs.c. */
76 int mount_ufs __P((int, char * const *));
77
78 /* Map from mount otions to printable formats. */
79 static struct opt {
80 int o_opt;
81 const char *o_name;
82 } optnames[] = {
83 { MNT_ASYNC, "asynchronous" },
84 { MNT_EXPORTED, "NFS exported" },
85 { MNT_LOCAL, "local" },
86 { MNT_NODEV, "nodev" },
87 { MNT_NOEXEC, "noexec" },
88 { MNT_NOSUID, "nosuid" },
89 { MNT_QUOTA, "with quotas" },
90 { MNT_RDONLY, "read-only" },
91 { MNT_SYNCHRONOUS, "synchronous" },
92 { MNT_UNION, "union" },
93 { NULL }
94 };
95
96 int
97 main(argc, argv)
98 int argc;
99 char * const argv[];
100 {
101 const char *mntfromname, **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 (checkvfsname(fs->fs_vfstype, vfslist))
166 continue;
167 if (hasopt(fs->fs_mntops, "noauto"))
168 continue;
169 if (mountfs(fs->fs_vfstype, fs->fs_spec,
170 fs->fs_file, init_flags, options,
171 fs->fs_mntops))
172 rval = 1;
173 }
174 else {
175 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
176 err(1, "getmntinfo");
177 for (i = 0; i < mntsize; i++) {
178 if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
179 continue;
180 prmount(&mntbuf[i]);
181 }
182 }
183 exit(rval);
184 case 1:
185 if (vfslist != NULL)
186 usage();
187
188 if (init_flags & MNT_UPDATE) {
189 if ((mntbuf = getmntpt(*argv)) == NULL)
190 errx(1,
191 "unknown special file or file system %s.",
192 *argv);
193 if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL)
194 mntfromname = fs->fs_spec;
195 else
196 mntfromname = mntbuf->f_mntfromname;
197 rval = mountfs(mntbuf->f_fstypename, mntfromname,
198 mntbuf->f_mntonname, init_flags, options, 0);
199 break;
200 }
201 if ((fs = getfsfile(*argv)) == NULL &&
202 (fs = getfsspec(*argv)) == NULL)
203 errx(1, "%s: unknown special file or file system.",
204 *argv);
205 if (BADTYPE(fs->fs_type))
206 errx(1, "%s has unknown file system type.",
207 *argv);
208 rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file,
209 init_flags, options, fs->fs_mntops);
210 break;
211 case 2:
212 /*
213 * If -t flag has not been specified, and spec contains either
214 * a ':' or a '@' then assume that an NFS filesystem is being
215 * specified ala Sun.
216 */
217 if (vfslist == NULL && strpbrk(argv[0], ":@") != NULL)
218 vfstype = "nfs";
219 rval = mountfs(vfstype,
220 argv[0], argv[1], init_flags, options, NULL);
221 break;
222 default:
223 usage();
224 /* NOTREACHED */
225 }
226
227 /*
228 * If the mount was successfully, and done by root, tell mountd the
229 * good news. Pid checks are probably unnecessary, but don't hurt.
230 */
231 if (rval == 0 && getuid() == 0 &&
232 (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
233 if (fscanf(mountdfp, "%ld", &pid) == 1 &&
234 pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
235 err(1, "signal mountd");
236 (void)fclose(mountdfp);
237 }
238
239 exit(rval);
240 }
241
242 int
243 hasopt(mntopts, option)
244 const char *mntopts, *option;
245 {
246 int negative, found;
247 char *opt, *optbuf;
248
249 if (option[0] == 'n' && option[1] == 'o') {
250 negative = 1;
251 option += 2;
252 } else
253 negative = 0;
254 optbuf = strdup(mntopts);
255 found = 0;
256 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
257 if (opt[0] == 'n' && opt[1] == 'o') {
258 if (!strcasecmp(opt + 2, option))
259 found = negative;
260 } else if (!strcasecmp(opt, option))
261 found = !negative;
262 }
263 free(optbuf);
264 return (found);
265 }
266
267 int
268 mountfs(vfstype, spec, name, flags, options, mntopts)
269 const char *vfstype, *spec, *name, *options, *mntopts;
270 int flags;
271 {
272 /* List of directories containing mount_xxx subcommands. */
273 static const char *edirs[] = {
274 _PATH_SBIN,
275 _PATH_USRSBIN,
276 NULL
277 };
278 const char *argv[100], **edir;
279 struct statfs sf;
280 pid_t pid;
281 int argc, i, status;
282 char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
283
284 if (realpath(name, mntpath) == NULL) {
285 warn("realpath %s", mntpath);
286 return (1);
287 }
288
289 name = mntpath;
290
291 if (mntopts == NULL)
292 mntopts = "";
293 if (options == NULL) {
294 if (*mntopts == '\0') {
295 options = "rw";
296 } else {
297 options = mntopts;
298 mntopts = "";
299 }
300 }
301 optbuf = catopt(strdup(mntopts), options);
302
303 if (strcmp(name, "/") == 0)
304 flags |= MNT_UPDATE;
305 if (flags & MNT_FORCE)
306 optbuf = catopt(optbuf, "force");
307 if (flags & MNT_RDONLY)
308 optbuf = catopt(optbuf, "ro");
309 /*
310 * XXX
311 * The mount_mfs (newfs) command uses -o to select the
312 * optimisation mode. We don't pass the default "-o rw"
313 * for that reason.
314 */
315 if (flags & MNT_UPDATE)
316 optbuf = catopt(optbuf, "update");
317
318 argc = 0;
319 argv[argc++] = vfstype;
320 mangle(optbuf, &argc, argv);
321 argv[argc++] = spec;
322 argv[argc++] = name;
323 argv[argc] = NULL;
324
325 if (debug) {
326 (void)printf("exec: mount_%s", vfstype);
327 for (i = 1; i < argc; i++)
328 (void)printf(" %s", argv[i]);
329 (void)printf("\n");
330 return (0);
331 }
332
333 switch (pid = vfork()) {
334 case -1: /* Error. */
335 warn("vfork");
336 free(optbuf);
337 return (1);
338 case 0: /* Child. */
339 if (strcmp(vfstype, "ufs") == 0)
340 exit(mount_ufs(argc, (char * const *) argv));
341
342 /* Go find an executable. */
343 edir = edirs;
344 do {
345 (void)snprintf(execname,
346 sizeof(execname), "%s/mount_%s", *edir, vfstype);
347 execv(execname, (char * const *)argv);
348 if (errno != ENOENT)
349 warn("exec %s for %s", execname, name);
350 } while (*++edir != NULL);
351
352 if (errno == ENOENT)
353 warn("exec %s for %s", execname, name);
354 exit(1);
355 /* NOTREACHED */
356 default: /* Parent. */
357 free(optbuf);
358
359 if (waitpid(pid, &status, 0) < 0) {
360 warn("waitpid");
361 return (1);
362 }
363
364 if (WIFEXITED(status)) {
365 if (WEXITSTATUS(status) != 0)
366 return (WEXITSTATUS(status));
367 } else if (WIFSIGNALED(status)) {
368 warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
369 return (1);
370 }
371
372 if (verbose) {
373 if (statfs(name, &sf) < 0) {
374 warn("statfs %s", name);
375 return (1);
376 }
377 prmount(&sf);
378 }
379 break;
380 }
381
382 return (0);
383 }
384
385 void
386 prmount(sfp)
387 struct statfs *sfp;
388 {
389 int flags;
390 struct opt *o;
391 struct passwd *pw;
392 int f;
393
394 (void)printf("%s on %s", sfp->f_mntfromname, sfp->f_mntonname);
395
396 flags = sfp->f_flags & MNT_VISFLAGMASK;
397 for (f = 0, o = optnames; flags && o->o_opt; o++)
398 if (flags & o->o_opt) {
399 (void)printf("%s%s", !f++ ? " (" : ", ", o->o_name);
400 flags &= ~o->o_opt;
401 }
402 if (sfp->f_owner) {
403 (void)printf("%smounted by ", !f++ ? " (" : ", ");
404 if ((pw = getpwuid(sfp->f_owner)) != NULL)
405 (void)printf("%s", pw->pw_name);
406 else
407 (void)printf("%d", sfp->f_owner);
408 }
409 (void)printf(f ? ")\n" : "\n");
410 }
411
412 struct statfs *
413 getmntpt(name)
414 const char *name;
415 {
416 struct statfs *mntbuf;
417 int i, mntsize;
418
419 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
420 for (i = 0; i < mntsize; i++)
421 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
422 strcmp(mntbuf[i].f_mntonname, name) == 0)
423 return (&mntbuf[i]);
424 return (NULL);
425 }
426
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
475 void
476 usage()
477 {
478
479 (void)fprintf(stderr,
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");
485 exit(1);
486 }
487