18fae3551SRodney W. Grimes /* 20c269d1fSCraig Rodrigues * copyright (c) 2003 30c269d1fSCraig Rodrigues * the regents of the university of michigan 40c269d1fSCraig Rodrigues * all rights reserved 50c269d1fSCraig Rodrigues * 60c269d1fSCraig Rodrigues * permission is granted to use, copy, create derivative works and redistribute 70c269d1fSCraig Rodrigues * this software and such derivative works for any purpose, so long as the name 80c269d1fSCraig Rodrigues * of the university of michigan is not used in any advertising or publicity 90c269d1fSCraig Rodrigues * pertaining to the use or distribution of this software without specific, 100c269d1fSCraig Rodrigues * written prior authorization. if the above copyright notice or any other 110c269d1fSCraig Rodrigues * identification of the university of michigan is included in any copy of any 120c269d1fSCraig Rodrigues * portion of this software, then the disclaimer below must also be included. 130c269d1fSCraig Rodrigues * 140c269d1fSCraig Rodrigues * this software is provided as is, without representation from the university 150c269d1fSCraig Rodrigues * of michigan as to its fitness for any purpose, and without warranty by the 160c269d1fSCraig Rodrigues * university of michigan of any kind, either express or implied, including 170c269d1fSCraig Rodrigues * without limitation the implied warranties of merchantability and fitness for 180c269d1fSCraig Rodrigues * a particular purpose. the regents of the university of michigan shall not be 190c269d1fSCraig Rodrigues * liable for any damages, including special, indirect, incidental, or 200c269d1fSCraig Rodrigues * consequential damages, with respect to any claim arising out of or in 210c269d1fSCraig Rodrigues * connection with the use of the software, even if it has been or is hereafter 220c269d1fSCraig Rodrigues * advised of the possibility of such damages. 230c269d1fSCraig Rodrigues */ 240c269d1fSCraig Rodrigues 250c269d1fSCraig Rodrigues /* 268fae3551SRodney W. Grimes * Copyright (c) 1992, 1993, 1994 278fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 288fae3551SRodney W. Grimes * 298fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by 308fae3551SRodney W. Grimes * Rick Macklem at The University of Guelph. 318fae3551SRodney W. Grimes * 328fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 338fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 348fae3551SRodney W. Grimes * are met: 358fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 368fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 378fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 388fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 398fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 408fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 418fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 428fae3551SRodney W. Grimes * without specific prior written permission. 438fae3551SRodney W. Grimes * 448fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 458fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 468fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 478fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 488fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 498fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 508fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 518fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 528fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 538fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 548fae3551SRodney W. Grimes * SUCH DAMAGE. 558fae3551SRodney W. Grimes */ 568fae3551SRodney W. Grimes 57c69284caSDavid E. O'Brien #if 0 588fae3551SRodney W. Grimes #ifndef lint 5946fc8f78SPhilippe Charnier static const char copyright[] = 608fae3551SRodney W. Grimes "@(#) Copyright (c) 1992, 1993, 1994\n\ 618fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 628fae3551SRodney W. Grimes #endif /* not lint */ 638fae3551SRodney W. Grimes 648fae3551SRodney W. Grimes #ifndef lint 654a4c5285SPeter Wemm static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95"; 668fae3551SRodney W. Grimes #endif /* not lint */ 67c69284caSDavid E. O'Brien #endif 68c69284caSDavid E. O'Brien #include <sys/cdefs.h> 69c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$"); 708fae3551SRodney W. Grimes 718fae3551SRodney W. Grimes #include <sys/param.h> 728fae3551SRodney W. Grimes #include <sys/mount.h> 738360efbdSAlfred Perlstein #include <sys/socket.h> 748fae3551SRodney W. Grimes #include <sys/stat.h> 758fae3551SRodney W. Grimes #include <sys/syslog.h> 76c5aa1dc8SCraig Rodrigues #include <sys/uio.h> 778fae3551SRodney W. Grimes 788fae3551SRodney W. Grimes #include <rpc/rpc.h> 798fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h> 808fae3551SRodney W. Grimes #include <rpc/pmap_prot.h> 818fae3551SRodney W. Grimes 828fae3551SRodney W. Grimes #include <nfs/rpcv2.h> 83a62dc406SDoug Rabson #include <nfs/nfsproto.h> 8491196234SPeter Wemm #include <nfsclient/nfs.h> 858fae3551SRodney W. Grimes 868fae3551SRodney W. Grimes #include <arpa/inet.h> 878fae3551SRodney W. Grimes 888fae3551SRodney W. Grimes #include <ctype.h> 898fae3551SRodney W. Grimes #include <err.h> 908fae3551SRodney W. Grimes #include <errno.h> 918360efbdSAlfred Perlstein #include <fcntl.h> 928fae3551SRodney W. Grimes #include <netdb.h> 938fae3551SRodney W. Grimes #include <stdio.h> 948fae3551SRodney W. Grimes #include <stdlib.h> 95c04affffSMatthew N. Dodd #include <string.h> 968fae3551SRodney W. Grimes #include <strings.h> 975e074e31SGarrett Wollman #include <sysexits.h> 988fae3551SRodney W. Grimes #include <unistd.h> 998fae3551SRodney W. Grimes 1008fae3551SRodney W. Grimes #include "mntopts.h" 101a69497d7SMatthew Dillon #include "mounttab.h" 1028fae3551SRodney W. Grimes 103a3d8f94bSIan Dowse /* Table for af,sotype -> netid conversions. */ 104a3d8f94bSIan Dowse struct nc_protos { 1054b5bc283SCraig Rodrigues const char *netid; 106a3d8f94bSIan Dowse int af; 107a3d8f94bSIan Dowse int sotype; 108a3d8f94bSIan Dowse } nc_protos[] = { 109a3d8f94bSIan Dowse {"udp", AF_INET, SOCK_DGRAM}, 110a3d8f94bSIan Dowse {"tcp", AF_INET, SOCK_STREAM}, 111a3d8f94bSIan Dowse {"udp6", AF_INET6, SOCK_DGRAM}, 112a3d8f94bSIan Dowse {"tcp6", AF_INET6, SOCK_STREAM}, 113b535b298SCraig Rodrigues {NULL, 0, 0} 114a3d8f94bSIan Dowse }; 115a3d8f94bSIan Dowse 1168fae3551SRodney W. Grimes struct nfhret { 1178fae3551SRodney W. Grimes u_long stat; 118a62dc406SDoug Rabson long vers; 119a62dc406SDoug Rabson long auth; 120a62dc406SDoug Rabson long fhsize; 121a62dc406SDoug Rabson u_char nfh[NFSX_V3FHMAX]; 1228fae3551SRodney W. Grimes }; 1238fae3551SRodney W. Grimes #define BGRND 1 1248fae3551SRodney W. Grimes #define ISBGRND 2 125302f15f9SMatthew N. Dodd #define OF_NOINET4 4 126302f15f9SMatthew N. Dodd #define OF_NOINET6 8 127e16873daSIan Dowse int retrycnt = -1; 1288fae3551SRodney W. Grimes int opflags = 0; 129a62dc406SDoug Rabson int nfsproto = IPPROTO_UDP; 130a62dc406SDoug Rabson int mnttcp_ok = 1; 1314b5bc283SCraig Rodrigues int noconn = 0; 132317d5933SIan Dowse char *portspec = NULL; /* Server nfs port; NULL means look up via rpcbind. */ 1334b5bc283SCraig Rodrigues struct sockaddr *addr; 1344b5bc283SCraig Rodrigues int addrlen = 0; 1354b5bc283SCraig Rodrigues u_char *fh = NULL; 1364b5bc283SCraig Rodrigues int fhsize = 0; 137a9148abdSDoug Rabson int secflavor = -1; 1384b5bc283SCraig Rodrigues 139317d5933SIan Dowse enum mountmode { 1402cd1c32cSDoug Rabson ANY, 1412cd1c32cSDoug Rabson V2, 1420c269d1fSCraig Rodrigues V3, 1430c269d1fSCraig Rodrigues V4 1442cd1c32cSDoug Rabson } mountmode = ANY; 1458fae3551SRodney W. Grimes 146317d5933SIan Dowse /* Return codes for nfs_tryproto. */ 147317d5933SIan Dowse enum tryret { 148317d5933SIan Dowse TRYRET_SUCCESS, 149317d5933SIan Dowse TRYRET_TIMEOUT, /* No response received. */ 150317d5933SIan Dowse TRYRET_REMOTEERR, /* Error received from remote server. */ 151317d5933SIan Dowse TRYRET_LOCALERR /* Local failure. */ 152317d5933SIan Dowse }; 153317d5933SIan Dowse 1544b5bc283SCraig Rodrigues int fallback_mount(struct iovec *iov, int iovlen, int mntflags); 155a9148abdSDoug Rabson int sec_name_to_num(char *sec); 156a9148abdSDoug Rabson char *sec_num_to_name(int num); 1574b5bc283SCraig Rodrigues int getnfsargs(char *, struct iovec **iov, int *iovlen); 1584b5bc283SCraig Rodrigues int getnfs4args(char *, struct iovec **iov, int *iovlen); 15985429990SWarner Losh /* void set_rpc_maxgrouplist(int); */ 160a3d8f94bSIan Dowse struct netconfig *getnetconf_cached(const char *netid); 1614b5bc283SCraig Rodrigues const char *netidbytype(int af, int sotype); 16285429990SWarner Losh void usage(void) __dead2; 16385429990SWarner Losh int xdr_dir(XDR *, char *); 16485429990SWarner Losh int xdr_fh(XDR *, struct nfhret *); 1654b5bc283SCraig Rodrigues enum tryret nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, 1664b5bc283SCraig Rodrigues char **errstr, struct iovec **iov, int *iovlen); 1674b5bc283SCraig Rodrigues enum tryret nfs4_tryproto(struct addrinfo *ai, char *hostp, char *spec, 1684b5bc283SCraig Rodrigues char **errstr); 169317d5933SIan Dowse enum tryret returncode(enum clnt_stat stat, struct rpc_err *rpcerr); 170049307baSCraig Rodrigues extern int getosreldate(void); 1718fae3551SRodney W. Grimes 1728fae3551SRodney W. Grimes int 17333924ad4SWarner Losh main(int argc, char *argv[]) 1748fae3551SRodney W. Grimes { 1753d438ad6SDavid E. O'Brien int c; 176c5aa1dc8SCraig Rodrigues struct iovec *iov; 177049307baSCraig Rodrigues int mntflags, num, iovlen; 178049307baSCraig Rodrigues int osversion; 179a83655a3SYaroslav Tykhiy char *name, *p, *spec, *fstype; 180a6b26402SCraig Rodrigues char mntpath[MAXPATHLEN], errmsg[255]; 1818fae3551SRodney W. Grimes 1828fae3551SRodney W. Grimes mntflags = 0; 183c5aa1dc8SCraig Rodrigues iov = NULL; 184c5aa1dc8SCraig Rodrigues iovlen = 0; 185a6b26402SCraig Rodrigues memset(errmsg, 0, sizeof(errmsg)); 186c5aa1dc8SCraig Rodrigues 187412ffff0SCraig Rodrigues fstype = strrchr(argv[0], '_'); 188412ffff0SCraig Rodrigues if (fstype == NULL) 189412ffff0SCraig Rodrigues errx(EX_USAGE, "argv[0] must end in _fstype"); 190412ffff0SCraig Rodrigues 191412ffff0SCraig Rodrigues ++fstype; 192412ffff0SCraig Rodrigues 1930c269d1fSCraig Rodrigues if (strcmp(fstype, "nfs4") == 0) { 1940c269d1fSCraig Rodrigues nfsproto = IPPROTO_TCP; 1950c269d1fSCraig Rodrigues portspec = "2049"; 1964b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "tcp", NULL, 0); 1970c269d1fSCraig Rodrigues mountmode = V4; 1980c269d1fSCraig Rodrigues } 1990c269d1fSCraig Rodrigues 2008fae3551SRodney W. Grimes while ((c = getopt(argc, argv, 2010c269d1fSCraig Rodrigues "234a:bcdD:g:I:iLlNo:PR:r:sTt:w:x:U")) != -1) 2028fae3551SRodney W. Grimes switch (c) { 2032cd1c32cSDoug Rabson case '2': 2042cd1c32cSDoug Rabson mountmode = V2; 2052cd1c32cSDoug Rabson break; 206a62dc406SDoug Rabson case '3': 2072cd1c32cSDoug Rabson mountmode = V3; 208a62dc406SDoug Rabson break; 2090c269d1fSCraig Rodrigues case '4': 2100c269d1fSCraig Rodrigues mountmode = V4; 2110c269d1fSCraig Rodrigues fstype = "nfs4"; 2120c269d1fSCraig Rodrigues break; 2138fae3551SRodney W. Grimes case 'a': 2144b5bc283SCraig Rodrigues printf("-a deprecated, use -o readhead=<value>\n"); 2154b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "readahead", optarg, (size_t)-1); 2168fae3551SRodney W. Grimes break; 2178fae3551SRodney W. Grimes case 'b': 2188fae3551SRodney W. Grimes opflags |= BGRND; 2198fae3551SRodney W. Grimes break; 2208fae3551SRodney W. Grimes case 'c': 2214b5bc283SCraig Rodrigues printf("-c deprecated, use -o noconn\n"); 2224b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "noconn", NULL, 0); 2234b5bc283SCraig Rodrigues noconn = 1; 2248fae3551SRodney W. Grimes break; 2258fae3551SRodney W. Grimes case 'D': 2264b5bc283SCraig Rodrigues printf("-D deprecated, use -o deadthresh=<value>\n"); 2274b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "deadthresh", optarg, (size_t)-1); 2288fae3551SRodney W. Grimes break; 2298fae3551SRodney W. Grimes case 'd': 2304b5bc283SCraig Rodrigues printf("-d deprecated, use -o dumbtimer"); 2314b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "dumbtimer", NULL, 0); 2328fae3551SRodney W. Grimes break; 2338fae3551SRodney W. Grimes case 'g': 2344b5bc283SCraig Rodrigues printf("-g deprecated, use -o maxgroups"); 2358fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 2368fae3551SRodney W. Grimes if (*p || num <= 0) 2378fae3551SRodney W. Grimes errx(1, "illegal -g value -- %s", optarg); 2384b5bc283SCraig Rodrigues //set_rpc_maxgrouplist(num); 2394b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "maxgroups", optarg, (size_t)-1); 2408fae3551SRodney W. Grimes break; 241a62dc406SDoug Rabson case 'I': 2424b5bc283SCraig Rodrigues printf("-I deprecated, use -o readdirsize=<value>\n"); 2434b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "readdirsize", optarg, (size_t)-1); 244a62dc406SDoug Rabson break; 2458fae3551SRodney W. Grimes case 'i': 2464b5bc283SCraig Rodrigues printf("-i deprecated, use -o intr\n"); 2474b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "intr", NULL, 0); 2488fae3551SRodney W. Grimes break; 24913190d87SAlfred Perlstein case 'L': 2504b5bc283SCraig Rodrigues printf("-i deprecated, use -o nolockd\n"); 2514b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "nolockd", NULL, 0); 25213190d87SAlfred Perlstein break; 2538fae3551SRodney W. Grimes case 'l': 2544b5bc283SCraig Rodrigues printf("-l deprecated, -o rdirplus\n"); 2554b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "rdirplus", NULL, 0); 2568fae3551SRodney W. Grimes break; 257cc75b131SJoerg Wunsch case 'N': 2584b5bc283SCraig Rodrigues printf("-N deprecated, do not specify -o resvport\n"); 259cc75b131SJoerg Wunsch break; 2604b5bc283SCraig Rodrigues case 'o': { 2614b5bc283SCraig Rodrigues int pass_flag_to_nmount; 2624b5bc283SCraig Rodrigues char *opt = optarg; 2634b5bc283SCraig Rodrigues while (opt) { 2644b5bc283SCraig Rodrigues char *pval = NULL; 2654b5bc283SCraig Rodrigues char *pnextopt = NULL; 2664b5bc283SCraig Rodrigues char *val = ""; 2674b5bc283SCraig Rodrigues pass_flag_to_nmount = 1; 2684b5bc283SCraig Rodrigues pval = strchr(opt, '='); 2694b5bc283SCraig Rodrigues pnextopt = strchr(opt, ','); 2704b5bc283SCraig Rodrigues if (pval != NULL) { 2714b5bc283SCraig Rodrigues *pval = '\0'; 2724b5bc283SCraig Rodrigues val = pval + 1; 2734b5bc283SCraig Rodrigues } 2744b5bc283SCraig Rodrigues if (pnextopt) { 2754b5bc283SCraig Rodrigues *pnextopt = '\0'; 2764b5bc283SCraig Rodrigues pnextopt++; 2774b5bc283SCraig Rodrigues } 2784b5bc283SCraig Rodrigues if (strcmp(opt, "bg") == 0) { 2793fa88decSGarrett Wollman opflags |= BGRND; 2804b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 2814b5bc283SCraig Rodrigues } else if (strcmp(opt, "fg") == 0) { 2824b5bc283SCraig Rodrigues /* same as not specifying -o bg */ 2834b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 2844b5bc283SCraig Rodrigues } else if (strcmp(opt, "mntudp") == 0) { 285a62dc406SDoug Rabson mnttcp_ok = 0; 286bf005f32SKris Kennaway nfsproto = IPPROTO_UDP; 2874b5bc283SCraig Rodrigues } else if (strcmp(opt, "udp") == 0) { 2884b5bc283SCraig Rodrigues nfsproto = IPPROTO_UDP; 2894b5bc283SCraig Rodrigues } else if (strcmp(opt, "tcp") == 0) { 290a62dc406SDoug Rabson nfsproto = IPPROTO_TCP; 2914b5bc283SCraig Rodrigues } else if (strcmp(opt, "noinet4") == 0) { 2924b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 2934b5bc283SCraig Rodrigues opflags |= OF_NOINET4; 2944b5bc283SCraig Rodrigues } else if (strcmp(opt, "noinet6") == 0) { 2954b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 2964b5bc283SCraig Rodrigues opflags |= OF_NOINET6; 2974b5bc283SCraig Rodrigues } else if (strcmp(opt, "noconn") == 0) { 2984b5bc283SCraig Rodrigues noconn = 1; 2994b5bc283SCraig Rodrigues } else if (strcmp(opt, "nfsv2") == 0) { 3004b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 3014b5bc283SCraig Rodrigues mountmode = V2; 3024b5bc283SCraig Rodrigues } else if (strcmp(opt, "nfsv3") == 0) { 3034b5bc283SCraig Rodrigues mountmode = V3; 3044b5bc283SCraig Rodrigues } else if (strcmp(opt, "nfsv4") == 0) { 3054b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 3064b5bc283SCraig Rodrigues mountmode = V4; 3074b5bc283SCraig Rodrigues fstype = "nfs4"; 3084b5bc283SCraig Rodrigues } else if (strcmp(opt, "port") == 0) { 3094b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 310317d5933SIan Dowse asprintf(&portspec, "%d", 3114b5bc283SCraig Rodrigues atoi(val)); 312317d5933SIan Dowse if (portspec == NULL) 313317d5933SIan Dowse err(1, "asprintf"); 314a9148abdSDoug Rabson } else if (strcmp(opt, "sec") == 0) { 315a9148abdSDoug Rabson /* 316a9148abdSDoug Rabson * Don't add this option to 317a9148abdSDoug Rabson * the iovec yet - we will 318a9148abdSDoug Rabson * negotiate which sec flavor 319a9148abdSDoug Rabson * to use with the remote 320a9148abdSDoug Rabson * mountd. 321a9148abdSDoug Rabson */ 322a9148abdSDoug Rabson pass_flag_to_nmount=0; 323a9148abdSDoug Rabson secflavor = sec_name_to_num(val); 324a9148abdSDoug Rabson if (secflavor < 0) { 325a9148abdSDoug Rabson errx(1, 326a9148abdSDoug Rabson "illegal sec value -- %s", 327a9148abdSDoug Rabson val); 328a9148abdSDoug Rabson } 3294b5bc283SCraig Rodrigues } else if (strcmp(opt, "retrycnt") == 0) { 3304b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 3314b5bc283SCraig Rodrigues num = strtol(val, &p, 10); 3324b5bc283SCraig Rodrigues if (*p || num < 0) 3334b5bc283SCraig Rodrigues errx(1, "illegal retrycnt value -- %s", val); 3344b5bc283SCraig Rodrigues retrycnt = num; 3354b5bc283SCraig Rodrigues } else if (strcmp(opt, "maxgroups") == 0) { 3364b5bc283SCraig Rodrigues num = strtol(val, &p, 10); 3374b5bc283SCraig Rodrigues if (*p || num <= 0) 3384b5bc283SCraig Rodrigues errx(1, "illegal maxgroups value -- %s", val); 3394b5bc283SCraig Rodrigues //set_rpc_maxgrouplist(num); 340317d5933SIan Dowse } 3414b5bc283SCraig Rodrigues if (pass_flag_to_nmount) 3424b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, opt, val, 3434b5bc283SCraig Rodrigues strlen(val) + 1); 3444b5bc283SCraig Rodrigues opt = pnextopt; 3454db56604SPeter Wemm } 3464db56604SPeter Wemm } 3478fae3551SRodney W. Grimes break; 3488fae3551SRodney W. Grimes case 'P': 3494b5bc283SCraig Rodrigues /* obsolete for -o noresvport now default */ 3504b5bc283SCraig Rodrigues printf("-P deprecated, use -o noresvport\n"); 3514b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "noresvport", NULL, 0); 3528fae3551SRodney W. Grimes break; 3538fae3551SRodney W. Grimes case 'R': 3544b5bc283SCraig Rodrigues printf("-R deprecated, use -o retrycnt=<retrycnt>\n"); 3558fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 356e16873daSIan Dowse if (*p || num < 0) 3578fae3551SRodney W. Grimes errx(1, "illegal -R value -- %s", optarg); 3588fae3551SRodney W. Grimes retrycnt = num; 3598fae3551SRodney W. Grimes break; 3608fae3551SRodney W. Grimes case 'r': 3614b5bc283SCraig Rodrigues printf("-r deprecated, use -o rsize=<rsize>\n"); 3624b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "rsize", optarg, (size_t)-1); 3638fae3551SRodney W. Grimes break; 3648fae3551SRodney W. Grimes case 's': 3654b5bc283SCraig Rodrigues printf("-s deprecated, use -o soft\n"); 3664b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "soft", NULL, 0); 3678fae3551SRodney W. Grimes break; 3688fae3551SRodney W. Grimes case 'T': 369a62dc406SDoug Rabson nfsproto = IPPROTO_TCP; 3704b5bc283SCraig Rodrigues printf("-T deprecated, use -o tcp\n"); 3718fae3551SRodney W. Grimes break; 3728fae3551SRodney W. Grimes case 't': 3734b5bc283SCraig Rodrigues printf("-t deprecated, use -o timeout=<value>\n"); 3744b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "timeout", optarg, (size_t)-1); 3758fae3551SRodney W. Grimes break; 3768fae3551SRodney W. Grimes case 'w': 3774b5bc283SCraig Rodrigues printf("-w deprecated, use -o wsize=<value>\n"); 3784b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "wsize", optarg, (size_t)-1); 3798fae3551SRodney W. Grimes break; 3808fae3551SRodney W. Grimes case 'x': 3814b5bc283SCraig Rodrigues printf("-x deprecated, use -o retrans=<value>\n"); 3824b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "retrans", optarg, (size_t)-1); 3838fae3551SRodney W. Grimes break; 384a62dc406SDoug Rabson case 'U': 3854b5bc283SCraig Rodrigues printf("-U deprecated, use -o mntudp\n"); 386a62dc406SDoug Rabson mnttcp_ok = 0; 3870c269d1fSCraig Rodrigues nfsproto = IPPROTO_UDP; 3884b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "mntudp", NULL, 0); 389a62dc406SDoug Rabson break; 3908fae3551SRodney W. Grimes default: 3918fae3551SRodney W. Grimes usage(); 3928fae3551SRodney W. Grimes break; 3938fae3551SRodney W. Grimes } 3948fae3551SRodney W. Grimes argc -= optind; 3958fae3551SRodney W. Grimes argv += optind; 3968fae3551SRodney W. Grimes 3974a4c5285SPeter Wemm if (argc != 2) { 3982f21d07aSDavid Greenman usage(); 3994a4c5285SPeter Wemm /* NOTREACHED */ 4004a4c5285SPeter Wemm } 4018fae3551SRodney W. Grimes 4028fae3551SRodney W. Grimes spec = *argv++; 4038fae3551SRodney W. Grimes name = *argv; 4048fae3551SRodney W. Grimes 405e16873daSIan Dowse if (retrycnt == -1) 4062bc53e11SIan Dowse /* The default is to keep retrying forever. */ 4072bc53e11SIan Dowse retrycnt = 0; 4080c269d1fSCraig Rodrigues 4090c269d1fSCraig Rodrigues if (mountmode == V4) { 4104b5bc283SCraig Rodrigues if (!getnfs4args(spec, &iov, &iovlen)) 4110c269d1fSCraig Rodrigues exit(1); 4120c269d1fSCraig Rodrigues } else { 4134b5bc283SCraig Rodrigues if (!getnfsargs(spec, &iov, &iovlen)) 4148fae3551SRodney W. Grimes exit(1); 4150c269d1fSCraig Rodrigues } 416d599144dSGarrett Wollman 41773dd3167SPoul-Henning Kamp /* resolve the mountpoint with realpath(3) */ 41873dd3167SPoul-Henning Kamp (void)checkpath(name, mntpath); 41973dd3167SPoul-Henning Kamp 420412ffff0SCraig Rodrigues build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1); 421c5aa1dc8SCraig Rodrigues build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1); 422a6b26402SCraig Rodrigues build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 423c5aa1dc8SCraig Rodrigues 424049307baSCraig Rodrigues /* 425049307baSCraig Rodrigues * XXX: 426049307baSCraig Rodrigues * Backwards compatibility routines for older kernels. 427049307baSCraig Rodrigues * Remove this and fallback_mount() code when we do not need to support 428049307baSCraig Rodrigues * NFS mounts against older kernels which still need 429049307baSCraig Rodrigues * struct nfs_args to be passed in via nmount(). 430049307baSCraig Rodrigues */ 431049307baSCraig Rodrigues osversion = getosreldate(); 432049307baSCraig Rodrigues if (osversion >= 800048) { 433049307baSCraig Rodrigues if (nmount(iov, iovlen, mntflags)) 434049307baSCraig Rodrigues err(1, "%s, %s", mntpath, errmsg); 435049307baSCraig Rodrigues } else { 436049307baSCraig Rodrigues if (fallback_mount(iov, iovlen, mntflags)) 437a6b26402SCraig Rodrigues err(1, "%s, %s", mntpath, errmsg); 4384b5bc283SCraig Rodrigues } 439a62dc406SDoug Rabson 4408fae3551SRodney W. Grimes exit(0); 4418fae3551SRodney W. Grimes } 4428fae3551SRodney W. Grimes 4434b5bc283SCraig Rodrigues static int 4444b5bc283SCraig Rodrigues findopt(struct iovec *iov, int iovlen, const char *name, 4454b5bc283SCraig Rodrigues char **valuep, int *lenp) 4464b5bc283SCraig Rodrigues { 4474b5bc283SCraig Rodrigues int i; 4484b5bc283SCraig Rodrigues 4494b5bc283SCraig Rodrigues for (i = 0; i < iovlen/2; i++, iov += 2) { 4504b5bc283SCraig Rodrigues if (strcmp(name, iov[0].iov_base) == 0) { 4514b5bc283SCraig Rodrigues if (valuep) 4524b5bc283SCraig Rodrigues *valuep = iov[1].iov_base; 4534b5bc283SCraig Rodrigues if (lenp) 4544b5bc283SCraig Rodrigues *lenp = iov[1].iov_len; 4554b5bc283SCraig Rodrigues return (0); 4564b5bc283SCraig Rodrigues } 4574b5bc283SCraig Rodrigues } 4584b5bc283SCraig Rodrigues return (ENOENT); 4594b5bc283SCraig Rodrigues } 4604b5bc283SCraig Rodrigues 4614b5bc283SCraig Rodrigues static void 4624b5bc283SCraig Rodrigues copyopt(struct iovec **newiov, int *newiovlen, 4634b5bc283SCraig Rodrigues struct iovec *iov, int iovlen, const char *name) 4644b5bc283SCraig Rodrigues { 4654b5bc283SCraig Rodrigues char *value; 4664b5bc283SCraig Rodrigues int len; 4674b5bc283SCraig Rodrigues 4684b5bc283SCraig Rodrigues if (findopt(iov, iovlen, name, &value, &len) == 0) 4694b5bc283SCraig Rodrigues build_iovec(newiov, newiovlen, name, value, len); 4704b5bc283SCraig Rodrigues } 4714b5bc283SCraig Rodrigues 4728fae3551SRodney W. Grimes int 4734b5bc283SCraig Rodrigues fallback_mount(struct iovec *iov, int iovlen, int mntflags) 4744b5bc283SCraig Rodrigues { 4754b5bc283SCraig Rodrigues struct nfs_args args = { 4764b5bc283SCraig Rodrigues .version = NFS_ARGSVERSION, 4774b5bc283SCraig Rodrigues .addr = NULL, 4784b5bc283SCraig Rodrigues .addrlen = sizeof (struct sockaddr_in), 4794b5bc283SCraig Rodrigues .sotype = SOCK_STREAM, 4804b5bc283SCraig Rodrigues .proto = 0, 4814b5bc283SCraig Rodrigues .fh = NULL, 4824b5bc283SCraig Rodrigues .fhsize = 0, 4834b5bc283SCraig Rodrigues .flags = NFSMNT_RESVPORT, 4844b5bc283SCraig Rodrigues .wsize = NFS_WSIZE, 4854b5bc283SCraig Rodrigues .rsize = NFS_RSIZE, 4864b5bc283SCraig Rodrigues .readdirsize = NFS_READDIRSIZE, 4874b5bc283SCraig Rodrigues .timeo = 10, 4884b5bc283SCraig Rodrigues .retrans = NFS_RETRANS, 4894b5bc283SCraig Rodrigues .maxgrouplist = NFS_MAXGRPS, 4904b5bc283SCraig Rodrigues .readahead = NFS_DEFRAHEAD, 4914b5bc283SCraig Rodrigues .wcommitsize = 0, /* was: NQ_DEFLEASE */ 4924b5bc283SCraig Rodrigues .deadthresh = NFS_MAXDEADTHRESH, /* was: NQ_DEADTHRESH */ 4934b5bc283SCraig Rodrigues .hostname = NULL, 4944b5bc283SCraig Rodrigues /* args version 4 */ 4954b5bc283SCraig Rodrigues .acregmin = NFS_MINATTRTIMO, 4964b5bc283SCraig Rodrigues .acregmax = NFS_MAXATTRTIMO, 4974b5bc283SCraig Rodrigues .acdirmin = NFS_MINDIRATTRTIMO, 4984b5bc283SCraig Rodrigues .acdirmax = NFS_MAXDIRATTRTIMO, 4994b5bc283SCraig Rodrigues }; 5004b5bc283SCraig Rodrigues int ret; 5014b5bc283SCraig Rodrigues char *opt; 5024b5bc283SCraig Rodrigues struct iovec *newiov; 5034b5bc283SCraig Rodrigues int newiovlen; 5044b5bc283SCraig Rodrigues 5054b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "dumbtimer", NULL, NULL) == 0) 5064b5bc283SCraig Rodrigues args.flags |= NFSMNT_DUMBTIMR; 5074b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "noconn", NULL, NULL) == 0) 5084b5bc283SCraig Rodrigues args.flags |= NFSMNT_NOCONN; 5094b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "conn", NULL, NULL) == 0) 5104b5bc283SCraig Rodrigues args.flags |= NFSMNT_NOCONN; 5114b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "nolockd", NULL, NULL) == 0) 5124b5bc283SCraig Rodrigues args.flags |= NFSMNT_NOLOCKD; 5134b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "lockd", NULL, NULL) == 0) 5144b5bc283SCraig Rodrigues args.flags &= ~NFSMNT_NOLOCKD; 5154b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "intr", NULL, NULL) == 0) 5164b5bc283SCraig Rodrigues args.flags |= NFSMNT_INT; 5174b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "rdirplus", NULL, NULL) == 0) 5184b5bc283SCraig Rodrigues args.flags |= NFSMNT_RDIRPLUS; 5194b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "resvport", NULL, NULL) == 0) 5204b5bc283SCraig Rodrigues args.flags |= NFSMNT_RESVPORT; 5214b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "noresvport", NULL, NULL) == 0) 5224b5bc283SCraig Rodrigues args.flags &= ~NFSMNT_RESVPORT; 5234b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "soft", NULL, NULL) == 0) 5244b5bc283SCraig Rodrigues args.flags |= NFSMNT_SOFT; 5254b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "hard", NULL, NULL) == 0) 5264b5bc283SCraig Rodrigues args.flags &= ~NFSMNT_SOFT; 5274b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "mntudp", NULL, NULL) == 0) 5284b5bc283SCraig Rodrigues args.sotype = SOCK_DGRAM; 5294b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "udp", NULL, NULL) == 0) 5304b5bc283SCraig Rodrigues args.sotype = SOCK_DGRAM; 5314b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "tcp", NULL, NULL) == 0) 5324b5bc283SCraig Rodrigues args.sotype = SOCK_STREAM; 5334b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "nfsv3", NULL, NULL) == 0) 5344b5bc283SCraig Rodrigues args.flags |= NFSMNT_NFSV3; 5354b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "readdirsize", &opt, NULL) == 0) { 5364b5bc283SCraig Rodrigues if (opt == NULL) { 5374b5bc283SCraig Rodrigues errx(1, "illegal readdirsize"); 5384b5bc283SCraig Rodrigues } 5394b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.readdirsize); 5404b5bc283SCraig Rodrigues if (ret != 1 || args.readdirsize <= 0) { 5414b5bc283SCraig Rodrigues errx(1, "illegal readdirsize: %s", opt); 5424b5bc283SCraig Rodrigues } 5434b5bc283SCraig Rodrigues args.flags |= NFSMNT_READDIRSIZE; 5444b5bc283SCraig Rodrigues } 5454b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "readahead", &opt, NULL) == 0) { 5464b5bc283SCraig Rodrigues if (opt == NULL) { 5474b5bc283SCraig Rodrigues errx(1, "illegal readahead"); 5484b5bc283SCraig Rodrigues } 5494b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.readahead); 5504b5bc283SCraig Rodrigues if (ret != 1 || args.readahead <= 0) { 5514b5bc283SCraig Rodrigues errx(1, "illegal readahead: %s", opt); 5524b5bc283SCraig Rodrigues } 5534b5bc283SCraig Rodrigues args.flags |= NFSMNT_READAHEAD; 5544b5bc283SCraig Rodrigues } 5554b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "wsize", &opt, NULL) == 0) { 5564b5bc283SCraig Rodrigues if (opt == NULL) { 5574b5bc283SCraig Rodrigues errx(1, "illegal wsize"); 5584b5bc283SCraig Rodrigues } 5594b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.wsize); 5604b5bc283SCraig Rodrigues if (ret != 1 || args.wsize <= 0) { 5614b5bc283SCraig Rodrigues errx(1, "illegal wsize: %s", opt); 5624b5bc283SCraig Rodrigues } 5634b5bc283SCraig Rodrigues args.flags |= NFSMNT_WSIZE; 5644b5bc283SCraig Rodrigues } 5654b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "rsize", &opt, NULL) == 0) { 5664b5bc283SCraig Rodrigues if (opt == NULL) { 5674b5bc283SCraig Rodrigues errx(1, "illegal rsize"); 5684b5bc283SCraig Rodrigues } 5694b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.rsize); 5704b5bc283SCraig Rodrigues if (ret != 1 || args.rsize <= 0) { 5714b5bc283SCraig Rodrigues errx(1, "illegal wsize: %s", opt); 5724b5bc283SCraig Rodrigues } 5734b5bc283SCraig Rodrigues args.flags |= NFSMNT_RSIZE; 5744b5bc283SCraig Rodrigues } 5754b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "retrans", &opt, NULL) == 0) { 5764b5bc283SCraig Rodrigues if (opt == NULL) { 5774b5bc283SCraig Rodrigues errx(1, "illegal retrans"); 5784b5bc283SCraig Rodrigues } 5794b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.retrans); 5804b5bc283SCraig Rodrigues if (ret != 1 || args.retrans <= 0) { 5814b5bc283SCraig Rodrigues errx(1, "illegal retrans: %s", opt); 5824b5bc283SCraig Rodrigues } 5834b5bc283SCraig Rodrigues args.flags |= NFSMNT_RETRANS; 5844b5bc283SCraig Rodrigues } 5854b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "acregmin", &opt, NULL) == 0) { 5864b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.acregmin); 5874b5bc283SCraig Rodrigues if (ret != 1 || args.acregmin <= 0) { 5884b5bc283SCraig Rodrigues errx(1, "illegal acregmin: %s", opt); 5894b5bc283SCraig Rodrigues } 5904b5bc283SCraig Rodrigues } 5914b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "acregmax", &opt, NULL) == 0) { 5924b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.acregmax); 5934b5bc283SCraig Rodrigues if (ret != 1 || args.acregmax <= 0) { 5944b5bc283SCraig Rodrigues errx(1, "illegal acregmax: %s", opt); 5954b5bc283SCraig Rodrigues } 5964b5bc283SCraig Rodrigues } 5974b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "acdirmin", &opt, NULL) == 0) { 5984b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.acdirmin); 5994b5bc283SCraig Rodrigues if (ret != 1 || args.acdirmin <= 0) { 6004b5bc283SCraig Rodrigues errx(1, "illegal acdirmin: %s", opt); 6014b5bc283SCraig Rodrigues } 6024b5bc283SCraig Rodrigues } 6034b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "acdirmax", &opt, NULL) == 0) { 6044b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.acdirmax); 6054b5bc283SCraig Rodrigues if (ret != 1 || args.acdirmax <= 0) { 6064b5bc283SCraig Rodrigues errx(1, "illegal acdirmax: %s", opt); 6074b5bc283SCraig Rodrigues } 6084b5bc283SCraig Rodrigues } 6094b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "deadthresh", &opt, NULL) == 0) { 6104b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.deadthresh); 6114b5bc283SCraig Rodrigues if (ret != 1 || args.deadthresh <= 0) { 6124b5bc283SCraig Rodrigues errx(1, "illegal deadthresh: %s", opt); 6134b5bc283SCraig Rodrigues } 6144b5bc283SCraig Rodrigues args.flags |= NFSMNT_DEADTHRESH; 6154b5bc283SCraig Rodrigues } 6164b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "timeout", &opt, NULL) == 0) { 6174b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.timeo); 6184b5bc283SCraig Rodrigues if (ret != 1 || args.timeo <= 0) { 6194b5bc283SCraig Rodrigues errx(1, "illegal timeout: %s", opt); 6204b5bc283SCraig Rodrigues } 6214b5bc283SCraig Rodrigues args.flags |= NFSMNT_TIMEO; 6224b5bc283SCraig Rodrigues } 6234b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "maxgroups", &opt, NULL) == 0) { 6244b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.maxgrouplist); 6254b5bc283SCraig Rodrigues if (ret != 1 || args.timeo <= 0) { 6264b5bc283SCraig Rodrigues errx(1, "illegal maxgroups: %s", opt); 6274b5bc283SCraig Rodrigues } 6284b5bc283SCraig Rodrigues args.flags |= NFSMNT_MAXGRPS; 6294b5bc283SCraig Rodrigues } 6304b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "addr", &opt, 6314b5bc283SCraig Rodrigues &args.addrlen) == 0) { 6324b5bc283SCraig Rodrigues args.addr = (struct sockaddr *) opt; 6334b5bc283SCraig Rodrigues } 6344b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "fh", &opt, &args.fhsize) == 0) { 6354b5bc283SCraig Rodrigues args.fh = opt; 6364b5bc283SCraig Rodrigues } 6374b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "hostname", &args.hostname, 6384b5bc283SCraig Rodrigues NULL) == 0) { 6394b5bc283SCraig Rodrigues } 6404b5bc283SCraig Rodrigues if (args.hostname == NULL) { 6414b5bc283SCraig Rodrigues errx(1, "Invalid hostname"); 6424b5bc283SCraig Rodrigues } 6434b5bc283SCraig Rodrigues 6444b5bc283SCraig Rodrigues newiov = NULL; 6454b5bc283SCraig Rodrigues newiovlen = 0; 6464b5bc283SCraig Rodrigues 6474b5bc283SCraig Rodrigues build_iovec(&newiov, &newiovlen, "nfs_args", &args, sizeof(args)); 6484b5bc283SCraig Rodrigues copyopt(&newiov, &newiovlen, iov, iovlen, "fstype"); 6494b5bc283SCraig Rodrigues copyopt(&newiov, &newiovlen, iov, iovlen, "fspath"); 6504b5bc283SCraig Rodrigues copyopt(&newiov, &newiovlen, iov, iovlen, "errmsg"); 6514b5bc283SCraig Rodrigues 6524b5bc283SCraig Rodrigues return nmount(newiov, newiovlen, mntflags); 6534b5bc283SCraig Rodrigues } 6544b5bc283SCraig Rodrigues 6554b5bc283SCraig Rodrigues int 656a9148abdSDoug Rabson sec_name_to_num(char *sec) 657a9148abdSDoug Rabson { 658a9148abdSDoug Rabson if (!strcmp(sec, "krb5")) 659a9148abdSDoug Rabson return (RPCSEC_GSS_KRB5); 660a9148abdSDoug Rabson if (!strcmp(sec, "krb5i")) 661a9148abdSDoug Rabson return (RPCSEC_GSS_KRB5I); 662a9148abdSDoug Rabson if (!strcmp(sec, "krb5p")) 663a9148abdSDoug Rabson return (RPCSEC_GSS_KRB5P); 664a9148abdSDoug Rabson if (!strcmp(sec, "sys")) 665a9148abdSDoug Rabson return (AUTH_SYS); 666a9148abdSDoug Rabson return (-1); 667a9148abdSDoug Rabson } 668a9148abdSDoug Rabson 669a9148abdSDoug Rabson char * 670a9148abdSDoug Rabson sec_num_to_name(int flavor) 671a9148abdSDoug Rabson { 672a9148abdSDoug Rabson switch (flavor) { 673a9148abdSDoug Rabson case RPCSEC_GSS_KRB5: 674a9148abdSDoug Rabson return ("krb5"); 675a9148abdSDoug Rabson case RPCSEC_GSS_KRB5I: 676a9148abdSDoug Rabson return ("krb5i"); 677a9148abdSDoug Rabson case RPCSEC_GSS_KRB5P: 678a9148abdSDoug Rabson return ("krb5p"); 679a9148abdSDoug Rabson case AUTH_SYS: 680a9148abdSDoug Rabson return ("sys"); 681a9148abdSDoug Rabson } 682a9148abdSDoug Rabson return (NULL); 683a9148abdSDoug Rabson } 684a9148abdSDoug Rabson 685a9148abdSDoug Rabson int 6864b5bc283SCraig Rodrigues getnfsargs(char *spec, struct iovec **iov, int *iovlen) 6878fae3551SRodney W. Grimes { 6888360efbdSAlfred Perlstein struct addrinfo hints, *ai_nfs, *ai; 689317d5933SIan Dowse enum tryret ret; 690317d5933SIan Dowse int ecode, speclen, remoteerr; 691317d5933SIan Dowse char *hostp, *delimp, *errstr; 69266a84ea7SBrian Feldman size_t len; 6938fae3551SRodney W. Grimes static char nam[MNAMELEN + 1]; 6948fae3551SRodney W. Grimes 6958360efbdSAlfred Perlstein if ((delimp = strrchr(spec, ':')) != NULL) { 6968fae3551SRodney W. Grimes hostp = spec; 6978fae3551SRodney W. Grimes spec = delimp + 1; 69873dd3167SPoul-Henning Kamp } else if ((delimp = strrchr(spec, '@')) != NULL) { 69973dd3167SPoul-Henning Kamp warnx("path@server syntax is deprecated, use server:path"); 70073dd3167SPoul-Henning Kamp hostp = delimp + 1; 7018fae3551SRodney W. Grimes } else { 70273dd3167SPoul-Henning Kamp warnx("no <host>:<dirpath> nfs-name"); 7038fae3551SRodney W. Grimes return (0); 7048fae3551SRodney W. Grimes } 7058fae3551SRodney W. Grimes *delimp = '\0'; 70673dd3167SPoul-Henning Kamp 70773dd3167SPoul-Henning Kamp /* 70873dd3167SPoul-Henning Kamp * If there has been a trailing slash at mounttime it seems 70973dd3167SPoul-Henning Kamp * that some mountd implementations fail to remove the mount 71073dd3167SPoul-Henning Kamp * entries from their mountlist while unmounting. 71173dd3167SPoul-Henning Kamp */ 71266a84ea7SBrian Feldman for (speclen = strlen(spec); 71366a84ea7SBrian Feldman speclen > 1 && spec[speclen - 1] == '/'; 71466a84ea7SBrian Feldman speclen--) 71573dd3167SPoul-Henning Kamp spec[speclen - 1] = '\0'; 71673dd3167SPoul-Henning Kamp if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) { 71773dd3167SPoul-Henning Kamp warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG)); 71873dd3167SPoul-Henning Kamp return (0); 71973dd3167SPoul-Henning Kamp } 72073dd3167SPoul-Henning Kamp /* Make both '@' and ':' notations equal */ 72166a84ea7SBrian Feldman if (*hostp != '\0') { 72266a84ea7SBrian Feldman len = strlen(hostp); 72366a84ea7SBrian Feldman memmove(nam, hostp, len); 72466a84ea7SBrian Feldman nam[len] = ':'; 72566a84ea7SBrian Feldman memmove(nam + len + 1, spec, speclen); 72666a84ea7SBrian Feldman nam[len + speclen + 1] = '\0'; 72766a84ea7SBrian Feldman } 7288fae3551SRodney W. Grimes 7298fae3551SRodney W. Grimes /* 73091196234SPeter Wemm * Handle an internet host address. 7318fae3551SRodney W. Grimes */ 7328360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 7338360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST; 7344b5bc283SCraig Rodrigues if (nfsproto == IPPROTO_TCP) 7354b5bc283SCraig Rodrigues hints.ai_socktype = SOCK_STREAM; 7364b5bc283SCraig Rodrigues else if (nfsproto == IPPROTO_UDP) 7374b5bc283SCraig Rodrigues hints.ai_socktype = SOCK_DGRAM; 7384b5bc283SCraig Rodrigues 73991196234SPeter Wemm if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) { 7408360efbdSAlfred Perlstein hints.ai_flags = 0; 741317d5933SIan Dowse if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs)) 742317d5933SIan Dowse != 0) { 743317d5933SIan Dowse if (portspec == NULL) 744317d5933SIan Dowse errx(1, "%s: %s", hostp, gai_strerror(ecode)); 745317d5933SIan Dowse else 746317d5933SIan Dowse errx(1, "%s:%s: %s", hostp, portspec, 7478360efbdSAlfred Perlstein gai_strerror(ecode)); 7488360efbdSAlfred Perlstein return (0); 7498360efbdSAlfred Perlstein } 7508360efbdSAlfred Perlstein } 7518fae3551SRodney W. Grimes 752317d5933SIan Dowse ret = TRYRET_LOCALERR; 753e16873daSIan Dowse for (;;) { 754deffdffaSAndrey A. Chernov /* 755317d5933SIan Dowse * Try each entry returned by getaddrinfo(). Note the 756317d5933SIan Dowse * occurence of remote errors by setting `remoteerr'. 757deffdffaSAndrey A. Chernov */ 758317d5933SIan Dowse remoteerr = 0; 759317d5933SIan Dowse for (ai = ai_nfs; ai != NULL; ai = ai->ai_next) { 760302f15f9SMatthew N. Dodd if ((ai->ai_family == AF_INET6) && 761302f15f9SMatthew N. Dodd (opflags & OF_NOINET6)) 762302f15f9SMatthew N. Dodd continue; 763302f15f9SMatthew N. Dodd if ((ai->ai_family == AF_INET) && 764302f15f9SMatthew N. Dodd (opflags & OF_NOINET4)) 765302f15f9SMatthew N. Dodd continue; 7664b5bc283SCraig Rodrigues ret = nfs_tryproto(ai, hostp, spec, &errstr, iov, 7674b5bc283SCraig Rodrigues iovlen); 768317d5933SIan Dowse if (ret == TRYRET_SUCCESS) 769317d5933SIan Dowse break; 770317d5933SIan Dowse if (ret != TRYRET_LOCALERR) 771317d5933SIan Dowse remoteerr = 1; 772317d5933SIan Dowse if ((opflags & ISBGRND) == 0) 773317d5933SIan Dowse fprintf(stderr, "%s\n", errstr); 774deffdffaSAndrey A. Chernov } 775317d5933SIan Dowse if (ret == TRYRET_SUCCESS) 776317d5933SIan Dowse break; 777deffdffaSAndrey A. Chernov 778e16873daSIan Dowse /* Exit if all errors were local. */ 779e16873daSIan Dowse if (!remoteerr) 780deffdffaSAndrey A. Chernov exit(1); 781317d5933SIan Dowse 782e16873daSIan Dowse /* 783e16873daSIan Dowse * If retrycnt == 0, we are to keep retrying forever. 784e16873daSIan Dowse * Otherwise decrement it, and exit if it hits zero. 785e16873daSIan Dowse */ 786e16873daSIan Dowse if (retrycnt != 0 && --retrycnt == 0) 787317d5933SIan Dowse exit(1); 788317d5933SIan Dowse 789317d5933SIan Dowse if ((opflags & (BGRND | ISBGRND)) == BGRND) { 790317d5933SIan Dowse warnx("Cannot immediately mount %s:%s, backgrounding", 791317d5933SIan Dowse hostp, spec); 792317d5933SIan Dowse opflags |= ISBGRND; 793317d5933SIan Dowse if (daemon(0, 0) != 0) 794317d5933SIan Dowse err(1, "daemon"); 7958fae3551SRodney W. Grimes } 7968fae3551SRodney W. Grimes sleep(60); 7978fae3551SRodney W. Grimes } 7988360efbdSAlfred Perlstein freeaddrinfo(ai_nfs); 7994b5bc283SCraig Rodrigues 8004b5bc283SCraig Rodrigues build_iovec(iov, iovlen, "hostname", nam, (size_t)-1); 801a69497d7SMatthew Dillon /* Add mounted file system to PATH_MOUNTTAB */ 802a69497d7SMatthew Dillon if (!add_mtab(hostp, spec)) 803a69497d7SMatthew Dillon warnx("can't update %s for %s:%s", PATH_MOUNTTAB, hostp, spec); 8048fae3551SRodney W. Grimes return (1); 8058fae3551SRodney W. Grimes } 8068fae3551SRodney W. Grimes 8070c269d1fSCraig Rodrigues 8080c269d1fSCraig Rodrigues int 8094b5bc283SCraig Rodrigues getnfs4args(char *spec, struct iovec **iov, int *iovlen) 8100c269d1fSCraig Rodrigues { 8110c269d1fSCraig Rodrigues struct addrinfo hints, *ai_nfs, *ai; 8120c269d1fSCraig Rodrigues enum tryret ret; 8134b5bc283SCraig Rodrigues int ecode, speclen, remoteerr, sotype; 8140c269d1fSCraig Rodrigues char *hostp, *delimp, *errstr; 8150c269d1fSCraig Rodrigues size_t len; 8160c269d1fSCraig Rodrigues static char nam[MNAMELEN + 1]; 8170c269d1fSCraig Rodrigues 8184b5bc283SCraig Rodrigues if (nfsproto == IPPROTO_TCP) 8194b5bc283SCraig Rodrigues sotype = SOCK_STREAM; 8204b5bc283SCraig Rodrigues else if (nfsproto == IPPROTO_UDP) 8214b5bc283SCraig Rodrigues sotype = SOCK_DGRAM; 8224b5bc283SCraig Rodrigues 8234b5bc283SCraig Rodrigues 8240c269d1fSCraig Rodrigues if ((delimp = strrchr(spec, ':')) != NULL) { 8250c269d1fSCraig Rodrigues hostp = spec; 8260c269d1fSCraig Rodrigues spec = delimp + 1; 8270c269d1fSCraig Rodrigues } else if ((delimp = strrchr(spec, '@')) != NULL) { 8280c269d1fSCraig Rodrigues warnx("path@server syntax is deprecated, use server:path"); 8290c269d1fSCraig Rodrigues hostp = delimp + 1; 8300c269d1fSCraig Rodrigues } else { 8310c269d1fSCraig Rodrigues warnx("no <host>:<dirpath> nfs-name"); 8320c269d1fSCraig Rodrigues return (0); 8330c269d1fSCraig Rodrigues } 8340c269d1fSCraig Rodrigues *delimp = '\0'; 8350c269d1fSCraig Rodrigues 8360c269d1fSCraig Rodrigues /* 8370c269d1fSCraig Rodrigues * If there has been a trailing slash at mounttime it seems 8380c269d1fSCraig Rodrigues * that some mountd implementations fail to remove the mount 8390c269d1fSCraig Rodrigues * entries from their mountlist while unmounting. 8400c269d1fSCraig Rodrigues */ 8410c269d1fSCraig Rodrigues for (speclen = strlen(spec); 8420c269d1fSCraig Rodrigues speclen > 1 && spec[speclen - 1] == '/'; 8430c269d1fSCraig Rodrigues speclen--) 8440c269d1fSCraig Rodrigues spec[speclen - 1] = '\0'; 8450c269d1fSCraig Rodrigues if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) { 8460c269d1fSCraig Rodrigues warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG)); 8470c269d1fSCraig Rodrigues return (0); 8480c269d1fSCraig Rodrigues } 8490c269d1fSCraig Rodrigues /* Make both '@' and ':' notations equal */ 8500c269d1fSCraig Rodrigues if (*hostp != '\0') { 8510c269d1fSCraig Rodrigues len = strlen(hostp); 8520c269d1fSCraig Rodrigues memmove(nam, hostp, len); 8530c269d1fSCraig Rodrigues nam[len] = ':'; 8540c269d1fSCraig Rodrigues memmove(nam + len + 1, spec, speclen); 8550c269d1fSCraig Rodrigues nam[len + speclen + 1] = '\0'; 8560c269d1fSCraig Rodrigues } 8570c269d1fSCraig Rodrigues 8580c269d1fSCraig Rodrigues /* 8590c269d1fSCraig Rodrigues * Handle an internet host address. 8600c269d1fSCraig Rodrigues */ 8610c269d1fSCraig Rodrigues memset(&hints, 0, sizeof hints); 8620c269d1fSCraig Rodrigues hints.ai_flags = AI_NUMERICHOST; 8634b5bc283SCraig Rodrigues hints.ai_socktype = sotype; 8640c269d1fSCraig Rodrigues if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) { 8650c269d1fSCraig Rodrigues hints.ai_flags = 0; 8660c269d1fSCraig Rodrigues if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs)) 8670c269d1fSCraig Rodrigues != 0) { 8680c269d1fSCraig Rodrigues if (portspec == NULL) 8690c269d1fSCraig Rodrigues errx(1, "%s: %s", hostp, gai_strerror(ecode)); 8700c269d1fSCraig Rodrigues else 8710c269d1fSCraig Rodrigues errx(1, "%s:%s: %s", hostp, portspec, 8720c269d1fSCraig Rodrigues gai_strerror(ecode)); 8730c269d1fSCraig Rodrigues return (0); 8740c269d1fSCraig Rodrigues } 8750c269d1fSCraig Rodrigues } 8760c269d1fSCraig Rodrigues 8770c269d1fSCraig Rodrigues ret = TRYRET_LOCALERR; 8780c269d1fSCraig Rodrigues for (;;) { 8790c269d1fSCraig Rodrigues /* 8800c269d1fSCraig Rodrigues * Try each entry returned by getaddrinfo(). Note the 8810c269d1fSCraig Rodrigues * occurence of remote errors by setting `remoteerr'. 8820c269d1fSCraig Rodrigues */ 8830c269d1fSCraig Rodrigues remoteerr = 0; 8840c269d1fSCraig Rodrigues for (ai = ai_nfs; ai != NULL; ai = ai->ai_next) { 8850c269d1fSCraig Rodrigues if ((ai->ai_family == AF_INET6) && 8860c269d1fSCraig Rodrigues (opflags & OF_NOINET6)) 8870c269d1fSCraig Rodrigues continue; 8880c269d1fSCraig Rodrigues if ((ai->ai_family == AF_INET) && 8890c269d1fSCraig Rodrigues (opflags & OF_NOINET4)) 8900c269d1fSCraig Rodrigues continue; 8914b5bc283SCraig Rodrigues ret = nfs4_tryproto(ai, hostp, spec, &errstr); 8920c269d1fSCraig Rodrigues if (ret == TRYRET_SUCCESS) 8930c269d1fSCraig Rodrigues break; 8940c269d1fSCraig Rodrigues if (ret != TRYRET_LOCALERR) 8950c269d1fSCraig Rodrigues remoteerr = 1; 8960c269d1fSCraig Rodrigues if ((opflags & ISBGRND) == 0) 8970c269d1fSCraig Rodrigues fprintf(stderr, "%s\n", errstr); 8980c269d1fSCraig Rodrigues } 8990c269d1fSCraig Rodrigues if (ret == TRYRET_SUCCESS) 9000c269d1fSCraig Rodrigues break; 9010c269d1fSCraig Rodrigues 9020c269d1fSCraig Rodrigues /* Exit if all errors were local. */ 9030c269d1fSCraig Rodrigues if (!remoteerr) 9040c269d1fSCraig Rodrigues exit(1); 9050c269d1fSCraig Rodrigues 9060c269d1fSCraig Rodrigues /* 9070c269d1fSCraig Rodrigues * If retrycnt == 0, we are to keep retrying forever. 9080c269d1fSCraig Rodrigues * Otherwise decrement it, and exit if it hits zero. 9090c269d1fSCraig Rodrigues */ 9100c269d1fSCraig Rodrigues if (retrycnt != 0 && --retrycnt == 0) 9110c269d1fSCraig Rodrigues exit(1); 9120c269d1fSCraig Rodrigues 9130c269d1fSCraig Rodrigues if ((opflags & (BGRND | ISBGRND)) == BGRND) { 9140c269d1fSCraig Rodrigues warnx("Cannot immediately mount %s:%s, backgrounding", 9150c269d1fSCraig Rodrigues hostp, spec); 9160c269d1fSCraig Rodrigues opflags |= ISBGRND; 9170c269d1fSCraig Rodrigues if (daemon(0, 0) != 0) 9180c269d1fSCraig Rodrigues err(1, "daemon"); 9190c269d1fSCraig Rodrigues } 9200c269d1fSCraig Rodrigues sleep(60); 9210c269d1fSCraig Rodrigues } 9220c269d1fSCraig Rodrigues freeaddrinfo(ai_nfs); 9234b5bc283SCraig Rodrigues build_iovec(iov, iovlen, "hostname", nam, (size_t)-1); 9240c269d1fSCraig Rodrigues /* Add mounted file system to PATH_MOUNTTAB */ 9250c269d1fSCraig Rodrigues if (!add_mtab(hostp, spec)) 9260c269d1fSCraig Rodrigues warnx("can't update %s for %s:%s", PATH_MOUNTTAB, hostp, spec); 9270c269d1fSCraig Rodrigues return (1); 9280c269d1fSCraig Rodrigues } 9290c269d1fSCraig Rodrigues 9308fae3551SRodney W. Grimes /* 931317d5933SIan Dowse * Try to set up the NFS arguments according to the address 932317d5933SIan Dowse * family, protocol (and possibly port) specified in `ai'. 933317d5933SIan Dowse * 934317d5933SIan Dowse * Returns TRYRET_SUCCESS if successful, or: 935317d5933SIan Dowse * TRYRET_TIMEOUT The server did not respond. 936317d5933SIan Dowse * TRYRET_REMOTEERR The server reported an error. 937317d5933SIan Dowse * TRYRET_LOCALERR Local failure. 938317d5933SIan Dowse * 939317d5933SIan Dowse * In all error cases, *errstr will be set to a statically-allocated string 940317d5933SIan Dowse * describing the error. 941317d5933SIan Dowse */ 942317d5933SIan Dowse enum tryret 9434b5bc283SCraig Rodrigues nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr, 9444b5bc283SCraig Rodrigues struct iovec **iov, int *iovlen) 945317d5933SIan Dowse { 946317d5933SIan Dowse static char errbuf[256]; 947317d5933SIan Dowse struct sockaddr_storage nfs_ss; 948317d5933SIan Dowse struct netbuf nfs_nb; 949317d5933SIan Dowse struct nfhret nfhret; 950317d5933SIan Dowse struct timeval try; 951317d5933SIan Dowse struct rpc_err rpcerr; 952317d5933SIan Dowse CLIENT *clp; 953317d5933SIan Dowse struct netconfig *nconf, *nconf_mnt; 9544b5bc283SCraig Rodrigues const char *netid, *netid_mnt; 955a9148abdSDoug Rabson char *secname; 9564b5bc283SCraig Rodrigues int doconnect, nfsvers, mntvers, sotype; 957317d5933SIan Dowse enum clnt_stat stat; 958317d5933SIan Dowse enum mountmode trymntmode; 959317d5933SIan Dowse 960317d5933SIan Dowse trymntmode = mountmode; 961317d5933SIan Dowse errbuf[0] = '\0'; 962317d5933SIan Dowse *errstr = errbuf; 963317d5933SIan Dowse 9644b5bc283SCraig Rodrigues if (nfsproto == IPPROTO_TCP) 9654b5bc283SCraig Rodrigues sotype = SOCK_STREAM; 9664b5bc283SCraig Rodrigues else if (nfsproto == IPPROTO_UDP) 9674b5bc283SCraig Rodrigues sotype = SOCK_DGRAM; 9684b5bc283SCraig Rodrigues 9694b5bc283SCraig Rodrigues if ((netid = netidbytype(ai->ai_family, sotype)) == NULL) { 970a3d8f94bSIan Dowse snprintf(errbuf, sizeof errbuf, 9714b5bc283SCraig Rodrigues "af %d sotype %d not supported", ai->ai_family, sotype); 972a3d8f94bSIan Dowse return (TRYRET_LOCALERR); 973a3d8f94bSIan Dowse } 974a3d8f94bSIan Dowse if ((nconf = getnetconf_cached(netid)) == NULL) { 975317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror()); 976317d5933SIan Dowse return (TRYRET_LOCALERR); 977317d5933SIan Dowse } 978317d5933SIan Dowse /* The RPCPROG_MNT netid may be different. */ 979317d5933SIan Dowse if (mnttcp_ok) { 980ba33efd9SIan Dowse netid_mnt = netid; 981317d5933SIan Dowse nconf_mnt = nconf; 982317d5933SIan Dowse } else { 983a3d8f94bSIan Dowse if ((netid_mnt = netidbytype(ai->ai_family, SOCK_DGRAM)) 984a3d8f94bSIan Dowse == NULL) { 985a3d8f94bSIan Dowse snprintf(errbuf, sizeof errbuf, 986a3d8f94bSIan Dowse "af %d sotype SOCK_DGRAM not supported", 987a3d8f94bSIan Dowse ai->ai_family); 988a3d8f94bSIan Dowse return (TRYRET_LOCALERR); 989a3d8f94bSIan Dowse } 990a3d8f94bSIan Dowse if ((nconf_mnt = getnetconf_cached(netid_mnt)) == NULL) { 991ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "%s: %s", netid_mnt, 992317d5933SIan Dowse nc_sperror()); 993317d5933SIan Dowse return (TRYRET_LOCALERR); 994317d5933SIan Dowse } 995317d5933SIan Dowse } 996317d5933SIan Dowse 997317d5933SIan Dowse tryagain: 998317d5933SIan Dowse if (trymntmode == V2) { 999317d5933SIan Dowse nfsvers = 2; 1000317d5933SIan Dowse mntvers = 1; 1001317d5933SIan Dowse } else { 1002317d5933SIan Dowse nfsvers = 3; 1003317d5933SIan Dowse mntvers = 3; 1004317d5933SIan Dowse } 1005317d5933SIan Dowse 1006317d5933SIan Dowse if (portspec != NULL) { 1007317d5933SIan Dowse /* `ai' contains the complete nfsd sockaddr. */ 1008317d5933SIan Dowse nfs_nb.buf = ai->ai_addr; 1009317d5933SIan Dowse nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen; 1010317d5933SIan Dowse } else { 1011317d5933SIan Dowse /* Ask the remote rpcbind. */ 1012317d5933SIan Dowse nfs_nb.buf = &nfs_ss; 1013317d5933SIan Dowse nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss; 1014317d5933SIan Dowse 1015317d5933SIan Dowse if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, &nfs_nb, 1016317d5933SIan Dowse hostp)) { 1017317d5933SIan Dowse if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH && 1018317d5933SIan Dowse trymntmode == ANY) { 1019317d5933SIan Dowse trymntmode = V2; 1020317d5933SIan Dowse goto tryagain; 1021317d5933SIan Dowse } 1022317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", 1023317d5933SIan Dowse netid, hostp, spec, 1024317d5933SIan Dowse clnt_spcreateerror("RPCPROG_NFS")); 1025317d5933SIan Dowse return (returncode(rpc_createerr.cf_stat, 1026317d5933SIan Dowse &rpc_createerr.cf_error)); 1027317d5933SIan Dowse } 1028317d5933SIan Dowse } 1029317d5933SIan Dowse 1030317d5933SIan Dowse /* Check that the server (nfsd) responds on the port we have chosen. */ 1031317d5933SIan Dowse clp = clnt_tli_create(RPC_ANYFD, nconf, &nfs_nb, RPCPROG_NFS, nfsvers, 1032317d5933SIan Dowse 0, 0); 1033317d5933SIan Dowse if (clp == NULL) { 1034317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 1035317d5933SIan Dowse hostp, spec, clnt_spcreateerror("nfsd: RPCPROG_NFS")); 1036317d5933SIan Dowse return (returncode(rpc_createerr.cf_stat, 1037317d5933SIan Dowse &rpc_createerr.cf_error)); 1038317d5933SIan Dowse } 10394b5bc283SCraig Rodrigues if (sotype == SOCK_DGRAM && noconn == 0) { 1040eca1c24eSIan Dowse /* 1041eca1c24eSIan Dowse * Use connect(), to match what the kernel does. This 1042eca1c24eSIan Dowse * catches cases where the server responds from the 1043eca1c24eSIan Dowse * wrong source address. 1044eca1c24eSIan Dowse */ 1045eca1c24eSIan Dowse doconnect = 1; 1046eca1c24eSIan Dowse if (!clnt_control(clp, CLSET_CONNECT, (char *)&doconnect)) { 1047eca1c24eSIan Dowse clnt_destroy(clp); 1048eca1c24eSIan Dowse snprintf(errbuf, sizeof errbuf, 1049eca1c24eSIan Dowse "[%s] %s:%s: CLSET_CONNECT failed", netid, hostp, 1050eca1c24eSIan Dowse spec); 1051eca1c24eSIan Dowse return (TRYRET_LOCALERR); 1052eca1c24eSIan Dowse } 1053eca1c24eSIan Dowse } 1054eca1c24eSIan Dowse 1055317d5933SIan Dowse try.tv_sec = 10; 1056317d5933SIan Dowse try.tv_usec = 0; 1057c04affffSMatthew N. Dodd stat = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL, 1058c04affffSMatthew N. Dodd (xdrproc_t)xdr_void, NULL, 1059317d5933SIan Dowse try); 1060317d5933SIan Dowse if (stat != RPC_SUCCESS) { 1061317d5933SIan Dowse if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 1062317d5933SIan Dowse clnt_destroy(clp); 1063317d5933SIan Dowse trymntmode = V2; 1064317d5933SIan Dowse goto tryagain; 1065317d5933SIan Dowse } 1066317d5933SIan Dowse clnt_geterr(clp, &rpcerr); 1067317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 1068317d5933SIan Dowse hostp, spec, clnt_sperror(clp, "NFSPROC_NULL")); 1069317d5933SIan Dowse clnt_destroy(clp); 1070317d5933SIan Dowse return (returncode(stat, &rpcerr)); 1071317d5933SIan Dowse } 1072317d5933SIan Dowse clnt_destroy(clp); 1073317d5933SIan Dowse 1074317d5933SIan Dowse /* Send the RPCMNT_MOUNT RPC to get the root filehandle. */ 1075317d5933SIan Dowse try.tv_sec = 10; 1076317d5933SIan Dowse try.tv_usec = 0; 1077317d5933SIan Dowse clp = clnt_tp_create(hostp, RPCPROG_MNT, mntvers, nconf_mnt); 1078317d5933SIan Dowse if (clp == NULL) { 1079ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 1080317d5933SIan Dowse hostp, spec, clnt_spcreateerror("RPCMNT: clnt_create")); 1081317d5933SIan Dowse return (returncode(rpc_createerr.cf_stat, 1082317d5933SIan Dowse &rpc_createerr.cf_error)); 1083317d5933SIan Dowse } 1084317d5933SIan Dowse clp->cl_auth = authsys_create_default(); 1085a9148abdSDoug Rabson nfhret.auth = secflavor; 1086317d5933SIan Dowse nfhret.vers = mntvers; 1087c04affffSMatthew N. Dodd stat = clnt_call(clp, RPCMNT_MOUNT, (xdrproc_t)xdr_dir, spec, 1088c04affffSMatthew N. Dodd (xdrproc_t)xdr_fh, &nfhret, 1089317d5933SIan Dowse try); 1090317d5933SIan Dowse auth_destroy(clp->cl_auth); 1091317d5933SIan Dowse if (stat != RPC_SUCCESS) { 1092317d5933SIan Dowse if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 1093317d5933SIan Dowse clnt_destroy(clp); 1094317d5933SIan Dowse trymntmode = V2; 1095317d5933SIan Dowse goto tryagain; 1096317d5933SIan Dowse } 1097317d5933SIan Dowse clnt_geterr(clp, &rpcerr); 1098ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 1099317d5933SIan Dowse hostp, spec, clnt_sperror(clp, "RPCPROG_MNT")); 1100317d5933SIan Dowse clnt_destroy(clp); 1101317d5933SIan Dowse return (returncode(stat, &rpcerr)); 1102317d5933SIan Dowse } 1103317d5933SIan Dowse clnt_destroy(clp); 1104317d5933SIan Dowse 1105317d5933SIan Dowse if (nfhret.stat != 0) { 1106ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 1107317d5933SIan Dowse hostp, spec, strerror(nfhret.stat)); 1108317d5933SIan Dowse return (TRYRET_REMOTEERR); 1109317d5933SIan Dowse } 1110317d5933SIan Dowse 1111317d5933SIan Dowse /* 1112317d5933SIan Dowse * Store the filehandle and server address in nfsargsp, making 1113317d5933SIan Dowse * sure to copy any locally allocated structures. 1114317d5933SIan Dowse */ 11154b5bc283SCraig Rodrigues addrlen = nfs_nb.len; 11164b5bc283SCraig Rodrigues addr = malloc(addrlen); 11174b5bc283SCraig Rodrigues fhsize = nfhret.fhsize; 11184b5bc283SCraig Rodrigues fh = malloc(fhsize); 11194b5bc283SCraig Rodrigues if (addr == NULL || fh == NULL) 1120317d5933SIan Dowse err(1, "malloc"); 11214b5bc283SCraig Rodrigues bcopy(nfs_nb.buf, addr, addrlen); 11224b5bc283SCraig Rodrigues bcopy(nfhret.nfh, fh, fhsize); 1123317d5933SIan Dowse 11244b5bc283SCraig Rodrigues build_iovec(iov, iovlen, "addr", addr, addrlen); 11254b5bc283SCraig Rodrigues build_iovec(iov, iovlen, "fh", fh, fhsize); 1126a9148abdSDoug Rabson secname = sec_num_to_name(nfhret.auth); 1127a9148abdSDoug Rabson if (secname) 1128a9148abdSDoug Rabson build_iovec(iov, iovlen, "sec", secname, (size_t)-1); 1129317d5933SIan Dowse if (nfsvers == 3) 11304b5bc283SCraig Rodrigues build_iovec(iov, iovlen, "nfsv3", NULL, 0); 1131317d5933SIan Dowse 1132317d5933SIan Dowse return (TRYRET_SUCCESS); 1133317d5933SIan Dowse } 1134317d5933SIan Dowse 1135317d5933SIan Dowse 1136317d5933SIan Dowse /* 11370c269d1fSCraig Rodrigues * Try to set up the NFS arguments according to the address 11380c269d1fSCraig Rodrigues * family, protocol (and possibly port) specified in `ai'. 11390c269d1fSCraig Rodrigues * 11400c269d1fSCraig Rodrigues * Returns TRYRET_SUCCESS if successful, or: 11410c269d1fSCraig Rodrigues * TRYRET_TIMEOUT The server did not respond. 11420c269d1fSCraig Rodrigues * TRYRET_REMOTEERR The server reported an error. 11430c269d1fSCraig Rodrigues * TRYRET_LOCALERR Local failure. 11440c269d1fSCraig Rodrigues * 11450c269d1fSCraig Rodrigues * In all error cases, *errstr will be set to a statically-allocated string 11460c269d1fSCraig Rodrigues * describing the error. 11470c269d1fSCraig Rodrigues */ 11480c269d1fSCraig Rodrigues enum tryret 11494b5bc283SCraig Rodrigues nfs4_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr) 11500c269d1fSCraig Rodrigues { 11510c269d1fSCraig Rodrigues static char errbuf[256]; 11520c269d1fSCraig Rodrigues struct sockaddr_storage nfs_ss; 11530c269d1fSCraig Rodrigues struct netbuf nfs_nb; 11540c269d1fSCraig Rodrigues struct netconfig *nconf; 11554b5bc283SCraig Rodrigues const char *netid; 11564b5bc283SCraig Rodrigues int nfsvers, sotype; 11570c269d1fSCraig Rodrigues 11580c269d1fSCraig Rodrigues errbuf[0] = '\0'; 11590c269d1fSCraig Rodrigues *errstr = errbuf; 11600c269d1fSCraig Rodrigues 11614b5bc283SCraig Rodrigues if (nfsproto == IPPROTO_TCP) 11624b5bc283SCraig Rodrigues sotype = SOCK_STREAM; 11634b5bc283SCraig Rodrigues else if (nfsproto == IPPROTO_UDP) 11644b5bc283SCraig Rodrigues sotype = SOCK_DGRAM; 11654b5bc283SCraig Rodrigues 11664b5bc283SCraig Rodrigues if ((netid = netidbytype(ai->ai_family, sotype)) == NULL) { 11670c269d1fSCraig Rodrigues snprintf(errbuf, sizeof errbuf, 11684b5bc283SCraig Rodrigues "af %d sotype %d not supported", ai->ai_family, sotype); 11690c269d1fSCraig Rodrigues return (TRYRET_LOCALERR); 11700c269d1fSCraig Rodrigues } 11710c269d1fSCraig Rodrigues if ((nconf = getnetconf_cached(netid)) == NULL) { 11720c269d1fSCraig Rodrigues snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror()); 11730c269d1fSCraig Rodrigues return (TRYRET_LOCALERR); 11740c269d1fSCraig Rodrigues } 11750c269d1fSCraig Rodrigues 11760c269d1fSCraig Rodrigues nfsvers = 4; 11770c269d1fSCraig Rodrigues 11780c269d1fSCraig Rodrigues if (portspec != NULL && atoi(portspec) != 0) { 11790c269d1fSCraig Rodrigues /* `ai' contains the complete nfsd sockaddr. */ 11800c269d1fSCraig Rodrigues nfs_nb.buf = ai->ai_addr; 11810c269d1fSCraig Rodrigues nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen; 11820c269d1fSCraig Rodrigues } else { 11830c269d1fSCraig Rodrigues /* Ask the remote rpcbind. */ 11840c269d1fSCraig Rodrigues nfs_nb.buf = &nfs_ss; 11850c269d1fSCraig Rodrigues nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss; 11860c269d1fSCraig Rodrigues 11870c269d1fSCraig Rodrigues if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, &nfs_nb, 11880c269d1fSCraig Rodrigues hostp)) { 11890c269d1fSCraig Rodrigues snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", 11900c269d1fSCraig Rodrigues netid, hostp, spec, 11910c269d1fSCraig Rodrigues clnt_spcreateerror("RPCPROG_NFS")); 11920c269d1fSCraig Rodrigues return (returncode(rpc_createerr.cf_stat, 11930c269d1fSCraig Rodrigues &rpc_createerr.cf_error)); 11940c269d1fSCraig Rodrigues } 11950c269d1fSCraig Rodrigues } 11960c269d1fSCraig Rodrigues 11970c269d1fSCraig Rodrigues /* 11980c269d1fSCraig Rodrigues * Store the filehandle and server address in nfsargsp, making 11990c269d1fSCraig Rodrigues * sure to copy any locally allocated structures. 12000c269d1fSCraig Rodrigues */ 12014b5bc283SCraig Rodrigues addrlen = nfs_nb.len; 12024b5bc283SCraig Rodrigues addr = malloc(addrlen); 12030c269d1fSCraig Rodrigues 12044b5bc283SCraig Rodrigues if (addr == NULL) 12050c269d1fSCraig Rodrigues err(1, "malloc"); 12064b5bc283SCraig Rodrigues bcopy(nfs_nb.buf, addr, addrlen); 12070c269d1fSCraig Rodrigues 12080c269d1fSCraig Rodrigues return (TRYRET_SUCCESS); 12090c269d1fSCraig Rodrigues } 12100c269d1fSCraig Rodrigues 12110c269d1fSCraig Rodrigues /* 1212317d5933SIan Dowse * Catagorise a RPC return status and error into an `enum tryret' 1213317d5933SIan Dowse * return code. 1214317d5933SIan Dowse */ 1215317d5933SIan Dowse enum tryret 1216317d5933SIan Dowse returncode(enum clnt_stat stat, struct rpc_err *rpcerr) 1217317d5933SIan Dowse { 1218317d5933SIan Dowse switch (stat) { 1219317d5933SIan Dowse case RPC_TIMEDOUT: 1220317d5933SIan Dowse return (TRYRET_TIMEOUT); 1221317d5933SIan Dowse case RPC_PMAPFAILURE: 1222317d5933SIan Dowse case RPC_PROGNOTREGISTERED: 1223317d5933SIan Dowse case RPC_PROGVERSMISMATCH: 1224eca1c24eSIan Dowse /* XXX, these can be local or remote. */ 1225eca1c24eSIan Dowse case RPC_CANTSEND: 1226eca1c24eSIan Dowse case RPC_CANTRECV: 1227317d5933SIan Dowse return (TRYRET_REMOTEERR); 1228317d5933SIan Dowse case RPC_SYSTEMERROR: 1229317d5933SIan Dowse switch (rpcerr->re_errno) { 1230317d5933SIan Dowse case ETIMEDOUT: 1231317d5933SIan Dowse return (TRYRET_TIMEOUT); 1232317d5933SIan Dowse case ENOMEM: 1233317d5933SIan Dowse break; 1234317d5933SIan Dowse default: 1235317d5933SIan Dowse return (TRYRET_REMOTEERR); 1236317d5933SIan Dowse } 1237317d5933SIan Dowse /* FALLTHROUGH */ 1238317d5933SIan Dowse default: 1239317d5933SIan Dowse break; 1240317d5933SIan Dowse } 1241317d5933SIan Dowse return (TRYRET_LOCALERR); 1242317d5933SIan Dowse } 1243317d5933SIan Dowse 1244317d5933SIan Dowse /* 1245a3d8f94bSIan Dowse * Look up a netid based on an address family and socket type. 1246a3d8f94bSIan Dowse * `af' is the address family, and `sotype' is SOCK_DGRAM or SOCK_STREAM. 1247a3d8f94bSIan Dowse * 1248a3d8f94bSIan Dowse * XXX there should be a library function for this. 1249a3d8f94bSIan Dowse */ 12504b5bc283SCraig Rodrigues const char * 125133924ad4SWarner Losh netidbytype(int af, int sotype) 125233924ad4SWarner Losh { 1253a3d8f94bSIan Dowse struct nc_protos *p; 1254a3d8f94bSIan Dowse 1255a3d8f94bSIan Dowse for (p = nc_protos; p->netid != NULL; p++) { 1256a3d8f94bSIan Dowse if (af != p->af || sotype != p->sotype) 1257a3d8f94bSIan Dowse continue; 1258a3d8f94bSIan Dowse return (p->netid); 1259a3d8f94bSIan Dowse } 1260a3d8f94bSIan Dowse return (NULL); 1261a3d8f94bSIan Dowse } 1262a3d8f94bSIan Dowse 1263a3d8f94bSIan Dowse /* 1264a3d8f94bSIan Dowse * Look up a netconfig entry based on a netid, and cache the result so 1265a3d8f94bSIan Dowse * that we don't need to remember to call freenetconfigent(). 1266a3d8f94bSIan Dowse * 1267a3d8f94bSIan Dowse * Otherwise it behaves just like getnetconfigent(), so nc_*error() 1268a3d8f94bSIan Dowse * work on failure. 1269a3d8f94bSIan Dowse */ 1270a3d8f94bSIan Dowse struct netconfig * 127133924ad4SWarner Losh getnetconf_cached(const char *netid) 127233924ad4SWarner Losh { 1273a3d8f94bSIan Dowse static struct nc_entry { 1274a3d8f94bSIan Dowse struct netconfig *nconf; 1275a3d8f94bSIan Dowse struct nc_entry *next; 1276a3d8f94bSIan Dowse } *head; 1277a3d8f94bSIan Dowse struct nc_entry *p; 1278a3d8f94bSIan Dowse struct netconfig *nconf; 1279a3d8f94bSIan Dowse 1280a3d8f94bSIan Dowse for (p = head; p != NULL; p = p->next) 1281a3d8f94bSIan Dowse if (strcmp(netid, p->nconf->nc_netid) == 0) 1282a3d8f94bSIan Dowse return (p->nconf); 1283a3d8f94bSIan Dowse 1284a3d8f94bSIan Dowse if ((nconf = getnetconfigent(netid)) == NULL) 1285a3d8f94bSIan Dowse return (NULL); 1286a3d8f94bSIan Dowse if ((p = malloc(sizeof(*p))) == NULL) 1287a3d8f94bSIan Dowse err(1, "malloc"); 1288a3d8f94bSIan Dowse p->nconf = nconf; 1289a3d8f94bSIan Dowse p->next = head; 1290a3d8f94bSIan Dowse head = p; 1291a3d8f94bSIan Dowse 1292a3d8f94bSIan Dowse return (p->nconf); 1293a3d8f94bSIan Dowse } 1294a3d8f94bSIan Dowse 1295a3d8f94bSIan Dowse /* 12968fae3551SRodney W. Grimes * xdr routines for mount rpc's 12978fae3551SRodney W. Grimes */ 12988fae3551SRodney W. Grimes int 129933924ad4SWarner Losh xdr_dir(XDR *xdrsp, char *dirp) 13008fae3551SRodney W. Grimes { 13018fae3551SRodney W. Grimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 13028fae3551SRodney W. Grimes } 13038fae3551SRodney W. Grimes 13048fae3551SRodney W. Grimes int 130533924ad4SWarner Losh xdr_fh(XDR *xdrsp, struct nfhret *np) 13068fae3551SRodney W. Grimes { 13073d438ad6SDavid E. O'Brien int i; 1308a62dc406SDoug Rabson long auth, authcnt, authfnd = 0; 1309a62dc406SDoug Rabson 1310a62dc406SDoug Rabson if (!xdr_u_long(xdrsp, &np->stat)) 13118fae3551SRodney W. Grimes return (0); 13128fae3551SRodney W. Grimes if (np->stat) 13138fae3551SRodney W. Grimes return (1); 1314a62dc406SDoug Rabson switch (np->vers) { 1315a62dc406SDoug Rabson case 1: 1316a62dc406SDoug Rabson np->fhsize = NFSX_V2FH; 1317a62dc406SDoug Rabson return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH)); 1318a62dc406SDoug Rabson case 3: 1319a62dc406SDoug Rabson if (!xdr_long(xdrsp, &np->fhsize)) 1320a62dc406SDoug Rabson return (0); 1321a62dc406SDoug Rabson if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX) 1322a62dc406SDoug Rabson return (0); 1323a62dc406SDoug Rabson if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize)) 1324a62dc406SDoug Rabson return (0); 1325a62dc406SDoug Rabson if (!xdr_long(xdrsp, &authcnt)) 1326a62dc406SDoug Rabson return (0); 1327a62dc406SDoug Rabson for (i = 0; i < authcnt; i++) { 1328a62dc406SDoug Rabson if (!xdr_long(xdrsp, &auth)) 1329a62dc406SDoug Rabson return (0); 13304b5bc283SCraig Rodrigues if (np->auth == -1) { 13314b5bc283SCraig Rodrigues np->auth = auth; 1332a62dc406SDoug Rabson authfnd++; 13334b5bc283SCraig Rodrigues } else if (auth == np->auth) { 13344b5bc283SCraig Rodrigues authfnd++; 13354b5bc283SCraig Rodrigues } 1336a62dc406SDoug Rabson } 1337a62dc406SDoug Rabson /* 1338a62dc406SDoug Rabson * Some servers, such as DEC's OSF/1 return a nil authenticator 1339a62dc406SDoug Rabson * list to indicate RPCAUTH_UNIX. 1340a62dc406SDoug Rabson */ 13414b5bc283SCraig Rodrigues if (authcnt == 0 && np->auth == -1) 13424b5bc283SCraig Rodrigues np->auth = AUTH_SYS; 13434b5bc283SCraig Rodrigues if (!authfnd && (authcnt > 0 || np->auth != AUTH_SYS)) 1344a62dc406SDoug Rabson np->stat = EAUTH; 1345a62dc406SDoug Rabson return (1); 1346a62dc406SDoug Rabson }; 1347a62dc406SDoug Rabson return (0); 13488fae3551SRodney W. Grimes } 13498fae3551SRodney W. Grimes 1350eaa86f9dSBruce Evans void 13518fae3551SRodney W. Grimes usage() 13528fae3551SRodney W. Grimes { 135346fc8f78SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 13540c269d1fSCraig Rodrigues "usage: mount_nfs [-234bcdiLlNPsTU] [-a maxreadahead] [-D deadthresh]", 13558d646af5SRuslan Ermilov " [-g maxgroups] [-I readdirsize] [-o options] [-R retrycnt]", 13568d646af5SRuslan Ermilov " [-r readsize] [-t timeout] [-w writesize] [-x retrans]", 13578d646af5SRuslan Ermilov " rhost:path node"); 13588fae3551SRodney W. Grimes exit(1); 13598fae3551SRodney W. Grimes } 1360