18fae3551SRodney W. Grimes /* 28fae3551SRodney W. Grimes * Copyright (c) 1992, 1993, 1994 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by 68fae3551SRodney W. Grimes * Rick Macklem at The University of Guelph. 78fae3551SRodney W. Grimes * 88fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 98fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 108fae3551SRodney W. Grimes * are met: 118fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 128fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 138fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 148fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 158fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 168fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 178fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 188fae3551SRodney W. Grimes * without specific prior written permission. 198fae3551SRodney W. Grimes * 208fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 218fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 228fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 238fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 248fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 258fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 268fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 278fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 288fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 298fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 308fae3551SRodney W. Grimes * SUCH DAMAGE. 318fae3551SRodney W. Grimes */ 328fae3551SRodney W. Grimes 33c69284caSDavid E. O'Brien #if 0 348fae3551SRodney W. Grimes #ifndef lint 3546fc8f78SPhilippe Charnier static const char copyright[] = 368fae3551SRodney W. Grimes "@(#) Copyright (c) 1992, 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 414a4c5285SPeter Wemm static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95"; 428fae3551SRodney W. Grimes #endif /* not lint */ 43c69284caSDavid E. O'Brien #endif 44c69284caSDavid E. O'Brien #include <sys/cdefs.h> 45c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$"); 468fae3551SRodney W. Grimes 478fae3551SRodney W. Grimes #include <sys/param.h> 48011981fdSRick Macklem #include <sys/linker.h> 49011981fdSRick Macklem #include <sys/module.h> 508fae3551SRodney W. Grimes #include <sys/mount.h> 518360efbdSAlfred Perlstein #include <sys/socket.h> 528fae3551SRodney W. Grimes #include <sys/stat.h> 538fae3551SRodney W. Grimes #include <sys/syslog.h> 54c5aa1dc8SCraig Rodrigues #include <sys/uio.h> 558fae3551SRodney W. Grimes 568fae3551SRodney W. Grimes #include <rpc/rpc.h> 578fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h> 588fae3551SRodney W. Grimes #include <rpc/pmap_prot.h> 590775314bSDoug Rabson #include <rpcsvc/nfs_prot.h> 600775314bSDoug Rabson #include <rpcsvc/mount.h> 618fae3551SRodney W. Grimes 6291196234SPeter Wemm #include <nfsclient/nfs.h> 638fae3551SRodney W. Grimes 648fae3551SRodney W. Grimes #include <arpa/inet.h> 658fae3551SRodney W. Grimes 668fae3551SRodney W. Grimes #include <ctype.h> 678fae3551SRodney W. Grimes #include <err.h> 688fae3551SRodney W. Grimes #include <errno.h> 698360efbdSAlfred Perlstein #include <fcntl.h> 708fae3551SRodney W. Grimes #include <netdb.h> 718fae3551SRodney W. Grimes #include <stdio.h> 728fae3551SRodney W. Grimes #include <stdlib.h> 73c04affffSMatthew N. Dodd #include <string.h> 748fae3551SRodney W. Grimes #include <strings.h> 755e074e31SGarrett Wollman #include <sysexits.h> 768fae3551SRodney W. Grimes #include <unistd.h> 778fae3551SRodney W. Grimes 788fae3551SRodney W. Grimes #include "mntopts.h" 79a69497d7SMatthew Dillon #include "mounttab.h" 808fae3551SRodney W. Grimes 81a3d8f94bSIan Dowse /* Table for af,sotype -> netid conversions. */ 82a3d8f94bSIan Dowse struct nc_protos { 834b5bc283SCraig Rodrigues const char *netid; 84a3d8f94bSIan Dowse int af; 85a3d8f94bSIan Dowse int sotype; 86a3d8f94bSIan Dowse } nc_protos[] = { 87a3d8f94bSIan Dowse {"udp", AF_INET, SOCK_DGRAM}, 88a3d8f94bSIan Dowse {"tcp", AF_INET, SOCK_STREAM}, 89a3d8f94bSIan Dowse {"udp6", AF_INET6, SOCK_DGRAM}, 90a3d8f94bSIan Dowse {"tcp6", AF_INET6, SOCK_STREAM}, 91b535b298SCraig Rodrigues {NULL, 0, 0} 92a3d8f94bSIan Dowse }; 93a3d8f94bSIan Dowse 948fae3551SRodney W. Grimes struct nfhret { 958fae3551SRodney W. Grimes u_long stat; 96a62dc406SDoug Rabson long vers; 97a62dc406SDoug Rabson long auth; 98a62dc406SDoug Rabson long fhsize; 990775314bSDoug Rabson u_char nfh[NFS3_FHSIZE]; 1008fae3551SRodney W. Grimes }; 1018fae3551SRodney W. Grimes #define BGRND 1 1028fae3551SRodney W. Grimes #define ISBGRND 2 103302f15f9SMatthew N. Dodd #define OF_NOINET4 4 104302f15f9SMatthew N. Dodd #define OF_NOINET6 8 105e16873daSIan Dowse int retrycnt = -1; 1068fae3551SRodney W. Grimes int opflags = 0; 107a62dc406SDoug Rabson int nfsproto = IPPROTO_UDP; 108a62dc406SDoug Rabson int mnttcp_ok = 1; 1094b5bc283SCraig Rodrigues int noconn = 0; 110317d5933SIan Dowse char *portspec = NULL; /* Server nfs port; NULL means look up via rpcbind. */ 1114b5bc283SCraig Rodrigues struct sockaddr *addr; 1124b5bc283SCraig Rodrigues int addrlen = 0; 1134b5bc283SCraig Rodrigues u_char *fh = NULL; 1144b5bc283SCraig Rodrigues int fhsize = 0; 115a9148abdSDoug Rabson int secflavor = -1; 116011981fdSRick Macklem int got_principal = 0; 1174b5bc283SCraig Rodrigues 118317d5933SIan Dowse enum mountmode { 1192cd1c32cSDoug Rabson ANY, 1202cd1c32cSDoug Rabson V2, 1210c269d1fSCraig Rodrigues V3, 122011981fdSRick Macklem V4 1232cd1c32cSDoug Rabson } mountmode = ANY; 1248fae3551SRodney W. Grimes 125317d5933SIan Dowse /* Return codes for nfs_tryproto. */ 126317d5933SIan Dowse enum tryret { 127317d5933SIan Dowse TRYRET_SUCCESS, 128317d5933SIan Dowse TRYRET_TIMEOUT, /* No response received. */ 129317d5933SIan Dowse TRYRET_REMOTEERR, /* Error received from remote server. */ 130317d5933SIan Dowse TRYRET_LOCALERR /* Local failure. */ 131317d5933SIan Dowse }; 132317d5933SIan Dowse 1334b5bc283SCraig Rodrigues int fallback_mount(struct iovec *iov, int iovlen, int mntflags); 134a9148abdSDoug Rabson int sec_name_to_num(char *sec); 135a9148abdSDoug Rabson char *sec_num_to_name(int num); 1364b5bc283SCraig Rodrigues int getnfsargs(char *, struct iovec **iov, int *iovlen); 13785429990SWarner Losh /* void set_rpc_maxgrouplist(int); */ 138a3d8f94bSIan Dowse struct netconfig *getnetconf_cached(const char *netid); 1394b5bc283SCraig Rodrigues const char *netidbytype(int af, int sotype); 14085429990SWarner Losh void usage(void) __dead2; 14185429990SWarner Losh int xdr_dir(XDR *, char *); 14285429990SWarner Losh int xdr_fh(XDR *, struct nfhret *); 1434b5bc283SCraig Rodrigues enum tryret nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, 1444b5bc283SCraig Rodrigues char **errstr, struct iovec **iov, int *iovlen); 145317d5933SIan Dowse enum tryret returncode(enum clnt_stat stat, struct rpc_err *rpcerr); 146049307baSCraig Rodrigues extern int getosreldate(void); 1478fae3551SRodney W. Grimes 1488fae3551SRodney W. Grimes int 14933924ad4SWarner Losh main(int argc, char *argv[]) 1508fae3551SRodney W. Grimes { 1513d438ad6SDavid E. O'Brien int c; 152c5aa1dc8SCraig Rodrigues struct iovec *iov; 153049307baSCraig Rodrigues int mntflags, num, iovlen; 154049307baSCraig Rodrigues int osversion; 155a83655a3SYaroslav Tykhiy char *name, *p, *spec, *fstype; 156a6b26402SCraig Rodrigues char mntpath[MAXPATHLEN], errmsg[255]; 157011981fdSRick Macklem char hostname[MAXHOSTNAMELEN + 1], *gssname, gssn[MAXHOSTNAMELEN + 50]; 1588fae3551SRodney W. Grimes 1598fae3551SRodney W. Grimes mntflags = 0; 160c5aa1dc8SCraig Rodrigues iov = NULL; 161c5aa1dc8SCraig Rodrigues iovlen = 0; 162a6b26402SCraig Rodrigues memset(errmsg, 0, sizeof(errmsg)); 163011981fdSRick Macklem gssname = NULL; 164c5aa1dc8SCraig Rodrigues 165412ffff0SCraig Rodrigues fstype = strrchr(argv[0], '_'); 166412ffff0SCraig Rodrigues if (fstype == NULL) 167412ffff0SCraig Rodrigues errx(EX_USAGE, "argv[0] must end in _fstype"); 168412ffff0SCraig Rodrigues 169412ffff0SCraig Rodrigues ++fstype; 170412ffff0SCraig Rodrigues 1718fae3551SRodney W. Grimes while ((c = getopt(argc, argv, 17286ce6a83SRobert Watson "23a:bcdD:g:I:iLlNo:PR:r:sTt:w:x:U")) != -1) 1738fae3551SRodney W. Grimes switch (c) { 1742cd1c32cSDoug Rabson case '2': 1752cd1c32cSDoug Rabson mountmode = V2; 1762cd1c32cSDoug Rabson break; 177a62dc406SDoug Rabson case '3': 1782cd1c32cSDoug Rabson mountmode = V3; 179a62dc406SDoug Rabson break; 1808fae3551SRodney W. Grimes case 'a': 1814b5bc283SCraig Rodrigues printf("-a deprecated, use -o readhead=<value>\n"); 1824b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "readahead", optarg, (size_t)-1); 1838fae3551SRodney W. Grimes break; 1848fae3551SRodney W. Grimes case 'b': 1858fae3551SRodney W. Grimes opflags |= BGRND; 1868fae3551SRodney W. Grimes break; 1878fae3551SRodney W. Grimes case 'c': 1884b5bc283SCraig Rodrigues printf("-c deprecated, use -o noconn\n"); 1894b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "noconn", NULL, 0); 1904b5bc283SCraig Rodrigues noconn = 1; 1918fae3551SRodney W. Grimes break; 1928fae3551SRodney W. Grimes case 'D': 1934b5bc283SCraig Rodrigues printf("-D deprecated, use -o deadthresh=<value>\n"); 1944b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "deadthresh", optarg, (size_t)-1); 1958fae3551SRodney W. Grimes break; 1968fae3551SRodney W. Grimes case 'd': 1974b5bc283SCraig Rodrigues printf("-d deprecated, use -o dumbtimer"); 1984b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "dumbtimer", NULL, 0); 1998fae3551SRodney W. Grimes break; 2008fae3551SRodney W. Grimes case 'g': 2014b5bc283SCraig Rodrigues printf("-g deprecated, use -o maxgroups"); 2028fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 2038fae3551SRodney W. Grimes if (*p || num <= 0) 2048fae3551SRodney W. Grimes errx(1, "illegal -g value -- %s", optarg); 2054b5bc283SCraig Rodrigues //set_rpc_maxgrouplist(num); 2064b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "maxgroups", optarg, (size_t)-1); 2078fae3551SRodney W. Grimes break; 208a62dc406SDoug Rabson case 'I': 2094b5bc283SCraig Rodrigues printf("-I deprecated, use -o readdirsize=<value>\n"); 2104b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "readdirsize", optarg, (size_t)-1); 211a62dc406SDoug Rabson break; 2128fae3551SRodney W. Grimes case 'i': 2134b5bc283SCraig Rodrigues printf("-i deprecated, use -o intr\n"); 2144b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "intr", NULL, 0); 2158fae3551SRodney W. Grimes break; 21613190d87SAlfred Perlstein case 'L': 2174b5bc283SCraig Rodrigues printf("-i deprecated, use -o nolockd\n"); 2184b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "nolockd", NULL, 0); 21913190d87SAlfred Perlstein break; 2208fae3551SRodney W. Grimes case 'l': 2214b5bc283SCraig Rodrigues printf("-l deprecated, -o rdirplus\n"); 2224b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "rdirplus", NULL, 0); 2238fae3551SRodney W. Grimes break; 224cc75b131SJoerg Wunsch case 'N': 2254b5bc283SCraig Rodrigues printf("-N deprecated, do not specify -o resvport\n"); 226cc75b131SJoerg Wunsch break; 2274b5bc283SCraig Rodrigues case 'o': { 2284b5bc283SCraig Rodrigues int pass_flag_to_nmount; 2294b5bc283SCraig Rodrigues char *opt = optarg; 2304b5bc283SCraig Rodrigues while (opt) { 2314b5bc283SCraig Rodrigues char *pval = NULL; 2324b5bc283SCraig Rodrigues char *pnextopt = NULL; 2334b5bc283SCraig Rodrigues char *val = ""; 2344b5bc283SCraig Rodrigues pass_flag_to_nmount = 1; 2354b5bc283SCraig Rodrigues pval = strchr(opt, '='); 2364b5bc283SCraig Rodrigues pnextopt = strchr(opt, ','); 2374b5bc283SCraig Rodrigues if (pval != NULL) { 2384b5bc283SCraig Rodrigues *pval = '\0'; 2394b5bc283SCraig Rodrigues val = pval + 1; 2404b5bc283SCraig Rodrigues } 2414b5bc283SCraig Rodrigues if (pnextopt) { 2424b5bc283SCraig Rodrigues *pnextopt = '\0'; 2434b5bc283SCraig Rodrigues pnextopt++; 2444b5bc283SCraig Rodrigues } 2454b5bc283SCraig Rodrigues if (strcmp(opt, "bg") == 0) { 2463fa88decSGarrett Wollman opflags |= BGRND; 2474b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 2484b5bc283SCraig Rodrigues } else if (strcmp(opt, "fg") == 0) { 2494b5bc283SCraig Rodrigues /* same as not specifying -o bg */ 2504b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 251011981fdSRick Macklem } else if (strcmp(opt, "gssname") == 0) { 252011981fdSRick Macklem pass_flag_to_nmount = 0; 253011981fdSRick Macklem gssname = val; 2544b5bc283SCraig Rodrigues } else if (strcmp(opt, "mntudp") == 0) { 255a62dc406SDoug Rabson mnttcp_ok = 0; 256bf005f32SKris Kennaway nfsproto = IPPROTO_UDP; 2574b5bc283SCraig Rodrigues } else if (strcmp(opt, "udp") == 0) { 2584b5bc283SCraig Rodrigues nfsproto = IPPROTO_UDP; 2594b5bc283SCraig Rodrigues } else if (strcmp(opt, "tcp") == 0) { 260a62dc406SDoug Rabson nfsproto = IPPROTO_TCP; 2614b5bc283SCraig Rodrigues } else if (strcmp(opt, "noinet4") == 0) { 2624b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 2634b5bc283SCraig Rodrigues opflags |= OF_NOINET4; 2644b5bc283SCraig Rodrigues } else if (strcmp(opt, "noinet6") == 0) { 2654b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 2664b5bc283SCraig Rodrigues opflags |= OF_NOINET6; 2674b5bc283SCraig Rodrigues } else if (strcmp(opt, "noconn") == 0) { 2684b5bc283SCraig Rodrigues noconn = 1; 2694b5bc283SCraig Rodrigues } else if (strcmp(opt, "nfsv2") == 0) { 2704b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 2714b5bc283SCraig Rodrigues mountmode = V2; 2724b5bc283SCraig Rodrigues } else if (strcmp(opt, "nfsv3") == 0) { 2734b5bc283SCraig Rodrigues mountmode = V3; 274011981fdSRick Macklem } else if (strcmp(opt, "nfsv4") == 0) { 275011981fdSRick Macklem pass_flag_to_nmount=0; 276011981fdSRick Macklem mountmode = V4; 277011981fdSRick Macklem fstype = "newnfs"; 278011981fdSRick Macklem nfsproto = IPPROTO_TCP; 279011981fdSRick Macklem if (portspec == NULL) 280011981fdSRick Macklem portspec = "2049"; 2814b5bc283SCraig Rodrigues } else if (strcmp(opt, "port") == 0) { 2824b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 283317d5933SIan Dowse asprintf(&portspec, "%d", 2844b5bc283SCraig Rodrigues atoi(val)); 285317d5933SIan Dowse if (portspec == NULL) 286317d5933SIan Dowse err(1, "asprintf"); 287011981fdSRick Macklem } else if (strcmp(opt, "principal") == 0) { 288011981fdSRick Macklem got_principal = 1; 289a9148abdSDoug Rabson } else if (strcmp(opt, "sec") == 0) { 290a9148abdSDoug Rabson /* 291a9148abdSDoug Rabson * Don't add this option to 292a9148abdSDoug Rabson * the iovec yet - we will 293a9148abdSDoug Rabson * negotiate which sec flavor 294a9148abdSDoug Rabson * to use with the remote 295a9148abdSDoug Rabson * mountd. 296a9148abdSDoug Rabson */ 297a9148abdSDoug Rabson pass_flag_to_nmount=0; 298a9148abdSDoug Rabson secflavor = sec_name_to_num(val); 299a9148abdSDoug Rabson if (secflavor < 0) { 300a9148abdSDoug Rabson errx(1, 301a9148abdSDoug Rabson "illegal sec value -- %s", 302a9148abdSDoug Rabson val); 303a9148abdSDoug Rabson } 3044b5bc283SCraig Rodrigues } else if (strcmp(opt, "retrycnt") == 0) { 3054b5bc283SCraig Rodrigues pass_flag_to_nmount=0; 3064b5bc283SCraig Rodrigues num = strtol(val, &p, 10); 3074b5bc283SCraig Rodrigues if (*p || num < 0) 3084b5bc283SCraig Rodrigues errx(1, "illegal retrycnt value -- %s", val); 3094b5bc283SCraig Rodrigues retrycnt = num; 3104b5bc283SCraig Rodrigues } else if (strcmp(opt, "maxgroups") == 0) { 3114b5bc283SCraig Rodrigues num = strtol(val, &p, 10); 3124b5bc283SCraig Rodrigues if (*p || num <= 0) 3134b5bc283SCraig Rodrigues errx(1, "illegal maxgroups value -- %s", val); 3144b5bc283SCraig Rodrigues //set_rpc_maxgrouplist(num); 315317d5933SIan Dowse } 3164b5bc283SCraig Rodrigues if (pass_flag_to_nmount) 3174b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, opt, val, 3184b5bc283SCraig Rodrigues strlen(val) + 1); 3194b5bc283SCraig Rodrigues opt = pnextopt; 3204db56604SPeter Wemm } 3214db56604SPeter Wemm } 3228fae3551SRodney W. Grimes break; 3238fae3551SRodney W. Grimes case 'P': 3244b5bc283SCraig Rodrigues /* obsolete for -o noresvport now default */ 3254b5bc283SCraig Rodrigues printf("-P deprecated, use -o noresvport\n"); 3264b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "noresvport", NULL, 0); 3278fae3551SRodney W. Grimes break; 3288fae3551SRodney W. Grimes case 'R': 3294b5bc283SCraig Rodrigues printf("-R deprecated, use -o retrycnt=<retrycnt>\n"); 3308fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 331e16873daSIan Dowse if (*p || num < 0) 3328fae3551SRodney W. Grimes errx(1, "illegal -R value -- %s", optarg); 3338fae3551SRodney W. Grimes retrycnt = num; 3348fae3551SRodney W. Grimes break; 3358fae3551SRodney W. Grimes case 'r': 3364b5bc283SCraig Rodrigues printf("-r deprecated, use -o rsize=<rsize>\n"); 3374b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "rsize", optarg, (size_t)-1); 3388fae3551SRodney W. Grimes break; 3398fae3551SRodney W. Grimes case 's': 3404b5bc283SCraig Rodrigues printf("-s deprecated, use -o soft\n"); 3414b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "soft", NULL, 0); 3428fae3551SRodney W. Grimes break; 3438fae3551SRodney W. Grimes case 'T': 344a62dc406SDoug Rabson nfsproto = IPPROTO_TCP; 3454b5bc283SCraig Rodrigues printf("-T deprecated, use -o tcp\n"); 3468fae3551SRodney W. Grimes break; 3478fae3551SRodney W. Grimes case 't': 3484b5bc283SCraig Rodrigues printf("-t deprecated, use -o timeout=<value>\n"); 3494b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "timeout", optarg, (size_t)-1); 3508fae3551SRodney W. Grimes break; 3518fae3551SRodney W. Grimes case 'w': 3524b5bc283SCraig Rodrigues printf("-w deprecated, use -o wsize=<value>\n"); 3534b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "wsize", optarg, (size_t)-1); 3548fae3551SRodney W. Grimes break; 3558fae3551SRodney W. Grimes case 'x': 3564b5bc283SCraig Rodrigues printf("-x deprecated, use -o retrans=<value>\n"); 3574b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "retrans", optarg, (size_t)-1); 3588fae3551SRodney W. Grimes break; 359a62dc406SDoug Rabson case 'U': 3604b5bc283SCraig Rodrigues printf("-U deprecated, use -o mntudp\n"); 361a62dc406SDoug Rabson mnttcp_ok = 0; 3620c269d1fSCraig Rodrigues nfsproto = IPPROTO_UDP; 3634b5bc283SCraig Rodrigues build_iovec(&iov, &iovlen, "mntudp", NULL, 0); 364a62dc406SDoug Rabson break; 3658fae3551SRodney W. Grimes default: 3668fae3551SRodney W. Grimes usage(); 3678fae3551SRodney W. Grimes break; 3688fae3551SRodney W. Grimes } 3698fae3551SRodney W. Grimes argc -= optind; 3708fae3551SRodney W. Grimes argv += optind; 3718fae3551SRodney W. Grimes 3724a4c5285SPeter Wemm if (argc != 2) { 3732f21d07aSDavid Greenman usage(); 3744a4c5285SPeter Wemm /* NOTREACHED */ 3754a4c5285SPeter Wemm } 3768fae3551SRodney W. Grimes 3778fae3551SRodney W. Grimes spec = *argv++; 3788fae3551SRodney W. Grimes name = *argv; 3798fae3551SRodney W. Grimes 380e16873daSIan Dowse if (retrycnt == -1) 3812bc53e11SIan Dowse /* The default is to keep retrying forever. */ 3822bc53e11SIan Dowse retrycnt = 0; 3830c269d1fSCraig Rodrigues 384011981fdSRick Macklem /* 385011981fdSRick Macklem * If the experimental nfs subsystem is loaded into the kernel 386011981fdSRick Macklem * and the regular one is not, use it. Otherwise, use it if the 387011981fdSRick Macklem * fstype is set to "newnfs", either via "mount -t newnfs ..." 388011981fdSRick Macklem * or by specifying an nfsv4 mount. 389011981fdSRick Macklem */ 390011981fdSRick Macklem if (modfind("nfscl") >= 0 && modfind("nfs") < 0) { 391011981fdSRick Macklem fstype = "newnfs"; 392011981fdSRick Macklem } else if (strcmp(fstype, "newnfs") == 0) { 393011981fdSRick Macklem if (modfind("nfscl") < 0) { 394011981fdSRick Macklem /* Not present in kernel, try loading it */ 395011981fdSRick Macklem if (kldload("nfscl") < 0 || 396011981fdSRick Macklem modfind("nfscl") < 0) 397011981fdSRick Macklem errx(1, "nfscl is not available"); 398011981fdSRick Macklem } 399011981fdSRick Macklem } 400011981fdSRick Macklem 401011981fdSRick Macklem /* 402011981fdSRick Macklem * Add the fqdn to the gssname, as required. 403011981fdSRick Macklem */ 404011981fdSRick Macklem if (gssname != NULL) { 405011981fdSRick Macklem if (strchr(gssname, '@') == NULL && 406011981fdSRick Macklem gethostname(hostname, MAXHOSTNAMELEN) == 0) { 407011981fdSRick Macklem snprintf(gssn, sizeof (gssn), "%s@%s", gssname, 408011981fdSRick Macklem hostname); 409011981fdSRick Macklem gssname = gssn; 410011981fdSRick Macklem } 411011981fdSRick Macklem build_iovec(&iov, &iovlen, "gssname", gssname, 412011981fdSRick Macklem strlen(gssname) + 1); 413011981fdSRick Macklem } 414011981fdSRick Macklem 4154b5bc283SCraig Rodrigues if (!getnfsargs(spec, &iov, &iovlen)) 4168fae3551SRodney W. Grimes exit(1); 417d599144dSGarrett Wollman 41873dd3167SPoul-Henning Kamp /* resolve the mountpoint with realpath(3) */ 41973dd3167SPoul-Henning Kamp (void)checkpath(name, mntpath); 42073dd3167SPoul-Henning Kamp 421412ffff0SCraig Rodrigues build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1); 422c5aa1dc8SCraig Rodrigues build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1); 423a6b26402SCraig Rodrigues build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 424c5aa1dc8SCraig Rodrigues 425049307baSCraig Rodrigues /* 426049307baSCraig Rodrigues * XXX: 427049307baSCraig Rodrigues * Backwards compatibility routines for older kernels. 428049307baSCraig Rodrigues * Remove this and fallback_mount() code when we do not need to support 429049307baSCraig Rodrigues * NFS mounts against older kernels which still need 430049307baSCraig Rodrigues * struct nfs_args to be passed in via nmount(). 431049307baSCraig Rodrigues */ 432049307baSCraig Rodrigues osversion = getosreldate(); 43331438685SCraig Rodrigues if (osversion >= 702100) { 434049307baSCraig Rodrigues if (nmount(iov, iovlen, mntflags)) 435049307baSCraig Rodrigues err(1, "%s, %s", mntpath, errmsg); 436049307baSCraig Rodrigues } else { 437049307baSCraig Rodrigues if (fallback_mount(iov, iovlen, mntflags)) 438a6b26402SCraig Rodrigues err(1, "%s, %s", mntpath, errmsg); 4394b5bc283SCraig Rodrigues } 440a62dc406SDoug Rabson 4418fae3551SRodney W. Grimes exit(0); 4428fae3551SRodney W. Grimes } 4438fae3551SRodney W. Grimes 4444b5bc283SCraig Rodrigues static int 4454b5bc283SCraig Rodrigues findopt(struct iovec *iov, int iovlen, const char *name, 4464b5bc283SCraig Rodrigues char **valuep, int *lenp) 4474b5bc283SCraig Rodrigues { 4484b5bc283SCraig Rodrigues int i; 4494b5bc283SCraig Rodrigues 4504b5bc283SCraig Rodrigues for (i = 0; i < iovlen/2; i++, iov += 2) { 4514b5bc283SCraig Rodrigues if (strcmp(name, iov[0].iov_base) == 0) { 4524b5bc283SCraig Rodrigues if (valuep) 4534b5bc283SCraig Rodrigues *valuep = iov[1].iov_base; 4544b5bc283SCraig Rodrigues if (lenp) 4554b5bc283SCraig Rodrigues *lenp = iov[1].iov_len; 4564b5bc283SCraig Rodrigues return (0); 4574b5bc283SCraig Rodrigues } 4584b5bc283SCraig Rodrigues } 4594b5bc283SCraig Rodrigues return (ENOENT); 4604b5bc283SCraig Rodrigues } 4614b5bc283SCraig Rodrigues 4624b5bc283SCraig Rodrigues static void 4634b5bc283SCraig Rodrigues copyopt(struct iovec **newiov, int *newiovlen, 4644b5bc283SCraig Rodrigues struct iovec *iov, int iovlen, const char *name) 4654b5bc283SCraig Rodrigues { 4664b5bc283SCraig Rodrigues char *value; 4674b5bc283SCraig Rodrigues int len; 4684b5bc283SCraig Rodrigues 4694b5bc283SCraig Rodrigues if (findopt(iov, iovlen, name, &value, &len) == 0) 4704b5bc283SCraig Rodrigues build_iovec(newiov, newiovlen, name, value, len); 4714b5bc283SCraig Rodrigues } 4724b5bc283SCraig Rodrigues 47360341db4SCraig Rodrigues /* 47460341db4SCraig Rodrigues * XXX: This function is provided for backwards 47560341db4SCraig Rodrigues * compatibility with older kernels which did not support 47660341db4SCraig Rodrigues * passing NFS mount options to nmount() as individual 47760341db4SCraig Rodrigues * parameters. It should be eventually be removed. 47860341db4SCraig Rodrigues */ 4798fae3551SRodney W. Grimes int 4804b5bc283SCraig Rodrigues fallback_mount(struct iovec *iov, int iovlen, int mntflags) 4814b5bc283SCraig Rodrigues { 4824b5bc283SCraig Rodrigues struct nfs_args args = { 4834b5bc283SCraig Rodrigues .version = NFS_ARGSVERSION, 4844b5bc283SCraig Rodrigues .addr = NULL, 4854b5bc283SCraig Rodrigues .addrlen = sizeof (struct sockaddr_in), 4864b5bc283SCraig Rodrigues .sotype = SOCK_STREAM, 4874b5bc283SCraig Rodrigues .proto = 0, 4884b5bc283SCraig Rodrigues .fh = NULL, 4894b5bc283SCraig Rodrigues .fhsize = 0, 4904b5bc283SCraig Rodrigues .flags = NFSMNT_RESVPORT, 4914b5bc283SCraig Rodrigues .wsize = NFS_WSIZE, 4924b5bc283SCraig Rodrigues .rsize = NFS_RSIZE, 4934b5bc283SCraig Rodrigues .readdirsize = NFS_READDIRSIZE, 4944b5bc283SCraig Rodrigues .timeo = 10, 4954b5bc283SCraig Rodrigues .retrans = NFS_RETRANS, 4964b5bc283SCraig Rodrigues .maxgrouplist = NFS_MAXGRPS, 4974b5bc283SCraig Rodrigues .readahead = NFS_DEFRAHEAD, 4984b5bc283SCraig Rodrigues .wcommitsize = 0, /* was: NQ_DEFLEASE */ 4994b5bc283SCraig Rodrigues .deadthresh = NFS_MAXDEADTHRESH, /* was: NQ_DEADTHRESH */ 5004b5bc283SCraig Rodrigues .hostname = NULL, 5014b5bc283SCraig Rodrigues /* args version 4 */ 5024b5bc283SCraig Rodrigues .acregmin = NFS_MINATTRTIMO, 5034b5bc283SCraig Rodrigues .acregmax = NFS_MAXATTRTIMO, 5044b5bc283SCraig Rodrigues .acdirmin = NFS_MINDIRATTRTIMO, 5054b5bc283SCraig Rodrigues .acdirmax = NFS_MAXDIRATTRTIMO, 5064b5bc283SCraig Rodrigues }; 5074b5bc283SCraig Rodrigues int ret; 5084b5bc283SCraig Rodrigues char *opt; 5094b5bc283SCraig Rodrigues struct iovec *newiov; 5104b5bc283SCraig Rodrigues int newiovlen; 5114b5bc283SCraig Rodrigues 5124b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "dumbtimer", NULL, NULL) == 0) 5134b5bc283SCraig Rodrigues args.flags |= NFSMNT_DUMBTIMR; 5144b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "noconn", NULL, NULL) == 0) 5154b5bc283SCraig Rodrigues args.flags |= NFSMNT_NOCONN; 5164b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "conn", NULL, NULL) == 0) 5174b5bc283SCraig Rodrigues args.flags |= NFSMNT_NOCONN; 5184b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "nolockd", NULL, NULL) == 0) 5194b5bc283SCraig Rodrigues args.flags |= NFSMNT_NOLOCKD; 5204b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "lockd", NULL, NULL) == 0) 5214b5bc283SCraig Rodrigues args.flags &= ~NFSMNT_NOLOCKD; 5224b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "intr", NULL, NULL) == 0) 5234b5bc283SCraig Rodrigues args.flags |= NFSMNT_INT; 5244b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "rdirplus", NULL, NULL) == 0) 5254b5bc283SCraig Rodrigues args.flags |= NFSMNT_RDIRPLUS; 5264b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "resvport", NULL, NULL) == 0) 5274b5bc283SCraig Rodrigues args.flags |= NFSMNT_RESVPORT; 5284b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "noresvport", NULL, NULL) == 0) 5294b5bc283SCraig Rodrigues args.flags &= ~NFSMNT_RESVPORT; 5304b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "soft", NULL, NULL) == 0) 5314b5bc283SCraig Rodrigues args.flags |= NFSMNT_SOFT; 5324b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "hard", NULL, NULL) == 0) 5334b5bc283SCraig Rodrigues args.flags &= ~NFSMNT_SOFT; 5344b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "mntudp", NULL, NULL) == 0) 5354b5bc283SCraig Rodrigues args.sotype = SOCK_DGRAM; 5364b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "udp", NULL, NULL) == 0) 5374b5bc283SCraig Rodrigues args.sotype = SOCK_DGRAM; 5384b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "tcp", NULL, NULL) == 0) 5394b5bc283SCraig Rodrigues args.sotype = SOCK_STREAM; 5404b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "nfsv3", NULL, NULL) == 0) 5414b5bc283SCraig Rodrigues args.flags |= NFSMNT_NFSV3; 5424b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "readdirsize", &opt, NULL) == 0) { 5434b5bc283SCraig Rodrigues if (opt == NULL) { 5444b5bc283SCraig Rodrigues errx(1, "illegal readdirsize"); 5454b5bc283SCraig Rodrigues } 5464b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.readdirsize); 5474b5bc283SCraig Rodrigues if (ret != 1 || args.readdirsize <= 0) { 5484b5bc283SCraig Rodrigues errx(1, "illegal readdirsize: %s", opt); 5494b5bc283SCraig Rodrigues } 5504b5bc283SCraig Rodrigues args.flags |= NFSMNT_READDIRSIZE; 5514b5bc283SCraig Rodrigues } 5524b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "readahead", &opt, NULL) == 0) { 5534b5bc283SCraig Rodrigues if (opt == NULL) { 5544b5bc283SCraig Rodrigues errx(1, "illegal readahead"); 5554b5bc283SCraig Rodrigues } 5564b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.readahead); 5574b5bc283SCraig Rodrigues if (ret != 1 || args.readahead <= 0) { 5584b5bc283SCraig Rodrigues errx(1, "illegal readahead: %s", opt); 5594b5bc283SCraig Rodrigues } 5604b5bc283SCraig Rodrigues args.flags |= NFSMNT_READAHEAD; 5614b5bc283SCraig Rodrigues } 5624b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "wsize", &opt, NULL) == 0) { 5634b5bc283SCraig Rodrigues if (opt == NULL) { 5644b5bc283SCraig Rodrigues errx(1, "illegal wsize"); 5654b5bc283SCraig Rodrigues } 5664b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.wsize); 5674b5bc283SCraig Rodrigues if (ret != 1 || args.wsize <= 0) { 5684b5bc283SCraig Rodrigues errx(1, "illegal wsize: %s", opt); 5694b5bc283SCraig Rodrigues } 5704b5bc283SCraig Rodrigues args.flags |= NFSMNT_WSIZE; 5714b5bc283SCraig Rodrigues } 5724b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "rsize", &opt, NULL) == 0) { 5734b5bc283SCraig Rodrigues if (opt == NULL) { 5744b5bc283SCraig Rodrigues errx(1, "illegal rsize"); 5754b5bc283SCraig Rodrigues } 5764b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.rsize); 5774b5bc283SCraig Rodrigues if (ret != 1 || args.rsize <= 0) { 5784b5bc283SCraig Rodrigues errx(1, "illegal wsize: %s", opt); 5794b5bc283SCraig Rodrigues } 5804b5bc283SCraig Rodrigues args.flags |= NFSMNT_RSIZE; 5814b5bc283SCraig Rodrigues } 5824b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "retrans", &opt, NULL) == 0) { 5834b5bc283SCraig Rodrigues if (opt == NULL) { 5844b5bc283SCraig Rodrigues errx(1, "illegal retrans"); 5854b5bc283SCraig Rodrigues } 5864b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.retrans); 5874b5bc283SCraig Rodrigues if (ret != 1 || args.retrans <= 0) { 5884b5bc283SCraig Rodrigues errx(1, "illegal retrans: %s", opt); 5894b5bc283SCraig Rodrigues } 5904b5bc283SCraig Rodrigues args.flags |= NFSMNT_RETRANS; 5914b5bc283SCraig Rodrigues } 5924b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "acregmin", &opt, NULL) == 0) { 5934b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.acregmin); 594e4f9e894SCraig Rodrigues if (ret != 1 || args.acregmin < 0) { 5954b5bc283SCraig Rodrigues errx(1, "illegal acregmin: %s", opt); 5964b5bc283SCraig Rodrigues } 59760341db4SCraig Rodrigues args.flags |= NFSMNT_ACREGMIN; 5984b5bc283SCraig Rodrigues } 5994b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "acregmax", &opt, NULL) == 0) { 6004b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.acregmax); 601e4f9e894SCraig Rodrigues if (ret != 1 || args.acregmax < 0) { 6024b5bc283SCraig Rodrigues errx(1, "illegal acregmax: %s", opt); 6034b5bc283SCraig Rodrigues } 60460341db4SCraig Rodrigues args.flags |= NFSMNT_ACREGMAX; 6054b5bc283SCraig Rodrigues } 6064b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "acdirmin", &opt, NULL) == 0) { 6074b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.acdirmin); 608e4f9e894SCraig Rodrigues if (ret != 1 || args.acdirmin < 0) { 6094b5bc283SCraig Rodrigues errx(1, "illegal acdirmin: %s", opt); 6104b5bc283SCraig Rodrigues } 61160341db4SCraig Rodrigues args.flags |= NFSMNT_ACDIRMIN; 6124b5bc283SCraig Rodrigues } 6134b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "acdirmax", &opt, NULL) == 0) { 6144b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.acdirmax); 615e4f9e894SCraig Rodrigues if (ret != 1 || args.acdirmax < 0) { 6164b5bc283SCraig Rodrigues errx(1, "illegal acdirmax: %s", opt); 6174b5bc283SCraig Rodrigues } 61882597249SCraig Rodrigues args.flags |= NFSMNT_ACDIRMAX; 6194b5bc283SCraig Rodrigues } 6204b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "deadthresh", &opt, NULL) == 0) { 6214b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.deadthresh); 6224b5bc283SCraig Rodrigues if (ret != 1 || args.deadthresh <= 0) { 6234b5bc283SCraig Rodrigues errx(1, "illegal deadthresh: %s", opt); 6244b5bc283SCraig Rodrigues } 6254b5bc283SCraig Rodrigues args.flags |= NFSMNT_DEADTHRESH; 6264b5bc283SCraig Rodrigues } 6274b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "timeout", &opt, NULL) == 0) { 6284b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.timeo); 6294b5bc283SCraig Rodrigues if (ret != 1 || args.timeo <= 0) { 6304b5bc283SCraig Rodrigues errx(1, "illegal timeout: %s", opt); 6314b5bc283SCraig Rodrigues } 6324b5bc283SCraig Rodrigues args.flags |= NFSMNT_TIMEO; 6334b5bc283SCraig Rodrigues } 6344b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "maxgroups", &opt, NULL) == 0) { 6354b5bc283SCraig Rodrigues ret = sscanf(opt, "%d", &args.maxgrouplist); 6364b5bc283SCraig Rodrigues if (ret != 1 || args.timeo <= 0) { 6374b5bc283SCraig Rodrigues errx(1, "illegal maxgroups: %s", opt); 6384b5bc283SCraig Rodrigues } 6394b5bc283SCraig Rodrigues args.flags |= NFSMNT_MAXGRPS; 6404b5bc283SCraig Rodrigues } 6414b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "addr", &opt, 6424b5bc283SCraig Rodrigues &args.addrlen) == 0) { 6434b5bc283SCraig Rodrigues args.addr = (struct sockaddr *) opt; 6444b5bc283SCraig Rodrigues } 6454b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "fh", &opt, &args.fhsize) == 0) { 6464b5bc283SCraig Rodrigues args.fh = opt; 6474b5bc283SCraig Rodrigues } 6484b5bc283SCraig Rodrigues if (findopt(iov, iovlen, "hostname", &args.hostname, 6494b5bc283SCraig Rodrigues NULL) == 0) { 6504b5bc283SCraig Rodrigues } 6514b5bc283SCraig Rodrigues if (args.hostname == NULL) { 6524b5bc283SCraig Rodrigues errx(1, "Invalid hostname"); 6534b5bc283SCraig Rodrigues } 6544b5bc283SCraig Rodrigues 6554b5bc283SCraig Rodrigues newiov = NULL; 6564b5bc283SCraig Rodrigues newiovlen = 0; 6574b5bc283SCraig Rodrigues 6584b5bc283SCraig Rodrigues build_iovec(&newiov, &newiovlen, "nfs_args", &args, sizeof(args)); 6594b5bc283SCraig Rodrigues copyopt(&newiov, &newiovlen, iov, iovlen, "fstype"); 6604b5bc283SCraig Rodrigues copyopt(&newiov, &newiovlen, iov, iovlen, "fspath"); 6614b5bc283SCraig Rodrigues copyopt(&newiov, &newiovlen, iov, iovlen, "errmsg"); 6624b5bc283SCraig Rodrigues 6634b5bc283SCraig Rodrigues return nmount(newiov, newiovlen, mntflags); 6644b5bc283SCraig Rodrigues } 6654b5bc283SCraig Rodrigues 6664b5bc283SCraig Rodrigues int 667a9148abdSDoug Rabson sec_name_to_num(char *sec) 668a9148abdSDoug Rabson { 669a9148abdSDoug Rabson if (!strcmp(sec, "krb5")) 670a9148abdSDoug Rabson return (RPCSEC_GSS_KRB5); 671a9148abdSDoug Rabson if (!strcmp(sec, "krb5i")) 672a9148abdSDoug Rabson return (RPCSEC_GSS_KRB5I); 673a9148abdSDoug Rabson if (!strcmp(sec, "krb5p")) 674a9148abdSDoug Rabson return (RPCSEC_GSS_KRB5P); 675a9148abdSDoug Rabson if (!strcmp(sec, "sys")) 676a9148abdSDoug Rabson return (AUTH_SYS); 677a9148abdSDoug Rabson return (-1); 678a9148abdSDoug Rabson } 679a9148abdSDoug Rabson 680a9148abdSDoug Rabson char * 681a9148abdSDoug Rabson sec_num_to_name(int flavor) 682a9148abdSDoug Rabson { 683a9148abdSDoug Rabson switch (flavor) { 684a9148abdSDoug Rabson case RPCSEC_GSS_KRB5: 685a9148abdSDoug Rabson return ("krb5"); 686a9148abdSDoug Rabson case RPCSEC_GSS_KRB5I: 687a9148abdSDoug Rabson return ("krb5i"); 688a9148abdSDoug Rabson case RPCSEC_GSS_KRB5P: 689a9148abdSDoug Rabson return ("krb5p"); 690a9148abdSDoug Rabson case AUTH_SYS: 691a9148abdSDoug Rabson return ("sys"); 692a9148abdSDoug Rabson } 693a9148abdSDoug Rabson return (NULL); 694a9148abdSDoug Rabson } 695a9148abdSDoug Rabson 696a9148abdSDoug Rabson int 6974b5bc283SCraig Rodrigues getnfsargs(char *spec, struct iovec **iov, int *iovlen) 6988fae3551SRodney W. Grimes { 6998360efbdSAlfred Perlstein struct addrinfo hints, *ai_nfs, *ai; 700317d5933SIan Dowse enum tryret ret; 701317d5933SIan Dowse int ecode, speclen, remoteerr; 702317d5933SIan Dowse char *hostp, *delimp, *errstr; 70366a84ea7SBrian Feldman size_t len; 704011981fdSRick Macklem static char nam[MNAMELEN + 1], pname[MAXHOSTNAMELEN + 5]; 7058fae3551SRodney W. Grimes 7068360efbdSAlfred Perlstein if ((delimp = strrchr(spec, ':')) != NULL) { 7078fae3551SRodney W. Grimes hostp = spec; 7088fae3551SRodney W. Grimes spec = delimp + 1; 70973dd3167SPoul-Henning Kamp } else if ((delimp = strrchr(spec, '@')) != NULL) { 71073dd3167SPoul-Henning Kamp warnx("path@server syntax is deprecated, use server:path"); 71173dd3167SPoul-Henning Kamp hostp = delimp + 1; 7128fae3551SRodney W. Grimes } else { 71373dd3167SPoul-Henning Kamp warnx("no <host>:<dirpath> nfs-name"); 7148fae3551SRodney W. Grimes return (0); 7158fae3551SRodney W. Grimes } 7168fae3551SRodney W. Grimes *delimp = '\0'; 71773dd3167SPoul-Henning Kamp 71873dd3167SPoul-Henning Kamp /* 71973dd3167SPoul-Henning Kamp * If there has been a trailing slash at mounttime it seems 72073dd3167SPoul-Henning Kamp * that some mountd implementations fail to remove the mount 72173dd3167SPoul-Henning Kamp * entries from their mountlist while unmounting. 72273dd3167SPoul-Henning Kamp */ 72366a84ea7SBrian Feldman for (speclen = strlen(spec); 72466a84ea7SBrian Feldman speclen > 1 && spec[speclen - 1] == '/'; 72566a84ea7SBrian Feldman speclen--) 72673dd3167SPoul-Henning Kamp spec[speclen - 1] = '\0'; 72773dd3167SPoul-Henning Kamp if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) { 72873dd3167SPoul-Henning Kamp warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG)); 72973dd3167SPoul-Henning Kamp return (0); 73073dd3167SPoul-Henning Kamp } 73173dd3167SPoul-Henning Kamp /* Make both '@' and ':' notations equal */ 73266a84ea7SBrian Feldman if (*hostp != '\0') { 73366a84ea7SBrian Feldman len = strlen(hostp); 73466a84ea7SBrian Feldman memmove(nam, hostp, len); 73566a84ea7SBrian Feldman nam[len] = ':'; 73666a84ea7SBrian Feldman memmove(nam + len + 1, spec, speclen); 73766a84ea7SBrian Feldman nam[len + speclen + 1] = '\0'; 73866a84ea7SBrian Feldman } 7398fae3551SRodney W. Grimes 7408fae3551SRodney W. Grimes /* 74191196234SPeter Wemm * Handle an internet host address. 7428fae3551SRodney W. Grimes */ 7438360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 7448360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST; 7454b5bc283SCraig Rodrigues if (nfsproto == IPPROTO_TCP) 7464b5bc283SCraig Rodrigues hints.ai_socktype = SOCK_STREAM; 7474b5bc283SCraig Rodrigues else if (nfsproto == IPPROTO_UDP) 7484b5bc283SCraig Rodrigues hints.ai_socktype = SOCK_DGRAM; 7494b5bc283SCraig Rodrigues 75091196234SPeter Wemm if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) { 751011981fdSRick Macklem hints.ai_flags = AI_CANONNAME; 752317d5933SIan Dowse if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs)) 753317d5933SIan Dowse != 0) { 754317d5933SIan Dowse if (portspec == NULL) 755317d5933SIan Dowse errx(1, "%s: %s", hostp, gai_strerror(ecode)); 756317d5933SIan Dowse else 757317d5933SIan Dowse errx(1, "%s:%s: %s", hostp, portspec, 7588360efbdSAlfred Perlstein gai_strerror(ecode)); 7598360efbdSAlfred Perlstein return (0); 7608360efbdSAlfred Perlstein } 761011981fdSRick Macklem 762011981fdSRick Macklem /* 763011981fdSRick Macklem * For a Kerberized nfs mount where the "principal" 764011981fdSRick Macklem * argument has not been set, add it here. 765011981fdSRick Macklem */ 766011981fdSRick Macklem if (got_principal == 0 && secflavor >= 0 && 767011981fdSRick Macklem secflavor != AUTH_SYS && ai_nfs->ai_canonname != NULL) { 768011981fdSRick Macklem snprintf(pname, sizeof (pname), "nfs@%s", 769011981fdSRick Macklem ai_nfs->ai_canonname); 770011981fdSRick Macklem build_iovec(iov, iovlen, "principal", pname, 771011981fdSRick Macklem strlen(pname) + 1); 772011981fdSRick Macklem } 7738360efbdSAlfred Perlstein } 7748fae3551SRodney W. Grimes 775317d5933SIan Dowse ret = TRYRET_LOCALERR; 776e16873daSIan Dowse for (;;) { 777deffdffaSAndrey A. Chernov /* 778317d5933SIan Dowse * Try each entry returned by getaddrinfo(). Note the 779317d5933SIan Dowse * occurence of remote errors by setting `remoteerr'. 780deffdffaSAndrey A. Chernov */ 781317d5933SIan Dowse remoteerr = 0; 782317d5933SIan Dowse for (ai = ai_nfs; ai != NULL; ai = ai->ai_next) { 783302f15f9SMatthew N. Dodd if ((ai->ai_family == AF_INET6) && 784302f15f9SMatthew N. Dodd (opflags & OF_NOINET6)) 785302f15f9SMatthew N. Dodd continue; 786302f15f9SMatthew N. Dodd if ((ai->ai_family == AF_INET) && 787302f15f9SMatthew N. Dodd (opflags & OF_NOINET4)) 788302f15f9SMatthew N. Dodd continue; 7894b5bc283SCraig Rodrigues ret = nfs_tryproto(ai, hostp, spec, &errstr, iov, 7904b5bc283SCraig Rodrigues iovlen); 791317d5933SIan Dowse if (ret == TRYRET_SUCCESS) 792317d5933SIan Dowse break; 793317d5933SIan Dowse if (ret != TRYRET_LOCALERR) 794317d5933SIan Dowse remoteerr = 1; 795317d5933SIan Dowse if ((opflags & ISBGRND) == 0) 796317d5933SIan Dowse fprintf(stderr, "%s\n", errstr); 797deffdffaSAndrey A. Chernov } 798317d5933SIan Dowse if (ret == TRYRET_SUCCESS) 799317d5933SIan Dowse break; 800deffdffaSAndrey A. Chernov 801e16873daSIan Dowse /* Exit if all errors were local. */ 802e16873daSIan Dowse if (!remoteerr) 803deffdffaSAndrey A. Chernov exit(1); 804317d5933SIan Dowse 805e16873daSIan Dowse /* 806e16873daSIan Dowse * If retrycnt == 0, we are to keep retrying forever. 807e16873daSIan Dowse * Otherwise decrement it, and exit if it hits zero. 808e16873daSIan Dowse */ 809e16873daSIan Dowse if (retrycnt != 0 && --retrycnt == 0) 810317d5933SIan Dowse exit(1); 811317d5933SIan Dowse 812317d5933SIan Dowse if ((opflags & (BGRND | ISBGRND)) == BGRND) { 813317d5933SIan Dowse warnx("Cannot immediately mount %s:%s, backgrounding", 814317d5933SIan Dowse hostp, spec); 815317d5933SIan Dowse opflags |= ISBGRND; 816317d5933SIan Dowse if (daemon(0, 0) != 0) 817317d5933SIan Dowse err(1, "daemon"); 8188fae3551SRodney W. Grimes } 8198fae3551SRodney W. Grimes sleep(60); 8208fae3551SRodney W. Grimes } 8218360efbdSAlfred Perlstein freeaddrinfo(ai_nfs); 8224b5bc283SCraig Rodrigues 8234b5bc283SCraig Rodrigues build_iovec(iov, iovlen, "hostname", nam, (size_t)-1); 824a69497d7SMatthew Dillon /* Add mounted file system to PATH_MOUNTTAB */ 825a69497d7SMatthew Dillon if (!add_mtab(hostp, spec)) 826a69497d7SMatthew Dillon warnx("can't update %s for %s:%s", PATH_MOUNTTAB, hostp, spec); 8278fae3551SRodney W. Grimes return (1); 8288fae3551SRodney W. Grimes } 8298fae3551SRodney W. Grimes 8308fae3551SRodney W. Grimes /* 831317d5933SIan Dowse * Try to set up the NFS arguments according to the address 832317d5933SIan Dowse * family, protocol (and possibly port) specified in `ai'. 833317d5933SIan Dowse * 834317d5933SIan Dowse * Returns TRYRET_SUCCESS if successful, or: 835317d5933SIan Dowse * TRYRET_TIMEOUT The server did not respond. 836317d5933SIan Dowse * TRYRET_REMOTEERR The server reported an error. 837317d5933SIan Dowse * TRYRET_LOCALERR Local failure. 838317d5933SIan Dowse * 839317d5933SIan Dowse * In all error cases, *errstr will be set to a statically-allocated string 840317d5933SIan Dowse * describing the error. 841317d5933SIan Dowse */ 842317d5933SIan Dowse enum tryret 8434b5bc283SCraig Rodrigues nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr, 8444b5bc283SCraig Rodrigues struct iovec **iov, int *iovlen) 845317d5933SIan Dowse { 846317d5933SIan Dowse static char errbuf[256]; 847317d5933SIan Dowse struct sockaddr_storage nfs_ss; 848317d5933SIan Dowse struct netbuf nfs_nb; 849317d5933SIan Dowse struct nfhret nfhret; 850317d5933SIan Dowse struct timeval try; 851317d5933SIan Dowse struct rpc_err rpcerr; 852317d5933SIan Dowse CLIENT *clp; 853317d5933SIan Dowse struct netconfig *nconf, *nconf_mnt; 8544b5bc283SCraig Rodrigues const char *netid, *netid_mnt; 855a9148abdSDoug Rabson char *secname; 8564b5bc283SCraig Rodrigues int doconnect, nfsvers, mntvers, sotype; 857317d5933SIan Dowse enum clnt_stat stat; 858317d5933SIan Dowse enum mountmode trymntmode; 859317d5933SIan Dowse 860317d5933SIan Dowse trymntmode = mountmode; 861317d5933SIan Dowse errbuf[0] = '\0'; 862317d5933SIan Dowse *errstr = errbuf; 863317d5933SIan Dowse 8644b5bc283SCraig Rodrigues if (nfsproto == IPPROTO_TCP) 8654b5bc283SCraig Rodrigues sotype = SOCK_STREAM; 8664b5bc283SCraig Rodrigues else if (nfsproto == IPPROTO_UDP) 8674b5bc283SCraig Rodrigues sotype = SOCK_DGRAM; 8684b5bc283SCraig Rodrigues 8694b5bc283SCraig Rodrigues if ((netid = netidbytype(ai->ai_family, sotype)) == NULL) { 870a3d8f94bSIan Dowse snprintf(errbuf, sizeof errbuf, 8714b5bc283SCraig Rodrigues "af %d sotype %d not supported", ai->ai_family, sotype); 872a3d8f94bSIan Dowse return (TRYRET_LOCALERR); 873a3d8f94bSIan Dowse } 874a3d8f94bSIan Dowse if ((nconf = getnetconf_cached(netid)) == NULL) { 875317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror()); 876317d5933SIan Dowse return (TRYRET_LOCALERR); 877317d5933SIan Dowse } 878317d5933SIan Dowse /* The RPCPROG_MNT netid may be different. */ 879317d5933SIan Dowse if (mnttcp_ok) { 880ba33efd9SIan Dowse netid_mnt = netid; 881317d5933SIan Dowse nconf_mnt = nconf; 882317d5933SIan Dowse } else { 883a3d8f94bSIan Dowse if ((netid_mnt = netidbytype(ai->ai_family, SOCK_DGRAM)) 884a3d8f94bSIan Dowse == NULL) { 885a3d8f94bSIan Dowse snprintf(errbuf, sizeof errbuf, 886a3d8f94bSIan Dowse "af %d sotype SOCK_DGRAM not supported", 887a3d8f94bSIan Dowse ai->ai_family); 888a3d8f94bSIan Dowse return (TRYRET_LOCALERR); 889a3d8f94bSIan Dowse } 890a3d8f94bSIan Dowse if ((nconf_mnt = getnetconf_cached(netid_mnt)) == NULL) { 891ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "%s: %s", netid_mnt, 892317d5933SIan Dowse nc_sperror()); 893317d5933SIan Dowse return (TRYRET_LOCALERR); 894317d5933SIan Dowse } 895317d5933SIan Dowse } 896317d5933SIan Dowse 897317d5933SIan Dowse tryagain: 898011981fdSRick Macklem if (trymntmode == V4) { 899011981fdSRick Macklem nfsvers = 4; 900011981fdSRick Macklem } else if (trymntmode == V2) { 901317d5933SIan Dowse nfsvers = 2; 902317d5933SIan Dowse mntvers = 1; 903317d5933SIan Dowse } else { 904317d5933SIan Dowse nfsvers = 3; 905317d5933SIan Dowse mntvers = 3; 906317d5933SIan Dowse } 907317d5933SIan Dowse 908317d5933SIan Dowse if (portspec != NULL) { 909317d5933SIan Dowse /* `ai' contains the complete nfsd sockaddr. */ 910317d5933SIan Dowse nfs_nb.buf = ai->ai_addr; 911317d5933SIan Dowse nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen; 912317d5933SIan Dowse } else { 913317d5933SIan Dowse /* Ask the remote rpcbind. */ 914317d5933SIan Dowse nfs_nb.buf = &nfs_ss; 915317d5933SIan Dowse nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss; 916317d5933SIan Dowse 9170775314bSDoug Rabson if (!rpcb_getaddr(NFS_PROGRAM, nfsvers, nconf, &nfs_nb, 918317d5933SIan Dowse hostp)) { 919317d5933SIan Dowse if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH && 920317d5933SIan Dowse trymntmode == ANY) { 921317d5933SIan Dowse trymntmode = V2; 922317d5933SIan Dowse goto tryagain; 923317d5933SIan Dowse } 924317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", 925317d5933SIan Dowse netid, hostp, spec, 926317d5933SIan Dowse clnt_spcreateerror("RPCPROG_NFS")); 927317d5933SIan Dowse return (returncode(rpc_createerr.cf_stat, 928317d5933SIan Dowse &rpc_createerr.cf_error)); 929317d5933SIan Dowse } 930317d5933SIan Dowse } 931317d5933SIan Dowse 932317d5933SIan Dowse /* Check that the server (nfsd) responds on the port we have chosen. */ 9330775314bSDoug Rabson clp = clnt_tli_create(RPC_ANYFD, nconf, &nfs_nb, NFS_PROGRAM, nfsvers, 934317d5933SIan Dowse 0, 0); 935317d5933SIan Dowse if (clp == NULL) { 936317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 937317d5933SIan Dowse hostp, spec, clnt_spcreateerror("nfsd: RPCPROG_NFS")); 938317d5933SIan Dowse return (returncode(rpc_createerr.cf_stat, 939317d5933SIan Dowse &rpc_createerr.cf_error)); 940317d5933SIan Dowse } 9414b5bc283SCraig Rodrigues if (sotype == SOCK_DGRAM && noconn == 0) { 942eca1c24eSIan Dowse /* 943eca1c24eSIan Dowse * Use connect(), to match what the kernel does. This 944eca1c24eSIan Dowse * catches cases where the server responds from the 945eca1c24eSIan Dowse * wrong source address. 946eca1c24eSIan Dowse */ 947eca1c24eSIan Dowse doconnect = 1; 948eca1c24eSIan Dowse if (!clnt_control(clp, CLSET_CONNECT, (char *)&doconnect)) { 949eca1c24eSIan Dowse clnt_destroy(clp); 950eca1c24eSIan Dowse snprintf(errbuf, sizeof errbuf, 951eca1c24eSIan Dowse "[%s] %s:%s: CLSET_CONNECT failed", netid, hostp, 952eca1c24eSIan Dowse spec); 953eca1c24eSIan Dowse return (TRYRET_LOCALERR); 954eca1c24eSIan Dowse } 955eca1c24eSIan Dowse } 956eca1c24eSIan Dowse 957317d5933SIan Dowse try.tv_sec = 10; 958317d5933SIan Dowse try.tv_usec = 0; 959c04affffSMatthew N. Dodd stat = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL, 960011981fdSRick Macklem (xdrproc_t)xdr_void, NULL, try); 961317d5933SIan Dowse if (stat != RPC_SUCCESS) { 962317d5933SIan Dowse if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 963317d5933SIan Dowse clnt_destroy(clp); 964317d5933SIan Dowse trymntmode = V2; 965317d5933SIan Dowse goto tryagain; 966317d5933SIan Dowse } 967317d5933SIan Dowse clnt_geterr(clp, &rpcerr); 968317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 969317d5933SIan Dowse hostp, spec, clnt_sperror(clp, "NFSPROC_NULL")); 970317d5933SIan Dowse clnt_destroy(clp); 971317d5933SIan Dowse return (returncode(stat, &rpcerr)); 972317d5933SIan Dowse } 973317d5933SIan Dowse clnt_destroy(clp); 974317d5933SIan Dowse 975011981fdSRick Macklem /* 976011981fdSRick Macklem * For NFSv4, there is no mount protocol. 977011981fdSRick Macklem */ 978011981fdSRick Macklem if (trymntmode == V4) { 979011981fdSRick Macklem /* 980011981fdSRick Macklem * Store the server address in nfsargsp, making 981011981fdSRick Macklem * sure to copy any locally allocated structures. 982011981fdSRick Macklem */ 983011981fdSRick Macklem addrlen = nfs_nb.len; 984011981fdSRick Macklem addr = malloc(addrlen); 985011981fdSRick Macklem if (addr == NULL) 986011981fdSRick Macklem err(1, "malloc"); 987011981fdSRick Macklem bcopy(nfs_nb.buf, addr, addrlen); 988011981fdSRick Macklem 989011981fdSRick Macklem build_iovec(iov, iovlen, "addr", addr, addrlen); 990011981fdSRick Macklem secname = sec_num_to_name(secflavor); 991011981fdSRick Macklem if (secname != NULL) 992011981fdSRick Macklem build_iovec(iov, iovlen, "sec", secname, (size_t)-1); 993011981fdSRick Macklem build_iovec(iov, iovlen, "nfsv4", NULL, 0); 994011981fdSRick Macklem build_iovec(iov, iovlen, "dirpath", spec, (size_t)-1); 995011981fdSRick Macklem 996011981fdSRick Macklem return (TRYRET_SUCCESS); 997011981fdSRick Macklem } 998011981fdSRick Macklem 9990775314bSDoug Rabson /* Send the MOUNTPROC_MNT RPC to get the root filehandle. */ 1000317d5933SIan Dowse try.tv_sec = 10; 1001317d5933SIan Dowse try.tv_usec = 0; 10020775314bSDoug Rabson clp = clnt_tp_create(hostp, MOUNTPROG, mntvers, nconf_mnt); 1003317d5933SIan Dowse if (clp == NULL) { 1004ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 1005317d5933SIan Dowse hostp, spec, clnt_spcreateerror("RPCMNT: clnt_create")); 1006317d5933SIan Dowse return (returncode(rpc_createerr.cf_stat, 1007317d5933SIan Dowse &rpc_createerr.cf_error)); 1008317d5933SIan Dowse } 1009317d5933SIan Dowse clp->cl_auth = authsys_create_default(); 1010a9148abdSDoug Rabson nfhret.auth = secflavor; 1011317d5933SIan Dowse nfhret.vers = mntvers; 10120775314bSDoug Rabson stat = clnt_call(clp, MOUNTPROC_MNT, (xdrproc_t)xdr_dir, spec, 1013c04affffSMatthew N. Dodd (xdrproc_t)xdr_fh, &nfhret, 1014317d5933SIan Dowse try); 1015317d5933SIan Dowse auth_destroy(clp->cl_auth); 1016317d5933SIan Dowse if (stat != RPC_SUCCESS) { 1017317d5933SIan Dowse if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 1018317d5933SIan Dowse clnt_destroy(clp); 1019317d5933SIan Dowse trymntmode = V2; 1020317d5933SIan Dowse goto tryagain; 1021317d5933SIan Dowse } 1022317d5933SIan Dowse clnt_geterr(clp, &rpcerr); 1023ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 1024317d5933SIan Dowse hostp, spec, clnt_sperror(clp, "RPCPROG_MNT")); 1025317d5933SIan Dowse clnt_destroy(clp); 1026317d5933SIan Dowse return (returncode(stat, &rpcerr)); 1027317d5933SIan Dowse } 1028317d5933SIan Dowse clnt_destroy(clp); 1029317d5933SIan Dowse 1030317d5933SIan Dowse if (nfhret.stat != 0) { 1031ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 1032317d5933SIan Dowse hostp, spec, strerror(nfhret.stat)); 1033317d5933SIan Dowse return (TRYRET_REMOTEERR); 1034317d5933SIan Dowse } 1035317d5933SIan Dowse 1036317d5933SIan Dowse /* 1037317d5933SIan Dowse * Store the filehandle and server address in nfsargsp, making 1038317d5933SIan Dowse * sure to copy any locally allocated structures. 1039317d5933SIan Dowse */ 10404b5bc283SCraig Rodrigues addrlen = nfs_nb.len; 10414b5bc283SCraig Rodrigues addr = malloc(addrlen); 10424b5bc283SCraig Rodrigues fhsize = nfhret.fhsize; 10434b5bc283SCraig Rodrigues fh = malloc(fhsize); 10444b5bc283SCraig Rodrigues if (addr == NULL || fh == NULL) 1045317d5933SIan Dowse err(1, "malloc"); 10464b5bc283SCraig Rodrigues bcopy(nfs_nb.buf, addr, addrlen); 10474b5bc283SCraig Rodrigues bcopy(nfhret.nfh, fh, fhsize); 1048317d5933SIan Dowse 10494b5bc283SCraig Rodrigues build_iovec(iov, iovlen, "addr", addr, addrlen); 10504b5bc283SCraig Rodrigues build_iovec(iov, iovlen, "fh", fh, fhsize); 1051a9148abdSDoug Rabson secname = sec_num_to_name(nfhret.auth); 1052a9148abdSDoug Rabson if (secname) 1053a9148abdSDoug Rabson build_iovec(iov, iovlen, "sec", secname, (size_t)-1); 1054317d5933SIan Dowse if (nfsvers == 3) 10554b5bc283SCraig Rodrigues build_iovec(iov, iovlen, "nfsv3", NULL, 0); 1056317d5933SIan Dowse 1057317d5933SIan Dowse return (TRYRET_SUCCESS); 1058317d5933SIan Dowse } 1059317d5933SIan Dowse 10600c269d1fSCraig Rodrigues /* 1061317d5933SIan Dowse * Catagorise a RPC return status and error into an `enum tryret' 1062317d5933SIan Dowse * return code. 1063317d5933SIan Dowse */ 1064317d5933SIan Dowse enum tryret 1065317d5933SIan Dowse returncode(enum clnt_stat stat, struct rpc_err *rpcerr) 1066317d5933SIan Dowse { 1067317d5933SIan Dowse switch (stat) { 1068317d5933SIan Dowse case RPC_TIMEDOUT: 1069317d5933SIan Dowse return (TRYRET_TIMEOUT); 1070317d5933SIan Dowse case RPC_PMAPFAILURE: 1071317d5933SIan Dowse case RPC_PROGNOTREGISTERED: 1072317d5933SIan Dowse case RPC_PROGVERSMISMATCH: 1073eca1c24eSIan Dowse /* XXX, these can be local or remote. */ 1074eca1c24eSIan Dowse case RPC_CANTSEND: 1075eca1c24eSIan Dowse case RPC_CANTRECV: 1076317d5933SIan Dowse return (TRYRET_REMOTEERR); 1077317d5933SIan Dowse case RPC_SYSTEMERROR: 1078317d5933SIan Dowse switch (rpcerr->re_errno) { 1079317d5933SIan Dowse case ETIMEDOUT: 1080317d5933SIan Dowse return (TRYRET_TIMEOUT); 1081317d5933SIan Dowse case ENOMEM: 1082317d5933SIan Dowse break; 1083317d5933SIan Dowse default: 1084317d5933SIan Dowse return (TRYRET_REMOTEERR); 1085317d5933SIan Dowse } 1086317d5933SIan Dowse /* FALLTHROUGH */ 1087317d5933SIan Dowse default: 1088317d5933SIan Dowse break; 1089317d5933SIan Dowse } 1090317d5933SIan Dowse return (TRYRET_LOCALERR); 1091317d5933SIan Dowse } 1092317d5933SIan Dowse 1093317d5933SIan Dowse /* 1094a3d8f94bSIan Dowse * Look up a netid based on an address family and socket type. 1095a3d8f94bSIan Dowse * `af' is the address family, and `sotype' is SOCK_DGRAM or SOCK_STREAM. 1096a3d8f94bSIan Dowse * 1097a3d8f94bSIan Dowse * XXX there should be a library function for this. 1098a3d8f94bSIan Dowse */ 10994b5bc283SCraig Rodrigues const char * 110033924ad4SWarner Losh netidbytype(int af, int sotype) 110133924ad4SWarner Losh { 1102a3d8f94bSIan Dowse struct nc_protos *p; 1103a3d8f94bSIan Dowse 1104a3d8f94bSIan Dowse for (p = nc_protos; p->netid != NULL; p++) { 1105a3d8f94bSIan Dowse if (af != p->af || sotype != p->sotype) 1106a3d8f94bSIan Dowse continue; 1107a3d8f94bSIan Dowse return (p->netid); 1108a3d8f94bSIan Dowse } 1109a3d8f94bSIan Dowse return (NULL); 1110a3d8f94bSIan Dowse } 1111a3d8f94bSIan Dowse 1112a3d8f94bSIan Dowse /* 1113a3d8f94bSIan Dowse * Look up a netconfig entry based on a netid, and cache the result so 1114a3d8f94bSIan Dowse * that we don't need to remember to call freenetconfigent(). 1115a3d8f94bSIan Dowse * 1116a3d8f94bSIan Dowse * Otherwise it behaves just like getnetconfigent(), so nc_*error() 1117a3d8f94bSIan Dowse * work on failure. 1118a3d8f94bSIan Dowse */ 1119a3d8f94bSIan Dowse struct netconfig * 112033924ad4SWarner Losh getnetconf_cached(const char *netid) 112133924ad4SWarner Losh { 1122a3d8f94bSIan Dowse static struct nc_entry { 1123a3d8f94bSIan Dowse struct netconfig *nconf; 1124a3d8f94bSIan Dowse struct nc_entry *next; 1125a3d8f94bSIan Dowse } *head; 1126a3d8f94bSIan Dowse struct nc_entry *p; 1127a3d8f94bSIan Dowse struct netconfig *nconf; 1128a3d8f94bSIan Dowse 1129a3d8f94bSIan Dowse for (p = head; p != NULL; p = p->next) 1130a3d8f94bSIan Dowse if (strcmp(netid, p->nconf->nc_netid) == 0) 1131a3d8f94bSIan Dowse return (p->nconf); 1132a3d8f94bSIan Dowse 1133a3d8f94bSIan Dowse if ((nconf = getnetconfigent(netid)) == NULL) 1134a3d8f94bSIan Dowse return (NULL); 1135a3d8f94bSIan Dowse if ((p = malloc(sizeof(*p))) == NULL) 1136a3d8f94bSIan Dowse err(1, "malloc"); 1137a3d8f94bSIan Dowse p->nconf = nconf; 1138a3d8f94bSIan Dowse p->next = head; 1139a3d8f94bSIan Dowse head = p; 1140a3d8f94bSIan Dowse 1141a3d8f94bSIan Dowse return (p->nconf); 1142a3d8f94bSIan Dowse } 1143a3d8f94bSIan Dowse 1144a3d8f94bSIan Dowse /* 11458fae3551SRodney W. Grimes * xdr routines for mount rpc's 11468fae3551SRodney W. Grimes */ 11478fae3551SRodney W. Grimes int 114833924ad4SWarner Losh xdr_dir(XDR *xdrsp, char *dirp) 11498fae3551SRodney W. Grimes { 11500775314bSDoug Rabson return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 11518fae3551SRodney W. Grimes } 11528fae3551SRodney W. Grimes 11538fae3551SRodney W. Grimes int 115433924ad4SWarner Losh xdr_fh(XDR *xdrsp, struct nfhret *np) 11558fae3551SRodney W. Grimes { 11563d438ad6SDavid E. O'Brien int i; 1157a62dc406SDoug Rabson long auth, authcnt, authfnd = 0; 1158a62dc406SDoug Rabson 1159a62dc406SDoug Rabson if (!xdr_u_long(xdrsp, &np->stat)) 11608fae3551SRodney W. Grimes return (0); 11618fae3551SRodney W. Grimes if (np->stat) 11628fae3551SRodney W. Grimes return (1); 1163a62dc406SDoug Rabson switch (np->vers) { 1164a62dc406SDoug Rabson case 1: 11650775314bSDoug Rabson np->fhsize = NFS_FHSIZE; 11660775314bSDoug Rabson return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFS_FHSIZE)); 1167a62dc406SDoug Rabson case 3: 1168a62dc406SDoug Rabson if (!xdr_long(xdrsp, &np->fhsize)) 1169a62dc406SDoug Rabson return (0); 11700775314bSDoug Rabson if (np->fhsize <= 0 || np->fhsize > NFS3_FHSIZE) 1171a62dc406SDoug Rabson return (0); 1172a62dc406SDoug Rabson if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize)) 1173a62dc406SDoug Rabson return (0); 1174a62dc406SDoug Rabson if (!xdr_long(xdrsp, &authcnt)) 1175a62dc406SDoug Rabson return (0); 1176a62dc406SDoug Rabson for (i = 0; i < authcnt; i++) { 1177a62dc406SDoug Rabson if (!xdr_long(xdrsp, &auth)) 1178a62dc406SDoug Rabson return (0); 11794b5bc283SCraig Rodrigues if (np->auth == -1) { 11804b5bc283SCraig Rodrigues np->auth = auth; 1181a62dc406SDoug Rabson authfnd++; 11824b5bc283SCraig Rodrigues } else if (auth == np->auth) { 11834b5bc283SCraig Rodrigues authfnd++; 11844b5bc283SCraig Rodrigues } 1185a62dc406SDoug Rabson } 1186a62dc406SDoug Rabson /* 1187a62dc406SDoug Rabson * Some servers, such as DEC's OSF/1 return a nil authenticator 1188a62dc406SDoug Rabson * list to indicate RPCAUTH_UNIX. 1189a62dc406SDoug Rabson */ 11904b5bc283SCraig Rodrigues if (authcnt == 0 && np->auth == -1) 11914b5bc283SCraig Rodrigues np->auth = AUTH_SYS; 11924b5bc283SCraig Rodrigues if (!authfnd && (authcnt > 0 || np->auth != AUTH_SYS)) 1193a62dc406SDoug Rabson np->stat = EAUTH; 1194a62dc406SDoug Rabson return (1); 1195a62dc406SDoug Rabson }; 1196a62dc406SDoug Rabson return (0); 11978fae3551SRodney W. Grimes } 11988fae3551SRodney W. Grimes 1199eaa86f9dSBruce Evans void 12008fae3551SRodney W. Grimes usage() 12018fae3551SRodney W. Grimes { 120246fc8f78SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 120386ce6a83SRobert Watson "usage: mount_nfs [-23bcdiLlNPsTU] [-a maxreadahead] [-D deadthresh]", 12048d646af5SRuslan Ermilov " [-g maxgroups] [-I readdirsize] [-o options] [-R retrycnt]", 12058d646af5SRuslan Ermilov " [-r readsize] [-t timeout] [-w writesize] [-x retrans]", 12068d646af5SRuslan Ermilov " rhost:path node"); 12078fae3551SRodney W. Grimes exit(1); 12088fae3551SRodney W. Grimes } 1209