xref: /onnv-gate/usr/src/cmd/fs.d/nfs/mount/mount.c (revision 13080:fcc1e406c13f)
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  */
215655Sth199096 
220Sstevel@tonic-gate /*
2312782SMarcel.Telka@Sun.COM  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
310Sstevel@tonic-gate  * The Regents of the University of California
320Sstevel@tonic-gate  * All Rights Reserved
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
350Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
360Sstevel@tonic-gate  * contributors.
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate  * nfs mount
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #define	NFSCLIENT
440Sstevel@tonic-gate #include <locale.h>
450Sstevel@tonic-gate #include <stdio.h>
460Sstevel@tonic-gate #include <string.h>
470Sstevel@tonic-gate #include <memory.h>
480Sstevel@tonic-gate #include <stdarg.h>
490Sstevel@tonic-gate #include <unistd.h>
500Sstevel@tonic-gate #include <ctype.h>
510Sstevel@tonic-gate #include <stdlib.h>
520Sstevel@tonic-gate #include <signal.h>
530Sstevel@tonic-gate #include <sys/param.h>
540Sstevel@tonic-gate #include <rpc/rpc.h>
550Sstevel@tonic-gate #include <errno.h>
560Sstevel@tonic-gate #include <sys/stat.h>
570Sstevel@tonic-gate #include <netdb.h>
580Sstevel@tonic-gate #include <sys/mount.h>
590Sstevel@tonic-gate #include <sys/mntent.h>
600Sstevel@tonic-gate #include <sys/mnttab.h>
610Sstevel@tonic-gate #include <nfs/nfs.h>
620Sstevel@tonic-gate #include <nfs/mount.h>
630Sstevel@tonic-gate #include <rpcsvc/mount.h>
640Sstevel@tonic-gate #include <sys/pathconf.h>
650Sstevel@tonic-gate #include <netdir.h>
660Sstevel@tonic-gate #include <netconfig.h>
670Sstevel@tonic-gate #include <sys/sockio.h>
680Sstevel@tonic-gate #include <net/if.h>
690Sstevel@tonic-gate #include <syslog.h>
700Sstevel@tonic-gate #include <fslib.h>
710Sstevel@tonic-gate #include <deflt.h>
720Sstevel@tonic-gate #include <sys/wait.h>
730Sstevel@tonic-gate #include "replica.h"
740Sstevel@tonic-gate #include <netinet/in.h>
750Sstevel@tonic-gate #include <nfs/nfs_sec.h>
760Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h>
770Sstevel@tonic-gate #include <priv.h>
783378Srica #include <tsol/label.h>
790Sstevel@tonic-gate #include "nfs_subr.h"
800Sstevel@tonic-gate #include "webnfs.h"
810Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h>
8212782SMarcel.Telka@Sun.COM #include <limits.h>
83*13080SPavan.Mettu@Oracle.COM #include <libscf.h>
84*13080SPavan.Mettu@Oracle.COM #include <libshare.h>
85*13080SPavan.Mettu@Oracle.COM #include "smfcfg.h"
860Sstevel@tonic-gate 
875302Sth199096 #include <nfs/nfssys.h>
885302Sth199096 extern int _nfssys(enum nfssys_op, void *);
895302Sth199096 
900Sstevel@tonic-gate #ifndef	NFS_VERSMAX
910Sstevel@tonic-gate #define	NFS_VERSMAX	4
920Sstevel@tonic-gate #endif
930Sstevel@tonic-gate #ifndef	NFS_VERSMIN
940Sstevel@tonic-gate #define	NFS_VERSMIN	2
950Sstevel@tonic-gate #endif
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define	RET_OK		0
980Sstevel@tonic-gate #define	RET_RETRY	32
990Sstevel@tonic-gate #define	RET_ERR		33
1000Sstevel@tonic-gate #define	RET_MNTERR	1000
1010Sstevel@tonic-gate #define	ERR_PROTO_NONE		0
1020Sstevel@tonic-gate #define	ERR_PROTO_INVALID	901
1030Sstevel@tonic-gate #define	ERR_PROTO_UNSUPP	902
1040Sstevel@tonic-gate #define	ERR_NETPATH		903
1050Sstevel@tonic-gate #define	ERR_NOHOST		904
1060Sstevel@tonic-gate #define	ERR_RPCERROR		905
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate typedef struct err_ret {
1090Sstevel@tonic-gate 	int error_type;
1100Sstevel@tonic-gate 	int error_value;
1110Sstevel@tonic-gate } err_ret_t;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate #define	SET_ERR_RET(errst, etype, eval) \
1140Sstevel@tonic-gate 	if (errst) { \
1150Sstevel@tonic-gate 		(errst)->error_type = etype; \
1160Sstevel@tonic-gate 		(errst)->error_value = eval; \
1170Sstevel@tonic-gate 	}
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /* number of transports to try */
1200Sstevel@tonic-gate #define	MNT_PREF_LISTLEN	2
1210Sstevel@tonic-gate #define	FIRST_TRY		1
1220Sstevel@tonic-gate #define	SECOND_TRY		2
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate #define	BIGRETRY	10000
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /* maximum length of RPC header for NFS messages */
1270Sstevel@tonic-gate #define	NFS_RPC_HDR	432
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate #define	NFS_ARGS_EXTB_secdata(args, secdata) \
1300Sstevel@tonic-gate 	{ (args)->nfs_args_ext = NFS_ARGS_EXTB, \
1310Sstevel@tonic-gate 	(args)->nfs_ext_u.nfs_extB.secdata = secdata; }
1320Sstevel@tonic-gate 
1335655Sth199096 extern int __clnt_bindresvport(CLIENT *);
1340Sstevel@tonic-gate extern char *nfs_get_qop_name();
1350Sstevel@tonic-gate extern AUTH * nfs_create_ah();
1360Sstevel@tonic-gate extern enum snego_stat nfs_sec_nego();
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate static void usage(void);
1390Sstevel@tonic-gate static int retry(struct mnttab *, int);
1400Sstevel@tonic-gate static int set_args(int *, struct nfs_args *, char *, struct mnttab *);
1410Sstevel@tonic-gate static int get_fh_via_pub(struct nfs_args *, char *, char *, bool_t, bool_t,
1420Sstevel@tonic-gate 	int *, struct netconfig **, ushort_t);
1430Sstevel@tonic-gate static int get_fh(struct nfs_args *, char *, char *, int *, bool_t,
1440Sstevel@tonic-gate 	struct netconfig **, ushort_t);
1450Sstevel@tonic-gate static int make_secure(struct nfs_args *, char *, struct netconfig *,
1460Sstevel@tonic-gate 	bool_t, rpcvers_t);
147489Soa138391 static int mount_nfs(struct mnttab *, int, err_ret_t *);
1480Sstevel@tonic-gate static int getaddr_nfs(struct nfs_args *, char *, struct netconfig **,
1490Sstevel@tonic-gate 		    bool_t, char *, ushort_t, err_ret_t *, bool_t);
1500Sstevel@tonic-gate static void pr_err(const char *fmt, ...);
1510Sstevel@tonic-gate static void usage(void);
1520Sstevel@tonic-gate static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t,
1530Sstevel@tonic-gate 	struct netconfig **, char *, ushort_t, struct t_info *,
1540Sstevel@tonic-gate 	caddr_t *, bool_t, char *, err_ret_t *);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate static struct netbuf *get_the_addr(char *, rpcprog_t, rpcvers_t,
1570Sstevel@tonic-gate 	struct netconfig *, ushort_t, struct t_info *, caddr_t *,
1580Sstevel@tonic-gate 	bool_t, char *, err_ret_t *);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate extern int self_check(char *);
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static void read_default(void);
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate static char typename[64];
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate static int bg = 0;
1670Sstevel@tonic-gate static int backgrounded = 0;
1680Sstevel@tonic-gate static int posix = 0;
1690Sstevel@tonic-gate static int retries = BIGRETRY;
1700Sstevel@tonic-gate static ushort_t nfs_port = 0;
1710Sstevel@tonic-gate static char *nfs_proto = NULL;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate static int mflg = 0;
1740Sstevel@tonic-gate static int Oflg = 0;	/* Overlay mounts */
1750Sstevel@tonic-gate static int qflg = 0;	/* quiet - don't print warnings on bad options */
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate static char *fstype = MNTTYPE_NFS;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate static seconfig_t nfs_sec;
1800Sstevel@tonic-gate static int sec_opt = 0;	/* any security option ? */
1810Sstevel@tonic-gate static bool_t snego_done;
1820Sstevel@tonic-gate static void sigusr1(int);
1830Sstevel@tonic-gate 
1845302Sth199096 extern void set_nfsv4_ephemeral_mount_to(void);
1855302Sth199096 
1860Sstevel@tonic-gate /*
1870Sstevel@tonic-gate  * list of support services needed
1880Sstevel@tonic-gate  */
1890Sstevel@tonic-gate static char	*service_list[] = { STATD, LOCKD, NULL };
1900Sstevel@tonic-gate static char	*service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL };
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate  * These two variables control the NFS version number to be used.
1940Sstevel@tonic-gate  *
1950Sstevel@tonic-gate  * nfsvers defaults to 0 which means to use the highest number that
1960Sstevel@tonic-gate  * both the client and the server support.  It can also be set to
1970Sstevel@tonic-gate  * a particular value, either 2, 3, or 4 to indicate the version
1980Sstevel@tonic-gate  * number of choice.  If the server (or the client) do not support
1990Sstevel@tonic-gate  * the version indicated, then the mount attempt will be failed.
2000Sstevel@tonic-gate  *
2010Sstevel@tonic-gate  * nfsvers_to_use is the actual version number found to use.  It
2020Sstevel@tonic-gate  * is determined in get_fh by pinging the various versions of the
2030Sstevel@tonic-gate  * NFS service on the server to see which responds positively.
204489Soa138391  *
205489Soa138391  * nfsretry_vers is the version number set when we retry the mount
206489Soa138391  * command with the version decremented from nfsvers_to_use.
207489Soa138391  * nfsretry_vers is set from nfsvers_to_use when we retry the mount
208489Soa138391  * for errors other than RPC errors; it helps un know why we are
209489Soa138391  * retrying. It is an indication that the retry is due to
210489Soa138391  * non-RPC errors.
2110Sstevel@tonic-gate  */
2120Sstevel@tonic-gate static rpcvers_t nfsvers = 0;
2130Sstevel@tonic-gate static rpcvers_t nfsvers_to_use = 0;
214489Soa138391 static rpcvers_t nfsretry_vers = 0;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate  * There are the defaults (range) for the client when determining
2180Sstevel@tonic-gate  * which NFS version to use when probing the server (see above).
2190Sstevel@tonic-gate  * These will only be used when the vers mount option is not used and
220*13080SPavan.Mettu@Oracle.COM  * these may be reset if NFS SMF is configured to do so.
2210Sstevel@tonic-gate  */
2220Sstevel@tonic-gate static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT;
2230Sstevel@tonic-gate static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT;
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate /*
2260Sstevel@tonic-gate  * This variable controls whether to try the public file handle.
2270Sstevel@tonic-gate  */
2280Sstevel@tonic-gate static bool_t public_opt;
2290Sstevel@tonic-gate 
230249Sjwahlig int
main(int argc,char * argv[])231249Sjwahlig main(int argc, char *argv[])
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	struct mnttab mnt;
2340Sstevel@tonic-gate 	extern char *optarg;
2350Sstevel@tonic-gate 	extern int optind;
2360Sstevel@tonic-gate 	char optbuf[MAX_MNTOPT_STR];
2370Sstevel@tonic-gate 	int ro = 0;
2380Sstevel@tonic-gate 	int r;
2390Sstevel@tonic-gate 	int c;
2400Sstevel@tonic-gate 	char *myname;
241489Soa138391 	err_ret_t retry_error;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2440Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
2450Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
2460Sstevel@tonic-gate #endif
2470Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	myname = strrchr(argv[0], '/');
2500Sstevel@tonic-gate 	myname = myname ? myname + 1 : argv[0];
2510Sstevel@tonic-gate 	(void) snprintf(typename, sizeof (typename), "%s %s",
2520Sstevel@tonic-gate 	    MNTTYPE_NFS, myname);
2530Sstevel@tonic-gate 	argv[0] = typename;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	mnt.mnt_mntopts = optbuf;
2560Sstevel@tonic-gate 	(void) strcpy(optbuf, "rw");
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	/*
2590Sstevel@tonic-gate 	 * Set options
2600Sstevel@tonic-gate 	 */
2610Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "ro:mOq")) != EOF) {
2620Sstevel@tonic-gate 		switch (c) {
2630Sstevel@tonic-gate 		case 'r':
2640Sstevel@tonic-gate 			ro++;
2650Sstevel@tonic-gate 			break;
2660Sstevel@tonic-gate 		case 'o':
2670Sstevel@tonic-gate 			if (strlen(optarg) >= MAX_MNTOPT_STR) {
2680Sstevel@tonic-gate 				pr_err(gettext("option string too long"));
2690Sstevel@tonic-gate 				return (RET_ERR);
2700Sstevel@tonic-gate 			}
2710Sstevel@tonic-gate 			(void) strcpy(mnt.mnt_mntopts, optarg);
2720Sstevel@tonic-gate #ifdef LATER					/* XXX */
2730Sstevel@tonic-gate 			if (strstr(optarg, MNTOPT_REMOUNT)) {
2740Sstevel@tonic-gate 				/*
2750Sstevel@tonic-gate 				 * If remount is specified, only rw is allowed.
2760Sstevel@tonic-gate 				 */
2770Sstevel@tonic-gate 				if ((strcmp(optarg, MNTOPT_REMOUNT) != 0) &&
2780Sstevel@tonic-gate 				    (strcmp(optarg, "remount,rw") != 0) &&
2790Sstevel@tonic-gate 				    (strcmp(optarg, "rw,remount") != 0)) {
2800Sstevel@tonic-gate 					pr_err(gettext("Invalid options\n"));
2810Sstevel@tonic-gate 					exit(RET_ERR);
2820Sstevel@tonic-gate 				}
2830Sstevel@tonic-gate 			}
2840Sstevel@tonic-gate #endif /* LATER */				/* XXX */
2850Sstevel@tonic-gate 			break;
2860Sstevel@tonic-gate 		case 'm':
2870Sstevel@tonic-gate 			mflg++;
2880Sstevel@tonic-gate 			break;
2890Sstevel@tonic-gate 		case 'O':
2900Sstevel@tonic-gate 			Oflg++;
2910Sstevel@tonic-gate 			break;
2920Sstevel@tonic-gate 		case 'q':
2930Sstevel@tonic-gate 			qflg++;
2940Sstevel@tonic-gate 			break;
2950Sstevel@tonic-gate 		default:
2960Sstevel@tonic-gate 			usage();
2970Sstevel@tonic-gate 			exit(RET_ERR);
2980Sstevel@tonic-gate 		}
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate 	if (argc - optind != 2) {
3010Sstevel@tonic-gate 		usage();
3020Sstevel@tonic-gate 		exit(RET_ERR);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	mnt.mnt_special = argv[optind];
3060Sstevel@tonic-gate 	mnt.mnt_mountp = argv[optind+1];
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	if (!priv_ineffect(PRIV_SYS_MOUNT) ||
3090Sstevel@tonic-gate 	    !priv_ineffect(PRIV_NET_PRIVADDR)) {
3100Sstevel@tonic-gate 		pr_err(gettext("insufficient privileges\n"));
3110Sstevel@tonic-gate 		exit(RET_ERR);
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	/*
3153378Srica 	 * On a labeled system, allow read-down nfs mounts if privileged
3163378Srica 	 * (PRIV_NET_MAC_AWARE) to do so.  Otherwise, ignore the error
3173378Srica 	 * and "mount equal label only" behavior will result.
3183378Srica 	 */
3193378Srica 	if (is_system_labeled())
3203378Srica 		(void) setpflags(NET_MAC_AWARE, 1);
3213378Srica 
3223378Srica 	/*
323*13080SPavan.Mettu@Oracle.COM 	 * Read the NFS SMF defaults to see if the min/max versions have
3240Sstevel@tonic-gate 	 * been set and therefore would override the encoded defaults.
3250Sstevel@tonic-gate 	 * Then check to make sure that if they were set that the
3260Sstevel@tonic-gate 	 * values are reasonable.
3270Sstevel@tonic-gate 	 */
3280Sstevel@tonic-gate 	read_default();
3290Sstevel@tonic-gate 	if (vers_min_default > vers_max_default ||
3305302Sth199096 	    vers_min_default < NFS_VERSMIN ||
3315302Sth199096 	    vers_max_default > NFS_VERSMAX) {
332*13080SPavan.Mettu@Oracle.COM 		pr_err("%s\n%s %s\n",
3335302Sth199096 		    gettext("Incorrect configuration of client\'s"),
334*13080SPavan.Mettu@Oracle.COM 		    gettext("client_versmin or 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
pr_err(const char * fmt,...)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
usage()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
mount_nfs(struct mnttab * mntp,int ro,err_ret_t * retry_error)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 
95412782SMarcel.Telka@Sun.COM static int
convert_int(int * val,char * str)95512782SMarcel.Telka@Sun.COM convert_int(int *val, char *str)
95612782SMarcel.Telka@Sun.COM {
95712782SMarcel.Telka@Sun.COM 	long lval;
95812782SMarcel.Telka@Sun.COM 
95912782SMarcel.Telka@Sun.COM 	if (str == NULL || !isdigit(*str))
96012782SMarcel.Telka@Sun.COM 		return (-1);
96112782SMarcel.Telka@Sun.COM 
96212782SMarcel.Telka@Sun.COM 	lval = strtol(str, &str, 10);
96312782SMarcel.Telka@Sun.COM 	if (*str != '\0' || lval > INT_MAX)
96412782SMarcel.Telka@Sun.COM 		return (-2);
96512782SMarcel.Telka@Sun.COM 
96612782SMarcel.Telka@Sun.COM 	*val = (int)lval;
96712782SMarcel.Telka@Sun.COM 	return (0);
96812782SMarcel.Telka@Sun.COM }
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate static int
set_args(int * mntflags,struct nfs_args * args,char * fshost,struct mnttab * mnt)9710Sstevel@tonic-gate set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt)
9720Sstevel@tonic-gate {
9730Sstevel@tonic-gate 	char *saveopt, *optstr, *opts, *newopts, *val;
97412782SMarcel.Telka@Sun.COM 	int num;
9750Sstevel@tonic-gate 	int largefiles = 0;
9760Sstevel@tonic-gate 	int invalid = 0;
9770Sstevel@tonic-gate 	int attrpref = 0;
9780Sstevel@tonic-gate 	int optlen;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	args->flags = NFSMNT_INT;	/* default is "intr" */
9810Sstevel@tonic-gate 	args->flags |= NFSMNT_HOSTNAME;
9820Sstevel@tonic-gate 	args->flags |= NFSMNT_NEWARGS;	/* using extented nfs_args structure */
9830Sstevel@tonic-gate 	args->hostname = fshost;
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	optstr = opts = strdup(mnt->mnt_mntopts);
9860Sstevel@tonic-gate 	/* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */
9870Sstevel@tonic-gate 	optlen = strlen(mnt->mnt_mntopts) + sizeof (MNTOPT_XATTR) + 1;
9880Sstevel@tonic-gate 	if (optlen > MAX_MNTOPT_STR) {
9890Sstevel@tonic-gate 		pr_err(gettext("option string too long"));
9900Sstevel@tonic-gate 		return (RET_ERR);
9910Sstevel@tonic-gate 	}
9920Sstevel@tonic-gate 	newopts = malloc(optlen);
9930Sstevel@tonic-gate 	if (opts == NULL || newopts == NULL) {
9940Sstevel@tonic-gate 		pr_err(gettext("no memory"));
9950Sstevel@tonic-gate 		if (opts)
9960Sstevel@tonic-gate 			free(opts);
9970Sstevel@tonic-gate 		if (newopts)
9980Sstevel@tonic-gate 			free(newopts);
9990Sstevel@tonic-gate 		return (RET_ERR);
10000Sstevel@tonic-gate 	}
10010Sstevel@tonic-gate 	newopts[0] = '\0';
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	while (*opts) {
10040Sstevel@tonic-gate 		invalid = 0;
10050Sstevel@tonic-gate 		saveopt = opts;
10060Sstevel@tonic-gate 		switch (getsubopt(&opts, optlist, &val)) {
10070Sstevel@tonic-gate 		case OPT_RO:
10080Sstevel@tonic-gate 			*mntflags |= MS_RDONLY;
10090Sstevel@tonic-gate 			break;
10100Sstevel@tonic-gate 		case OPT_RW:
10110Sstevel@tonic-gate 			*mntflags &= ~(MS_RDONLY);
10120Sstevel@tonic-gate 			break;
10130Sstevel@tonic-gate 		case OPT_QUOTA:
10140Sstevel@tonic-gate 		case OPT_NOQUOTA:
10150Sstevel@tonic-gate 			break;
10160Sstevel@tonic-gate 		case OPT_SOFT:
10170Sstevel@tonic-gate 			args->flags |= NFSMNT_SOFT;
10180Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_SEMISOFT);
10190Sstevel@tonic-gate 			break;
10200Sstevel@tonic-gate 		case OPT_SEMISOFT:
10210Sstevel@tonic-gate 			args->flags |= NFSMNT_SOFT;
10220Sstevel@tonic-gate 			args->flags |= NFSMNT_SEMISOFT;
10230Sstevel@tonic-gate 			break;
10240Sstevel@tonic-gate 		case OPT_HARD:
10250Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_SOFT);
10260Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_SEMISOFT);
10270Sstevel@tonic-gate 			break;
10280Sstevel@tonic-gate 		case OPT_SUID:
10290Sstevel@tonic-gate 			*mntflags &= ~(MS_NOSUID);
10300Sstevel@tonic-gate 			break;
10310Sstevel@tonic-gate 		case OPT_NOSUID:
10320Sstevel@tonic-gate 			*mntflags |= MS_NOSUID;
10330Sstevel@tonic-gate 			break;
10340Sstevel@tonic-gate 		case OPT_GRPID:
10350Sstevel@tonic-gate 			args->flags |= NFSMNT_GRPID;
10360Sstevel@tonic-gate 			break;
10370Sstevel@tonic-gate 		case OPT_REMOUNT:
10380Sstevel@tonic-gate 			*mntflags |= MS_REMOUNT;
10390Sstevel@tonic-gate 			break;
10400Sstevel@tonic-gate 		case OPT_INTR:
10410Sstevel@tonic-gate 			args->flags |= NFSMNT_INT;
10420Sstevel@tonic-gate 			break;
10430Sstevel@tonic-gate 		case OPT_NOINTR:
10440Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_INT);
10450Sstevel@tonic-gate 			break;
10460Sstevel@tonic-gate 		case OPT_NOAC:
10470Sstevel@tonic-gate 			args->flags |= NFSMNT_NOAC;
10480Sstevel@tonic-gate 			break;
10490Sstevel@tonic-gate 		case OPT_PORT:
105012782SMarcel.Telka@Sun.COM 			if (convert_int(&num, val) != 0)
10510Sstevel@tonic-gate 				goto badopt;
105212782SMarcel.Telka@Sun.COM 			nfs_port = htons((ushort_t)num);
10530Sstevel@tonic-gate 			break;
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 		case OPT_SECURE:
10560Sstevel@tonic-gate 			if (nfs_getseconfig_byname("dh", &nfs_sec)) {
10575302Sth199096 				pr_err(gettext("can not get \"dh\" from %s\n"),
10585302Sth199096 				    NFSSEC_CONF);
10595302Sth199096 				goto badopt;
10600Sstevel@tonic-gate 			}
10610Sstevel@tonic-gate 			sec_opt++;
10620Sstevel@tonic-gate 			break;
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 		case OPT_NOCTO:
10650Sstevel@tonic-gate 			args->flags |= NFSMNT_NOCTO;
10660Sstevel@tonic-gate 			break;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 		case OPT_RSIZE:
106912782SMarcel.Telka@Sun.COM 			if (convert_int(&args->rsize, val) != 0)
107012782SMarcel.Telka@Sun.COM 				goto badopt;
10710Sstevel@tonic-gate 			args->flags |= NFSMNT_RSIZE;
10720Sstevel@tonic-gate 			break;
10730Sstevel@tonic-gate 		case OPT_WSIZE:
107412782SMarcel.Telka@Sun.COM 			if (convert_int(&args->wsize, val) != 0)
107512782SMarcel.Telka@Sun.COM 				goto badopt;
10760Sstevel@tonic-gate 			args->flags |= NFSMNT_WSIZE;
10770Sstevel@tonic-gate 			break;
10780Sstevel@tonic-gate 		case OPT_TIMEO:
107912782SMarcel.Telka@Sun.COM 			if (convert_int(&args->timeo, val) != 0)
108012782SMarcel.Telka@Sun.COM 				goto badopt;
10810Sstevel@tonic-gate 			args->flags |= NFSMNT_TIMEO;
10820Sstevel@tonic-gate 			break;
10830Sstevel@tonic-gate 		case OPT_RETRANS:
108412782SMarcel.Telka@Sun.COM 			if (convert_int(&args->retrans, val) != 0)
108512782SMarcel.Telka@Sun.COM 				goto badopt;
10860Sstevel@tonic-gate 			args->flags |= NFSMNT_RETRANS;
10870Sstevel@tonic-gate 			break;
10880Sstevel@tonic-gate 		case OPT_ACTIMEO:
108912782SMarcel.Telka@Sun.COM 			if (convert_int(&args->acregmax, val) != 0)
109012782SMarcel.Telka@Sun.COM 				goto badopt;
109112782SMarcel.Telka@Sun.COM 			args->acdirmin = args->acregmin = args->acdirmax
109212782SMarcel.Telka@Sun.COM 			    = args->acregmax;
10930Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMAX;
10940Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMAX;
10950Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMIN;
10960Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMIN;
10970Sstevel@tonic-gate 			break;
10980Sstevel@tonic-gate 		case OPT_ACREGMIN:
109912782SMarcel.Telka@Sun.COM 			if (convert_int(&args->acregmin, val) != 0)
110012782SMarcel.Telka@Sun.COM 				goto badopt;
11010Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMIN;
11020Sstevel@tonic-gate 			break;
11030Sstevel@tonic-gate 		case OPT_ACREGMAX:
110412782SMarcel.Telka@Sun.COM 			if (convert_int(&args->acregmax, val) != 0)
110512782SMarcel.Telka@Sun.COM 				goto badopt;
11060Sstevel@tonic-gate 			args->flags |= NFSMNT_ACREGMAX;
11070Sstevel@tonic-gate 			break;
11080Sstevel@tonic-gate 		case OPT_ACDIRMIN:
110912782SMarcel.Telka@Sun.COM 			if (convert_int(&args->acdirmin, val) != 0)
111012782SMarcel.Telka@Sun.COM 				goto badopt;
11110Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMIN;
11120Sstevel@tonic-gate 			break;
11130Sstevel@tonic-gate 		case OPT_ACDIRMAX:
111412782SMarcel.Telka@Sun.COM 			if (convert_int(&args->acdirmax, val) != 0)
111512782SMarcel.Telka@Sun.COM 				goto badopt;
11160Sstevel@tonic-gate 			args->flags |= NFSMNT_ACDIRMAX;
11170Sstevel@tonic-gate 			break;
11180Sstevel@tonic-gate 		case OPT_BG:
11190Sstevel@tonic-gate 			bg++;
11200Sstevel@tonic-gate 			break;
11210Sstevel@tonic-gate 		case OPT_FG:
11220Sstevel@tonic-gate 			bg = 0;
11230Sstevel@tonic-gate 			break;
11240Sstevel@tonic-gate 		case OPT_RETRY:
112512782SMarcel.Telka@Sun.COM 			if (convert_int(&retries, val) != 0)
11260Sstevel@tonic-gate 				goto badopt;
11270Sstevel@tonic-gate 			break;
11280Sstevel@tonic-gate 		case OPT_LLOCK:
11290Sstevel@tonic-gate 			args->flags |= NFSMNT_LLOCK;
11300Sstevel@tonic-gate 			break;
11310Sstevel@tonic-gate 		case OPT_POSIX:
11320Sstevel@tonic-gate 			posix = 1;
11330Sstevel@tonic-gate 			break;
11340Sstevel@tonic-gate 		case OPT_VERS:
113512782SMarcel.Telka@Sun.COM 			if (convert_int(&num, val) != 0)
11360Sstevel@tonic-gate 				goto badopt;
113712782SMarcel.Telka@Sun.COM 			nfsvers = (rpcvers_t)num;
11380Sstevel@tonic-gate 			break;
11390Sstevel@tonic-gate 		case OPT_PROTO:
114077Soa138391 			if (val == NULL)
114177Soa138391 				goto badopt;
114277Soa138391 
11430Sstevel@tonic-gate 			nfs_proto = (char *)malloc(strlen(val)+1);
114477Soa138391 			if (!nfs_proto) {
114577Soa138391 				pr_err(gettext("no memory"));
114677Soa138391 				return (RET_ERR);
114777Soa138391 			}
114877Soa138391 
114977Soa138391 			(void) strncpy(nfs_proto, val, strlen(val)+1);
11500Sstevel@tonic-gate 			break;
11515302Sth199096 
11520Sstevel@tonic-gate 		case OPT_NOPRINT:
11530Sstevel@tonic-gate 			args->flags |= NFSMNT_NOPRINT;
11540Sstevel@tonic-gate 			break;
11555302Sth199096 
11560Sstevel@tonic-gate 		case OPT_LARGEFILES:
11570Sstevel@tonic-gate 			largefiles = 1;
11580Sstevel@tonic-gate 			break;
11595302Sth199096 
11600Sstevel@tonic-gate 		case OPT_NOLARGEFILES:
11610Sstevel@tonic-gate 			pr_err(gettext("NFS can't support \"nolargefiles\"\n"));
11620Sstevel@tonic-gate 			free(optstr);
11630Sstevel@tonic-gate 			return (RET_ERR);
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 		case OPT_SEC:
11665885Sdougm 			if (val == NULL) {
11675885Sdougm 				pr_err(gettext(
11685885Sdougm 				    "\"sec\" option requires argument\n"));
11695885Sdougm 				return (RET_ERR);
11705885Sdougm 			}
11710Sstevel@tonic-gate 			if (nfs_getseconfig_byname(val, &nfs_sec)) {
11725302Sth199096 				pr_err(gettext("can not get \"%s\" from %s\n"),
11735302Sth199096 				    val, NFSSEC_CONF);
11745302Sth199096 				return (RET_ERR);
11750Sstevel@tonic-gate 			}
11760Sstevel@tonic-gate 			sec_opt++;
11770Sstevel@tonic-gate 			break;
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 		case OPT_PUBLIC:
11800Sstevel@tonic-gate 			public_opt = TRUE;
11810Sstevel@tonic-gate 			break;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 		case OPT_DIRECTIO:
11840Sstevel@tonic-gate 			args->flags |= NFSMNT_DIRECTIO;
11850Sstevel@tonic-gate 			break;
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 		case OPT_NODIRECTIO:
11880Sstevel@tonic-gate 			args->flags &= ~(NFSMNT_DIRECTIO);
11890Sstevel@tonic-gate 			break;
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 		case OPT_XATTR:
11920Sstevel@tonic-gate 		case OPT_NOXATTR:
11930Sstevel@tonic-gate 			/*
11940Sstevel@tonic-gate 			 * VFS options; just need to get them into the
11950Sstevel@tonic-gate 			 * new mount option string and note we've seen them
11960Sstevel@tonic-gate 			 */
11970Sstevel@tonic-gate 			attrpref = 1;
11980Sstevel@tonic-gate 			break;
11990Sstevel@tonic-gate 		default:
12000Sstevel@tonic-gate 			/*
12010Sstevel@tonic-gate 			 * Note that this could be a valid OPT_* option so
12020Sstevel@tonic-gate 			 * we can't use "val" but need to use "saveopt".
12030Sstevel@tonic-gate 			 */
12040Sstevel@tonic-gate 			if (fsisstdopt(saveopt))
12050Sstevel@tonic-gate 				break;
12060Sstevel@tonic-gate 			invalid = 1;
12070Sstevel@tonic-gate 			if (!qflg)
12080Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
12090Sstevel@tonic-gate 				    "mount: %s on %s - WARNING unknown option"
12100Sstevel@tonic-gate 				    " \"%s\"\n"), mnt->mnt_special,
12110Sstevel@tonic-gate 				    mnt->mnt_mountp, saveopt);
12120Sstevel@tonic-gate 			break;
12130Sstevel@tonic-gate 		}
12140Sstevel@tonic-gate 		if (!invalid) {
12150Sstevel@tonic-gate 			if (newopts[0])
12160Sstevel@tonic-gate 				strcat(newopts, ",");
12170Sstevel@tonic-gate 			strcat(newopts, saveopt);
12180Sstevel@tonic-gate 		}
12190Sstevel@tonic-gate 	}
12200Sstevel@tonic-gate 	/* Default is to turn extended attrs on */
12210Sstevel@tonic-gate 	if (!attrpref) {
12220Sstevel@tonic-gate 		if (newopts[0])
12230Sstevel@tonic-gate 			strcat(newopts, ",");
12240Sstevel@tonic-gate 		strcat(newopts, MNTOPT_XATTR);
12250Sstevel@tonic-gate 	}
12260Sstevel@tonic-gate 	strcpy(mnt->mnt_mntopts, newopts);
12270Sstevel@tonic-gate 	free(newopts);
12280Sstevel@tonic-gate 	free(optstr);
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	/* ensure that only one secure mode is requested */
12310Sstevel@tonic-gate 	if (sec_opt > 1) {
12320Sstevel@tonic-gate 		pr_err(gettext("Security options conflict\n"));
12330Sstevel@tonic-gate 		return (RET_ERR);
12340Sstevel@tonic-gate 	}
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	/* ensure that the user isn't trying to get large files over V2 */
12370Sstevel@tonic-gate 	if (nfsvers == NFS_VERSION && largefiles) {
12380Sstevel@tonic-gate 		pr_err(gettext("NFS V2 can't support \"largefiles\"\n"));
12390Sstevel@tonic-gate 		return (RET_ERR);
12400Sstevel@tonic-gate 	}
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	if (nfsvers == NFS_V4 &&
12430Sstevel@tonic-gate 	    nfs_proto != NULL &&
12440Sstevel@tonic-gate 	    strncasecmp(nfs_proto, NC_UDP, strlen(NC_UDP)) == 0) {
12450Sstevel@tonic-gate 		pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto);
12460Sstevel@tonic-gate 		return (RET_ERR);
12470Sstevel@tonic-gate 	}
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	return (RET_OK);
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate badopt:
12520Sstevel@tonic-gate 	pr_err(gettext("invalid option: \"%s\"\n"), saveopt);
12530Sstevel@tonic-gate 	free(optstr);
12540Sstevel@tonic-gate 	return (RET_ERR);
12550Sstevel@tonic-gate }
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate static int
make_secure(struct nfs_args * args,char * hostname,struct netconfig * nconf,bool_t use_pubfh,rpcvers_t vers)12580Sstevel@tonic-gate make_secure(struct nfs_args *args, char *hostname, struct netconfig *nconf,
12590Sstevel@tonic-gate 	bool_t use_pubfh, rpcvers_t vers)
12600Sstevel@tonic-gate {
12610Sstevel@tonic-gate 	sec_data_t *secdata;
12620Sstevel@tonic-gate 	int flags;
12630Sstevel@tonic-gate 	struct netbuf *syncaddr = NULL;
12640Sstevel@tonic-gate 	struct nd_addrlist *retaddrs = NULL;
12650Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	/*
12680Sstevel@tonic-gate 	 * check to see if any secure mode is requested.
12690Sstevel@tonic-gate 	 * if not, use default security mode.
12700Sstevel@tonic-gate 	 */
12710Sstevel@tonic-gate 	if (!snego_done && !sec_opt) {
12720Sstevel@tonic-gate 		/*
12735302Sth199096 		 * Get default security mode.
12745302Sth199096 		 * AUTH_UNIX has been the default choice for a long time.
12755302Sth199096 		 * The better NFS security service becomes, the better chance
12765302Sth199096 		 * we will set stronger security service as the default NFS
12775302Sth199096 		 * security mode.
12780Sstevel@tonic-gate 		 */
12795302Sth199096 		if (nfs_getseconfig_default(&nfs_sec)) {
12805302Sth199096 			pr_err(gettext("error getting default"
12815302Sth199096 			    " security entry\n"));
12825302Sth199096 			return (-1);
12835302Sth199096 		}
12845302Sth199096 		args->flags |= NFSMNT_SECDEFAULT;
12850Sstevel@tonic-gate 	}
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	/*
12880Sstevel@tonic-gate 	 * Get the network address for the time service on the server.
12890Sstevel@tonic-gate 	 * If an RPC based time service is not available then try the
12900Sstevel@tonic-gate 	 * IP time service.
12910Sstevel@tonic-gate 	 *
12920Sstevel@tonic-gate 	 * This is for AUTH_DH processing. We will also pass down syncaddr
12930Sstevel@tonic-gate 	 * and netname for NFS V4 even if AUTH_DH is not requested right now.
12940Sstevel@tonic-gate 	 * NFS V4 does security negotiation in the kernel via SECINFO.
12950Sstevel@tonic-gate 	 * These information might be needed later in the kernel.
12960Sstevel@tonic-gate 	 *
12970Sstevel@tonic-gate 	 * Eventurally, we want to move this code to nfs_clnt_secdata()
12980Sstevel@tonic-gate 	 * when autod_nfs.c and mount.c can share the same get_the_addr()
12990Sstevel@tonic-gate 	 * routine.
13000Sstevel@tonic-gate 	 */
13010Sstevel@tonic-gate 	flags = 0;
13020Sstevel@tonic-gate 	syncaddr = NULL;
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate 	if (nfs_sec.sc_rpcnum == AUTH_DH || vers == NFS_V4) {
13050Sstevel@tonic-gate 		/*
13060Sstevel@tonic-gate 		 * If using the public fh or nfsv4, we will not contact the
13070Sstevel@tonic-gate 		 * remote RPCBINDer, since it is possibly behind a firewall.
13080Sstevel@tonic-gate 		 */
13095302Sth199096 		if (use_pubfh == FALSE && vers != NFS_V4)
13100Sstevel@tonic-gate 			syncaddr = get_the_addr(hostname, RPCBPROG, RPCBVERS,
13115302Sth199096 			    nconf, 0, NULL, NULL, FALSE, NULL, NULL);
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 		if (syncaddr != NULL) {
13140Sstevel@tonic-gate 			/* for flags in sec_data */
13150Sstevel@tonic-gate 			flags |= AUTH_F_RPCTIMESYNC;
13160Sstevel@tonic-gate 		} else {
13170Sstevel@tonic-gate 			struct nd_hostserv hs;
13180Sstevel@tonic-gate 			int error;
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 			hs.h_host = hostname;
13210Sstevel@tonic-gate 			hs.h_serv = "timserver";
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 			error = netdir_getbyname(nconf, &hs, &retaddrs);
13240Sstevel@tonic-gate 
13250Sstevel@tonic-gate 			if (error != ND_OK && (nfs_sec.sc_rpcnum == AUTH_DH)) {
13265302Sth199096 				pr_err(gettext("%s: secure: no time service\n"),
13275302Sth199096 				    hostname);
13285302Sth199096 				return (-1);
13290Sstevel@tonic-gate 			}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 			if (error == ND_OK)
13320Sstevel@tonic-gate 				syncaddr = retaddrs->n_addrs;
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 			/*
13350Sstevel@tonic-gate 			 * For NFS_V4 if AUTH_DH is negotiated later in the
13360Sstevel@tonic-gate 			 * kernel thru SECINFO, it will need syncaddr
13370Sstevel@tonic-gate 			 * and netname data.
13380Sstevel@tonic-gate 			 */
13390Sstevel@tonic-gate 			if (vers == NFS_V4 && syncaddr &&
13405302Sth199096 			    host2netname(netname, hostname, NULL)) {
13415302Sth199096 				args->syncaddr = malloc(sizeof (struct netbuf));
13425302Sth199096 				args->syncaddr->buf = malloc(syncaddr->len);
13435302Sth199096 				(void) memcpy(args->syncaddr->buf,
13445302Sth199096 				    syncaddr->buf, syncaddr->len);
13455302Sth199096 				args->syncaddr->len = syncaddr->len;
13465302Sth199096 				args->syncaddr->maxlen = syncaddr->maxlen;
13475302Sth199096 				args->netname = strdup(netname);
13485302Sth199096 				args->flags |= NFSMNT_SECURE;
13490Sstevel@tonic-gate 			}
13500Sstevel@tonic-gate 		}
13510Sstevel@tonic-gate 	}
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	/*
13540Sstevel@tonic-gate 	 * For the initial chosen flavor (any flavor defined in nfssec.conf),
13550Sstevel@tonic-gate 	 * the data will be stored in the sec_data structure via
13560Sstevel@tonic-gate 	 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
13570Sstevel@tonic-gate 	 * extended data structure.
13580Sstevel@tonic-gate 	 */
13590Sstevel@tonic-gate 	if (!(secdata = nfs_clnt_secdata(&nfs_sec, hostname, args->knconf,
13605302Sth199096 	    syncaddr, flags))) {
13610Sstevel@tonic-gate 		pr_err(gettext("errors constructing security related data\n"));
13620Sstevel@tonic-gate 		if (flags & AUTH_F_RPCTIMESYNC) {
13630Sstevel@tonic-gate 			free(syncaddr->buf);
13640Sstevel@tonic-gate 			free(syncaddr);
13650Sstevel@tonic-gate 		} else if (retaddrs)
13660Sstevel@tonic-gate 			netdir_free((void *)retaddrs, ND_ADDRLIST);
13670Sstevel@tonic-gate 		return (-1);
13680Sstevel@tonic-gate 	}
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 	NFS_ARGS_EXTB_secdata(args, secdata);
13710Sstevel@tonic-gate 	if (flags & AUTH_F_RPCTIMESYNC) {
13720Sstevel@tonic-gate 		free(syncaddr->buf);
13730Sstevel@tonic-gate 		free(syncaddr);
13740Sstevel@tonic-gate 	} else if (retaddrs)
13750Sstevel@tonic-gate 		netdir_free((void *)retaddrs, ND_ADDRLIST);
13760Sstevel@tonic-gate 	return (0);
13770Sstevel@tonic-gate }
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate /*
13800Sstevel@tonic-gate  * Get the network address on "hostname" for program "prog"
13810Sstevel@tonic-gate  * with version "vers" by using the nconf configuration data
13820Sstevel@tonic-gate  * passed in.
13830Sstevel@tonic-gate  *
13840Sstevel@tonic-gate  * If the address of a netconfig pointer is null then
13850Sstevel@tonic-gate  * information is not sufficient and no netbuf will be returned.
13860Sstevel@tonic-gate  *
13870Sstevel@tonic-gate  * Finally, ping the null procedure of that service.
13880Sstevel@tonic-gate  *
13890Sstevel@tonic-gate  * A similar routine is also defined in ../../autofs/autod_nfs.c.
13900Sstevel@tonic-gate  * This is a potential routine to move to ../lib for common usage.
13910Sstevel@tonic-gate  */
13920Sstevel@tonic-gate static struct netbuf *
get_the_addr(char * hostname,ulong_t prog,ulong_t vers,struct netconfig * nconf,ushort_t port,struct t_info * tinfo,caddr_t * fhp,bool_t get_pubfh,char * fspath,err_ret_t * error)13930Sstevel@tonic-gate get_the_addr(char *hostname, ulong_t prog, ulong_t vers,
13940Sstevel@tonic-gate 	struct netconfig *nconf, ushort_t port, struct t_info *tinfo,
13950Sstevel@tonic-gate 	caddr_t *fhp, bool_t get_pubfh, char *fspath, err_ret_t *error)
13960Sstevel@tonic-gate {
13970Sstevel@tonic-gate 	struct netbuf *nb = NULL;
13980Sstevel@tonic-gate 	struct t_bind *tbind = NULL;
13990Sstevel@tonic-gate 	CLIENT *cl = NULL;
14000Sstevel@tonic-gate 	struct timeval tv;
14010Sstevel@tonic-gate 	int fd = -1;
14020Sstevel@tonic-gate 	AUTH *ah = NULL;
14030Sstevel@tonic-gate 	AUTH *new_ah = NULL;
14040Sstevel@tonic-gate 	struct snego_t snego;
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	if (nconf == NULL)
14070Sstevel@tonic-gate 		return (NULL);
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 	if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1)
14105302Sth199096 		goto done;
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	/* LINTED pointer alignment */
14130Sstevel@tonic-gate 	if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
14145302Sth199096 	    == NULL)
14150Sstevel@tonic-gate 		goto done;
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 	/*
14180Sstevel@tonic-gate 	 * In the case of public filehandle usage or NFSv4 we want to
14190Sstevel@tonic-gate 	 * avoid use of the rpcbind/portmap protocol
14200Sstevel@tonic-gate 	 */
14210Sstevel@tonic-gate 	if ((get_pubfh == TRUE) || (vers == NFS_V4)) {
14220Sstevel@tonic-gate 		struct nd_hostserv hs;
14230Sstevel@tonic-gate 		struct nd_addrlist *retaddrs;
14240Sstevel@tonic-gate 		int retval;
14250Sstevel@tonic-gate 		hs.h_host = hostname;
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate 		/* NFS where vers==4 does not support UDP */
14280Sstevel@tonic-gate 		if (vers == NFS_V4 &&
14290Sstevel@tonic-gate 		    strncasecmp(nconf->nc_proto, NC_UDP,
14305302Sth199096 		    strlen(NC_UDP)) == 0) {
143177Soa138391 			SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
14320Sstevel@tonic-gate 			goto done;
14330Sstevel@tonic-gate 		}
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 		if (port == 0)
14360Sstevel@tonic-gate 			hs.h_serv = "nfs";
14370Sstevel@tonic-gate 		else
14380Sstevel@tonic-gate 			hs.h_serv = NULL;
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 		if ((retval = netdir_getbyname(nconf, &hs, &retaddrs))
14410Sstevel@tonic-gate 		    != ND_OK) {
14420Sstevel@tonic-gate 			/*
14430Sstevel@tonic-gate 			 * Carefully set the error value here. Want to signify
14440Sstevel@tonic-gate 			 * that the error was an unknown host.
14450Sstevel@tonic-gate 			 */
14460Sstevel@tonic-gate 			if (retval == ND_NOHOST) {
14470Sstevel@tonic-gate 				SET_ERR_RET(error, ERR_NOHOST, retval);
14480Sstevel@tonic-gate 			}
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 			goto done;
14510Sstevel@tonic-gate 		}
14520Sstevel@tonic-gate 		memcpy(tbind->addr.buf, retaddrs->n_addrs->buf,
14535302Sth199096 		    retaddrs->n_addrs->len);
14540Sstevel@tonic-gate 		tbind->addr.len = retaddrs->n_addrs->len;
14550Sstevel@tonic-gate 		netdir_free((void *)retaddrs, ND_ADDRLIST);
14560Sstevel@tonic-gate 		(void) netdir_options(nconf, ND_SET_RESERVEDPORT, fd, NULL);
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	} else {
14590Sstevel@tonic-gate 		if (rpcb_getaddr(prog, vers, nconf, &tbind->addr,
14600Sstevel@tonic-gate 		    hostname) == FALSE) {
14610Sstevel@tonic-gate 			goto done;
14620Sstevel@tonic-gate 		}
14630Sstevel@tonic-gate 	}
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	if (port) {
14660Sstevel@tonic-gate 		/* LINTED pointer alignment */
14670Sstevel@tonic-gate 		if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
14680Sstevel@tonic-gate 			((struct sockaddr_in *)tbind->addr.buf)->sin_port
14695302Sth199096 			    = port;
14700Sstevel@tonic-gate 		else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
14710Sstevel@tonic-gate 			((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port
14725302Sth199096 			    = port;
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 	}
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
14770Sstevel@tonic-gate 	if (cl == NULL) {
147877Soa138391 		/*
147977Soa138391 		 * clnt_tli_create() returns either RPC_SYSTEMERROR,
148077Soa138391 		 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates
148177Soa138391 		 * to "Misc. TLI error". This is not too helpful. Most likely
148277Soa138391 		 * the connection to the remote server timed out, so this
148377Soa138391 		 * error is at least less perplexing.
148477Soa138391 		 * See: usr/src/cmd/rpcinfo/rpcinfo.c
148577Soa138391 		 */
148677Soa138391 		if (rpc_createerr.cf_stat == RPC_TLIERROR) {
148777Soa138391 			SET_ERR_RET(error, ERR_RPCERROR, RPC_PMAPFAILURE);
148877Soa138391 		} else {
148977Soa138391 			SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat);
149077Soa138391 		}
14910Sstevel@tonic-gate 		goto done;
14920Sstevel@tonic-gate 	}
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	ah = authsys_create_default();
14950Sstevel@tonic-gate 	if (ah != NULL)
14960Sstevel@tonic-gate 		cl->cl_auth = ah;
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 	tv.tv_sec = 5;
14990Sstevel@tonic-gate 	tv.tv_usec = 0;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	(void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 	if ((get_pubfh == TRUE) && (vers != NFS_V4)) {
15045302Sth199096 		enum snego_stat sec;
15050Sstevel@tonic-gate 
15065302Sth199096 		if (!snego_done) {
15075302Sth199096 			/*
15085302Sth199096 			 * negotiate sec flavor.
15095302Sth199096 			 */
15105302Sth199096 			snego.cnt = 0;
15115302Sth199096 			if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) ==
15125302Sth199096 			    SNEGO_SUCCESS) {
15135302Sth199096 				int jj;
15140Sstevel@tonic-gate 
15155302Sth199096 				/*
15165302Sth199096 				 * check if server supports the one
15175302Sth199096 				 * specified in the sec= option.
15185302Sth199096 				 */
15190Sstevel@tonic-gate 				if (sec_opt) {
15205302Sth199096 					for (jj = 0; jj < snego.cnt; jj++) {
15215302Sth199096 						if (snego.array[jj] ==
15225302Sth199096 						    nfs_sec.sc_nfsnum) {
15235302Sth199096 							snego_done = TRUE;
15245302Sth199096 							break;
15255302Sth199096 						}
15265302Sth199096 					}
15270Sstevel@tonic-gate 				}
15285302Sth199096 
15295302Sth199096 				/*
15305302Sth199096 				 * find a common sec flavor
15315302Sth199096 				 */
15325302Sth199096 				if (!snego_done) {
15335302Sth199096 					if (sec_opt) {
15345302Sth199096 						pr_err(gettext(
15355302Sth199096 						    "Server does not support"
15365302Sth199096 						    " the security flavor"
15375302Sth199096 						    " specified.\n"));
15385302Sth199096 					}
15390Sstevel@tonic-gate 
15405302Sth199096 					for (jj = 0; jj < snego.cnt; jj++) {
15415302Sth199096 						if (!nfs_getseconfig_bynumber(
15425302Sth199096 						    snego.array[jj],
15435302Sth199096 						    &nfs_sec)) {
15445302Sth199096 							snego_done = TRUE;
15455302Sth199096 #define	EMSG80SUX "Security flavor %d was negotiated and will be used.\n"
15465302Sth199096 							if (sec_opt)
15475302Sth199096 								pr_err(gettext(
15485302Sth199096 								    EMSG80SUX),
15495302Sth199096 								    nfs_sec.
15505302Sth199096 								    sc_nfsnum);
15515302Sth199096 							break;
15525302Sth199096 						}
15535302Sth199096 					}
15545302Sth199096 				}
15555302Sth199096 
15565302Sth199096 				if (!snego_done)
15575302Sth199096 					return (NULL);
15580Sstevel@tonic-gate 
15595302Sth199096 				/*
15605302Sth199096 				 * Now that the flavor has been
15615302Sth199096 				 * negotiated, get the fh.
15625302Sth199096 				 *
15635302Sth199096 				 * First, create an auth handle using the
15645302Sth199096 				 * negotiated sec flavor in the next lookup to
15655302Sth199096 				 * fetch the filehandle.
15665302Sth199096 				 */
15675302Sth199096 				new_ah = nfs_create_ah(cl, hostname, &nfs_sec);
15685302Sth199096 				if (new_ah == NULL)
15695302Sth199096 					goto done;
15705302Sth199096 				cl->cl_auth = new_ah;
15715302Sth199096 			} else if (sec == SNEGO_ARRAY_TOO_SMALL || sec ==
15725302Sth199096 			    SNEGO_FAILURE) {
15735302Sth199096 				goto done;
15745302Sth199096 			}
15750Sstevel@tonic-gate 
15765302Sth199096 			/*
15775302Sth199096 			 * Note that if sec == SNEGO_DEF_VALID
15785302Sth199096 			 * default sec flavor is acceptable.
15795302Sth199096 			 * Use it to get the filehandle.
15805302Sth199096 			 */
15810Sstevel@tonic-gate 		}
15820Sstevel@tonic-gate 
15835302Sth199096 		if (vers == NFS_VERSION) {
15845302Sth199096 			wnl_diropargs arg;
15857693SVallish.Vaidyeshwara@Sun.COM 			wnl_diropres res;
15865302Sth199096 
15875302Sth199096 			memset((char *)&arg.dir, 0, sizeof (wnl_fh));
15885302Sth199096 			arg.name = fspath;
15897693SVallish.Vaidyeshwara@Sun.COM 			memset((char *)&res, 0, sizeof (wnl_diropres));
15907693SVallish.Vaidyeshwara@Sun.COM 			if (wnlproc_lookup_2(&arg, &res, cl) !=
15917693SVallish.Vaidyeshwara@Sun.COM 			    RPC_SUCCESS || res.status != NFS_OK)
15927693SVallish.Vaidyeshwara@Sun.COM 				goto done;
15935302Sth199096 
15945302Sth199096 			*fhp = malloc(sizeof (wnl_fh));
15950Sstevel@tonic-gate 
15965302Sth199096 			if (*fhp == NULL) {
15975302Sth199096 				pr_err(gettext("no memory\n"));
15985302Sth199096 				goto done;
15995302Sth199096 			}
16000Sstevel@tonic-gate 
16015302Sth199096 			memcpy((char *)*fhp,
16027693SVallish.Vaidyeshwara@Sun.COM 			    (char *)&res.wnl_diropres_u.wnl_diropres.file,
16035302Sth199096 			    sizeof (wnl_fh));
16045302Sth199096 		} else {
16055302Sth199096 			WNL_LOOKUP3args arg;
16067693SVallish.Vaidyeshwara@Sun.COM 			WNL_LOOKUP3res res;
16075302Sth199096 			nfs_fh3 *fh3p;
16080Sstevel@tonic-gate 
16095302Sth199096 			memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3));
16105302Sth199096 			arg.what.name = fspath;
16117693SVallish.Vaidyeshwara@Sun.COM 			memset((char *)&res, 0, sizeof (WNL_LOOKUP3res));
16127693SVallish.Vaidyeshwara@Sun.COM 			if (wnlproc3_lookup_3(&arg, &res, cl) !=
16137693SVallish.Vaidyeshwara@Sun.COM 			    RPC_SUCCESS || res.status != NFS3_OK)
16145302Sth199096 				goto done;
16155302Sth199096 
16165302Sth199096 			fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
16170Sstevel@tonic-gate 
16185302Sth199096 			if (fh3p == NULL) {
16195302Sth199096 				pr_err(gettext("no memory\n"));
16205302Sth199096 				goto done;
16215302Sth199096 			}
16220Sstevel@tonic-gate 
16235302Sth199096 			fh3p->fh3_length =
16247693SVallish.Vaidyeshwara@Sun.COM 			    res.WNL_LOOKUP3res_u.res_ok.object.data.data_len;
16255302Sth199096 			memcpy(fh3p->fh3_u.data,
16268650SVallish.Vaidyeshwara@Sun.COM 			    res.WNL_LOOKUP3res_u.res_ok.object.data.data_val,
16275302Sth199096 			    fh3p->fh3_length);
16280Sstevel@tonic-gate 
16295302Sth199096 			*fhp = (caddr_t)fh3p;
16305302Sth199096 		}
16310Sstevel@tonic-gate 	} else {
16320Sstevel@tonic-gate 		struct rpc_err r_err;
16337693SVallish.Vaidyeshwara@Sun.COM 		enum clnt_stat rc;
16340Sstevel@tonic-gate 
16357693SVallish.Vaidyeshwara@Sun.COM 		/*
16367693SVallish.Vaidyeshwara@Sun.COM 		 * NULL procedures need not have an argument or
16377693SVallish.Vaidyeshwara@Sun.COM 		 * result param.
16387693SVallish.Vaidyeshwara@Sun.COM 		 */
16390Sstevel@tonic-gate 		if (vers == NFS_VERSION)
16407693SVallish.Vaidyeshwara@Sun.COM 			rc = wnlproc_null_2(NULL, NULL, cl);
16410Sstevel@tonic-gate 		else if (vers == NFS_V3)
16427693SVallish.Vaidyeshwara@Sun.COM 			rc = wnlproc3_null_3(NULL, NULL, cl);
16430Sstevel@tonic-gate 		else
16447693SVallish.Vaidyeshwara@Sun.COM 			rc = wnlproc4_null_4(NULL, NULL, cl);
16450Sstevel@tonic-gate 
16467693SVallish.Vaidyeshwara@Sun.COM 		if (rc != RPC_SUCCESS) {
16470Sstevel@tonic-gate 			clnt_geterr(cl, &r_err);
16480Sstevel@tonic-gate 			if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
16490Sstevel@tonic-gate 				switch (r_err.re_status) {
16500Sstevel@tonic-gate 				case RPC_TLIERROR:
16510Sstevel@tonic-gate 				case RPC_CANTRECV:
16520Sstevel@tonic-gate 				case RPC_CANTSEND:
16530Sstevel@tonic-gate 					r_err.re_status = RPC_PROGVERSMISMATCH;
16540Sstevel@tonic-gate 				}
16550Sstevel@tonic-gate 			}
16560Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status);
16570Sstevel@tonic-gate 			goto done;
16580Sstevel@tonic-gate 		}
16590Sstevel@tonic-gate 	}
16600Sstevel@tonic-gate 
16610Sstevel@tonic-gate 	/*
16620Sstevel@tonic-gate 	 * Make a copy of the netbuf to return
16630Sstevel@tonic-gate 	 */
16640Sstevel@tonic-gate 	nb = (struct netbuf *)malloc(sizeof (*nb));
16650Sstevel@tonic-gate 	if (nb == NULL) {
16660Sstevel@tonic-gate 		pr_err(gettext("no memory\n"));
16670Sstevel@tonic-gate 		goto done;
16680Sstevel@tonic-gate 	}
16690Sstevel@tonic-gate 	*nb = tbind->addr;
16700Sstevel@tonic-gate 	nb->buf = (char *)malloc(nb->maxlen);
16710Sstevel@tonic-gate 	if (nb->buf == NULL) {
16720Sstevel@tonic-gate 		pr_err(gettext("no memory\n"));
16730Sstevel@tonic-gate 		free(nb);
16740Sstevel@tonic-gate 		nb = NULL;
16750Sstevel@tonic-gate 		goto done;
16760Sstevel@tonic-gate 	}
16770Sstevel@tonic-gate 	(void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate done:
16800Sstevel@tonic-gate 	if (cl) {
16815302Sth199096 		if (ah != NULL) {
16825302Sth199096 			if (new_ah != NULL)
16835302Sth199096 				AUTH_DESTROY(ah);
16845302Sth199096 			AUTH_DESTROY(cl->cl_auth);
16855302Sth199096 			cl->cl_auth = NULL;
16865302Sth199096 		}
16875302Sth199096 		clnt_destroy(cl);
16885302Sth199096 		cl = NULL;
16890Sstevel@tonic-gate 	}
16900Sstevel@tonic-gate 	if (tbind) {
16910Sstevel@tonic-gate 		t_free((char *)tbind, T_BIND);
16920Sstevel@tonic-gate 		tbind = NULL;
16930Sstevel@tonic-gate 	}
16940Sstevel@tonic-gate 	if (fd >= 0)
16950Sstevel@tonic-gate 		(void) t_close(fd);
16960Sstevel@tonic-gate 	return (nb);
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate 
16995302Sth199096 static int
check_nconf(struct netconfig * nconf,int nthtry,int * valid_proto)17005302Sth199096 check_nconf(struct netconfig *nconf, int nthtry, int *valid_proto)
17015302Sth199096 {
17025302Sth199096 	int	try_test = 0;
17035302Sth199096 	int	valid_family;
17045302Sth199096 	char	*proto = NULL;
17055302Sth199096 
17065302Sth199096 
17075302Sth199096 	if (nthtry == FIRST_TRY) {
17085302Sth199096 		try_test = ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
17095302Sth199096 		    (nconf->nc_semantics == NC_TPI_COTS));
17105302Sth199096 		proto = NC_TCP;
17115302Sth199096 	} else if (nthtry == SECOND_TRY) {
17125302Sth199096 		try_test = (nconf->nc_semantics == NC_TPI_CLTS);
17135302Sth199096 		proto = NC_UDP;
17145302Sth199096 	}
17155302Sth199096 
17165302Sth199096 	if (proto &&
17175302Sth199096 	    (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
17185302Sth199096 	    strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
17195302Sth199096 	    (strcmp(nconf->nc_proto, proto) == 0))
17205302Sth199096 		*valid_proto = TRUE;
17215302Sth199096 	else
17225302Sth199096 		*valid_proto = FALSE;
17235302Sth199096 
17245302Sth199096 	return (try_test);
17255302Sth199096 }
17265302Sth199096 
17270Sstevel@tonic-gate /*
17280Sstevel@tonic-gate  * Get a network address on "hostname" for program "prog"
17290Sstevel@tonic-gate  * with version "vers".  If the port number is specified (non zero)
17300Sstevel@tonic-gate  * then try for a TCP/UDP transport and set the port number of the
17310Sstevel@tonic-gate  * resulting IP address.
17320Sstevel@tonic-gate  *
17330Sstevel@tonic-gate  * If the address of a netconfig pointer was passed and
17340Sstevel@tonic-gate  * if it's not null, use it as the netconfig otherwise
17350Sstevel@tonic-gate  * assign the address of the netconfig that was used to
17360Sstevel@tonic-gate  * establish contact with the service.
17370Sstevel@tonic-gate  *
17380Sstevel@tonic-gate  * A similar routine is also defined in ../../autofs/autod_nfs.c.
17390Sstevel@tonic-gate  * This is a potential routine to move to ../lib for common usage.
17400Sstevel@tonic-gate  *
17410Sstevel@tonic-gate  * "error" refers to a more descriptive term when get_addr fails
17420Sstevel@tonic-gate  * and returns NULL: ERR_PROTO_NONE if no error introduced by
17430Sstevel@tonic-gate  * -o proto option, ERR_NETPATH if error found in NETPATH
17440Sstevel@tonic-gate  * environment variable, ERR_PROTO_INVALID if an unrecognized
17450Sstevel@tonic-gate  * protocol is specified by user, and ERR_PROTO_UNSUPP for a
17460Sstevel@tonic-gate  * recognized but invalid protocol (eg. ticlts, ticots, etc.).
17470Sstevel@tonic-gate  * "error" is ignored if get_addr returns non-NULL result.
17480Sstevel@tonic-gate  *
17490Sstevel@tonic-gate  */
17500Sstevel@tonic-gate static struct netbuf *
get_addr(char * hostname,ulong_t prog,ulong_t vers,struct netconfig ** nconfp,char * proto,ushort_t port,struct t_info * tinfo,caddr_t * fhp,bool_t get_pubfh,char * fspath,err_ret_t * error)17510Sstevel@tonic-gate get_addr(char *hostname, ulong_t prog, ulong_t vers, struct netconfig **nconfp,
17520Sstevel@tonic-gate 	char *proto, ushort_t port, struct t_info *tinfo, caddr_t *fhp,
17530Sstevel@tonic-gate 	bool_t get_pubfh, char *fspath, err_ret_t *error)
17540Sstevel@tonic-gate {
17550Sstevel@tonic-gate 	struct netbuf *nb = NULL;
17560Sstevel@tonic-gate 	struct netconfig *nconf = NULL;
17570Sstevel@tonic-gate 	NCONF_HANDLE *nc = NULL;
17580Sstevel@tonic-gate 	int nthtry = FIRST_TRY;
17590Sstevel@tonic-gate 	err_ret_t errsave_nohost, errsave_rpcerr;
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 	SET_ERR_RET(&errsave_nohost, ERR_PROTO_NONE, 0);
17620Sstevel@tonic-gate 	SET_ERR_RET(&errsave_rpcerr, ERR_PROTO_NONE, 0);
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 	SET_ERR_RET(error, ERR_PROTO_NONE, 0);
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	if (nconfp && *nconfp)
17670Sstevel@tonic-gate 		return (get_the_addr(hostname, prog, vers, *nconfp, port,
17685302Sth199096 		    tinfo, fhp, get_pubfh, fspath, error));
17690Sstevel@tonic-gate 	/*
17700Sstevel@tonic-gate 	 * No nconf passed in.
17710Sstevel@tonic-gate 	 *
17720Sstevel@tonic-gate 	 * Try to get a nconf from /etc/netconfig filtered by
17730Sstevel@tonic-gate 	 * the NETPATH environment variable.
17740Sstevel@tonic-gate 	 * First search for COTS, second for CLTS unless proto
17750Sstevel@tonic-gate 	 * is specified.  When we retry, we reset the
17760Sstevel@tonic-gate 	 * netconfig list so that we would search the whole list
17770Sstevel@tonic-gate 	 * all over again.
17780Sstevel@tonic-gate 	 */
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	if ((nc = setnetpath()) == NULL) {
17810Sstevel@tonic-gate 		/* should only return an error if problems with NETPATH */
17820Sstevel@tonic-gate 		/* In which case you are hosed */
17830Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_NETPATH, 0);
17840Sstevel@tonic-gate 		goto done;
17850Sstevel@tonic-gate 	}
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 	/*
17880Sstevel@tonic-gate 	 * If proto is specified, then only search for the match,
17890Sstevel@tonic-gate 	 * otherwise try COTS first, if failed, try CLTS.
17900Sstevel@tonic-gate 	 */
17910Sstevel@tonic-gate 	if (proto) {
17920Sstevel@tonic-gate 		/* no matching proto name */
17930Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_PROTO_INVALID, 0);
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 		while (nconf = getnetpath(nc)) {
17960Sstevel@tonic-gate 			if (strcmp(nconf->nc_netid, proto))
17970Sstevel@tonic-gate 				continue;
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate 			/* may be unsupported */
18000Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 			if ((port != 0) &&
18035302Sth199096 			    ((strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
18045302Sth199096 			    strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
18055302Sth199096 			    (strcmp(nconf->nc_proto, NC_TCP) != 0 &&
18065302Sth199096 			    strcmp(nconf->nc_proto, NC_UDP) != 0))) {
18070Sstevel@tonic-gate 				continue;
18085302Sth199096 			} else {
18090Sstevel@tonic-gate 				nb = get_the_addr(hostname, prog,
18105302Sth199096 				    vers, nconf, port, tinfo,
18115302Sth199096 				    fhp, get_pubfh, fspath, error);
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 				if (nb != NULL)
18140Sstevel@tonic-gate 					break;
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 				/* nb is NULL - deal with errors */
18170Sstevel@tonic-gate 				if (error) {
18180Sstevel@tonic-gate 					if (error->error_type == ERR_NOHOST)
18190Sstevel@tonic-gate 						SET_ERR_RET(&errsave_nohost,
18205302Sth199096 						    error->error_type,
18215302Sth199096 						    error->error_value);
18220Sstevel@tonic-gate 					if (error->error_type == ERR_RPCERROR)
18230Sstevel@tonic-gate 						SET_ERR_RET(&errsave_rpcerr,
18245302Sth199096 						    error->error_type,
18255302Sth199096 						    error->error_value);
18260Sstevel@tonic-gate 				}
18270Sstevel@tonic-gate 				/*
18280Sstevel@tonic-gate 				 * continue with same protocol
18290Sstevel@tonic-gate 				 * selection
18300Sstevel@tonic-gate 				 */
18310Sstevel@tonic-gate 				continue;
18320Sstevel@tonic-gate 			}
18330Sstevel@tonic-gate 		} /* end of while */
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 		if (nconf == NULL)
18360Sstevel@tonic-gate 			goto done;
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 		if ((nb = get_the_addr(hostname, prog, vers, nconf, port,
18395302Sth199096 		    tinfo, fhp, get_pubfh, fspath, error)) == NULL)
18400Sstevel@tonic-gate 			goto done;
18410Sstevel@tonic-gate 	} else {
18420Sstevel@tonic-gate retry:
18430Sstevel@tonic-gate 		SET_ERR_RET(error, ERR_NETPATH, 0);
18440Sstevel@tonic-gate 		while (nconf = getnetpath(nc)) {
18450Sstevel@tonic-gate 			SET_ERR_RET(error, ERR_PROTO_NONE, 0);
18465302Sth199096 
18470Sstevel@tonic-gate 			if (nconf->nc_flag & NC_VISIBLE) {
18485302Sth199096 				int	valid_proto;
18490Sstevel@tonic-gate 
18505302Sth199096 				if (check_nconf(nconf,
18515302Sth199096 				    nthtry, &valid_proto)) {
18525302Sth199096 					if (port == 0)
18535302Sth199096 						break;
18545302Sth199096 
18555302Sth199096 					if (valid_proto == TRUE)
18565302Sth199096 						break;
18570Sstevel@tonic-gate 				}
18580Sstevel@tonic-gate 			}
18590Sstevel@tonic-gate 		} /* while */
18600Sstevel@tonic-gate 		if (nconf == NULL) {
18610Sstevel@tonic-gate 			if (++nthtry <= MNT_PREF_LISTLEN) {
18620Sstevel@tonic-gate 				endnetpath(nc);
18630Sstevel@tonic-gate 				if ((nc = setnetpath()) == NULL)
18640Sstevel@tonic-gate 					goto done;
18650Sstevel@tonic-gate 				goto retry;
18660Sstevel@tonic-gate 			} else
18670Sstevel@tonic-gate 				goto done;
18680Sstevel@tonic-gate 		} else {
18690Sstevel@tonic-gate 			if ((nb = get_the_addr(hostname, prog, vers, nconf,
18705302Sth199096 			    port, tinfo, fhp, get_pubfh, fspath, error))
18715302Sth199096 			    == NULL) {
18720Sstevel@tonic-gate 				/* nb is NULL - deal with errors */
18730Sstevel@tonic-gate 				if (error) {
18740Sstevel@tonic-gate 					if (error->error_type == ERR_NOHOST)
18750Sstevel@tonic-gate 						SET_ERR_RET(&errsave_nohost,
18765302Sth199096 						    error->error_type,
18775302Sth199096 						    error->error_value);
18780Sstevel@tonic-gate 					if (error->error_type == ERR_RPCERROR)
18790Sstevel@tonic-gate 						SET_ERR_RET(&errsave_rpcerr,
18805302Sth199096 						    error->error_type,
18815302Sth199096 						    error->error_value);
18820Sstevel@tonic-gate 				}
18830Sstevel@tonic-gate 				/*
18840Sstevel@tonic-gate 				 * Continue the same search path in the
18850Sstevel@tonic-gate 				 * netconfig db until no more matched
18860Sstevel@tonic-gate 				 * nconf (nconf == NULL).
18870Sstevel@tonic-gate 				 */
18880Sstevel@tonic-gate 				goto retry;
18890Sstevel@tonic-gate 			}
18900Sstevel@tonic-gate 		}
18910Sstevel@tonic-gate 	}
18920Sstevel@tonic-gate 	SET_ERR_RET(error, ERR_PROTO_NONE, 0);
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 	/*
18950Sstevel@tonic-gate 	 * Got nconf and nb.  Now dup the netconfig structure (nconf)
18960Sstevel@tonic-gate 	 * and return it thru nconfp.
18970Sstevel@tonic-gate 	 */
18980Sstevel@tonic-gate 	*nconfp = getnetconfigent(nconf->nc_netid);
18990Sstevel@tonic-gate 	if (*nconfp == NULL) {
19000Sstevel@tonic-gate 		syslog(LOG_ERR, "no memory\n");
19010Sstevel@tonic-gate 		free(nb);
19020Sstevel@tonic-gate 		nb = NULL;
19030Sstevel@tonic-gate 	}
19040Sstevel@tonic-gate done:
19050Sstevel@tonic-gate 	if (nc)
19060Sstevel@tonic-gate 		endnetpath(nc);
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	if (nb == NULL) {
190977Soa138391 		/*
191077Soa138391 		 * Check the saved errors. The RPC error has *
191177Soa138391 		 * precedence over the no host error.
191277Soa138391 		 */
191377Soa138391 		if (errsave_nohost.error_type != ERR_PROTO_NONE)
191477Soa138391 			SET_ERR_RET(error, errsave_nohost.error_type,
19155302Sth199096 			    errsave_nohost.error_value);
191677Soa138391 
191777Soa138391 		if (errsave_rpcerr.error_type != ERR_PROTO_NONE)
191877Soa138391 			SET_ERR_RET(error, errsave_rpcerr.error_type,
19195302Sth199096 			    errsave_rpcerr.error_value);
19200Sstevel@tonic-gate 	}
192177Soa138391 
19220Sstevel@tonic-gate 	return (nb);
19230Sstevel@tonic-gate }
19240Sstevel@tonic-gate 
19250Sstevel@tonic-gate /*
19260Sstevel@tonic-gate  * Get a file handle usinging multi-component lookup with the public
19270Sstevel@tonic-gate  * file handle.
19280Sstevel@tonic-gate  */
19290Sstevel@tonic-gate static int
get_fh_via_pub(struct nfs_args * args,char * fshost,char * fspath,bool_t url,bool_t loud,int * versp,struct netconfig ** nconfp,ushort_t port)19300Sstevel@tonic-gate get_fh_via_pub(struct nfs_args *args, char *fshost, char *fspath, bool_t url,
19310Sstevel@tonic-gate 	bool_t loud, int *versp, struct netconfig **nconfp, ushort_t port)
19320Sstevel@tonic-gate {
19330Sstevel@tonic-gate 	uint_t vers_min;
19340Sstevel@tonic-gate 	uint_t vers_max;
19350Sstevel@tonic-gate 	int r;
19360Sstevel@tonic-gate 	char *path;
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 	if (nfsvers != 0) {
19390Sstevel@tonic-gate 		vers_max = vers_min = nfsvers;
19400Sstevel@tonic-gate 	} else {
19410Sstevel@tonic-gate 		vers_max = vers_max_default;
19420Sstevel@tonic-gate 		vers_min = vers_min_default;
19430Sstevel@tonic-gate 	}
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 	if (url == FALSE) {
19460Sstevel@tonic-gate 		path = malloc(strlen(fspath) + 2);
19470Sstevel@tonic-gate 		if (path == NULL) {
19485302Sth199096 			if (loud == TRUE)
19490Sstevel@tonic-gate 				pr_err(gettext("no memory\n"));
19500Sstevel@tonic-gate 			return (RET_ERR);
19510Sstevel@tonic-gate 		}
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 		path[0] = (char)WNL_NATIVEPATH;
19540Sstevel@tonic-gate 		(void) strcpy(&path[1], fspath);
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	} else  {
19570Sstevel@tonic-gate 		path = fspath;
19580Sstevel@tonic-gate 	}
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 	for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min;
19610Sstevel@tonic-gate 	    nfsvers_to_use--) {
19620Sstevel@tonic-gate 		/*
19630Sstevel@tonic-gate 		 * getaddr_nfs will also fill in the fh for us.
19640Sstevel@tonic-gate 		 */
19650Sstevel@tonic-gate 		r = getaddr_nfs(args, fshost, nconfp,
19665302Sth199096 		    TRUE, path, port, NULL, FALSE);
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 		if (r == RET_OK) {
19690Sstevel@tonic-gate 			/*
19700Sstevel@tonic-gate 			 * Since we are using the public fh, and NLM is
19710Sstevel@tonic-gate 			 * not firewall friendly, use local locking.
19720Sstevel@tonic-gate 			 * Not the case for v4.
19730Sstevel@tonic-gate 			 */
19740Sstevel@tonic-gate 			*versp = nfsvers_to_use;
19750Sstevel@tonic-gate 			switch (nfsvers_to_use) {
19760Sstevel@tonic-gate 			case NFS_V4:
19770Sstevel@tonic-gate 				fstype = MNTTYPE_NFS4;
19780Sstevel@tonic-gate 				break;
19790Sstevel@tonic-gate 			case NFS_V3:
19800Sstevel@tonic-gate 				fstype = MNTTYPE_NFS3;
19810Sstevel@tonic-gate 				/* fall through to pick up llock option */
19820Sstevel@tonic-gate 			default:
19830Sstevel@tonic-gate 				args->flags |= NFSMNT_LLOCK;
19840Sstevel@tonic-gate 				break;
19850Sstevel@tonic-gate 			}
19860Sstevel@tonic-gate 			if (fspath != path)
19870Sstevel@tonic-gate 				free(path);
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 			return (r);
19900Sstevel@tonic-gate 		}
19910Sstevel@tonic-gate 	}
19920Sstevel@tonic-gate 
19935302Sth199096 	if (fspath != path)
19940Sstevel@tonic-gate 		free(path);
19950Sstevel@tonic-gate 
19960Sstevel@tonic-gate 	if (loud == TRUE) {
19970Sstevel@tonic-gate 		pr_err(gettext("Could not use public filehandle in request to"
19985302Sth199096 		    " server %s\n"), fshost);
19990Sstevel@tonic-gate 	}
20000Sstevel@tonic-gate 
20010Sstevel@tonic-gate 	return (r);
20020Sstevel@tonic-gate }
20030Sstevel@tonic-gate 
20040Sstevel@tonic-gate /*
20050Sstevel@tonic-gate  * get fhandle of remote path from server's mountd
20060Sstevel@tonic-gate  */
20070Sstevel@tonic-gate static int
get_fh(struct nfs_args * args,char * fshost,char * fspath,int * versp,bool_t loud_on_mnt_err,struct netconfig ** nconfp,ushort_t port)20080Sstevel@tonic-gate get_fh(struct nfs_args *args, char *fshost, char *fspath, int *versp,
20090Sstevel@tonic-gate 	bool_t loud_on_mnt_err, struct netconfig **nconfp, ushort_t port)
20100Sstevel@tonic-gate {
20110Sstevel@tonic-gate 	static struct fhstatus fhs;
20120Sstevel@tonic-gate 	static struct mountres3 mountres3;
20130Sstevel@tonic-gate 	static struct pathcnf p;
20140Sstevel@tonic-gate 	nfs_fh3 *fh3p;
20150Sstevel@tonic-gate 	struct timeval timeout = { 25, 0};
20160Sstevel@tonic-gate 	CLIENT *cl;
20170Sstevel@tonic-gate 	enum clnt_stat rpc_stat;
20180Sstevel@tonic-gate 	rpcvers_t outvers = 0;
20190Sstevel@tonic-gate 	rpcvers_t vers_to_try;
20200Sstevel@tonic-gate 	rpcvers_t vers_min;
20210Sstevel@tonic-gate 	static int printed = 0;
20220Sstevel@tonic-gate 	int count, i, *auths;
20230Sstevel@tonic-gate 	char *msg;
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate 	switch (nfsvers) {
20260Sstevel@tonic-gate 	case 2: /* version 2 specified try that only */
20270Sstevel@tonic-gate 		vers_to_try = MOUNTVERS_POSIX;
20280Sstevel@tonic-gate 		vers_min = MOUNTVERS;
20290Sstevel@tonic-gate 		break;
20300Sstevel@tonic-gate 	case 3: /* version 3 specified try that only */
20310Sstevel@tonic-gate 		vers_to_try = MOUNTVERS3;
20320Sstevel@tonic-gate 		vers_min = MOUNTVERS3;
20330Sstevel@tonic-gate 		break;
20340Sstevel@tonic-gate 	case 4: /* version 4 specified try that only */
20350Sstevel@tonic-gate 		/*
20360Sstevel@tonic-gate 		 * This assignment is in the wrong version sequence.
20370Sstevel@tonic-gate 		 * The above are MOUNT program and this is NFS
20380Sstevel@tonic-gate 		 * program.  However, it happens to work out since the
20390Sstevel@tonic-gate 		 * two don't collide for NFSv4.
20400Sstevel@tonic-gate 		 */
20410Sstevel@tonic-gate 		vers_to_try = NFS_V4;
20420Sstevel@tonic-gate 		vers_min = NFS_V4;
20430Sstevel@tonic-gate 		break;
20440Sstevel@tonic-gate 	default: /* no version specified, start with default */
2045489Soa138391 		/*
2046489Soa138391 		 * If the retry version is set, use that. This will
2047489Soa138391 		 * be set if the last mount attempt returned any other
2048489Soa138391 		 * besides an RPC error.
2049489Soa138391 		 */
2050489Soa138391 		if (nfsretry_vers)
2051489Soa138391 			vers_to_try = nfsretry_vers;
2052489Soa138391 		else {
2053489Soa138391 			vers_to_try = vers_max_default;
2054489Soa138391 			vers_min = vers_min_default;
2055489Soa138391 		}
2056489Soa138391 
20570Sstevel@tonic-gate 		break;
20580Sstevel@tonic-gate 	}
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate 	/*
20610Sstevel@tonic-gate 	 * In the case of version 4, just NULL proc the server since
20620Sstevel@tonic-gate 	 * there is no MOUNT program.  If this fails, then decrease
20630Sstevel@tonic-gate 	 * vers_to_try and continue on with regular MOUNT program
20640Sstevel@tonic-gate 	 * processing.
20650Sstevel@tonic-gate 	 */
20660Sstevel@tonic-gate 	if (vers_to_try == NFS_V4) {
20670Sstevel@tonic-gate 		int savevers = nfsvers_to_use;
20680Sstevel@tonic-gate 		err_ret_t error;
20690Sstevel@tonic-gate 		int retval;
20700Sstevel@tonic-gate 		SET_ERR_RET(&error, ERR_PROTO_NONE, 0);
20710Sstevel@tonic-gate 
20720Sstevel@tonic-gate 		/* Let's hope for the best */
20730Sstevel@tonic-gate 		nfsvers_to_use = NFS_V4;
20745302Sth199096 		retval = getaddr_nfs(args, fshost, nconfp, FALSE,
20755302Sth199096 		    fspath, port, &error, vers_min == NFS_V4);
20760Sstevel@tonic-gate 
20770Sstevel@tonic-gate 		if (retval == RET_OK) {
20780Sstevel@tonic-gate 			*versp = nfsvers_to_use = NFS_V4;
20790Sstevel@tonic-gate 			fstype = MNTTYPE_NFS4;
20800Sstevel@tonic-gate 			args->fh = strdup(fspath);
20810Sstevel@tonic-gate 			if (args->fh == NULL) {
20820Sstevel@tonic-gate 				pr_err(gettext("no memory\n"));
20830Sstevel@tonic-gate 				*versp = nfsvers_to_use = savevers;
20840Sstevel@tonic-gate 				return (RET_ERR);
20850Sstevel@tonic-gate 			}
20860Sstevel@tonic-gate 			return (RET_OK);
20870Sstevel@tonic-gate 		}
20880Sstevel@tonic-gate 		nfsvers_to_use = savevers;
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 		vers_to_try--;
20910Sstevel@tonic-gate 		/* If no more versions to try, let the user know. */
20925302Sth199096 		if (vers_to_try < vers_min)
20930Sstevel@tonic-gate 			return (retval);
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate 		/*
20960Sstevel@tonic-gate 		 * If we are here, there are more versions to try but
20970Sstevel@tonic-gate 		 * there has been an error of some sort.  If it is not
20980Sstevel@tonic-gate 		 * an RPC error (e.g. host unknown), we just stop and
20990Sstevel@tonic-gate 		 * return the error since the other versions would see
21000Sstevel@tonic-gate 		 * the same error as well.
21010Sstevel@tonic-gate 		 */
21020Sstevel@tonic-gate 		if (retval == RET_ERR && error.error_type != ERR_RPCERROR)
21030Sstevel@tonic-gate 			return (retval);
21040Sstevel@tonic-gate 	}
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	while ((cl = clnt_create_vers(fshost, MOUNTPROG, &outvers,
21075302Sth199096 	    vers_min, vers_to_try, "datagram_v")) == NULL) {
21080Sstevel@tonic-gate 		if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST) {
21090Sstevel@tonic-gate 			pr_err(gettext("%s: %s\n"), fshost,
21100Sstevel@tonic-gate 			    clnt_spcreateerror(""));
21110Sstevel@tonic-gate 			return (RET_ERR);
21120Sstevel@tonic-gate 		}
21130Sstevel@tonic-gate 
21140Sstevel@tonic-gate 		/*
21150Sstevel@tonic-gate 		 * We don't want to downgrade version on lost packets
21160Sstevel@tonic-gate 		 */
21170Sstevel@tonic-gate 		if ((rpc_createerr.cf_stat == RPC_TIMEDOUT) ||
21185302Sth199096 		    (rpc_createerr.cf_stat == RPC_PMAPFAILURE)) {
21190Sstevel@tonic-gate 			pr_err(gettext("%s: %s\n"), fshost,
21200Sstevel@tonic-gate 			    clnt_spcreateerror(""));
21210Sstevel@tonic-gate 			return (RET_RETRY);
21220Sstevel@tonic-gate 		}
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 		/*
21250Sstevel@tonic-gate 		 * back off and try the previous version - patch to the
21260Sstevel@tonic-gate 		 * problem of version numbers not being contigous and
21270Sstevel@tonic-gate 		 * clnt_create_vers failing (SunOS4.1 clients & SGI servers)
21280Sstevel@tonic-gate 		 * The problem happens with most non-Sun servers who
21290Sstevel@tonic-gate 		 * don't support mountd protocol #2. So, in case the
21300Sstevel@tonic-gate 		 * call fails, we re-try the call anyway.
21310Sstevel@tonic-gate 		 */
21320Sstevel@tonic-gate 		vers_to_try--;
21330Sstevel@tonic-gate 		if (vers_to_try < vers_min) {
21340Sstevel@tonic-gate 			if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) {
21350Sstevel@tonic-gate 				if (nfsvers == 0) {
21360Sstevel@tonic-gate 					pr_err(gettext(
21370Sstevel@tonic-gate 			"%s:%s: no applicable versions of NFS supported\n"),
21380Sstevel@tonic-gate 					    fshost, fspath);
21390Sstevel@tonic-gate 				} else {
21400Sstevel@tonic-gate 					pr_err(gettext(
21410Sstevel@tonic-gate 			"%s:%s: NFS Version %d not supported\n"),
21420Sstevel@tonic-gate 					    fshost, fspath, nfsvers);
21430Sstevel@tonic-gate 				}
21440Sstevel@tonic-gate 				return (RET_ERR);
21450Sstevel@tonic-gate 			}
21460Sstevel@tonic-gate 			if (!printed) {
21470Sstevel@tonic-gate 				pr_err(gettext("%s: %s\n"), fshost,
21480Sstevel@tonic-gate 				    clnt_spcreateerror(""));
21490Sstevel@tonic-gate 				printed = 1;
21500Sstevel@tonic-gate 			}
21510Sstevel@tonic-gate 			return (RET_RETRY);
21520Sstevel@tonic-gate 		}
21530Sstevel@tonic-gate 	}
21540Sstevel@tonic-gate 	if (posix && outvers < MOUNTVERS_POSIX) {
21550Sstevel@tonic-gate 		pr_err(gettext("%s: %s: no pathconf info\n"),
21560Sstevel@tonic-gate 		    fshost, clnt_sperror(cl, ""));
21570Sstevel@tonic-gate 		clnt_destroy(cl);
21580Sstevel@tonic-gate 		return (RET_ERR);
21590Sstevel@tonic-gate 	}
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 	if (__clnt_bindresvport(cl) < 0) {
21620Sstevel@tonic-gate 		pr_err(gettext("Couldn't bind to reserved port\n"));
21630Sstevel@tonic-gate 		clnt_destroy(cl);
21640Sstevel@tonic-gate 		return (RET_RETRY);
21650Sstevel@tonic-gate 	}
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	if ((cl->cl_auth = authsys_create_default()) == NULL) {
21680Sstevel@tonic-gate 		pr_err(
21690Sstevel@tonic-gate 		    gettext("Couldn't create default authentication handle\n"));
21700Sstevel@tonic-gate 		clnt_destroy(cl);
21710Sstevel@tonic-gate 		return (RET_RETRY);
21720Sstevel@tonic-gate 	}
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	switch (outvers) {
21750Sstevel@tonic-gate 	case MOUNTVERS:
21760Sstevel@tonic-gate 	case MOUNTVERS_POSIX:
21770Sstevel@tonic-gate 		*versp = nfsvers_to_use = NFS_VERSION;
21780Sstevel@tonic-gate 		rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
21795302Sth199096 		    (caddr_t)&fspath, xdr_fhstatus, (caddr_t)&fhs, timeout);
21800Sstevel@tonic-gate 		if (rpc_stat != RPC_SUCCESS) {
21810Sstevel@tonic-gate 			pr_err(gettext("%s:%s: server not responding %s\n"),
21820Sstevel@tonic-gate 			    fshost, fspath, clnt_sperror(cl, ""));
21830Sstevel@tonic-gate 			clnt_destroy(cl);
21840Sstevel@tonic-gate 			return (RET_RETRY);
21850Sstevel@tonic-gate 		}
21860Sstevel@tonic-gate 
21870Sstevel@tonic-gate 		if ((errno = fhs.fhs_status) != MNT_OK) {
21880Sstevel@tonic-gate 			if (loud_on_mnt_err) {
21895302Sth199096 				if (errno == EACCES) {
21905302Sth199096 					pr_err(gettext(
21915302Sth199096 					    "%s:%s: access denied\n"),
21925302Sth199096 					    fshost, fspath);
21935302Sth199096 				} else {
21945302Sth199096 					pr_err(gettext("%s:%s: %s\n"), fshost,
21955706Sgt29601 					    fspath, errno >= 0 ?
21965706Sgt29601 					    strerror(errno) : "invalid error "
21975706Sgt29601 					    "returned by server");
21985302Sth199096 				}
21990Sstevel@tonic-gate 			}
22000Sstevel@tonic-gate 			clnt_destroy(cl);
22010Sstevel@tonic-gate 			return (RET_MNTERR);
22020Sstevel@tonic-gate 		}
22030Sstevel@tonic-gate 		args->fh = malloc(sizeof (fhs.fhstatus_u.fhs_fhandle));
22040Sstevel@tonic-gate 		if (args->fh == NULL) {
22050Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
22060Sstevel@tonic-gate 			return (RET_ERR);
22070Sstevel@tonic-gate 		}
22080Sstevel@tonic-gate 		memcpy((caddr_t)args->fh, (caddr_t)&fhs.fhstatus_u.fhs_fhandle,
22095302Sth199096 		    sizeof (fhs.fhstatus_u.fhs_fhandle));
22100Sstevel@tonic-gate 		if (!errno && posix) {
22110Sstevel@tonic-gate 			rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF,
22125302Sth199096 			    xdr_dirpath, (caddr_t)&fspath, xdr_ppathcnf,
22135302Sth199096 			    (caddr_t)&p, timeout);
22140Sstevel@tonic-gate 			if (rpc_stat != RPC_SUCCESS) {
22150Sstevel@tonic-gate 				pr_err(gettext(
22160Sstevel@tonic-gate 				    "%s:%s: server not responding %s\n"),
22170Sstevel@tonic-gate 				    fshost, fspath, clnt_sperror(cl, ""));
22180Sstevel@tonic-gate 				free(args->fh);
22190Sstevel@tonic-gate 				clnt_destroy(cl);
22200Sstevel@tonic-gate 				return (RET_RETRY);
22210Sstevel@tonic-gate 			}
22220Sstevel@tonic-gate 			if (_PC_ISSET(_PC_ERROR, p.pc_mask)) {
22230Sstevel@tonic-gate 				pr_err(gettext(
22240Sstevel@tonic-gate 				    "%s:%s: no pathconf info\n"),
22250Sstevel@tonic-gate 				    fshost, fspath);
22260Sstevel@tonic-gate 				free(args->fh);
22270Sstevel@tonic-gate 				clnt_destroy(cl);
22280Sstevel@tonic-gate 				return (RET_ERR);
22290Sstevel@tonic-gate 			}
22300Sstevel@tonic-gate 			args->flags |= NFSMNT_POSIX;
22310Sstevel@tonic-gate 			args->pathconf = malloc(sizeof (p));
22320Sstevel@tonic-gate 			if (args->pathconf == NULL) {
22330Sstevel@tonic-gate 				pr_err(gettext("no memory\n"));
22340Sstevel@tonic-gate 				free(args->fh);
22350Sstevel@tonic-gate 				clnt_destroy(cl);
22360Sstevel@tonic-gate 				return (RET_ERR);
22370Sstevel@tonic-gate 			}
22380Sstevel@tonic-gate 			memcpy((caddr_t)args->pathconf, (caddr_t)&p,
22395302Sth199096 			    sizeof (p));
22400Sstevel@tonic-gate 		}
22410Sstevel@tonic-gate 		break;
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate 	case MOUNTVERS3:
22440Sstevel@tonic-gate 		*versp = nfsvers_to_use = NFS_V3;
22450Sstevel@tonic-gate 		rpc_stat = clnt_call(cl, MOUNTPROC_MNT, xdr_dirpath,
22465302Sth199096 		    (caddr_t)&fspath, xdr_mountres3, (caddr_t)&mountres3,
22475302Sth199096 		    timeout);
22480Sstevel@tonic-gate 		if (rpc_stat != RPC_SUCCESS) {
22490Sstevel@tonic-gate 			pr_err(gettext("%s:%s: server not responding %s\n"),
22500Sstevel@tonic-gate 			    fshost, fspath, clnt_sperror(cl, ""));
22510Sstevel@tonic-gate 			clnt_destroy(cl);
22520Sstevel@tonic-gate 			return (RET_RETRY);
22530Sstevel@tonic-gate 		}
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate 		/*
22560Sstevel@tonic-gate 		 * Assume here that most of the MNT3ERR_*
22570Sstevel@tonic-gate 		 * codes map into E* errors.
22580Sstevel@tonic-gate 		 */
22590Sstevel@tonic-gate 		if ((errno = mountres3.fhs_status) != MNT_OK) {
22605302Sth199096 			if (loud_on_mnt_err) {
22615302Sth199096 				switch (errno) {
22625302Sth199096 				case MNT3ERR_NAMETOOLONG:
22635302Sth199096 					msg = "path name is too long";
22645302Sth199096 					break;
22655302Sth199096 				case MNT3ERR_NOTSUPP:
22665302Sth199096 					msg = "operation not supported";
22675302Sth199096 					break;
22685302Sth199096 				case MNT3ERR_SERVERFAULT:
22695302Sth199096 					msg = "server fault";
22705302Sth199096 					break;
22715302Sth199096 				default:
22725706Sgt29601 					if (errno >= 0)
22735706Sgt29601 						msg = strerror(errno);
22745706Sgt29601 					else
22755706Sgt29601 						msg = "invalid error returned "
22765706Sgt29601 						    "by server";
22775302Sth199096 					break;
22785302Sth199096 				}
22795302Sth199096 				pr_err(gettext("%s:%s: %s\n"), fshost,
22805302Sth199096 				    fspath, msg);
22810Sstevel@tonic-gate 			}
22825302Sth199096 			clnt_destroy(cl);
22835302Sth199096 			return (RET_MNTERR);
22840Sstevel@tonic-gate 		}
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate 		fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
22870Sstevel@tonic-gate 		if (fh3p == NULL) {
22880Sstevel@tonic-gate 			pr_err(gettext("no memory\n"));
22890Sstevel@tonic-gate 			return (RET_ERR);
22900Sstevel@tonic-gate 		}
22910Sstevel@tonic-gate 		fh3p->fh3_length =
22925302Sth199096 		    mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
22930Sstevel@tonic-gate 		(void) memcpy(fh3p->fh3_u.data,
22945302Sth199096 		    mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
22955302Sth199096 		    fh3p->fh3_length);
22960Sstevel@tonic-gate 		args->fh = (caddr_t)fh3p;
22970Sstevel@tonic-gate 		fstype = MNTTYPE_NFS3;
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate 		/*
23000Sstevel@tonic-gate 		 * Check the security flavor to be used.
23010Sstevel@tonic-gate 		 *
23020Sstevel@tonic-gate 		 * If "secure" or "sec=flavor" is a mount
23030Sstevel@tonic-gate 		 * option, check if the server supports the "flavor".
23040Sstevel@tonic-gate 		 * If the server does not support the flavor, return
23050Sstevel@tonic-gate 		 * error.
23060Sstevel@tonic-gate 		 *
230710186SVallish.Vaidyeshwara@Sun.COM 		 * If no mount option is given then look for default auth
230810186SVallish.Vaidyeshwara@Sun.COM 		 * (default auth entry in /etc/nfssec.conf) in the auth list
230910186SVallish.Vaidyeshwara@Sun.COM 		 * returned from server. If default auth not found, then use
231010186SVallish.Vaidyeshwara@Sun.COM 		 * the first supported security flavor (by the client) in the
231110186SVallish.Vaidyeshwara@Sun.COM 		 * auth list returned from the server.
23120Sstevel@tonic-gate 		 *
23130Sstevel@tonic-gate 		 */
23140Sstevel@tonic-gate 		auths =
23155302Sth199096 		    mountres3.mountres3_u.mountinfo.auth_flavors
23165302Sth199096 		    .auth_flavors_val;
23170Sstevel@tonic-gate 		count =
23185302Sth199096 		    mountres3.mountres3_u.mountinfo.auth_flavors
23195302Sth199096 		    .auth_flavors_len;
23200Sstevel@tonic-gate 
232110186SVallish.Vaidyeshwara@Sun.COM 		if (count <= 0) {
232210186SVallish.Vaidyeshwara@Sun.COM 			pr_err(gettext(
232310186SVallish.Vaidyeshwara@Sun.COM 			    "server %s did not return any security mode\n"),
232410186SVallish.Vaidyeshwara@Sun.COM 			    fshost);
232510186SVallish.Vaidyeshwara@Sun.COM 			clnt_destroy(cl);
232610186SVallish.Vaidyeshwara@Sun.COM 			return (RET_ERR);
232710186SVallish.Vaidyeshwara@Sun.COM 		}
232810186SVallish.Vaidyeshwara@Sun.COM 
23290Sstevel@tonic-gate 		if (sec_opt) {
23300Sstevel@tonic-gate 			for (i = 0; i < count; i++) {
23310Sstevel@tonic-gate 				if (auths[i] == nfs_sec.sc_nfsnum)
23325302Sth199096 					break;
23330Sstevel@tonic-gate 			}
233410186SVallish.Vaidyeshwara@Sun.COM 			if (i == count)
23350Sstevel@tonic-gate 				goto autherr;
23360Sstevel@tonic-gate 		} else {
233710186SVallish.Vaidyeshwara@Sun.COM 			seconfig_t default_sec;
233810186SVallish.Vaidyeshwara@Sun.COM 
233910186SVallish.Vaidyeshwara@Sun.COM 			/*
234010186SVallish.Vaidyeshwara@Sun.COM 			 * Get client configured default auth.
234110186SVallish.Vaidyeshwara@Sun.COM 			 */
234210186SVallish.Vaidyeshwara@Sun.COM 			nfs_sec.sc_nfsnum = -1;
234310186SVallish.Vaidyeshwara@Sun.COM 			default_sec.sc_nfsnum = -1;
234410186SVallish.Vaidyeshwara@Sun.COM 			(void) nfs_getseconfig_default(&default_sec);
23455302Sth199096 
234610186SVallish.Vaidyeshwara@Sun.COM 			/*
234710186SVallish.Vaidyeshwara@Sun.COM 			 * Look for clients default auth in servers list.
234810186SVallish.Vaidyeshwara@Sun.COM 			 */
234910186SVallish.Vaidyeshwara@Sun.COM 			if (default_sec.sc_nfsnum != -1) {
235010186SVallish.Vaidyeshwara@Sun.COM 				for (i = 0; i < count; i++) {
235110186SVallish.Vaidyeshwara@Sun.COM 					if (auths[i] == default_sec.sc_nfsnum) {
235210186SVallish.Vaidyeshwara@Sun.COM 						sec_opt++;
235310186SVallish.Vaidyeshwara@Sun.COM 						nfs_sec = default_sec;
235410186SVallish.Vaidyeshwara@Sun.COM 						break;
235510186SVallish.Vaidyeshwara@Sun.COM 					}
23565302Sth199096 				}
23570Sstevel@tonic-gate 			}
23585302Sth199096 
235910186SVallish.Vaidyeshwara@Sun.COM 			/*
236010186SVallish.Vaidyeshwara@Sun.COM 			 * Could not find clients default auth in servers list.
236110186SVallish.Vaidyeshwara@Sun.COM 			 * Pick the first auth from servers list that is
236210186SVallish.Vaidyeshwara@Sun.COM 			 * also supported on the client.
236310186SVallish.Vaidyeshwara@Sun.COM 			 */
236410186SVallish.Vaidyeshwara@Sun.COM 			if (nfs_sec.sc_nfsnum == -1) {
236510186SVallish.Vaidyeshwara@Sun.COM 				for (i = 0; i < count; i++) {
236610186SVallish.Vaidyeshwara@Sun.COM 					if (!nfs_getseconfig_bynumber(auths[i],
236710186SVallish.Vaidyeshwara@Sun.COM 					    &nfs_sec)) {
236810186SVallish.Vaidyeshwara@Sun.COM 						sec_opt++;
236910186SVallish.Vaidyeshwara@Sun.COM 						break;
237010186SVallish.Vaidyeshwara@Sun.COM 
237110186SVallish.Vaidyeshwara@Sun.COM 					}
237210186SVallish.Vaidyeshwara@Sun.COM 				}
237310186SVallish.Vaidyeshwara@Sun.COM 			}
237410186SVallish.Vaidyeshwara@Sun.COM 
237510186SVallish.Vaidyeshwara@Sun.COM 			if (i == count)
23765302Sth199096 				goto autherr;
23770Sstevel@tonic-gate 		}
23780Sstevel@tonic-gate 		break;
23790Sstevel@tonic-gate 	default:
23800Sstevel@tonic-gate 		pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
23810Sstevel@tonic-gate 		    fshost, fspath, outvers);
23820Sstevel@tonic-gate 		clnt_destroy(cl);
23830Sstevel@tonic-gate 		return (RET_ERR);
23840Sstevel@tonic-gate 	}
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 	clnt_destroy(cl);
23870Sstevel@tonic-gate 	return (RET_OK);
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate autherr:
23900Sstevel@tonic-gate 	pr_err(gettext(
23915302Sth199096 	    "security mode does not match the server exporting %s:%s\n"),
23925302Sth199096 	    fshost, fspath);
23930Sstevel@tonic-gate 	clnt_destroy(cl);
23940Sstevel@tonic-gate 	return (RET_ERR);
23950Sstevel@tonic-gate }
23960Sstevel@tonic-gate 
23970Sstevel@tonic-gate /*
23980Sstevel@tonic-gate  * Fill in the address for the server's NFS service and
23990Sstevel@tonic-gate  * fill in a knetconfig structure for the transport that
24000Sstevel@tonic-gate  * the service is available on.
24010Sstevel@tonic-gate  */
24020Sstevel@tonic-gate static int
getaddr_nfs(struct nfs_args * args,char * fshost,struct netconfig ** nconfp,bool_t get_pubfh,char * fspath,ushort_t port,err_ret_t * error,bool_t print_rpcerror)24030Sstevel@tonic-gate getaddr_nfs(struct nfs_args *args, char *fshost, struct netconfig **nconfp,
24040Sstevel@tonic-gate 	    bool_t get_pubfh, char *fspath, ushort_t port, err_ret_t *error,
24050Sstevel@tonic-gate 	    bool_t print_rpcerror)
24060Sstevel@tonic-gate {
24070Sstevel@tonic-gate 	struct stat sb;
24080Sstevel@tonic-gate 	struct netconfig *nconf;
24090Sstevel@tonic-gate 	struct knetconfig *knconfp;
24100Sstevel@tonic-gate 	static int printed = 0;
24110Sstevel@tonic-gate 	struct t_info tinfo;
24120Sstevel@tonic-gate 	err_ret_t addr_error;
24130Sstevel@tonic-gate 
24140Sstevel@tonic-gate 	SET_ERR_RET(error, ERR_PROTO_NONE, 0);
24150Sstevel@tonic-gate 	SET_ERR_RET(&addr_error, ERR_PROTO_NONE, 0);
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate 	if (nfs_proto) {
24180Sstevel@tonic-gate 		/*
24190Sstevel@tonic-gate 		 * If a proto is specified and its rdma try this. The kernel
24200Sstevel@tonic-gate 		 * will later do the reachablity test and fail form there
24210Sstevel@tonic-gate 		 * if rdma transport is not available to kernel rpc
24220Sstevel@tonic-gate 		 */
24230Sstevel@tonic-gate 		if (strcmp(nfs_proto, "rdma") == 0) {
24240Sstevel@tonic-gate 			args->addr = get_addr(fshost, NFS_PROGRAM,
24250Sstevel@tonic-gate 			    nfsvers_to_use, nconfp, NULL, port, &tinfo,
24260Sstevel@tonic-gate 			    &args->fh, get_pubfh, fspath, &addr_error);
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 			args->flags |= NFSMNT_DORDMA;
24290Sstevel@tonic-gate 		} else {
24300Sstevel@tonic-gate 			args->addr = get_addr(fshost, NFS_PROGRAM,
24310Sstevel@tonic-gate 			    nfsvers_to_use, nconfp, nfs_proto, port, &tinfo,
24320Sstevel@tonic-gate 			    &args->fh, get_pubfh, fspath, &addr_error);
24330Sstevel@tonic-gate 		}
24340Sstevel@tonic-gate 	} else {
24350Sstevel@tonic-gate 		args->addr = get_addr(fshost, NFS_PROGRAM, nfsvers_to_use,
24360Sstevel@tonic-gate 		    nconfp, nfs_proto, port, &tinfo, &args->fh, get_pubfh,
24370Sstevel@tonic-gate 		    fspath, &addr_error);
24380Sstevel@tonic-gate 		/*
24390Sstevel@tonic-gate 		 * If no proto is specified set this flag.
24400Sstevel@tonic-gate 		 * Kernel mount code will try to use RDMA if its on the
24410Sstevel@tonic-gate 		 * system, otherwise it will keep on using the protocol
24420Sstevel@tonic-gate 		 * selected here, through the above get_addr call.
24430Sstevel@tonic-gate 		 */
24440Sstevel@tonic-gate 		if (nfs_proto == NULL)
24450Sstevel@tonic-gate 			args->flags |= NFSMNT_TRYRDMA;
24460Sstevel@tonic-gate 	}
24470Sstevel@tonic-gate 
24480Sstevel@tonic-gate 	if (args->addr == NULL) {
24490Sstevel@tonic-gate 		/*
24500Sstevel@tonic-gate 		 * We could have failed because the server had no public
24510Sstevel@tonic-gate 		 * file handle support. So don't print a message and don't
24520Sstevel@tonic-gate 		 * retry.
24530Sstevel@tonic-gate 		 */
24540Sstevel@tonic-gate 		if (get_pubfh == TRUE)
24550Sstevel@tonic-gate 			return (RET_ERR);
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 		if (!printed) {
24580Sstevel@tonic-gate 			switch (addr_error.error_type) {
24590Sstevel@tonic-gate 			case 0:
2460489Soa138391 				printed = 1;
24610Sstevel@tonic-gate 				break;
24620Sstevel@tonic-gate 			case ERR_RPCERROR:
24630Sstevel@tonic-gate 				if (!print_rpcerror)
24640Sstevel@tonic-gate 					/* no error print at this time */
24650Sstevel@tonic-gate 					break;
24660Sstevel@tonic-gate 				pr_err(gettext("%s NFS service not"
24675302Sth199096 				    " available %s\n"), fshost,
24680Sstevel@tonic-gate 				    clnt_sperrno(addr_error.error_value));
2469489Soa138391 				printed = 1;
24700Sstevel@tonic-gate 				break;
24710Sstevel@tonic-gate 			case ERR_NETPATH:
24720Sstevel@tonic-gate 				pr_err(gettext("%s: Error in NETPATH.\n"),
24735302Sth199096 				    fshost);
2474489Soa138391 				printed = 1;
24750Sstevel@tonic-gate 				break;
24760Sstevel@tonic-gate 			case ERR_PROTO_INVALID:
24770Sstevel@tonic-gate 				pr_err(gettext("%s: NFS service does not"
24785302Sth199096 				    " recognize protocol: %s.\n"), fshost,
24795302Sth199096 				    nfs_proto);
2480489Soa138391 				printed = 1;
24810Sstevel@tonic-gate 				break;
24820Sstevel@tonic-gate 			case ERR_PROTO_UNSUPP:
2483489Soa138391 				if (nfsvers || nfsvers_to_use == NFS_VERSMIN) {
2484112Soa138391 					/*
2485489Soa138391 					 * Don't set "printed" here. Since we
2486489Soa138391 					 * have to keep checking here till we
2487489Soa138391 					 * exhaust transport errors on all vers.
2488489Soa138391 					 *
2489489Soa138391 					 * Print this message if:
2490489Soa138391 					 * 1. After we have tried all versions
2491489Soa138391 					 *    of NFS and none support the asked
2492489Soa138391 					 *    transport.
2493489Soa138391 					 *
2494489Soa138391 					 * 2. If a version is specified and it
2495489Soa138391 					 *    does'nt support the asked
2496489Soa138391 					 *    transport.
2497489Soa138391 					 *
2498489Soa138391 					 * Otherwise we decrement the version
2499112Soa138391 					 * and retry below.
2500112Soa138391 					 */
2501112Soa138391 					pr_err(gettext("%s: NFS service does"
25025302Sth199096 					    " not support protocol: %s.\n"),
25035302Sth199096 					    fshost, nfs_proto);
2504112Soa138391 				}
25050Sstevel@tonic-gate 				break;
25060Sstevel@tonic-gate 			case ERR_NOHOST:
250777Soa138391 				pr_err("%s: %s\n", fshost, "Unknown host");
2508489Soa138391 				printed = 1;
25090Sstevel@tonic-gate 				break;
25100Sstevel@tonic-gate 			default:
25110Sstevel@tonic-gate 				/* case ERR_PROTO_NONE falls through */
25120Sstevel@tonic-gate 				pr_err(gettext("%s: NFS service not responding"
25135302Sth199096 				    "\n"), fshost);
2514489Soa138391 				printed = 1;
25150Sstevel@tonic-gate 				break;
25160Sstevel@tonic-gate 			}
25170Sstevel@tonic-gate 		}
25180Sstevel@tonic-gate 		SET_ERR_RET(error,
25195302Sth199096 		    addr_error.error_type, addr_error.error_value);
25200Sstevel@tonic-gate 		if (addr_error.error_type == ERR_PROTO_NONE)
25210Sstevel@tonic-gate 			return (RET_RETRY);
25220Sstevel@tonic-gate 		else if (addr_error.error_type == ERR_RPCERROR &&
25235302Sth199096 		    !IS_UNRECOVERABLE_RPC(addr_error.error_value)) {
25240Sstevel@tonic-gate 			return (RET_RETRY);
2525112Soa138391 		} else if (nfsvers == 0 && addr_error.error_type ==
25265302Sth199096 		    ERR_PROTO_UNSUPP && nfsvers_to_use != NFS_VERSMIN) {
2527112Soa138391 			/*
2528112Soa138391 			 * If no version is specified, and the error is due
2529489Soa138391 			 * to an unsupported transport, then decrement the
2530112Soa138391 			 * version and retry.
2531112Soa138391 			 */
2532112Soa138391 			return (RET_RETRY);
2533112Soa138391 		} else
25340Sstevel@tonic-gate 			return (RET_ERR);
25350Sstevel@tonic-gate 	}
25360Sstevel@tonic-gate 	nconf = *nconfp;
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate 	if (stat(nconf->nc_device, &sb) < 0) {
25390Sstevel@tonic-gate 		pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"),
25400Sstevel@tonic-gate 		    nconf->nc_device, strerror(errno));
25410Sstevel@tonic-gate 		return (RET_ERR);
25420Sstevel@tonic-gate 	}
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 	knconfp = (struct knetconfig *)malloc(sizeof (*knconfp));
25450Sstevel@tonic-gate 	if (!knconfp) {
25460Sstevel@tonic-gate 		pr_err(gettext("no memory\n"));
25470Sstevel@tonic-gate 		return (RET_ERR);
25480Sstevel@tonic-gate 	}
25490Sstevel@tonic-gate 	knconfp->knc_semantics = nconf->nc_semantics;
25500Sstevel@tonic-gate 	knconfp->knc_protofmly = nconf->nc_protofmly;
25510Sstevel@tonic-gate 	knconfp->knc_proto = nconf->nc_proto;
25520Sstevel@tonic-gate 	knconfp->knc_rdev = sb.st_rdev;
25530Sstevel@tonic-gate 
25540Sstevel@tonic-gate 	/* make sure we don't overload the transport */
25550Sstevel@tonic-gate 	if (tinfo.tsdu > 0 && tinfo.tsdu < NFS_MAXDATA + NFS_RPC_HDR) {
25560Sstevel@tonic-gate 		args->flags |= (NFSMNT_RSIZE | NFSMNT_WSIZE);
25570Sstevel@tonic-gate 		if (args->rsize == 0 || args->rsize > tinfo.tsdu - NFS_RPC_HDR)
25580Sstevel@tonic-gate 			args->rsize = tinfo.tsdu - NFS_RPC_HDR;
25590Sstevel@tonic-gate 		if (args->wsize == 0 || args->wsize > tinfo.tsdu - NFS_RPC_HDR)
25600Sstevel@tonic-gate 			args->wsize = tinfo.tsdu - NFS_RPC_HDR;
25610Sstevel@tonic-gate 	}
25620Sstevel@tonic-gate 
25630Sstevel@tonic-gate 	args->flags |= NFSMNT_KNCONF;
25640Sstevel@tonic-gate 	args->knconf = knconfp;
25650Sstevel@tonic-gate 	return (RET_OK);
25660Sstevel@tonic-gate }
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate static int
retry(struct mnttab * mntp,int ro)25690Sstevel@tonic-gate retry(struct mnttab *mntp, int ro)
25700Sstevel@tonic-gate {
25710Sstevel@tonic-gate 	int delay = 5;
25720Sstevel@tonic-gate 	int count = retries;
25730Sstevel@tonic-gate 	int r;
25740Sstevel@tonic-gate 
2575489Soa138391 	/*
2576489Soa138391 	 * Please see comments on nfsretry_vers in the beginning of this file
2577489Soa138391 	 * and in main() routine.
2578489Soa138391 	 */
2579489Soa138391 
25800Sstevel@tonic-gate 	if (bg) {
25810Sstevel@tonic-gate 		if (fork() > 0)
25820Sstevel@tonic-gate 			return (RET_OK);
25835706Sgt29601 		backgrounded = 1;
25840Sstevel@tonic-gate 		pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp);
2585489Soa138391 	} else {
2586489Soa138391 		if (!nfsretry_vers)
2587489Soa138391 			pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp);
2588489Soa138391 	}
25890Sstevel@tonic-gate 
25900Sstevel@tonic-gate 	while (count--) {
2591489Soa138391 		if ((r = mount_nfs(mntp, ro, NULL)) == RET_OK) {
25920Sstevel@tonic-gate 			pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp);
25930Sstevel@tonic-gate 			return (RET_OK);
25940Sstevel@tonic-gate 		}
25950Sstevel@tonic-gate 		if (r != RET_RETRY)
25960Sstevel@tonic-gate 			break;
25970Sstevel@tonic-gate 
25980Sstevel@tonic-gate 		if (count > 0) {
25995302Sth199096 			(void) sleep(delay);
26005302Sth199096 			delay *= 2;
26015302Sth199096 			if (delay > 120)
26025302Sth199096 				delay = 120;
26030Sstevel@tonic-gate 		}
26040Sstevel@tonic-gate 	}
2605489Soa138391 
2606489Soa138391 	if (!nfsretry_vers)
2607489Soa138391 		pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp);
2608489Soa138391 
26090Sstevel@tonic-gate 	return (RET_ERR);
26100Sstevel@tonic-gate }
26110Sstevel@tonic-gate 
26120Sstevel@tonic-gate /*
2613*13080SPavan.Mettu@Oracle.COM  * Read the NFS SMF Parameters  to determine if the
26140Sstevel@tonic-gate  * client has been configured for a new min/max for the NFS version to
26150Sstevel@tonic-gate  * use.
26160Sstevel@tonic-gate  */
26170Sstevel@tonic-gate static void
read_default(void)26180Sstevel@tonic-gate read_default(void)
26190Sstevel@tonic-gate {
2620*13080SPavan.Mettu@Oracle.COM 	char value[4];
26210Sstevel@tonic-gate 	int errno;
2622*13080SPavan.Mettu@Oracle.COM 	int tmp = 0, bufsz = 0, ret = 0;
26230Sstevel@tonic-gate 
2624*13080SPavan.Mettu@Oracle.COM 	/* Maximum number of bytes expected. */
2625*13080SPavan.Mettu@Oracle.COM 	bufsz = 4;
2626*13080SPavan.Mettu@Oracle.COM 	ret = nfs_smf_get_prop("client_versmin", value, DEFAULT_INSTANCE,
2627*13080SPavan.Mettu@Oracle.COM 	    SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
2628*13080SPavan.Mettu@Oracle.COM 	if (ret == SA_OK) {
2629*13080SPavan.Mettu@Oracle.COM 		errno = 0;
2630*13080SPavan.Mettu@Oracle.COM 		tmp = strtol(value, (char **)NULL, 10);
2631*13080SPavan.Mettu@Oracle.COM 		if (errno == 0) {
2632*13080SPavan.Mettu@Oracle.COM 			vers_min_default = tmp;
26330Sstevel@tonic-gate 		}
2634*13080SPavan.Mettu@Oracle.COM 	}
2635*13080SPavan.Mettu@Oracle.COM 
2636*13080SPavan.Mettu@Oracle.COM 	/* Maximum number of bytes expected. */
2637*13080SPavan.Mettu@Oracle.COM 	bufsz = 4;
2638*13080SPavan.Mettu@Oracle.COM 	ret = nfs_smf_get_prop("client_versmax", value, DEFAULT_INSTANCE,
2639*13080SPavan.Mettu@Oracle.COM 	    SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
2640*13080SPavan.Mettu@Oracle.COM 	if (ret == SA_OK) {
2641*13080SPavan.Mettu@Oracle.COM 		errno = 0;
2642*13080SPavan.Mettu@Oracle.COM 		tmp = strtol(value, (char **)NULL, 10);
2643*13080SPavan.Mettu@Oracle.COM 		if (errno == 0) {
2644*13080SPavan.Mettu@Oracle.COM 			vers_max_default = tmp;
26450Sstevel@tonic-gate 		}
26460Sstevel@tonic-gate 	}
26470Sstevel@tonic-gate }
26480Sstevel@tonic-gate 
26490Sstevel@tonic-gate static void
sigusr1(int s)26500Sstevel@tonic-gate sigusr1(int s)
26510Sstevel@tonic-gate {
26520Sstevel@tonic-gate }
2653