xref: /illumos-gate/usr/src/cmd/fs.d/nfs/mount/mount.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
32*7c478bd9Sstevel@tonic-gate  * The Regents of the University of California
33*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
36*7c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
37*7c478bd9Sstevel@tonic-gate  * contributors.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate /*
43*7c478bd9Sstevel@tonic-gate  * nfs mount
44*7c478bd9Sstevel@tonic-gate  */
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #define	NFSCLIENT
47*7c478bd9Sstevel@tonic-gate #include <locale.h>
48*7c478bd9Sstevel@tonic-gate #include <stdio.h>
49*7c478bd9Sstevel@tonic-gate #include <string.h>
50*7c478bd9Sstevel@tonic-gate #include <memory.h>
51*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
52*7c478bd9Sstevel@tonic-gate #include <unistd.h>
53*7c478bd9Sstevel@tonic-gate #include <ctype.h>
54*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
55*7c478bd9Sstevel@tonic-gate #include <signal.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
57*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
58*7c478bd9Sstevel@tonic-gate #include <errno.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
60*7c478bd9Sstevel@tonic-gate #include <netdb.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/mount.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
63*7c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
64*7c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
65*7c478bd9Sstevel@tonic-gate #include <nfs/mount.h>
66*7c478bd9Sstevel@tonic-gate #include <rpcsvc/mount.h>
67*7c478bd9Sstevel@tonic-gate #include <sys/pathconf.h>
68*7c478bd9Sstevel@tonic-gate #include <netdir.h>
69*7c478bd9Sstevel@tonic-gate #include <netconfig.h>
70*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
71*7c478bd9Sstevel@tonic-gate #include <net/if.h>
72*7c478bd9Sstevel@tonic-gate #include <syslog.h>
73*7c478bd9Sstevel@tonic-gate #include <fslib.h>
74*7c478bd9Sstevel@tonic-gate #include <deflt.h>
75*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
76*7c478bd9Sstevel@tonic-gate #include "replica.h"
77*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
78*7c478bd9Sstevel@tonic-gate #include <nfs/nfs_sec.h>
79*7c478bd9Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
80*7c478bd9Sstevel@tonic-gate #include <priv.h>
81*7c478bd9Sstevel@tonic-gate #include "nfs_subr.h"
82*7c478bd9Sstevel@tonic-gate #include "webnfs.h"
83*7c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h>
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #ifndef	NFS_VERSMAX
86*7c478bd9Sstevel@tonic-gate #define	NFS_VERSMAX	4
87*7c478bd9Sstevel@tonic-gate #endif
88*7c478bd9Sstevel@tonic-gate #ifndef	NFS_VERSMIN
89*7c478bd9Sstevel@tonic-gate #define	NFS_VERSMIN	2
90*7c478bd9Sstevel@tonic-gate #endif
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate #define	RET_OK		0
93*7c478bd9Sstevel@tonic-gate #define	RET_RETRY	32
94*7c478bd9Sstevel@tonic-gate #define	RET_ERR		33
95*7c478bd9Sstevel@tonic-gate #define	RET_MNTERR	1000
96*7c478bd9Sstevel@tonic-gate #define	ERR_PROTO_NONE		0
97*7c478bd9Sstevel@tonic-gate #define	ERR_PROTO_INVALID	901
98*7c478bd9Sstevel@tonic-gate #define	ERR_PROTO_UNSUPP	902
99*7c478bd9Sstevel@tonic-gate #define	ERR_NETPATH		903
100*7c478bd9Sstevel@tonic-gate #define	ERR_NOHOST		904
101*7c478bd9Sstevel@tonic-gate #define	ERR_RPCERROR		905
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate typedef struct err_ret {
104*7c478bd9Sstevel@tonic-gate 	int error_type;
105*7c478bd9Sstevel@tonic-gate 	int error_value;
106*7c478bd9Sstevel@tonic-gate } err_ret_t;
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate #define	SET_ERR_RET(errst, etype, eval) \
109*7c478bd9Sstevel@tonic-gate 	if (errst) { \
110*7c478bd9Sstevel@tonic-gate 		(errst)->error_type = etype; \
111*7c478bd9Sstevel@tonic-gate 		(errst)->error_value = eval; \
112*7c478bd9Sstevel@tonic-gate 	}
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate /* number of transports to try */
115*7c478bd9Sstevel@tonic-gate #define	MNT_PREF_LISTLEN	2
116*7c478bd9Sstevel@tonic-gate #define	FIRST_TRY		1
117*7c478bd9Sstevel@tonic-gate #define	SECOND_TRY		2
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate #define	BIGRETRY	10000
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate /* maximum length of RPC header for NFS messages */
122*7c478bd9Sstevel@tonic-gate #define	NFS_RPC_HDR	432
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate #define	NFS_ARGS_EXTB_secdata(args, secdata) \
125*7c478bd9Sstevel@tonic-gate 	{ (args)->nfs_args_ext = NFS_ARGS_EXTB, \
126*7c478bd9Sstevel@tonic-gate 	(args)->nfs_ext_u.nfs_extB.secdata = secdata; }
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate extern int __clnt_bindresvport();
129*7c478bd9Sstevel@tonic-gate extern char *nfs_get_qop_name();
130*7c478bd9Sstevel@tonic-gate extern AUTH * nfs_create_ah();
131*7c478bd9Sstevel@tonic-gate extern enum snego_stat nfs_sec_nego();
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate static void usage(void);
134*7c478bd9Sstevel@tonic-gate static int retry(struct mnttab *, int);
135*7c478bd9Sstevel@tonic-gate static int set_args(int *, struct nfs_args *, char *, struct mnttab *);
136*7c478bd9Sstevel@tonic-gate static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t,
137*7c478bd9Sstevel@tonic-gate 	int *, struct netconfig **, ushort_t);
138*7c478bd9Sstevel@tonic-gate static int get_fh(struct nfs_args *, char *, char *, int *, bool_t,
139*7c478bd9Sstevel@tonic-gate 	struct netconfig **, ushort_t);
140*7c478bd9Sstevel@tonic-gate static int make_secure(struct nfs_args *, char *, struct netconfig *,
141*7c478bd9Sstevel@tonic-gate 	bool_t, rpcvers_t);
142*7c478bd9Sstevel@tonic-gate static int mount_nfs(struct mnttab *, int);
143*7c478bd9Sstevel@tonic-gate static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **,
144*7c478bd9Sstevel@tonic-gate 		    bool_t, char *, ushort_t, err_ret_t *, bool_t);
145*7c478bd9Sstevel@tonic-gate static void pr_err(const char *fmt, ...);
146*7c478bd9Sstevel@tonic-gate static void usage(void);
147*7c478bd9Sstevel@tonic-gate static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t,
148*7c478bd9Sstevel@tonic-gate 	struct netconfig **, char *, ushort_t, struct t_info *,
149*7c478bd9Sstevel@tonic-gate 	caddr_t *, bool_t, char *, err_ret_t *);
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate static struct netbuf *get_the_addr(char *, rpcprog_t, rpcvers_t,
152*7c478bd9Sstevel@tonic-gate 	struct netconfig *, ushort_t, struct t_info *, caddr_t *,
153*7c478bd9Sstevel@tonic-gate 	bool_t, char *, err_ret_t *);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate extern int self_check(char *);
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate static void read_default(void);
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate static char typename[64];
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate static int bg = 0;
162*7c478bd9Sstevel@tonic-gate static int backgrounded = 0;
163*7c478bd9Sstevel@tonic-gate static int posix = 0;
164*7c478bd9Sstevel@tonic-gate static int retries = BIGRETRY;
165*7c478bd9Sstevel@tonic-gate static ushort_t nfs_port = 0;
166*7c478bd9Sstevel@tonic-gate static char *nfs_proto = NULL;
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate static int mflg = 0;
169*7c478bd9Sstevel@tonic-gate static int Oflg = 0;	/* Overlay mounts */
170*7c478bd9Sstevel@tonic-gate static int qflg = 0;	/* quiet - don't print warnings on bad options */
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate static char *fstype = MNTTYPE_NFS;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate static seconfig_t nfs_sec;
175*7c478bd9Sstevel@tonic-gate static int sec_opt = 0;	/* any security option ? */
176*7c478bd9Sstevel@tonic-gate static bool_t snego_done;
177*7c478bd9Sstevel@tonic-gate static void sigusr1(int);
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate /*
180*7c478bd9Sstevel@tonic-gate  * list of support services needed
181*7c478bd9Sstevel@tonic-gate  */
182*7c478bd9Sstevel@tonic-gate static char	*service_list[] = { STATD, LOCKD, NULL };
183*7c478bd9Sstevel@tonic-gate static char	*service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL };
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate /*
186*7c478bd9Sstevel@tonic-gate  * These two variables control the NFS version number to be used.
187*7c478bd9Sstevel@tonic-gate  *
188*7c478bd9Sstevel@tonic-gate  * nfsvers defaults to 0 which means to use the highest number that
189*7c478bd9Sstevel@tonic-gate  * both the client and the server support.  It can also be set to
190*7c478bd9Sstevel@tonic-gate  * a particular value, either 2, 3, or 4 to indicate the version
191*7c478bd9Sstevel@tonic-gate  * number of choice.  If the server (or the client) do not support
192*7c478bd9Sstevel@tonic-gate  * the version indicated, then the mount attempt will be failed.
193*7c478bd9Sstevel@tonic-gate  *
194*7c478bd9Sstevel@tonic-gate  * nfsvers_to_use is the actual version number found to use.  It
195*7c478bd9Sstevel@tonic-gate  * is determined in get_fh by pinging the various versions of the
196*7c478bd9Sstevel@tonic-gate  * NFS service on the server to see which responds positively.
197*7c478bd9Sstevel@tonic-gate  */
198*7c478bd9Sstevel@tonic-gate static rpcvers_t nfsvers = 0;
199*7c478bd9Sstevel@tonic-gate static rpcvers_t nfsvers_to_use = 0;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate /*
202*7c478bd9Sstevel@tonic-gate  * There are the defaults (range) for the client when determining
203*7c478bd9Sstevel@tonic-gate  * which NFS version to use when probing the server (see above).
204*7c478bd9Sstevel@tonic-gate  * These will only be used when the vers mount option is not used and
205*7c478bd9Sstevel@tonic-gate  * these may be reset if /etc/default/nfs is configured to do so.
206*7c478bd9Sstevel@tonic-gate  */
207*7c478bd9Sstevel@tonic-gate static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT;
208*7c478bd9Sstevel@tonic-gate static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate /*
211*7c478bd9Sstevel@tonic-gate  * This variable controls whether to try the public file handle.
212*7c478bd9Sstevel@tonic-gate  */
213*7c478bd9Sstevel@tonic-gate static bool_t public_opt;
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
216*7c478bd9Sstevel@tonic-gate {
217*7c478bd9Sstevel@tonic-gate 	struct mnttab mnt;
218*7c478bd9Sstevel@tonic-gate 	extern char *optarg;
219*7c478bd9Sstevel@tonic-gate 	extern int optind;
220*7c478bd9Sstevel@tonic-gate 	char optbuf[MAX_MNTOPT_STR];
221*7c478bd9Sstevel@tonic-gate 	int ro = 0;
222*7c478bd9Sstevel@tonic-gate 	int r;
223*7c478bd9Sstevel@tonic-gate 	int c;
224*7c478bd9Sstevel@tonic-gate 	char *myname;
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
227*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
228*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
229*7c478bd9Sstevel@tonic-gate #endif
230*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	myname = strrchr(argv[0], '/');
233*7c478bd9Sstevel@tonic-gate 	myname = myname ? myname + 1 : argv[0];
234*7c478bd9Sstevel@tonic-gate 	(void) snprintf(typename, sizeof (typename), "%s %s",
235*7c478bd9Sstevel@tonic-gate 	    MNTTYPE_NFS, myname);
236*7c478bd9Sstevel@tonic-gate 	argv[0] = typename;
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	mnt.mnt_mntopts = optbuf;
239*7c478bd9Sstevel@tonic-gate 	(void) strcpy(optbuf, "rw");
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	/*
242*7c478bd9Sstevel@tonic-gate 	 * Set options
243*7c478bd9Sstevel@tonic-gate 	 */
244*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ro:mOq")) != EOF) {
245*7c478bd9Sstevel@tonic-gate 		switch (c) {
246*7c478bd9Sstevel@tonic-gate 		case 'r':
247*7c478bd9Sstevel@tonic-gate 			ro++;
248*7c478bd9Sstevel@tonic-gate 			break;
249*7c478bd9Sstevel@tonic-gate 		case 'o':
250*7c478bd9Sstevel@tonic-gate 			if (strlen(optarg) >= MAX_MNTOPT_STR) {
251*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("option string too long"));
252*7c478bd9Sstevel@tonic-gate 				return (RET_ERR);
253*7c478bd9Sstevel@tonic-gate 			}
254*7c478bd9Sstevel@tonic-gate 			(void) strcpy(mnt.mnt_mntopts, optarg);
255*7c478bd9Sstevel@tonic-gate #ifdef LATER					/* XXX */
256*7c478bd9Sstevel@tonic-gate 			if (strstr(optarg, MNTOPT_REMOUNT)) {
257*7c478bd9Sstevel@tonic-gate 				/*
258*7c478bd9Sstevel@tonic-gate 				 * If remount is specified, only rw is allowed.
259*7c478bd9Sstevel@tonic-gate 				 */
260*7c478bd9Sstevel@tonic-gate 				if ((strcmp(optarg, MNTOPT_REMOUNT) != 0) &&
261*7c478bd9Sstevel@tonic-gate 				    (strcmp(optarg, "remount,rw") != 0) &&
262*7c478bd9Sstevel@tonic-gate 				    (strcmp(optarg, "rw,remount") != 0)) {
263*7c478bd9Sstevel@tonic-gate 					pr_err(gettext("Invalid options\n"));
264*7c478bd9Sstevel@tonic-gate 					exit(RET_ERR);
265*7c478bd9Sstevel@tonic-gate 				}
266*7c478bd9Sstevel@tonic-gate 			}
267*7c478bd9Sstevel@tonic-gate #endif /* LATER */				/* XXX */
268*7c478bd9Sstevel@tonic-gate 			break;
269*7c478bd9Sstevel@tonic-gate 		case 'm':
270*7c478bd9Sstevel@tonic-gate 			mflg++;
271*7c478bd9Sstevel@tonic-gate 			break;
272*7c478bd9Sstevel@tonic-gate 		case 'O':
273*7c478bd9Sstevel@tonic-gate 			Oflg++;
274*7c478bd9Sstevel@tonic-gate 			break;
275*7c478bd9Sstevel@tonic-gate 		case 'q':
276*7c478bd9Sstevel@tonic-gate 			qflg++;
277*7c478bd9Sstevel@tonic-gate 			break;
278*7c478bd9Sstevel@tonic-gate 		default:
279*7c478bd9Sstevel@tonic-gate 			usage();
280*7c478bd9Sstevel@tonic-gate 			exit(RET_ERR);
281*7c478bd9Sstevel@tonic-gate 		}
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 	if (argc - optind != 2) {
284*7c478bd9Sstevel@tonic-gate 		usage();
285*7c478bd9Sstevel@tonic-gate 		exit(RET_ERR);
286*7c478bd9Sstevel@tonic-gate 	}
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	mnt.mnt_special = argv[optind];
289*7c478bd9Sstevel@tonic-gate 	mnt.mnt_mountp = argv[optind+1];
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	if (!priv_ineffect(PRIV_SYS_MOUNT) ||
292*7c478bd9Sstevel@tonic-gate 	    !priv_ineffect(PRIV_NET_PRIVADDR)) {
293*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("insufficient privileges\n"));
294*7c478bd9Sstevel@tonic-gate 		exit(RET_ERR);
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	/*
298*7c478bd9Sstevel@tonic-gate 	 * Read the defaults file to see if the min/max versions have
299*7c478bd9Sstevel@tonic-gate 	 * been set and therefore would override the encoded defaults.
300*7c478bd9Sstevel@tonic-gate 	 * Then check to make sure that if they were set that the
301*7c478bd9Sstevel@tonic-gate 	 * values are reasonable.
302*7c478bd9Sstevel@tonic-gate 	 */
303*7c478bd9Sstevel@tonic-gate 	read_default();
304*7c478bd9Sstevel@tonic-gate 	if (vers_min_default > vers_max_default ||
305*7c478bd9Sstevel@tonic-gate 		vers_min_default < NFS_VERSMIN ||
306*7c478bd9Sstevel@tonic-gate 		vers_max_default > NFS_VERSMAX) {
307*7c478bd9Sstevel@tonic-gate 		pr_err("%s %s\n%s %s\n",
308*7c478bd9Sstevel@tonic-gate 			gettext("Incorrect configuration of client\'s"),
309*7c478bd9Sstevel@tonic-gate 			NFSADMIN,
310*7c478bd9Sstevel@tonic-gate 			gettext("NFS_CLIENT_VERSMIN or NFS_CLIENT_VERSMAX"),
311*7c478bd9Sstevel@tonic-gate 			gettext("is either out of range or overlaps."));
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	r = mount_nfs(&mnt, ro);
315*7c478bd9Sstevel@tonic-gate 	if (r == RET_RETRY && retries)
316*7c478bd9Sstevel@tonic-gate 		r = retry(&mnt, ro);
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	/*
319*7c478bd9Sstevel@tonic-gate 	 * exit(r);
320*7c478bd9Sstevel@tonic-gate 	 */
321*7c478bd9Sstevel@tonic-gate 	return (r);
322*7c478bd9Sstevel@tonic-gate }
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate static void
325*7c478bd9Sstevel@tonic-gate pr_err(const char *fmt, ...)
326*7c478bd9Sstevel@tonic-gate {
327*7c478bd9Sstevel@tonic-gate 	va_list ap;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
330*7c478bd9Sstevel@tonic-gate 	if (backgrounded != 0) {
331*7c478bd9Sstevel@tonic-gate 		(void) vsyslog(LOG_ERR, fmt, ap);
332*7c478bd9Sstevel@tonic-gate 	} else {
333*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", typename);
334*7c478bd9Sstevel@tonic-gate 		(void) vfprintf(stderr, fmt, ap);
335*7c478bd9Sstevel@tonic-gate 		(void) fflush(stderr);
336*7c478bd9Sstevel@tonic-gate 	}
337*7c478bd9Sstevel@tonic-gate 	va_end(ap);
338*7c478bd9Sstevel@tonic-gate }
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate static void
341*7c478bd9Sstevel@tonic-gate usage()
342*7c478bd9Sstevel@tonic-gate {
343*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
344*7c478bd9Sstevel@tonic-gate 	    gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n"));
345*7c478bd9Sstevel@tonic-gate 	exit(RET_ERR);
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate static int
349*7c478bd9Sstevel@tonic-gate mount_nfs(struct mnttab *mntp, int ro)
350*7c478bd9Sstevel@tonic-gate {
351*7c478bd9Sstevel@tonic-gate 	struct nfs_args *args = NULL, *argp = NULL, *prev_argp = NULL;
352*7c478bd9Sstevel@tonic-gate 	struct netconfig *nconf = NULL;
353*7c478bd9Sstevel@tonic-gate 	struct replica *list = NULL;
354*7c478bd9Sstevel@tonic-gate 	int mntflags = 0;
355*7c478bd9Sstevel@tonic-gate 	int i, r, n;
356*7c478bd9Sstevel@tonic-gate 	int oldvers = 0, vers = 0;
357*7c478bd9Sstevel@tonic-gate 	int last_error = RET_OK;
358*7c478bd9Sstevel@tonic-gate 	int replicated = 0;
359*7c478bd9Sstevel@tonic-gate 	char *p;
360*7c478bd9Sstevel@tonic-gate 	bool_t url;
361*7c478bd9Sstevel@tonic-gate 	bool_t use_pubfh;
362*7c478bd9Sstevel@tonic-gate 	char *special = NULL;
363*7c478bd9Sstevel@tonic-gate 	char *oldpath = NULL;
364*7c478bd9Sstevel@tonic-gate 	char *newpath = NULL;
365*7c478bd9Sstevel@tonic-gate 	char *service;
366*7c478bd9Sstevel@tonic-gate 	pid_t pi;
367*7c478bd9Sstevel@tonic-gate 	struct flock f;
368*7c478bd9Sstevel@tonic-gate 	char *saveopts = NULL;
369*7c478bd9Sstevel@tonic-gate 	char **sl = NULL;
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	mntp->mnt_fstype = MNTTYPE_NFS;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	if (ro) {
374*7c478bd9Sstevel@tonic-gate 		mntflags |= MS_RDONLY;
375*7c478bd9Sstevel@tonic-gate 		/* convert "rw"->"ro" */
376*7c478bd9Sstevel@tonic-gate 		if (p = strstr(mntp->mnt_mntopts, "rw")) {
377*7c478bd9Sstevel@tonic-gate 			if (*(p+2) == ',' || *(p+2) == '\0')
378*7c478bd9Sstevel@tonic-gate 				*(p+1) = 'o';
379*7c478bd9Sstevel@tonic-gate 		}
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 	if (Oflg)
383*7c478bd9Sstevel@tonic-gate 		mntflags |= MS_OVERLAY;
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	list = parse_replica(mntp->mnt_special, &n);
386*7c478bd9Sstevel@tonic-gate 	if (list == NULL) {
387*7c478bd9Sstevel@tonic-gate 		if (n < 0)
388*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("nfs file system; use [host:]path\n"));
389*7c478bd9Sstevel@tonic-gate 		else
390*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
391*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	replicated = (n > 1);
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	/*
397*7c478bd9Sstevel@tonic-gate 	 * There are some free() calls at the bottom of this loop, so be
398*7c478bd9Sstevel@tonic-gate 	 * careful about adding continue statements.
399*7c478bd9Sstevel@tonic-gate 	 */
400*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
401*7c478bd9Sstevel@tonic-gate 		char *path;
402*7c478bd9Sstevel@tonic-gate 		char *host;
403*7c478bd9Sstevel@tonic-gate 		ushort_t port;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 		argp = (struct nfs_args *)malloc(sizeof (*argp));
406*7c478bd9Sstevel@tonic-gate 		if (argp == NULL) {
407*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
408*7c478bd9Sstevel@tonic-gate 			last_error = RET_ERR;
409*7c478bd9Sstevel@tonic-gate 			goto out;
410*7c478bd9Sstevel@tonic-gate 		}
411*7c478bd9Sstevel@tonic-gate 		memset(argp, 0, sizeof (*argp));
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 		memset(&nfs_sec, 0, sizeof (nfs_sec));
414*7c478bd9Sstevel@tonic-gate 		sec_opt = 0;
415*7c478bd9Sstevel@tonic-gate 		use_pubfh = FALSE;
416*7c478bd9Sstevel@tonic-gate 		url = FALSE;
417*7c478bd9Sstevel@tonic-gate 		port = 0;
418*7c478bd9Sstevel@tonic-gate 		snego_done = FALSE;
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 		/*
421*7c478bd9Sstevel@tonic-gate 		 * Looking for resources of the form
422*7c478bd9Sstevel@tonic-gate 		 *	nfs://server_host[:port_number]/path_name
423*7c478bd9Sstevel@tonic-gate 		 */
424*7c478bd9Sstevel@tonic-gate 		if (strcmp(list[i].host, "nfs") == 0 && strncmp(list[i].path,
425*7c478bd9Sstevel@tonic-gate 		    "//", 2) == 0) {
426*7c478bd9Sstevel@tonic-gate 			char *sport, *cb;
427*7c478bd9Sstevel@tonic-gate 			url = TRUE;
428*7c478bd9Sstevel@tonic-gate 			oldpath = strdup(list[i].path);
429*7c478bd9Sstevel@tonic-gate 			if (oldpath == NULL) {
430*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("memory allocation failure\n"));
431*7c478bd9Sstevel@tonic-gate 				last_error = RET_ERR;
432*7c478bd9Sstevel@tonic-gate 				goto out;
433*7c478bd9Sstevel@tonic-gate 			}
434*7c478bd9Sstevel@tonic-gate 			host = list[i].path+2;
435*7c478bd9Sstevel@tonic-gate 			path = strchr(host, '/');
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 			if (path == NULL) {
438*7c478bd9Sstevel@tonic-gate 				pr_err(gettext(
439*7c478bd9Sstevel@tonic-gate 				    "illegal nfs url syntax\n"));
440*7c478bd9Sstevel@tonic-gate 				last_error = RET_ERR;
441*7c478bd9Sstevel@tonic-gate 				goto out;
442*7c478bd9Sstevel@tonic-gate 			}
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 			*path = '\0';
445*7c478bd9Sstevel@tonic-gate 			if (*host == '[') {
446*7c478bd9Sstevel@tonic-gate 				cb = strchr(host, ']');
447*7c478bd9Sstevel@tonic-gate 				if (cb == NULL) {
448*7c478bd9Sstevel@tonic-gate 					pr_err(gettext(
449*7c478bd9Sstevel@tonic-gate 						"illegal nfs url syntax\n"));
450*7c478bd9Sstevel@tonic-gate 					last_error = RET_ERR;
451*7c478bd9Sstevel@tonic-gate 					goto out;
452*7c478bd9Sstevel@tonic-gate 				} else {
453*7c478bd9Sstevel@tonic-gate 					*cb = '\0';
454*7c478bd9Sstevel@tonic-gate 					host++;
455*7c478bd9Sstevel@tonic-gate 					cb++;
456*7c478bd9Sstevel@tonic-gate 					if (*cb == ':')
457*7c478bd9Sstevel@tonic-gate 						port = htons((ushort_t)
458*7c478bd9Sstevel@tonic-gate 							atoi(cb+1));
459*7c478bd9Sstevel@tonic-gate 				}
460*7c478bd9Sstevel@tonic-gate 			} else {
461*7c478bd9Sstevel@tonic-gate 				sport = strchr(host, ':');
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 				if (sport != NULL && sport < path) {
464*7c478bd9Sstevel@tonic-gate 					*sport = '\0';
465*7c478bd9Sstevel@tonic-gate 					port = htons((ushort_t)atoi(sport+1));
466*7c478bd9Sstevel@tonic-gate 				}
467*7c478bd9Sstevel@tonic-gate 			}
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 			path++;
470*7c478bd9Sstevel@tonic-gate 			if (*path == '\0')
471*7c478bd9Sstevel@tonic-gate 				path = ".";
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 		} else {
474*7c478bd9Sstevel@tonic-gate 			host = list[i].host;
475*7c478bd9Sstevel@tonic-gate 			path = list[i].path;
476*7c478bd9Sstevel@tonic-gate 		}
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 		if (r = set_args(&mntflags, argp, host, mntp)) {
479*7c478bd9Sstevel@tonic-gate 			last_error = r;
480*7c478bd9Sstevel@tonic-gate 			goto out;
481*7c478bd9Sstevel@tonic-gate 		}
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 		if (public_opt == TRUE)
484*7c478bd9Sstevel@tonic-gate 			use_pubfh = TRUE;
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 		if (port == 0) {
487*7c478bd9Sstevel@tonic-gate 			port = nfs_port;
488*7c478bd9Sstevel@tonic-gate 		} else if (nfs_port != 0 && nfs_port != port) {
489*7c478bd9Sstevel@tonic-gate 			pr_err(gettext(
490*7c478bd9Sstevel@tonic-gate 			    "port (%u) in nfs URL not the same"
491*7c478bd9Sstevel@tonic-gate 			    " as port (%u) in port option\n"),
492*7c478bd9Sstevel@tonic-gate 			    (unsigned int)ntohs(port),
493*7c478bd9Sstevel@tonic-gate 			    (unsigned int)ntohs(nfs_port));
494*7c478bd9Sstevel@tonic-gate 			last_error = RET_ERR;
495*7c478bd9Sstevel@tonic-gate 			goto out;
496*7c478bd9Sstevel@tonic-gate 		}
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 		if (replicated && !(mntflags & MS_RDONLY)) {
500*7c478bd9Sstevel@tonic-gate 			pr_err(gettext(
501*7c478bd9Sstevel@tonic-gate 				"replicated mounts must be read-only\n"));
502*7c478bd9Sstevel@tonic-gate 			last_error = RET_ERR;
503*7c478bd9Sstevel@tonic-gate 			goto out;
504*7c478bd9Sstevel@tonic-gate 		}
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 		if (replicated && (argp->flags & NFSMNT_SOFT)) {
507*7c478bd9Sstevel@tonic-gate 			pr_err(gettext(
508*7c478bd9Sstevel@tonic-gate 				"replicated mounts must not be soft\n"));
509*7c478bd9Sstevel@tonic-gate 			last_error = RET_ERR;
510*7c478bd9Sstevel@tonic-gate 			goto out;
511*7c478bd9Sstevel@tonic-gate 		}
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 		oldvers = vers;
514*7c478bd9Sstevel@tonic-gate 		nconf = NULL;
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 		r = RET_ERR;
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 		/*
519*7c478bd9Sstevel@tonic-gate 		 * If -o public was specified, and/or a URL was specified,
520*7c478bd9Sstevel@tonic-gate 		 * then try the public file handle method.
521*7c478bd9Sstevel@tonic-gate 		 */
522*7c478bd9Sstevel@tonic-gate 		if ((use_pubfh == TRUE) || (url == TRUE)) {
523*7c478bd9Sstevel@tonic-gate 			r = get_fh_via_pub(argp, host, path, url, use_pubfh,
524*7c478bd9Sstevel@tonic-gate 				&vers, &nconf, port);
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 			if (r != RET_OK) {
527*7c478bd9Sstevel@tonic-gate 				/*
528*7c478bd9Sstevel@tonic-gate 				 * If -o public was specified, then return the
529*7c478bd9Sstevel@tonic-gate 				 * error now.
530*7c478bd9Sstevel@tonic-gate 				 */
531*7c478bd9Sstevel@tonic-gate 				if (use_pubfh == TRUE) {
532*7c478bd9Sstevel@tonic-gate 					last_error = r;
533*7c478bd9Sstevel@tonic-gate 					goto out;
534*7c478bd9Sstevel@tonic-gate 				}
535*7c478bd9Sstevel@tonic-gate 			} else
536*7c478bd9Sstevel@tonic-gate 				use_pubfh = TRUE;
537*7c478bd9Sstevel@tonic-gate 			argp->flags |= NFSMNT_PUBLIC;
538*7c478bd9Sstevel@tonic-gate 		}
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 		if ((r != RET_OK) || (vers == NFS_V4)) {
541*7c478bd9Sstevel@tonic-gate 			bool_t loud_on_mnt_err;
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 			/*
544*7c478bd9Sstevel@tonic-gate 			 * This can happen if -o public is not specified,
545*7c478bd9Sstevel@tonic-gate 			 * special is a URL, and server doesn't support
546*7c478bd9Sstevel@tonic-gate 			 * public file handle.
547*7c478bd9Sstevel@tonic-gate 			 */
548*7c478bd9Sstevel@tonic-gate 			if (url) {
549*7c478bd9Sstevel@tonic-gate 				URLparse(path);
550*7c478bd9Sstevel@tonic-gate 			}
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 			/*
553*7c478bd9Sstevel@tonic-gate 			 * If the path portion of the URL didn't have
554*7c478bd9Sstevel@tonic-gate 			 * a leading / then there is good possibility
555*7c478bd9Sstevel@tonic-gate 			 * that a mount without a leading slash will
556*7c478bd9Sstevel@tonic-gate 			 * fail.
557*7c478bd9Sstevel@tonic-gate 			 */
558*7c478bd9Sstevel@tonic-gate 			if (url == TRUE && *path != '/')
559*7c478bd9Sstevel@tonic-gate 				loud_on_mnt_err = FALSE;
560*7c478bd9Sstevel@tonic-gate 			else
561*7c478bd9Sstevel@tonic-gate 				loud_on_mnt_err = TRUE;
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 			r = get_fh(argp, host, path, &vers,
564*7c478bd9Sstevel@tonic-gate 				loud_on_mnt_err, &nconf, port);
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 			if (r != RET_OK) {
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 				/*
569*7c478bd9Sstevel@tonic-gate 				 * If there was no leading / and the path was
570*7c478bd9Sstevel@tonic-gate 				 * derived from a URL, then try again
571*7c478bd9Sstevel@tonic-gate 				 * with a leading /.
572*7c478bd9Sstevel@tonic-gate 				 */
573*7c478bd9Sstevel@tonic-gate 				if ((r == RET_MNTERR) &&
574*7c478bd9Sstevel@tonic-gate 				    (loud_on_mnt_err == FALSE)) {
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 					newpath = malloc(strlen(path)+2);
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 					if (newpath == NULL) {
579*7c478bd9Sstevel@tonic-gate 						pr_err(gettext("memory "
580*7c478bd9Sstevel@tonic-gate 						    "allocation failure\n"));
581*7c478bd9Sstevel@tonic-gate 						last_error = RET_ERR;
582*7c478bd9Sstevel@tonic-gate 						goto out;
583*7c478bd9Sstevel@tonic-gate 					}
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 					strcpy(newpath, "/");
586*7c478bd9Sstevel@tonic-gate 					strcat(newpath, path);
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 					r = get_fh(argp, host, newpath, &vers,
589*7c478bd9Sstevel@tonic-gate 						TRUE, &nconf, port);
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 					if (r == RET_OK)
592*7c478bd9Sstevel@tonic-gate 						path = newpath;
593*7c478bd9Sstevel@tonic-gate 				}
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 				/*
596*7c478bd9Sstevel@tonic-gate 				 * map exit code back to RET_ERR.
597*7c478bd9Sstevel@tonic-gate 				 */
598*7c478bd9Sstevel@tonic-gate 				if (r == RET_MNTERR)
599*7c478bd9Sstevel@tonic-gate 					r = RET_ERR;
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 				if (r != RET_OK) {
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 					if (replicated) {
604*7c478bd9Sstevel@tonic-gate 						if (argp->fh)
605*7c478bd9Sstevel@tonic-gate 							free(argp->fh);
606*7c478bd9Sstevel@tonic-gate 						if (argp->pathconf)
607*7c478bd9Sstevel@tonic-gate 							free(argp->pathconf);
608*7c478bd9Sstevel@tonic-gate 						free(argp);
609*7c478bd9Sstevel@tonic-gate 						goto cont;
610*7c478bd9Sstevel@tonic-gate 					}
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 					last_error = r;
613*7c478bd9Sstevel@tonic-gate 					goto out;
614*7c478bd9Sstevel@tonic-gate 				}
615*7c478bd9Sstevel@tonic-gate 			}
616*7c478bd9Sstevel@tonic-gate 		}
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 		if (oldvers && vers != oldvers) {
619*7c478bd9Sstevel@tonic-gate 			pr_err(
620*7c478bd9Sstevel@tonic-gate 			    gettext("replicas must have the same version\n"));
621*7c478bd9Sstevel@tonic-gate 			last_error = RET_ERR;
622*7c478bd9Sstevel@tonic-gate 			goto out;
623*7c478bd9Sstevel@tonic-gate 		}
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 		/*
626*7c478bd9Sstevel@tonic-gate 		 * decide whether to use remote host's
627*7c478bd9Sstevel@tonic-gate 		 * lockd or do local locking
628*7c478bd9Sstevel@tonic-gate 		 */
629*7c478bd9Sstevel@tonic-gate 		if (!(argp->flags & NFSMNT_LLOCK) && vers == NFS_VERSION &&
630*7c478bd9Sstevel@tonic-gate 		    remote_lock(host, argp->fh)) {
631*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
632*7c478bd9Sstevel@tonic-gate 			    "WARNING: No network locking on %s:%s:"),
633*7c478bd9Sstevel@tonic-gate 			    host, path);
634*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
635*7c478bd9Sstevel@tonic-gate 			    " contact admin to install server change\n"));
636*7c478bd9Sstevel@tonic-gate 				argp->flags |= NFSMNT_LLOCK;
637*7c478bd9Sstevel@tonic-gate 		}
638*7c478bd9Sstevel@tonic-gate 
639*7c478bd9Sstevel@tonic-gate 		if (self_check(host))
640*7c478bd9Sstevel@tonic-gate 			argp->flags |= NFSMNT_LOOPBACK;
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 		if (use_pubfh == FALSE) {
643*7c478bd9Sstevel@tonic-gate 			/*
644*7c478bd9Sstevel@tonic-gate 			 * Call to get_fh() above may have obtained the
645*7c478bd9Sstevel@tonic-gate 			 * netconfig info and NULL proc'd the server.
646*7c478bd9Sstevel@tonic-gate 			 * This would be the case with v4
647*7c478bd9Sstevel@tonic-gate 			 */
648*7c478bd9Sstevel@tonic-gate 			if (!(argp->flags & NFSMNT_KNCONF)) {
649*7c478bd9Sstevel@tonic-gate 				nconf = NULL;
650*7c478bd9Sstevel@tonic-gate 				if (r = getaddr_nfs(argp, host, &nconf,
651*7c478bd9Sstevel@tonic-gate 					    FALSE, path, port, NULL, TRUE)) {
652*7c478bd9Sstevel@tonic-gate 					last_error = r;
653*7c478bd9Sstevel@tonic-gate 					goto out;
654*7c478bd9Sstevel@tonic-gate 				}
655*7c478bd9Sstevel@tonic-gate 			}
656*7c478bd9Sstevel@tonic-gate 		}
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 		if (make_secure(argp, host, nconf, use_pubfh, vers) < 0) {
659*7c478bd9Sstevel@tonic-gate 			last_error = RET_ERR;
660*7c478bd9Sstevel@tonic-gate 			goto out;
661*7c478bd9Sstevel@tonic-gate 		}
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 		if ((url == TRUE) && (use_pubfh == FALSE)) {
664*7c478bd9Sstevel@tonic-gate 			/*
665*7c478bd9Sstevel@tonic-gate 			 * Convert the special from
666*7c478bd9Sstevel@tonic-gate 			 *	nfs://host/path
667*7c478bd9Sstevel@tonic-gate 			 * to
668*7c478bd9Sstevel@tonic-gate 			 *	host:path
669*7c478bd9Sstevel@tonic-gate 			 */
670*7c478bd9Sstevel@tonic-gate 			if (convert_special(&special, host, oldpath, path,
671*7c478bd9Sstevel@tonic-gate 			    mntp->mnt_special) == -1) {
672*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
673*7c478bd9Sstevel@tonic-gate 				    "could not convert URL nfs:%s to %s:%s\n"),
674*7c478bd9Sstevel@tonic-gate 				    oldpath, host, path);
675*7c478bd9Sstevel@tonic-gate 				last_error = RET_ERR;
676*7c478bd9Sstevel@tonic-gate 				goto out;
677*7c478bd9Sstevel@tonic-gate 			} else {
678*7c478bd9Sstevel@tonic-gate 				mntp->mnt_special = special;
679*7c478bd9Sstevel@tonic-gate 			}
680*7c478bd9Sstevel@tonic-gate 		}
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 		if (prev_argp == NULL)
683*7c478bd9Sstevel@tonic-gate 			args = argp;
684*7c478bd9Sstevel@tonic-gate 		else
685*7c478bd9Sstevel@tonic-gate 			prev_argp->nfs_ext_u.nfs_extB.next = argp;
686*7c478bd9Sstevel@tonic-gate 		prev_argp = argp;
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate cont:
689*7c478bd9Sstevel@tonic-gate 		if (oldpath != NULL) {
690*7c478bd9Sstevel@tonic-gate 			free(oldpath);
691*7c478bd9Sstevel@tonic-gate 			oldpath = NULL;
692*7c478bd9Sstevel@tonic-gate 		}
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 		if (newpath != NULL) {
695*7c478bd9Sstevel@tonic-gate 			free(newpath);
696*7c478bd9Sstevel@tonic-gate 			newpath = NULL;
697*7c478bd9Sstevel@tonic-gate 		}
698*7c478bd9Sstevel@tonic-gate 	}
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	argp = NULL;
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 	if (args == NULL) {
703*7c478bd9Sstevel@tonic-gate 		last_error = RET_RETRY;
704*7c478bd9Sstevel@tonic-gate 		goto out;
705*7c478bd9Sstevel@tonic-gate 	}
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	/* Determine which services are appropriate for the NFS version */
708*7c478bd9Sstevel@tonic-gate 	if (strcmp(fstype, MNTTYPE_NFS4) == 0)
709*7c478bd9Sstevel@tonic-gate 		sl = service_list_v4;
710*7c478bd9Sstevel@tonic-gate 	else
711*7c478bd9Sstevel@tonic-gate 		sl = service_list;
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 	/*
714*7c478bd9Sstevel@tonic-gate 	 * enable services as needed.
715*7c478bd9Sstevel@tonic-gate 	 */
716*7c478bd9Sstevel@tonic-gate 	_check_services(sl);
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	mntflags |= MS_DATA | MS_OPTIONSTR;
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	if (mflg)
721*7c478bd9Sstevel@tonic-gate 		mntflags |= MS_NOMNTTAB;
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	if (!qflg)
724*7c478bd9Sstevel@tonic-gate 		saveopts = strdup(mntp->mnt_mntopts);
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	if (mount(mntp->mnt_special, mntp->mnt_mountp, mntflags, fstype, args,
727*7c478bd9Sstevel@tonic-gate 		sizeof (*args), mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) {
728*7c478bd9Sstevel@tonic-gate 		if (errno != ENOENT) {
729*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("mount: %s: %s\n"),
730*7c478bd9Sstevel@tonic-gate 				mntp->mnt_mountp, strerror(errno));
731*7c478bd9Sstevel@tonic-gate 		} else {
732*7c478bd9Sstevel@tonic-gate 			struct stat sb;
733*7c478bd9Sstevel@tonic-gate 			if (stat(mntp->mnt_mountp, &sb) < 0 && errno == ENOENT)
734*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("mount: %s: %s\n"),
735*7c478bd9Sstevel@tonic-gate 					mntp->mnt_mountp, strerror(ENOENT));
736*7c478bd9Sstevel@tonic-gate 			else
737*7c478bd9Sstevel@tonic-gate 				pr_err("%s: %s\n", mntp->mnt_special,
738*7c478bd9Sstevel@tonic-gate 					strerror(ENOENT));
739*7c478bd9Sstevel@tonic-gate 		}
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 		last_error = RET_ERR;
742*7c478bd9Sstevel@tonic-gate 		goto out;
743*7c478bd9Sstevel@tonic-gate 	}
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 	if (!qflg && saveopts != NULL) {
746*7c478bd9Sstevel@tonic-gate 		cmp_requested_to_actual_options(saveopts, mntp->mnt_mntopts,
747*7c478bd9Sstevel@tonic-gate 		    mntp->mnt_special, mntp->mnt_mountp);
748*7c478bd9Sstevel@tonic-gate 	}
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate out:
751*7c478bd9Sstevel@tonic-gate 	if (saveopts != NULL)
752*7c478bd9Sstevel@tonic-gate 		free(saveopts);
753*7c478bd9Sstevel@tonic-gate 	if (special != NULL)
754*7c478bd9Sstevel@tonic-gate 		free(special);
755*7c478bd9Sstevel@tonic-gate 	if (oldpath != NULL)
756*7c478bd9Sstevel@tonic-gate 		free(oldpath);
757*7c478bd9Sstevel@tonic-gate 	if (newpath != NULL)
758*7c478bd9Sstevel@tonic-gate 		free(newpath);
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 	free_replica(list, n);
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	if (argp != NULL) {
763*7c478bd9Sstevel@tonic-gate 		/*
764*7c478bd9Sstevel@tonic-gate 		 * If we had a new entry which was not added to the
765*7c478bd9Sstevel@tonic-gate 		 * list yet, then add it now that it can be freed.
766*7c478bd9Sstevel@tonic-gate 		 */
767*7c478bd9Sstevel@tonic-gate 		if (prev_argp == NULL)
768*7c478bd9Sstevel@tonic-gate 			args = argp;
769*7c478bd9Sstevel@tonic-gate 		else
770*7c478bd9Sstevel@tonic-gate 			prev_argp->nfs_ext_u.nfs_extB.next = argp;
771*7c478bd9Sstevel@tonic-gate 	}
772*7c478bd9Sstevel@tonic-gate 	argp = args;
773*7c478bd9Sstevel@tonic-gate 	while (argp != NULL) {
774*7c478bd9Sstevel@tonic-gate 		if (argp->fh)
775*7c478bd9Sstevel@tonic-gate 			free(argp->fh);
776*7c478bd9Sstevel@tonic-gate 		if (argp->pathconf)
777*7c478bd9Sstevel@tonic-gate 			free(argp->pathconf);
778*7c478bd9Sstevel@tonic-gate 		if (argp->knconf)
779*7c478bd9Sstevel@tonic-gate 			free(argp->knconf);
780*7c478bd9Sstevel@tonic-gate 		if (argp->addr) {
781*7c478bd9Sstevel@tonic-gate 			free(argp->addr->buf);
782*7c478bd9Sstevel@tonic-gate 			free(argp->addr);
783*7c478bd9Sstevel@tonic-gate 		}
784*7c478bd9Sstevel@tonic-gate 		nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata);
785*7c478bd9Sstevel@tonic-gate 		if (argp->syncaddr) {
786*7c478bd9Sstevel@tonic-gate 			free(argp->syncaddr->buf);
787*7c478bd9Sstevel@tonic-gate 			free(argp->syncaddr);
788*7c478bd9Sstevel@tonic-gate 		}
789*7c478bd9Sstevel@tonic-gate 		if (argp->netname)
790*7c478bd9Sstevel@tonic-gate 			free(argp->netname);
791*7c478bd9Sstevel@tonic-gate 		prev_argp = argp;
792*7c478bd9Sstevel@tonic-gate 		argp = argp->nfs_ext_u.nfs_extB.next;
793*7c478bd9Sstevel@tonic-gate 		free(prev_argp);
794*7c478bd9Sstevel@tonic-gate 	}
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	return (last_error);
797*7c478bd9Sstevel@tonic-gate }
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate /*
800*7c478bd9Sstevel@tonic-gate  * These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c
801*7c478bd9Sstevel@tonic-gate  * Changes must be made to both lists.
802*7c478bd9Sstevel@tonic-gate  */
803*7c478bd9Sstevel@tonic-gate static char *optlist[] = {
804*7c478bd9Sstevel@tonic-gate #define	OPT_RO		0
805*7c478bd9Sstevel@tonic-gate 	MNTOPT_RO,
806*7c478bd9Sstevel@tonic-gate #define	OPT_RW		1
807*7c478bd9Sstevel@tonic-gate 	MNTOPT_RW,
808*7c478bd9Sstevel@tonic-gate #define	OPT_QUOTA	2
809*7c478bd9Sstevel@tonic-gate 	MNTOPT_QUOTA,
810*7c478bd9Sstevel@tonic-gate #define	OPT_NOQUOTA	3
811*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOQUOTA,
812*7c478bd9Sstevel@tonic-gate #define	OPT_SOFT	4
813*7c478bd9Sstevel@tonic-gate 	MNTOPT_SOFT,
814*7c478bd9Sstevel@tonic-gate #define	OPT_HARD	5
815*7c478bd9Sstevel@tonic-gate 	MNTOPT_HARD,
816*7c478bd9Sstevel@tonic-gate #define	OPT_SUID	6
817*7c478bd9Sstevel@tonic-gate 	MNTOPT_SUID,
818*7c478bd9Sstevel@tonic-gate #define	OPT_NOSUID	7
819*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOSUID,
820*7c478bd9Sstevel@tonic-gate #define	OPT_GRPID	8
821*7c478bd9Sstevel@tonic-gate 	MNTOPT_GRPID,
822*7c478bd9Sstevel@tonic-gate #define	OPT_REMOUNT	9
823*7c478bd9Sstevel@tonic-gate 	MNTOPT_REMOUNT,
824*7c478bd9Sstevel@tonic-gate #define	OPT_NOSUB	10
825*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOSUB,
826*7c478bd9Sstevel@tonic-gate #define	OPT_INTR	11
827*7c478bd9Sstevel@tonic-gate 	MNTOPT_INTR,
828*7c478bd9Sstevel@tonic-gate #define	OPT_NOINTR	12
829*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOINTR,
830*7c478bd9Sstevel@tonic-gate #define	OPT_PORT	13
831*7c478bd9Sstevel@tonic-gate 	MNTOPT_PORT,
832*7c478bd9Sstevel@tonic-gate #define	OPT_SECURE	14
833*7c478bd9Sstevel@tonic-gate 	MNTOPT_SECURE,
834*7c478bd9Sstevel@tonic-gate #define	OPT_RSIZE	15
835*7c478bd9Sstevel@tonic-gate 	MNTOPT_RSIZE,
836*7c478bd9Sstevel@tonic-gate #define	OPT_WSIZE	16
837*7c478bd9Sstevel@tonic-gate 	MNTOPT_WSIZE,
838*7c478bd9Sstevel@tonic-gate #define	OPT_TIMEO	17
839*7c478bd9Sstevel@tonic-gate 	MNTOPT_TIMEO,
840*7c478bd9Sstevel@tonic-gate #define	OPT_RETRANS	18
841*7c478bd9Sstevel@tonic-gate 	MNTOPT_RETRANS,
842*7c478bd9Sstevel@tonic-gate #define	OPT_ACTIMEO	19
843*7c478bd9Sstevel@tonic-gate 	MNTOPT_ACTIMEO,
844*7c478bd9Sstevel@tonic-gate #define	OPT_ACREGMIN	20
845*7c478bd9Sstevel@tonic-gate 	MNTOPT_ACREGMIN,
846*7c478bd9Sstevel@tonic-gate #define	OPT_ACREGMAX	21
847*7c478bd9Sstevel@tonic-gate 	MNTOPT_ACREGMAX,
848*7c478bd9Sstevel@tonic-gate #define	OPT_ACDIRMIN	22
849*7c478bd9Sstevel@tonic-gate 	MNTOPT_ACDIRMIN,
850*7c478bd9Sstevel@tonic-gate #define	OPT_ACDIRMAX	23
851*7c478bd9Sstevel@tonic-gate 	MNTOPT_ACDIRMAX,
852*7c478bd9Sstevel@tonic-gate #define	OPT_BG		24
853*7c478bd9Sstevel@tonic-gate 	MNTOPT_BG,
854*7c478bd9Sstevel@tonic-gate #define	OPT_FG		25
855*7c478bd9Sstevel@tonic-gate 	MNTOPT_FG,
856*7c478bd9Sstevel@tonic-gate #define	OPT_RETRY	26
857*7c478bd9Sstevel@tonic-gate 	MNTOPT_RETRY,
858*7c478bd9Sstevel@tonic-gate #define	OPT_NOAC	27
859*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOAC,
860*7c478bd9Sstevel@tonic-gate #define	OPT_NOCTO	28
861*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOCTO,
862*7c478bd9Sstevel@tonic-gate #define	OPT_LLOCK	29
863*7c478bd9Sstevel@tonic-gate 	MNTOPT_LLOCK,
864*7c478bd9Sstevel@tonic-gate #define	OPT_POSIX	30
865*7c478bd9Sstevel@tonic-gate 	MNTOPT_POSIX,
866*7c478bd9Sstevel@tonic-gate #define	OPT_VERS	31
867*7c478bd9Sstevel@tonic-gate 	MNTOPT_VERS,
868*7c478bd9Sstevel@tonic-gate #define	OPT_PROTO	32
869*7c478bd9Sstevel@tonic-gate 	MNTOPT_PROTO,
870*7c478bd9Sstevel@tonic-gate #define	OPT_SEMISOFT	33
871*7c478bd9Sstevel@tonic-gate 	MNTOPT_SEMISOFT,
872*7c478bd9Sstevel@tonic-gate #define	OPT_NOPRINT	34
873*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOPRINT,
874*7c478bd9Sstevel@tonic-gate #define	OPT_SEC		35
875*7c478bd9Sstevel@tonic-gate 	MNTOPT_SEC,
876*7c478bd9Sstevel@tonic-gate #define	OPT_LARGEFILES	36
877*7c478bd9Sstevel@tonic-gate 	MNTOPT_LARGEFILES,
878*7c478bd9Sstevel@tonic-gate #define	OPT_NOLARGEFILES 37
879*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOLARGEFILES,
880*7c478bd9Sstevel@tonic-gate #define	OPT_PUBLIC	38
881*7c478bd9Sstevel@tonic-gate 	MNTOPT_PUBLIC,
882*7c478bd9Sstevel@tonic-gate #define	OPT_DIRECTIO	39
883*7c478bd9Sstevel@tonic-gate 	MNTOPT_FORCEDIRECTIO,
884*7c478bd9Sstevel@tonic-gate #define	OPT_NODIRECTIO	40
885*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOFORCEDIRECTIO,
886*7c478bd9Sstevel@tonic-gate #define	OPT_XATTR	41
887*7c478bd9Sstevel@tonic-gate 	MNTOPT_XATTR,
888*7c478bd9Sstevel@tonic-gate #define	OPT_NOXATTR	42
889*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOXATTR,
890*7c478bd9Sstevel@tonic-gate #define	OPT_DEVICES	43
891*7c478bd9Sstevel@tonic-gate 	MNTOPT_DEVICES,
892*7c478bd9Sstevel@tonic-gate #define	OPT_NODEVICES	44
893*7c478bd9Sstevel@tonic-gate 	MNTOPT_NODEVICES,
894*7c478bd9Sstevel@tonic-gate #define	OPT_SETUID	45
895*7c478bd9Sstevel@tonic-gate 	MNTOPT_SETUID,
896*7c478bd9Sstevel@tonic-gate #define	OPT_NOSETUID	46
897*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOSETUID,
898*7c478bd9Sstevel@tonic-gate #define	OPT_EXEC	47
899*7c478bd9Sstevel@tonic-gate 	MNTOPT_EXEC,
900*7c478bd9Sstevel@tonic-gate #define	OPT_NOEXEC	48
901*7c478bd9Sstevel@tonic-gate 	MNTOPT_NOEXEC,
902*7c478bd9Sstevel@tonic-gate 	NULL
903*7c478bd9Sstevel@tonic-gate };
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate #define	bad(val) (val == NULL || !isdigit(*val))
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate static int
908*7c478bd9Sstevel@tonic-gate set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt)
909*7c478bd9Sstevel@tonic-gate {
910*7c478bd9Sstevel@tonic-gate 	char *saveopt, *optstr, *opts, *newopts, *val;
911*7c478bd9Sstevel@tonic-gate 	int largefiles = 0;
912*7c478bd9Sstevel@tonic-gate 	int invalid = 0;
913*7c478bd9Sstevel@tonic-gate 	int attrpref = 0;
914*7c478bd9Sstevel@tonic-gate 	int optlen;
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	args->flags = NFSMNT_INT;	/* default is "intr" */
917*7c478bd9Sstevel@tonic-gate 	args->flags |= NFSMNT_HOSTNAME;
918*7c478bd9Sstevel@tonic-gate 	args->flags |= NFSMNT_NEWARGS;	/* using extented nfs_args structure */
919*7c478bd9Sstevel@tonic-gate 	args->hostname = fshost;
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	optstr = opts = strdup(mnt->mnt_mntopts);
922*7c478bd9Sstevel@tonic-gate 	/* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */
923*7c478bd9Sstevel@tonic-gate 	optlen = strlen(mnt->mnt_mntopts) + sizeof (MNTOPT_XATTR) + 1;
924*7c478bd9Sstevel@tonic-gate 	if (optlen > MAX_MNTOPT_STR) {
925*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("option string too long"));
926*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
927*7c478bd9Sstevel@tonic-gate 	}
928*7c478bd9Sstevel@tonic-gate 	newopts = malloc(optlen);
929*7c478bd9Sstevel@tonic-gate 	if (opts == NULL || newopts == NULL) {
930*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("no memory"));
931*7c478bd9Sstevel@tonic-gate 		if (opts)
932*7c478bd9Sstevel@tonic-gate 			free(opts);
933*7c478bd9Sstevel@tonic-gate 		if (newopts)
934*7c478bd9Sstevel@tonic-gate 			free(newopts);
935*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
936*7c478bd9Sstevel@tonic-gate 	}
937*7c478bd9Sstevel@tonic-gate 	newopts[0] = '\0';
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	while (*opts) {
940*7c478bd9Sstevel@tonic-gate 		invalid = 0;
941*7c478bd9Sstevel@tonic-gate 		saveopt = opts;
942*7c478bd9Sstevel@tonic-gate 		switch (getsubopt(&opts, optlist, &val)) {
943*7c478bd9Sstevel@tonic-gate 		case OPT_RO:
944*7c478bd9Sstevel@tonic-gate 			*mntflags |= MS_RDONLY;
945*7c478bd9Sstevel@tonic-gate 			break;
946*7c478bd9Sstevel@tonic-gate 		case OPT_RW:
947*7c478bd9Sstevel@tonic-gate 			*mntflags &= ~(MS_RDONLY);
948*7c478bd9Sstevel@tonic-gate 			break;
949*7c478bd9Sstevel@tonic-gate 		case OPT_QUOTA:
950*7c478bd9Sstevel@tonic-gate 		case OPT_NOQUOTA:
951*7c478bd9Sstevel@tonic-gate 			break;
952*7c478bd9Sstevel@tonic-gate 		case OPT_SOFT:
953*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_SOFT;
954*7c478bd9Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_SEMISOFT);
955*7c478bd9Sstevel@tonic-gate 			break;
956*7c478bd9Sstevel@tonic-gate 		case OPT_SEMISOFT:
957*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_SOFT;
958*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_SEMISOFT;
959*7c478bd9Sstevel@tonic-gate 			break;
960*7c478bd9Sstevel@tonic-gate 		case OPT_HARD:
961*7c478bd9Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_SOFT);
962*7c478bd9Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_SEMISOFT);
963*7c478bd9Sstevel@tonic-gate 			break;
964*7c478bd9Sstevel@tonic-gate 		case OPT_SUID:
965*7c478bd9Sstevel@tonic-gate 			*mntflags &= ~(MS_NOSUID);
966*7c478bd9Sstevel@tonic-gate 			break;
967*7c478bd9Sstevel@tonic-gate 		case OPT_NOSUID:
968*7c478bd9Sstevel@tonic-gate 			*mntflags |= MS_NOSUID;
969*7c478bd9Sstevel@tonic-gate 			break;
970*7c478bd9Sstevel@tonic-gate 		case OPT_GRPID:
971*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_GRPID;
972*7c478bd9Sstevel@tonic-gate 			break;
973*7c478bd9Sstevel@tonic-gate 		case OPT_REMOUNT:
974*7c478bd9Sstevel@tonic-gate 			*mntflags |= MS_REMOUNT;
975*7c478bd9Sstevel@tonic-gate 			break;
976*7c478bd9Sstevel@tonic-gate 		case OPT_INTR:
977*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_INT;
978*7c478bd9Sstevel@tonic-gate 			break;
979*7c478bd9Sstevel@tonic-gate 		case OPT_NOINTR:
980*7c478bd9Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_INT);
981*7c478bd9Sstevel@tonic-gate 			break;
982*7c478bd9Sstevel@tonic-gate 		case OPT_NOAC:
983*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_NOAC;
984*7c478bd9Sstevel@tonic-gate 			break;
985*7c478bd9Sstevel@tonic-gate 		case OPT_PORT:
986*7c478bd9Sstevel@tonic-gate 			if (bad(val))
987*7c478bd9Sstevel@tonic-gate 				goto badopt;
988*7c478bd9Sstevel@tonic-gate 			nfs_port = htons((ushort_t)atoi(val));
989*7c478bd9Sstevel@tonic-gate 			break;
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 		case OPT_SECURE:
992*7c478bd9Sstevel@tonic-gate 			if (nfs_getseconfig_byname("dh", &nfs_sec)) {
993*7c478bd9Sstevel@tonic-gate 			    pr_err(gettext("can not get \"dh\" from %s\n"),
994*7c478bd9Sstevel@tonic-gate 						NFSSEC_CONF);
995*7c478bd9Sstevel@tonic-gate 			    goto badopt;
996*7c478bd9Sstevel@tonic-gate 			}
997*7c478bd9Sstevel@tonic-gate 			sec_opt++;
998*7c478bd9Sstevel@tonic-gate 			break;
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 		case OPT_NOCTO:
1001*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_NOCTO;
1002*7c478bd9Sstevel@tonic-gate 			break;
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 		case OPT_RSIZE:
1005*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_RSIZE;
1006*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1007*7c478bd9Sstevel@tonic-gate 				goto badopt;
1008*7c478bd9Sstevel@tonic-gate 			args->rsize = atoi(val);
1009*7c478bd9Sstevel@tonic-gate 			break;
1010*7c478bd9Sstevel@tonic-gate 		case OPT_WSIZE:
1011*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_WSIZE;
1012*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1013*7c478bd9Sstevel@tonic-gate 				goto badopt;
1014*7c478bd9Sstevel@tonic-gate 			args->wsize = atoi(val);
1015*7c478bd9Sstevel@tonic-gate 			break;
1016*7c478bd9Sstevel@tonic-gate 		case OPT_TIMEO:
1017*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_TIMEO;
1018*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1019*7c478bd9Sstevel@tonic-gate 				goto badopt;
1020*7c478bd9Sstevel@tonic-gate 			args->timeo = atoi(val);
1021*7c478bd9Sstevel@tonic-gate 			break;
1022*7c478bd9Sstevel@tonic-gate 		case OPT_RETRANS:
1023*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_RETRANS;
1024*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1025*7c478bd9Sstevel@tonic-gate 				goto badopt;
1026*7c478bd9Sstevel@tonic-gate 			args->retrans = atoi(val);
1027*7c478bd9Sstevel@tonic-gate 			break;
1028*7c478bd9Sstevel@tonic-gate 		case OPT_ACTIMEO:
1029*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMAX;
1030*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMAX;
1031*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMIN;
1032*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMIN;
1033*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1034*7c478bd9Sstevel@tonic-gate 				goto badopt;
1035*7c478bd9Sstevel@tonic-gate 			args->acdirmin = args->acregmin = args->acdirmax
1036*7c478bd9Sstevel@tonic-gate 				= args->acregmax = atoi(val);
1037*7c478bd9Sstevel@tonic-gate 			break;
1038*7c478bd9Sstevel@tonic-gate 		case OPT_ACREGMIN:
1039*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMIN;
1040*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1041*7c478bd9Sstevel@tonic-gate 				goto badopt;
1042*7c478bd9Sstevel@tonic-gate 			args->acregmin = atoi(val);
1043*7c478bd9Sstevel@tonic-gate 			break;
1044*7c478bd9Sstevel@tonic-gate 		case OPT_ACREGMAX:
1045*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMAX;
1046*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1047*7c478bd9Sstevel@tonic-gate 				goto badopt;
1048*7c478bd9Sstevel@tonic-gate 			args->acregmax = atoi(val);
1049*7c478bd9Sstevel@tonic-gate 			break;
1050*7c478bd9Sstevel@tonic-gate 		case OPT_ACDIRMIN:
1051*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMIN;
1052*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1053*7c478bd9Sstevel@tonic-gate 				goto badopt;
1054*7c478bd9Sstevel@tonic-gate 			args->acdirmin = atoi(val);
1055*7c478bd9Sstevel@tonic-gate 			break;
1056*7c478bd9Sstevel@tonic-gate 		case OPT_ACDIRMAX:
1057*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMAX;
1058*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1059*7c478bd9Sstevel@tonic-gate 				goto badopt;
1060*7c478bd9Sstevel@tonic-gate 			args->acdirmax = atoi(val);
1061*7c478bd9Sstevel@tonic-gate 			break;
1062*7c478bd9Sstevel@tonic-gate 		case OPT_BG:
1063*7c478bd9Sstevel@tonic-gate 			bg++;
1064*7c478bd9Sstevel@tonic-gate 			break;
1065*7c478bd9Sstevel@tonic-gate 		case OPT_FG:
1066*7c478bd9Sstevel@tonic-gate 			bg = 0;
1067*7c478bd9Sstevel@tonic-gate 			break;
1068*7c478bd9Sstevel@tonic-gate 		case OPT_RETRY:
1069*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1070*7c478bd9Sstevel@tonic-gate 				goto badopt;
1071*7c478bd9Sstevel@tonic-gate 			retries = atoi(val);
1072*7c478bd9Sstevel@tonic-gate 			break;
1073*7c478bd9Sstevel@tonic-gate 		case OPT_LLOCK:
1074*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_LLOCK;
1075*7c478bd9Sstevel@tonic-gate 			break;
1076*7c478bd9Sstevel@tonic-gate 		case OPT_POSIX:
1077*7c478bd9Sstevel@tonic-gate 			posix = 1;
1078*7c478bd9Sstevel@tonic-gate 			break;
1079*7c478bd9Sstevel@tonic-gate 		case OPT_VERS:
1080*7c478bd9Sstevel@tonic-gate 			if (bad(val))
1081*7c478bd9Sstevel@tonic-gate 				goto badopt;
1082*7c478bd9Sstevel@tonic-gate 			nfsvers = (rpcvers_t)atoi(val);
1083*7c478bd9Sstevel@tonic-gate 			break;
1084*7c478bd9Sstevel@tonic-gate 		case OPT_PROTO:
1085*7c478bd9Sstevel@tonic-gate 			nfs_proto = (char *)malloc(strlen(val)+1);
1086*7c478bd9Sstevel@tonic-gate 			(void) strcpy(nfs_proto, val);
1087*7c478bd9Sstevel@tonic-gate 			break;
1088*7c478bd9Sstevel@tonic-gate 		case OPT_NOPRINT:
1089*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_NOPRINT;
1090*7c478bd9Sstevel@tonic-gate 			break;
1091*7c478bd9Sstevel@tonic-gate 		case OPT_LARGEFILES:
1092*7c478bd9Sstevel@tonic-gate 			largefiles = 1;
1093*7c478bd9Sstevel@tonic-gate 			break;
1094*7c478bd9Sstevel@tonic-gate 		case OPT_NOLARGEFILES:
1095*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("NFS can't support \"nolargefiles\"\n"));
1096*7c478bd9Sstevel@tonic-gate 			free(optstr);
1097*7c478bd9Sstevel@tonic-gate 			return (RET_ERR);
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 		case OPT_SEC:
1100*7c478bd9Sstevel@tonic-gate 			if (nfs_getseconfig_byname(val, &nfs_sec)) {
1101*7c478bd9Sstevel@tonic-gate 			    pr_err(gettext("can not get \"%s\" from %s\n"),
1102*7c478bd9Sstevel@tonic-gate 						val, NFSSEC_CONF);
1103*7c478bd9Sstevel@tonic-gate 			    return (RET_ERR);
1104*7c478bd9Sstevel@tonic-gate 			}
1105*7c478bd9Sstevel@tonic-gate 			sec_opt++;
1106*7c478bd9Sstevel@tonic-gate 			break;
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate 		case OPT_PUBLIC:
1109*7c478bd9Sstevel@tonic-gate 			public_opt = TRUE;
1110*7c478bd9Sstevel@tonic-gate 			break;
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 		case OPT_DIRECTIO:
1113*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_DIRECTIO;
1114*7c478bd9Sstevel@tonic-gate 			break;
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 		case OPT_NODIRECTIO:
1117*7c478bd9Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_DIRECTIO);
1118*7c478bd9Sstevel@tonic-gate 			break;
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 		case OPT_XATTR:
1121*7c478bd9Sstevel@tonic-gate 		case OPT_NOXATTR:
1122*7c478bd9Sstevel@tonic-gate 			/*
1123*7c478bd9Sstevel@tonic-gate 			 * VFS options; just need to get them into the
1124*7c478bd9Sstevel@tonic-gate 			 * new mount option string and note we've seen them
1125*7c478bd9Sstevel@tonic-gate 			 */
1126*7c478bd9Sstevel@tonic-gate 			attrpref = 1;
1127*7c478bd9Sstevel@tonic-gate 			break;
1128*7c478bd9Sstevel@tonic-gate 		default:
1129*7c478bd9Sstevel@tonic-gate 			/*
1130*7c478bd9Sstevel@tonic-gate 			 * Note that this could be a valid OPT_* option so
1131*7c478bd9Sstevel@tonic-gate 			 * we can't use "val" but need to use "saveopt".
1132*7c478bd9Sstevel@tonic-gate 			 */
1133*7c478bd9Sstevel@tonic-gate 			if (fsisstdopt(saveopt))
1134*7c478bd9Sstevel@tonic-gate 				break;
1135*7c478bd9Sstevel@tonic-gate 			invalid = 1;
1136*7c478bd9Sstevel@tonic-gate 			if (!qflg)
1137*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1138*7c478bd9Sstevel@tonic-gate 				    "mount: %s on %s - WARNING unknown option"
1139*7c478bd9Sstevel@tonic-gate 				    " \"%s\"\n"), mnt->mnt_special,
1140*7c478bd9Sstevel@tonic-gate 				    mnt->mnt_mountp, saveopt);
1141*7c478bd9Sstevel@tonic-gate 			break;
1142*7c478bd9Sstevel@tonic-gate 		}
1143*7c478bd9Sstevel@tonic-gate 		if (!invalid) {
1144*7c478bd9Sstevel@tonic-gate 			if (newopts[0])
1145*7c478bd9Sstevel@tonic-gate 				strcat(newopts, ",");
1146*7c478bd9Sstevel@tonic-gate 			strcat(newopts, saveopt);
1147*7c478bd9Sstevel@tonic-gate 		}
1148*7c478bd9Sstevel@tonic-gate 	}
1149*7c478bd9Sstevel@tonic-gate 	/* Default is to turn extended attrs on */
1150*7c478bd9Sstevel@tonic-gate 	if (!attrpref) {
1151*7c478bd9Sstevel@tonic-gate 		if (newopts[0])
1152*7c478bd9Sstevel@tonic-gate 			strcat(newopts, ",");
1153*7c478bd9Sstevel@tonic-gate 		strcat(newopts, MNTOPT_XATTR);
1154*7c478bd9Sstevel@tonic-gate 	}
1155*7c478bd9Sstevel@tonic-gate 	strcpy(mnt->mnt_mntopts, newopts);
1156*7c478bd9Sstevel@tonic-gate 	free(newopts);
1157*7c478bd9Sstevel@tonic-gate 	free(optstr);
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 	/* ensure that only one secure mode is requested */
1160*7c478bd9Sstevel@tonic-gate 	if (sec_opt > 1) {
1161*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("Security options conflict\n"));
1162*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
1163*7c478bd9Sstevel@tonic-gate 	}
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate 	/* ensure that the user isn't trying to get large files over V2 */
1166*7c478bd9Sstevel@tonic-gate 	if (nfsvers == NFS_VERSION && largefiles) {
1167*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("NFS V2 can't support \"largefiles\"\n"));
1168*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
1169*7c478bd9Sstevel@tonic-gate 	}
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 	if (nfsvers == NFS_V4 &&
1172*7c478bd9Sstevel@tonic-gate 	    nfs_proto != NULL &&
1173*7c478bd9Sstevel@tonic-gate 	    strncasecmp(nfs_proto, NC_UDP, strlen(NC_UDP)) == 0) {
1174*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto);
1175*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
1176*7c478bd9Sstevel@tonic-gate 	}
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate 	return (RET_OK);
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate badopt:
1181*7c478bd9Sstevel@tonic-gate 	pr_err(gettext("invalid option: \"%s\"\n"), saveopt);
1182*7c478bd9Sstevel@tonic-gate 	free(optstr);
1183*7c478bd9Sstevel@tonic-gate 	return (RET_ERR);
1184*7c478bd9Sstevel@tonic-gate }
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate static int
1187*7c478bd9Sstevel@tonic-gate make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf,
1188*7c478bd9Sstevel@tonic-gate 	bool_t use_pubfh, rpcvers_t vers)
1189*7c478bd9Sstevel@tonic-gate {
1190*7c478bd9Sstevel@tonic-gate 	sec_data_t *secdata;
1191*7c478bd9Sstevel@tonic-gate 	int flags;
1192*7c478bd9Sstevel@tonic-gate 	struct netbuf *syncaddr = NULL;
1193*7c478bd9Sstevel@tonic-gate 	struct nd_addrlist *retaddrs = NULL;
1194*7c478bd9Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 	/*
1197*7c478bd9Sstevel@tonic-gate 	 * check to see if any secure mode is requested.
1198*7c478bd9Sstevel@tonic-gate 	 * if not, use default security mode.
1199*7c478bd9Sstevel@tonic-gate 	 */
1200*7c478bd9Sstevel@tonic-gate 	if (!snego_done && !sec_opt) {
1201*7c478bd9Sstevel@tonic-gate 		/*
1202*7c478bd9Sstevel@tonic-gate 		 *  Get default security mode.
1203*7c478bd9Sstevel@tonic-gate 		 *  AUTH_UNIX has been the default choice for a long time.
1204*7c478bd9Sstevel@tonic-gate 		 *  The better NFS security service becomes, the better chance
1205*7c478bd9Sstevel@tonic-gate 		 *  we will set stronger security service as the default NFS
1206*7c478bd9Sstevel@tonic-gate 		 *  security mode.
1207*7c478bd9Sstevel@tonic-gate 		 *
1208*7c478bd9Sstevel@tonic-gate 		 */
1209*7c478bd9Sstevel@tonic-gate 	    if (nfs_getseconfig_default(&nfs_sec)) {
1210*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("error getting default security entry\n"));
1211*7c478bd9Sstevel@tonic-gate 		return (-1);
1212*7c478bd9Sstevel@tonic-gate 	    }
1213*7c478bd9Sstevel@tonic-gate 	    args->flags |= NFSMNT_SECDEFAULT;
1214*7c478bd9Sstevel@tonic-gate 	}
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 	/*
1217*7c478bd9Sstevel@tonic-gate 	 * Get the network address for the time service on the server.
1218*7c478bd9Sstevel@tonic-gate 	 * If an RPC based time service is not available then try the
1219*7c478bd9Sstevel@tonic-gate 	 * IP time service.
1220*7c478bd9Sstevel@tonic-gate 	 *
1221*7c478bd9Sstevel@tonic-gate 	 * This is for AUTH_DH processing. We will also pass down syncaddr
1222*7c478bd9Sstevel@tonic-gate 	 * and netname for NFS V4 even if AUTH_DH is not requested right now.
1223*7c478bd9Sstevel@tonic-gate 	 * NFS V4 does security negotiation in the kernel via SECINFO.
1224*7c478bd9Sstevel@tonic-gate 	 * These information might be needed later in the kernel.
1225*7c478bd9Sstevel@tonic-gate 	 *
1226*7c478bd9Sstevel@tonic-gate 	 * Eventurally, we want to move this code to nfs_clnt_secdata()
1227*7c478bd9Sstevel@tonic-gate 	 * when autod_nfs.c and mount.c can share the same get_the_addr()
1228*7c478bd9Sstevel@tonic-gate 	 * routine.
1229*7c478bd9Sstevel@tonic-gate 	 */
1230*7c478bd9Sstevel@tonic-gate 	flags = 0;
1231*7c478bd9Sstevel@tonic-gate 	syncaddr = NULL;
1232*7c478bd9Sstevel@tonic-gate 
1233*7c478bd9Sstevel@tonic-gate 	if (nfs_sec.sc_rpcnum == AUTH_DH || vers == NFS_V4) {
1234*7c478bd9Sstevel@tonic-gate 		/*
1235*7c478bd9Sstevel@tonic-gate 		 * If using the public fh or nfsv4, we will not contact the
1236*7c478bd9Sstevel@tonic-gate 		 * remote RPCBINDer, since it is possibly behind a firewall.
1237*7c478bd9Sstevel@tonic-gate 		 */
1238*7c478bd9Sstevel@tonic-gate 		if (use_pubfh == FALSE && vers != NFS_V4) {
1239*7c478bd9Sstevel@tonic-gate 			syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS,
1240*7c478bd9Sstevel@tonic-gate 				nconf, 0, NULL, NULL, FALSE, NULL, NULL);
1241*7c478bd9Sstevel@tonic-gate 		}
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 		if (syncaddr != NULL) {
1244*7c478bd9Sstevel@tonic-gate 			/* for flags in sec_data */
1245*7c478bd9Sstevel@tonic-gate 			flags |= AUTH_F_RPCTIMESYNC;
1246*7c478bd9Sstevel@tonic-gate 		} else {
1247*7c478bd9Sstevel@tonic-gate 			struct nd_hostserv hs;
1248*7c478bd9Sstevel@tonic-gate 			int error;
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 			hs.h_host = hostname;
1251*7c478bd9Sstevel@tonic-gate 			hs.h_serv = "timserver";
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 			error = netdir_getbyname(nconf, &hs, &retaddrs);
1254*7c478bd9Sstevel@tonic-gate 
1255*7c478bd9Sstevel@tonic-gate 			if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) {
1256*7c478bd9Sstevel@tonic-gate 			    pr_err(gettext("%s: secure: no time service\n"),
1257*7c478bd9Sstevel@tonic-gate 						hostname);
1258*7c478bd9Sstevel@tonic-gate 			    return (-1);
1259*7c478bd9Sstevel@tonic-gate 			}
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate 			if (error == ND_OK)
1262*7c478bd9Sstevel@tonic-gate 				syncaddr = retaddrs->n_addrs;
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 			/*
1265*7c478bd9Sstevel@tonic-gate 			 * For NFS_V4 if AUTH_DH is negotiated later in the
1266*7c478bd9Sstevel@tonic-gate 			 * kernel thru SECINFO, it will need syncaddr
1267*7c478bd9Sstevel@tonic-gate 			 * and netname data.
1268*7c478bd9Sstevel@tonic-gate 			 */
1269*7c478bd9Sstevel@tonic-gate 			if (vers == NFS_V4 && syncaddr &&
1270*7c478bd9Sstevel@tonic-gate 				    host2netname(netname, hostname, NULL)) {
1271*7c478bd9Sstevel@tonic-gate 			    args->syncaddr = malloc(sizeof (struct netbuf));
1272*7c478bd9Sstevel@tonic-gate 			    args->syncaddr->buf = malloc(syncaddr->len);
1273*7c478bd9Sstevel@tonic-gate 			    (void) memcpy(args->syncaddr->buf, syncaddr->buf,
1274*7c478bd9Sstevel@tonic-gate 							syncaddr->len);
1275*7c478bd9Sstevel@tonic-gate 			    args->syncaddr->len = syncaddr->len;
1276*7c478bd9Sstevel@tonic-gate 			    args->syncaddr->maxlen = syncaddr->maxlen;
1277*7c478bd9Sstevel@tonic-gate 			    args->netname = strdup(netname);
1278*7c478bd9Sstevel@tonic-gate 			    args->flags |= NFSMNT_SECURE;
1279*7c478bd9Sstevel@tonic-gate 			}
1280*7c478bd9Sstevel@tonic-gate 		}
1281*7c478bd9Sstevel@tonic-gate 	}
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	/*
1284*7c478bd9Sstevel@tonic-gate 	 * For the initial chosen flavor (any flavor defined in nfssec.conf),
1285*7c478bd9Sstevel@tonic-gate 	 * the data will be stored in the sec_data structure via
1286*7c478bd9Sstevel@tonic-gate 	 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
1287*7c478bd9Sstevel@tonic-gate 	 * extended data structure.
1288*7c478bd9Sstevel@tonic-gate 	 */
1289*7c478bd9Sstevel@tonic-gate 	if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf,
1290*7c478bd9Sstevel@tonic-gate 					syncaddr, flags))) {
1291*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("errors constructing security related data\n"));
1292*7c478bd9Sstevel@tonic-gate 		if (flags & AUTH_F_RPCTIMESYNC) {
1293*7c478bd9Sstevel@tonic-gate 			free(syncaddr->buf);
1294*7c478bd9Sstevel@tonic-gate 			free(syncaddr);
1295*7c478bd9Sstevel@tonic-gate 		} else if (retaddrs)
1296*7c478bd9Sstevel@tonic-gate 			netdir_free((void *)retaddrs, ND_ADDRLIST);
1297*7c478bd9Sstevel@tonic-gate 		return (-1);
1298*7c478bd9Sstevel@tonic-gate 	}
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 	NFS_ARGS_EXTB_secdata(args, secdata);
1301*7c478bd9Sstevel@tonic-gate 	if (flags & AUTH_F_RPCTIMESYNC) {
1302*7c478bd9Sstevel@tonic-gate 		free(syncaddr->buf);
1303*7c478bd9Sstevel@tonic-gate 		free(syncaddr);
1304*7c478bd9Sstevel@tonic-gate 	} else if (retaddrs)
1305*7c478bd9Sstevel@tonic-gate 		netdir_free((void *)retaddrs, ND_ADDRLIST);
1306*7c478bd9Sstevel@tonic-gate 	return (0);
1307*7c478bd9Sstevel@tonic-gate }
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate /*
1310*7c478bd9Sstevel@tonic-gate  * Get the network address on "hostname" for program "prog"
1311*7c478bd9Sstevel@tonic-gate  * with version "vers" by using the nconf configuration data
1312*7c478bd9Sstevel@tonic-gate  * passed in.
1313*7c478bd9Sstevel@tonic-gate  *
1314*7c478bd9Sstevel@tonic-gate  * If the address of a netconfig pointer is null then
1315*7c478bd9Sstevel@tonic-gate  * information is not sufficient and no netbuf will be returned.
1316*7c478bd9Sstevel@tonic-gate  *
1317*7c478bd9Sstevel@tonic-gate  * Finally, ping the null procedure of that service.
1318*7c478bd9Sstevel@tonic-gate  *
1319*7c478bd9Sstevel@tonic-gate  * A similar routine is also defined in ../../autofs/autod_nfs.c.
1320*7c478bd9Sstevel@tonic-gate  * This is a potential routine to move to ../lib for common usage.
1321*7c478bd9Sstevel@tonic-gate  */
1322*7c478bd9Sstevel@tonic-gate static struct netbuf *
1323*7c478bd9Sstevel@tonic-gate get_the_addr(char *hostname, ulong_t prog, ulong_t vers,
1324*7c478bd9Sstevel@tonic-gate 	struct netconfig *nconf, ushort_t port, struct t_info *tinfo,
1325*7c478bd9Sstevel@tonic-gate 	caddr_t *fhp, bool_t get_pubfh, char *fspath, err_ret_t *error)
1326*7c478bd9Sstevel@tonic-gate {
1327*7c478bd9Sstevel@tonic-gate 	struct netbuf *nb = NULL;
1328*7c478bd9Sstevel@tonic-gate 	struct t_bind *tbind = NULL;
1329*7c478bd9Sstevel@tonic-gate 	CLIENT *cl = NULL;
1330*7c478bd9Sstevel@tonic-gate 	struct timeval tv;
1331*7c478bd9Sstevel@tonic-gate 	int fd = -1;
1332*7c478bd9Sstevel@tonic-gate 	AUTH *ah = NULL;
1333*7c478bd9Sstevel@tonic-gate 	AUTH *new_ah = NULL;
1334*7c478bd9Sstevel@tonic-gate 	struct snego_t snego;
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 	if (nconf == NULL)
1337*7c478bd9Sstevel@tonic-gate 		return (NULL);
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 	if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1)
1340*7c478bd9Sstevel@tonic-gate 		    goto done;
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer alignment */
1343*7c478bd9Sstevel@tonic-gate 	if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
1344*7c478bd9Sstevel@tonic-gate 		== NULL)
1345*7c478bd9Sstevel@tonic-gate 		goto done;
1346*7c478bd9Sstevel@tonic-gate 
1347*7c478bd9Sstevel@tonic-gate 	/*
1348*7c478bd9Sstevel@tonic-gate 	 * In the case of public filehandle usage or NFSv4 we want to
1349*7c478bd9Sstevel@tonic-gate 	 * avoid use of the rpcbind/portmap protocol
1350*7c478bd9Sstevel@tonic-gate 	 */
1351*7c478bd9Sstevel@tonic-gate 	if ((get_pubfh == TRUE) || (vers == NFS_V4)) {
1352*7c478bd9Sstevel@tonic-gate 		struct nd_hostserv hs;
1353*7c478bd9Sstevel@tonic-gate 		struct nd_addrlist *retaddrs;
1354*7c478bd9Sstevel@tonic-gate 		int retval;
1355*7c478bd9Sstevel@tonic-gate 		hs.h_host = hostname;
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 		/* NFS where vers==4 does not support UDP */
1358*7c478bd9Sstevel@tonic-gate 		if (vers == NFS_V4 &&
1359*7c478bd9Sstevel@tonic-gate 		    strncasecmp(nconf->nc_proto, NC_UDP,
1360*7c478bd9Sstevel@tonic-gate 				strlen(NC_UDP)) == 0) {
1361*7c478bd9Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_RPCERROR, 0);
1362*7c478bd9Sstevel@tonic-gate 			goto done;
1363*7c478bd9Sstevel@tonic-gate 		}
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate 		if (port == 0)
1366*7c478bd9Sstevel@tonic-gate 			hs.h_serv = "nfs";
1367*7c478bd9Sstevel@tonic-gate 		else
1368*7c478bd9Sstevel@tonic-gate 			hs.h_serv = NULL;
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 		if ((retval = netdir_getbyname(nconf, &hs, &retaddrs))
1371*7c478bd9Sstevel@tonic-gate 		    != ND_OK) {
1372*7c478bd9Sstevel@tonic-gate 			/*
1373*7c478bd9Sstevel@tonic-gate 			 * Carefully set the error value here. Want to signify
1374*7c478bd9Sstevel@tonic-gate 			 * that the error was an unknown host.
1375*7c478bd9Sstevel@tonic-gate 			 */
1376*7c478bd9Sstevel@tonic-gate 			if (retval == ND_NOHOST) {
1377*7c478bd9Sstevel@tonic-gate 				SET_ERR_RET(error, ERR_NOHOST, retval);
1378*7c478bd9Sstevel@tonic-gate 			}
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 			goto done;
1381*7c478bd9Sstevel@tonic-gate 		}
1382*7c478bd9Sstevel@tonic-gate 		memcpy(tbind->addr.buf, retaddrs->n_addrs->buf,
1383*7c478bd9Sstevel@tonic-gate 			retaddrs->n_addrs->len);
1384*7c478bd9Sstevel@tonic-gate 		tbind->addr.len = retaddrs->n_addrs->len;
1385*7c478bd9Sstevel@tonic-gate 		netdir_free((void *)retaddrs, ND_ADDRLIST);
1386*7c478bd9Sstevel@tonic-gate 		(void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL);
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 	} else {
1389*7c478bd9Sstevel@tonic-gate 		if (rpcb_getaddr(prog, vers, nconf, &tbind->addr,
1390*7c478bd9Sstevel@tonic-gate 		    hostname) == FALSE) {
1391*7c478bd9Sstevel@tonic-gate 			goto done;
1392*7c478bd9Sstevel@tonic-gate 		}
1393*7c478bd9Sstevel@tonic-gate 	}
1394*7c478bd9Sstevel@tonic-gate 
1395*7c478bd9Sstevel@tonic-gate 	if (port) {
1396*7c478bd9Sstevel@tonic-gate 		/* LINTED pointer alignment */
1397*7c478bd9Sstevel@tonic-gate 		if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
1398*7c478bd9Sstevel@tonic-gate 			((struct sockaddr_in *)tbind->addr.buf)->sin_port
1399*7c478bd9Sstevel@tonic-gate 				= port;
1400*7c478bd9Sstevel@tonic-gate 		else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
1401*7c478bd9Sstevel@tonic-gate 			((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port
1402*7c478bd9Sstevel@tonic-gate 				= port;
1403*7c478bd9Sstevel@tonic-gate 
1404*7c478bd9Sstevel@tonic-gate 	}
1405*7c478bd9Sstevel@tonic-gate 
1406*7c478bd9Sstevel@tonic-gate 	cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
1407*7c478bd9Sstevel@tonic-gate 	if (cl == NULL) {
1408*7c478bd9Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat);
1409*7c478bd9Sstevel@tonic-gate 		goto done;
1410*7c478bd9Sstevel@tonic-gate 	}
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate 	ah = authsys_create_default();
1413*7c478bd9Sstevel@tonic-gate 	if (ah != NULL)
1414*7c478bd9Sstevel@tonic-gate 		cl->cl_auth = ah;
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate 	tv.tv_sec = 5;
1417*7c478bd9Sstevel@tonic-gate 	tv.tv_usec = 0;
1418*7c478bd9Sstevel@tonic-gate 
1419*7c478bd9Sstevel@tonic-gate 	(void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
1420*7c478bd9Sstevel@tonic-gate 
1421*7c478bd9Sstevel@tonic-gate 	if ((get_pubfh == TRUE) && (vers != NFS_V4)) {
1422*7c478bd9Sstevel@tonic-gate 	    enum snego_stat sec;
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 	    if (!snego_done) {
1425*7c478bd9Sstevel@tonic-gate 		/*
1426*7c478bd9Sstevel@tonic-gate 		 * negotiate sec flavor.
1427*7c478bd9Sstevel@tonic-gate 		 */
1428*7c478bd9Sstevel@tonic-gate 		snego.cnt = 0;
1429*7c478bd9Sstevel@tonic-gate 		if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) ==
1430*7c478bd9Sstevel@tonic-gate 			SNEGO_SUCCESS) {
1431*7c478bd9Sstevel@tonic-gate 		    int jj;
1432*7c478bd9Sstevel@tonic-gate 
1433*7c478bd9Sstevel@tonic-gate 		/*
1434*7c478bd9Sstevel@tonic-gate 		 * check if server supports the one
1435*7c478bd9Sstevel@tonic-gate 		 * specified in the sec= option.
1436*7c478bd9Sstevel@tonic-gate 		 */
1437*7c478bd9Sstevel@tonic-gate 		    if (sec_opt) {
1438*7c478bd9Sstevel@tonic-gate 			for (jj = 0; jj < snego.cnt; jj++) {
1439*7c478bd9Sstevel@tonic-gate 			    if (snego.array[jj] == nfs_sec.sc_nfsnum) {
1440*7c478bd9Sstevel@tonic-gate 				snego_done = TRUE;
1441*7c478bd9Sstevel@tonic-gate 				break;
1442*7c478bd9Sstevel@tonic-gate 			    }
1443*7c478bd9Sstevel@tonic-gate 			}
1444*7c478bd9Sstevel@tonic-gate 		    }
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate 		/*
1447*7c478bd9Sstevel@tonic-gate 		 * find a common sec flavor
1448*7c478bd9Sstevel@tonic-gate 		 */
1449*7c478bd9Sstevel@tonic-gate 		    if (!snego_done) {
1450*7c478bd9Sstevel@tonic-gate 			if (sec_opt) {
1451*7c478bd9Sstevel@tonic-gate 			    pr_err(gettext(
1452*7c478bd9Sstevel@tonic-gate 				"Server does not support the security"
1453*7c478bd9Sstevel@tonic-gate 				" flavor specified.\n"));
1454*7c478bd9Sstevel@tonic-gate 			}
1455*7c478bd9Sstevel@tonic-gate 			for (jj = 0; jj < snego.cnt; jj++) {
1456*7c478bd9Sstevel@tonic-gate 			    if (!nfs_getseconfig_bynumber(snego.array[jj],
1457*7c478bd9Sstevel@tonic-gate 				&nfs_sec)) {
1458*7c478bd9Sstevel@tonic-gate 				snego_done = TRUE;
1459*7c478bd9Sstevel@tonic-gate 				if (sec_opt) {
1460*7c478bd9Sstevel@tonic-gate 				    pr_err(gettext(
1461*7c478bd9Sstevel@tonic-gate 					"Security flavor %d was negotiated and"
1462*7c478bd9Sstevel@tonic-gate 					" will be used.\n"),
1463*7c478bd9Sstevel@tonic-gate 					nfs_sec.sc_nfsnum);
1464*7c478bd9Sstevel@tonic-gate 				}
1465*7c478bd9Sstevel@tonic-gate 				break;
1466*7c478bd9Sstevel@tonic-gate 			    }
1467*7c478bd9Sstevel@tonic-gate 			}
1468*7c478bd9Sstevel@tonic-gate 		    }
1469*7c478bd9Sstevel@tonic-gate 		    if (!snego_done)
1470*7c478bd9Sstevel@tonic-gate 			return (NULL);
1471*7c478bd9Sstevel@tonic-gate 
1472*7c478bd9Sstevel@tonic-gate 		/*
1473*7c478bd9Sstevel@tonic-gate 		 * Now that the flavor has been
1474*7c478bd9Sstevel@tonic-gate 		 * negotiated, get the fh.
1475*7c478bd9Sstevel@tonic-gate 		 *
1476*7c478bd9Sstevel@tonic-gate 		 * First, create an auth handle using the negotiated
1477*7c478bd9Sstevel@tonic-gate 		 * sec flavor in the next lookup to
1478*7c478bd9Sstevel@tonic-gate 		 * fetch the filehandle.
1479*7c478bd9Sstevel@tonic-gate 		 */
1480*7c478bd9Sstevel@tonic-gate 		    new_ah = nfs_create_ah(cl, hostname, &nfs_sec);
1481*7c478bd9Sstevel@tonic-gate 		    if (new_ah == NULL)
1482*7c478bd9Sstevel@tonic-gate 			goto done;
1483*7c478bd9Sstevel@tonic-gate 		    cl->cl_auth = new_ah;
1484*7c478bd9Sstevel@tonic-gate 		} else if (sec == SNEGO_ARRAY_TOO_SMALL || sec ==
1485*7c478bd9Sstevel@tonic-gate 		    SNEGO_FAILURE) {
1486*7c478bd9Sstevel@tonic-gate 			goto done;
1487*7c478bd9Sstevel@tonic-gate 		}
1488*7c478bd9Sstevel@tonic-gate 		/*
1489*7c478bd9Sstevel@tonic-gate 		 * Note that if sec == SNEGO_DEF_VALID
1490*7c478bd9Sstevel@tonic-gate 		 * default sec flavor is acceptable.
1491*7c478bd9Sstevel@tonic-gate 		 * Use it to get the filehandle.
1492*7c478bd9Sstevel@tonic-gate 		 */
1493*7c478bd9Sstevel@tonic-gate 	    }
1494*7c478bd9Sstevel@tonic-gate 
1495*7c478bd9Sstevel@tonic-gate 	    if (vers == NFS_VERSION) {
1496*7c478bd9Sstevel@tonic-gate 		wnl_diropargs arg;
1497*7c478bd9Sstevel@tonic-gate 		wnl_diropres *res;
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate 		memset((char *)&arg.dir, 0, sizeof (wnl_fh));
1500*7c478bd9Sstevel@tonic-gate 		arg.name = fspath;
1501*7c478bd9Sstevel@tonic-gate 		res = wnlproc_lookup_2(&arg, cl);
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 		if (res == NULL || res->status != NFS_OK)
1504*7c478bd9Sstevel@tonic-gate 		    goto done;
1505*7c478bd9Sstevel@tonic-gate 		*fhp = malloc(sizeof (wnl_fh));
1506*7c478bd9Sstevel@tonic-gate 
1507*7c478bd9Sstevel@tonic-gate 		if (*fhp == NULL) {
1508*7c478bd9Sstevel@tonic-gate 		    pr_err(gettext("no memory\n"));
1509*7c478bd9Sstevel@tonic-gate 		    goto done;
1510*7c478bd9Sstevel@tonic-gate 		}
1511*7c478bd9Sstevel@tonic-gate 
1512*7c478bd9Sstevel@tonic-gate 		memcpy((char *)*fhp,
1513*7c478bd9Sstevel@tonic-gate 		    (char *)&res->wnl_diropres_u.wnl_diropres.file,
1514*7c478bd9Sstevel@tonic-gate 		    sizeof (wnl_fh));
1515*7c478bd9Sstevel@tonic-gate 	    } else {
1516*7c478bd9Sstevel@tonic-gate 		WNL_LOOKUP3args arg;
1517*7c478bd9Sstevel@tonic-gate 		WNL_LOOKUP3res *res;
1518*7c478bd9Sstevel@tonic-gate 		nfs_fh3 *fh3p;
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate 		memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
1521*7c478bd9Sstevel@tonic-gate 		arg.what.name = fspath;
1522*7c478bd9Sstevel@tonic-gate 		res = wnlproc3_lookup_3(&arg, cl);
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate 		if (res == NULL || res->status != NFS3_OK)
1525*7c478bd9Sstevel@tonic-gate 		    goto done;
1526*7c478bd9Sstevel@tonic-gate 
1527*7c478bd9Sstevel@tonic-gate 		fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
1528*7c478bd9Sstevel@tonic-gate 
1529*7c478bd9Sstevel@tonic-gate 		if (fh3p == NULL) {
1530*7c478bd9Sstevel@tonic-gate 		    pr_err(gettext("no memory\n"));
1531*7c478bd9Sstevel@tonic-gate 		    CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res);
1532*7c478bd9Sstevel@tonic-gate 		    goto done;
1533*7c478bd9Sstevel@tonic-gate 		}
1534*7c478bd9Sstevel@tonic-gate 
1535*7c478bd9Sstevel@tonic-gate 		fh3p->fh3_length =
1536*7c478bd9Sstevel@tonic-gate 		    res->WNL_LOOKUP3res_u.res_ok.object.data.data_len;
1537*7c478bd9Sstevel@tonic-gate 		memcpy(fh3p->fh3_u.data,
1538*7c478bd9Sstevel@tonic-gate 		    res->WNL_LOOKUP3res_u.res_ok.object.data.data_val,
1539*7c478bd9Sstevel@tonic-gate 		    fh3p->fh3_length);
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate 		*fhp = (caddr_t)fh3p;
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 		CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res);
1544*7c478bd9Sstevel@tonic-gate 	    }
1545*7c478bd9Sstevel@tonic-gate 	} else {
1546*7c478bd9Sstevel@tonic-gate 		void *res;
1547*7c478bd9Sstevel@tonic-gate 		struct rpc_err r_err;
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 		if (vers == NFS_VERSION)
1550*7c478bd9Sstevel@tonic-gate 		    res = wnlproc_null_2(NULL, cl);
1551*7c478bd9Sstevel@tonic-gate 		else if (vers == NFS_V3)
1552*7c478bd9Sstevel@tonic-gate 		    res = wnlproc3_null_3(NULL, cl);
1553*7c478bd9Sstevel@tonic-gate 		else
1554*7c478bd9Sstevel@tonic-gate 		    res = wnlproc4_null_4(NULL, cl);
1555*7c478bd9Sstevel@tonic-gate 
1556*7c478bd9Sstevel@tonic-gate 		if (res == NULL) {
1557*7c478bd9Sstevel@tonic-gate 			clnt_geterr(cl, &r_err);
1558*7c478bd9Sstevel@tonic-gate 			if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
1559*7c478bd9Sstevel@tonic-gate 				switch (r_err.re_status) {
1560*7c478bd9Sstevel@tonic-gate 				case RPC_TLIERROR:
1561*7c478bd9Sstevel@tonic-gate 				case RPC_CANTRECV:
1562*7c478bd9Sstevel@tonic-gate 				case RPC_CANTSEND:
1563*7c478bd9Sstevel@tonic-gate 					r_err.re_status = RPC_PROGVERSMISMATCH;
1564*7c478bd9Sstevel@tonic-gate 				}
1565*7c478bd9Sstevel@tonic-gate 			}
1566*7c478bd9Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status);
1567*7c478bd9Sstevel@tonic-gate 			goto done;
1568*7c478bd9Sstevel@tonic-gate 		}
1569*7c478bd9Sstevel@tonic-gate 	}
1570*7c478bd9Sstevel@tonic-gate 
1571*7c478bd9Sstevel@tonic-gate 	/*
1572*7c478bd9Sstevel@tonic-gate 	 * Make a copy of the netbuf to return
1573*7c478bd9Sstevel@tonic-gate 	 */
1574*7c478bd9Sstevel@tonic-gate 	nb = (struct netbuf *)malloc(sizeof (*nb));
1575*7c478bd9Sstevel@tonic-gate 	if (nb == NULL) {
1576*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("no memory\n"));
1577*7c478bd9Sstevel@tonic-gate 		goto done;
1578*7c478bd9Sstevel@tonic-gate 	}
1579*7c478bd9Sstevel@tonic-gate 	*nb = tbind->addr;
1580*7c478bd9Sstevel@tonic-gate 	nb->buf = (char *)malloc(nb->maxlen);
1581*7c478bd9Sstevel@tonic-gate 	if (nb->buf == NULL) {
1582*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("no memory\n"));
1583*7c478bd9Sstevel@tonic-gate 		free(nb);
1584*7c478bd9Sstevel@tonic-gate 		nb = NULL;
1585*7c478bd9Sstevel@tonic-gate 		goto done;
1586*7c478bd9Sstevel@tonic-gate 	}
1587*7c478bd9Sstevel@tonic-gate 	(void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate done:
1590*7c478bd9Sstevel@tonic-gate 	if (cl) {
1591*7c478bd9Sstevel@tonic-gate 	    if (ah != NULL) {
1592*7c478bd9Sstevel@tonic-gate 		if (new_ah != NULL)
1593*7c478bd9Sstevel@tonic-gate 		    AUTH_DESTROY(ah);
1594*7c478bd9Sstevel@tonic-gate 		AUTH_DESTROY(cl->cl_auth);
1595*7c478bd9Sstevel@tonic-gate 		cl->cl_auth = NULL;
1596*7c478bd9Sstevel@tonic-gate 	    }
1597*7c478bd9Sstevel@tonic-gate 	    clnt_destroy(cl);
1598*7c478bd9Sstevel@tonic-gate 	    cl = NULL;
1599*7c478bd9Sstevel@tonic-gate 	}
1600*7c478bd9Sstevel@tonic-gate 	if (tbind) {
1601*7c478bd9Sstevel@tonic-gate 		t_free((char *)tbind, T_BIND);
1602*7c478bd9Sstevel@tonic-gate 		tbind = NULL;
1603*7c478bd9Sstevel@tonic-gate 	}
1604*7c478bd9Sstevel@tonic-gate 	if (fd >= 0)
1605*7c478bd9Sstevel@tonic-gate 		(void) t_close(fd);
1606*7c478bd9Sstevel@tonic-gate 	return (nb);
1607*7c478bd9Sstevel@tonic-gate }
1608*7c478bd9Sstevel@tonic-gate 
1609*7c478bd9Sstevel@tonic-gate /*
1610*7c478bd9Sstevel@tonic-gate  * Get a network address on "hostname" for program "prog"
1611*7c478bd9Sstevel@tonic-gate  * with version "vers".  If the port number is specified (non zero)
1612*7c478bd9Sstevel@tonic-gate  * then try for a TCP/UDP transport and set the port number of the
1613*7c478bd9Sstevel@tonic-gate  * resulting IP address.
1614*7c478bd9Sstevel@tonic-gate  *
1615*7c478bd9Sstevel@tonic-gate  * If the address of a netconfig pointer was passed and
1616*7c478bd9Sstevel@tonic-gate  * if it's not null, use it as the netconfig otherwise
1617*7c478bd9Sstevel@tonic-gate  * assign the address of the netconfig that was used to
1618*7c478bd9Sstevel@tonic-gate  * establish contact with the service.
1619*7c478bd9Sstevel@tonic-gate  *
1620*7c478bd9Sstevel@tonic-gate  * A similar routine is also defined in ../../autofs/autod_nfs.c.
1621*7c478bd9Sstevel@tonic-gate  * This is a potential routine to move to ../lib for common usage.
1622*7c478bd9Sstevel@tonic-gate  *
1623*7c478bd9Sstevel@tonic-gate  * "error" refers to a more descriptive term when get_addr fails
1624*7c478bd9Sstevel@tonic-gate  * and returns NULL: ERR_PROTO_NONE if no error introduced by
1625*7c478bd9Sstevel@tonic-gate  * -o proto option, ERR_NETPATH if error found in NETPATH
1626*7c478bd9Sstevel@tonic-gate  * environment variable, ERR_PROTO_INVALID if an unrecognized
1627*7c478bd9Sstevel@tonic-gate  * protocol is specified by user, and ERR_PROTO_UNSUPP for a
1628*7c478bd9Sstevel@tonic-gate  * recognized but invalid protocol (eg. ticlts, ticots, etc.).
1629*7c478bd9Sstevel@tonic-gate  * "error" is ignored if get_addr returns non-NULL result.
1630*7c478bd9Sstevel@tonic-gate  *
1631*7c478bd9Sstevel@tonic-gate  */
1632*7c478bd9Sstevel@tonic-gate static struct netbuf *
1633*7c478bd9Sstevel@tonic-gate get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp,
1634*7c478bd9Sstevel@tonic-gate 	char *proto, ushort_t port, struct t_info *tinfo, caddr_t *fhp,
1635*7c478bd9Sstevel@tonic-gate 	bool_t get_pubfh, char *fspath, err_ret_t *error)
1636*7c478bd9Sstevel@tonic-gate {
1637*7c478bd9Sstevel@tonic-gate 	struct netbuf *nb = NULL;
1638*7c478bd9Sstevel@tonic-gate 	struct netconfig *nconf = NULL;
1639*7c478bd9Sstevel@tonic-gate 	NCONF_HANDLE *nc = NULL;
1640*7c478bd9Sstevel@tonic-gate 	int nthtry = FIRST_TRY;
1641*7c478bd9Sstevel@tonic-gate 	err_ret_t errsave_nohost, errsave_rpcerr;
1642*7c478bd9Sstevel@tonic-gate 
1643*7c478bd9Sstevel@tonic-gate 	SET_ERR_RET(&errsave_nohost, ERR_PROTO_NONE, 0);
1644*7c478bd9Sstevel@tonic-gate 	SET_ERR_RET(&errsave_rpcerr, ERR_PROTO_NONE, 0);
1645*7c478bd9Sstevel@tonic-gate 
1646*7c478bd9Sstevel@tonic-gate 	SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1647*7c478bd9Sstevel@tonic-gate 
1648*7c478bd9Sstevel@tonic-gate 	if (nconfp && *nconfp)
1649*7c478bd9Sstevel@tonic-gate 		return (get_the_addr(hostname, prog, vers, *nconfp, port,
1650*7c478bd9Sstevel@tonic-gate 			tinfo, fhp, get_pubfh, fspath, error));
1651*7c478bd9Sstevel@tonic-gate 	/*
1652*7c478bd9Sstevel@tonic-gate 	 * No nconf passed in.
1653*7c478bd9Sstevel@tonic-gate 	 *
1654*7c478bd9Sstevel@tonic-gate 	 * Try to get a nconf from /etc/netconfig filtered by
1655*7c478bd9Sstevel@tonic-gate 	 * the NETPATH environment variable.
1656*7c478bd9Sstevel@tonic-gate 	 * First search for COTS, second for CLTS unless proto
1657*7c478bd9Sstevel@tonic-gate 	 * is specified.  When we retry, we reset the
1658*7c478bd9Sstevel@tonic-gate 	 * netconfig list so that we would search the whole list
1659*7c478bd9Sstevel@tonic-gate 	 * all over again.
1660*7c478bd9Sstevel@tonic-gate 	 */
1661*7c478bd9Sstevel@tonic-gate 
1662*7c478bd9Sstevel@tonic-gate 	if ((nc = setnetpath()) == NULL) {
1663*7c478bd9Sstevel@tonic-gate 		/* should only return an error if problems with NETPATH */
1664*7c478bd9Sstevel@tonic-gate 		/* In which case you are hosed */
1665*7c478bd9Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_NETPATH, 0);
1666*7c478bd9Sstevel@tonic-gate 		goto done;
1667*7c478bd9Sstevel@tonic-gate 	}
1668*7c478bd9Sstevel@tonic-gate 
1669*7c478bd9Sstevel@tonic-gate 	/*
1670*7c478bd9Sstevel@tonic-gate 	 * If proto is specified, then only search for the match,
1671*7c478bd9Sstevel@tonic-gate 	 * otherwise try COTS first, if failed, try CLTS.
1672*7c478bd9Sstevel@tonic-gate 	 */
1673*7c478bd9Sstevel@tonic-gate 	if (proto) {
1674*7c478bd9Sstevel@tonic-gate 		/* no matching proto name */
1675*7c478bd9Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_PROTO_INVALID, 0);
1676*7c478bd9Sstevel@tonic-gate 
1677*7c478bd9Sstevel@tonic-gate 		while (nconf = getnetpath(nc)) {
1678*7c478bd9Sstevel@tonic-gate 			if (strcmp(nconf->nc_netid, proto))
1679*7c478bd9Sstevel@tonic-gate 				continue;
1680*7c478bd9Sstevel@tonic-gate 
1681*7c478bd9Sstevel@tonic-gate 			/* may be unsupported */
1682*7c478bd9Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
1683*7c478bd9Sstevel@tonic-gate 
1684*7c478bd9Sstevel@tonic-gate 			if ((port != 0) &&
1685*7c478bd9Sstevel@tonic-gate 				((strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
1686*7c478bd9Sstevel@tonic-gate 				strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
1687*7c478bd9Sstevel@tonic-gate 				(strcmp(nconf->nc_proto, NC_TCP) != 0 &&
1688*7c478bd9Sstevel@tonic-gate 				strcmp(nconf->nc_proto, NC_UDP) != 0)))
1689*7c478bd9Sstevel@tonic-gate 
1690*7c478bd9Sstevel@tonic-gate 				continue;
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate 			else {
1693*7c478bd9Sstevel@tonic-gate 				nb = get_the_addr(hostname, prog,
1694*7c478bd9Sstevel@tonic-gate 					vers, nconf, port, tinfo,
1695*7c478bd9Sstevel@tonic-gate 						fhp, get_pubfh, fspath, error);
1696*7c478bd9Sstevel@tonic-gate 
1697*7c478bd9Sstevel@tonic-gate 				if (nb != NULL)
1698*7c478bd9Sstevel@tonic-gate 					break;
1699*7c478bd9Sstevel@tonic-gate 
1700*7c478bd9Sstevel@tonic-gate 				/* nb is NULL - deal with errors */
1701*7c478bd9Sstevel@tonic-gate 				if (error) {
1702*7c478bd9Sstevel@tonic-gate 					if (error->error_type == ERR_NOHOST)
1703*7c478bd9Sstevel@tonic-gate 						SET_ERR_RET(&errsave_nohost,
1704*7c478bd9Sstevel@tonic-gate 							error->error_type,
1705*7c478bd9Sstevel@tonic-gate 							error->error_value);
1706*7c478bd9Sstevel@tonic-gate 					if (error->error_type == ERR_RPCERROR)
1707*7c478bd9Sstevel@tonic-gate 						SET_ERR_RET(&errsave_rpcerr,
1708*7c478bd9Sstevel@tonic-gate 							error->error_type,
1709*7c478bd9Sstevel@tonic-gate 							error->error_value);
1710*7c478bd9Sstevel@tonic-gate 				}
1711*7c478bd9Sstevel@tonic-gate 				/*
1712*7c478bd9Sstevel@tonic-gate 				 * continue with same protocol
1713*7c478bd9Sstevel@tonic-gate 				 * selection
1714*7c478bd9Sstevel@tonic-gate 				 */
1715*7c478bd9Sstevel@tonic-gate 				continue;
1716*7c478bd9Sstevel@tonic-gate 			}
1717*7c478bd9Sstevel@tonic-gate 		} /* end of while */
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate 		if (nconf == NULL)
1720*7c478bd9Sstevel@tonic-gate 			goto done;
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 		if ((nb = get_the_addr(hostname, prog, vers, nconf, port,
1723*7c478bd9Sstevel@tonic-gate 				tinfo, fhp, get_pubfh, fspath, error)) == NULL)
1724*7c478bd9Sstevel@tonic-gate 			goto done;
1725*7c478bd9Sstevel@tonic-gate 
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate 	} else {
1728*7c478bd9Sstevel@tonic-gate retry:
1729*7c478bd9Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_NETPATH, 0);
1730*7c478bd9Sstevel@tonic-gate 		while (nconf = getnetpath(nc)) {
1731*7c478bd9Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1732*7c478bd9Sstevel@tonic-gate 			if (nconf->nc_flag & NC_VISIBLE) {
1733*7c478bd9Sstevel@tonic-gate 				if (nthtry == FIRST_TRY) {
1734*7c478bd9Sstevel@tonic-gate 					if ((nconf->nc_semantics ==
1735*7c478bd9Sstevel@tonic-gate 						NC_TPI_COTS_ORD) ||
1736*7c478bd9Sstevel@tonic-gate 					    (nconf->nc_semantics ==
1737*7c478bd9Sstevel@tonic-gate 						NC_TPI_COTS)) {
1738*7c478bd9Sstevel@tonic-gate 
1739*7c478bd9Sstevel@tonic-gate 						if (port == 0)
1740*7c478bd9Sstevel@tonic-gate 							break;
1741*7c478bd9Sstevel@tonic-gate 
1742*7c478bd9Sstevel@tonic-gate 						if ((strcmp(nconf->nc_protofmly,
1743*7c478bd9Sstevel@tonic-gate 							NC_INET) == 0 ||
1744*7c478bd9Sstevel@tonic-gate 							strcmp(nconf->
1745*7c478bd9Sstevel@tonic-gate 							nc_protofmly,
1746*7c478bd9Sstevel@tonic-gate 							NC_INET6) == 0) &&
1747*7c478bd9Sstevel@tonic-gate 						    (strcmp(nconf->nc_proto,
1748*7c478bd9Sstevel@tonic-gate 							NC_TCP) == 0))
1749*7c478bd9Sstevel@tonic-gate 
1750*7c478bd9Sstevel@tonic-gate 							break;
1751*7c478bd9Sstevel@tonic-gate 					}
1752*7c478bd9Sstevel@tonic-gate 				}
1753*7c478bd9Sstevel@tonic-gate 				if (nthtry == SECOND_TRY) {
1754*7c478bd9Sstevel@tonic-gate 					if (nconf->nc_semantics ==
1755*7c478bd9Sstevel@tonic-gate 						NC_TPI_CLTS) {
1756*7c478bd9Sstevel@tonic-gate 						if (port == 0)
1757*7c478bd9Sstevel@tonic-gate 							break;
1758*7c478bd9Sstevel@tonic-gate 						if ((strcmp(nconf->nc_protofmly,
1759*7c478bd9Sstevel@tonic-gate 							NC_INET) == 0 ||
1760*7c478bd9Sstevel@tonic-gate 							strcmp(nconf->
1761*7c478bd9Sstevel@tonic-gate 							nc_protofmly, NC_INET6)
1762*7c478bd9Sstevel@tonic-gate 							== 0) &&
1763*7c478bd9Sstevel@tonic-gate 							(strcmp(
1764*7c478bd9Sstevel@tonic-gate 							nconf->nc_proto,
1765*7c478bd9Sstevel@tonic-gate 							NC_UDP) == 0))
1766*7c478bd9Sstevel@tonic-gate 							break;
1767*7c478bd9Sstevel@tonic-gate 					}
1768*7c478bd9Sstevel@tonic-gate 				}
1769*7c478bd9Sstevel@tonic-gate 			}
1770*7c478bd9Sstevel@tonic-gate 		} /* while */
1771*7c478bd9Sstevel@tonic-gate 		if (nconf == NULL) {
1772*7c478bd9Sstevel@tonic-gate 			if (++nthtry <= MNT_PREF_LISTLEN) {
1773*7c478bd9Sstevel@tonic-gate 				endnetpath(nc);
1774*7c478bd9Sstevel@tonic-gate 				if ((nc = setnetpath()) == NULL)
1775*7c478bd9Sstevel@tonic-gate 					goto done;
1776*7c478bd9Sstevel@tonic-gate 				goto retry;
1777*7c478bd9Sstevel@tonic-gate 			} else
1778*7c478bd9Sstevel@tonic-gate 				goto done;
1779*7c478bd9Sstevel@tonic-gate 		} else {
1780*7c478bd9Sstevel@tonic-gate 			if ((nb = get_the_addr(hostname, prog, vers, nconf,
1781*7c478bd9Sstevel@tonic-gate 				port, tinfo, fhp, get_pubfh, fspath, error))
1782*7c478bd9Sstevel@tonic-gate 				== NULL) {
1783*7c478bd9Sstevel@tonic-gate 				/* nb is NULL - deal with errors */
1784*7c478bd9Sstevel@tonic-gate 				if (error) {
1785*7c478bd9Sstevel@tonic-gate 					if (error->error_type == ERR_NOHOST)
1786*7c478bd9Sstevel@tonic-gate 						SET_ERR_RET(&errsave_nohost,
1787*7c478bd9Sstevel@tonic-gate 							error->error_type,
1788*7c478bd9Sstevel@tonic-gate 							error->error_value);
1789*7c478bd9Sstevel@tonic-gate 					if (error->error_type == ERR_RPCERROR)
1790*7c478bd9Sstevel@tonic-gate 						SET_ERR_RET(&errsave_rpcerr,
1791*7c478bd9Sstevel@tonic-gate 							error->error_type,
1792*7c478bd9Sstevel@tonic-gate 							error->error_value);
1793*7c478bd9Sstevel@tonic-gate 				}
1794*7c478bd9Sstevel@tonic-gate 				/*
1795*7c478bd9Sstevel@tonic-gate 				 * Continue the same search path in the
1796*7c478bd9Sstevel@tonic-gate 				 * netconfig db until no more matched
1797*7c478bd9Sstevel@tonic-gate 				 * nconf (nconf == NULL).
1798*7c478bd9Sstevel@tonic-gate 				 */
1799*7c478bd9Sstevel@tonic-gate 				goto retry;
1800*7c478bd9Sstevel@tonic-gate 			}
1801*7c478bd9Sstevel@tonic-gate 		}
1802*7c478bd9Sstevel@tonic-gate 	}
1803*7c478bd9Sstevel@tonic-gate 	SET_ERR_RET(error, ERR_PROTO_NONE, 0);
1804*7c478bd9Sstevel@tonic-gate 
1805*7c478bd9Sstevel@tonic-gate 	/*
1806*7c478bd9Sstevel@tonic-gate 	 * Got nconf and nb.  Now dup the netconfig structure (nconf)
1807*7c478bd9Sstevel@tonic-gate 	 * and return it thru nconfp.
1808*7c478bd9Sstevel@tonic-gate 	 */
1809*7c478bd9Sstevel@tonic-gate 	*nconfp = getnetconfigent(nconf->nc_netid);
1810*7c478bd9Sstevel@tonic-gate 	if (*nconfp == NULL) {
1811*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "no memory\n");
1812*7c478bd9Sstevel@tonic-gate 		free(nb);
1813*7c478bd9Sstevel@tonic-gate 		nb = NULL;
1814*7c478bd9Sstevel@tonic-gate 	}
1815*7c478bd9Sstevel@tonic-gate done:
1816*7c478bd9Sstevel@tonic-gate 	if (nc)
1817*7c478bd9Sstevel@tonic-gate 		endnetpath(nc);
1818*7c478bd9Sstevel@tonic-gate 
1819*7c478bd9Sstevel@tonic-gate 	if (nb == NULL) {
1820*7c478bd9Sstevel@tonic-gate 		if (error) {
1821*7c478bd9Sstevel@tonic-gate 			/*
1822*7c478bd9Sstevel@tonic-gate 			 * Check the saved errors. The RPC error has *
1823*7c478bd9Sstevel@tonic-gate 			 * precedence over the no host error.
1824*7c478bd9Sstevel@tonic-gate 			 */
1825*7c478bd9Sstevel@tonic-gate 			if (errsave_nohost.error_type != ERR_PROTO_NONE)
1826*7c478bd9Sstevel@tonic-gate 				SET_ERR_RET(error, errsave_nohost.error_type,
1827*7c478bd9Sstevel@tonic-gate 					errsave_nohost.error_value);
1828*7c478bd9Sstevel@tonic-gate 			if (errsave_rpcerr.error_type != ERR_PROTO_NONE)
1829*7c478bd9Sstevel@tonic-gate 				SET_ERR_RET(error, errsave_rpcerr.error_type,
1830*7c478bd9Sstevel@tonic-gate 					errsave_rpcerr.error_value);
1831*7c478bd9Sstevel@tonic-gate 		}
1832*7c478bd9Sstevel@tonic-gate 	}
1833*7c478bd9Sstevel@tonic-gate 	return (nb);
1834*7c478bd9Sstevel@tonic-gate }
1835*7c478bd9Sstevel@tonic-gate 
1836*7c478bd9Sstevel@tonic-gate /*
1837*7c478bd9Sstevel@tonic-gate  * Get a file handle usinging multi-component lookup with the public
1838*7c478bd9Sstevel@tonic-gate  * file handle.
1839*7c478bd9Sstevel@tonic-gate  */
1840*7c478bd9Sstevel@tonic-gate static int
1841*7c478bd9Sstevel@tonic-gate get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url,
1842*7c478bd9Sstevel@tonic-gate 	bool_t loud, int *versp, struct netconfig **nconfp, ushort_t port)
1843*7c478bd9Sstevel@tonic-gate {
1844*7c478bd9Sstevel@tonic-gate 	uint_t vers_min;
1845*7c478bd9Sstevel@tonic-gate 	uint_t vers_max;
1846*7c478bd9Sstevel@tonic-gate 	int r;
1847*7c478bd9Sstevel@tonic-gate 	char *path;
1848*7c478bd9Sstevel@tonic-gate 
1849*7c478bd9Sstevel@tonic-gate 	if (nfsvers != 0) {
1850*7c478bd9Sstevel@tonic-gate 		vers_max = vers_min = nfsvers;
1851*7c478bd9Sstevel@tonic-gate 	} else {
1852*7c478bd9Sstevel@tonic-gate 		vers_max = vers_max_default;
1853*7c478bd9Sstevel@tonic-gate 		vers_min = vers_min_default;
1854*7c478bd9Sstevel@tonic-gate 	}
1855*7c478bd9Sstevel@tonic-gate 
1856*7c478bd9Sstevel@tonic-gate 	if (url == FALSE) {
1857*7c478bd9Sstevel@tonic-gate 		path = malloc(strlen(fspath) + 2);
1858*7c478bd9Sstevel@tonic-gate 		if (path == NULL) {
1859*7c478bd9Sstevel@tonic-gate 			if (loud == TRUE)  {
1860*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("no memory\n"));
1861*7c478bd9Sstevel@tonic-gate 			}
1862*7c478bd9Sstevel@tonic-gate 			return (RET_ERR);
1863*7c478bd9Sstevel@tonic-gate 		}
1864*7c478bd9Sstevel@tonic-gate 
1865*7c478bd9Sstevel@tonic-gate 		path[0] = (char)WNL_NATIVEPATH;
1866*7c478bd9Sstevel@tonic-gate 		(void) strcpy(&path[1], fspath);
1867*7c478bd9Sstevel@tonic-gate 
1868*7c478bd9Sstevel@tonic-gate 	} else  {
1869*7c478bd9Sstevel@tonic-gate 		path = fspath;
1870*7c478bd9Sstevel@tonic-gate 	}
1871*7c478bd9Sstevel@tonic-gate 
1872*7c478bd9Sstevel@tonic-gate 	for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min;
1873*7c478bd9Sstevel@tonic-gate 	    nfsvers_to_use--) {
1874*7c478bd9Sstevel@tonic-gate 		/*
1875*7c478bd9Sstevel@tonic-gate 		 * getaddr_nfs will also fill in the fh for us.
1876*7c478bd9Sstevel@tonic-gate 		 */
1877*7c478bd9Sstevel@tonic-gate 		r = getaddr_nfs(args, fshost, nconfp,
1878*7c478bd9Sstevel@tonic-gate 				TRUE, path, port, NULL, FALSE);
1879*7c478bd9Sstevel@tonic-gate 
1880*7c478bd9Sstevel@tonic-gate 		if (r == RET_OK) {
1881*7c478bd9Sstevel@tonic-gate 			/*
1882*7c478bd9Sstevel@tonic-gate 			 * Since we are using the public fh, and NLM is
1883*7c478bd9Sstevel@tonic-gate 			 * not firewall friendly, use local locking.
1884*7c478bd9Sstevel@tonic-gate 			 * Not the case for v4.
1885*7c478bd9Sstevel@tonic-gate 			 */
1886*7c478bd9Sstevel@tonic-gate 			*versp = nfsvers_to_use;
1887*7c478bd9Sstevel@tonic-gate 			switch (nfsvers_to_use) {
1888*7c478bd9Sstevel@tonic-gate 			case NFS_V4:
1889*7c478bd9Sstevel@tonic-gate 				fstype = MNTTYPE_NFS4;
1890*7c478bd9Sstevel@tonic-gate 				break;
1891*7c478bd9Sstevel@tonic-gate 			case NFS_V3:
1892*7c478bd9Sstevel@tonic-gate 				fstype = MNTTYPE_NFS3;
1893*7c478bd9Sstevel@tonic-gate 				/* fall through to pick up llock option */
1894*7c478bd9Sstevel@tonic-gate 			default:
1895*7c478bd9Sstevel@tonic-gate 				args->flags |= NFSMNT_LLOCK;
1896*7c478bd9Sstevel@tonic-gate 				break;
1897*7c478bd9Sstevel@tonic-gate 			}
1898*7c478bd9Sstevel@tonic-gate 			if (fspath != path)
1899*7c478bd9Sstevel@tonic-gate 				free(path);
1900*7c478bd9Sstevel@tonic-gate 
1901*7c478bd9Sstevel@tonic-gate 			return (r);
1902*7c478bd9Sstevel@tonic-gate 		}
1903*7c478bd9Sstevel@tonic-gate 	}
1904*7c478bd9Sstevel@tonic-gate 
1905*7c478bd9Sstevel@tonic-gate 	if (fspath != path) {
1906*7c478bd9Sstevel@tonic-gate 		free(path);
1907*7c478bd9Sstevel@tonic-gate 	}
1908*7c478bd9Sstevel@tonic-gate 
1909*7c478bd9Sstevel@tonic-gate 	if (loud == TRUE) {
1910*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("Could not use public filehandle in request to"
1911*7c478bd9Sstevel@tonic-gate 			" server %s\n"), fshost);
1912*7c478bd9Sstevel@tonic-gate 	}
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate 	return (r);
1915*7c478bd9Sstevel@tonic-gate }
1916*7c478bd9Sstevel@tonic-gate 
1917*7c478bd9Sstevel@tonic-gate /*
1918*7c478bd9Sstevel@tonic-gate  * get fhandle of remote path from server's mountd
1919*7c478bd9Sstevel@tonic-gate  */
1920*7c478bd9Sstevel@tonic-gate static int
1921*7c478bd9Sstevel@tonic-gate get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp,
1922*7c478bd9Sstevel@tonic-gate 	bool_t loud_on_mnt_err, struct netconfig **nconfp, ushort_t port)
1923*7c478bd9Sstevel@tonic-gate {
1924*7c478bd9Sstevel@tonic-gate 	static struct fhstatus fhs;
1925*7c478bd9Sstevel@tonic-gate 	static struct mountres3 mountres3;
1926*7c478bd9Sstevel@tonic-gate 	static struct pathcnf p;
1927*7c478bd9Sstevel@tonic-gate 	nfs_fh3 *fh3p;
1928*7c478bd9Sstevel@tonic-gate 	struct timeval timeout = { 25, 0};
1929*7c478bd9Sstevel@tonic-gate 	CLIENT *cl;
1930*7c478bd9Sstevel@tonic-gate 	enum clnt_stat rpc_stat;
1931*7c478bd9Sstevel@tonic-gate 	rpcvers_t outvers = 0;
1932*7c478bd9Sstevel@tonic-gate 	rpcvers_t vers_to_try;
1933*7c478bd9Sstevel@tonic-gate 	rpcvers_t vers_min;
1934*7c478bd9Sstevel@tonic-gate 	static int printed = 0;
1935*7c478bd9Sstevel@tonic-gate 	int count, i, *auths;
1936*7c478bd9Sstevel@tonic-gate 	char *msg;
1937*7c478bd9Sstevel@tonic-gate 
1938*7c478bd9Sstevel@tonic-gate 	switch (nfsvers) {
1939*7c478bd9Sstevel@tonic-gate 	case 2: /* version 2 specified try that only */
1940*7c478bd9Sstevel@tonic-gate 		vers_to_try = MOUNTVERS_POSIX;
1941*7c478bd9Sstevel@tonic-gate 		vers_min = MOUNTVERS;
1942*7c478bd9Sstevel@tonic-gate 		break;
1943*7c478bd9Sstevel@tonic-gate 	case 3: /* version 3 specified try that only */
1944*7c478bd9Sstevel@tonic-gate 		vers_to_try = MOUNTVERS3;
1945*7c478bd9Sstevel@tonic-gate 		vers_min = MOUNTVERS3;
1946*7c478bd9Sstevel@tonic-gate 		break;
1947*7c478bd9Sstevel@tonic-gate 	case 4: /* version 4 specified try that only */
1948*7c478bd9Sstevel@tonic-gate 		/*
1949*7c478bd9Sstevel@tonic-gate 		 * This assignment is in the wrong version sequence.
1950*7c478bd9Sstevel@tonic-gate 		 * The above are MOUNT program and this is NFS
1951*7c478bd9Sstevel@tonic-gate 		 * program.  However, it happens to work out since the
1952*7c478bd9Sstevel@tonic-gate 		 * two don't collide for NFSv4.
1953*7c478bd9Sstevel@tonic-gate 		 */
1954*7c478bd9Sstevel@tonic-gate 		vers_to_try = NFS_V4;
1955*7c478bd9Sstevel@tonic-gate 		vers_min = NFS_V4;
1956*7c478bd9Sstevel@tonic-gate 		break;
1957*7c478bd9Sstevel@tonic-gate 	default: /* no version specified, start with default */
1958*7c478bd9Sstevel@tonic-gate 		vers_to_try = vers_max_default;
1959*7c478bd9Sstevel@tonic-gate 		vers_min = vers_min_default;
1960*7c478bd9Sstevel@tonic-gate 		break;
1961*7c478bd9Sstevel@tonic-gate 	}
1962*7c478bd9Sstevel@tonic-gate 
1963*7c478bd9Sstevel@tonic-gate 	/*
1964*7c478bd9Sstevel@tonic-gate 	 * In the case of version 4, just NULL proc the server since
1965*7c478bd9Sstevel@tonic-gate 	 * there is no MOUNT program.  If this fails, then decrease
1966*7c478bd9Sstevel@tonic-gate 	 * vers_to_try and continue on with regular MOUNT program
1967*7c478bd9Sstevel@tonic-gate 	 * processing.
1968*7c478bd9Sstevel@tonic-gate 	 */
1969*7c478bd9Sstevel@tonic-gate 	if (vers_to_try == NFS_V4) {
1970*7c478bd9Sstevel@tonic-gate 		int savevers = nfsvers_to_use;
1971*7c478bd9Sstevel@tonic-gate 		err_ret_t error;
1972*7c478bd9Sstevel@tonic-gate 		int retval;
1973*7c478bd9Sstevel@tonic-gate 		SET_ERR_RET(&error, ERR_PROTO_NONE, 0);
1974*7c478bd9Sstevel@tonic-gate 
1975*7c478bd9Sstevel@tonic-gate 		/* Let's hope for the best */
1976*7c478bd9Sstevel@tonic-gate 		nfsvers_to_use = NFS_V4;
1977*7c478bd9Sstevel@tonic-gate 		retval =
1978*7c478bd9Sstevel@tonic-gate 			getaddr_nfs(args, fshost, nconfp, FALSE,
1979*7c478bd9Sstevel@tonic-gate 				    fspath, port, &error, vers_min == NFS_V4);
1980*7c478bd9Sstevel@tonic-gate 
1981*7c478bd9Sstevel@tonic-gate 		if (retval == RET_OK) {
1982*7c478bd9Sstevel@tonic-gate 			*versp = nfsvers_to_use = NFS_V4;
1983*7c478bd9Sstevel@tonic-gate 			fstype = MNTTYPE_NFS4;
1984*7c478bd9Sstevel@tonic-gate 			args->fh = strdup(fspath);
1985*7c478bd9Sstevel@tonic-gate 			if (args->fh == NULL) {
1986*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("no memory\n"));
1987*7c478bd9Sstevel@tonic-gate 				*versp = nfsvers_to_use = savevers;
1988*7c478bd9Sstevel@tonic-gate 				return (RET_ERR);
1989*7c478bd9Sstevel@tonic-gate 			}
1990*7c478bd9Sstevel@tonic-gate 			return (RET_OK);
1991*7c478bd9Sstevel@tonic-gate 		}
1992*7c478bd9Sstevel@tonic-gate 		nfsvers_to_use = savevers;
1993*7c478bd9Sstevel@tonic-gate 
1994*7c478bd9Sstevel@tonic-gate 		vers_to_try--;
1995*7c478bd9Sstevel@tonic-gate 		/* If no more versions to try, let the user know. */
1996*7c478bd9Sstevel@tonic-gate 		if (vers_to_try < vers_min) {
1997*7c478bd9Sstevel@tonic-gate 			return (retval);
1998*7c478bd9Sstevel@tonic-gate 		}
1999*7c478bd9Sstevel@tonic-gate 
2000*7c478bd9Sstevel@tonic-gate 		/*
2001*7c478bd9Sstevel@tonic-gate 		 * If we are here, there are more versions to try but
2002*7c478bd9Sstevel@tonic-gate 		 * there has been an error of some sort.  If it is not
2003*7c478bd9Sstevel@tonic-gate 		 * an RPC error (e.g. host unknown), we just stop and
2004*7c478bd9Sstevel@tonic-gate 		 * return the error since the other versions would see
2005*7c478bd9Sstevel@tonic-gate 		 * the same error as well.
2006*7c478bd9Sstevel@tonic-gate 		 */
2007*7c478bd9Sstevel@tonic-gate 		if (retval == RET_ERR && error.error_type != ERR_RPCERROR)
2008*7c478bd9Sstevel@tonic-gate 			return (retval);
2009*7c478bd9Sstevel@tonic-gate 	}
2010*7c478bd9Sstevel@tonic-gate 
2011*7c478bd9Sstevel@tonic-gate 	while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers,
2012*7c478bd9Sstevel@tonic-gate 			vers_min, vers_to_try, "datagram_v")) == NULL) {
2013*7c478bd9Sstevel@tonic-gate 		if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) {
2014*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("%s: %s\n"), fshost,
2015*7c478bd9Sstevel@tonic-gate 			    clnt_spcreateerror(""));
2016*7c478bd9Sstevel@tonic-gate 			return (RET_ERR);
2017*7c478bd9Sstevel@tonic-gate 		}
2018*7c478bd9Sstevel@tonic-gate 
2019*7c478bd9Sstevel@tonic-gate 		/*
2020*7c478bd9Sstevel@tonic-gate 		 * We don't want to downgrade version on lost packets
2021*7c478bd9Sstevel@tonic-gate 		 */
2022*7c478bd9Sstevel@tonic-gate 		if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) ||
2023*7c478bd9Sstevel@tonic-gate 			(rpc_createerr.cf_stat == RPC_PMAPFAILURE)) {
2024*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("%s: %s\n"), fshost,
2025*7c478bd9Sstevel@tonic-gate 			    clnt_spcreateerror(""));
2026*7c478bd9Sstevel@tonic-gate 			return (RET_RETRY);
2027*7c478bd9Sstevel@tonic-gate 		}
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate 		/*
2030*7c478bd9Sstevel@tonic-gate 		 * back off and try the previous version - patch to the
2031*7c478bd9Sstevel@tonic-gate 		 * problem of version numbers not being contigous and
2032*7c478bd9Sstevel@tonic-gate 		 * clnt_create_vers failing (SunOS4.1 clients & SGI servers)
2033*7c478bd9Sstevel@tonic-gate 		 * The problem happens with most non-Sun servers who
2034*7c478bd9Sstevel@tonic-gate 		 * don't support mountd protocol #2. So, in case the
2035*7c478bd9Sstevel@tonic-gate 		 * call fails, we re-try the call anyway.
2036*7c478bd9Sstevel@tonic-gate 		 */
2037*7c478bd9Sstevel@tonic-gate 		vers_to_try--;
2038*7c478bd9Sstevel@tonic-gate 		if (vers_to_try < vers_min) {
2039*7c478bd9Sstevel@tonic-gate 			if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) {
2040*7c478bd9Sstevel@tonic-gate 				if (nfsvers == 0) {
2041*7c478bd9Sstevel@tonic-gate 					pr_err(gettext(
2042*7c478bd9Sstevel@tonic-gate 			"%s:%s: no applicable versions of NFS supported\n"),
2043*7c478bd9Sstevel@tonic-gate 					    fshost, fspath);
2044*7c478bd9Sstevel@tonic-gate 				} else {
2045*7c478bd9Sstevel@tonic-gate 					pr_err(gettext(
2046*7c478bd9Sstevel@tonic-gate 			"%s:%s: NFS Version %d not supported\n"),
2047*7c478bd9Sstevel@tonic-gate 					    fshost, fspath, nfsvers);
2048*7c478bd9Sstevel@tonic-gate 				}
2049*7c478bd9Sstevel@tonic-gate 				return (RET_ERR);
2050*7c478bd9Sstevel@tonic-gate 			}
2051*7c478bd9Sstevel@tonic-gate 			if (!printed) {
2052*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("%s: %s\n"), fshost,
2053*7c478bd9Sstevel@tonic-gate 				    clnt_spcreateerror(""));
2054*7c478bd9Sstevel@tonic-gate 				printed = 1;
2055*7c478bd9Sstevel@tonic-gate 			}
2056*7c478bd9Sstevel@tonic-gate 			return (RET_RETRY);
2057*7c478bd9Sstevel@tonic-gate 		}
2058*7c478bd9Sstevel@tonic-gate 	}
2059*7c478bd9Sstevel@tonic-gate 	if (posix && outvers < MOUNTVERS_POSIX) {
2060*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("%s: %s: no pathconf info\n"),
2061*7c478bd9Sstevel@tonic-gate 		    fshost, clnt_sperror(cl, ""));
2062*7c478bd9Sstevel@tonic-gate 		clnt_destroy(cl);
2063*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
2064*7c478bd9Sstevel@tonic-gate 	}
2065*7c478bd9Sstevel@tonic-gate 
2066*7c478bd9Sstevel@tonic-gate 	if (__clnt_bindresvport(cl) < 0) {
2067*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("Couldn't bind to reserved port\n"));
2068*7c478bd9Sstevel@tonic-gate 		clnt_destroy(cl);
2069*7c478bd9Sstevel@tonic-gate 		return (RET_RETRY);
2070*7c478bd9Sstevel@tonic-gate 	}
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate 	if ((cl->cl_auth = authsys_create_default()) == NULL) {
2073*7c478bd9Sstevel@tonic-gate 		pr_err(
2074*7c478bd9Sstevel@tonic-gate 		    gettext("Couldn't create default authentication handle\n"));
2075*7c478bd9Sstevel@tonic-gate 		clnt_destroy(cl);
2076*7c478bd9Sstevel@tonic-gate 		return (RET_RETRY);
2077*7c478bd9Sstevel@tonic-gate 	}
2078*7c478bd9Sstevel@tonic-gate 
2079*7c478bd9Sstevel@tonic-gate 	switch (outvers) {
2080*7c478bd9Sstevel@tonic-gate 	case MOUNTVERS:
2081*7c478bd9Sstevel@tonic-gate 	case MOUNTVERS_POSIX:
2082*7c478bd9Sstevel@tonic-gate 		*versp = nfsvers_to_use = NFS_VERSION;
2083*7c478bd9Sstevel@tonic-gate 		rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2084*7c478bd9Sstevel@tonic-gate 			(caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout);
2085*7c478bd9Sstevel@tonic-gate 		if (rpc_stat != RPC_SUCCESS) {
2086*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("%s:%s: server not responding %s\n"),
2087*7c478bd9Sstevel@tonic-gate 			    fshost, fspath, clnt_sperror(cl, ""));
2088*7c478bd9Sstevel@tonic-gate 			clnt_destroy(cl);
2089*7c478bd9Sstevel@tonic-gate 			return (RET_RETRY);
2090*7c478bd9Sstevel@tonic-gate 		}
2091*7c478bd9Sstevel@tonic-gate 
2092*7c478bd9Sstevel@tonic-gate 		if ((errno = fhs.fhs_status) != MNT_OK) {
2093*7c478bd9Sstevel@tonic-gate 			if (loud_on_mnt_err) {
2094*7c478bd9Sstevel@tonic-gate 			    if (errno == EACCES) {
2095*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("%s:%s: access denied\n"),
2096*7c478bd9Sstevel@tonic-gate 				    fshost, fspath);
2097*7c478bd9Sstevel@tonic-gate 			    } else {
2098*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("%s:%s: %s\n"), fshost, fspath,
2099*7c478bd9Sstevel@tonic-gate 				    strerror(errno));
2100*7c478bd9Sstevel@tonic-gate 			    }
2101*7c478bd9Sstevel@tonic-gate 			}
2102*7c478bd9Sstevel@tonic-gate 			clnt_destroy(cl);
2103*7c478bd9Sstevel@tonic-gate 			return (RET_MNTERR);
2104*7c478bd9Sstevel@tonic-gate 		}
2105*7c478bd9Sstevel@tonic-gate 		args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle));
2106*7c478bd9Sstevel@tonic-gate 		if (args->fh == NULL) {
2107*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
2108*7c478bd9Sstevel@tonic-gate 			return (RET_ERR);
2109*7c478bd9Sstevel@tonic-gate 		}
2110*7c478bd9Sstevel@tonic-gate 		memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle,
2111*7c478bd9Sstevel@tonic-gate 			sizeof (fhs.fhstatus_u.fhs_fhandle));
2112*7c478bd9Sstevel@tonic-gate 		if (!errno && posix) {
2113*7c478bd9Sstevel@tonic-gate 			rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF,
2114*7c478bd9Sstevel@tonic-gate 				xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf,
2115*7c478bd9Sstevel@tonic-gate 				(caddr_t)&p, timeout);
2116*7c478bd9Sstevel@tonic-gate 			if (rpc_stat != RPC_SUCCESS) {
2117*7c478bd9Sstevel@tonic-gate 				pr_err(gettext(
2118*7c478bd9Sstevel@tonic-gate 				    "%s:%s: server not responding %s\n"),
2119*7c478bd9Sstevel@tonic-gate 				    fshost, fspath, clnt_sperror(cl, ""));
2120*7c478bd9Sstevel@tonic-gate 				free(args->fh);
2121*7c478bd9Sstevel@tonic-gate 				clnt_destroy(cl);
2122*7c478bd9Sstevel@tonic-gate 				return (RET_RETRY);
2123*7c478bd9Sstevel@tonic-gate 			}
2124*7c478bd9Sstevel@tonic-gate 			if (_PC_ISSET(_PC_ERROR, p.pc_mask)) {
2125*7c478bd9Sstevel@tonic-gate 				pr_err(gettext(
2126*7c478bd9Sstevel@tonic-gate 				    "%s:%s: no pathconf info\n"),
2127*7c478bd9Sstevel@tonic-gate 				    fshost, fspath);
2128*7c478bd9Sstevel@tonic-gate 				free(args->fh);
2129*7c478bd9Sstevel@tonic-gate 				clnt_destroy(cl);
2130*7c478bd9Sstevel@tonic-gate 				return (RET_ERR);
2131*7c478bd9Sstevel@tonic-gate 			}
2132*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_POSIX;
2133*7c478bd9Sstevel@tonic-gate 			args->pathconf = malloc(sizeof (p));
2134*7c478bd9Sstevel@tonic-gate 			if (args->pathconf == NULL) {
2135*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("no memory\n"));
2136*7c478bd9Sstevel@tonic-gate 				free(args->fh);
2137*7c478bd9Sstevel@tonic-gate 				clnt_destroy(cl);
2138*7c478bd9Sstevel@tonic-gate 				return (RET_ERR);
2139*7c478bd9Sstevel@tonic-gate 			}
2140*7c478bd9Sstevel@tonic-gate 			memcpy((caddr_t)args->pathconf, (caddr_t)&p,
2141*7c478bd9Sstevel@tonic-gate 				sizeof (p));
2142*7c478bd9Sstevel@tonic-gate 		}
2143*7c478bd9Sstevel@tonic-gate 		break;
2144*7c478bd9Sstevel@tonic-gate 
2145*7c478bd9Sstevel@tonic-gate 	case MOUNTVERS3:
2146*7c478bd9Sstevel@tonic-gate 		*versp = nfsvers_to_use = NFS_V3;
2147*7c478bd9Sstevel@tonic-gate 		rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
2148*7c478bd9Sstevel@tonic-gate 				(caddr_t)&fspath,
2149*7c478bd9Sstevel@tonic-gate 				xdr_mountres3, (caddr_t)&mountres3, timeout);
2150*7c478bd9Sstevel@tonic-gate 		if (rpc_stat != RPC_SUCCESS) {
2151*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("%s:%s: server not responding %s\n"),
2152*7c478bd9Sstevel@tonic-gate 			    fshost, fspath, clnt_sperror(cl, ""));
2153*7c478bd9Sstevel@tonic-gate 			clnt_destroy(cl);
2154*7c478bd9Sstevel@tonic-gate 			return (RET_RETRY);
2155*7c478bd9Sstevel@tonic-gate 		}
2156*7c478bd9Sstevel@tonic-gate 
2157*7c478bd9Sstevel@tonic-gate 		/*
2158*7c478bd9Sstevel@tonic-gate 		 * Assume here that most of the MNT3ERR_*
2159*7c478bd9Sstevel@tonic-gate 		 * codes map into E* errors.
2160*7c478bd9Sstevel@tonic-gate 		 */
2161*7c478bd9Sstevel@tonic-gate 		if ((errno = mountres3.fhs_status) != MNT_OK) {
2162*7c478bd9Sstevel@tonic-gate 		    if (loud_on_mnt_err) {
2163*7c478bd9Sstevel@tonic-gate 			switch (errno) {
2164*7c478bd9Sstevel@tonic-gate 			case MNT3ERR_NAMETOOLONG:
2165*7c478bd9Sstevel@tonic-gate 				msg = "path name is too long";
2166*7c478bd9Sstevel@tonic-gate 				break;
2167*7c478bd9Sstevel@tonic-gate 			case MNT3ERR_NOTSUPP:
2168*7c478bd9Sstevel@tonic-gate 				msg = "operation not supported";
2169*7c478bd9Sstevel@tonic-gate 				break;
2170*7c478bd9Sstevel@tonic-gate 			case MNT3ERR_SERVERFAULT:
2171*7c478bd9Sstevel@tonic-gate 				msg = "server fault";
2172*7c478bd9Sstevel@tonic-gate 				break;
2173*7c478bd9Sstevel@tonic-gate 			default:
2174*7c478bd9Sstevel@tonic-gate 				msg = strerror(errno);
2175*7c478bd9Sstevel@tonic-gate 				break;
2176*7c478bd9Sstevel@tonic-gate 			}
2177*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("%s:%s: %s\n"), fshost, fspath, msg);
2178*7c478bd9Sstevel@tonic-gate 		    }
2179*7c478bd9Sstevel@tonic-gate 		    clnt_destroy(cl);
2180*7c478bd9Sstevel@tonic-gate 		    return (RET_MNTERR);
2181*7c478bd9Sstevel@tonic-gate 		}
2182*7c478bd9Sstevel@tonic-gate 
2183*7c478bd9Sstevel@tonic-gate 		fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
2184*7c478bd9Sstevel@tonic-gate 		if (fh3p == NULL) {
2185*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
2186*7c478bd9Sstevel@tonic-gate 			return (RET_ERR);
2187*7c478bd9Sstevel@tonic-gate 		}
2188*7c478bd9Sstevel@tonic-gate 		fh3p->fh3_length =
2189*7c478bd9Sstevel@tonic-gate 			mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
2190*7c478bd9Sstevel@tonic-gate 		(void) memcpy(fh3p->fh3_u.data,
2191*7c478bd9Sstevel@tonic-gate 			mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
2192*7c478bd9Sstevel@tonic-gate 			fh3p->fh3_length);
2193*7c478bd9Sstevel@tonic-gate 		args->fh = (caddr_t)fh3p;
2194*7c478bd9Sstevel@tonic-gate 		fstype = MNTTYPE_NFS3;
2195*7c478bd9Sstevel@tonic-gate 
2196*7c478bd9Sstevel@tonic-gate 		/*
2197*7c478bd9Sstevel@tonic-gate 		 * Check the security flavor to be used.
2198*7c478bd9Sstevel@tonic-gate 		 *
2199*7c478bd9Sstevel@tonic-gate 		 * If "secure" or "sec=flavor" is a mount
2200*7c478bd9Sstevel@tonic-gate 		 * option, check if the server supports the "flavor".
2201*7c478bd9Sstevel@tonic-gate 		 * If the server does not support the flavor, return
2202*7c478bd9Sstevel@tonic-gate 		 * error.
2203*7c478bd9Sstevel@tonic-gate 		 *
2204*7c478bd9Sstevel@tonic-gate 		 * If no mount option is given then use the first supported
2205*7c478bd9Sstevel@tonic-gate 		 * security flavor (by the client) in the auth list returned
2206*7c478bd9Sstevel@tonic-gate 		 * from the server.
2207*7c478bd9Sstevel@tonic-gate 		 *
2208*7c478bd9Sstevel@tonic-gate 		 */
2209*7c478bd9Sstevel@tonic-gate 		auths =
2210*7c478bd9Sstevel@tonic-gate 		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val;
2211*7c478bd9Sstevel@tonic-gate 		count =
2212*7c478bd9Sstevel@tonic-gate 		mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len;
2213*7c478bd9Sstevel@tonic-gate 
2214*7c478bd9Sstevel@tonic-gate 		if (sec_opt) {
2215*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < count; i++) {
2216*7c478bd9Sstevel@tonic-gate 				if (auths[i] == nfs_sec.sc_nfsnum)
2217*7c478bd9Sstevel@tonic-gate 				    break;
2218*7c478bd9Sstevel@tonic-gate 			}
2219*7c478bd9Sstevel@tonic-gate 			if (i >= count) {
2220*7c478bd9Sstevel@tonic-gate 				goto autherr;
2221*7c478bd9Sstevel@tonic-gate 			}
2222*7c478bd9Sstevel@tonic-gate 		} else {
2223*7c478bd9Sstevel@tonic-gate 		    if (count > 0) {
2224*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < count; i++) {
2225*7c478bd9Sstevel@tonic-gate 			    if (!nfs_getseconfig_bynumber(auths[i], &nfs_sec)) {
2226*7c478bd9Sstevel@tonic-gate 				sec_opt++;
2227*7c478bd9Sstevel@tonic-gate 				break;
2228*7c478bd9Sstevel@tonic-gate 			    }
2229*7c478bd9Sstevel@tonic-gate 			}
2230*7c478bd9Sstevel@tonic-gate 			if (i >= count) {
2231*7c478bd9Sstevel@tonic-gate 			    goto autherr;
2232*7c478bd9Sstevel@tonic-gate 			}
2233*7c478bd9Sstevel@tonic-gate 		    }
2234*7c478bd9Sstevel@tonic-gate 		}
2235*7c478bd9Sstevel@tonic-gate 		break;
2236*7c478bd9Sstevel@tonic-gate 	default:
2237*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
2238*7c478bd9Sstevel@tonic-gate 		    fshost, fspath, outvers);
2239*7c478bd9Sstevel@tonic-gate 		clnt_destroy(cl);
2240*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
2241*7c478bd9Sstevel@tonic-gate 	}
2242*7c478bd9Sstevel@tonic-gate 
2243*7c478bd9Sstevel@tonic-gate 	clnt_destroy(cl);
2244*7c478bd9Sstevel@tonic-gate 	return (RET_OK);
2245*7c478bd9Sstevel@tonic-gate 
2246*7c478bd9Sstevel@tonic-gate autherr:
2247*7c478bd9Sstevel@tonic-gate 	pr_err(gettext(
2248*7c478bd9Sstevel@tonic-gate 		"security mode does not match the server exporting %s:%s\n"),
2249*7c478bd9Sstevel@tonic-gate 		fshost, fspath);
2250*7c478bd9Sstevel@tonic-gate 	clnt_destroy(cl);
2251*7c478bd9Sstevel@tonic-gate 	return (RET_ERR);
2252*7c478bd9Sstevel@tonic-gate }
2253*7c478bd9Sstevel@tonic-gate 
2254*7c478bd9Sstevel@tonic-gate /*
2255*7c478bd9Sstevel@tonic-gate  * Fill in the address for the server's NFS service and
2256*7c478bd9Sstevel@tonic-gate  * fill in a knetconfig structure for the transport that
2257*7c478bd9Sstevel@tonic-gate  * the service is available on.
2258*7c478bd9Sstevel@tonic-gate  */
2259*7c478bd9Sstevel@tonic-gate static int
2260*7c478bd9Sstevel@tonic-gate getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp,
2261*7c478bd9Sstevel@tonic-gate 	    bool_t get_pubfh, char *fspath, ushort_t port, err_ret_t *error,
2262*7c478bd9Sstevel@tonic-gate 	    bool_t print_rpcerror)
2263*7c478bd9Sstevel@tonic-gate {
2264*7c478bd9Sstevel@tonic-gate 	struct stat sb;
2265*7c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
2266*7c478bd9Sstevel@tonic-gate 	struct knetconfig *knconfp;
2267*7c478bd9Sstevel@tonic-gate 	static int printed = 0;
2268*7c478bd9Sstevel@tonic-gate 	struct t_info tinfo;
2269*7c478bd9Sstevel@tonic-gate 	err_ret_t addr_error;
2270*7c478bd9Sstevel@tonic-gate 
2271*7c478bd9Sstevel@tonic-gate 	SET_ERR_RET(error, ERR_PROTO_NONE, 0);
2272*7c478bd9Sstevel@tonic-gate 	SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0);
2273*7c478bd9Sstevel@tonic-gate 
2274*7c478bd9Sstevel@tonic-gate 	if (nfs_proto) {
2275*7c478bd9Sstevel@tonic-gate 		/*
2276*7c478bd9Sstevel@tonic-gate 		 * If a proto is specified and its rdma try this. The kernel
2277*7c478bd9Sstevel@tonic-gate 		 * will later do the reachablity test and fail form there
2278*7c478bd9Sstevel@tonic-gate 		 * if rdma transport is not available to kernel rpc
2279*7c478bd9Sstevel@tonic-gate 		 */
2280*7c478bd9Sstevel@tonic-gate 		if (strcmp(nfs_proto, "rdma") == 0) {
2281*7c478bd9Sstevel@tonic-gate 			args->addr = get_addr(fshost, NFS_PROGRAM,
2282*7c478bd9Sstevel@tonic-gate 			    nfsvers_to_use, nconfp, NULL, port, &tinfo,
2283*7c478bd9Sstevel@tonic-gate 			    &args->fh, get_pubfh, fspath, &addr_error);
2284*7c478bd9Sstevel@tonic-gate 
2285*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_DORDMA;
2286*7c478bd9Sstevel@tonic-gate 		} else {
2287*7c478bd9Sstevel@tonic-gate 			args->addr = get_addr(fshost, NFS_PROGRAM,
2288*7c478bd9Sstevel@tonic-gate 			    nfsvers_to_use, nconfp, nfs_proto, port, &tinfo,
2289*7c478bd9Sstevel@tonic-gate 			    &args->fh, get_pubfh, fspath, &addr_error);
2290*7c478bd9Sstevel@tonic-gate 		}
2291*7c478bd9Sstevel@tonic-gate 	} else {
2292*7c478bd9Sstevel@tonic-gate 		args->addr = get_addr(fshost, NFS_PROGRAM, nfsvers_to_use,
2293*7c478bd9Sstevel@tonic-gate 		    nconfp, nfs_proto, port, &tinfo, &args->fh, get_pubfh,
2294*7c478bd9Sstevel@tonic-gate 		    fspath, &addr_error);
2295*7c478bd9Sstevel@tonic-gate 		/*
2296*7c478bd9Sstevel@tonic-gate 		 * If no proto is specified set this flag.
2297*7c478bd9Sstevel@tonic-gate 		 * Kernel mount code will try to use RDMA if its on the
2298*7c478bd9Sstevel@tonic-gate 		 * system, otherwise it will keep on using the protocol
2299*7c478bd9Sstevel@tonic-gate 		 * selected here, through the above get_addr call.
2300*7c478bd9Sstevel@tonic-gate 		 */
2301*7c478bd9Sstevel@tonic-gate 		if (nfs_proto == NULL)
2302*7c478bd9Sstevel@tonic-gate 			args->flags |= NFSMNT_TRYRDMA;
2303*7c478bd9Sstevel@tonic-gate 	}
2304*7c478bd9Sstevel@tonic-gate 
2305*7c478bd9Sstevel@tonic-gate 	if (args->addr == NULL) {
2306*7c478bd9Sstevel@tonic-gate 		/*
2307*7c478bd9Sstevel@tonic-gate 		 * We could have failed because the server had no public
2308*7c478bd9Sstevel@tonic-gate 		 * file handle support. So don't print a message and don't
2309*7c478bd9Sstevel@tonic-gate 		 * retry.
2310*7c478bd9Sstevel@tonic-gate 		 */
2311*7c478bd9Sstevel@tonic-gate 		if (get_pubfh == TRUE)
2312*7c478bd9Sstevel@tonic-gate 			return (RET_ERR);
2313*7c478bd9Sstevel@tonic-gate 
2314*7c478bd9Sstevel@tonic-gate 		if (!printed) {
2315*7c478bd9Sstevel@tonic-gate 			switch (addr_error.error_type) {
2316*7c478bd9Sstevel@tonic-gate 			case 0:
2317*7c478bd9Sstevel@tonic-gate 				break;
2318*7c478bd9Sstevel@tonic-gate 			case ERR_RPCERROR:
2319*7c478bd9Sstevel@tonic-gate 				if (!print_rpcerror)
2320*7c478bd9Sstevel@tonic-gate 					/* no error print at this time */
2321*7c478bd9Sstevel@tonic-gate 					break;
2322*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("%s NFS service not"
2323*7c478bd9Sstevel@tonic-gate 					    " available %s\n"), fshost,
2324*7c478bd9Sstevel@tonic-gate 				    clnt_sperrno(addr_error.error_value));
2325*7c478bd9Sstevel@tonic-gate 				break;
2326*7c478bd9Sstevel@tonic-gate 			case ERR_NETPATH:
2327*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("%s: Error in NETPATH.\n"),
2328*7c478bd9Sstevel@tonic-gate 					fshost);
2329*7c478bd9Sstevel@tonic-gate 				break;
2330*7c478bd9Sstevel@tonic-gate 			case ERR_PROTO_INVALID:
2331*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("%s: NFS service does not"
2332*7c478bd9Sstevel@tonic-gate 					" recognize protocol: %s.\n"), fshost,
2333*7c478bd9Sstevel@tonic-gate 					nfs_proto);
2334*7c478bd9Sstevel@tonic-gate 				break;
2335*7c478bd9Sstevel@tonic-gate 			case ERR_PROTO_UNSUPP:
2336*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("%s: NFS service does not"
2337*7c478bd9Sstevel@tonic-gate 					" support protocol: %s.\n"), fshost,
2338*7c478bd9Sstevel@tonic-gate 					nfs_proto);
2339*7c478bd9Sstevel@tonic-gate 				break;
2340*7c478bd9Sstevel@tonic-gate 			case ERR_NOHOST:
2341*7c478bd9Sstevel@tonic-gate 				pr_err("%s: %s\n", fshost, netdir_sperror());
2342*7c478bd9Sstevel@tonic-gate 				break;
2343*7c478bd9Sstevel@tonic-gate 			default:
2344*7c478bd9Sstevel@tonic-gate 				/* case ERR_PROTO_NONE falls through */
2345*7c478bd9Sstevel@tonic-gate 				pr_err(gettext("%s: NFS service not responding"
2346*7c478bd9Sstevel@tonic-gate 					"\n"), fshost);
2347*7c478bd9Sstevel@tonic-gate 				break;
2348*7c478bd9Sstevel@tonic-gate 			}
2349*7c478bd9Sstevel@tonic-gate 			printed = 1;
2350*7c478bd9Sstevel@tonic-gate 		}
2351*7c478bd9Sstevel@tonic-gate 		SET_ERR_RET(error,
2352*7c478bd9Sstevel@tonic-gate 			addr_error.error_type, addr_error.error_value);
2353*7c478bd9Sstevel@tonic-gate 		if (addr_error.error_type == ERR_PROTO_NONE)
2354*7c478bd9Sstevel@tonic-gate 			return (RET_RETRY);
2355*7c478bd9Sstevel@tonic-gate 		else if (addr_error.error_type == ERR_RPCERROR &&
2356*7c478bd9Sstevel@tonic-gate 			! IS_UNRECOVERABLE_RPC(addr_error.error_value)) {
2357*7c478bd9Sstevel@tonic-gate 			return (RET_RETRY);
2358*7c478bd9Sstevel@tonic-gate 		}
2359*7c478bd9Sstevel@tonic-gate 		else
2360*7c478bd9Sstevel@tonic-gate 			return (RET_ERR);
2361*7c478bd9Sstevel@tonic-gate 	}
2362*7c478bd9Sstevel@tonic-gate 	nconf = *nconfp;
2363*7c478bd9Sstevel@tonic-gate 
2364*7c478bd9Sstevel@tonic-gate 	if (stat(nconf->nc_device, &sb) < 0) {
2365*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"),
2366*7c478bd9Sstevel@tonic-gate 		    nconf->nc_device, strerror(errno));
2367*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
2368*7c478bd9Sstevel@tonic-gate 	}
2369*7c478bd9Sstevel@tonic-gate 
2370*7c478bd9Sstevel@tonic-gate 	knconfp = (struct knetconfig *)malloc(sizeof (*knconfp));
2371*7c478bd9Sstevel@tonic-gate 	if (!knconfp) {
2372*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("no memory\n"));
2373*7c478bd9Sstevel@tonic-gate 		return (RET_ERR);
2374*7c478bd9Sstevel@tonic-gate 	}
2375*7c478bd9Sstevel@tonic-gate 	knconfp->knc_semantics = nconf->nc_semantics;
2376*7c478bd9Sstevel@tonic-gate 	knconfp->knc_protofmly = nconf->nc_protofmly;
2377*7c478bd9Sstevel@tonic-gate 	knconfp->knc_proto = nconf->nc_proto;
2378*7c478bd9Sstevel@tonic-gate 	knconfp->knc_rdev = sb.st_rdev;
2379*7c478bd9Sstevel@tonic-gate 
2380*7c478bd9Sstevel@tonic-gate 	/* make sure we don't overload the transport */
2381*7c478bd9Sstevel@tonic-gate 	if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) {
2382*7c478bd9Sstevel@tonic-gate 		args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE);
2383*7c478bd9Sstevel@tonic-gate 		if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR)
2384*7c478bd9Sstevel@tonic-gate 			args->rsize = tinfo.tsdu - NFS_RPC_HDR;
2385*7c478bd9Sstevel@tonic-gate 		if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR)
2386*7c478bd9Sstevel@tonic-gate 			args->wsize = tinfo.tsdu - NFS_RPC_HDR;
2387*7c478bd9Sstevel@tonic-gate 	}
2388*7c478bd9Sstevel@tonic-gate 
2389*7c478bd9Sstevel@tonic-gate 	args->flags |= NFSMNT_KNCONF;
2390*7c478bd9Sstevel@tonic-gate 	args->knconf = knconfp;
2391*7c478bd9Sstevel@tonic-gate 	return (RET_OK);
2392*7c478bd9Sstevel@tonic-gate }
2393*7c478bd9Sstevel@tonic-gate 
2394*7c478bd9Sstevel@tonic-gate static int
2395*7c478bd9Sstevel@tonic-gate retry(struct mnttab *mntp, int ro)
2396*7c478bd9Sstevel@tonic-gate {
2397*7c478bd9Sstevel@tonic-gate 	int delay = 5;
2398*7c478bd9Sstevel@tonic-gate 	int count = retries;
2399*7c478bd9Sstevel@tonic-gate 	int r;
2400*7c478bd9Sstevel@tonic-gate 
2401*7c478bd9Sstevel@tonic-gate 	if (bg) {
2402*7c478bd9Sstevel@tonic-gate 		if (fork() > 0)
2403*7c478bd9Sstevel@tonic-gate 			return (RET_OK);
2404*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp);
2405*7c478bd9Sstevel@tonic-gate 		backgrounded = 1;
2406*7c478bd9Sstevel@tonic-gate 	} else
2407*7c478bd9Sstevel@tonic-gate 		pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp);
2408*7c478bd9Sstevel@tonic-gate 
2409*7c478bd9Sstevel@tonic-gate 	while (count--) {
2410*7c478bd9Sstevel@tonic-gate 		if ((r = mount_nfs(mntp, ro)) == RET_OK) {
2411*7c478bd9Sstevel@tonic-gate 			pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp);
2412*7c478bd9Sstevel@tonic-gate 			return (RET_OK);
2413*7c478bd9Sstevel@tonic-gate 		}
2414*7c478bd9Sstevel@tonic-gate 		if (r != RET_RETRY)
2415*7c478bd9Sstevel@tonic-gate 			break;
2416*7c478bd9Sstevel@tonic-gate 
2417*7c478bd9Sstevel@tonic-gate 		if (count > 0) {
2418*7c478bd9Sstevel@tonic-gate 		    (void) sleep(delay);
2419*7c478bd9Sstevel@tonic-gate 		    delay *= 2;
2420*7c478bd9Sstevel@tonic-gate 		    if (delay > 120)
2421*7c478bd9Sstevel@tonic-gate 			    delay = 120;
2422*7c478bd9Sstevel@tonic-gate 		}
2423*7c478bd9Sstevel@tonic-gate 	}
2424*7c478bd9Sstevel@tonic-gate 	pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp);
2425*7c478bd9Sstevel@tonic-gate 	return (RET_ERR);
2426*7c478bd9Sstevel@tonic-gate }
2427*7c478bd9Sstevel@tonic-gate 
2428*7c478bd9Sstevel@tonic-gate /*
2429*7c478bd9Sstevel@tonic-gate  * Read the /etc/default/nfs configuration file to determine if the
2430*7c478bd9Sstevel@tonic-gate  * client has been configured for a new min/max for the NFS version to
2431*7c478bd9Sstevel@tonic-gate  * use.
2432*7c478bd9Sstevel@tonic-gate  */
2433*7c478bd9Sstevel@tonic-gate static void
2434*7c478bd9Sstevel@tonic-gate read_default(void)
2435*7c478bd9Sstevel@tonic-gate {
2436*7c478bd9Sstevel@tonic-gate 	char *defval;
2437*7c478bd9Sstevel@tonic-gate 	int errno;
2438*7c478bd9Sstevel@tonic-gate 	int tmp;
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate 	/* Fail silently if error in opening the default nfs config file */
2441*7c478bd9Sstevel@tonic-gate 	if ((defopen(NFSADMIN)) == 0) {
2442*7c478bd9Sstevel@tonic-gate 		if ((defval = defread("NFS_CLIENT_VERSMIN=")) != NULL) {
2443*7c478bd9Sstevel@tonic-gate 			errno = 0;
2444*7c478bd9Sstevel@tonic-gate 			tmp = strtol(defval, (char **)NULL, 10);
2445*7c478bd9Sstevel@tonic-gate 			if (errno == 0) {
2446*7c478bd9Sstevel@tonic-gate 				vers_min_default = tmp;
2447*7c478bd9Sstevel@tonic-gate 			}
2448*7c478bd9Sstevel@tonic-gate 		}
2449*7c478bd9Sstevel@tonic-gate 		if ((defval = defread("NFS_CLIENT_VERSMAX=")) != NULL) {
2450*7c478bd9Sstevel@tonic-gate 			errno = 0;
2451*7c478bd9Sstevel@tonic-gate 			tmp = strtol(defval, (char **)NULL, 10);
2452*7c478bd9Sstevel@tonic-gate 			if (errno == 0) {
2453*7c478bd9Sstevel@tonic-gate 				vers_max_default = tmp;
2454*7c478bd9Sstevel@tonic-gate 			}
2455*7c478bd9Sstevel@tonic-gate 		}
2456*7c478bd9Sstevel@tonic-gate 		/* close defaults file */
2457*7c478bd9Sstevel@tonic-gate 		defopen(NULL);
2458*7c478bd9Sstevel@tonic-gate 	}
2459*7c478bd9Sstevel@tonic-gate }
2460*7c478bd9Sstevel@tonic-gate 
2461*7c478bd9Sstevel@tonic-gate static void
2462*7c478bd9Sstevel@tonic-gate sigusr1(int s)
2463*7c478bd9Sstevel@tonic-gate {
2464*7c478bd9Sstevel@tonic-gate }
2465