xref: /freebsd/sbin/mount_nfs/mount_nfs.c (revision a9148abd)
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