Deleted Added
full compact
mount.c (197200) mount.c (200796)
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 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char copyright[] =
32"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\
33 The Regents of the University of California. All rights reserved.\n";
34#if 0
35static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95";
36#endif
37#endif /* not lint */
38
39#include <sys/cdefs.h>
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 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char copyright[] =
32"@(#) Copyright (c) 1980, 1989, 1993, 1994\n\
33 The Regents of the University of California. All rights reserved.\n";
34#if 0
35static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95";
36#endif
37#endif /* not lint */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sbin/mount/mount.c 197200 2009-09-14 21:08:22Z pjd $");
40__FBSDID("$FreeBSD: head/sbin/mount/mount.c 200796 2009-12-21 19:39:10Z trasz $");
41
42#include <sys/param.h>
43#include <sys/mount.h>
44#include <sys/stat.h>
45#include <sys/wait.h>
46
47#include <ctype.h>
48#include <err.h>
49#include <errno.h>
50#include <fstab.h>
51#include <paths.h>
52#include <pwd.h>
53#include <signal.h>
54#include <stdint.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <unistd.h>
59#include <libutil.h>
60
61#include "extern.h"
62#include "mntopts.h"
63#include "pathnames.h"
64
65/* `meta' options */
66#define MOUNT_META_OPTION_FSTAB "fstab"
67#define MOUNT_META_OPTION_CURRENT "current"
68
69int debug, fstab_style, verbose;
70
71struct cpa {
72 char **a;
73 ssize_t sz;
74 int c;
75};
76
77char *catopt(char *, const char *);
78struct statfs *getmntpt(const char *);
79int hasopt(const char *, const char *);
80int ismounted(struct fstab *, struct statfs *, int);
81int isremountable(const char *);
82void mangle(char *, struct cpa *);
83char *update_options(char *, char *, int);
84int mountfs(const char *, const char *, const char *,
85 int, const char *, const char *);
86void remopt(char *, const char *);
87void prmount(struct statfs *);
88void putfsent(struct statfs *);
89void usage(void);
90char *flags2opts(int);
91
92/* Map from mount options to printable formats. */
93static struct opt {
94 int o_opt;
95 const char *o_name;
96} optnames[] = {
97 { MNT_ASYNC, "asynchronous" },
98 { MNT_EXPORTED, "NFS exported" },
99 { MNT_LOCAL, "local" },
100 { MNT_NOATIME, "noatime" },
101 { MNT_NOEXEC, "noexec" },
102 { MNT_NOSUID, "nosuid" },
103 { MNT_NOSYMFOLLOW, "nosymfollow" },
104 { MNT_QUOTA, "with quotas" },
105 { MNT_RDONLY, "read-only" },
106 { MNT_SYNCHRONOUS, "synchronous" },
107 { MNT_UNION, "union" },
108 { MNT_NOCLUSTERR, "noclusterr" },
109 { MNT_NOCLUSTERW, "noclusterw" },
110 { MNT_SUIDDIR, "suiddir" },
111 { MNT_SOFTDEP, "soft-updates" },
112 { MNT_MULTILABEL, "multilabel" },
113 { MNT_ACLS, "acls" },
41
42#include <sys/param.h>
43#include <sys/mount.h>
44#include <sys/stat.h>
45#include <sys/wait.h>
46
47#include <ctype.h>
48#include <err.h>
49#include <errno.h>
50#include <fstab.h>
51#include <paths.h>
52#include <pwd.h>
53#include <signal.h>
54#include <stdint.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <unistd.h>
59#include <libutil.h>
60
61#include "extern.h"
62#include "mntopts.h"
63#include "pathnames.h"
64
65/* `meta' options */
66#define MOUNT_META_OPTION_FSTAB "fstab"
67#define MOUNT_META_OPTION_CURRENT "current"
68
69int debug, fstab_style, verbose;
70
71struct cpa {
72 char **a;
73 ssize_t sz;
74 int c;
75};
76
77char *catopt(char *, const char *);
78struct statfs *getmntpt(const char *);
79int hasopt(const char *, const char *);
80int ismounted(struct fstab *, struct statfs *, int);
81int isremountable(const char *);
82void mangle(char *, struct cpa *);
83char *update_options(char *, char *, int);
84int mountfs(const char *, const char *, const char *,
85 int, const char *, const char *);
86void remopt(char *, const char *);
87void prmount(struct statfs *);
88void putfsent(struct statfs *);
89void usage(void);
90char *flags2opts(int);
91
92/* Map from mount options to printable formats. */
93static struct opt {
94 int o_opt;
95 const char *o_name;
96} optnames[] = {
97 { MNT_ASYNC, "asynchronous" },
98 { MNT_EXPORTED, "NFS exported" },
99 { MNT_LOCAL, "local" },
100 { MNT_NOATIME, "noatime" },
101 { MNT_NOEXEC, "noexec" },
102 { MNT_NOSUID, "nosuid" },
103 { MNT_NOSYMFOLLOW, "nosymfollow" },
104 { MNT_QUOTA, "with quotas" },
105 { MNT_RDONLY, "read-only" },
106 { MNT_SYNCHRONOUS, "synchronous" },
107 { MNT_UNION, "union" },
108 { MNT_NOCLUSTERR, "noclusterr" },
109 { MNT_NOCLUSTERW, "noclusterw" },
110 { MNT_SUIDDIR, "suiddir" },
111 { MNT_SOFTDEP, "soft-updates" },
112 { MNT_MULTILABEL, "multilabel" },
113 { MNT_ACLS, "acls" },
114 { MNT_NFS4ACLS, "nfsv4acls" },
114 { MNT_GJOURNAL, "gjournal" },
115 { 0, NULL }
116};
117
118/*
119 * List of VFS types that can be remounted without becoming mounted on top
120 * of each other.
121 * XXX Is this list correct?
122 */
123static const char *
124remountable_fs_names[] = {
125 "ufs", "ffs", "ext2fs",
126 0
127};
128
129static const char userquotaeq[] = "userquota=";
130static const char groupquotaeq[] = "groupquota=";
131
132static char *mountprog = NULL;
133
134static int
135use_mountprog(const char *vfstype)
136{
137 /* XXX: We need to get away from implementing external mount
138 * programs for every filesystem, and move towards having
139 * each filesystem properly implement the nmount() system call.
140 */
141 unsigned int i;
142 const char *fs[] = {
143 "cd9660", "mfs", "msdosfs", "newnfs", "nfs", "ntfs",
144 "nwfs", "nullfs", "portalfs", "smbfs", "udf", "unionfs",
145 NULL
146 };
147
148 if (mountprog != NULL)
149 return (1);
150
151 for (i = 0; fs[i] != NULL; ++i) {
152 if (strcmp(vfstype, fs[i]) == 0)
153 return (1);
154 }
155
156 return (0);
157}
158
159static int
160exec_mountprog(const char *name, const char *execname, char *const argv[])
161{
162 pid_t pid;
163 int status;
164
165 switch (pid = fork()) {
166 case -1: /* Error. */
167 warn("fork");
168 exit (1);
169 case 0: /* Child. */
170 /* Go find an executable. */
171 execvP(execname, _PATH_SYSPATH, argv);
172 if (errno == ENOENT) {
173 warn("exec %s not found", execname);
174 if (execname[0] != '/') {
175 warnx("in path: %s", _PATH_SYSPATH);
176 }
177 }
178 exit(1);
179 default: /* Parent. */
180 if (waitpid(pid, &status, 0) < 0) {
181 warn("waitpid");
182 return (1);
183 }
184
185 if (WIFEXITED(status)) {
186 if (WEXITSTATUS(status) != 0)
187 return (WEXITSTATUS(status));
188 } else if (WIFSIGNALED(status)) {
189 warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
190 return (1);
191 }
192 break;
193 }
194
195 return (0);
196}
197
198static int
199specified_ro(const char *arg)
200{
201 char *optbuf, *opt;
202 int ret = 0;
203
204 optbuf = strdup(arg);
205 if (optbuf == NULL)
206 err(1, NULL);
207
208 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
209 if (strcmp(opt, "ro") == 0) {
210 ret = 1;
211 break;
212 }
213 }
214 free(optbuf);
215 return (ret);
216}
217
218static void
219restart_mountd(void)
220{
221 struct pidfh *pfh;
222 pid_t mountdpid;
223
224 pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &mountdpid);
225 if (pfh != NULL) {
226 /* Mountd is not running. */
227 pidfile_remove(pfh);
228 return;
229 }
230 if (errno != EEXIST) {
231 /* Cannot open pidfile for some reason. */
232 return;
233 }
234 /* We have mountd(8) PID in mountdpid varible, let's signal it. */
235 if (kill(mountdpid, SIGHUP) == -1)
236 err(1, "signal mountd");
237}
238
239int
240main(int argc, char *argv[])
241{
242 const char *mntfromname, **vfslist, *vfstype;
243 struct fstab *fs;
244 struct statfs *mntbuf;
245 int all, ch, i, init_flags, late, mntsize, rval, have_fstab, ro;
246 char *cp, *ep, *options;
247
248 all = init_flags = late = 0;
249 ro = 0;
250 options = NULL;
251 vfslist = NULL;
252 vfstype = "ufs";
253 while ((ch = getopt(argc, argv, "adF:flo:prt:uvw")) != -1)
254 switch (ch) {
255 case 'a':
256 all = 1;
257 break;
258 case 'd':
259 debug = 1;
260 break;
261 case 'F':
262 setfstab(optarg);
263 break;
264 case 'f':
265 init_flags |= MNT_FORCE;
266 break;
267 case 'l':
268 late = 1;
269 break;
270 case 'o':
271 if (*optarg) {
272 options = catopt(options, optarg);
273 if (specified_ro(optarg))
274 ro = 1;
275 }
276 break;
277 case 'p':
278 fstab_style = 1;
279 verbose = 1;
280 break;
281 case 'r':
282 options = catopt(options, "ro");
283 ro = 1;
284 break;
285 case 't':
286 if (vfslist != NULL)
287 errx(1, "only one -t option may be specified");
288 vfslist = makevfslist(optarg);
289 vfstype = optarg;
290 break;
291 case 'u':
292 init_flags |= MNT_UPDATE;
293 break;
294 case 'v':
295 verbose = 1;
296 break;
297 case 'w':
298 options = catopt(options, "noro");
299 break;
300 case '?':
301 default:
302 usage();
303 /* NOTREACHED */
304 }
305 argc -= optind;
306 argv += optind;
307
308#define BADTYPE(type) \
309 (strcmp(type, FSTAB_RO) && \
310 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
311
312 if ((init_flags & MNT_UPDATE) && (ro == 0))
313 options = catopt(options, "noro");
314
315 rval = 0;
316 switch (argc) {
317 case 0:
318 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
319 err(1, "getmntinfo");
320 if (all) {
321 while ((fs = getfsent()) != NULL) {
322 if (BADTYPE(fs->fs_type))
323 continue;
324 if (checkvfsname(fs->fs_vfstype, vfslist))
325 continue;
326 if (hasopt(fs->fs_mntops, "noauto"))
327 continue;
328 if (hasopt(fs->fs_mntops, "late") && !late)
329 continue;
330 if (!(init_flags & MNT_UPDATE) &&
331 ismounted(fs, mntbuf, mntsize))
332 continue;
333 options = update_options(options, fs->fs_mntops,
334 mntbuf->f_flags);
335 if (mountfs(fs->fs_vfstype, fs->fs_spec,
336 fs->fs_file, init_flags, options,
337 fs->fs_mntops))
338 rval = 1;
339 }
340 } else if (fstab_style) {
341 for (i = 0; i < mntsize; i++) {
342 if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
343 continue;
344 putfsent(&mntbuf[i]);
345 }
346 } else {
347 for (i = 0; i < mntsize; i++) {
348 if (checkvfsname(mntbuf[i].f_fstypename,
349 vfslist))
350 continue;
351 if (!verbose &&
352 (mntbuf[i].f_flags & MNT_IGNORE) != 0)
353 continue;
354 prmount(&mntbuf[i]);
355 }
356 }
357 exit(rval);
358 case 1:
359 if (vfslist != NULL)
360 usage();
361
362 rmslashes(*argv, *argv);
363 if (init_flags & MNT_UPDATE) {
364 mntfromname = NULL;
365 have_fstab = 0;
366 if ((mntbuf = getmntpt(*argv)) == NULL)
367 errx(1, "not currently mounted %s", *argv);
368 /*
369 * Only get the mntflags from fstab if both mntpoint
370 * and mntspec are identical. Also handle the special
371 * case where just '/' is mounted and 'spec' is not
372 * identical with the one from fstab ('/dev' is missing
373 * in the spec-string at boot-time).
374 */
375 if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) {
376 if (strcmp(fs->fs_spec,
377 mntbuf->f_mntfromname) == 0 &&
378 strcmp(fs->fs_file,
379 mntbuf->f_mntonname) == 0) {
380 have_fstab = 1;
381 mntfromname = mntbuf->f_mntfromname;
382 } else if (argv[0][0] == '/' &&
383 argv[0][1] == '\0') {
384 fs = getfsfile("/");
385 have_fstab = 1;
386 mntfromname = fs->fs_spec;
387 }
388 }
389 if (have_fstab) {
390 options = update_options(options, fs->fs_mntops,
391 mntbuf->f_flags);
392 } else {
393 mntfromname = mntbuf->f_mntfromname;
394 options = update_options(options, NULL,
395 mntbuf->f_flags);
396 }
397 rval = mountfs(mntbuf->f_fstypename, mntfromname,
398 mntbuf->f_mntonname, init_flags, options, 0);
399 break;
400 }
401 if ((fs = getfsfile(*argv)) == NULL &&
402 (fs = getfsspec(*argv)) == NULL)
403 errx(1, "%s: unknown special file or file system",
404 *argv);
405 if (BADTYPE(fs->fs_type))
406 errx(1, "%s has unknown file system type",
407 *argv);
408 rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file,
409 init_flags, options, fs->fs_mntops);
410 break;
411 case 2:
412 /*
413 * If -t flag has not been specified, the path cannot be
414 * found, spec contains either a ':' or a '@', then assume
415 * that an NFS file system is being specified ala Sun.
416 * Check if the hostname contains only allowed characters
417 * to reduce false positives. IPv6 addresses containing
418 * ':' will be correctly parsed only if the separator is '@'.
419 * The definition of a valid hostname is taken from RFC 1034.
420 */
421 if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL ||
422 (ep = strchr(argv[0], ':')) != NULL)) {
423 if (*ep == '@') {
424 cp = ep + 1;
425 ep = cp + strlen(cp);
426 } else
427 cp = argv[0];
428 while (cp != ep) {
429 if (!isdigit(*cp) && !isalpha(*cp) &&
430 *cp != '.' && *cp != '-' && *cp != ':')
431 break;
432 cp++;
433 }
434 if (cp == ep)
435 vfstype = "nfs";
436 }
437 rval = mountfs(vfstype,
438 argv[0], argv[1], init_flags, options, NULL);
439 break;
440 default:
441 usage();
442 /* NOTREACHED */
443 }
444
445 /*
446 * If the mount was successfully, and done by root, tell mountd the
447 * good news.
448 */
449 if (rval == 0 && getuid() == 0)
450 restart_mountd();
451
452 exit(rval);
453}
454
455int
456ismounted(struct fstab *fs, struct statfs *mntbuf, int mntsize)
457{
458 char realfsfile[PATH_MAX];
459 int i;
460
461 if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0')
462 /* the root file system can always be remounted */
463 return (0);
464
465 /* The user may have specified a symlink in fstab, resolve the path */
466 if (realpath(fs->fs_file, realfsfile) == NULL) {
467 /* Cannot resolve the path, use original one */
468 strlcpy(realfsfile, fs->fs_file, sizeof(realfsfile));
469 }
470
471 for (i = mntsize - 1; i >= 0; --i)
472 if (strcmp(realfsfile, mntbuf[i].f_mntonname) == 0 &&
473 (!isremountable(fs->fs_vfstype) ||
474 strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0))
475 return (1);
476 return (0);
477}
478
479int
480isremountable(const char *vfsname)
481{
482 const char **cp;
483
484 for (cp = remountable_fs_names; *cp; cp++)
485 if (strcmp(*cp, vfsname) == 0)
486 return (1);
487 return (0);
488}
489
490int
491hasopt(const char *mntopts, const char *option)
492{
493 int negative, found;
494 char *opt, *optbuf;
495
496 if (option[0] == 'n' && option[1] == 'o') {
497 negative = 1;
498 option += 2;
499 } else
500 negative = 0;
501 optbuf = strdup(mntopts);
502 found = 0;
503 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
504 if (opt[0] == 'n' && opt[1] == 'o') {
505 if (!strcasecmp(opt + 2, option))
506 found = negative;
507 } else if (!strcasecmp(opt, option))
508 found = !negative;
509 }
510 free(optbuf);
511 return (found);
512}
513
514static void
515append_arg(struct cpa *sa, char *arg)
516{
517 if (sa->c + 1 == sa->sz) {
518 sa->sz = sa->sz == 0 ? 8 : sa->sz * 2;
519 sa->a = realloc(sa->a, sizeof(sa->a) * sa->sz);
520 if (sa->a == NULL)
521 errx(1, "realloc failed");
522 }
523 sa->a[++sa->c] = arg;
524}
525
526int
527mountfs(const char *vfstype, const char *spec, const char *name, int flags,
528 const char *options, const char *mntopts)
529{
530 struct statfs sf;
531 int i, ret;
532 char *optbuf, execname[PATH_MAX], mntpath[PATH_MAX];
533 static struct cpa mnt_argv;
534
535 /* resolve the mountpoint with realpath(3) */
536 (void)checkpath(name, mntpath);
537 name = mntpath;
538
539 if (mntopts == NULL)
540 mntopts = "";
541 optbuf = catopt(strdup(mntopts), options);
542
543 if (strcmp(name, "/") == 0)
544 flags |= MNT_UPDATE;
545 if (flags & MNT_FORCE)
546 optbuf = catopt(optbuf, "force");
547 if (flags & MNT_RDONLY)
548 optbuf = catopt(optbuf, "ro");
549 /*
550 * XXX
551 * The mount_mfs (newfs) command uses -o to select the
552 * optimization mode. We don't pass the default "-o rw"
553 * for that reason.
554 */
555 if (flags & MNT_UPDATE)
556 optbuf = catopt(optbuf, "update");
557
558 /* Compatibility glue. */
559 if (strcmp(vfstype, "msdos") == 0) {
560 warnx(
561 "Using \"-t msdosfs\", since \"-t msdos\" is deprecated.");
562 vfstype = "msdosfs";
563 }
564
565 /* Construct the name of the appropriate mount command */
566 (void)snprintf(execname, sizeof(execname), "mount_%s", vfstype);
567
568 mnt_argv.c = -1;
569 append_arg(&mnt_argv, execname);
570 mangle(optbuf, &mnt_argv);
571 if (mountprog != NULL)
572 strcpy(execname, mountprog);
573
574 append_arg(&mnt_argv, strdup(spec));
575 append_arg(&mnt_argv, strdup(name));
576 append_arg(&mnt_argv, NULL);
577
578 if (debug) {
579 if (use_mountprog(vfstype))
580 printf("exec: %s", execname);
581 else
582 printf("mount -t %s", vfstype);
583 for (i = 1; i < mnt_argv.c; i++)
584 (void)printf(" %s", mnt_argv.a[i]);
585 (void)printf("\n");
586 return (0);
587 }
588
589 if (use_mountprog(vfstype)) {
590 ret = exec_mountprog(name, execname, mnt_argv.a);
591 } else {
592 ret = mount_fs(vfstype, mnt_argv.c, mnt_argv.a);
593 }
594
595 free(optbuf);
596
597 if (verbose) {
598 if (statfs(name, &sf) < 0) {
599 warn("statfs %s", name);
600 return (1);
601 }
602 if (fstab_style)
603 putfsent(&sf);
604 else
605 prmount(&sf);
606 }
607
608 return (ret);
609}
610
611void
612prmount(struct statfs *sfp)
613{
614 int flags;
615 unsigned int i;
616 struct opt *o;
617 struct passwd *pw;
618
619 (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname,
620 sfp->f_fstypename);
621
622 flags = sfp->f_flags & MNT_VISFLAGMASK;
623 for (o = optnames; flags && o->o_opt; o++)
624 if (flags & o->o_opt) {
625 (void)printf(", %s", o->o_name);
626 flags &= ~o->o_opt;
627 }
628 /*
629 * Inform when file system is mounted by an unprivileged user
630 * or privileged non-root user.
631 */
632 if ((flags & MNT_USER) != 0 || sfp->f_owner != 0) {
633 (void)printf(", mounted by ");
634 if ((pw = getpwuid(sfp->f_owner)) != NULL)
635 (void)printf("%s", pw->pw_name);
636 else
637 (void)printf("%d", sfp->f_owner);
638 }
639 if (verbose) {
640 if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0)
641 (void)printf(", writes: sync %ju async %ju",
642 (uintmax_t)sfp->f_syncwrites,
643 (uintmax_t)sfp->f_asyncwrites);
644 if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0)
645 (void)printf(", reads: sync %ju async %ju",
646 (uintmax_t)sfp->f_syncreads,
647 (uintmax_t)sfp->f_asyncreads);
648 if (sfp->f_fsid.val[0] != 0 || sfp->f_fsid.val[1] != 0) {
649 printf(", fsid ");
650 for (i = 0; i < sizeof(sfp->f_fsid); i++)
651 printf("%02x", ((u_char *)&sfp->f_fsid)[i]);
652 }
653 }
654 (void)printf(")\n");
655}
656
657struct statfs *
658getmntpt(const char *name)
659{
660 struct statfs *mntbuf;
661 int i, mntsize;
662
663 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
664 for (i = mntsize - 1; i >= 0; i--) {
665 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
666 strcmp(mntbuf[i].f_mntonname, name) == 0)
667 return (&mntbuf[i]);
668 }
669 return (NULL);
670}
671
672char *
673catopt(char *s0, const char *s1)
674{
675 size_t i;
676 char *cp;
677
678 if (s1 == NULL || *s1 == '\0')
679 return (s0);
680
681 if (s0 && *s0) {
682 i = strlen(s0) + strlen(s1) + 1 + 1;
683 if ((cp = malloc(i)) == NULL)
684 errx(1, "malloc failed");
685 (void)snprintf(cp, i, "%s,%s", s0, s1);
686 } else
687 cp = strdup(s1);
688
689 if (s0)
690 free(s0);
691 return (cp);
692}
693
694void
695mangle(char *options, struct cpa *a)
696{
697 char *p, *s, *val;
698
699 for (s = options; (p = strsep(&s, ",")) != NULL;)
700 if (*p != '\0') {
701 if (strcmp(p, "noauto") == 0) {
702 /*
703 * Do not pass noauto option to nmount().
704 * or external mount program. noauto is
705 * only used to prevent mounting a filesystem
706 * when 'mount -a' is specified, and is
707 * not a real mount option.
708 */
709 continue;
710 } else if (strcmp(p, "late") == 0) {
711 /*
712 * "late" is used to prevent certain file
713 * systems from being mounted before late
714 * in the boot cycle; for instance,
715 * loopback NFS mounts can't be mounted
716 * before mountd starts.
717 */
718 continue;
719 } else if (strncmp(p, "mountprog", 9) == 0) {
720 /*
721 * "mountprog" is used to force the use of
722 * userland mount programs.
723 */
724 val = strchr(p, '=');
725 if (val != NULL) {
726 ++val;
727 if (*val != '\0')
728 mountprog = strdup(val);
729 }
730
731 if (mountprog == NULL) {
732 errx(1, "Need value for -o mountprog");
733 }
734 continue;
735 } else if (strcmp(p, "userquota") == 0) {
736 continue;
737 } else if (strncmp(p, userquotaeq,
738 sizeof(userquotaeq) - 1) == 0) {
739 continue;
740 } else if (strcmp(p, "groupquota") == 0) {
741 continue;
742 } else if (strncmp(p, groupquotaeq,
743 sizeof(groupquotaeq) - 1) == 0) {
744 continue;
745 } else if (*p == '-') {
746 append_arg(a, p);
747 p = strchr(p, '=');
748 if (p != NULL) {
749 *p = '\0';
750 append_arg(a, p + 1);
751 }
752 } else {
753 append_arg(a, strdup("-o"));
754 append_arg(a, p);
755 }
756 }
757}
758
759
760char *
761update_options(char *opts, char *fstab, int curflags)
762{
763 char *o, *p;
764 char *cur;
765 char *expopt, *newopt, *tmpopt;
766
767 if (opts == NULL)
768 return (strdup(""));
769
770 /* remove meta options from list */
771 remopt(fstab, MOUNT_META_OPTION_FSTAB);
772 remopt(fstab, MOUNT_META_OPTION_CURRENT);
773 cur = flags2opts(curflags);
774
775 /*
776 * Expand all meta-options passed to us first.
777 */
778 expopt = NULL;
779 for (p = opts; (o = strsep(&p, ",")) != NULL;) {
780 if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0)
781 expopt = catopt(expopt, fstab);
782 else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0)
783 expopt = catopt(expopt, cur);
784 else
785 expopt = catopt(expopt, o);
786 }
787 free(cur);
788 free(opts);
789
790 /*
791 * Remove previous contradictory arguments. Given option "foo" we
792 * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo"
793 * and "foo" - so we can deal with possible options like "notice".
794 */
795 newopt = NULL;
796 for (p = expopt; (o = strsep(&p, ",")) != NULL;) {
797 if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL)
798 errx(1, "malloc failed");
799
800 strcpy(tmpopt, "no");
801 strcat(tmpopt, o);
802 remopt(newopt, tmpopt);
803 free(tmpopt);
804
805 if (strncmp("no", o, 2) == 0)
806 remopt(newopt, o+2);
807
808 newopt = catopt(newopt, o);
809 }
810 free(expopt);
811
812 return (newopt);
813}
814
815void
816remopt(char *string, const char *opt)
817{
818 char *o, *p, *r;
819
820 if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0')
821 return;
822
823 r = string;
824
825 for (p = string; (o = strsep(&p, ",")) != NULL;) {
826 if (strcmp(opt, o) != 0) {
827 if (*r == ',' && *o != '\0')
828 r++;
829 while ((*r++ = *o++) != '\0')
830 ;
831 *--r = ',';
832 }
833 }
834 *r = '\0';
835}
836
837void
838usage(void)
839{
840
841 (void)fprintf(stderr, "%s\n%s\n%s\n",
842"usage: mount [-adflpruvw] [-F fstab] [-o options] [-t ufs | external_type]",
843" mount [-dfpruvw] special | node",
844" mount [-dfpruvw] [-o options] [-t ufs | external_type] special node");
845 exit(1);
846}
847
848void
849putfsent(struct statfs *ent)
850{
851 struct fstab *fst;
852 char *opts;
853 int l;
854
855 opts = flags2opts(ent->f_flags);
856
857 if (strncmp(ent->f_mntfromname, "<below>", 7) == 0 ||
858 strncmp(ent->f_mntfromname, "<above>", 7) == 0) {
859 strcpy(ent->f_mntfromname, (strnstr(ent->f_mntfromname, ":", 8)
860 +1));
861 }
862
863 /*
864 * "rw" is not a real mount option; this is why we print NULL as "rw"
865 * if opts is still NULL here.
866 */
867 l = strlen(ent->f_mntfromname);
868 printf("%s%s%s%s", ent->f_mntfromname,
869 l < 8 ? "\t" : "",
870 l < 16 ? "\t" : "",
871 l < 24 ? "\t" : " ");
872 l = strlen(ent->f_mntonname);
873 printf("%s%s%s%s", ent->f_mntonname,
874 l < 8 ? "\t" : "",
875 l < 16 ? "\t" : "",
876 l < 24 ? "\t" : " ");
877 printf("%s\t", ent->f_fstypename);
878 if (opts == NULL) {
879 printf("%s\t", "rw");
880 } else {
881 l = strlen(opts);
882 printf("%s%s", opts,
883 l < 8 ? "\t" : " ");
884 }
885 free(opts);
886
887 if ((fst = getfsspec(ent->f_mntfromname)))
888 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
889 else if ((fst = getfsfile(ent->f_mntonname)))
890 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
891 else if (strcmp(ent->f_fstypename, "ufs") == 0) {
892 if (strcmp(ent->f_mntonname, "/") == 0)
893 printf("\t1 1\n");
894 else
895 printf("\t2 2\n");
896 } else
897 printf("\t0 0\n");
898}
899
900
901char *
902flags2opts(int flags)
903{
904 char *res;
905
906 res = NULL;
907
908 if (flags & MNT_RDONLY) res = catopt(res, "ro");
909 if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync");
910 if (flags & MNT_NOEXEC) res = catopt(res, "noexec");
911 if (flags & MNT_NOSUID) res = catopt(res, "nosuid");
912 if (flags & MNT_UNION) res = catopt(res, "union");
913 if (flags & MNT_ASYNC) res = catopt(res, "async");
914 if (flags & MNT_NOATIME) res = catopt(res, "noatime");
915 if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr");
916 if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw");
917 if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow");
918 if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir");
919 if (flags & MNT_MULTILABEL) res = catopt(res, "multilabel");
920 if (flags & MNT_ACLS) res = catopt(res, "acls");
115 { MNT_GJOURNAL, "gjournal" },
116 { 0, NULL }
117};
118
119/*
120 * List of VFS types that can be remounted without becoming mounted on top
121 * of each other.
122 * XXX Is this list correct?
123 */
124static const char *
125remountable_fs_names[] = {
126 "ufs", "ffs", "ext2fs",
127 0
128};
129
130static const char userquotaeq[] = "userquota=";
131static const char groupquotaeq[] = "groupquota=";
132
133static char *mountprog = NULL;
134
135static int
136use_mountprog(const char *vfstype)
137{
138 /* XXX: We need to get away from implementing external mount
139 * programs for every filesystem, and move towards having
140 * each filesystem properly implement the nmount() system call.
141 */
142 unsigned int i;
143 const char *fs[] = {
144 "cd9660", "mfs", "msdosfs", "newnfs", "nfs", "ntfs",
145 "nwfs", "nullfs", "portalfs", "smbfs", "udf", "unionfs",
146 NULL
147 };
148
149 if (mountprog != NULL)
150 return (1);
151
152 for (i = 0; fs[i] != NULL; ++i) {
153 if (strcmp(vfstype, fs[i]) == 0)
154 return (1);
155 }
156
157 return (0);
158}
159
160static int
161exec_mountprog(const char *name, const char *execname, char *const argv[])
162{
163 pid_t pid;
164 int status;
165
166 switch (pid = fork()) {
167 case -1: /* Error. */
168 warn("fork");
169 exit (1);
170 case 0: /* Child. */
171 /* Go find an executable. */
172 execvP(execname, _PATH_SYSPATH, argv);
173 if (errno == ENOENT) {
174 warn("exec %s not found", execname);
175 if (execname[0] != '/') {
176 warnx("in path: %s", _PATH_SYSPATH);
177 }
178 }
179 exit(1);
180 default: /* Parent. */
181 if (waitpid(pid, &status, 0) < 0) {
182 warn("waitpid");
183 return (1);
184 }
185
186 if (WIFEXITED(status)) {
187 if (WEXITSTATUS(status) != 0)
188 return (WEXITSTATUS(status));
189 } else if (WIFSIGNALED(status)) {
190 warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
191 return (1);
192 }
193 break;
194 }
195
196 return (0);
197}
198
199static int
200specified_ro(const char *arg)
201{
202 char *optbuf, *opt;
203 int ret = 0;
204
205 optbuf = strdup(arg);
206 if (optbuf == NULL)
207 err(1, NULL);
208
209 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
210 if (strcmp(opt, "ro") == 0) {
211 ret = 1;
212 break;
213 }
214 }
215 free(optbuf);
216 return (ret);
217}
218
219static void
220restart_mountd(void)
221{
222 struct pidfh *pfh;
223 pid_t mountdpid;
224
225 pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &mountdpid);
226 if (pfh != NULL) {
227 /* Mountd is not running. */
228 pidfile_remove(pfh);
229 return;
230 }
231 if (errno != EEXIST) {
232 /* Cannot open pidfile for some reason. */
233 return;
234 }
235 /* We have mountd(8) PID in mountdpid varible, let's signal it. */
236 if (kill(mountdpid, SIGHUP) == -1)
237 err(1, "signal mountd");
238}
239
240int
241main(int argc, char *argv[])
242{
243 const char *mntfromname, **vfslist, *vfstype;
244 struct fstab *fs;
245 struct statfs *mntbuf;
246 int all, ch, i, init_flags, late, mntsize, rval, have_fstab, ro;
247 char *cp, *ep, *options;
248
249 all = init_flags = late = 0;
250 ro = 0;
251 options = NULL;
252 vfslist = NULL;
253 vfstype = "ufs";
254 while ((ch = getopt(argc, argv, "adF:flo:prt:uvw")) != -1)
255 switch (ch) {
256 case 'a':
257 all = 1;
258 break;
259 case 'd':
260 debug = 1;
261 break;
262 case 'F':
263 setfstab(optarg);
264 break;
265 case 'f':
266 init_flags |= MNT_FORCE;
267 break;
268 case 'l':
269 late = 1;
270 break;
271 case 'o':
272 if (*optarg) {
273 options = catopt(options, optarg);
274 if (specified_ro(optarg))
275 ro = 1;
276 }
277 break;
278 case 'p':
279 fstab_style = 1;
280 verbose = 1;
281 break;
282 case 'r':
283 options = catopt(options, "ro");
284 ro = 1;
285 break;
286 case 't':
287 if (vfslist != NULL)
288 errx(1, "only one -t option may be specified");
289 vfslist = makevfslist(optarg);
290 vfstype = optarg;
291 break;
292 case 'u':
293 init_flags |= MNT_UPDATE;
294 break;
295 case 'v':
296 verbose = 1;
297 break;
298 case 'w':
299 options = catopt(options, "noro");
300 break;
301 case '?':
302 default:
303 usage();
304 /* NOTREACHED */
305 }
306 argc -= optind;
307 argv += optind;
308
309#define BADTYPE(type) \
310 (strcmp(type, FSTAB_RO) && \
311 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
312
313 if ((init_flags & MNT_UPDATE) && (ro == 0))
314 options = catopt(options, "noro");
315
316 rval = 0;
317 switch (argc) {
318 case 0:
319 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
320 err(1, "getmntinfo");
321 if (all) {
322 while ((fs = getfsent()) != NULL) {
323 if (BADTYPE(fs->fs_type))
324 continue;
325 if (checkvfsname(fs->fs_vfstype, vfslist))
326 continue;
327 if (hasopt(fs->fs_mntops, "noauto"))
328 continue;
329 if (hasopt(fs->fs_mntops, "late") && !late)
330 continue;
331 if (!(init_flags & MNT_UPDATE) &&
332 ismounted(fs, mntbuf, mntsize))
333 continue;
334 options = update_options(options, fs->fs_mntops,
335 mntbuf->f_flags);
336 if (mountfs(fs->fs_vfstype, fs->fs_spec,
337 fs->fs_file, init_flags, options,
338 fs->fs_mntops))
339 rval = 1;
340 }
341 } else if (fstab_style) {
342 for (i = 0; i < mntsize; i++) {
343 if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
344 continue;
345 putfsent(&mntbuf[i]);
346 }
347 } else {
348 for (i = 0; i < mntsize; i++) {
349 if (checkvfsname(mntbuf[i].f_fstypename,
350 vfslist))
351 continue;
352 if (!verbose &&
353 (mntbuf[i].f_flags & MNT_IGNORE) != 0)
354 continue;
355 prmount(&mntbuf[i]);
356 }
357 }
358 exit(rval);
359 case 1:
360 if (vfslist != NULL)
361 usage();
362
363 rmslashes(*argv, *argv);
364 if (init_flags & MNT_UPDATE) {
365 mntfromname = NULL;
366 have_fstab = 0;
367 if ((mntbuf = getmntpt(*argv)) == NULL)
368 errx(1, "not currently mounted %s", *argv);
369 /*
370 * Only get the mntflags from fstab if both mntpoint
371 * and mntspec are identical. Also handle the special
372 * case where just '/' is mounted and 'spec' is not
373 * identical with the one from fstab ('/dev' is missing
374 * in the spec-string at boot-time).
375 */
376 if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) {
377 if (strcmp(fs->fs_spec,
378 mntbuf->f_mntfromname) == 0 &&
379 strcmp(fs->fs_file,
380 mntbuf->f_mntonname) == 0) {
381 have_fstab = 1;
382 mntfromname = mntbuf->f_mntfromname;
383 } else if (argv[0][0] == '/' &&
384 argv[0][1] == '\0') {
385 fs = getfsfile("/");
386 have_fstab = 1;
387 mntfromname = fs->fs_spec;
388 }
389 }
390 if (have_fstab) {
391 options = update_options(options, fs->fs_mntops,
392 mntbuf->f_flags);
393 } else {
394 mntfromname = mntbuf->f_mntfromname;
395 options = update_options(options, NULL,
396 mntbuf->f_flags);
397 }
398 rval = mountfs(mntbuf->f_fstypename, mntfromname,
399 mntbuf->f_mntonname, init_flags, options, 0);
400 break;
401 }
402 if ((fs = getfsfile(*argv)) == NULL &&
403 (fs = getfsspec(*argv)) == NULL)
404 errx(1, "%s: unknown special file or file system",
405 *argv);
406 if (BADTYPE(fs->fs_type))
407 errx(1, "%s has unknown file system type",
408 *argv);
409 rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file,
410 init_flags, options, fs->fs_mntops);
411 break;
412 case 2:
413 /*
414 * If -t flag has not been specified, the path cannot be
415 * found, spec contains either a ':' or a '@', then assume
416 * that an NFS file system is being specified ala Sun.
417 * Check if the hostname contains only allowed characters
418 * to reduce false positives. IPv6 addresses containing
419 * ':' will be correctly parsed only if the separator is '@'.
420 * The definition of a valid hostname is taken from RFC 1034.
421 */
422 if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL ||
423 (ep = strchr(argv[0], ':')) != NULL)) {
424 if (*ep == '@') {
425 cp = ep + 1;
426 ep = cp + strlen(cp);
427 } else
428 cp = argv[0];
429 while (cp != ep) {
430 if (!isdigit(*cp) && !isalpha(*cp) &&
431 *cp != '.' && *cp != '-' && *cp != ':')
432 break;
433 cp++;
434 }
435 if (cp == ep)
436 vfstype = "nfs";
437 }
438 rval = mountfs(vfstype,
439 argv[0], argv[1], init_flags, options, NULL);
440 break;
441 default:
442 usage();
443 /* NOTREACHED */
444 }
445
446 /*
447 * If the mount was successfully, and done by root, tell mountd the
448 * good news.
449 */
450 if (rval == 0 && getuid() == 0)
451 restart_mountd();
452
453 exit(rval);
454}
455
456int
457ismounted(struct fstab *fs, struct statfs *mntbuf, int mntsize)
458{
459 char realfsfile[PATH_MAX];
460 int i;
461
462 if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0')
463 /* the root file system can always be remounted */
464 return (0);
465
466 /* The user may have specified a symlink in fstab, resolve the path */
467 if (realpath(fs->fs_file, realfsfile) == NULL) {
468 /* Cannot resolve the path, use original one */
469 strlcpy(realfsfile, fs->fs_file, sizeof(realfsfile));
470 }
471
472 for (i = mntsize - 1; i >= 0; --i)
473 if (strcmp(realfsfile, mntbuf[i].f_mntonname) == 0 &&
474 (!isremountable(fs->fs_vfstype) ||
475 strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0))
476 return (1);
477 return (0);
478}
479
480int
481isremountable(const char *vfsname)
482{
483 const char **cp;
484
485 for (cp = remountable_fs_names; *cp; cp++)
486 if (strcmp(*cp, vfsname) == 0)
487 return (1);
488 return (0);
489}
490
491int
492hasopt(const char *mntopts, const char *option)
493{
494 int negative, found;
495 char *opt, *optbuf;
496
497 if (option[0] == 'n' && option[1] == 'o') {
498 negative = 1;
499 option += 2;
500 } else
501 negative = 0;
502 optbuf = strdup(mntopts);
503 found = 0;
504 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
505 if (opt[0] == 'n' && opt[1] == 'o') {
506 if (!strcasecmp(opt + 2, option))
507 found = negative;
508 } else if (!strcasecmp(opt, option))
509 found = !negative;
510 }
511 free(optbuf);
512 return (found);
513}
514
515static void
516append_arg(struct cpa *sa, char *arg)
517{
518 if (sa->c + 1 == sa->sz) {
519 sa->sz = sa->sz == 0 ? 8 : sa->sz * 2;
520 sa->a = realloc(sa->a, sizeof(sa->a) * sa->sz);
521 if (sa->a == NULL)
522 errx(1, "realloc failed");
523 }
524 sa->a[++sa->c] = arg;
525}
526
527int
528mountfs(const char *vfstype, const char *spec, const char *name, int flags,
529 const char *options, const char *mntopts)
530{
531 struct statfs sf;
532 int i, ret;
533 char *optbuf, execname[PATH_MAX], mntpath[PATH_MAX];
534 static struct cpa mnt_argv;
535
536 /* resolve the mountpoint with realpath(3) */
537 (void)checkpath(name, mntpath);
538 name = mntpath;
539
540 if (mntopts == NULL)
541 mntopts = "";
542 optbuf = catopt(strdup(mntopts), options);
543
544 if (strcmp(name, "/") == 0)
545 flags |= MNT_UPDATE;
546 if (flags & MNT_FORCE)
547 optbuf = catopt(optbuf, "force");
548 if (flags & MNT_RDONLY)
549 optbuf = catopt(optbuf, "ro");
550 /*
551 * XXX
552 * The mount_mfs (newfs) command uses -o to select the
553 * optimization mode. We don't pass the default "-o rw"
554 * for that reason.
555 */
556 if (flags & MNT_UPDATE)
557 optbuf = catopt(optbuf, "update");
558
559 /* Compatibility glue. */
560 if (strcmp(vfstype, "msdos") == 0) {
561 warnx(
562 "Using \"-t msdosfs\", since \"-t msdos\" is deprecated.");
563 vfstype = "msdosfs";
564 }
565
566 /* Construct the name of the appropriate mount command */
567 (void)snprintf(execname, sizeof(execname), "mount_%s", vfstype);
568
569 mnt_argv.c = -1;
570 append_arg(&mnt_argv, execname);
571 mangle(optbuf, &mnt_argv);
572 if (mountprog != NULL)
573 strcpy(execname, mountprog);
574
575 append_arg(&mnt_argv, strdup(spec));
576 append_arg(&mnt_argv, strdup(name));
577 append_arg(&mnt_argv, NULL);
578
579 if (debug) {
580 if (use_mountprog(vfstype))
581 printf("exec: %s", execname);
582 else
583 printf("mount -t %s", vfstype);
584 for (i = 1; i < mnt_argv.c; i++)
585 (void)printf(" %s", mnt_argv.a[i]);
586 (void)printf("\n");
587 return (0);
588 }
589
590 if (use_mountprog(vfstype)) {
591 ret = exec_mountprog(name, execname, mnt_argv.a);
592 } else {
593 ret = mount_fs(vfstype, mnt_argv.c, mnt_argv.a);
594 }
595
596 free(optbuf);
597
598 if (verbose) {
599 if (statfs(name, &sf) < 0) {
600 warn("statfs %s", name);
601 return (1);
602 }
603 if (fstab_style)
604 putfsent(&sf);
605 else
606 prmount(&sf);
607 }
608
609 return (ret);
610}
611
612void
613prmount(struct statfs *sfp)
614{
615 int flags;
616 unsigned int i;
617 struct opt *o;
618 struct passwd *pw;
619
620 (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname,
621 sfp->f_fstypename);
622
623 flags = sfp->f_flags & MNT_VISFLAGMASK;
624 for (o = optnames; flags && o->o_opt; o++)
625 if (flags & o->o_opt) {
626 (void)printf(", %s", o->o_name);
627 flags &= ~o->o_opt;
628 }
629 /*
630 * Inform when file system is mounted by an unprivileged user
631 * or privileged non-root user.
632 */
633 if ((flags & MNT_USER) != 0 || sfp->f_owner != 0) {
634 (void)printf(", mounted by ");
635 if ((pw = getpwuid(sfp->f_owner)) != NULL)
636 (void)printf("%s", pw->pw_name);
637 else
638 (void)printf("%d", sfp->f_owner);
639 }
640 if (verbose) {
641 if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0)
642 (void)printf(", writes: sync %ju async %ju",
643 (uintmax_t)sfp->f_syncwrites,
644 (uintmax_t)sfp->f_asyncwrites);
645 if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0)
646 (void)printf(", reads: sync %ju async %ju",
647 (uintmax_t)sfp->f_syncreads,
648 (uintmax_t)sfp->f_asyncreads);
649 if (sfp->f_fsid.val[0] != 0 || sfp->f_fsid.val[1] != 0) {
650 printf(", fsid ");
651 for (i = 0; i < sizeof(sfp->f_fsid); i++)
652 printf("%02x", ((u_char *)&sfp->f_fsid)[i]);
653 }
654 }
655 (void)printf(")\n");
656}
657
658struct statfs *
659getmntpt(const char *name)
660{
661 struct statfs *mntbuf;
662 int i, mntsize;
663
664 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
665 for (i = mntsize - 1; i >= 0; i--) {
666 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
667 strcmp(mntbuf[i].f_mntonname, name) == 0)
668 return (&mntbuf[i]);
669 }
670 return (NULL);
671}
672
673char *
674catopt(char *s0, const char *s1)
675{
676 size_t i;
677 char *cp;
678
679 if (s1 == NULL || *s1 == '\0')
680 return (s0);
681
682 if (s0 && *s0) {
683 i = strlen(s0) + strlen(s1) + 1 + 1;
684 if ((cp = malloc(i)) == NULL)
685 errx(1, "malloc failed");
686 (void)snprintf(cp, i, "%s,%s", s0, s1);
687 } else
688 cp = strdup(s1);
689
690 if (s0)
691 free(s0);
692 return (cp);
693}
694
695void
696mangle(char *options, struct cpa *a)
697{
698 char *p, *s, *val;
699
700 for (s = options; (p = strsep(&s, ",")) != NULL;)
701 if (*p != '\0') {
702 if (strcmp(p, "noauto") == 0) {
703 /*
704 * Do not pass noauto option to nmount().
705 * or external mount program. noauto is
706 * only used to prevent mounting a filesystem
707 * when 'mount -a' is specified, and is
708 * not a real mount option.
709 */
710 continue;
711 } else if (strcmp(p, "late") == 0) {
712 /*
713 * "late" is used to prevent certain file
714 * systems from being mounted before late
715 * in the boot cycle; for instance,
716 * loopback NFS mounts can't be mounted
717 * before mountd starts.
718 */
719 continue;
720 } else if (strncmp(p, "mountprog", 9) == 0) {
721 /*
722 * "mountprog" is used to force the use of
723 * userland mount programs.
724 */
725 val = strchr(p, '=');
726 if (val != NULL) {
727 ++val;
728 if (*val != '\0')
729 mountprog = strdup(val);
730 }
731
732 if (mountprog == NULL) {
733 errx(1, "Need value for -o mountprog");
734 }
735 continue;
736 } else if (strcmp(p, "userquota") == 0) {
737 continue;
738 } else if (strncmp(p, userquotaeq,
739 sizeof(userquotaeq) - 1) == 0) {
740 continue;
741 } else if (strcmp(p, "groupquota") == 0) {
742 continue;
743 } else if (strncmp(p, groupquotaeq,
744 sizeof(groupquotaeq) - 1) == 0) {
745 continue;
746 } else if (*p == '-') {
747 append_arg(a, p);
748 p = strchr(p, '=');
749 if (p != NULL) {
750 *p = '\0';
751 append_arg(a, p + 1);
752 }
753 } else {
754 append_arg(a, strdup("-o"));
755 append_arg(a, p);
756 }
757 }
758}
759
760
761char *
762update_options(char *opts, char *fstab, int curflags)
763{
764 char *o, *p;
765 char *cur;
766 char *expopt, *newopt, *tmpopt;
767
768 if (opts == NULL)
769 return (strdup(""));
770
771 /* remove meta options from list */
772 remopt(fstab, MOUNT_META_OPTION_FSTAB);
773 remopt(fstab, MOUNT_META_OPTION_CURRENT);
774 cur = flags2opts(curflags);
775
776 /*
777 * Expand all meta-options passed to us first.
778 */
779 expopt = NULL;
780 for (p = opts; (o = strsep(&p, ",")) != NULL;) {
781 if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0)
782 expopt = catopt(expopt, fstab);
783 else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0)
784 expopt = catopt(expopt, cur);
785 else
786 expopt = catopt(expopt, o);
787 }
788 free(cur);
789 free(opts);
790
791 /*
792 * Remove previous contradictory arguments. Given option "foo" we
793 * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo"
794 * and "foo" - so we can deal with possible options like "notice".
795 */
796 newopt = NULL;
797 for (p = expopt; (o = strsep(&p, ",")) != NULL;) {
798 if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL)
799 errx(1, "malloc failed");
800
801 strcpy(tmpopt, "no");
802 strcat(tmpopt, o);
803 remopt(newopt, tmpopt);
804 free(tmpopt);
805
806 if (strncmp("no", o, 2) == 0)
807 remopt(newopt, o+2);
808
809 newopt = catopt(newopt, o);
810 }
811 free(expopt);
812
813 return (newopt);
814}
815
816void
817remopt(char *string, const char *opt)
818{
819 char *o, *p, *r;
820
821 if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0')
822 return;
823
824 r = string;
825
826 for (p = string; (o = strsep(&p, ",")) != NULL;) {
827 if (strcmp(opt, o) != 0) {
828 if (*r == ',' && *o != '\0')
829 r++;
830 while ((*r++ = *o++) != '\0')
831 ;
832 *--r = ',';
833 }
834 }
835 *r = '\0';
836}
837
838void
839usage(void)
840{
841
842 (void)fprintf(stderr, "%s\n%s\n%s\n",
843"usage: mount [-adflpruvw] [-F fstab] [-o options] [-t ufs | external_type]",
844" mount [-dfpruvw] special | node",
845" mount [-dfpruvw] [-o options] [-t ufs | external_type] special node");
846 exit(1);
847}
848
849void
850putfsent(struct statfs *ent)
851{
852 struct fstab *fst;
853 char *opts;
854 int l;
855
856 opts = flags2opts(ent->f_flags);
857
858 if (strncmp(ent->f_mntfromname, "<below>", 7) == 0 ||
859 strncmp(ent->f_mntfromname, "<above>", 7) == 0) {
860 strcpy(ent->f_mntfromname, (strnstr(ent->f_mntfromname, ":", 8)
861 +1));
862 }
863
864 /*
865 * "rw" is not a real mount option; this is why we print NULL as "rw"
866 * if opts is still NULL here.
867 */
868 l = strlen(ent->f_mntfromname);
869 printf("%s%s%s%s", ent->f_mntfromname,
870 l < 8 ? "\t" : "",
871 l < 16 ? "\t" : "",
872 l < 24 ? "\t" : " ");
873 l = strlen(ent->f_mntonname);
874 printf("%s%s%s%s", ent->f_mntonname,
875 l < 8 ? "\t" : "",
876 l < 16 ? "\t" : "",
877 l < 24 ? "\t" : " ");
878 printf("%s\t", ent->f_fstypename);
879 if (opts == NULL) {
880 printf("%s\t", "rw");
881 } else {
882 l = strlen(opts);
883 printf("%s%s", opts,
884 l < 8 ? "\t" : " ");
885 }
886 free(opts);
887
888 if ((fst = getfsspec(ent->f_mntfromname)))
889 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
890 else if ((fst = getfsfile(ent->f_mntonname)))
891 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
892 else if (strcmp(ent->f_fstypename, "ufs") == 0) {
893 if (strcmp(ent->f_mntonname, "/") == 0)
894 printf("\t1 1\n");
895 else
896 printf("\t2 2\n");
897 } else
898 printf("\t0 0\n");
899}
900
901
902char *
903flags2opts(int flags)
904{
905 char *res;
906
907 res = NULL;
908
909 if (flags & MNT_RDONLY) res = catopt(res, "ro");
910 if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync");
911 if (flags & MNT_NOEXEC) res = catopt(res, "noexec");
912 if (flags & MNT_NOSUID) res = catopt(res, "nosuid");
913 if (flags & MNT_UNION) res = catopt(res, "union");
914 if (flags & MNT_ASYNC) res = catopt(res, "async");
915 if (flags & MNT_NOATIME) res = catopt(res, "noatime");
916 if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr");
917 if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw");
918 if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow");
919 if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir");
920 if (flags & MNT_MULTILABEL) res = catopt(res, "multilabel");
921 if (flags & MNT_ACLS) res = catopt(res, "acls");
922 if (flags & MNT_NFS4ACLS) res = catopt(res, "nfsv4acls");
921
922 return (res);
923}
923
924 return (res);
925}