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