walters / rpms / nfs-utils

Forked from rpms/nfs-utils 6 years ago
Clone
e955777
diff --git a/.gitignore b/.gitignore
e955777
index cfc329a..632609e 100644
e955777
--- a/.gitignore
e955777
+++ b/.gitignore
e955777
@@ -13,6 +13,11 @@ ltmain.sh
e955777
 Makefile.in
e955777
 missing
e955777
 support/include/config.h.in
e955777
+aclocal/libtool.m4
e955777
+aclocal/ltoptions.m4
e955777
+aclocal/ltsugar.m4
e955777
+aclocal/ltversion.m4
e955777
+aclocal/lt~obsolete.m4
e955777
 # files generated by configure
e955777
 confdefs.h
e955777
 config.status
e955777
diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h
e955777
index 543c35b..dff6af7 100644
e955777
--- a/support/include/nfsrpc.h
e955777
+++ b/support/include/nfsrpc.h
e955777
@@ -49,6 +49,25 @@
e955777
 #define NSMPROG		((rpcprog_t)100024)
e955777
 #endif
e955777
 
e955777
+/**
e955777
+ * nfs_clear_rpc_createerr - zap all error reporting fields
e955777
+ *
e955777
+ */
e955777
+static inline void nfs_clear_rpc_createerr(void)
e955777
+{
e955777
+	memset(&rpc_createerr, 0, sizeof(rpc_createerr));
e955777
+}
e955777
+
e955777
+/*
e955777
+ * Extract port value from a socket address
e955777
+ */
e955777
+extern uint16_t		nfs_get_port(const struct sockaddr *);
e955777
+
e955777
+/*
e955777
+ * Set port value in a socket address
e955777
+ */
e955777
+extern void		nfs_set_port(struct sockaddr *, const uint16_t);
e955777
+
e955777
 /*
e955777
  * Look up an RPC program name in /etc/rpc
e955777
  */
e955777
@@ -73,8 +92,7 @@ extern CLIENT		*nfs_get_priv_rpcclient( const struct sockaddr *,
e955777
 /*
e955777
  * Convert a socket address to a universal address
e955777
  */
e955777
-extern char		*nfs_sockaddr2universal(const struct sockaddr *,
e955777
-				const socklen_t);
e955777
+extern char		*nfs_sockaddr2universal(const struct sockaddr *);
e955777
 
e955777
 /*
e955777
  * Extract port number from a universal address
e955777
@@ -114,7 +132,6 @@ extern unsigned short	nfs_rpcb_getaddr(const struct sockaddr *,
e955777
 				const socklen_t,
e955777
 				const unsigned short,
e955777
 				const struct sockaddr *,
e955777
-				const socklen_t,
e955777
 				const rpcprog_t,
e955777
 				const rpcvers_t,
e955777
 				const unsigned short,
e955777
diff --git a/support/nfs/getport.c b/support/nfs/getport.c
e955777
index cf1677e..4bdf556 100644
e955777
--- a/support/nfs/getport.c
e955777
+++ b/support/nfs/getport.c
e955777
@@ -65,77 +65,52 @@ static const rpcvers_t default_rpcb_version = RPCBVERS_4;
e955777
 static const rpcvers_t default_rpcb_version = PMAPVERS;
e955777
 #endif	/* !HAVE_LIBTIRPC */
e955777
 
e955777
-#ifdef HAVE_DECL_AI_ADDRCONFIG
e955777
 /*
e955777
- * getaddrinfo(3) generates a usable loopback address based on how the
e955777
- * local network interfaces are configured.  RFC 3484 requires that the
e955777
- * results are sorted so that the first result has the best likelihood
e955777
- * of working, so we try just that first result.
e955777
+ * Historical: Map TCP connect timeouts to timeout
e955777
+ * error code used by UDP.
e955777
+ */
e955777
+static void
e955777
+nfs_gp_map_tcp_errorcodes(const unsigned short protocol)
e955777
+{
e955777
+	if (protocol != IPPROTO_TCP)
e955777
+		return;
e955777
+
e955777
+	switch (rpc_createerr.cf_error.re_errno) {
e955777
+	case ETIMEDOUT:
e955777
+		rpc_createerr.cf_stat = RPC_TIMEDOUT;
e955777
+		break;
e955777
+	case ECONNREFUSED:
e955777
+		rpc_createerr.cf_stat = RPC_CANTRECV;
e955777
+		break;
e955777
+	}
e955777
+}
e955777
+
e955777
+/*
e955777
+ * There's no easy way to tell how the local system's networking
e955777
+ * and rpcbind is configured (ie. whether we want to use IPv6 or
e955777
+ * IPv4 loopback to contact RPC services on the local host).  We
e955777
+ * punt and simply try to look up "localhost".
e955777
  *
e955777
  * Returns TRUE on success.
e955777
  */
e955777
 static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
e955777
 {
e955777
 	struct addrinfo *gai_results;
e955777
-	struct addrinfo gai_hint = {
e955777
-		.ai_flags	= AI_ADDRCONFIG,
e955777
-	};
e955777
-	socklen_t len = *salen;
e955777
 	int ret = 0;
e955777
 
e955777
-	if (getaddrinfo(NULL, "sunrpc", &gai_hint, &gai_results))
e955777
+	if (getaddrinfo("localhost", NULL, NULL, &gai_results))
e955777
 		return 0;
e955777
 
e955777
-	switch (gai_results->ai_addr->sa_family) {
e955777
-	case AF_INET:
e955777
-	case AF_INET6:
e955777
-		if (len >= gai_results->ai_addrlen) {
e955777
-			memcpy(sap, gai_results->ai_addr,
e955777
-					gai_results->ai_addrlen);
e955777
-			*salen = gai_results->ai_addrlen;
e955777
-			ret = 1;
e955777
-		}
e955777
+	if (*salen >= gai_results->ai_addrlen) {
e955777
+		memcpy(sap, gai_results->ai_addr,
e955777
+				gai_results->ai_addrlen);
e955777
+		*salen = gai_results->ai_addrlen;
e955777
+		ret = 1;
e955777
 	}
e955777
 
e955777
 	freeaddrinfo(gai_results);
e955777
 	return ret;
e955777
 }
e955777
-#else
e955777
-/*
e955777
- * Old versions of getaddrinfo(3) don't support AI_ADDRCONFIG, so we
e955777
- * have a fallback for building on legacy systems.
e955777
- */
e955777
-static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
e955777
-{
e955777
-	struct sockaddr_in *sin = (struct sockaddr_in *)sap;
e955777
-
e955777
-	memset(sin, 0, sizeof(*sin));
e955777
-
e955777
-	sin->sin_family = AF_INET;
e955777
-	sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
e955777
-	*salen = sizeof(*sin);
e955777
-
e955777
-	return 1;
e955777
-}
e955777
-#endif
e955777
-
e955777
-/*
e955777
- * Plant port number in @sap.  @port is already in network byte order.
e955777
- */
e955777
-static void nfs_gp_set_port(struct sockaddr *sap, const in_port_t port)
e955777
-{
e955777
-	struct sockaddr_in *sin = (struct sockaddr_in *)sap;
e955777
-	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
e955777
-
e955777
-	switch (sap->sa_family) {
e955777
-	case AF_INET:
e955777
-		sin->sin_port = port;
e955777
-		break;
e955777
-	case AF_INET6:
e955777
-		sin6->sin6_port = port;
e955777
-		break;
e955777
-	}
e955777
-}
e955777
 
e955777
 /*
e955777
  * Look up a network service in /etc/services and return the
e955777
@@ -201,7 +176,7 @@ static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol)
e955777
  * client.  Otherwise returns NULL, and rpc_createerr.cf_stat is set to
e955777
  * reflect the error.
e955777
  */
e955777
-static CLIENT *nfs_gp_get_rpcbclient(const struct sockaddr *sap,
e955777
+static CLIENT *nfs_gp_get_rpcbclient(struct sockaddr *sap,
e955777
 				     const socklen_t salen,
e955777
 				     const unsigned short transport,
e955777
 				     const rpcvers_t version,
e955777
@@ -214,15 +189,14 @@ static CLIENT *nfs_gp_get_rpcbclient(const struct sockaddr *sap,
e955777
 		"sunrpc",
e955777
 		NULL,
e955777
 	};
e955777
-	struct sockaddr_storage address;
e955777
-	struct sockaddr *saddr = (struct sockaddr *)&address;
e955777
 	rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, rpcb_pgmtbl);
e955777
+	CLIENT *clnt;
e955777
 
e955777
-	memcpy(saddr, sap, (size_t)salen);
e955777
-	nfs_gp_set_port(saddr, nfs_gp_get_rpcb_port(transport));
e955777
-
e955777
-	return nfs_get_rpcclient(saddr, salen, transport, rpcb_prog,
e955777
-					version, timeout);
e955777
+	nfs_set_port(sap, ntohs(nfs_gp_get_rpcb_port(transport)));
e955777
+	clnt = nfs_get_rpcclient(sap, salen, transport, rpcb_prog,
e955777
+							version, timeout);
e955777
+	nfs_gp_map_tcp_errorcodes(transport);
e955777
+	return clnt;
e955777
 }
e955777
 
e955777
 /*
e955777
@@ -352,7 +326,6 @@ int nfs_universal2port(const char *uaddr)
e955777
 /**
e955777
  * nfs_sockaddr2universal - convert a sockaddr to a "universal address"
e955777
  * @sap: pointer to a socket address
e955777
- * @salen: length of socket address
e955777
  *
e955777
  * Universal addresses (defined in RFC 1833) are used when calling an
e955777
  * rpcbind daemon via protocol versions 3 or 4..
e955777
@@ -361,81 +334,56 @@ int nfs_universal2port(const char *uaddr)
e955777
  * the returned string.  Otherwise NULL is returned and
e955777
  * rpc_createerr.cf_stat is set to reflect the error.
e955777
  *
e955777
+ * inet_ntop(3) is used here, since getnameinfo(3) is not available
e955777
+ * in some earlier glibc releases, and we don't require support for
e955777
+ * scope IDs for universal addresses.
e955777
  */
e955777
-#ifdef HAVE_GETNAMEINFO
e955777
-
e955777
-char *nfs_sockaddr2universal(const struct sockaddr *sap,
e955777
-			     const socklen_t salen)
e955777
+char *nfs_sockaddr2universal(const struct sockaddr *sap)
e955777
 {
e955777
-	struct sockaddr_un *sun = (struct sockaddr_un *)sap;
e955777
-	char buf[NI_MAXHOST];
e955777
+	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
e955777
+	const struct sockaddr_un *sun = (const struct sockaddr_un *)sap;
e955777
+	const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
e955777
+	char buf[INET6_ADDRSTRLEN + 8 /* for port information */];
e955777
 	uint16_t port;
e955777
+	size_t count;
e955777
+	char *result;
e955777
+	int len;
e955777
 
e955777
 	switch (sap->sa_family) {
e955777
 	case AF_LOCAL:
e955777
 		return strndup(sun->sun_path, sizeof(sun->sun_path));
e955777
 	case AF_INET:
e955777
-		if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
e955777
-					NULL, 0, NI_NUMERICHOST) != 0)
e955777
+		if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr,
e955777
+					buf, (socklen_t)sizeof(buf)) == NULL)
e955777
 			goto out_err;
