mount.c revision b4625e144349c1ef903a75b1ba2cead8d2bb5d7e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* nfs mount
*/
#define NFSCLIENT
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <stdarg.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <netdb.h>
#include <sys/pathconf.h>
#include <netdir.h>
#include <netconfig.h>
#include <syslog.h>
#include <fslib.h>
#include <deflt.h>
#include "replica.h"
#include <rpcsvc/daemon_utils.h>
#include <priv.h>
#include "nfs_subr.h"
#include "webnfs.h"
#include <rpcsvc/nfs4_prot.h>
#ifndef NFS_VERSMAX
#define NFS_VERSMAX 4
#endif
#ifndef NFS_VERSMIN
#define NFS_VERSMIN 2
#endif
#define RET_OK 0
#define RET_RETRY 32
#define RET_ERR 33
#define RET_MNTERR 1000
#define ERR_PROTO_NONE 0
#define ERR_PROTO_INVALID 901
#define ERR_PROTO_UNSUPP 902
#define ERR_NETPATH 903
#define ERR_NOHOST 904
#define ERR_RPCERROR 905
typedef struct err_ret {
int error_type;
int error_value;
} err_ret_t;
if (errst) { \
}
/* number of transports to try */
#define MNT_PREF_LISTLEN 2
#define FIRST_TRY 1
#define SECOND_TRY 2
#define BIGRETRY 10000
/* maximum length of RPC header for NFS messages */
#define NFS_RPC_HDR 432
extern int __clnt_bindresvport(CLIENT *);
extern char *nfs_get_qop_name();
extern AUTH * nfs_create_ah();
extern enum snego_stat nfs_sec_nego();
static void usage(void);
static void usage(void);
extern int self_check(char *);
static void read_default(void);
static char typename[64];
static int bg = 0;
static int backgrounded = 0;
static int posix = 0;
static int mflg = 0;
static int Oflg = 0; /* Overlay mounts */
static int qflg = 0; /* quiet - don't print warnings on bad options */
static char *fstype = MNTTYPE_NFS;
static seconfig_t nfs_sec;
static int sec_opt = 0; /* any security option ? */
static bool_t snego_done;
static void sigusr1(int);
extern void set_nfsv4_ephemeral_mount_to(void);
/*
* list of support services needed
*/
/*
* These two variables control the NFS version number to be used.
*
* nfsvers defaults to 0 which means to use the highest number that
* both the client and the server support. It can also be set to
* a particular value, either 2, 3, or 4 to indicate the version
* number of choice. If the server (or the client) do not support
* the version indicated, then the mount attempt will be failed.
*
* nfsvers_to_use is the actual version number found to use. It
* is determined in get_fh by pinging the various versions of the
* NFS service on the server to see which responds positively.
*
* nfsretry_vers is the version number set when we retry the mount
* command with the version decremented from nfsvers_to_use.
* nfsretry_vers is set from nfsvers_to_use when we retry the mount
* for errors other than RPC errors; it helps un know why we are
* retrying. It is an indication that the retry is due to
* non-RPC errors.
*/
static rpcvers_t nfsvers_to_use = 0;
static rpcvers_t nfsretry_vers = 0;
/*
* There are the defaults (range) for the client when determining
* which NFS version to use when probing the server (see above).
* These will only be used when the vers mount option is not used and
*/
/*
* This variable controls whether to try the public file handle.
*/
static bool_t public_opt;
int
{
extern char *optarg;
extern int optind;
char optbuf[MAX_MNTOPT_STR];
int ro = 0;
int r;
int c;
char *myname;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* Set options
*/
switch (c) {
case 'r':
ro++;
break;
case 'o':
return (RET_ERR);
}
#ifdef LATER /* XXX */
/*
* If remount is specified, only rw is allowed.
*/
}
}
#endif /* LATER */ /* XXX */
break;
case 'm':
mflg++;
break;
case 'O':
Oflg++;
break;
case 'q':
qflg++;
break;
default:
usage();
}
}
usage();
}
if (!priv_ineffect(PRIV_SYS_MOUNT) ||
}
/*
* On a labeled system, allow read-down nfs mounts if privileged
* (PRIV_NET_MAC_AWARE) to do so. Otherwise, ignore the error
* and "mount equal label only" behavior will result.
*/
if (is_system_labeled())
/*
* been set and therefore would override the encoded defaults.
* Then check to make sure that if they were set that the
* values are reasonable.
*/
read_default();
if (vers_min_default > vers_max_default ||
pr_err("%s %s\n%s %s\n",
gettext("Incorrect configuration of client\'s"),
gettext("NFS_CLIENT_VERSMIN or NFS_CLIENT_VERSMAX"),
gettext("is either out of range or overlaps."));
}
/*
* Check the error code from the last mount attempt if it was
* an RPC error, then retry as is. Otherwise we retry with the
* nfsretry_vers set. It is set by decrementing nfsvers_to_use.
* If we are retrying with nfsretry_vers then we don't print any
* retry messages, since we are not retrying due to an RPC
* error.
*/
if (retry_error.error_type) {
nfsvers_to_use - 1;
if (nfsretry_vers < NFS_VERSMIN)
return (r);
}
}
}
/*
* exit(r);
*/
return (r);
}
static void
{
if (backgrounded != 0) {
} else {
}
}
static void
usage()
{
gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n"));
}
static int
{
int mntflags = 0;
int i, r, n;
int last_error = RET_OK;
int replicated = 0;
char *p;
char *service;
struct flock f;
if (ro) {
/* convert "rw"->"ro" */
if (*(p+2) == ',' || *(p+2) == '\0')
*(p+1) = 'o';
}
}
if (Oflg)
mntflags |= MS_OVERLAY;
if (n < 0)
else
return (RET_ERR);
}
replicated = (n > 1);
/*
* There are some free() calls at the bottom of this loop, so be
* careful about adding continue statements.
*/
for (i = 0; i < n; i++) {
char *path;
char *host;
goto out;
}
sec_opt = 0;
port = 0;
snego_done = FALSE;
/*
* Looking for resources of the form
* nfs://server_host[:port_number]/path_name
*/
"//", 2) == 0) {
goto out;
}
"illegal nfs url syntax\n"));
goto out;
}
*path = '\0';
if (*host == '[') {
"illegal nfs url syntax\n"));
goto out;
} else {
*cb = '\0';
host++;
cb++;
if (*cb == ':')
}
} else {
*sport = '\0';
}
}
path++;
if (*path == '\0')
path = ".";
} else {
}
last_error = r;
goto out;
}
if (public_opt == TRUE)
if (port == 0) {
"port (%u) in nfs URL not the same"
" as port (%u) in port option\n"),
goto out;
}
"replicated mounts must be read-only\n"));
goto out;
}
"replicated mounts must not be soft\n"));
goto out;
}
r = RET_ERR;
/*
* then try the public file handle method.
*/
if (r != RET_OK) {
/*
* If -o public was specified, then return the
* error now.
*/
last_error = r;
goto out;
}
} else
}
/*
* This can happen if -o public is not specified,
* special is a URL, and server doesn't support
* public file handle.
*/
if (url) {
}
/*
* If the path portion of the URL didn't have
* a leading / then there is good possibility
* that a mount without a leading slash will
* fail.
*/
else
if (r != RET_OK) {
/*
* If there was no leading / and the path was
* derived from a URL, then try again
* with a leading /.
*/
if ((r == RET_MNTERR) &&
(loud_on_mnt_err == FALSE)) {
"allocation failure\n"));
goto out;
}
if (r == RET_OK)
}
/*
* map exit code back to RET_ERR.
*/
if (r == RET_MNTERR)
r = RET_ERR;
if (r != RET_OK) {
if (replicated) {
goto cont;
}
last_error = r;
goto out;
}
}
}
gettext("replicas must have the same version\n"));
goto out;
}
/*
* decide whether to use remote host's
* lockd or do local locking
*/
"WARNING: No network locking on %s:%s:"),
" contact admin to install server change\n"));
}
if (self_check(host))
/*
* Call to get_fh() above may have obtained the
* netconfig info and NULL proc'd the server.
* This would be the case with v4
*/
TRUE)) {
last_error = r;
goto out;
}
}
}
goto out;
}
/*
* Convert the special from
* to
* host:path
*/
"could not convert URL nfs:%s to %s:%s\n"),
goto out;
} else {
}
}
else
cont:
}
}
}
goto out;
}
/* Determine which services are appropriate for the NFS version */
else
sl = service_list;
/*
* enable services as needed.
*/
if (mflg)
mntflags |= MS_NOMNTTAB;
if (!qflg)
/*
* And make sure that we have the ephemeral mount_to
* set for this zone.
*/
} else {
else
}
goto out;
}
}
out:
free_replica(list, n);
/*
* If we had a new entry which was not added to the
* list yet, then add it now that it can be freed.
*/
else
}
}
}
}
return (last_error);
}
/*
* These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c
* Changes must be made to both lists.
*/
static char *optlist[] = {
#define OPT_RO 0
#define OPT_RW 1
#define OPT_QUOTA 2
#define OPT_NOQUOTA 3
#define OPT_SOFT 4
#define OPT_HARD 5
#define OPT_SUID 6
#define OPT_NOSUID 7
#define OPT_GRPID 8
#define OPT_REMOUNT 9
#define OPT_NOSUB 10
#define OPT_INTR 11
#define OPT_NOINTR 12
#define OPT_PORT 13
#define OPT_SECURE 14
#define OPT_RSIZE 15
#define OPT_WSIZE 16
#define OPT_TIMEO 17
#define OPT_RETRANS 18
#define OPT_ACTIMEO 19
#define OPT_ACREGMIN 20
#define OPT_ACREGMAX 21
#define OPT_ACDIRMIN 22
#define OPT_ACDIRMAX 23
#define OPT_BG 24
#define OPT_FG 25
#define OPT_RETRY 26
#define OPT_NOAC 27
#define OPT_NOCTO 28
#define OPT_LLOCK 29
#define OPT_POSIX 30
#define OPT_VERS 31
#define OPT_PROTO 32
#define OPT_SEMISOFT 33
#define OPT_NOPRINT 34
#define OPT_SEC 35
#define OPT_LARGEFILES 36
#define OPT_NOLARGEFILES 37
#define OPT_PUBLIC 38
#define OPT_DIRECTIO 39
#define OPT_NODIRECTIO 40
#define OPT_XATTR 41
#define OPT_NOXATTR 42
#define OPT_DEVICES 43
#define OPT_NODEVICES 44
#define OPT_SETUID 45
#define OPT_NOSETUID 46
#define OPT_EXEC 47
#define OPT_NOEXEC 48
};
static int
{
int largefiles = 0;
int invalid = 0;
int attrpref = 0;
int optlen;
/* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */
if (optlen > MAX_MNTOPT_STR) {
return (RET_ERR);
}
if (opts)
if (newopts)
return (RET_ERR);
}
newopts[0] = '\0';
while (*opts) {
invalid = 0;
case OPT_RO:
break;
case OPT_RW:
break;
case OPT_QUOTA:
case OPT_NOQUOTA:
break;
case OPT_SOFT:
break;
case OPT_SEMISOFT:
break;
case OPT_HARD:
break;
case OPT_SUID:
break;
case OPT_NOSUID:
break;
case OPT_GRPID:
break;
case OPT_REMOUNT:
*mntflags |= MS_REMOUNT;
break;
case OPT_INTR:
break;
case OPT_NOINTR:
break;
case OPT_NOAC:
break;
case OPT_PORT:
goto badopt;
break;
case OPT_SECURE:
goto badopt;
}
sec_opt++;
break;
case OPT_NOCTO:
break;
case OPT_RSIZE:
goto badopt;
break;
case OPT_WSIZE:
goto badopt;
break;
case OPT_TIMEO:
goto badopt;
break;
case OPT_RETRANS:
goto badopt;
break;
case OPT_ACTIMEO:
goto badopt;
break;
case OPT_ACREGMIN:
goto badopt;
break;
case OPT_ACREGMAX:
goto badopt;
break;
case OPT_ACDIRMIN:
goto badopt;
break;
case OPT_ACDIRMAX:
goto badopt;
break;
case OPT_BG:
bg++;
break;
case OPT_FG:
bg = 0;
break;
case OPT_RETRY:
goto badopt;
break;
case OPT_LLOCK:
break;
case OPT_POSIX:
posix = 1;
break;
case OPT_VERS:
goto badopt;
break;
case OPT_PROTO:
goto badopt;
if (!nfs_proto) {
return (RET_ERR);
}
break;
case OPT_NOPRINT:
break;
case OPT_LARGEFILES:
largefiles = 1;
break;
case OPT_NOLARGEFILES:
return (RET_ERR);
case OPT_SEC:
val, NFSSEC_CONF);
return (RET_ERR);
}
sec_opt++;
break;
case OPT_PUBLIC:
public_opt = TRUE;
break;
case OPT_DIRECTIO:
break;
case OPT_NODIRECTIO:
break;
case OPT_XATTR:
case OPT_NOXATTR:
/*
* VFS options; just need to get them into the
* new mount option string and note we've seen them
*/
attrpref = 1;
break;
default:
/*
* Note that this could be a valid OPT_* option so
* we can't use "val" but need to use "saveopt".
*/
if (fsisstdopt(saveopt))
break;
invalid = 1;
if (!qflg)
"mount: %s on %s - WARNING unknown option"
break;
}
if (!invalid) {
if (newopts[0])
}
}
/* Default is to turn extended attrs on */
if (!attrpref) {
if (newopts[0])
}
/* ensure that only one secure mode is requested */
if (sec_opt > 1) {
return (RET_ERR);
}
/* ensure that the user isn't trying to get large files over V2 */
return (RET_ERR);
}
return (RET_ERR);
}
return (RET_OK);
return (RET_ERR);
}
static int
{
int flags;
/*
* check to see if any secure mode is requested.
* if not, use default security mode.
*/
if (!snego_done && !sec_opt) {
/*
* Get default security mode.
* AUTH_UNIX has been the default choice for a long time.
* The better NFS security service becomes, the better chance
* we will set stronger security service as the default NFS
* security mode.
*/
if (nfs_getseconfig_default(&nfs_sec)) {
" security entry\n"));
return (-1);
}
}
/*
* Get the network address for the time service on the server.
* If an RPC based time service is not available then try the
* IP time service.
*
* This is for AUTH_DH processing. We will also pass down syncaddr
* and netname for NFS V4 even if AUTH_DH is not requested right now.
* NFS V4 does security negotiation in the kernel via SECINFO.
* These information might be needed later in the kernel.
*
* Eventurally, we want to move this code to nfs_clnt_secdata()
* when autod_nfs.c and mount.c can share the same get_the_addr()
* routine.
*/
flags = 0;
/*
* If using the public fh or nfsv4, we will not contact the
* remote RPCBINDer, since it is possibly behind a firewall.
*/
/* for flags in sec_data */
} else {
struct nd_hostserv hs;
int error;
hostname);
return (-1);
}
/*
* For NFS_V4 if AUTH_DH is negotiated later in the
* kernel thru SECINFO, it will need syncaddr
* and netname data.
*/
}
}
}
/*
* For the initial chosen flavor (any flavor defined in nfssec.conf),
* the data will be stored in the sec_data structure via
* nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
* extended data structure.
*/
if (flags & AUTH_F_RPCTIMESYNC) {
} else if (retaddrs)
return (-1);
}
if (flags & AUTH_F_RPCTIMESYNC) {
} else if (retaddrs)
return (0);
}
/*
* Get the network address on "hostname" for program "prog"
* with version "vers" by using the nconf configuration data
* passed in.
*
* If the address of a netconfig pointer is null then
* information is not sufficient and no netbuf will be returned.
*
* Finally, ping the null procedure of that service.
*
* A similar routine is also defined in ../../autofs/autod_nfs.c.
* This is a potential routine to move to ../lib for common usage.
*/
static struct netbuf *
{
int fd = -1;
return (NULL);
goto done;
/* LINTED pointer alignment */
== NULL)
goto done;
/*
* In the case of public filehandle usage or NFSv4 we want to
*/
struct nd_hostserv hs;
struct nd_addrlist *retaddrs;
int retval;
/* NFS where vers==4 does not support UDP */
goto done;
}
if (port == 0)
else
!= ND_OK) {
/*
* Carefully set the error value here. Want to signify
* that the error was an unknown host.
*/
}
goto done;
}
} else {
goto done;
}
}
if (port) {
/* LINTED pointer alignment */
= port;
= port;
}
/*
* clnt_tli_create() returns either RPC_SYSTEMERROR,
* RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates
* to "Misc. TLI error". This is not too helpful. Most likely
* the connection to the remote server timed out, so this
* error is at least less perplexing.
*/
} else {
}
goto done;
}
ah = authsys_create_default();
enum snego_stat sec;
if (!snego_done) {
/*
* negotiate sec flavor.
*/
int jj;
/*
* check if server supports the one
* specified in the sec= option.
*/
if (sec_opt) {
snego_done = TRUE;
break;
}
}
}
/*
* find a common sec flavor
*/
if (!snego_done) {
if (sec_opt) {
"Server does not support"
" the security flavor"
" specified.\n"));
}
if (!nfs_getseconfig_bynumber(
&nfs_sec)) {
snego_done = TRUE;
#define EMSG80SUX "Security flavor %d was negotiated and will be used.\n"
if (sec_opt)
break;
}
}
}
if (!snego_done)
return (NULL);
/*
* Now that the flavor has been
* negotiated, get the fh.
*
* First, create an auth handle using the
* negotiated sec flavor in the next lookup to
* fetch the filehandle.
*/
goto done;
goto done;
}
/*
* Note that if sec == SNEGO_DEF_VALID
* default sec flavor is acceptable.
* Use it to get the filehandle.
*/
}
if (vers == NFS_VERSION) {
goto done;
goto done;
}
sizeof (wnl_fh));
} else {
goto done;
(char *)res);
goto done;
}
fh3p->fh3_length =
fh3p->fh3_length);
}
} else {
void *res;
if (vers == NFS_VERSION)
else
case RPC_TLIERROR:
case RPC_CANTRECV:
case RPC_CANTSEND:
}
}
goto done;
}
}
/*
* Make a copy of the netbuf to return
*/
goto done;
}
goto done;
}
done:
if (cl) {
}
}
if (tbind) {
}
if (fd >= 0)
return (nb);
}
static int
{
int try_test = 0;
int valid_family;
} else if (nthtry == SECOND_TRY) {
}
if (proto &&
*valid_proto = TRUE;
else
*valid_proto = FALSE;
return (try_test);
}
/*
* Get a network address on "hostname" for program "prog"
* with version "vers". If the port number is specified (non zero)
* resulting IP address.
*
* If the address of a netconfig pointer was passed and
* if it's not null, use it as the netconfig otherwise
* assign the address of the netconfig that was used to
* establish contact with the service.
*
* A similar routine is also defined in ../../autofs/autod_nfs.c.
* This is a potential routine to move to ../lib for common usage.
*
* "error" refers to a more descriptive term when get_addr fails
* and returns NULL: ERR_PROTO_NONE if no error introduced by
* -o proto option, ERR_NETPATH if error found in NETPATH
* environment variable, ERR_PROTO_INVALID if an unrecognized
* protocol is specified by user, and ERR_PROTO_UNSUPP for a
* recognized but invalid protocol (eg. ticlts, ticots, etc.).
* "error" is ignored if get_addr returns non-NULL result.
*
*/
static struct netbuf *
{
/*
* No nconf passed in.
*
* the NETPATH environment variable.
* First search for COTS, second for CLTS unless proto
* is specified. When we retry, we reset the
* netconfig list so that we would search the whole list
* all over again.
*/
/* should only return an error if problems with NETPATH */
/* In which case you are hosed */
goto done;
}
/*
* If proto is specified, then only search for the match,
* otherwise try COTS first, if failed, try CLTS.
*/
if (proto) {
/* no matching proto name */
continue;
/* may be unsupported */
if ((port != 0) &&
continue;
} else {
break;
/* nb is NULL - deal with errors */
if (error) {
error->error_value);
error->error_value);
}
/*
* continue with same protocol
* selection
*/
continue;
}
} /* end of while */
goto done;
goto done;
} else {
int valid_proto;
if (check_nconf(nconf,
nthtry, &valid_proto)) {
if (port == 0)
break;
if (valid_proto == TRUE)
break;
}
}
} /* while */
if (++nthtry <= MNT_PREF_LISTLEN) {
endnetpath(nc);
goto done;
goto retry;
} else
goto done;
} else {
== NULL) {
/* nb is NULL - deal with errors */
if (error) {
error->error_value);
error->error_value);
}
/*
* Continue the same search path in the
* netconfig db until no more matched
* nconf (nconf == NULL).
*/
goto retry;
}
}
}
/*
* Got nconf and nb. Now dup the netconfig structure (nconf)
* and return it thru nconfp.
*/
}
done:
if (nc)
endnetpath(nc);
/*
* Check the saved errors. The RPC error has *
* precedence over the no host error.
*/
}
return (nb);
}
/*
* Get a file handle usinging multi-component lookup with the public
* file handle.
*/
static int
{
int r;
char *path;
if (nfsvers != 0) {
} else {
}
return (RET_ERR);
}
path[0] = (char)WNL_NATIVEPATH;
} else {
}
nfsvers_to_use--) {
/*
* getaddr_nfs will also fill in the fh for us.
*/
if (r == RET_OK) {
/*
* Since we are using the public fh, and NLM is
* not firewall friendly, use local locking.
* Not the case for v4.
*/
*versp = nfsvers_to_use;
switch (nfsvers_to_use) {
case NFS_V4:
break;
case NFS_V3:
/* fall through to pick up llock option */
default:
break;
}
return (r);
}
}
" server %s\n"), fshost);
}
return (r);
}
/*
* get fhandle of remote path from server's mountd
*/
static int
{
static struct pathcnf p;
static int printed = 0;
char *msg;
switch (nfsvers) {
case 2: /* version 2 specified try that only */
break;
case 3: /* version 3 specified try that only */
break;
case 4: /* version 4 specified try that only */
/*
* This assignment is in the wrong version sequence.
* The above are MOUNT program and this is NFS
* program. However, it happens to work out since the
* two don't collide for NFSv4.
*/
break;
default: /* no version specified, start with default */
/*
* If the retry version is set, use that. This will
* be set if the last mount attempt returned any other
* besides an RPC error.
*/
if (nfsretry_vers)
else {
}
break;
}
/*
* In the case of version 4, just NULL proc the server since
* there is no MOUNT program. If this fails, then decrease
* vers_to_try and continue on with regular MOUNT program
* processing.
*/
if (vers_to_try == NFS_V4) {
int savevers = nfsvers_to_use;
int retval;
/* Let's hope for the best */
return (RET_ERR);
}
return (RET_OK);
}
vers_to_try--;
/* If no more versions to try, let the user know. */
if (vers_to_try < vers_min)
return (retval);
/*
* If we are here, there are more versions to try but
* there has been an error of some sort. If it is not
* an RPC error (e.g. host unknown), we just stop and
* return the error since the other versions would see
* the same error as well.
*/
return (retval);
}
clnt_spcreateerror(""));
return (RET_ERR);
}
/*
* We don't want to downgrade version on lost packets
*/
clnt_spcreateerror(""));
return (RET_RETRY);
}
/*
* back off and try the previous version - patch to the
* problem of version numbers not being contigous and
* clnt_create_vers failing (SunOS4.1 clients & SGI servers)
* The problem happens with most non-Sun servers who
* don't support mountd protocol #2. So, in case the
* call fails, we re-try the call anyway.
*/
vers_to_try--;
if (vers_to_try < vers_min) {
if (nfsvers == 0) {
"%s:%s: no applicable versions of NFS supported\n"),
} else {
"%s:%s: NFS Version %d not supported\n"),
}
return (RET_ERR);
}
if (!printed) {
clnt_spcreateerror(""));
printed = 1;
}
return (RET_RETRY);
}
}
return (RET_ERR);
}
if (__clnt_bindresvport(cl) < 0) {
return (RET_RETRY);
}
gettext("Couldn't create default authentication handle\n"));
return (RET_RETRY);
}
switch (outvers) {
case MOUNTVERS:
case MOUNTVERS_POSIX:
if (rpc_stat != RPC_SUCCESS) {
return (RET_RETRY);
}
if (loud_on_mnt_err) {
"%s:%s: access denied\n"),
} else {
"returned by server");
}
}
return (RET_MNTERR);
}
return (RET_ERR);
}
if (rpc_stat != RPC_SUCCESS) {
"%s:%s: server not responding %s\n"),
return (RET_RETRY);
}
"%s:%s: no pathconf info\n"),
return (RET_ERR);
}
return (RET_ERR);
}
sizeof (p));
}
break;
case MOUNTVERS3:
timeout);
if (rpc_stat != RPC_SUCCESS) {
return (RET_RETRY);
}
/*
* Assume here that most of the MNT3ERR_*
* codes map into E* errors.
*/
if (loud_on_mnt_err) {
switch (errno) {
case MNT3ERR_NAMETOOLONG:
msg = "path name is too long";
break;
case MNT3ERR_NOTSUPP:
msg = "operation not supported";
break;
case MNT3ERR_SERVERFAULT:
msg = "server fault";
break;
default:
if (errno >= 0)
else
msg = "invalid error returned "
"by server";
break;
}
}
return (RET_MNTERR);
}
return (RET_ERR);
}
fh3p->fh3_length =
fh3p->fh3_length);
/*
* Check the security flavor to be used.
*
* If "secure" or "sec=flavor" is a mount
* option, check if the server supports the "flavor".
* If the server does not support the flavor, return
* error.
*
* If no mount option is given then use the first supported
* security flavor (by the client) in the auth list returned
* from the server.
*
*/
auths =
count =
if (sec_opt) {
for (i = 0; i < count; i++) {
break;
}
if (i >= count)
goto autherr;
} else {
if (count < 0)
break;
for (i = 0; i < count; i++) {
if (!nfs_getseconfig_bynumber(auths[i],
&nfs_sec)) {
sec_opt++;
break;
}
}
if (i >= count)
goto autherr;
}
break;
default:
return (RET_ERR);
}
return (RET_OK);
"security mode does not match the server exporting %s:%s\n"),
return (RET_ERR);
}
/*
* Fill in the address for the server's NFS service and
* fill in a knetconfig structure for the transport that
* the service is available on.
*/
static int
{
struct knetconfig *knconfp;
static int printed = 0;
if (nfs_proto) {
/*
* If a proto is specified and its rdma try this. The kernel
* will later do the reachablity test and fail form there
* if rdma transport is not available to kernel rpc
*/
} else {
}
} else {
fspath, &addr_error);
/*
* If no proto is specified set this flag.
* Kernel mount code will try to use RDMA if its on the
* system, otherwise it will keep on using the protocol
* selected here, through the above get_addr call.
*/
}
/*
* We could have failed because the server had no public
* file handle support. So don't print a message and don't
* retry.
*/
return (RET_ERR);
if (!printed) {
switch (addr_error.error_type) {
case 0:
printed = 1;
break;
case ERR_RPCERROR:
if (!print_rpcerror)
/* no error print at this time */
break;
" available %s\n"), fshost,
printed = 1;
break;
case ERR_NETPATH:
fshost);
printed = 1;
break;
case ERR_PROTO_INVALID:
" recognize protocol: %s.\n"), fshost,
printed = 1;
break;
case ERR_PROTO_UNSUPP:
/*
* Don't set "printed" here. Since we
* have to keep checking here till we
* exhaust transport errors on all vers.
*
* Print this message if:
* 1. After we have tried all versions
* of NFS and none support the asked
* transport.
*
* 2. If a version is specified and it
* does'nt support the asked
* transport.
*
* Otherwise we decrement the version
* and retry below.
*/
" not support protocol: %s.\n"),
}
break;
case ERR_NOHOST:
printed = 1;
break;
default:
/* case ERR_PROTO_NONE falls through */
"\n"), fshost);
printed = 1;
break;
}
}
return (RET_RETRY);
return (RET_RETRY);
/*
* If no version is specified, and the error is due
* to an unsupported transport, then decrement the
* version and retry.
*/
return (RET_RETRY);
} else
return (RET_ERR);
}
return (RET_ERR);
}
if (!knconfp) {
return (RET_ERR);
}
/* make sure we don't overload the transport */
}
return (RET_OK);
}
static int
{
int delay = 5;
int r;
/*
* Please see comments on nfsretry_vers in the beginning of this file
* and in main() routine.
*/
if (bg) {
if (fork() > 0)
return (RET_OK);
backgrounded = 1;
} else {
if (!nfsretry_vers)
}
while (count--) {
return (RET_OK);
}
if (r != RET_RETRY)
break;
if (count > 0) {
delay *= 2;
if (delay > 120)
delay = 120;
}
}
if (!nfsretry_vers)
return (RET_ERR);
}
/*
* use.
*/
static void
read_default(void)
{
char *defval;
int errno;
int tmp;
/* Fail silently if error in opening the default nfs config file */
errno = 0;
if (errno == 0) {
}
}
errno = 0;
if (errno == 0) {
}
}
/* close defaults file */
}
}
static void
sigusr1(int s)
{
}