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> 57a3ba4c65SGordon Tetlow #include <paths.h> 58c06fe0a0SPeter Wemm #include <pwd.h> 598fae3551SRodney W. Grimes #include <signal.h> 608fae3551SRodney W. Grimes #include <stdio.h> 618fae3551SRodney W. Grimes #include <stdlib.h> 628fae3551SRodney W. Grimes #include <string.h> 638fae3551SRodney W. Grimes #include <unistd.h> 648fae3551SRodney W. Grimes 65fba1c154SSteve Price #include "extern.h" 6673dd3167SPoul-Henning Kamp #include "mntopts.h" 678fae3551SRodney W. Grimes #include "pathnames.h" 688fae3551SRodney W. Grimes 6918af6044SJoseph Koshy /* `meta' options */ 7018af6044SJoseph Koshy #define MOUNT_META_OPTION_FSTAB "fstab" 7118af6044SJoseph Koshy #define MOUNT_META_OPTION_CURRENT "current" 7218af6044SJoseph Koshy 7374cf460bSBruce Evans int debug, fstab_style, verbose; 74a257a45eSJordan K. Hubbard 7585429990SWarner Losh char *catopt(char *, const char *); 7685429990SWarner Losh struct statfs *getmntpt(const char *); 7785429990SWarner Losh int hasopt(const char *, const char *); 7885429990SWarner Losh int ismounted(struct fstab *, struct statfs *, int); 7985429990SWarner Losh int isremountable(const char *); 8085429990SWarner Losh void mangle(char *, int *, const char **); 8185429990SWarner Losh char *update_options(char *, char *, int); 8285429990SWarner Losh int mountfs(const char *, const char *, const char *, 8385429990SWarner Losh int, const char *, const char *); 8485429990SWarner Losh void remopt(char *, const char *); 8585429990SWarner Losh void prmount(struct statfs *); 8685429990SWarner Losh void putfsent(const struct statfs *); 8785429990SWarner Losh void usage(void); 8885429990SWarner Losh char *flags2opts(int); 898fae3551SRodney W. Grimes 90bcb1d846SPhilippe Charnier /* Map from mount options to printable formats. */ 918fae3551SRodney W. Grimes static struct opt { 928fae3551SRodney W. Grimes int o_opt; 938fae3551SRodney W. Grimes const char *o_name; 948fae3551SRodney W. Grimes } optnames[] = { 958fae3551SRodney W. Grimes { MNT_ASYNC, "asynchronous" }, 968fae3551SRodney W. Grimes { MNT_EXPORTED, "NFS exported" }, 978fae3551SRodney W. Grimes { MNT_LOCAL, "local" }, 9855e50aceSDavid Greenman { MNT_NOATIME, "noatime" }, 998fae3551SRodney W. Grimes { MNT_NODEV, "nodev" }, 1008fae3551SRodney W. Grimes { MNT_NOEXEC, "noexec" }, 1018fae3551SRodney W. Grimes { MNT_NOSUID, "nosuid" }, 1025ddc8dedSWolfram Schneider { MNT_NOSYMFOLLOW, "nosymfollow" }, 1038fae3551SRodney W. Grimes { MNT_QUOTA, "with quotas" }, 1048fae3551SRodney W. Grimes { MNT_RDONLY, "read-only" }, 1058fae3551SRodney W. Grimes { MNT_SYNCHRONOUS, "synchronous" }, 1068fae3551SRodney W. Grimes { MNT_UNION, "union" }, 10775b714acSKATO Takenori { MNT_NOCLUSTERR, "noclusterr" }, 10875b714acSKATO Takenori { MNT_NOCLUSTERW, "noclusterw" }, 10952bf64c7SJulian Elischer { MNT_SUIDDIR, "suiddir" }, 110b1897c19SJulian Elischer { MNT_SOFTDEP, "soft-updates" }, 111ba0fbe96SRobert Watson { MNT_MULTILABEL, "multilabel" }, 11203d94b50SRobert Watson { MNT_ACLS, "acls" }, 11318af6044SJoseph Koshy { 0, NULL } 1148fae3551SRodney W. Grimes }; 1158fae3551SRodney W. Grimes 116fba1c154SSteve Price /* 117fba1c154SSteve Price * List of VFS types that can be remounted without becoming mounted on top 118fba1c154SSteve Price * of each other. 119fba1c154SSteve Price * XXX Is this list correct? 120fba1c154SSteve Price */ 121fba1c154SSteve Price static const char * 122fba1c154SSteve Price remountable_fs_names[] = { 1235a4420e3SAlexey Zelkin "ufs", "ffs", "ext2fs", 124fba1c154SSteve Price 0 125fba1c154SSteve Price }; 126fba1c154SSteve Price 1278fae3551SRodney W. Grimes int 1288fae3551SRodney W. Grimes main(argc, argv) 1298fae3551SRodney W. Grimes int argc; 1308fae3551SRodney W. Grimes char * const argv[]; 1318fae3551SRodney W. Grimes { 132c06fe0a0SPeter Wemm const char *mntfromname, **vfslist, *vfstype; 1338fae3551SRodney W. Grimes struct fstab *fs; 1348fae3551SRodney W. Grimes struct statfs *mntbuf; 1358fae3551SRodney W. Grimes FILE *mountdfp; 1368fae3551SRodney W. Grimes pid_t pid; 137cf96af72SBrian Feldman int all, ch, i, init_flags, mntsize, rval, have_fstab; 138003dbca6SMaxime Henrion char *cp, *ep, *options; 1398fae3551SRodney W. Grimes 1408fae3551SRodney W. Grimes all = init_flags = 0; 1418fae3551SRodney W. Grimes options = NULL; 1428fae3551SRodney W. Grimes vfslist = NULL; 1438fae3551SRodney W. Grimes vfstype = "ufs"; 144ef258dd9SMatthew N. Dodd while ((ch = getopt(argc, argv, "adF:fo:prwt:uv")) != -1) 1458fae3551SRodney W. Grimes switch (ch) { 1468fae3551SRodney W. Grimes case 'a': 1478fae3551SRodney W. Grimes all = 1; 1488fae3551SRodney W. Grimes break; 1498fae3551SRodney W. Grimes case 'd': 1508fae3551SRodney W. Grimes debug = 1; 1518fae3551SRodney W. Grimes break; 152ef258dd9SMatthew N. Dodd case 'F': 153ef258dd9SMatthew N. Dodd setfstab(optarg); 154ef258dd9SMatthew N. Dodd break; 1558fae3551SRodney W. Grimes case 'f': 1568fae3551SRodney W. Grimes init_flags |= MNT_FORCE; 1578fae3551SRodney W. Grimes break; 1588fae3551SRodney W. Grimes case 'o': 1598fae3551SRodney W. Grimes if (*optarg) 1608fae3551SRodney W. Grimes options = catopt(options, optarg); 1618fae3551SRodney W. Grimes break; 16274cf460bSBruce Evans case 'p': 16374cf460bSBruce Evans fstab_style = 1; 16474cf460bSBruce Evans verbose = 1; 16574cf460bSBruce Evans break; 1668fae3551SRodney W. Grimes case 'r': 167ad044771SDima Dorfman options = catopt(options, "ro"); 1688fae3551SRodney W. Grimes break; 1698fae3551SRodney W. Grimes case 't': 1708fae3551SRodney W. Grimes if (vfslist != NULL) 171bcb1d846SPhilippe Charnier errx(1, "only one -t option may be specified"); 1728fae3551SRodney W. Grimes vfslist = makevfslist(optarg); 1738fae3551SRodney W. Grimes vfstype = optarg; 1748fae3551SRodney W. Grimes break; 1758fae3551SRodney W. Grimes case 'u': 1768fae3551SRodney W. Grimes init_flags |= MNT_UPDATE; 1778fae3551SRodney W. Grimes break; 1788fae3551SRodney W. Grimes case 'v': 1798fae3551SRodney W. Grimes verbose = 1; 1808fae3551SRodney W. Grimes break; 1818fae3551SRodney W. Grimes case 'w': 182ad044771SDima Dorfman options = catopt(options, "noro"); 1838fae3551SRodney W. Grimes break; 1848fae3551SRodney W. Grimes case '?': 1858fae3551SRodney W. Grimes default: 1868fae3551SRodney W. Grimes usage(); 1878fae3551SRodney W. Grimes /* NOTREACHED */ 1888fae3551SRodney W. Grimes } 1898fae3551SRodney W. Grimes argc -= optind; 1908fae3551SRodney W. Grimes argv += optind; 1918fae3551SRodney W. Grimes 1928fae3551SRodney W. Grimes #define BADTYPE(type) \ 1938fae3551SRodney W. Grimes (strcmp(type, FSTAB_RO) && \ 1948fae3551SRodney W. Grimes strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 1958fae3551SRodney W. Grimes 1968fae3551SRodney W. Grimes rval = 0; 1978fae3551SRodney W. Grimes switch (argc) { 1988fae3551SRodney W. Grimes case 0: 199fba1c154SSteve Price if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 200fba1c154SSteve Price err(1, "getmntinfo"); 201fba1c154SSteve Price if (all) { 2028fae3551SRodney W. Grimes while ((fs = getfsent()) != NULL) { 2038fae3551SRodney W. Grimes if (BADTYPE(fs->fs_type)) 2048fae3551SRodney W. Grimes continue; 205c06fe0a0SPeter Wemm if (checkvfsname(fs->fs_vfstype, vfslist)) 2068fae3551SRodney W. Grimes continue; 207c06fe0a0SPeter Wemm if (hasopt(fs->fs_mntops, "noauto")) 20889beb278SDavid Greenman continue; 20998201b0cSBruce Evans if (!(init_flags & MNT_UPDATE) && 21098201b0cSBruce Evans ismounted(fs, mntbuf, mntsize)) 211fba1c154SSteve Price continue; 2128fae3551SRodney W. Grimes if (mountfs(fs->fs_vfstype, fs->fs_spec, 2138fae3551SRodney W. Grimes fs->fs_file, init_flags, options, 2148fae3551SRodney W. Grimes fs->fs_mntops)) 2158fae3551SRodney W. Grimes rval = 1; 2168fae3551SRodney W. Grimes } 217fba1c154SSteve Price } else if (fstab_style) { 218a257a45eSJordan K. Hubbard for (i = 0; i < mntsize; i++) { 219c06fe0a0SPeter Wemm if (checkvfsname(mntbuf[i].f_fstypename, vfslist)) 220a257a45eSJordan K. Hubbard continue; 221a257a45eSJordan K. Hubbard putfsent(&mntbuf[i]); 222a257a45eSJordan K. Hubbard } 22374cf460bSBruce Evans } else { 2248fae3551SRodney W. Grimes for (i = 0; i < mntsize; i++) { 22574cf460bSBruce Evans if (checkvfsname(mntbuf[i].f_fstypename, 22674cf460bSBruce Evans vfslist)) 2278fae3551SRodney W. Grimes continue; 228c06fe0a0SPeter Wemm prmount(&mntbuf[i]); 2298fae3551SRodney W. Grimes } 2308fae3551SRodney W. Grimes } 2318fae3551SRodney W. Grimes exit(rval); 2328fae3551SRodney W. Grimes case 1: 2338fae3551SRodney W. Grimes if (vfslist != NULL) 2348fae3551SRodney W. Grimes usage(); 2358fae3551SRodney W. Grimes 2368fae3551SRodney W. Grimes if (init_flags & MNT_UPDATE) { 237cf96af72SBrian Feldman mntfromname = NULL; 238cf96af72SBrian Feldman have_fstab = 0; 2398fae3551SRodney W. Grimes if ((mntbuf = getmntpt(*argv)) == NULL) 240cf96af72SBrian Feldman errx(1, "not currently mounted %s", *argv); 241cf96af72SBrian Feldman /* 242cf96af72SBrian Feldman * Only get the mntflags from fstab if both mntpoint 243cf96af72SBrian Feldman * and mntspec are identical. Also handle the special 244cf96af72SBrian Feldman * case where just '/' is mounted and 'spec' is not 245cf96af72SBrian Feldman * identical with the one from fstab ('/dev' is missing 246cf96af72SBrian Feldman * in the spec-string at boot-time). 247cf96af72SBrian Feldman */ 24818af6044SJoseph Koshy if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 249cf96af72SBrian Feldman if (strcmp(fs->fs_spec, 250cf96af72SBrian Feldman mntbuf->f_mntfromname) == 0 && 251cf96af72SBrian Feldman strcmp(fs->fs_file, 252cf96af72SBrian Feldman mntbuf->f_mntonname) == 0) { 253cf96af72SBrian Feldman have_fstab = 1; 254cf96af72SBrian Feldman mntfromname = mntbuf->f_mntfromname; 255cf96af72SBrian Feldman } else if (argv[0][0] == '/' && 256cf96af72SBrian Feldman argv[0][1] == '\0') { 257cf96af72SBrian Feldman fs = getfsfile("/"); 258cf96af72SBrian Feldman have_fstab = 1; 259c06fe0a0SPeter Wemm mntfromname = fs->fs_spec; 260cf96af72SBrian Feldman } 261cf96af72SBrian Feldman } 262cf96af72SBrian Feldman if (have_fstab) { 26318af6044SJoseph Koshy options = update_options(options, fs->fs_mntops, 26418af6044SJoseph Koshy mntbuf->f_flags); 26518af6044SJoseph Koshy } else { 266c06fe0a0SPeter Wemm mntfromname = mntbuf->f_mntfromname; 26718af6044SJoseph Koshy options = update_options(options, NULL, 26818af6044SJoseph Koshy mntbuf->f_flags); 26918af6044SJoseph Koshy } 270c06fe0a0SPeter Wemm rval = mountfs(mntbuf->f_fstypename, mntfromname, 271c06fe0a0SPeter Wemm mntbuf->f_mntonname, init_flags, options, 0); 272c06fe0a0SPeter Wemm break; 273c06fe0a0SPeter Wemm } 2742b184c50SEivind Eklund rmslashes(*argv, *argv); 2758fae3551SRodney W. Grimes if ((fs = getfsfile(*argv)) == NULL && 2768fae3551SRodney W. Grimes (fs = getfsspec(*argv)) == NULL) 277bcb1d846SPhilippe Charnier errx(1, "%s: unknown special file or file system", 2788fae3551SRodney W. Grimes *argv); 2798fae3551SRodney W. Grimes if (BADTYPE(fs->fs_type)) 280bcb1d846SPhilippe Charnier errx(1, "%s has unknown file system type", 2818fae3551SRodney W. Grimes *argv); 282c06fe0a0SPeter Wemm rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, 283c06fe0a0SPeter Wemm init_flags, options, fs->fs_mntops); 2848fae3551SRodney W. Grimes break; 2858fae3551SRodney W. Grimes case 2: 2868fae3551SRodney W. Grimes /* 287cf96af72SBrian Feldman * If -t flag has not been specified, the path cannot be 288003dbca6SMaxime Henrion * found, spec contains either a ':' or a '@', then assume 289cf96af72SBrian Feldman * that an NFS file system is being specified ala Sun. 290003dbca6SMaxime Henrion * Check if the hostname contains only allowed characters 291003dbca6SMaxime Henrion * to reduce false positives. IPv6 addresses containing 292003dbca6SMaxime Henrion * ':' will be correctly parsed only if the separator is '@'. 293003dbca6SMaxime Henrion * The definition of a valid hostname is taken from RFC 1034. 2948fae3551SRodney W. Grimes */ 295003dbca6SMaxime Henrion if (vfslist == NULL && ((ep = strchr(argv[0], '@')) != NULL) || 296003dbca6SMaxime Henrion ((ep = strchr(argv[0], ':')) != NULL)) { 297da85c82bSMaxime Henrion if (*ep == '@') { 298da85c82bSMaxime Henrion cp = ep + 1; 299da85c82bSMaxime Henrion ep = cp + strlen(cp); 300da85c82bSMaxime Henrion } else 301003dbca6SMaxime Henrion cp = argv[0]; 302003dbca6SMaxime Henrion while (cp != ep) { 303003dbca6SMaxime Henrion if (!isdigit(*cp) && !isalpha(*cp) && 304003dbca6SMaxime Henrion *cp != '.' && *cp != '-' && *cp != ':') 305003dbca6SMaxime Henrion break; 306003dbca6SMaxime Henrion cp++; 307003dbca6SMaxime Henrion } 308003dbca6SMaxime Henrion if (cp == ep) 3098fae3551SRodney W. Grimes vfstype = "nfs"; 310003dbca6SMaxime Henrion } 3118fae3551SRodney W. Grimes rval = mountfs(vfstype, 3128fae3551SRodney W. Grimes argv[0], argv[1], init_flags, options, NULL); 3138fae3551SRodney W. Grimes break; 3148fae3551SRodney W. Grimes default: 3158fae3551SRodney W. Grimes usage(); 3168fae3551SRodney W. Grimes /* NOTREACHED */ 3178fae3551SRodney W. Grimes } 3188fae3551SRodney W. Grimes 3198fae3551SRodney W. Grimes /* 3208fae3551SRodney W. Grimes * If the mount was successfully, and done by root, tell mountd the 3218fae3551SRodney W. Grimes * good news. Pid checks are probably unnecessary, but don't hurt. 3228fae3551SRodney W. Grimes */ 3238fae3551SRodney W. Grimes if (rval == 0 && getuid() == 0 && 3248fae3551SRodney W. Grimes (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 325fba1c154SSteve Price if (fscanf(mountdfp, "%d", &pid) == 1 && 3268fae3551SRodney W. Grimes pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) 3278fae3551SRodney W. Grimes err(1, "signal mountd"); 3288fae3551SRodney W. Grimes (void)fclose(mountdfp); 3298fae3551SRodney W. Grimes } 3308fae3551SRodney W. Grimes 3318fae3551SRodney W. Grimes exit(rval); 3328fae3551SRodney W. Grimes } 3338fae3551SRodney W. Grimes 3348fae3551SRodney W. Grimes int 335fba1c154SSteve Price ismounted(fs, mntbuf, mntsize) 336fba1c154SSteve Price struct fstab *fs; 337fba1c154SSteve Price struct statfs *mntbuf; 338fba1c154SSteve Price int mntsize; 339fba1c154SSteve Price { 340fba1c154SSteve Price int i; 341fba1c154SSteve Price 342fba1c154SSteve Price if (fs->fs_file[0] == '/' && fs->fs_file[1] == '\0') 343fba1c154SSteve Price /* the root file system can always be remounted */ 344fba1c154SSteve Price return (0); 345fba1c154SSteve Price 346fba1c154SSteve Price for (i = mntsize - 1; i >= 0; --i) 347fba1c154SSteve Price if (strcmp(fs->fs_file, mntbuf[i].f_mntonname) == 0 && 348fba1c154SSteve Price (!isremountable(fs->fs_vfstype) || 349fba1c154SSteve Price strcmp(fs->fs_spec, mntbuf[i].f_mntfromname) == 0)) 350fba1c154SSteve Price return (1); 351fba1c154SSteve Price return (0); 352fba1c154SSteve Price } 353fba1c154SSteve Price 354fba1c154SSteve Price int 355fba1c154SSteve Price isremountable(vfsname) 356fba1c154SSteve Price const char *vfsname; 357fba1c154SSteve Price { 358fba1c154SSteve Price const char **cp; 359fba1c154SSteve Price 360fba1c154SSteve Price for (cp = remountable_fs_names; *cp; cp++) 361fba1c154SSteve Price if (strcmp(*cp, vfsname) == 0) 362fba1c154SSteve Price return (1); 363fba1c154SSteve Price return (0); 364fba1c154SSteve Price } 365fba1c154SSteve Price 366fba1c154SSteve Price int 367c06fe0a0SPeter Wemm hasopt(mntopts, option) 368c06fe0a0SPeter Wemm const char *mntopts, *option; 369c06fe0a0SPeter Wemm { 370c06fe0a0SPeter Wemm int negative, found; 371c06fe0a0SPeter Wemm char *opt, *optbuf; 372c06fe0a0SPeter Wemm 373c06fe0a0SPeter Wemm if (option[0] == 'n' && option[1] == 'o') { 374c06fe0a0SPeter Wemm negative = 1; 375c06fe0a0SPeter Wemm option += 2; 376c06fe0a0SPeter Wemm } else 377c06fe0a0SPeter Wemm negative = 0; 378c06fe0a0SPeter Wemm optbuf = strdup(mntopts); 379c06fe0a0SPeter Wemm found = 0; 380c06fe0a0SPeter Wemm for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 381c06fe0a0SPeter Wemm if (opt[0] == 'n' && opt[1] == 'o') { 382c06fe0a0SPeter Wemm if (!strcasecmp(opt + 2, option)) 383c06fe0a0SPeter Wemm found = negative; 384c06fe0a0SPeter Wemm } else if (!strcasecmp(opt, option)) 385c06fe0a0SPeter Wemm found = !negative; 386c06fe0a0SPeter Wemm } 387c06fe0a0SPeter Wemm free(optbuf); 388c06fe0a0SPeter Wemm return (found); 389c06fe0a0SPeter Wemm } 390c06fe0a0SPeter Wemm 391c06fe0a0SPeter Wemm int 3928fae3551SRodney W. Grimes mountfs(vfstype, spec, name, flags, options, mntopts) 3938fae3551SRodney W. Grimes const char *vfstype, *spec, *name, *options, *mntopts; 3948fae3551SRodney W. Grimes int flags; 3958fae3551SRodney W. Grimes { 3968fae3551SRodney W. Grimes const char *argv[100], **edir; 397a3ba4c65SGordon Tetlow char *path, *cur; 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. */ 468a3ba4c65SGordon Tetlow (void)snprintf(execname, sizeof(execname), "mount_%s", vfstype); 469a3ba4c65SGordon Tetlow execvP(execname, _PATH_SYSPATH, (char * const *)argv); 470b6cf6bb2SSatoshi Asami if (errno == ENOENT) { 471a3ba4c65SGordon Tetlow warn("exec mount_%s not found in %s", vfstype, path); 472b6cf6bb2SSatoshi Asami } 4738fae3551SRodney W. Grimes exit(1); 4748fae3551SRodney W. Grimes /* NOTREACHED */ 4758fae3551SRodney W. Grimes default: /* Parent. */ 4768fae3551SRodney W. Grimes free(optbuf); 4778fae3551SRodney W. Grimes 4788fae3551SRodney W. Grimes if (waitpid(pid, &status, 0) < 0) { 4798fae3551SRodney W. Grimes warn("waitpid"); 4808fae3551SRodney W. Grimes return (1); 4818fae3551SRodney W. Grimes } 4828fae3551SRodney W. Grimes 4838fae3551SRodney W. Grimes if (WIFEXITED(status)) { 4848fae3551SRodney W. Grimes if (WEXITSTATUS(status) != 0) 4858fae3551SRodney W. Grimes return (WEXITSTATUS(status)); 4868fae3551SRodney W. Grimes } else if (WIFSIGNALED(status)) { 4878fae3551SRodney W. Grimes warnx("%s: %s", name, sys_siglist[WTERMSIG(status)]); 4888fae3551SRodney W. Grimes return (1); 4898fae3551SRodney W. Grimes } 4908fae3551SRodney W. Grimes 4918fae3551SRodney W. Grimes if (verbose) { 4928fae3551SRodney W. Grimes if (statfs(name, &sf) < 0) { 493c06fe0a0SPeter Wemm warn("statfs %s", name); 4948fae3551SRodney W. Grimes return (1); 4958fae3551SRodney W. Grimes } 496a257a45eSJordan K. Hubbard if (fstab_style) 497a257a45eSJordan K. Hubbard putfsent(&sf); 498a257a45eSJordan K. Hubbard else 499c06fe0a0SPeter Wemm prmount(&sf); 5008fae3551SRodney W. Grimes } 5018fae3551SRodney W. Grimes break; 5028fae3551SRodney W. Grimes } 5038fae3551SRodney W. Grimes 5048fae3551SRodney W. Grimes return (0); 5058fae3551SRodney W. Grimes } 5068fae3551SRodney W. Grimes 5078fae3551SRodney W. Grimes void 508c06fe0a0SPeter Wemm prmount(sfp) 509c06fe0a0SPeter Wemm struct statfs *sfp; 5108fae3551SRodney W. Grimes { 511c06fe0a0SPeter Wemm int flags; 5128fae3551SRodney W. Grimes struct opt *o; 513c06fe0a0SPeter Wemm struct passwd *pw; 5148fae3551SRodney W. Grimes 515af2ea5aaSNick Hibma (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname, 516af2ea5aaSNick Hibma sfp->f_fstypename); 5178fae3551SRodney W. Grimes 518c06fe0a0SPeter Wemm flags = sfp->f_flags & MNT_VISFLAGMASK; 519af2ea5aaSNick Hibma for (o = optnames; flags && o->o_opt; o++) 5208fae3551SRodney W. Grimes if (flags & o->o_opt) { 521af2ea5aaSNick Hibma (void)printf(", %s", o->o_name); 5228fae3551SRodney W. Grimes flags &= ~o->o_opt; 5238fae3551SRodney W. Grimes } 524c06fe0a0SPeter Wemm if (sfp->f_owner) { 525af2ea5aaSNick Hibma (void)printf(", mounted by "); 526c06fe0a0SPeter Wemm if ((pw = getpwuid(sfp->f_owner)) != NULL) 527c06fe0a0SPeter Wemm (void)printf("%s", pw->pw_name); 528c06fe0a0SPeter Wemm else 529c06fe0a0SPeter Wemm (void)printf("%d", sfp->f_owner); 530c06fe0a0SPeter Wemm } 531c62ffab6SSheldon Hearn if (verbose) { 532677b9b3fSBruce Evans if (sfp->f_syncwrites != 0 || sfp->f_asyncwrites != 0) 533af2ea5aaSNick Hibma (void)printf(", writes: sync %ld async %ld", 534af2ea5aaSNick Hibma sfp->f_syncwrites, sfp->f_asyncwrites); 535461bb71eSKirk McKusick if (sfp->f_syncreads != 0 || sfp->f_asyncreads != 0) 536461bb71eSKirk McKusick (void)printf(", reads: sync %ld async %ld", 537461bb71eSKirk McKusick sfp->f_syncreads, sfp->f_asyncreads); 538c62ffab6SSheldon Hearn } 539af2ea5aaSNick Hibma (void)printf(")\n"); 5408fae3551SRodney W. Grimes } 5418fae3551SRodney W. Grimes 5428fae3551SRodney W. Grimes struct statfs * 5438fae3551SRodney W. Grimes getmntpt(name) 5448fae3551SRodney W. Grimes const char *name; 5458fae3551SRodney W. Grimes { 5468fae3551SRodney W. Grimes struct statfs *mntbuf; 5478fae3551SRodney W. Grimes int i, mntsize; 5488fae3551SRodney W. Grimes 5498fae3551SRodney W. Grimes mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 550cf96af72SBrian Feldman for (i = mntsize - 1; i >= 0; i--) { 5518fae3551SRodney W. Grimes if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 5528fae3551SRodney W. Grimes strcmp(mntbuf[i].f_mntonname, name) == 0) 5538fae3551SRodney W. Grimes return (&mntbuf[i]); 554cf96af72SBrian Feldman } 5558fae3551SRodney W. Grimes return (NULL); 5568fae3551SRodney W. Grimes } 5578fae3551SRodney W. Grimes 5588fae3551SRodney W. Grimes char * 5598fae3551SRodney W. Grimes catopt(s0, s1) 5608fae3551SRodney W. Grimes char *s0; 5618fae3551SRodney W. Grimes const char *s1; 5628fae3551SRodney W. Grimes { 5638fae3551SRodney W. Grimes size_t i; 5648fae3551SRodney W. Grimes char *cp; 5658fae3551SRodney W. Grimes 56618af6044SJoseph Koshy if (s1 == NULL || *s1 == '\0') 56718af6044SJoseph Koshy return s0; 56818af6044SJoseph Koshy 5698fae3551SRodney W. Grimes if (s0 && *s0) { 5708fae3551SRodney W. Grimes i = strlen(s0) + strlen(s1) + 1 + 1; 5718fae3551SRodney W. Grimes if ((cp = malloc(i)) == NULL) 572bcb1d846SPhilippe Charnier errx(1, "malloc failed"); 5738fae3551SRodney W. Grimes (void)snprintf(cp, i, "%s,%s", s0, s1); 5748fae3551SRodney W. Grimes } else 5758fae3551SRodney W. Grimes cp = strdup(s1); 5768fae3551SRodney W. Grimes 5778fae3551SRodney W. Grimes if (s0) 5788fae3551SRodney W. Grimes free(s0); 5798fae3551SRodney W. Grimes return (cp); 5808fae3551SRodney W. Grimes } 5818fae3551SRodney W. Grimes 5828fae3551SRodney W. Grimes void 5838fae3551SRodney W. Grimes mangle(options, argcp, argv) 5848fae3551SRodney W. Grimes char *options; 5858fae3551SRodney W. Grimes int *argcp; 5868fae3551SRodney W. Grimes const char **argv; 5878fae3551SRodney W. Grimes { 5888fae3551SRodney W. Grimes char *p, *s; 5898fae3551SRodney W. Grimes int argc; 5908fae3551SRodney W. Grimes 5918fae3551SRodney W. Grimes argc = *argcp; 5928fae3551SRodney W. Grimes for (s = options; (p = strsep(&s, ",")) != NULL;) 59318af6044SJoseph Koshy if (*p != '\0') { 5948fae3551SRodney W. Grimes if (*p == '-') { 5958fae3551SRodney W. Grimes argv[argc++] = p; 5968fae3551SRodney W. Grimes p = strchr(p, '='); 5978fae3551SRodney W. Grimes if (p) { 5988fae3551SRodney W. Grimes *p = '\0'; 5998fae3551SRodney W. Grimes argv[argc++] = p+1; 6008fae3551SRodney W. Grimes } 6018fae3551SRodney W. Grimes } else if (strcmp(p, "rw") != 0) { 6028fae3551SRodney W. Grimes argv[argc++] = "-o"; 6038fae3551SRodney W. Grimes argv[argc++] = p; 6048fae3551SRodney W. Grimes } 60518af6044SJoseph Koshy } 6068fae3551SRodney W. Grimes 6078fae3551SRodney W. Grimes *argcp = argc; 6088fae3551SRodney W. Grimes } 6098fae3551SRodney W. Grimes 61018af6044SJoseph Koshy 61118af6044SJoseph Koshy char * 61218af6044SJoseph Koshy update_options(opts, fstab, curflags) 61318af6044SJoseph Koshy char *opts; 61418af6044SJoseph Koshy char *fstab; 61518af6044SJoseph Koshy int curflags; 61618af6044SJoseph Koshy { 61718af6044SJoseph Koshy char *o, *p; 61818af6044SJoseph Koshy char *cur; 61918af6044SJoseph Koshy char *expopt, *newopt, *tmpopt; 62018af6044SJoseph Koshy 62118af6044SJoseph Koshy if (opts == NULL) 62218af6044SJoseph Koshy return strdup(""); 62318af6044SJoseph Koshy 62418af6044SJoseph Koshy /* remove meta options from list */ 62518af6044SJoseph Koshy remopt(fstab, MOUNT_META_OPTION_FSTAB); 62618af6044SJoseph Koshy remopt(fstab, MOUNT_META_OPTION_CURRENT); 62718af6044SJoseph Koshy cur = flags2opts(curflags); 62818af6044SJoseph Koshy 62918af6044SJoseph Koshy /* 63018af6044SJoseph Koshy * Expand all meta-options passed to us first. 63118af6044SJoseph Koshy */ 63218af6044SJoseph Koshy expopt = NULL; 63318af6044SJoseph Koshy for (p = opts; (o = strsep(&p, ",")) != NULL;) { 63418af6044SJoseph Koshy if (strcmp(MOUNT_META_OPTION_FSTAB, o) == 0) 63518af6044SJoseph Koshy expopt = catopt(expopt, fstab); 63618af6044SJoseph Koshy else if (strcmp(MOUNT_META_OPTION_CURRENT, o) == 0) 63718af6044SJoseph Koshy expopt = catopt(expopt, cur); 63818af6044SJoseph Koshy else 63918af6044SJoseph Koshy expopt = catopt(expopt, o); 64018af6044SJoseph Koshy } 64118af6044SJoseph Koshy free(cur); 64218af6044SJoseph Koshy free(opts); 64318af6044SJoseph Koshy 64418af6044SJoseph Koshy /* 64518af6044SJoseph Koshy * Remove previous contradictory arguments. Given option "foo" we 64618af6044SJoseph Koshy * remove all the "nofoo" options. Given "nofoo" we remove "nonofoo" 64718af6044SJoseph Koshy * and "foo" - so we can deal with possible options like "notice". 64818af6044SJoseph Koshy */ 64918af6044SJoseph Koshy newopt = NULL; 65018af6044SJoseph Koshy for (p = expopt; (o = strsep(&p, ",")) != NULL;) { 65118af6044SJoseph Koshy if ((tmpopt = malloc( strlen(o) + 2 + 1 )) == NULL) 65218af6044SJoseph Koshy errx(1, "malloc failed"); 65318af6044SJoseph Koshy 65418af6044SJoseph Koshy strcpy(tmpopt, "no"); 65518af6044SJoseph Koshy strcat(tmpopt, o); 65618af6044SJoseph Koshy remopt(newopt, tmpopt); 65718af6044SJoseph Koshy free(tmpopt); 65818af6044SJoseph Koshy 65918af6044SJoseph Koshy if (strncmp("no", o, 2) == 0) 66018af6044SJoseph Koshy remopt(newopt, o+2); 66118af6044SJoseph Koshy 66218af6044SJoseph Koshy newopt = catopt(newopt, o); 66318af6044SJoseph Koshy } 66418af6044SJoseph Koshy free(expopt); 66518af6044SJoseph Koshy 66618af6044SJoseph Koshy return newopt; 66718af6044SJoseph Koshy } 66818af6044SJoseph Koshy 66918af6044SJoseph Koshy void 67018af6044SJoseph Koshy remopt(string, opt) 67118af6044SJoseph Koshy char *string; 67218af6044SJoseph Koshy const char *opt; 67318af6044SJoseph Koshy { 67418af6044SJoseph Koshy char *o, *p, *r; 67518af6044SJoseph Koshy 67618af6044SJoseph Koshy if (string == NULL || *string == '\0' || opt == NULL || *opt == '\0') 67718af6044SJoseph Koshy return; 67818af6044SJoseph Koshy 67918af6044SJoseph Koshy r = string; 68018af6044SJoseph Koshy 68118af6044SJoseph Koshy for (p = string; (o = strsep(&p, ",")) != NULL;) { 68218af6044SJoseph Koshy if (strcmp(opt, o) != 0) { 68318af6044SJoseph Koshy if (*r == ',' && *o != '\0') 68418af6044SJoseph Koshy r++; 68518af6044SJoseph Koshy while ((*r++ = *o++) != '\0') 68618af6044SJoseph Koshy ; 68718af6044SJoseph Koshy *--r = ','; 68818af6044SJoseph Koshy } 68918af6044SJoseph Koshy } 69018af6044SJoseph Koshy *r = '\0'; 69118af6044SJoseph Koshy } 69218af6044SJoseph Koshy 6938fae3551SRodney W. Grimes void 6948fae3551SRodney W. Grimes usage() 6958fae3551SRodney W. Grimes { 6968fae3551SRodney W. Grimes 697bcb1d846SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n%s\n", 698bcb1d846SPhilippe Charnier "usage: mount [-dfpruvw] [-o options] [-t ufs | external_type] special node", 699ef258dd9SMatthew N. Dodd " mount [-adfpruvw] [ -F fstab] [-t ufs | external_type]", 700bcb1d846SPhilippe Charnier " mount [-dfpruvw] special | node"); 7018fae3551SRodney W. Grimes exit(1); 7028fae3551SRodney W. Grimes } 703a257a45eSJordan K. Hubbard 704a257a45eSJordan K. Hubbard void 705a257a45eSJordan K. Hubbard putfsent(ent) 706a257a45eSJordan K. Hubbard const struct statfs *ent; 707a257a45eSJordan K. Hubbard { 708a257a45eSJordan K. Hubbard struct fstab *fst; 70918af6044SJoseph Koshy char *opts; 710a257a45eSJordan K. Hubbard 71118af6044SJoseph Koshy opts = flags2opts(ent->f_flags); 71274cf460bSBruce Evans printf("%s\t%s\t%s %s", ent->f_mntfromname, ent->f_mntonname, 71318af6044SJoseph Koshy ent->f_fstypename, opts); 71418af6044SJoseph Koshy free(opts); 715c06fe0a0SPeter Wemm 716fba1c154SSteve Price if ((fst = getfsspec(ent->f_mntfromname))) 717a257a45eSJordan K. Hubbard printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 718fba1c154SSteve Price else if ((fst = getfsfile(ent->f_mntonname))) 719a257a45eSJordan K. Hubbard printf("\t%u %u\n", fst->fs_freq, fst->fs_passno); 720ab80d6faSBrian Feldman else if (strcmp(ent->f_fstypename, "ufs") == 0) { 721ab80d6faSBrian Feldman if (strcmp(ent->f_mntonname, "/") == 0) 722a257a45eSJordan K. Hubbard printf("\t1 1\n"); 723a257a45eSJordan K. Hubbard else 724ab80d6faSBrian Feldman printf("\t2 2\n"); 725ab80d6faSBrian Feldman } else 726a257a45eSJordan K. Hubbard printf("\t0 0\n"); 727a257a45eSJordan K. Hubbard } 72818af6044SJoseph Koshy 72918af6044SJoseph Koshy 73018af6044SJoseph Koshy char * 73118af6044SJoseph Koshy flags2opts(flags) 73218af6044SJoseph Koshy int flags; 73318af6044SJoseph Koshy { 73418af6044SJoseph Koshy char *res; 73518af6044SJoseph Koshy 73618af6044SJoseph Koshy res = NULL; 73718af6044SJoseph Koshy 73818af6044SJoseph Koshy res = catopt(res, (flags & MNT_RDONLY) ? "ro" : "rw"); 73918af6044SJoseph Koshy 74018af6044SJoseph Koshy if (flags & MNT_SYNCHRONOUS) res = catopt(res, "sync"); 74118af6044SJoseph Koshy if (flags & MNT_NOEXEC) res = catopt(res, "noexec"); 74218af6044SJoseph Koshy if (flags & MNT_NOSUID) res = catopt(res, "nosuid"); 74318af6044SJoseph Koshy if (flags & MNT_NODEV) res = catopt(res, "nodev"); 74418af6044SJoseph Koshy if (flags & MNT_UNION) res = catopt(res, "union"); 74518af6044SJoseph Koshy if (flags & MNT_ASYNC) res = catopt(res, "async"); 74618af6044SJoseph Koshy if (flags & MNT_NOATIME) res = catopt(res, "noatime"); 74718af6044SJoseph Koshy if (flags & MNT_NOCLUSTERR) res = catopt(res, "noclusterr"); 74818af6044SJoseph Koshy if (flags & MNT_NOCLUSTERW) res = catopt(res, "noclusterw"); 74918af6044SJoseph Koshy if (flags & MNT_NOSYMFOLLOW) res = catopt(res, "nosymfollow"); 75018af6044SJoseph Koshy if (flags & MNT_SUIDDIR) res = catopt(res, "suiddir"); 751ba0fbe96SRobert Watson if (flags & MNT_MULTILABEL) res = catopt(res, "multilabel"); 75203d94b50SRobert Watson if (flags & MNT_ACLS) res = catopt(res, "acls"); 75318af6044SJoseph Koshy 75418af6044SJoseph Koshy return res; 75518af6044SJoseph Koshy } 756