e955777
-		port = ntohs(((struct sockaddr_in *)sap)->sin_port);
e955777
+		port = ntohs(sin->sin_port);
e955777
 		break;
e955777
 	case AF_INET6:
e955777
-		if (getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
e955777
-					NULL, 0, NI_NUMERICHOST) != 0)
e955777
+		if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr,
e955777
+					buf, (socklen_t)sizeof(buf)) == NULL)
e955777
 			goto out_err;
e955777
-		port = ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
e955777
+		port = ntohs(sin6->sin6_port);
e955777
 		break;
e955777
 	default:
e955777
 		goto out_err;
e955777
 	}
e955777
 
e955777
-	(void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
e955777
+	count = sizeof(buf) - strlen(buf);
e955777
+	len = snprintf(buf + strlen(buf), count, ".%u.%u",
e955777
 			(unsigned)(port >> 8), (unsigned)(port & 0xff));
e955777
-
e955777
-	return strdup(buf);
e955777
-
e955777
-out_err:
e955777
-	rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
e955777
-	return NULL;
e955777
-}
e955777
-
e955777
-#else	/* HAVE_GETNAMEINFO */
e955777
-
e955777
-char *nfs_sockaddr2universal(const struct sockaddr *sap,
e955777
-			     const socklen_t salen)
e955777
-{
e955777
-	struct sockaddr_un *sun = (struct sockaddr_un *)sap;
e955777
-	char buf[NI_MAXHOST];
e955777
-	uint16_t port;
e955777
-	char *addr;
e955777
-
e955777
-	switch (sap->sa_family) {
e955777
-	case AF_LOCAL:
e955777
-		return strndup(sun->sun_path, sizeof(sun->sun_path));
e955777
-	case AF_INET:
e955777
-		addr = inet_ntoa(((struct sockaddr_in *)sap)->sin_addr);
e955777
-		if (addr != NULL && strlen(addr) > sizeof(buf))
e955777
-			goto out_err;
e955777
-		strcpy(buf, addr);
e955777
-		port = ntohs(((struct sockaddr_in *)sap)->sin_port);
e955777
-		break;
e955777
-	default:
e955777
+	/* before glibc 2.0.6, snprintf(3) could return -1 */
e955777
+	if (len < 0 || (size_t)len > count)
e955777
 		goto out_err;
e955777
-	}
e955777
 
e955777
-	(void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%u.%u",
e955777
-			(unsigned)(port >> 8), (unsigned)(port & 0xff));
e955777
-
e955777
-	return strdup(buf);
e955777
+	result = strdup(buf);
e955777
+	if (result != NULL)
e955777
+		return result;
e955777
 
e955777
 out_err:
e955777
 	rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
e955777
 	return NULL;
e955777
 }
e955777
 
e955777
-#endif	/* HAVE_GETNAMEINFO */
e955777
-
e955777
 /*
e955777
  * Send a NULL request to the indicated RPC service.
e955777
  *
e955777
@@ -450,6 +398,10 @@ static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
e955777
 			   (xdrproc_t)xdr_void, NULL,
e955777
 			   timeout);
e955777
 
e955777
+	if (status != RPC_SUCCESS) {
e955777
+		rpc_createerr.cf_stat = status;
e955777
+		CLNT_GETERR(client, &rpc_createerr.cf_error);
e955777
+	}
e955777
 	return (int)(status == RPC_SUCCESS);
e955777
 }
e955777
 
e955777
@@ -458,15 +410,10 @@ static int nfs_gp_ping(CLIENT *client, struct timeval timeout)
e955777
 /*
e955777
  * Initialize the rpcb argument for a GETADDR request.
e955777
  *
e955777
- * The rpcbind daemon ignores the parms.r_owner field in GETADDR
e955777
- * requests, but we plant an eye-catcher to help distinguish these
e955777
- * requests in network traces.
e955777
- *
e955777
  * Returns 1 if successful, and caller must free strings pointed
e955777
  * to by r_netid and r_addr; otherwise 0.
e955777
  */
e955777
 static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
e955777
-				  const socklen_t salen,
e955777
 				  const rpcprog_t program,
e955777
 				  const rpcvers_t version,
e955777
 				  const unsigned short protocol,
e955777
@@ -478,7 +425,7 @@ static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
e955777
 	if (netid == NULL)
e955777
 		return 0;
e955777
 
e955777
-	addr = nfs_sockaddr2universal(sap, salen);
e955777
+	addr = nfs_sockaddr2universal(sap);
e955777
 	if (addr == NULL) {
e955777
 		free(netid);
e955777
 		return 0;
e955777
@@ -489,7 +436,7 @@ static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap,
e955777
 	parms->r_vers	= version;
e955777
 	parms->r_netid	= netid;
e955777
 	parms->r_addr	= addr;
e955777
-	parms->r_owner	= "nfs-utils";	/* eye-catcher */
e955777
+	parms->r_owner	= "";
e955777
 
e955777
 	return 1;
e955777
 }
e955777
@@ -531,7 +478,7 @@ static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client,
e955777
 		case RPC_SUCCESS:
e955777
 			if ((uaddr == NULL) || (uaddr[0] == '\0')) {
e955777
 				rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
e955777
-				continue;
e955777
+				return 0;
e955777
 			}
e955777
 
e955777
 			port = nfs_universal2port(uaddr);
