1fba1c154SSteve Price /*- 28fae3551SRodney W. Grimes * Copyright (c) 1980, 1989, 1993, 1994 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 68fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 78fae3551SRodney W. Grimes * are met: 88fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 98fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 108fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 128fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 138fae3551SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 148fae3551SRodney W. Grimes * must display the following acknowledgement: 158fae3551SRodney W. Grimes * This product includes software developed by the University of 168fae3551SRodney W. Grimes * California, Berkeley and its contributors. 178fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 188fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 198fae3551SRodney W. Grimes * without specific prior written permission. 208fae3551SRodney W. Grimes * 218fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 228fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 238fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 248fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 258fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 268fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 278fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 288fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 298fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 308fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 318fae3551SRodney W. Grimes * SUCH DAMAGE. 328fae3551SRodney W. Grimes */ 338fae3551SRodney W. Grimes 348fae3551SRodney W. Grimes #ifndef lint 35fba1c154SSteve Price static const char copyright[] = 368fae3551SRodney W. Grimes "@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ 378fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 388fae3551SRodney W. Grimes #endif /* not lint */ 398fae3551SRodney W. Grimes 408fae3551SRodney W. Grimes #ifndef lint 41fba1c154SSteve Price #if 0 42c06fe0a0SPeter Wemm static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95"; 43fba1c154SSteve Price #endif 44bcb1d846SPhilippe Charnier static const char rcsid[] = 457f3dea24SPeter Wemm "$FreeBSD$"; 468fae3551SRodney W. Grimes #endif /* not lint */ 478fae3551SRodney W. Grimes 488fae3551SRodney W. Grimes #include <sys/param.h> 498fae3551SRodney W. Grimes #include <sys/mount.h> 508a978495SDavid Greenman #include <sys/stat.h> 5174cf460bSBruce Evans #include <sys/wait.h> 528fae3551SRodney W. Grimes 53003dbca6SMaxime Henrion #include <ctype.h> 548fae3551SRodney W. Grimes #include <err.h> 558fae3551SRodney W. Grimes #include <errno.h> 568fae3551SRodney W. Grimes #include <fstab.h> 57c06fe0a0SPeter Wemm #include <pwd.h> 588fae3551SRodney W. Grimes #include <signal.h> 598fae3551SRodney W. Grimes #include <stdio.h> 608fae3551SRodney W. Grimes #include <stdlib.h> 618fae3551SRodney W. Grimes #include <string.h> 628fae3551SRodney W. Grimes #include <unistd.h> 638fae3551SRodney W. Grimes 64fba1c154SSteve Price #include "extern.h" 6573dd3167SPoul-Henning Kamp #include "mntopts.h" 668fae3551SRodney W. Grimes #include "pathnames.h" 678fae3551SRodney W. Grimes 6818af6044SJoseph Koshy /* `meta' options */ 6918af6044SJoseph Koshy #define MOUNT_META_OPTION_FSTAB "fstab" 7018af6044SJoseph Koshy #define MOUNT_META_OPTION_CURRENT "current" 7118af6044SJoseph Koshy 7274cf460bSBruce Evans int debug, fstab_style, verbose; 73a257a45eSJordan K. Hubbard 7485429990SWarner Losh char *catopt(char *, const char *); 7585429990SWarner Losh struct statfs *getmntpt(const char *); 7685429990SWarner Losh int hasopt(const char *, const char *); 7785429990SWarner Losh int ismounted(struct fstab *, struct statfs *, int); 7885429990SWarner Losh int isremountable(const char *); 7985429990SWarner Losh void mangle(char *, int *, const char **); 8085429990SWarner Losh char *update_options(char *, char *, int); 8185429990SWarner Losh int mountfs(const char *, const char *, const char *, 8285429990SWarner Losh int, const char *, const char *); 8385429990SWarner Losh void remopt(char *, const char *); 8485429990SWarner Losh void prmount(struct statfs *); 8585429990SWarner Losh void putfsent(const struct statfs *); 8685429990SWarner Losh void usage(void); 8785429990SWarner Losh char *flags2opts(int); 888fae3551SRodney W. Grimes 89bcb1d846SPhilippe Charnier /* Map from mount options to printable formats. */ 908fae3551SRodney W. Grimes static struct opt { 918fae3551SRodney W. Grimes int o_opt; 928fae3551SRodney W. Grimes const char *o_name; 938fae3551SRodney W. Grimes } optnames[] = { 948fae3551SRodney W. Grimes { MNT_ASYNC, "asynchronous" }, 958fae3551SRodney W. Grimes { MNT_EXPORTED, "NFS exported" }, 968fae3551SRodney W. Grimes { MNT_LOCAL, "local" }, 9755e50aceSDavid Greenman { MNT_NOATIME, "noatime" }, 988fae3551SRodney W. Grimes { MNT_NODEV, "nodev" }, 998fae3551SRodney W. Grimes { MNT_NOEXEC, "noexec" }, 1008fae3551SRodney W. Grimes { MNT_NOSUID, "nosuid" }, 1015ddc8dedSWolfram Schneider { MNT_NOSYMFOLLOW, "nosymfollow" }, 1028fae3551SRodney W. Grimes { MNT_QUOTA, "with quotas" }, 1038fae3551SRodney W. Grimes { MNT_RDONLY, "read-only" }, 1048fae3551SRodney W. Grimes { MNT_SYNCHRONOUS, "synchronous" }, 1058fae3551SRodney W. Grimes { MNT_UNION, "union" }, 10675b714acSKATO Takenori { MNT_NOCLUSTERR, "noclusterr" }, 10775b714acSKATO Takenori { MNT_NOCLUSTERW, "noclusterw" }, 10852bf64c7SJulian Elischer { MNT_SUIDDIR, "suiddir" }, 109b1897c19SJulian Elischer { MNT_SOFTDEP, "soft-updates" }, 110ba0fbe96SRobert Watson { MNT_MULTILABEL, "multilabel" }, 11118af6044SJoseph Koshy { 0, NULL } 1128fae3551SRodney W. Grimes }; 1138fae3551SRodney W. Grimes 114fba1c154SSteve Price /* 115fba1c154SSteve Price * List of VFS types that can be remounted without becoming mounted on top 116fba1c154SSteve Price * of each other. 117fba1c154SSteve Price * XXX Is this list correct? 118fba1c154SSteve Price */ 119fba1c154SSteve Price static const char * 120fba1c154SSteve Price remountable_fs_names[] = { 1215a4420e3SAlexey Zelkin "ufs", "ffs", "ext2fs", 122fba1c154SSteve Price 0 123fba1c154SSteve Price }; 124fba1c154SSteve Price 1258fae3551SRodney W. Grimes int 1268fae3551SRodney W. Grimes main(argc, argv) 1278fae3551SRodney W. Grimes int argc; 1288fae3551SRodney W. Grimes char * const argv[]; 1298fae3551SRodney W. Grimes { 130c06fe0a0SPeter Wemm const char *mntfromname, **vfslist, *vfstype; 1318fae3551SRodney W. Grimes struct fstab *fs; 1328fae3551SRodney W. Grimes struct statfs *mntbuf; 1338fae3551SRodney W. Grimes FILE *mountdfp; 1348fae3551SRodney W. Grimes pid_t pid; 135cf96af72SBrian Feldman int all, ch, i, init_flags, mntsize, rval, have_fstab; 136003dbca6SMaxime Henrion char *cp, *ep, *options; 1378fae3551SRodney W. Grimes 1388fae3551SRodney W. Grimes all = init_flags = 0; 1398fae3551SRodney W. Grimes options = NULL; 1408fae3551SRodney W. Grimes vfslist = NULL; 1418fae3551SRodney W. Grimes vfstype = "ufs"; 14274cf460bSBruce Evans while ((ch = getopt(argc, argv, "adfo:prwt:uv")) != -1) 1438fae3551SRodney W. Grimes switch (ch) { 1448fae3551SRodney W. Grimes case 'a': 1458fae3551SRodney W. Grimes all = 1; 1468fae3551SRodney W. Grimes break; 1478fae3551SRodney W. Grimes case 'd': 1488fae3551SRodney W. Grimes debug = 1; 1498fae3551SRodney W. Grimes break; 1508fae3551SRodney W. Grimes case 'f': 1518fae3551SRodney W. Grimes init_flags |= MNT_FORCE; 1528fae3551SRodney W. Grimes break; 1538fae3551SRodney W. Grimes case 'o': 1548fae3551SRodney W. Grimes if (*optarg) 1558fae3551SRodney W. Grimes options = catopt(options, optarg); 1568fae3551SRodney W. Grimes break; 15774cf460bSBruce Evans case 'p': 15874cf460bSBruce Evans fstab_style = 1; 15974cf460bSBruce Evans verbose = 1; 16074cf460bSBruce Evans break; 1618fae3551SRodney W. Grimes case 'r': 162ad044771SDima Dorfman options = catopt(options, "ro"); 1638fae3551SRodney W. Grimes break; 1648fae3551SRodney W. Grimes case 't': 1658fae3551SRodney W. Grimes if (vfslist != NULL) 166bcb1d846SPhilippe Charnier errx(1, "only one -t option may be specified"); 1678fae3551SRodney W. Grimes vfslist = makevfslist(optarg); 1688fae3551SRodney W. Grimes vfstype = optarg; 1698fae3551SRodney W. Grimes break; 1708fae3551SRodney W. Grimes case 'u': 1718fae3551SRodney W. Grimes init_flags |= MNT_UPDATE; 1728fae3551SRodney W. Grimes break; 1738fae3551SRodney W. Grimes case 'v': 1748fae3551SRodney W. Grimes verbose = 1; 1758fae3551SRodney W. Grimes break; 1768fae3551SRodney W. Grimes case 'w': 177ad044771SDima Dorfman options = catopt(options, "noro"); 1788fae3551SRodney W. Grimes break; 1798fae3551SRodney W. Grimes case '?': 1808fae3551SRodney W. Grimes default: 1818fae3551SRodney W. Grimes usage(); 1828fae3551SRodney W. Grimes /* NOTREACHED */ 1838fae3551SRodney W. Grimes } 1848fae3551SRodney W. Grimes argc -= optind; 1858fae3551SRodney W. Grimes argv += optind; 1868fae3551SRodney W. Grimes 1878fae3551SRodney W. Grimes #define BADTYPE(type) \ 1888fae3551SRodney W. Grimes (strcmp(type, FSTAB_RO) && \ 1898fae3551SRodney W. Grimes strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 1908fae3551SRodney W. Grimes 1918fae3551SRodney W. Grimes rval = 0; 1928fae3551SRodney W. Grimes switch (argc) { 1938fae3551SRodney W. Grimes case 0: 194fba1c154SSteve Price if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 195fba1c154SSteve Price err(1, "getmntinfo"); 196fba1c154SSteve Price if (all) { 1978fae3551SRodney W. Grimes while ((fs = getfsent()) != NULL) { 1988fae3551SRodney W. Grimes if (BADTYPE(fs->fs_type)) 1998fae3551SRodney W. Grimes continue; 200c06fe0a0SPeter Wemm if (checkvfsname(fs->fs_vfstype, vfslist)) 2018fae3551SRodney W. Grimes continue; 202c06fe0a0SPeter Wemm if (hasopt(fs->fs_mntops, "noauto")) 20389beb278SDavid Greenman continue; 20498201b0cSBruce Evans if (!(init_flags & MNT_UPDATE) && 20598201b0cSBruce Evans ismounted(fs, mntbuf, mntsize)) 206fba1c154SSteve Price continue; 2078fae3551SRodney W. Grimes if (mountfs(fs->fs_vfstype, fs->fs_spec, 2088fae3551SRodney W. Grimes fs->fs_file, init_flags, options, 2098fae3551SRodney W. Grimes fs->fs_mntops)) 2108fae3551SRodney W. Grimes rval = 1; 2118fae3551SRodney W. Grimes } 212fba1c154SSteve Price } else if (fstab_style) { 213a257a45eSJordan K. Hubbard for (i = 0; i < mntsize; i++) { 214c06fe0a0SPeter Wemm if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 215a257a45eSJordan K. Hubbard continue; 216a257a45eSJordan K. Hubbard putfsent(&mntbuf[i]); 217a257a45eSJordan K. Hubbard } 21874cf460bSBruce Evans } else { 2198fae3551SRodney W. Grimes for (i = 0; i < mntsize; i++) { 22074cf460bSBruce Evans if (checkvfsname(mntbuf[i].f_fstypename, 22174cf460bSBruce Evans vfslist)) 2228fae3551SRodney W. Grimes continue; 223c06fe0a0SPeter Wemm prmount(&mntbuf[i]); 2248fae3551SRodney W. Grimes } 2258fae3551SRodney W. Grimes } 2268fae3551SRodney W. Grimes exit(rval); 2278fae3551SRodney W. Grimes case 1: 2288fae3551SRodney W. Grimes if (vfslist != NULL) 2298fae3551SRodney W. Grimes usage(); 2308fae3551SRodney W. Grimes 2318fae3551SRodney W. Grimes if (init_flags & MNT_UPDATE) { 232cf96af72SBrian Feldman mntfromname = NULL; 233cf96af72SBrian Feldman have_fstab = 0; 2348fae3551SRodney W. Grimes if ((mntbuf = getmntpt(*argv)) == NULL) 235cf96af72SBrian Feldman errx(1, "not currently mounted %s", *argv); 236cf96af72SBrian Feldman /* 237cf96af72SBrian Feldman * Only get the mntflags from fstab if both mntpoint 238cf96af72SBrian Feldman * and mntspec are identical. Also handle the special 239cf96af72SBrian Feldman * case where just '/' is mounted and 'spec' is not 240cf96af72SBrian Feldman * identical with the one from fstab ('/dev' is missing 241cf96af72SBrian Feldman * in the spec-string at boot-time). 242cf96af72SBrian Feldman */ 24318af6044SJoseph Koshy if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 244cf96af72SBrian Feldman if (strcmp(fs->fs_spec, 245cf96af72SBrian Feldman mntbuf->f_mntfromname) == 0 && 246cf96af72SBrian Feldman strcmp(fs->fs_file, 247cf96af72SBrian Feldman mntbuf->f_mntonname) == 0) { 248cf96af72SBrian Feldman have_fstab = 1; 249cf96af72SBrian Feldman mntfromname = mntbuf->f_mntfromname; 250cf96af72SBrian Feldman } else if (argv[0][0] == '/' && 251cf96af72SBrian Feldman argv[0][1] == '\0') { 252cf96af72SBrian Feldman fs = getfsfile("/"); 253cf96af72SBrian Feldman have_fstab = 1; 254c06fe0a0SPeter Wemm mntfromname = fs->fs_spec; 255cf96af72SBrian Feldman } 256cf96af72SBrian Feldman } 257cf96af72SBrian Feldman if (have_fstab) { 25818af6044SJoseph Koshy options = update_options(options, fs->fs_mntops, 25918af6044SJoseph Koshy mntbuf->f_flags); 26018af6044SJoseph Koshy } else { 261c06fe0a0SPeter Wemm mntfromname = mntbuf->f_mntfromname; 26218af6044SJoseph Koshy options = update_options(options, NULL, 26318af6044SJoseph Koshy mntbuf->f_flags); 26418af6044SJoseph Koshy } 265c06fe0a0SPeter Wemm rval = mountfs(mntbuf->f_fstypename, mntfromname, 266c06fe0a0SPeter Wemm mntbuf->f_mntonname, init_flags, options, 0); 267c06fe0a0SPeter Wemm break; 268c06fe0a0SPeter Wemm } 2692b184c50SEivind Eklund rmslashes(*argv, *argv); 2708fae3551SRodney W. Grimes if ((fs = getfsfile(*argv)) == NULL && 2718fae3551SRodney W. Grimes (fs = getfsspec(*argv)) == NULL) 272bcb1d846SPhilippe Charnier errx(1, "%s: unknown special file or filesystem", 2738fae3551SRodney W. Grimes *argv); 2748fae3551SRodney W. Grimes if (BADTYPE(fs->fs_type)) 275bcb1d846SPhilippe Charnier errx(1, "%s has unknown filesystem type", 2768fae3551SRodney W. Grimes *argv); 277c06fe0a0SPeter Wemm rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, 278c06fe0a0SPeter Wemm init_flags, options, fs->fs_mntops); 2798fae3551SRodney W. Grimes break; 2808fae3551SRodney W. Grimes case 2: 2818fae3551SRodney W. Grimes /* 282cf96af72SBrian Feldman * If -t flag has not been specified, the path cannot be 283003dbca6SMaxime Henrion * found, spec contains either a ':' or a '@', then assume 284cf96af72SBrian Feldman * that an NFS filesystem is being specified ala Sun. 285003dbca6SMaxime Henrion * Check if the hostname contains only allowed characters 286003dbca6SMaxime Henrion * to reduce false positives. IPv6 addresses containing 287003dbca6SMaxime Henrion * ':' will be correctly parsed only if the separator is '@'. 288003dbca6SMaxime Henrion * The definition of a valid hostname is taken from RFC 1034. 2898fae3551SRodney W. Grimes */ 290003dbca6SMaxime Henrion if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL) || 291003dbca6SMaxime Henrion ((ep = strchr(argv[0], ':')) != NULL)) { 292da85c82bSMaxime Henrion if (*ep == '@') { 293da85c82bSMaxime Henrion cp = ep + 1; 294da85c82bSMaxime Henrion ep = cp + strlen(cp); 295da85c82bSMaxime Henrion } else 296003dbca6SMaxime Henrion cp = argv[0]; 297003dbca6SMaxime Henrion while (cp != ep) { 298003dbca6SMaxime Henrion if (!isdigit(*cp) && !isalpha(*cp) && 299003dbca6SMaxime Henrion *cp != '.' && *cp != '-' && *cp != ':') 300003dbca6SMaxime Henrion break; 301003dbca6SMaxime Henrion cp++; 302003dbca6SMaxime Henrion } 303003dbca6SMaxime Henrion if (cp == ep) 3048fae3551SRodney W. Grimes vfstype = "nfs"; 305003dbca6SMaxime Henrion } 3068fae3551SRodney W. Grimes rval = mountfs(vfstype, 3078fae3551SRodney W. Grimes argv[0], argv[1], init_flags, options, NULL); 3088fae3551SRodney W. Grimes break; 3098fae3551SRodney W. Grimes default: 3108fae3551SRodney W. Grimes usage(); 3118fae3551SRodney W. Grimes /* NOTREACHED */ 3128fae3551SRodney W. Grimes } 3138fae3551SRodney W. Grimes 3148fae3551SRodney W. Grimes /* 3158fae3551SRodney W. Grimes * If the mount was successfully, and done by root, tell mountd the 3168fae3551SRodney W. Grimes * good news. Pid checks are probably unnecessary, but don't hurt. 3178fae3551SRodney W. Grimes */ 3188fae3551SRodney W. Grimes if (rval == 0 && getuid() == 0 && 3198fae3551SRodney W. Grimes (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 320fba1c154SSteve Price if (fscanf(mountdfp, "%d", &pid) == 1 && 3218fae3551SRodney W. Grimes pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) 3228fae3551SRodney W. Grimes err(1, "signal mountd"); 3238fae3551SRodney W. Grimes (void)fclose(mountdfp); 3248fae3551SRodney W. Grimes } 3258fae3551SRodney W. Grimes 3268fae3551SRodney W. Grimes exit(rval); 3278fae3551SRodney W. Grimes } 3288fae3551SRodney W. Grimes 3298fae3551SRodney W. Grimes int 330fba1c154SSteve Price ismounted(fs, mntbuf, mntsize) 331fba1c154SSteve Price struct fstab *fs; 332fba1c154SSteve Price struct statfs *mntbuf; 333fba1c154SSteve Price int mntsize; 334fba1c154SSteve Price { 335fba1c154SSteve Price int i; 336fba1c154SSteve Price 337fba1c154SSteve Price if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0') 338fba1c154SSteve Price /* the root filesystem can always be remounted */ 339fba1c154SSteve Price return (0); 340fba1c154SSteve Price 341fba1c154SSteve Price for (i = mntsize - 1; i >= 0; --i) 342fba1c154SSteve Price if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 && 343fba1c154SSteve Price (!isremountable(fs->fs_vfstype) || 344fba1c154SSteve Price strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0)) 345fba1c154SSteve Price return (1); 346fba1c154SSteve Price return (0); 347fba1c154SSteve Price } 348fba1c154SSteve Price 349fba1c154SSteve Price int 350fba1c154SSteve Price isremountable(vfsname) 351fba1c154SSteve Price const char *vfsname; 352fba1c154SSteve Price { 353fba1c154SSteve Price const char **cp; 354fba1c154SSteve Price 355fba1c154SSteve Price for (cp = remountable_fs_names; *cp; cp++) 356fba1c154SSteve Price if (strcmp(*cp, vfsname) == 0) 357fba1c154SSteve Price return (1); 358fba1c154SSteve Price return (0); 359fba1c154SSteve Price } 360fba1c154SSteve Price 361fba1c154SSteve Price int 362c06fe0a0SPeter Wemm hasopt(mntopts, option) 363c06fe0a0SPeter Wemm const char *mntopts, *option; 364c06fe0a0SPeter Wemm { 365c06fe0a0SPeter Wemm int negative, found; 366c06fe0a0SPeter Wemm char *opt, *optbuf; 367c06fe0a0SPeter Wemm 368c06fe0a0SPeter Wemm if (option[0] == 'n' && option[1] == 'o') { 369c06fe0a0SPeter Wemm negative = 1; 370c06fe0a0SPeter Wemm option += 2; 371c06fe0a0SPeter Wemm } else 372c06fe0a0SPeter Wemm negative = 0; 373c06fe0a0SPeter Wemm optbuf = strdup(mntopts); 374c06fe0a0SPeter Wemm found = 0; 375c06fe0a0SPeter Wemm for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 376c06fe0a0SPeter Wemm if (opt[0] == 'n' && opt[1] == 'o') { 377c06fe0a0SPeter Wemm if (!strcasecmp(opt + 2, option)) 378c06fe0a0SPeter Wemm found = negative; 379c06fe0a0SPeter Wemm } else if (!strcasecmp(opt, option)) 380c06fe0a0SPeter Wemm found = !negative; 381c06fe0a0SPeter Wemm } 382c06fe0a0SPeter Wemm free(optbuf); 383c06fe0a0SPeter Wemm return (found); 384c06fe0a0SPeter Wemm } 385c06fe0a0SPeter Wemm 386c06fe0a0SPeter Wemm int 3878fae3551SRodney W. Grimes mountfs(vfstype, spec, name, flags, options, mntopts) 3888fae3551SRodney W. Grimes const char *vfstype, *spec, *name, *options, *mntopts; 3898fae3551SRodney W. Grimes int flags; 3908fae3551SRodney W. Grimes { 3918fae3551SRodney W. Grimes /* List of directories containing mount_xxx subcommands. */ 3928fae3551SRodney W. Grimes static const char *edirs[] = { 3938fae3551SRodney W. Grimes _PATH_SBIN, 3948fae3551SRodney W. Grimes _PATH_USRSBIN, 3958fae3551SRodney W. Grimes NULL 3968fae3551SRodney W. Grimes }; 3978fae3551SRodney W. Grimes const char *argv[100], **edir; 3988fae3551SRodney W. Grimes struct statfs sf; 3998fae3551SRodney W. Grimes pid_t pid; 4008fae3551SRodney W. Grimes int argc, i, status; 4018fae3551SRodney W. Grimes char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN]; 4028fae3551SRodney W. Grimes 403fba1c154SSteve Price #if __GNUC__ 404fba1c154SSteve Price (void)&optbuf; 405fba1c154SSteve Price (void)&name; 406fba1c154SSteve Price #endif 407fba1c154SSteve Price 40873dd3167SPoul-Henning Kamp /* resolve the mountpoint with realpath(3) */ 40973dd3167SPoul-Henning Kamp (void)checkpath(name, mntpath); 4108fae3551SRodney W. Grimes name = mntpath; 4118fae3551SRodney W. Grimes 412c06fe0a0SPeter Wemm if (mntopts == NULL) 413c06fe0a0SPeter Wemm mntopts = ""; 4148fae3551SRodney W. Grimes if (options == NULL) { 415c06fe0a0SPeter Wemm if (*mntopts == '\0') { 4168fae3551SRodney W. Grimes options = "rw"; 417c06fe0a0SPeter Wemm } else { 4188fae3551SRodney W. Grimes options = mntopts; 4198fae3551SRodney W. Grimes mntopts = ""; 4208fae3551SRodney W. Grimes } 421c06fe0a0SPeter Wemm } 4228fae3551SRodney W. Grimes optbuf = catopt(strdup(mntopts), options); 4238fae3551SRodney W. Grimes 4248fae3551SRodney W. Grimes if (strcmp(name, "/") == 0) 4258fae3551SRodney W. Grimes flags |= MNT_UPDATE; 4268fae3551SRodney W. Grimes if (flags & MNT_FORCE) 4278fae3551SRodney W. Grimes optbuf = catopt(optbuf, "force"); 4288fae3551SRodney W. Grimes if (flags & MNT_RDONLY) 4298fae3551SRodney W. Grimes optbuf = catopt(optbuf, "ro"); 4308fae3551SRodney W. Grimes /* 4318fae3551SRodney W. Grimes * XXX 4328fae3551SRodney W. Grimes * The mount_mfs (newfs) command uses -o to select the 433bcb1d846SPhilippe Charnier * optimization mode. We don't pass the default "-o rw" 4348fae3551SRodney W. Grimes * for that reason. 4358fae3551SRodney W. Grimes */ 4368fae3551SRodney W. Grimes if (flags & MNT_UPDATE) 4378fae3551SRodney W. Grimes optbuf = catopt(optbuf, "update"); 4388fae3551SRodney W. Grimes 4394ccd7546SRuslan Ermilov /* Compatibility glue. */ 4404ccd7546SRuslan Ermilov if (strcmp(vfstype, "msdos") == 0) 4414ccd7546SRuslan Ermilov vfstype = "msdosfs"; 4424ccd7546SRuslan Ermilov 4438fae3551SRodney W. Grimes argc = 0; 4448fae3551SRodney W. Grimes argv[argc++] = vfstype; 4458fae3551SRodney W. Grimes mangle(optbuf, &argc, argv); 4468fae3551SRodney W. Grimes argv[argc++] = spec; 4478fae3551SRodney W. Grimes argv[argc++] = name; 4488fae3551SRodney W. Grimes argv[argc] = NULL; 4498fae3551SRodney W. Grimes 4508fae3551SRodney W. Grimes if (debug) { 4518fae3551SRodney W. Grimes (void)printf("exec: mount_%s", vfstype); 4528fae3551SRodney W. Grimes for (i = 1; i < argc; i++) 4538fae3551SRodney W. Grimes (void)printf(" %s", argv[i]); 4548fae3551SRodney W. Grimes (void)printf("\n"); 4558fae3551SRodney W. Grimes return (0); 4568fae3551SRodney W. Grimes } 4578fae3551SRodney W. Grimes 4587c506958SAndrey A. Chernov switch (pid = fork()) { 4598fae3551SRodney W. Grimes case -1: /* Error. */ 4607c506958SAndrey A. Chernov warn("fork"); 4618fae3551SRodney W. Grimes free(optbuf); 4628fae3551SRodney W. Grimes return (1); 4638fae3551SRodney W. Grimes case 0: /* Child. */ 4648fae3551SRodney W. Grimes if (strcmp(vfstype, "ufs") == 0) 4658fae3551SRodney W. Grimes exit(mount_ufs(argc, (char * const *) argv)); 4668fae3551SRodney W. Grimes 4678fae3551SRodney W. Grimes /* Go find an executable. */ 468b6cf6bb2SSatoshi Asami for (edir = edirs; *edir; edir++) { 4698fae3551SRodney W. Grimes (void)snprintf(execname, 4708fae3551SRodney W. Grimes sizeof(execname), "%s/mount_%s", *edir, vfstype); 4718fae3551SRodney W. Grimes execv(execname, (char * const *)argv); 472b6cf6bb2SSatoshi Asami } 473b6cf6bb2SSatoshi Asami if (errno == ENOENT) { 474b6cf6bb2SSatoshi Asami int len = 0; 475b6cf6bb2SSatoshi Asami char *cp; 476b6cf6bb2SSatoshi Asami for (edir = edirs; *edir; edir++) 477b6cf6bb2SSatoshi Asami len += strlen(*edir) + 2; /* ", " */ 478bcb1d846SPhilippe Charnier if ((cp = malloc(len)) == NULL) 479bcb1d846SPhilippe Charnier errx(1, "malloc failed"); 480b6cf6bb2SSatoshi Asami cp[0] = '\0'; 481b6cf6bb2SSatoshi Asami for (edir = edirs; *edir; edir++) { 482b6cf6bb2SSatoshi Asami strcat(cp, *edir); 483b6cf6bb2SSatoshi Asami if (edir[1] != NULL) 484b6cf6bb2SSatoshi Asami strcat(cp, ", "); 485b6cf6bb2SSatoshi Asami } 486b6cf6bb2SSatoshi Asami warn("exec mount_%s not found in %s", vfstype, cp); 487b6cf6bb2SSatoshi Asami } 4888fae3551SRodney W. Grimes exit(1); 4898fae3551SRodney W. Grimes /* NOTREACHED */ 4908fae3551SRodney W. Grimes default: /* Parent. */ 4918fae3551SRodney W. Grimes free(optbuf); 4928fae3551SRodney W. Grimes 4938fae3551SRodney W. Grimes if (waitpid(pid, &status, 0) < 0) { 4948fae3551SRodney W. Grimes warn("waitpid"); 4958fae3551SRodney W. Grimes return (1); 4968fae3551SRodney W. Grimes } 4978fae3551SRodney W. Grimes 4988fae3551SRodney W. Grimes if (WIFEXITED(status)) { 4998fae3551SRodney W. Grimes if (WEXITSTATUS(status) != 0) 5008fae3551SRodney W. Grimes return (WEXITSTATUS(status)); 5018fae3551SRodney W. Grimes } else if (WIFSIGNALED(status)) { 5028fae3551SRodney W. Grimes warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); 5038fae3551SRodney W. Grimes return (1); 5048fae3551SRodney W. Grimes } 5058fae3551SRodney W. Grimes 5068fae3551SRodney W. Grimes if (verbose) { 5078fae3551SRodney W. Grimes if (statfs(name, &sf) < 0) { 508c06fe0a0SPeter Wemm warn("statfs %s", name); 5098fae3551SRodney W. Grimes return (1); 5108fae3551SRodney W. Grimes } 511a257a45eSJordan K. Hubbard if (fstab_style) 512a257a45eSJordan K. Hubbard putfsent(&sf); 513a257a45eSJordan K. Hubbard else 514c06fe0a0SPeter Wemm prmount(&sf); 5158fae3551SRodney W. Grimes } 5168fae3551SRodney W. Grimes break; 5178fae3551SRodney W. Grimes } 5188fae3551SRodney W. Grimes 5198fae3551SRodney W. Grimes return (0); 5208fae3551SRodney W. Grimes } 5218fae3551SRodney W. Grimes 5228fae3551SRodney W. Grimes void 523c06fe0a0SPeter Wemm prmount(sfp) 524c06fe0a0SPeter Wemm struct statfs *sfp; 5258fae3551SRodney W. Grimes { 526c06fe0a0SPeter Wemm int flags; 5278fae3551SRodney W. Grimes struct opt *o; 528c06fe0a0SPeter Wemm struct passwd *pw; 5298fae3551SRodney W. Grimes 530af2ea5aaSNick Hibma (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname, 531af2ea5aaSNick Hibma sfp->f_fstypename); 5328fae3551SRodney W. Grimes 533c06fe0a0SPeter Wemm flags = sfp->f_flags & MNT_VISFLAGMASK; 534af2ea5aaSNick Hibma for (o = optnames; flags && o->o_opt; o++) 5358fae3551SRodney W. Grimes if (flags & o->o_opt) { 536af2ea5aaSNick Hibma (void)printf(", %s", o->o_name); 5378fae3551SRodney W. Grimes flags &= ~o->o_opt; 5388fae3551SRodney W. Grimes } 539c06fe0a0SPeter Wemm if (sfp->f_owner) { 540af2ea5aaSNick Hibma (void)printf(", mounted by "); 541c06fe0a0SPeter Wemm if ((pw = getpwuid(sfp->f_owner)) != NULL) 542c06fe0a0SPeter Wemm (void)printf("%s", pw->pw_name); 543c06fe0a0SPeter Wemm else 544c06fe0a0SPeter Wemm (void)printf("%d", sfp->f_owner); 545c06fe0a0SPeter Wemm } 546c62ffab6SSheldon Hearn if (verbose) { 547677b9b3fSBruce Evans if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0) 548af2ea5aaSNick Hibma (void)printf(", writes: sync %ld async %ld", 549af2ea5aaSNick Hibma sfp->f_syncwrites, sfp->f_asyncwrites); 550461bb71eSKirk McKusick if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0) 551461bb71eSKirk McKusick (void)printf(", reads: sync %ld async %ld", 552461bb71eSKirk McKusick sfp->f_syncreads, sfp->f_asyncreads); 553c62ffab6SSheldon Hearn } 554af2ea5aaSNick Hibma (void)printf(")\n"); 5558fae3551SRodney W. Grimes } 5568fae3551SRodney W. Grimes 5578fae3551SRodney W. Grimes struct statfs * 5588fae3551SRodney W. Grimes getmntpt(name) 5598fae3551SRodney W. Grimes const char *name; 5608fae3551SRodney W. Grimes { 5618fae3551SRodney W. Grimes struct statfs *mntbuf; 5628fae3551SRodney W. Grimes int i, mntsize; 5638fae3551SRodney W. Grimes 5648fae3551SRodney W. Grimes mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 565cf96af72SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 5668fae3551SRodney W. Grimes if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 5678fae3551SRodney W. Grimes strcmp(mntbuf[i].f_mntonname, name) == 0) 5688fae3551SRodney W. Grimes return (&mntbuf[i]); 569cf96af72SBrian Feldman } 5708fae3551SRodney W. Grimes return (NULL); 5718fae3551SRodney W. Grimes } 5728fae3551SRodney W. Grimes 5738fae3551SRodney W. Grimes char * 5748fae3551SRodney W. Grimes catopt(s0, s1) 5758fae3551SRodney W. Grimes char *s0; 5768fae3551SRodney W. Grimes const char *s1; 5778fae3551SRodney W. Grimes { 5788fae3551SRodney W. Grimes size_t i; 5798fae3551SRodney W. Grimes char *cp; 5808fae3551SRodney W. Grimes 58118af6044SJoseph Koshy if (s1 == NULL || *s1 == '\0') 58218af6044SJoseph Koshy return s0; 58318af6044SJoseph Koshy 5848fae3551SRodney W. Grimes if (s0 && *s0) { 5858fae3551SRodney W. Grimes i = strlen(s0) + strlen(s1) + 1 + 1; 5868fae3551SRodney W. Grimes if ((cp = malloc(i)) == NULL) 587bcb1d846SPhilippe Charnier errx(1, "malloc failed"); 5888fae3551SRodney W. Grimes (void)snprintf(cp, i, "%s,%s", s0, s1); 5898fae3551SRodney W. Grimes } else 5908fae3551SRodney W. Grimes cp = strdup(s1); 5918fae3551SRodney W. Grimes 5928fae3551SRodney W. Grimes if (s0) 5938fae3551SRodney W. Grimes free(s0); 5948fae3551SRodney W. Grimes return (cp); 5958fae3551SRodney W. Grimes } 5968fae3551SRodney W. Grimes 5978fae3551SRodney W. Grimes void 5988fae3551SRodney W. Grimes mangle(options, argcp, argv) 5998fae3551SRodney W. Grimes char *options; 6008fae3551SRodney W. Grimes int *argcp; 6018fae3551SRodney W. Grimes const char **argv; 6028fae3551SRodney W. Grimes { 6038fae3551SRodney W. Grimes char *p, *s; 6048fae3551SRodney W. Grimes int argc; 6058fae3551SRodney W. Grimes 6068fae3551SRodney W. Grimes argc = *argcp; 6078fae3551SRodney W. Grimes for (s = options; (p = strsep(&s, ",")) != NULL;) 60818af6044SJoseph Koshy if (*p != '\0') { 6098fae3551SRodney W. Grimes if (*p == '-') { 6108fae3551SRodney W. Grimes argv[argc++] = p; 6118fae3551SRodney W. Grimes p = strchr(p, '='); 6128fae3551SRodney W. Grimes if (p) { 6138fae3551SRodney W. Grimes *p = '\0'; 6148fae3551SRodney W. Grimes argv[argc++] = p+1; 6158fae3551SRodney W. Grimes } 6168fae3551SRodney W. Grimes } else if (strcmp(p, "rw") != 0) { 6178fae3551SRodney W. Grimes argv[argc++] = "-o"; 6188fae3551SRodney W. Grimes argv[argc++] = p; 6198fae3551SRodney W. Grimes } 62018af6044SJoseph Koshy } 6218fae3551SRodney W. Grimes 6228fae3551SRodney W. Grimes *argcp = argc; 6238fae3551SRodney W. Grimes } 6248fae3551SRodney W. Grimes 62518af6044SJoseph Koshy 62618af6044SJoseph Koshy char * 62718af6044SJoseph Koshy update_options(opts, fstab, curflags) 62818af6044SJoseph Koshy char *opts; 62918af6044SJoseph Koshy char *fstab; 63018af6044SJoseph Koshy int curflags; 63118af6044SJoseph Koshy { 63218af6044SJoseph Koshy char *o, *p; 63318af6044SJoseph Koshy char *cur; 63418af6044SJoseph Koshy char *expopt, *newopt, *tmpopt; 63518af6044SJoseph Koshy 63618af6044SJoseph Koshy if (opts == NULL) 63718af6044SJoseph Koshy return strdup(""); 63818af6044SJoseph Koshy 63918af6044SJoseph Koshy /* remove meta options from list */ 64018af6044SJoseph Koshy remopt(fstab, MOUNT_META_OPTION_FSTAB); 64118af6044SJoseph Koshy remopt(fstab, MOUNT_META_OPTION_CURRENT); 64218af6044SJoseph Koshy cur = flags2opts(curflags); 64318af6044SJoseph Koshy 64418af6044SJoseph Koshy /* 64518af6044SJoseph Koshy * Expand all meta-options passed to us first. 64618af6044SJoseph Koshy */ 64718af6044SJoseph Koshy expopt = NULL; 64818af6044SJoseph Koshy for (p = opts; (o = strsep(&p, ",")) != NULL;) { 64918af6044SJoseph Koshy if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0) 65018af6044SJoseph Koshy expopt = catopt(expopt, fstab); 65118af6044SJoseph Koshy else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0) 65218af6044SJoseph Koshy expopt = catopt(expopt, cur); 65318af6044SJoseph Koshy else 65418af6044SJoseph Koshy expopt = catopt(expopt, o); 65518af6044SJoseph Koshy } 65618af6044SJoseph Koshy free(cur); 65718af6044SJoseph Koshy free(opts); 65818af6044SJoseph Koshy 65918af6044SJoseph Koshy /* 66018af6044SJoseph Koshy * Remove previous contradictory arguments. Given option "foo" we 66118af6044SJoseph Koshy * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo" 66218af6044SJoseph Koshy * and "foo" - so we can deal with possible options like "notice". 66318af6044SJoseph Koshy */ 66418af6044SJoseph Koshy newopt = NULL; 66518af6044SJoseph Koshy for (p = expopt; (o = strsep(&p, ",")) != NULL;) { 66618af6044SJoseph Koshy if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL) 66718af6044SJoseph Koshy errx(1, "malloc failed"); 66818af6044SJoseph Koshy 66918af6044SJoseph Koshy strcpy(tmpopt, "no"); 67018af6044SJoseph Koshy strcat(tmpopt, o); 67118af6044SJoseph Koshy remopt(newopt, tmpopt); 67218af6044SJoseph Koshy free(tmpopt); 67318af6044SJoseph Koshy 67418af6044SJoseph Koshy if (strncmp("no", o, 2) == 0) 67518af6044SJoseph Koshy remopt(newopt, o+2); 67618af6044SJoseph Koshy 67718af6044SJoseph Koshy newopt = catopt(newopt, o); 67818af6044SJoseph Koshy } 67918af6044SJoseph Koshy free(expopt); 68018af6044SJoseph Koshy 68118af6044SJoseph Koshy return newopt; 68218af6044SJoseph Koshy } 68318af6044SJoseph Koshy 68418af6044SJoseph Koshy void 68518af6044SJoseph Koshy remopt(string, opt) 68618af6044SJoseph Koshy char *string; 68718af6044SJoseph Koshy const char *opt; 68818af6044SJoseph Koshy { 68918af6044SJoseph Koshy char *o, *p, *r; 69018af6044SJoseph Koshy 69118af6044SJoseph Koshy if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0') 69218af6044SJoseph Koshy return; 69318af6044SJoseph Koshy 69418af6044SJoseph Koshy r = string; 69518af6044SJoseph Koshy 69618af6044SJoseph Koshy for (p = string; (o = strsep(&p, ",")) != NULL;) { 69718af6044SJoseph Koshy if (strcmp(opt, o) != 0) { 69818af6044SJoseph Koshy if (*r == ',' && *o != '\0') 69918af6044SJoseph Koshy r++; 70018af6044SJoseph Koshy while ((*r++ = *o++) != '\0') 70118af6044SJoseph Koshy ; 70218af6044SJoseph Koshy *--r = ','; 70318af6044SJoseph Koshy } 70418af6044SJoseph Koshy } 70518af6044SJoseph Koshy *r = '\0'; 70618af6044SJoseph Koshy } 70718af6044SJoseph Koshy 7088fae3551SRodney W. Grimes void 7098fae3551SRodney W. Grimes usage() 7108fae3551SRodney W. Grimes { 7118fae3551SRodney W. Grimes 712bcb1d846SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n%s\n", 713bcb1d846SPhilippe Charnier "usage: mount [-dfpruvw] [-o options] [-t ufs | external_type] special node", 714bcb1d846SPhilippe Charnier " mount [-adfpruvw] [-t ufs | external_type]", 715bcb1d846SPhilippe Charnier " mount [-dfpruvw] special | node"); 7168fae3551SRodney W. Grimes exit(1); 7178fae3551SRodney W. Grimes } 718a257a45eSJordan K. Hubbard 719a257a45eSJordan K. Hubbard void 720a257a45eSJordan K. Hubbard putfsent(ent) 721a257a45eSJordan K. Hubbard const struct statfs *ent; 722a257a45eSJordan K. Hubbard { 723a257a45eSJordan K. Hubbard struct fstab *fst; 72418af6044SJoseph Koshy char *opts; 725a257a45eSJordan K. Hubbard 72618af6044SJoseph Koshy opts = flags2opts(ent->f_flags); 72774cf460bSBruce Evans printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname, 72818af6044SJoseph Koshy ent->f_fstypename, opts); 72918af6044SJoseph Koshy free(opts); 730c06fe0a0SPeter Wemm 731fba1c154SSteve Price if ((fst = getfsspec(ent->f_mntfromname))) 732a257a45eSJordan K. Hubbard printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 733fba1c154SSteve Price else if ((fst = getfsfile(ent->f_mntonname))) 734a257a45eSJordan K. Hubbard printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 735ab80d6faSBrian Feldman else if (strcmp(ent->f_fstypename, "ufs") == 0) { 736ab80d6faSBrian Feldman if (strcmp(ent->f_mntonname, "/") == 0) 737a257a45eSJordan K. Hubbard printf("\t1 1\n"); 738a257a45eSJordan K. Hubbard else 739ab80d6faSBrian Feldman printf("\t2 2\n"); 740ab80d6faSBrian Feldman } else 741a257a45eSJordan K. Hubbard printf("\t0 0\n"); 742a257a45eSJordan K. Hubbard } 74318af6044SJoseph Koshy 74418af6044SJoseph Koshy 74518af6044SJoseph Koshy char * 74618af6044SJoseph Koshy flags2opts(flags) 74718af6044SJoseph Koshy int flags; 74818af6044SJoseph Koshy { 74918af6044SJoseph Koshy char *res; 75018af6044SJoseph Koshy 75118af6044SJoseph Koshy res = NULL; 75218af6044SJoseph Koshy 75318af6044SJoseph Koshy res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw"); 75418af6044SJoseph Koshy 75518af6044SJoseph Koshy if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync"); 75618af6044SJoseph Koshy if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); 75718af6044SJoseph Koshy if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); 75818af6044SJoseph Koshy if (flags & MNT_NODEV) res = catopt(res, "nodev"); 75918af6044SJoseph Koshy if (flags & MNT_UNION) res = catopt(res, "union"); 76018af6044SJoseph Koshy if (flags & MNT_ASYNC) res = catopt(res, "async"); 76118af6044SJoseph Koshy if (flags & MNT_NOATIME) res = catopt(res, "noatime"); 76218af6044SJoseph Koshy if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); 76318af6044SJoseph Koshy if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw"); 76418af6044SJoseph Koshy if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow"); 76518af6044SJoseph Koshy if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir"); 766ba0fbe96SRobert Watson if (flags & MNT_MULTILABEL) res = catopt(res, "multilabel"); 76718af6044SJoseph Koshy 76818af6044SJoseph Koshy return res; 76918af6044SJoseph Koshy } 770