xref: /onnv-gate/usr/src/cmd/fs.d/nfs/mount/mount.c (revision 5655:2b4de7c11b38)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53378Srica  * Common Development and Distribution License (the "License").
63378Srica  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*5655Sth199096 
220Sstevel@tonic-gate /*
233378Srica  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
320Sstevel@tonic-gate  * The Regents of the University of California
330Sstevel@tonic-gate  * All Rights Reserved
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
360Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
370Sstevel@tonic-gate  * contributors.
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * nfs mount
440Sstevel@tonic-gate  */
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #define	NFSCLIENT
470Sstevel@tonic-gate #include <locale.h>
480Sstevel@tonic-gate #include <stdio.h>
490Sstevel@tonic-gate #include <string.h>
500Sstevel@tonic-gate #include <memory.h>
510Sstevel@tonic-gate #include <stdarg.h>
520Sstevel@tonic-gate #include <unistd.h>
530Sstevel@tonic-gate #include <ctype.h>
540Sstevel@tonic-gate #include <stdlib.h>
550Sstevel@tonic-gate #include <signal.h>
560Sstevel@tonic-gate #include <sys/param.h>
570Sstevel@tonic-gate #include <rpc/rpc.h>
580Sstevel@tonic-gate #include <errno.h>
590Sstevel@tonic-gate #include <sys/stat.h>
600Sstevel@tonic-gate #include <netdb.h>
610Sstevel@tonic-gate #include <sys/mount.h>
620Sstevel@tonic-gate #include <sys/mntent.h>
630Sstevel@tonic-gate #include <sys/mnttab.h>
640Sstevel@tonic-gate #include <nfs/nfs.h>
650Sstevel@tonic-gate #include <nfs/mount.h>
660Sstevel@tonic-gate #include <rpcsvc/mount.h>
670Sstevel@tonic-gate #include <sys/pathconf.h>
680Sstevel@tonic-gate #include <netdir.h>
690Sstevel@tonic-gate #include <netconfig.h>
700Sstevel@tonic-gate #include <sys/sockio.h>
710Sstevel@tonic-gate #include <net/if.h>
720Sstevel@tonic-gate #include <syslog.h>
730Sstevel@tonic-gate #include <fslib.h>
740Sstevel@tonic-gate #include <deflt.h>
750Sstevel@tonic-gate #include <sys/wait.h>
760Sstevel@tonic-gate #include "replica.h"
770Sstevel@tonic-gate #include <netinet/in.h>
780Sstevel@tonic-gate #include <nfs/nfs_sec.h>
790Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
800Sstevel@tonic-gate #include <priv.h>
813378Srica #include <tsol/label.h>
820Sstevel@tonic-gate #include "nfs_subr.h"
830Sstevel@tonic-gate #include "webnfs.h"
840Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h>
850Sstevel@tonic-gate 
865302Sth199096 #include <nfs/nfssys.h>
875302Sth199096 extern int _nfssys(enum nfssys_op, void *);
885302Sth199096 
890Sstevel@tonic-gate #ifndef	NFS_VERSMAX
900Sstevel@tonic-gate #define	NFS_VERSMAX	4
910Sstevel@tonic-gate #endif
920Sstevel@tonic-gate #ifndef	NFS_VERSMIN
930Sstevel@tonic-gate #define	NFS_VERSMIN	2
940Sstevel@tonic-gate #endif
950Sstevel@tonic-gate 
960Sstevel@tonic-gate #define	RET_OK		0
970Sstevel@tonic-gate #define	RET_RETRY	32
980Sstevel@tonic-gate #define	RET_ERR		33
990Sstevel@tonic-gate #define	RET_MNTERR	1000
1000Sstevel@tonic-gate #define	ERR_PROTO_NONE		0
1010Sstevel@tonic-gate #define	ERR_PROTO_INVALID	901
1020Sstevel@tonic-gate #define	ERR_PROTO_UNSUPP	902
1030Sstevel@tonic-gate #define	ERR_NETPATH		903
1040Sstevel@tonic-gate #define	ERR_NOHOST		904
1050Sstevel@tonic-gate #define	ERR_RPCERROR		905
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate typedef struct err_ret {
1080Sstevel@tonic-gate 	int error_type;
1090Sstevel@tonic-gate 	int error_value;
1100Sstevel@tonic-gate } err_ret_t;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate #define	SET_ERR_RET(errst, etype, eval) \
1130Sstevel@tonic-gate 	if (errst) { \
1140Sstevel@tonic-gate 		(errst)->error_type = etype; \
1150Sstevel@tonic-gate 		(errst)->error_value = eval; \
1160Sstevel@tonic-gate 	}
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /* number of transports to try */
1190Sstevel@tonic-gate #define	MNT_PREF_LISTLEN	2
1200Sstevel@tonic-gate #define	FIRST_TRY		1
1210Sstevel@tonic-gate #define	SECOND_TRY		2
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate #define	BIGRETRY	10000
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /* maximum length of RPC header for NFS messages */
1260Sstevel@tonic-gate #define	NFS_RPC_HDR	432
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate #define	NFS_ARGS_EXTB_secdata(args, secdata) \
1290Sstevel@tonic-gate 	{ (args)->nfs_args_ext = NFS_ARGS_EXTB, \
1300Sstevel@tonic-gate 	(args)->nfs_ext_u.nfs_extB.secdata = secdata; }
1310Sstevel@tonic-gate 
132*5655Sth199096 extern int __clnt_bindresvport(CLIENT *);
1330Sstevel@tonic-gate extern char *nfs_get_qop_name();
1340Sstevel@tonic-gate extern AUTH * nfs_create_ah();
1350Sstevel@tonic-gate extern enum snego_stat nfs_sec_nego();
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate static void usage(void);
1380Sstevel@tonic-gate static int retry(struct mnttab *, int);
1390Sstevel@tonic-gate static int set_args(int *, struct nfs_args *, char *, struct mnttab *);
1400Sstevel@tonic-gate static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t,
1410Sstevel@tonic-gate 	int *, struct netconfig **, ushort_t);
1420Sstevel@tonic-gate static int get_fh(struct nfs_args *, char *, char *, int *, bool_t,
1430Sstevel@tonic-gate 	struct netconfig **, ushort_t);
1440Sstevel@tonic-gate static int make_secure(struct nfs_args *, char *, struct netconfig *,
1450Sstevel@tonic-gate 	bool_t, rpcvers_t);
146489Soa138391 static int mount_nfs(struct mnttab *, int, err_ret_t *);
1470Sstevel@tonic-gate static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **,
1480Sstevel@tonic-gate 		    bool_t, char *, ushort_t, err_ret_t *, bool_t);
1490Sstevel@tonic-gate static void pr_err(const char *fmt, ...);
1500Sstevel@tonic-gate static void usage(void);
1510Sstevel@tonic-gate static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t,
1520Sstevel@tonic-gate 	struct netconfig **, char *, ushort_t, struct t_info *,
1530Sstevel@tonic-gate 	caddr_t *, bool_t, char *, err_ret_t *);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate static struct netbuf *get_the_addr(char *, rpcprog_t, rpcvers_t,
1560Sstevel@tonic-gate 	struct netconfig *, ushort_t, struct t_info *, caddr_t *,
1570Sstevel@tonic-gate 	bool_t, char *, err_ret_t *);
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate extern int self_check(char *);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static void read_default(void);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate static char typename[64];
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate static int bg = 0;
1660Sstevel@tonic-gate static int backgrounded = 0;
1670Sstevel@tonic-gate static int posix = 0;
1680Sstevel@tonic-gate static int retries = BIGRETRY;
1690Sstevel@tonic-gate static ushort_t nfs_port = 0;
1700Sstevel@tonic-gate static char *nfs_proto = NULL;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate static int mflg = 0;
1730Sstevel@tonic-gate static int Oflg = 0;	/* Overlay mounts */
1740Sstevel@tonic-gate static int qflg = 0;	/* quiet - don't print warnings on bad options */
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate static char *fstype = MNTTYPE_NFS;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate static seconfig_t nfs_sec;
1790Sstevel@tonic-gate static int sec_opt = 0;	/* any security option ? */
1800Sstevel@tonic-gate static bool_t snego_done;
1810Sstevel@tonic-gate static void sigusr1(int);
1820Sstevel@tonic-gate 
1835302Sth199096 extern void set_nfsv4_ephemeral_mount_to(void);
1845302Sth199096 
1850Sstevel@tonic-gate /*
1860Sstevel@tonic-gate  * list of support services needed
1870Sstevel@tonic-gate  */
1880Sstevel@tonic-gate static char	*service_list[] = { STATD, LOCKD, NULL };
1890Sstevel@tonic-gate static char	*service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL };
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate /*
1920Sstevel@tonic-gate  * These two variables control the NFS version number to be used.
1930Sstevel@tonic-gate  *
1940Sstevel@tonic-gate  * nfsvers defaults to 0 which means to use the highest number that
1950Sstevel@tonic-gate  * both the client and the server support.  It can also be set to
1960Sstevel@tonic-gate  * a particular value, either 2, 3, or 4 to indicate the version
1970Sstevel@tonic-gate  * number of choice.  If the server (or the client) do not support
1980Sstevel@tonic-gate  * the version indicated, then the mount attempt will be failed.
1990Sstevel@tonic-gate  *
2000Sstevel@tonic-gate  * nfsvers_to_use is the actual version number found to use.  It
2010Sstevel@tonic-gate  * is determined in get_fh by pinging the various versions of the
2020Sstevel@tonic-gate  * NFS service on the server to see which responds positively.
203489Soa138391  *
204489Soa138391  * nfsretry_vers is the version number set when we retry the mount
205489Soa138391  * command with the version decremented from nfsvers_to_use.
206489Soa138391  * nfsretry_vers is set from nfsvers_to_use when we retry the mount
207489Soa138391  * for errors other than RPC errors; it helps un know why we are
208489Soa138391  * retrying. It is an indication that the retry is due to
209489Soa138391  * non-RPC errors.
2100Sstevel@tonic-gate  */
2110Sstevel@tonic-gate static rpcvers_t nfsvers = 0;
2120Sstevel@tonic-gate static rpcvers_t nfsvers_to_use = 0;
213489Soa138391 static rpcvers_t nfsretry_vers = 0;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate /*
2160Sstevel@tonic-gate  * There are the defaults (range) for the client when determining
2170Sstevel@tonic-gate  * which NFS version to use when probing the server (see above).
2180Sstevel@tonic-gate  * These will only be used when the vers mount option is not used and
2190Sstevel@tonic-gate  * these may be reset if /etc/default/nfs is configured to do so.
2200Sstevel@tonic-gate  */
2210Sstevel@tonic-gate static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT;
2220Sstevel@tonic-gate static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate /*
2250Sstevel@tonic-gate  * This variable controls whether to try the public file handle.
2260Sstevel@tonic-gate  */
2270Sstevel@tonic-gate static bool_t public_opt;
2280Sstevel@tonic-gate 
229249Sjwahlig int
230249Sjwahlig main(int argc, char *argv[])
2310Sstevel@tonic-gate {
2320Sstevel@tonic-gate 	struct mnttab mnt;
2330Sstevel@tonic-gate 	extern char *optarg;
2340Sstevel@tonic-gate 	extern int optind;
2350Sstevel@tonic-gate 	char optbuf[MAX_MNTOPT_STR];
2360Sstevel@tonic-gate 	int ro = 0;
2370Sstevel@tonic-gate 	int r;
2380Sstevel@tonic-gate 	int c;
2390Sstevel@tonic-gate 	char *myname;
240489Soa138391 	err_ret_t retry_error;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2430Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
2440Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
2450Sstevel@tonic-gate #endif
2460Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	myname = strrchr(argv[0], '/');
2490Sstevel@tonic-gate 	myname = myname ? myname + 1 : argv[0];
2500Sstevel@tonic-gate 	(void) snprintf(typename, sizeof (typename), "%s %s",
2510Sstevel@tonic-gate 	    MNTTYPE_NFS, myname);
2520Sstevel@tonic-gate 	argv[0] = typename;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	mnt.mnt_mntopts = optbuf;
2550Sstevel@tonic-gate 	(void) strcpy(optbuf, "rw");
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	/*
2580Sstevel@tonic-gate 	 * Set options
2590Sstevel@tonic-gate 	 */
2600Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ro:mOq")) != EOF) {
2610Sstevel@tonic-gate 		switch (c) {
2620Sstevel@tonic-gate 		case 'r':
2630Sstevel@tonic-gate 			ro++;
2640Sstevel@tonic-gate 			break;
2650Sstevel@tonic-gate 		case 'o':
2660Sstevel@tonic-gate 			if (strlen(optarg) >= MAX_MNTOPT_STR) {
2670Sstevel@tonic-gate 				pr_err(gettext("option string too long"));
2680Sstevel@tonic-gate 				return (RET_ERR);
2690Sstevel@tonic-gate 			}
2700Sstevel@tonic-gate 			(void) strcpy(mnt.mnt_mntopts, optarg);
2710Sstevel@tonic-gate #ifdef LATER					/* XXX */
2720Sstevel@tonic-gate 			if (strstr(optarg, MNTOPT_REMOUNT)) {
2730Sstevel@tonic-gate 				/*
2740Sstevel@tonic-gate 				 * If remount is specified, only rw is allowed.
2750Sstevel@tonic-gate 				 */
2760Sstevel@tonic-gate 				if ((strcmp(optarg, MNTOPT_REMOUNT) != 0) &&
2770Sstevel@tonic-gate 				    (strcmp(optarg, "remount,rw") != 0) &&
2780Sstevel@tonic-gate 				    (strcmp(optarg, "rw,remount") != 0)) {
2790Sstevel@tonic-gate 					pr_err(gettext("Invalid options\n"));
2800Sstevel@tonic-gate 					exit(RET_ERR);
2810Sstevel@tonic-gate 				}
2820Sstevel@tonic-gate 			}
2830Sstevel@tonic-gate #endif /* LATER */				/* XXX */
2840Sstevel@tonic-gate 			break;
2850Sstevel@tonic-gate 		case 'm':
2860Sstevel@tonic-gate 			mflg++;
2870Sstevel@tonic-gate 			break;
2880Sstevel@tonic-gate 		case 'O':
2890Sstevel@tonic-gate 			Oflg++;
2900Sstevel@tonic-gate 			break;
2910Sstevel@tonic-gate 		case 'q':
2920Sstevel@tonic-gate 			qflg++;
2930Sstevel@tonic-gate 			break;
2940Sstevel@tonic-gate 		default:
2950Sstevel@tonic-gate 			usage();
2960Sstevel@tonic-gate 			exit(RET_ERR);
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 	if (argc - optind != 2) {
3000Sstevel@tonic-gate 		usage();
3010Sstevel@tonic-gate 		exit(RET_ERR);
3020Sstevel@tonic-gate 	}
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	mnt.mnt_special = argv[optind];
3050Sstevel@tonic-gate 	mnt.mnt_mountp = argv[optind+1];
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	if (!priv_ineffect(PRIV_SYS_MOUNT) ||
3080Sstevel@tonic-gate 	    !priv_ineffect(PRIV_NET_PRIVADDR)) {
3090Sstevel@tonic-gate 		pr_err(gettext("insufficient privileges\n"));
3100Sstevel@tonic-gate 		exit(RET_ERR);
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	/*
3143378Srica 	 * On a labeled system, allow read-down nfs mounts if privileged
3153378Srica 	 * (PRIV_NET_MAC_AWARE) to do so.  Otherwise, ignore the error
3163378Srica 	 * and "mount equal label only" behavior will result.
3173378Srica 	 */
3183378Srica 	if (is_system_labeled())
3193378Srica 		(void) setpflags(NET_MAC_AWARE, 1);
3203378Srica 
3213378Srica 	/*
3220Sstevel@tonic-gate 	 * Read the defaults file to see if the min/max versions have
3230Sstevel@tonic-gate 	 * been set and therefore would override the encoded defaults.
3240Sstevel@tonic-gate 	 * Then check to make sure that if they were set that the
3250Sstevel@tonic-gate 	 * values are reasonable.
3260Sstevel@tonic-gate 	 */
3270Sstevel@tonic-gate 	read_default();
3280Sstevel@tonic-gate 	if (vers_min_default > vers_max_default ||
3295302Sth199096 	    vers_min_default < NFS_VERSMIN ||
3305302Sth199096 	    vers_max_default > NFS_VERSMAX) {
3310Sstevel@tonic-gate 		pr_err("%s %s\n%s %s\n",
3325302Sth199096 		    gettext("Incorrect configuration of client\'s"),
3335302Sth199096 		    NFSADMIN,
3345302Sth199096 		    gettext("NFS_CLIENT_VERSMIN or NFS_CLIENT_VERSMAX"),
3355302Sth199096 		    gettext("is either out of range or overlaps."));
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 
338489Soa138391 	SET_ERR_RET(&retry_error, ERR_PROTO_NONE, 0);
339489Soa138391 	r = mount_nfs(&mnt, ro, &retry_error);
340489Soa138391 	if (r == RET_RETRY && retries) {
341489Soa138391 		/*
342489Soa138391 		 * Check the error code from the last mount attempt if it was
343489Soa138391 		 * an RPC error, then retry as is. Otherwise we retry with the
344489Soa138391 		 * nfsretry_vers set. It is set by decrementing nfsvers_to_use.
345489Soa138391 		 * If we are retrying with nfsretry_vers then we don't print any
346489Soa138391 		 * retry messages, since we are not retrying due to an RPC
347489Soa138391 		 * error.
348489Soa138391 		 */
349489Soa138391 		if (retry_error.error_type) {
350489Soa138391 			if (retry_error.error_type != ERR_RPCERROR) {
351489Soa138391 				nfsretry_vers = nfsvers_to_use =
352489Soa138391 				    nfsvers_to_use - 1;
353489Soa138391 				if (nfsretry_vers < NFS_VERSMIN)
354489Soa138391 					return (r);
355489Soa138391 			}
356489Soa138391 		}
357489Soa138391 
3580Sstevel@tonic-gate 		r = retry(&mnt, ro);
359489Soa138391 	}
3600Sstevel@tonic-gate 	/*
3610Sstevel@tonic-gate 	 * exit(r);
3620Sstevel@tonic-gate 	 */
3630Sstevel@tonic-gate 	return (r);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate static void
3670Sstevel@tonic-gate pr_err(const char *fmt, ...)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate 	va_list ap;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	va_start(ap, fmt);
3720Sstevel@tonic-gate 	if (backgrounded != 0) {
3730Sstevel@tonic-gate 		(void) vsyslog(LOG_ERR, fmt, ap);
3740Sstevel@tonic-gate 	} else {
3750Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", typename);
3760Sstevel@tonic-gate 		(void) vfprintf(stderr, fmt, ap);
3770Sstevel@tonic-gate 		(void) fflush(stderr);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 	va_end(ap);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate static void
3830Sstevel@tonic-gate usage()
3840Sstevel@tonic-gate {
3850Sstevel@tonic-gate 	(void) fprintf(stderr,
3860Sstevel@tonic-gate 	    gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n"));
3870Sstevel@tonic-gate 	exit(RET_ERR);
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate static int
391489Soa138391 mount_nfs(struct mnttab *mntp, int ro, err_ret_t *retry_error)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	struct nfs_args *args = NULL, *argp = NULL, *prev_argp = NULL;
3940Sstevel@tonic-gate 	struct netconfig *nconf = NULL;
3950Sstevel@tonic-gate 	struct replica *list = NULL;
3960Sstevel@tonic-gate 	int mntflags = 0;
3970Sstevel@tonic-gate 	int i, r, n;
3980Sstevel@tonic-gate 	int oldvers = 0, vers = 0;
3990Sstevel@tonic-gate 	int last_error = RET_OK;
4000Sstevel@tonic-gate 	int replicated = 0;
4010Sstevel@tonic-gate 	char *p;
4020Sstevel@tonic-gate 	bool_t url;
4030Sstevel@tonic-gate 	bool_t use_pubfh;
4040Sstevel@tonic-gate 	char *special = NULL;
4050Sstevel@tonic-gate 	char *oldpath = NULL;
4060Sstevel@tonic-gate 	char *newpath = NULL;
4070Sstevel@tonic-gate 	char *service;
4080Sstevel@tonic-gate 	pid_t pi;
4090Sstevel@tonic-gate 	struct flock f;
4100Sstevel@tonic-gate 	char *saveopts = NULL;
4110Sstevel@tonic-gate 	char **sl = NULL;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	mntp->mnt_fstype = MNTTYPE_NFS;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	if (ro) {
4160Sstevel@tonic-gate 		mntflags |= MS_RDONLY;
4170Sstevel@tonic-gate 		/* convert "rw"->"ro" */
4180Sstevel@tonic-gate 		if (p = strstr(mntp->mnt_mntopts, "rw")) {
4190Sstevel@tonic-gate 			if (*(p+2) == ',' || *(p+2) == '\0')
4200Sstevel@tonic-gate 				*(p+1) = 'o';
4210Sstevel@tonic-gate 		}
4220Sstevel@tonic-gate 	}
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	if (Oflg)
4250Sstevel@tonic-gate 		mntflags |= MS_OVERLAY;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	list = parse_replica(mntp->mnt_special, &n);
4280Sstevel@tonic-gate 	if (list == NULL) {
4290Sstevel@tonic-gate 		if (n < 0)
4300Sstevel@tonic-gate 			pr_err(gettext("nfs file system; use [host:]path\n"));
4310Sstevel@tonic-gate 		else
4320Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
4330Sstevel@tonic-gate 		return (RET_ERR);
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	replicated = (n > 1);
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	/*
4390Sstevel@tonic-gate 	 * There are some free() calls at the bottom of this loop, so be
4400Sstevel@tonic-gate 	 * careful about adding continue statements.
4410Sstevel@tonic-gate 	 */
4420Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
4430Sstevel@tonic-gate 		char *path;
4440Sstevel@tonic-gate 		char *host;
4450Sstevel@tonic-gate 		ushort_t port;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 		argp = (struct nfs_args *)malloc(sizeof (*argp));
4480Sstevel@tonic-gate 		if (argp == NULL) {
4490Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
4500Sstevel@tonic-gate 			last_error = RET_ERR;
4510Sstevel@tonic-gate 			goto out;
4520Sstevel@tonic-gate 		}
4530Sstevel@tonic-gate 		memset(argp, 0, sizeof (*argp));
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		memset(&nfs_sec, 0, sizeof (nfs_sec));
4560Sstevel@tonic-gate 		sec_opt = 0;
4570Sstevel@tonic-gate 		use_pubfh = FALSE;
4580Sstevel@tonic-gate 		url = FALSE;
4590Sstevel@tonic-gate 		port = 0;
4600Sstevel@tonic-gate 		snego_done = FALSE;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		/*
4630Sstevel@tonic-gate 		 * Looking for resources of the form
4640Sstevel@tonic-gate 		 *	nfs://server_host[:port_number]/path_name
4650Sstevel@tonic-gate 		 */
4660Sstevel@tonic-gate 		if (strcmp(list[i].host, "nfs") == 0 && strncmp(list[i].path,
4670Sstevel@tonic-gate 		    "//", 2) == 0) {
4680Sstevel@tonic-gate 			char *sport, *cb;
4690Sstevel@tonic-gate 			url = TRUE;
4700Sstevel@tonic-gate 			oldpath = strdup(list[i].path);
4710Sstevel@tonic-gate 			if (oldpath == NULL) {
4720Sstevel@tonic-gate 				pr_err(gettext("memory allocation failure\n"));
4730Sstevel@tonic-gate 				last_error = RET_ERR;
4740Sstevel@tonic-gate 				goto out;
4750Sstevel@tonic-gate 			}
4760Sstevel@tonic-gate 			host = list[i].path+2;
4770Sstevel@tonic-gate 			path = strchr(host, '/');
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 			if (path == NULL) {
4800Sstevel@tonic-gate 				pr_err(gettext(
4810Sstevel@tonic-gate 				    "illegal nfs url syntax\n"));
4820Sstevel@tonic-gate 				last_error = RET_ERR;
4830Sstevel@tonic-gate 				goto out;
4840Sstevel@tonic-gate 			}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 			*path = '\0';
4870Sstevel@tonic-gate 			if (*host == '[') {
4880Sstevel@tonic-gate 				cb = strchr(host, ']');
4890Sstevel@tonic-gate 				if (cb == NULL) {
4900Sstevel@tonic-gate 					pr_err(gettext(
4915302Sth199096 					    "illegal nfs url syntax\n"));
4920Sstevel@tonic-gate 					last_error = RET_ERR;
4930Sstevel@tonic-gate 					goto out;
4940Sstevel@tonic-gate 				} else {
4950Sstevel@tonic-gate 					*cb = '\0';
4960Sstevel@tonic-gate 					host++;
4970Sstevel@tonic-gate 					cb++;
4980Sstevel@tonic-gate 					if (*cb == ':')
4990Sstevel@tonic-gate 						port = htons((ushort_t)
5005302Sth199096 						    atoi(cb+1));
5010Sstevel@tonic-gate 				}
5020Sstevel@tonic-gate 			} else {
5030Sstevel@tonic-gate 				sport = strchr(host, ':');
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 				if (sport != NULL && sport < path) {
5060Sstevel@tonic-gate 					*sport = '\0';
5070Sstevel@tonic-gate 					port = htons((ushort_t)atoi(sport+1));
5080Sstevel@tonic-gate 				}
5090Sstevel@tonic-gate 			}
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 			path++;
5120Sstevel@tonic-gate 			if (*path == '\0')
5130Sstevel@tonic-gate 				path = ".";
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 		} else {
5160Sstevel@tonic-gate 			host = list[i].host;
5170Sstevel@tonic-gate 			path = list[i].path;
5180Sstevel@tonic-gate 		}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 		if (r = set_args(&mntflags, argp, host, mntp)) {
5210Sstevel@tonic-gate 			last_error = r;
5220Sstevel@tonic-gate 			goto out;
5230Sstevel@tonic-gate 		}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		if (public_opt == TRUE)
5260Sstevel@tonic-gate 			use_pubfh = TRUE;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		if (port == 0) {
5290Sstevel@tonic-gate 			port = nfs_port;
5300Sstevel@tonic-gate 		} else if (nfs_port != 0 && nfs_port != port) {
5310Sstevel@tonic-gate 			pr_err(gettext(
5320Sstevel@tonic-gate 			    "port (%u) in nfs URL not the same"
5330Sstevel@tonic-gate 			    " as port (%u) in port option\n"),
5340Sstevel@tonic-gate 			    (unsigned int)ntohs(port),
5350Sstevel@tonic-gate 			    (unsigned int)ntohs(nfs_port));
5360Sstevel@tonic-gate 			last_error = RET_ERR;
5370Sstevel@tonic-gate 			goto out;
5380Sstevel@tonic-gate 		}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 		if (replicated && !(mntflags & MS_RDONLY)) {
5420Sstevel@tonic-gate 			pr_err(gettext(
5435302Sth199096 			    "replicated mounts must be read-only\n"));
5440Sstevel@tonic-gate 			last_error = RET_ERR;
5450Sstevel@tonic-gate 			goto out;
5460Sstevel@tonic-gate 		}
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 		if (replicated && (argp->flags & NFSMNT_SOFT)) {
5490Sstevel@tonic-gate 			pr_err(gettext(
5505302Sth199096 			    "replicated mounts must not be soft\n"));
5510Sstevel@tonic-gate 			last_error = RET_ERR;
5520Sstevel@tonic-gate 			goto out;
5530Sstevel@tonic-gate 		}
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 		oldvers = vers;
5560Sstevel@tonic-gate 		nconf = NULL;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 		r = RET_ERR;
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 		/*
5610Sstevel@tonic-gate 		 * If -o public was specified, and/or a URL was specified,
5620Sstevel@tonic-gate 		 * then try the public file handle method.
5630Sstevel@tonic-gate 		 */
5640Sstevel@tonic-gate 		if ((use_pubfh == TRUE) || (url == TRUE)) {
5650Sstevel@tonic-gate 			r = get_fh_via_pub(argp, host, path, url, use_pubfh,
5665302Sth199096 			    &vers, &nconf, port);
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 			if (r != RET_OK) {
5690Sstevel@tonic-gate 				/*
5700Sstevel@tonic-gate 				 * If -o public was specified, then return the
5710Sstevel@tonic-gate 				 * error now.
5720Sstevel@tonic-gate 				 */
5730Sstevel@tonic-gate 				if (use_pubfh == TRUE) {
5740Sstevel@tonic-gate 					last_error = r;
5750Sstevel@tonic-gate 					goto out;
5760Sstevel@tonic-gate 				}
5770Sstevel@tonic-gate 			} else
5780Sstevel@tonic-gate 				use_pubfh = TRUE;
5790Sstevel@tonic-gate 			argp->flags |= NFSMNT_PUBLIC;
5800Sstevel@tonic-gate 		}
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 		if ((r != RET_OK) || (vers == NFS_V4)) {
5830Sstevel@tonic-gate 			bool_t loud_on_mnt_err;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 			/*
5860Sstevel@tonic-gate 			 * This can happen if -o public is not specified,
5870Sstevel@tonic-gate 			 * special is a URL, and server doesn't support
5880Sstevel@tonic-gate 			 * public file handle.
5890Sstevel@tonic-gate 			 */
5900Sstevel@tonic-gate 			if (url) {
5910Sstevel@tonic-gate 				URLparse(path);
5920Sstevel@tonic-gate 			}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 			/*
5950Sstevel@tonic-gate 			 * If the path portion of the URL didn't have
5960Sstevel@tonic-gate 			 * a leading / then there is good possibility
5970Sstevel@tonic-gate 			 * that a mount without a leading slash will
5980Sstevel@tonic-gate 			 * fail.
5990Sstevel@tonic-gate 			 */
6000Sstevel@tonic-gate 			if (url == TRUE && *path != '/')
6010Sstevel@tonic-gate 				loud_on_mnt_err = FALSE;
6020Sstevel@tonic-gate 			else
6030Sstevel@tonic-gate 				loud_on_mnt_err = TRUE;
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 			r = get_fh(argp, host, path, &vers,
6065302Sth199096 			    loud_on_mnt_err, &nconf, port);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 			if (r != RET_OK) {
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 				/*
6110Sstevel@tonic-gate 				 * If there was no leading / and the path was
6120Sstevel@tonic-gate 				 * derived from a URL, then try again
6130Sstevel@tonic-gate 				 * with a leading /.
6140Sstevel@tonic-gate 				 */
6150Sstevel@tonic-gate 				if ((r == RET_MNTERR) &&
6160Sstevel@tonic-gate 				    (loud_on_mnt_err == FALSE)) {
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 					newpath = malloc(strlen(path)+2);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 					if (newpath == NULL) {
6210Sstevel@tonic-gate 						pr_err(gettext("memory "
6220Sstevel@tonic-gate 						    "allocation failure\n"));
6230Sstevel@tonic-gate 						last_error = RET_ERR;
6240Sstevel@tonic-gate 						goto out;
6250Sstevel@tonic-gate 					}
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 					strcpy(newpath, "/");
6280Sstevel@tonic-gate 					strcat(newpath, path);
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 					r = get_fh(argp, host, newpath, &vers,
6315302Sth199096 					    TRUE, &nconf, port);
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 					if (r == RET_OK)
6340Sstevel@tonic-gate 						path = newpath;
6350Sstevel@tonic-gate 				}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 				/*
6380Sstevel@tonic-gate 				 * map exit code back to RET_ERR.
6390Sstevel@tonic-gate 				 */
6400Sstevel@tonic-gate 				if (r == RET_MNTERR)
6410Sstevel@tonic-gate 					r = RET_ERR;
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 				if (r != RET_OK) {
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 					if (replicated) {
6460Sstevel@tonic-gate 						if (argp->fh)
6470Sstevel@tonic-gate 							free(argp->fh);
6480Sstevel@tonic-gate 						if (argp->pathconf)
6490Sstevel@tonic-gate 							free(argp->pathconf);
6500Sstevel@tonic-gate 						free(argp);
6510Sstevel@tonic-gate 						goto cont;
6520Sstevel@tonic-gate 					}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 					last_error = r;
6550Sstevel@tonic-gate 					goto out;
6560Sstevel@tonic-gate 				}
6570Sstevel@tonic-gate 			}
6580Sstevel@tonic-gate 		}
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 		if (oldvers && vers != oldvers) {
6610Sstevel@tonic-gate 			pr_err(
6620Sstevel@tonic-gate 			    gettext("replicas must have the same version\n"));
6630Sstevel@tonic-gate 			last_error = RET_ERR;
6640Sstevel@tonic-gate 			goto out;
6650Sstevel@tonic-gate 		}
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 		/*
6680Sstevel@tonic-gate 		 * decide whether to use remote host's
6690Sstevel@tonic-gate 		 * lockd or do local locking
6700Sstevel@tonic-gate 		 */
6710Sstevel@tonic-gate 		if (!(argp->flags & NFSMNT_LLOCK) && vers == NFS_VERSION &&
6720Sstevel@tonic-gate 		    remote_lock(host, argp->fh)) {
6730Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
6740Sstevel@tonic-gate 			    "WARNING: No network locking on %s:%s:"),
6750Sstevel@tonic-gate 			    host, path);
6760Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
6770Sstevel@tonic-gate 			    " contact admin to install server change\n"));
6785302Sth199096 			argp->flags |= NFSMNT_LLOCK;
6790Sstevel@tonic-gate 		}
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 		if (self_check(host))
6820Sstevel@tonic-gate 			argp->flags |= NFSMNT_LOOPBACK;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 		if (use_pubfh == FALSE) {
6850Sstevel@tonic-gate 			/*
6860Sstevel@tonic-gate 			 * Call to get_fh() above may have obtained the
6870Sstevel@tonic-gate 			 * netconfig info and NULL proc'd the server.
6880Sstevel@tonic-gate 			 * This would be the case with v4
6890Sstevel@tonic-gate 			 */
6900Sstevel@tonic-gate 			if (!(argp->flags & NFSMNT_KNCONF)) {
6910Sstevel@tonic-gate 				nconf = NULL;
6920Sstevel@tonic-gate 				if (r = getaddr_nfs(argp, host, &nconf,
6935302Sth199096 				    FALSE, path, port, retry_error,
6945302Sth199096 				    TRUE)) {
695489Soa138391 						last_error = r;
696489Soa138391 						goto out;
6970Sstevel@tonic-gate 				}
6980Sstevel@tonic-gate 			}
6990Sstevel@tonic-gate 		}
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 		if (make_secure(argp, host, nconf, use_pubfh, vers) < 0) {
7020Sstevel@tonic-gate 			last_error = RET_ERR;
7030Sstevel@tonic-gate 			goto out;
7040Sstevel@tonic-gate 		}
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 		if ((url == TRUE) && (use_pubfh == FALSE)) {
7070Sstevel@tonic-gate 			/*
7080Sstevel@tonic-gate 			 * Convert the special from
7090Sstevel@tonic-gate 			 *	nfs://host/path
7100Sstevel@tonic-gate 			 * to
7110Sstevel@tonic-gate 			 *	host:path
7120Sstevel@tonic-gate 			 */
7130Sstevel@tonic-gate 			if (convert_special(&special, host, oldpath, path,
7140Sstevel@tonic-gate 			    mntp->mnt_special) == -1) {
7150Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
7160Sstevel@tonic-gate 				    "could not convert URL nfs:%s to %s:%s\n"),
7170Sstevel@tonic-gate 				    oldpath, host, path);
7180Sstevel@tonic-gate 				last_error = RET_ERR;
7190Sstevel@tonic-gate 				goto out;
7200Sstevel@tonic-gate 			} else {
7210Sstevel@tonic-gate 				mntp->mnt_special = special;
7220Sstevel@tonic-gate 			}
7230Sstevel@tonic-gate 		}
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 		if (prev_argp == NULL)
7260Sstevel@tonic-gate 			args = argp;
7270Sstevel@tonic-gate 		else
7280Sstevel@tonic-gate 			prev_argp->nfs_ext_u.nfs_extB.next = argp;
7290Sstevel@tonic-gate 		prev_argp = argp;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate cont:
7320Sstevel@tonic-gate 		if (oldpath != NULL) {
7330Sstevel@tonic-gate 			free(oldpath);
7340Sstevel@tonic-gate 			oldpath = NULL;
7350Sstevel@tonic-gate 		}
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 		if (newpath != NULL) {
7380Sstevel@tonic-gate 			free(newpath);
7390Sstevel@tonic-gate 			newpath = NULL;
7400Sstevel@tonic-gate 		}
7410Sstevel@tonic-gate 	}
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	argp = NULL;
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	if (args == NULL) {
7460Sstevel@tonic-gate 		last_error = RET_RETRY;
7470Sstevel@tonic-gate 		goto out;
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	/* Determine which services are appropriate for the NFS version */
7510Sstevel@tonic-gate 	if (strcmp(fstype, MNTTYPE_NFS4) == 0)
7520Sstevel@tonic-gate 		sl = service_list_v4;
7530Sstevel@tonic-gate 	else
7540Sstevel@tonic-gate 		sl = service_list;
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	/*
7570Sstevel@tonic-gate 	 * enable services as needed.
7580Sstevel@tonic-gate 	 */
7590Sstevel@tonic-gate 	_check_services(sl);
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	mntflags |= MS_DATA | MS_OPTIONSTR;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	if (mflg)
7640Sstevel@tonic-gate 		mntflags |= MS_NOMNTTAB;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	if (!qflg)
7670Sstevel@tonic-gate 		saveopts = strdup(mntp->mnt_mntopts);
7680Sstevel@tonic-gate 
7695302Sth199096 	/*
7705302Sth199096 	 * And make sure that we have the ephemeral mount_to
7715302Sth199096 	 * set for this zone.
7725302Sth199096 	 */
7735302Sth199096 	set_nfsv4_ephemeral_mount_to();
7745302Sth199096 
7750Sstevel@tonic-gate 	if (mount(mntp->mnt_special, mntp->mnt_mountp, mntflags, fstype, args,
7765302Sth199096 	    sizeof (*args), mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) {
7770Sstevel@tonic-gate 		if (errno != ENOENT) {
7780Sstevel@tonic-gate 			pr_err(gettext("mount: %s: %s\n"),
7795302Sth199096 			    mntp->mnt_mountp, strerror(errno));
7800Sstevel@tonic-gate 		} else {
7810Sstevel@tonic-gate 			struct stat sb;
7820Sstevel@tonic-gate 			if (stat(mntp->mnt_mountp, &sb) < 0 && errno == ENOENT)
7830Sstevel@tonic-gate 				pr_err(gettext("mount: %s: %s\n"),
7845302Sth199096 				    mntp->mnt_mountp, strerror(ENOENT));
7850Sstevel@tonic-gate 			else
7860Sstevel@tonic-gate 				pr_err("%s: %s\n", mntp->mnt_special,
7875302Sth199096 				    strerror(ENOENT));
7880Sstevel@tonic-gate 		}
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 		last_error = RET_ERR;
7910Sstevel@tonic-gate 		goto out;
7920Sstevel@tonic-gate 	}
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	if (!qflg && saveopts != NULL) {
7950Sstevel@tonic-gate 		cmp_requested_to_actual_options(saveopts, mntp->mnt_mntopts,
7960Sstevel@tonic-gate 		    mntp->mnt_special, mntp->mnt_mountp);
7970Sstevel@tonic-gate 	}
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate out:
8000Sstevel@tonic-gate 	if (saveopts != NULL)
8010Sstevel@tonic-gate 		free(saveopts);
8020Sstevel@tonic-gate 	if (special != NULL)
8030Sstevel@tonic-gate 		free(special);
8040Sstevel@tonic-gate 	if (oldpath != NULL)
8050Sstevel@tonic-gate 		free(oldpath);
8060Sstevel@tonic-gate 	if (newpath != NULL)
8070Sstevel@tonic-gate 		free(newpath);
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	free_replica(list, n);
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 	if (argp != NULL) {
8120Sstevel@tonic-gate 		/*
8130Sstevel@tonic-gate 		 * If we had a new entry which was not added to the
8140Sstevel@tonic-gate 		 * list yet, then add it now that it can be freed.
8150Sstevel@tonic-gate 		 */
8160Sstevel@tonic-gate 		if (prev_argp == NULL)
8170Sstevel@tonic-gate 			args = argp;
8180Sstevel@tonic-gate 		else
8190Sstevel@tonic-gate 			prev_argp->nfs_ext_u.nfs_extB.next = argp;
8200Sstevel@tonic-gate 	}
8210Sstevel@tonic-gate 	argp = args;
8220Sstevel@tonic-gate 	while (argp != NULL) {
8230Sstevel@tonic-gate 		if (argp->fh)
8240Sstevel@tonic-gate 			free(argp->fh);
8250Sstevel@tonic-gate 		if (argp->pathconf)
8260Sstevel@tonic-gate 			free(argp->pathconf);
8270Sstevel@tonic-gate 		if (argp->knconf)
8280Sstevel@tonic-gate 			free(argp->knconf);
8290Sstevel@tonic-gate 		if (argp->addr) {
8300Sstevel@tonic-gate 			free(argp->addr->buf);
8310Sstevel@tonic-gate 			free(argp->addr);
8320Sstevel@tonic-gate 		}
8330Sstevel@tonic-gate 		nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata);
8340Sstevel@tonic-gate 		if (argp->syncaddr) {
8350Sstevel@tonic-gate 			free(argp->syncaddr->buf);
8360Sstevel@tonic-gate 			free(argp->syncaddr);
8370Sstevel@tonic-gate 		}
8380Sstevel@tonic-gate 		if (argp->netname)
8390Sstevel@tonic-gate 			free(argp->netname);
8400Sstevel@tonic-gate 		prev_argp = argp;
8410Sstevel@tonic-gate 		argp = argp->nfs_ext_u.nfs_extB.next;
8420Sstevel@tonic-gate 		free(prev_argp);
8430Sstevel@tonic-gate 	}
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	return (last_error);
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate /*
8490Sstevel@tonic-gate  * These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c
8500Sstevel@tonic-gate  * Changes must be made to both lists.
8510Sstevel@tonic-gate  */
8520Sstevel@tonic-gate static char *optlist[] = {
8530Sstevel@tonic-gate #define	OPT_RO		0
8540Sstevel@tonic-gate 	MNTOPT_RO,
8550Sstevel@tonic-gate #define	OPT_RW		1
8560Sstevel@tonic-gate 	MNTOPT_RW,
8570Sstevel@tonic-gate #define	OPT_QUOTA	2
8580Sstevel@tonic-gate 	MNTOPT_QUOTA,
8590Sstevel@tonic-gate #define	OPT_NOQUOTA	3
8600Sstevel@tonic-gate 	MNTOPT_NOQUOTA,
8610Sstevel@tonic-gate #define	OPT_SOFT	4
8620Sstevel@tonic-gate 	MNTOPT_SOFT,
8630Sstevel@tonic-gate #define	OPT_HARD	5
8640Sstevel@tonic-gate 	MNTOPT_HARD,
8650Sstevel@tonic-gate #define	OPT_SUID	6
8660Sstevel@tonic-gate 	MNTOPT_SUID,
8670Sstevel@tonic-gate #define	OPT_NOSUID	7
8680Sstevel@tonic-gate 	MNTOPT_NOSUID,
8690Sstevel@tonic-gate #define	OPT_GRPID	8
8700Sstevel@tonic-gate 	MNTOPT_GRPID,
8710Sstevel@tonic-gate #define	OPT_REMOUNT	9
8720Sstevel@tonic-gate 	MNTOPT_REMOUNT,
8730Sstevel@tonic-gate #define	OPT_NOSUB	10
8740Sstevel@tonic-gate 	MNTOPT_NOSUB,
8750Sstevel@tonic-gate #define	OPT_INTR	11
8760Sstevel@tonic-gate 	MNTOPT_INTR,
8770Sstevel@tonic-gate #define	OPT_NOINTR	12
8780Sstevel@tonic-gate 	MNTOPT_NOINTR,
8790Sstevel@tonic-gate #define	OPT_PORT	13
8800Sstevel@tonic-gate 	MNTOPT_PORT,
8810Sstevel@tonic-gate #define	OPT_SECURE	14
8820Sstevel@tonic-gate 	MNTOPT_SECURE,
8830Sstevel@tonic-gate #define	OPT_RSIZE	15
8840Sstevel@tonic-gate 	MNTOPT_RSIZE,
8850Sstevel@tonic-gate #define	OPT_WSIZE	16
8860Sstevel@tonic-gate 	MNTOPT_WSIZE,
8870Sstevel@tonic-gate #define	OPT_TIMEO	17
8880Sstevel@tonic-gate 	MNTOPT_TIMEO,
8890Sstevel@tonic-gate #define	OPT_RETRANS	18
8900Sstevel@tonic-gate 	MNTOPT_RETRANS,
8910Sstevel@tonic-gate #define	OPT_ACTIMEO	19
8920Sstevel@tonic-gate 	MNTOPT_ACTIMEO,
8930Sstevel@tonic-gate #define	OPT_ACREGMIN	20
8940Sstevel@tonic-gate 	MNTOPT_ACREGMIN,
8950Sstevel@tonic-gate #define	OPT_ACREGMAX	21
8960Sstevel@tonic-gate 	MNTOPT_ACREGMAX,
8970Sstevel@tonic-gate #define	OPT_ACDIRMIN	22
8980Sstevel@tonic-gate 	MNTOPT_ACDIRMIN,
8990Sstevel@tonic-gate #define	OPT_ACDIRMAX	23
9000Sstevel@tonic-gate 	MNTOPT_ACDIRMAX,
9010Sstevel@tonic-gate #define	OPT_BG		24
9020Sstevel@tonic-gate 	MNTOPT_BG,
9030Sstevel@tonic-gate #define	OPT_FG		25
9040Sstevel@tonic-gate 	MNTOPT_FG,
9050Sstevel@tonic-gate #define	OPT_RETRY	26
9060Sstevel@tonic-gate 	MNTOPT_RETRY,
9070Sstevel@tonic-gate #define	OPT_NOAC	27
9080Sstevel@tonic-gate 	MNTOPT_NOAC,
9090Sstevel@tonic-gate #define	OPT_NOCTO	28
9100Sstevel@tonic-gate 	MNTOPT_NOCTO,
9110Sstevel@tonic-gate #define	OPT_LLOCK	29
9120Sstevel@tonic-gate 	MNTOPT_LLOCK,
9130Sstevel@tonic-gate #define	OPT_POSIX	30
9140Sstevel@tonic-gate 	MNTOPT_POSIX,
9150Sstevel@tonic-gate #define	OPT_VERS	31
9160Sstevel@tonic-gate 	MNTOPT_VERS,
9170Sstevel@tonic-gate #define	OPT_PROTO	32
9180Sstevel@tonic-gate 	MNTOPT_PROTO,
9190Sstevel@tonic-gate #define	OPT_SEMISOFT	33
9200Sstevel@tonic-gate 	MNTOPT_SEMISOFT,
9210Sstevel@tonic-gate #define	OPT_NOPRINT	34
9220Sstevel@tonic-gate 	MNTOPT_NOPRINT,
9230Sstevel@tonic-gate #define	OPT_SEC		35
9240Sstevel@tonic-gate 	MNTOPT_SEC,
9250Sstevel@tonic-gate #define	OPT_LARGEFILES	36
9260Sstevel@tonic-gate 	MNTOPT_LARGEFILES,
9270Sstevel@tonic-gate #define	OPT_NOLARGEFILES 37
9280Sstevel@tonic-gate 	MNTOPT_NOLARGEFILES,
9290Sstevel@tonic-gate #define	OPT_PUBLIC	38
9300Sstevel@tonic-gate 	MNTOPT_PUBLIC,
9310Sstevel@tonic-gate #define	OPT_DIRECTIO	39
9320Sstevel@tonic-gate 	MNTOPT_FORCEDIRECTIO,
9330Sstevel@tonic-gate #define	OPT_NODIRECTIO	40
9340Sstevel@tonic-gate 	MNTOPT_NOFORCEDIRECTIO,
9350Sstevel@tonic-gate #define	OPT_XATTR	41
9360Sstevel@tonic-gate 	MNTOPT_XATTR,
9370Sstevel@tonic-gate #define	OPT_NOXATTR	42
9380Sstevel@tonic-gate 	MNTOPT_NOXATTR,
9390Sstevel@tonic-gate #define	OPT_DEVICES	43
9400Sstevel@tonic-gate 	MNTOPT_DEVICES,
9410Sstevel@tonic-gate #define	OPT_NODEVICES	44
9420Sstevel@tonic-gate 	MNTOPT_NODEVICES,
9430Sstevel@tonic-gate #define	OPT_SETUID	45
9440Sstevel@tonic-gate 	MNTOPT_SETUID,
9450Sstevel@tonic-gate #define	OPT_NOSETUID	46
9460Sstevel@tonic-gate 	MNTOPT_NOSETUID,
9470Sstevel@tonic-gate #define	OPT_EXEC	47
9480Sstevel@tonic-gate 	MNTOPT_EXEC,
9490Sstevel@tonic-gate #define	OPT_NOEXEC	48
9500Sstevel@tonic-gate 	MNTOPT_NOEXEC,
9510Sstevel@tonic-gate 	NULL
9520Sstevel@tonic-gate };
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate #define	bad(val) (val == NULL || !isdigit(*val))
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate static int
9570Sstevel@tonic-gate set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt)
9580Sstevel@tonic-gate {
9590Sstevel@tonic-gate 	char *saveopt, *optstr, *opts, *newopts, *val;
9600Sstevel@tonic-gate 	int largefiles = 0;
9610Sstevel@tonic-gate 	int invalid = 0;
9620Sstevel@tonic-gate 	int attrpref = 0;
9630Sstevel@tonic-gate 	int optlen;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	args->flags = NFSMNT_INT;	/* default is "intr" */
9660Sstevel@tonic-gate 	args->flags |= NFSMNT_HOSTNAME;
9670Sstevel@tonic-gate 	args->flags |= NFSMNT_NEWARGS;	/* using extented nfs_args structure */
9680Sstevel@tonic-gate 	args->hostname = fshost;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	optstr = opts = strdup(mnt->mnt_mntopts);
9710Sstevel@tonic-gate 	/* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */
9720Sstevel@tonic-gate 	optlen = strlen(mnt->mnt_mntopts) + sizeof (MNTOPT_XATTR) + 1;
9730Sstevel@tonic-gate 	if (optlen > MAX_MNTOPT_STR) {
9740Sstevel@tonic-gate 		pr_err(gettext("option string too long"));
9750Sstevel@tonic-gate 		return (RET_ERR);
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate 	newopts = malloc(optlen);
9780Sstevel@tonic-gate 	if (opts == NULL || newopts == NULL) {
9790Sstevel@tonic-gate 		pr_err(gettext("no memory"));
9800Sstevel@tonic-gate 		if (opts)
9810Sstevel@tonic-gate 			free(opts);
9820Sstevel@tonic-gate 		if (newopts)
9830Sstevel@tonic-gate 			free(newopts);
9840Sstevel@tonic-gate 		return (RET_ERR);
9850Sstevel@tonic-gate 	}
9860Sstevel@tonic-gate 	newopts[0] = '\0';
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	while (*opts) {
9890Sstevel@tonic-gate 		invalid = 0;
9900Sstevel@tonic-gate 		saveopt = opts;
9910Sstevel@tonic-gate 		switch (getsubopt(&opts, optlist, &val)) {
9920Sstevel@tonic-gate 		case OPT_RO:
9930Sstevel@tonic-gate 			*mntflags |= MS_RDONLY;
9940Sstevel@tonic-gate 			break;
9950Sstevel@tonic-gate 		case OPT_RW:
9960Sstevel@tonic-gate 			*mntflags &= ~(MS_RDONLY);
9970Sstevel@tonic-gate 			break;
9980Sstevel@tonic-gate 		case OPT_QUOTA:
9990Sstevel@tonic-gate 		case OPT_NOQUOTA:
10000Sstevel@tonic-gate 			break;
10010Sstevel@tonic-gate 		case OPT_SOFT:
10020Sstevel@tonic-gate 			args->flags |= NFSMNT_SOFT;
10030Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_SEMISOFT);
10040Sstevel@tonic-gate 			break;
10050Sstevel@tonic-gate 		case OPT_SEMISOFT:
10060Sstevel@tonic-gate 			args->flags |= NFSMNT_SOFT;
10070Sstevel@tonic-gate 			args->flags |= NFSMNT_SEMISOFT;
10080Sstevel@tonic-gate 			break;
10090Sstevel@tonic-gate 		case OPT_HARD:
10100Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_SOFT);
10110Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_SEMISOFT);
10120Sstevel@tonic-gate 			break;
10130Sstevel@tonic-gate 		case OPT_SUID:
10140Sstevel@tonic-gate 			*mntflags &= ~(MS_NOSUID);
10150Sstevel@tonic-gate 			break;
10160Sstevel@tonic-gate 		case OPT_NOSUID:
10170Sstevel@tonic-gate 			*mntflags |= MS_NOSUID;
10180Sstevel@tonic-gate 			break;
10190Sstevel@tonic-gate 		case OPT_GRPID:
10200Sstevel@tonic-gate 			args->flags |= NFSMNT_GRPID;
10210Sstevel@tonic-gate 			break;
10220Sstevel@tonic-gate 		case OPT_REMOUNT:
10230Sstevel@tonic-gate 			*mntflags |= MS_REMOUNT;
10240Sstevel@tonic-gate 			break;
10250Sstevel@tonic-gate 		case OPT_INTR:
10260Sstevel@tonic-gate 			args->flags |= NFSMNT_INT;
10270Sstevel@tonic-gate 			break;
10280Sstevel@tonic-gate 		case OPT_NOINTR:
10290Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_INT);
10300Sstevel@tonic-gate 			break;
10310Sstevel@tonic-gate 		case OPT_NOAC:
10320Sstevel@tonic-gate 			args->flags |= NFSMNT_NOAC;
10330Sstevel@tonic-gate 			break;
10340Sstevel@tonic-gate 		case OPT_PORT:
10350Sstevel@tonic-gate 			if (bad(val))
10360Sstevel@tonic-gate 				goto badopt;
10370Sstevel@tonic-gate 			nfs_port = htons((ushort_t)atoi(val));
10380Sstevel@tonic-gate 			break;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 		case OPT_SECURE:
10410Sstevel@tonic-gate 			if (nfs_getseconfig_byname("dh", &nfs_sec)) {
10425302Sth199096 				pr_err(gettext("can not get \"dh\" from %s\n"),
10435302Sth199096 				    NFSSEC_CONF);
10445302Sth199096 				goto badopt;
10450Sstevel@tonic-gate 			}
10460Sstevel@tonic-gate 			sec_opt++;
10470Sstevel@tonic-gate 			break;
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 		case OPT_NOCTO:
10500Sstevel@tonic-gate 			args->flags |= NFSMNT_NOCTO;
10510Sstevel@tonic-gate 			break;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 		case OPT_RSIZE:
10540Sstevel@tonic-gate 			args->flags |= NFSMNT_RSIZE;
10550Sstevel@tonic-gate 			if (bad(val))
10560Sstevel@tonic-gate 				goto badopt;
10570Sstevel@tonic-gate 			args->rsize = atoi(val);
10580Sstevel@tonic-gate 			break;
10590Sstevel@tonic-gate 		case OPT_WSIZE:
10600Sstevel@tonic-gate 			args->flags |= NFSMNT_WSIZE;
10610Sstevel@tonic-gate 			if (bad(val))
10620Sstevel@tonic-gate 				goto badopt;
10630Sstevel@tonic-gate 			args->wsize = atoi(val);
10640Sstevel@tonic-gate 			break;
10650Sstevel@tonic-gate 		case OPT_TIMEO:
10660Sstevel@tonic-gate 			args->flags |= NFSMNT_TIMEO;
10670Sstevel@tonic-gate 			if (bad(val))
10680Sstevel@tonic-gate 				goto badopt;
10690Sstevel@tonic-gate 			args->timeo = atoi(val);
10700Sstevel@tonic-gate 			break;
10710Sstevel@tonic-gate 		case OPT_RETRANS:
10720Sstevel@tonic-gate 			args->flags |= NFSMNT_RETRANS;
10730Sstevel@tonic-gate 			if (bad(val))
10740Sstevel@tonic-gate 				goto badopt;
10750Sstevel@tonic-gate 			args->retrans = atoi(val);
10760Sstevel@tonic-gate 			break;
10770Sstevel@tonic-gate 		case OPT_ACTIMEO:
10780Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMAX;
10790Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMAX;
10800Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMIN;
10810Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMIN;
10820Sstevel@tonic-gate 			if (bad(val))
10830Sstevel@tonic-gate 				goto badopt;
10840Sstevel@tonic-gate 			args->acdirmin = args->acregmin = args->acdirmax
10855302Sth199096 			    = args->acregmax = atoi(val);
10860Sstevel@tonic-gate 			break;
10870Sstevel@tonic-gate 		case OPT_ACREGMIN:
10880Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMIN;
10890Sstevel@tonic-gate 			if (bad(val))
10900Sstevel@tonic-gate 				goto badopt;
10910Sstevel@tonic-gate 			args->acregmin = atoi(val);
10920Sstevel@tonic-gate 			break;
10930Sstevel@tonic-gate 		case OPT_ACREGMAX:
10940Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMAX;
10950Sstevel@tonic-gate 			if (bad(val))
10960Sstevel@tonic-gate 				goto badopt;
10970Sstevel@tonic-gate 			args->acregmax = atoi(val);
10980Sstevel@tonic-gate 			break;
10990Sstevel@tonic-gate 		case OPT_ACDIRMIN:
11000Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMIN;
11010Sstevel@tonic-gate 			if (bad(val))
11020Sstevel@tonic-gate 				goto badopt;
11030Sstevel@tonic-gate 			args->acdirmin = atoi(val);
11040Sstevel@tonic-gate 			break;
11050Sstevel@tonic-gate 		case OPT_ACDIRMAX:
11060Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMAX;
11070Sstevel@tonic-gate 			if (bad(val))
11080Sstevel@tonic-gate 				goto badopt;
11090Sstevel@tonic-gate 			args->acdirmax = atoi(val);
11100Sstevel@tonic-gate 			break;
11110Sstevel@tonic-gate 		case OPT_BG:
11120Sstevel@tonic-gate 			bg++;
11130Sstevel@tonic-gate 			break;
11140Sstevel@tonic-gate 		case OPT_FG:
11150Sstevel@tonic-gate 			bg = 0;
11160Sstevel@tonic-gate 			break;
11170Sstevel@tonic-gate 		case OPT_RETRY:
11180Sstevel@tonic-gate 			if (bad(val))
11190Sstevel@tonic-gate 				goto badopt;
11200Sstevel@tonic-gate 			retries = atoi(val);
11210Sstevel@tonic-gate 			break;
11220Sstevel@tonic-gate 		case OPT_LLOCK:
11230Sstevel@tonic-gate 			args->flags |= NFSMNT_LLOCK;
11240Sstevel@tonic-gate 			break;
11250Sstevel@tonic-gate 		case OPT_POSIX:
11260Sstevel@tonic-gate 			posix = 1;
11270Sstevel@tonic-gate 			break;
11280Sstevel@tonic-gate 		case OPT_VERS:
11290Sstevel@tonic-gate 			if (bad(val))
11300Sstevel@tonic-gate 				goto badopt;
11310Sstevel@tonic-gate 			nfsvers = (rpcvers_t)atoi(val);
11320Sstevel@tonic-gate 			break;
11330Sstevel@tonic-gate 		case OPT_PROTO:
113477Soa138391 			if (val == NULL)
113577Soa138391 				goto badopt;
113677Soa138391 
11370Sstevel@tonic-gate 			nfs_proto = (char *)malloc(strlen(val)+1);
113877Soa138391 			if (!nfs_proto) {
113977Soa138391 				pr_err(gettext("no memory"));
114077Soa138391 				return (RET_ERR);
114177Soa138391 			}
114277Soa138391 
114377Soa138391 			(void) strncpy(nfs_proto, val, strlen(val)+1);
11440Sstevel@tonic-gate 			break;
11455302Sth199096 
11460Sstevel@tonic-gate 		case OPT_NOPRINT:
11470Sstevel@tonic-gate 			args->flags |= NFSMNT_NOPRINT;
11480Sstevel@tonic-gate 			break;
11495302Sth199096 
11500Sstevel@tonic-gate 		case OPT_LARGEFILES:
11510Sstevel@tonic-gate 			largefiles = 1;
11520Sstevel@tonic-gate 			break;
11535302Sth199096 
11540Sstevel@tonic-gate 		case OPT_NOLARGEFILES:
11550Sstevel@tonic-gate 			pr_err(gettext("NFS can't support \"nolargefiles\"\n"));
11560Sstevel@tonic-gate 			free(optstr);
11570Sstevel@tonic-gate 			return (RET_ERR);
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 		case OPT_SEC:
11600Sstevel@tonic-gate 			if (nfs_getseconfig_byname(val, &nfs_sec)) {
11615302Sth199096 				pr_err(gettext("can not get \"%s\" from %s\n"),
11625302Sth199096 				    val, NFSSEC_CONF);
11635302Sth199096 				return (RET_ERR);
11640Sstevel@tonic-gate 			}
11650Sstevel@tonic-gate 			sec_opt++;
11660Sstevel@tonic-gate 			break;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 		case OPT_PUBLIC:
11690Sstevel@tonic-gate 			public_opt = TRUE;
11700Sstevel@tonic-gate 			break;
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 		case OPT_DIRECTIO:
11730Sstevel@tonic-gate 			args->flags |= NFSMNT_DIRECTIO;
11740Sstevel@tonic-gate 			break;
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 		case OPT_NODIRECTIO:
11770Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_DIRECTIO);
11780Sstevel@tonic-gate 			break;
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 		case OPT_XATTR:
11810Sstevel@tonic-gate 		case OPT_NOXATTR:
11820Sstevel@tonic-gate 			/*
11830Sstevel@tonic-gate 			 * VFS options; just need to get them into the
11840Sstevel@tonic-gate 			 * new mount option string and note we've seen them
11850Sstevel@tonic-gate 			 */
11860Sstevel@tonic-gate 			attrpref = 1;
11870Sstevel@tonic-gate 			break;
11880Sstevel@tonic-gate 		default:
11890Sstevel@tonic-gate 			/*
11900Sstevel@tonic-gate 			 * Note that this could be a valid OPT_* option so
11910Sstevel@tonic-gate 			 * we can't use "val" but need to use "saveopt".
11920Sstevel@tonic-gate 			 */
11930Sstevel@tonic-gate 			if (fsisstdopt(saveopt))
11940Sstevel@tonic-gate 				break;
11950Sstevel@tonic-gate 			invalid = 1;
11960Sstevel@tonic-gate 			if (!qflg)
11970Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
11980Sstevel@tonic-gate 				    "mount: %s on %s - WARNING unknown option"
11990Sstevel@tonic-gate 				    " \"%s\"\n"), mnt->mnt_special,
12000Sstevel@tonic-gate 				    mnt->mnt_mountp, saveopt);
12010Sstevel@tonic-gate 			break;
12020Sstevel@tonic-gate 		}
12030Sstevel@tonic-gate 		if (!invalid) {
12040Sstevel@tonic-gate 			if (newopts[0])
12050Sstevel@tonic-gate 				strcat(newopts, ",");
12060Sstevel@tonic-gate 			strcat(newopts, saveopt);
12070Sstevel@tonic-gate 		}
12080Sstevel@tonic-gate 	}
12090Sstevel@tonic-gate 	/* Default is to turn extended attrs on */
12100Sstevel@tonic-gate 	if (!attrpref) {
12110Sstevel@tonic-gate 		if (newopts[0])
12120Sstevel@tonic-gate 			strcat(newopts, ",");
12130Sstevel@tonic-gate 		strcat(newopts, MNTOPT_XATTR);
12140Sstevel@tonic-gate 	}
12150Sstevel@tonic-gate 	strcpy(mnt->mnt_mntopts, newopts);
12160Sstevel@tonic-gate 	free(newopts);
12170Sstevel@tonic-gate 	free(optstr);
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	/* ensure that only one secure mode is requested */
12200Sstevel@tonic-gate 	if (sec_opt > 1) {
12210Sstevel@tonic-gate 		pr_err(gettext("Security options conflict\n"));
12220Sstevel@tonic-gate 		return (RET_ERR);
12230Sstevel@tonic-gate 	}
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	/* ensure that the user isn't trying to get large files over V2 */
12260Sstevel@tonic-gate 	if (nfsvers == NFS_VERSION && largefiles) {
12270Sstevel@tonic-gate 		pr_err(gettext("NFS V2 can't support \"largefiles\"\n"));
12280Sstevel@tonic-gate 		return (RET_ERR);
12290Sstevel@tonic-gate 	}
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	if (nfsvers == NFS_V4 &&
12320Sstevel@tonic-gate 	    nfs_proto != NULL &&
12330Sstevel@tonic-gate 	    strncasecmp(nfs_proto, NC_UDP, strlen(NC_UDP)) == 0) {
12340Sstevel@tonic-gate 		pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto);
12350Sstevel@tonic-gate 		return (RET_ERR);
12360Sstevel@tonic-gate 	}
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	return (RET_OK);
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate badopt:
12410Sstevel@tonic-gate 	pr_err(gettext("invalid option: \"%s\"\n"), saveopt);
12420Sstevel@tonic-gate 	free(optstr);
12430Sstevel@tonic-gate 	return (RET_ERR);
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate static int
12470Sstevel@tonic-gate make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf,
12480Sstevel@tonic-gate 	bool_t use_pubfh, rpcvers_t vers)
12490Sstevel@tonic-gate {
12500Sstevel@tonic-gate 	sec_data_t *secdata;
12510Sstevel@tonic-gate 	int flags;
12520Sstevel@tonic-gate 	struct netbuf *syncaddr = NULL;
12530Sstevel@tonic-gate 	struct nd_addrlist *retaddrs = NULL;
12540Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	/*
12570Sstevel@tonic-gate 	 * check to see if any secure mode is requested.
12580Sstevel@tonic-gate 	 * if not, use default security mode.
12590Sstevel@tonic-gate 	 */
12600Sstevel@tonic-gate 	if (!snego_done && !sec_opt) {
12610Sstevel@tonic-gate 		/*
12625302Sth199096 		 * Get default security mode.
12635302Sth199096 		 * AUTH_UNIX has been the default choice for a long time.
12645302Sth199096 		 * The better NFS security service becomes, the better chance
12655302Sth199096 		 * we will set stronger security service as the default NFS
12665302Sth199096 		 * security mode.
12670Sstevel@tonic-gate 		 */
12685302Sth199096 		if (nfs_getseconfig_default(&nfs_sec)) {
12695302Sth199096 			pr_err(gettext("error getting default"
12705302Sth199096 			    " security entry\n"));
12715302Sth199096 			return (-1);
12725302Sth199096 		}
12735302Sth199096 		args->flags |= NFSMNT_SECDEFAULT;
12740Sstevel@tonic-gate 	}
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	/*
12770Sstevel@tonic-gate 	 * Get the network address for the time service on the server.
12780Sstevel@tonic-gate 	 * If an RPC based time service is not available then try the
12790Sstevel@tonic-gate 	 * IP time service.
12800Sstevel@tonic-gate 	 *
12810Sstevel@tonic-gate 	 * This is for AUTH_DH processing. We will also pass down syncaddr
12820Sstevel@tonic-gate 	 * and netname for NFS V4 even if AUTH_DH is not requested right now.
12830Sstevel@tonic-gate 	 * NFS V4 does security negotiation in the kernel via SECINFO.
12840Sstevel@tonic-gate 	 * These information might be needed later in the kernel.
12850Sstevel@tonic-gate 	 *
12860Sstevel@tonic-gate 	 * Eventurally, we want to move this code to nfs_clnt_secdata()
12870Sstevel@tonic-gate 	 * when autod_nfs.c and mount.c can share the same get_the_addr()
12880Sstevel@tonic-gate 	 * routine.
12890Sstevel@tonic-gate 	 */
12900Sstevel@tonic-gate 	flags = 0;
12910Sstevel@tonic-gate 	syncaddr = NULL;
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	if (nfs_sec.sc_rpcnum == AUTH_DH || vers == NFS_V4) {
12940Sstevel@tonic-gate 		/*
12950Sstevel@tonic-gate 		 * If using the public fh or nfsv4, we will not contact the
12960Sstevel@tonic-gate 		 * remote RPCBINDer, since it is possibly behind a firewall.
12970Sstevel@tonic-gate 		 */
12985302Sth199096 		if (use_pubfh == FALSE && vers != NFS_V4)
12990Sstevel@tonic-gate 			syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS,
13005302Sth199096 			    nconf, 0, NULL, NULL, FALSE, NULL, NULL);
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 		if (syncaddr != NULL) {
13030Sstevel@tonic-gate 			/* for flags in sec_data */
13040Sstevel@tonic-gate 			flags |= AUTH_F_RPCTIMESYNC;
13050Sstevel@tonic-gate 		} else {
13060Sstevel@tonic-gate 			struct nd_hostserv hs;
13070Sstevel@tonic-gate 			int error;
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 			hs.h_host = hostname;
13100Sstevel@tonic-gate 			hs.h_serv = "timserver";
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 			error = netdir_getbyname(nconf, &hs, &retaddrs);
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 			if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) {
13155302Sth199096 				pr_err(gettext("%s: secure: no time service\n"),
13165302Sth199096 				    hostname);
13175302Sth199096 				return (-1);
13180Sstevel@tonic-gate 			}
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 			if (error == ND_OK)
13210Sstevel@tonic-gate 				syncaddr = retaddrs->n_addrs;
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 			/*
13240Sstevel@tonic-gate 			 * For NFS_V4 if AUTH_DH is negotiated later in the
13250Sstevel@tonic-gate 			 * kernel thru SECINFO, it will need syncaddr
13260Sstevel@tonic-gate 			 * and netname data.
13270Sstevel@tonic-gate 			 */
13280Sstevel@tonic-gate 			if (vers == NFS_V4 && syncaddr &&
13295302Sth199096 			    host2netname(netname, hostname, NULL)) {
13305302Sth199096 				args->syncaddr = malloc(sizeof (struct netbuf));
13315302Sth199096 				args->syncaddr->buf = malloc(syncaddr->len);
13325302Sth199096 				(void) memcpy(args->syncaddr->buf,
13335302Sth199096 				    syncaddr->buf, syncaddr->len);
13345302Sth199096 				args->syncaddr->len = syncaddr->len;
13355302Sth199096 				args->syncaddr->maxlen = syncaddr->maxlen;
13365302Sth199096 				args->netname = strdup(netname);
13375302Sth199096 				args->flags |= NFSMNT_SECURE;
13380Sstevel@tonic-gate 			}
13390Sstevel@tonic-gate 		}
13400Sstevel@tonic-gate 	}
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	/*
13430Sstevel@tonic-gate 	 * For the initial chosen flavor (any flavor defined in nfssec.conf),
13440Sstevel@tonic-gate 	 * the data will be stored in the sec_data structure via
13450Sstevel@tonic-gate 	 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
13460Sstevel@tonic-gate 	 * extended data structure.
13470Sstevel@tonic-gate 	 */
13480Sstevel@tonic-gate 	if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf,
13495302Sth199096 	    syncaddr, flags))) {
13500Sstevel@tonic-gate 		pr_err(gettext("errors constructing security related data\n"));
13510Sstevel@tonic-gate 		if (flags & AUTH_F_RPCTIMESYNC) {
13520Sstevel@tonic-gate 			free(syncaddr->buf);
13530Sstevel@tonic-gate 			free(syncaddr);
13540Sstevel@tonic-gate 		} else if (retaddrs)
13550Sstevel@tonic-gate 			netdir_free((void *)retaddrs, ND_ADDRLIST);
13560Sstevel@tonic-gate 		return (-1);
13570Sstevel@tonic-gate 	}
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	NFS_ARGS_EXTB_secdata(args, secdata);
13600Sstevel@tonic-gate 	if (flags & AUTH_F_RPCTIMESYNC) {
13610Sstevel@tonic-gate 		free(syncaddr->buf);
13620Sstevel@tonic-gate 		free(syncaddr);
13630Sstevel@tonic-gate 	} else if (retaddrs)
13640Sstevel@tonic-gate 		netdir_free((void *)retaddrs, ND_ADDRLIST);
13650Sstevel@tonic-gate 	return (0);
13660Sstevel@tonic-gate }
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate /*
13690Sstevel@tonic-gate  * Get the network address on "hostname" for program "prog"
13700Sstevel@tonic-gate  * with version "vers" by using the nconf configuration data
13710Sstevel@tonic-gate  * passed in.
13720Sstevel@tonic-gate  *
13730Sstevel@tonic-gate  * If the address of a netconfig pointer is null then
13740Sstevel@tonic-gate  * information is not sufficient and no netbuf will be returned.
13750Sstevel@tonic-gate  *
13760Sstevel@tonic-gate  * Finally, ping the null procedure of that service.
13770Sstevel@tonic-gate  *
13780Sstevel@tonic-gate  * A similar routine is also defined in ../../autofs/autod_nfs.c.
13790Sstevel@tonic-gate  * This is a potential routine to move to ../lib for common usage.
13800Sstevel@tonic-gate  */
13810Sstevel@tonic-gate static struct netbuf *
13820Sstevel@tonic-gate get_the_addr(char *hostname, ulong_t prog, ulong_t vers,
13830Sstevel@tonic-gate 	struct netconfig *nconf, ushort_t port, struct t_info *tinfo,
13840Sstevel@tonic-gate 	caddr_t *fhp, bool_t get_pubfh, char *fspath, err_ret_t *error)
13850Sstevel@tonic-gate {
13860Sstevel@tonic-gate 	struct netbuf *nb = NULL;
13870Sstevel@tonic-gate 	struct t_bind *tbind = NULL;
13880Sstevel@tonic-gate 	CLIENT *cl = NULL;
13890Sstevel@tonic-gate 	struct timeval tv;
13900Sstevel@tonic-gate 	int fd = -1;
13910Sstevel@tonic-gate 	AUTH *ah = NULL;
13920Sstevel@tonic-gate 	AUTH *new_ah = NULL;
13930Sstevel@tonic-gate 	struct snego_t snego;
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	if (nconf == NULL)
13960Sstevel@tonic-gate 		return (NULL);
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1)
13995302Sth199096 		goto done;
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 	/* LINTED pointer alignment */
14020Sstevel@tonic-gate 	if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
14035302Sth199096 	    == NULL)
14040Sstevel@tonic-gate 		goto done;
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	/*
14070Sstevel@tonic-gate 	 * In the case of public filehandle usage or NFSv4 we want to
14080Sstevel@tonic-gate 	 * avoid use of the rpcbind/portmap protocol
14090Sstevel@tonic-gate 	 */
14100Sstevel@tonic-gate 	if ((get_pubfh == TRUE) || (vers == NFS_V4)) {
14110Sstevel@tonic-gate 		struct nd_hostserv hs;
14120Sstevel@tonic-gate 		struct nd_addrlist *retaddrs;
14130Sstevel@tonic-gate 		int retval;
14140Sstevel@tonic-gate 		hs.h_host = hostname;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 		/* NFS where vers==4 does not support UDP */
14170Sstevel@tonic-gate 		if (vers == NFS_V4 &&
14180Sstevel@tonic-gate 		    strncasecmp(nconf->nc_proto, NC_UDP,
14195302Sth199096 		    strlen(NC_UDP)) == 0) {
142077Soa138391 			SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
14210Sstevel@tonic-gate 			goto done;
14220Sstevel@tonic-gate 		}
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 		if (port == 0)
14250Sstevel@tonic-gate 			hs.h_serv = "nfs";
14260Sstevel@tonic-gate 		else
14270Sstevel@tonic-gate 			hs.h_serv = NULL;
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 		if ((retval = netdir_getbyname(nconf, &hs, &retaddrs))
14300Sstevel@tonic-gate 		    != ND_OK) {
14310Sstevel@tonic-gate 			/*
14320Sstevel@tonic-gate 			 * Carefully set the error value here. Want to signify
14330Sstevel@tonic-gate 			 * that the error was an unknown host.
14340Sstevel@tonic-gate 			 */
14350Sstevel@tonic-gate 			if (retval == ND_NOHOST) {
14360Sstevel@tonic-gate 				SET_ERR_RET(error, ERR_NOHOST, retval);
14370Sstevel@tonic-gate 			}
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 			goto done;
14400Sstevel@tonic-gate 		}
14410Sstevel@tonic-gate 		memcpy(tbind->addr.buf, retaddrs->n_addrs->buf,
14425302Sth199096 		    retaddrs->n_addrs->len);
14430Sstevel@tonic-gate 		tbind->addr.len = retaddrs->n_addrs->len;
14440Sstevel@tonic-gate 		netdir_free((void *)retaddrs, ND_ADDRLIST);
14450Sstevel@tonic-gate 		(void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL);
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	} else {
14480Sstevel@tonic-gate 		if (rpcb_getaddr(prog, vers, nconf, &tbind->addr,
14490Sstevel@tonic-gate 		    hostname) == FALSE) {
14500Sstevel@tonic-gate 			goto done;
14510Sstevel@tonic-gate 		}
14520Sstevel@tonic-gate 	}
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	if (port) {
14550Sstevel@tonic-gate 		/* LINTED pointer alignment */
14560Sstevel@tonic-gate 		if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
14570Sstevel@tonic-gate 			((struct sockaddr_in *)tbind->addr.buf)->sin_port
14585302Sth199096 			    = port;
14590Sstevel@tonic-gate 		else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
14600Sstevel@tonic-gate 			((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port
14615302Sth199096 			    = port;
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	}
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
14660Sstevel@tonic-gate 	if (cl == NULL) {
146777Soa138391 		/*
146877Soa138391 		 * clnt_tli_create() returns either RPC_SYSTEMERROR,
146977Soa138391 		 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates
147077Soa138391 		 * to "Misc. TLI error". This is not too helpful. Most likely
147177Soa138391 		 * the connection to the remote server timed out, so this
147277Soa138391 		 * error is at least less perplexing.
147377Soa138391 		 * See: usr/src/cmd/rpcinfo/rpcinfo.c
147477Soa138391 		 */
147577Soa138391 		if (rpc_createerr.cf_stat == RPC_TLIERROR) {
147677Soa138391 			SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE);
147777Soa138391 		} else {
147877Soa138391 			SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat);
147977Soa138391 		}
14800Sstevel@tonic-gate 		goto done;
14810Sstevel@tonic-gate 	}
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	ah = authsys_create_default();
14840Sstevel@tonic-gate 	if (ah != NULL)
14850Sstevel@tonic-gate 		cl->cl_auth = ah;
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	tv.tv_sec = 5;
14880Sstevel@tonic-gate 	tv.tv_usec = 0;
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 	(void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	if ((get_pubfh == TRUE) && (vers != NFS_V4)) {
14935302Sth199096 		enum snego_stat sec;
14940Sstevel@tonic-gate 
14955302Sth199096 		if (!snego_done) {
14965302Sth199096 			/*
14975302Sth199096 			 * negotiate sec flavor.
14985302Sth199096 			 */
14995302Sth199096 			snego.cnt = 0;
15005302Sth199096 			if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) ==
15015302Sth199096 			    SNEGO_SUCCESS) {
15025302Sth199096 				int jj;
15030Sstevel@tonic-gate 
15045302Sth199096 				/*
15055302Sth199096 				 * check if server supports the one
15065302Sth199096 				 * specified in the sec= option.
15075302Sth199096 				 */
15080Sstevel@tonic-gate 				if (sec_opt) {
15095302Sth199096 					for (jj = 0; jj < snego.cnt; jj++) {
15105302Sth199096 						if (snego.array[jj] ==
15115302Sth199096 						    nfs_sec.sc_nfsnum) {
15125302Sth199096 							snego_done = TRUE;
15135302Sth199096 							break;
15145302Sth199096 						}
15155302Sth199096 					}
15160Sstevel@tonic-gate 				}
15175302Sth199096 
15185302Sth199096 				/*
15195302Sth199096 				 * find a common sec flavor
15205302Sth199096 				 */
15215302Sth199096 				if (!snego_done) {
15225302Sth199096 					if (sec_opt) {
15235302Sth199096 						pr_err(gettext(
15245302Sth199096 						    "Server does not support"
15255302Sth199096 						    " the security flavor"
15265302Sth199096 						    " specified.\n"));
15275302Sth199096 					}
15280Sstevel@tonic-gate 
15295302Sth199096 					for (jj = 0; jj < snego.cnt; jj++) {
15305302Sth199096 						if (!nfs_getseconfig_bynumber(
15315302Sth199096 						    snego.array[jj],
15325302Sth199096 						    &nfs_sec)) {
15335302Sth199096 							snego_done = TRUE;
15345302Sth199096 #define	EMSG80SUX "Security flavor %d was negotiated and will be used.\n"
15355302Sth199096 							if (sec_opt)
15365302Sth199096 								pr_err(gettext(
15375302Sth199096 								    EMSG80SUX),
15385302Sth199096 								    nfs_sec.
15395302Sth199096 								    sc_nfsnum);
15405302Sth199096 							break;
15415302Sth199096 						}
15425302Sth199096 					}
15435302Sth199096 				}
15445302Sth199096 
15455302Sth199096 				if (!snego_done)
15465302Sth199096 					return (NULL);
15470Sstevel@tonic-gate 
15485302Sth199096 				/*
15495302Sth199096 				 * Now that the flavor has been
15505302Sth199096 				 * negotiated, get the fh.
15515302Sth199096 				 *
15525302Sth199096 				 * First, create an auth handle using the
15535302Sth199096 				 * negotiated sec flavor in the next lookup to
15545302Sth199096 				 * fetch the filehandle.
15555302Sth199096 				 */
15565302Sth199096 				new_ah = nfs_create_ah(cl, hostname, &nfs_sec);
15575302Sth199096 				if (new_ah == NULL)
15585302Sth199096 					goto done;
15595302Sth199096 				cl->cl_auth = new_ah;
15605302Sth199096 			} else if (sec == SNEGO_ARRAY_TOO_SMALL || sec ==
15615302Sth199096 			    SNEGO_FAILURE) {
15625302Sth199096 				goto done;
15635302Sth199096 			}
15640Sstevel@tonic-gate 
15655302Sth199096 			/*
15665302Sth199096 			 * Note that if sec == SNEGO_DEF_VALID
15675302Sth199096 			 * default sec flavor is acceptable.
15685302Sth199096 			 * Use it to get the filehandle.
15695302Sth199096 			 */
15700Sstevel@tonic-gate 		}
15710Sstevel@tonic-gate 
15725302Sth199096 		if (vers == NFS_VERSION) {
15735302Sth199096 			wnl_diropargs arg;
15745302Sth199096 			wnl_diropres *res;
15755302Sth199096 
15765302Sth199096 			memset((char *)&arg.dir, 0, sizeof (wnl_fh));
15775302Sth199096 			arg.name = fspath;
15785302Sth199096 			res = wnlproc_lookup_2(&arg, cl);
15795302Sth199096 
15805302Sth199096 			if (res == NULL || res->status != NFS_OK)
15815302Sth199096 				goto done;
15825302Sth199096 			*fhp = malloc(sizeof (wnl_fh));
15830Sstevel@tonic-gate 
15845302Sth199096 			if (*fhp == NULL) {
15855302Sth199096 				pr_err(gettext("no memory\n"));
15865302Sth199096 				goto done;
15875302Sth199096 			}
15880Sstevel@tonic-gate 
15895302Sth199096 			memcpy((char *)*fhp,
15905302Sth199096 			    (char *)&res->wnl_diropres_u.wnl_diropres.file,
15915302Sth199096 			    sizeof (wnl_fh));
15925302Sth199096 		} else {
15935302Sth199096 			WNL_LOOKUP3args arg;
15945302Sth199096 			WNL_LOOKUP3res *res;
15955302Sth199096 			nfs_fh3 *fh3p;
15960Sstevel@tonic-gate 
15975302Sth199096 			memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
15985302Sth199096 			arg.what.name = fspath;
15995302Sth199096 			res = wnlproc3_lookup_3(&arg, cl);
16005302Sth199096 
16015302Sth199096 			if (res == NULL || res->status != NFS3_OK)
16025302Sth199096 				goto done;
16035302Sth199096 
16045302Sth199096 			fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
16050Sstevel@tonic-gate 
16065302Sth199096 			if (fh3p == NULL) {
16075302Sth199096 				pr_err(gettext("no memory\n"));
16085302Sth199096 				CLNT_FREERES(cl, xdr_WNL_LOOKUP3res,
16095302Sth199096 				    (char *)res);
16105302Sth199096 				goto done;
16115302Sth199096 			}
16120Sstevel@tonic-gate 
16135302Sth199096 			fh3p->fh3_length =
16145302Sth199096 			    res->WNL_LOOKUP3res_u.res_ok.object.data.data_len;
16155302Sth199096 			memcpy(fh3p->fh3_u.data,
16165302Sth199096 			    res->WNL_LOOKUP3res_u.res_ok.object.data.data_val,
16175302Sth199096 			    fh3p->fh3_length);
16180Sstevel@tonic-gate 
16195302Sth199096 			*fhp = (caddr_t)fh3p;
16205302Sth199096 			CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res);
16215302Sth199096 		}
16220Sstevel@tonic-gate 	} else {
16230Sstevel@tonic-gate 		void *res;
16240Sstevel@tonic-gate 		struct rpc_err r_err;
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 		if (vers == NFS_VERSION)
16275302Sth199096 			res = wnlproc_null_2(NULL, cl);
16280Sstevel@tonic-gate 		else if (vers == NFS_V3)
16295302Sth199096 			res = wnlproc3_null_3(NULL, cl);
16300Sstevel@tonic-gate 		else
16315302Sth199096 			res = wnlproc4_null_4(NULL, cl);
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 		if (res == NULL) {
16340Sstevel@tonic-gate 			clnt_geterr(cl, &r_err);
16350Sstevel@tonic-gate 			if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
16360Sstevel@tonic-gate 				switch (r_err.re_status) {
16370Sstevel@tonic-gate 				case RPC_TLIERROR:
16380Sstevel@tonic-gate 				case RPC_CANTRECV:
16390Sstevel@tonic-gate 				case RPC_CANTSEND:
16400Sstevel@tonic-gate 					r_err.re_status = RPC_PROGVERSMISMATCH;
16410Sstevel@tonic-gate 				}
16420Sstevel@tonic-gate 			}
16430Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status);
16440Sstevel@tonic-gate 			goto done;
16450Sstevel@tonic-gate 		}
16460Sstevel@tonic-gate 	}
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	/*
16490Sstevel@tonic-gate 	 * Make a copy of the netbuf to return
16500Sstevel@tonic-gate 	 */
16510Sstevel@tonic-gate 	nb = (struct netbuf *)malloc(sizeof (*nb));
16520Sstevel@tonic-gate 	if (nb == NULL) {
16530Sstevel@tonic-gate 		pr_err(gettext("no memory\n"));
16540Sstevel@tonic-gate 		goto done;
16550Sstevel@tonic-gate 	}
16560Sstevel@tonic-gate 	*nb = tbind->addr;
16570Sstevel@tonic-gate 	nb->buf = (char *)malloc(nb->maxlen);
16580Sstevel@tonic-gate 	if (nb->buf == NULL) {
16590Sstevel@tonic-gate 		pr_err(gettext("no memory\n"));
16600Sstevel@tonic-gate 		free(nb);
16610Sstevel@tonic-gate 		nb = NULL;
16620Sstevel@tonic-gate 		goto done;
16630Sstevel@tonic-gate 	}
16640Sstevel@tonic-gate 	(void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate done:
16670Sstevel@tonic-gate 	if (cl) {
16685302Sth199096 		if (ah != NULL) {
16695302Sth199096 			if (new_ah != NULL)
16705302Sth199096 				AUTH_DESTROY(ah);
16715302Sth199096 			AUTH_DESTROY(cl->cl_auth);
16725302Sth199096 			cl->cl_auth = NULL;
16735302Sth199096 		}
16745302Sth199096 		clnt_destroy(cl);
16755302Sth199096 		cl = NULL;
16760Sstevel@tonic-gate 	}
16770Sstevel@tonic-gate 	if (tbind) {
16780Sstevel@tonic-gate 		t_free((char *)tbind, T_BIND);
16790Sstevel@tonic-gate 		tbind = NULL;
16800Sstevel@tonic-gate 	}
16810Sstevel@tonic-gate 	if (fd >= 0)
16820Sstevel@tonic-gate 		(void) t_close(fd);
16830Sstevel@tonic-gate 	return (nb);
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate 
16865302Sth199096 static int
16875302Sth199096 check_nconf(struct netconfig *nconf, int nthtry, int *valid_proto)
16885302Sth199096 {
16895302Sth199096 	int	try_test = 0;
16905302Sth199096 	int	valid_family;
16915302Sth199096 	char	*proto = NULL;
16925302Sth199096 
16935302Sth199096 
16945302Sth199096 	if (nthtry == FIRST_TRY) {
16955302Sth199096 		try_test = ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
16965302Sth199096 		    (nconf->nc_semantics == NC_TPI_COTS));
16975302Sth199096 		proto = NC_TCP;
16985302Sth199096 	} else if (nthtry == SECOND_TRY) {
16995302Sth199096 		try_test = (nconf->nc_semantics == NC_TPI_CLTS);
17005302Sth199096 		proto = NC_UDP;
17015302Sth199096 	}
17025302Sth199096 
17035302Sth199096 	if (proto &&
17045302Sth199096 	    (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
17055302Sth199096 	    strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
17065302Sth199096 	    (strcmp(nconf->nc_proto, proto) == 0))
17075302Sth199096 		*valid_proto = TRUE;
17085302Sth199096 	else
17095302Sth199096 		*valid_proto = FALSE;
17105302Sth199096 
17115302Sth199096 	return (try_test);
17125302Sth199096 }
17135302Sth199096 
17140Sstevel@tonic-gate /*
17150Sstevel@tonic-gate  * Get a network address on "hostname" for program "prog"
17160Sstevel@tonic-gate  * with version "vers".  If the port number is specified (non zero)
17170Sstevel@tonic-gate  * then try for a TCP/UDP transport and set the port number of the
17180Sstevel@tonic-gate  * resulting IP address.
17190Sstevel@tonic-gate  *
17200Sstevel@tonic-gate  * If the address of a netconfig pointer was passed and
17210Sstevel@tonic-gate  * if it's not null, use it as the netconfig otherwise
17220Sstevel@tonic-gate  * assign the address of the netconfig that was used to
17230Sstevel@tonic-gate  * establish contact with the service.
17240Sstevel@tonic-gate  *
17250Sstevel@tonic-gate  * A similar routine is also defined in ../../autofs/autod_nfs.c.
17260Sstevel@tonic-gate  * This is a potential routine to move to ../lib for common usage.
17270Sstevel@tonic-gate  *
17280Sstevel@tonic-gate  * "error" refers to a more descriptive term when get_addr fails
17290Sstevel@tonic-gate  * and returns NULL: ERR_PROTO_NONE if no error introduced by
17300Sstevel@tonic-gate  * -o proto option, ERR_NETPATH if error found in NETPATH
17310Sstevel@tonic-gate  * environment variable, ERR_PROTO_INVALID if an unrecognized
17320Sstevel@tonic-gate  * protocol is specified by user, and ERR_PROTO_UNSUPP for a
17330Sstevel@tonic-gate  * recognized but invalid protocol (eg. ticlts, ticots, etc.).
17340Sstevel@tonic-gate  * "error" is ignored if get_addr returns non-NULL result.
17350Sstevel@tonic-gate  *
17360Sstevel@tonic-gate  */
17370Sstevel@tonic-gate static struct netbuf *
17380Sstevel@tonic-gate get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp,
17390Sstevel@tonic-gate 	char *proto, ushort_t port, struct t_info *tinfo, caddr_t *fhp,
17400Sstevel@tonic-gate 	bool_t get_pubfh, char *fspath, err_ret_t *error)
17410Sstevel@tonic-gate {
17420Sstevel@tonic-gate 	struct netbuf *nb = NULL;
17430Sstevel@tonic-gate 	struct netconfig *nconf = NULL;
17440Sstevel@tonic-gate 	NCONF_HANDLE *nc = NULL;
17450Sstevel@tonic-gate 	int nthtry = FIRST_TRY;
17460Sstevel@tonic-gate 	err_ret_t errsave_nohost, errsave_rpcerr;
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	SET_ERR_RET(&errsave_nohost, ERR_PROTO_NONE, 0);
17490Sstevel@tonic-gate 	SET_ERR_RET(&errsave_rpcerr, ERR_PROTO_NONE, 0);
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 	SET_ERR_RET(error, ERR_PROTO_NONE, 0);
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 	if (nconfp && *nconfp)
17540Sstevel@tonic-gate 		return (get_the_addr(hostname, prog, vers, *nconfp, port,
17555302Sth199096 		    tinfo, fhp, get_pubfh, fspath, error));
17560Sstevel@tonic-gate 	/*
17570Sstevel@tonic-gate 	 * No nconf passed in.
17580Sstevel@tonic-gate 	 *
17590Sstevel@tonic-gate 	 * Try to get a nconf from /etc/netconfig filtered by
17600Sstevel@tonic-gate 	 * the NETPATH environment variable.
17610Sstevel@tonic-gate 	 * First search for COTS, second for CLTS unless proto
17620Sstevel@tonic-gate 	 * is specified.  When we retry, we reset the
17630Sstevel@tonic-gate 	 * netconfig list so that we would search the whole list
17640Sstevel@tonic-gate 	 * all over again.
17650Sstevel@tonic-gate 	 */
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 	if ((nc = setnetpath()) == NULL) {
17680Sstevel@tonic-gate 		/* should only return an error if problems with NETPATH */
17690Sstevel@tonic-gate 		/* In which case you are hosed */
17700Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_NETPATH, 0);
17710Sstevel@tonic-gate 		goto done;
17720Sstevel@tonic-gate 	}
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 	/*
17750Sstevel@tonic-gate 	 * If proto is specified, then only search for the match,
17760Sstevel@tonic-gate 	 * otherwise try COTS first, if failed, try CLTS.
17770Sstevel@tonic-gate 	 */
17780Sstevel@tonic-gate 	if (proto) {
17790Sstevel@tonic-gate 		/* no matching proto name */
17800Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_PROTO_INVALID, 0);
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 		while (nconf = getnetpath(nc)) {
17830Sstevel@tonic-gate 			if (strcmp(nconf->nc_netid, proto))
17840Sstevel@tonic-gate 				continue;
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 			/* may be unsupported */
17870Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 			if ((port != 0) &&
17905302Sth199096 			    ((strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
17915302Sth199096 			    strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
17925302Sth199096 			    (strcmp(nconf->nc_proto, NC_TCP) != 0 &&
17935302Sth199096 			    strcmp(nconf->nc_proto, NC_UDP) != 0))) {
17940Sstevel@tonic-gate 				continue;
17955302Sth199096 			} else {
17960Sstevel@tonic-gate 				nb = get_the_addr(hostname, prog,
17975302Sth199096 				    vers, nconf, port, tinfo,
17985302Sth199096 				    fhp, get_pubfh, fspath, error);
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 				if (nb != NULL)
18010Sstevel@tonic-gate 					break;
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate 				/* nb is NULL - deal with errors */
18040Sstevel@tonic-gate 				if (error) {
18050Sstevel@tonic-gate 					if (error->error_type == ERR_NOHOST)
18060Sstevel@tonic-gate 						SET_ERR_RET(&errsave_nohost,
18075302Sth199096 						    error->error_type,
18085302Sth199096 						    error->error_value);
18090Sstevel@tonic-gate 					if (error->error_type == ERR_RPCERROR)
18100Sstevel@tonic-gate 						SET_ERR_RET(&errsave_rpcerr,
18115302Sth199096 						    error->error_type,
18125302Sth199096 						    error->error_value);
18130Sstevel@tonic-gate 				}
18140Sstevel@tonic-gate 				/*
18150Sstevel@tonic-gate 				 * continue with same protocol
18160Sstevel@tonic-gate 				 * selection
18170Sstevel@tonic-gate 				 */
18180Sstevel@tonic-gate 				continue;
18190Sstevel@tonic-gate 			}
18200Sstevel@tonic-gate 		} /* end of while */
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate 		if (nconf == NULL)
18230Sstevel@tonic-gate 			goto done;
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 		if ((nb = get_the_addr(hostname, prog, vers, nconf, port,
18265302Sth199096 		    tinfo, fhp, get_pubfh, fspath, error)) == NULL)
18270Sstevel@tonic-gate 			goto done;
18280Sstevel@tonic-gate 	} else {
18290Sstevel@tonic-gate retry:
18300Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_NETPATH, 0);
18310Sstevel@tonic-gate 		while (nconf = getnetpath(nc)) {
18320Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_PROTO_NONE, 0);
18335302Sth199096 
18340Sstevel@tonic-gate 			if (nconf->nc_flag & NC_VISIBLE) {
18355302Sth199096 				int	valid_proto;
18360Sstevel@tonic-gate 
18375302Sth199096 				if (check_nconf(nconf,
18385302Sth199096 				    nthtry, &valid_proto)) {
18395302Sth199096 					if (port == 0)
18405302Sth199096 						break;
18415302Sth199096 
18425302Sth199096 					if (valid_proto == TRUE)
18435302Sth199096 						break;
18440Sstevel@tonic-gate 				}
18450Sstevel@tonic-gate 			}
18460Sstevel@tonic-gate 		} /* while */
18470Sstevel@tonic-gate 		if (nconf == NULL) {
18480Sstevel@tonic-gate 			if (++nthtry <= MNT_PREF_LISTLEN) {
18490Sstevel@tonic-gate 				endnetpath(nc);
18500Sstevel@tonic-gate 				if ((nc = setnetpath()) == NULL)
18510Sstevel@tonic-gate 					goto done;
18520Sstevel@tonic-gate 				goto retry;
18530Sstevel@tonic-gate 			} else
18540Sstevel@tonic-gate 				goto done;
18550Sstevel@tonic-gate 		} else {
18560Sstevel@tonic-gate 			if ((nb = get_the_addr(hostname, prog, vers, nconf,
18575302Sth199096 			    port, tinfo, fhp, get_pubfh, fspath, error))
18585302Sth199096 			    == NULL) {
18590Sstevel@tonic-gate 				/* nb is NULL - deal with errors */
18600Sstevel@tonic-gate 				if (error) {
18610Sstevel@tonic-gate 					if (error->error_type == ERR_NOHOST)
18620Sstevel@tonic-gate 						SET_ERR_RET(&errsave_nohost,
18635302Sth199096 						    error->error_type,
18645302Sth199096 						    error->error_value);
18650Sstevel@tonic-gate 					if (error->error_type == ERR_RPCERROR)
18660Sstevel@tonic-gate 						SET_ERR_RET(&errsave_rpcerr,
18675302Sth199096 						    error->error_type,
18685302Sth199096 						    error->error_value);
18690Sstevel@tonic-gate 				}
18700Sstevel@tonic-gate 				/*
18710Sstevel@tonic-gate 				 * Continue the same search path in the
18720Sstevel@tonic-gate 				 * netconfig db until no more matched
18730Sstevel@tonic-gate 				 * nconf (nconf == NULL).
18740Sstevel@tonic-gate 				 */
18750Sstevel@tonic-gate 				goto retry;
18760Sstevel@tonic-gate 			}
18770Sstevel@tonic-gate 		}
18780Sstevel@tonic-gate 	}
18790Sstevel@tonic-gate 	SET_ERR_RET(error, ERR_PROTO_NONE, 0);
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate 	/*
18820Sstevel@tonic-gate 	 * Got nconf and nb.  Now dup the netconfig structure (nconf)
18830Sstevel@tonic-gate 	 * and return it thru nconfp.
18840Sstevel@tonic-gate 	 */
18850Sstevel@tonic-gate 	*nconfp = getnetconfigent(nconf->nc_netid);
18860Sstevel@tonic-gate 	if (*nconfp == NULL) {
18870Sstevel@tonic-gate 		syslog(LOG_ERR, "no memory\n");
18880Sstevel@tonic-gate 		free(nb);
18890Sstevel@tonic-gate 		nb = NULL;
18900Sstevel@tonic-gate 	}
18910Sstevel@tonic-gate done:
18920Sstevel@tonic-gate 	if (nc)
18930Sstevel@tonic-gate 		endnetpath(nc);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	if (nb == NULL) {
189677Soa138391 		/*
189777Soa138391 		 * Check the saved errors. The RPC error has *
189877Soa138391 		 * precedence over the no host error.
189977Soa138391 		 */
190077Soa138391 		if (errsave_nohost.error_type != ERR_PROTO_NONE)
190177Soa138391 			SET_ERR_RET(error, errsave_nohost.error_type,
19025302Sth199096 			    errsave_nohost.error_value);
190377Soa138391 
190477Soa138391 		if (errsave_rpcerr.error_type != ERR_PROTO_NONE)
190577Soa138391 			SET_ERR_RET(error, errsave_rpcerr.error_type,
19065302Sth199096 			    errsave_rpcerr.error_value);
19070Sstevel@tonic-gate 	}
190877Soa138391 
19090Sstevel@tonic-gate 	return (nb);
19100Sstevel@tonic-gate }
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate /*
19130Sstevel@tonic-gate  * Get a file handle usinging multi-component lookup with the public
19140Sstevel@tonic-gate  * file handle.
19150Sstevel@tonic-gate  */
19160Sstevel@tonic-gate static int
19170Sstevel@tonic-gate get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url,
19180Sstevel@tonic-gate 	bool_t loud, int *versp, struct netconfig **nconfp, ushort_t port)
19190Sstevel@tonic-gate {
19200Sstevel@tonic-gate 	uint_t vers_min;
19210Sstevel@tonic-gate 	uint_t vers_max;
19220Sstevel@tonic-gate 	int r;
19230Sstevel@tonic-gate 	char *path;
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate 	if (nfsvers != 0) {
19260Sstevel@tonic-gate 		vers_max = vers_min = nfsvers;
19270Sstevel@tonic-gate 	} else {
19280Sstevel@tonic-gate 		vers_max = vers_max_default;
19290Sstevel@tonic-gate 		vers_min = vers_min_default;
19300Sstevel@tonic-gate 	}
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate 	if (url == FALSE) {
19330Sstevel@tonic-gate 		path = malloc(strlen(fspath) + 2);
19340Sstevel@tonic-gate 		if (path == NULL) {
19355302Sth199096 			if (loud == TRUE)
19360Sstevel@tonic-gate 				pr_err(gettext("no memory\n"));
19370Sstevel@tonic-gate 			return (RET_ERR);
19380Sstevel@tonic-gate 		}
19390Sstevel@tonic-gate 
19400Sstevel@tonic-gate 		path[0] = (char)WNL_NATIVEPATH;
19410Sstevel@tonic-gate 		(void) strcpy(&path[1], fspath);
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	} else  {
19440Sstevel@tonic-gate 		path = fspath;
19450Sstevel@tonic-gate 	}
19460Sstevel@tonic-gate 
19470Sstevel@tonic-gate 	for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min;
19480Sstevel@tonic-gate 	    nfsvers_to_use--) {
19490Sstevel@tonic-gate 		/*
19500Sstevel@tonic-gate 		 * getaddr_nfs will also fill in the fh for us.
19510Sstevel@tonic-gate 		 */
19520Sstevel@tonic-gate 		r = getaddr_nfs(args, fshost, nconfp,
19535302Sth199096 		    TRUE, path, port, NULL, FALSE);
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 		if (r == RET_OK) {
19560Sstevel@tonic-gate 			/*
19570Sstevel@tonic-gate 			 * Since we are using the public fh, and NLM is
19580Sstevel@tonic-gate 			 * not firewall friendly, use local locking.
19590Sstevel@tonic-gate 			 * Not the case for v4.
19600Sstevel@tonic-gate 			 */
19610Sstevel@tonic-gate 			*versp = nfsvers_to_use;
19620Sstevel@tonic-gate 			switch (nfsvers_to_use) {
19630Sstevel@tonic-gate 			case NFS_V4:
19640Sstevel@tonic-gate 				fstype = MNTTYPE_NFS4;
19650Sstevel@tonic-gate 				break;
19660Sstevel@tonic-gate 			case NFS_V3:
19670Sstevel@tonic-gate 				fstype = MNTTYPE_NFS3;
19680Sstevel@tonic-gate 				/* fall through to pick up llock option */
19690Sstevel@tonic-gate 			default:
19700Sstevel@tonic-gate 				args->flags |= NFSMNT_LLOCK;
19710Sstevel@tonic-gate 				break;
19720Sstevel@tonic-gate 			}
19730Sstevel@tonic-gate 			if (fspath != path)
19740Sstevel@tonic-gate 				free(path);
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate 			return (r);
19770Sstevel@tonic-gate 		}
19780Sstevel@tonic-gate 	}
19790Sstevel@tonic-gate 
19805302Sth199096 	if (fspath != path)
19810Sstevel@tonic-gate 		free(path);
19820Sstevel@tonic-gate 
19830Sstevel@tonic-gate 	if (loud == TRUE) {
19840Sstevel@tonic-gate 		pr_err(gettext("Could not use public filehandle in request to"
19855302Sth199096 		    " server %s\n"), fshost);
19860Sstevel@tonic-gate 	}
19870Sstevel@tonic-gate 
19880Sstevel@tonic-gate 	return (r);
19890Sstevel@tonic-gate }
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate /*
19920Sstevel@tonic-gate  * get fhandle of remote path from server's mountd
19930Sstevel@tonic-gate  */
19940Sstevel@tonic-gate static int
19950Sstevel@tonic-gate get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp,
19960Sstevel@tonic-gate 	bool_t loud_on_mnt_err, struct netconfig **nconfp, ushort_t port)
19970Sstevel@tonic-gate {
19980Sstevel@tonic-gate 	static struct fhstatus fhs;
19990Sstevel@tonic-gate 	static struct mountres3 mountres3;
20000Sstevel@tonic-gate 	static struct pathcnf p;
20010Sstevel@tonic-gate 	nfs_fh3 *fh3p;
20020Sstevel@tonic-gate 	struct timeval timeout = { 25, 0};
20030Sstevel@tonic-gate 	CLIENT *cl;
20040Sstevel@tonic-gate 	enum clnt_stat rpc_stat;
20050Sstevel@tonic-gate 	rpcvers_t outvers = 0;
20060Sstevel@tonic-gate 	rpcvers_t vers_to_try;
20070Sstevel@tonic-gate 	rpcvers_t vers_min;
20080Sstevel@tonic-gate 	static int printed = 0;
20090Sstevel@tonic-gate 	int count, i, *auths;
20100Sstevel@tonic-gate 	char *msg;
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	switch (nfsvers) {
20130Sstevel@tonic-gate 	case 2: /* version 2 specified try that only */
20140Sstevel@tonic-gate 		vers_to_try = MOUNTVERS_POSIX;
20150Sstevel@tonic-gate 		vers_min = MOUNTVERS;
20160Sstevel@tonic-gate 		break;
20170Sstevel@tonic-gate 	case 3: /* version 3 specified try that only */
20180Sstevel@tonic-gate 		vers_to_try = MOUNTVERS3;
20190Sstevel@tonic-gate 		vers_min = MOUNTVERS3;
20200Sstevel@tonic-gate 		break;
20210Sstevel@tonic-gate 	case 4: /* version 4 specified try that only */
20220Sstevel@tonic-gate 		/*
20230Sstevel@tonic-gate 		 * This assignment is in the wrong version sequence.
20240Sstevel@tonic-gate 		 * The above are MOUNT program and this is NFS
20250Sstevel@tonic-gate 		 * program.  However, it happens to work out since the
20260Sstevel@tonic-gate 		 * two don't collide for NFSv4.
20270Sstevel@tonic-gate 		 */
20280Sstevel@tonic-gate 		vers_to_try = NFS_V4;
20290Sstevel@tonic-gate 		vers_min = NFS_V4;
20300Sstevel@tonic-gate 		break;
20310Sstevel@tonic-gate 	default: /* no version specified, start with default */
2032489Soa138391 		/*
2033489Soa138391 		 * If the retry version is set, use that. This will
2034489Soa138391 		 * be set if the last mount attempt returned any other
2035489Soa138391 		 * besides an RPC error.
2036489Soa138391 		 */
2037489Soa138391 		if (nfsretry_vers)
2038489Soa138391 			vers_to_try = nfsretry_vers;
2039489Soa138391 		else {
2040489Soa138391 			vers_to_try = vers_max_default;
2041489Soa138391 			vers_min = vers_min_default;
2042489Soa138391 		}
2043489Soa138391 
20440Sstevel@tonic-gate 		break;
20450Sstevel@tonic-gate 	}
20460Sstevel@tonic-gate 
20470Sstevel@tonic-gate 	/*
20480Sstevel@tonic-gate 	 * In the case of version 4, just NULL proc the server since
20490Sstevel@tonic-gate 	 * there is no MOUNT program.  If this fails, then decrease
20500Sstevel@tonic-gate 	 * vers_to_try and continue on with regular MOUNT program
20510Sstevel@tonic-gate 	 * processing.
20520Sstevel@tonic-gate 	 */
20530Sstevel@tonic-gate 	if (vers_to_try == NFS_V4) {
20540Sstevel@tonic-gate 		int savevers = nfsvers_to_use;
20550Sstevel@tonic-gate 		err_ret_t error;
20560Sstevel@tonic-gate 		int retval;
20570Sstevel@tonic-gate 		SET_ERR_RET(&error, ERR_PROTO_NONE, 0);
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate 		/* Let's hope for the best */
20600Sstevel@tonic-gate 		nfsvers_to_use = NFS_V4;
20615302Sth199096 		retval = getaddr_nfs(args, fshost, nconfp, FALSE,
20625302Sth199096 		    fspath, port, &error, vers_min == NFS_V4);
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate 		if (retval == RET_OK) {
20650Sstevel@tonic-gate 			*versp = nfsvers_to_use = NFS_V4;
20660Sstevel@tonic-gate 			fstype = MNTTYPE_NFS4;
20670Sstevel@tonic-gate 			args->fh = strdup(fspath);
20680Sstevel@tonic-gate 			if (args->fh == NULL) {
20690Sstevel@tonic-gate 				pr_err(gettext("no memory\n"));
20700Sstevel@tonic-gate 				*versp = nfsvers_to_use = savevers;
20710Sstevel@tonic-gate 				return (RET_ERR);
20720Sstevel@tonic-gate 			}
20730Sstevel@tonic-gate 			return (RET_OK);
20740Sstevel@tonic-gate 		}
20750Sstevel@tonic-gate 		nfsvers_to_use = savevers;
20760Sstevel@tonic-gate 
20770Sstevel@tonic-gate 		vers_to_try--;
20780Sstevel@tonic-gate 		/* If no more versions to try, let the user know. */
20795302Sth199096 		if (vers_to_try < vers_min)
20800Sstevel@tonic-gate 			return (retval);
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 		/*
20830Sstevel@tonic-gate 		 * If we are here, there are more versions to try but
20840Sstevel@tonic-gate 		 * there has been an error of some sort.  If it is not
20850Sstevel@tonic-gate 		 * an RPC error (e.g. host unknown), we just stop and
20860Sstevel@tonic-gate 		 * return the error since the other versions would see
20870Sstevel@tonic-gate 		 * the same error as well.
20880Sstevel@tonic-gate 		 */
20890Sstevel@tonic-gate 		if (retval == RET_ERR && error.error_type != ERR_RPCERROR)
20900Sstevel@tonic-gate 			return (retval);
20910Sstevel@tonic-gate 	}
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 	while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers,
20945302Sth199096 	    vers_min, vers_to_try, "datagram_v")) == NULL) {
20950Sstevel@tonic-gate 		if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) {
20960Sstevel@tonic-gate 			pr_err(gettext("%s: %s\n"), fshost,
20970Sstevel@tonic-gate 			    clnt_spcreateerror(""));
20980Sstevel@tonic-gate 			return (RET_ERR);
20990Sstevel@tonic-gate 		}
21000Sstevel@tonic-gate 
21010Sstevel@tonic-gate 		/*
21020Sstevel@tonic-gate 		 * We don't want to downgrade version on lost packets
21030Sstevel@tonic-gate 		 */
21040Sstevel@tonic-gate 		if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) ||
21055302Sth199096 		    (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) {
21060Sstevel@tonic-gate 			pr_err(gettext("%s: %s\n"), fshost,
21070Sstevel@tonic-gate 			    clnt_spcreateerror(""));
21080Sstevel@tonic-gate 			return (RET_RETRY);
21090Sstevel@tonic-gate 		}
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 		/*
21120Sstevel@tonic-gate 		 * back off and try the previous version - patch to the
21130Sstevel@tonic-gate 		 * problem of version numbers not being contigous and
21140Sstevel@tonic-gate 		 * clnt_create_vers failing (SunOS4.1 clients & SGI servers)
21150Sstevel@tonic-gate 		 * The problem happens with most non-Sun servers who
21160Sstevel@tonic-gate 		 * don't support mountd protocol #2. So, in case the
21170Sstevel@tonic-gate 		 * call fails, we re-try the call anyway.
21180Sstevel@tonic-gate 		 */
21190Sstevel@tonic-gate 		vers_to_try--;
21200Sstevel@tonic-gate 		if (vers_to_try < vers_min) {
21210Sstevel@tonic-gate 			if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) {
21220Sstevel@tonic-gate 				if (nfsvers == 0) {
21230Sstevel@tonic-gate 					pr_err(gettext(
21240Sstevel@tonic-gate 			"%s:%s: no applicable versions of NFS supported\n"),
21250Sstevel@tonic-gate 					    fshost, fspath);
21260Sstevel@tonic-gate 				} else {
21270Sstevel@tonic-gate 					pr_err(gettext(
21280Sstevel@tonic-gate 			"%s:%s: NFS Version %d not supported\n"),
21290Sstevel@tonic-gate 					    fshost, fspath, nfsvers);
21300Sstevel@tonic-gate 				}
21310Sstevel@tonic-gate 				return (RET_ERR);
21320Sstevel@tonic-gate 			}
21330Sstevel@tonic-gate 			if (!printed) {
21340Sstevel@tonic-gate 				pr_err(gettext("%s: %s\n"), fshost,
21350Sstevel@tonic-gate 				    clnt_spcreateerror(""));
21360Sstevel@tonic-gate 				printed = 1;
21370Sstevel@tonic-gate 			}
21380Sstevel@tonic-gate 			return (RET_RETRY);
21390Sstevel@tonic-gate 		}
21400Sstevel@tonic-gate 	}
21410Sstevel@tonic-gate 	if (posix && outvers < MOUNTVERS_POSIX) {
21420Sstevel@tonic-gate 		pr_err(gettext("%s: %s: no pathconf info\n"),
21430Sstevel@tonic-gate 		    fshost, clnt_sperror(cl, ""));
21440Sstevel@tonic-gate 		clnt_destroy(cl);
21450Sstevel@tonic-gate 		return (RET_ERR);
21460Sstevel@tonic-gate 	}
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate 	if (__clnt_bindresvport(cl) < 0) {
21490Sstevel@tonic-gate 		pr_err(gettext("Couldn't bind to reserved port\n"));
21500Sstevel@tonic-gate 		clnt_destroy(cl);
21510Sstevel@tonic-gate 		return (RET_RETRY);
21520Sstevel@tonic-gate 	}
21530Sstevel@tonic-gate 
21540Sstevel@tonic-gate 	if ((cl->cl_auth = authsys_create_default()) == NULL) {
21550Sstevel@tonic-gate 		pr_err(
21560Sstevel@tonic-gate 		    gettext("Couldn't create default authentication handle\n"));
21570Sstevel@tonic-gate 		clnt_destroy(cl);
21580Sstevel@tonic-gate 		return (RET_RETRY);
21590Sstevel@tonic-gate 	}
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 	switch (outvers) {
21620Sstevel@tonic-gate 	case MOUNTVERS:
21630Sstevel@tonic-gate 	case MOUNTVERS_POSIX:
21640Sstevel@tonic-gate 		*versp = nfsvers_to_use = NFS_VERSION;
21650Sstevel@tonic-gate 		rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
21665302Sth199096 		    (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout);
21670Sstevel@tonic-gate 		if (rpc_stat != RPC_SUCCESS) {
21680Sstevel@tonic-gate 			pr_err(gettext("%s:%s: server not responding %s\n"),
21690Sstevel@tonic-gate 			    fshost, fspath, clnt_sperror(cl, ""));
21700Sstevel@tonic-gate 			clnt_destroy(cl);
21710Sstevel@tonic-gate 			return (RET_RETRY);
21720Sstevel@tonic-gate 		}
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 		if ((errno = fhs.fhs_status) != MNT_OK) {
21750Sstevel@tonic-gate 			if (loud_on_mnt_err) {
21765302Sth199096 				if (errno == EACCES) {
21775302Sth199096 					pr_err(gettext(
21785302Sth199096 					    "%s:%s: access denied\n"),
21795302Sth199096 					    fshost, fspath);
21805302Sth199096 				} else {
21815302Sth199096 					pr_err(gettext("%s:%s: %s\n"), fshost,
21825302Sth199096 					    fspath, strerror(errno));
21835302Sth199096 				}
21840Sstevel@tonic-gate 			}
21850Sstevel@tonic-gate 			clnt_destroy(cl);
21860Sstevel@tonic-gate 			return (RET_MNTERR);
21870Sstevel@tonic-gate 		}
21880Sstevel@tonic-gate 		args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle));
21890Sstevel@tonic-gate 		if (args->fh == NULL) {
21900Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
21910Sstevel@tonic-gate 			return (RET_ERR);
21920Sstevel@tonic-gate 		}
21930Sstevel@tonic-gate 		memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle,
21945302Sth199096 		    sizeof (fhs.fhstatus_u.fhs_fhandle));
21950Sstevel@tonic-gate 		if (!errno && posix) {
21960Sstevel@tonic-gate 			rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF,
21975302Sth199096 			    xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf,
21985302Sth199096 			    (caddr_t)&p, timeout);
21990Sstevel@tonic-gate 			if (rpc_stat != RPC_SUCCESS) {
22000Sstevel@tonic-gate 				pr_err(gettext(
22010Sstevel@tonic-gate 				    "%s:%s: server not responding %s\n"),
22020Sstevel@tonic-gate 				    fshost, fspath, clnt_sperror(cl, ""));
22030Sstevel@tonic-gate 				free(args->fh);
22040Sstevel@tonic-gate 				clnt_destroy(cl);
22050Sstevel@tonic-gate 				return (RET_RETRY);
22060Sstevel@tonic-gate 			}
22070Sstevel@tonic-gate 			if (_PC_ISSET(_PC_ERROR, p.pc_mask)) {
22080Sstevel@tonic-gate 				pr_err(gettext(
22090Sstevel@tonic-gate 				    "%s:%s: no pathconf info\n"),
22100Sstevel@tonic-gate 				    fshost, fspath);
22110Sstevel@tonic-gate 				free(args->fh);
22120Sstevel@tonic-gate 				clnt_destroy(cl);
22130Sstevel@tonic-gate 				return (RET_ERR);
22140Sstevel@tonic-gate 			}
22150Sstevel@tonic-gate 			args->flags |= NFSMNT_POSIX;
22160Sstevel@tonic-gate 			args->pathconf = malloc(sizeof (p));
22170Sstevel@tonic-gate 			if (args->pathconf == NULL) {
22180Sstevel@tonic-gate 				pr_err(gettext("no memory\n"));
22190Sstevel@tonic-gate 				free(args->fh);
22200Sstevel@tonic-gate 				clnt_destroy(cl);
22210Sstevel@tonic-gate 				return (RET_ERR);
22220Sstevel@tonic-gate 			}
22230Sstevel@tonic-gate 			memcpy((caddr_t)args->pathconf, (caddr_t)&p,
22245302Sth199096 			    sizeof (p));
22250Sstevel@tonic-gate 		}
22260Sstevel@tonic-gate 		break;
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate 	case MOUNTVERS3:
22290Sstevel@tonic-gate 		*versp = nfsvers_to_use = NFS_V3;
22300Sstevel@tonic-gate 		rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
22315302Sth199096 		    (caddr_t)&fspath, xdr_mountres3, (caddr_t)&mountres3,
22325302Sth199096 		    timeout);
22330Sstevel@tonic-gate 		if (rpc_stat != RPC_SUCCESS) {
22340Sstevel@tonic-gate 			pr_err(gettext("%s:%s: server not responding %s\n"),
22350Sstevel@tonic-gate 			    fshost, fspath, clnt_sperror(cl, ""));
22360Sstevel@tonic-gate 			clnt_destroy(cl);
22370Sstevel@tonic-gate 			return (RET_RETRY);
22380Sstevel@tonic-gate 		}
22390Sstevel@tonic-gate 
22400Sstevel@tonic-gate 		/*
22410Sstevel@tonic-gate 		 * Assume here that most of the MNT3ERR_*
22420Sstevel@tonic-gate 		 * codes map into E* errors.
22430Sstevel@tonic-gate 		 */
22440Sstevel@tonic-gate 		if ((errno = mountres3.fhs_status) != MNT_OK) {
22455302Sth199096 			if (loud_on_mnt_err) {
22465302Sth199096 				switch (errno) {
22475302Sth199096 				case MNT3ERR_NAMETOOLONG:
22485302Sth199096 					msg = "path name is too long";
22495302Sth199096 					break;
22505302Sth199096 				case MNT3ERR_NOTSUPP:
22515302Sth199096 					msg = "operation not supported";
22525302Sth199096 					break;
22535302Sth199096 				case MNT3ERR_SERVERFAULT:
22545302Sth199096 					msg = "server fault";
22555302Sth199096 					break;
22565302Sth199096 				default:
22575302Sth199096 					msg = strerror(errno);
22585302Sth199096 					break;
22595302Sth199096 				}
22605302Sth199096 				pr_err(gettext("%s:%s: %s\n"), fshost,
22615302Sth199096 				    fspath, msg);
22620Sstevel@tonic-gate 			}
22635302Sth199096 			clnt_destroy(cl);
22645302Sth199096 			return (RET_MNTERR);
22650Sstevel@tonic-gate 		}
22660Sstevel@tonic-gate 
22670Sstevel@tonic-gate 		fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
22680Sstevel@tonic-gate 		if (fh3p == NULL) {
22690Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
22700Sstevel@tonic-gate 			return (RET_ERR);
22710Sstevel@tonic-gate 		}
22720Sstevel@tonic-gate 		fh3p->fh3_length =
22735302Sth199096 		    mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
22740Sstevel@tonic-gate 		(void) memcpy(fh3p->fh3_u.data,
22755302Sth199096 		    mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
22765302Sth199096 		    fh3p->fh3_length);
22770Sstevel@tonic-gate 		args->fh = (caddr_t)fh3p;
22780Sstevel@tonic-gate 		fstype = MNTTYPE_NFS3;
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate 		/*
22810Sstevel@tonic-gate 		 * Check the security flavor to be used.
22820Sstevel@tonic-gate 		 *
22830Sstevel@tonic-gate 		 * If "secure" or "sec=flavor" is a mount
22840Sstevel@tonic-gate 		 * option, check if the server supports the "flavor".
22850Sstevel@tonic-gate 		 * If the server does not support the flavor, return
22860Sstevel@tonic-gate 		 * error.
22870Sstevel@tonic-gate 		 *
22880Sstevel@tonic-gate 		 * If no mount option is given then use the first supported
22890Sstevel@tonic-gate 		 * security flavor (by the client) in the auth list returned
22900Sstevel@tonic-gate 		 * from the server.
22910Sstevel@tonic-gate 		 *
22920Sstevel@tonic-gate 		 */
22930Sstevel@tonic-gate 		auths =
22945302Sth199096 		    mountres3.mountres3_u.mountinfo.auth_flavors
22955302Sth199096 		    .auth_flavors_val;
22960Sstevel@tonic-gate 		count =
22975302Sth199096 		    mountres3.mountres3_u.mountinfo.auth_flavors
22985302Sth199096 		    .auth_flavors_len;
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 		if (sec_opt) {
23010Sstevel@tonic-gate 			for (i = 0; i < count; i++) {
23020Sstevel@tonic-gate 				if (auths[i] == nfs_sec.sc_nfsnum)
23035302Sth199096 					break;
23040Sstevel@tonic-gate 			}
23055302Sth199096 			if (i >= count)
23060Sstevel@tonic-gate 				goto autherr;
23070Sstevel@tonic-gate 		} else {
23085302Sth199096 			if (count < 0)
23095302Sth199096 				break;
23105302Sth199096 
23110Sstevel@tonic-gate 			for (i = 0; i < count; i++) {
23125302Sth199096 				if (!nfs_getseconfig_bynumber(auths[i],
23135302Sth199096 				    &nfs_sec)) {
23145302Sth199096 					sec_opt++;
23155302Sth199096 					break;
23165302Sth199096 				}
23170Sstevel@tonic-gate 			}
23185302Sth199096 
23195302Sth199096 			if (i >= count)
23205302Sth199096 				goto autherr;
23210Sstevel@tonic-gate 		}
23220Sstevel@tonic-gate 		break;
23230Sstevel@tonic-gate 	default:
23240Sstevel@tonic-gate 		pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
23250Sstevel@tonic-gate 		    fshost, fspath, outvers);
23260Sstevel@tonic-gate 		clnt_destroy(cl);
23270Sstevel@tonic-gate 		return (RET_ERR);
23280Sstevel@tonic-gate 	}
23290Sstevel@tonic-gate 
23300Sstevel@tonic-gate 	clnt_destroy(cl);
23310Sstevel@tonic-gate 	return (RET_OK);
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate autherr:
23340Sstevel@tonic-gate 	pr_err(gettext(
23355302Sth199096 	    "security mode does not match the server exporting %s:%s\n"),
23365302Sth199096 	    fshost, fspath);
23370Sstevel@tonic-gate 	clnt_destroy(cl);
23380Sstevel@tonic-gate 	return (RET_ERR);
23390Sstevel@tonic-gate }
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate /*
23420Sstevel@tonic-gate  * Fill in the address for the server's NFS service and
23430Sstevel@tonic-gate  * fill in a knetconfig structure for the transport that
23440Sstevel@tonic-gate  * the service is available on.
23450Sstevel@tonic-gate  */
23460Sstevel@tonic-gate static int
23470Sstevel@tonic-gate getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp,
23480Sstevel@tonic-gate 	    bool_t get_pubfh, char *fspath, ushort_t port, err_ret_t *error,
23490Sstevel@tonic-gate 	    bool_t print_rpcerror)
23500Sstevel@tonic-gate {
23510Sstevel@tonic-gate 	struct stat sb;
23520Sstevel@tonic-gate 	struct netconfig *nconf;
23530Sstevel@tonic-gate 	struct knetconfig *knconfp;
23540Sstevel@tonic-gate 	static int printed = 0;
23550Sstevel@tonic-gate 	struct t_info tinfo;
23560Sstevel@tonic-gate 	err_ret_t addr_error;
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 	SET_ERR_RET(error, ERR_PROTO_NONE, 0);
23590Sstevel@tonic-gate 	SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0);
23600Sstevel@tonic-gate 
23610Sstevel@tonic-gate 	if (nfs_proto) {
23620Sstevel@tonic-gate 		/*
23630Sstevel@tonic-gate 		 * If a proto is specified and its rdma try this. The kernel
23640Sstevel@tonic-gate 		 * will later do the reachablity test and fail form there
23650Sstevel@tonic-gate 		 * if rdma transport is not available to kernel rpc
23660Sstevel@tonic-gate 		 */
23670Sstevel@tonic-gate 		if (strcmp(nfs_proto, "rdma") == 0) {
23680Sstevel@tonic-gate 			args->addr = get_addr(fshost, NFS_PROGRAM,
23690Sstevel@tonic-gate 			    nfsvers_to_use, nconfp, NULL, port, &tinfo,
23700Sstevel@tonic-gate 			    &args->fh, get_pubfh, fspath, &addr_error);
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 			args->flags |= NFSMNT_DORDMA;
23730Sstevel@tonic-gate 		} else {
23740Sstevel@tonic-gate 			args->addr = get_addr(fshost, NFS_PROGRAM,
23750Sstevel@tonic-gate 			    nfsvers_to_use, nconfp, nfs_proto, port, &tinfo,
23760Sstevel@tonic-gate 			    &args->fh, get_pubfh, fspath, &addr_error);
23770Sstevel@tonic-gate 		}
23780Sstevel@tonic-gate 	} else {
23790Sstevel@tonic-gate 		args->addr = get_addr(fshost, NFS_PROGRAM, nfsvers_to_use,
23800Sstevel@tonic-gate 		    nconfp, nfs_proto, port, &tinfo, &args->fh, get_pubfh,
23810Sstevel@tonic-gate 		    fspath, &addr_error);
23820Sstevel@tonic-gate 		/*
23830Sstevel@tonic-gate 		 * If no proto is specified set this flag.
23840Sstevel@tonic-gate 		 * Kernel mount code will try to use RDMA if its on the
23850Sstevel@tonic-gate 		 * system, otherwise it will keep on using the protocol
23860Sstevel@tonic-gate 		 * selected here, through the above get_addr call.
23870Sstevel@tonic-gate 		 */
23880Sstevel@tonic-gate 		if (nfs_proto == NULL)
23890Sstevel@tonic-gate 			args->flags |= NFSMNT_TRYRDMA;
23900Sstevel@tonic-gate 	}
23910Sstevel@tonic-gate 
23920Sstevel@tonic-gate 	if (args->addr == NULL) {
23930Sstevel@tonic-gate 		/*
23940Sstevel@tonic-gate 		 * We could have failed because the server had no public
23950Sstevel@tonic-gate 		 * file handle support. So don't print a message and don't
23960Sstevel@tonic-gate 		 * retry.
23970Sstevel@tonic-gate 		 */
23980Sstevel@tonic-gate 		if (get_pubfh == TRUE)
23990Sstevel@tonic-gate 			return (RET_ERR);
24000Sstevel@tonic-gate 
24010Sstevel@tonic-gate 		if (!printed) {
24020Sstevel@tonic-gate 			switch (addr_error.error_type) {
24030Sstevel@tonic-gate 			case 0:
2404489Soa138391 				printed = 1;
24050Sstevel@tonic-gate 				break;
24060Sstevel@tonic-gate 			case ERR_RPCERROR:
24070Sstevel@tonic-gate 				if (!print_rpcerror)
24080Sstevel@tonic-gate 					/* no error print at this time */
24090Sstevel@tonic-gate 					break;
24100Sstevel@tonic-gate 				pr_err(gettext("%s NFS service not"
24115302Sth199096 				    " available %s\n"), fshost,
24120Sstevel@tonic-gate 				    clnt_sperrno(addr_error.error_value));
2413489Soa138391 				printed = 1;
24140Sstevel@tonic-gate 				break;
24150Sstevel@tonic-gate 			case ERR_NETPATH:
24160Sstevel@tonic-gate 				pr_err(gettext("%s: Error in NETPATH.\n"),
24175302Sth199096 				    fshost);
2418489Soa138391 				printed = 1;
24190Sstevel@tonic-gate 				break;
24200Sstevel@tonic-gate 			case ERR_PROTO_INVALID:
24210Sstevel@tonic-gate 				pr_err(gettext("%s: NFS service does not"
24225302Sth199096 				    " recognize protocol: %s.\n"), fshost,
24235302Sth199096 				    nfs_proto);
2424489Soa138391 				printed = 1;
24250Sstevel@tonic-gate 				break;
24260Sstevel@tonic-gate 			case ERR_PROTO_UNSUPP:
2427489Soa138391 				if (nfsvers || nfsvers_to_use == NFS_VERSMIN) {
2428112Soa138391 					/*
2429489Soa138391 					 * Don't set "printed" here. Since we
2430489Soa138391 					 * have to keep checking here till we
2431489Soa138391 					 * exhaust transport errors on all vers.
2432489Soa138391 					 *
2433489Soa138391 					 * Print this message if:
2434489Soa138391 					 * 1. After we have tried all versions
2435489Soa138391 					 *    of NFS and none support the asked
2436489Soa138391 					 *    transport.
2437489Soa138391 					 *
2438489Soa138391 					 * 2. If a version is specified and it
2439489Soa138391 					 *    does'nt support the asked
2440489Soa138391 					 *    transport.
2441489Soa138391 					 *
2442489Soa138391 					 * Otherwise we decrement the version
2443112Soa138391 					 * and retry below.
2444112Soa138391 					 */
2445112Soa138391 					pr_err(gettext("%s: NFS service does"
24465302Sth199096 					    " not support protocol: %s.\n"),
24475302Sth199096 					    fshost, nfs_proto);
2448112Soa138391 				}
24490Sstevel@tonic-gate 				break;
24500Sstevel@tonic-gate 			case ERR_NOHOST:
245177Soa138391 				pr_err("%s: %s\n", fshost, "Unknown host");
2452489Soa138391 				printed = 1;
24530Sstevel@tonic-gate 				break;
24540Sstevel@tonic-gate 			default:
24550Sstevel@tonic-gate 				/* case ERR_PROTO_NONE falls through */
24560Sstevel@tonic-gate 				pr_err(gettext("%s: NFS service not responding"
24575302Sth199096 				    "\n"), fshost);
2458489Soa138391 				printed = 1;
24590Sstevel@tonic-gate 				break;
24600Sstevel@tonic-gate 			}
24610Sstevel@tonic-gate 		}
24620Sstevel@tonic-gate 		SET_ERR_RET(error,
24635302Sth199096 		    addr_error.error_type, addr_error.error_value);
24640Sstevel@tonic-gate 		if (addr_error.error_type == ERR_PROTO_NONE)
24650Sstevel@tonic-gate 			return (RET_RETRY);
24660Sstevel@tonic-gate 		else if (addr_error.error_type == ERR_RPCERROR &&
24675302Sth199096 		    !IS_UNRECOVERABLE_RPC(addr_error.error_value)) {
24680Sstevel@tonic-gate 			return (RET_RETRY);
2469112Soa138391 		} else if (nfsvers == 0 && addr_error.error_type ==
24705302Sth199096 		    ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) {
2471112Soa138391 			/*
2472112Soa138391 			 * If no version is specified, and the error is due
2473489Soa138391 			 * to an unsupported transport, then decrement the
2474112Soa138391 			 * version and retry.
2475112Soa138391 			 */
2476112Soa138391 			return (RET_RETRY);
2477112Soa138391 		} else
24780Sstevel@tonic-gate 			return (RET_ERR);
24790Sstevel@tonic-gate 	}
24800Sstevel@tonic-gate 	nconf = *nconfp;
24810Sstevel@tonic-gate 
24820Sstevel@tonic-gate 	if (stat(nconf->nc_device, &sb) < 0) {
24830Sstevel@tonic-gate 		pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"),
24840Sstevel@tonic-gate 		    nconf->nc_device, strerror(errno));
24850Sstevel@tonic-gate 		return (RET_ERR);
24860Sstevel@tonic-gate 	}
24870Sstevel@tonic-gate 
24880Sstevel@tonic-gate 	knconfp = (struct knetconfig *)malloc(sizeof (*knconfp));
24890Sstevel@tonic-gate 	if (!knconfp) {
24900Sstevel@tonic-gate 		pr_err(gettext("no memory\n"));
24910Sstevel@tonic-gate 		return (RET_ERR);
24920Sstevel@tonic-gate 	}
24930Sstevel@tonic-gate 	knconfp->knc_semantics = nconf->nc_semantics;
24940Sstevel@tonic-gate 	knconfp->knc_protofmly = nconf->nc_protofmly;
24950Sstevel@tonic-gate 	knconfp->knc_proto = nconf->nc_proto;
24960Sstevel@tonic-gate 	knconfp->knc_rdev = sb.st_rdev;
24970Sstevel@tonic-gate 
24980Sstevel@tonic-gate 	/* make sure we don't overload the transport */
24990Sstevel@tonic-gate 	if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) {
25000Sstevel@tonic-gate 		args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE);
25010Sstevel@tonic-gate 		if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR)
25020Sstevel@tonic-gate 			args->rsize = tinfo.tsdu - NFS_RPC_HDR;
25030Sstevel@tonic-gate 		if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR)
25040Sstevel@tonic-gate 			args->wsize = tinfo.tsdu - NFS_RPC_HDR;
25050Sstevel@tonic-gate 	}
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 	args->flags |= NFSMNT_KNCONF;
25080Sstevel@tonic-gate 	args->knconf = knconfp;
25090Sstevel@tonic-gate 	return (RET_OK);
25100Sstevel@tonic-gate }
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate static int
25130Sstevel@tonic-gate retry(struct mnttab *mntp, int ro)
25140Sstevel@tonic-gate {
25150Sstevel@tonic-gate 	int delay = 5;
25160Sstevel@tonic-gate 	int count = retries;
25170Sstevel@tonic-gate 	int r;
25180Sstevel@tonic-gate 
2519489Soa138391 	/*
2520489Soa138391 	 * Please see comments on nfsretry_vers in the beginning of this file
2521489Soa138391 	 * and in main() routine.
2522489Soa138391 	 */
2523489Soa138391 
25240Sstevel@tonic-gate 	if (bg) {
25250Sstevel@tonic-gate 		if (fork() > 0)
25260Sstevel@tonic-gate 			return (RET_OK);
25270Sstevel@tonic-gate 		pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp);
25280Sstevel@tonic-gate 		backgrounded = 1;
2529489Soa138391 	} else {
2530489Soa138391 		if (!nfsretry_vers)
2531489Soa138391 			pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp);
2532489Soa138391 	}
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate 	while (count--) {
2535489Soa138391 		if ((r = mount_nfs(mntp, ro, NULL)) == RET_OK) {
25360Sstevel@tonic-gate 			pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp);
25370Sstevel@tonic-gate 			return (RET_OK);
25380Sstevel@tonic-gate 		}
25390Sstevel@tonic-gate 		if (r != RET_RETRY)
25400Sstevel@tonic-gate 			break;
25410Sstevel@tonic-gate 
25420Sstevel@tonic-gate 		if (count > 0) {
25435302Sth199096 			(void) sleep(delay);
25445302Sth199096 			delay *= 2;
25455302Sth199096 			if (delay > 120)
25465302Sth199096 				delay = 120;
25470Sstevel@tonic-gate 		}
25480Sstevel@tonic-gate 	}
2549489Soa138391 
2550489Soa138391 	if (!nfsretry_vers)
2551489Soa138391 		pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp);
2552489Soa138391 
25530Sstevel@tonic-gate 	return (RET_ERR);
25540Sstevel@tonic-gate }
25550Sstevel@tonic-gate 
25560Sstevel@tonic-gate /*
25570Sstevel@tonic-gate  * Read the /etc/default/nfs configuration file to determine if the
25580Sstevel@tonic-gate  * client has been configured for a new min/max for the NFS version to
25590Sstevel@tonic-gate  * use.
25600Sstevel@tonic-gate  */
25610Sstevel@tonic-gate static void
25620Sstevel@tonic-gate read_default(void)
25630Sstevel@tonic-gate {
25640Sstevel@tonic-gate 	char *defval;
25650Sstevel@tonic-gate 	int errno;
25660Sstevel@tonic-gate 	int tmp;
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	/* Fail silently if error in opening the default nfs config file */
25690Sstevel@tonic-gate 	if ((defopen(NFSADMIN)) == 0) {
25700Sstevel@tonic-gate 		if ((defval = defread("NFS_CLIENT_VERSMIN=")) != NULL) {
25710Sstevel@tonic-gate 			errno = 0;
25720Sstevel@tonic-gate 			tmp = strtol(defval, (char **)NULL, 10);
25730Sstevel@tonic-gate 			if (errno == 0) {
25740Sstevel@tonic-gate 				vers_min_default = tmp;
25750Sstevel@tonic-gate 			}
25760Sstevel@tonic-gate 		}
25770Sstevel@tonic-gate 		if ((defval = defread("NFS_CLIENT_VERSMAX=")) != NULL) {
25780Sstevel@tonic-gate 			errno = 0;
25790Sstevel@tonic-gate 			tmp = strtol(defval, (char **)NULL, 10);
25800Sstevel@tonic-gate 			if (errno == 0) {
25810Sstevel@tonic-gate 				vers_max_default = tmp;
25820Sstevel@tonic-gate 			}
25830Sstevel@tonic-gate 		}
25840Sstevel@tonic-gate 		/* close defaults file */
25850Sstevel@tonic-gate 		defopen(NULL);
25860Sstevel@tonic-gate 	}
25870Sstevel@tonic-gate }
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate static void
25900Sstevel@tonic-gate sigusr1(int s)
25910Sstevel@tonic-gate {
25920Sstevel@tonic-gate }
2593