e955777
@@ -587,7 +534,7 @@ static unsigned long nfs_gp_pmap_getport(CLIENT *client,
e955777
 
e955777
 	if (status != RPC_SUCCESS) {
e955777
 		rpc_createerr.cf_stat = status;
e955777
-		clnt_geterr(client, &rpc_createerr.cf_error);
e955777
+		CLNT_GETERR(client, &rpc_createerr.cf_error);
e955777
 		port = 0;
e955777
 	} else if (port == 0)
e955777
 		rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
e955777
@@ -599,7 +546,6 @@ static unsigned long nfs_gp_pmap_getport(CLIENT *client,
e955777
 
e955777
 static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
e955777
 					  const struct sockaddr *sap,
e955777
-					  const socklen_t salen,
e955777
 					  const rpcprog_t program,
e955777
 					  const rpcvers_t version,
e955777
 					  const unsigned short protocol,
e955777
@@ -608,8 +554,8 @@ static unsigned short nfs_gp_getport_rpcb(CLIENT *client,
e955777
 	unsigned short port = 0;
e955777
 	struct rpcb parms;
e955777
 
e955777
-	if (nfs_gp_init_rpcb_parms(sap, salen, program,
e955777
-					version, protocol, &parms) != 0) {
e955777
+	if (nfs_gp_init_rpcb_parms(sap, program, version,
e955777
+					protocol, &parms) != 0) {
e955777
 		port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
e955777
 		nfs_gp_free_rpcb_parms(&parms);
e955777
 	}
e955777
@@ -645,7 +591,6 @@ static unsigned long nfs_gp_getport_pmap(CLIENT *client,
e955777
  */
e955777
 static unsigned short nfs_gp_getport(CLIENT *client,
e955777
 				     const struct sockaddr *sap,
e955777
-				     const socklen_t salen,
e955777
 				     const rpcprog_t program,
e955777
 				     const rpcvers_t version,
e955777
 				     const unsigned short protocol,
e955777
@@ -654,7 +599,7 @@ static unsigned short nfs_gp_getport(CLIENT *client,
e955777
 	switch (sap->sa_family) {
e955777
 #ifdef HAVE_LIBTIRPC
e955777
 	case AF_INET6:
e955777
-		return nfs_gp_getport_rpcb(client, sap, salen, program,
e955777
+		return nfs_gp_getport_rpcb(client, sap, program,
e955777
 						version, protocol, timeout);
e955777
 #endif	/* HAVE_LIBTIRPC */
e955777
 	case AF_INET:
e955777
@@ -667,7 +612,7 @@ static unsigned short nfs_gp_getport(CLIENT *client,
e955777
 }
e955777
 
e955777
 /**
e955777
- * nfs_rcp_ping - Determine if RPC service is responding to requests
e955777
+ * nfs_rpc_ping - Determine if RPC service is responding to requests
e955777
  * @sap: pointer to address of server to query (port is already filled in)
e955777
  * @salen: length of server address
e955777
  * @program: requested RPC program number
e955777
@@ -682,6 +627,8 @@ int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen,
e955777
 		 const rpcprog_t program, const rpcvers_t version,
e955777
 		 const unsigned short protocol, const struct timeval *timeout)
e955777
 {
e955777
+	struct sockaddr_storage address;
e955777
+	struct sockaddr *saddr = (struct sockaddr *)&address;
e955777
 	CLIENT *client;
e955777
 	struct timeval tout = { -1, 0 };
e955777
 	int result = 0;
e955777
@@ -689,9 +636,14 @@ int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen,
e955777
 	if (timeout != NULL)
e955777
 		tout = *timeout;
e955777
 
e955777
-	client = nfs_get_rpcclient(sap, salen, protocol, program, version, &tout);
e955777
+	nfs_clear_rpc_createerr();
e955777
+
e955777
+	memcpy(saddr, sap, (size_t)salen);
e955777
+	client = nfs_get_rpcclient(saddr, salen, protocol,
e955777
+						program, version, &tout);
e955777
 	if (client != NULL) {
e955777
 		result = nfs_gp_ping(client, tout);
e955777
+		nfs_gp_map_tcp_errorcodes(protocol);
e955777
 		CLNT_DESTROY(client);
e955777
 	}
e955777
 
e955777
@@ -744,14 +696,19 @@ unsigned short nfs_getport(const struct sockaddr *sap,
e955777
 			   const rpcvers_t version,
e955777
 			   const unsigned short protocol)
e955777
 {
e955777
+	struct sockaddr_storage address;
e955777
+	struct sockaddr *saddr = (struct sockaddr *)&address;
e955777
 	struct timeval timeout = { -1, 0 };
e955777
 	unsigned short port = 0;
e955777
 	CLIENT *client;
e955777
 
e955777
-	client = nfs_gp_get_rpcbclient(sap, salen, protocol,
e955777
+	nfs_clear_rpc_createerr();
e955777
+
e955777
+	memcpy(saddr, sap, (size_t)salen);
e955777
+	client = nfs_gp_get_rpcbclient(saddr, salen, protocol,
e955777
 						default_rpcb_version, &timeout);
e955777
 	if (client != NULL) {
e955777
-		port = nfs_gp_getport(client, sap, salen, program,
e955777
+		port = nfs_gp_getport(client, saddr, program,
e955777
 					version, protocol, timeout);
e955777
 		CLNT_DESTROY(client);
e955777
 	}
e955777
@@ -786,10 +743,12 @@ int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
e955777
 	CLIENT *client;
e955777
 	int result = 0;
e955777
 	
e955777
+	nfs_clear_rpc_createerr();
e955777
+
e955777
 	client = nfs_gp_get_rpcbclient(sap, salen, protocol,
e955777
 						default_rpcb_version, &timeout);
e955777
 	if (client != NULL) {
e955777
-		port = nfs_gp_getport(client, sap, salen, program,
e955777
+		port = nfs_gp_getport(client, sap, program,
e955777
 					version, protocol, timeout);
e955777
 		CLNT_DESTROY(client);
e955777
 		client = NULL;
e955777
@@ -800,18 +759,21 @@ int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
e955777
 		struct sockaddr *saddr = (struct sockaddr *)&address;
e955777
 
e955777
 		memcpy(saddr, sap, (size_t)salen);
e955777
-		nfs_gp_set_port(saddr, htons(port));
e955777
+		nfs_set_port(saddr, port);
e955777
+
e955777
+		nfs_clear_rpc_createerr();
e955777
 
e955777
 		client = nfs_get_rpcclient(saddr, salen, protocol,
e955777
 						program, version, &timeout);
e955777
 		if (client != NULL) {
e955777
 			result = nfs_gp_ping(client, timeout);
e955777
+			nfs_gp_map_tcp_errorcodes(protocol);
e955777
 			CLNT_DESTROY(client);
e955777
 		}
e955777
 	}
e955777
 
e955777
 	if (result)
e955777
-		nfs_gp_set_port(sap, htons(port));
e955777
+		nfs_set_port(sap, port);
e955777
 
e955777
 	return result;
e955777
 }
e955777
@@ -840,13 +802,6 @@ int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen,
e955777
  * isn't listening on /var/run/rpcbind.sock), send a query via UDP to localhost
e955777
  * (UDP doesn't leave a socket in TIME_WAIT, and the timeout is a relatively
e955777
  * short 3 seconds).
e955777
- *
e955777
- * getaddrinfo(3) generates a usable loopback address.  RFC 3484 requires that
e955777
- * the results are sorted so that the first result has the best likelihood of
e955777
- * working, so we try just that first result.  If IPv6 is all that is
e955777
- * available, we are sure to generate an AF_INET6 loopback address and use
e955777
- * rpcbindv4/v3 GETADDR.  AF_INET6 requests go via rpcbind v4/3 in order to
e955777
- * detect if the requested RPC service supports AF_INET6 or not.
e955777
  */
e955777
 unsigned short nfs_getlocalport(const rpcprot_t program,
e955777
 				const rpcvers_t version,
e955777
@@ -867,11 +822,13 @@ unsigned short nfs_getlocalport(const rpcprot_t program,
e955777
 	CLIENT *client;
e955777
 	struct timeval timeout = { -1, 0 };
e955777
 
e955777
+	nfs_clear_rpc_createerr();
e955777
+
e955777
 	client = nfs_gp_get_rpcbclient(sap, salen, 0, RPCBVERS_4, &timeout);
e955777
 	if (client != NULL) {
e955777
 		struct rpcb parms;
e955777
 
e955777
-		if (nfs_gp_init_rpcb_parms(sap, salen, program, version,
e955777
+		if (nfs_gp_init_rpcb_parms(sap, program, version,
e955777
 						protocol, &parms) != 0) {
e955777
 			port = nfs_gp_rpcb_getaddr(client, &parms, timeout);
e955777
 			nfs_gp_free_rpcb_parms(&parms);
e955777
@@ -881,6 +838,8 @@ unsigned short nfs_getlocalport(const rpcprot_t program,
e955777
 #endif	/* NFS_GP_LOCAL */
e955777
 
e955777
 	if (port == 0) {
e955777
+		nfs_clear_rpc_createerr();
e955777
+
e955777
 		if (nfs_gp_loopback_address(lb_addr, &lb_len)) {
e955777
 			port = nfs_getport(lb_addr, lb_len,
e955777
 						program, version, protocol);
e955777
@@ -897,7 +856,6 @@ unsigned short nfs_getlocalport(const rpcprot_t program,
e955777
  * @salen: length of server address
e955777
  * @transport: transport protocol to use for the query
e955777
  * @addr: pointer to r_addr address
e955777
- * @addrlen: length of address
e955777
  * @program: requested RPC program number
e955777
  * @version: requested RPC version number
e955777
  * @protocol: requested IPPROTO_ value of transport protocol
e955777
@@ -928,12 +886,13 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
e955777
 				const socklen_t salen,
e955777
 				const unsigned short transport,
e955777
 				const struct sockaddr *addr,
e955777
-				const socklen_t addrlen,
e955777
 				const rpcprog_t program,
e955777
 				const rpcvers_t version,
e955777
 				const unsigned short protocol,
e955777
 				const struct timeval *timeout)
e955777
 {
e955777
+	struct sockaddr_storage address;
e955777
+	struct sockaddr *saddr = (struct sockaddr *)&address;
e955777
 	CLIENT *client;
e955777
 	struct rpcb parms;
e955777
 	struct timeval tout = { -1, 0 };
e955777
@@ -942,9 +901,13 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
e955777
 	if (timeout != NULL)
e955777
 		tout = *timeout;
e955777
 
e955777
-	client = nfs_gp_get_rpcbclient(sap, salen, transport, RPCBVERS_4, &tout);
e955777
+	nfs_clear_rpc_createerr();
e955777
+
e955777
+	memcpy(saddr, sap, (size_t)salen);
e955777
+	client = nfs_gp_get_rpcbclient(saddr, salen, transport,
e955777
+							RPCBVERS_4, &tout);
e955777
 	if (client != NULL) {
e955777
-		if (nfs_gp_init_rpcb_parms(addr, addrlen, program, version,
e955777
+		if (nfs_gp_init_rpcb_parms(addr, program, version,
e955777
 						protocol, &parms) != 0) {
e955777
 			port = nfs_gp_rpcb_getaddr(client, &parms, tout);
e955777
 			nfs_gp_free_rpcb_parms(&parms);
e955777
@@ -957,16 +920,17 @@ unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
e955777
 
e955777
 #else	/* !HAVE_LIBTIRPC */
e955777
 
e955777
-unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap,
e955777
-				const socklen_t salen,
e955777
-				const unsigned short transport,
e955777
-				const struct sockaddr *addr,
e955777
-				const socklen_t addrlen,
e955777
-				const rpcprog_t program,
e955777
-				const rpcvers_t version,
e955777
-				const unsigned short protocol,
e955777
-				const struct timeval *timeout)
e955777
+unsigned short nfs_rpcb_getaddr(__attribute__((unused)) const struct sockaddr *sap,
e955777
+				__attribute__((unused)) const socklen_t salen,
e955777
+				__attribute__((unused)) const unsigned short transport,
e955777
+				__attribute__((unused)) const struct sockaddr *addr,
e955777
+				__attribute__((unused)) const rpcprog_t program,
e955777
+				__attribute__((unused)) const rpcvers_t version,
e955777
+				__attribute__((unused)) const unsigned short protocol,
e955777
+				__attribute__((unused)) const struct timeval *timeout)
e955777
 {
e955777
+	nfs_clear_rpc_createerr();
e955777
+
e955777
 	rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
e955777
 	return 0;
e955777
 }
e955777
@@ -1008,6 +972,8 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin,
e955777
 			       const unsigned long protocol,
e955777
 			       const struct timeval *timeout)
e955777
 {
e955777
+	struct sockaddr_in address;
e955777
+	struct sockaddr *saddr = (struct sockaddr *)&address;
e955777
 	CLIENT *client;
e955777
 	struct pmap parms = {
e955777
 		.pm_prog	= program,
e955777
@@ -1020,8 +986,10 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin,
e955777
 	if (timeout != NULL)
e955777
 		tout = *timeout;
e955777
 
e955777
-	client = nfs_gp_get_rpcbclient((struct sockaddr *)sin,
e955777
-					(socklen_t)sizeof(*sin),
e955777
+	nfs_clear_rpc_createerr();
e955777
+
e955777
+	memcpy(saddr, sin, sizeof(address));
e955777
+	client = nfs_gp_get_rpcbclient(saddr, (socklen_t)sizeof(*sin),
e955777
 					transport, PMAPVERS, &tout);
e955777
 	if (client != NULL) {
e955777
 		port = nfs_gp_pmap_getport(client, &parms, tout);
e955777
diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c
e955777
index cebf83d..9c20f61 100644
e955777
--- a/support/nfs/rpc_socket.c
e955777
+++ b/support/nfs/rpc_socket.c
e955777
@@ -132,7 +132,7 @@ static int nfs_bind(const int sock, const sa_family_t family)
e955777
 	return -1;
e955777
 }
e955777
 
e955777
-#ifdef IPV6_SUPPORTED
e955777
+#ifdef HAVE_LIBTIRPC
e955777
 
e955777
 /*
e955777
  * Bind a socket using an unused privileged source port.
e955777
@@ -162,7 +162,7 @@ static int nfs_bindresvport(const int sock, const sa_family_t family)
e955777
 	return -1;
e955777
 }
e955777
 
e955777
-#else	/* !IPV6_SUPPORTED */
e955777
+#else	/* !HAVE_LIBTIRPC */
e955777
 
e955777
 /*
e955777
  * Bind a socket using an unused privileged source port.
e955777
@@ -180,7 +180,7 @@ static int nfs_bindresvport(const int sock, const sa_family_t family)
e955777
 	return bindresvport(sock, NULL);
e955777
 }
e955777
 
e955777
-#endif	/* !IPV6_SUPPORTED */
e955777
+#endif	/* !HAVE_LIBTIRPC */
e955777
 
e955777
 /*
e955777
  * Perform a non-blocking connect on the socket fd.
e955777
@@ -326,7 +326,9 @@ static CLIENT *nfs_get_udpclient(const struct sockaddr *sap,
e955777
 					version, *timeout, &sock);
e955777
 #endif	/* !HAVE_LIBTIRPC */
e955777
 	if (client != NULL) {
e955777
-		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)timeout);
e955777
+		struct timeval retry_timeout = { 1, 0 };
e955777
+		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT,
e955777
+						(char *)&retry_timeout);
e955777
 		CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL);
e955777
 	} else
e955777
 		(void)close(sock);
e955777
@@ -414,6 +416,49 @@ static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap,
e955777
 }
e955777
 
e955777
 /**
e955777
+ * nfs_get_port - extract port value from a socket address
e955777
+ * @sap: pointer to socket address
e955777
+ *
e955777
+ * Returns port value in host byte order.
e955777
+ */
e955777
+uint16_t
e955777
+nfs_get_port(const struct sockaddr *sap)
e955777
+{
e955777
+       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
e955777
+       const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
e955777
+
e955777
+       switch (sap->sa_family) {
e955777
+       case AF_INET:
e955777
+               return ntohs(sin->sin_port);
e955777
+       case AF_INET6:
e955777
+               return ntohs(sin6->sin6_port);
e955777
+       }
e955777
+       return 0;
e955777
+}
e955777
+
e955777
+/**
e955777
+ * nfs_set_port - set port value in a socket address
e955777
+ * @sap: pointer to socket address
e955777
+ * @port: port value to set
e955777
+ *
e955777
+ */
e955777
+void
e955777
+nfs_set_port(struct sockaddr *sap, const uint16_t port)
e955777
+{
e955777
+       struct sockaddr_in *sin = (struct sockaddr_in *)sap;
e955777
+       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
e955777
+
e955777
+       switch (sap->sa_family) {
e955777
+       case AF_INET:
e955777
+               sin->sin_port = htons(port);
e955777
+               break;
e955777
+       case AF_INET6:
e955777
+               sin6->sin6_port = htons(port);
e955777
+               break;
e955777
+       }
e955777
+}
e955777
+
e955777
+/**
e955777
  * nfs_get_rpcclient - acquire an RPC client
e955777
  * @sap: pointer to socket address of RPC server
e955777
  * @salen: length of socket address
e955777
@@ -438,27 +483,21 @@ CLIENT *nfs_get_rpcclient(const struct sockaddr *sap,
e955777
 			  const rpcvers_t version,
e955777
 			  struct timeval *timeout)
e955777
 {
e955777
-	struct sockaddr_in *sin = (struct sockaddr_in *)sap;
e955777
-	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
e955777
+	nfs_clear_rpc_createerr();
e955777
 
e955777
 	switch (sap->sa_family) {
e955777
 	case AF_LOCAL:
e955777
 		return nfs_get_localclient(sap, salen, program,
e955777
 						version, timeout);
e955777
 	case AF_INET:
e955777
-		if (sin->sin_port == 0) {
e955777
-			rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
e955777
-			return NULL;
e955777
-		}
e955777
-		break;
e955777
 	case AF_INET6:
e955777
-		if (sin6->sin6_port == 0) {
e955777
+		if (nfs_get_port(sap) == 0) {
e955777
 			rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
e955777
 			return NULL;
e955777
 		}
e955777
 		break;
e955777
 	default:
e955777
-		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
e955777
+		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
e955777
 		return NULL;
e955777
 	}
e955777
 
e955777
@@ -501,27 +540,21 @@ CLIENT *nfs_get_priv_rpcclient(const struct sockaddr *sap,
e955777
 			       const rpcvers_t version,
e955777
 			       struct timeval *timeout)
e955777
 {
e955777
-	struct sockaddr_in *sin = (struct sockaddr_in *)sap;
e955777
-	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
e955777
+	nfs_clear_rpc_createerr();
e955777
 
e955777
 	switch (sap->sa_family) {
e955777
 	case AF_LOCAL:
e955777
 		return nfs_get_localclient(sap, salen, program,
e955777
 						version, timeout);
e955777
 	case AF_INET:
e955777
-		if (sin->sin_port == 0) {
e955777
-			rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
e955777
-			return NULL;
e955777
-		}
e955777
-		break;
e955777
 	case AF_INET6:
e955777
-		if (sin6->sin6_port == 0) {
e955777
+		if (nfs_get_port(sap) == 0) {
e955777
 			rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
e955777
 			return NULL;
e955777
 		}
e955777
 		break;
e955777
 	default:
e955777
-		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
e955777
+		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
e955777
 		return NULL;
e955777
 	}
e955777
 
e955777
diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c
e955777
index 69d2a69..729b6a6 100644
e955777
--- a/utils/gssd/svcgssd.c
e955777
+++ b/utils/gssd/svcgssd.c
e955777
@@ -117,10 +117,16 @@ mydaemon(int nochdir, int noclose)
e955777
 
e955777
 	if (noclose == 0) {
e955777
 		tempfd = open("/dev/null", O_RDWR);
e955777
-		dup2(tempfd, 0);
e955777
-		dup2(tempfd, 1);
e955777
-		dup2(tempfd, 2);
e955777
-		closeall(3);
e955777
+		if (tempfd >= 0) {
e955777
+			dup2(tempfd, 0);
e955777
+			dup2(tempfd, 1);
e955777
+			dup2(tempfd, 2);
e955777
+			close(tempfd);
e955777
+		} else {
e955777
+			printerr(1, "mydaemon: can't open /dev/null: errno %d "
e955777
+				    "(%s)\n", errno, strerror(errno));
e955777
+			exit(1);
e955777
+		}
e955777
 	}
e955777
 
e955777
 	return;
e955777
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
e955777
index b690e21..9cbe96c 100644
e955777
--- a/utils/idmapd/idmapd.c
e955777
+++ b/utils/idmapd/idmapd.c
e955777
@@ -978,9 +978,12 @@ mydaemon(int nochdir, int noclose)
e955777
 			dup2(tempfd, 0);
e955777
 			dup2(tempfd, 1);
e955777
 			dup2(tempfd, 2);
e955777
-			closeall(3);
e955777
-		} else
e955777
-			closeall(0);
e955777
+			close(tempfd);
e955777
+		} else {
e955777
+			err(1, "mydaemon: can't open /dev/null: errno %d",
e955777
+			       errno);
e955777
+			exit(1);
e955777
+		}
e955777
 	}
e955777
 
e955777
 	return;
e955777
diff --git a/utils/mount/error.c b/utils/mount/error.c
e955777
index 5c9d3f2..1b64bd7 100644
e955777
--- a/utils/mount/error.c
e955777
+++ b/utils/mount/error.c
e955777
@@ -70,9 +70,15 @@ static int rpc_strerror(int spos)
e955777
 			pos = snprintf(tmp, (erreob - tmp),
e955777
 					_("System Error: %s"),
e955777
 						strerror(cf_errno));
e955777
-		else
e955777
-			pos = snprintf(tmp, (erreob - tmp),
e955777
-					_("RPC Error:%s"), estr);
e955777
+		else {
e955777
+			if (cf_errno) 
e955777
+				pos = snprintf(tmp, (erreob - tmp),
e955777
+					_("RPC Error:%s; errno = %s"), 
e955777
+					estr, strerror(cf_errno));
e955777
+			else
e955777
+				pos = snprintf(tmp, (erreob - tmp),
e955777
+						_("RPC Error:%s"), estr);
e955777
+		}
e955777
 	}
e955777
 	return pos;
e955777
 }
e955777
@@ -300,6 +306,8 @@ void umount_error(int err, const char *dev)
e955777
 #define EDQUOT	ENOSPC
e955777
 #endif
e955777
 
e955777
+#define ARRAY_SIZE(x)		(sizeof(x) / sizeof((x)[0])) 
e955777
+
e955777
 static struct {
e955777
 	enum nfsstat stat;
e955777
 	int errnum;
e955777
@@ -329,19 +337,17 @@ static struct {
e955777
 #endif
e955777
 	/* Throw in some NFSv3 values for even more fun (HP returns these) */
e955777
 	{ 71,			EREMOTE		},
e955777
-
e955777
-	{ -1,			EIO		}
e955777
 };
e955777
 
e955777
-char *nfs_strerror(int stat)
e955777
+char *nfs_strerror(unsigned int stat)
e955777
 {
e955777
-	int i;
e955777
+	unsigned int i;
e955777
 	static char buf[256];
e955777
 
e955777
-	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
e955777
+	for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
e955777
 		if (nfs_errtbl[i].stat == stat)
e955777
 			return strerror(nfs_errtbl[i].errnum);
e955777
 	}
e955777
-	sprintf(buf, _("unknown nfs status return value: %d"), stat);
e955777
+	sprintf(buf, _("unknown nfs status return value: %u"), stat);
e955777
 	return buf;
e955777
 }
e955777
diff --git a/utils/mount/error.h b/utils/mount/error.h
e955777
index 7126de5..42b28cf 100644
e955777
--- a/utils/mount/error.h
e955777
+++ b/utils/mount/error.h
e955777
@@ -24,7 +24,7 @@
e955777
 #ifndef _NFS_UTILS_MOUNT_ERROR_H
e955777
 #define _NFS_UTILS_MOUNT_ERROR_H
e955777
 
e955777
-char *nfs_strerror(int);
e955777
+char *nfs_strerror(unsigned int);
e955777
 
e955777
 void mount_error(const char *, const char *, int);
e955777
 void rpc_mount_errors(char *, int, int);
e955777
diff --git a/utils/mount/fstab.c b/utils/mount/fstab.c
e955777
index 7668167..2775d0b 100644
e955777
--- a/utils/mount/fstab.c
e955777
+++ b/utils/mount/fstab.c
e955777
@@ -285,7 +285,7 @@ handler (int sig) {
e955777
 }
e955777
 
e955777
 static void
e955777
-setlkw_timeout (int sig) {
e955777
+setlkw_timeout (__attribute__((unused)) int sig) {
e955777
      /* nothing, fcntl will fail anyway */
e955777
 }
e955777
 
e955777
diff --git a/utils/mount/mount.c b/utils/mount/mount.c
e955777
index 06e2804..a668cd9 100644
e955777
--- a/utils/mount/mount.c
e955777
+++ b/utils/mount/mount.c
e955777
@@ -156,7 +156,7 @@ static void parse_opts(const char *options, int *flags, char **extra_opts);
e955777
  */
e955777
 static void discover_nfs_mount_data_version(void)
e955777
 {
e955777
-	int kernel_version = linux_version_code();
e955777
+	unsigned int kernel_version = linux_version_code();
e955777
 
e955777
 	if (kernel_version) {
e955777
 		if (kernel_version < MAKE_VERSION(2, 1, 32))
e955777
@@ -417,7 +417,7 @@ static int chk_mountpoint(char *mount_point)
e955777
 
e955777
 static int try_mount(char *spec, char *mount_point, int flags,
e955777
 			char *fs_type, char **extra_opts, char *mount_opts,
e955777
-			int fake, int nomtab, int bg)
e955777
+			int fake, int bg)
e955777
 {
e955777
 	int ret;
e955777
 
e955777
@@ -582,7 +582,7 @@ int main(int argc, char *argv[])
e955777
 	}
e955777
 
e955777
 	mnt_err = try_mount(spec, mount_point, flags, fs_type, &extra_opts,
e955777
-				mount_opts, fake, nomtab, FOREGROUND);
e955777
+				mount_opts, fake, FOREGROUND);
e955777
 	if (mnt_err == EX_BG) {
e955777
 		printf(_("%s: backgrounding \"%s\"\n"),
e955777
 			progname, spec);
e955777
@@ -600,7 +600,7 @@ int main(int argc, char *argv[])
e955777
 
e955777
 		mnt_err = try_mount(spec, mount_point, flags, fs_type,
e955777
 					&extra_opts, mount_opts, fake,
e955777
-					nomtab, BACKGROUND);
e955777
+					BACKGROUND);
e955777
 		if (verbose && mnt_err)
e955777
 			printf(_("%s: giving up \"%s\"\n"),
e955777
 				progname, spec);
e955777
diff --git a/utils/mount/network.c b/utils/mount/network.c
e955777
index 04a62ab..f6fa5fd 100644
e955777
--- a/utils/mount/network.c
e955777
+++ b/utils/mount/network.c
e955777
@@ -170,21 +170,6 @@ static const unsigned long probe_mnt3_first[] = {
e955777
 	0,
e955777
 };
e955777
 
e955777
-static void nfs_set_port(struct sockaddr *sap, const unsigned short port)
e955777
-{
e955777
-	switch (sap->sa_family) {
e955777
-	case AF_INET:
e955777
-		((struct sockaddr_in *)sap)->sin_port = htons(port);
e955777
-		break;
e955777
-	case AF_INET6:
e955777
-		((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
e955777
-		break;
e955777
-	default:
e955777
-		nfs_error(_("%s: unrecognized address family in %s"),
e955777
-			progname, __func__);
e955777
-	}
e955777
-}
e955777
-
e955777
 static int nfs_lookup(const char *hostname, const sa_family_t family,
e955777
 		      struct sockaddr *sap, socklen_t *salen)
e955777
 {
e955777
@@ -270,7 +255,6 @@ int nfs_gethostbyname(const char *hostname, struct sockaddr_in *sin)
e955777
 /**
e955777
  * nfs_string_to_sockaddr - convert string address to sockaddr
e955777
  * @address:	pointer to presentation format address to convert
e955777
- * @addrlen:	length of presentation address
e955777
  * @sap:	pointer to socket address buffer to fill in
e955777
  * @salen:	IN: length of address buffer
e955777
  *		OUT: length of converted socket address
e955777
@@ -284,8 +268,8 @@ int nfs_gethostbyname(const char *hostname, struct sockaddr_in *sin)
e955777
  * See RFC 4038 section 5.1 or RFC 3513 section 2.2 for more details
e955777
  * on presenting IPv6 addresses as text strings.
e955777
  */
e955777
-int nfs_string_to_sockaddr(const char *address, const size_t addrlen,
e955777
-			   struct sockaddr *sap, socklen_t *salen)
e955777
+int nfs_string_to_sockaddr(const char *address, struct sockaddr *sap,
e955777
+			   socklen_t *salen)
e955777
 {
e955777
 	struct addrinfo *gai_results;
e955777
 	struct addrinfo gai_hint = {
e955777
@@ -509,6 +493,21 @@ static void nfs_pp_debug(const struct sockaddr *sap, const socklen_t salen,
e955777
 			port);
e955777
 }
e955777
 
e955777
+static void nfs_pp_debug2(const char *str)
e955777
+{
e955777
+	if (!verbose)
e955777
+		return;
e955777
+
e955777
+	if (rpc_createerr.cf_error.re_status == RPC_CANTRECV ||
e955777
+	    rpc_createerr.cf_error.re_status == RPC_CANTSEND)
e955777
+		nfs_error(_("%s: portmap query %s%s - %s"),
e955777
+				progname, str, clnt_spcreateerror(""),
e955777
+				strerror(rpc_createerr.cf_error.re_errno));
e955777
+	else
e955777
+		nfs_error(_("%s: portmap query %s%s"),
e955777
+				progname, str, clnt_spcreateerror(""));
e955777
+}
e955777
+
e955777
 /*
e955777
  * Use the portmapper to discover whether or not the service we want is
e955777
  * available. The lists 'versions' and 'protos' define ordered sequences
e955777
@@ -538,9 +537,11 @@ static int nfs_probe_port(const struct sockaddr *sap, const socklen_t salen,
e955777
 	memcpy(saddr, sap, salen);
e955777
 	p_prot = prot ? &prot : protos;
e955777
 	p_vers = vers ? &vers : versions;
e955777
-	rpc_createerr.cf_stat = 0;
e955777
 
e955777
 	for (;;) {
e955777
+		if (verbose)
e955777
+			printf(_("%s: prog %lu, trying vers=%lu, prot=%u\n"),
e955777
+				progname, prog, *p_vers, *p_prot);
e955777
 		p_port = nfs_getport(saddr, salen, prog, *p_vers, *p_prot);
e955777
 		if (p_port) {
e955777
 			if (!port || port == p_port) {
e955777
@@ -550,28 +551,31 @@ static int nfs_probe_port(const struct sockaddr *sap, const socklen_t salen,
e955777
 				if (nfs_rpc_ping(saddr, salen, prog,
e955777
 							*p_vers, *p_prot, NULL))
e955777
 					goto out_ok;
e955777
-			}
e955777
+			} else
e955777
+				rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
e955777
 		}
e955777
 		if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
e955777
 		    rpc_createerr.cf_stat != RPC_TIMEDOUT &&
e955777
 		    rpc_createerr.cf_stat != RPC_CANTRECV &&
e955777
 		    rpc_createerr.cf_stat != RPC_PROGVERSMISMATCH)
e955777
-			goto out_bad;
e955777
+			break;
e955777
 
e955777
 		if (!prot) {
e955777
-			if (*++p_prot)
e955777
+			if (*++p_prot) {
e955777
+				nfs_pp_debug2("retrying");
e955777
 				continue;
e955777
+			}
e955777
 			p_prot = protos;
e955777
 		}
e955777
 		if (rpc_createerr.cf_stat == RPC_TIMEDOUT ||
e955777
 		    rpc_createerr.cf_stat == RPC_CANTRECV)
e955777
-			goto out_bad;
e955777
+			break;
e955777
 
e955777
 		if (vers || !*++p_vers)
e955777
 			break;
e955777
 	}
e955777
 
e955777
-out_bad:
e955777
+	nfs_pp_debug2("failed");
e955777
 	return 0;
e955777
 
e955777
 out_ok:
e955777
@@ -581,7 +585,7 @@ out_ok:
e955777
 		pmap->pm_prot = *p_prot;
e955777
 	if (!port)
e955777
 		pmap->pm_port = p_port;
e955777
-	rpc_createerr.cf_stat = 0;
e955777
+	nfs_clear_rpc_createerr();
e955777
 	return 1;
e955777
 }
e955777
 
e955777
@@ -778,8 +782,8 @@ int start_statd(void)
e955777
 				execl(START_STATD, START_STATD, NULL);
e955777
 				exit(1);
e955777
 			case -1: /* error */
e955777
-				nfs_error(_("fork failed: %s"),
e955777
-							strerror(errno));
e955777
+				nfs_error(_("%s: fork failed: %s"),
e955777
+						progname, strerror(errno));
e955777
 				break;
e955777
 			default: /* parent */
e955777
 				waitpid(pid, NULL,0);
e955777
@@ -844,10 +848,14 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen,
e955777
 			(xdrproc_t)xdr_dirpath, (caddr_t)argp,
e955777
 			(xdrproc_t)xdr_void, NULL,
e955777
 			timeout);
e955777
-	if (verbose && res != RPC_SUCCESS)
e955777
-		nfs_error(_("%s: UMNT call failed: %s"),
e955777
-			progname, clnt_sperrno(res));
e955777
+	if (res != RPC_SUCCESS) {
e955777
+		rpc_createerr.cf_stat = res;
e955777
+		CLNT_GETERR(client, &rpc_createerr.cf_error);
e955777
+		if (verbose)
e955777
+			nfs_error(_("%s: UMNT call failed: %s"),
e955777
+				progname, clnt_sperrno(res));
e955777
 
e955777
+	}
e955777
 	auth_destroy(client->cl_auth);
e955777
 	CLNT_DESTROY(client);
e955777
 
e955777
@@ -1098,7 +1106,7 @@ static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen,
e955777
  *
e955777
  * Returns 1 and fills in @buf if successful; otherwise, zero.
e955777
  */
e955777
-static int nfs_ca_gai(const struct sockaddr *sap, const socklen_t salen,
e955777
+static int nfs_ca_gai(const struct sockaddr *sap,
e955777
 		      struct sockaddr *buf, socklen_t *buflen)
e955777
 {
e955777
 	struct addrinfo *gai_results;
e955777
@@ -1139,7 +1147,7 @@ int nfs_callback_address(const struct sockaddr *sap, const socklen_t salen,
e955777
 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
e955777
 
e955777
 	if (nfs_ca_sockname(sap, salen, buf, buflen) == 0)
e955777
-		if (nfs_ca_gai(sap, salen, buf, buflen) == 0)
e955777
+		if (nfs_ca_gai(sap, buf, buflen) == 0)
e955777
 			goto out_failed;
e955777
 
e955777
 	/*
e955777
@@ -1154,173 +1162,285 @@ int nfs_callback_address(const struct sockaddr *sap, const socklen_t salen,
e955777
 out_failed:
e955777
 	*buflen = 0;
e955777
 	if (verbose)
e955777
-		nfs_error(_("%s: failed to construct callback address"));
e955777
+		nfs_error(_("%s: failed to construct callback address"),
e955777
+				progname);
e955777
 	return 0;
e955777
-
e955777
 }
e955777
 
e955777
 /*
e955777
- * "nfsprog" is only supported by the legacy mount command.  The
e955777
+ * "nfsprog" is supported only by the legacy mount command.  The
e955777
  * kernel mount client does not support this option.
e955777
  *
e955777
- * Returns the value set by the nfsprog= option, the value of
e955777
- * the RPC NFS program specified in /etc/rpc, or a baked-in
e955777
- * default program number, if all fails.
e955777
+ * Returns TRUE if @program contains a valid value for this option,
e955777
+ * or FALSE if the option was specified with an invalid value.
e955777
  */
e955777
-static rpcprog_t nfs_nfs_program(struct mount_options *options)
e955777
+static int
e955777
+nfs_nfs_program(struct mount_options *options, unsigned long *program)
e955777
 {
e955777
 	long tmp;
e955777
 
e955777
-	if (po_get_numeric(options, "nfsprog", &tmp) == PO_FOUND)
e955777
-		if (tmp >= 0)
e955777
-			return tmp;
e955777
-	return nfs_getrpcbyname(NFSPROG, nfs_nfs_pgmtbl);
e955777
-}
e955777
+	switch (po_get_numeric(options, "nfsprog", &tmp)) {
e955777
+	case PO_NOT_FOUND:
e955777
+		break;
e955777
+	case PO_FOUND:
e955777
+		if (tmp > 0) {
e955777
+			*program = tmp;
e955777
+			return 1;
e955777
+		}
e955777
+	case PO_BAD_VALUE:
e955777
+		return 0;
e955777
+	}
e955777
 
e955777
+	/*
e955777
+	 * NFS RPC program wasn't specified.  The RPC program
e955777
+	 * cannot be determined via an rpcbind query.
e955777
+	 */
e955777
+	*program = nfs_getrpcbyname(NFSPROG, nfs_nfs_pgmtbl);
e955777
+	return 1;
e955777
+}
e955777
 
e955777
 /*
e955777
- * Returns the RPC version number specified by the given mount
e955777
- * options for the NFS service, or zero if all fails.
e955777
+ * Returns TRUE if @version contains a valid value for this option,
e955777
+ * or FALSE if the option was specified with an invalid value.
e955777
  */
e955777
-static rpcvers_t nfs_nfs_version(struct mount_options *options)
e955777
+static int
e955777
+nfs_nfs_version(struct mount_options *options, unsigned long *version)
e955777
 {
e955777
 	long tmp;
e955777
 
e955777
 	switch (po_rightmost(options, nfs_version_opttbl)) {
e955777
 	case 0:	/* v2 */
e955777
-		return 2;
e955777
+		*version = 2;
e955777
+		return 1;
e955777
 	case 1: /* v3 */
e955777
-		return 3;
e955777
+		*version = 3;
e955777
+		return 1;
e955777
 	case 2:	/* vers */
e955777
-		if (po_get_numeric(options, "vers", &tmp) == PO_FOUND)
e955777
-			if (tmp >= 2 && tmp <= 3)
e955777
-				return tmp;
e955777
-		break;
e955777
+		switch (po_get_numeric(options, "vers", &tmp)) {
e955777
+		case PO_FOUND:
e955777
+			if (tmp >= 2 && tmp <= 3) {
e955777
+				*version = tmp;
e955777
+				return 1;
e955777
+			}
e955777
+			return 0;
e955777
+		case PO_NOT_FOUND:
e955777
+			nfs_error(_("%s: option parsing error\n"),
e955777
+					progname);
e955777
+		case PO_BAD_VALUE:
e955777
+			return 0;
e955777
+		}
e955777
 	case 3: /* nfsvers */
e955777
-		if (po_get_numeric(options, "nfsvers", &tmp) == PO_FOUND)
e955777
-			if (tmp >= 2 && tmp <= 3)
e955777
-				return tmp;
e955777
-		break;
e955777
+		switch (po_get_numeric(options, "nfsvers", &tmp)) {
e955777
+		case PO_FOUND:
e955777
+			if (tmp >= 2 && tmp <= 3) {
e955777
+				*version = tmp;
e955777
+				return 1;
e955777
+			}
e955777
+			return 0;
e955777
+		case PO_NOT_FOUND:
e955777
+			nfs_error(_("%s: option parsing error\n"),
e955777
+					progname);
e955777
+		case PO_BAD_VALUE:
e955777
+			return 0;
e955777
+		}
e955777
 	}
e955777
 
e955777
-	return 0;
e955777
+	/*
e955777
+	 * NFS version wasn't specified.  The pmap version value
e955777
+	 * will be filled in later by an rpcbind query in this case.
e955777
+	 */
e955777
+	*version = 0;
e955777
+	return 1;
e955777
 }
e955777
 
e955777
 /*
e955777
- * Returns the NFS transport protocol specified by the given mount options
e955777
- *
e955777
- * Returns the IPPROTO_ value specified by the given mount options, or
e955777
- * IPPROTO_UDP if all fails.
e955777
+ * Returns TRUE if @protocol contains a valid value for this option,
e955777
+ * or FALSE if the option was specified with an invalid value.
e955777
  */
e955777
-static unsigned short nfs_nfs_protocol(struct mount_options *options)
e955777
+static int
e955777
+nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol)
e955777
 {
e955777
 	char *option;
e955777
 
e955777
 	switch (po_rightmost(options, nfs_transport_opttbl)) {
e955777
+	case 0:	/* udp */
e955777
+		*protocol = IPPROTO_UDP;
e955777
+		return 1;
e955777
 	case 1: /* tcp */
e955777
-		return IPPROTO_TCP;
e955777
+		*protocol = IPPROTO_TCP;
e955777
+		return 1;
e955777
 	case 2: /* proto */
e955777
 		option = po_get(options, "proto");
e955777
 		if (option) {
e955777
-			if (strcmp(option, "tcp") == 0)
e955777
-				return IPPROTO_TCP;
e955777
-			if (strcmp(option, "udp") == 0)
e955777
-				return IPPROTO_UDP;
e955777
+			if (strcmp(option, "tcp") == 0) {
e955777
+				*protocol = IPPROTO_TCP;
e955777
+				return 1;
e955777
+			}
e955777
+			if (strcmp(option, "udp") == 0) {
e955777
+				*protocol = IPPROTO_UDP;
e955777
+				return 1;
e955777
+			}
e955777
+			return 0;
e955777
 		}
e955777
 	}
e955777
 
e955777
-	return IPPROTO_UDP;
e955777
+	/*
e955777
+	 * NFS transport protocol wasn't specified.  The pmap
e955777
+	 * protocol value will be filled in later by an rpcbind
e955777
+	 * query in this case.
e955777
+	 */
e955777
+	*protocol = 0;
e955777
+	return 1;
e955777
 }
e955777
 
e955777
 /*
e955777
- * Returns the NFS server's port number specified by the given
e955777
- * mount options, or zero if all fails.  Zero results in a portmap
e955777
- * query to discover the server's mountd service port.
e955777
- *
e955777
- * port=0 will guarantee an rpcbind request precedes the first
e955777
- * NFS RPC so the client can determine the server's port number.
e955777
+ * Returns TRUE if @port contains a valid value for this option,
e955777
+ * or FALSE if the option was specified with an invalid value.
e955777
  */
e955777
-static unsigned short nfs_nfs_port(struct mount_options *options)
e955777
+static int
e955777
+nfs_nfs_port(struct mount_options *options, unsigned long *port)
e955777
 {
e955777
 	long tmp;
e955777
 
e955777
-	if (po_get_numeric(options, "port", &tmp) == PO_FOUND)
e955777
-		if (tmp >= 0 && tmp <= 65535)
e955777
-			return tmp;
e955777
-	return 0;
e955777
+	switch (po_get_numeric(options, "port", &tmp)) {
e955777
+	case PO_NOT_FOUND:
e955777
+		break;
e955777
+	case PO_FOUND:
e955777
+		if (tmp >= 1 && tmp <= 65535) {
e955777
+			*port = tmp;
e955777
+			return 1;
e955777
+		}
e955777
+	case PO_BAD_VALUE:
e955777
+		return 0;
e955777
+	}
e955777
+
e955777
+	/*
e955777
+	 * NFS service port wasn't specified.  The pmap port value
e955777
+	 * will be filled in later by an rpcbind query in this case.
e955777
+	 */
e955777
+	*port = 0;
e955777
+	return 1;
e955777
 }
e955777
 
e955777
 /*
e955777
- * "mountprog" is only supported by the legacy mount command.  The
e955777
+ * "mountprog" is supported only by the legacy mount command.  The
e955777
  * kernel mount client does not support this option.
e955777
  *
e955777
- * Returns the value set by the mountprog= option, the value of
e955777
- * the RPC mount program specified in /etc/rpc, or a baked-in
e955777
- * default program number, if all fails.
e955777
+ * Returns TRUE if @program contains a valid value for this option,
e955777
+ * or FALSE if the option was specified with an invalid value.
e955777
  */
e955777
-static rpcprog_t nfs_mount_program(struct mount_options *options)
e955777
+static int
e955777
+nfs_mount_program(struct mount_options *options, unsigned long *program)
e955777
 {
e955777
 	long tmp;
e955777
 
e955777
-	if (po_get_numeric(options, "mountprog", &tmp) == PO_FOUND)
e955777
-		if (tmp >= 0)
e955777
-			return tmp;
e955777
-	return nfs_getrpcbyname(MOUNTPROG, nfs_mnt_pgmtbl);
e955777
+	switch (po_get_numeric(options, "mountprog", &tmp)) {
e955777
+	case PO_NOT_FOUND:
e955777
+		break;
e955777
+	case PO_FOUND:
e955777
+		if (tmp > 0) {
e955777
+			*program = tmp;
e955777
+			return 1;
e955777
+		}
e955777
+	case PO_BAD_VALUE:
e955777
+		return 0;
e955777
+	}
e955777
+
e955777
+	/*
e955777
+	 * MNT RPC program wasn't specified.  The RPC program
e955777
+	 * cannot be determined via an rpcbind query.
e955777
+	 */
e955777
+	*program = nfs_getrpcbyname(MOUNTPROG, nfs_mnt_pgmtbl);
e955777
+	return 1;
e955777
 }
e955777
 
e955777
 /*
e955777
- * Returns the RPC version number specified by the given mount options,
e955777
- * or the version "3" if all fails.
e955777
+ * Returns TRUE if @version contains a valid value for this option,
e955777
+ * or FALSE if the option was specified with an invalid value.
e955777
  */
e955777
-static rpcvers_t nfs_mount_version(struct mount_options *options)
e955777
+static int
e955777
+nfs_mount_version(struct mount_options *options, unsigned long *version)
e955777
 {
e955777
 	long tmp;
e955777
 
e955777
-	if (po_get_numeric(options, "mountvers", &tmp) == PO_FOUND)
e955777
-		if (tmp >= 1 && tmp <= 4)
e955777
-			return tmp;
e955777
+	switch (po_get_numeric(options, "mountvers", &tmp)) {
e955777
+	case PO_NOT_FOUND:
e955777
+		break;
e955777
+	case PO_FOUND:
e955777
+		if (tmp >= 1 && tmp <= 4) {
e955777
+			*version = tmp;
e955777
+			return 1;
e955777
+		}
e955777
+	case PO_BAD_VALUE:
e955777
+		return 0;
e955777
+	}
e955777
 
e955777
-	return nfsvers_to_mnt(nfs_nfs_version(options));
e955777
+	/*
e955777
+	 * MNT version wasn't specified.  The pmap version value
e955777
+	 * will be filled in later by an rpcbind query in this case.
e955777
+	 */
e955777
+	*version = 0;
e955777
+	return 1;
e955777
 }
e955777
 
e955777
 /*
e955777
- * Returns the transport protocol to use for the mount service
e955777
- *
e955777
- * Returns the IPPROTO_ value specified by the mountproto option, or
e955777
- * if that doesn't exist, the IPPROTO_ value specified for NFS
e955777
- * itself.
e955777
+ * Returns TRUE if @protocol contains a valid value for this option,
e955777
+ * or FALSE if the option was specified with an invalid value.
e955777
  */
e955777
-static unsigned short nfs_mount_protocol(struct mount_options *options)
e955777
+static int
e955777
+nfs_mount_protocol(struct mount_options *options, unsigned long *protocol)
e955777
 {
e955777
 	char *option;
e955777
 
e955777
 	option = po_get(options, "mountproto");
e955777
 	if (option) {
e955777
-		if (strcmp(option, "tcp") == 0)
e955777
-			return IPPROTO_TCP;
e955777
-		if (strcmp(option, "udp") == 0)
e955777
-			return IPPROTO_UDP;
e955777
+		if (strcmp(option, "tcp") == 0) {
e955777
+			*protocol = IPPROTO_TCP;
e955777
+			return 1;
e955777
+		}
e955777
+		if (strcmp(option, "udp") == 0) {
e955777
+			*protocol = IPPROTO_UDP;
e955777
+			return 1;
e955777
+		}
e955777
+		return 0;
e955777
 	}
e955777
 
e955777
-	return nfs_nfs_protocol(options);
e955777
+	/*
e955777
+	 * MNT transport protocol wasn't specified.  If the NFS
e955777
+	 * transport protocol was specified, use that; otherwise
e955777
+	 * set @protocol to zero.  The pmap protocol value will
e955777
+	 * be filled in later by an rpcbind query in this case.
e955777
+	 */
e955777
+	return nfs_nfs_protocol(options, protocol);
e955777
 }
e955777
 
e955777
 /*
e955777
- * Returns the mountd server's port number specified by the given
e955777
- * mount options, or zero if all fails.  Zero results in a portmap
e955777
- * query to discover the server's mountd service port.
e955777
- *
e955777
- * port=0 will guarantee an rpcbind request precedes the mount
e955777
- * RPC so the client can determine the server's port number.
e955777
+ * Returns TRUE if @port contains a valid value for this option,
e955777
+ * or FALSE if the option was specified with an invalid value.
e955777
  */
e955777
-static unsigned short nfs_mount_port(struct mount_options *options)
e955777
+static int
e955777
+nfs_mount_port(struct mount_options *options, unsigned long *port)
e955777
 {
e955777
 	long tmp;
e955777
 
e955777
-	if (po_get_numeric(options, "mountport", &tmp) == PO_FOUND)
e955777
-		if (tmp >= 0 && tmp <= 65535)
e955777
-			return tmp;
e955777
-	return 0;
e955777
+	switch (po_get_numeric(options, "mountport", &tmp)) {
e955777
+	case PO_NOT_FOUND:
e955777
+		break;
e955777
+	case PO_FOUND:
e955777
+		if (tmp >= 1 && tmp <= 65535) {
e955777
+			*port = tmp;
e955777
+			return 1;
e955777
+		}
e955777
+	case PO_BAD_VALUE:
e955777
+		return 0;
e955777
+	}
e955777
+
e955777
+	/*
e955777
+	 * MNT service port wasn't specified.  The pmap port value
e955777
+	 * will be filled in later by an rpcbind query in this case.
e955777
+	 */
e955777
+	*port = 0;
e955777
+	return 1;
e955777
 }
e955777
 
e955777
 /**
e955777
@@ -1329,17 +1449,29 @@ static unsigned short nfs_mount_port(struct mount_options *options)
e955777
  * @nfs_pmap: OUT: pointer to pmap arguments for NFS server
e955777
  * @mnt_pmap: OUT: pointer to pmap arguments for mountd server
e955777
  *
e955777
+ * Returns TRUE if the pmap options specified in @options have valid
e955777
+ * values; otherwise FALSE is returned.
e955777
  */
e955777
-void nfs_options2pmap(struct mount_options *options,
e955777
-		      struct pmap *nfs_pmap, struct pmap *mnt_pmap)
e955777
+int nfs_options2pmap(struct mount_options *options,
e955777
+		     struct pmap *nfs_pmap, struct pmap *mnt_pmap)
e955777
 {
e955777
-	nfs_pmap->pm_prog = nfs_nfs_program(options);
e955777
-	nfs_pmap->pm_vers = nfs_nfs_version(options);
e955777
-	nfs_pmap->pm_prot = nfs_nfs_protocol(options);
e955777
-	nfs_pmap->pm_port = nfs_nfs_port(options);
e955777
-
e955777
-	mnt_pmap->pm_prog = nfs_mount_program(options);
e955777
-	mnt_pmap->pm_vers = nfs_mount_version(options);
e955777
-	mnt_pmap->pm_prot = nfs_mount_protocol(options);
e955777
-	mnt_pmap->pm_port = nfs_mount_port(options);
e955777
+	if (!nfs_nfs_program(options, &nfs_pmap->pm_prog))
e955777
+		return 0;
e955777
+	if (!nfs_nfs_version(options, &nfs_pmap->pm_vers))
e955777
+		return 0;
e955777
+	if (!nfs_nfs_protocol(options, &nfs_pmap->pm_prot))
e955777
+		return 0;
e955777
+	if (!nfs_nfs_port(options, &nfs_pmap->pm_port))
e955777
+		return 0;
e955777
+
e955777
+	if (!nfs_mount_program(options, &mnt_pmap->pm_prog))
e955777
+		return 0;
e955777
+	if (!nfs_mount_version(options, &mnt_pmap->pm_vers))
e955777
+		return 0;
e955777
+	if (!nfs_mount_protocol(options, &mnt_pmap->pm_prot))
e955777
+		return 0;
e955777
+	if (!nfs_mount_port(options, &mnt_pmap->pm_port))
e955777
+		return 0;
e955777
+
e955777
+	return 1;
e955777
 }
e955777
diff --git a/utils/mount/network.h b/utils/mount/network.h
e955777
index b3f9bd2..db5134c 100644
e955777
--- a/utils/mount/network.h
e955777
+++ b/utils/mount/network.h
e955777
@@ -45,8 +45,7 @@ int nfs_probe_bothports(const struct sockaddr *, const socklen_t,
e955777
 			const socklen_t, struct pmap *);
e955777
 int nfs_gethostbyname(const char *, struct sockaddr_in *);
e955777
 int nfs_name_to_address(const char *, struct sockaddr *, socklen_t *);
e955777
-int nfs_string_to_sockaddr(const char *, const size_t,
e955777
-			   struct sockaddr *, socklen_t *);
e955777
+int nfs_string_to_sockaddr(const char *, struct sockaddr *, socklen_t *);
e955777
 int nfs_present_sockaddr(const struct sockaddr *,
e955777
 			 const socklen_t, char *, const size_t);
e955777
 int nfs_callback_address(const struct sockaddr *, const socklen_t,
e955777
@@ -57,7 +56,7 @@ int clnt_ping(struct sockaddr_in *, const unsigned long,
e955777
 
e955777
 struct mount_options;
e955777
 
e955777
-void nfs_options2pmap(struct mount_options *,
e955777
+int nfs_options2pmap(struct mount_options *,
e955777
 		      struct pmap *, struct pmap *);
e955777
 
e955777
 int start_statd(void);
e955777
diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c
e955777
index 9b48cc9..f81db14 100644
e955777
--- a/utils/mount/nfsumount.c
e955777
+++ b/utils/mount/nfsumount.c
e955777
@@ -174,7 +174,10 @@ static int nfs_umount_do_umnt(struct mount_options *options,
e955777
 	socklen_t salen = sizeof(address);
e955777
 	struct pmap nfs_pmap, mnt_pmap;
e955777
 
e955777
-	nfs_options2pmap(options, &nfs_pmap, &mnt_pmap);
e955777
+	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) {
e955777
+		nfs_error(_("%s: bad mount options"), progname);
e955777
+		return EX_FAIL;
e955777
+	}
e955777
 
e955777
 	*hostname = nfs_umount_hostname(options, *hostname);
e955777
 	if (!*hostname) {
e955777
@@ -333,7 +336,7 @@ int nfsumount(int argc, char *argv[])
e955777
 			char *opt = hasmntopt(&mc->m, "user");
e955777
 			struct passwd *pw;
e955777
 			char *comma;
e955777
-			int len;
e955777
+			size_t len;
e955777
 			if (!opt)
e955777
 				goto only_root;
e955777
 			if (opt[4] != '=')
e955777
diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c
e955777
index c0a8e18..c8a58b1 100644
e955777
--- a/utils/mount/parse_dev.c
e955777
+++ b/utils/mount/parse_dev.c
e955777
@@ -183,8 +183,9 @@ static int nfs_parse_square_bracket(const char *dev,
e955777
  * with the mount request and failing with a cryptic error message
e955777
  * later.
e955777
  */
e955777
-static int nfs_parse_nfs_url(const char *dev,
e955777
-			     char **hostname, char **pathname)
e955777
+static int nfs_parse_nfs_url(__attribute__((unused)) const char *dev,
e955777
+			     __attribute__((unused)) char **hostname,
e955777
+			     __attribute__((unused)) char **pathname)
e955777
 {
e955777
 	nfs_error(_("%s: NFS URLs are not supported"), progname);
e955777
 	return 0;
e955777
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
e955777
index ec95b78..a12ace7 100644
e955777
--- a/utils/mount/stropts.c
e955777
+++ b/utils/mount/stropts.c
e955777
@@ -130,12 +130,14 @@ static int nfs_append_generic_address_option(const struct sockaddr *sap,
e955777
 {
e955777
 	char address[NI_MAXHOST];
e955777
 	char new_option[512];
e955777
+	int len;
e955777
 
e955777
 	if (!nfs_present_sockaddr(sap, salen, address, sizeof(address)))
e955777
 		goto out_err;
e955777
 
e955777
-	if (snprintf(new_option, sizeof(new_option), "%s=%s",
e955777
-					keyword, address) >= sizeof(new_option))
e955777
+	len = snprintf(new_option, sizeof(new_option), "%s=%s",
e955777
+						keyword, address);
e955777
+	if (len < 0 || (size_t)len >= sizeof(new_option))
e955777
 		goto out_err;
e955777
 
e955777
 	if (po_append(options, new_option) != PO_SUCCEEDED)
e955777
@@ -283,27 +285,16 @@ static int nfs_validate_options(struct nfsmount_info *mi)
e955777
 	if (!nfs_append_sloppy_option(mi->options))
e955777
 		return 0;
e955777
 
e955777
-	return nfs_append_addr_option(sap, salen, mi->options);
e955777
-}
e955777
+	if (!nfs_append_addr_option(sap, salen, mi->options))
e955777
+		return 0;
e955777
 
e955777
-/*
e955777
- * Distinguish between permanent and temporary errors.
e955777
- *
e955777
- * Returns 0 if the passed-in error is temporary, thus the
e955777
- * mount system call should be retried; returns one if the
e955777
- * passed-in error is permanent, thus the mount system call
e955777
- * should not be retried.
e955777
- */
e955777
-static int nfs_is_permanent_error(int error)
e955777
-{
e955777
-	switch (error) {
e955777
-	case ESTALE:
e955777
-	case ETIMEDOUT:
e955777
-	case ECONNREFUSED:
e955777
-		return 0;	/* temporary */
e955777
-	default:
e955777
-		return 1;	/* permanent */
e955777
-	}
e955777
+	/*
e955777
+	 * Update option string to be recorded in /etc/mnttab
e955777
+	 */
e955777
+	if (po_join(mi->options, mi->extra_opts) == PO_FAILED)
e955777
+		return 0;
e955777
+
e955777
+	return 1;
e955777
 }
e955777
 
e955777
 /*
e955777
@@ -323,16 +314,14 @@ static int nfs_extract_server_addresses(struct mount_options *options,
e955777
 	option = po_get(options, "addr");
e955777
 	if (option == NULL)
e955777
 		return 0;
e955777
-	if (!nfs_string_to_sockaddr(option, strlen(option),
e955777
-						nfs_saddr, nfs_salen))
e955777
+	if (!nfs_string_to_sockaddr(option, nfs_saddr, nfs_salen))
e955777
 		return 0;
e955777
 
e955777
 	option = po_get(options, "mountaddr");
e955777
 	if (option == NULL) {
e955777
 		memcpy(mnt_saddr, nfs_saddr, *nfs_salen);
e955777
 		*mnt_salen = *nfs_salen;
e955777
-	} else if (!nfs_string_to_sockaddr(option, strlen(option),
e955777
-						mnt_saddr, mnt_salen))
e955777
+	} else if (!nfs_string_to_sockaddr(option, mnt_saddr, mnt_salen))
e955777
 		return 0;
e955777
 
e955777
 	return 1;
e955777
@@ -420,206 +409,135 @@ static int nfs_construct_new_options(struct mount_options *options,
e955777
  *
e955777
  * To handle version and transport protocol fallback properly, we
e955777
  * need to parse some of the mount options in order to set up a
e955777
- * portmap probe.  Mount options that nfs_rewrite_mount_options()
e955777
+ * portmap probe.  Mount options that nfs_rewrite_pmap_mount_options()
e955777
  * doesn't recognize are left alone.
e955777
  *
e955777
- * Returns a new group of mount options if successful; otherwise
e955777
- * NULL is returned if some failure occurred.
e955777
+ * Returns TRUE if rewriting was successful; otherwise
e955777
+ * FALSE is returned if some failure occurred.
e955777
  */
e955777
-static struct mount_options *nfs_rewrite_mount_options(char *str)
e955777
+static int
e955777
+nfs_rewrite_pmap_mount_options(struct mount_options *options)
e955777
 {
e955777
-	struct mount_options *options;
e955777
 	struct sockaddr_storage nfs_address;
e955777
 	struct sockaddr *nfs_saddr = (struct sockaddr *)&nfs_address;
e955777
-	socklen_t nfs_salen;
e955777
+	socklen_t nfs_salen = sizeof(nfs_address);
e955777
 	struct pmap nfs_pmap;
e955777
 	struct sockaddr_storage mnt_address;
e955777
 	struct sockaddr *mnt_saddr = (struct sockaddr *)&mnt_address;
e955777
-	socklen_t mnt_salen;
e955777
+	socklen_t mnt_salen = sizeof(mnt_address);
e955777
 	struct pmap mnt_pmap;
e955777
+	char *option;
e955777
 
e955777
-	options = po_split(str);
e955777
-	if (!options) {
e955777
-		errno = EFAULT;
e955777
-		return NULL;
e955777
-	}
e955777
+	/*
e955777
+	 * Skip option negotiation for proto=rdma mounts.
e955777
+	 */
e955777
+	option = po_get(options, "proto");
e955777
+	if (option && strcmp(option, "rdma") == 0)
e955777
+		goto out;
e955777
 
e955777
+	/*
e955777
+	 * Extract just the options needed to contact server.
e955777
+	 * Bail now if any of these have bad values.
e955777
+	 */
e955777
 	if (!nfs_extract_server_addresses(options, nfs_saddr, &nfs_salen,
e955777
 						mnt_saddr, &mnt_salen)) {
e955777
 		errno = EINVAL;
e955777
-		goto err;
e955777
+		return 0;
e955777
+	}
e955777
+	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) {
e955777
+		errno = EINVAL;
e955777
+		return 0;
e955777
 	}
e955777
 
e955777
-	nfs_options2pmap(options, &nfs_pmap, &mnt_pmap);
e955777
-
e955777
-	/* The kernel NFS client doesn't support changing the RPC program
e955777
-	 * number for these services, so reset these fields before probing
e955777
-	 * the server's ports.  */
e955777
+	/*
e955777
+	 * The kernel NFS client doesn't support changing the RPC
e955777
+	 * program number for these services, so force the value of
e955777
+	 * these fields before probing the server's ports.
e955777
+	 */
e955777
 	nfs_pmap.pm_prog = NFS_PROGRAM;
e955777
 	mnt_pmap.pm_prog = MOUNTPROG;
e955777
 
e955777
+	/*
e955777
+	 * If the server's rpcbind service isn't available, we can't
e955777
+	 * negotiate.  Bail now if we can't contact it.
e955777
+	 */
e955777
 	if (!nfs_probe_bothports(mnt_saddr, mnt_salen, &mnt_pmap,
e955777
 				 nfs_saddr, nfs_salen, &nfs_pmap)) {
e955777
 		errno = ESPIPE;
e955777
-		goto err;
e955777
+		return 0;
e955777
 	}
e955777
 
e955777
 	if (!nfs_construct_new_options(options, &nfs_pmap, &mnt_pmap)) {
e955777
 		errno = EINVAL;
e955777
-		goto err;
e955777
+		return 0;
e955777
 	}
e955777
 
e955777
+out:
e955777
 	errno = 0;
e955777
-	return options;
e955777
-
e955777
-err:
e955777
-	po_destroy(options);
e955777
-	return NULL;
e955777
+	return 1;
e955777
 }
e955777
 
e955777
 /*
e955777
  * Do the mount(2) system call.
e955777
  *
e955777
- * Returns 1 if successful, otherwise zero.
e955777
+ * Returns TRUE if successful, otherwise FALSE.
e955777
  * "errno" is set to reflect the individual error.
e955777
  */
e955777
-static int nfs_sys_mount(const struct nfsmount_info *mi, const char *type,
e955777
-			 const char *options)
e955777
+static int nfs_try_mount(struct nfsmount_info *mi)
e955777
 {
e955777
+	char *options = NULL;
e955777
 	int result;
e955777
 
e955777
-	result = mount(mi->spec, mi->node, type,
e955777
-				mi->flags & ~(MS_USER|MS_USERS), options);
e955777
-	if (verbose && result) {
e955777
-		int save = errno;
e955777
-		nfs_error(_("%s: mount(2): %s"), progname, strerror(save));
e955777
-		errno = save;
e955777
-	}
e955777
-	return !result;
e955777
-}
e955777
-
e955777
-/*
e955777
- * Retry an NFS mount that failed because the requested service isn't
e955777
- * available on the server.
e955777
- *
e955777
- * Returns 1 if successful.  Otherwise, returns zero.
e955777
- * "errno" is set to reflect the individual error.
e955777
- *
e955777
- * Side effect: If the retry is successful, both 'options' and
e955777
- * 'extra_opts' are updated to reflect the mount options that worked.
e955777
- * If the retry fails, 'options' and 'extra_opts' are left unchanged.
e955777
- */
e955777
-static int nfs_retry_nfs23mount(struct nfsmount_info *mi)
e955777
-{
e955777
-	struct mount_options *retry_options;
e955777
-	char *retry_str = NULL;
e955777
-	char **extra_opts = mi->extra_opts;
e955777
-
e955777
-	retry_options = nfs_rewrite_mount_options(*extra_opts);
e955777
-	if (!retry_options)
e955777
-		return 0;
e955777
-
e955777
-	if (po_join(retry_options, &retry_str) == PO_FAILED) {
e955777
-		po_destroy(retry_options);
e955777
-		errno = EIO;
e955777
-		return 0;
e955777
-	}
e955777
-
e955777
-	if (verbose)
e955777
-		printf(_("%s: text-based options (retry): '%s'\n"),
e955777
-			progname, retry_str);
e955777
-
e955777
-	if (!nfs_sys_mount(mi, "nfs", retry_str)) {
e955777
-		po_destroy(retry_options);
e955777
-		free(retry_str);
e955777
-		return 0;
e955777
+	if (strncmp(mi->type, "nfs4", 4) != 0) {
e955777
+		if (!nfs_rewrite_pmap_mount_options(mi->options))
e955777
+			return 0;
e955777
 	}
e955777
 
e955777
-	free(*extra_opts);
e955777
-	*extra_opts = retry_str;
e955777
-	po_replace(mi->options, retry_options);
e955777
-	return 1;
e955777
-}
e955777
-
e955777
-/*
e955777
- * Attempt an NFSv2/3 mount via a mount(2) system call.  If the kernel
e955777
- * claims the requested service isn't supported on the server, probe
e955777
- * the server to see what's supported, rewrite the mount options,
e955777
- * and retry the request.
e955777
- *
e955777
- * Returns 1 if successful.  Otherwise, returns zero.
e955777
- * "errno" is set to reflect the individual error.
e955777
- *
e955777
- * Side effect: If the retry is successful, both 'options' and
e955777
- * 'extra_opts' are updated to reflect the mount options that worked.
e955777
- * If the retry fails, 'options' and 'extra_opts' are left unchanged.
e955777
- */
e955777
-static int nfs_try_nfs23mount(struct nfsmount_info *mi)
e955777
-{
e955777
-	char **extra_opts = mi->extra_opts;
e955777
-
e955777
-	if (po_join(mi->options, extra_opts) == PO_FAILED) {
e955777
+	if (po_join(mi->options, &options) == PO_FAILED) {
e955777
 		errno = EIO;
e955777
 		return 0;
e955777
 	}
e955777
 
e955777
 	if (verbose)
e955777
-		printf(_("%s: text-based options: '%s'\n"),
e955777
-			progname, *extra_opts);
e955777
+		printf(_("%s: trying text-based options '%s'\n"),
e955777
+			progname, options);
e955777
 
e955777
 	if (mi->fake)
e955777
 		return 1;
e955777
 
e955777
-	if (nfs_sys_mount(mi, "nfs", *extra_opts))
e955777
-		return 1;
e955777
-
e955777
-	/*
e955777
-	 * The kernel returns EOPNOTSUPP if the RPC bind failed,
e955777
-	 * and EPROTONOSUPPORT if the version isn't supported.
e955777
-	 */
e955777
-	if (errno != EOPNOTSUPP && errno != EPROTONOSUPPORT)
e955777
-		return 0;
e955777
-
e955777
-	return nfs_retry_nfs23mount(mi);
e955777
-}
e955777
-
e955777
-/*
e955777
- * Attempt an NFS v4 mount via a mount(2) system call.
e955777
- *
e955777
- * Returns 1 if successful.  Otherwise, returns zero.
e955777
- * "errno" is set to reflect the individual error.
e955777
- */
e955777
-static int nfs_try_nfs4mount(struct nfsmount_info *mi)
e955777
-{
e955777
-	char **extra_opts = mi->extra_opts;
e955777
-
e955777
-	if (po_join(mi->options, extra_opts) == PO_FAILED) {
e955777
-		errno = EIO;
e955777
-		return 0;
e955777
+	result = mount(mi->spec, mi->node, mi->type,
e955777
+			mi->flags & ~(MS_USER|MS_USERS), options);
e955777
+	if (verbose && result) {
e955777
+		int save = errno;
e955777
+		nfs_error(_("%s: mount(2): %s"), progname, strerror(save));
e955777
+		errno = save;
e955777
 	}
e955777
-
e955777
-	if (verbose)
e955777
-		printf(_("%s: text-based options: '%s'\n"),
e955777
-			progname, *extra_opts);
e955777
-
e955777
-	if (mi->fake)
e955777
-		return 1;
e955777
-
e955777
-	return nfs_sys_mount(mi, "nfs4", *extra_opts);
e955777
+	return !result;
e955777
 }
e955777
 
e955777
 /*
e955777
- * Perform either an NFSv2/3 mount, or an NFSv4 mount system call.
e955777
+ * Distinguish between permanent and temporary errors.
e955777
  *
e955777
- * Returns 1 if successful.  Otherwise, returns zero.
e955777
- * "errno" is set to reflect the individual error.
e955777
+ * Basically, we retry if communication with the server has
e955777
+ * failed so far, but fail immediately if there is a local
e955777
+ * error (like a bad mount option).
e955777
+ *
e955777
+ * ESTALE is also a temporary error because some servers
e955777
+ * return ESTALE when a share is temporarily offline.
e955777
+ *
e955777
+ * Returns 1 if we should fail immediately, or 0 if we
e955777
+ * should retry.
e955777
  */
e955777
-static int nfs_try_mount(struct nfsmount_info *mi)
e955777
+static int nfs_is_permanent_error(int error)
e955777
 {
e955777
-	if (strncmp(mi->type, "nfs4", 4) == 0)
e955777
-		return nfs_try_nfs4mount(mi);
e955777
-	else
e955777
-		return nfs_try_nfs23mount(mi);
e955777
+	switch (error) {
e955777
+	case ESTALE:
e955777
+	case ETIMEDOUT:
e955777
+	case ECONNREFUSED:
e955777
+		return 0;	/* temporary */
e955777
+	default:
e955777
+		return 1;	/* permanent */
e955777
+	}
e955777
 }
e955777
 
e955777
 /*