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 * 4. Neither the name of the University nor the names of its contributors 148fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 158fae3551SRodney W. Grimes * without specific prior written permission. 168fae3551SRodney W. Grimes * 178fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 188fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 218fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278fae3551SRodney W. Grimes * SUCH DAMAGE. 288fae3551SRodney W. Grimes */ 298fae3551SRodney W. Grimes 308fae3551SRodney W. Grimes #ifndef lint 31fba1c154SSteve Price static const char copyright[] = 328fae3551SRodney W. Grimes "@(#) Copyright (c) 1980, 1989, 1993, 1994\n\ 338fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 348fae3551SRodney W. Grimes #endif /* not lint */ 358fae3551SRodney W. Grimes 368fae3551SRodney W. Grimes #ifndef lint 37fba1c154SSteve Price #if 0 38c06fe0a0SPeter Wemm static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95"; 39fba1c154SSteve Price #endif 40bcb1d846SPhilippe Charnier static const char rcsid[] = 417f3dea24SPeter Wemm "$FreeBSD$"; 428fae3551SRodney W. Grimes #endif /* not lint */ 438fae3551SRodney W. Grimes 448fae3551SRodney W. Grimes #include <sys/param.h> 458fae3551SRodney W. Grimes #include <sys/mount.h> 468a978495SDavid Greenman #include <sys/stat.h> 4774cf460bSBruce Evans #include <sys/wait.h> 488fae3551SRodney W. Grimes 49003dbca6SMaxime Henrion #include <ctype.h> 508fae3551SRodney W. Grimes #include <err.h> 518fae3551SRodney W. Grimes #include <errno.h> 528fae3551SRodney W. Grimes #include <fstab.h> 53a3ba4c65SGordon Tetlow #include <paths.h> 54c06fe0a0SPeter Wemm #include <pwd.h> 558fae3551SRodney W. Grimes #include <signal.h> 5696c65ccbSIan Dowse #include <stdint.h> 578fae3551SRodney W. Grimes #include <stdio.h> 588fae3551SRodney W. Grimes #include <stdlib.h> 598fae3551SRodney W. Grimes #include <string.h> 608fae3551SRodney W. Grimes #include <unistd.h> 618fae3551SRodney W. Grimes 62fba1c154SSteve Price #include "extern.h" 6373dd3167SPoul-Henning Kamp #include "mntopts.h" 648fae3551SRodney W. Grimes #include "pathnames.h" 658fae3551SRodney W. Grimes 6618af6044SJoseph Koshy /* `meta' options */ 6718af6044SJoseph Koshy #define MOUNT_META_OPTION_FSTAB "fstab" 6818af6044SJoseph Koshy #define MOUNT_META_OPTION_CURRENT "current" 6918af6044SJoseph Koshy 7074cf460bSBruce Evans int debug, fstab_style, verbose; 71a257a45eSJordan K. Hubbard 7285429990SWarner Losh char *catopt(char *, const char *); 7385429990SWarner Losh struct statfs *getmntpt(const char *); 7485429990SWarner Losh int hasopt(const char *, const char *); 7585429990SWarner Losh int ismounted(struct fstab *, struct statfs *, int); 7685429990SWarner Losh int isremountable(const char *); 7785429990SWarner Losh void mangle(char *, int *, const char **); 7885429990SWarner Losh char *update_options(char *, char *, int); 7985429990SWarner Losh int mountfs(const char *, const char *, const char *, 8085429990SWarner Losh int, const char *, const char *); 8185429990SWarner Losh void remopt(char *, const char *); 8285429990SWarner Losh void prmount(struct statfs *); 8385429990SWarner Losh void putfsent(const struct statfs *); 8485429990SWarner Losh void usage(void); 8585429990SWarner Losh char *flags2opts(int); 868fae3551SRodney W. Grimes 87bcb1d846SPhilippe Charnier /* Map from mount options to printable formats. */ 888fae3551SRodney W. Grimes static struct opt { 898fae3551SRodney W. Grimes int o_opt; 908fae3551SRodney W. Grimes const char *o_name; 918fae3551SRodney W. Grimes } optnames[] = { 928fae3551SRodney W. Grimes { MNT_ASYNC, "asynchronous" }, 938fae3551SRodney W. Grimes { MNT_EXPORTED, "NFS exported" }, 948fae3551SRodney W. Grimes { MNT_LOCAL, "local" }, 9555e50aceSDavid Greenman { MNT_NOATIME, "noatime" }, 968fae3551SRodney W. Grimes { MNT_NOEXEC, "noexec" }, 978fae3551SRodney W. Grimes { MNT_NOSUID, "nosuid" }, 985ddc8dedSWolfram Schneider { MNT_NOSYMFOLLOW, "nosymfollow" }, 998fae3551SRodney W. Grimes { MNT_QUOTA, "with quotas" }, 1008fae3551SRodney W. Grimes { MNT_RDONLY, "read-only" }, 1018fae3551SRodney W. Grimes { MNT_SYNCHRONOUS, "synchronous" }, 1028fae3551SRodney W. Grimes { MNT_UNION, "union" }, 10375b714acSKATO Takenori { MNT_NOCLUSTERR, "noclusterr" }, 10475b714acSKATO Takenori { MNT_NOCLUSTERW, "noclusterw" }, 10552bf64c7SJulian Elischer { MNT_SUIDDIR, "suiddir" }, 106b1897c19SJulian Elischer { MNT_SOFTDEP, "soft-updates" }, 107ba0fbe96SRobert Watson { MNT_MULTILABEL, "multilabel" }, 10803d94b50SRobert Watson { MNT_ACLS, "acls" }, 10918af6044SJoseph Koshy { 0, NULL } 1108fae3551SRodney W. Grimes }; 1118fae3551SRodney W. Grimes 112fba1c154SSteve Price /* 113fba1c154SSteve Price * List of VFS types that can be remounted without becoming mounted on top 114fba1c154SSteve Price * of each other. 115fba1c154SSteve Price * XXX Is this list correct? 116fba1c154SSteve Price */ 117fba1c154SSteve Price static const char * 118fba1c154SSteve Price remountable_fs_names[] = { 1195a4420e3SAlexey Zelkin "ufs", "ffs", "ext2fs", 120fba1c154SSteve Price 0 121fba1c154SSteve Price }; 122fba1c154SSteve Price 1238fae3551SRodney W. Grimes int 1248fae3551SRodney W. Grimes main(argc, argv) 1258fae3551SRodney W. Grimes int argc; 1268fae3551SRodney W. Grimes char * const argv[]; 1278fae3551SRodney W. Grimes { 128c06fe0a0SPeter Wemm const char *mntfromname, **vfslist, *vfstype; 1298fae3551SRodney W. Grimes struct fstab *fs; 1308fae3551SRodney W. Grimes struct statfs *mntbuf; 1318fae3551SRodney W. Grimes FILE *mountdfp; 1328fae3551SRodney W. Grimes pid_t pid; 133cf96af72SBrian Feldman int all, ch, i, init_flags, mntsize, rval, have_fstab; 134003dbca6SMaxime Henrion char *cp, *ep, *options; 1358fae3551SRodney W. Grimes 1368fae3551SRodney W. Grimes all = init_flags = 0; 1378fae3551SRodney W. Grimes options = NULL; 1388fae3551SRodney W. Grimes vfslist = NULL; 1398fae3551SRodney W. Grimes vfstype = "ufs"; 140ef258dd9SMatthew N. Dodd while ((ch = getopt(argc, argv, "adF:fo:prwt:uv")) != -1) 1418fae3551SRodney W. Grimes switch (ch) { 1428fae3551SRodney W. Grimes case 'a': 1438fae3551SRodney W. Grimes all = 1; 1448fae3551SRodney W. Grimes break; 1458fae3551SRodney W. Grimes case 'd': 1468fae3551SRodney W. Grimes debug = 1; 1478fae3551SRodney W. Grimes break; 148ef258dd9SMatthew N. Dodd case 'F': 149ef258dd9SMatthew N. Dodd setfstab(optarg); 150ef258dd9SMatthew N. Dodd break; 1518fae3551SRodney W. Grimes case 'f': 1528fae3551SRodney W. Grimes init_flags |= MNT_FORCE; 1538fae3551SRodney W. Grimes break; 1548fae3551SRodney W. Grimes case 'o': 1558fae3551SRodney W. Grimes if (*optarg) 1568fae3551SRodney W. Grimes options = catopt(options, optarg); 1578fae3551SRodney W. Grimes break; 15874cf460bSBruce Evans case 'p': 15974cf460bSBruce Evans fstab_style = 1; 16074cf460bSBruce Evans verbose = 1; 16174cf460bSBruce Evans break; 1628fae3551SRodney W. Grimes case 'r': 163ad044771SDima Dorfman options = catopt(options, "ro"); 1648fae3551SRodney W. Grimes break; 1658fae3551SRodney W. Grimes case 't': 1668fae3551SRodney W. Grimes if (vfslist != NULL) 167bcb1d846SPhilippe Charnier errx(1, "only one -t option may be specified"); 1688fae3551SRodney W. Grimes vfslist = makevfslist(optarg); 1698fae3551SRodney W. Grimes vfstype = optarg; 1708fae3551SRodney W. Grimes break; 1718fae3551SRodney W. Grimes case 'u': 1728fae3551SRodney W. Grimes init_flags |= MNT_UPDATE; 1738fae3551SRodney W. Grimes break; 1748fae3551SRodney W. Grimes case 'v': 1758fae3551SRodney W. Grimes verbose = 1; 1768fae3551SRodney W. Grimes break; 1778fae3551SRodney W. Grimes case 'w': 178ad044771SDima Dorfman options = catopt(options, "noro"); 1798fae3551SRodney W. Grimes break; 1808fae3551SRodney W. Grimes case '?': 1818fae3551SRodney W. Grimes default: 1828fae3551SRodney W. Grimes usage(); 1838fae3551SRodney W. Grimes /* NOTREACHED */ 1848fae3551SRodney W. Grimes } 1858fae3551SRodney W. Grimes argc -= optind; 1868fae3551SRodney W. Grimes argv += optind; 1878fae3551SRodney W. Grimes 1888fae3551SRodney W. Grimes #define BADTYPE(type) \ 1898fae3551SRodney W. Grimes (strcmp(type, FSTAB_RO) && \ 1908fae3551SRodney W. Grimes strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 1918fae3551SRodney W. Grimes 1928fae3551SRodney W. Grimes rval = 0; 1938fae3551SRodney W. Grimes switch (argc) { 1948fae3551SRodney W. Grimes case 0: 195fba1c154SSteve Price if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 196fba1c154SSteve Price err(1, "getmntinfo"); 197fba1c154SSteve Price if (all) { 1988fae3551SRodney W. Grimes while ((fs = getfsent()) != NULL) { 1998fae3551SRodney W. Grimes if (BADTYPE(fs->fs_type)) 2008fae3551SRodney W. Grimes continue; 201c06fe0a0SPeter Wemm if (checkvfsname(fs->fs_vfstype, vfslist)) 2028fae3551SRodney W. Grimes continue; 203c06fe0a0SPeter Wemm if (hasopt(fs->fs_mntops, "noauto")) 20489beb278SDavid Greenman continue; 20598201b0cSBruce Evans if (!(init_flags & MNT_UPDATE) && 20698201b0cSBruce Evans ismounted(fs, mntbuf, mntsize)) 207fba1c154SSteve Price continue; 20813cbdf24SGuido van Rooij options = update_options(options, fs->fs_mntops, 20913cbdf24SGuido van Rooij mntbuf->f_flags); 2108fae3551SRodney W. Grimes if (mountfs(fs->fs_vfstype, fs->fs_spec, 2118fae3551SRodney W. Grimes fs->fs_file, init_flags, options, 2128fae3551SRodney W. Grimes fs->fs_mntops)) 2138fae3551SRodney W. Grimes rval = 1; 2148fae3551SRodney W. Grimes } 215fba1c154SSteve Price } else if (fstab_style) { 216a257a45eSJordan K. Hubbard for (i = 0; i < mntsize; i++) { 217c06fe0a0SPeter Wemm if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 218a257a45eSJordan K. Hubbard continue; 219a257a45eSJordan K. Hubbard putfsent(&mntbuf[i]); 220a257a45eSJordan K. Hubbard } 22174cf460bSBruce Evans } else { 2228fae3551SRodney W. Grimes for (i = 0; i < mntsize; i++) { 22374cf460bSBruce Evans if (checkvfsname(mntbuf[i].f_fstypename, 22474cf460bSBruce Evans vfslist)) 2258fae3551SRodney W. Grimes continue; 226c06fe0a0SPeter Wemm prmount(&mntbuf[i]); 2278fae3551SRodney W. Grimes } 2288fae3551SRodney W. Grimes } 2298fae3551SRodney W. Grimes exit(rval); 2308fae3551SRodney W. Grimes case 1: 2318fae3551SRodney W. Grimes if (vfslist != NULL) 2328fae3551SRodney W. Grimes usage(); 2338fae3551SRodney W. Grimes 23401a9bce5SEric Anholt rmslashes(*argv, *argv); 2358fae3551SRodney W. Grimes if (init_flags & MNT_UPDATE) { 236cf96af72SBrian Feldman mntfromname = NULL; 237cf96af72SBrian Feldman have_fstab = 0; 2388fae3551SRodney W. Grimes if ((mntbuf = getmntpt(*argv)) == NULL) 239cf96af72SBrian Feldman errx(1, "not currently mounted %s", *argv); 240cf96af72SBrian Feldman /* 241cf96af72SBrian Feldman * Only get the mntflags from fstab if both mntpoint 242cf96af72SBrian Feldman * and mntspec are identical. Also handle the special 243cf96af72SBrian Feldman * case where just '/' is mounted and 'spec' is not 244cf96af72SBrian Feldman * identical with the one from fstab ('/dev' is missing 245cf96af72SBrian Feldman * in the spec-string at boot-time). 246cf96af72SBrian Feldman */ 24718af6044SJoseph Koshy if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 248cf96af72SBrian Feldman if (strcmp(fs->fs_spec, 249cf96af72SBrian Feldman mntbuf->f_mntfromname) == 0 && 250cf96af72SBrian Feldman strcmp(fs->fs_file, 251cf96af72SBrian Feldman mntbuf->f_mntonname) == 0) { 252cf96af72SBrian Feldman have_fstab = 1; 253cf96af72SBrian Feldman mntfromname = mntbuf->f_mntfromname; 254cf96af72SBrian Feldman } else if (argv[0][0] == '/' && 255cf96af72SBrian Feldman argv[0][1] == '\0') { 256cf96af72SBrian Feldman fs = getfsfile("/"); 257cf96af72SBrian Feldman have_fstab = 1; 258c06fe0a0SPeter Wemm mntfromname = fs->fs_spec; 259cf96af72SBrian Feldman } 260cf96af72SBrian Feldman } 261cf96af72SBrian Feldman if (have_fstab) { 26218af6044SJoseph Koshy options = update_options(options, fs->fs_mntops, 26318af6044SJoseph Koshy mntbuf->f_flags); 26418af6044SJoseph Koshy } else { 265c06fe0a0SPeter Wemm mntfromname = mntbuf->f_mntfromname; 26618af6044SJoseph Koshy options = update_options(options, NULL, 26718af6044SJoseph Koshy mntbuf->f_flags); 26818af6044SJoseph Koshy } 269c06fe0a0SPeter Wemm rval = mountfs(mntbuf->f_fstypename, mntfromname, 270c06fe0a0SPeter Wemm mntbuf->f_mntonname, init_flags, options, 0); 271c06fe0a0SPeter Wemm break; 272c06fe0a0SPeter Wemm } 2738fae3551SRodney W. Grimes if ((fs = getfsfile(*argv)) == NULL && 2748fae3551SRodney W. Grimes (fs = getfsspec(*argv)) == NULL) 275bcb1d846SPhilippe Charnier errx(1, "%s: unknown special file or file system", 2768fae3551SRodney W. Grimes *argv); 2778fae3551SRodney W. Grimes if (BADTYPE(fs->fs_type)) 278bcb1d846SPhilippe Charnier errx(1, "%s has unknown file system type", 2798fae3551SRodney W. Grimes *argv); 280c06fe0a0SPeter Wemm rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, 281c06fe0a0SPeter Wemm init_flags, options, fs->fs_mntops); 2828fae3551SRodney W. Grimes break; 2838fae3551SRodney W. Grimes case 2: 2848fae3551SRodney W. Grimes /* 285cf96af72SBrian Feldman * If -t flag has not been specified, the path cannot be 286003dbca6SMaxime Henrion * found, spec contains either a ':' or a '@', then assume 287cf96af72SBrian Feldman * that an NFS file system is being specified ala Sun. 288003dbca6SMaxime Henrion * Check if the hostname contains only allowed characters 289003dbca6SMaxime Henrion * to reduce false positives. IPv6 addresses containing 290003dbca6SMaxime Henrion * ':' will be correctly parsed only if the separator is '@'. 291003dbca6SMaxime Henrion * The definition of a valid hostname is taken from RFC 1034. 2928fae3551SRodney W. Grimes */ 29305779418SIan Dowse if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL || 29405779418SIan Dowse (ep = strchr(argv[0], ':')) != NULL)) { 295da85c82bSMaxime Henrion if (*ep == '@') { 296da85c82bSMaxime Henrion cp = ep + 1; 297da85c82bSMaxime Henrion ep = cp + strlen(cp); 298da85c82bSMaxime Henrion } else 299003dbca6SMaxime Henrion cp = argv[0]; 300003dbca6SMaxime Henrion while (cp != ep) { 301003dbca6SMaxime Henrion if (!isdigit(*cp) && !isalpha(*cp) && 302003dbca6SMaxime Henrion *cp != '.' && *cp != '-' && *cp != ':') 303003dbca6SMaxime Henrion break; 304003dbca6SMaxime Henrion cp++; 305003dbca6SMaxime Henrion } 306003dbca6SMaxime Henrion if (cp == ep) 3078fae3551SRodney W. Grimes vfstype = "nfs"; 308003dbca6SMaxime Henrion } 3098fae3551SRodney W. Grimes rval = mountfs(vfstype, 3108fae3551SRodney W. Grimes argv[0], argv[1], init_flags, options, NULL); 3118fae3551SRodney W. Grimes break; 3128fae3551SRodney W. Grimes default: 3138fae3551SRodney W. Grimes usage(); 3148fae3551SRodney W. Grimes /* NOTREACHED */ 3158fae3551SRodney W. Grimes } 3168fae3551SRodney W. Grimes 3178fae3551SRodney W. Grimes /* 3188fae3551SRodney W. Grimes * If the mount was successfully, and done by root, tell mountd the 3198fae3551SRodney W. Grimes * good news. Pid checks are probably unnecessary, but don't hurt. 3208fae3551SRodney W. Grimes */ 3218fae3551SRodney W. Grimes if (rval == 0 && getuid() == 0 && 3228fae3551SRodney W. Grimes (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 323fba1c154SSteve Price if (fscanf(mountdfp, "%d", &pid) == 1 && 3248fae3551SRodney W. Grimes pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) 3258fae3551SRodney W. Grimes err(1, "signal mountd"); 3268fae3551SRodney W. Grimes (void)fclose(mountdfp); 3278fae3551SRodney W. Grimes } 3288fae3551SRodney W. Grimes 3298fae3551SRodney W. Grimes exit(rval); 3308fae3551SRodney W. Grimes } 3318fae3551SRodney W. Grimes 3328fae3551SRodney W. Grimes int 333fba1c154SSteve Price ismounted(fs, mntbuf, mntsize) 334fba1c154SSteve Price struct fstab *fs; 335fba1c154SSteve Price struct statfs *mntbuf; 336fba1c154SSteve Price int mntsize; 337fba1c154SSteve Price { 338fba1c154SSteve Price int i; 339fba1c154SSteve Price 340fba1c154SSteve Price if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0') 341fba1c154SSteve Price /* the root file system can always be remounted */ 342fba1c154SSteve Price return (0); 343fba1c154SSteve Price 344fba1c154SSteve Price for (i = mntsize - 1; i >= 0; --i) 345fba1c154SSteve Price if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 && 346fba1c154SSteve Price (!isremountable(fs->fs_vfstype) || 347fba1c154SSteve Price strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0)) 348fba1c154SSteve Price return (1); 349fba1c154SSteve Price return (0); 350fba1c154SSteve Price } 351fba1c154SSteve Price 352fba1c154SSteve Price int 353fba1c154SSteve Price isremountable(vfsname) 354fba1c154SSteve Price const char *vfsname; 355fba1c154SSteve Price { 356fba1c154SSteve Price const char **cp; 357fba1c154SSteve Price 358fba1c154SSteve Price for (cp = remountable_fs_names; *cp; cp++) 359fba1c154SSteve Price if (strcmp(*cp, vfsname) == 0) 360fba1c154SSteve Price return (1); 361fba1c154SSteve Price return (0); 362fba1c154SSteve Price } 363fba1c154SSteve Price 364fba1c154SSteve Price int 365c06fe0a0SPeter Wemm hasopt(mntopts, option) 366c06fe0a0SPeter Wemm const char *mntopts, *option; 367c06fe0a0SPeter Wemm { 368c06fe0a0SPeter Wemm int negative, found; 369c06fe0a0SPeter Wemm char *opt, *optbuf; 370c06fe0a0SPeter Wemm 371c06fe0a0SPeter Wemm if (option[0] == 'n' && option[1] == 'o') { 372c06fe0a0SPeter Wemm negative = 1; 373c06fe0a0SPeter Wemm option += 2; 374c06fe0a0SPeter Wemm } else 375c06fe0a0SPeter Wemm negative = 0; 376c06fe0a0SPeter Wemm optbuf = strdup(mntopts); 377c06fe0a0SPeter Wemm found = 0; 378c06fe0a0SPeter Wemm for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 379c06fe0a0SPeter Wemm if (opt[0] == 'n' && opt[1] == 'o') { 380c06fe0a0SPeter Wemm if (!strcasecmp(opt + 2, option)) 381c06fe0a0SPeter Wemm found = negative; 382c06fe0a0SPeter Wemm } else if (!strcasecmp(opt, option)) 383c06fe0a0SPeter Wemm found = !negative; 384c06fe0a0SPeter Wemm } 385c06fe0a0SPeter Wemm free(optbuf); 386c06fe0a0SPeter Wemm return (found); 387c06fe0a0SPeter Wemm } 388c06fe0a0SPeter Wemm 389c06fe0a0SPeter Wemm int 3908fae3551SRodney W. Grimes mountfs(vfstype, spec, name, flags, options, mntopts) 3918fae3551SRodney W. Grimes const char *vfstype, *spec, *name, *options, *mntopts; 3928fae3551SRodney W. Grimes int flags; 3938fae3551SRodney W. Grimes { 39405779418SIan Dowse const char *argv[100]; 3958fae3551SRodney W. Grimes struct statfs sf; 3968fae3551SRodney W. Grimes pid_t pid; 3978fae3551SRodney W. Grimes int argc, i, status; 39868dd1ff4SWarner Losh char *optbuf, execname[PATH_MAX], mntpath[PATH_MAX]; 3998fae3551SRodney W. Grimes 400fba1c154SSteve Price #if __GNUC__ 401fba1c154SSteve Price (void)&optbuf; 402fba1c154SSteve Price (void)&name; 403fba1c154SSteve Price #endif 404fba1c154SSteve Price 40573dd3167SPoul-Henning Kamp /* resolve the mountpoint with realpath(3) */ 40673dd3167SPoul-Henning Kamp (void)checkpath(name, mntpath); 4078fae3551SRodney W. Grimes name = mntpath; 4088fae3551SRodney W. Grimes 409c06fe0a0SPeter Wemm if (mntopts == NULL) 410c06fe0a0SPeter Wemm mntopts = ""; 4118fae3551SRodney W. Grimes if (options == NULL) { 412c06fe0a0SPeter Wemm if (*mntopts == '\0') { 4138fae3551SRodney W. Grimes options = "rw"; 414c06fe0a0SPeter Wemm } else { 4158fae3551SRodney W. Grimes options = mntopts; 4168fae3551SRodney W. Grimes mntopts = ""; 4178fae3551SRodney W. Grimes } 418c06fe0a0SPeter Wemm } 4198fae3551SRodney W. Grimes optbuf = catopt(strdup(mntopts), options); 4208fae3551SRodney W. Grimes 4218fae3551SRodney W. Grimes if (strcmp(name, "/") == 0) 4228fae3551SRodney W. Grimes flags |= MNT_UPDATE; 4238fae3551SRodney W. Grimes if (flags & MNT_FORCE) 4248fae3551SRodney W. Grimes optbuf = catopt(optbuf, "force"); 4258fae3551SRodney W. Grimes if (flags & MNT_RDONLY) 4268fae3551SRodney W. Grimes optbuf = catopt(optbuf, "ro"); 4278fae3551SRodney W. Grimes /* 4288fae3551SRodney W. Grimes * XXX 4298fae3551SRodney W. Grimes * The mount_mfs (newfs) command uses -o to select the 430bcb1d846SPhilippe Charnier * optimization mode. We don't pass the default "-o rw" 4318fae3551SRodney W. Grimes * for that reason. 4328fae3551SRodney W. Grimes */ 4338fae3551SRodney W. Grimes if (flags & MNT_UPDATE) 4348fae3551SRodney W. Grimes optbuf = catopt(optbuf, "update"); 4358fae3551SRodney W. Grimes 4364ccd7546SRuslan Ermilov /* Compatibility glue. */ 4374ccd7546SRuslan Ermilov if (strcmp(vfstype, "msdos") == 0) 4384ccd7546SRuslan Ermilov vfstype = "msdosfs"; 4394ccd7546SRuslan Ermilov 4408fae3551SRodney W. Grimes argc = 0; 4418fae3551SRodney W. Grimes argv[argc++] = vfstype; 4428fae3551SRodney W. Grimes mangle(optbuf, &argc, argv); 4438fae3551SRodney W. Grimes argv[argc++] = spec; 4448fae3551SRodney W. Grimes argv[argc++] = name; 4458fae3551SRodney W. Grimes argv[argc] = NULL; 4468fae3551SRodney W. Grimes 4478fae3551SRodney W. Grimes if (debug) { 4488fae3551SRodney W. Grimes (void)printf("exec: mount_%s", vfstype); 4498fae3551SRodney W. Grimes for (i = 1; i < argc; i++) 4508fae3551SRodney W. Grimes (void)printf(" %s", argv[i]); 4518fae3551SRodney W. Grimes (void)printf("\n"); 4528fae3551SRodney W. Grimes return (0); 4538fae3551SRodney W. Grimes } 4548fae3551SRodney W. Grimes 4557c506958SAndrey A. Chernov switch (pid = fork()) { 4568fae3551SRodney W. Grimes case -1: /* Error. */ 4577c506958SAndrey A. Chernov warn("fork"); 4588fae3551SRodney W. Grimes free(optbuf); 4598fae3551SRodney W. Grimes return (1); 4608fae3551SRodney W. Grimes case 0: /* Child. */ 4618fae3551SRodney W. Grimes if (strcmp(vfstype, "ufs") == 0) 4628fae3551SRodney W. Grimes exit(mount_ufs(argc, (char * const *) argv)); 4638fae3551SRodney W. Grimes 4648fae3551SRodney W. Grimes /* Go find an executable. */ 465a3ba4c65SGordon Tetlow (void)snprintf(execname, sizeof(execname), "mount_%s", vfstype); 466a3ba4c65SGordon Tetlow execvP(execname, _PATH_SYSPATH, (char * const *)argv); 467b6cf6bb2SSatoshi Asami if (errno == ENOENT) { 46805779418SIan Dowse warn("exec mount_%s not found in %s", vfstype, 46905779418SIan Dowse _PATH_SYSPATH); 470b6cf6bb2SSatoshi Asami } 4718fae3551SRodney W. Grimes exit(1); 4728fae3551SRodney W. Grimes /* NOTREACHED */ 4738fae3551SRodney W. Grimes default: /* Parent. */ 4748fae3551SRodney W. Grimes free(optbuf); 4758fae3551SRodney W. Grimes 4768fae3551SRodney W. Grimes if (waitpid(pid, &status, 0) < 0) { 4778fae3551SRodney W. Grimes warn("waitpid"); 4788fae3551SRodney W. Grimes return (1); 4798fae3551SRodney W. Grimes } 4808fae3551SRodney W. Grimes 4818fae3551SRodney W. Grimes if (WIFEXITED(status)) { 4828fae3551SRodney W. Grimes if (WEXITSTATUS(status) != 0) 4838fae3551SRodney W. Grimes return (WEXITSTATUS(status)); 4848fae3551SRodney W. Grimes } else if (WIFSIGNALED(status)) { 4858fae3551SRodney W. Grimes warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); 4868fae3551SRodney W. Grimes return (1); 4878fae3551SRodney W. Grimes } 4888fae3551SRodney W. Grimes 4898fae3551SRodney W. Grimes if (verbose) { 4908fae3551SRodney W. Grimes if (statfs(name, &sf) < 0) { 491c06fe0a0SPeter Wemm warn("statfs %s", name); 4928fae3551SRodney W. Grimes return (1); 4938fae3551SRodney W. Grimes } 494a257a45eSJordan K. Hubbard if (fstab_style) 495a257a45eSJordan K. Hubbard putfsent(&sf); 496a257a45eSJordan K. Hubbard else 497c06fe0a0SPeter Wemm prmount(&sf); 4988fae3551SRodney W. Grimes } 4998fae3551SRodney W. Grimes break; 5008fae3551SRodney W. Grimes } 5018fae3551SRodney W. Grimes 5028fae3551SRodney W. Grimes return (0); 5038fae3551SRodney W. Grimes } 5048fae3551SRodney W. Grimes 5058fae3551SRodney W. Grimes void 506c06fe0a0SPeter Wemm prmount(sfp) 507c06fe0a0SPeter Wemm struct statfs *sfp; 5088fae3551SRodney W. Grimes { 50938f102c2SIan Dowse int flags, i; 5108fae3551SRodney W. Grimes struct opt *o; 511c06fe0a0SPeter Wemm struct passwd *pw; 5128fae3551SRodney W. Grimes 513af2ea5aaSNick Hibma (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname, 514af2ea5aaSNick Hibma sfp->f_fstypename); 5158fae3551SRodney W. Grimes 516c06fe0a0SPeter Wemm flags = sfp->f_flags & MNT_VISFLAGMASK; 517af2ea5aaSNick Hibma for (o = optnames; flags && o->o_opt; o++) 5188fae3551SRodney W. Grimes if (flags & o->o_opt) { 519af2ea5aaSNick Hibma (void)printf(", %s", o->o_name); 5208fae3551SRodney W. Grimes flags &= ~o->o_opt; 5218fae3551SRodney W. Grimes } 522dc9c6194SPawel Jakub Dawidek /* 523dc9c6194SPawel Jakub Dawidek * Inform when file system is mounted by an unprivileged user 524dc9c6194SPawel Jakub Dawidek * or privileged non-root user. 525dc9c6194SPawel Jakub Dawidek */ 526ddb842ccSJacques Vidrine if ((flags & MNT_USER) != 0 || sfp->f_owner != 0) { 527af2ea5aaSNick Hibma (void)printf(", mounted by "); 528c06fe0a0SPeter Wemm if ((pw = getpwuid(sfp->f_owner)) != NULL) 529c06fe0a0SPeter Wemm (void)printf("%s", pw->pw_name); 530c06fe0a0SPeter Wemm else 531c06fe0a0SPeter Wemm (void)printf("%d", sfp->f_owner); 532c06fe0a0SPeter Wemm } 533c62ffab6SSheldon Hearn if (verbose) { 534677b9b3fSBruce Evans if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0) 53596c65ccbSIan Dowse (void)printf(", writes: sync %ju async %ju", 53696c65ccbSIan Dowse (uintmax_t)sfp->f_syncwrites, 53796c65ccbSIan Dowse (uintmax_t)sfp->f_asyncwrites); 538461bb71eSKirk McKusick if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0) 53996c65ccbSIan Dowse (void)printf(", reads: sync %ju async %ju", 54096c65ccbSIan Dowse (uintmax_t)sfp->f_syncreads, 54196c65ccbSIan Dowse (uintmax_t)sfp->f_asyncreads); 54205779418SIan Dowse if (sfp->f_fsid.val[0] != 0 || sfp->f_fsid.val[1] != 0) { 54338f102c2SIan Dowse printf(", fsid "); 54438f102c2SIan Dowse for (i = 0; i < sizeof(sfp->f_fsid); i++) 54538f102c2SIan Dowse printf("%02x", ((u_char *)&sfp->f_fsid)[i]); 546c62ffab6SSheldon Hearn } 54705779418SIan Dowse } 548af2ea5aaSNick Hibma (void)printf(")\n"); 5498fae3551SRodney W. Grimes } 5508fae3551SRodney W. Grimes 5518fae3551SRodney W. Grimes struct statfs * 5528fae3551SRodney W. Grimes getmntpt(name) 5538fae3551SRodney W. Grimes const char *name; 5548fae3551SRodney W. Grimes { 5558fae3551SRodney W. Grimes struct statfs *mntbuf; 5568fae3551SRodney W. Grimes int i, mntsize; 5578fae3551SRodney W. Grimes 5588fae3551SRodney W. Grimes mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 559cf96af72SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 5608fae3551SRodney W. Grimes if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 5618fae3551SRodney W. Grimes strcmp(mntbuf[i].f_mntonname, name) == 0) 5628fae3551SRodney W. Grimes return (&mntbuf[i]); 563cf96af72SBrian Feldman } 5648fae3551SRodney W. Grimes return (NULL); 5658fae3551SRodney W. Grimes } 5668fae3551SRodney W. Grimes 5678fae3551SRodney W. Grimes char * 5688fae3551SRodney W. Grimes catopt(s0, s1) 5698fae3551SRodney W. Grimes char *s0; 5708fae3551SRodney W. Grimes const char *s1; 5718fae3551SRodney W. Grimes { 5728fae3551SRodney W. Grimes size_t i; 5738fae3551SRodney W. Grimes char *cp; 5748fae3551SRodney W. Grimes 57518af6044SJoseph Koshy if (s1 == NULL || *s1 == '\0') 57618af6044SJoseph Koshy return s0; 57718af6044SJoseph Koshy 5788fae3551SRodney W. Grimes if (s0 && *s0) { 5798fae3551SRodney W. Grimes i = strlen(s0) + strlen(s1) + 1 + 1; 5808fae3551SRodney W. Grimes if ((cp = malloc(i)) == NULL) 581bcb1d846SPhilippe Charnier errx(1, "malloc failed"); 5828fae3551SRodney W. Grimes (void)snprintf(cp, i, "%s,%s", s0, s1); 5838fae3551SRodney W. Grimes } else 5848fae3551SRodney W. Grimes cp = strdup(s1); 5858fae3551SRodney W. Grimes 5868fae3551SRodney W. Grimes if (s0) 5878fae3551SRodney W. Grimes free(s0); 5888fae3551SRodney W. Grimes return (cp); 5898fae3551SRodney W. Grimes } 5908fae3551SRodney W. Grimes 5918fae3551SRodney W. Grimes void 5928fae3551SRodney W. Grimes mangle(options, argcp, argv) 5938fae3551SRodney W. Grimes char *options; 5948fae3551SRodney W. Grimes int *argcp; 5958fae3551SRodney W. Grimes const char **argv; 5968fae3551SRodney W. Grimes { 5978fae3551SRodney W. Grimes char *p, *s; 5988fae3551SRodney W. Grimes int argc; 5998fae3551SRodney W. Grimes 6008fae3551SRodney W. Grimes argc = *argcp; 6018fae3551SRodney W. Grimes for (s = options; (p = strsep(&s, ",")) != NULL;) 60218af6044SJoseph Koshy if (*p != '\0') { 6038fae3551SRodney W. Grimes if (*p == '-') { 6048fae3551SRodney W. Grimes argv[argc++] = p; 6058fae3551SRodney W. Grimes p = strchr(p, '='); 606adfdbe22STom Rhodes if (p != NULL) { 6078fae3551SRodney W. Grimes *p = '\0'; 6088fae3551SRodney W. Grimes argv[argc++] = p+1; 6098fae3551SRodney W. Grimes } 6108fae3551SRodney W. Grimes } else if (strcmp(p, "rw") != 0) { 6118fae3551SRodney W. Grimes argv[argc++] = "-o"; 6128fae3551SRodney W. Grimes argv[argc++] = p; 6138fae3551SRodney W. Grimes } 61418af6044SJoseph Koshy } 6158fae3551SRodney W. Grimes 6168fae3551SRodney W. Grimes *argcp = argc; 6178fae3551SRodney W. Grimes } 6188fae3551SRodney W. Grimes 61918af6044SJoseph Koshy 62018af6044SJoseph Koshy char * 62118af6044SJoseph Koshy update_options(opts, fstab, curflags) 62218af6044SJoseph Koshy char *opts; 62318af6044SJoseph Koshy char *fstab; 62418af6044SJoseph Koshy int curflags; 62518af6044SJoseph Koshy { 62618af6044SJoseph Koshy char *o, *p; 62718af6044SJoseph Koshy char *cur; 62818af6044SJoseph Koshy char *expopt, *newopt, *tmpopt; 62918af6044SJoseph Koshy 63018af6044SJoseph Koshy if (opts == NULL) 63118af6044SJoseph Koshy return strdup(""); 63218af6044SJoseph Koshy 63318af6044SJoseph Koshy /* remove meta options from list */ 63418af6044SJoseph Koshy remopt(fstab, MOUNT_META_OPTION_FSTAB); 63518af6044SJoseph Koshy remopt(fstab, MOUNT_META_OPTION_CURRENT); 63618af6044SJoseph Koshy cur = flags2opts(curflags); 63718af6044SJoseph Koshy 63818af6044SJoseph Koshy /* 63918af6044SJoseph Koshy * Expand all meta-options passed to us first. 64018af6044SJoseph Koshy */ 64118af6044SJoseph Koshy expopt = NULL; 64218af6044SJoseph Koshy for (p = opts; (o = strsep(&p, ",")) != NULL;) { 64318af6044SJoseph Koshy if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0) 64418af6044SJoseph Koshy expopt = catopt(expopt, fstab); 64518af6044SJoseph Koshy else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0) 64618af6044SJoseph Koshy expopt = catopt(expopt, cur); 64718af6044SJoseph Koshy else 64818af6044SJoseph Koshy expopt = catopt(expopt, o); 64918af6044SJoseph Koshy } 65018af6044SJoseph Koshy free(cur); 65118af6044SJoseph Koshy free(opts); 65218af6044SJoseph Koshy 65318af6044SJoseph Koshy /* 65418af6044SJoseph Koshy * Remove previous contradictory arguments. Given option "foo" we 65518af6044SJoseph Koshy * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo" 65618af6044SJoseph Koshy * and "foo" - so we can deal with possible options like "notice". 65718af6044SJoseph Koshy */ 65818af6044SJoseph Koshy newopt = NULL; 65918af6044SJoseph Koshy for (p = expopt; (o = strsep(&p, ",")) != NULL;) { 66018af6044SJoseph Koshy if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL) 66118af6044SJoseph Koshy errx(1, "malloc failed"); 66218af6044SJoseph Koshy 66318af6044SJoseph Koshy strcpy(tmpopt, "no"); 66418af6044SJoseph Koshy strcat(tmpopt, o); 66518af6044SJoseph Koshy remopt(newopt, tmpopt); 66618af6044SJoseph Koshy free(tmpopt); 66718af6044SJoseph Koshy 66818af6044SJoseph Koshy if (strncmp("no", o, 2) == 0) 66918af6044SJoseph Koshy remopt(newopt, o+2); 67018af6044SJoseph Koshy 67118af6044SJoseph Koshy newopt = catopt(newopt, o); 67218af6044SJoseph Koshy } 67318af6044SJoseph Koshy free(expopt); 67418af6044SJoseph Koshy 67518af6044SJoseph Koshy return newopt; 67618af6044SJoseph Koshy } 67718af6044SJoseph Koshy 67818af6044SJoseph Koshy void 67918af6044SJoseph Koshy remopt(string, opt) 68018af6044SJoseph Koshy char *string; 68118af6044SJoseph Koshy const char *opt; 68218af6044SJoseph Koshy { 68318af6044SJoseph Koshy char *o, *p, *r; 68418af6044SJoseph Koshy 68518af6044SJoseph Koshy if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0') 68618af6044SJoseph Koshy return; 68718af6044SJoseph Koshy 68818af6044SJoseph Koshy r = string; 68918af6044SJoseph Koshy 69018af6044SJoseph Koshy for (p = string; (o = strsep(&p, ",")) != NULL;) { 69118af6044SJoseph Koshy if (strcmp(opt, o) != 0) { 69218af6044SJoseph Koshy if (*r == ',' && *o != '\0') 69318af6044SJoseph Koshy r++; 69418af6044SJoseph Koshy while ((*r++ = *o++) != '\0') 69518af6044SJoseph Koshy ; 69618af6044SJoseph Koshy *--r = ','; 69718af6044SJoseph Koshy } 69818af6044SJoseph Koshy } 69918af6044SJoseph Koshy *r = '\0'; 70018af6044SJoseph Koshy } 70118af6044SJoseph Koshy 7028fae3551SRodney W. Grimes void 7038fae3551SRodney W. Grimes usage() 7048fae3551SRodney W. Grimes { 7058fae3551SRodney W. Grimes 706bcb1d846SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n%s\n", 7078d646af5SRuslan Ermilov "usage: mount [-adfpruvw] [-F fstab] [-o options] [-t ufs | external_type]", 7088d646af5SRuslan Ermilov " mount [-dfpruvw] special | node", 7098d646af5SRuslan Ermilov " mount [-dfpruvw] [-o options] [-t ufs | external_type] special node"); 7108fae3551SRodney W. Grimes exit(1); 7118fae3551SRodney W. Grimes } 712a257a45eSJordan K. Hubbard 713a257a45eSJordan K. Hubbard void 714a257a45eSJordan K. Hubbard putfsent(ent) 715a257a45eSJordan K. Hubbard const struct statfs *ent; 716a257a45eSJordan K. Hubbard { 717a257a45eSJordan K. Hubbard struct fstab *fst; 71818af6044SJoseph Koshy char *opts; 719a257a45eSJordan K. Hubbard 72018af6044SJoseph Koshy opts = flags2opts(ent->f_flags); 72174cf460bSBruce Evans printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname, 72218af6044SJoseph Koshy ent->f_fstypename, opts); 72318af6044SJoseph Koshy free(opts); 724c06fe0a0SPeter Wemm 725fba1c154SSteve Price if ((fst = getfsspec(ent->f_mntfromname))) 726a257a45eSJordan K. Hubbard printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 727fba1c154SSteve Price else if ((fst = getfsfile(ent->f_mntonname))) 728a257a45eSJordan K. Hubbard printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 729ab80d6faSBrian Feldman else if (strcmp(ent->f_fstypename, "ufs") == 0) { 730ab80d6faSBrian Feldman if (strcmp(ent->f_mntonname, "/") == 0) 731a257a45eSJordan K. Hubbard printf("\t1 1\n"); 732a257a45eSJordan K. Hubbard else 733ab80d6faSBrian Feldman printf("\t2 2\n"); 734ab80d6faSBrian Feldman } else 735a257a45eSJordan K. Hubbard printf("\t0 0\n"); 736a257a45eSJordan K. Hubbard } 73718af6044SJoseph Koshy 73818af6044SJoseph Koshy 73918af6044SJoseph Koshy char * 74018af6044SJoseph Koshy flags2opts(flags) 74118af6044SJoseph Koshy int flags; 74218af6044SJoseph Koshy { 74318af6044SJoseph Koshy char *res; 74418af6044SJoseph Koshy 74518af6044SJoseph Koshy res = NULL; 74618af6044SJoseph Koshy 74718af6044SJoseph Koshy res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw"); 74818af6044SJoseph Koshy 74918af6044SJoseph Koshy if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync"); 75018af6044SJoseph Koshy if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); 75118af6044SJoseph Koshy if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); 75218af6044SJoseph Koshy if (flags & MNT_UNION) res = catopt(res, "union"); 75318af6044SJoseph Koshy if (flags & MNT_ASYNC) res = catopt(res, "async"); 75418af6044SJoseph Koshy if (flags & MNT_NOATIME) res = catopt(res, "noatime"); 75518af6044SJoseph Koshy if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); 75618af6044SJoseph Koshy if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw"); 75718af6044SJoseph Koshy if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow"); 75818af6044SJoseph Koshy if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir"); 759ba0fbe96SRobert Watson if (flags & MNT_MULTILABEL) res = catopt(res, "multilabel"); 76003d94b50SRobert Watson if (flags & MNT_ACLS) res = catopt(res, "acls"); 76118af6044SJoseph Koshy 76218af6044SJoseph Koshy return res; 76318af6044SJoseph Koshy } 764