1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <stdio.h> 30*0Sstevel@tonic-gate #include <unistd.h> 31*0Sstevel@tonic-gate #include <stdlib.h> 32*0Sstevel@tonic-gate #include <ctype.h> 33*0Sstevel@tonic-gate #include <syslog.h> 34*0Sstevel@tonic-gate #include <string.h> 35*0Sstevel@tonic-gate #include <deflt.h> 36*0Sstevel@tonic-gate #include <kstat.h> 37*0Sstevel@tonic-gate #include <sys/param.h> 38*0Sstevel@tonic-gate #include <sys/types.h> 39*0Sstevel@tonic-gate #include <sys/time.h> 40*0Sstevel@tonic-gate #include <sys/stat.h> 41*0Sstevel@tonic-gate #include <sys/wait.h> 42*0Sstevel@tonic-gate #include <sys/socket.h> 43*0Sstevel@tonic-gate #include <netinet/in.h> 44*0Sstevel@tonic-gate #include <signal.h> 45*0Sstevel@tonic-gate #include <sys/signal.h> 46*0Sstevel@tonic-gate #include <rpc/rpc.h> 47*0Sstevel@tonic-gate #include <rpc/pmap_clnt.h> 48*0Sstevel@tonic-gate #include <sys/mount.h> 49*0Sstevel@tonic-gate #include <sys/mntent.h> 50*0Sstevel@tonic-gate #include <sys/mnttab.h> 51*0Sstevel@tonic-gate #include <sys/fstyp.h> 52*0Sstevel@tonic-gate #include <sys/fsid.h> 53*0Sstevel@tonic-gate #include <arpa/inet.h> 54*0Sstevel@tonic-gate #include <netdb.h> 55*0Sstevel@tonic-gate #include <netconfig.h> 56*0Sstevel@tonic-gate #include <netdir.h> 57*0Sstevel@tonic-gate #include <errno.h> 58*0Sstevel@tonic-gate #define NFSCLIENT 59*0Sstevel@tonic-gate #include <nfs/nfs.h> 60*0Sstevel@tonic-gate #include <nfs/mount.h> 61*0Sstevel@tonic-gate #include <rpcsvc/mount.h> 62*0Sstevel@tonic-gate #include <rpc/nettype.h> 63*0Sstevel@tonic-gate #include <locale.h> 64*0Sstevel@tonic-gate #include <setjmp.h> 65*0Sstevel@tonic-gate #include <sys/socket.h> 66*0Sstevel@tonic-gate #include <thread.h> 67*0Sstevel@tonic-gate #include <limits.h> 68*0Sstevel@tonic-gate #include <nss_dbdefs.h> /* for NSS_BUFLEN_HOSTS */ 69*0Sstevel@tonic-gate #include <nfs/nfs_sec.h> 70*0Sstevel@tonic-gate #include <sys/sockio.h> 71*0Sstevel@tonic-gate #include <net/if.h> 72*0Sstevel@tonic-gate #include <assert.h> 73*0Sstevel@tonic-gate #include <nfs/nfs_clnt.h> 74*0Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h> 75*0Sstevel@tonic-gate #define NO_RDDIR_CACHE 76*0Sstevel@tonic-gate #include "automount.h" 77*0Sstevel@tonic-gate #include "replica.h" 78*0Sstevel@tonic-gate #include "nfs_subr.h" 79*0Sstevel@tonic-gate #include "webnfs.h" 80*0Sstevel@tonic-gate #include <sys/sockio.h> 81*0Sstevel@tonic-gate #include <net/if.h> 82*0Sstevel@tonic-gate #include <assert.h> 83*0Sstevel@tonic-gate #include <rpcsvc/daemon_utils.h> 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate extern char *nfs_get_qop_name(); 86*0Sstevel@tonic-gate extern AUTH *nfs_create_ah(); 87*0Sstevel@tonic-gate extern enum snego_stat nfs_sec_nego(); 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate #define MAXHOSTS 512 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate /* number of transports to try */ 92*0Sstevel@tonic-gate #define MNT_PREF_LISTLEN 2 93*0Sstevel@tonic-gate #define FIRST_TRY 1 94*0Sstevel@tonic-gate #define SECOND_TRY 2 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate #define MNTTYPE_CACHEFS "cachefs" 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate /* 99*0Sstevel@tonic-gate * host cache states 100*0Sstevel@tonic-gate */ 101*0Sstevel@tonic-gate #define NOHOST 0 102*0Sstevel@tonic-gate #define GOODHOST 1 103*0Sstevel@tonic-gate #define DEADHOST 2 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate #define NFS_ARGS_EXTB_secdata(args, secdata) \ 106*0Sstevel@tonic-gate { (args).nfs_args_ext = NFS_ARGS_EXTB, \ 107*0Sstevel@tonic-gate (args).nfs_ext_u.nfs_extB.secdata = secdata; } 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate struct cache_entry { 110*0Sstevel@tonic-gate struct cache_entry *cache_next; 111*0Sstevel@tonic-gate char *cache_host; 112*0Sstevel@tonic-gate time_t cache_time; 113*0Sstevel@tonic-gate int cache_state; 114*0Sstevel@tonic-gate rpcvers_t cache_reqvers; 115*0Sstevel@tonic-gate rpcvers_t cache_outvers; 116*0Sstevel@tonic-gate char *cache_proto; 117*0Sstevel@tonic-gate }; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate struct mfs_snego_t { 120*0Sstevel@tonic-gate int sec_opt; 121*0Sstevel@tonic-gate bool_t snego_done; 122*0Sstevel@tonic-gate char *nfs_flavor; 123*0Sstevel@tonic-gate seconfig_t nfs_sec; 124*0Sstevel@tonic-gate }; 125*0Sstevel@tonic-gate typedef struct mfs_snego_t mfs_snego_t; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate static struct cache_entry *cache_head = NULL; 128*0Sstevel@tonic-gate rwlock_t cache_lock; /* protect the cache chain */ 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate static enum nfsstat nfsmount(struct mapfs *, char *, char *, int, int, 131*0Sstevel@tonic-gate struct authunix_parms *); 132*0Sstevel@tonic-gate static int is_nfs_port(char *); 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate static void netbuf_free(struct netbuf *); 135*0Sstevel@tonic-gate static struct knetconfig *get_knconf(struct netconfig *); 136*0Sstevel@tonic-gate static void free_knconf(struct knetconfig *); 137*0Sstevel@tonic-gate static int get_pathconf(CLIENT *, char *, char *, struct pathcnf **, int); 138*0Sstevel@tonic-gate static struct mapfs *enum_servers(struct mapent *, char *); 139*0Sstevel@tonic-gate static struct mapfs *get_mysubnet_servers(struct mapfs *); 140*0Sstevel@tonic-gate static int subnet_test(int af, struct sioc_addrreq *); 141*0Sstevel@tonic-gate static struct netbuf *get_addr(char *, rpcprog_t, rpcvers_t, 142*0Sstevel@tonic-gate struct netconfig **, char *, ushort_t, struct t_info *); 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate static struct netbuf *get_pubfh(char *, rpcvers_t, mfs_snego_t *, 145*0Sstevel@tonic-gate struct netconfig **, char *, ushort_t, struct t_info *, caddr_t *, 146*0Sstevel@tonic-gate bool_t, char *); 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate enum type_of_stuff { 149*0Sstevel@tonic-gate SERVER_ADDR = 0, 150*0Sstevel@tonic-gate SERVER_PING = 1, 151*0Sstevel@tonic-gate SERVER_FH = 2 152*0Sstevel@tonic-gate }; 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate static void *get_server_stuff(enum type_of_stuff, char *, rpcprog_t, 155*0Sstevel@tonic-gate rpcvers_t, mfs_snego_t *, struct netconfig **, char *, ushort_t, 156*0Sstevel@tonic-gate struct t_info *, caddr_t *, bool_t, char *, enum clnt_stat *); 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate static void *get_the_stuff(enum type_of_stuff, char *, rpcprog_t, 159*0Sstevel@tonic-gate rpcvers_t, mfs_snego_t *, struct netconfig *, ushort_t, struct t_info *, 160*0Sstevel@tonic-gate caddr_t *, bool_t, char *, enum clnt_stat *); 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate struct mapfs *add_mfs(struct mapfs *, int, struct mapfs **, struct mapfs **); 163*0Sstevel@tonic-gate void free_mfs(struct mapfs *); 164*0Sstevel@tonic-gate static void dump_mfs(struct mapfs *, char *, int); 165*0Sstevel@tonic-gate static char *dump_distance(struct mapfs *); 166*0Sstevel@tonic-gate static void cache_free(struct cache_entry *); 167*0Sstevel@tonic-gate static int cache_check(char *, rpcvers_t *, char *); 168*0Sstevel@tonic-gate static void cache_enter(char *, rpcvers_t, rpcvers_t, char *, int); 169*0Sstevel@tonic-gate static void destroy_auth_client_handle(CLIENT *cl); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate #ifdef CACHE_DEBUG 172*0Sstevel@tonic-gate static void trace_host_cache(); 173*0Sstevel@tonic-gate static void trace_portmap_cache(); 174*0Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate static int rpc_timeout = 20; 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate #ifdef CACHE_DEBUG 179*0Sstevel@tonic-gate /* 180*0Sstevel@tonic-gate * host cache counters. These variables do not need to be protected 181*0Sstevel@tonic-gate * by mutex's. They have been added to measure the utility of the 182*0Sstevel@tonic-gate * goodhost/deadhost cache in the lazy hierarchical mounting scheme. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate static int host_cache_accesses = 0; 185*0Sstevel@tonic-gate static int host_cache_lookups = 0; 186*0Sstevel@tonic-gate static int deadhost_cache_hits = 0; 187*0Sstevel@tonic-gate static int goodhost_cache_hits = 0; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate /* 190*0Sstevel@tonic-gate * portmap cache counters. These variables do not need to be protected 191*0Sstevel@tonic-gate * by mutex's. They have been added to measure the utility of the portmap 192*0Sstevel@tonic-gate * cache in the lazy hierarchical mounting scheme. 193*0Sstevel@tonic-gate */ 194*0Sstevel@tonic-gate static int portmap_cache_accesses = 0; 195*0Sstevel@tonic-gate static int portmap_cache_lookups = 0; 196*0Sstevel@tonic-gate static int portmap_cache_hits = 0; 197*0Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate /* 200*0Sstevel@tonic-gate * There are the defaults (range) for the client when determining 201*0Sstevel@tonic-gate * which NFS version to use when probing the server (see above). 202*0Sstevel@tonic-gate * These will only be used when the vers mount option is not used and 203*0Sstevel@tonic-gate * these may be reset if /etc/default/nfs is configured to do so. 204*0Sstevel@tonic-gate */ 205*0Sstevel@tonic-gate static rpcvers_t vers_max_default = NFS_VERSMAX_DEFAULT; 206*0Sstevel@tonic-gate static rpcvers_t vers_min_default = NFS_VERSMIN_DEFAULT; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* 209*0Sstevel@tonic-gate * list of support services needed 210*0Sstevel@tonic-gate */ 211*0Sstevel@tonic-gate static char *service_list[] = { STATD, LOCKD, NULL }; 212*0Sstevel@tonic-gate static char *service_list_v4[] = { STATD, LOCKD, NFS4CBD, NFSMAPID, NULL }; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate static void read_default_nfs(void); 215*0Sstevel@tonic-gate static int is_v4_mount(char *); 216*0Sstevel@tonic-gate static void start_nfs4cbd(void); 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate int 219*0Sstevel@tonic-gate mount_nfs(me, mntpnt, prevhost, overlay, cred) 220*0Sstevel@tonic-gate struct mapent *me; 221*0Sstevel@tonic-gate char *mntpnt; 222*0Sstevel@tonic-gate char *prevhost; 223*0Sstevel@tonic-gate int overlay; 224*0Sstevel@tonic-gate struct authunix_parms *cred; 225*0Sstevel@tonic-gate { 226*0Sstevel@tonic-gate struct mapfs *mfs, *mp; 227*0Sstevel@tonic-gate int err = -1; 228*0Sstevel@tonic-gate int cached; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate read_default_nfs(); 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate mfs = enum_servers(me, prevhost); 233*0Sstevel@tonic-gate if (mfs == NULL) 234*0Sstevel@tonic-gate return (ENOENT); 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate /* 237*0Sstevel@tonic-gate * Try loopback if we have something on localhost; if nothing 238*0Sstevel@tonic-gate * works, we will fall back to NFS 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate if (is_nfs_port(me->map_mntopts)) { 241*0Sstevel@tonic-gate for (mp = mfs; mp; mp = mp->mfs_next) { 242*0Sstevel@tonic-gate if (self_check(mp->mfs_host)) { 243*0Sstevel@tonic-gate err = loopbackmount(mp->mfs_dir, 244*0Sstevel@tonic-gate mntpnt, me->map_mntopts, overlay); 245*0Sstevel@tonic-gate if (err) { 246*0Sstevel@tonic-gate mp->mfs_ignore = 1; 247*0Sstevel@tonic-gate } else { 248*0Sstevel@tonic-gate break; 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate if (err) { 254*0Sstevel@tonic-gate cached = strcmp(me->map_mounter, MNTTYPE_CACHEFS) == 0; 255*0Sstevel@tonic-gate err = nfsmount(mfs, mntpnt, me->map_mntopts, 256*0Sstevel@tonic-gate cached, overlay, cred); 257*0Sstevel@tonic-gate if (err && trace > 1) { 258*0Sstevel@tonic-gate trace_prt(1, " Couldn't mount %s:%s, err=%d\n", 259*0Sstevel@tonic-gate mfs->mfs_host, mfs->mfs_dir, err); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate free_mfs(mfs); 263*0Sstevel@tonic-gate return (err); 264*0Sstevel@tonic-gate } 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate /* 268*0Sstevel@tonic-gate * Using the new ioctl SIOCTONLINK to determine if a host is on the same 269*0Sstevel@tonic-gate * subnet. Remove the old network, subnet check. 270*0Sstevel@tonic-gate */ 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate static struct mapfs * 273*0Sstevel@tonic-gate get_mysubnet_servers(struct mapfs *mfs_in) 274*0Sstevel@tonic-gate { 275*0Sstevel@tonic-gate int s; 276*0Sstevel@tonic-gate struct mapfs *mfs, *p, *mfs_head = NULL, *mfs_tail = NULL; 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate struct netconfig *nconf; 279*0Sstevel@tonic-gate NCONF_HANDLE *nc = NULL; 280*0Sstevel@tonic-gate struct nd_hostserv hs; 281*0Sstevel@tonic-gate struct nd_addrlist *retaddrs; 282*0Sstevel@tonic-gate struct netbuf *nb; 283*0Sstevel@tonic-gate struct sioc_addrreq areq; 284*0Sstevel@tonic-gate int res; 285*0Sstevel@tonic-gate int af; 286*0Sstevel@tonic-gate int i; 287*0Sstevel@tonic-gate int sa_size; 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate hs.h_serv = "rpcbind"; 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { 292*0Sstevel@tonic-gate nc = setnetconfig(); 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate while (nconf = getnetconfig(nc)) { 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate /* 297*0Sstevel@tonic-gate * Care about INET family only. proto_done flag 298*0Sstevel@tonic-gate * indicates if we have already covered this 299*0Sstevel@tonic-gate * protocol family. If so skip it 300*0Sstevel@tonic-gate */ 301*0Sstevel@tonic-gate if (((strcmp(nconf->nc_protofmly, NC_INET6) == 0) || 302*0Sstevel@tonic-gate (strcmp(nconf->nc_protofmly, NC_INET) == 0)) && 303*0Sstevel@tonic-gate (nconf->nc_semantics == NC_TPI_CLTS)) { 304*0Sstevel@tonic-gate } else 305*0Sstevel@tonic-gate continue; 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate hs.h_host = mfs->mfs_host; 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate if (netdir_getbyname(nconf, &hs, &retaddrs) != ND_OK) 310*0Sstevel@tonic-gate continue; 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /* 313*0Sstevel@tonic-gate * For each host address see if it's on our 314*0Sstevel@tonic-gate * local subnet. 315*0Sstevel@tonic-gate */ 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) 318*0Sstevel@tonic-gate af = AF_INET6; 319*0Sstevel@tonic-gate else 320*0Sstevel@tonic-gate af = AF_INET; 321*0Sstevel@tonic-gate nb = retaddrs->n_addrs; 322*0Sstevel@tonic-gate for (i = 0; i < retaddrs->n_cnt; i++, nb++) { 323*0Sstevel@tonic-gate memset(&areq.sa_addr, 0, sizeof (areq.sa_addr)); 324*0Sstevel@tonic-gate memcpy(&areq.sa_addr, nb->buf, MIN(nb->len, 325*0Sstevel@tonic-gate sizeof (areq.sa_addr))); 326*0Sstevel@tonic-gate if (res = subnet_test(af, &areq)) { 327*0Sstevel@tonic-gate p = add_mfs(mfs, DIST_MYNET, 328*0Sstevel@tonic-gate &mfs_head, &mfs_tail); 329*0Sstevel@tonic-gate if (!p) { 330*0Sstevel@tonic-gate netdir_free(retaddrs, 331*0Sstevel@tonic-gate ND_ADDRLIST); 332*0Sstevel@tonic-gate endnetconfig(nc); 333*0Sstevel@tonic-gate return (NULL); 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate break; 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate } /* end of every host */ 338*0Sstevel@tonic-gate if (trace > 2) { 339*0Sstevel@tonic-gate trace_prt(1, "get_mysubnet_servers: host=%s " 340*0Sstevel@tonic-gate "netid=%s res=%s\n", mfs->mfs_host, 341*0Sstevel@tonic-gate nconf->nc_netid, res == 1?"SUC":"FAIL"); 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate netdir_free(retaddrs, ND_ADDRLIST); 345*0Sstevel@tonic-gate } /* end of while */ 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate endnetconfig(nc); 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate } /* end of every map */ 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate return (mfs_head); 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate int 356*0Sstevel@tonic-gate subnet_test(int af, struct sioc_addrreq *areq) 357*0Sstevel@tonic-gate { 358*0Sstevel@tonic-gate int s; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate if ((s = socket(af, SOCK_DGRAM, 0)) < 0) { 361*0Sstevel@tonic-gate return (0); 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate areq->sa_res = -1; 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gate if (ioctl(s, SIOCTONLINK, (caddr_t)areq) < 0) { 367*0Sstevel@tonic-gate syslog(LOG_ERR, "subnet_test:SIOCTONLINK failed"); 368*0Sstevel@tonic-gate return (0); 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate close(s); 371*0Sstevel@tonic-gate if (areq->sa_res == 1) 372*0Sstevel@tonic-gate return (1); 373*0Sstevel@tonic-gate else 374*0Sstevel@tonic-gate return (0); 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate /* 380*0Sstevel@tonic-gate * ping a bunch of hosts at once and sort by who responds first 381*0Sstevel@tonic-gate */ 382*0Sstevel@tonic-gate static struct mapfs * 383*0Sstevel@tonic-gate sort_servers(struct mapfs *mfs_in, int timeout) 384*0Sstevel@tonic-gate { 385*0Sstevel@tonic-gate struct mapfs *m1 = NULL; 386*0Sstevel@tonic-gate enum clnt_stat clnt_stat; 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate if (!mfs_in) 389*0Sstevel@tonic-gate return (NULL); 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate clnt_stat = nfs_cast(mfs_in, &m1, timeout); 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate if (!m1) { 394*0Sstevel@tonic-gate char buff[2048] = {'\0'}; 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate for (m1 = mfs_in; m1; m1 = m1->mfs_next) { 397*0Sstevel@tonic-gate (void) strcat(buff, m1->mfs_host); 398*0Sstevel@tonic-gate if (m1->mfs_next) 399*0Sstevel@tonic-gate (void) strcat(buff, ","); 400*0Sstevel@tonic-gate } 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate syslog(LOG_ERR, "servers %s not responding: %s", 403*0Sstevel@tonic-gate buff, clnt_sperrno(clnt_stat)); 404*0Sstevel@tonic-gate } 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate return (m1); 407*0Sstevel@tonic-gate } 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate /* 410*0Sstevel@tonic-gate * Add a mapfs entry to the list described by *mfs_head and *mfs_tail, 411*0Sstevel@tonic-gate * provided it is not marked "ignored" and isn't a dupe of ones we've 412*0Sstevel@tonic-gate * already seen. 413*0Sstevel@tonic-gate */ 414*0Sstevel@tonic-gate struct mapfs * 415*0Sstevel@tonic-gate add_mfs(struct mapfs *mfs, int distance, struct mapfs **mfs_head, 416*0Sstevel@tonic-gate struct mapfs **mfs_tail) 417*0Sstevel@tonic-gate { 418*0Sstevel@tonic-gate struct mapfs *tmp, *new; 419*0Sstevel@tonic-gate void bcopy(); 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate for (tmp = *mfs_head; tmp; tmp = tmp->mfs_next) 422*0Sstevel@tonic-gate if ((strcmp(tmp->mfs_host, mfs->mfs_host) == 0 && 423*0Sstevel@tonic-gate strcmp(tmp->mfs_dir, mfs->mfs_dir) == 0) || 424*0Sstevel@tonic-gate mfs->mfs_ignore) 425*0Sstevel@tonic-gate return (*mfs_head); 426*0Sstevel@tonic-gate new = (struct mapfs *)malloc(sizeof (struct mapfs)); 427*0Sstevel@tonic-gate if (!new) { 428*0Sstevel@tonic-gate syslog(LOG_ERR, "Memory allocation failed: %m"); 429*0Sstevel@tonic-gate return (NULL); 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate bcopy(mfs, new, sizeof (struct mapfs)); 432*0Sstevel@tonic-gate new->mfs_next = NULL; 433*0Sstevel@tonic-gate if (distance) 434*0Sstevel@tonic-gate new->mfs_distance = distance; 435*0Sstevel@tonic-gate if (!*mfs_head) 436*0Sstevel@tonic-gate *mfs_tail = *mfs_head = new; 437*0Sstevel@tonic-gate else { 438*0Sstevel@tonic-gate (*mfs_tail)->mfs_next = new; 439*0Sstevel@tonic-gate *mfs_tail = new; 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate return (*mfs_head); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate static void 445*0Sstevel@tonic-gate dump_mfs(struct mapfs *mfs, char *message, int level) 446*0Sstevel@tonic-gate { 447*0Sstevel@tonic-gate struct mapfs *m1; 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate if (trace <= level) 450*0Sstevel@tonic-gate return; 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate trace_prt(1, "%s", message); 453*0Sstevel@tonic-gate if (!mfs) { 454*0Sstevel@tonic-gate trace_prt(0, "mfs is null\n"); 455*0Sstevel@tonic-gate return; 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate for (m1 = mfs; m1; m1 = m1->mfs_next) 458*0Sstevel@tonic-gate trace_prt(0, "%s[%s] ", m1->mfs_host, dump_distance(m1)); 459*0Sstevel@tonic-gate trace_prt(0, "\n"); 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate static char * 463*0Sstevel@tonic-gate dump_distance(struct mapfs *mfs) 464*0Sstevel@tonic-gate { 465*0Sstevel@tonic-gate switch (mfs->mfs_distance) { 466*0Sstevel@tonic-gate case 0: return ("zero"); 467*0Sstevel@tonic-gate case DIST_SELF: return ("self"); 468*0Sstevel@tonic-gate case DIST_MYSUB: return ("mysub"); 469*0Sstevel@tonic-gate case DIST_MYNET: return ("mynet"); 470*0Sstevel@tonic-gate case DIST_OTHER: return ("other"); 471*0Sstevel@tonic-gate default: return ("other"); 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate /* 476*0Sstevel@tonic-gate * Walk linked list "raw", building a new list consisting of members 477*0Sstevel@tonic-gate * NOT found in list "filter", returning the result. 478*0Sstevel@tonic-gate */ 479*0Sstevel@tonic-gate static struct mapfs * 480*0Sstevel@tonic-gate filter_mfs(struct mapfs *raw, struct mapfs *filter) 481*0Sstevel@tonic-gate { 482*0Sstevel@tonic-gate struct mapfs *mfs, *p, *mfs_head = NULL, *mfs_tail = NULL; 483*0Sstevel@tonic-gate int skip; 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate if (!raw) 486*0Sstevel@tonic-gate return (NULL); 487*0Sstevel@tonic-gate for (mfs = raw; mfs; mfs = mfs->mfs_next) { 488*0Sstevel@tonic-gate for (skip = 0, p = filter; p; p = p->mfs_next) { 489*0Sstevel@tonic-gate if (strcmp(p->mfs_host, mfs->mfs_host) == 0 && 490*0Sstevel@tonic-gate strcmp(p->mfs_dir, mfs->mfs_dir) == 0) { 491*0Sstevel@tonic-gate skip = 1; 492*0Sstevel@tonic-gate break; 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate } 495*0Sstevel@tonic-gate if (skip) 496*0Sstevel@tonic-gate continue; 497*0Sstevel@tonic-gate p = add_mfs(mfs, 0, &mfs_head, &mfs_tail); 498*0Sstevel@tonic-gate if (!p) 499*0Sstevel@tonic-gate return (NULL); 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate return (mfs_head); 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate /* 505*0Sstevel@tonic-gate * Walk a linked list of mapfs structs, freeing each member. 506*0Sstevel@tonic-gate */ 507*0Sstevel@tonic-gate void 508*0Sstevel@tonic-gate free_mfs(struct mapfs *mfs) 509*0Sstevel@tonic-gate { 510*0Sstevel@tonic-gate struct mapfs *tmp; 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate while (mfs) { 513*0Sstevel@tonic-gate tmp = mfs->mfs_next; 514*0Sstevel@tonic-gate free(mfs); 515*0Sstevel@tonic-gate mfs = tmp; 516*0Sstevel@tonic-gate } 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* 520*0Sstevel@tonic-gate * New code for NFS client failover: we need to carry and sort 521*0Sstevel@tonic-gate * lists of server possibilities rather than return a single 522*0Sstevel@tonic-gate * entry. It preserves previous behaviour of sorting first by 523*0Sstevel@tonic-gate * locality (loopback-or-preferred/subnet/net/other) and then 524*0Sstevel@tonic-gate * by ping times. We'll short-circuit this process when we 525*0Sstevel@tonic-gate * have ENOUGH or more entries. 526*0Sstevel@tonic-gate */ 527*0Sstevel@tonic-gate static struct mapfs * 528*0Sstevel@tonic-gate enum_servers(struct mapent *me, char *preferred) 529*0Sstevel@tonic-gate { 530*0Sstevel@tonic-gate struct mapfs *p, *m1, *m2, *mfs_head = NULL, *mfs_tail = NULL; 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate /* 533*0Sstevel@tonic-gate * Short-circuit for simple cases. 534*0Sstevel@tonic-gate */ 535*0Sstevel@tonic-gate if (!me->map_fs->mfs_next) { 536*0Sstevel@tonic-gate p = add_mfs(me->map_fs, DIST_OTHER, &mfs_head, &mfs_tail); 537*0Sstevel@tonic-gate if (!p) 538*0Sstevel@tonic-gate return (NULL); 539*0Sstevel@tonic-gate return (mfs_head); 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate dump_mfs(me->map_fs, " enum_servers: mapent: ", 2); 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate /* 545*0Sstevel@tonic-gate * get addresses & see if any are myself 546*0Sstevel@tonic-gate * or were mounted from previously in a 547*0Sstevel@tonic-gate * hierarchical mount. 548*0Sstevel@tonic-gate */ 549*0Sstevel@tonic-gate if (trace > 2) 550*0Sstevel@tonic-gate trace_prt(1, " enum_servers: looking for pref/self\n"); 551*0Sstevel@tonic-gate for (m1 = me->map_fs; m1; m1 = m1->mfs_next) { 552*0Sstevel@tonic-gate if (m1->mfs_ignore) 553*0Sstevel@tonic-gate continue; 554*0Sstevel@tonic-gate if (self_check(m1->mfs_host) || 555*0Sstevel@tonic-gate strcmp(m1->mfs_host, preferred) == 0) { 556*0Sstevel@tonic-gate p = add_mfs(m1, DIST_SELF, &mfs_head, &mfs_tail); 557*0Sstevel@tonic-gate if (!p) 558*0Sstevel@tonic-gate return (NULL); 559*0Sstevel@tonic-gate } 560*0Sstevel@tonic-gate } 561*0Sstevel@tonic-gate if (trace > 2 && m1) 562*0Sstevel@tonic-gate trace_prt(1, " enum_servers: pref/self found, %s\n", 563*0Sstevel@tonic-gate m1->mfs_host); 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate /* 566*0Sstevel@tonic-gate * look for entries on this subnet 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate dump_mfs(m1, " enum_servers: input of get_mysubnet_servers: ", 2); 569*0Sstevel@tonic-gate m1 = get_mysubnet_servers(me->map_fs); 570*0Sstevel@tonic-gate dump_mfs(m1, " enum_servers: output of get_mysubnet_servers: ", 3); 571*0Sstevel@tonic-gate if (m1 && m1->mfs_next) { 572*0Sstevel@tonic-gate m2 = sort_servers(m1, rpc_timeout / 2); 573*0Sstevel@tonic-gate dump_mfs(m2, " enum_servers: output of sort_servers: ", 3); 574*0Sstevel@tonic-gate free_mfs(m1); 575*0Sstevel@tonic-gate m1 = m2; 576*0Sstevel@tonic-gate } 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate for (m2 = m1; m2; m2 = m2->mfs_next) { 579*0Sstevel@tonic-gate p = add_mfs(m2, 0, &mfs_head, &mfs_tail); 580*0Sstevel@tonic-gate if (!p) 581*0Sstevel@tonic-gate return (NULL); 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate if (m1) 584*0Sstevel@tonic-gate free_mfs(m1); 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate /* 587*0Sstevel@tonic-gate * add the rest of the entries at the end 588*0Sstevel@tonic-gate */ 589*0Sstevel@tonic-gate m1 = filter_mfs(me->map_fs, mfs_head); 590*0Sstevel@tonic-gate dump_mfs(m1, " enum_servers: etc: output of filter_mfs: ", 3); 591*0Sstevel@tonic-gate m2 = sort_servers(m1, rpc_timeout / 2); 592*0Sstevel@tonic-gate dump_mfs(m2, " enum_servers: etc: output of sort_servers: ", 3); 593*0Sstevel@tonic-gate if (m1) 594*0Sstevel@tonic-gate free_mfs(m1); 595*0Sstevel@tonic-gate m1 = m2; 596*0Sstevel@tonic-gate for (m2 = m1; m2; m2 = m2->mfs_next) { 597*0Sstevel@tonic-gate p = add_mfs(m2, DIST_OTHER, &mfs_head, &mfs_tail); 598*0Sstevel@tonic-gate if (!p) 599*0Sstevel@tonic-gate return (NULL); 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate if (m1) 602*0Sstevel@tonic-gate free_mfs(m1); 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate done: 605*0Sstevel@tonic-gate dump_mfs(mfs_head, " enum_servers: output: ", 1); 606*0Sstevel@tonic-gate return (mfs_head); 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate static enum nfsstat 610*0Sstevel@tonic-gate nfsmount(mfs_in, mntpnt, opts, cached, overlay, cred) 611*0Sstevel@tonic-gate struct mapfs *mfs_in; 612*0Sstevel@tonic-gate char *mntpnt, *opts; 613*0Sstevel@tonic-gate int cached, overlay; 614*0Sstevel@tonic-gate struct authunix_parms *cred; 615*0Sstevel@tonic-gate { 616*0Sstevel@tonic-gate CLIENT *cl; 617*0Sstevel@tonic-gate char remname[MAXPATHLEN], *mnttabtext = NULL; 618*0Sstevel@tonic-gate char mopts[MAX_MNTOPT_STR]; 619*0Sstevel@tonic-gate char netname[MAXNETNAMELEN+1]; 620*0Sstevel@tonic-gate int mnttabcnt = 0; 621*0Sstevel@tonic-gate int loglevel; 622*0Sstevel@tonic-gate struct mnttab m; 623*0Sstevel@tonic-gate struct nfs_args *argp = NULL, *head = NULL, *tail = NULL, 624*0Sstevel@tonic-gate *prevhead, *prevtail; 625*0Sstevel@tonic-gate int flags; 626*0Sstevel@tonic-gate struct fhstatus fhs; 627*0Sstevel@tonic-gate struct timeval timeout; 628*0Sstevel@tonic-gate enum clnt_stat rpc_stat; 629*0Sstevel@tonic-gate enum nfsstat status; 630*0Sstevel@tonic-gate struct stat stbuf; 631*0Sstevel@tonic-gate struct netconfig *nconf; 632*0Sstevel@tonic-gate rpcvers_t vers, versmin; /* used to negotiate nfs version in pingnfs */ 633*0Sstevel@tonic-gate /* and mount version with mountd */ 634*0Sstevel@tonic-gate rpcvers_t outvers; /* final version to be used during mount() */ 635*0Sstevel@tonic-gate rpcvers_t nfsvers; /* version in map options, 0 if not there */ 636*0Sstevel@tonic-gate rpcvers_t mountversmax; /* tracks the max mountvers during retries */ 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate /* used to negotiate nfs version using webnfs */ 639*0Sstevel@tonic-gate rpcvers_t pubvers, pubversmin, pubversmax; 640*0Sstevel@tonic-gate int posix; 641*0Sstevel@tonic-gate struct nd_addrlist *retaddrs; 642*0Sstevel@tonic-gate struct mountres3 res3; 643*0Sstevel@tonic-gate nfs_fh3 fh3; 644*0Sstevel@tonic-gate char *fstype; 645*0Sstevel@tonic-gate int count, i; 646*0Sstevel@tonic-gate char scerror_msg[MAXMSGLEN]; 647*0Sstevel@tonic-gate int *auths; 648*0Sstevel@tonic-gate int delay; 649*0Sstevel@tonic-gate int retries; 650*0Sstevel@tonic-gate char *nfs_proto = NULL; 651*0Sstevel@tonic-gate uint_t nfs_port = 0; 652*0Sstevel@tonic-gate char *p, *host, *dir; 653*0Sstevel@tonic-gate struct mapfs *mfs = NULL; 654*0Sstevel@tonic-gate int error, last_error = 0; 655*0Sstevel@tonic-gate int replicated; 656*0Sstevel@tonic-gate int entries = 0; 657*0Sstevel@tonic-gate int v2cnt = 0, v3cnt = 0, v4cnt = 0; 658*0Sstevel@tonic-gate int v2near = 0, v3near = 0, v4near = 0; 659*0Sstevel@tonic-gate int skipentry = 0; 660*0Sstevel@tonic-gate char *nfs_flavor; 661*0Sstevel@tonic-gate seconfig_t nfs_sec; 662*0Sstevel@tonic-gate int sec_opt, scerror; 663*0Sstevel@tonic-gate struct sec_data *secdata; 664*0Sstevel@tonic-gate int secflags; 665*0Sstevel@tonic-gate struct netbuf *syncaddr; 666*0Sstevel@tonic-gate bool_t use_pubfh; 667*0Sstevel@tonic-gate ushort_t thisport; 668*0Sstevel@tonic-gate int got_val; 669*0Sstevel@tonic-gate mfs_snego_t mfssnego_init, mfssnego; 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate dump_mfs(mfs_in, " nfsmount: input: ", 2); 672*0Sstevel@tonic-gate replicated = (mfs_in->mfs_next != NULL); 673*0Sstevel@tonic-gate m.mnt_mntopts = opts; 674*0Sstevel@tonic-gate if (replicated && hasmntopt(&m, MNTOPT_SOFT)) { 675*0Sstevel@tonic-gate if (verbose) 676*0Sstevel@tonic-gate syslog(LOG_WARNING, 677*0Sstevel@tonic-gate "mount on %s is soft and will not be replicated.", mntpnt); 678*0Sstevel@tonic-gate replicated = 0; 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate if (replicated && !hasmntopt(&m, MNTOPT_RO)) { 681*0Sstevel@tonic-gate if (verbose) 682*0Sstevel@tonic-gate syslog(LOG_WARNING, 683*0Sstevel@tonic-gate "mount on %s is not read-only and will not be replicated.", 684*0Sstevel@tonic-gate mntpnt); 685*0Sstevel@tonic-gate replicated = 0; 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate if (replicated && cached) { 688*0Sstevel@tonic-gate if (verbose) 689*0Sstevel@tonic-gate syslog(LOG_WARNING, 690*0Sstevel@tonic-gate "mount on %s is cached and will not be replicated.", 691*0Sstevel@tonic-gate mntpnt); 692*0Sstevel@tonic-gate replicated = 0; 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate if (replicated) 695*0Sstevel@tonic-gate loglevel = LOG_WARNING; 696*0Sstevel@tonic-gate else 697*0Sstevel@tonic-gate loglevel = LOG_ERR; 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate if (trace > 1) { 700*0Sstevel@tonic-gate if (replicated) 701*0Sstevel@tonic-gate trace_prt(1, " nfsmount: replicated mount on %s %s:\n", 702*0Sstevel@tonic-gate mntpnt, opts); 703*0Sstevel@tonic-gate else 704*0Sstevel@tonic-gate trace_prt(1, " nfsmount: standard mount on %s %s:\n", 705*0Sstevel@tonic-gate mntpnt, opts); 706*0Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) 707*0Sstevel@tonic-gate trace_prt(1, " %s:%s\n", 708*0Sstevel@tonic-gate mfs->mfs_host, mfs->mfs_dir); 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate /* 712*0Sstevel@tonic-gate * Make sure mountpoint is safe to mount on 713*0Sstevel@tonic-gate */ 714*0Sstevel@tonic-gate if (lstat(mntpnt, &stbuf) < 0) { 715*0Sstevel@tonic-gate syslog(LOG_ERR, "Couldn't stat %s: %m", mntpnt); 716*0Sstevel@tonic-gate return (NFSERR_NOENT); 717*0Sstevel@tonic-gate } 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate /* 720*0Sstevel@tonic-gate * Get protocol specified in options list, if any. 721*0Sstevel@tonic-gate */ 722*0Sstevel@tonic-gate if ((str_opt(&m, "proto", &nfs_proto)) == -1) { 723*0Sstevel@tonic-gate return (NFSERR_NOENT); 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate /* 727*0Sstevel@tonic-gate * Get port specified in options list, if any. 728*0Sstevel@tonic-gate */ 729*0Sstevel@tonic-gate got_val = nopt(&m, MNTOPT_PORT, (int *)&nfs_port); 730*0Sstevel@tonic-gate if (!got_val) 731*0Sstevel@tonic-gate nfs_port = 0; /* "unspecified" */ 732*0Sstevel@tonic-gate if (nfs_port > USHRT_MAX) { 733*0Sstevel@tonic-gate syslog(LOG_ERR, "%s: invalid port number %d", mntpnt, nfs_port); 734*0Sstevel@tonic-gate return (NFSERR_NOENT); 735*0Sstevel@tonic-gate } 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate /* 738*0Sstevel@tonic-gate * Set mount(2) flags here, outside of the loop. 739*0Sstevel@tonic-gate */ 740*0Sstevel@tonic-gate flags = MS_OPTIONSTR; 741*0Sstevel@tonic-gate flags |= (hasmntopt(&m, MNTOPT_RO) == NULL) ? 0 : MS_RDONLY; 742*0Sstevel@tonic-gate flags |= (hasmntopt(&m, MNTOPT_NOSUID) == NULL) ? 0 : MS_NOSUID; 743*0Sstevel@tonic-gate flags |= overlay ? MS_OVERLAY : 0; 744*0Sstevel@tonic-gate if (mntpnt[strlen(mntpnt) - 1] != ' ') 745*0Sstevel@tonic-gate /* direct mount point without offsets */ 746*0Sstevel@tonic-gate flags |= MS_OVERLAY; 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate use_pubfh = (hasmntopt(&m, MNTOPT_PUBLIC) == NULL) ? FALSE : TRUE; 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate (void) memset(&mfssnego_init, 0, sizeof (mfs_snego_t)); 751*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_SECURE) != NULL) { 752*0Sstevel@tonic-gate if (++mfssnego_init.sec_opt > 1) { 753*0Sstevel@tonic-gate syslog(loglevel, 754*0Sstevel@tonic-gate "conflicting security options"); 755*0Sstevel@tonic-gate return (NFSERR_IO); 756*0Sstevel@tonic-gate } 757*0Sstevel@tonic-gate if (nfs_getseconfig_byname("dh", &mfssnego_init.nfs_sec)) { 758*0Sstevel@tonic-gate syslog(loglevel, 759*0Sstevel@tonic-gate "error getting dh information from %s", 760*0Sstevel@tonic-gate NFSSEC_CONF); 761*0Sstevel@tonic-gate return (NFSERR_IO); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate /* 766*0Sstevel@tonic-gate * Have to workaround the fact that hasmntopt() returns true 767*0Sstevel@tonic-gate * when comparing "secure" (in &m) with "sec". 768*0Sstevel@tonic-gate */ 769*0Sstevel@tonic-gate if (hasmntopt(&m, "sec=") != NULL) { 770*0Sstevel@tonic-gate if ((str_opt(&m, MNTOPT_SEC, 771*0Sstevel@tonic-gate &mfssnego_init.nfs_flavor)) == -1) { 772*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 773*0Sstevel@tonic-gate return (NFSERR_IO); 774*0Sstevel@tonic-gate } 775*0Sstevel@tonic-gate } 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate if (mfssnego_init.nfs_flavor) { 778*0Sstevel@tonic-gate if (++mfssnego_init.sec_opt > 1) { 779*0Sstevel@tonic-gate syslog(loglevel, 780*0Sstevel@tonic-gate "conflicting security options"); 781*0Sstevel@tonic-gate free(mfssnego_init.nfs_flavor); 782*0Sstevel@tonic-gate return (NFSERR_IO); 783*0Sstevel@tonic-gate } 784*0Sstevel@tonic-gate if (nfs_getseconfig_byname(mfssnego_init.nfs_flavor, 785*0Sstevel@tonic-gate &mfssnego_init.nfs_sec)) { 786*0Sstevel@tonic-gate syslog(loglevel, 787*0Sstevel@tonic-gate "error getting %s information from %s", 788*0Sstevel@tonic-gate mfssnego_init.nfs_flavor, NFSSEC_CONF); 789*0Sstevel@tonic-gate free(mfssnego_init.nfs_flavor); 790*0Sstevel@tonic-gate return (NFSERR_IO); 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate free(mfssnego_init.nfs_flavor); 793*0Sstevel@tonic-gate } 794*0Sstevel@tonic-gate 795*0Sstevel@tonic-gate nextentry: 796*0Sstevel@tonic-gate skipentry = 0; 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate got_val = nopt(&m, MNTOPT_VERS, (int *)&nfsvers); 799*0Sstevel@tonic-gate if (!got_val) 800*0Sstevel@tonic-gate nfsvers = 0; /* "unspecified" */ 801*0Sstevel@tonic-gate if (set_versrange(nfsvers, &vers, &versmin) != 0) { 802*0Sstevel@tonic-gate syslog(LOG_ERR, "Incorrect NFS version specified for %s", 803*0Sstevel@tonic-gate mntpnt); 804*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 805*0Sstevel@tonic-gate goto ret; 806*0Sstevel@tonic-gate } 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate if (nfsvers != 0) { 809*0Sstevel@tonic-gate pubversmax = pubversmin = nfsvers; 810*0Sstevel@tonic-gate } else { 811*0Sstevel@tonic-gate pubversmax = vers; 812*0Sstevel@tonic-gate pubversmin = versmin; 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate /* 816*0Sstevel@tonic-gate * Walk the whole list, pinging and collecting version 817*0Sstevel@tonic-gate * info so that we can make sure the mount will be 818*0Sstevel@tonic-gate * homogeneous with respect to version. 819*0Sstevel@tonic-gate * 820*0Sstevel@tonic-gate * If we have a version preference, this is easy; we'll 821*0Sstevel@tonic-gate * just reject anything that doesn't match. 822*0Sstevel@tonic-gate * 823*0Sstevel@tonic-gate * If not, we want to try to provide the best compromise 824*0Sstevel@tonic-gate * that considers proximity, preference for a higher version, 825*0Sstevel@tonic-gate * sorted order, and number of replicas. We will count 826*0Sstevel@tonic-gate * the number of V2 and V3 replicas and also the number 827*0Sstevel@tonic-gate * which are "near", i.e. the localhost or on the same 828*0Sstevel@tonic-gate * subnet. 829*0Sstevel@tonic-gate */ 830*0Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate if (mfs->mfs_ignore) 834*0Sstevel@tonic-gate continue; 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate host = mfs->mfs_host; 837*0Sstevel@tonic-gate (void) memcpy(&mfssnego, &mfssnego_init, sizeof (mfs_snego_t)); 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate if (use_pubfh == TRUE || mfs->mfs_flags & MFS_URL) { 840*0Sstevel@tonic-gate char *path; 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate if (nfs_port != 0 && mfs->mfs_port != 0 && 843*0Sstevel@tonic-gate nfs_port != mfs->mfs_port) { 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: port (%u) in nfs URL" 846*0Sstevel@tonic-gate " not the same as port (%d) in port " 847*0Sstevel@tonic-gate "option\n", mfs->mfs_port, nfs_port); 848*0Sstevel@tonic-gate last_error = NFSERR_IO; 849*0Sstevel@tonic-gate goto out; 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate } else if (nfs_port != 0) 852*0Sstevel@tonic-gate thisport = nfs_port; 853*0Sstevel@tonic-gate else 854*0Sstevel@tonic-gate thisport = mfs->mfs_port; 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate dir = mfs->mfs_dir; 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_URL) == 0) { 859*0Sstevel@tonic-gate path = malloc(strlen(dir) + 2); 860*0Sstevel@tonic-gate if (path == NULL) { 861*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 862*0Sstevel@tonic-gate last_error = NFSERR_IO; 863*0Sstevel@tonic-gate goto out; 864*0Sstevel@tonic-gate } 865*0Sstevel@tonic-gate path[0] = (char)WNL_NATIVEPATH; 866*0Sstevel@tonic-gate (void) strcpy(&path[1], dir); 867*0Sstevel@tonic-gate } else { 868*0Sstevel@tonic-gate path = dir; 869*0Sstevel@tonic-gate } 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate argp = (struct nfs_args *) 872*0Sstevel@tonic-gate malloc(sizeof (struct nfs_args)); 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate if (!argp) { 875*0Sstevel@tonic-gate if (path != dir) 876*0Sstevel@tonic-gate free(path); 877*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 878*0Sstevel@tonic-gate last_error = NFSERR_IO; 879*0Sstevel@tonic-gate goto out; 880*0Sstevel@tonic-gate } 881*0Sstevel@tonic-gate (void) memset(argp, 0, sizeof (*argp)); 882*0Sstevel@tonic-gate 883*0Sstevel@tonic-gate /* 884*0Sstevel@tonic-gate * RDMA support 885*0Sstevel@tonic-gate * By now Mount argument struct has been allocated, 886*0Sstevel@tonic-gate * either a pub_fh path will be taken or the regular 887*0Sstevel@tonic-gate * one. So here if a protocol was specified and it 888*0Sstevel@tonic-gate * was not rdma we let it be, else we set DO_RDMA. 889*0Sstevel@tonic-gate * If no proto was there we advise on trying RDMA. 890*0Sstevel@tonic-gate */ 891*0Sstevel@tonic-gate if (nfs_proto) { 892*0Sstevel@tonic-gate if (strcmp(nfs_proto, "rdma") == 0) { 893*0Sstevel@tonic-gate free(nfs_proto); 894*0Sstevel@tonic-gate nfs_proto = NULL; 895*0Sstevel@tonic-gate argp->flags |= NFSMNT_DORDMA; 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate } else 898*0Sstevel@tonic-gate argp->flags |= NFSMNT_TRYRDMA; 899*0Sstevel@tonic-gate 900*0Sstevel@tonic-gate for (pubvers = pubversmax; pubvers >= pubversmin; 901*0Sstevel@tonic-gate pubvers--) { 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate nconf = NULL; 904*0Sstevel@tonic-gate argp->addr = get_pubfh(host, pubvers, &mfssnego, 905*0Sstevel@tonic-gate &nconf, nfs_proto, thisport, NULL, 906*0Sstevel@tonic-gate &argp->fh, TRUE, path); 907*0Sstevel@tonic-gate 908*0Sstevel@tonic-gate if (argp->addr != NULL) 909*0Sstevel@tonic-gate break; 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate if (nconf != NULL) 912*0Sstevel@tonic-gate freenetconfigent(nconf); 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate if (path != dir) 916*0Sstevel@tonic-gate free(path); 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate if (argp->addr != NULL) { 919*0Sstevel@tonic-gate 920*0Sstevel@tonic-gate /* 921*0Sstevel@tonic-gate * The use of llock option for NFSv4 922*0Sstevel@tonic-gate * mounts is not required since file 923*0Sstevel@tonic-gate * locking is included within the protocol 924*0Sstevel@tonic-gate */ 925*0Sstevel@tonic-gate if (pubvers != NFS_V4) 926*0Sstevel@tonic-gate argp->flags |= NFSMNT_LLOCK; 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate argp->flags |= NFSMNT_PUBLIC; 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate mfs->mfs_args = argp; 931*0Sstevel@tonic-gate mfs->mfs_version = pubvers; 932*0Sstevel@tonic-gate mfs->mfs_nconf = nconf; 933*0Sstevel@tonic-gate mfs->mfs_flags |= MFS_FH_VIA_WEBNFS; 934*0Sstevel@tonic-gate 935*0Sstevel@tonic-gate } else { 936*0Sstevel@tonic-gate free(argp); 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate /* 939*0Sstevel@tonic-gate * If -public was specified, give up 940*0Sstevel@tonic-gate * on this entry now. 941*0Sstevel@tonic-gate */ 942*0Sstevel@tonic-gate if (use_pubfh == TRUE) { 943*0Sstevel@tonic-gate syslog(loglevel, 944*0Sstevel@tonic-gate "%s: no public file handle support", 945*0Sstevel@tonic-gate host); 946*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 947*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 948*0Sstevel@tonic-gate continue; 949*0Sstevel@tonic-gate } 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate /* 952*0Sstevel@tonic-gate * Back off to a conventional mount. 953*0Sstevel@tonic-gate * 954*0Sstevel@tonic-gate * URL's can contain escape characters. Get 955*0Sstevel@tonic-gate * rid of them. 956*0Sstevel@tonic-gate */ 957*0Sstevel@tonic-gate path = malloc(strlen(dir) + 2); 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate if (path == NULL) { 960*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 961*0Sstevel@tonic-gate last_error = NFSERR_IO; 962*0Sstevel@tonic-gate goto out; 963*0Sstevel@tonic-gate } 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate strcpy(path, dir); 966*0Sstevel@tonic-gate URLparse(path); 967*0Sstevel@tonic-gate mfs->mfs_dir = path; 968*0Sstevel@tonic-gate mfs->mfs_flags |= MFS_ALLOC_DIR; 969*0Sstevel@tonic-gate mfs->mfs_flags &= ~MFS_URL; 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate } 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0) { 974*0Sstevel@tonic-gate i = pingnfs(host, get_retry(opts) + 1, &vers, versmin, 975*0Sstevel@tonic-gate 0, FALSE, NULL, nfs_proto); 976*0Sstevel@tonic-gate if (i != RPC_SUCCESS) { 977*0Sstevel@tonic-gate if (i == RPC_PROGVERSMISMATCH) { 978*0Sstevel@tonic-gate syslog(loglevel, "server %s: NFS " 979*0Sstevel@tonic-gate "protocol version mismatch", 980*0Sstevel@tonic-gate host); 981*0Sstevel@tonic-gate } else { 982*0Sstevel@tonic-gate syslog(loglevel, "server %s not " 983*0Sstevel@tonic-gate "responding", host); 984*0Sstevel@tonic-gate } 985*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 986*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 987*0Sstevel@tonic-gate continue; 988*0Sstevel@tonic-gate } 989*0Sstevel@tonic-gate if (nfsvers != 0 && nfsvers != vers) { 990*0Sstevel@tonic-gate if (nfs_proto == NULL) 991*0Sstevel@tonic-gate syslog(loglevel, 992*0Sstevel@tonic-gate "NFS version %d " 993*0Sstevel@tonic-gate "not supported by %s", 994*0Sstevel@tonic-gate nfsvers, host); 995*0Sstevel@tonic-gate else 996*0Sstevel@tonic-gate syslog(loglevel, 997*0Sstevel@tonic-gate "NFS version %d " 998*0Sstevel@tonic-gate "with proto %s " 999*0Sstevel@tonic-gate "not supported by %s", 1000*0Sstevel@tonic-gate nfsvers, nfs_proto, host); 1001*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1002*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1003*0Sstevel@tonic-gate continue; 1004*0Sstevel@tonic-gate } 1005*0Sstevel@tonic-gate } 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gate switch (vers) { 1008*0Sstevel@tonic-gate case NFS_V4: v4cnt++; break; 1009*0Sstevel@tonic-gate case NFS_V3: v3cnt++; break; 1010*0Sstevel@tonic-gate case NFS_VERSION: v2cnt++; break; 1011*0Sstevel@tonic-gate default: break; 1012*0Sstevel@tonic-gate } 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate /* 1015*0Sstevel@tonic-gate * It's not clear how useful this stuff is if 1016*0Sstevel@tonic-gate * we are using webnfs across the internet, but it 1017*0Sstevel@tonic-gate * can't hurt. 1018*0Sstevel@tonic-gate */ 1019*0Sstevel@tonic-gate if (mfs->mfs_distance && 1020*0Sstevel@tonic-gate mfs->mfs_distance <= DIST_MYSUB) { 1021*0Sstevel@tonic-gate switch (vers) { 1022*0Sstevel@tonic-gate case NFS_V4: v4near++; break; 1023*0Sstevel@tonic-gate case NFS_V3: v3near++; break; 1024*0Sstevel@tonic-gate case NFS_VERSION: v2near++; break; 1025*0Sstevel@tonic-gate default: break; 1026*0Sstevel@tonic-gate } 1027*0Sstevel@tonic-gate } 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate /* 1030*0Sstevel@tonic-gate * If the mount is not replicated, we don't want to 1031*0Sstevel@tonic-gate * ping every entry, so we'll stop here. This means 1032*0Sstevel@tonic-gate * that we may have to go back to "nextentry" above 1033*0Sstevel@tonic-gate * to consider another entry if there we can't get 1034*0Sstevel@tonic-gate * all the way to mount(2) with this one. 1035*0Sstevel@tonic-gate */ 1036*0Sstevel@tonic-gate if (!replicated) 1037*0Sstevel@tonic-gate break; 1038*0Sstevel@tonic-gate } 1039*0Sstevel@tonic-gate 1040*0Sstevel@tonic-gate if (nfsvers == 0) { 1041*0Sstevel@tonic-gate /* 1042*0Sstevel@tonic-gate * Choose the NFS version. 1043*0Sstevel@tonic-gate * We prefer higher versions, but will choose a one- 1044*0Sstevel@tonic-gate * version downgrade in service if we can use a local 1045*0Sstevel@tonic-gate * network interface and avoid a router. 1046*0Sstevel@tonic-gate */ 1047*0Sstevel@tonic-gate if (v4cnt && v4cnt >= v3cnt && (v4near || !v3near)) 1048*0Sstevel@tonic-gate nfsvers = NFS_V4; 1049*0Sstevel@tonic-gate else if (v3cnt && v3cnt >= v2cnt && (v3near || !v2near)) 1050*0Sstevel@tonic-gate nfsvers = NFS_V3; 1051*0Sstevel@tonic-gate else 1052*0Sstevel@tonic-gate nfsvers = NFS_VERSION; 1053*0Sstevel@tonic-gate if (trace > 2) 1054*0Sstevel@tonic-gate trace_prt(1, 1055*0Sstevel@tonic-gate " nfsmount: v4=%d[%d]v3=%d[%d],v2=%d[%d] => v%d.\n", 1056*0Sstevel@tonic-gate v4cnt, v4near, v3cnt, v3near, 1057*0Sstevel@tonic-gate v2cnt, v2near, nfsvers); 1058*0Sstevel@tonic-gate } 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate /* 1061*0Sstevel@tonic-gate * Since we don't support different NFS versions in replicated 1062*0Sstevel@tonic-gate * mounts, set fstype now. 1063*0Sstevel@tonic-gate * Also take the opportunity to set 1064*0Sstevel@tonic-gate * the mount protocol version as appropriate. 1065*0Sstevel@tonic-gate */ 1066*0Sstevel@tonic-gate switch (nfsvers) { 1067*0Sstevel@tonic-gate case NFS_V4: 1068*0Sstevel@tonic-gate fstype = MNTTYPE_NFS4; 1069*0Sstevel@tonic-gate break; 1070*0Sstevel@tonic-gate case NFS_V3: 1071*0Sstevel@tonic-gate fstype = MNTTYPE_NFS3; 1072*0Sstevel@tonic-gate if (use_pubfh == FALSE) { 1073*0Sstevel@tonic-gate mountversmax = MOUNTVERS3; 1074*0Sstevel@tonic-gate versmin = MOUNTVERS3; 1075*0Sstevel@tonic-gate } 1076*0Sstevel@tonic-gate break; 1077*0Sstevel@tonic-gate case NFS_VERSION: 1078*0Sstevel@tonic-gate fstype = MNTTYPE_NFS; 1079*0Sstevel@tonic-gate if (use_pubfh == FALSE) { 1080*0Sstevel@tonic-gate mountversmax = MOUNTVERS_POSIX; 1081*0Sstevel@tonic-gate versmin = MOUNTVERS; 1082*0Sstevel@tonic-gate } 1083*0Sstevel@tonic-gate break; 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate /* 1087*0Sstevel@tonic-gate * Our goal here is to evaluate each of several possible 1088*0Sstevel@tonic-gate * replicas and try to come up with a list we can hand 1089*0Sstevel@tonic-gate * to mount(2). If we don't have a valid "head" at the 1090*0Sstevel@tonic-gate * end of this process, it means we have rejected all 1091*0Sstevel@tonic-gate * potential server:/path tuples. We will fail quietly 1092*0Sstevel@tonic-gate * in front of mount(2), and will have printed errors 1093*0Sstevel@tonic-gate * where we found them. 1094*0Sstevel@tonic-gate * XXX - do option work outside loop w careful design 1095*0Sstevel@tonic-gate * XXX - use macro for error condition free handling 1096*0Sstevel@tonic-gate */ 1097*0Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate /* 1100*0Sstevel@tonic-gate * Initialize retry and delay values on a per-server basis. 1101*0Sstevel@tonic-gate */ 1102*0Sstevel@tonic-gate retries = get_retry(opts); 1103*0Sstevel@tonic-gate delay = INITDELAY; 1104*0Sstevel@tonic-gate retry: 1105*0Sstevel@tonic-gate if (mfs->mfs_ignore) 1106*0Sstevel@tonic-gate continue; 1107*0Sstevel@tonic-gate 1108*0Sstevel@tonic-gate /* 1109*0Sstevel@tonic-gate * If we don't have a fh yet, and if this is not a replicated 1110*0Sstevel@tonic-gate * mount, we haven't done a pingnfs() on the next entry, 1111*0Sstevel@tonic-gate * so we don't know if the next entry is up or if it 1112*0Sstevel@tonic-gate * supports an NFS version we like. So if we had a problem 1113*0Sstevel@tonic-gate * with an entry, we need to go back and run through some new 1114*0Sstevel@tonic-gate * code. 1115*0Sstevel@tonic-gate */ 1116*0Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 && 1117*0Sstevel@tonic-gate !replicated && skipentry) 1118*0Sstevel@tonic-gate goto nextentry; 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate vers = mountversmax; 1121*0Sstevel@tonic-gate host = mfs->mfs_host; 1122*0Sstevel@tonic-gate dir = mfs->mfs_dir; 1123*0Sstevel@tonic-gate (void) sprintf(remname, "%s:%s", host, dir); 1124*0Sstevel@tonic-gate if (trace > 4 && replicated) 1125*0Sstevel@tonic-gate trace_prt(1, " nfsmount: examining %s\n", remname); 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate /* 1128*0Sstevel@tonic-gate * If it's cached we need to get cachefs to mount it. 1129*0Sstevel@tonic-gate */ 1130*0Sstevel@tonic-gate if (cached) { 1131*0Sstevel@tonic-gate char *copts = opts; 1132*0Sstevel@tonic-gate 1133*0Sstevel@tonic-gate /* 1134*0Sstevel@tonic-gate * If we started with a URL we need to turn on 1135*0Sstevel@tonic-gate * -o public if not on already 1136*0Sstevel@tonic-gate */ 1137*0Sstevel@tonic-gate if (use_pubfh == FALSE && 1138*0Sstevel@tonic-gate (mfs->mfs_flags & MFS_FH_VIA_WEBNFS)) { 1139*0Sstevel@tonic-gate 1140*0Sstevel@tonic-gate copts = malloc(strlen(opts) + 1141*0Sstevel@tonic-gate strlen(",public")+1); 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate if (copts == NULL) { 1144*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 1145*0Sstevel@tonic-gate last_error = NFSERR_IO; 1146*0Sstevel@tonic-gate goto out; 1147*0Sstevel@tonic-gate } 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate strcpy(copts, opts); 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate if (strlen(copts) != 0) 1152*0Sstevel@tonic-gate strcat(copts, ","); 1153*0Sstevel@tonic-gate 1154*0Sstevel@tonic-gate strcat(copts, "public"); 1155*0Sstevel@tonic-gate } 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate last_error = mount_generic(remname, MNTTYPE_CACHEFS, 1158*0Sstevel@tonic-gate copts, mntpnt, overlay); 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate if (copts != opts) 1161*0Sstevel@tonic-gate free(copts); 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate if (last_error) { 1164*0Sstevel@tonic-gate skipentry = 1; 1165*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1166*0Sstevel@tonic-gate continue; 1167*0Sstevel@tonic-gate } 1168*0Sstevel@tonic-gate goto out; 1169*0Sstevel@tonic-gate } 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate if (mfs->mfs_args == NULL) { 1172*0Sstevel@tonic-gate 1173*0Sstevel@tonic-gate /* 1174*0Sstevel@tonic-gate * Allocate nfs_args structure 1175*0Sstevel@tonic-gate */ 1176*0Sstevel@tonic-gate argp = (struct nfs_args *) 1177*0Sstevel@tonic-gate malloc(sizeof (struct nfs_args)); 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate if (!argp) { 1180*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 1181*0Sstevel@tonic-gate last_error = NFSERR_IO; 1182*0Sstevel@tonic-gate goto out; 1183*0Sstevel@tonic-gate } 1184*0Sstevel@tonic-gate 1185*0Sstevel@tonic-gate (void) memset(argp, 0, sizeof (*argp)); 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate /* 1188*0Sstevel@tonic-gate * RDMA support 1189*0Sstevel@tonic-gate * By now Mount argument struct has been allocated, 1190*0Sstevel@tonic-gate * either a pub_fh path will be taken or the regular 1191*0Sstevel@tonic-gate * one. So here if a protocol was specified and it 1192*0Sstevel@tonic-gate * was not rdma we let it be, else we set DO_RDMA. 1193*0Sstevel@tonic-gate * If no proto was there we advise on trying RDMA. 1194*0Sstevel@tonic-gate */ 1195*0Sstevel@tonic-gate if (nfs_proto) { 1196*0Sstevel@tonic-gate if (strcmp(nfs_proto, "rdma") == 0) { 1197*0Sstevel@tonic-gate free(nfs_proto); 1198*0Sstevel@tonic-gate nfs_proto = NULL; 1199*0Sstevel@tonic-gate argp->flags |= NFSMNT_DORDMA; 1200*0Sstevel@tonic-gate } 1201*0Sstevel@tonic-gate } else 1202*0Sstevel@tonic-gate argp->flags |= NFSMNT_TRYRDMA; 1203*0Sstevel@tonic-gate } else { 1204*0Sstevel@tonic-gate argp = mfs->mfs_args; 1205*0Sstevel@tonic-gate mfs->mfs_args = NULL; 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate /* 1208*0Sstevel@tonic-gate * Skip entry if we already have file handle but the 1209*0Sstevel@tonic-gate * NFS version is wrong. 1210*0Sstevel@tonic-gate */ 1211*0Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) && 1212*0Sstevel@tonic-gate mfs->mfs_version != nfsvers) { 1213*0Sstevel@tonic-gate 1214*0Sstevel@tonic-gate free(argp); 1215*0Sstevel@tonic-gate skipentry = 1; 1216*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1217*0Sstevel@tonic-gate continue; 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate 1221*0Sstevel@tonic-gate prevhead = head; 1222*0Sstevel@tonic-gate prevtail = tail; 1223*0Sstevel@tonic-gate if (!head) 1224*0Sstevel@tonic-gate head = tail = argp; 1225*0Sstevel@tonic-gate else 1226*0Sstevel@tonic-gate tail = tail->nfs_ext_u.nfs_extB.next = argp; 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate /* 1229*0Sstevel@tonic-gate * WebNFS and NFSv4 behave similarly in that they 1230*0Sstevel@tonic-gate * don't use the mount protocol. Therefore, avoid 1231*0Sstevel@tonic-gate * mount protocol like things when version 4 is being 1232*0Sstevel@tonic-gate * used. 1233*0Sstevel@tonic-gate */ 1234*0Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 && 1235*0Sstevel@tonic-gate nfsvers != NFS_V4) { 1236*0Sstevel@tonic-gate timeout.tv_usec = 0; 1237*0Sstevel@tonic-gate timeout.tv_sec = rpc_timeout; 1238*0Sstevel@tonic-gate rpc_stat = RPC_TIMEDOUT; 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate /* Create the client handle. */ 1241*0Sstevel@tonic-gate 1242*0Sstevel@tonic-gate if (trace > 1) { 1243*0Sstevel@tonic-gate trace_prt(1, " nfsmount: Get mount version: request " 1244*0Sstevel@tonic-gate "vers=%d min=%d\n", vers, versmin); 1245*0Sstevel@tonic-gate } 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate while ((cl = clnt_create_vers(host, MOUNTPROG, &outvers, 1248*0Sstevel@tonic-gate versmin, vers, "udp")) == NULL) { 1249*0Sstevel@tonic-gate if (trace > 4) { 1250*0Sstevel@tonic-gate trace_prt(1, 1251*0Sstevel@tonic-gate " nfsmount: Can't get mount version: rpcerr=%d\n", 1252*0Sstevel@tonic-gate rpc_createerr.cf_stat); 1253*0Sstevel@tonic-gate } 1254*0Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST || 1255*0Sstevel@tonic-gate rpc_createerr.cf_stat == RPC_TIMEDOUT) 1256*0Sstevel@tonic-gate break; 1257*0Sstevel@tonic-gate 1258*0Sstevel@tonic-gate /* 1259*0Sstevel@tonic-gate * backoff and return lower version to retry the ping. 1260*0Sstevel@tonic-gate * XXX we should be more careful and handle 1261*0Sstevel@tonic-gate * RPC_PROGVERSMISMATCH here, because that error 1262*0Sstevel@tonic-gate * is handled in clnt_create_vers(). It's not done to 1263*0Sstevel@tonic-gate * stay in sync with the nfs mount command. 1264*0Sstevel@tonic-gate */ 1265*0Sstevel@tonic-gate vers--; 1266*0Sstevel@tonic-gate if (vers < versmin) 1267*0Sstevel@tonic-gate break; 1268*0Sstevel@tonic-gate if (trace > 4) { 1269*0Sstevel@tonic-gate trace_prt(1, " nfsmount: Try version=%d\n", vers); 1270*0Sstevel@tonic-gate } 1271*0Sstevel@tonic-gate } 1272*0Sstevel@tonic-gate 1273*0Sstevel@tonic-gate if (cl == NULL) { 1274*0Sstevel@tonic-gate free(argp); 1275*0Sstevel@tonic-gate head = prevhead; 1276*0Sstevel@tonic-gate tail = prevtail; 1277*0Sstevel@tonic-gate if (tail) 1278*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1279*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate if (rpc_createerr.cf_stat != RPC_UNKNOWNHOST && 1282*0Sstevel@tonic-gate rpc_createerr.cf_stat != RPC_PROGVERSMISMATCH && 1283*0Sstevel@tonic-gate retries-- > 0) { 1284*0Sstevel@tonic-gate DELAY(delay) 1285*0Sstevel@tonic-gate goto retry; 1286*0Sstevel@tonic-gate } 1287*0Sstevel@tonic-gate 1288*0Sstevel@tonic-gate syslog(loglevel, "%s %s", host, 1289*0Sstevel@tonic-gate clnt_spcreateerror("server not responding")); 1290*0Sstevel@tonic-gate skipentry = 1; 1291*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1292*0Sstevel@tonic-gate continue; 1293*0Sstevel@tonic-gate } 1294*0Sstevel@tonic-gate if (trace > 1) { 1295*0Sstevel@tonic-gate trace_prt(1, " nfsmount: mount version=%d\n", outvers); 1296*0Sstevel@tonic-gate } 1297*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 1298*0Sstevel@tonic-gate add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__); 1299*0Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 1300*0Sstevel@tonic-gate __FILE__, __LINE__); 1301*0Sstevel@tonic-gate #endif 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate if (__clnt_bindresvport(cl) < 0) { 1304*0Sstevel@tonic-gate free(argp); 1305*0Sstevel@tonic-gate head = prevhead; 1306*0Sstevel@tonic-gate tail = prevtail; 1307*0Sstevel@tonic-gate if (tail) 1308*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1309*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1310*0Sstevel@tonic-gate 1311*0Sstevel@tonic-gate if (retries-- > 0) { 1312*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1313*0Sstevel@tonic-gate DELAY(delay); 1314*0Sstevel@tonic-gate goto retry; 1315*0Sstevel@tonic-gate } 1316*0Sstevel@tonic-gate 1317*0Sstevel@tonic-gate syslog(loglevel, "mount %s: %s", host, 1318*0Sstevel@tonic-gate "Couldn't bind to reserved port"); 1319*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1320*0Sstevel@tonic-gate skipentry = 1; 1321*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1322*0Sstevel@tonic-gate continue; 1323*0Sstevel@tonic-gate } 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 1326*0Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, __FILE__, __LINE__); 1327*0Sstevel@tonic-gate #endif 1328*0Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 1329*0Sstevel@tonic-gate if ((cl->cl_auth = authsys_create_default()) == NULL) { 1330*0Sstevel@tonic-gate free(argp); 1331*0Sstevel@tonic-gate head = prevhead; 1332*0Sstevel@tonic-gate tail = prevtail; 1333*0Sstevel@tonic-gate if (tail) 1334*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1335*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate if (retries-- > 0) { 1338*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1339*0Sstevel@tonic-gate DELAY(delay); 1340*0Sstevel@tonic-gate goto retry; 1341*0Sstevel@tonic-gate } 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate syslog(loglevel, "mount %s: %s", host, 1344*0Sstevel@tonic-gate "Failed creating default auth handle"); 1345*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1346*0Sstevel@tonic-gate skipentry = 1; 1347*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1348*0Sstevel@tonic-gate continue; 1349*0Sstevel@tonic-gate } 1350*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 1351*0Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 1352*0Sstevel@tonic-gate __FILE__, __LINE__); 1353*0Sstevel@tonic-gate #endif 1354*0Sstevel@tonic-gate } else 1355*0Sstevel@tonic-gate cl = NULL; 1356*0Sstevel@tonic-gate 1357*0Sstevel@tonic-gate /* 1358*0Sstevel@tonic-gate * set security options 1359*0Sstevel@tonic-gate */ 1360*0Sstevel@tonic-gate sec_opt = 0; 1361*0Sstevel@tonic-gate (void) memset(&nfs_sec, 0, sizeof (nfs_sec)); 1362*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_SECURE) != NULL) { 1363*0Sstevel@tonic-gate if (++sec_opt > 1) { 1364*0Sstevel@tonic-gate syslog(loglevel, 1365*0Sstevel@tonic-gate "conflicting security options for %s", 1366*0Sstevel@tonic-gate remname); 1367*0Sstevel@tonic-gate free(argp); 1368*0Sstevel@tonic-gate head = prevhead; 1369*0Sstevel@tonic-gate tail = prevtail; 1370*0Sstevel@tonic-gate if (tail) 1371*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1372*0Sstevel@tonic-gate last_error = NFSERR_IO; 1373*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1374*0Sstevel@tonic-gate skipentry = 1; 1375*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1376*0Sstevel@tonic-gate continue; 1377*0Sstevel@tonic-gate } 1378*0Sstevel@tonic-gate if (nfs_getseconfig_byname("dh", &nfs_sec)) { 1379*0Sstevel@tonic-gate syslog(loglevel, 1380*0Sstevel@tonic-gate "error getting dh information from %s", 1381*0Sstevel@tonic-gate NFSSEC_CONF); 1382*0Sstevel@tonic-gate free(argp); 1383*0Sstevel@tonic-gate head = prevhead; 1384*0Sstevel@tonic-gate tail = prevtail; 1385*0Sstevel@tonic-gate if (tail) 1386*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1387*0Sstevel@tonic-gate last_error = NFSERR_IO; 1388*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1389*0Sstevel@tonic-gate skipentry = 1; 1390*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1391*0Sstevel@tonic-gate continue; 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate } 1394*0Sstevel@tonic-gate 1395*0Sstevel@tonic-gate nfs_flavor = NULL; 1396*0Sstevel@tonic-gate /* 1397*0Sstevel@tonic-gate * Have to workaround the fact that hasmntopt() returns true 1398*0Sstevel@tonic-gate * when comparing "secure" (in &m) with "sec". 1399*0Sstevel@tonic-gate */ 1400*0Sstevel@tonic-gate if (hasmntopt(&m, "sec=") != NULL) { 1401*0Sstevel@tonic-gate if ((str_opt(&m, MNTOPT_SEC, &nfs_flavor)) == -1) { 1402*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 1403*0Sstevel@tonic-gate last_error = NFSERR_IO; 1404*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1405*0Sstevel@tonic-gate goto out; 1406*0Sstevel@tonic-gate } 1407*0Sstevel@tonic-gate } 1408*0Sstevel@tonic-gate 1409*0Sstevel@tonic-gate if (nfs_flavor) { 1410*0Sstevel@tonic-gate if (++sec_opt > 1) { 1411*0Sstevel@tonic-gate syslog(loglevel, 1412*0Sstevel@tonic-gate "conflicting security options for %s", 1413*0Sstevel@tonic-gate remname); 1414*0Sstevel@tonic-gate free(nfs_flavor); 1415*0Sstevel@tonic-gate free(argp); 1416*0Sstevel@tonic-gate head = prevhead; 1417*0Sstevel@tonic-gate tail = prevtail; 1418*0Sstevel@tonic-gate if (tail) 1419*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1420*0Sstevel@tonic-gate last_error = NFSERR_IO; 1421*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1422*0Sstevel@tonic-gate skipentry = 1; 1423*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1424*0Sstevel@tonic-gate continue; 1425*0Sstevel@tonic-gate } 1426*0Sstevel@tonic-gate if (nfs_getseconfig_byname(nfs_flavor, &nfs_sec)) { 1427*0Sstevel@tonic-gate syslog(loglevel, 1428*0Sstevel@tonic-gate "error getting %s information from %s", 1429*0Sstevel@tonic-gate nfs_flavor, NFSSEC_CONF); 1430*0Sstevel@tonic-gate free(nfs_flavor); 1431*0Sstevel@tonic-gate free(argp); 1432*0Sstevel@tonic-gate head = prevhead; 1433*0Sstevel@tonic-gate tail = prevtail; 1434*0Sstevel@tonic-gate if (tail) 1435*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1436*0Sstevel@tonic-gate last_error = NFSERR_IO; 1437*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1438*0Sstevel@tonic-gate skipentry = 1; 1439*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1440*0Sstevel@tonic-gate continue; 1441*0Sstevel@tonic-gate } 1442*0Sstevel@tonic-gate free(nfs_flavor); 1443*0Sstevel@tonic-gate } 1444*0Sstevel@tonic-gate 1445*0Sstevel@tonic-gate posix = (nfsvers != NFS_V4 && 1446*0Sstevel@tonic-gate hasmntopt(&m, MNTOPT_POSIX) != NULL) ? 1 : 0; 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 && 1449*0Sstevel@tonic-gate nfsvers != NFS_V4) { 1450*0Sstevel@tonic-gate bool_t give_up_on_mnt; 1451*0Sstevel@tonic-gate bool_t got_mnt_error; 1452*0Sstevel@tonic-gate /* 1453*0Sstevel@tonic-gate * If we started with a URL, if first byte of path is not "/", 1454*0Sstevel@tonic-gate * then the mount will likely fail, so we should try again 1455*0Sstevel@tonic-gate * with a prepended "/". 1456*0Sstevel@tonic-gate */ 1457*0Sstevel@tonic-gate if (mfs->mfs_flags & MFS_ALLOC_DIR && *dir != '/') 1458*0Sstevel@tonic-gate give_up_on_mnt = FALSE; 1459*0Sstevel@tonic-gate else 1460*0Sstevel@tonic-gate give_up_on_mnt = TRUE; 1461*0Sstevel@tonic-gate 1462*0Sstevel@tonic-gate got_mnt_error = FALSE; 1463*0Sstevel@tonic-gate 1464*0Sstevel@tonic-gate try_mnt_slash: 1465*0Sstevel@tonic-gate if (got_mnt_error == TRUE) { 1466*0Sstevel@tonic-gate int i, l; 1467*0Sstevel@tonic-gate 1468*0Sstevel@tonic-gate give_up_on_mnt = TRUE; 1469*0Sstevel@tonic-gate l = strlen(dir); 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate /* 1472*0Sstevel@tonic-gate * Insert a "/" to front of mfs_dir. 1473*0Sstevel@tonic-gate */ 1474*0Sstevel@tonic-gate for (i = l; i > 0; i--) 1475*0Sstevel@tonic-gate dir[i] = dir[i-1]; 1476*0Sstevel@tonic-gate 1477*0Sstevel@tonic-gate dir[0] = '/'; 1478*0Sstevel@tonic-gate } 1479*0Sstevel@tonic-gate 1480*0Sstevel@tonic-gate /* Get fhandle of remote path from server's mountd */ 1481*0Sstevel@tonic-gate 1482*0Sstevel@tonic-gate switch (outvers) { 1483*0Sstevel@tonic-gate case MOUNTVERS: 1484*0Sstevel@tonic-gate if (posix) { 1485*0Sstevel@tonic-gate free(argp); 1486*0Sstevel@tonic-gate head = prevhead; 1487*0Sstevel@tonic-gate tail = prevtail; 1488*0Sstevel@tonic-gate if (tail) 1489*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1490*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1491*0Sstevel@tonic-gate syslog(loglevel, "can't get posix info for %s", 1492*0Sstevel@tonic-gate host); 1493*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1494*0Sstevel@tonic-gate skipentry = 1; 1495*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1496*0Sstevel@tonic-gate continue; 1497*0Sstevel@tonic-gate } 1498*0Sstevel@tonic-gate /* FALLTHRU */ 1499*0Sstevel@tonic-gate case MOUNTVERS_POSIX: 1500*0Sstevel@tonic-gate if (nfsvers == NFS_V3) { 1501*0Sstevel@tonic-gate free(argp); 1502*0Sstevel@tonic-gate head = prevhead; 1503*0Sstevel@tonic-gate tail = prevtail; 1504*0Sstevel@tonic-gate if (tail) 1505*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1506*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1507*0Sstevel@tonic-gate syslog(loglevel, 1508*0Sstevel@tonic-gate "%s doesn't support NFS Version 3", 1509*0Sstevel@tonic-gate host); 1510*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1511*0Sstevel@tonic-gate skipentry = 1; 1512*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1513*0Sstevel@tonic-gate continue; 1514*0Sstevel@tonic-gate } 1515*0Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, 1516*0Sstevel@tonic-gate xdr_dirpath, (caddr_t)&dir, 1517*0Sstevel@tonic-gate xdr_fhstatus, (caddr_t)&fhs, timeout); 1518*0Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 1519*0Sstevel@tonic-gate 1520*0Sstevel@tonic-gate if (give_up_on_mnt == FALSE) { 1521*0Sstevel@tonic-gate got_mnt_error = TRUE; 1522*0Sstevel@tonic-gate goto try_mnt_slash; 1523*0Sstevel@tonic-gate } 1524*0Sstevel@tonic-gate 1525*0Sstevel@tonic-gate /* 1526*0Sstevel@tonic-gate * Given the way "clnt_sperror" works, the "%s" 1527*0Sstevel@tonic-gate * immediately following the "not responding" 1528*0Sstevel@tonic-gate * is correct. 1529*0Sstevel@tonic-gate */ 1530*0Sstevel@tonic-gate free(argp); 1531*0Sstevel@tonic-gate head = prevhead; 1532*0Sstevel@tonic-gate tail = prevtail; 1533*0Sstevel@tonic-gate if (tail) 1534*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1535*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1536*0Sstevel@tonic-gate 1537*0Sstevel@tonic-gate if (retries-- > 0) { 1538*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1539*0Sstevel@tonic-gate DELAY(delay); 1540*0Sstevel@tonic-gate goto retry; 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate 1543*0Sstevel@tonic-gate if (trace > 3) { 1544*0Sstevel@tonic-gate trace_prt(1, 1545*0Sstevel@tonic-gate " nfsmount: mount RPC failed for %s\n", 1546*0Sstevel@tonic-gate host); 1547*0Sstevel@tonic-gate } 1548*0Sstevel@tonic-gate syslog(loglevel, "%s server not responding%s", 1549*0Sstevel@tonic-gate host, clnt_sperror(cl, "")); 1550*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1551*0Sstevel@tonic-gate skipentry = 1; 1552*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1553*0Sstevel@tonic-gate continue; 1554*0Sstevel@tonic-gate } 1555*0Sstevel@tonic-gate if ((errno = fhs.fhs_status) != MNT_OK) { 1556*0Sstevel@tonic-gate 1557*0Sstevel@tonic-gate if (give_up_on_mnt == FALSE) { 1558*0Sstevel@tonic-gate got_mnt_error = TRUE; 1559*0Sstevel@tonic-gate goto try_mnt_slash; 1560*0Sstevel@tonic-gate } 1561*0Sstevel@tonic-gate 1562*0Sstevel@tonic-gate free(argp); 1563*0Sstevel@tonic-gate head = prevhead; 1564*0Sstevel@tonic-gate tail = prevtail; 1565*0Sstevel@tonic-gate if (tail) 1566*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1567*0Sstevel@tonic-gate if (errno == EACCES) { 1568*0Sstevel@tonic-gate status = NFSERR_ACCES; 1569*0Sstevel@tonic-gate } else { 1570*0Sstevel@tonic-gate syslog(loglevel, "%s: %m", host); 1571*0Sstevel@tonic-gate status = NFSERR_IO; 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate if (trace > 3) { 1574*0Sstevel@tonic-gate trace_prt(1, " nfsmount: mount RPC gave" 1575*0Sstevel@tonic-gate " %d for %s:%s\n", 1576*0Sstevel@tonic-gate errno, host, dir); 1577*0Sstevel@tonic-gate } 1578*0Sstevel@tonic-gate last_error = status; 1579*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1580*0Sstevel@tonic-gate skipentry = 1; 1581*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1582*0Sstevel@tonic-gate continue; 1583*0Sstevel@tonic-gate } 1584*0Sstevel@tonic-gate argp->fh = malloc((sizeof (fhandle))); 1585*0Sstevel@tonic-gate if (!argp->fh) { 1586*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 1587*0Sstevel@tonic-gate last_error = NFSERR_IO; 1588*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1589*0Sstevel@tonic-gate goto out; 1590*0Sstevel@tonic-gate } 1591*0Sstevel@tonic-gate (void) memcpy(argp->fh, &fhs.fhstatus_u.fhs_fhandle, 1592*0Sstevel@tonic-gate sizeof (fhandle)); 1593*0Sstevel@tonic-gate break; 1594*0Sstevel@tonic-gate case MOUNTVERS3: 1595*0Sstevel@tonic-gate posix = 0; 1596*0Sstevel@tonic-gate (void) memset((char *)&res3, '\0', sizeof (res3)); 1597*0Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_MNT, 1598*0Sstevel@tonic-gate xdr_dirpath, (caddr_t)&dir, 1599*0Sstevel@tonic-gate xdr_mountres3, (caddr_t)&res3, timeout); 1600*0Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 1601*0Sstevel@tonic-gate 1602*0Sstevel@tonic-gate if (give_up_on_mnt == FALSE) { 1603*0Sstevel@tonic-gate got_mnt_error = TRUE; 1604*0Sstevel@tonic-gate goto try_mnt_slash; 1605*0Sstevel@tonic-gate } 1606*0Sstevel@tonic-gate 1607*0Sstevel@tonic-gate /* 1608*0Sstevel@tonic-gate * Given the way "clnt_sperror" works, the "%s" 1609*0Sstevel@tonic-gate * immediately following the "not responding" 1610*0Sstevel@tonic-gate * is correct. 1611*0Sstevel@tonic-gate */ 1612*0Sstevel@tonic-gate free(argp); 1613*0Sstevel@tonic-gate head = prevhead; 1614*0Sstevel@tonic-gate tail = prevtail; 1615*0Sstevel@tonic-gate if (tail) 1616*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1617*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1618*0Sstevel@tonic-gate 1619*0Sstevel@tonic-gate if (retries-- > 0) { 1620*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1621*0Sstevel@tonic-gate DELAY(delay); 1622*0Sstevel@tonic-gate goto retry; 1623*0Sstevel@tonic-gate } 1624*0Sstevel@tonic-gate 1625*0Sstevel@tonic-gate if (trace > 3) { 1626*0Sstevel@tonic-gate trace_prt(1, 1627*0Sstevel@tonic-gate " nfsmount: mount RPC failed for %s\n", 1628*0Sstevel@tonic-gate host); 1629*0Sstevel@tonic-gate } 1630*0Sstevel@tonic-gate syslog(loglevel, "%s server not responding%s", 1631*0Sstevel@tonic-gate remname, clnt_sperror(cl, "")); 1632*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1633*0Sstevel@tonic-gate skipentry = 1; 1634*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1635*0Sstevel@tonic-gate continue; 1636*0Sstevel@tonic-gate } 1637*0Sstevel@tonic-gate if ((errno = res3.fhs_status) != MNT_OK) { 1638*0Sstevel@tonic-gate 1639*0Sstevel@tonic-gate if (give_up_on_mnt == FALSE) { 1640*0Sstevel@tonic-gate got_mnt_error = TRUE; 1641*0Sstevel@tonic-gate goto try_mnt_slash; 1642*0Sstevel@tonic-gate } 1643*0Sstevel@tonic-gate 1644*0Sstevel@tonic-gate free(argp); 1645*0Sstevel@tonic-gate head = prevhead; 1646*0Sstevel@tonic-gate tail = prevtail; 1647*0Sstevel@tonic-gate if (tail) 1648*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1649*0Sstevel@tonic-gate if (errno == EACCES) { 1650*0Sstevel@tonic-gate status = NFSERR_ACCES; 1651*0Sstevel@tonic-gate } else { 1652*0Sstevel@tonic-gate syslog(loglevel, "%s: %m", remname); 1653*0Sstevel@tonic-gate status = NFSERR_IO; 1654*0Sstevel@tonic-gate } 1655*0Sstevel@tonic-gate if (trace > 3) { 1656*0Sstevel@tonic-gate trace_prt(1, " nfsmount: mount RPC gave" 1657*0Sstevel@tonic-gate " %d for %s:%s\n", 1658*0Sstevel@tonic-gate errno, host, dir); 1659*0Sstevel@tonic-gate } 1660*0Sstevel@tonic-gate last_error = status; 1661*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1662*0Sstevel@tonic-gate skipentry = 1; 1663*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1664*0Sstevel@tonic-gate continue; 1665*0Sstevel@tonic-gate } 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate /* 1668*0Sstevel@tonic-gate * Negotiate the security flavor for nfs_mount 1669*0Sstevel@tonic-gate */ 1670*0Sstevel@tonic-gate auths = 1671*0Sstevel@tonic-gate res3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val; 1672*0Sstevel@tonic-gate count = 1673*0Sstevel@tonic-gate res3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len; 1674*0Sstevel@tonic-gate 1675*0Sstevel@tonic-gate if (sec_opt) { 1676*0Sstevel@tonic-gate for (i = 0; i < count; i++) 1677*0Sstevel@tonic-gate if (auths[i] == nfs_sec.sc_nfsnum) { 1678*0Sstevel@tonic-gate break; 1679*0Sstevel@tonic-gate } 1680*0Sstevel@tonic-gate if (i >= count) { 1681*0Sstevel@tonic-gate syslog(LOG_ERR, 1682*0Sstevel@tonic-gate "%s: does not support security \"%s\"\n", 1683*0Sstevel@tonic-gate remname, nfs_sec.sc_name); 1684*0Sstevel@tonic-gate clnt_freeres(cl, xdr_mountres3, 1685*0Sstevel@tonic-gate (caddr_t)&res3); 1686*0Sstevel@tonic-gate free(argp); 1687*0Sstevel@tonic-gate head = prevhead; 1688*0Sstevel@tonic-gate tail = prevtail; 1689*0Sstevel@tonic-gate if (tail) 1690*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1691*0Sstevel@tonic-gate last_error = NFSERR_IO; 1692*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1693*0Sstevel@tonic-gate skipentry = 1; 1694*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1695*0Sstevel@tonic-gate continue; 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate } else { 1698*0Sstevel@tonic-gate if (count > 0) { 1699*0Sstevel@tonic-gate for (i = 0; i < count; i++) { 1700*0Sstevel@tonic-gate if (!(scerror = 1701*0Sstevel@tonic-gate nfs_getseconfig_bynumber(auths[i], &nfs_sec))) { 1702*0Sstevel@tonic-gate sec_opt++; 1703*0Sstevel@tonic-gate break; 1704*0Sstevel@tonic-gate } 1705*0Sstevel@tonic-gate } 1706*0Sstevel@tonic-gate if (i >= count) { 1707*0Sstevel@tonic-gate if (nfs_syslog_scerr(scerror, 1708*0Sstevel@tonic-gate scerror_msg) 1709*0Sstevel@tonic-gate != -1) { 1710*0Sstevel@tonic-gate syslog(LOG_ERR, 1711*0Sstevel@tonic-gate "%s cannot be mounted because it is shared with " 1712*0Sstevel@tonic-gate "security flavor %d which %s", 1713*0Sstevel@tonic-gate remname, 1714*0Sstevel@tonic-gate auths[i-1], 1715*0Sstevel@tonic-gate scerror_msg); 1716*0Sstevel@tonic-gate } 1717*0Sstevel@tonic-gate clnt_freeres(cl, xdr_mountres3, 1718*0Sstevel@tonic-gate (caddr_t)&res3); 1719*0Sstevel@tonic-gate free(argp); 1720*0Sstevel@tonic-gate head = prevhead; 1721*0Sstevel@tonic-gate tail = prevtail; 1722*0Sstevel@tonic-gate if (tail) 1723*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1724*0Sstevel@tonic-gate last_error = NFSERR_IO; 1725*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1726*0Sstevel@tonic-gate skipentry = 1; 1727*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1728*0Sstevel@tonic-gate continue; 1729*0Sstevel@tonic-gate } 1730*0Sstevel@tonic-gate } 1731*0Sstevel@tonic-gate } 1732*0Sstevel@tonic-gate 1733*0Sstevel@tonic-gate fh3.fh3_length = 1734*0Sstevel@tonic-gate res3.mountres3_u.mountinfo.fhandle.fhandle3_len; 1735*0Sstevel@tonic-gate (void) memcpy(fh3.fh3_u.data, 1736*0Sstevel@tonic-gate res3.mountres3_u.mountinfo.fhandle.fhandle3_val, 1737*0Sstevel@tonic-gate fh3.fh3_length); 1738*0Sstevel@tonic-gate clnt_freeres(cl, xdr_mountres3, 1739*0Sstevel@tonic-gate (caddr_t)&res3); 1740*0Sstevel@tonic-gate argp->fh = malloc(sizeof (nfs_fh3)); 1741*0Sstevel@tonic-gate if (!argp->fh) { 1742*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 1743*0Sstevel@tonic-gate last_error = NFSERR_IO; 1744*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1745*0Sstevel@tonic-gate goto out; 1746*0Sstevel@tonic-gate } 1747*0Sstevel@tonic-gate (void) memcpy(argp->fh, &fh3, sizeof (nfs_fh3)); 1748*0Sstevel@tonic-gate break; 1749*0Sstevel@tonic-gate default: 1750*0Sstevel@tonic-gate free(argp); 1751*0Sstevel@tonic-gate head = prevhead; 1752*0Sstevel@tonic-gate tail = prevtail; 1753*0Sstevel@tonic-gate if (tail) 1754*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1755*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1756*0Sstevel@tonic-gate syslog(loglevel, "unknown MOUNT version %ld on %s", 1757*0Sstevel@tonic-gate vers, remname); 1758*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1759*0Sstevel@tonic-gate skipentry = 1; 1760*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1761*0Sstevel@tonic-gate continue; 1762*0Sstevel@tonic-gate } /* switch */ 1763*0Sstevel@tonic-gate } 1764*0Sstevel@tonic-gate if (nfsvers == NFS_V4) { 1765*0Sstevel@tonic-gate argp->fh = strdup(dir); 1766*0Sstevel@tonic-gate if (argp->fh == NULL) { 1767*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 1768*0Sstevel@tonic-gate last_error = NFSERR_IO; 1769*0Sstevel@tonic-gate goto out; 1770*0Sstevel@tonic-gate } 1771*0Sstevel@tonic-gate } 1772*0Sstevel@tonic-gate 1773*0Sstevel@tonic-gate if (trace > 4) 1774*0Sstevel@tonic-gate trace_prt(1, " nfsmount: have %s filehandle for %s\n", 1775*0Sstevel@tonic-gate fstype, remname); 1776*0Sstevel@tonic-gate 1777*0Sstevel@tonic-gate argp->flags |= NFSMNT_NEWARGS; 1778*0Sstevel@tonic-gate argp->flags |= NFSMNT_INT; /* default is "intr" */ 1779*0Sstevel@tonic-gate argp->hostname = host; 1780*0Sstevel@tonic-gate argp->flags |= NFSMNT_HOSTNAME; 1781*0Sstevel@tonic-gate 1782*0Sstevel@tonic-gate /* 1783*0Sstevel@tonic-gate * In this case, we want NFSv4 to behave like 1784*0Sstevel@tonic-gate * non-WebNFS so that we get the server address. 1785*0Sstevel@tonic-gate */ 1786*0Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0) { 1787*0Sstevel@tonic-gate nconf = NULL; 1788*0Sstevel@tonic-gate 1789*0Sstevel@tonic-gate if (nfs_port != 0) 1790*0Sstevel@tonic-gate thisport = nfs_port; 1791*0Sstevel@tonic-gate else 1792*0Sstevel@tonic-gate thisport = mfs->mfs_port; 1793*0Sstevel@tonic-gate 1794*0Sstevel@tonic-gate /* 1795*0Sstevel@tonic-gate * For NFSv4, we want to avoid rpcbind, so call 1796*0Sstevel@tonic-gate * get_server_stuff() directly to tell it that 1797*0Sstevel@tonic-gate * we want to go "direct_to_server". Otherwise, 1798*0Sstevel@tonic-gate * do what has always been done. 1799*0Sstevel@tonic-gate */ 1800*0Sstevel@tonic-gate if (nfsvers == NFS_V4) { 1801*0Sstevel@tonic-gate enum clnt_stat cstat; 1802*0Sstevel@tonic-gate argp->addr = get_server_stuff(SERVER_ADDR, 1803*0Sstevel@tonic-gate host, NFS_PROGRAM, nfsvers, NULL, 1804*0Sstevel@tonic-gate &nconf, nfs_proto, thisport, NULL, 1805*0Sstevel@tonic-gate NULL, TRUE, NULL, &cstat); 1806*0Sstevel@tonic-gate } else { 1807*0Sstevel@tonic-gate argp->addr = get_addr(host, NFS_PROGRAM, 1808*0Sstevel@tonic-gate nfsvers, &nconf, nfs_proto, 1809*0Sstevel@tonic-gate thisport, NULL); 1810*0Sstevel@tonic-gate } 1811*0Sstevel@tonic-gate 1812*0Sstevel@tonic-gate if (argp->addr == NULL) { 1813*0Sstevel@tonic-gate free(argp->fh); 1814*0Sstevel@tonic-gate free(argp); 1815*0Sstevel@tonic-gate head = prevhead; 1816*0Sstevel@tonic-gate tail = prevtail; 1817*0Sstevel@tonic-gate if (tail) 1818*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1819*0Sstevel@tonic-gate last_error = NFSERR_NOENT; 1820*0Sstevel@tonic-gate 1821*0Sstevel@tonic-gate if (retries-- > 0) { 1822*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1823*0Sstevel@tonic-gate DELAY(delay); 1824*0Sstevel@tonic-gate goto retry; 1825*0Sstevel@tonic-gate } 1826*0Sstevel@tonic-gate 1827*0Sstevel@tonic-gate syslog(loglevel, "%s: no NFS service", host); 1828*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1829*0Sstevel@tonic-gate skipentry = 1; 1830*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1831*0Sstevel@tonic-gate continue; 1832*0Sstevel@tonic-gate } 1833*0Sstevel@tonic-gate if (trace > 4) 1834*0Sstevel@tonic-gate trace_prt(1, 1835*0Sstevel@tonic-gate "\tnfsmount: have net address for %s\n", 1836*0Sstevel@tonic-gate remname); 1837*0Sstevel@tonic-gate 1838*0Sstevel@tonic-gate } else { 1839*0Sstevel@tonic-gate nconf = mfs->mfs_nconf; 1840*0Sstevel@tonic-gate mfs->mfs_nconf = NULL; 1841*0Sstevel@tonic-gate } 1842*0Sstevel@tonic-gate 1843*0Sstevel@tonic-gate argp->flags |= NFSMNT_KNCONF; 1844*0Sstevel@tonic-gate argp->knconf = get_knconf(nconf); 1845*0Sstevel@tonic-gate if (argp->knconf == NULL) { 1846*0Sstevel@tonic-gate netbuf_free(argp->addr); 1847*0Sstevel@tonic-gate freenetconfigent(nconf); 1848*0Sstevel@tonic-gate free(argp->fh); 1849*0Sstevel@tonic-gate free(argp); 1850*0Sstevel@tonic-gate head = prevhead; 1851*0Sstevel@tonic-gate tail = prevtail; 1852*0Sstevel@tonic-gate if (tail) 1853*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1854*0Sstevel@tonic-gate last_error = NFSERR_NOSPC; 1855*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1856*0Sstevel@tonic-gate skipentry = 1; 1857*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1858*0Sstevel@tonic-gate continue; 1859*0Sstevel@tonic-gate } 1860*0Sstevel@tonic-gate if (trace > 4) 1861*0Sstevel@tonic-gate trace_prt(1, 1862*0Sstevel@tonic-gate "\tnfsmount: have net config for %s\n", 1863*0Sstevel@tonic-gate remname); 1864*0Sstevel@tonic-gate 1865*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_SOFT) != NULL) { 1866*0Sstevel@tonic-gate argp->flags |= NFSMNT_SOFT; 1867*0Sstevel@tonic-gate } 1868*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_NOINTR) != NULL) { 1869*0Sstevel@tonic-gate argp->flags &= ~(NFSMNT_INT); 1870*0Sstevel@tonic-gate } 1871*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_NOAC) != NULL) { 1872*0Sstevel@tonic-gate argp->flags |= NFSMNT_NOAC; 1873*0Sstevel@tonic-gate } 1874*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_NOCTO) != NULL) { 1875*0Sstevel@tonic-gate argp->flags |= NFSMNT_NOCTO; 1876*0Sstevel@tonic-gate } 1877*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_FORCEDIRECTIO) != NULL) { 1878*0Sstevel@tonic-gate argp->flags |= NFSMNT_DIRECTIO; 1879*0Sstevel@tonic-gate } 1880*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_NOFORCEDIRECTIO) != NULL) { 1881*0Sstevel@tonic-gate argp->flags &= ~(NFSMNT_DIRECTIO); 1882*0Sstevel@tonic-gate } 1883*0Sstevel@tonic-gate 1884*0Sstevel@tonic-gate /* 1885*0Sstevel@tonic-gate * Set up security data for argp->nfs_ext_u.nfs_extB.secdata. 1886*0Sstevel@tonic-gate */ 1887*0Sstevel@tonic-gate if (mfssnego.snego_done) { 1888*0Sstevel@tonic-gate memcpy(&nfs_sec, &mfssnego.nfs_sec, 1889*0Sstevel@tonic-gate sizeof (seconfig_t)); 1890*0Sstevel@tonic-gate } else if (!sec_opt) { 1891*0Sstevel@tonic-gate /* 1892*0Sstevel@tonic-gate * Get default security mode. 1893*0Sstevel@tonic-gate */ 1894*0Sstevel@tonic-gate if (nfs_getseconfig_default(&nfs_sec)) { 1895*0Sstevel@tonic-gate syslog(loglevel, 1896*0Sstevel@tonic-gate "error getting default security entry\n"); 1897*0Sstevel@tonic-gate free_knconf(argp->knconf); 1898*0Sstevel@tonic-gate netbuf_free(argp->addr); 1899*0Sstevel@tonic-gate freenetconfigent(nconf); 1900*0Sstevel@tonic-gate free(argp->fh); 1901*0Sstevel@tonic-gate free(argp); 1902*0Sstevel@tonic-gate head = prevhead; 1903*0Sstevel@tonic-gate tail = prevtail; 1904*0Sstevel@tonic-gate if (tail) 1905*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1906*0Sstevel@tonic-gate last_error = NFSERR_NOSPC; 1907*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1908*0Sstevel@tonic-gate skipentry = 1; 1909*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1910*0Sstevel@tonic-gate continue; 1911*0Sstevel@tonic-gate } 1912*0Sstevel@tonic-gate argp->flags |= NFSMNT_SECDEFAULT; 1913*0Sstevel@tonic-gate } 1914*0Sstevel@tonic-gate 1915*0Sstevel@tonic-gate /* 1916*0Sstevel@tonic-gate * For AUTH_DH 1917*0Sstevel@tonic-gate * get the network address for the time service on 1918*0Sstevel@tonic-gate * the server. If an RPC based time service is 1919*0Sstevel@tonic-gate * not available then try the IP time service. 1920*0Sstevel@tonic-gate * 1921*0Sstevel@tonic-gate * Eventurally, we want to move this code to nfs_clnt_secdata() 1922*0Sstevel@tonic-gate * when autod_nfs.c and mount.c can share the same 1923*0Sstevel@tonic-gate * get_the_addr/get_the_stuff routine. 1924*0Sstevel@tonic-gate */ 1925*0Sstevel@tonic-gate secflags = 0; 1926*0Sstevel@tonic-gate syncaddr = NULL; 1927*0Sstevel@tonic-gate retaddrs = NULL; 1928*0Sstevel@tonic-gate 1929*0Sstevel@tonic-gate if (nfs_sec.sc_rpcnum == AUTH_DH || nfsvers == NFS_V4) { 1930*0Sstevel@tonic-gate /* 1931*0Sstevel@tonic-gate * If not using the public fh and not NFS_V4, we can try 1932*0Sstevel@tonic-gate * talking RPCBIND. Otherwise, assume that firewalls 1933*0Sstevel@tonic-gate * prevent us from doing that. 1934*0Sstevel@tonic-gate */ 1935*0Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_FH_VIA_WEBNFS) == 0 && 1936*0Sstevel@tonic-gate nfsvers != NFS_V4) { 1937*0Sstevel@tonic-gate syncaddr = get_the_stuff(SERVER_ADDR, host, RPCBPROG, 1938*0Sstevel@tonic-gate RPCBVERS, NULL, nconf, 0, NULL, NULL, FALSE, 1939*0Sstevel@tonic-gate NULL, NULL); 1940*0Sstevel@tonic-gate } 1941*0Sstevel@tonic-gate 1942*0Sstevel@tonic-gate if (syncaddr != NULL) { 1943*0Sstevel@tonic-gate /* for flags in sec_data */ 1944*0Sstevel@tonic-gate secflags |= AUTH_F_RPCTIMESYNC; 1945*0Sstevel@tonic-gate } else { 1946*0Sstevel@tonic-gate struct nd_hostserv hs; 1947*0Sstevel@tonic-gate int error; 1948*0Sstevel@tonic-gate 1949*0Sstevel@tonic-gate hs.h_host = host; 1950*0Sstevel@tonic-gate hs.h_serv = "timserver"; 1951*0Sstevel@tonic-gate error = netdir_getbyname(nconf, &hs, &retaddrs); 1952*0Sstevel@tonic-gate 1953*0Sstevel@tonic-gate if (error != ND_OK && nfs_sec.sc_rpcnum == AUTH_DH) { 1954*0Sstevel@tonic-gate syslog(loglevel, 1955*0Sstevel@tonic-gate "%s: secure: no time service\n", host); 1956*0Sstevel@tonic-gate free_knconf(argp->knconf); 1957*0Sstevel@tonic-gate netbuf_free(argp->addr); 1958*0Sstevel@tonic-gate freenetconfigent(nconf); 1959*0Sstevel@tonic-gate free(argp->fh); 1960*0Sstevel@tonic-gate free(argp); 1961*0Sstevel@tonic-gate head = prevhead; 1962*0Sstevel@tonic-gate tail = prevtail; 1963*0Sstevel@tonic-gate if (tail) 1964*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 1965*0Sstevel@tonic-gate last_error = NFSERR_IO; 1966*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 1967*0Sstevel@tonic-gate skipentry = 1; 1968*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 1969*0Sstevel@tonic-gate continue; 1970*0Sstevel@tonic-gate } 1971*0Sstevel@tonic-gate 1972*0Sstevel@tonic-gate if (error == ND_OK) 1973*0Sstevel@tonic-gate syncaddr = retaddrs->n_addrs; 1974*0Sstevel@tonic-gate 1975*0Sstevel@tonic-gate /* 1976*0Sstevel@tonic-gate * For potential usage by NFS V4 when AUTH_DH 1977*0Sstevel@tonic-gate * is negotiated via SECINFO in the kernel. 1978*0Sstevel@tonic-gate */ 1979*0Sstevel@tonic-gate if (nfsvers == NFS_V4 && syncaddr && 1980*0Sstevel@tonic-gate host2netname(netname, host, NULL)) { 1981*0Sstevel@tonic-gate argp->syncaddr = malloc(sizeof (struct netbuf)); 1982*0Sstevel@tonic-gate argp->syncaddr->buf = malloc(syncaddr->len); 1983*0Sstevel@tonic-gate (void) memcpy(argp->syncaddr->buf, 1984*0Sstevel@tonic-gate syncaddr->buf, syncaddr->len); 1985*0Sstevel@tonic-gate argp->syncaddr->len = syncaddr->len; 1986*0Sstevel@tonic-gate argp->syncaddr->maxlen = syncaddr->maxlen; 1987*0Sstevel@tonic-gate argp->netname = strdup(netname); 1988*0Sstevel@tonic-gate argp->flags |= NFSMNT_SECURE; 1989*0Sstevel@tonic-gate } 1990*0Sstevel@tonic-gate } /* syncaddr */ 1991*0Sstevel@tonic-gate } /* AUTH_DH */ 1992*0Sstevel@tonic-gate 1993*0Sstevel@tonic-gate nfs_sec.sc_uid = cred->aup_uid; 1994*0Sstevel@tonic-gate /* 1995*0Sstevel@tonic-gate * If AUTH_DH is a chosen flavor now, its data will be stored 1996*0Sstevel@tonic-gate * in the sec_data structure via nfs_clnt_secdata(). 1997*0Sstevel@tonic-gate */ 1998*0Sstevel@tonic-gate if (!(secdata = nfs_clnt_secdata(&nfs_sec, host, argp->knconf, 1999*0Sstevel@tonic-gate syncaddr, secflags))) { 2000*0Sstevel@tonic-gate syslog(LOG_ERR, 2001*0Sstevel@tonic-gate "errors constructing security related data\n"); 2002*0Sstevel@tonic-gate if (secflags & AUTH_F_RPCTIMESYNC) 2003*0Sstevel@tonic-gate netbuf_free(syncaddr); 2004*0Sstevel@tonic-gate else if (retaddrs) 2005*0Sstevel@tonic-gate netdir_free(retaddrs, ND_ADDRLIST); 2006*0Sstevel@tonic-gate if (argp->syncaddr) 2007*0Sstevel@tonic-gate netbuf_free(argp->syncaddr); 2008*0Sstevel@tonic-gate if (argp->netname) 2009*0Sstevel@tonic-gate free(argp->netname); 2010*0Sstevel@tonic-gate free_knconf(argp->knconf); 2011*0Sstevel@tonic-gate netbuf_free(argp->addr); 2012*0Sstevel@tonic-gate freenetconfigent(nconf); 2013*0Sstevel@tonic-gate free(argp->fh); 2014*0Sstevel@tonic-gate free(argp); 2015*0Sstevel@tonic-gate head = prevhead; 2016*0Sstevel@tonic-gate tail = prevtail; 2017*0Sstevel@tonic-gate if (tail) 2018*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 2019*0Sstevel@tonic-gate last_error = NFSERR_IO; 2020*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 2021*0Sstevel@tonic-gate skipentry = 1; 2022*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 2023*0Sstevel@tonic-gate continue; 2024*0Sstevel@tonic-gate } 2025*0Sstevel@tonic-gate NFS_ARGS_EXTB_secdata(*argp, secdata); 2026*0Sstevel@tonic-gate /* end of security stuff */ 2027*0Sstevel@tonic-gate 2028*0Sstevel@tonic-gate if (trace > 4) 2029*0Sstevel@tonic-gate trace_prt(1, 2030*0Sstevel@tonic-gate " nfsmount: have secure info for %s\n", remname); 2031*0Sstevel@tonic-gate 2032*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_GRPID) != NULL) { 2033*0Sstevel@tonic-gate argp->flags |= NFSMNT_GRPID; 2034*0Sstevel@tonic-gate } 2035*0Sstevel@tonic-gate if (nopt(&m, MNTOPT_RSIZE, &argp->rsize)) { 2036*0Sstevel@tonic-gate argp->flags |= NFSMNT_RSIZE; 2037*0Sstevel@tonic-gate } 2038*0Sstevel@tonic-gate if (nopt(&m, MNTOPT_WSIZE, &argp->wsize)) { 2039*0Sstevel@tonic-gate argp->flags |= NFSMNT_WSIZE; 2040*0Sstevel@tonic-gate } 2041*0Sstevel@tonic-gate if (nopt(&m, MNTOPT_TIMEO, &argp->timeo)) { 2042*0Sstevel@tonic-gate argp->flags |= NFSMNT_TIMEO; 2043*0Sstevel@tonic-gate } 2044*0Sstevel@tonic-gate if (nopt(&m, MNTOPT_RETRANS, &argp->retrans)) { 2045*0Sstevel@tonic-gate argp->flags |= NFSMNT_RETRANS; 2046*0Sstevel@tonic-gate } 2047*0Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACTIMEO, &argp->acregmax)) { 2048*0Sstevel@tonic-gate argp->flags |= NFSMNT_ACREGMAX; 2049*0Sstevel@tonic-gate argp->flags |= NFSMNT_ACDIRMAX; 2050*0Sstevel@tonic-gate argp->flags |= NFSMNT_ACDIRMIN; 2051*0Sstevel@tonic-gate argp->flags |= NFSMNT_ACREGMIN; 2052*0Sstevel@tonic-gate argp->acdirmin = argp->acregmin = argp->acdirmax 2053*0Sstevel@tonic-gate = argp->acregmax; 2054*0Sstevel@tonic-gate } else { 2055*0Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACREGMIN, &argp->acregmin)) { 2056*0Sstevel@tonic-gate argp->flags |= NFSMNT_ACREGMIN; 2057*0Sstevel@tonic-gate } 2058*0Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACREGMAX, &argp->acregmax)) { 2059*0Sstevel@tonic-gate argp->flags |= NFSMNT_ACREGMAX; 2060*0Sstevel@tonic-gate } 2061*0Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACDIRMIN, &argp->acdirmin)) { 2062*0Sstevel@tonic-gate argp->flags |= NFSMNT_ACDIRMIN; 2063*0Sstevel@tonic-gate } 2064*0Sstevel@tonic-gate if (nopt(&m, MNTOPT_ACDIRMAX, &argp->acdirmax)) { 2065*0Sstevel@tonic-gate argp->flags |= NFSMNT_ACDIRMAX; 2066*0Sstevel@tonic-gate } 2067*0Sstevel@tonic-gate } 2068*0Sstevel@tonic-gate 2069*0Sstevel@tonic-gate if (posix) { 2070*0Sstevel@tonic-gate argp->pathconf = NULL; 2071*0Sstevel@tonic-gate if (error = get_pathconf(cl, dir, remname, 2072*0Sstevel@tonic-gate &argp->pathconf, retries)) { 2073*0Sstevel@tonic-gate if (secflags & AUTH_F_RPCTIMESYNC) 2074*0Sstevel@tonic-gate netbuf_free(syncaddr); 2075*0Sstevel@tonic-gate else if (retaddrs) 2076*0Sstevel@tonic-gate netdir_free(retaddrs, ND_ADDRLIST); 2077*0Sstevel@tonic-gate free_knconf(argp->knconf); 2078*0Sstevel@tonic-gate netbuf_free(argp->addr); 2079*0Sstevel@tonic-gate freenetconfigent(nconf); 2080*0Sstevel@tonic-gate nfs_free_secdata( 2081*0Sstevel@tonic-gate argp->nfs_ext_u.nfs_extB.secdata); 2082*0Sstevel@tonic-gate if (argp->syncaddr) 2083*0Sstevel@tonic-gate netbuf_free(argp->syncaddr); 2084*0Sstevel@tonic-gate if (argp->netname) 2085*0Sstevel@tonic-gate free(argp->netname); 2086*0Sstevel@tonic-gate free(argp->fh); 2087*0Sstevel@tonic-gate free(argp); 2088*0Sstevel@tonic-gate head = prevhead; 2089*0Sstevel@tonic-gate tail = prevtail; 2090*0Sstevel@tonic-gate if (tail) 2091*0Sstevel@tonic-gate tail->nfs_ext_u.nfs_extB.next = NULL; 2092*0Sstevel@tonic-gate last_error = NFSERR_IO; 2093*0Sstevel@tonic-gate 2094*0Sstevel@tonic-gate if (error == RET_RETRY && retries-- > 0) { 2095*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 2096*0Sstevel@tonic-gate DELAY(delay); 2097*0Sstevel@tonic-gate goto retry; 2098*0Sstevel@tonic-gate } 2099*0Sstevel@tonic-gate 2100*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 2101*0Sstevel@tonic-gate skipentry = 1; 2102*0Sstevel@tonic-gate mfs->mfs_ignore = 1; 2103*0Sstevel@tonic-gate continue; 2104*0Sstevel@tonic-gate } 2105*0Sstevel@tonic-gate argp->flags |= NFSMNT_POSIX; 2106*0Sstevel@tonic-gate if (trace > 4) 2107*0Sstevel@tonic-gate trace_prt(1, 2108*0Sstevel@tonic-gate " nfsmount: have pathconf for %s\n", 2109*0Sstevel@tonic-gate remname); 2110*0Sstevel@tonic-gate } 2111*0Sstevel@tonic-gate 2112*0Sstevel@tonic-gate /* 2113*0Sstevel@tonic-gate * free loop-specific data structures 2114*0Sstevel@tonic-gate */ 2115*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 2116*0Sstevel@tonic-gate freenetconfigent(nconf); 2117*0Sstevel@tonic-gate if (secflags & AUTH_F_RPCTIMESYNC) 2118*0Sstevel@tonic-gate netbuf_free(syncaddr); 2119*0Sstevel@tonic-gate else if (retaddrs) 2120*0Sstevel@tonic-gate netdir_free(retaddrs, ND_ADDRLIST); 2121*0Sstevel@tonic-gate 2122*0Sstevel@tonic-gate /* 2123*0Sstevel@tonic-gate * Decide whether to use remote host's lockd or local locking. 2124*0Sstevel@tonic-gate * If we are using the public fh, we've already turned 2125*0Sstevel@tonic-gate * LLOCK on. 2126*0Sstevel@tonic-gate */ 2127*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_LLOCK)) 2128*0Sstevel@tonic-gate argp->flags |= NFSMNT_LLOCK; 2129*0Sstevel@tonic-gate if (!(argp->flags & NFSMNT_LLOCK) && nfsvers == NFS_VERSION && 2130*0Sstevel@tonic-gate remote_lock(host, argp->fh)) { 2131*0Sstevel@tonic-gate syslog(loglevel, "No network locking on %s : " 2132*0Sstevel@tonic-gate "contact admin to install server change", host); 2133*0Sstevel@tonic-gate argp->flags |= NFSMNT_LLOCK; 2134*0Sstevel@tonic-gate } 2135*0Sstevel@tonic-gate 2136*0Sstevel@tonic-gate /* 2137*0Sstevel@tonic-gate * Build a string for /etc/mnttab. 2138*0Sstevel@tonic-gate * If possible, coalesce strings with same 'dir' info. 2139*0Sstevel@tonic-gate */ 2140*0Sstevel@tonic-gate if ((mfs->mfs_flags & MFS_URL) == 0) { 2141*0Sstevel@tonic-gate char *tmp; 2142*0Sstevel@tonic-gate 2143*0Sstevel@tonic-gate if (mnttabcnt) { 2144*0Sstevel@tonic-gate p = strrchr(mnttabtext, (int)':'); 2145*0Sstevel@tonic-gate if (!p || strcmp(p+1, dir) != 0) { 2146*0Sstevel@tonic-gate mnttabcnt += strlen(remname) + 2; 2147*0Sstevel@tonic-gate } else { 2148*0Sstevel@tonic-gate *p = '\0'; 2149*0Sstevel@tonic-gate mnttabcnt += strlen(host) + 2; 2150*0Sstevel@tonic-gate } 2151*0Sstevel@tonic-gate if ((tmp = realloc(mnttabtext, 2152*0Sstevel@tonic-gate mnttabcnt)) != NULL) { 2153*0Sstevel@tonic-gate mnttabtext = tmp; 2154*0Sstevel@tonic-gate strcat(mnttabtext, ","); 2155*0Sstevel@tonic-gate } else { 2156*0Sstevel@tonic-gate free(mnttabtext); 2157*0Sstevel@tonic-gate mnttabtext = NULL; 2158*0Sstevel@tonic-gate } 2159*0Sstevel@tonic-gate } else { 2160*0Sstevel@tonic-gate mnttabcnt = strlen(remname) + 1; 2161*0Sstevel@tonic-gate if ((mnttabtext = malloc(mnttabcnt)) != NULL) 2162*0Sstevel@tonic-gate mnttabtext[0] = '\0'; 2163*0Sstevel@tonic-gate } 2164*0Sstevel@tonic-gate 2165*0Sstevel@tonic-gate if (mnttabtext != NULL) 2166*0Sstevel@tonic-gate strcat(mnttabtext, remname); 2167*0Sstevel@tonic-gate 2168*0Sstevel@tonic-gate } else { 2169*0Sstevel@tonic-gate char *tmp; 2170*0Sstevel@tonic-gate int more_cnt = 0; 2171*0Sstevel@tonic-gate char sport[16]; 2172*0Sstevel@tonic-gate 2173*0Sstevel@tonic-gate more_cnt += strlen("nfs://"); 2174*0Sstevel@tonic-gate more_cnt += strlen(mfs->mfs_host); 2175*0Sstevel@tonic-gate 2176*0Sstevel@tonic-gate if (mfs->mfs_port != 0) { 2177*0Sstevel@tonic-gate (void) sprintf(sport, ":%u", mfs->mfs_port); 2178*0Sstevel@tonic-gate } else 2179*0Sstevel@tonic-gate sport[0] = '\0'; 2180*0Sstevel@tonic-gate 2181*0Sstevel@tonic-gate more_cnt += strlen(sport); 2182*0Sstevel@tonic-gate more_cnt += 1; /* "/" */ 2183*0Sstevel@tonic-gate more_cnt += strlen(mfs->mfs_dir); 2184*0Sstevel@tonic-gate 2185*0Sstevel@tonic-gate if (mnttabcnt) { 2186*0Sstevel@tonic-gate more_cnt += 1; /* "," */ 2187*0Sstevel@tonic-gate mnttabcnt += more_cnt; 2188*0Sstevel@tonic-gate 2189*0Sstevel@tonic-gate if ((tmp = realloc(mnttabtext, 2190*0Sstevel@tonic-gate mnttabcnt)) != NULL) { 2191*0Sstevel@tonic-gate mnttabtext = tmp; 2192*0Sstevel@tonic-gate strcat(mnttabtext, ","); 2193*0Sstevel@tonic-gate } else { 2194*0Sstevel@tonic-gate free(mnttabtext); 2195*0Sstevel@tonic-gate mnttabtext = NULL; 2196*0Sstevel@tonic-gate } 2197*0Sstevel@tonic-gate } else { 2198*0Sstevel@tonic-gate mnttabcnt = more_cnt + 1; 2199*0Sstevel@tonic-gate if ((mnttabtext = malloc(mnttabcnt)) != NULL) 2200*0Sstevel@tonic-gate mnttabtext[0] = '\0'; 2201*0Sstevel@tonic-gate } 2202*0Sstevel@tonic-gate 2203*0Sstevel@tonic-gate if (mnttabtext != NULL) { 2204*0Sstevel@tonic-gate strcat(mnttabtext, "nfs://"); 2205*0Sstevel@tonic-gate strcat(mnttabtext, mfs->mfs_host); 2206*0Sstevel@tonic-gate strcat(mnttabtext, sport); 2207*0Sstevel@tonic-gate strcat(mnttabtext, "/"); 2208*0Sstevel@tonic-gate strcat(mnttabtext, mfs->mfs_dir); 2209*0Sstevel@tonic-gate } 2210*0Sstevel@tonic-gate } 2211*0Sstevel@tonic-gate 2212*0Sstevel@tonic-gate if (!mnttabtext) { 2213*0Sstevel@tonic-gate syslog(LOG_ERR, "nfsmount: no memory"); 2214*0Sstevel@tonic-gate last_error = NFSERR_IO; 2215*0Sstevel@tonic-gate goto out; 2216*0Sstevel@tonic-gate } 2217*0Sstevel@tonic-gate 2218*0Sstevel@tonic-gate /* 2219*0Sstevel@tonic-gate * At least one entry, can call mount(2). 2220*0Sstevel@tonic-gate */ 2221*0Sstevel@tonic-gate entries++; 2222*0Sstevel@tonic-gate 2223*0Sstevel@tonic-gate /* 2224*0Sstevel@tonic-gate * If replication was defeated, don't do more work 2225*0Sstevel@tonic-gate */ 2226*0Sstevel@tonic-gate if (!replicated) 2227*0Sstevel@tonic-gate break; 2228*0Sstevel@tonic-gate } 2229*0Sstevel@tonic-gate 2230*0Sstevel@tonic-gate 2231*0Sstevel@tonic-gate /* 2232*0Sstevel@tonic-gate * Did we get through all possibilities without success? 2233*0Sstevel@tonic-gate */ 2234*0Sstevel@tonic-gate if (!entries) 2235*0Sstevel@tonic-gate goto out; 2236*0Sstevel@tonic-gate 2237*0Sstevel@tonic-gate /* Make "xattr" the default if "noxattr" is not specified. */ 2238*0Sstevel@tonic-gate strcpy(mopts, opts); 2239*0Sstevel@tonic-gate if (!hasmntopt(&m, MNTOPT_NOXATTR) && !hasmntopt(&m, MNTOPT_XATTR)) { 2240*0Sstevel@tonic-gate if (strlen(mopts) > 0) 2241*0Sstevel@tonic-gate strcat(mopts, ","); 2242*0Sstevel@tonic-gate strcat(mopts, "xattr"); 2243*0Sstevel@tonic-gate } 2244*0Sstevel@tonic-gate 2245*0Sstevel@tonic-gate /* 2246*0Sstevel@tonic-gate * enable services as needed. 2247*0Sstevel@tonic-gate */ 2248*0Sstevel@tonic-gate { 2249*0Sstevel@tonic-gate char **sl; 2250*0Sstevel@tonic-gate 2251*0Sstevel@tonic-gate if (strcmp(fstype, MNTTYPE_NFS4) == 0) 2252*0Sstevel@tonic-gate sl = service_list_v4; 2253*0Sstevel@tonic-gate else 2254*0Sstevel@tonic-gate sl = service_list; 2255*0Sstevel@tonic-gate 2256*0Sstevel@tonic-gate _check_services(sl); 2257*0Sstevel@tonic-gate } 2258*0Sstevel@tonic-gate 2259*0Sstevel@tonic-gate /* 2260*0Sstevel@tonic-gate * Whew; do the mount, at last. 2261*0Sstevel@tonic-gate */ 2262*0Sstevel@tonic-gate if (trace > 1) { 2263*0Sstevel@tonic-gate trace_prt(1, " mount %s %s (%s)\n", mnttabtext, mntpnt, mopts); 2264*0Sstevel@tonic-gate } 2265*0Sstevel@tonic-gate 2266*0Sstevel@tonic-gate if (mount(mnttabtext, mntpnt, flags | MS_DATA, fstype, 2267*0Sstevel@tonic-gate head, sizeof (*head), mopts, MAX_MNTOPT_STR) < 0) { 2268*0Sstevel@tonic-gate if (trace > 1) 2269*0Sstevel@tonic-gate trace_prt(1, " Mount of %s on %s: %d\n", 2270*0Sstevel@tonic-gate mnttabtext, mntpnt, errno); 2271*0Sstevel@tonic-gate if (errno != EBUSY || verbose) 2272*0Sstevel@tonic-gate syslog(LOG_ERR, 2273*0Sstevel@tonic-gate "Mount of %s on %s: %m", mnttabtext, mntpnt); 2274*0Sstevel@tonic-gate last_error = NFSERR_IO; 2275*0Sstevel@tonic-gate goto out; 2276*0Sstevel@tonic-gate } 2277*0Sstevel@tonic-gate 2278*0Sstevel@tonic-gate last_error = NFS_OK; 2279*0Sstevel@tonic-gate if (stat(mntpnt, &stbuf) == 0) { 2280*0Sstevel@tonic-gate if (trace > 1) { 2281*0Sstevel@tonic-gate trace_prt(1, " mount %s dev=%x rdev=%x OK\n", 2282*0Sstevel@tonic-gate mnttabtext, stbuf.st_dev, stbuf.st_rdev); 2283*0Sstevel@tonic-gate } 2284*0Sstevel@tonic-gate } else { 2285*0Sstevel@tonic-gate if (trace > 1) { 2286*0Sstevel@tonic-gate trace_prt(1, " mount %s OK\n", mnttabtext); 2287*0Sstevel@tonic-gate trace_prt(1, " stat of %s failed\n", mntpnt); 2288*0Sstevel@tonic-gate } 2289*0Sstevel@tonic-gate } 2290*0Sstevel@tonic-gate 2291*0Sstevel@tonic-gate out: 2292*0Sstevel@tonic-gate argp = head; 2293*0Sstevel@tonic-gate while (argp) { 2294*0Sstevel@tonic-gate if (argp->pathconf) 2295*0Sstevel@tonic-gate free(argp->pathconf); 2296*0Sstevel@tonic-gate free_knconf(argp->knconf); 2297*0Sstevel@tonic-gate netbuf_free(argp->addr); 2298*0Sstevel@tonic-gate if (argp->syncaddr) 2299*0Sstevel@tonic-gate netbuf_free(argp->syncaddr); 2300*0Sstevel@tonic-gate if (argp->netname) { 2301*0Sstevel@tonic-gate free(argp->netname); 2302*0Sstevel@tonic-gate } 2303*0Sstevel@tonic-gate nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata); 2304*0Sstevel@tonic-gate free(argp->fh); 2305*0Sstevel@tonic-gate head = argp; 2306*0Sstevel@tonic-gate argp = argp->nfs_ext_u.nfs_extB.next; 2307*0Sstevel@tonic-gate free(head); 2308*0Sstevel@tonic-gate } 2309*0Sstevel@tonic-gate ret: 2310*0Sstevel@tonic-gate if (nfs_proto) 2311*0Sstevel@tonic-gate free(nfs_proto); 2312*0Sstevel@tonic-gate if (mnttabtext) 2313*0Sstevel@tonic-gate free(mnttabtext); 2314*0Sstevel@tonic-gate 2315*0Sstevel@tonic-gate for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { 2316*0Sstevel@tonic-gate 2317*0Sstevel@tonic-gate if (mfs->mfs_flags & MFS_ALLOC_DIR) { 2318*0Sstevel@tonic-gate free(mfs->mfs_dir); 2319*0Sstevel@tonic-gate mfs->mfs_dir = NULL; 2320*0Sstevel@tonic-gate mfs->mfs_flags &= ~MFS_ALLOC_DIR; 2321*0Sstevel@tonic-gate } 2322*0Sstevel@tonic-gate 2323*0Sstevel@tonic-gate if (mfs->mfs_args != NULL) { 2324*0Sstevel@tonic-gate free(mfs->mfs_args); 2325*0Sstevel@tonic-gate mfs->mfs_args = NULL; 2326*0Sstevel@tonic-gate } 2327*0Sstevel@tonic-gate 2328*0Sstevel@tonic-gate if (mfs->mfs_nconf != NULL) { 2329*0Sstevel@tonic-gate freenetconfigent(mfs->mfs_nconf); 2330*0Sstevel@tonic-gate mfs->mfs_nconf = NULL; 2331*0Sstevel@tonic-gate } 2332*0Sstevel@tonic-gate } 2333*0Sstevel@tonic-gate 2334*0Sstevel@tonic-gate return (last_error); 2335*0Sstevel@tonic-gate } 2336*0Sstevel@tonic-gate 2337*0Sstevel@tonic-gate /* 2338*0Sstevel@tonic-gate * get_pathconf(cl, path, fsname, pcnf, cretries) 2339*0Sstevel@tonic-gate * ugliness that requires that ppathcnf and pathcnf stay consistent 2340*0Sstevel@tonic-gate * cretries is a copy of retries used to determine when to syslog 2341*0Sstevel@tonic-gate * on retry situations. 2342*0Sstevel@tonic-gate */ 2343*0Sstevel@tonic-gate static int 2344*0Sstevel@tonic-gate get_pathconf(CLIENT *cl, char *path, char *fsname, struct pathcnf **pcnf, 2345*0Sstevel@tonic-gate int cretries) 2346*0Sstevel@tonic-gate { 2347*0Sstevel@tonic-gate struct ppathcnf *p = NULL; 2348*0Sstevel@tonic-gate enum clnt_stat rpc_stat; 2349*0Sstevel@tonic-gate struct timeval timeout; 2350*0Sstevel@tonic-gate 2351*0Sstevel@tonic-gate p = (struct ppathcnf *)malloc(sizeof (struct ppathcnf)); 2352*0Sstevel@tonic-gate if (p == NULL) { 2353*0Sstevel@tonic-gate syslog(LOG_ERR, "get_pathconf: Out of memory"); 2354*0Sstevel@tonic-gate return (RET_ERR); 2355*0Sstevel@tonic-gate } 2356*0Sstevel@tonic-gate memset((caddr_t)p, 0, sizeof (struct ppathcnf)); 2357*0Sstevel@tonic-gate 2358*0Sstevel@tonic-gate timeout.tv_sec = 10; 2359*0Sstevel@tonic-gate timeout.tv_usec = 0; 2360*0Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_PATHCONF, 2361*0Sstevel@tonic-gate xdr_dirpath, (caddr_t)&path, xdr_ppathcnf, (caddr_t)p, timeout); 2362*0Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 2363*0Sstevel@tonic-gate if (cretries-- <= 0) { 2364*0Sstevel@tonic-gate syslog(LOG_ERR, 2365*0Sstevel@tonic-gate "get_pathconf: %s: server not responding: %s", 2366*0Sstevel@tonic-gate fsname, clnt_sperror(cl, "")); 2367*0Sstevel@tonic-gate } 2368*0Sstevel@tonic-gate free(p); 2369*0Sstevel@tonic-gate return (RET_RETRY); 2370*0Sstevel@tonic-gate } 2371*0Sstevel@tonic-gate if (_PC_ISSET(_PC_ERROR, p->pc_mask)) { 2372*0Sstevel@tonic-gate syslog(LOG_ERR, "get_pathconf: no info for %s", fsname); 2373*0Sstevel@tonic-gate free(p); 2374*0Sstevel@tonic-gate return (RET_ERR); 2375*0Sstevel@tonic-gate } 2376*0Sstevel@tonic-gate *pcnf = (struct pathcnf *)p; 2377*0Sstevel@tonic-gate return (RET_OK); 2378*0Sstevel@tonic-gate } 2379*0Sstevel@tonic-gate 2380*0Sstevel@tonic-gate static struct knetconfig * 2381*0Sstevel@tonic-gate get_knconf(nconf) 2382*0Sstevel@tonic-gate struct netconfig *nconf; 2383*0Sstevel@tonic-gate { 2384*0Sstevel@tonic-gate struct stat stbuf; 2385*0Sstevel@tonic-gate struct knetconfig *k; 2386*0Sstevel@tonic-gate 2387*0Sstevel@tonic-gate if (stat(nconf->nc_device, &stbuf) < 0) { 2388*0Sstevel@tonic-gate syslog(LOG_ERR, "get_knconf: stat %s: %m", nconf->nc_device); 2389*0Sstevel@tonic-gate return (NULL); 2390*0Sstevel@tonic-gate } 2391*0Sstevel@tonic-gate k = (struct knetconfig *)malloc(sizeof (*k)); 2392*0Sstevel@tonic-gate if (k == NULL) 2393*0Sstevel@tonic-gate goto nomem; 2394*0Sstevel@tonic-gate k->knc_semantics = nconf->nc_semantics; 2395*0Sstevel@tonic-gate k->knc_protofmly = strdup(nconf->nc_protofmly); 2396*0Sstevel@tonic-gate if (k->knc_protofmly == NULL) 2397*0Sstevel@tonic-gate goto nomem; 2398*0Sstevel@tonic-gate k->knc_proto = strdup(nconf->nc_proto); 2399*0Sstevel@tonic-gate if (k->knc_proto == NULL) 2400*0Sstevel@tonic-gate goto nomem; 2401*0Sstevel@tonic-gate k->knc_rdev = stbuf.st_rdev; 2402*0Sstevel@tonic-gate 2403*0Sstevel@tonic-gate return (k); 2404*0Sstevel@tonic-gate 2405*0Sstevel@tonic-gate nomem: 2406*0Sstevel@tonic-gate syslog(LOG_ERR, "get_knconf: no memory"); 2407*0Sstevel@tonic-gate free_knconf(k); 2408*0Sstevel@tonic-gate return (NULL); 2409*0Sstevel@tonic-gate } 2410*0Sstevel@tonic-gate 2411*0Sstevel@tonic-gate static void 2412*0Sstevel@tonic-gate free_knconf(k) 2413*0Sstevel@tonic-gate struct knetconfig *k; 2414*0Sstevel@tonic-gate { 2415*0Sstevel@tonic-gate if (k == NULL) 2416*0Sstevel@tonic-gate return; 2417*0Sstevel@tonic-gate if (k->knc_protofmly) 2418*0Sstevel@tonic-gate free(k->knc_protofmly); 2419*0Sstevel@tonic-gate if (k->knc_proto) 2420*0Sstevel@tonic-gate free(k->knc_proto); 2421*0Sstevel@tonic-gate free(k); 2422*0Sstevel@tonic-gate } 2423*0Sstevel@tonic-gate 2424*0Sstevel@tonic-gate static void 2425*0Sstevel@tonic-gate netbuf_free(nb) 2426*0Sstevel@tonic-gate struct netbuf *nb; 2427*0Sstevel@tonic-gate { 2428*0Sstevel@tonic-gate if (nb == NULL) 2429*0Sstevel@tonic-gate return; 2430*0Sstevel@tonic-gate if (nb->buf) 2431*0Sstevel@tonic-gate free(nb->buf); 2432*0Sstevel@tonic-gate free(nb); 2433*0Sstevel@tonic-gate } 2434*0Sstevel@tonic-gate 2435*0Sstevel@tonic-gate #define SMALL_HOSTNAME 20 2436*0Sstevel@tonic-gate #define SMALL_PROTONAME 10 2437*0Sstevel@tonic-gate #define SMALL_PROTOFMLYNAME 10 2438*0Sstevel@tonic-gate 2439*0Sstevel@tonic-gate struct portmap_cache { 2440*0Sstevel@tonic-gate int cache_prog; 2441*0Sstevel@tonic-gate int cache_vers; 2442*0Sstevel@tonic-gate time_t cache_time; 2443*0Sstevel@tonic-gate char cache_small_hosts[SMALL_HOSTNAME + 1]; 2444*0Sstevel@tonic-gate char *cache_hostname; 2445*0Sstevel@tonic-gate char *cache_proto; 2446*0Sstevel@tonic-gate char *cache_protofmly; 2447*0Sstevel@tonic-gate char cache_small_protofmly[SMALL_PROTOFMLYNAME + 1]; 2448*0Sstevel@tonic-gate char cache_small_proto[SMALL_PROTONAME + 1]; 2449*0Sstevel@tonic-gate struct netbuf cache_srv_addr; 2450*0Sstevel@tonic-gate struct portmap_cache *cache_prev, *cache_next; 2451*0Sstevel@tonic-gate }; 2452*0Sstevel@tonic-gate 2453*0Sstevel@tonic-gate rwlock_t portmap_cache_lock; 2454*0Sstevel@tonic-gate static int portmap_cache_valid_time = 30; 2455*0Sstevel@tonic-gate struct portmap_cache *portmap_cache_head, *portmap_cache_tail; 2456*0Sstevel@tonic-gate 2457*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 2458*0Sstevel@tonic-gate void 2459*0Sstevel@tonic-gate portmap_cache_flush() 2460*0Sstevel@tonic-gate { 2461*0Sstevel@tonic-gate struct portmap_cache *next = NULL, *cp; 2462*0Sstevel@tonic-gate 2463*0Sstevel@tonic-gate (void) rw_wrlock(&portmap_cache_lock); 2464*0Sstevel@tonic-gate for (cp = portmap_cache_head; cp; cp = cp->cache_next) { 2465*0Sstevel@tonic-gate if (cp->cache_hostname != NULL && 2466*0Sstevel@tonic-gate cp->cache_hostname != 2467*0Sstevel@tonic-gate cp->cache_small_hosts) 2468*0Sstevel@tonic-gate free(cp->cache_hostname); 2469*0Sstevel@tonic-gate if (cp->cache_proto != NULL && 2470*0Sstevel@tonic-gate cp->cache_proto != 2471*0Sstevel@tonic-gate cp->cache_small_proto) 2472*0Sstevel@tonic-gate free(cp->cache_proto); 2473*0Sstevel@tonic-gate if (cp->cache_srv_addr.buf != NULL) 2474*0Sstevel@tonic-gate free(cp->cache_srv_addr.buf); 2475*0Sstevel@tonic-gate next = cp->cache_next; 2476*0Sstevel@tonic-gate free(cp); 2477*0Sstevel@tonic-gate } 2478*0Sstevel@tonic-gate portmap_cache_head = NULL; 2479*0Sstevel@tonic-gate portmap_cache_tail = NULL; 2480*0Sstevel@tonic-gate (void) rw_unlock(&portmap_cache_lock); 2481*0Sstevel@tonic-gate } 2482*0Sstevel@tonic-gate #endif 2483*0Sstevel@tonic-gate 2484*0Sstevel@tonic-gate /* 2485*0Sstevel@tonic-gate * Returns 1 if the entry is found in the cache, 0 otherwise. 2486*0Sstevel@tonic-gate */ 2487*0Sstevel@tonic-gate static int 2488*0Sstevel@tonic-gate portmap_cache_lookup(hostname, prog, vers, nconf, addrp) 2489*0Sstevel@tonic-gate char *hostname; 2490*0Sstevel@tonic-gate rpcprog_t prog; 2491*0Sstevel@tonic-gate rpcvers_t vers; 2492*0Sstevel@tonic-gate struct netconfig *nconf; 2493*0Sstevel@tonic-gate struct netbuf *addrp; 2494*0Sstevel@tonic-gate { 2495*0Sstevel@tonic-gate struct portmap_cache *cachep, *prev, *next = NULL, *cp; 2496*0Sstevel@tonic-gate int retval = 0; 2497*0Sstevel@tonic-gate 2498*0Sstevel@tonic-gate timenow = time(NULL); 2499*0Sstevel@tonic-gate 2500*0Sstevel@tonic-gate (void) rw_rdlock(&portmap_cache_lock); 2501*0Sstevel@tonic-gate 2502*0Sstevel@tonic-gate /* 2503*0Sstevel@tonic-gate * Increment the portmap cache counters for # accesses and lookups 2504*0Sstevel@tonic-gate * Use a smaller factor (100 vs 1000 for the host cache) since 2505*0Sstevel@tonic-gate * initial analysis shows this cache is looked up 10% that of the 2506*0Sstevel@tonic-gate * host cache. 2507*0Sstevel@tonic-gate */ 2508*0Sstevel@tonic-gate #ifdef CACHE_DEBUG 2509*0Sstevel@tonic-gate portmap_cache_accesses++; 2510*0Sstevel@tonic-gate portmap_cache_lookups++; 2511*0Sstevel@tonic-gate if ((portmap_cache_lookups%100) == 0) 2512*0Sstevel@tonic-gate trace_portmap_cache(); 2513*0Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 2514*0Sstevel@tonic-gate 2515*0Sstevel@tonic-gate for (cachep = portmap_cache_head; cachep; 2516*0Sstevel@tonic-gate cachep = cachep->cache_next) { 2517*0Sstevel@tonic-gate if (timenow > cachep->cache_time) { 2518*0Sstevel@tonic-gate /* 2519*0Sstevel@tonic-gate * We stumbled across an entry in the cache which 2520*0Sstevel@tonic-gate * has timed out. Free up all the entries that 2521*0Sstevel@tonic-gate * were added before it, which will positionally 2522*0Sstevel@tonic-gate * be after this entry. And adjust neighboring 2523*0Sstevel@tonic-gate * pointers. 2524*0Sstevel@tonic-gate * When we drop the lock and re-acquire it, we 2525*0Sstevel@tonic-gate * need to start from the beginning. 2526*0Sstevel@tonic-gate */ 2527*0Sstevel@tonic-gate (void) rw_unlock(&portmap_cache_lock); 2528*0Sstevel@tonic-gate (void) rw_wrlock(&portmap_cache_lock); 2529*0Sstevel@tonic-gate for (cp = portmap_cache_head; 2530*0Sstevel@tonic-gate cp && (cp->cache_time >= timenow); 2531*0Sstevel@tonic-gate cp = cp->cache_next) 2532*0Sstevel@tonic-gate ; 2533*0Sstevel@tonic-gate if (cp == NULL) 2534*0Sstevel@tonic-gate goto done; 2535*0Sstevel@tonic-gate /* 2536*0Sstevel@tonic-gate * Adjust the link of the predecessor. 2537*0Sstevel@tonic-gate * Make the tail point to the new last entry. 2538*0Sstevel@tonic-gate */ 2539*0Sstevel@tonic-gate prev = cp->cache_prev; 2540*0Sstevel@tonic-gate if (prev == NULL) { 2541*0Sstevel@tonic-gate portmap_cache_head = NULL; 2542*0Sstevel@tonic-gate portmap_cache_tail = NULL; 2543*0Sstevel@tonic-gate } else { 2544*0Sstevel@tonic-gate prev->cache_next = NULL; 2545*0Sstevel@tonic-gate portmap_cache_tail = prev; 2546*0Sstevel@tonic-gate } 2547*0Sstevel@tonic-gate for (; cp; cp = next) { 2548*0Sstevel@tonic-gate if (cp->cache_hostname != NULL && 2549*0Sstevel@tonic-gate cp->cache_hostname != 2550*0Sstevel@tonic-gate cp->cache_small_hosts) 2551*0Sstevel@tonic-gate free(cp->cache_hostname); 2552*0Sstevel@tonic-gate if (cp->cache_proto != NULL && 2553*0Sstevel@tonic-gate cp->cache_proto != 2554*0Sstevel@tonic-gate cp->cache_small_proto) 2555*0Sstevel@tonic-gate free(cp->cache_proto); 2556*0Sstevel@tonic-gate if (cp->cache_srv_addr.buf != NULL) 2557*0Sstevel@tonic-gate free(cp->cache_srv_addr.buf); 2558*0Sstevel@tonic-gate next = cp->cache_next; 2559*0Sstevel@tonic-gate free(cp); 2560*0Sstevel@tonic-gate } 2561*0Sstevel@tonic-gate goto done; 2562*0Sstevel@tonic-gate } 2563*0Sstevel@tonic-gate if (cachep->cache_hostname == NULL || 2564*0Sstevel@tonic-gate prog != cachep->cache_prog || vers != cachep->cache_vers || 2565*0Sstevel@tonic-gate strcmp(nconf->nc_proto, cachep->cache_proto) != 0 || 2566*0Sstevel@tonic-gate strcmp(nconf->nc_protofmly, cachep->cache_protofmly) != 0 || 2567*0Sstevel@tonic-gate strcmp(hostname, cachep->cache_hostname) != 0) 2568*0Sstevel@tonic-gate continue; 2569*0Sstevel@tonic-gate /* 2570*0Sstevel@tonic-gate * Cache Hit. 2571*0Sstevel@tonic-gate */ 2572*0Sstevel@tonic-gate #ifdef CACHE_DEBUG 2573*0Sstevel@tonic-gate portmap_cache_hits++; /* up portmap cache hit counter */ 2574*0Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 2575*0Sstevel@tonic-gate addrp->len = cachep->cache_srv_addr.len; 2576*0Sstevel@tonic-gate memcpy(addrp->buf, cachep->cache_srv_addr.buf, addrp->len); 2577*0Sstevel@tonic-gate retval = 1; 2578*0Sstevel@tonic-gate break; 2579*0Sstevel@tonic-gate } 2580*0Sstevel@tonic-gate done: 2581*0Sstevel@tonic-gate (void) rw_unlock(&portmap_cache_lock); 2582*0Sstevel@tonic-gate return (retval); 2583*0Sstevel@tonic-gate } 2584*0Sstevel@tonic-gate 2585*0Sstevel@tonic-gate static void 2586*0Sstevel@tonic-gate portmap_cache_enter(hostname, prog, vers, nconf, addrp) 2587*0Sstevel@tonic-gate char *hostname; 2588*0Sstevel@tonic-gate rpcprog_t prog; 2589*0Sstevel@tonic-gate rpcvers_t vers; 2590*0Sstevel@tonic-gate struct netconfig *nconf; 2591*0Sstevel@tonic-gate struct netbuf *addrp; 2592*0Sstevel@tonic-gate { 2593*0Sstevel@tonic-gate struct portmap_cache *cachep; 2594*0Sstevel@tonic-gate int protofmlylen; 2595*0Sstevel@tonic-gate int protolen, hostnamelen; 2596*0Sstevel@tonic-gate 2597*0Sstevel@tonic-gate timenow = time(NULL); 2598*0Sstevel@tonic-gate 2599*0Sstevel@tonic-gate cachep = malloc(sizeof (struct portmap_cache)); 2600*0Sstevel@tonic-gate if (cachep == NULL) 2601*0Sstevel@tonic-gate return; 2602*0Sstevel@tonic-gate memset((char *)cachep, 0, sizeof (*cachep)); 2603*0Sstevel@tonic-gate 2604*0Sstevel@tonic-gate hostnamelen = strlen(hostname); 2605*0Sstevel@tonic-gate if (hostnamelen <= SMALL_HOSTNAME) 2606*0Sstevel@tonic-gate cachep->cache_hostname = cachep->cache_small_hosts; 2607*0Sstevel@tonic-gate else { 2608*0Sstevel@tonic-gate cachep->cache_hostname = malloc(hostnamelen + 1); 2609*0Sstevel@tonic-gate if (cachep->cache_hostname == NULL) 2610*0Sstevel@tonic-gate goto nomem; 2611*0Sstevel@tonic-gate } 2612*0Sstevel@tonic-gate strcpy(cachep->cache_hostname, hostname); 2613*0Sstevel@tonic-gate protolen = strlen(nconf->nc_proto); 2614*0Sstevel@tonic-gate if (protolen <= SMALL_PROTONAME) 2615*0Sstevel@tonic-gate cachep->cache_proto = cachep->cache_small_proto; 2616*0Sstevel@tonic-gate else { 2617*0Sstevel@tonic-gate cachep->cache_proto = malloc(protolen + 1); 2618*0Sstevel@tonic-gate if (cachep->cache_proto == NULL) 2619*0Sstevel@tonic-gate goto nomem; 2620*0Sstevel@tonic-gate } 2621*0Sstevel@tonic-gate protofmlylen = strlen(nconf->nc_protofmly); 2622*0Sstevel@tonic-gate if (protofmlylen <= SMALL_PROTOFMLYNAME) 2623*0Sstevel@tonic-gate cachep->cache_protofmly = cachep->cache_small_protofmly; 2624*0Sstevel@tonic-gate else { 2625*0Sstevel@tonic-gate cachep->cache_protofmly = malloc(protofmlylen + 1); 2626*0Sstevel@tonic-gate if (cachep->cache_protofmly == NULL) 2627*0Sstevel@tonic-gate goto nomem; 2628*0Sstevel@tonic-gate } 2629*0Sstevel@tonic-gate 2630*0Sstevel@tonic-gate strcpy(cachep->cache_proto, nconf->nc_proto); 2631*0Sstevel@tonic-gate cachep->cache_prog = prog; 2632*0Sstevel@tonic-gate cachep->cache_vers = vers; 2633*0Sstevel@tonic-gate cachep->cache_time = timenow + portmap_cache_valid_time; 2634*0Sstevel@tonic-gate cachep->cache_srv_addr.len = addrp->len; 2635*0Sstevel@tonic-gate cachep->cache_srv_addr.buf = malloc(addrp->len); 2636*0Sstevel@tonic-gate if (cachep->cache_srv_addr.buf == NULL) 2637*0Sstevel@tonic-gate goto nomem; 2638*0Sstevel@tonic-gate memcpy(cachep->cache_srv_addr.buf, addrp->buf, addrp->maxlen); 2639*0Sstevel@tonic-gate cachep->cache_prev = NULL; 2640*0Sstevel@tonic-gate (void) rw_wrlock(&portmap_cache_lock); 2641*0Sstevel@tonic-gate /* 2642*0Sstevel@tonic-gate * There's a window in which we could have multiple threads making 2643*0Sstevel@tonic-gate * the same cache entry. This can be avoided by walking the cache 2644*0Sstevel@tonic-gate * once again here to check and see if there are duplicate entries 2645*0Sstevel@tonic-gate * (after grabbing the write lock). This isn't fatal and I'm not 2646*0Sstevel@tonic-gate * going to bother with this. 2647*0Sstevel@tonic-gate */ 2648*0Sstevel@tonic-gate #ifdef CACHE_DEBUG 2649*0Sstevel@tonic-gate portmap_cache_accesses++; /* up portmap cache access counter */ 2650*0Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 2651*0Sstevel@tonic-gate cachep->cache_next = portmap_cache_head; 2652*0Sstevel@tonic-gate if (portmap_cache_head != NULL) 2653*0Sstevel@tonic-gate portmap_cache_head->cache_prev = cachep; 2654*0Sstevel@tonic-gate portmap_cache_head = cachep; 2655*0Sstevel@tonic-gate (void) rw_unlock(&portmap_cache_lock); 2656*0Sstevel@tonic-gate return; 2657*0Sstevel@tonic-gate 2658*0Sstevel@tonic-gate nomem: 2659*0Sstevel@tonic-gate syslog(LOG_ERR, "portmap_cache_enter: Memory allocation failed"); 2660*0Sstevel@tonic-gate if (cachep->cache_srv_addr.buf) 2661*0Sstevel@tonic-gate free(cachep->cache_srv_addr.buf); 2662*0Sstevel@tonic-gate if (cachep->cache_proto && protolen > SMALL_PROTONAME) 2663*0Sstevel@tonic-gate free(cachep->cache_proto); 2664*0Sstevel@tonic-gate if (cachep->cache_hostname && hostnamelen > SMALL_HOSTNAME) 2665*0Sstevel@tonic-gate free(cachep->cache_hostname); 2666*0Sstevel@tonic-gate if (cachep->cache_protofmly && protofmlylen > SMALL_PROTOFMLYNAME) 2667*0Sstevel@tonic-gate free(cachep->cache_protofmly); 2668*0Sstevel@tonic-gate if (cachep) 2669*0Sstevel@tonic-gate free(cachep); 2670*0Sstevel@tonic-gate cachep = NULL; 2671*0Sstevel@tonic-gate } 2672*0Sstevel@tonic-gate 2673*0Sstevel@tonic-gate static int 2674*0Sstevel@tonic-gate get_cached_srv_addr(char *hostname, rpcprog_t prog, rpcvers_t vers, 2675*0Sstevel@tonic-gate struct netconfig *nconf, struct netbuf *addrp) 2676*0Sstevel@tonic-gate { 2677*0Sstevel@tonic-gate if (portmap_cache_lookup(hostname, prog, vers, nconf, addrp)) 2678*0Sstevel@tonic-gate return (1); 2679*0Sstevel@tonic-gate if (rpcb_getaddr(prog, vers, nconf, addrp, hostname) == 0) 2680*0Sstevel@tonic-gate return (0); 2681*0Sstevel@tonic-gate portmap_cache_enter(hostname, prog, vers, nconf, addrp); 2682*0Sstevel@tonic-gate return (1); 2683*0Sstevel@tonic-gate } 2684*0Sstevel@tonic-gate 2685*0Sstevel@tonic-gate /* 2686*0Sstevel@tonic-gate * Get the network address on "hostname" for program "prog" 2687*0Sstevel@tonic-gate * with version "vers" by using the nconf configuration data 2688*0Sstevel@tonic-gate * passed in. 2689*0Sstevel@tonic-gate * 2690*0Sstevel@tonic-gate * If the address of a netconfig pointer is null then 2691*0Sstevel@tonic-gate * information is not sufficient and no netbuf will be returned. 2692*0Sstevel@tonic-gate * 2693*0Sstevel@tonic-gate * tinfo argument is for matching the get_the_addr() defined in 2694*0Sstevel@tonic-gate * ../nfs/mount/mount.c 2695*0Sstevel@tonic-gate */ 2696*0Sstevel@tonic-gate static void * 2697*0Sstevel@tonic-gate get_the_stuff( 2698*0Sstevel@tonic-gate enum type_of_stuff type_of_stuff, 2699*0Sstevel@tonic-gate char *hostname, 2700*0Sstevel@tonic-gate rpcprog_t prog, 2701*0Sstevel@tonic-gate rpcprog_t vers, 2702*0Sstevel@tonic-gate mfs_snego_t *mfssnego, 2703*0Sstevel@tonic-gate struct netconfig *nconf, 2704*0Sstevel@tonic-gate ushort_t port, 2705*0Sstevel@tonic-gate struct t_info *tinfo, 2706*0Sstevel@tonic-gate caddr_t *fhp, 2707*0Sstevel@tonic-gate bool_t direct_to_server, 2708*0Sstevel@tonic-gate char *fspath, 2709*0Sstevel@tonic-gate enum clnt_stat *cstat) 2710*0Sstevel@tonic-gate 2711*0Sstevel@tonic-gate { 2712*0Sstevel@tonic-gate struct netbuf *nb = NULL; 2713*0Sstevel@tonic-gate struct t_bind *tbind = NULL; 2714*0Sstevel@tonic-gate int fd = -1; 2715*0Sstevel@tonic-gate enum clnt_stat cs = RPC_TIMEDOUT; 2716*0Sstevel@tonic-gate CLIENT *cl = NULL; 2717*0Sstevel@tonic-gate struct timeval tv; 2718*0Sstevel@tonic-gate AUTH *ah = NULL; 2719*0Sstevel@tonic-gate AUTH *new_ah = NULL; 2720*0Sstevel@tonic-gate struct snego_t snego; 2721*0Sstevel@tonic-gate 2722*0Sstevel@tonic-gate if (nconf == NULL) { 2723*0Sstevel@tonic-gate goto done; 2724*0Sstevel@tonic-gate } 2725*0Sstevel@tonic-gate 2726*0Sstevel@tonic-gate if (prog == NFS_PROGRAM && vers == NFS_V4) 2727*0Sstevel@tonic-gate if (strncasecmp(nconf->nc_proto, NC_UDP, strlen(NC_UDP)) == 0) 2728*0Sstevel@tonic-gate goto done; 2729*0Sstevel@tonic-gate 2730*0Sstevel@tonic-gate if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) < 0) { 2731*0Sstevel@tonic-gate goto done; 2732*0Sstevel@tonic-gate } 2733*0Sstevel@tonic-gate 2734*0Sstevel@tonic-gate /* LINTED pointer alignment */ 2735*0Sstevel@tonic-gate if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR)) 2736*0Sstevel@tonic-gate == NULL) { 2737*0Sstevel@tonic-gate goto done; 2738*0Sstevel@tonic-gate } 2739*0Sstevel@tonic-gate 2740*0Sstevel@tonic-gate if (direct_to_server == TRUE) { 2741*0Sstevel@tonic-gate struct nd_hostserv hs; 2742*0Sstevel@tonic-gate struct nd_addrlist *retaddrs; 2743*0Sstevel@tonic-gate hs.h_host = hostname; 2744*0Sstevel@tonic-gate 2745*0Sstevel@tonic-gate if (trace > 1) 2746*0Sstevel@tonic-gate trace_prt(1, " get_the_stuff: %s call " 2747*0Sstevel@tonic-gate "direct to server %s\n", 2748*0Sstevel@tonic-gate type_of_stuff == SERVER_FH ? "pub fh" : 2749*0Sstevel@tonic-gate type_of_stuff == SERVER_ADDR ? "get address" : 2750*0Sstevel@tonic-gate type_of_stuff == SERVER_PING ? "ping" : 2751*0Sstevel@tonic-gate "unknown", hostname); 2752*0Sstevel@tonic-gate if (port == 0) 2753*0Sstevel@tonic-gate hs.h_serv = "nfs"; 2754*0Sstevel@tonic-gate else 2755*0Sstevel@tonic-gate hs.h_serv = NULL; 2756*0Sstevel@tonic-gate 2757*0Sstevel@tonic-gate if (netdir_getbyname(nconf, &hs, &retaddrs) != ND_OK) { 2758*0Sstevel@tonic-gate goto done; 2759*0Sstevel@tonic-gate } 2760*0Sstevel@tonic-gate memcpy(tbind->addr.buf, retaddrs->n_addrs->buf, 2761*0Sstevel@tonic-gate retaddrs->n_addrs->len); 2762*0Sstevel@tonic-gate tbind->addr.len = retaddrs->n_addrs->len; 2763*0Sstevel@tonic-gate netdir_free((void *)retaddrs, ND_ADDRLIST); 2764*0Sstevel@tonic-gate if (port) { 2765*0Sstevel@tonic-gate /* LINTED pointer alignment */ 2766*0Sstevel@tonic-gate 2767*0Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == NULL) 2768*0Sstevel@tonic-gate ((struct sockaddr_in *) 2769*0Sstevel@tonic-gate tbind->addr.buf)->sin_port = 2770*0Sstevel@tonic-gate htons((ushort_t)port); 2771*0Sstevel@tonic-gate else if (strcmp(nconf->nc_protofmly, NC_INET6) == NULL) 2772*0Sstevel@tonic-gate ((struct sockaddr_in6 *) 2773*0Sstevel@tonic-gate tbind->addr.buf)->sin6_port = 2774*0Sstevel@tonic-gate htons((ushort_t)port); 2775*0Sstevel@tonic-gate } 2776*0Sstevel@tonic-gate 2777*0Sstevel@tonic-gate if (type_of_stuff == SERVER_FH) { 2778*0Sstevel@tonic-gate if (netdir_options(nconf, ND_SET_RESERVEDPORT, fd, 2779*0Sstevel@tonic-gate NULL) == -1) 2780*0Sstevel@tonic-gate if (trace > 1) 2781*0Sstevel@tonic-gate trace_prt(1, "\tget_the_stuff: " 2782*0Sstevel@tonic-gate "ND_SET_RESERVEDPORT(%s) " 2783*0Sstevel@tonic-gate "failed\n", hostname); 2784*0Sstevel@tonic-gate } 2785*0Sstevel@tonic-gate 2786*0Sstevel@tonic-gate cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, 2787*0Sstevel@tonic-gate vers, 0, 0); 2788*0Sstevel@tonic-gate 2789*0Sstevel@tonic-gate if (trace > 1) 2790*0Sstevel@tonic-gate trace_prt(1, " get_the_stuff: clnt_tli_create(%s) " 2791*0Sstevel@tonic-gate "returned %p\n", hostname, cl); 2792*0Sstevel@tonic-gate if (cl == NULL) 2793*0Sstevel@tonic-gate goto done; 2794*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 2795*0Sstevel@tonic-gate add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__); 2796*0Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 2797*0Sstevel@tonic-gate __FILE__, __LINE__); 2798*0Sstevel@tonic-gate #endif 2799*0Sstevel@tonic-gate 2800*0Sstevel@tonic-gate switch (type_of_stuff) { 2801*0Sstevel@tonic-gate case SERVER_FH: 2802*0Sstevel@tonic-gate { 2803*0Sstevel@tonic-gate enum snego_stat sec; 2804*0Sstevel@tonic-gate 2805*0Sstevel@tonic-gate ah = authsys_create_default(); 2806*0Sstevel@tonic-gate if (ah != NULL) { 2807*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 2808*0Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, 2809*0Sstevel@tonic-gate __FILE__, __LINE__); 2810*0Sstevel@tonic-gate #endif 2811*0Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 2812*0Sstevel@tonic-gate cl->cl_auth = ah; 2813*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 2814*0Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 2815*0Sstevel@tonic-gate __FILE__, __LINE__); 2816*0Sstevel@tonic-gate #endif 2817*0Sstevel@tonic-gate } 2818*0Sstevel@tonic-gate 2819*0Sstevel@tonic-gate if (!mfssnego->snego_done && vers != NFS_V4) { 2820*0Sstevel@tonic-gate /* 2821*0Sstevel@tonic-gate * negotiate sec flavor. 2822*0Sstevel@tonic-gate */ 2823*0Sstevel@tonic-gate snego.cnt = 0; 2824*0Sstevel@tonic-gate if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) == 2825*0Sstevel@tonic-gate SNEGO_SUCCESS) { 2826*0Sstevel@tonic-gate int jj; 2827*0Sstevel@tonic-gate 2828*0Sstevel@tonic-gate /* 2829*0Sstevel@tonic-gate * check if server supports the one 2830*0Sstevel@tonic-gate * specified in the sec= option. 2831*0Sstevel@tonic-gate */ 2832*0Sstevel@tonic-gate if (mfssnego->sec_opt) { 2833*0Sstevel@tonic-gate for (jj = 0; jj < snego.cnt; jj++) { 2834*0Sstevel@tonic-gate if (snego.array[jj] == 2835*0Sstevel@tonic-gate mfssnego->nfs_sec.sc_nfsnum) { 2836*0Sstevel@tonic-gate mfssnego->snego_done = TRUE; 2837*0Sstevel@tonic-gate break; 2838*0Sstevel@tonic-gate } 2839*0Sstevel@tonic-gate } 2840*0Sstevel@tonic-gate } 2841*0Sstevel@tonic-gate 2842*0Sstevel@tonic-gate /* 2843*0Sstevel@tonic-gate * find a common sec flavor 2844*0Sstevel@tonic-gate */ 2845*0Sstevel@tonic-gate if (!mfssnego->snego_done) { 2846*0Sstevel@tonic-gate for (jj = 0; jj < snego.cnt; jj++) { 2847*0Sstevel@tonic-gate if (!nfs_getseconfig_bynumber( 2848*0Sstevel@tonic-gate snego.array[jj], &mfssnego->nfs_sec)) { 2849*0Sstevel@tonic-gate mfssnego->snego_done = TRUE; 2850*0Sstevel@tonic-gate break; 2851*0Sstevel@tonic-gate } 2852*0Sstevel@tonic-gate } 2853*0Sstevel@tonic-gate } 2854*0Sstevel@tonic-gate if (!mfssnego->snego_done) 2855*0Sstevel@tonic-gate return (NULL); 2856*0Sstevel@tonic-gate 2857*0Sstevel@tonic-gate /* 2858*0Sstevel@tonic-gate * Now that the flavor has been 2859*0Sstevel@tonic-gate * negotiated, get the fh. 2860*0Sstevel@tonic-gate * 2861*0Sstevel@tonic-gate * First, create an auth handle using the negotiated 2862*0Sstevel@tonic-gate * sec flavor in the next lookup to 2863*0Sstevel@tonic-gate * fetch the filehandle. 2864*0Sstevel@tonic-gate */ 2865*0Sstevel@tonic-gate new_ah = nfs_create_ah(cl, hostname, 2866*0Sstevel@tonic-gate &mfssnego->nfs_sec); 2867*0Sstevel@tonic-gate if (new_ah == NULL) 2868*0Sstevel@tonic-gate goto done; 2869*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 2870*0Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, 2871*0Sstevel@tonic-gate __FILE__, __LINE__); 2872*0Sstevel@tonic-gate #endif 2873*0Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 2874*0Sstevel@tonic-gate cl->cl_auth = new_ah; 2875*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 2876*0Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 2877*0Sstevel@tonic-gate __FILE__, __LINE__); 2878*0Sstevel@tonic-gate #endif 2879*0Sstevel@tonic-gate } else if (sec == SNEGO_ARRAY_TOO_SMALL || 2880*0Sstevel@tonic-gate sec == SNEGO_FAILURE) { 2881*0Sstevel@tonic-gate goto done; 2882*0Sstevel@tonic-gate } 2883*0Sstevel@tonic-gate /* 2884*0Sstevel@tonic-gate * Note that if sec == SNEGO_DEF_VALID 2885*0Sstevel@tonic-gate * the default sec flavor is acceptable. 2886*0Sstevel@tonic-gate * Use it to get the filehandle. 2887*0Sstevel@tonic-gate */ 2888*0Sstevel@tonic-gate } 2889*0Sstevel@tonic-gate } 2890*0Sstevel@tonic-gate 2891*0Sstevel@tonic-gate switch (vers) { 2892*0Sstevel@tonic-gate case NFS_VERSION: 2893*0Sstevel@tonic-gate { 2894*0Sstevel@tonic-gate wnl_diropargs arg; 2895*0Sstevel@tonic-gate wnl_diropres *res; 2896*0Sstevel@tonic-gate 2897*0Sstevel@tonic-gate memset((char *)&arg.dir, 0, sizeof (wnl_fh)); 2898*0Sstevel@tonic-gate arg.name = fspath; 2899*0Sstevel@tonic-gate res = wnlproc_lookup_2(&arg, cl); 2900*0Sstevel@tonic-gate 2901*0Sstevel@tonic-gate if (res == NULL || res->status != NFS_OK) 2902*0Sstevel@tonic-gate goto done; 2903*0Sstevel@tonic-gate *fhp = malloc(sizeof (wnl_fh)); 2904*0Sstevel@tonic-gate 2905*0Sstevel@tonic-gate if (*fhp == NULL) { 2906*0Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 2907*0Sstevel@tonic-gate goto done; 2908*0Sstevel@tonic-gate } 2909*0Sstevel@tonic-gate 2910*0Sstevel@tonic-gate memcpy((char *)*fhp, 2911*0Sstevel@tonic-gate (char *)&res->wnl_diropres_u.wnl_diropres.file, 2912*0Sstevel@tonic-gate sizeof (wnl_fh)); 2913*0Sstevel@tonic-gate cs = RPC_SUCCESS; 2914*0Sstevel@tonic-gate } 2915*0Sstevel@tonic-gate break; 2916*0Sstevel@tonic-gate case NFS_V3: 2917*0Sstevel@tonic-gate { 2918*0Sstevel@tonic-gate WNL_LOOKUP3args arg; 2919*0Sstevel@tonic-gate WNL_LOOKUP3res *res; 2920*0Sstevel@tonic-gate nfs_fh3 *fh3p; 2921*0Sstevel@tonic-gate 2922*0Sstevel@tonic-gate memset((char *)&arg.what.dir, 0, sizeof (wnl_fh3)); 2923*0Sstevel@tonic-gate arg.what.name = fspath; 2924*0Sstevel@tonic-gate res = wnlproc3_lookup_3(&arg, cl); 2925*0Sstevel@tonic-gate 2926*0Sstevel@tonic-gate if (res == NULL || res->status != NFS3_OK) 2927*0Sstevel@tonic-gate goto done; 2928*0Sstevel@tonic-gate 2929*0Sstevel@tonic-gate fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p)); 2930*0Sstevel@tonic-gate 2931*0Sstevel@tonic-gate if (fh3p == NULL) { 2932*0Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 2933*0Sstevel@tonic-gate CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, 2934*0Sstevel@tonic-gate (char *)res); 2935*0Sstevel@tonic-gate goto done; 2936*0Sstevel@tonic-gate } 2937*0Sstevel@tonic-gate 2938*0Sstevel@tonic-gate fh3p->fh3_length = res-> 2939*0Sstevel@tonic-gate WNL_LOOKUP3res_u.res_ok.object.data.data_len; 2940*0Sstevel@tonic-gate memcpy(fh3p->fh3_u.data, res-> 2941*0Sstevel@tonic-gate WNL_LOOKUP3res_u.res_ok.object.data.data_val, 2942*0Sstevel@tonic-gate fh3p->fh3_length); 2943*0Sstevel@tonic-gate 2944*0Sstevel@tonic-gate *fhp = (caddr_t)fh3p; 2945*0Sstevel@tonic-gate 2946*0Sstevel@tonic-gate CLNT_FREERES(cl, xdr_WNL_LOOKUP3res, (char *)res); 2947*0Sstevel@tonic-gate cs = RPC_SUCCESS; 2948*0Sstevel@tonic-gate } 2949*0Sstevel@tonic-gate break; 2950*0Sstevel@tonic-gate case NFS_V4: 2951*0Sstevel@tonic-gate *fhp = strdup(fspath); 2952*0Sstevel@tonic-gate cs = RPC_SUCCESS; 2953*0Sstevel@tonic-gate break; 2954*0Sstevel@tonic-gate } 2955*0Sstevel@tonic-gate break; 2956*0Sstevel@tonic-gate case SERVER_ADDR: 2957*0Sstevel@tonic-gate case SERVER_PING: 2958*0Sstevel@tonic-gate tv.tv_sec = 10; 2959*0Sstevel@tonic-gate tv.tv_usec = 0; 2960*0Sstevel@tonic-gate cs = clnt_call(cl, NULLPROC, xdr_void, 0, 2961*0Sstevel@tonic-gate xdr_void, 0, tv); 2962*0Sstevel@tonic-gate if (trace > 1) 2963*0Sstevel@tonic-gate trace_prt(1, 2964*0Sstevel@tonic-gate "get_the_stuff: clnt_call(%s) " 2965*0Sstevel@tonic-gate "returned %s\n", 2966*0Sstevel@tonic-gate hostname, 2967*0Sstevel@tonic-gate cs == RPC_SUCCESS ? "success" : 2968*0Sstevel@tonic-gate "failure"); 2969*0Sstevel@tonic-gate 2970*0Sstevel@tonic-gate if (cs != RPC_SUCCESS) 2971*0Sstevel@tonic-gate goto done; 2972*0Sstevel@tonic-gate break; 2973*0Sstevel@tonic-gate } 2974*0Sstevel@tonic-gate 2975*0Sstevel@tonic-gate } else if (type_of_stuff != SERVER_FH) { 2976*0Sstevel@tonic-gate 2977*0Sstevel@tonic-gate if (type_of_stuff == SERVER_ADDR) { 2978*0Sstevel@tonic-gate if (get_cached_srv_addr(hostname, prog, vers, nconf, 2979*0Sstevel@tonic-gate &tbind->addr) == 0) 2980*0Sstevel@tonic-gate goto done; 2981*0Sstevel@tonic-gate } 2982*0Sstevel@tonic-gate 2983*0Sstevel@tonic-gate if (port) { 2984*0Sstevel@tonic-gate /* LINTED pointer alignment */ 2985*0Sstevel@tonic-gate if (strcmp(nconf->nc_protofmly, NC_INET) == NULL) 2986*0Sstevel@tonic-gate ((struct sockaddr_in *) 2987*0Sstevel@tonic-gate tbind->addr.buf)->sin_port = 2988*0Sstevel@tonic-gate htons((ushort_t)port); 2989*0Sstevel@tonic-gate else if (strcmp(nconf->nc_protofmly, NC_INET6) == NULL) 2990*0Sstevel@tonic-gate ((struct sockaddr_in6 *) 2991*0Sstevel@tonic-gate tbind->addr.buf)->sin6_port = 2992*0Sstevel@tonic-gate htons((ushort_t)port); 2993*0Sstevel@tonic-gate cl = clnt_tli_create(fd, nconf, &tbind->addr, 2994*0Sstevel@tonic-gate prog, vers, 0, 0); 2995*0Sstevel@tonic-gate if (cl == NULL) 2996*0Sstevel@tonic-gate goto done; 2997*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 2998*0Sstevel@tonic-gate add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__); 2999*0Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 3000*0Sstevel@tonic-gate __FILE__, __LINE__); 3001*0Sstevel@tonic-gate #endif 3002*0Sstevel@tonic-gate tv.tv_sec = 10; 3003*0Sstevel@tonic-gate tv.tv_usec = 0; 3004*0Sstevel@tonic-gate cs = clnt_call(cl, NULLPROC, xdr_void, 0, xdr_void, 3005*0Sstevel@tonic-gate 0, tv); 3006*0Sstevel@tonic-gate if (cs != RPC_SUCCESS) 3007*0Sstevel@tonic-gate goto done; 3008*0Sstevel@tonic-gate } 3009*0Sstevel@tonic-gate 3010*0Sstevel@tonic-gate } else { 3011*0Sstevel@tonic-gate /* can't happen */ 3012*0Sstevel@tonic-gate goto done; 3013*0Sstevel@tonic-gate } 3014*0Sstevel@tonic-gate 3015*0Sstevel@tonic-gate if (type_of_stuff != SERVER_PING) { 3016*0Sstevel@tonic-gate 3017*0Sstevel@tonic-gate cs = RPC_SYSTEMERROR; 3018*0Sstevel@tonic-gate 3019*0Sstevel@tonic-gate /* 3020*0Sstevel@tonic-gate * Make a copy of the netbuf to return 3021*0Sstevel@tonic-gate */ 3022*0Sstevel@tonic-gate nb = (struct netbuf *)malloc(sizeof (struct netbuf)); 3023*0Sstevel@tonic-gate if (nb == NULL) { 3024*0Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 3025*0Sstevel@tonic-gate goto done; 3026*0Sstevel@tonic-gate } 3027*0Sstevel@tonic-gate *nb = tbind->addr; 3028*0Sstevel@tonic-gate nb->buf = (char *)malloc(nb->maxlen); 3029*0Sstevel@tonic-gate if (nb->buf == NULL) { 3030*0Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 3031*0Sstevel@tonic-gate free(nb); 3032*0Sstevel@tonic-gate nb = NULL; 3033*0Sstevel@tonic-gate goto done; 3034*0Sstevel@tonic-gate } 3035*0Sstevel@tonic-gate (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len); 3036*0Sstevel@tonic-gate 3037*0Sstevel@tonic-gate cs = RPC_SUCCESS; 3038*0Sstevel@tonic-gate } 3039*0Sstevel@tonic-gate 3040*0Sstevel@tonic-gate done: 3041*0Sstevel@tonic-gate if (cl != NULL) { 3042*0Sstevel@tonic-gate if (ah != NULL) { 3043*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 3044*0Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, 3045*0Sstevel@tonic-gate __FILE__, __LINE__); 3046*0Sstevel@tonic-gate #endif 3047*0Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 3048*0Sstevel@tonic-gate cl->cl_auth = NULL; 3049*0Sstevel@tonic-gate } 3050*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 3051*0Sstevel@tonic-gate drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__); 3052*0Sstevel@tonic-gate #endif 3053*0Sstevel@tonic-gate clnt_destroy(cl); 3054*0Sstevel@tonic-gate } 3055*0Sstevel@tonic-gate 3056*0Sstevel@tonic-gate if (tbind) { 3057*0Sstevel@tonic-gate t_free((char *)tbind, T_BIND); 3058*0Sstevel@tonic-gate tbind = NULL; 3059*0Sstevel@tonic-gate } 3060*0Sstevel@tonic-gate 3061*0Sstevel@tonic-gate if (fd >= 0) 3062*0Sstevel@tonic-gate (void) t_close(fd); 3063*0Sstevel@tonic-gate 3064*0Sstevel@tonic-gate if (cstat != NULL) 3065*0Sstevel@tonic-gate *cstat = cs; 3066*0Sstevel@tonic-gate 3067*0Sstevel@tonic-gate return (nb); 3068*0Sstevel@tonic-gate } 3069*0Sstevel@tonic-gate 3070*0Sstevel@tonic-gate /* 3071*0Sstevel@tonic-gate * Get a network address on "hostname" for program "prog" 3072*0Sstevel@tonic-gate * with version "vers". If the port number is specified (non zero) 3073*0Sstevel@tonic-gate * then try for a TCP/UDP transport and set the port number of the 3074*0Sstevel@tonic-gate * resulting IP address. 3075*0Sstevel@tonic-gate * 3076*0Sstevel@tonic-gate * If the address of a netconfig pointer was passed and 3077*0Sstevel@tonic-gate * if it's not null, use it as the netconfig otherwise 3078*0Sstevel@tonic-gate * assign the address of the netconfig that was used to 3079*0Sstevel@tonic-gate * establish contact with the service. 3080*0Sstevel@tonic-gate * 3081*0Sstevel@tonic-gate * tinfo argument is for matching the get_addr() defined in 3082*0Sstevel@tonic-gate * ../nfs/mount/mount.c 3083*0Sstevel@tonic-gate */ 3084*0Sstevel@tonic-gate 3085*0Sstevel@tonic-gate static struct netbuf * 3086*0Sstevel@tonic-gate get_addr(char *hostname, rpcprog_t prog, rpcvers_t vers, 3087*0Sstevel@tonic-gate struct netconfig **nconfp, char *proto, ushort_t port, 3088*0Sstevel@tonic-gate struct t_info *tinfo) 3089*0Sstevel@tonic-gate 3090*0Sstevel@tonic-gate { 3091*0Sstevel@tonic-gate enum clnt_stat cstat; 3092*0Sstevel@tonic-gate 3093*0Sstevel@tonic-gate return (get_server_stuff(SERVER_ADDR, hostname, prog, vers, NULL, 3094*0Sstevel@tonic-gate nconfp, proto, port, tinfo, NULL, FALSE, NULL, &cstat)); 3095*0Sstevel@tonic-gate } 3096*0Sstevel@tonic-gate 3097*0Sstevel@tonic-gate static struct netbuf * 3098*0Sstevel@tonic-gate get_pubfh(char *hostname, rpcvers_t vers, mfs_snego_t *mfssnego, 3099*0Sstevel@tonic-gate struct netconfig **nconfp, char *proto, ushort_t port, 3100*0Sstevel@tonic-gate struct t_info *tinfo, caddr_t *fhp, bool_t get_pubfh, char *fspath) 3101*0Sstevel@tonic-gate { 3102*0Sstevel@tonic-gate enum clnt_stat cstat; 3103*0Sstevel@tonic-gate 3104*0Sstevel@tonic-gate return (get_server_stuff(SERVER_FH, hostname, NFS_PROGRAM, vers, 3105*0Sstevel@tonic-gate mfssnego, nconfp, proto, port, tinfo, fhp, get_pubfh, fspath, 3106*0Sstevel@tonic-gate &cstat)); 3107*0Sstevel@tonic-gate } 3108*0Sstevel@tonic-gate 3109*0Sstevel@tonic-gate static enum clnt_stat 3110*0Sstevel@tonic-gate get_ping(char *hostname, rpcprog_t prog, rpcvers_t vers, 3111*0Sstevel@tonic-gate struct netconfig **nconfp, ushort_t port, bool_t direct_to_server) 3112*0Sstevel@tonic-gate { 3113*0Sstevel@tonic-gate enum clnt_stat cstat; 3114*0Sstevel@tonic-gate 3115*0Sstevel@tonic-gate (void) get_server_stuff(SERVER_PING, hostname, prog, vers, NULL, nconfp, 3116*0Sstevel@tonic-gate NULL, port, NULL, NULL, direct_to_server, NULL, &cstat); 3117*0Sstevel@tonic-gate 3118*0Sstevel@tonic-gate return (cstat); 3119*0Sstevel@tonic-gate } 3120*0Sstevel@tonic-gate 3121*0Sstevel@tonic-gate static void * 3122*0Sstevel@tonic-gate get_server_stuff( 3123*0Sstevel@tonic-gate enum type_of_stuff type_of_stuff, 3124*0Sstevel@tonic-gate char *hostname, 3125*0Sstevel@tonic-gate rpcprog_t prog, 3126*0Sstevel@tonic-gate rpcvers_t vers, 3127*0Sstevel@tonic-gate mfs_snego_t *mfssnego, 3128*0Sstevel@tonic-gate struct netconfig **nconfp, 3129*0Sstevel@tonic-gate char *proto, 3130*0Sstevel@tonic-gate ushort_t port, /* may be zero */ 3131*0Sstevel@tonic-gate struct t_info *tinfo, 3132*0Sstevel@tonic-gate caddr_t *fhp, 3133*0Sstevel@tonic-gate bool_t direct_to_server, 3134*0Sstevel@tonic-gate char *fspath, 3135*0Sstevel@tonic-gate enum clnt_stat *cstatp) 3136*0Sstevel@tonic-gate { 3137*0Sstevel@tonic-gate struct netbuf *nb = NULL; 3138*0Sstevel@tonic-gate struct netconfig *nconf = NULL; 3139*0Sstevel@tonic-gate NCONF_HANDLE *nc = NULL; 3140*0Sstevel@tonic-gate int nthtry = FIRST_TRY; 3141*0Sstevel@tonic-gate 3142*0Sstevel@tonic-gate if (nconfp && *nconfp) 3143*0Sstevel@tonic-gate return (get_the_stuff(type_of_stuff, hostname, prog, vers, 3144*0Sstevel@tonic-gate mfssnego, *nconfp, port, tinfo, fhp, direct_to_server, 3145*0Sstevel@tonic-gate fspath, cstatp)); 3146*0Sstevel@tonic-gate 3147*0Sstevel@tonic-gate 3148*0Sstevel@tonic-gate /* 3149*0Sstevel@tonic-gate * No nconf passed in. 3150*0Sstevel@tonic-gate * 3151*0Sstevel@tonic-gate * Try to get a nconf from /etc/netconfig. 3152*0Sstevel@tonic-gate * First choice is COTS, second is CLTS unless proto 3153*0Sstevel@tonic-gate * is specified. When we retry, we reset the 3154*0Sstevel@tonic-gate * netconfig list, so that we search the whole list 3155*0Sstevel@tonic-gate * for the next choice. 3156*0Sstevel@tonic-gate */ 3157*0Sstevel@tonic-gate if ((nc = setnetpath()) == NULL) 3158*0Sstevel@tonic-gate goto done; 3159*0Sstevel@tonic-gate 3160*0Sstevel@tonic-gate /* 3161*0Sstevel@tonic-gate * If proto is specified, then only search for the match, 3162*0Sstevel@tonic-gate * otherwise try COTS first, if failed, then try CLTS. 3163*0Sstevel@tonic-gate */ 3164*0Sstevel@tonic-gate if (proto) { 3165*0Sstevel@tonic-gate 3166*0Sstevel@tonic-gate while (nconf = getnetpath(nc)) { 3167*0Sstevel@tonic-gate if (strcmp(nconf->nc_proto, proto)) 3168*0Sstevel@tonic-gate continue; 3169*0Sstevel@tonic-gate /* 3170*0Sstevel@tonic-gate * If the port number is specified then TCP/UDP 3171*0Sstevel@tonic-gate * is needed. Otherwise any cots/clts will do. 3172*0Sstevel@tonic-gate */ 3173*0Sstevel@tonic-gate if (port) { 3174*0Sstevel@tonic-gate if ((strcmp(nconf->nc_protofmly, NC_INET) && 3175*0Sstevel@tonic-gate strcmp(nconf->nc_protofmly, NC_INET6)) || 3176*0Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) && 3177*0Sstevel@tonic-gate strcmp(nconf->nc_proto, NC_UDP))) 3178*0Sstevel@tonic-gate continue; 3179*0Sstevel@tonic-gate } 3180*0Sstevel@tonic-gate 3181*0Sstevel@tonic-gate nb = get_the_stuff(type_of_stuff, hostname, prog, vers, 3182*0Sstevel@tonic-gate mfssnego, nconf, port, tinfo, fhp, 3183*0Sstevel@tonic-gate direct_to_server, fspath, cstatp); 3184*0Sstevel@tonic-gate 3185*0Sstevel@tonic-gate if (*cstatp == RPC_SUCCESS) 3186*0Sstevel@tonic-gate break; 3187*0Sstevel@tonic-gate 3188*0Sstevel@tonic-gate assert(nb == NULL); 3189*0Sstevel@tonic-gate 3190*0Sstevel@tonic-gate } /* end of while */ 3191*0Sstevel@tonic-gate 3192*0Sstevel@tonic-gate if (nconf == NULL) 3193*0Sstevel@tonic-gate goto done; 3194*0Sstevel@tonic-gate 3195*0Sstevel@tonic-gate } else { 3196*0Sstevel@tonic-gate retry: 3197*0Sstevel@tonic-gate while (nconf = getnetpath(nc)) { 3198*0Sstevel@tonic-gate if (nconf->nc_flag & NC_VISIBLE) { 3199*0Sstevel@tonic-gate if (nthtry == FIRST_TRY) { 3200*0Sstevel@tonic-gate if ((nconf->nc_semantics == NC_TPI_COTS_ORD) || 3201*0Sstevel@tonic-gate (nconf->nc_semantics == NC_TPI_COTS)) { 3202*0Sstevel@tonic-gate if (port == 0) 3203*0Sstevel@tonic-gate break; 3204*0Sstevel@tonic-gate if ((strcmp(nconf->nc_protofmly, 3205*0Sstevel@tonic-gate NC_INET) == 0 || 3206*0Sstevel@tonic-gate strcmp(nconf->nc_protofmly, 3207*0Sstevel@tonic-gate NC_INET6) == 0) && 3208*0Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_TCP) == 0)) 3209*0Sstevel@tonic-gate break; 3210*0Sstevel@tonic-gate } 3211*0Sstevel@tonic-gate } 3212*0Sstevel@tonic-gate if (nthtry == SECOND_TRY) { 3213*0Sstevel@tonic-gate if (nconf->nc_semantics == NC_TPI_CLTS) { 3214*0Sstevel@tonic-gate if (port == 0) 3215*0Sstevel@tonic-gate break; 3216*0Sstevel@tonic-gate if ((strcmp(nconf->nc_protofmly, 3217*0Sstevel@tonic-gate NC_INET) == 0 || 3218*0Sstevel@tonic-gate strcmp(nconf->nc_protofmly, 3219*0Sstevel@tonic-gate NC_INET6) == 0) && 3220*0Sstevel@tonic-gate (strcmp(nconf->nc_proto, NC_UDP) == 0)) 3221*0Sstevel@tonic-gate break; 3222*0Sstevel@tonic-gate } 3223*0Sstevel@tonic-gate } 3224*0Sstevel@tonic-gate } 3225*0Sstevel@tonic-gate } /* while */ 3226*0Sstevel@tonic-gate if (nconf == NULL) { 3227*0Sstevel@tonic-gate if (++nthtry <= MNT_PREF_LISTLEN) { 3228*0Sstevel@tonic-gate endnetpath(nc); 3229*0Sstevel@tonic-gate if ((nc = setnetpath()) == NULL) 3230*0Sstevel@tonic-gate goto done; 3231*0Sstevel@tonic-gate goto retry; 3232*0Sstevel@tonic-gate } else 3233*0Sstevel@tonic-gate goto done; 3234*0Sstevel@tonic-gate } else { 3235*0Sstevel@tonic-gate nb = get_the_stuff(type_of_stuff, hostname, prog, vers, 3236*0Sstevel@tonic-gate mfssnego, nconf, port, tinfo, fhp, direct_to_server, 3237*0Sstevel@tonic-gate fspath, cstatp); 3238*0Sstevel@tonic-gate if (*cstatp != RPC_SUCCESS) 3239*0Sstevel@tonic-gate /* 3240*0Sstevel@tonic-gate * Continue the same search path in the 3241*0Sstevel@tonic-gate * netconfig db until no more matched nconf 3242*0Sstevel@tonic-gate * (nconf == NULL). 3243*0Sstevel@tonic-gate */ 3244*0Sstevel@tonic-gate goto retry; 3245*0Sstevel@tonic-gate } 3246*0Sstevel@tonic-gate } /* if !proto */ 3247*0Sstevel@tonic-gate 3248*0Sstevel@tonic-gate /* 3249*0Sstevel@tonic-gate * Got nconf and nb. Now dup the netconfig structure (nconf) 3250*0Sstevel@tonic-gate * and return it thru nconfp. 3251*0Sstevel@tonic-gate */ 3252*0Sstevel@tonic-gate *nconfp = getnetconfigent(nconf->nc_netid); 3253*0Sstevel@tonic-gate if (*nconfp == NULL) { 3254*0Sstevel@tonic-gate syslog(LOG_ERR, "no memory\n"); 3255*0Sstevel@tonic-gate free(nb); 3256*0Sstevel@tonic-gate nb = NULL; 3257*0Sstevel@tonic-gate } 3258*0Sstevel@tonic-gate done: 3259*0Sstevel@tonic-gate if (nc) 3260*0Sstevel@tonic-gate endnetpath(nc); 3261*0Sstevel@tonic-gate return (nb); 3262*0Sstevel@tonic-gate } 3263*0Sstevel@tonic-gate 3264*0Sstevel@tonic-gate 3265*0Sstevel@tonic-gate /* 3266*0Sstevel@tonic-gate * Sends a null call to the remote host's (NFS program, versp). versp 3267*0Sstevel@tonic-gate * may be "NULL" in which case the default maximum version is used. 3268*0Sstevel@tonic-gate * Upon return, versp contains the maximum version supported iff versp!= NULL. 3269*0Sstevel@tonic-gate */ 3270*0Sstevel@tonic-gate enum clnt_stat 3271*0Sstevel@tonic-gate pingnfs( 3272*0Sstevel@tonic-gate char *hostpart, 3273*0Sstevel@tonic-gate int attempts, 3274*0Sstevel@tonic-gate rpcvers_t *versp, 3275*0Sstevel@tonic-gate rpcvers_t versmin, 3276*0Sstevel@tonic-gate ushort_t port, /* may be zeor */ 3277*0Sstevel@tonic-gate bool_t usepub, 3278*0Sstevel@tonic-gate char *path, 3279*0Sstevel@tonic-gate char *proto) 3280*0Sstevel@tonic-gate { 3281*0Sstevel@tonic-gate CLIENT *cl = NULL; 3282*0Sstevel@tonic-gate struct timeval rpc_to_new = {15, 0}; 3283*0Sstevel@tonic-gate static struct timeval rpc_rtrans_new = {-1, -1}; 3284*0Sstevel@tonic-gate enum clnt_stat clnt_stat; 3285*0Sstevel@tonic-gate int i, j; 3286*0Sstevel@tonic-gate rpcvers_t versmax; /* maximum version to try against server */ 3287*0Sstevel@tonic-gate rpcvers_t outvers; /* version supported by host on last call */ 3288*0Sstevel@tonic-gate rpcvers_t vers_to_try; /* to try different versions against host */ 3289*0Sstevel@tonic-gate char *hostname = hostpart; 3290*0Sstevel@tonic-gate struct netconfig *nconf; 3291*0Sstevel@tonic-gate 3292*0Sstevel@tonic-gate if (path != NULL && strcmp(hostname, "nfs") == 0 && 3293*0Sstevel@tonic-gate strncmp(path, "//", 2) == 0) { 3294*0Sstevel@tonic-gate char *sport; 3295*0Sstevel@tonic-gate 3296*0Sstevel@tonic-gate hostname = strdup(path+2); 3297*0Sstevel@tonic-gate 3298*0Sstevel@tonic-gate if (hostname == NULL) 3299*0Sstevel@tonic-gate return (RPC_SYSTEMERROR); 3300*0Sstevel@tonic-gate 3301*0Sstevel@tonic-gate path = strchr(hostname, '/'); 3302*0Sstevel@tonic-gate 3303*0Sstevel@tonic-gate /* 3304*0Sstevel@tonic-gate * This cannot happen. If it does, give up 3305*0Sstevel@tonic-gate * on the ping as this is obviously a corrupt 3306*0Sstevel@tonic-gate * entry. 3307*0Sstevel@tonic-gate */ 3308*0Sstevel@tonic-gate if (path == NULL) { 3309*0Sstevel@tonic-gate free(hostname); 3310*0Sstevel@tonic-gate return (RPC_SUCCESS); 3311*0Sstevel@tonic-gate } 3312*0Sstevel@tonic-gate 3313*0Sstevel@tonic-gate /* 3314*0Sstevel@tonic-gate * Probable end point of host string. 3315*0Sstevel@tonic-gate */ 3316*0Sstevel@tonic-gate *path = '\0'; 3317*0Sstevel@tonic-gate 3318*0Sstevel@tonic-gate sport = strchr(hostname, ':'); 3319*0Sstevel@tonic-gate 3320*0Sstevel@tonic-gate if (sport != NULL && sport < path) { 3321*0Sstevel@tonic-gate 3322*0Sstevel@tonic-gate /* 3323*0Sstevel@tonic-gate * Actual end point of host string. 3324*0Sstevel@tonic-gate */ 3325*0Sstevel@tonic-gate *sport = '\0'; 3326*0Sstevel@tonic-gate port = htons((ushort_t)atoi(sport+1)); 3327*0Sstevel@tonic-gate } 3328*0Sstevel@tonic-gate 3329*0Sstevel@tonic-gate usepub = TRUE; 3330*0Sstevel@tonic-gate } 3331*0Sstevel@tonic-gate 3332*0Sstevel@tonic-gate /* Pick up the default versions and then set them appropriately */ 3333*0Sstevel@tonic-gate if (versp) { 3334*0Sstevel@tonic-gate versmax = *versp; 3335*0Sstevel@tonic-gate /* use versmin passed in */ 3336*0Sstevel@tonic-gate } else { 3337*0Sstevel@tonic-gate read_default_nfs(); 3338*0Sstevel@tonic-gate set_versrange(0, &versmax, &versmin); 3339*0Sstevel@tonic-gate } 3340*0Sstevel@tonic-gate 3341*0Sstevel@tonic-gate if (proto && 3342*0Sstevel@tonic-gate strncasecmp(proto, NC_UDP, strlen(NC_UDP)) == 0 && 3343*0Sstevel@tonic-gate versmax == NFS_V4) { 3344*0Sstevel@tonic-gate if (versmin == NFS_V4) { 3345*0Sstevel@tonic-gate if (versp) { 3346*0Sstevel@tonic-gate *versp = versmax - 1; 3347*0Sstevel@tonic-gate return (RPC_SUCCESS); 3348*0Sstevel@tonic-gate } 3349*0Sstevel@tonic-gate return (RPC_PROGUNAVAIL); 3350*0Sstevel@tonic-gate } else { 3351*0Sstevel@tonic-gate versmax--; 3352*0Sstevel@tonic-gate } 3353*0Sstevel@tonic-gate } 3354*0Sstevel@tonic-gate 3355*0Sstevel@tonic-gate if (versp) 3356*0Sstevel@tonic-gate *versp = versmax; 3357*0Sstevel@tonic-gate 3358*0Sstevel@tonic-gate switch (cache_check(hostname, versp, proto)) { 3359*0Sstevel@tonic-gate case GOODHOST: 3360*0Sstevel@tonic-gate if (hostname != hostpart) 3361*0Sstevel@tonic-gate free(hostname); 3362*0Sstevel@tonic-gate return (RPC_SUCCESS); 3363*0Sstevel@tonic-gate case DEADHOST: 3364*0Sstevel@tonic-gate if (hostname != hostpart) 3365*0Sstevel@tonic-gate free(hostname); 3366*0Sstevel@tonic-gate return (RPC_TIMEDOUT); 3367*0Sstevel@tonic-gate case NOHOST: 3368*0Sstevel@tonic-gate default: 3369*0Sstevel@tonic-gate break; 3370*0Sstevel@tonic-gate } 3371*0Sstevel@tonic-gate 3372*0Sstevel@tonic-gate /* 3373*0Sstevel@tonic-gate * XXX The retransmission time rpcbrmttime is a global defined 3374*0Sstevel@tonic-gate * in the rpc library (rpcb_clnt.c). We use (and like) the default 3375*0Sstevel@tonic-gate * value of 15 sec in the rpc library. The code below is to protect 3376*0Sstevel@tonic-gate * us in case it changes. This need not be done under a lock since 3377*0Sstevel@tonic-gate * any # of threads entering this function will get the same 3378*0Sstevel@tonic-gate * retransmission value. 3379*0Sstevel@tonic-gate */ 3380*0Sstevel@tonic-gate if (rpc_rtrans_new.tv_sec == -1 && rpc_rtrans_new.tv_usec == -1) { 3381*0Sstevel@tonic-gate __rpc_control(CLCR_GET_RPCB_RMTTIME, (char *)&rpc_rtrans_new); 3382*0Sstevel@tonic-gate if (rpc_rtrans_new.tv_sec != 15 && rpc_rtrans_new.tv_sec != 0) 3383*0Sstevel@tonic-gate if (trace > 1) 3384*0Sstevel@tonic-gate trace_prt(1, "RPC library rttimer changed\n"); 3385*0Sstevel@tonic-gate } 3386*0Sstevel@tonic-gate 3387*0Sstevel@tonic-gate /* 3388*0Sstevel@tonic-gate * XXX Manipulate the total timeout to get the number of 3389*0Sstevel@tonic-gate * desired retransmissions. This code is heavily dependant on 3390*0Sstevel@tonic-gate * the RPC backoff mechanism in clnt_dg_call (clnt_dg.c). 3391*0Sstevel@tonic-gate */ 3392*0Sstevel@tonic-gate for (i = 0, j = rpc_rtrans_new.tv_sec; i < attempts-1; i++) { 3393*0Sstevel@tonic-gate if (j < RPC_MAX_BACKOFF) 3394*0Sstevel@tonic-gate j *= 2; 3395*0Sstevel@tonic-gate else 3396*0Sstevel@tonic-gate j = RPC_MAX_BACKOFF; 3397*0Sstevel@tonic-gate rpc_to_new.tv_sec += j; 3398*0Sstevel@tonic-gate } 3399*0Sstevel@tonic-gate 3400*0Sstevel@tonic-gate vers_to_try = versmax; 3401*0Sstevel@tonic-gate 3402*0Sstevel@tonic-gate /* 3403*0Sstevel@tonic-gate * check the host's version within the timeout 3404*0Sstevel@tonic-gate */ 3405*0Sstevel@tonic-gate if (trace > 1) 3406*0Sstevel@tonic-gate trace_prt(1, " ping: %s timeout=%ld request vers=%d min=%d\n", 3407*0Sstevel@tonic-gate hostname, rpc_to_new.tv_sec, versmax, versmin); 3408*0Sstevel@tonic-gate 3409*0Sstevel@tonic-gate if (usepub == FALSE) { 3410*0Sstevel@tonic-gate do { 3411*0Sstevel@tonic-gate /* 3412*0Sstevel@tonic-gate * If NFSv4, then we do the same thing as is used 3413*0Sstevel@tonic-gate * for public filehandles so that we avoid rpcbind 3414*0Sstevel@tonic-gate */ 3415*0Sstevel@tonic-gate if (vers_to_try == NFS_V4) { 3416*0Sstevel@tonic-gate if (trace > 4) { 3417*0Sstevel@tonic-gate trace_prt(1, " pingnfs: Trying ping via " 3418*0Sstevel@tonic-gate "\"circuit_v\"\n"); 3419*0Sstevel@tonic-gate } 3420*0Sstevel@tonic-gate 3421*0Sstevel@tonic-gate if ((cl = clnt_create_service_timed(hostname, "nfs", 3422*0Sstevel@tonic-gate NFS_PROGRAM, 3423*0Sstevel@tonic-gate vers_to_try, 3424*0Sstevel@tonic-gate port, "circuit_v", 3425*0Sstevel@tonic-gate &rpc_to_new)) 3426*0Sstevel@tonic-gate != NULL) { 3427*0Sstevel@tonic-gate outvers = vers_to_try; 3428*0Sstevel@tonic-gate break; 3429*0Sstevel@tonic-gate } 3430*0Sstevel@tonic-gate if (trace > 4) { 3431*0Sstevel@tonic-gate trace_prt(1, " pingnfs: Can't ping via " 3432*0Sstevel@tonic-gate "\"circuit_v\" %s: RPC error=%d\n", 3433*0Sstevel@tonic-gate hostname, rpc_createerr.cf_stat); 3434*0Sstevel@tonic-gate } 3435*0Sstevel@tonic-gate 3436*0Sstevel@tonic-gate } else { 3437*0Sstevel@tonic-gate if ((cl = clnt_create_vers_timed(hostname, NFS_PROGRAM, 3438*0Sstevel@tonic-gate &outvers, versmin, vers_to_try, 3439*0Sstevel@tonic-gate "datagram_v", &rpc_to_new)) 3440*0Sstevel@tonic-gate != NULL) 3441*0Sstevel@tonic-gate break; 3442*0Sstevel@tonic-gate if (trace > 4) { 3443*0Sstevel@tonic-gate trace_prt(1, " pingnfs: Can't ping via " 3444*0Sstevel@tonic-gate "\"datagram_v\"%s: RPC error=%d\n", 3445*0Sstevel@tonic-gate hostname, rpc_createerr.cf_stat); 3446*0Sstevel@tonic-gate } 3447*0Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_UNKNOWNHOST || 3448*0Sstevel@tonic-gate rpc_createerr.cf_stat == RPC_TIMEDOUT) 3449*0Sstevel@tonic-gate break; 3450*0Sstevel@tonic-gate if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) { 3451*0Sstevel@tonic-gate if (trace > 4) { 3452*0Sstevel@tonic-gate trace_prt(1, " pingnfs: Trying ping " 3453*0Sstevel@tonic-gate "via \"circuit_v\"\n"); 3454*0Sstevel@tonic-gate } 3455*0Sstevel@tonic-gate if ((cl = clnt_create_vers_timed(hostname, 3456*0Sstevel@tonic-gate NFS_PROGRAM, &outvers, 3457*0Sstevel@tonic-gate versmin, vers_to_try, 3458*0Sstevel@tonic-gate "circuit_v", &rpc_to_new)) != NULL) 3459*0Sstevel@tonic-gate break; 3460*0Sstevel@tonic-gate if (trace > 4) { 3461*0Sstevel@tonic-gate trace_prt(1, " pingnfs: Can't ping " 3462*0Sstevel@tonic-gate "via \"circuit_v\" %s: " 3463*0Sstevel@tonic-gate "RPC error=%d\n", 3464*0Sstevel@tonic-gate hostname, 3465*0Sstevel@tonic-gate rpc_createerr.cf_stat); 3466*0Sstevel@tonic-gate } 3467*0Sstevel@tonic-gate } 3468*0Sstevel@tonic-gate } 3469*0Sstevel@tonic-gate 3470*0Sstevel@tonic-gate /* 3471*0Sstevel@tonic-gate * backoff and return lower version to retry the ping. 3472*0Sstevel@tonic-gate * XXX we should be more careful and handle 3473*0Sstevel@tonic-gate * RPC_PROGVERSMISMATCH here, because that error is handled 3474*0Sstevel@tonic-gate * in clnt_create_vers(). It's not done to stay in sync 3475*0Sstevel@tonic-gate * with the nfs mount command. 3476*0Sstevel@tonic-gate */ 3477*0Sstevel@tonic-gate vers_to_try--; 3478*0Sstevel@tonic-gate if (vers_to_try < versmin) 3479*0Sstevel@tonic-gate break; 3480*0Sstevel@tonic-gate if (versp != NULL) { /* recheck the cache */ 3481*0Sstevel@tonic-gate *versp = vers_to_try; 3482*0Sstevel@tonic-gate if (trace > 4) { 3483*0Sstevel@tonic-gate trace_prt(1, 3484*0Sstevel@tonic-gate " pingnfs: check cache: vers=%d\n", 3485*0Sstevel@tonic-gate *versp); 3486*0Sstevel@tonic-gate } 3487*0Sstevel@tonic-gate switch (cache_check(hostname, versp, proto)) { 3488*0Sstevel@tonic-gate case GOODHOST: 3489*0Sstevel@tonic-gate if (hostname != hostpart) 3490*0Sstevel@tonic-gate free(hostname); 3491*0Sstevel@tonic-gate return (RPC_SUCCESS); 3492*0Sstevel@tonic-gate case DEADHOST: 3493*0Sstevel@tonic-gate if (hostname != hostpart) 3494*0Sstevel@tonic-gate free(hostname); 3495*0Sstevel@tonic-gate return (RPC_TIMEDOUT); 3496*0Sstevel@tonic-gate case NOHOST: 3497*0Sstevel@tonic-gate default: 3498*0Sstevel@tonic-gate break; 3499*0Sstevel@tonic-gate } 3500*0Sstevel@tonic-gate } 3501*0Sstevel@tonic-gate if (trace > 4) { 3502*0Sstevel@tonic-gate trace_prt(1, " pingnfs: Try version=%d\n", 3503*0Sstevel@tonic-gate vers_to_try); 3504*0Sstevel@tonic-gate } 3505*0Sstevel@tonic-gate } while (cl == NULL); 3506*0Sstevel@tonic-gate 3507*0Sstevel@tonic-gate 3508*0Sstevel@tonic-gate if (cl == NULL) { 3509*0Sstevel@tonic-gate if (verbose) 3510*0Sstevel@tonic-gate syslog(LOG_ERR, "pingnfs: %s%s", 3511*0Sstevel@tonic-gate hostname, clnt_spcreateerror("")); 3512*0Sstevel@tonic-gate clnt_stat = rpc_createerr.cf_stat; 3513*0Sstevel@tonic-gate } else { 3514*0Sstevel@tonic-gate clnt_destroy(cl); 3515*0Sstevel@tonic-gate clnt_stat = RPC_SUCCESS; 3516*0Sstevel@tonic-gate } 3517*0Sstevel@tonic-gate 3518*0Sstevel@tonic-gate } else { 3519*0Sstevel@tonic-gate for (vers_to_try = versmax; vers_to_try >= versmin; 3520*0Sstevel@tonic-gate vers_to_try--) { 3521*0Sstevel@tonic-gate 3522*0Sstevel@tonic-gate nconf = NULL; 3523*0Sstevel@tonic-gate 3524*0Sstevel@tonic-gate if (trace > 4) { 3525*0Sstevel@tonic-gate trace_prt(1, " pingnfs: Try version=%d " 3526*0Sstevel@tonic-gate "using get_ping()\n", vers_to_try); 3527*0Sstevel@tonic-gate } 3528*0Sstevel@tonic-gate 3529*0Sstevel@tonic-gate clnt_stat = get_ping(hostname, NFS_PROGRAM, 3530*0Sstevel@tonic-gate vers_to_try, &nconf, port, TRUE); 3531*0Sstevel@tonic-gate 3532*0Sstevel@tonic-gate if (nconf != NULL) 3533*0Sstevel@tonic-gate freenetconfigent(nconf); 3534*0Sstevel@tonic-gate 3535*0Sstevel@tonic-gate if (clnt_stat == RPC_SUCCESS) { 3536*0Sstevel@tonic-gate outvers = vers_to_try; 3537*0Sstevel@tonic-gate break; 3538*0Sstevel@tonic-gate } 3539*0Sstevel@tonic-gate } 3540*0Sstevel@tonic-gate } 3541*0Sstevel@tonic-gate 3542*0Sstevel@tonic-gate if (trace > 1) 3543*0Sstevel@tonic-gate clnt_stat == RPC_SUCCESS ? 3544*0Sstevel@tonic-gate trace_prt(1, " pingnfs OK: nfs version=%d\n", outvers): 3545*0Sstevel@tonic-gate trace_prt(1, " pingnfs FAIL: can't get nfs version\n"); 3546*0Sstevel@tonic-gate 3547*0Sstevel@tonic-gate if (clnt_stat == RPC_SUCCESS) { 3548*0Sstevel@tonic-gate cache_enter(hostname, versmax, outvers, proto, GOODHOST); 3549*0Sstevel@tonic-gate if (versp != NULL) 3550*0Sstevel@tonic-gate *versp = outvers; 3551*0Sstevel@tonic-gate } else 3552*0Sstevel@tonic-gate cache_enter(hostname, versmax, versmax, proto, DEADHOST); 3553*0Sstevel@tonic-gate 3554*0Sstevel@tonic-gate if (hostpart != hostname) 3555*0Sstevel@tonic-gate free(hostname); 3556*0Sstevel@tonic-gate 3557*0Sstevel@tonic-gate return (clnt_stat); 3558*0Sstevel@tonic-gate } 3559*0Sstevel@tonic-gate 3560*0Sstevel@tonic-gate #define MNTTYPE_LOFS "lofs" 3561*0Sstevel@tonic-gate 3562*0Sstevel@tonic-gate int 3563*0Sstevel@tonic-gate loopbackmount(fsname, dir, mntopts, overlay) 3564*0Sstevel@tonic-gate char *fsname; /* Directory being mounted */ 3565*0Sstevel@tonic-gate char *dir; /* Directory being mounted on */ 3566*0Sstevel@tonic-gate char *mntopts; 3567*0Sstevel@tonic-gate int overlay; 3568*0Sstevel@tonic-gate { 3569*0Sstevel@tonic-gate struct mnttab mnt; 3570*0Sstevel@tonic-gate int flags = 0; 3571*0Sstevel@tonic-gate char fstype[] = MNTTYPE_LOFS; 3572*0Sstevel@tonic-gate int dirlen; 3573*0Sstevel@tonic-gate struct stat st; 3574*0Sstevel@tonic-gate char optbuf[MAX_MNTOPT_STR]; 3575*0Sstevel@tonic-gate 3576*0Sstevel@tonic-gate dirlen = strlen(dir); 3577*0Sstevel@tonic-gate if (dir[dirlen-1] == ' ') 3578*0Sstevel@tonic-gate dirlen--; 3579*0Sstevel@tonic-gate 3580*0Sstevel@tonic-gate if (dirlen == strlen(fsname) && 3581*0Sstevel@tonic-gate strncmp(fsname, dir, dirlen) == 0) { 3582*0Sstevel@tonic-gate syslog(LOG_ERR, 3583*0Sstevel@tonic-gate "Mount of %s on %s would result in deadlock, aborted\n", 3584*0Sstevel@tonic-gate fsname, dir); 3585*0Sstevel@tonic-gate return (RET_ERR); 3586*0Sstevel@tonic-gate } 3587*0Sstevel@tonic-gate mnt.mnt_mntopts = mntopts; 3588*0Sstevel@tonic-gate if (hasmntopt(&mnt, MNTOPT_RO) != NULL) 3589*0Sstevel@tonic-gate flags |= MS_RDONLY; 3590*0Sstevel@tonic-gate 3591*0Sstevel@tonic-gate (void) strlcpy(optbuf, mntopts, sizeof (optbuf)); 3592*0Sstevel@tonic-gate 3593*0Sstevel@tonic-gate if (overlay) 3594*0Sstevel@tonic-gate flags |= MS_OVERLAY; 3595*0Sstevel@tonic-gate 3596*0Sstevel@tonic-gate if (trace > 1) 3597*0Sstevel@tonic-gate trace_prt(1, 3598*0Sstevel@tonic-gate " loopbackmount: fsname=%s, dir=%s, flags=%d\n", 3599*0Sstevel@tonic-gate fsname, dir, flags); 3600*0Sstevel@tonic-gate 3601*0Sstevel@tonic-gate if (mount(fsname, dir, flags | MS_DATA | MS_OPTIONSTR, fstype, 3602*0Sstevel@tonic-gate NULL, 0, optbuf, sizeof (optbuf)) < 0) { 3603*0Sstevel@tonic-gate syslog(LOG_ERR, "Mount of %s on %s: %m", fsname, dir); 3604*0Sstevel@tonic-gate return (RET_ERR); 3605*0Sstevel@tonic-gate } 3606*0Sstevel@tonic-gate 3607*0Sstevel@tonic-gate if (stat(dir, &st) == 0) { 3608*0Sstevel@tonic-gate if (trace > 1) { 3609*0Sstevel@tonic-gate trace_prt(1, 3610*0Sstevel@tonic-gate " loopbackmount of %s on %s dev=%x rdev=%x OK\n", 3611*0Sstevel@tonic-gate fsname, dir, st.st_dev, st.st_rdev); 3612*0Sstevel@tonic-gate } 3613*0Sstevel@tonic-gate } else { 3614*0Sstevel@tonic-gate if (trace > 1) { 3615*0Sstevel@tonic-gate trace_prt(1, 3616*0Sstevel@tonic-gate " loopbackmount of %s on %s OK\n", fsname, dir); 3617*0Sstevel@tonic-gate trace_prt(1, " stat of %s failed\n", dir); 3618*0Sstevel@tonic-gate } 3619*0Sstevel@tonic-gate } 3620*0Sstevel@tonic-gate 3621*0Sstevel@tonic-gate return (0); 3622*0Sstevel@tonic-gate } 3623*0Sstevel@tonic-gate 3624*0Sstevel@tonic-gate /* 3625*0Sstevel@tonic-gate * Look for the value of a numeric option of the form foo=x. If found, set 3626*0Sstevel@tonic-gate * *valp to the value and return non-zero. If not found or the option is 3627*0Sstevel@tonic-gate * malformed, return zero. 3628*0Sstevel@tonic-gate */ 3629*0Sstevel@tonic-gate 3630*0Sstevel@tonic-gate int 3631*0Sstevel@tonic-gate nopt(mnt, opt, valp) 3632*0Sstevel@tonic-gate struct mnttab *mnt; 3633*0Sstevel@tonic-gate char *opt; 3634*0Sstevel@tonic-gate int *valp; /* OUT */ 3635*0Sstevel@tonic-gate { 3636*0Sstevel@tonic-gate char *equal; 3637*0Sstevel@tonic-gate char *str; 3638*0Sstevel@tonic-gate 3639*0Sstevel@tonic-gate /* 3640*0Sstevel@tonic-gate * We should never get a null pointer, but if we do, it's better to 3641*0Sstevel@tonic-gate * ignore the option than to dump core. 3642*0Sstevel@tonic-gate */ 3643*0Sstevel@tonic-gate 3644*0Sstevel@tonic-gate if (valp == NULL) { 3645*0Sstevel@tonic-gate syslog(LOG_DEBUG, "null pointer for %s option", opt); 3646*0Sstevel@tonic-gate return (0); 3647*0Sstevel@tonic-gate } 3648*0Sstevel@tonic-gate 3649*0Sstevel@tonic-gate if (str = hasmntopt(mnt, opt)) { 3650*0Sstevel@tonic-gate if (equal = strchr(str, '=')) { 3651*0Sstevel@tonic-gate *valp = atoi(&equal[1]); 3652*0Sstevel@tonic-gate return (1); 3653*0Sstevel@tonic-gate } else { 3654*0Sstevel@tonic-gate syslog(LOG_ERR, "Bad numeric option '%s'", str); 3655*0Sstevel@tonic-gate } 3656*0Sstevel@tonic-gate } 3657*0Sstevel@tonic-gate return (0); 3658*0Sstevel@tonic-gate } 3659*0Sstevel@tonic-gate 3660*0Sstevel@tonic-gate nfsunmount(mnt) 3661*0Sstevel@tonic-gate struct mnttab *mnt; 3662*0Sstevel@tonic-gate { 3663*0Sstevel@tonic-gate struct timeval timeout; 3664*0Sstevel@tonic-gate CLIENT *cl; 3665*0Sstevel@tonic-gate enum clnt_stat rpc_stat; 3666*0Sstevel@tonic-gate char *host, *path; 3667*0Sstevel@tonic-gate struct replica *list; 3668*0Sstevel@tonic-gate int i, count = 0; 3669*0Sstevel@tonic-gate int isv4mount = is_v4_mount(mnt->mnt_mountp); 3670*0Sstevel@tonic-gate 3671*0Sstevel@tonic-gate if (trace > 1) 3672*0Sstevel@tonic-gate trace_prt(1, " nfsunmount: umount %s\n", mnt->mnt_mountp); 3673*0Sstevel@tonic-gate 3674*0Sstevel@tonic-gate if (umount(mnt->mnt_mountp) < 0) { 3675*0Sstevel@tonic-gate if (trace > 1) 3676*0Sstevel@tonic-gate trace_prt(1, " nfsunmount: umount %s FAILED\n", 3677*0Sstevel@tonic-gate mnt->mnt_mountp); 3678*0Sstevel@tonic-gate if (errno) 3679*0Sstevel@tonic-gate return (errno); 3680*0Sstevel@tonic-gate } 3681*0Sstevel@tonic-gate 3682*0Sstevel@tonic-gate /* 3683*0Sstevel@tonic-gate * If this is a NFSv4 mount, the mount protocol was not used 3684*0Sstevel@tonic-gate * so we just return. 3685*0Sstevel@tonic-gate */ 3686*0Sstevel@tonic-gate if (isv4mount) { 3687*0Sstevel@tonic-gate if (trace > 1) 3688*0Sstevel@tonic-gate trace_prt(1, " nfsunmount: umount %s OK\n", 3689*0Sstevel@tonic-gate mnt->mnt_mountp); 3690*0Sstevel@tonic-gate return (0); 3691*0Sstevel@tonic-gate } 3692*0Sstevel@tonic-gate 3693*0Sstevel@tonic-gate /* 3694*0Sstevel@tonic-gate * If mounted with -o public, then no need to contact server 3695*0Sstevel@tonic-gate * because mount protocol was not used. 3696*0Sstevel@tonic-gate */ 3697*0Sstevel@tonic-gate if (hasmntopt(mnt, MNTOPT_PUBLIC) != NULL) { 3698*0Sstevel@tonic-gate return (0); 3699*0Sstevel@tonic-gate } 3700*0Sstevel@tonic-gate 3701*0Sstevel@tonic-gate /* 3702*0Sstevel@tonic-gate * The rest of this code is advisory to the server. 3703*0Sstevel@tonic-gate * If it fails return success anyway. 3704*0Sstevel@tonic-gate */ 3705*0Sstevel@tonic-gate 3706*0Sstevel@tonic-gate list = parse_replica(mnt->mnt_special, &count); 3707*0Sstevel@tonic-gate if (!list) { 3708*0Sstevel@tonic-gate if (count >= 0) 3709*0Sstevel@tonic-gate syslog(LOG_ERR, 3710*0Sstevel@tonic-gate "Memory allocation failed: %m"); 3711*0Sstevel@tonic-gate return (ENOMEM); 3712*0Sstevel@tonic-gate } 3713*0Sstevel@tonic-gate 3714*0Sstevel@tonic-gate for (i = 0; i < count; i++) { 3715*0Sstevel@tonic-gate 3716*0Sstevel@tonic-gate host = list[i].host; 3717*0Sstevel@tonic-gate path = list[i].path; 3718*0Sstevel@tonic-gate 3719*0Sstevel@tonic-gate /* 3720*0Sstevel@tonic-gate * Skip file systems mounted using WebNFS, because mount 3721*0Sstevel@tonic-gate * protocol was not used. 3722*0Sstevel@tonic-gate */ 3723*0Sstevel@tonic-gate if (strcmp(host, "nfs") == 0 && strncmp(path, "//", 2) == 0) 3724*0Sstevel@tonic-gate continue; 3725*0Sstevel@tonic-gate 3726*0Sstevel@tonic-gate cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "datagram_v"); 3727*0Sstevel@tonic-gate if (cl == NULL) 3728*0Sstevel@tonic-gate break; 3729*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 3730*0Sstevel@tonic-gate add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__); 3731*0Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, 3732*0Sstevel@tonic-gate __FILE__, __LINE__); 3733*0Sstevel@tonic-gate #endif 3734*0Sstevel@tonic-gate if (__clnt_bindresvport(cl) < 0) { 3735*0Sstevel@tonic-gate if (verbose) 3736*0Sstevel@tonic-gate syslog(LOG_ERR, "umount %s:%s: %s", 3737*0Sstevel@tonic-gate host, path, 3738*0Sstevel@tonic-gate "Couldn't bind to reserved port"); 3739*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 3740*0Sstevel@tonic-gate continue; 3741*0Sstevel@tonic-gate } 3742*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 3743*0Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, __FILE__, __LINE__); 3744*0Sstevel@tonic-gate #endif 3745*0Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 3746*0Sstevel@tonic-gate if ((cl->cl_auth = authsys_create_default()) == NULL) { 3747*0Sstevel@tonic-gate if (verbose) 3748*0Sstevel@tonic-gate syslog(LOG_ERR, "umount %s:%s: %s", 3749*0Sstevel@tonic-gate host, path, 3750*0Sstevel@tonic-gate "Failed creating default auth handle"); 3751*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 3752*0Sstevel@tonic-gate continue; 3753*0Sstevel@tonic-gate } 3754*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 3755*0Sstevel@tonic-gate add_alloc("AUTH_HANDLE", cl->cl_auth, 0, __FILE__, __LINE__); 3756*0Sstevel@tonic-gate #endif 3757*0Sstevel@tonic-gate timeout.tv_usec = 0; 3758*0Sstevel@tonic-gate timeout.tv_sec = 5; 3759*0Sstevel@tonic-gate rpc_stat = clnt_call(cl, MOUNTPROC_UMNT, xdr_dirpath, 3760*0Sstevel@tonic-gate (caddr_t)&path, xdr_void, (char *)NULL, timeout); 3761*0Sstevel@tonic-gate if (verbose && rpc_stat != RPC_SUCCESS) 3762*0Sstevel@tonic-gate syslog(LOG_ERR, "%s: %s", 3763*0Sstevel@tonic-gate host, clnt_sperror(cl, "unmount")); 3764*0Sstevel@tonic-gate destroy_auth_client_handle(cl); 3765*0Sstevel@tonic-gate } 3766*0Sstevel@tonic-gate 3767*0Sstevel@tonic-gate free_replica(list, count); 3768*0Sstevel@tonic-gate 3769*0Sstevel@tonic-gate if (trace > 1) 3770*0Sstevel@tonic-gate trace_prt(1, " nfsunmount: umount %s OK\n", mnt->mnt_mountp); 3771*0Sstevel@tonic-gate 3772*0Sstevel@tonic-gate done: 3773*0Sstevel@tonic-gate return (0); 3774*0Sstevel@tonic-gate } 3775*0Sstevel@tonic-gate 3776*0Sstevel@tonic-gate /* 3777*0Sstevel@tonic-gate * Put a new entry in the cache chain by prepending it to the front. 3778*0Sstevel@tonic-gate * If there isn't enough memory then just give up. 3779*0Sstevel@tonic-gate */ 3780*0Sstevel@tonic-gate static void 3781*0Sstevel@tonic-gate cache_enter(host, reqvers, outvers, proto, state) 3782*0Sstevel@tonic-gate char *host; 3783*0Sstevel@tonic-gate rpcvers_t reqvers; 3784*0Sstevel@tonic-gate rpcvers_t outvers; 3785*0Sstevel@tonic-gate char *proto; 3786*0Sstevel@tonic-gate int state; 3787*0Sstevel@tonic-gate { 3788*0Sstevel@tonic-gate struct cache_entry *entry; 3789*0Sstevel@tonic-gate int cache_time = 30; /* sec */ 3790*0Sstevel@tonic-gate 3791*0Sstevel@tonic-gate timenow = time(NULL); 3792*0Sstevel@tonic-gate 3793*0Sstevel@tonic-gate entry = (struct cache_entry *)malloc(sizeof (struct cache_entry)); 3794*0Sstevel@tonic-gate if (entry == NULL) 3795*0Sstevel@tonic-gate return; 3796*0Sstevel@tonic-gate (void) memset((caddr_t)entry, 0, sizeof (struct cache_entry)); 3797*0Sstevel@tonic-gate entry->cache_host = strdup(host); 3798*0Sstevel@tonic-gate if (entry->cache_host == NULL) { 3799*0Sstevel@tonic-gate cache_free(entry); 3800*0Sstevel@tonic-gate return; 3801*0Sstevel@tonic-gate } 3802*0Sstevel@tonic-gate entry->cache_reqvers = reqvers; 3803*0Sstevel@tonic-gate entry->cache_outvers = outvers; 3804*0Sstevel@tonic-gate entry->cache_proto = (proto == NULL ? NULL : strdup(proto)); 3805*0Sstevel@tonic-gate entry->cache_state = state; 3806*0Sstevel@tonic-gate entry->cache_time = timenow + cache_time; 3807*0Sstevel@tonic-gate (void) rw_wrlock(&cache_lock); 3808*0Sstevel@tonic-gate #ifdef CACHE_DEBUG 3809*0Sstevel@tonic-gate host_cache_accesses++; /* up host cache access counter */ 3810*0Sstevel@tonic-gate #endif /* CACHE DEBUG */ 3811*0Sstevel@tonic-gate entry->cache_next = cache_head; 3812*0Sstevel@tonic-gate cache_head = entry; 3813*0Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 3814*0Sstevel@tonic-gate } 3815*0Sstevel@tonic-gate 3816*0Sstevel@tonic-gate static int 3817*0Sstevel@tonic-gate cache_check(host, versp, proto) 3818*0Sstevel@tonic-gate char *host; 3819*0Sstevel@tonic-gate rpcvers_t *versp; 3820*0Sstevel@tonic-gate char *proto; 3821*0Sstevel@tonic-gate { 3822*0Sstevel@tonic-gate int state = NOHOST; 3823*0Sstevel@tonic-gate struct cache_entry *ce, *prev; 3824*0Sstevel@tonic-gate 3825*0Sstevel@tonic-gate timenow = time(NULL); 3826*0Sstevel@tonic-gate 3827*0Sstevel@tonic-gate (void) rw_rdlock(&cache_lock); 3828*0Sstevel@tonic-gate 3829*0Sstevel@tonic-gate #ifdef CACHE_DEBUG 3830*0Sstevel@tonic-gate /* Increment the lookup and access counters for the host cache */ 3831*0Sstevel@tonic-gate host_cache_accesses++; 3832*0Sstevel@tonic-gate host_cache_lookups++; 3833*0Sstevel@tonic-gate if ((host_cache_lookups%1000) == 0) 3834*0Sstevel@tonic-gate trace_host_cache(); 3835*0Sstevel@tonic-gate #endif /* CACHE DEBUG */ 3836*0Sstevel@tonic-gate 3837*0Sstevel@tonic-gate for (ce = cache_head; ce; ce = ce->cache_next) { 3838*0Sstevel@tonic-gate if (timenow > ce->cache_time) { 3839*0Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 3840*0Sstevel@tonic-gate (void) rw_wrlock(&cache_lock); 3841*0Sstevel@tonic-gate for (prev = NULL, ce = cache_head; ce; 3842*0Sstevel@tonic-gate prev = ce, ce = ce->cache_next) { 3843*0Sstevel@tonic-gate if (timenow > ce->cache_time) { 3844*0Sstevel@tonic-gate cache_free(ce); 3845*0Sstevel@tonic-gate if (prev) 3846*0Sstevel@tonic-gate prev->cache_next = NULL; 3847*0Sstevel@tonic-gate else 3848*0Sstevel@tonic-gate cache_head = NULL; 3849*0Sstevel@tonic-gate break; 3850*0Sstevel@tonic-gate } 3851*0Sstevel@tonic-gate } 3852*0Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 3853*0Sstevel@tonic-gate return (state); 3854*0Sstevel@tonic-gate } 3855*0Sstevel@tonic-gate if (strcmp(host, ce->cache_host) != 0) 3856*0Sstevel@tonic-gate continue; 3857*0Sstevel@tonic-gate if ((proto == NULL && ce->cache_proto != NULL) || 3858*0Sstevel@tonic-gate (proto != NULL && ce->cache_proto == NULL)) 3859*0Sstevel@tonic-gate continue; 3860*0Sstevel@tonic-gate if (proto != NULL && 3861*0Sstevel@tonic-gate strcmp(proto, ce->cache_proto) != 0) 3862*0Sstevel@tonic-gate continue; 3863*0Sstevel@tonic-gate 3864*0Sstevel@tonic-gate if (versp == NULL || 3865*0Sstevel@tonic-gate (versp != NULL && *versp == ce->cache_reqvers) || 3866*0Sstevel@tonic-gate (versp != NULL && *versp == ce->cache_outvers)) { 3867*0Sstevel@tonic-gate if (versp != NULL) 3868*0Sstevel@tonic-gate *versp = ce->cache_outvers; 3869*0Sstevel@tonic-gate state = ce->cache_state; 3870*0Sstevel@tonic-gate 3871*0Sstevel@tonic-gate /* increment the host cache hit counters */ 3872*0Sstevel@tonic-gate #ifdef CACHE_DEBUG 3873*0Sstevel@tonic-gate if (state == GOODHOST) 3874*0Sstevel@tonic-gate goodhost_cache_hits++; 3875*0Sstevel@tonic-gate if (state == DEADHOST) 3876*0Sstevel@tonic-gate deadhost_cache_hits++; 3877*0Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 3878*0Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 3879*0Sstevel@tonic-gate return (state); 3880*0Sstevel@tonic-gate } 3881*0Sstevel@tonic-gate } 3882*0Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 3883*0Sstevel@tonic-gate return (state); 3884*0Sstevel@tonic-gate } 3885*0Sstevel@tonic-gate 3886*0Sstevel@tonic-gate /* 3887*0Sstevel@tonic-gate * Free a cache entry and all entries 3888*0Sstevel@tonic-gate * further down the chain since they 3889*0Sstevel@tonic-gate * will also be expired. 3890*0Sstevel@tonic-gate */ 3891*0Sstevel@tonic-gate static void 3892*0Sstevel@tonic-gate cache_free(entry) 3893*0Sstevel@tonic-gate struct cache_entry *entry; 3894*0Sstevel@tonic-gate { 3895*0Sstevel@tonic-gate struct cache_entry *ce, *next = NULL; 3896*0Sstevel@tonic-gate 3897*0Sstevel@tonic-gate for (ce = entry; ce; ce = next) { 3898*0Sstevel@tonic-gate if (ce->cache_host) 3899*0Sstevel@tonic-gate free(ce->cache_host); 3900*0Sstevel@tonic-gate if (ce->cache_proto) 3901*0Sstevel@tonic-gate free(ce->cache_proto); 3902*0Sstevel@tonic-gate next = ce->cache_next; 3903*0Sstevel@tonic-gate free(ce); 3904*0Sstevel@tonic-gate } 3905*0Sstevel@tonic-gate } 3906*0Sstevel@tonic-gate 3907*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 3908*0Sstevel@tonic-gate void 3909*0Sstevel@tonic-gate cache_flush() 3910*0Sstevel@tonic-gate { 3911*0Sstevel@tonic-gate (void) rw_wrlock(&cache_lock); 3912*0Sstevel@tonic-gate cache_free(cache_head); 3913*0Sstevel@tonic-gate cache_head = NULL; 3914*0Sstevel@tonic-gate (void) rw_unlock(&cache_lock); 3915*0Sstevel@tonic-gate } 3916*0Sstevel@tonic-gate 3917*0Sstevel@tonic-gate void 3918*0Sstevel@tonic-gate flush_caches() 3919*0Sstevel@tonic-gate { 3920*0Sstevel@tonic-gate mutex_lock(&cleanup_lock); 3921*0Sstevel@tonic-gate cond_signal(&cleanup_start_cv); 3922*0Sstevel@tonic-gate (void) cond_wait(&cleanup_done_cv, &cleanup_lock); 3923*0Sstevel@tonic-gate mutex_unlock(&cleanup_lock); 3924*0Sstevel@tonic-gate cache_flush(); 3925*0Sstevel@tonic-gate portmap_cache_flush(); 3926*0Sstevel@tonic-gate } 3927*0Sstevel@tonic-gate #endif 3928*0Sstevel@tonic-gate 3929*0Sstevel@tonic-gate /* 3930*0Sstevel@tonic-gate * Returns 1, if port option is NFS_PORT or 3931*0Sstevel@tonic-gate * nfsd is running on the port given 3932*0Sstevel@tonic-gate * Returns 0, if both port is not NFS_PORT and nfsd is not 3933*0Sstevel@tonic-gate * running on the port. 3934*0Sstevel@tonic-gate */ 3935*0Sstevel@tonic-gate 3936*0Sstevel@tonic-gate static int 3937*0Sstevel@tonic-gate is_nfs_port(char *opts) 3938*0Sstevel@tonic-gate { 3939*0Sstevel@tonic-gate struct mnttab m; 3940*0Sstevel@tonic-gate uint_t nfs_port = 0; 3941*0Sstevel@tonic-gate struct servent sv; 3942*0Sstevel@tonic-gate char buf[256]; 3943*0Sstevel@tonic-gate int got_port; 3944*0Sstevel@tonic-gate 3945*0Sstevel@tonic-gate m.mnt_mntopts = opts; 3946*0Sstevel@tonic-gate 3947*0Sstevel@tonic-gate /* 3948*0Sstevel@tonic-gate * Get port specified in options list, if any. 3949*0Sstevel@tonic-gate */ 3950*0Sstevel@tonic-gate got_port = nopt(&m, MNTOPT_PORT, (int *)&nfs_port); 3951*0Sstevel@tonic-gate 3952*0Sstevel@tonic-gate /* 3953*0Sstevel@tonic-gate * if no port specified or it is same as NFS_PORT return nfs 3954*0Sstevel@tonic-gate * To use any other daemon the port number should be different 3955*0Sstevel@tonic-gate */ 3956*0Sstevel@tonic-gate if (!got_port || nfs_port == NFS_PORT) 3957*0Sstevel@tonic-gate return (1); 3958*0Sstevel@tonic-gate /* 3959*0Sstevel@tonic-gate * If daemon is nfsd, return nfs 3960*0Sstevel@tonic-gate */ 3961*0Sstevel@tonic-gate if (getservbyport_r(nfs_port, NULL, &sv, buf, 256) == &sv && 3962*0Sstevel@tonic-gate strcmp(sv.s_name, "nfsd") == 0) 3963*0Sstevel@tonic-gate return (1); 3964*0Sstevel@tonic-gate 3965*0Sstevel@tonic-gate /* 3966*0Sstevel@tonic-gate * daemon is not nfs 3967*0Sstevel@tonic-gate */ 3968*0Sstevel@tonic-gate return (0); 3969*0Sstevel@tonic-gate } 3970*0Sstevel@tonic-gate 3971*0Sstevel@tonic-gate 3972*0Sstevel@tonic-gate /* 3973*0Sstevel@tonic-gate * destroy_auth_client_handle(cl) 3974*0Sstevel@tonic-gate * destroys the created client handle 3975*0Sstevel@tonic-gate */ 3976*0Sstevel@tonic-gate static void 3977*0Sstevel@tonic-gate destroy_auth_client_handle(CLIENT *cl) 3978*0Sstevel@tonic-gate { 3979*0Sstevel@tonic-gate if (cl) { 3980*0Sstevel@tonic-gate if (cl->cl_auth) { 3981*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 3982*0Sstevel@tonic-gate drop_alloc("AUTH_HANDLE", cl->cl_auth, 3983*0Sstevel@tonic-gate __FILE__, __LINE__); 3984*0Sstevel@tonic-gate #endif 3985*0Sstevel@tonic-gate AUTH_DESTROY(cl->cl_auth); 3986*0Sstevel@tonic-gate cl->cl_auth = NULL; 3987*0Sstevel@tonic-gate } 3988*0Sstevel@tonic-gate #ifdef MALLOC_DEBUG 3989*0Sstevel@tonic-gate drop_alloc("CLNT_HANDLE", cl, 3990*0Sstevel@tonic-gate __FILE__, __LINE__); 3991*0Sstevel@tonic-gate #endif 3992*0Sstevel@tonic-gate clnt_destroy(cl); 3993*0Sstevel@tonic-gate } 3994*0Sstevel@tonic-gate } 3995*0Sstevel@tonic-gate 3996*0Sstevel@tonic-gate 3997*0Sstevel@tonic-gate /* 3998*0Sstevel@tonic-gate * Attempt to figure out which version of NFS to use in pingnfs(). If 3999*0Sstevel@tonic-gate * the version number was specified (i.e., non-zero), then use it. 4000*0Sstevel@tonic-gate * Otherwise, default to the compiled-in default or the default as set 4001*0Sstevel@tonic-gate * by the /etc/default/nfs configuration (as read by read_default(). 4002*0Sstevel@tonic-gate */ 4003*0Sstevel@tonic-gate int 4004*0Sstevel@tonic-gate set_versrange(rpcvers_t nfsvers, rpcvers_t *vers, rpcvers_t *versmin) 4005*0Sstevel@tonic-gate { 4006*0Sstevel@tonic-gate switch (nfsvers) { 4007*0Sstevel@tonic-gate case 0: 4008*0Sstevel@tonic-gate *vers = vers_max_default; 4009*0Sstevel@tonic-gate *versmin = vers_min_default; 4010*0Sstevel@tonic-gate break; 4011*0Sstevel@tonic-gate case NFS_V4: 4012*0Sstevel@tonic-gate *vers = NFS_V4; 4013*0Sstevel@tonic-gate *versmin = NFS_V4; 4014*0Sstevel@tonic-gate break; 4015*0Sstevel@tonic-gate case NFS_V3: 4016*0Sstevel@tonic-gate *vers = NFS_V3; 4017*0Sstevel@tonic-gate *versmin = NFS_V3; 4018*0Sstevel@tonic-gate break; 4019*0Sstevel@tonic-gate case NFS_VERSION: 4020*0Sstevel@tonic-gate *vers = NFS_VERSION; /* version 2 */ 4021*0Sstevel@tonic-gate *versmin = NFS_VERSMIN; /* version 2 */ 4022*0Sstevel@tonic-gate break; 4023*0Sstevel@tonic-gate default: 4024*0Sstevel@tonic-gate return (-1); 4025*0Sstevel@tonic-gate } 4026*0Sstevel@tonic-gate return (0); 4027*0Sstevel@tonic-gate } 4028*0Sstevel@tonic-gate 4029*0Sstevel@tonic-gate #ifdef CACHE_DEBUG 4030*0Sstevel@tonic-gate /* 4031*0Sstevel@tonic-gate * trace_portmap_cache() 4032*0Sstevel@tonic-gate * traces the portmap cache values at desired points 4033*0Sstevel@tonic-gate */ 4034*0Sstevel@tonic-gate static void 4035*0Sstevel@tonic-gate trace_portmap_cache() 4036*0Sstevel@tonic-gate { 4037*0Sstevel@tonic-gate syslog(LOG_ERR, "portmap_cache: accesses=%d lookups=%d hits=%d\n", 4038*0Sstevel@tonic-gate portmap_cache_accesses, portmap_cache_lookups, 4039*0Sstevel@tonic-gate portmap_cache_hits); 4040*0Sstevel@tonic-gate } 4041*0Sstevel@tonic-gate 4042*0Sstevel@tonic-gate /* 4043*0Sstevel@tonic-gate * trace_host_cache() 4044*0Sstevel@tonic-gate * traces the host cache values at desired points 4045*0Sstevel@tonic-gate */ 4046*0Sstevel@tonic-gate static void 4047*0Sstevel@tonic-gate trace_host_cache() 4048*0Sstevel@tonic-gate { 4049*0Sstevel@tonic-gate syslog(LOG_ERR, 4050*0Sstevel@tonic-gate "host_cache: accesses=%d lookups=%d deadhits=%d goodhits=%d\n", 4051*0Sstevel@tonic-gate host_cache_accesses, host_cache_lookups, deadhost_cache_hits, 4052*0Sstevel@tonic-gate goodhost_cache_hits); 4053*0Sstevel@tonic-gate } 4054*0Sstevel@tonic-gate #endif /* CACHE_DEBUG */ 4055*0Sstevel@tonic-gate 4056*0Sstevel@tonic-gate /* 4057*0Sstevel@tonic-gate * Read the /etc/default/nfs configuration file to determine if the 4058*0Sstevel@tonic-gate * client has been configured for a new min/max for the NFS version to 4059*0Sstevel@tonic-gate * use. 4060*0Sstevel@tonic-gate */ 4061*0Sstevel@tonic-gate 4062*0Sstevel@tonic-gate #define NFS_DEFAULT_CHECK 60 /* Seconds to check for nfs default changes */ 4063*0Sstevel@tonic-gate 4064*0Sstevel@tonic-gate static void 4065*0Sstevel@tonic-gate read_default_nfs(void) 4066*0Sstevel@tonic-gate { 4067*0Sstevel@tonic-gate static time_t lastread = 0; 4068*0Sstevel@tonic-gate struct stat buf; 4069*0Sstevel@tonic-gate char *defval; 4070*0Sstevel@tonic-gate int errno; 4071*0Sstevel@tonic-gate int tmp; 4072*0Sstevel@tonic-gate 4073*0Sstevel@tonic-gate /* 4074*0Sstevel@tonic-gate * Fail silently if we can't stat the default nfs config file 4075*0Sstevel@tonic-gate */ 4076*0Sstevel@tonic-gate if (stat(NFSADMIN, &buf)) 4077*0Sstevel@tonic-gate return; 4078*0Sstevel@tonic-gate 4079*0Sstevel@tonic-gate if (buf.st_mtime == lastread) 4080*0Sstevel@tonic-gate return; 4081*0Sstevel@tonic-gate 4082*0Sstevel@tonic-gate /* 4083*0Sstevel@tonic-gate * Fail silently if error in opening the default nfs config file 4084*0Sstevel@tonic-gate * We'll check back in NFS_DEFAULT_CHECK seconds 4085*0Sstevel@tonic-gate */ 4086*0Sstevel@tonic-gate if ((defopen(NFSADMIN)) == 0) { 4087*0Sstevel@tonic-gate if ((defval = defread("NFS_CLIENT_VERSMIN=")) != NULL) { 4088*0Sstevel@tonic-gate errno = 0; 4089*0Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 4090*0Sstevel@tonic-gate if (errno == 0) { 4091*0Sstevel@tonic-gate vers_min_default = tmp; 4092*0Sstevel@tonic-gate } 4093*0Sstevel@tonic-gate } 4094*0Sstevel@tonic-gate if ((defval = defread("NFS_CLIENT_VERSMAX=")) != NULL) { 4095*0Sstevel@tonic-gate errno = 0; 4096*0Sstevel@tonic-gate tmp = strtol(defval, (char **)NULL, 10); 4097*0Sstevel@tonic-gate if (errno == 0) { 4098*0Sstevel@tonic-gate vers_max_default = tmp; 4099*0Sstevel@tonic-gate } 4100*0Sstevel@tonic-gate } 4101*0Sstevel@tonic-gate /* close defaults file */ 4102*0Sstevel@tonic-gate defopen(NULL); 4103*0Sstevel@tonic-gate 4104*0Sstevel@tonic-gate lastread = buf.st_mtime; 4105*0Sstevel@tonic-gate 4106*0Sstevel@tonic-gate /* 4107*0Sstevel@tonic-gate * Quick sanity check on the values picked up from the 4108*0Sstevel@tonic-gate * defaults file. Make sure that a mistake wasn't 4109*0Sstevel@tonic-gate * made that will confuse things later on. 4110*0Sstevel@tonic-gate * If so, reset to compiled-in defaults 4111*0Sstevel@tonic-gate */ 4112*0Sstevel@tonic-gate if (vers_min_default > vers_max_default || 4113*0Sstevel@tonic-gate vers_min_default < NFS_VERSMIN || 4114*0Sstevel@tonic-gate vers_max_default > NFS_VERSMAX) { 4115*0Sstevel@tonic-gate if (trace > 1) { 4116*0Sstevel@tonic-gate trace_prt(1, 4117*0Sstevel@tonic-gate " read_default: version minimum/maximum incorrectly configured\n"); 4118*0Sstevel@tonic-gate trace_prt(1, 4119*0Sstevel@tonic-gate " read_default: config is min=%d, max%d. Resetting to min=%d, max%d\n", 4120*0Sstevel@tonic-gate vers_min_default, vers_max_default, 4121*0Sstevel@tonic-gate NFS_VERSMIN_DEFAULT, 4122*0Sstevel@tonic-gate NFS_VERSMAX_DEFAULT); 4123*0Sstevel@tonic-gate } 4124*0Sstevel@tonic-gate vers_min_default = NFS_VERSMIN_DEFAULT; 4125*0Sstevel@tonic-gate vers_max_default = NFS_VERSMAX_DEFAULT; 4126*0Sstevel@tonic-gate } 4127*0Sstevel@tonic-gate } 4128*0Sstevel@tonic-gate } 4129*0Sstevel@tonic-gate 4130*0Sstevel@tonic-gate /* 4131*0Sstevel@tonic-gate * Find the mnttab entry that corresponds to "name". 4132*0Sstevel@tonic-gate * We're not sure what the name represents: either 4133*0Sstevel@tonic-gate * a mountpoint name, or a special name (server:/path). 4134*0Sstevel@tonic-gate * Return the last entry in the file that matches. 4135*0Sstevel@tonic-gate */ 4136*0Sstevel@tonic-gate static struct extmnttab * 4137*0Sstevel@tonic-gate mnttab_find(dirname) 4138*0Sstevel@tonic-gate char *dirname; 4139*0Sstevel@tonic-gate { 4140*0Sstevel@tonic-gate FILE *fp; 4141*0Sstevel@tonic-gate struct extmnttab mnt; 4142*0Sstevel@tonic-gate struct extmnttab *res = NULL; 4143*0Sstevel@tonic-gate 4144*0Sstevel@tonic-gate fp = fopen(MNTTAB, "r"); 4145*0Sstevel@tonic-gate if (fp == NULL) { 4146*0Sstevel@tonic-gate if (trace > 1) 4147*0Sstevel@tonic-gate trace_prt(1, " mnttab_find: unable to open mnttab\n"); 4148*0Sstevel@tonic-gate return (NULL); 4149*0Sstevel@tonic-gate } 4150*0Sstevel@tonic-gate while (getextmntent(fp, &mnt, sizeof (struct extmnttab)) == 0) { 4151*0Sstevel@tonic-gate if (strcmp(mnt.mnt_mountp, dirname) == 0 || 4152*0Sstevel@tonic-gate strcmp(mnt.mnt_special, dirname) == 0) { 4153*0Sstevel@tonic-gate if (res) 4154*0Sstevel@tonic-gate fsfreemnttab(res); 4155*0Sstevel@tonic-gate res = fsdupmnttab(&mnt); 4156*0Sstevel@tonic-gate } 4157*0Sstevel@tonic-gate } 4158*0Sstevel@tonic-gate 4159*0Sstevel@tonic-gate resetmnttab(fp); 4160*0Sstevel@tonic-gate fclose(fp); 4161*0Sstevel@tonic-gate if (res == NULL) { 4162*0Sstevel@tonic-gate if (trace > 1) 4163*0Sstevel@tonic-gate trace_prt(1, " mnttab_find: unable to find %s\n", 4164*0Sstevel@tonic-gate dirname); 4165*0Sstevel@tonic-gate } 4166*0Sstevel@tonic-gate return (res); 4167*0Sstevel@tonic-gate } 4168*0Sstevel@tonic-gate 4169*0Sstevel@tonic-gate /* 4170*0Sstevel@tonic-gate * This function's behavior is taken from nfsstat. 4171*0Sstevel@tonic-gate * Trying to determine what NFS version was used for the mount. 4172*0Sstevel@tonic-gate */ 4173*0Sstevel@tonic-gate static int 4174*0Sstevel@tonic-gate is_v4_mount(char *mntpath) 4175*0Sstevel@tonic-gate { 4176*0Sstevel@tonic-gate kstat_ctl_t *kc = NULL; /* libkstat cookie */ 4177*0Sstevel@tonic-gate kstat_t *ksp; 4178*0Sstevel@tonic-gate ulong_t fsid; 4179*0Sstevel@tonic-gate struct mntinfo_kstat mik; 4180*0Sstevel@tonic-gate struct extmnttab *mntp; 4181*0Sstevel@tonic-gate uint_t mnt_minor; 4182*0Sstevel@tonic-gate 4183*0Sstevel@tonic-gate if ((mntp = mnttab_find(mntpath)) == NULL) 4184*0Sstevel@tonic-gate return (FALSE); 4185*0Sstevel@tonic-gate 4186*0Sstevel@tonic-gate /* save the minor number and free the struct so we don't forget */ 4187*0Sstevel@tonic-gate mnt_minor = mntp->mnt_minor; 4188*0Sstevel@tonic-gate fsfreemnttab(mntp); 4189*0Sstevel@tonic-gate 4190*0Sstevel@tonic-gate if ((kc = kstat_open()) == NULL) 4191*0Sstevel@tonic-gate return (FALSE); 4192*0Sstevel@tonic-gate 4193*0Sstevel@tonic-gate for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 4194*0Sstevel@tonic-gate if (ksp->ks_type != KSTAT_TYPE_RAW) 4195*0Sstevel@tonic-gate continue; 4196*0Sstevel@tonic-gate if (strcmp(ksp->ks_module, "nfs") != 0) 4197*0Sstevel@tonic-gate continue; 4198*0Sstevel@tonic-gate if (strcmp(ksp->ks_name, "mntinfo") != 0) 4199*0Sstevel@tonic-gate continue; 4200*0Sstevel@tonic-gate if (mnt_minor != ksp->ks_instance) 4201*0Sstevel@tonic-gate continue; 4202*0Sstevel@tonic-gate 4203*0Sstevel@tonic-gate if (kstat_read(kc, ksp, &mik) == -1) 4204*0Sstevel@tonic-gate continue; 4205*0Sstevel@tonic-gate 4206*0Sstevel@tonic-gate (void) kstat_close(kc); 4207*0Sstevel@tonic-gate if (mik.mik_vers == 4) 4208*0Sstevel@tonic-gate return (TRUE); 4209*0Sstevel@tonic-gate else 4210*0Sstevel@tonic-gate return (FALSE); 4211*0Sstevel@tonic-gate } 4212*0Sstevel@tonic-gate (void) kstat_close(kc); 4213*0Sstevel@tonic-gate 4214*0Sstevel@tonic-gate return (FALSE); 4215*0Sstevel@tonic-gate } 4216