Deleted Added
full compact
mount.c (96707) mount.c (101205)
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
35static const 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#if 0
42static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95";
43#endif
44static const char rcsid[] =
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
35static const 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#if 0
42static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95";
43#endif
44static const char rcsid[] =
45 "$FreeBSD: head/sbin/mount/mount.c 96707 2002-05-16 04:10:46Z trhodes $";
45 "$FreeBSD: head/sbin/mount/mount.c 101205 2002-08-02 07:02:51Z rwatson $";
46#endif /* not lint */
47
48#include <sys/param.h>
49#include <sys/mount.h>
50#include <sys/stat.h>
51#include <sys/wait.h>
52
53#include <ctype.h>
54#include <err.h>
55#include <errno.h>
56#include <fstab.h>
57#include <pwd.h>
58#include <signal.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <unistd.h>
63
64#include "extern.h"
65#include "mntopts.h"
66#include "pathnames.h"
67
68/* `meta' options */
69#define MOUNT_META_OPTION_FSTAB "fstab"
70#define MOUNT_META_OPTION_CURRENT "current"
71
72int debug, fstab_style, verbose;
73
74char *catopt(char *, const char *);
75struct statfs *getmntpt(const char *);
76int hasopt(const char *, const char *);
77int ismounted(struct fstab *, struct statfs *, int);
78int isremountable(const char *);
79void mangle(char *, int *, const char **);
80char *update_options(char *, char *, int);
81int mountfs(const char *, const char *, const char *,
82 int, const char *, const char *);
83void remopt(char *, const char *);
84void prmount(struct statfs *);
85void putfsent(const struct statfs *);
86void usage(void);
87char *flags2opts(int);
88
89/* Map from mount options to printable formats. */
90static struct opt {
91 int o_opt;
92 const char *o_name;
93} optnames[] = {
94 { MNT_ASYNC, "asynchronous" },
95 { MNT_EXPORTED, "NFS exported" },
96 { MNT_LOCAL, "local" },
97 { MNT_NOATIME, "noatime" },
98 { MNT_NODEV, "nodev" },
99 { MNT_NOEXEC, "noexec" },
100 { MNT_NOSUID, "nosuid" },
101 { MNT_NOSYMFOLLOW, "nosymfollow" },
102 { MNT_QUOTA, "with quotas" },
103 { MNT_RDONLY, "read-only" },
104 { MNT_SYNCHRONOUS, "synchronous" },
105 { MNT_UNION, "union" },
106 { MNT_NOCLUSTERR, "noclusterr" },
107 { MNT_NOCLUSTERW, "noclusterw" },
108 { MNT_SUIDDIR, "suiddir" },
109 { MNT_SOFTDEP, "soft-updates" },
46#endif /* not lint */
47
48#include <sys/param.h>
49#include <sys/mount.h>
50#include <sys/stat.h>
51#include <sys/wait.h>
52
53#include <ctype.h>
54#include <err.h>
55#include <errno.h>
56#include <fstab.h>
57#include <pwd.h>
58#include <signal.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <unistd.h>
63
64#include "extern.h"
65#include "mntopts.h"
66#include "pathnames.h"
67
68/* `meta' options */
69#define MOUNT_META_OPTION_FSTAB "fstab"
70#define MOUNT_META_OPTION_CURRENT "current"
71
72int debug, fstab_style, verbose;
73
74char *catopt(char *, const char *);
75struct statfs *getmntpt(const char *);
76int hasopt(const char *, const char *);
77int ismounted(struct fstab *, struct statfs *, int);
78int isremountable(const char *);
79void mangle(char *, int *, const char **);
80char *update_options(char *, char *, int);
81int mountfs(const char *, const char *, const char *,
82 int, const char *, const char *);
83void remopt(char *, const char *);
84void prmount(struct statfs *);
85void putfsent(const struct statfs *);
86void usage(void);
87char *flags2opts(int);
88
89/* Map from mount options to printable formats. */
90static struct opt {
91 int o_opt;
92 const char *o_name;
93} optnames[] = {
94 { MNT_ASYNC, "asynchronous" },
95 { MNT_EXPORTED, "NFS exported" },
96 { MNT_LOCAL, "local" },
97 { MNT_NOATIME, "noatime" },
98 { MNT_NODEV, "nodev" },
99 { MNT_NOEXEC, "noexec" },
100 { MNT_NOSUID, "nosuid" },
101 { MNT_NOSYMFOLLOW, "nosymfollow" },
102 { MNT_QUOTA, "with quotas" },
103 { MNT_RDONLY, "read-only" },
104 { MNT_SYNCHRONOUS, "synchronous" },
105 { MNT_UNION, "union" },
106 { MNT_NOCLUSTERR, "noclusterr" },
107 { MNT_NOCLUSTERW, "noclusterw" },
108 { MNT_SUIDDIR, "suiddir" },
109 { MNT_SOFTDEP, "soft-updates" },
110 { MNT_MULTILABEL, "multilabel" },
110 { 0, NULL }
111};
112
113/*
114 * List of VFS types that can be remounted without becoming mounted on top
115 * of each other.
116 * XXX Is this list correct?
117 */
118static const char *
119remountable_fs_names[] = {
120 "ufs", "ffs", "ext2fs",
121 0
122};
123
124int
125main(argc, argv)
126 int argc;
127 char * const argv[];
128{
129 const char *mntfromname, **vfslist, *vfstype;
130 struct fstab *fs;
131 struct statfs *mntbuf;
132 FILE *mountdfp;
133 pid_t pid;
134 int all, ch, i, init_flags, mntsize, rval, have_fstab;
135 char *cp, *ep, *options;
136
137 all = init_flags = 0;
138 options = NULL;
139 vfslist = NULL;
140 vfstype = "ufs";
141 while ((ch = getopt(argc, argv, "adfo:prwt:uv")) != -1)
142 switch (ch) {
143 case 'a':
144 all = 1;
145 break;
146 case 'd':
147 debug = 1;
148 break;
149 case 'f':
150 init_flags |= MNT_FORCE;
151 break;
152 case 'o':
153 if (*optarg)
154 options = catopt(options, optarg);
155 break;
156 case 'p':
157 fstab_style = 1;
158 verbose = 1;
159 break;
160 case 'r':
161 options = catopt(options, "ro");
162 break;
163 case 't':
164 if (vfslist != NULL)
165 errx(1, "only one -t option may be specified");
166 vfslist = makevfslist(optarg);
167 vfstype = optarg;
168 break;
169 case 'u':
170 init_flags |= MNT_UPDATE;
171 break;
172 case 'v':
173 verbose = 1;
174 break;
175 case 'w':
176 options = catopt(options, "noro");
177 break;
178 case '?':
179 default:
180 usage();
181 /* NOTREACHED */
182 }
183 argc -= optind;
184 argv += optind;
185
186#define BADTYPE(type) \
187 (strcmp(type, FSTAB_RO) && \
188 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
189
190 rval = 0;
191 switch (argc) {
192 case 0:
193 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
194 err(1, "getmntinfo");
195 if (all) {
196 while ((fs = getfsent()) != NULL) {
197 if (BADTYPE(fs->fs_type))
198 continue;
199 if (checkvfsname(fs->fs_vfstype, vfslist))
200 continue;
201 if (hasopt(fs->fs_mntops, "noauto"))
202 continue;
203 if (!(init_flags & MNT_UPDATE) &&
204 ismounted(fs, mntbuf, mntsize))
205 continue;
206 if (mountfs(fs->fs_vfstype, fs->fs_spec,
207 fs->fs_file, init_flags, options,
208 fs->fs_mntops))
209 rval = 1;
210 }
211 } else if (fstab_style) {
212 for (i = 0; i < mntsize; i++) {
213 if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
214 continue;
215 putfsent(&mntbuf[i]);
216 }
217 } else {
218 for (i = 0; i < mntsize; i++) {
219 if (checkvfsname(mntbuf[i].f_fstypename,
220 vfslist))
221 continue;
222 prmount(&mntbuf[i]);
223 }
224 }
225 exit(rval);
226 case 1:
227 if (vfslist != NULL)
228 usage();
229
230 if (init_flags & MNT_UPDATE) {
231 mntfromname = NULL;
232 have_fstab = 0;
233 if ((mntbuf = getmntpt(*argv)) == NULL)
234 errx(1, "not currently mounted %s", *argv);
235 /*
236 * Only get the mntflags from fstab if both mntpoint
237 * and mntspec are identical. Also handle the special
238 * case where just '/' is mounted and 'spec' is not
239 * identical with the one from fstab ('/dev' is missing
240 * in the spec-string at boot-time).
241 */
242 if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) {
243 if (strcmp(fs->fs_spec,
244 mntbuf->f_mntfromname) == 0 &&
245 strcmp(fs->fs_file,
246 mntbuf->f_mntonname) == 0) {
247 have_fstab = 1;
248 mntfromname = mntbuf->f_mntfromname;
249 } else if (argv[0][0] == '/' &&
250 argv[0][1] == '\0') {
251 fs = getfsfile("/");
252 have_fstab = 1;
253 mntfromname = fs->fs_spec;
254 }
255 }
256 if (have_fstab) {
257 options = update_options(options, fs->fs_mntops,
258 mntbuf->f_flags);
259 } else {
260 mntfromname = mntbuf->f_mntfromname;
261 options = update_options(options, NULL,
262 mntbuf->f_flags);
263 }
264 rval = mountfs(mntbuf->f_fstypename, mntfromname,
265 mntbuf->f_mntonname, init_flags, options, 0);
266 break;
267 }
268 rmslashes(*argv, *argv);
269 if ((fs = getfsfile(*argv)) == NULL &&
270 (fs = getfsspec(*argv)) == NULL)
271 errx(1, "%s: unknown special file or filesystem",
272 *argv);
273 if (BADTYPE(fs->fs_type))
274 errx(1, "%s has unknown filesystem type",
275 *argv);
276 rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file,
277 init_flags, options, fs->fs_mntops);
278 break;
279 case 2:
280 /*
281 * If -t flag has not been specified, the path cannot be
282 * found, spec contains either a ':' or a '@', then assume
283 * that an NFS filesystem is being specified ala Sun.
284 * Check if the hostname contains only allowed characters
285 * to reduce false positives. IPv6 addresses containing
286 * ':' will be correctly parsed only if the separator is '@'.
287 * The definition of a valid hostname is taken from RFC 1034.
288 */
289 if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL) ||
290 ((ep = strchr(argv[0], ':')) != NULL)) {
291 if (*ep == '@') {
292 cp = ep + 1;
293 ep = cp + strlen(cp);
294 } else
295 cp = argv[0];
296 while (cp != ep) {
297 if (!isdigit(*cp) && !isalpha(*cp) &&
298 *cp != '.' && *cp != '-' && *cp != ':')
299 break;
300 cp++;
301 }
302 if (cp == ep)
303 vfstype = "nfs";
304 }
305 rval = mountfs(vfstype,
306 argv[0], argv[1], init_flags, options, NULL);
307 break;
308 default:
309 usage();
310 /* NOTREACHED */
311 }
312
313 /*
314 * If the mount was successfully, and done by root, tell mountd the
315 * good news. Pid checks are probably unnecessary, but don't hurt.
316 */
317 if (rval == 0 && getuid() == 0 &&
318 (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
319 if (fscanf(mountdfp, "%d", &pid) == 1 &&
320 pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
321 err(1, "signal mountd");
322 (void)fclose(mountdfp);
323 }
324
325 exit(rval);
326}
327
328int
329ismounted(fs, mntbuf, mntsize)
330 struct fstab *fs;
331 struct statfs *mntbuf;
332 int mntsize;
333{
334 int i;
335
336 if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0')
337 /* the root filesystem can always be remounted */
338 return (0);
339
340 for (i = mntsize - 1; i >= 0; --i)
341 if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 &&
342 (!isremountable(fs->fs_vfstype) ||
343 strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0))
344 return (1);
345 return (0);
346}
347
348int
349isremountable(vfsname)
350 const char *vfsname;
351{
352 const char **cp;
353
354 for (cp = remountable_fs_names; *cp; cp++)
355 if (strcmp(*cp, vfsname) == 0)
356 return (1);
357 return (0);
358}
359
360int
361hasopt(mntopts, option)
362 const char *mntopts, *option;
363{
364 int negative, found;
365 char *opt, *optbuf;
366
367 if (option[0] == 'n' && option[1] == 'o') {
368 negative = 1;
369 option += 2;
370 } else
371 negative = 0;
372 optbuf = strdup(mntopts);
373 found = 0;
374 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
375 if (opt[0] == 'n' && opt[1] == 'o') {
376 if (!strcasecmp(opt + 2, option))
377 found = negative;
378 } else if (!strcasecmp(opt, option))
379 found = !negative;
380 }
381 free(optbuf);
382 return (found);
383}
384
385int
386mountfs(vfstype, spec, name, flags, options, mntopts)
387 const char *vfstype, *spec, *name, *options, *mntopts;
388 int flags;
389{
390 /* List of directories containing mount_xxx subcommands. */
391 static const char *edirs[] = {
392 _PATH_SBIN,
393 _PATH_USRSBIN,
394 NULL
395 };
396 const char *argv[100], **edir;
397 struct statfs sf;
398 pid_t pid;
399 int argc, i, status;
400 char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
401
402#if __GNUC__
403 (void)&optbuf;
404 (void)&name;
405#endif
406
407 /* resolve the mountpoint with realpath(3) */
408 (void)checkpath(name, mntpath);
409 name = mntpath;
410
411 if (mntopts == NULL)
412 mntopts = "";
413 if (options == NULL) {
414 if (*mntopts == '\0') {
415 options = "rw";
416 } else {
417 options = mntopts;
418 mntopts = "";
419 }
420 }
421 optbuf = catopt(strdup(mntopts), options);
422
423 if (strcmp(name, "/") == 0)
424 flags |= MNT_UPDATE;
425 if (flags & MNT_FORCE)
426 optbuf = catopt(optbuf, "force");
427 if (flags & MNT_RDONLY)
428 optbuf = catopt(optbuf, "ro");
429 /*
430 * XXX
431 * The mount_mfs (newfs) command uses -o to select the
432 * optimization mode. We don't pass the default "-o rw"
433 * for that reason.
434 */
435 if (flags & MNT_UPDATE)
436 optbuf = catopt(optbuf, "update");
437
438 /* Compatibility glue. */
439 if (strcmp(vfstype, "msdos") == 0)
440 vfstype = "msdosfs";
441
442 argc = 0;
443 argv[argc++] = vfstype;
444 mangle(optbuf, &argc, argv);
445 argv[argc++] = spec;
446 argv[argc++] = name;
447 argv[argc] = NULL;
448
449 if (debug) {
450 (void)printf("exec: mount_%s", vfstype);
451 for (i = 1; i < argc; i++)
452 (void)printf(" %s", argv[i]);
453 (void)printf("\n");
454 return (0);
455 }
456
457 switch (pid = fork()) {
458 case -1: /* Error. */
459 warn("fork");
460 free(optbuf);
461 return (1);
462 case 0: /* Child. */
463 if (strcmp(vfstype, "ufs") == 0)
464 exit(mount_ufs(argc, (char * const *) argv));
465
466 /* Go find an executable. */
467 for (edir = edirs; *edir; edir++) {
468 (void)snprintf(execname,
469 sizeof(execname), "%s/mount_%s", *edir, vfstype);
470 execv(execname, (char * const *)argv);
471 }
472 if (errno == ENOENT) {
473 int len = 0;
474 char *cp;
475 for (edir = edirs; *edir; edir++)
476 len += strlen(*edir) + 2; /* ", " */
477 if ((cp = malloc(len)) == NULL)
478 errx(1, "malloc failed");
479 cp[0] = '\0';
480 for (edir = edirs; *edir; edir++) {
481 strcat(cp, *edir);
482 if (edir[1] != NULL)
483 strcat(cp, ", ");
484 }
485 warn("exec mount_%s not found in %s", vfstype, cp);
486 }
487 exit(1);
488 /* NOTREACHED */
489 default: /* Parent. */
490 free(optbuf);
491
492 if (waitpid(pid, &status, 0) < 0) {
493 warn("waitpid");
494 return (1);
495 }
496
497 if (WIFEXITED(status)) {
498 if (WEXITSTATUS(status) != 0)
499 return (WEXITSTATUS(status));
500 } else if (WIFSIGNALED(status)) {
501 warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
502 return (1);
503 }
504
505 if (verbose) {
506 if (statfs(name, &sf) < 0) {
507 warn("statfs %s", name);
508 return (1);
509 }
510 if (fstab_style)
511 putfsent(&sf);
512 else
513 prmount(&sf);
514 }
515 break;
516 }
517
518 return (0);
519}
520
521void
522prmount(sfp)
523 struct statfs *sfp;
524{
525 int flags;
526 struct opt *o;
527 struct passwd *pw;
528
529 (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname,
530 sfp->f_fstypename);
531
532 flags = sfp->f_flags & MNT_VISFLAGMASK;
533 for (o = optnames; flags && o->o_opt; o++)
534 if (flags & o->o_opt) {
535 (void)printf(", %s", o->o_name);
536 flags &= ~o->o_opt;
537 }
538 if (sfp->f_owner) {
539 (void)printf(", mounted by ");
540 if ((pw = getpwuid(sfp->f_owner)) != NULL)
541 (void)printf("%s", pw->pw_name);
542 else
543 (void)printf("%d", sfp->f_owner);
544 }
545 if (verbose) {
546 if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0)
547 (void)printf(", writes: sync %ld async %ld",
548 sfp->f_syncwrites, sfp->f_asyncwrites);
549 if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0)
550 (void)printf(", reads: sync %ld async %ld",
551 sfp->f_syncreads, sfp->f_asyncreads);
552 }
553 (void)printf(")\n");
554}
555
556struct statfs *
557getmntpt(name)
558 const char *name;
559{
560 struct statfs *mntbuf;
561 int i, mntsize;
562
563 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
564 for (i = mntsize - 1; i >= 0; i--) {
565 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
566 strcmp(mntbuf[i].f_mntonname, name) == 0)
567 return (&mntbuf[i]);
568 }
569 return (NULL);
570}
571
572char *
573catopt(s0, s1)
574 char *s0;
575 const char *s1;
576{
577 size_t i;
578 char *cp;
579
580 if (s1 == NULL || *s1 == '\0')
581 return s0;
582
583 if (s0 && *s0) {
584 i = strlen(s0) + strlen(s1) + 1 + 1;
585 if ((cp = malloc(i)) == NULL)
586 errx(1, "malloc failed");
587 (void)snprintf(cp, i, "%s,%s", s0, s1);
588 } else
589 cp = strdup(s1);
590
591 if (s0)
592 free(s0);
593 return (cp);
594}
595
596void
597mangle(options, argcp, argv)
598 char *options;
599 int *argcp;
600 const char **argv;
601{
602 char *p, *s;
603 int argc;
604
605 argc = *argcp;
606 for (s = options; (p = strsep(&s, ",")) != NULL;)
607 if (*p != '\0') {
608 if (*p == '-') {
609 argv[argc++] = p;
610 p = strchr(p, '=');
611 if (p) {
612 *p = '\0';
613 argv[argc++] = p+1;
614 }
615 } else if (strcmp(p, "rw") != 0) {
616 argv[argc++] = "-o";
617 argv[argc++] = p;
618 }
619 }
620
621 *argcp = argc;
622}
623
624
625char *
626update_options(opts, fstab, curflags)
627 char *opts;
628 char *fstab;
629 int curflags;
630{
631 char *o, *p;
632 char *cur;
633 char *expopt, *newopt, *tmpopt;
634
635 if (opts == NULL)
636 return strdup("");
637
638 /* remove meta options from list */
639 remopt(fstab, MOUNT_META_OPTION_FSTAB);
640 remopt(fstab, MOUNT_META_OPTION_CURRENT);
641 cur = flags2opts(curflags);
642
643 /*
644 * Expand all meta-options passed to us first.
645 */
646 expopt = NULL;
647 for (p = opts; (o = strsep(&p, ",")) != NULL;) {
648 if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0)
649 expopt = catopt(expopt, fstab);
650 else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0)
651 expopt = catopt(expopt, cur);
652 else
653 expopt = catopt(expopt, o);
654 }
655 free(cur);
656 free(opts);
657
658 /*
659 * Remove previous contradictory arguments. Given option "foo" we
660 * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo"
661 * and "foo" - so we can deal with possible options like "notice".
662 */
663 newopt = NULL;
664 for (p = expopt; (o = strsep(&p, ",")) != NULL;) {
665 if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL)
666 errx(1, "malloc failed");
667
668 strcpy(tmpopt, "no");
669 strcat(tmpopt, o);
670 remopt(newopt, tmpopt);
671 free(tmpopt);
672
673 if (strncmp("no", o, 2) == 0)
674 remopt(newopt, o+2);
675
676 newopt = catopt(newopt, o);
677 }
678 free(expopt);
679
680 return newopt;
681}
682
683void
684remopt(string, opt)
685 char *string;
686 const char *opt;
687{
688 char *o, *p, *r;
689
690 if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0')
691 return;
692
693 r = string;
694
695 for (p = string; (o = strsep(&p, ",")) != NULL;) {
696 if (strcmp(opt, o) != 0) {
697 if (*r == ',' && *o != '\0')
698 r++;
699 while ((*r++ = *o++) != '\0')
700 ;
701 *--r = ',';
702 }
703 }
704 *r = '\0';
705}
706
707void
708usage()
709{
710
711 (void)fprintf(stderr, "%s\n%s\n%s\n",
712"usage: mount [-dfpruvw] [-o options] [-t ufs | external_type] special node",
713" mount [-adfpruvw] [-t ufs | external_type]",
714" mount [-dfpruvw] special | node");
715 exit(1);
716}
717
718void
719putfsent(ent)
720 const struct statfs *ent;
721{
722 struct fstab *fst;
723 char *opts;
724
725 opts = flags2opts(ent->f_flags);
726 printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname,
727 ent->f_fstypename, opts);
728 free(opts);
729
730 if ((fst = getfsspec(ent->f_mntfromname)))
731 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
732 else if ((fst = getfsfile(ent->f_mntonname)))
733 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
734 else if (strcmp(ent->f_fstypename, "ufs") == 0) {
735 if (strcmp(ent->f_mntonname, "/") == 0)
736 printf("\t1 1\n");
737 else
738 printf("\t2 2\n");
739 } else
740 printf("\t0 0\n");
741}
742
743
744char *
745flags2opts(flags)
746 int flags;
747{
748 char *res;
749
750 res = NULL;
751
752 res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw");
753
754 if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync");
755 if (flags & MNT_NOEXEC) res = catopt(res, "noexec");
756 if (flags & MNT_NOSUID) res = catopt(res, "nosuid");
757 if (flags & MNT_NODEV) res = catopt(res, "nodev");
758 if (flags & MNT_UNION) res = catopt(res, "union");
759 if (flags & MNT_ASYNC) res = catopt(res, "async");
760 if (flags & MNT_NOATIME) res = catopt(res, "noatime");
761 if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr");
762 if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw");
763 if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow");
764 if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir");
111 { 0, NULL }
112};
113
114/*
115 * List of VFS types that can be remounted without becoming mounted on top
116 * of each other.
117 * XXX Is this list correct?
118 */
119static const char *
120remountable_fs_names[] = {
121 "ufs", "ffs", "ext2fs",
122 0
123};
124
125int
126main(argc, argv)
127 int argc;
128 char * const argv[];
129{
130 const char *mntfromname, **vfslist, *vfstype;
131 struct fstab *fs;
132 struct statfs *mntbuf;
133 FILE *mountdfp;
134 pid_t pid;
135 int all, ch, i, init_flags, mntsize, rval, have_fstab;
136 char *cp, *ep, *options;
137
138 all = init_flags = 0;
139 options = NULL;
140 vfslist = NULL;
141 vfstype = "ufs";
142 while ((ch = getopt(argc, argv, "adfo:prwt:uv")) != -1)
143 switch (ch) {
144 case 'a':
145 all = 1;
146 break;
147 case 'd':
148 debug = 1;
149 break;
150 case 'f':
151 init_flags |= MNT_FORCE;
152 break;
153 case 'o':
154 if (*optarg)
155 options = catopt(options, optarg);
156 break;
157 case 'p':
158 fstab_style = 1;
159 verbose = 1;
160 break;
161 case 'r':
162 options = catopt(options, "ro");
163 break;
164 case 't':
165 if (vfslist != NULL)
166 errx(1, "only one -t option may be specified");
167 vfslist = makevfslist(optarg);
168 vfstype = optarg;
169 break;
170 case 'u':
171 init_flags |= MNT_UPDATE;
172 break;
173 case 'v':
174 verbose = 1;
175 break;
176 case 'w':
177 options = catopt(options, "noro");
178 break;
179 case '?':
180 default:
181 usage();
182 /* NOTREACHED */
183 }
184 argc -= optind;
185 argv += optind;
186
187#define BADTYPE(type) \
188 (strcmp(type, FSTAB_RO) && \
189 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
190
191 rval = 0;
192 switch (argc) {
193 case 0:
194 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
195 err(1, "getmntinfo");
196 if (all) {
197 while ((fs = getfsent()) != NULL) {
198 if (BADTYPE(fs->fs_type))
199 continue;
200 if (checkvfsname(fs->fs_vfstype, vfslist))
201 continue;
202 if (hasopt(fs->fs_mntops, "noauto"))
203 continue;
204 if (!(init_flags & MNT_UPDATE) &&
205 ismounted(fs, mntbuf, mntsize))
206 continue;
207 if (mountfs(fs->fs_vfstype, fs->fs_spec,
208 fs->fs_file, init_flags, options,
209 fs->fs_mntops))
210 rval = 1;
211 }
212 } else if (fstab_style) {
213 for (i = 0; i < mntsize; i++) {
214 if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
215 continue;
216 putfsent(&mntbuf[i]);
217 }
218 } else {
219 for (i = 0; i < mntsize; i++) {
220 if (checkvfsname(mntbuf[i].f_fstypename,
221 vfslist))
222 continue;
223 prmount(&mntbuf[i]);
224 }
225 }
226 exit(rval);
227 case 1:
228 if (vfslist != NULL)
229 usage();
230
231 if (init_flags & MNT_UPDATE) {
232 mntfromname = NULL;
233 have_fstab = 0;
234 if ((mntbuf = getmntpt(*argv)) == NULL)
235 errx(1, "not currently mounted %s", *argv);
236 /*
237 * Only get the mntflags from fstab if both mntpoint
238 * and mntspec are identical. Also handle the special
239 * case where just '/' is mounted and 'spec' is not
240 * identical with the one from fstab ('/dev' is missing
241 * in the spec-string at boot-time).
242 */
243 if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) {
244 if (strcmp(fs->fs_spec,
245 mntbuf->f_mntfromname) == 0 &&
246 strcmp(fs->fs_file,
247 mntbuf->f_mntonname) == 0) {
248 have_fstab = 1;
249 mntfromname = mntbuf->f_mntfromname;
250 } else if (argv[0][0] == '/' &&
251 argv[0][1] == '\0') {
252 fs = getfsfile("/");
253 have_fstab = 1;
254 mntfromname = fs->fs_spec;
255 }
256 }
257 if (have_fstab) {
258 options = update_options(options, fs->fs_mntops,
259 mntbuf->f_flags);
260 } else {
261 mntfromname = mntbuf->f_mntfromname;
262 options = update_options(options, NULL,
263 mntbuf->f_flags);
264 }
265 rval = mountfs(mntbuf->f_fstypename, mntfromname,
266 mntbuf->f_mntonname, init_flags, options, 0);
267 break;
268 }
269 rmslashes(*argv, *argv);
270 if ((fs = getfsfile(*argv)) == NULL &&
271 (fs = getfsspec(*argv)) == NULL)
272 errx(1, "%s: unknown special file or filesystem",
273 *argv);
274 if (BADTYPE(fs->fs_type))
275 errx(1, "%s has unknown filesystem type",
276 *argv);
277 rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file,
278 init_flags, options, fs->fs_mntops);
279 break;
280 case 2:
281 /*
282 * If -t flag has not been specified, the path cannot be
283 * found, spec contains either a ':' or a '@', then assume
284 * that an NFS filesystem is being specified ala Sun.
285 * Check if the hostname contains only allowed characters
286 * to reduce false positives. IPv6 addresses containing
287 * ':' will be correctly parsed only if the separator is '@'.
288 * The definition of a valid hostname is taken from RFC 1034.
289 */
290 if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL) ||
291 ((ep = strchr(argv[0], ':')) != NULL)) {
292 if (*ep == '@') {
293 cp = ep + 1;
294 ep = cp + strlen(cp);
295 } else
296 cp = argv[0];
297 while (cp != ep) {
298 if (!isdigit(*cp) && !isalpha(*cp) &&
299 *cp != '.' && *cp != '-' && *cp != ':')
300 break;
301 cp++;
302 }
303 if (cp == ep)
304 vfstype = "nfs";
305 }
306 rval = mountfs(vfstype,
307 argv[0], argv[1], init_flags, options, NULL);
308 break;
309 default:
310 usage();
311 /* NOTREACHED */
312 }
313
314 /*
315 * If the mount was successfully, and done by root, tell mountd the
316 * good news. Pid checks are probably unnecessary, but don't hurt.
317 */
318 if (rval == 0 && getuid() == 0 &&
319 (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) {
320 if (fscanf(mountdfp, "%d", &pid) == 1 &&
321 pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH)
322 err(1, "signal mountd");
323 (void)fclose(mountdfp);
324 }
325
326 exit(rval);
327}
328
329int
330ismounted(fs, mntbuf, mntsize)
331 struct fstab *fs;
332 struct statfs *mntbuf;
333 int mntsize;
334{
335 int i;
336
337 if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0')
338 /* the root filesystem can always be remounted */
339 return (0);
340
341 for (i = mntsize - 1; i >= 0; --i)
342 if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 &&
343 (!isremountable(fs->fs_vfstype) ||
344 strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0))
345 return (1);
346 return (0);
347}
348
349int
350isremountable(vfsname)
351 const char *vfsname;
352{
353 const char **cp;
354
355 for (cp = remountable_fs_names; *cp; cp++)
356 if (strcmp(*cp, vfsname) == 0)
357 return (1);
358 return (0);
359}
360
361int
362hasopt(mntopts, option)
363 const char *mntopts, *option;
364{
365 int negative, found;
366 char *opt, *optbuf;
367
368 if (option[0] == 'n' && option[1] == 'o') {
369 negative = 1;
370 option += 2;
371 } else
372 negative = 0;
373 optbuf = strdup(mntopts);
374 found = 0;
375 for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
376 if (opt[0] == 'n' && opt[1] == 'o') {
377 if (!strcasecmp(opt + 2, option))
378 found = negative;
379 } else if (!strcasecmp(opt, option))
380 found = !negative;
381 }
382 free(optbuf);
383 return (found);
384}
385
386int
387mountfs(vfstype, spec, name, flags, options, mntopts)
388 const char *vfstype, *spec, *name, *options, *mntopts;
389 int flags;
390{
391 /* List of directories containing mount_xxx subcommands. */
392 static const char *edirs[] = {
393 _PATH_SBIN,
394 _PATH_USRSBIN,
395 NULL
396 };
397 const char *argv[100], **edir;
398 struct statfs sf;
399 pid_t pid;
400 int argc, i, status;
401 char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
402
403#if __GNUC__
404 (void)&optbuf;
405 (void)&name;
406#endif
407
408 /* resolve the mountpoint with realpath(3) */
409 (void)checkpath(name, mntpath);
410 name = mntpath;
411
412 if (mntopts == NULL)
413 mntopts = "";
414 if (options == NULL) {
415 if (*mntopts == '\0') {
416 options = "rw";
417 } else {
418 options = mntopts;
419 mntopts = "";
420 }
421 }
422 optbuf = catopt(strdup(mntopts), options);
423
424 if (strcmp(name, "/") == 0)
425 flags |= MNT_UPDATE;
426 if (flags & MNT_FORCE)
427 optbuf = catopt(optbuf, "force");
428 if (flags & MNT_RDONLY)
429 optbuf = catopt(optbuf, "ro");
430 /*
431 * XXX
432 * The mount_mfs (newfs) command uses -o to select the
433 * optimization mode. We don't pass the default "-o rw"
434 * for that reason.
435 */
436 if (flags & MNT_UPDATE)
437 optbuf = catopt(optbuf, "update");
438
439 /* Compatibility glue. */
440 if (strcmp(vfstype, "msdos") == 0)
441 vfstype = "msdosfs";
442
443 argc = 0;
444 argv[argc++] = vfstype;
445 mangle(optbuf, &argc, argv);
446 argv[argc++] = spec;
447 argv[argc++] = name;
448 argv[argc] = NULL;
449
450 if (debug) {
451 (void)printf("exec: mount_%s", vfstype);
452 for (i = 1; i < argc; i++)
453 (void)printf(" %s", argv[i]);
454 (void)printf("\n");
455 return (0);
456 }
457
458 switch (pid = fork()) {
459 case -1: /* Error. */
460 warn("fork");
461 free(optbuf);
462 return (1);
463 case 0: /* Child. */
464 if (strcmp(vfstype, "ufs") == 0)
465 exit(mount_ufs(argc, (char * const *) argv));
466
467 /* Go find an executable. */
468 for (edir = edirs; *edir; edir++) {
469 (void)snprintf(execname,
470 sizeof(execname), "%s/mount_%s", *edir, vfstype);
471 execv(execname, (char * const *)argv);
472 }
473 if (errno == ENOENT) {
474 int len = 0;
475 char *cp;
476 for (edir = edirs; *edir; edir++)
477 len += strlen(*edir) + 2; /* ", " */
478 if ((cp = malloc(len)) == NULL)
479 errx(1, "malloc failed");
480 cp[0] = '\0';
481 for (edir = edirs; *edir; edir++) {
482 strcat(cp, *edir);
483 if (edir[1] != NULL)
484 strcat(cp, ", ");
485 }
486 warn("exec mount_%s not found in %s", vfstype, cp);
487 }
488 exit(1);
489 /* NOTREACHED */
490 default: /* Parent. */
491 free(optbuf);
492
493 if (waitpid(pid, &status, 0) < 0) {
494 warn("waitpid");
495 return (1);
496 }
497
498 if (WIFEXITED(status)) {
499 if (WEXITSTATUS(status) != 0)
500 return (WEXITSTATUS(status));
501 } else if (WIFSIGNALED(status)) {
502 warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]);
503 return (1);
504 }
505
506 if (verbose) {
507 if (statfs(name, &sf) < 0) {
508 warn("statfs %s", name);
509 return (1);
510 }
511 if (fstab_style)
512 putfsent(&sf);
513 else
514 prmount(&sf);
515 }
516 break;
517 }
518
519 return (0);
520}
521
522void
523prmount(sfp)
524 struct statfs *sfp;
525{
526 int flags;
527 struct opt *o;
528 struct passwd *pw;
529
530 (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname,
531 sfp->f_fstypename);
532
533 flags = sfp->f_flags & MNT_VISFLAGMASK;
534 for (o = optnames; flags && o->o_opt; o++)
535 if (flags & o->o_opt) {
536 (void)printf(", %s", o->o_name);
537 flags &= ~o->o_opt;
538 }
539 if (sfp->f_owner) {
540 (void)printf(", mounted by ");
541 if ((pw = getpwuid(sfp->f_owner)) != NULL)
542 (void)printf("%s", pw->pw_name);
543 else
544 (void)printf("%d", sfp->f_owner);
545 }
546 if (verbose) {
547 if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0)
548 (void)printf(", writes: sync %ld async %ld",
549 sfp->f_syncwrites, sfp->f_asyncwrites);
550 if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0)
551 (void)printf(", reads: sync %ld async %ld",
552 sfp->f_syncreads, sfp->f_asyncreads);
553 }
554 (void)printf(")\n");
555}
556
557struct statfs *
558getmntpt(name)
559 const char *name;
560{
561 struct statfs *mntbuf;
562 int i, mntsize;
563
564 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
565 for (i = mntsize - 1; i >= 0; i--) {
566 if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
567 strcmp(mntbuf[i].f_mntonname, name) == 0)
568 return (&mntbuf[i]);
569 }
570 return (NULL);
571}
572
573char *
574catopt(s0, s1)
575 char *s0;
576 const char *s1;
577{
578 size_t i;
579 char *cp;
580
581 if (s1 == NULL || *s1 == '\0')
582 return s0;
583
584 if (s0 && *s0) {
585 i = strlen(s0) + strlen(s1) + 1 + 1;
586 if ((cp = malloc(i)) == NULL)
587 errx(1, "malloc failed");
588 (void)snprintf(cp, i, "%s,%s", s0, s1);
589 } else
590 cp = strdup(s1);
591
592 if (s0)
593 free(s0);
594 return (cp);
595}
596
597void
598mangle(options, argcp, argv)
599 char *options;
600 int *argcp;
601 const char **argv;
602{
603 char *p, *s;
604 int argc;
605
606 argc = *argcp;
607 for (s = options; (p = strsep(&s, ",")) != NULL;)
608 if (*p != '\0') {
609 if (*p == '-') {
610 argv[argc++] = p;
611 p = strchr(p, '=');
612 if (p) {
613 *p = '\0';
614 argv[argc++] = p+1;
615 }
616 } else if (strcmp(p, "rw") != 0) {
617 argv[argc++] = "-o";
618 argv[argc++] = p;
619 }
620 }
621
622 *argcp = argc;
623}
624
625
626char *
627update_options(opts, fstab, curflags)
628 char *opts;
629 char *fstab;
630 int curflags;
631{
632 char *o, *p;
633 char *cur;
634 char *expopt, *newopt, *tmpopt;
635
636 if (opts == NULL)
637 return strdup("");
638
639 /* remove meta options from list */
640 remopt(fstab, MOUNT_META_OPTION_FSTAB);
641 remopt(fstab, MOUNT_META_OPTION_CURRENT);
642 cur = flags2opts(curflags);
643
644 /*
645 * Expand all meta-options passed to us first.
646 */
647 expopt = NULL;
648 for (p = opts; (o = strsep(&p, ",")) != NULL;) {
649 if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0)
650 expopt = catopt(expopt, fstab);
651 else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0)
652 expopt = catopt(expopt, cur);
653 else
654 expopt = catopt(expopt, o);
655 }
656 free(cur);
657 free(opts);
658
659 /*
660 * Remove previous contradictory arguments. Given option "foo" we
661 * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo"
662 * and "foo" - so we can deal with possible options like "notice".
663 */
664 newopt = NULL;
665 for (p = expopt; (o = strsep(&p, ",")) != NULL;) {
666 if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL)
667 errx(1, "malloc failed");
668
669 strcpy(tmpopt, "no");
670 strcat(tmpopt, o);
671 remopt(newopt, tmpopt);
672 free(tmpopt);
673
674 if (strncmp("no", o, 2) == 0)
675 remopt(newopt, o+2);
676
677 newopt = catopt(newopt, o);
678 }
679 free(expopt);
680
681 return newopt;
682}
683
684void
685remopt(string, opt)
686 char *string;
687 const char *opt;
688{
689 char *o, *p, *r;
690
691 if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0')
692 return;
693
694 r = string;
695
696 for (p = string; (o = strsep(&p, ",")) != NULL;) {
697 if (strcmp(opt, o) != 0) {
698 if (*r == ',' && *o != '\0')
699 r++;
700 while ((*r++ = *o++) != '\0')
701 ;
702 *--r = ',';
703 }
704 }
705 *r = '\0';
706}
707
708void
709usage()
710{
711
712 (void)fprintf(stderr, "%s\n%s\n%s\n",
713"usage: mount [-dfpruvw] [-o options] [-t ufs | external_type] special node",
714" mount [-adfpruvw] [-t ufs | external_type]",
715" mount [-dfpruvw] special | node");
716 exit(1);
717}
718
719void
720putfsent(ent)
721 const struct statfs *ent;
722{
723 struct fstab *fst;
724 char *opts;
725
726 opts = flags2opts(ent->f_flags);
727 printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname,
728 ent->f_fstypename, opts);
729 free(opts);
730
731 if ((fst = getfsspec(ent->f_mntfromname)))
732 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
733 else if ((fst = getfsfile(ent->f_mntonname)))
734 printf("\t%u %u\n", fst->fs_freq, fst->fs_passno);
735 else if (strcmp(ent->f_fstypename, "ufs") == 0) {
736 if (strcmp(ent->f_mntonname, "/") == 0)
737 printf("\t1 1\n");
738 else
739 printf("\t2 2\n");
740 } else
741 printf("\t0 0\n");
742}
743
744
745char *
746flags2opts(flags)
747 int flags;
748{
749 char *res;
750
751 res = NULL;
752
753 res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw");
754
755 if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync");
756 if (flags & MNT_NOEXEC) res = catopt(res, "noexec");
757 if (flags & MNT_NOSUID) res = catopt(res, "nosuid");
758 if (flags & MNT_NODEV) res = catopt(res, "nodev");
759 if (flags & MNT_UNION) res = catopt(res, "union");
760 if (flags & MNT_ASYNC) res = catopt(res, "async");
761 if (flags & MNT_NOATIME) res = catopt(res, "noatime");
762 if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr");
763 if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw");
764 if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow");
765 if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir");
766 if (flags & MNT_MULTILABEL) res = catopt(res, "multilabel");
765
766 return res;
767}
767
768 return res;
769}