[nfs-utils] - Update to upstream RC release: nfs-utils-1-2-3-rc5

Steve Dickson steved at fedoraproject.org
Thu Sep 9 15:29:20 UTC 2010


commit 2672323f34ef4cc3e0567b48f3dc8f367242cf2a
Author: Steve Dickson <steved at redhat.com>
Date:   Thu Sep 9 11:27:39 2010 -0400

    - Update to upstream RC release: nfs-utils-1-2-3-rc5
    
    Signed-off-by: Steve Dickson <steved at redhat.com>

 nfs-utils-1-2-3-rc5.patch | 5668 +++++++++++++++++++++++++++++++++++++++++++++
 nfs-utils.spec            |    7 +-
 2 files changed, 5673 insertions(+), 2 deletions(-)
---
diff --git a/nfs-utils-1-2-3-rc5.patch b/nfs-utils-1-2-3-rc5.patch
new file mode 100644
index 0000000..504ab01
--- /dev/null
+++ b/nfs-utils-1-2-3-rc5.patch
@@ -0,0 +1,5668 @@
+diff -up nfs-utils-1.2.2/aclocal/libcap.m4.orig nfs-utils-1.2.2/aclocal/libcap.m4
+--- nfs-utils-1.2.2/aclocal/libcap.m4.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/aclocal/libcap.m4	2010-09-09 11:02:27.029025000 -0400
+@@ -5,11 +5,19 @@ AC_DEFUN([AC_LIBCAP], [
+   dnl look for prctl
+   AC_CHECK_FUNC([prctl], , )
+ 
+-  dnl look for the library; do not add to LIBS if found
+-  AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
+-  AC_SUBST(LIBCAP)
++  AC_ARG_ENABLE([caps],
++    [AS_HELP_STRING([--disable-caps], [Disable capabilities support])])
++
++  LIBCAP=
++
++  if test "x$enable_caps" != "xno" ; then
++    dnl look for the library; do not add to LIBS if found
++    AC_CHECK_LIB([cap], [cap_get_proc], [LIBCAP=-lcap], ,)
+ 
+-  AC_CHECK_HEADERS([sys/capability.h], ,
+-                   [AC_MSG_ERROR([libcap headers not found.])])
++    AC_CHECK_HEADERS([sys/capability.h], ,
++      [test "x$enable_caps" = "xyes" && AC_MSG_ERROR([libcap headers not found.])])
++  fi
++
++  AC_SUBST(LIBCAP)
+ 
+ ])dnl
+diff -up nfs-utils-1.2.2/configure.ac.orig nfs-utils-1.2.2/configure.ac
+--- nfs-utils-1.2.2/configure.ac.orig	2010-09-09 11:01:45.340743000 -0400
++++ nfs-utils-1.2.2/configure.ac	2010-09-09 11:02:27.035022000 -0400
+@@ -89,7 +89,7 @@ AC_ARG_ENABLE(nfsv41,
+ 	if test "$enable_nfsv41" = yes; then
+ 		AC_DEFINE(NFS41_SUPPORTED, 1, [Define this if you want NFSv41 support compiled in])
+ 	else
+-		enable_nfsv4=
++		enable_nfsv41=
+ 	fi
+ 	AC_SUBST(enable_nfsv41)
+ 	AM_CONDITIONAL(CONFIG_NFSV41, [test "$enable_nfsv41" = "yes"])
+@@ -411,7 +411,7 @@ case $host in
+     ARCHFLAGS="" ;;
+ esac
+ 
+-my_am_cflags="-Wall -Wstrict-prototypes $ARCHFLAGS -pipe"
++my_am_cflags="-Wall -Wextra -Wstrict-prototypes $ARCHFLAGS -pipe"
+ 
+ AC_SUBST([AM_CFLAGS], ["$my_am_cflags"])
+ 
+@@ -436,6 +436,8 @@ AC_CONFIG_FILES([
+ 	tools/nlmtest/Makefile
+ 	tools/rpcdebug/Makefile
+ 	tools/rpcgen/Makefile
++	tools/mountstats/Makefile
++	tools/nfs-iostat/Makefile
+ 	utils/Makefile
+ 	utils/exportfs/Makefile
+ 	utils/gssd/Makefile
+diff -up nfs-utils-1.2.2/support/export/client.c.orig nfs-utils-1.2.2/support/export/client.c
+--- nfs-utils-1.2.2/support/export/client.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/export/client.c	2010-09-09 11:02:27.041022000 -0400
+@@ -17,7 +17,9 @@
+ #include <string.h>
+ #include <ctype.h>
+ #include <netdb.h>
+-#include "xmalloc.h"
++#include <errno.h>
++
++#include "sockaddr.h"
+ #include "misc.h"
+ #include "nfslib.h"
+ #include "exportfs.h"
+@@ -28,58 +30,260 @@
+ #if !defined(__GLIBC__) || __GLIBC__ < 2
+ extern int	innetgr(char *netgr, char *host, char *, char *);
+ #endif
+-static void	client_init(nfs_client *clp, const char *hname,
+-					struct hostent *hp);
+-static int	client_checkaddr(nfs_client *clp, struct in_addr addr);
++
++static char	*add_name(char *old, const char *add);
+ 
+ nfs_client	*clientlist[MCL_MAXTYPES] = { NULL, };
+ 
+ 
+-/* if canonical is set, then we *know* this is already a canonical name
+- * so hostname lookup is avoided.
+- * This is used when reading /proc/fs/nfs/exports
++static void
++init_addrlist(nfs_client *clp, const struct addrinfo *ai)
++{
++	int i;
++
++	if (ai == NULL)
++		return;
++
++	for (i = 0; (ai != NULL) && (i < NFSCLNT_ADDRMAX); i++) {
++		set_addrlist(clp, i, ai->ai_addr);
++		ai = ai->ai_next;
++	}
++
++	clp->m_naddr = i;
++}
++
++static void
++client_free(nfs_client *clp)
++{
++	free(clp->m_hostname);
++	free(clp);
++}
++
++static int
++init_netmask4(nfs_client *clp, const char *slash)
++{
++	struct sockaddr_in sin = {
++		.sin_family		= AF_INET,
++	};
++	uint32_t shift;
++
++	/*
++	 * Decide what kind of netmask was specified.  If there's
++	 * no '/' present, assume the netmask is all ones.  If
++	 * there is a '/' and at least one '.', look for a spelled-
++	 * out netmask.  Otherwise, assume it was a prefixlen.
++	 */
++	if (slash == NULL)
++		shift = 0;
++	else {
++		unsigned long prefixlen;
++
++		if (strchr(slash + 1, '.') != NULL) {
++			if (inet_pton(AF_INET, slash + 1,
++						&sin.sin_addr.s_addr) == 0)
++				goto out_badmask;
++			set_addrlist_in(clp, 1, &sin);
++			return 1;
++		} else {
++			char *endptr;
++
++			prefixlen = strtoul(slash + 1, &endptr, 10);
++			if (*endptr != '\0' && prefixlen != ULONG_MAX &&
++			    errno != ERANGE)
++				goto out_badprefix;
++		}
++		if (prefixlen > 32)
++			goto out_badprefix;
++		shift = 32 - (uint32_t)prefixlen;
++	}
++
++	/*
++	 * Now construct the full netmask bitmask in a sockaddr_in,
++	 * and plant it in the nfs_client record.
++	 */
++	sin.sin_addr.s_addr = htonl((uint32_t)~0 << shift);
++	set_addrlist_in(clp, 1, &sin);
++
++	return 1;
++
++out_badmask:
++	xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname);
++	return 0;
++
++out_badprefix:
++	xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname);
++	return 0;
++}
++
++#ifdef IPV6_SUPPORTED
++static int
++init_netmask6(nfs_client *clp, const char *slash)
++{
++	struct sockaddr_in6 sin6 = {
++		.sin6_family		= AF_INET6,
++	};
++	unsigned long prefixlen;
++	uint32_t shift;
++	int i;
++
++	/*
++	 * Decide what kind of netmask was specified.  If there's
++	 * no '/' present, assume the netmask is all ones.  If
++	 * there is a '/' and at least one ':', look for a spelled-
++	 * out netmask.  Otherwise, assume it was a prefixlen.
++	 */
++	if (slash == NULL)
++		prefixlen = 128;
++	else {
++		if (strchr(slash + 1, ':') != NULL) {
++			if (!inet_pton(AF_INET6, slash + 1, &sin6.sin6_addr))
++				goto out_badmask;
++			set_addrlist_in6(clp, 1, &sin6);
++			return 1;
++		} else {
++			char *endptr;
++
++			prefixlen = strtoul(slash + 1, &endptr, 10);
++			if (*endptr != '\0' && prefixlen != ULONG_MAX &&
++			    errno != ERANGE)
++				goto out_badprefix;
++		}
++		if (prefixlen > 128)
++			goto out_badprefix;
++	}
++
++	/*
++	 * Now construct the full netmask bitmask in a sockaddr_in6,
++	 * and plant it in the nfs_client record.
++	 */
++	for (i = 0; prefixlen > 32; i++) {
++		sin6.sin6_addr.s6_addr32[i] = 0xffffffff;
++		prefixlen -= 32;
++	}
++	shift = 32 - (uint32_t)prefixlen;
++	sin6.sin6_addr.s6_addr32[i] = htonl((uint32_t)~0 << shift);
++	set_addrlist_in6(clp, 1, &sin6);
++
++	return 1;
++
++out_badmask:
++	xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname);
++	return 0;
++
++out_badprefix:
++	xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname);
++	return 0;
++}
++#else	/* IPV6_SUPPORTED */
++static int
++init_netmask6(nfs_client *UNUSED(clp), const char *UNUSED(slash))
++{
++}
++#endif	/* IPV6_SUPPORTED */
++
++/*
++ * Parse the network mask for M_SUBNETWORK type clients.
++ *
++ * Return TRUE if successful, or FALSE if some error occurred.
++ */
++static int
++init_subnetwork(nfs_client *clp)
++{
++	struct addrinfo *ai;
++	sa_family_t family;
++	int result = 0;
++	char *slash;
++
++	slash = strchr(clp->m_hostname, '/');
++	if (slash != NULL) {
++		*slash = '\0';
++		ai = host_pton(clp->m_hostname);
++		*slash = '/';
++	} else
++		ai = host_pton(clp->m_hostname);
++	if (ai == NULL) {
++		xlog(L_ERROR, "Invalid IP address %s", clp->m_hostname);
++		return result;
++	}
++
++	set_addrlist(clp, 0, ai->ai_addr);
++	family = ai->ai_addr->sa_family;
++
++	freeaddrinfo(ai);
++
++	switch (family) {
++	case AF_INET:
++		result = init_netmask4(clp, slash);
++		break;
++	case AF_INET6:
++		result = init_netmask6(clp, slash);
++		break;
++	default:
++		xlog(L_ERROR, "Unsupported address family for %s",
++			clp->m_hostname);
++	}
++
++	return result;
++}
++
++static int
++client_init(nfs_client *clp, const char *hname, const struct addrinfo *ai)
++{
++	clp->m_hostname = strdup(hname);
++	if (clp->m_hostname == NULL)
++		return 0;
++
++	clp->m_exported = 0;
++	clp->m_count = 0;
++	clp->m_naddr = 0;
++
++	if (clp->m_type == MCL_SUBNETWORK)
++		return init_subnetwork(clp);
++
++	init_addrlist(clp, ai);
++	return 1;
++}
++
++static void
++client_add(nfs_client *clp)
++{
++	nfs_client **cpp;
++
++	cpp = &clientlist[clp->m_type];
++	while (*cpp != NULL)
++		cpp = &((*cpp)->m_next);
++	clp->m_next = NULL;
++	*cpp = clp;
++}
++
++/**
++ * client_lookup - look for @hname in our list of cached nfs_clients
++ * @hname: '\0'-terminated ASCII string containing hostname to look for
++ * @canonical: if set, @hname is known to be canonical DNS name
++ *
++ * Returns pointer to a matching or freshly created nfs_client.  NULL
++ * is returned if some problem occurs.
+  */
+ nfs_client *
+ client_lookup(char *hname, int canonical)
+ {
+ 	nfs_client	*clp = NULL;
+ 	int		htype;
+-	struct hostent	*hp = NULL;
++	struct addrinfo	*ai = NULL;
+ 
+ 	htype = client_gettype(hname);
+ 
+ 	if (htype == MCL_FQDN && !canonical) {
+-		struct hostent *hp2;
+-		hp = gethostbyname(hname);
+-		if (hp == NULL || hp->h_addrtype != AF_INET) {
+-			xlog(L_ERROR, "%s has non-inet addr", hname);
+-			return NULL;
++		ai = host_addrinfo(hname);
++		if (!ai) {
++			xlog(L_ERROR, "Failed to resolve %s", hname);
++			goto out;
+ 		}
+-		/* make sure we have canonical name */
+-		hp2 = hostent_dup(hp);
+-		hp = gethostbyaddr(hp2->h_addr, hp2->h_length,
+-				   hp2->h_addrtype);
+-		if (hp) {
+-			hp = hostent_dup(hp);
+-			/* but now we might not have all addresses... */
+-			if (hp2->h_addr_list[1]) {
+-				struct hostent *hp3 =
+-					gethostbyname(hp->h_name);
+-				if (hp3) {
+-					free(hp);
+-					hp = hostent_dup(hp3);
+-				}
+-			}
+-			free(hp2);
+-		} else
+-			hp = hp2;
+-
+-		hname = (char *) hp->h_name;
++		hname = ai->ai_canonname;
+ 
+-		for (clp = clientlist[htype]; clp; clp = clp->m_next) {
+-			if (client_check(clp, hp))
++		for (clp = clientlist[htype]; clp; clp = clp->m_next)
++			if (client_check(clp, ai))
+ 				break;
+-		}
+ 	} else {
+ 		for (clp = clientlist[htype]; clp; clp = clp->m_next) {
+ 			if (strcasecmp(hname, clp->m_hostname)==0)
+@@ -87,106 +291,60 @@ client_lookup(char *hname, int canonical
+ 		}
+ 	}
+ 
+-	if (!clp) {
+-		clp = (nfs_client *) xmalloc(sizeof(*clp));
+-		memset(clp, 0, sizeof(*clp));
++	if (clp == NULL) {
++		clp = calloc(1, sizeof(*clp));
++		if (clp == NULL)
++			goto out;
+ 		clp->m_type = htype;
+-		client_init(clp, hname, NULL);
++		if (!client_init(clp, hname, NULL)) {
++			client_free(clp);
++			clp = NULL;
++			goto out;
++		}
+ 		client_add(clp);
+ 	}
+ 
+-	if (htype == MCL_FQDN && clp->m_naddr == 0 && hp != NULL) {
+-		char	**ap = hp->h_addr_list;
+-		int	i;
+-
+-		for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++)
+-			clp->m_addrlist[i] = *(struct in_addr *)*ap;
+-		clp->m_naddr = i;
+-	}
+-
+-	if (hp)
+-		free (hp);
++	if (htype == MCL_FQDN && clp->m_naddr == 0)
++		init_addrlist(clp, ai);
+ 
++out:
++	freeaddrinfo(ai);
+ 	return clp;
+ }
+ 
++/**
++ * client_dup - create a copy of an nfs_client
++ * @clp: pointer to nfs_client to copy
++ * @ai: pointer to addrinfo used to initialize the new client's addrlist
++ *
++ * Returns a dynamically allocated nfs_client if successful, or
++ * NULL if some problem occurs.  Caller must free the returned
++ * nfs_client with free(3).
++ */
+ nfs_client *
+-client_dup(nfs_client *clp, struct hostent *hp)
++client_dup(const nfs_client *clp, const struct addrinfo *ai)
+ {
+ 	nfs_client		*new;
+ 
+-	new = (nfs_client *) xmalloc(sizeof(*new));
++	new = (nfs_client *)malloc(sizeof(*new));
++	if (new == NULL)
++		return NULL;
+ 	memcpy(new, clp, sizeof(*new));
+ 	new->m_type = MCL_FQDN;
+ 	new->m_hostname = NULL;
+ 
+-	client_init(new, (char *) hp->h_name, hp);
++	if (!client_init(new, ai->ai_canonname, ai)) {
++		client_free(new);
++		return NULL;
++	}
+ 	client_add(new);
+ 	return new;
+ }
+ 
+-static void
+-client_init(nfs_client *clp, const char *hname, struct hostent *hp)
+-{
+-	xfree(clp->m_hostname);
+-	if (hp)
+-		clp->m_hostname = xstrdup(hp->h_name);
+-	else
+-		clp->m_hostname = xstrdup(hname);
+-
+-	clp->m_exported = 0;
+-	clp->m_count = 0;
+-
+-	if (clp->m_type == MCL_SUBNETWORK) {
+-		char	*cp = strchr(clp->m_hostname, '/');
+-		static char slash32[] = "/32";
+-
+-		if(!cp) cp = slash32;
+-		*cp = '\0';
+-		clp->m_addrlist[0].s_addr = inet_addr(clp->m_hostname);
+-		if (strchr(cp + 1, '.')) {
+-			clp->m_addrlist[1].s_addr = inet_addr(cp+1);
+-		}
+-		else {
+-			int netmask = atoi(cp + 1);
+-			if (0 < netmask && netmask <= 32) {
+-				clp->m_addrlist[1].s_addr =
+-					htonl ((uint32_t) ~0 << (32 - netmask));
+-			}
+-			else {
+-				xlog(L_FATAL, "invalid netmask `%s' for %s",
+-				     cp + 1, clp->m_hostname);
+-			}
+-		}
+-		*cp = '/';
+-		clp->m_naddr = 0;
+-	} else if (!hp) {
+-		clp->m_naddr = 0;
+-	} else {
+-		char	**ap = hp->h_addr_list;
+-		int	i;
+-
+-		for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++) {
+-			clp->m_addrlist[i] = *(struct in_addr *)*ap;
+-		}
+-		clp->m_naddr = i;
+-	}
+-}
+-
+-void
+-client_add(nfs_client *clp)
+-{
+-	nfs_client	**cpp;
+-
+-	if (clp->m_type < 0 || clp->m_type >= MCL_MAXTYPES)
+-		xlog(L_FATAL, "unknown client type in client_add");
+-	cpp = clientlist + clp->m_type;
+-	while (*cpp)
+-		cpp = &((*cpp)->m_next);
+-	clp->m_next = NULL;
+-	*cpp = clp;
+-}
+-
++/**
++ * client_release - drop a reference to an nfs_client record
++ *
++ */
+ void
+ client_release(nfs_client *clp)
+ {
+@@ -195,6 +353,10 @@ client_release(nfs_client *clp)
+ 	clp->m_count--;
+ }
+ 
++/**
++ * client_freeall - deallocate all nfs_client records
++ *
++ */
+ void
+ client_freeall(void)
+ {
+@@ -205,57 +367,45 @@ client_freeall(void)
+ 		head = clientlist + i;
+ 		while (*head) {
+ 			*head = (clp = *head)->m_next;
+-			xfree(clp->m_hostname);
+-			xfree(clp);
++			client_free(clp);
+ 		}
+ 	}
+ }
+ 
+-nfs_client *
+-client_find(struct hostent *hp)
+-{
+-	nfs_client	*clp;
+-	int		i;
+-
+-	for (i = 0; i < MCL_MAXTYPES; i++) {
+-		for (clp = clientlist[i]; clp; clp = clp->m_next) {
+-			if (!client_check(clp, hp))
+-				continue;
+-#ifdef notdef
+-			if (clp->m_type == MCL_FQDN)
+-				return clp;
+-			return client_dup(clp, hp);
+-#else
+-			return clp;
+-#endif
+-		}
+-	}
+-	return NULL;
+-}
+-
+-struct hostent *
+-client_resolve(struct in_addr addr)
++/**
++ * client_resolve - look up an IP address
++ * @sap: pointer to socket address to resolve
++ *
++ * Returns an addrinfo structure, or NULL if some problem occurred.
++ * Caller must free the result with freeaddrinfo(3).
++ */
++struct addrinfo *
++client_resolve(const struct sockaddr *sap)
+ {
+-	struct hostent *he = NULL;
++	struct addrinfo *ai = NULL;
+ 
+ 	if (clientlist[MCL_WILDCARD] || clientlist[MCL_NETGROUP])
+-		he = get_reliable_hostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
+-	if (he == NULL)
+-		he = get_hostent((const char*)&addr, sizeof(addr), AF_INET);
++		ai = host_reliable_addrinfo(sap);
++	if (ai == NULL)
++		ai = host_numeric_addrinfo(sap);
+ 
+-	return he;
++	return ai;
+ }
+ 
+-/*
+- * Find client name given an IP address
+- * This is found by gathering all known names that match that IP address,
+- * sorting them and joining them with '+'
++/**
++ * client_compose - Make a list of cached hostnames that match an IP address
++ * @ai: pointer to addrinfo containing IP address information to match
++ *
++ * Gather all known client hostnames that match the IP address, and sort
++ * the result into a comma-separated list.
+  *
++ * Returns a '\0'-terminated ASCII string containing a comma-separated
++ * sorted list of client hostnames, or NULL if no client records matched
++ * the IP address or memory could not be allocated.  Caller must free the
++ * returned string with free(3).
+  */
+-static char *add_name(char *old, char *add);
+-
+ char *
+-client_compose(struct hostent *he)
++client_compose(const struct addrinfo *ai)
+ {
+ 	char *name = NULL;
+ 	int i;
+@@ -263,7 +413,7 @@ client_compose(struct hostent *he)
+ 	for (i = 0 ; i < MCL_MAXTYPES; i++) {
+ 		nfs_client	*clp;
+ 		for (clp = clientlist[i]; clp ; clp = clp->m_next) {
+-			if (!client_check(clp, he))
++			if (!client_check(clp, ai))
+ 				continue;
+ 			name = add_name(name, clp->m_hostname);
+ 		}
+@@ -271,13 +421,19 @@ client_compose(struct hostent *he)
+ 	return name;
+ }
+ 
++/**
++ * client_member - check if @name is contained in the list @client
++ * @client: '\0'-terminated ASCII string containing
++ *		comma-separated list of hostnames
++ * @name: '\0'-terminated ASCII string containing hostname to look for
++ *
++ * Returns 1 if @name was found in @client, otherwise zero is returned.
++ */
+ int
+-client_member(char *client, char *name)
++client_member(const char *client, const char *name)
+ {
+-	/* check if "client" (a ',' separated list of names)
+-	 * contains 'name' as a member
+-	 */
+-	int l = strlen(name);
++	size_t l = strlen(name);
++
+ 	while (*client) {
+ 		if (strncmp(client, name, l) == 0 &&
+ 		    (client[l] == ',' || client[l] == '\0'))
+@@ -290,9 +446,8 @@ client_member(char *client, char *name)
+ 	return 0;
+ }
+ 
+-
+-int
+-name_cmp(char *a, char *b)
++static int
++name_cmp(const char *a, const char *b)
+ {
+ 	/* compare strings a and b, but only upto ',' in a */
+ 	while (*a && *b && *a != ',' && *a == *b)
+@@ -305,9 +460,9 @@ name_cmp(char *a, char *b)
+ }
+ 
+ static char *
+-add_name(char *old, char *add)
++add_name(char *old, const char *add)
+ {
+-	int len = strlen(add)+2;
++	size_t len = strlen(add) + 2;
+ 	char *new;
+ 	char *cp;
+ 	if (old) len += strlen(old);
+@@ -340,108 +495,257 @@ add_name(char *old, char *add)
+ }
+ 
+ /*
+- * Match a host (given its hostent record) to a client record. This
+- * is usually called from mountd.
++ * Check each address listed in @ai against each address
++ * stored in @clp.  Return 1 if a match is found, otherwise
++ * zero.
+  */
+-int
+-client_check(nfs_client *clp, struct hostent *hp)
++static int
++check_fqdn(const nfs_client *clp, const struct addrinfo *ai)
+ {
+-	char	*hname = (char *) hp->h_name;
+-	char	*cname = clp->m_hostname;
+-	char	**ap;
++	int i;
+ 
+-	switch (clp->m_type) {
+-	case MCL_FQDN:
+-	case MCL_SUBNETWORK:
+-		for (ap = hp->h_addr_list; *ap; ap++) {
+-			if (client_checkaddr(clp, *(struct in_addr *) *ap))
++	for (; ai; ai = ai->ai_next)
++		for (i = 0; i < clp->m_naddr; i++)
++			if (nfs_compare_sockaddr(ai->ai_addr,
++							get_addrlist(clp, i)))
+ 				return 1;
+-		}
+-		return 0;
+-	case MCL_WILDCARD:
+-		if (wildmat(hname, cname))
++
++	return 0;
++}
++
++static _Bool
++mask_match(const uint32_t a, const uint32_t b, const uint32_t m)
++{
++	return ((a ^ b) & m) == 0;
++}
++
++static int
++check_subnet_v4(const struct sockaddr_in *address,
++		const struct sockaddr_in *mask, const struct addrinfo *ai)
++{
++	for (; ai; ai = ai->ai_next) {
++		struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
++
++		if (sin->sin_family != AF_INET)
++			continue;
++
++		if (mask_match(address->sin_addr.s_addr,
++				sin->sin_addr.s_addr,
++				mask->sin_addr.s_addr))
+ 			return 1;
+-		else {
+-			for (ap = hp->h_aliases; *ap; ap++)
+-				if (wildmat(*ap, cname))
+-					return 1;
+-		}
+-		return 0;
+-	case MCL_NETGROUP:
+-#ifdef HAVE_INNETGR
+-		{
+-			char	*dot;
+-			int	match, i;
+-			struct hostent *nhp = NULL;
+-			struct sockaddr_in addr;
+-
+-			/* First, try to match the hostname without
+-			 * splitting off the domain */
+-			if (innetgr(cname+1, hname, NULL, NULL))
+-				return 1;
++	}
++	return 0;
++}
+ 
+-			/* try the aliases as well */
+-			for (i = 0; hp->h_aliases[i]; i++) {
+-				if (innetgr(cname+1, hp->h_aliases[i], NULL, NULL))
+-					return 1;
+-			}
++#ifdef IPV6_SUPPORTED
++static int
++check_subnet_v6(const struct sockaddr_in6 *address,
++		const struct sockaddr_in6 *mask, const struct addrinfo *ai)
++{
++	for (; ai; ai = ai->ai_next) {
++		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
+ 
+-			/* If hname is ip address convert to FQDN */
+-			if (inet_aton(hname, &addr.sin_addr) &&
+-			   (nhp = gethostbyaddr((const char *)&(addr.sin_addr),
+-			    sizeof(addr.sin_addr), AF_INET))) {
+-				hname = (char *)nhp->h_name;
+-				if (innetgr(cname+1, hname, NULL, NULL))
+-					return 1;
+-			}
++		if (sin6->sin6_family != AF_INET6)
++			continue;
+ 
+-			/* Okay, strip off the domain (if we have one) */
+-			if ((dot = strchr(hname, '.')) == NULL)
+-				return 0;
+-
+-			*dot = '\0';
+-			match = innetgr(cname+1, hname, NULL, NULL);
+-			*dot = '.';
++		if (mask_match(address->sin6_addr.s6_addr32[0],
++				sin6->sin6_addr.s6_addr32[0],
++				mask->sin6_addr.s6_addr32[0]) &&
++		    mask_match(address->sin6_addr.s6_addr32[1],
++				sin6->sin6_addr.s6_addr32[1],
++				mask->sin6_addr.s6_addr32[1]) &&
++		    mask_match(address->sin6_addr.s6_addr32[2],
++				sin6->sin6_addr.s6_addr32[2],
++				mask->sin6_addr.s6_addr32[2]) &&
++		    mask_match(address->sin6_addr.s6_addr32[3],
++				sin6->sin6_addr.s6_addr32[3],
++				mask->sin6_addr.s6_addr32[3]))
++			return 1;
++	}
++	return 0;
++}
++#else	/* !IPV6_SUPPORTED */
++static int
++check_subnet_v6(const struct sockaddr_in6 *UNUSED(address),
++		const struct sockaddr_in6 *UNUSED(mask),
++		const struct addrinfo *UNUSED(ai))
++{
++	return 0;
++}
++#endif	/* !IPV6_SUPPORTED */
+ 
+-			return match;
+-		}
+-#else
+-		return 0;
+-#endif
+-	case MCL_ANONYMOUS:
++/*
++ * Check each address listed in @ai against the subnetwork or
++ * host address stored in @clp.  Return 1 if an address in @hp
++ * matches the host address stored in @clp, otherwise zero.
++ */
++static int
++check_subnetwork(const nfs_client *clp, const struct addrinfo *ai)
++{
++	switch (get_addrlist(clp, 0)->sa_family) {
++	case AF_INET:
++		return check_subnet_v4(get_addrlist_in(clp, 0),
++				get_addrlist_in(clp, 1), ai);
++	case AF_INET6:
++		return check_subnet_v6(get_addrlist_in6(clp, 0),
++				get_addrlist_in6(clp, 1), ai);
++	}
++
++	return 0;
++}
++
++/*
++ * Check if a wildcard nfs_client record matches the canonical name
++ * or the aliases of a host.  Return 1 if a match is found, otherwise
++ * zero.
++ */
++static int
++check_wildcard(const nfs_client *clp, const struct addrinfo *ai)
++{
++	char *cname = clp->m_hostname;
++	char *hname = ai->ai_canonname;
++	struct hostent *hp;
++	char **ap;
++
++	if (wildmat(hname, cname))
+ 		return 1;
+-	case MCL_GSS:
+-		return 0;
+-	default:
+-		xlog(L_FATAL, "internal: bad client type %d", clp->m_type);
++
++	/* See if hname aliases listed in /etc/hosts or nis[+]
++	 * match the requested wildcard */
++	hp = gethostbyname(hname);
++	if (hp != NULL) {
++		for (ap = hp->h_aliases; *ap; ap++)
++			if (wildmat(*ap, cname))
++				return 1;
+ 	}
+ 
+ 	return 0;
+ }
+ 
++/*
++ * Check if @ai's hostname or aliases fall in a given netgroup.
++ * Return 1 if @ai represents a host in the netgroup, otherwise
++ * zero.
++ */
++#ifdef HAVE_INNETGR
++static int
++check_netgroup(const nfs_client *clp, const struct addrinfo *ai)
++{
++	const char *netgroup = clp->m_hostname + 1;
++	struct addrinfo *tmp = NULL;
++	struct hostent *hp;
++	char *dot, *hname;
++	int i, match;
++
++	match = 0;
++
++	hname = strdup(ai->ai_canonname);
++	if (hname == NULL) {
++		xlog(D_GENERAL, "%s: no memory for strdup", __func__);
++		goto out;
++	}
++
++	/* First, try to match the hostname without
++	 * splitting off the domain */
++	if (innetgr(netgroup, hname, NULL, NULL)) {
++		match = 1;
++		goto out;
++	}
++
++	/* See if hname aliases listed in /etc/hosts or nis[+]
++	 * match the requested netgroup */
++	hp = gethostbyname(hname);
++	if (hp != NULL) {
++		for (i = 0; hp->h_aliases[i]; i++)
++			if (innetgr(netgroup, hp->h_aliases[i], NULL, NULL)) {
++				match = 1;
++				goto out;
++			}
++	}
++
++	/* If hname happens to be an IP address, convert it
++	 * to a the canonical DNS name bound to this address. */
++	tmp = host_pton(hname);
++	if (tmp != NULL) {
++		char *cname = host_canonname(tmp->ai_addr);
++		freeaddrinfo(tmp);
++
++		/* The resulting FQDN may be in our netgroup. */
++		if (cname != NULL) {
++			free(hname);
++			hname = cname;
++			if (innetgr(netgroup, hname, NULL, NULL)) {
++				match = 1;
++				goto out;
++			}
++		}
++	}
++
++	/* Okay, strip off the domain (if we have one) */
++	dot = strchr(hname, '.');
++	if (dot == NULL)
++		goto out;
++
++	*dot = '\0';
++	match = innetgr(netgroup, hname, NULL, NULL);
++
++out:
++	free(hname);
++	return match;
++}
++#else	/* !HAVE_INNETGR */
+ static int
+-client_checkaddr(nfs_client *clp, struct in_addr addr)
++check_netgroup(__attribute__((unused)) const nfs_client *clp,
++		__attribute__((unused)) const struct addrinfo *ai)
+ {
+-	int	i;
++	return 0;
++}
++#endif	/* !HAVE_INNETGR */
+ 
++/**
++ * client_check - check if IP address information matches a cached nfs_client
++ * @clp: pointer to a cached nfs_client record
++ * @ai: pointer to addrinfo to compare it with
++ *
++ * Returns 1 if the address information matches the cached nfs_client,
++ * otherwise zero.
++ */
++int
++client_check(const nfs_client *clp, const struct addrinfo *ai)
++{
+ 	switch (clp->m_type) {
+ 	case MCL_FQDN:
+-		for (i = 0; i < clp->m_naddr; i++) {
+-			if (clp->m_addrlist[i].s_addr == addr.s_addr)
+-				return 1;
+-		}
+-		return 0;
++		return check_fqdn(clp, ai);
+ 	case MCL_SUBNETWORK:
+-		return !((clp->m_addrlist[0].s_addr ^ addr.s_addr)
+-			& clp->m_addrlist[1].s_addr);
++		return check_subnetwork(clp, ai);
++	case MCL_WILDCARD:
++		return check_wildcard(clp, ai);
++	case MCL_NETGROUP:
++		return check_netgroup(clp, ai);
++	case MCL_ANONYMOUS:
++		return 1;
++	case MCL_GSS:
++		return 0;
++	default:
++		xlog(D_GENERAL, "%s: unrecognized client type: %d",
++				__func__, clp->m_type);
+ 	}
++
+ 	return 0;
+ }
+ 
++/**
++ * client_gettype - determine type of nfs_client given an identifier
++ * @ident: '\0'-terminated ASCII string containing a client identifier
++ *
++ * Returns the type of nfs_client record that would be used for
++ * this client.
++ */
+ int
+ client_gettype(char *ident)
+ {
+-	char	*sp;
++	struct addrinfo *ai;
++	char *sp;
+ 
+ 	if (ident[0] == '\0' || strcmp(ident, "*")==0)
+ 		return MCL_ANONYMOUS;
+@@ -461,12 +765,16 @@ client_gettype(char *ident)
+ 		if (*sp == '\\' && sp[1])
+ 			sp++;
+ 	}
+-	/* check for N.N.N.N */
+-	sp = ident;
+-	if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
+-	sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
+-	sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
+-	sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '\0') return MCL_FQDN;
+-	/* we lie here a bit. but technically N.N.N.N == N.N.N.N/32 :) */
+-	return MCL_SUBNETWORK;
++
++	/*
++	 * Treat unadorned IP addresses as MCL_SUBNETWORK.
++	 * Everything else is MCL_FQDN.
++	 */
++	ai = host_pton(ident);
++	if (ai != NULL) {
++		freeaddrinfo(ai);
++		return MCL_SUBNETWORK;
++	}
++
++	return MCL_FQDN;
+ }
+diff -up nfs-utils-1.2.2/support/export/export.c.orig nfs-utils-1.2.2/support/export/export.c
+--- nfs-utils-1.2.2/support/export/export.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/export/export.c	2010-09-09 11:02:27.046023000 -0400
+@@ -24,9 +24,24 @@ static int export_hash(char *);
+ 
+ static void	export_init(nfs_export *exp, nfs_client *clp,
+ 					struct exportent *nep);
+-static int	export_check(nfs_export *, struct hostent *, char *);
++static void	export_add(nfs_export *exp);
++static int	export_check(const nfs_export *exp, const struct addrinfo *ai,
++				const char *path);
+ static nfs_export *
+-		export_allowed_internal(struct hostent *hp, char *path);
++		export_allowed_internal(const struct addrinfo *ai,
++				const char *path);
++
++static void
++export_free(nfs_export *exp)
++{
++	xfree(exp->m_export.e_squids);
++	xfree(exp->m_export.e_sqgids);
++	free(exp->m_export.e_mountpoint);
++	free(exp->m_export.e_fslocdata);
++
++	xfree(exp->m_export.e_hostname);
++	xfree(exp);
++}
+ 
+ static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
+ {
+@@ -44,7 +59,12 @@ static void warn_duplicated_exports(nfs_
+ 	}
+ }
+ 
+-int
++/**
++ * export_read - read entries from /etc/exports
++ * @fname: name of file to read from
++ *
++ */
++void
+ export_read(char *fname)
+ {
+ 	struct exportent	*eep;
+@@ -59,11 +79,15 @@ export_read(char *fname)
+ 			warn_duplicated_exports(exp, eep);
+ 	}
+ 	endexportent();
+-	return 0;
+ }
+ 
+-/*
+- * Create an in-core export struct from an export entry.
++/**
++ * export_create - create an in-core nfs_export record from an export entry
++ * @xep: export entry to lookup
++ * @canonical: if set, e_hostname is known to be canonical DNS name
++ *
++ * Returns a freshly instantiated export record, or NULL if
++ * a problem occurred.
+  */
+ nfs_export *
+ export_create(struct exportent *xep, int canonical)
+@@ -105,8 +129,8 @@ export_init(nfs_export *exp, nfs_client 
+  * original hostname from /etc/exports, while the in-core client struct
+  * gets the newly found FQDN.
+  */
+-nfs_export *
+-export_dup(nfs_export *exp, struct hostent *hp)
++static nfs_export *
++export_dup(nfs_export *exp, const struct addrinfo *ai)
+ {
+ 	nfs_export		*new;
+ 	nfs_client		*clp;
+@@ -116,7 +140,11 @@ export_dup(nfs_export *exp, struct hoste
+ 	dupexportent(&new->m_export, &exp->m_export);
+ 	if (exp->m_export.e_hostname)
+ 		new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname);
+-	clp = client_dup(exp->m_client, hp);
++	clp = client_dup(exp->m_client, ai);
++	if (clp == NULL) {
++		export_free(new);
++		return NULL;
++	}
+ 	clp->m_count++;
+ 	new->m_client = clp;
+ 	new->m_mayexport = exp->m_mayexport;
+@@ -128,10 +156,8 @@ export_dup(nfs_export *exp, struct hoste
+ 
+ 	return new;
+ }
+-/*
+- * Add export entry to hash table
+- */
+-void 
++
++static void
+ export_add(nfs_export *exp)
+ {
+ 	exp_hash_table *p_tbl;
+@@ -159,19 +185,27 @@ export_add(nfs_export *exp)
+ 	}
+ }
+ 
++/**
++ * export_find - find or create a suitable nfs_export for @ai and @path
++ * @ai: pointer to addrinfo for client
++ * @path: '\0'-terminated ASCII string containing export path
++ *
++ * Returns a pointer to nfs_export data matching @ai and @path,
++ * or NULL if an error occurs.
++ */
+ nfs_export *
+-export_find(struct hostent *hp, char *path)
++export_find(const struct addrinfo *ai, const char *path)
+ {
+ 	nfs_export	*exp;
+ 	int		i;
+ 
+ 	for (i = 0; i < MCL_MAXTYPES; i++) {
+ 		for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
+-			if (!export_check(exp, hp, path))
++			if (!export_check(exp, ai, path))
+ 				continue;
+ 			if (exp->m_client->m_type == MCL_FQDN)
+ 				return exp;
+-			return export_dup(exp, hp);
++			return export_dup(exp, ai);
+ 		}
+ 	}
+ 
+@@ -179,7 +213,7 @@ export_find(struct hostent *hp, char *pa
+ }
+ 
+ static nfs_export *
+-export_allowed_internal (struct hostent *hp, char *path)
++export_allowed_internal(const struct addrinfo *ai, const char *path)
+ {
+ 	nfs_export	*exp;
+ 	int		i;
+@@ -187,7 +221,7 @@ export_allowed_internal (struct hostent 
+ 	for (i = 0; i < MCL_MAXTYPES; i++) {
+ 		for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
+ 			if (!exp->m_mayexport ||
+-			    !export_check(exp, hp, path))
++			    !export_check(exp, ai, path))
+ 				continue;
+ 			return exp;
+ 		}
+@@ -196,8 +230,16 @@ export_allowed_internal (struct hostent 
+ 	return NULL;
+ }
+ 
++/**
++ * export_allowed - determine if this export is allowed
++ * @ai: pointer to addrinfo for client
++ * @path: '\0'-terminated ASCII string containing export path
++ *
++ * Returns a pointer to nfs_export data matching @ai and @path,
++ * or NULL if the export is not allowed.
++ */
+ nfs_export *
+-export_allowed(struct hostent *hp, char *path)
++export_allowed(const struct addrinfo *ai, const char *path)
+ {
+ 	nfs_export		*exp;
+ 	char			epath[MAXPATHLEN+1];
+@@ -210,7 +252,7 @@ export_allowed(struct hostent *hp, char 
+ 
+ 	/* Try the longest matching exported pathname. */
+ 	while (1) {
+-		exp = export_allowed_internal (hp, epath);
++		exp = export_allowed_internal(ai, epath);
+ 		if (exp)
+ 			return exp;
+ 		/* We have to treat the root, "/", specially. */
+@@ -223,11 +265,17 @@ export_allowed(struct hostent *hp, char 
+ 	return NULL;
+ }
+ 
+-/*
+- * Search hash table for export entry. 
+- */  
++/**
++ * export_lookup - search hash table for export entry
++ * @hname: '\0'-terminated ASCII string containing client hostname to look for
++ * @path: '\0'-terminated ASCII string containing export path to look for
++ * @canonical: if set, @hname is known to be canonical DNS name
++ *
++ * Returns a pointer to nfs_export record matching @hname and @path,
++ * or NULL if the export was not found.
++ */
+ nfs_export *
+-export_lookup(char *hname, char *path, int canonical) 
++export_lookup(char *hname, char *path, int canonical)
+ {
+ 	nfs_client *clp;
+ 	nfs_export *exp;
+@@ -251,14 +299,18 @@ export_lookup(char *hname, char *path, i
+ }
+ 
+ static int
+-export_check(nfs_export *exp, struct hostent *hp, char *path)
++export_check(const nfs_export *exp, const struct addrinfo *ai, const char *path)
+ {
+ 	if (strcmp(path, exp->m_export.e_path))
+ 		return 0;
+ 
+-	return client_check(exp->m_client, hp);
++	return client_check(exp->m_client, ai);
+ }
+ 
++/**
++ * export_freeall - deallocate all nfs_export records
++ *
++ */
+ void
+ export_freeall(void)
+ {
+@@ -269,22 +321,13 @@ export_freeall(void)
+ 		for (exp = exportlist[i].p_head; exp; exp = nxt) {
+ 			nxt = exp->m_next;
+ 			client_release(exp->m_client);
+-			if (exp->m_export.e_squids)
+-				xfree(exp->m_export.e_squids);
+-			if (exp->m_export.e_sqgids)
+-				xfree(exp->m_export.e_sqgids);
+-			if (exp->m_export.e_mountpoint)
+-				free(exp->m_export.e_mountpoint);
+-			if (exp->m_export.e_fslocdata)
+-				xfree(exp->m_export.e_fslocdata);
+-			xfree(exp->m_export.e_hostname);
+-			xfree(exp);
++			export_free(exp);
++		}
++		for (j = 0; j < HASH_TABLE_SIZE; j++) {
++			exportlist[i].entries[j].p_first = NULL;
++			exportlist[i].entries[j].p_last = NULL;
+ 		}
+-      for(j = 0; j < HASH_TABLE_SIZE; j++) {
+-        exportlist[i].entries[j].p_first = NULL;
+-        exportlist[i].entries[j].p_last = NULL;
+-      }
+-      exportlist[i].p_head = NULL;
++		exportlist[i].p_head = NULL;
+ 	}
+ 	client_freeall();
+ }
+diff -up nfs-utils-1.2.2/support/export/hostname.c.orig nfs-utils-1.2.2/support/export/hostname.c
+--- nfs-utils-1.2.2/support/export/hostname.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/export/hostname.c	2010-09-09 11:02:27.051025000 -0400
+@@ -1,315 +1,377 @@
+ /*
+- * support/export/hostname.c
++ * Copyright 2010 Oracle.  All rights reserved.
+  *
+- * Functions for hostname.
++ * This file is part of nfs-utils.
+  *
++ * nfs-utils is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * nfs-utils is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #endif
+ 
+-/*
+-#define TEST
+-*/
+-
+ #include <string.h>
+-#include <netdb.h>
+-#include <netinet/in.h>
+-#include <arpa/inet.h>
+ #include <stdlib.h>
+-#include <xlog.h>
+-#ifdef TEST
+-#define xmalloc malloc
+-#else
+-#include "xmalloc.h"
+-#include "misc.h"
+-#endif
++#include <arpa/inet.h>
++#include <netdb.h>
++#include <errno.h>
+ 
+-#define ALIGNMENT	sizeof (char *)
++#include "sockaddr.h"
++#include "exportfs.h"
+ 
+-static int
+-align (int len, int al)
++#ifndef HAVE_DECL_AI_ADDRCONFIG
++#define AI_ADDRCONFIG	0
++#endif
++
++#ifdef HAVE_GETNAMEINFO
++static socklen_t
++sockaddr_size(const struct sockaddr *sap)
+ {
+-  int i;
+-  i = len % al;
+-  if (i)
+-    len += al - i;
+-  return len;
++	if (sap->sa_family != AF_INET)
++		return 0;
++	return (socklen_t)sizeof(struct sockaddr_in);
+ }
++#endif	/* HAVE_GETNAMEINFO */
+ 
+-struct hostent *
+-get_hostent (const char *addr, int len, int type)
++/**
++ * host_ntop - generate presentation address given a sockaddr
++ * @sap: pointer to socket address
++ * @buf: working storage
++ * @buflen: size of @buf in bytes
++ *
++ * Returns a pointer to a @buf.
++ */
++#ifdef HAVE_GETNAMEINFO
++char *
++host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
+ {
+-  struct hostent *cp;
+-  int len_ent;
+-  const char *name;
+-  int len_name;
+-  int num_aliases = 1;
+-  int len_aliases = sizeof (char *);
+-  int num_addr_list = 1;
+-  int len_addr_list = sizeof (char *);
+-  int pos;
+-  struct in_addr *ipv4;
+-
+-  switch (type)
+-    {
+-    case AF_INET:
+-      ipv4 = (struct in_addr *) addr;
+-      name = inet_ntoa (*ipv4);
+-      break;
+-
+-    default:
+-      return NULL;
+-    }
+-
+-  len_ent = align (sizeof (*cp), ALIGNMENT);
+-  len_name = align (strlen (name) + 1, ALIGNMENT);
+-
+-  num_addr_list++;
+-  len_addr_list += align (len, ALIGNMENT) + sizeof (char *);
+-
+-  cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
+-				   + len_addr_list);
+-
+-  cp->h_addrtype = type;
+-  cp->h_length = len;
+-  pos = len_ent;
+-  cp->h_name = (char *) &(((char *) cp) [pos]);
+-  strcpy (cp->h_name, name);
+-
+-  pos += len_name;
+-  cp->h_aliases = (char **) &(((char *) cp) [pos]);
+-  pos += num_aliases * sizeof (char *);
+-  cp->h_aliases [0] = NULL;
+-
+-  pos = len_ent + len_name + len_aliases;
+-  cp->h_addr_list = (char **) &(((char *) cp) [pos]);
+-  pos += num_addr_list * sizeof (char *);
+-  cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]);
+-  memcpy (cp->h_addr_list [0], addr, cp->h_length);
+-  pos += align (cp->h_length, ALIGNMENT);
+-  cp->h_addr_list [1] = NULL;
++	socklen_t salen = sockaddr_size(sap);
++	int error;
+ 
+-  return cp;
+-}
++	memset(buf, 0, buflen);
+ 
+-struct hostent *
+-hostent_dup (struct hostent *hp)
++	if (salen == 0) {
++		(void)strncpy(buf, "bad family", buflen - 1);
++		return buf;
++	}
++
++	error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
++						NULL, 0, NI_NUMERICHOST);
++	if (error != 0) {
++		buf[0] = '\0';
++		(void)strncpy(buf, "bad address", buflen - 1);
++	}
++
++	return buf;
++}
++#else	/* !HAVE_GETNAMEINFO */
++char *
++host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
+ {
+-  int len_ent = align (sizeof (*hp), ALIGNMENT);
+-  int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT);
+-  int num_aliases = 1;
+-  int len_aliases = sizeof (char *);
+-  int num_addr_list = 1;
+-  int len_addr_list = sizeof (char *);
+-  int pos, i;
+-  char **sp;
+-  struct hostent *cp;
+-
+-  for (sp = hp->h_aliases; sp && *sp; sp++)
+-    {
+-      num_aliases++;
+-      len_aliases += align (strlen (*sp) + 1, ALIGNMENT)
+-		     + sizeof (char *);
+-    }
+-
+-  for (sp = hp->h_addr_list; *sp; sp++)
+-    {
+-      num_addr_list++;
+-      len_addr_list += align (hp->h_length, ALIGNMENT)
+-		       + sizeof (char *);
+-    }
+-
+-  cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
+-				   + len_addr_list);
+-
+-  *cp = *hp;
+-  pos = len_ent;
+-  cp->h_name = (char *) &(((char *) cp) [pos]);
+-  strcpy (cp->h_name, hp->h_name);
+-
+-  pos += len_name;
+-  cp->h_aliases = (char **) &(((char *) cp) [pos]);
+-  pos += num_aliases * sizeof (char *);
+-  for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++)
+-    if (sp && *sp)
+-      {
+-	cp->h_aliases [i] = (char *) &(((char *) cp) [pos]);
+-	strcpy (cp->h_aliases [i], *sp);
+-	pos += align (strlen (*sp) + 1, ALIGNMENT);
+-      }
+-    else
+-      cp->h_aliases [i] = NULL;
+-
+-  pos = len_ent + len_name + len_aliases;
+-  cp->h_addr_list = (char **) &(((char *) cp) [pos]);
+-  pos += num_addr_list * sizeof (char *);
+-  for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++)
+-    if (*sp)
+-      {
+-	cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]);
+-	memcpy (cp->h_addr_list [i], *sp, hp->h_length);
+-	pos += align (hp->h_length, ALIGNMENT);
+-      }
+-    else
+-      cp->h_addr_list [i] = *sp;
++	const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
+ 
+-  return cp;
++	memset(buf, 0, buflen);
++
++	if (sin->sin_family != AF_INET)
++		(void)strncpy(buf, "bad family", buflen - 1);
++		return buf;
++	}
++
++	if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL)
++		return buf;
++
++	buf[0] = '\0';
++	(void)strncpy(buf, "bad address", buflen - 1);
++	return buf;
+ }
++#endif	/* !HAVE_GETNAMEINFO */
+ 
+-static int
+-is_hostname(const char *sp)
++/**
++ * host_pton - return addrinfo for a given presentation address
++ * @paddr: pointer to a '\0'-terminated ASCII string containing an
++ *		IP presentation address
++ *
++ * Returns address info structure, or NULL if an error occurs.  Caller
++ * must free the returned structure with freeaddrinfo(3).
++ */
++__attribute_malloc__
++struct addrinfo *
++host_pton(const char *paddr)
+ {
+-  if (*sp == '\0' || *sp == '@')
+-    return 0;
++	struct addrinfo *ai = NULL;
++	struct addrinfo hint = {
++		/* don't return duplicates */
++		.ai_protocol	= (int)IPPROTO_UDP,
++		.ai_flags	= AI_NUMERICHOST,
++		.ai_family	= AF_UNSPEC,
++	};
++	struct sockaddr_in sin;
++	int error;
++
++	/*
++	 * Although getaddrinfo(3) is easier to use and supports
++	 * IPv6, it recognizes incomplete addresses like "10.4"
++	 * as valid AF_INET addresses.  It also accepts presentation
++	 * addresses that end with a blank.
++	 *
++	 * inet_pton(3) is much stricter.  Use it to be certain we
++	 * have a real AF_INET presentation address, before invoking
++	 * getaddrinfo(3) to generate the full addrinfo list.
++	 */
++	if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
++		return NULL;
+ 
+-  for (; *sp; sp++)
+-    {
+-      if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
+-	return 0;
+-      if (*sp == '\\' && sp[1])
+-	sp++;
+-    }
++	error = getaddrinfo(paddr, NULL, &hint, &ai);
++	switch (error) {
++	case 0:
++		return ai;
++	case EAI_NONAME:
++		if (paddr == NULL)
++			xlog(D_GENERAL, "%s: passed a NULL presentation address",
++				__func__);
++		break;
++	case EAI_SYSTEM:
++		xlog(D_GENERAL, "%s: failed to convert %s: (%d) %m",
++				__func__, paddr, errno);
++		break;
++	default:
++		xlog(D_GENERAL, "%s: failed to convert %s: %s",
++				__func__, paddr, gai_strerror(error));
++		break;
++	}
+ 
+-  return 1;
++	return NULL;
+ }
+ 
+-int
+-matchhostname (const char *h1, const char *h2)
++/**
++ * host_addrinfo - return addrinfo for a given hostname
++ * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname
++ *
++ * Returns address info structure with ai_canonname filled in, or NULL
++ * if no information is available for @hostname.  Caller must free the
++ * returned structure with freeaddrinfo(3).
++ */
++__attribute_malloc__
++struct addrinfo *
++host_addrinfo(const char *hostname)
+ {
+-  struct hostent *hp1, *hp2;
+-  int status;
++	struct addrinfo *ai = NULL;
++	struct addrinfo hint = {
++		.ai_family	= AF_INET,
++		/* don't return duplicates */
++		.ai_protocol	= (int)IPPROTO_UDP,
++		.ai_flags	= AI_ADDRCONFIG | AI_CANONNAME,
++	};
++	int error;
++
++	error = getaddrinfo(hostname, NULL, &hint, &ai);
++	switch (error) {
++	case 0:
++		return ai;
++	case EAI_SYSTEM:
++		xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
++				__func__, hostname, errno);
++		break;
++	default:
++		xlog(D_GENERAL, "%s: failed to resolve %s: %s",
++				__func__, hostname, gai_strerror(error));
++		break;
++	}
+ 
+-  if (strcasecmp (h1, h2) == 0)
+-    return 1;
++	return NULL;
++}
+ 
+-  if (!is_hostname (h1) || !is_hostname (h2))
+-    return 0;
++/**
++ * host_canonname - return canonical hostname bound to an address
++ * @sap: pointer to socket address to look up
++ *
++ * Discover the canonical hostname associated with the given socket
++ * address.  The host's reverse mapping is verified in the process.
++ *
++ * Returns a '\0'-terminated ASCII string containing a hostname, or
++ * NULL if no hostname can be found for @sap.  Caller must free
++ * the string.
++ */
++#ifdef HAVE_GETNAMEINFO
++__attribute_malloc__
++char *
++host_canonname(const struct sockaddr *sap)
++{
++	socklen_t salen = sockaddr_size(sap);
++	char buf[NI_MAXHOST];
++	int error;
++
++	if (salen == 0) {
++		xlog(D_GENERAL, "%s: unsupported address family %d",
++				__func__, sap->sa_family);
++		return NULL;
++	}
+ 
+-  hp1 = gethostbyname (h1);
+-  if (hp1 == NULL)
+-    return 0;
+-
+-  hp1 = hostent_dup (hp1);
+-
+-  hp2 = gethostbyname (h2);
+-  if (hp2)
+-    {
+-      if (strcasecmp (hp1->h_name, hp2->h_name) == 0)
+-	status = 1;
+-      else
+-	{
+-	  char **ap1, **ap2;
+-
+-	  status = 0;
+-	  for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++)
+-	    for (ap2 = hp2->h_addr_list; *ap2; ap2++)
+-	      if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0)
+-		{
+-		  status = 1;
+-		  break;
+-		}
++	memset(buf, 0, sizeof(buf));
++	error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
++							NULL, 0, NI_NAMEREQD);
++	switch (error) {
++	case 0:
++		break;
++	case EAI_SYSTEM:
++		xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
++				__func__, errno);
++		return NULL;
++	default:
++		(void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
++							NULL, 0, NI_NUMERICHOST);
++		xlog(D_GENERAL, "%s: failed to resolve %s: %s",
++				__func__, buf, gai_strerror(error));
++		return NULL;
+ 	}
+-    }
+-  else
+-    status = 0;
+ 
+-  free (hp1);
+-  return status;
++	return strdup(buf);
+ }
++#else	/* !HAVE_GETNAMEINFO */
++__attribute_malloc__
++char *
++host_canonname(const struct sockaddr *sap)
++{
++	const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap;
++	const struct in_addr *addr = &sin->sin_addr;
++	struct hostent *hp;
+ 
++	if (sap->sa_family != AF_INET)
++		return NULL;
++
++	hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET);
++	if (hp == NULL)
++		return NULL;
++
++	return strdup(hp->h_name);
++}
++#endif	/* !HAVE_GETNAMEINFO */
+ 
+-/* Map IP to hostname, and then map back to addr to make sure it is a
+- * reliable hostname
++/**
++ * host_reliable_addrinfo - return addrinfo for a given address
++ * @sap: pointer to socket address to look up
++ *
++ * Reverse and forward lookups are performed to ensure the address has
++ * proper forward and reverse mappings.
++ *
++ * Returns address info structure with ai_canonname filled in, or NULL
++ * if no information is available for @sap.  Caller must free the returned
++ * structure with freeaddrinfo(3).
+  */
+-struct hostent *
+-get_reliable_hostbyaddr(const char *addr, int len, int type)
++__attribute_malloc__
++struct addrinfo *
++host_reliable_addrinfo(const struct sockaddr *sap)
+ {
+-	struct hostent *hp = NULL;
+-
+-	struct hostent *reverse;
+-	struct hostent *forward;
+-	char **sp;
++	struct addrinfo *ai;
++	char *hostname;
+ 
+-	reverse = gethostbyaddr (addr, len, type);
+-	if (!reverse)
++	hostname = host_canonname(sap);
++	if (hostname == NULL)
+ 		return NULL;
+ 
+-	/* must make sure the hostent is authorative. */
++	ai = host_addrinfo(hostname);
+ 
+-	reverse = hostent_dup (reverse);
+-	forward = gethostbyname (reverse->h_name);
++	free(hostname);
++	return ai;
++}
+ 
+-	if (forward) {
+-		/* now make sure the "addr" is in the list */
+-		for (sp = forward->h_addr_list ; *sp ; sp++) {
+-			if (memcmp (*sp, addr, forward->h_length) == 0)
+-				break;
+-		}
++/**
++ * host_numeric_addrinfo - return addrinfo without doing DNS queries
++ * @sap: pointer to socket address
++ *
++ * Returns address info structure, or NULL if an error occurred.
++ * Caller must free the returned structure with freeaddrinfo(3).
++ */
++#ifdef HAVE_GETNAMEINFO
++__attribute_malloc__
++struct addrinfo *
++host_numeric_addrinfo(const struct sockaddr *sap)
++{
++	socklen_t salen = sockaddr_size(sap);
++	char buf[INET_ADDRSTRLEN];
++	struct addrinfo *ai;
++	int error;
++
++	if (salen == 0) {
++		xlog(D_GENERAL, "%s: unsupported address family %d",
++				__func__, sap->sa_family);
++		return NULL;
++	}
+ 
+-		if (*sp) {
+-			/* it's valid */
+-			hp = hostent_dup (forward);
+-		}
+-		else {
+-			/* it was a FAKE */
+-			xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't match reverse",
+-			      reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
+-		}
++	memset(buf, 0, sizeof(buf));
++	error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf),
++						NULL, 0, NI_NUMERICHOST);
++	switch (error) {
++	case 0:
++		break;
++	case EAI_SYSTEM:
++		xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m",
++				__func__, errno);
++		return NULL;
++	default:
++		xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s",
++				__func__, gai_strerror(error));
++		return NULL;
+ 	}
+-	else {
+-		/* never heard of it. misconfigured DNS? */
+-		xlog (L_WARNING, "Fake hostname %s for %s - forward lookup doesn't exist",
+-		      reverse->h_name, inet_ntoa(*(struct in_addr*)addr));
++
++	ai = host_pton(buf);
++
++	/*
++	 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
++	 */
++	if (ai != NULL) {
++		free(ai->ai_canonname);		/* just in case */
++		ai->ai_canonname = strdup(buf);
++		if (ai->ai_canonname == NULL) {
++			freeaddrinfo(ai);
++			ai = NULL;
++		}
+ 	}
+ 
+-	free (reverse);
+-	return hp;
++	return ai;
+ }
++#else	/* !HAVE_GETNAMEINFO */
++__attribute_malloc__
++struct addrinfo *
++host_numeric_addrinfo(const struct sockaddr *sap)
++{
++	const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
++	const struct in_addr *addr = &sin->sin_addr;
++	char buf[INET_ADDRSTRLEN];
++	struct addrinfo *ai;
+ 
++	if (sap->sa_family != AF_INET)
++		return NULL;
+ 
+-#ifdef TEST
+-void
+-print_host (struct hostent *hp)
+-{
+-  char **sp;
++	memset(buf, 0, sizeof(buf));
++	if (inet_ntop(AF_INET, (char *)addr, buf,
++					(socklen_t)sizeof(buf)) == NULL)
++		return NULL;
+ 
+-  if (hp)
+-    {
+-      printf ("official hostname: %s\n", hp->h_name);
+-      printf ("aliases:\n");
+-      for (sp = hp->h_aliases; *sp; sp++)
+-	printf ("  %s\n", *sp);
+-      printf ("IP addresses:\n");
+-      for (sp = hp->h_addr_list; *sp; sp++)
+-	printf ("  %s\n", inet_ntoa (*(struct in_addr *) *sp));
+-    }
+-  else
+-    printf ("Not host information\n");
+-}
++	ai = host_pton(buf);
+ 
+-int
+-main (int argc, char **argv)
+-{
+-  struct hostent *hp = gethostbyname (argv [1]);
+-  struct hostent *cp;
+-  struct in_addr addr;
+-
+-  print_host (hp);
+-
+-  if (hp)
+-    {
+-      cp = hostent_dup (hp);
+-      print_host (cp);
+-      free (cp);
+-    }
+-  printf ("127.0.0.1 == %s: %d\n", argv [1],
+-	  matchhostname ("127.0.0.1", argv [1]));
+-  addr.s_addr = inet_addr(argv [2]);
+-  printf ("%s\n", inet_ntoa (addr));
+-  cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET);
+-  print_host (cp);
+-  return 0;
++	/*
++	 * getaddrinfo(AI_NUMERICHOST) never fills in ai_canonname
++	 */
++	if (ai != NULL) {
++		ai->ai_canonname = strdup(buf);
++		if (ai->ai_canonname == NULL) {
++			freeaddrinfo(ai);
++			ai = NULL;
++		}
++	}
++
++	return ai;
+ }
+-#endif
++#endif	/* !HAVE_GETNAMEINFO */
+diff -up nfs-utils-1.2.2/support/export/nfsctl.c.orig nfs-utils-1.2.2/support/export/nfsctl.c
+--- nfs-utils-1.2.2/support/export/nfsctl.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/export/nfsctl.c	2010-09-09 11:02:27.056025000 -0400
+@@ -66,7 +66,7 @@ str_tolower(char *s)
+ static int
+ cltsetup(struct nfsctl_client *cltarg, nfs_client *clp)
+ {
+-	int	i;
++	int i, j;
+ 
+ 	if (clp->m_type != MCL_FQDN) {
+ 		xlog(L_ERROR, "internal: can't export non-FQDN host");
+@@ -76,10 +76,19 @@ cltsetup(struct nfsctl_client *cltarg, n
+ 	strncpy(cltarg->cl_ident, clp->m_hostname,
+ 		sizeof (cltarg->cl_ident) - 1);
+ 	str_tolower(cltarg->cl_ident);
+-	cltarg->cl_naddr = clp->m_naddr;
+-	for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++)
+-		cltarg->cl_addrlist[i] = clp->m_addrlist[i];
+ 
++	j = 0;
++	for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++) {
++		const struct sockaddr_in *sin = get_addrlist_in(clp, i);
++		if (sin->sin_family == AF_INET)
++			cltarg->cl_addrlist[j++] = sin->sin_addr;
++	}
++	if (j == 0) {
++		xlog(L_ERROR, "internal: no supported addresses in nfs_client");
++		return 0;
++	}
++
++	cltarg->cl_naddr = j;
+ 	return 1;
+ }
+ 
+@@ -100,7 +109,7 @@ expsetup(struct nfsctl_export *exparg, n
+ 	str_tolower(exparg->ex_client);
+ 	exparg->ex_flags    = exp->m_export.e_flags;
+ 	exparg->ex_dev      = (!unexport && (exp->m_export.e_flags & NFSEXP_FSID)) ?
+-				exp->m_export.e_fsid : stb.st_dev;
++			(__nfsd_dev_t)exp->m_export.e_fsid : stb.st_dev;
+ 	exparg->ex_ino      = stb.st_ino;
+ 	exparg->ex_anon_uid = exp->m_export.e_anonuid;
+ 	exparg->ex_anon_gid = exp->m_export.e_anongid;
+diff -up nfs-utils-1.2.2/support/export/rmtab.c.orig nfs-utils-1.2.2/support/export/rmtab.c
+--- nfs-utils-1.2.2/support/export/rmtab.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/export/rmtab.c	2010-09-09 11:02:27.061025000 -0400
+@@ -19,39 +19,54 @@
+ #include "xio.h"
+ #include "xlog.h"
+ 
++/*
++ * See if the entry already exists.  If not,
++ * this was an instantiated wild card, and we
++ * must add it.
++ */
++static void
++rmtab_read_wildcard(struct rmtabent *rep)
++{
++	nfs_export *exp, *exp2;
++	struct addrinfo *ai;
++
++	ai = host_addrinfo(rep->r_client);
++	if (ai == NULL)
++		return;
++
++	exp = export_allowed(ai, rep->r_path);
++	freeaddrinfo(ai);
++	if (exp == NULL)
++		return;
++
++	exp2 = export_lookup(rep->r_client, exp->m_export.e_path, 0);
++	if (exp2 == NULL) {
++		struct exportent ee;
++
++		memset(&ee, 0, sizeof(ee));
++		dupexportent(&ee, &exp->m_export);
++
++		ee.e_hostname = rep->r_client;
++		exp2 = export_create(&ee, 0);
++		exp2->m_changed = exp->m_changed;
++	}
++	exp2->m_mayexport = 1;
++}
++
+ int
+ rmtab_read(void)
+ {
+ 	struct rmtabent		*rep;
+-	nfs_export		*exp = NULL;
+ 
+ 	setrmtabent("r");
+ 	while ((rep = getrmtabent(1, NULL)) != NULL) {
+-		struct hostent		*hp = NULL;
+ 		int			htype;
+-		
++
+ 		htype = client_gettype(rep->r_client);
+-		if ((htype == MCL_FQDN || htype == MCL_SUBNETWORK)
+-		    && (hp = gethostbyname (rep->r_client))
+-		    && (hp = hostent_dup (hp),
+-			exp = export_allowed (hp, rep->r_path))) {
+-			/* see if the entry already exists, otherwise this was an instantiated
+-			 * wild card, and we must add it
+-			 */
+-			nfs_export *exp2 = export_lookup(rep->r_client,
+-							exp->m_export.e_path, 0);
+-			if (!exp2) {
+-				struct exportent ee;
+-				dupexportent(&ee, &exp->m_export);
+-				ee.e_hostname = rep->r_client;
+-				exp2 = export_create(&ee, 0);
+-				exp2->m_changed = exp->m_changed;
+-			}
+-			free (hp);
+-			exp2->m_mayexport = 1;
+-		} else if (hp) /* export_allowed failed */
+-			free(hp);
++		if (htype == MCL_FQDN || htype == MCL_SUBNETWORK)
++			rmtab_read_wildcard(rep);
+ 	}
++
+ 	if (errno == EINVAL) {
+ 		/* Something goes wrong. We need to fix the rmtab
+ 		   file. */
+diff -up nfs-utils-1.2.2/support/include/exportfs.h.orig nfs-utils-1.2.2/support/include/exportfs.h
+--- nfs-utils-1.2.2/support/include/exportfs.h.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/include/exportfs.h	2010-09-09 11:02:27.066025000 -0400
+@@ -10,6 +10,8 @@
+ #define EXPORTFS_H
+ 
+ #include <netdb.h>
++
++#include "sockaddr.h"
+ #include "nfslib.h"
+ 
+ enum {
+@@ -35,11 +37,56 @@ typedef struct mclient {
+ 	char *			m_hostname;
+ 	int			m_type;
+ 	int			m_naddr;
+-	struct in_addr		m_addrlist[NFSCLNT_ADDRMAX];
++	union nfs_sockaddr	m_addrlist[NFSCLNT_ADDRMAX];
+ 	int			m_exported;	/* exported to nfsd */
+ 	int			m_count;
+ } nfs_client;
+ 
++static inline const struct sockaddr *
++get_addrlist(const nfs_client *clp, const int i)
++{
++	return &clp->m_addrlist[i].sa;
++}
++
++static inline const struct sockaddr_in *
++get_addrlist_in(const nfs_client *clp, const int i)
++{
++	return &clp->m_addrlist[i].s4;
++}
++
++static inline const struct sockaddr_in6 *
++get_addrlist_in6(const nfs_client *clp, const int i)
++{
++	return &clp->m_addrlist[i].s6;
++}
++
++static inline void
++set_addrlist_in(nfs_client *clp, const int i, const struct sockaddr_in *sin)
++{
++	memcpy(&clp->m_addrlist[i].s4, sin, sizeof(*sin));
++}
++
++static inline void
++set_addrlist_in6(nfs_client *clp, const int i, const struct sockaddr_in6 *sin6)
++{
++	memcpy(&clp->m_addrlist[i].s6, sin6, sizeof(*sin6));
++}
++
++static inline void
++set_addrlist(nfs_client *clp, const int i, const struct sockaddr *sap)
++{
++	switch (sap->sa_family) {
++	case AF_INET:
++		memcpy(&clp->m_addrlist[i].s4, sap, sizeof(struct sockaddr_in));
++		break;
++#ifdef IPV6_SUPPORTED
++	case AF_INET6:
++		memcpy(&clp->m_addrlist[i].s6, sap, sizeof(struct sockaddr_in6));
++		break;
++#endif
++	}
++}
++
+ typedef struct mexport {
+ 	struct mexport *	m_next;
+ 	struct mclient *	m_client;
+@@ -69,26 +116,26 @@ extern exp_hash_table exportlist[MCL_MAX
+ extern nfs_client *		clientlist[MCL_MAXTYPES];
+ 
+ nfs_client *			client_lookup(char *hname, int canonical);
+-nfs_client *			client_find(struct hostent *);
+-void				client_add(nfs_client *);
+-nfs_client *			client_dup(nfs_client *, struct hostent *);
++nfs_client *			client_dup(const nfs_client *clp,
++						const struct addrinfo *ai);
+ int				client_gettype(char *hname);
+-int				client_check(nfs_client *, struct hostent *);
+-int				client_match(nfs_client *, char *hname);
++int				client_check(const nfs_client *clp,
++						const struct addrinfo *ai);
+ void				client_release(nfs_client *);
+ void				client_freeall(void);
+-char *				client_compose(struct hostent *he);
+-struct hostent *		client_resolve(struct in_addr addr);
+-int 				client_member(char *client, char *name);
++char *				client_compose(const struct addrinfo *ai);
++struct addrinfo *		client_resolve(const struct sockaddr *sap);
++int 				client_member(const char *client,
++						const char *name);
+ 
+-int				export_read(char *fname);
+-void			export_add(nfs_export *);
++void				export_read(char *fname);
+ void				export_reset(nfs_export *);
+ nfs_export *			export_lookup(char *hname, char *path, int caconical);
+-nfs_export *			export_find(struct hostent *, char *path);
+-nfs_export *			export_allowed(struct hostent *, char *path);
++nfs_export *			export_find(const struct addrinfo *ai,
++						const char *path);
++nfs_export *			export_allowed(const struct addrinfo *ai,
++						const char *path);
+ nfs_export *			export_create(struct exportent *, int canonical);
+-nfs_export *			export_dup(nfs_export *, struct hostent *);
+ void				export_freeall(void);
+ int				export_export(nfs_export *);
+ int				export_unexport(nfs_export *);
+@@ -101,6 +148,19 @@ void				xtab_append(nfs_export *);
+ 
+ int				secinfo_addflavor(struct flav_info *, struct exportent *);
+ 
++char *				host_ntop(const struct sockaddr *sap,
++						char *buf, const size_t buflen);
++__attribute_malloc__
++struct addrinfo *		host_pton(const char *paddr);
++__attribute_malloc__
++struct addrinfo *		host_addrinfo(const char *hostname);
++__attribute_malloc__
++char *				host_canonname(const struct sockaddr *sap);
++__attribute_malloc__
++struct addrinfo *		host_reliable_addrinfo(const struct sockaddr *sap);
++__attribute_malloc__
++struct addrinfo *		host_numeric_addrinfo(const struct sockaddr *sap);
++
+ int				rmtab_read(void);
+ 
+ struct nfskey *			key_lookup(char *hname);
+diff -up nfs-utils-1.2.2/support/include/misc.h.orig nfs-utils-1.2.2/support/include/misc.h
+--- nfs-utils-1.2.2/support/include/misc.h.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/include/misc.h	2010-09-09 11:02:27.071028000 -0400
+@@ -15,13 +15,6 @@
+ int	randomkey(unsigned char *keyout, int len);
+ int	weakrandomkey(unsigned char *keyout, int len);
+ 
+-int	matchhostname(const char *h1, const char *h2); 
+-
+-struct hostent;
+-struct hostent	*hostent_dup(struct hostent *hp);
+-struct hostent	*get_hostent (const char *addr, int len, int type);
+-struct hostent *get_reliable_hostbyaddr(const char *addr, int len, int type);
+-
+ extern int is_mountpoint(char *path);
+ 
+ #endif /* MISC_H */
+diff -up nfs-utils-1.2.2/support/include/nfslib.h.orig nfs-utils-1.2.2/support/include/nfslib.h
+--- nfs-utils-1.2.2/support/include/nfslib.h.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/include/nfslib.h	2010-09-09 11:02:27.076025000 -0400
+@@ -83,7 +83,7 @@ struct exportent {
+ 	int		e_nsquids;
+ 	int *		e_sqgids;
+ 	int		e_nsqgids;
+-	int		e_fsid;
++	unsigned int	e_fsid;
+ 	char *		e_mountpoint;
+ 	int             e_fslocmethod;
+ 	char *          e_fslocdata;
+@@ -152,10 +152,15 @@ void qword_addhex(char **bpp, int *lp, c
+ void qword_addint(char **bpp, int *lp, int n);
+ void qword_adduint(char **bpp, int *lp, unsigned int n);
+ void qword_addeol(char **bpp, int *lp);
++int qword_get_uint(char **bpp, unsigned int *anint);
++void qword_printuint(FILE *f, unsigned int num);
+ 
+ void closeall(int min);
+ 
+ int			svctcp_socket (u_long __number, int __reuse);
+-int			svcudp_socket (u_long __number, int __reuse);
++int			svcudp_socket (u_long __number);
++
++
++#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+ 
+ #endif /* NFSLIB_H */
+diff -up nfs-utils-1.2.2/support/include/nfsrpc.h.orig nfs-utils-1.2.2/support/include/nfsrpc.h
+--- nfs-utils-1.2.2/support/include/nfsrpc.h.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/include/nfsrpc.h	2010-09-09 11:02:27.081025000 -0400
+@@ -27,6 +27,12 @@
+ #include <rpc/clnt.h>
+ 
+ /*
++ * IANA does not define an IP protocol number for RDMA transports.
++ * Choose an arbitrary value we can use locally.
++ */
++#define NFSPROTO_RDMA		(3939)
++
++/*
+  * Conventional RPC program numbers
+  */
+ #ifndef RPCBPROG
+@@ -160,4 +166,7 @@ extern int		nfs_rpc_ping(const struct so
+ 				const unsigned short protocol,
+ 				const struct timeval *timeout);
+ 
++/* create AUTH_SYS handle with no supplemental groups */
++extern AUTH *			 nfs_authsys_create(void);
++
+ #endif	/* !__NFS_UTILS_NFSRPC_H */
+diff -up nfs-utils-1.2.2/support/include/rpcmisc.h.orig nfs-utils-1.2.2/support/include/rpcmisc.h
+--- nfs-utils-1.2.2/support/include/rpcmisc.h.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/include/rpcmisc.h	2010-09-09 11:02:27.086024000 -0400
+@@ -60,12 +60,12 @@ extern int	_rpcsvcdirty;
+ 
+ static inline struct sockaddr_in *nfs_getrpccaller_in(SVCXPRT *xprt)
+ {
+-	return (struct sockaddr_in *)svc_getcaller(xprt);
++	return (struct sockaddr_in *)(char *)svc_getcaller(xprt);
+ }
+ 
+ static inline struct sockaddr *nfs_getrpccaller(SVCXPRT *xprt)
+ {
+-	return (struct sockaddr *)svc_getcaller(xprt);
++	return (struct sockaddr *)(char *)svc_getcaller(xprt);
+ }
+ 
+ #endif /* RPCMISC_H */
+diff -up nfs-utils-1.2.2/support/nfs/cacheio.c.orig nfs-utils-1.2.2/support/nfs/cacheio.c
+--- nfs-utils-1.2.2/support/nfs/cacheio.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/nfs/cacheio.c	2010-09-09 11:02:27.091025000 -0400
+@@ -148,6 +148,11 @@ void qword_printint(FILE *f, int num)
+ 	fprintf(f, "%d ", num);
+ }
+ 
++void qword_printuint(FILE *f, unsigned int num)
++{
++	fprintf(f, "%u ", num);
++}
++
+ int qword_eol(FILE *f)
+ {
+ 	int err;
+@@ -236,6 +241,20 @@ int qword_get_int(char **bpp, int *anint
+ 	return 0;
+ }
+ 
++int qword_get_uint(char **bpp, unsigned int *anint)
++{
++	char buf[50];
++	char *ep;
++	unsigned int rv;
++	int len = qword_get(bpp, buf, 50);
++	if (len < 0) return -1;
++	if (len ==0) return -1;
++	rv = strtoul(buf, &ep, 0);
++	if (*ep) return -1;
++	*anint = rv;
++	return 0;
++}
++
+ #define READLINE_BUFFER_INCREMENT 2048
+ 
+ int readline(int fd, char **buf, int *lenp)
+@@ -330,7 +349,7 @@ cache_flush(int force)
+ 		sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]);
+ 		fd = open(path, O_RDWR);
+ 		if (fd >= 0) {
+-			if (write(fd, stime, strlen(stime)) != strlen(stime)) {
++			if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) {
+ 				xlog_warn("Writing to '%s' failed: errno %d (%s)",
+ 				path, errno, strerror(errno));
+ 			}
+diff -up nfs-utils-1.2.2/support/nfs/conffile.c.orig nfs-utils-1.2.2/support/nfs/conffile.c
+--- nfs-utils-1.2.2/support/nfs/conffile.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/nfs/conffile.c	2010-09-09 11:02:27.097022000 -0400
+@@ -49,7 +49,7 @@
+ #include "conffile.h"
+ #include "xlog.h"
+ 
+-static void conf_load_defaults (int);
++static void conf_load_defaults(void);
+ static int conf_set(int , char *, char *, char *, 
+ 	char *, int , int );
+ 
+@@ -212,7 +212,7 @@ conf_parse_line(int trans, char *line, s
+ {
+ 	char *val, *ptr;
+ 	size_t i;
+-	int j;
++	size_t j;
+ 	static char *section = 0;
+ 	static char *arg = 0;
+ 	static int ln = 0;
+@@ -353,7 +353,7 @@ conf_parse(int trans, char *buf, size_t 
+ }
+ 
+ static void
+-conf_load_defaults(int tr)
++conf_load_defaults(void)
+ {
+ 	/* No defaults */
+ 	return;
+@@ -412,7 +412,7 @@ conf_reinit(void)
+ 		trans = conf_begin();
+ 
+ 	/* Load default configuration values.  */
+-	conf_load_defaults(trans);
++	conf_load_defaults();
+ 
+ 	/* Free potential existing configuration.  */
+ 	if (conf_addr) {
+diff -up nfs-utils-1.2.2/support/nfs/getport.c.orig nfs-utils-1.2.2/support/nfs/getport.c
+--- nfs-utils-1.2.2/support/nfs/getport.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/nfs/getport.c	2010-09-09 11:02:27.103022000 -0400
+@@ -216,6 +216,21 @@ nfs_get_proto(const char *netid, sa_fami
+ 	struct netconfig *nconf;
+ 	struct protoent *proto;
+ 
++	/*
++	 * IANA does not define a protocol number for rdma netids,
++	 * since "rdma" is not an IP protocol.
++	 */
++	if (strcmp(netid, "rdma") == 0) {
++		*family = AF_INET;
++		*protocol = NFSPROTO_RDMA;
++		return 1;
++	}
++	if (strcmp(netid, "rdma6") == 0) {
++		*family = AF_INET6;
++		*protocol = NFSPROTO_RDMA;
++		return 1;
++	}
++
+ 	nconf = getnetconfigent(netid);
+ 	if (nconf == NULL)
+ 		return 0;
+@@ -242,6 +257,16 @@ nfs_get_proto(const char *netid, sa_fami
+ {
+ 	struct protoent *proto;
+ 
++	/*
++	 * IANA does not define a protocol number for rdma netids,
++	 * since "rdma" is not an IP protocol.
++	 */
++	if (strcmp(netid, "rdma") == 0) {
++		*family = AF_INET;
++		*protocol = NFSPROTO_RDMA;
++		return 1;
++	}
++
+ 	proto = getprotobyname(netid);
+ 	if (proto == NULL)
+ 		return 0;
+diff -up nfs-utils-1.2.2/support/nfs/nfs_mntent.c.orig nfs-utils-1.2.2/support/nfs/nfs_mntent.c
+--- nfs-utils-1.2.2/support/nfs/nfs_mntent.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/nfs/nfs_mntent.c	2010-09-09 11:02:27.108025000 -0400
+@@ -28,7 +28,7 @@ static char *
+ mangle(const char *arg) {
+ 	const unsigned char *s = (const unsigned char *)arg;
+ 	char *ss, *sp;
+-	int n;
++	unsigned int n;
+ 
+ 	n = strlen(arg);
+ 	ss = sp = xmalloc(4*n+1);
+diff -up nfs-utils-1.2.2/support/nfs/rmtab.c.orig nfs-utils-1.2.2/support/nfs/rmtab.c
+--- nfs-utils-1.2.2/support/nfs/rmtab.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/nfs/rmtab.c	2010-09-09 11:02:27.113025000 -0400
+@@ -19,6 +19,18 @@
+ #include <signal.h>
+ #include "nfslib.h"
+ 
++/*
++ * Colons in incoming IPv6 presentation addresses have to
++ * replaced with another character, since rmtab already
++ * uses colons to delineate fields.
++ *
++ * Use a printable character, but one that would never be
++ * found in a presentation address or domain name
++ */
++#define IPV6_COLON	';'
++
++#define LINELEN		(2048)
++
+ static FILE	*rmfp = NULL;
+ 
+ int
+@@ -56,7 +68,8 @@ struct rmtabent *
+ fgetrmtabent(FILE *fp, int log, long *pos)
+ {
+ 	static struct rmtabent	re;
+-	char	buf[2048], *count, *host, *path;
++	char		*count, *host, *path, *c;
++	static char	buf[LINELEN];
+ 
+ 	errno = 0;
+ 	if (!fp)
+@@ -84,10 +97,16 @@ fgetrmtabent(FILE *fp, int log, long *po
+ 		else
+ 			re.r_count = 1;
+ 	} while (0);
++
+ 	strncpy(re.r_client, host, sizeof (re.r_client) - 1);
+ 	re.r_client[sizeof (re.r_client) - 1] = '\0';
++	for (c = re.r_client; *c != '\0'; c++)
++		if (*c == IPV6_COLON)
++			*c = ':';
++
+ 	strncpy(re.r_path, path, sizeof (re.r_path) - 1);
+ 	re.r_path[sizeof (re.r_path) - 1] = '\0';
++
+ 	return &re;
+ }
+ 
+@@ -100,10 +119,27 @@ putrmtabent(struct rmtabent *rep, long *
+ void
+ fputrmtabent(FILE *fp, struct rmtabent *rep, long *pos)
+ {
++	static char	buf[LINELEN];
++	char		*c;
++
+ 	if (!fp || (pos && fseek (fp, *pos, SEEK_SET) != 0))
+ 		return;
+-	fprintf(fp, "%s:%s:0x%.8x\n", rep->r_client, rep->r_path,
+-		rep->r_count);
++
++	/*
++	 * To avoid confusing the token parser in fgetrmtabent(),
++	 * convert colons in incoming IPv6 presentation addresses
++	 * to semicolons.
++	 */
++	if (strlen(rep->r_client) > sizeof(buf)) {
++		xlog(L_ERROR, "client name too large");
++		return;
++	}
++	strncpy(buf, rep->r_client, sizeof(buf));
++	for (c = buf; *c != '\0'; c++)
++		if (*c == ':')
++			*c = IPV6_COLON;
++
++	(void)fprintf(fp, "%s:%s:0x%.8x\n", buf, rep->r_path, rep->r_count);
+ }
+ 
+ void
+diff -up nfs-utils-1.2.2/support/nfs/rpcdispatch.c.orig nfs-utils-1.2.2/support/nfs/rpcdispatch.c
+--- nfs-utils-1.2.2/support/nfs/rpcdispatch.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/nfs/rpcdispatch.c	2010-09-09 11:02:27.136025000 -0400
+@@ -27,12 +27,12 @@ rpc_dispatch(struct svc_req *rqstp, SVCX
+ {
+ 	struct rpc_dentry	*dent;
+ 
+-	if (rqstp->rq_vers > nvers) {
++	if (((int)rqstp->rq_vers) > nvers) {
+ 		svcerr_progvers(transp, 1, nvers);
+ 		return;
+ 	}
+ 	dtable += (rqstp->rq_vers - 1);
+-	if (rqstp->rq_proc > dtable->nproc) {
++	if (((int)rqstp->rq_proc) > dtable->nproc) {
+ 		svcerr_noproc(transp);
+ 		return;
+ 	}
+diff -up nfs-utils-1.2.2/support/nfs/rpcmisc.c.orig nfs-utils-1.2.2/support/nfs/rpcmisc.c
+--- nfs-utils-1.2.2/support/nfs/rpcmisc.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/nfs/rpcmisc.c	2010-09-09 11:02:27.145022000 -0400
+@@ -154,7 +154,7 @@ rpc_init(char *name, int prog, int vers,
+ 				sock = makesock(defport, IPPROTO_UDP);
+ 		}
+ 		if (sock == RPC_ANYSOCK)
+-			sock = svcudp_socket (prog, 1);
++			sock = svcudp_socket (prog);
+ 		transp = svcudp_create(sock);
+ 		if (transp == NULL) {
+ 			xlog(L_FATAL, "cannot create udp service.");
+diff -up nfs-utils-1.2.2/support/nfs/rpc_socket.c.orig nfs-utils-1.2.2/support/nfs/rpc_socket.c
+--- nfs-utils-1.2.2/support/nfs/rpc_socket.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/nfs/rpc_socket.c	2010-09-09 11:02:27.131022000 -0400
+@@ -557,3 +557,24 @@ rpcprog_t nfs_getrpcbyname(const rpcprog
+ 
+ 	return program;
+ }
++
++/*
++ * AUTH_SYS doesn't allow more than 16 gids in the supplemental group list.
++ * If there are more than that, trying to determine which ones to include
++ * in the list is problematic. This function creates an auth handle that
++ * only has the primary gid in the supplemental gids list. It's intended to
++ * be used for protocols where credentials really don't matter much (the MNT
++ * protocol, for instance).
++ */
++AUTH *
++nfs_authsys_create(void)
++{
++	char machname[MAXHOSTNAMELEN + 1];
++	uid_t	uid = geteuid();
++	gid_t	gid = getegid();
++
++	if (gethostname(machname, sizeof(machname)) == -1)
++		return NULL;
++
++	return authunix_create(machname, uid, gid, 1, &gid);
++}
+diff -up nfs-utils-1.2.2/support/nfs/svc_socket.c.orig nfs-utils-1.2.2/support/nfs/svc_socket.c
+--- nfs-utils-1.2.2/support/nfs/svc_socket.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/support/nfs/svc_socket.c	2010-09-09 11:02:27.150025000 -0400
+@@ -157,9 +157,9 @@ svctcp_socket (u_long number, int reuse)
+  * Create and bind a UDP socket based on program number
+  */
+ int
+-svcudp_socket (u_long number, int reuse)
++svcudp_socket (u_long number)
+ {
+-  return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, 0);
++  return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, FALSE);
+ }
+ 
+ #ifdef TEST
+@@ -174,7 +174,7 @@ check (u_long number, u_short port, int 
+   if (protocol == IPPROTO_TCP)
+     socket = svctcp_socket (number, reuse);
+   else
+-    socket = svcudp_socket (number, reuse);
++    socket = svcudp_socket (number);
+ 
+   if (socket < 0)
+     return 1;
+diff -up nfs-utils-1.2.2/support/nsm/file.c.orig nfs-utils-1.2.2/support/nsm/file.c
+--- nfs-utils-1.2.2/support/nsm/file.c.orig	2010-09-09 11:01:45.345738000 -0400
++++ nfs-utils-1.2.2/support/nsm/file.c	2010-09-09 11:02:27.167022000 -0400
+@@ -67,7 +67,9 @@
+ #endif
+ 
+ #include <sys/types.h>
++#ifdef HAVE_SYS_CAPABILITY_H
+ #include <sys/capability.h>
++#endif
+ #include <sys/prctl.h>
+ #include <sys/stat.h>
+ 
+@@ -348,6 +350,7 @@ nsm_is_default_parentdir(void)
+ static _Bool
+ nsm_clear_capabilities(void)
+ {
++#ifdef HAVE_SYS_CAPABILITY_H
+ 	cap_t caps;
+ 
+ 	caps = cap_from_text("cap_net_bind_service=ep");
+@@ -363,6 +366,7 @@ nsm_clear_capabilities(void)
+ 	}
+ 
+ 	(void)cap_free(caps);
++#endif
+ 	return true;
+ }
+ 
+diff -up nfs-utils-1.2.2/tools/Makefile.am.orig nfs-utils-1.2.2/tools/Makefile.am
+--- nfs-utils-1.2.2/tools/Makefile.am.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/tools/Makefile.am	2010-09-09 11:02:27.172025000 -0400
+@@ -6,6 +6,6 @@ if CONFIG_RPCGEN
+ OPTDIRS += rpcgen
+ endif
+ 
+-SUBDIRS = locktest rpcdebug nlmtest $(OPTDIRS)
++SUBDIRS = locktest rpcdebug nlmtest mountstats nfs-iostat $(OPTDIRS)
+ 
+ MAINTAINERCLEANFILES = Makefile.in
+diff -up nfs-utils-1.2.2/tools/mountstats/Makefile.am.orig nfs-utils-1.2.2/tools/mountstats/Makefile.am
+--- nfs-utils-1.2.2/tools/mountstats/Makefile.am.orig	2010-09-09 11:02:27.191022000 -0400
++++ nfs-utils-1.2.2/tools/mountstats/Makefile.am	2010-09-09 11:02:27.193022000 -0400
+@@ -0,0 +1,13 @@
++## Process this file with automake to produce Makefile.in
++PYTHON_FILES =  mountstats.py
++
++man8_MANS	= mountstats.man
++
++EXTRA_DIST	= $(man8_MANS) $(PYTHON_FILES)
++
++all-local: $(PYTHON_FILES)
++
++install-data-hook:
++	$(INSTALL) --mode 755 mountstats.py $(DESTDIR)$(sbindir)/mountstats
++
++MAINTAINERCLEANFILES=Makefile.in
+diff -up nfs-utils-1.2.2/tools/mountstats/mountstats.man.orig nfs-utils-1.2.2/tools/mountstats/mountstats.man
+--- nfs-utils-1.2.2/tools/mountstats/mountstats.man.orig	2010-09-09 11:02:27.196022000 -0400
++++ nfs-utils-1.2.2/tools/mountstats/mountstats.man	2010-09-09 11:02:27.197027000 -0400
+@@ -0,0 +1,32 @@
++.\"
++.\" mountstats(8)
++.\"
++.TH mountstats 8 "15 Apr 2010"
++.SH NAME
++mountstats \- Displays NFS client per-mount statistics
++.SH SYNOPSIS
++.BI "mountstats ["<options> "] " <mount_point> " [ " <mount_point> "]" 
++.SH DESCRIPTION
++The
++.B mountstats
++command displays NFS client statisitics on each given
++.I <mount_point>
++.SH OPTIONS
++.TP
++.B " \-\-nfs
++display only the NFS statistics
++.TP
++.B " \-\-rpc 
++display only the RPC statistics
++.TP
++.B " \-\-version 
++display the version of this command
++.SH FILES
++.TP
++.B /proc/self/mountstats
++.SH SEE ALSO
++.BR iostat (8),
++.BR nfsiostat (8),
++.BR nfsstat(8)
++.SH AUTHOR
++Chuck Lever <chuck.lever at oracle.com>
+diff -up nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am.orig nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am
+--- nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am.orig	2010-09-09 11:02:27.218022000 -0400
++++ nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am	2010-09-09 11:02:27.219031000 -0400
+@@ -0,0 +1,13 @@
++## Process this file with automake to produce Makefile.in
++PYTHON_FILES =  nfs-iostat.py
++
++man8_MANS	= nfsiostat.man
++
++EXTRA_DIST	= $(man8_MANS) $(PYTHON_FILES)
++
++all-local: $(PYTHON_FILES)
++
++install-data-hook:
++	$(INSTALL) --mode 755 nfs-iostat.py $(DESTDIR)$(sbindir)/nfsiostat
++
++MAINTAINERCLEANFILES=Makefile.in
+diff -up nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man.orig nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man
+--- nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man.orig	2010-09-09 11:02:27.228021000 -0400
++++ nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man	2010-09-09 11:02:27.229027000 -0400
+@@ -0,0 +1,71 @@
++.\"
++.\" nfsiostat(8)
++.\"
++.TH nfsiostat 8 "15 Apr 2010"
++.SH NAME
++nfsiostat \- Emulate iostat for NFS mount points using /proc/self/mountstats
++.SH SYNOPSIS
++.BI "nfsiostat [[" <interval> "] [" <count> "]] [" <options> "]["<mount_point> "]
++.SH DESCRIPTION
++The
++.B nfsiostat
++command displays NFS client per-mount statisitics. 
++.TP 
++<interval>
++specifies the amount of time in seconds between each report.
++The first report contains statistics for the time since each file
++system was mounted.  Each subsequent report contains statistics collected
++during the interval since the previous report.
++.TP
++<count>
++If the
++.I <count>
++parameter is
++specified, the value of 
++.I <count> 
++determines the number of reports generated at
++. <interval> 
++seconds apart. if the interval parameter is 
++specified without the
++.I <count> 
++parameter, the command generates reports continuously.
++.TP
++<options>
++Define below
++.TP
++<mount_point>
++If one or more
++.I <mount point> 
++names are specified, statistics for only these mount points will
++be displayed.  Otherwise, all NFS mount points on the client are listed.
++.SH OPTIONS
++.TP
++.B \-a " or " \-\-attr
++displays statistics related to the attribute cache
++.TP
++.B \-d " or " \-\-dir 
++displays statistics related to directory operations
++.TP
++.B \-h " or " \-\-help 
++shows help message and exit
++.TP
++.B \-l LIST or " \-\-list=LIST 
++only print stats for first LIST mount points
++.TP
++.B \-p " or " \-\-page
++displays statistics related to the page cache
++.TP
++.B \-s " or " \-\-sort
++Sort NFS mount points by ops/second
++.TP
++.B \-\-version
++show program's version number and exit
++.SH FILES
++.TP
++.B /proc/self/mountstats
++.SH SEE ALSO
++.BR iostat (8),
++.BR mountstats (8),
++.BR nfsstat(8)
++.SH AUTHOR
++Chuck Lever <chuck.lever at oracle.com>
+diff -up nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py.orig nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py
+--- nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/tools/nfs-iostat/nfs-iostat.py	2010-09-09 11:02:27.224025000 -0400
+@@ -366,6 +366,12 @@ class DeviceData:
+         sends = float(self.__rpc_data['rpcsends'])
+         if sample_time == 0:
+             sample_time = float(self.__nfs_data['age'])
++        #  sample_time could still be zero if the export was just mounted.
++        #  Set it to 1 to avoid divide by zero errors in this case since we'll
++        #  likely still have relevant mount statistics to show.
++        #
++        if sample_time == 0:
++            sample_time = 1;
+         if sends != 0:
+             backlog = (float(self.__rpc_data['backlogutil']) / sends) / sample_time
+         else:
+diff -up nfs-utils-1.2.2/utils/exportfs/exportfs.c.orig nfs-utils-1.2.2/utils/exportfs/exportfs.c
+--- nfs-utils-1.2.2/utils/exportfs/exportfs.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/exportfs/exportfs.c	2010-09-09 11:02:27.234025000 -0400
+@@ -12,20 +12,23 @@
+ #include <config.h>
+ #endif
+ 
++#include <sys/types.h>
++#include <sys/stat.h>
+ #include <sys/vfs.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
++#include <stdbool.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <stdarg.h>
+ #include <getopt.h>
++#include <fcntl.h>
+ #include <netdb.h>
+ #include <errno.h>
+-#include "xmalloc.h"
++
+ #include "misc.h"
+ #include "nfslib.h"
+ #include "exportfs.h"
+-#include "xmalloc.h"
+ #include "xlog.h"
+ 
+ static void	export_all(int verbose);
+@@ -34,13 +37,15 @@ static void	unexportfs(char *arg, int ve
+ static void	exports_update(int verbose);
+ static void	dump(int verbose);
+ static void	error(nfs_export *exp, int err);
+-static void	usage(void);
++static void	usage(const char *progname);
+ static void	validate_export(nfs_export *exp);
++static int	matchhostname(const char *hostname1, const char *hostname2);
+ 
+ int
+ main(int argc, char **argv)
+ {
+ 	char	*options = NULL;
++	char	*progname = NULL;
+ 	int	f_export = 1;
+ 	int	f_all = 0;
+ 	int	f_verbose = 0;
+@@ -50,7 +55,14 @@ main(int argc, char **argv)
+ 	int	new_cache = 0;
+ 	int	force_flush = 0;
+ 
+-	xlog_open("exportfs");
++	if ((progname = strrchr(argv[0], '/')) != NULL)
++		progname++;
++	else
++		progname = argv[0];
++
++	xlog_open(progname);
++	xlog_stderr(1);
++	xlog_syslog(0);
+ 
+ 	export_errno = 0;
+ 
+@@ -79,21 +91,21 @@ main(int argc, char **argv)
+ 			force_flush = 1;
+ 			break;
+ 		default:
+-			usage();
++			usage(progname);
+ 			break;
+ 		}
+ 	}
+ 
+ 	if (optind != argc && f_all) {
+-		fprintf(stderr,"exportfs: extra arguments are not permitted with -a or -r.\n");
++		xlog(L_ERROR, "extra arguments are not permitted with -a or -r");
+ 		return 1;
+ 	}
+ 	if (f_ignore && (f_all || ! f_export)) {
+-		fprintf(stderr,"exportfs: -i not meaningful with -a, -r or -u.\n");
++		xlog(L_ERROR, "-i not meaningful with -a, -r or -u");
+ 		return 1;
+ 	}
+ 	if (f_reexport && ! f_export) {
+-		fprintf(stderr, "exportfs: -r and -u are incompatible.\n");
++		xlog(L_ERROR, "-r and -u are incompatible");
+ 		return 1;
+ 	}
+ 	new_cache = check_new_cache();
+@@ -102,8 +114,10 @@ main(int argc, char **argv)
+ 			if (new_cache)
+ 				cache_flush(1);
+ 			else {
+-				fprintf(stderr, "exportfs: -f: only available with new cache controls: mount /proc/fs/nfsd first\n");
+-				exit(1);
++				xlog(L_ERROR, "-f is available only "
++					"with new cache controls. "
++					"Mount /proc/fs/nfsd first");
++				return 1;
+ 			}
+ 			return 0;
+ 		} else {
+@@ -232,7 +246,7 @@ exportfs(char *arg, char *options, int v
+ {
+ 	struct exportent *eep;
+ 	nfs_export	*exp;
+-	struct hostent	*hp = NULL;
++	struct addrinfo	*ai = NULL;
+ 	char		*path;
+ 	char		*hname = arg;
+ 	int		htype;
+@@ -241,36 +255,25 @@ exportfs(char *arg, char *options, int v
+ 		*path++ = '\0';
+ 
+ 	if (!path || *path != '/') {
+-		fprintf(stderr, "Invalid exporting option: %s\n", arg);
++		xlog(L_ERROR, "Invalid exporting option: %s", arg);
+ 		return;
+ 	}
+ 
+-	if ((htype = client_gettype(hname)) == MCL_FQDN &&
+-	    (hp = gethostbyname(hname)) != NULL) {
+-		struct hostent *hp2 = hostent_dup (hp);
+-		hp = gethostbyaddr(hp2->h_addr, hp2->h_length,
+-				   hp2->h_addrtype);
+-		if (hp) {
+-			free(hp2);
+-			hp = hostent_dup(hp);
+-		} else
+-			hp = hp2;
+-		exp = export_find(hp, path);
+-		hname = hp->h_name;
+-	} else {
++	if ((htype = client_gettype(hname)) == MCL_FQDN) {
++		ai = host_addrinfo(hname);
++		if (ai != NULL) {
++			exp = export_find(ai, path);
++			hname = ai->ai_canonname;
++		}
++	} else
+ 		exp = export_lookup(hname, path, 0);
+-	}
+ 
+ 	if (!exp) {
+ 		if (!(eep = mkexportent(hname, path, options)) ||
+-		    !(exp = export_create(eep, 0))) {
+-			if (hp) free (hp);
+-			return;
+-		}
+-	} else if (!updateexportent(&exp->m_export, options)) {
+-		if (hp) free (hp);
+-		return;
+-	}
++		    !(exp = export_create(eep, 0)))
++			goto out;
++	} else if (!updateexportent(&exp->m_export, options))
++		goto out;
+ 
+ 	if (verbose)
+ 		printf("exporting %s:%s\n", exp->m_client->m_hostname, 
+@@ -280,14 +283,16 @@ exportfs(char *arg, char *options, int v
+ 	exp->m_changed = 1;
+ 	exp->m_warned = 0;
+ 	validate_export(exp);
+-	if (hp) free (hp);
++
++out:
++	freeaddrinfo(ai);
+ }
+ 
+ static void
+ unexportfs(char *arg, int verbose)
+ {
+ 	nfs_export	*exp;
+-	struct hostent	*hp = NULL;
++	struct addrinfo *ai = NULL;
+ 	char		*path;
+ 	char		*hname = arg;
+ 	int		htype;
+@@ -296,16 +301,14 @@ unexportfs(char *arg, int verbose)
+ 		*path++ = '\0';
+ 
+ 	if (!path || *path != '/') {
+-		fprintf(stderr, "Invalid unexporting option: %s\n",
+-			arg);
++		xlog(L_ERROR, "Invalid unexporting option: %s", arg);
+ 		return;
+ 	}
+ 
+ 	if ((htype = client_gettype(hname)) == MCL_FQDN) {
+-		if ((hp = gethostbyname(hname)) != 0) {
+-			hp = hostent_dup (hp);
+-			hname = (char *) hp->h_name;
+-		}
++		ai = host_addrinfo(hname);
++		if (ai)
++			hname = ai->ai_canonname;
+ 	}
+ 
+ 	for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
+@@ -341,7 +344,7 @@ unexportfs(char *arg, int verbose)
+ 		exp->m_mayexport = 0;
+ 	}
+ 
+-	if (hp) free (hp);
++	freeaddrinfo(ai);
+ }
+ 
+ static int can_test(void)
+@@ -393,14 +396,12 @@ validate_export(nfs_export *exp)
+ 	int fs_has_fsid = 0;
+ 
+ 	if (stat(path, &stb) < 0) {
+-		fprintf(stderr, "exportfs: Warning: %s does not exist\n",
+-			path);
++		xlog(L_ERROR, "Failed to stat %s: %m \n", path);
+ 		return;
+ 	}
+ 	if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) {
+-		fprintf(stderr, "exportfs: Warning: %s is neither "
+-			"a directory nor a file.\n"
+-			"     remote access will fail\n", path);
++		xlog(L_ERROR, "%s is neither a directory nor a file. "
++			"Remote access will fail", path);
+ 		return;
+ 	}
+ 	if (!can_test())
+@@ -413,24 +414,95 @@ validate_export(nfs_export *exp)
+ 	if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid ||
+ 	    fs_has_fsid) {
+ 		if ( !test_export(path, 1)) {
+-			fprintf(stderr, "exportfs: Warning: %s does not "
+-				"support NFS export.\n",
+-				path);
++			xlog(L_ERROR, "%s does not support NFS export", path);
+ 			return;
+ 		}
+ 	} else if ( ! test_export(path, 0)) {
+ 		if (test_export(path, 1))
+-			fprintf(stderr, "exportfs: Warning: %s requires fsid= "
+-				"for NFS export\n", path);
++			xlog(L_ERROR, "%s requires fsid= for NFS export", path);
+ 		else
+-			fprintf(stderr, "exportfs: Warning: %s does not "
+-				"support NFS export.\n",
+-				path);
++			xlog(L_ERROR, "%s does not support NFS export", path);
+ 		return;
+ 
+ 	}
+ }
+ 
++static _Bool
++is_hostname(const char *sp)
++{
++	if (*sp == '\0' || *sp == '@')
++		return false;
++
++	for (; *sp != '\0'; sp++) {
++		if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
++			return false;
++		if (*sp == '\\' && sp[1] != '\0')
++			sp++;
++	}
++
++	return true;
++}
++
++static _Bool
++compare_sockaddrs4(const struct sockaddr *sa1, const struct sockaddr *sa2)
++{
++	const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
++	const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
++	return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
++}
++
++static _Bool
++compare_sockaddrs(const struct sockaddr *sa1, const struct sockaddr *sa2)
++{
++	if (sa1->sa_family == sa2->sa_family)
++		switch (sa1->sa_family) {
++		case AF_INET:
++			return compare_sockaddrs4(sa1, sa2);
++		}
++
++	return false;
++}
++
++static int
++matchhostname(const char *hostname1, const char *hostname2)
++{
++	struct addrinfo *results1 = NULL, *results2 = NULL;
++	struct addrinfo *ai1, *ai2;
++	int result = 0;
++
++	if (strcasecmp(hostname1, hostname2) == 0)
++		return 1;
++
++	/*
++	 * Don't pass export wildcards or netgroup names to DNS
++	 */
++	if (!is_hostname(hostname1) || !is_hostname(hostname2))
++		return 0;
++
++	results1 = host_addrinfo(hostname1);
++	if (results1 == NULL)
++		goto out;
++	results2 = host_addrinfo(hostname2);
++	if (results2 == NULL)
++		goto out;
++
++	if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
++		result = 1;
++		goto out;
++	}
++
++	for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next)
++		for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next)
++			if (compare_sockaddrs(ai1->ai_addr, ai2->ai_addr)) {
++				result = 1;
++				break;
++			}
++
++out:
++	freeaddrinfo(results1);
++	freeaddrinfo(results2);
++	return result;
++}
+ 
+ static char
+ dumpopt(char c, char *fmt, ...)
+@@ -532,13 +604,13 @@ dump(int verbose)
+ static void
+ error(nfs_export *exp, int err)
+ {
+-	fprintf(stderr, "%s:%s: %s\n", exp->m_client->m_hostname, 
++	xlog(L_ERROR, "%s:%s: %s\n", exp->m_client->m_hostname,
+ 		exp->m_export.e_path, strerror(err));
+ }
+ 
+ static void
+-usage(void)
++usage(const char *progname)
+ {
+-	fprintf(stderr, "usage: exportfs [-aruv] [host:/path]\n");
++	fprintf(stderr, "usage: %s [-aruv] [host:/path]\n", progname);
+ 	exit(1);
+ }
+diff -up nfs-utils-1.2.2/utils/gssd/context.h.orig nfs-utils-1.2.2/utils/gssd/context.h
+--- nfs-utils-1.2.2/utils/gssd/context.h.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/context.h	2010-09-09 11:02:27.239025000 -0400
+@@ -1,5 +1,5 @@
+ /*
+-  Copyright (c) 2004 The Regents of the University of Michigan.
++  Copyright (c) 2004,2008 The Regents of the University of Michigan.
+   All rights reserved.
+ 
+   Redistribution and use in source and binary forms, with or without
+@@ -36,6 +36,10 @@
+ /* Hopefully big enough to hold any serialized context */
+ #define MAX_CTX_LEN 4096
+ 
++/* New context format flag values */
++#define KRB5_CTX_FLAG_INITIATOR         0x00000001
++#define KRB5_CTX_FLAG_CFX               0x00000002
++#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
+ 
+ int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf,
+ 				 gss_OID mech, int32_t *endtime);
+diff -up nfs-utils-1.2.2/utils/gssd/context_lucid.c.orig nfs-utils-1.2.2/utils/gssd/context_lucid.c
+--- nfs-utils-1.2.2/utils/gssd/context_lucid.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/context_lucid.c	2010-09-09 11:02:27.245022000 -0400
+@@ -42,6 +42,7 @@
+ #include <stdio.h>
+ #include <syslog.h>
+ #include <string.h>
++#include <errno.h>
+ 
+ #include <gssapi/gssapi_krb5.h>
+ 
+@@ -76,7 +77,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_luc
+ 	unsigned char fakeseed[FAKESEED_SIZE];
+ 	uint32_t word_send_seq;
+ 	gss_krb5_lucid_key_t enc_key;
+-	int i;
++	uint32_t i;
+ 	char *skd, *dkd;
+ 	gss_buffer_desc fakeoid;
+ 
+@@ -119,15 +120,13 @@ prepare_krb5_rfc1964_buffer(gss_krb5_luc
+ 	 * Note that the rfc1964 version only supports DES enctypes.
+ 	 */
+ 	if (lctx->rfc1964_kd.ctx_key.type != 4) {
+-		printerr(1, "prepare_krb5_rfc1964_buffer: "
+-			    "overriding heimdal keytype (%d => %d)\n",
+-			    lctx->rfc1964_kd.ctx_key.type, 4);
++		printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
++			 __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4);
+ 		lctx->rfc1964_kd.ctx_key.type = 4;
+ 	}
+ #endif
+-	printerr(2, "prepare_krb5_rfc1964_buffer: serializing keys with "
+-		 "enctype %d and length %d\n",
+-		 lctx->rfc1964_kd.ctx_key.type,
++	printerr(2, "%s: serializing keys with enctype %d and length %d\n",
++		 __FUNCTION__, lctx->rfc1964_kd.ctx_key.type,
+ 		 lctx->rfc1964_kd.ctx_key.length);
+ 
+ 	/* derive the encryption key and copy it into buffer */
+@@ -158,11 +157,102 @@ out_err:
+ 	return -1;
+ }
+ 
++/* Flags for version 2 context flags */
++#define KRB5_CTX_FLAG_INITIATOR		0x00000001
++#define KRB5_CTX_FLAG_CFX		0x00000002
++#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY	0x00000004
++
++/*
++ * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx),
++ * to send to the kernel for newer encryption types -- or for DES3.
++ *
++ * The new format is:
++ *
++ *	u32 flags;
++ *	#define KRB5_CTX_FLAG_INITIATOR		0x00000001
++ *	#define KRB5_CTX_FLAG_CFX		0x00000002
++ *	#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY	0x00000004
++ *	s32 endtime;
++ *	u64 seq_send;
++ *	u32  enctype;			( encrption type of key )
++ *	raw key;			( raw key bytes (kernel will derive))
++ *
++ */
+ static int
+-prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx,
++prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx,
+ 	gss_buffer_desc *buf, int32_t *endtime)
+ {
+-	printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n");
++	char *p, *end;
++	uint32_t v2_flags = 0;
++	uint32_t enctype;
++	uint32_t keysize;
++
++	if (!(buf->value = calloc(1, MAX_CTX_LEN)))
++		goto out_err;
++	p = buf->value;
++	end = buf->value + MAX_CTX_LEN;
++
++	/* Version 2 */
++	if (lctx->initiate)
++		v2_flags |= KRB5_CTX_FLAG_INITIATOR;
++	if (lctx->protocol != 0)
++		v2_flags |= KRB5_CTX_FLAG_CFX;
++	if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1)
++		v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
++
++	if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
++	if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
++	if (endtime)
++		*endtime = lctx->endtime;
++	if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
++
++	/* Protocol 0 here implies DES3 or RC4 */
++	printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol);
++	if (lctx->protocol == 0) {
++		enctype = lctx->rfc1964_kd.ctx_key.type;
++		keysize = lctx->rfc1964_kd.ctx_key.length;
++	} else {
++		if (lctx->cfx_kd.have_acceptor_subkey) {
++			enctype = lctx->cfx_kd.acceptor_subkey.type;
++			keysize = lctx->cfx_kd.acceptor_subkey.length;
++		} else {
++			enctype = lctx->cfx_kd.ctx_key.type;
++			keysize = lctx->cfx_kd.ctx_key.length;
++		}
++	}
++	printerr(2, "%s: serializing key with enctype %d and size %d\n",
++		 __FUNCTION__, enctype, keysize);
++
++	if (WRITE_BYTES(&p, end, enctype)) goto out_err;
++
++	if (lctx->protocol == 0) {
++		if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
++				lctx->rfc1964_kd.ctx_key.length))
++			goto out_err;
++	} else {
++		if (lctx->cfx_kd.have_acceptor_subkey) {
++			if (write_bytes(&p, end,
++					lctx->cfx_kd.acceptor_subkey.data,
++					lctx->cfx_kd.acceptor_subkey.length))
++				goto out_err;
++		} else {
++			if (write_bytes(&p, end, lctx->cfx_kd.ctx_key.data,
++					lctx->cfx_kd.ctx_key.length))
++				goto out_err;
++		}
++	}
++
++	buf->length = p - (char *)buf->value;
++	return 0;
++
++out_err:
++	printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n",
++		 __FUNCTION__);
++	if (buf->value) {
++		free(buf->value);
++		buf->value = NULL;
++	}
++	buf->length = 0;
+ 	return -1;
+ }
+ 
+@@ -176,7 +266,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
+ 	gss_krb5_lucid_context_v1_t *lctx = 0;
+ 	int retcode = 0;
+ 
+-	printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n");
++	printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__);
+ 	maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
+ 						1, &return_ctx);
+ 	if (maj_stat != GSS_S_COMPLETE) {
+@@ -198,11 +288,20 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
+ 		break;
+ 	}
+ 
+-	/* Now lctx points to a lucid context that we can send down to kernel */
+-	if (lctx->protocol == 0)
++	/*
++	 * Now lctx points to a lucid context that we can send down to kernel
++	 *
++	 * Note: we send down different information to the kernel depending
++	 * on the protocol version and the enctyption type.
++	 * For protocol version 0 with all enctypes besides DES3, we use
++	 * the original format.  For protocol version != 0 or DES3, we
++	 * send down the new style information.
++	 */
++
++	if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4)
+ 		retcode = prepare_krb5_rfc1964_buffer(lctx, buf, endtime);
+ 	else
+-		retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf, endtime);
++		retcode = prepare_krb5_rfc4121_buffer(lctx, buf, endtime);
+ 
+ 	maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx);
+ 	if (maj_stat != GSS_S_COMPLETE) {
+@@ -212,8 +311,8 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
+ 	}
+ 
+ 	if (retcode) {
+-		printerr(1, "serialize_krb5_ctx: prepare_krb5_*_buffer "
+-			 "failed (retcode = %d)\n", retcode);
++		printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n",
++			 __FUNCTION__, retcode);
+ 		goto out_err;
+ 	}
+ 
+@@ -223,4 +322,7 @@ out_err:
+ 	printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
+ 	return -1;
+ }
++
++
++
+ #endif /* HAVE_LUCID_CONTEXT_SUPPORT */
+diff -up nfs-utils-1.2.2/utils/gssd/context_mit.c.orig nfs-utils-1.2.2/utils/gssd/context_mit.c
+--- nfs-utils-1.2.2/utils/gssd/context_mit.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/context_mit.c	2010-09-09 11:02:27.250022000 -0400
+@@ -1,5 +1,5 @@
+ /*
+-  Copyright (c) 2004 The Regents of the University of Michigan.
++  Copyright (c) 2004-2006 The Regents of the University of Michigan.
+   All rights reserved.
+ 
+   Redistribution and use in source and binary forms, with or without
+@@ -38,6 +38,7 @@
+ #include <stdio.h>
+ #include <syslog.h>
+ #include <string.h>
++#include <errno.h>
+ #include <gssapi/gssapi.h>
+ #include <rpc/rpc.h>
+ #include <rpc/auth_gss.h>
+@@ -52,8 +53,7 @@
+ /* XXX argggg, there's gotta be a better way than just duplicating this
+  * whole struct.  Unfortunately, this is in a "private" header file,
+  * so this is our best choice at this point :-/
+- *
+- * XXX Does this match the Heimdal definition?  */
++ */
+ 
+ typedef struct _krb5_gss_ctx_id_rec {
+    unsigned int initiate : 1;   /* nonzero if initiating, zero if accepting */
+@@ -156,50 +156,122 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
+ {
+ 	krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)ctx)->internal_ctx_id;
+ 	char *p, *end;
+-	static int constant_one = 1;
+ 	static int constant_zero = 0;
++	static int constant_one = 1;
++	static int constant_two = 2;
+ 	uint32_t word_seq_send;
++	u_int64_t seq_send_64bit;
++	uint32_t v2_flags = 0;
+ 
+ 	if (!(buf->value = calloc(1, MAX_CTX_LEN)))
+ 		goto out_err;
+ 	p = buf->value;
+ 	end = buf->value + MAX_CTX_LEN;
+ 
+-	if (kctx->initiate) {
+-		if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
+-	}
+-	else {
+-		if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
+-	}
+-	if (kctx->seed_init) {
+-		if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
+-	}
+-	else {
+-		if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
+-	}
+-	if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
++	switch (kctx->enc->enctype) {
++	case ENCTYPE_DES_CBC_CRC:
++	case ENCTYPE_DES_CBC_MD4:
++	case ENCTYPE_DES_CBC_MD5:
++	case ENCTYPE_DES_CBC_RAW:
++		/* Old format of context to the kernel */
++		if (kctx->initiate) {
++			if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
++		}
++		else {
++			if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
++		}
++		if (kctx->seed_init) {
++			if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
++		}
++		else {
++			if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
++		}
++		if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
++			goto out_err;
++		if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
++		if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
++		if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
++		if (endtime)
++			*endtime = kctx->endtime;
++		word_seq_send = kctx->seq_send;
++		if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
++		if (write_oid(&p, end, kctx->mech_used)) goto out_err;
++
++		printerr(2, "serialize_krb5_ctx: serializing keys with "
++			 "enctype %d and length %d\n",
++			 kctx->enc->enctype, kctx->enc->length);
++
++		if (write_keyblock(&p, end, kctx->enc)) goto out_err;
++		if (write_keyblock(&p, end, kctx->seq)) goto out_err;
++		break;
++	case ENCTYPE_DES3_CBC_RAW:
++	case ENCTYPE_DES3_CBC_SHA1:
++	case ENCTYPE_ARCFOUR_HMAC:
++	case ENCTYPE_ARCFOUR_HMAC_EXP:
++	case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
++	case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
++		/* New format of context to the kernel */
++		/* u32 flags;
++		 * #define KRB5_CTX_FLAG_INITIATOR        0x00000001
++		 * #define KRB5_CTX_FLAG_CFX              0x00000002
++		 * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY  0x00000004
++		 * s32 endtime;
++		 * u64 seq_send;
++		 * u32  enctype;
++		 * rawkey data
++		 */
++
++		if (kctx->initiate)
++			v2_flags |= KRB5_CTX_FLAG_INITIATOR;
++		if (kctx->proto == 1)
++			v2_flags |= KRB5_CTX_FLAG_CFX;
++		if (kctx->have_acceptor_subkey)
++			v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
++		if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
++		if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
++
++		seq_send_64bit = kctx->seq_send;
++		if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err;
++
++		if (kctx->have_acceptor_subkey) {
++			if (WRITE_BYTES(&p, end, kctx->acceptor_subkey->enctype))
++				goto out_err;
++			printerr(2, "serialize_krb5_ctx: serializing subkey "
++				 "with enctype %d and size %d\n",
++				 kctx->acceptor_subkey->enctype,
++				 kctx->acceptor_subkey->length);
++
++			if (write_bytes(&p, end,
++					kctx->acceptor_subkey->contents,
++					kctx->acceptor_subkey->length))
++				goto out_err;
++		} else {
++			if (WRITE_BYTES(&p, end, kctx->enc->enctype))
++				goto out_err;
++			printerr(2, "serialize_krb5_ctx: serializing key "
++				 "with enctype %d and size %d\n",
++				 kctx->enc->enctype, kctx->enc->length);
++
++			if (write_bytes(&p, end, kctx->enc->contents,
++					kctx->enc->length))
++				goto out_err;
++		}
++		break;
++	default:
++		printerr(0, "ERROR: serialize_krb5_ctx: unsupported encryption "
++			 "algorithm %d\n", kctx->enc->enctype);
+ 		goto out_err;
+-	if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
+-	if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
+-	if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
+-	if (endtime)
+-		*endtime = kctx->endtime;
+-	word_seq_send = kctx->seq_send;
+-	if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
+-	if (write_oid(&p, end, kctx->mech_used)) goto out_err;
+-
+-	printerr(2, "serialize_krb5_ctx: serializing keys with "
+-		 "enctype %d and length %d\n",
+-		 kctx->enc->enctype, kctx->enc->length);
+-
+-	if (write_keyblock(&p, end, kctx->enc)) goto out_err;
+-	if (write_keyblock(&p, end, kctx->seq)) goto out_err;
++	}
+ 
+ 	buf->length = p - (char *)buf->value;
+ 	return 0;
++
+ out_err:
+ 	printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
+-	if (buf->value) free(buf->value);
++	if (buf->value) {
++		free(buf->value);
++	}
++	buf->value = NULL;
+ 	buf->length = 0;
+ 	return -1;
+ }
+diff -up nfs-utils-1.2.2/utils/gssd/gssd.c.orig nfs-utils-1.2.2/utils/gssd/gssd.c
+--- nfs-utils-1.2.2/utils/gssd/gssd.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/gssd.c	2010-09-09 11:02:27.255022000 -0400
+@@ -78,7 +78,7 @@ void
+ sig_hup(int signal)
+ {
+ 	/* don't exit on SIGHUP */
+-	printerr(1, "Received SIGHUP... Ignoring.\n");
++	printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal);
+ 	return;
+ }
+ 
+diff -up nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c.orig nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c
+--- nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/gssd_main_loop.c	2010-09-09 11:02:27.260025000 -0400
+@@ -63,6 +63,8 @@ static volatile int dir_changed = 1;
+ 
+ static void dir_notify_handler(int sig, siginfo_t *si, void *data)
+ {
++	printerr(2, "dir_notify_handler: sig %d si %p data %p\n", sig, si, data);
++
+ 	dir_changed = 1;
+ }
+ 
+diff -up nfs-utils-1.2.2/utils/gssd/gssd_proc.c.orig nfs-utils-1.2.2/utils/gssd/gssd_proc.c
+--- nfs-utils-1.2.2/utils/gssd/gssd_proc.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/gssd_proc.c	2010-09-09 11:02:27.266022000 -0400
+@@ -600,6 +600,67 @@ update_client_list(void)
+ 	return retval;
+ }
+ 
++/* Encryption types supported by the kernel rpcsec_gss code */
++int num_krb5_enctypes = 0;
++krb5_enctype *krb5_enctypes = NULL;
++
++/*
++ * Parse the supported encryption type information
++ */
++static int
++parse_enctypes(char *enctypes)
++{
++	int n = 0;
++	char *curr, *comma;
++	int i;
++	static char *cached_types;
++
++	if (cached_types && strcmp(cached_types, enctypes) == 0)
++		return 0;
++	free(cached_types);
++
++	if (krb5_enctypes != NULL) {
++		free(krb5_enctypes);
++		krb5_enctypes = NULL;
++		num_krb5_enctypes = 0;
++	}
++
++	/* count the number of commas */
++	for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
++		comma = strchr(curr, ',');
++		if (comma != NULL)
++			n++;
++		else
++			break;
++	}
++	/* If no more commas and we're not at the end, there's one more value */
++	if (*curr != '\0')
++		n++;
++
++	/* Empty string, return an error */
++	if (n == 0)
++		return ENOENT;
++
++	/* Allocate space for enctypes array */
++	if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
++		return ENOMEM;
++	}
++
++	/* Now parse each value into the array */
++	for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
++		krb5_enctypes[i++] = atoi(curr);
++		comma = strchr(curr, ',');
++		if (comma == NULL)
++			break;
++	}
++
++	num_krb5_enctypes = n;
++	if ((cached_types = malloc(strlen(enctypes)+1)))
++		strcpy(cached_types, enctypes);
++
++	return 0;
++}
++
+ static int
+ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
+ 	    gss_buffer_desc *context_token)
+@@ -798,7 +859,7 @@ int create_auth_rpc_client(struct clnt_i
+ 		 * Do this before creating rpc connection since we won't need
+ 		 * rpc connection if it fails!
+ 		 */
+-		if (limit_krb5_enctypes(&sec, uid)) {
++		if (limit_krb5_enctypes(&sec)) {
+ 			printerr(1, "WARNING: Failed while limiting krb5 "
+ 				    "encryption types for user with uid %d\n",
+ 				 uid);
+@@ -875,7 +936,7 @@ int create_auth_rpc_client(struct clnt_i
+ 	if (sec.cred != GSS_C_NO_CREDENTIAL)
+ 		gss_release_cred(&min_stat, &sec.cred);
+ 	/* Restore euid to original value */
+-	if ((save_uid != -1) && (setfsuid(save_uid) != uid)) {
++	if (((int)save_uid != -1) && (setfsuid(save_uid) != (int)uid)) {
+ 		printerr(0, "WARNING: Failed to restore fsuid"
+ 			    " to uid %d from %d\n", save_uid, uid);
+ 	}
+@@ -1100,7 +1161,7 @@ handle_krb5_upcall(struct clnt_info *clp
+ {
+ 	uid_t			uid;
+ 
+-	if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) {
++	if (read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
+ 		printerr(0, "WARNING: failed reading uid from krb5 "
+ 			    "upcall pipe: %s\n", strerror(errno));
+ 		return;
+@@ -1114,7 +1175,7 @@ handle_spkm3_upcall(struct clnt_info *cl
+ {
+ 	uid_t			uid;
+ 
+-	if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) {
++	if (read(clp->spkm3_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
+ 		printerr(0, "WARNING: failed reading uid from spkm3 "
+ 			 "upcall pipe: %s\n", strerror(errno));
+ 		return;
+@@ -1133,6 +1194,7 @@ handle_gssd_upcall(struct clnt_info *clp
+ 	char			*mech = NULL;
+ 	char			*target = NULL;
+ 	char			*service = NULL;
++	char			*enctypes = NULL;
+ 
+ 	printerr(1, "handling gssd upcall (%s)\n", clp->dirname);
+ 
+@@ -1176,6 +1238,23 @@ handle_gssd_upcall(struct clnt_info *clp
+ 		goto out;
+ 	}
+ 
++	/* read supported encryption types if supplied */
++	if ((p = strstr(lbuf, "enctypes=")) != NULL) {
++		enctypes = malloc(lbuflen);
++		if (!enctypes)
++			goto out;
++		if (sscanf(p, "enctypes=%s", enctypes) != 1) {
++			printerr(0, "WARNING: handle_gssd_upcall: "
++				    "failed to parse target name "
++				    "in upcall string '%s'\n", lbuf);
++			goto out;
++		}
++		if (parse_enctypes(enctypes) != 0) {
++			printerr(0, "WARNING: handle_gssd_upcall: "
++				"parsing encryption types failed: errno %d\n", errno);
++		}
++	}
++
+ 	/* read target name */
+ 	if ((p = strstr(lbuf, "target=")) != NULL) {
+ 		target = malloc(lbuflen);
+@@ -1222,6 +1301,7 @@ handle_gssd_upcall(struct clnt_info *clp
+ out:
+ 	free(lbuf);
+ 	free(mech);
++	free(enctypes);
+ 	free(target);
+ 	free(service);
+ 	return;	
+diff -up nfs-utils-1.2.2/utils/gssd/krb5_util.c.orig nfs-utils-1.2.2/utils/gssd/krb5_util.c
+--- nfs-utils-1.2.2/utils/gssd/krb5_util.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/krb5_util.c	2010-09-09 11:02:27.272022000 -0400
+@@ -224,6 +224,13 @@ gssd_find_existing_krb5_ccache(uid_t uid
+ 				free(namelist[i]);
+ 				continue;
+ 			}
++			if (uid == 0 && !root_uses_machine_creds && 
++				strstr(namelist[i]->d_name, "_machine_")) {
++				printerr(3, "CC file '%s' not available to root\n",
++					 statname);
++				free(namelist[i]);
++				continue;
++			}
+ 			if (!query_krb5_ccache(buf, &princname, &realm)) {
+ 				printerr(3, "CC file '%s' is expired or corrupt\n",
+ 					 statname);
+@@ -292,61 +299,6 @@ gssd_find_existing_krb5_ccache(uid_t uid
+ 	return err;
+ }
+ 
+-
+-#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
+-/*
+- * this routine obtains a credentials handle via gss_acquire_cred()
+- * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
+- * types negotiated.
+- *
+- * XXX Should call some function to determine the enctypes supported
+- * by the kernel. (Only need to do that once!)
+- *
+- * Returns:
+- *	0 => all went well
+- *     -1 => there was an error
+- */
+-
+-int
+-limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
+-{
+-	u_int maj_stat, min_stat;
+-	gss_cred_id_t credh;
+-	gss_OID_set_desc  desired_mechs;
+-	krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
+-				    ENCTYPE_DES_CBC_MD5,
+-				    ENCTYPE_DES_CBC_MD4 };
+-	int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
+-
+-	/* We only care about getting a krb5 cred */
+-	desired_mechs.count = 1;
+-	desired_mechs.elements = &krb5oid;
+-
+-	maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
+-				    &desired_mechs, GSS_C_INITIATE,
+-				    &credh, NULL, NULL);
+-
+-	if (maj_stat != GSS_S_COMPLETE) {
+-		if (get_verbosity() > 0)
+-			pgsserr("gss_acquire_cred",
+-				maj_stat, min_stat, &krb5oid);
+-		return -1;
+-	}
+-
+-	maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid,
+-					     num_enctypes, &enctypes);
+-	if (maj_stat != GSS_S_COMPLETE) {
+-		pgsserr("gss_set_allowable_enctypes",
+-			maj_stat, min_stat, &krb5oid);
+-		gss_release_cred(&min_stat, &credh);
+-		return -1;
+-	}
+-	sec->cred = credh;
+-
+-	return 0;
+-}
+-#endif	/* HAVE_SET_ALLOWABLE_ENCTYPES */
+-
+ /*
+  * Obtain credentials via a key in the keytab given
+  * a keytab handle and a gssd_k5_kt_princ structure.
+@@ -661,24 +613,32 @@ out:
+  * and has *any* instance (hostname), return 1.
+  * Otherwise return 0, indicating no match.
+  */
++#ifdef HAVE_KRB5
+ static int
+-realm_and_service_match(krb5_context context, krb5_principal p,
+-			const char *realm, const char *service)
++realm_and_service_match(krb5_principal p, const char *realm, const char *service)
+ {
+-#ifdef HAVE_KRB5
+ 	/* Must have two components */
+ 	if (p->length != 2)
+ 		return 0;
++
+ 	if ((strlen(realm) == p->realm.length)
+ 	    && (strncmp(realm, p->realm.data, p->realm.length) == 0)
+ 	    && (strlen(service) == p->data[0].length)
+ 	    && (strncmp(service, p->data[0].data, p->data[0].length) == 0))
+ 		return 1;
++
++	return 0;
++}
+ #else
++static int
++realm_and_service_match(krb5_context context, krb5_principal p,
++			const char *realm, const char *service)
++{
+ 	const char *name, *inst;
+ 
+ 	if (p->name.name_string.len != 2)
+ 		return 0;
++
+ 	name = krb5_principal_get_comp_string(context, p, 0);
+ 	inst = krb5_principal_get_comp_string(context, p, 1);
+ 	if (name == NULL || inst == NULL)
+@@ -686,9 +646,10 @@ realm_and_service_match(krb5_context con
+ 	if ((strcmp(realm, p->realm) == 0)
+ 	    && (strcmp(service, name) == 0))
+ 		return 1;
+-#endif
++
+ 	return 0;
+ }
++#endif
+ 
+ /*
+  * Search the given keytab file looking for an entry with the given
+@@ -710,7 +671,7 @@ gssd_search_krb5_keytab(krb5_context con
+ 	krb5_kt_cursor cursor;
+ 	krb5_error_code code;
+ 	struct gssd_k5_kt_princ *ple;
+-	int retval = -1;
++	int retval = -1, status;
+ 	char kt_name[BUFSIZ];
+ 	char *pname;
+ 	char *k5err = NULL;
+@@ -753,8 +714,12 @@ gssd_search_krb5_keytab(krb5_context con
+ 		printerr(4, "Processing keytab entry for principal '%s'\n",
+ 			 pname);
+ 		/* Use the first matching keytab entry found */
+-	        if ((realm_and_service_match(context, kte->principal, realm,
+-					     service))) {
++#ifdef HAVE_KRB5
++		status = realm_and_service_match(kte->principal, realm, service);
++#else
++		status = realm_and_service_match(context, kte->principal, realm, service);
++#endif
++		if (status) {
+ 			printerr(4, "We WILL use this entry (%s)\n", pname);
+ 			ple = get_ple_by_princ(context, kte->principal);
+ 			/*
+@@ -1304,3 +1269,68 @@ gssd_k5_get_default_realm(char **def_rea
+ 
+ 	krb5_free_context(context);
+ }
++
++#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
++/*
++ * this routine obtains a credentials handle via gss_acquire_cred()
++ * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
++ * types negotiated.
++ *
++ * XXX Should call some function to determine the enctypes supported
++ * by the kernel. (Only need to do that once!)
++ *
++ * Returns:
++ *	0 => all went well
++ *     -1 => there was an error
++ */
++
++int
++limit_krb5_enctypes(struct rpc_gss_sec *sec)
++{
++	u_int maj_stat, min_stat;
++	gss_cred_id_t credh;
++	gss_OID_set_desc  desired_mechs;
++	krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
++				    ENCTYPE_DES_CBC_MD5,
++				    ENCTYPE_DES_CBC_MD4 };
++	int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
++	extern int num_krb5_enctypes;
++	extern krb5_enctype *krb5_enctypes;
++
++	/* We only care about getting a krb5 cred */
++	desired_mechs.count = 1;
++	desired_mechs.elements = &krb5oid;
++
++	maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
++				    &desired_mechs, GSS_C_INITIATE,
++				    &credh, NULL, NULL);
++
++	if (maj_stat != GSS_S_COMPLETE) {
++		if (get_verbosity() > 0)
++			pgsserr("gss_acquire_cred",
++				maj_stat, min_stat, &krb5oid);
++		return -1;
++	}
++
++	/*
++	 * If we failed for any reason to produce global
++	 * list of supported enctypes, use local default here.
++	 */
++	if (krb5_enctypes == NULL)
++		maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
++					&krb5oid, num_enctypes, enctypes);
++	else
++		maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
++					&krb5oid, num_krb5_enctypes, krb5_enctypes);
++
++	if (maj_stat != GSS_S_COMPLETE) {
++		pgsserr("gss_set_allowable_enctypes",
++			maj_stat, min_stat, &krb5oid);
++		gss_release_cred(&min_stat, &credh);
++		return -1;
++	}
++	sec->cred = credh;
++
++	return 0;
++}
++#endif	/* HAVE_SET_ALLOWABLE_ENCTYPES */
+diff -up nfs-utils-1.2.2/utils/gssd/krb5_util.h.orig nfs-utils-1.2.2/utils/gssd/krb5_util.h
+--- nfs-utils-1.2.2/utils/gssd/krb5_util.h.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/krb5_util.h	2010-09-09 11:02:27.277030000 -0400
+@@ -36,7 +36,7 @@ char *gssd_k5_err_msg(krb5_context conte
+ void gssd_k5_get_default_realm(char **def_realm);
+ 
+ #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
+-int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid);
++int limit_krb5_enctypes(struct rpc_gss_sec *sec);
+ #endif
+ 
+ /*
+diff -up nfs-utils-1.2.2/utils/gssd/svcgssd.c.orig nfs-utils-1.2.2/utils/gssd/svcgssd.c
+--- nfs-utils-1.2.2/utils/gssd/svcgssd.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/svcgssd.c	2010-09-09 11:02:27.282029000 -0400
+@@ -160,7 +160,7 @@ void
+ sig_hup(int signal)
+ {
+ 	/* don't exit on SIGHUP */
+-	printerr(1, "Received SIGHUP... Ignoring.\n");
++	printerr(1, "Received SIGHUP(%d)... Ignoring.\n", signal);
+ 	return;
+ }
+ 
+diff -up nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c.orig nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c
+--- nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/gssd/svcgssd_proc.c	2010-09-09 11:02:27.288022000 -0400
+@@ -132,7 +132,7 @@ struct gss_verifier {
+ #define RPCSEC_GSS_SEQ_WIN	5
+ 
+ static int
+-send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
++send_response(gss_buffer_desc *in_handle, gss_buffer_desc *in_token,
+ 	      u_int32_t maj_stat, u_int32_t min_stat,
+ 	      gss_buffer_desc *out_handle, gss_buffer_desc *out_token)
+ {
+@@ -431,12 +431,6 @@ handle_nullreq(FILE *f) {
+ 	print_hexl("in_tok", in_tok.value, in_tok.length);
+ #endif
+ 
+-	if (in_tok.length < 0) {
+-		printerr(0, "WARNING: handle_nullreq: "
+-			    "failed parsing request\n");
+-		goto out_err;
+-	}
+-
+ 	if (in_handle.length != 0) { /* CONTINUE_INIT case */
+ 		if (in_handle.length != sizeof(ctx)) {
+ 			printerr(0, "WARNING: handle_nullreq: "
+@@ -498,7 +492,7 @@ handle_nullreq(FILE *f) {
+ 	do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime,
+ 			hostbased_name);
+ continue_needed:
+-	send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
++	send_response(&in_handle, &in_tok, maj_stat, min_stat,
+ 			&out_handle, &out_tok);
+ out:
+ 	if (ctx_token.value != NULL)
+@@ -514,7 +508,7 @@ out:
+ out_err:
+ 	if (ctx != GSS_C_NO_CONTEXT)
+ 		gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
+-	send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
++	send_response(&in_handle, &in_tok, maj_stat, min_stat,
+ 			&null_token, &null_token);
+ 	goto out;
+ }
+diff -up nfs-utils-1.2.2/utils/idmapd/atomicio.c.orig nfs-utils-1.2.2/utils/idmapd/atomicio.c
+--- nfs-utils-1.2.2/utils/idmapd/atomicio.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/idmapd/atomicio.c	2010-09-09 11:02:27.311022000 -0400
+@@ -43,7 +43,8 @@ atomicio(
+ 	size_t n)
+ {
+ 	char *s = _s;
+-	ssize_t res, pos = 0;
++	ssize_t res;
++	size_t pos = 0;
+ 
+ 	while (n > pos) {
+ 		res = (f) (fd, s + pos, n - pos);
+diff -up nfs-utils-1.2.2/utils/idmapd/idmapd.c.orig nfs-utils-1.2.2/utils/idmapd/idmapd.c
+--- nfs-utils-1.2.2/utils/idmapd/idmapd.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/idmapd/idmapd.c	2010-09-09 11:02:27.316022000 -0400
+@@ -117,8 +117,24 @@ struct idmap_client {
+ 	TAILQ_ENTRY(idmap_client)  ic_next;
+ };
+ static struct idmap_client nfsd_ic[2] = {
+-{IC_IDNAME, "Server", "", IC_IDNAME_CHAN, -1, -1, 0},
+-{IC_NAMEID, "Server", "", IC_NAMEID_CHAN, -1, -1, 0},
++{
++	.ic_which = IC_IDNAME, 
++	.ic_clid = "Server", 
++	.ic_id = "", 
++	.ic_path = IC_IDNAME_CHAN, 
++	.ic_fd = -1, 
++	.ic_dirfd = -1, 
++	.ic_scanned = 0
++},
++{
++	.ic_which = IC_NAMEID, 
++	.ic_clid = "Server", 
++	.ic_id = "", 
++	.ic_path = IC_NAMEID_CHAN, 
++	.ic_fd = -1, 
++	.ic_dirfd = -1, 
++	.ic_scanned = 0
++},
+ };
+ 
+ TAILQ_HEAD(idmap_clientq, idmap_client);
+@@ -170,7 +186,7 @@ flush_nfsd_cache(char *path, time_t now)
+ 	fd = open(path, O_RDWR);
+ 	if (fd == -1)
+ 		return -1;
+-	if (write(fd, stime, strlen(stime)) != strlen(stime)) {
++	if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) {
+ 		errx(1, "Flushing nfsd cache failed: errno %d (%s)",
+ 			errno, strerror(errno));
+ 	}
+@@ -381,7 +397,7 @@ main(int argc, char **argv)
+ }
+ 
+ static void
+-dirscancb(int fd, short which, void *data)
++dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
+ {
+ 	int nent, i;
+ 	struct dirent **ents;
+@@ -465,13 +481,13 @@ out:
+ }
+ 
+ static void
+-svrreopen(int fd, short which, void *data)
++svrreopen(int UNUSED(fd), short UNUSED(which), void *UNUSED(data))
+ {
+ 	nfsdreopen();
+ }
+ 
+ static void
+-clntscancb(int fd, short which, void *data)
++clntscancb(int UNUSED(fd), short UNUSED(which), void *data)
+ {
+ 	struct idmap_clientq *icq = data;
+ 	struct idmap_client *ic;
+@@ -485,7 +501,7 @@ clntscancb(int fd, short which, void *da
+ }
+ 
+ static void
+-nfsdcb(int fd, short which, void *data)
++nfsdcb(int UNUSED(fd), short which, void *data)
+ {
+ 	struct idmap_client *ic = data;
+ 	struct idmap_msg im;
+@@ -660,7 +676,7 @@ imconv(struct idmap_client *ic, struct i
+ }
+ 
+ static void
+-nfscb(int fd, short which, void *data)
++nfscb(int UNUSED(fd), short which, void *data)
+ {
+ 	struct idmap_client *ic = data;
+ 	struct idmap_msg im;
+@@ -845,7 +861,7 @@ nametoidres(struct idmap_msg *im)
+ static int
+ validateascii(char *string, u_int32_t len)
+ {
+-	int i;
++	u_int32_t i;
+ 
+ 	for (i = 0; i < len; i++) {
+ 		if (string[i] == '\0')
+@@ -901,7 +917,7 @@ static int
+ getfield(char **bpp, char *fld, size_t fldsz)
+ {
+ 	char *bp;
+-	u_int val, n;
++	int val, n;
+ 
+ 	while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0')
+ 		;
+diff -up nfs-utils-1.2.2/utils/mount/configfile.c.orig nfs-utils-1.2.2/utils/mount/configfile.c
+--- nfs-utils-1.2.2/utils/mount/configfile.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mount/configfile.c	2010-09-09 11:02:27.321025000 -0400
+@@ -192,7 +192,8 @@ void free_all(void)
+ 	}
+ }
+ static char *versions[] = {"v2", "v3", "v4", "vers", "nfsvers", NULL};
+-int inline check_vers(char *mopt, char *field)
++static int 
++check_vers(char *mopt, char *field)
+ {
+ 	int i, found=0;
+ 
+@@ -229,7 +230,8 @@ extern sa_family_t config_default_family
+  * If so, set the appropriate global value which will 
+  * be used as the initial value in the server negation.
+  */
+-int inline default_value(char *mopt)
++static int 
++default_value(char *mopt)
+ {
+ 	struct mount_options *options = NULL;
+ 	int dftlen = strlen("default");
+diff -up nfs-utils-1.2.2/utils/mountd/auth.c.orig nfs-utils-1.2.2/utils/mountd/auth.c
+--- nfs-utils-1.2.2/utils/mountd/auth.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mountd/auth.c	2010-09-09 11:02:27.375018000 -0400
+@@ -110,13 +110,15 @@ auth_reload()
+ 	return counter;
+ }
+ 
+-static char *get_client_hostname(struct sockaddr_in *caller, struct hostent *hp, enum auth_error *error)
++static char *
++get_client_hostname(struct sockaddr_in *caller, struct addrinfo *ai,
++		enum auth_error *error)
+ {
+ 	char *n;
+ 
+ 	if (use_ipaddr)
+ 		return strdup(inet_ntoa(caller->sin_addr));
+-	n = client_compose(hp);
++	n = client_compose(ai);
+ 	*error = unknown_host;
+ 	if (!n)
+ 		return NULL;
+@@ -128,8 +130,8 @@ static char *get_client_hostname(struct 
+ 
+ /* return static nfs_export with details filled in */
+ static nfs_export *
+-auth_authenticate_newcache(char *what, struct sockaddr_in *caller,
+-			   char *path, struct hostent *hp,
++auth_authenticate_newcache(struct sockaddr_in *caller,
++			   char *path, struct addrinfo *ai,
+ 			   enum auth_error *error)
+ {
+ 	nfs_export *exp;
+@@ -137,12 +139,12 @@ auth_authenticate_newcache(char *what, s
+ 
+ 	free(my_client.m_hostname);
+ 
+-	my_client.m_hostname = get_client_hostname(caller, hp, error);
++	my_client.m_hostname = get_client_hostname(caller, ai, error);
+ 	if (my_client.m_hostname == NULL)
+ 		return NULL;
+ 
+ 	my_client.m_naddr = 1;
+-	my_client.m_addrlist[0] = caller->sin_addr;
++	set_addrlist_in(&my_client, 0, caller);
+ 	my_exp.m_client = &my_client;
+ 
+ 	exp = NULL;
+@@ -152,7 +154,7 @@ auth_authenticate_newcache(char *what, s
+ 				continue;
+ 			if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
+ 				continue;
+-			if (use_ipaddr && !client_check(exp->m_client, hp))
++			if (use_ipaddr && !client_check(exp->m_client, ai))
+ 				continue;
+ 			break;
+ 		}
+@@ -166,18 +168,19 @@ auth_authenticate_newcache(char *what, s
+ }
+ 
+ static nfs_export *
+-auth_authenticate_internal(char *what, struct sockaddr_in *caller,
+-			   char *path, struct hostent *hp,
++auth_authenticate_internal(struct sockaddr_in *caller,
++			   char *path, struct addrinfo *ai,
+ 			   enum auth_error *error)
+ {
+ 	nfs_export *exp;
+ 
+ 	if (new_cache) {
+-		exp = auth_authenticate_newcache(what, caller, path, hp, error);
++		exp = auth_authenticate_newcache(caller, path, ai, error);
+ 		if (!exp)
+ 			return NULL;
+ 	} else {
+-		if (!(exp = export_find(hp, path))) {
++		exp = export_find(ai, path);
++		if (exp == NULL) {
+ 			*error = no_entry;
+ 			return NULL;
+ 		}
+@@ -202,7 +205,7 @@ auth_authenticate(char *what, struct soc
+ 	nfs_export	*exp = NULL;
+ 	char		epath[MAXPATHLEN+1];
+ 	char		*p = NULL;
+-	struct hostent	*hp = NULL;
++	struct addrinfo *ai = NULL;
+ 	struct in_addr	addr = caller->sin_addr;
+ 	enum auth_error	error = bad_path;
+ 
+@@ -216,14 +219,14 @@ auth_authenticate(char *what, struct soc
+ 	epath[sizeof (epath) - 1] = '\0';
+ 	auth_fixpath(epath); /* strip duplicate '/' etc */
+ 
+-	hp = client_resolve(caller->sin_addr);
+-	if (!hp)
++	ai = client_resolve((struct sockaddr *)caller);
++	if (ai == NULL)
+ 		return exp;
+ 
+ 	/* Try the longest matching exported pathname. */
+ 	while (1) {
+-		exp = auth_authenticate_internal(what, caller, epath,
+-						 hp, &error);
++		exp = auth_authenticate_internal(caller, epath,
++						 ai, &error);
+ 		if (exp || (error != not_exported && error != no_entry))
+ 			break;
+ 		/* We have to treat the root, "/", specially. */
+@@ -246,31 +249,30 @@ auth_authenticate(char *what, struct soc
+ 
+ 	case no_entry:
+ 		xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry",
+-		     what, hp->h_name, path, epath);
++		     what, ai->ai_canonname, path, epath);
+ 		break;
+ 
+ 	case not_exported:
+ 		xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported",
+-		     what, hp->h_name, path, epath);
++		     what, ai->ai_canonname, path, epath);
+ 		break;
+ 
+ 	case illegal_port:
+ 		xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %d",
+-		     what, hp->h_name, path, epath, ntohs(caller->sin_port));
++		     what, ai->ai_canonname, path, epath, ntohs(caller->sin_port));
+ 		break;
+ 
+ 	case success:
+ 		xlog(L_NOTICE, "authenticated %s request from %s:%d for %s (%s)",
+-		     what, hp->h_name, ntohs(caller->sin_port), path, epath);
++		     what, ai->ai_canonname, ntohs(caller->sin_port), path, epath);
+ 		break;
+ 	default:
+ 		xlog(L_NOTICE, "%s request from %s:%d for %s (%s) gave %d",
+-		     what, hp->h_name, ntohs(caller->sin_port), path, epath, error);
++		     what, ai->ai_canonname, ntohs(caller->sin_port),
++			path, epath, error);
+ 	}
+ 
+-	if (hp)
+-		free (hp);
+-
++	freeaddrinfo(ai);
+ 	return exp;
+ }
+ 
+diff -up nfs-utils-1.2.2/utils/mountd/cache.c.orig nfs-utils-1.2.2/utils/mountd/cache.c
+--- nfs-utils-1.2.2/utils/mountd/cache.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mountd/cache.c	2010-09-09 11:02:27.380016000 -0400
+@@ -77,8 +77,8 @@ void auth_unix_ip(FILE *f)
+ 	char class[20];
+ 	char ipaddr[20];
+ 	char *client = NULL;
+-	struct in_addr addr;
+-	struct hostent *he = NULL;
++	struct addrinfo *tmp = NULL;
++	struct addrinfo *ai = NULL;
+ 	if (readline(fileno(f), &lbuf, &lbuflen) != 1)
+ 		return;
+ 
+@@ -93,17 +93,20 @@ void auth_unix_ip(FILE *f)
+ 	if (qword_get(&cp, ipaddr, 20) <= 0)
+ 		return;
+ 
+-	if (inet_aton(ipaddr, &addr)==0)
++	tmp = host_pton(ipaddr);
++	if (tmp == NULL)
+ 		return;
+ 
+ 	auth_reload();
+ 
+ 	/* addr is a valid, interesting address, find the domain name... */
+ 	if (!use_ipaddr) {
+-		he = client_resolve(addr);
+-		client = client_compose(he);
++		ai = client_resolve(tmp->ai_addr);
++		client = client_compose(ai);
++		freeaddrinfo(ai);
+ 	}
+-	
++	freeaddrinfo(tmp);
++
+ 	qword_print(f, "nfsd");
+ 	qword_print(f, ipaddr);
+ 	qword_printint(f, time(0)+30*60);
+@@ -114,8 +117,7 @@ void auth_unix_ip(FILE *f)
+ 	qword_eol(f);
+ 	xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT");
+ 
+-	if (client) free(client);
+-	free(he);
++	free(client);
+ }
+ 
+ void auth_unix_gid(FILE *f)
+@@ -125,7 +127,7 @@ void auth_unix_gid(FILE *f)
+ 	 * reply is
+ 	 *  uid expiry count list of group ids
+ 	 */
+-	int uid;
++	uid_t uid;
+ 	struct passwd *pw;
+ 	gid_t glist[100], *groups = glist;
+ 	int ngroups = 100;
+@@ -136,7 +138,7 @@ void auth_unix_gid(FILE *f)
+ 		return;
+ 
+ 	cp = lbuf;
+-	if (qword_get_int(&cp, &uid) != 0)
++	if (qword_get_uint(&cp, &uid) != 0)
+ 		return;
+ 
+ 	pw = getpwuid(uid);
+@@ -153,14 +155,14 @@ void auth_unix_gid(FILE *f)
+ 						  groups, &ngroups);
+ 		}
+ 	}
+-	qword_printint(f, uid);
+-	qword_printint(f, time(0)+30*60);
++	qword_printuint(f, uid);
++	qword_printuint(f, time(0)+30*60);
+ 	if (rv >= 0) {
+-		qword_printint(f, ngroups);
++		qword_printuint(f, ngroups);
+ 		for (i=0; i<ngroups; i++)
+-			qword_printint(f, groups[i]);
++			qword_printuint(f, groups[i]);
+ 	} else
+-		qword_printint(f, 0);
++		qword_printuint(f, 0);
+ 	qword_eol(f);
+ 
+ 	if (groups != glist)
+@@ -170,13 +172,16 @@ void auth_unix_gid(FILE *f)
+ #if USE_BLKID
+ static const char *get_uuid_blkdev(char *path)
+ {
++	/* We set *safe if we know that we need the
++	 * fsid from statfs too.
++	 */
+ 	static blkid_cache cache = NULL;
+ 	struct stat stb;
+ 	char *devname;
+ 	blkid_tag_iterate iter;
+ 	blkid_dev dev;
+ 	const char *type;
+-	const char *val = NULL;
++	const char *val, *uuid = NULL;
+ 
+ 	if (cache == NULL)
+ 		blkid_get_cache(&cache, NULL);
+@@ -193,42 +198,29 @@ static const char *get_uuid_blkdev(char 
+ 	iter = blkid_tag_iterate_begin(dev);
+ 	if (!iter)
+ 		return NULL;
+-	while (blkid_tag_next(iter, &type, &val) == 0)
++	while (blkid_tag_next(iter, &type, &val) == 0) {
+ 		if (strcmp(type, "UUID") == 0)
++			uuid = val;
++		if (strcmp(type, "TYPE") == 0 &&
++		    strcmp(val, "btrfs") == 0) {
++			uuid = NULL;
+ 			break;
++		}
++	}
+ 	blkid_tag_iterate_end(iter);
+-	return val;
++	return uuid;
+ }
+ #else
+ #define get_uuid_blkdev(path) (NULL)
+ #endif
+ 
+-int get_uuid(char *path, char *uuid, int uuidlen, char *u)
++int get_uuid(const char *val, int uuidlen, char *u)
+ {
+ 	/* extract hex digits from uuidstr and compose a uuid
+ 	 * of the given length (max 16), xoring bytes to make
+-	 * a smaller uuid.  Then compare with uuid
++	 * a smaller uuid.
+ 	 */
+ 	int i = 0;
+-	const char *val = NULL;
+-	char fsid_val[17];
+-
+-	if (path) {
+-		val = get_uuid_blkdev(path);
+-		if (!val) {
+-			struct statfs64 st;
+-
+-			if (statfs64(path, &st))
+-				return 0;
+-			if (!st.f_fsid.__val[0] && !st.f_fsid.__val[1])
+-				return 0;
+-			snprintf(fsid_val, 17, "%08x%08x",
+-				 st.f_fsid.__val[0], st.f_fsid.__val[1]);
+-			val = fsid_val;
+-		}
+-	} else {
+-		val = uuid;
+-	}
+ 	
+ 	memset(u, 0, uuidlen);
+ 	for ( ; *val ; val++) {
+@@ -252,6 +244,60 @@ int get_uuid(char *path, char *uuid, int
+ 	return 1;
+ }
+ 
++int uuid_by_path(char *path, int type, int uuidlen, char *uuid)
++{
++	/* get a uuid for the filesystem found at 'path'.
++	 * There are several possible ways of generating the
++	 * uuids (types).
++	 * Type 0 is used for new filehandles, while other types
++	 * may be used to interpret old filehandle - to ensure smooth
++	 * forward migration.
++	 * We return 1 if a uuid was found (and it might be worth 
++	 * trying the next type) or 0 if no more uuid types can be
++	 * extracted.
++	 */
++
++	/* Possible sources of uuid are
++	 * - blkid uuid
++	 * - statfs64 uuid
++	 *
++	 * On some filesystems (e.g. vfat) the statfs64 uuid is simply an
++	 * encoding of the device that the filesystem is mounted from, so
++	 * it we be very bad to use that (as device numbers change).  blkid
++	 * must be preferred.
++	 * On other filesystems (e.g. btrfs) the statfs64 uuid contains
++	 * important info that the blkid uuid cannot contain:  This happens
++	 * when multiple subvolumes are exported (they have the same
++	 * blkid uuid but different statfs64 uuids).
++	 * We rely on get_uuid_blkdev *knowing* which is which and not returning
++	 * a uuid for filesystems where the statfs64 uuid is better.
++	 *
++	 */
++	struct statfs64 st;
++	char fsid_val[17];
++	const char *blkid_val;
++	const char *val;
++
++	blkid_val = get_uuid_blkdev(path);
++
++	if (statfs64(path, &st) == 0 &&
++	    (st.f_fsid.__val[0] || st.f_fsid.__val[1]))
++		snprintf(fsid_val, 17, "%08x%08x",
++			 st.f_fsid.__val[0], st.f_fsid.__val[1]);
++	else
++		fsid_val[0] = 0;
++
++	if (blkid_val && (type--) == 0)
++		val = blkid_val;
++	else if (fsid_val[0] && (type--) == 0)
++		val = fsid_val;
++	else
++		return 0;
++
++	get_uuid(val, uuidlen, uuid);
++	return 1;
++}
++
+ /* Iterate through /etc/mtab, finding mountpoints
+  * at or below a given path
+  */
+@@ -294,8 +340,7 @@ void nfsd_fh(FILE *f)
+ 	unsigned int fsidnum=0;
+ 	char fsid[32];
+ 	struct exportent *found = NULL;
+-	struct hostent *he = NULL;
+-	struct in_addr addr;
++	struct addrinfo *ai = NULL;
+ 	char *found_path = NULL;
+ 	nfs_export *exp;
+ 	int i;
+@@ -398,6 +443,7 @@ void nfsd_fh(FILE *f)
+ 			struct stat stb;
+ 			char u[16];
+ 			char *path;
++			int type;
+ 
+ 			if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
+ 				static nfs_export *prev = NULL;
+@@ -461,22 +507,29 @@ void nfsd_fh(FILE *f)
+ 					continue;
+ 			check_uuid:
+ 				if (exp->m_export.e_uuid)
+-					get_uuid(NULL, exp->m_export.e_uuid,
++					get_uuid(exp->m_export.e_uuid,
+ 						 uuidlen, u);
+-				else if (get_uuid(path, NULL, uuidlen, u) == 0)
+-					continue;
++				else
++					for (type = 0;
++					     uuid_by_path(path, type, uuidlen, u);
++					     type++)
++						if (memcmp(u, fhuuid, uuidlen) == 0)
++							break;
+ 
+ 				if (memcmp(u, fhuuid, uuidlen) != 0)
+ 					continue;
+ 				break;
+ 			}
+ 			if (use_ipaddr) {
+-				if (he == NULL) {
+-					if (!inet_aton(dom, &addr))
++				if (ai == NULL) {
++					struct addrinfo *tmp;
++					tmp = host_pton(dom);
++					if (tmp == NULL)
+ 						goto out;
+-					he = client_resolve(addr);
++					ai = client_resolve(tmp->ai_addr);
++					freeaddrinfo(tmp);
+ 				}
+-				if (!client_check(exp->m_client, he))
++				if (!client_check(exp->m_client, ai))
+ 					continue;
+ 			}
+ 			/* It's a match !! */
+@@ -534,21 +587,20 @@ void nfsd_fh(FILE *f)
+  out:
+ 	if (found_path)
+ 		free(found_path);
+-	if (he)
+-		free(he);
++	freeaddrinfo(ai);
+ 	free(dom);
+ 	xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL);
+ 	return;		
+ }
+ 
+-static void write_fsloc(FILE *f, struct exportent *ep, char *path)
++static void write_fsloc(FILE *f, struct exportent *ep)
+ {
+ 	struct servers *servers;
+ 
+ 	if (ep->e_fslocmethod == FSLOC_NONE)
+ 		return;
+ 
+-	servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata, path);
++	servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata);
+ 	if (!servers)
+ 		return;
+ 	qword_print(f, "fsloc");
+@@ -596,17 +648,17 @@ static int dump_to_cache(FILE *f, char *
+ 		qword_printint(f, exp->e_anonuid);
+ 		qword_printint(f, exp->e_anongid);
+ 		qword_printint(f, exp->e_fsid);
+-		write_fsloc(f, exp, path);
++		write_fsloc(f, exp);
+ 		write_secinfo(f, exp, flag_mask);
+  		if (exp->e_uuid == NULL || different_fs) {
+  			char u[16];
+- 			if (get_uuid(path, NULL, 16, u)) {
++ 			if (uuid_by_path(path, 0, 16, u)) {
+  				qword_print(f, "uuid");
+  				qword_printhex(f, u, 16);
+  			}
+  		} else {
+  			char u[16];
+- 			get_uuid(NULL, exp->e_uuid, 16, u);
++ 			get_uuid(exp->e_uuid, 16, u);
+  			qword_print(f, "uuid");
+  			qword_printhex(f, u, 16);
+  		}
+@@ -614,12 +666,12 @@ static int dump_to_cache(FILE *f, char *
+ 	return qword_eol(f);
+ }
+ 
+-static int is_subdirectory(char *subpath, char *path)
++static int is_subdirectory(char *child, char *parent)
+ {
+-	int l = strlen(path);
++	int l = strlen(parent);
+ 
+-	return strcmp(subpath, path) == 0
+-		|| (strncmp(subpath, path, l) == 0 && path[l] == '/');
++	return strcmp(child, parent) == 0
++		|| (strncmp(child, parent, l) == 0 && child[l] == '/');
+ }
+ 
+ static int path_matches(nfs_export *exp, char *path)
+@@ -629,19 +681,22 @@ static int path_matches(nfs_export *exp,
+ 	return strcmp(path, exp->m_export.e_path) == 0;
+ }
+ 
+-static int client_matches(nfs_export *exp, char *dom, struct hostent *he)
++static int
++client_matches(nfs_export *exp, char *dom, struct addrinfo *ai)
+ {
+ 	if (use_ipaddr)
+-		return client_check(exp->m_client, he);
++		return client_check(exp->m_client, ai);
+ 	return client_member(dom, exp->m_client->m_hostname);
+ }
+ 
+-static int export_matches(nfs_export *exp, char *dom, char *path, struct hostent *he)
++static int
++export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai)
+ {
+-	return path_matches(exp, path) && client_matches(exp, dom, he);
++	return path_matches(exp, path) && client_matches(exp, dom, ai);
+ }
+ 
+-static nfs_export *lookup_export(char *dom, char *path, struct hostent *he)
++static nfs_export *
++lookup_export(char *dom, char *path, struct addrinfo *ai)
+ {
+ 	nfs_export *exp;
+ 	nfs_export *found = NULL;
+@@ -650,7 +705,7 @@ static nfs_export *lookup_export(char *d
+ 
+ 	for (i=0 ; i < MCL_MAXTYPES; i++) {
+ 		for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
+-			if (!export_matches(exp, dom, path, he))
++			if (!export_matches(exp, dom, path, ai))
+ 				continue;
+ 			if (!found) {
+ 				found = exp;
+@@ -698,9 +753,7 @@ void nfsd_export(FILE *f)
+ 	char *cp;
+ 	char *dom, *path;
+ 	nfs_export *found = NULL;
+-	struct in_addr addr;
+-	struct hostent *he = NULL;
+-
++	struct addrinfo *ai = NULL;
+ 
+ 	if (readline(fileno(f), &lbuf, &lbuflen) != 1)
+ 		return;
+@@ -722,12 +775,16 @@ void nfsd_export(FILE *f)
+ 	auth_reload();
+ 
+ 	if (use_ipaddr) {
+-		if (!inet_aton(dom, &addr))
++		struct addrinfo *tmp;
++		tmp = host_pton(dom);
++		if (tmp == NULL)
++			goto out;
++		ai = client_resolve(tmp->ai_addr);
++		freeaddrinfo(tmp);
+ 			goto out;
+-		he = client_resolve(addr);
+ 	}
+ 
+-	found = lookup_export(dom, path, he);
++	found = lookup_export(dom, path, ai);
+ 
+ 	if (found) {
+ 		if (dump_to_cache(f, dom, path, &found->m_export) < 0) {
+@@ -743,7 +800,7 @@ void nfsd_export(FILE *f)
+ 	xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL);
+ 	if (dom) free(dom);
+ 	if (path) free(path);
+-	if (he) free(he);
++	freeaddrinfo(ai);
+ }
+ 
+ 
+@@ -752,11 +809,11 @@ struct {
+ 	void (*cache_handle)(FILE *f);
+ 	FILE *f;
+ } cachelist[] = {
+-	{ "auth.unix.ip", auth_unix_ip},
+-	{ "auth.unix.gid", auth_unix_gid},
+-	{ "nfsd.export", nfsd_export},
+-	{ "nfsd.fh", nfsd_fh},
+-	{ NULL, NULL }
++	{ "auth.unix.ip", auth_unix_ip, NULL},
++	{ "auth.unix.gid", auth_unix_gid, NULL},
++	{ "nfsd.export", nfsd_export, NULL},
++	{ "nfsd.fh", nfsd_fh, NULL},
++	{ NULL, NULL, NULL }
+ };
+ 
+ extern int manage_gids;
+@@ -824,8 +881,8 @@ int cache_export_ent(char *domain, struc
+ 		 * and export them with the same options
+ 		 */
+ 		struct stat stb;
+-		int l = strlen(exp->e_path);
+-		int dev;
++		size_t l = strlen(exp->e_path);
++		__dev_t dev;
+ 
+ 		if (strlen(path) <= l || path[l] != '/' ||
+ 		    strncmp(exp->e_path, path, l) != 0)
+@@ -863,6 +920,7 @@ int cache_export_ent(char *domain, struc
+ 
+ int cache_export(nfs_export *exp, char *path)
+ {
++	char buf[INET_ADDRSTRLEN];
+ 	int err;
+ 	FILE *f;
+ 
+@@ -870,8 +928,10 @@ int cache_export(nfs_export *exp, char *
+ 	if (!f)
+ 		return -1;
+ 
++
+ 	qword_print(f, "nfsd");
+-	qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0]));
++	qword_print(f, 
++		host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf)));
+ 	qword_printint(f, time(0)+30*60);
+ 	qword_print(f, exp->m_client->m_hostname);
+ 	err = qword_eol(f);
+diff -up nfs-utils-1.2.2/utils/mountd/fsloc.c.orig nfs-utils-1.2.2/utils/mountd/fsloc.c
+--- nfs-utils-1.2.2/utils/mountd/fsloc.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mountd/fsloc.c	2010-09-09 11:02:27.385011000 -0400
+@@ -146,7 +146,7 @@ static struct servers *method_list(char 
+ }
+ 
+ /* Returns appropriately filled struct servers, or NULL if had a problem */
+-struct servers *replicas_lookup(int method, char *data, char *key)
++struct servers *replicas_lookup(int method, char *data)
+ {
+ 	struct servers *sp=NULL;
+ 	switch(method) {
+diff -up nfs-utils-1.2.2/utils/mountd/fsloc.h.orig nfs-utils-1.2.2/utils/mountd/fsloc.h
+--- nfs-utils-1.2.2/utils/mountd/fsloc.h.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mountd/fsloc.h	2010-09-09 11:02:27.390006000 -0400
+@@ -44,7 +44,7 @@ struct servers {
+ 	int h_referral;		/* 0=replica, 1=referral */
+ };
+ 
+-struct servers *replicas_lookup(int method, char *data, char *key);
++struct servers *replicas_lookup(int method, char *data);
+ void release_replicas(struct servers *server);
+ 
+ #endif /* FSLOC_H */
+diff -up nfs-utils-1.2.2/utils/mountd/mountd.c.orig nfs-utils-1.2.2/utils/mountd/mountd.c
+--- nfs-utils-1.2.2/utils/mountd/mountd.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mountd/mountd.c	2010-09-09 11:02:27.395001000 -0400
+@@ -80,10 +80,10 @@ static int nfs_version = -1;
+ static void
+ unregister_services (void)
+ {
+-	if (nfs_version & 0x1)
++	if (nfs_version & (0x1 << 1)) {
+ 		pmap_unset (MOUNTPROG, MOUNTVERS);
+-	if (nfs_version & (0x1 << 1))
+ 		pmap_unset (MOUNTPROG, MOUNTVERS_POSIX);
++	}
+ 	if (nfs_version & (0x1 << 2))
+ 		pmap_unset (MOUNTPROG, MOUNTVERS_NFSV3);
+ }
+@@ -192,7 +192,8 @@ sig_hup (int sig)
+ }
+ 
+ bool_t
+-mount_null_1_svc(struct svc_req *rqstp, void *argp, void *resp)
++mount_null_1_svc(struct svc_req *UNUSED(rqstp), void *UNUSED(argp), 
++	void *UNUSED(resp))
+ {
+ 	return 1;
+ }
+@@ -210,7 +211,7 @@ mount_mnt_1_svc(struct svc_req *rqstp, d
+ }
+ 
+ bool_t
+-mount_dump_1_svc(struct svc_req *rqstp, void *argp, mountlist *res)
++mount_dump_1_svc(struct svc_req *rqstp, void *UNUSED(argp), mountlist *res)
+ {
+ 	struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt);
+ 
+@@ -221,7 +222,7 @@ mount_dump_1_svc(struct svc_req *rqstp, 
+ }
+ 
+ bool_t
+-mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *resp)
++mount_umnt_1_svc(struct svc_req *rqstp, dirpath *argp, void *UNUSED(resp))
+ {
+ 	struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt);
+ 	nfs_export	*exp;
+@@ -245,7 +246,8 @@ mount_umnt_1_svc(struct svc_req *rqstp, 
+ }
+ 
+ bool_t
+-mount_umntall_1_svc(struct svc_req *rqstp, void *argp, void *resp)
++mount_umntall_1_svc(struct svc_req *rqstp, void *UNUSED(argp), 
++	void *UNUSED(resp))
+ {
+ 	/* Reload /etc/xtab if necessary */
+ 	auth_reload();
+@@ -255,7 +257,7 @@ mount_umntall_1_svc(struct svc_req *rqst
+ }
+ 
+ bool_t
+-mount_export_1_svc(struct svc_req *rqstp, void *argp, exports *resp)
++mount_export_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp)
+ {
+ 	struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt);
+ 
+@@ -266,7 +268,7 @@ mount_export_1_svc(struct svc_req *rqstp
+ }
+ 
+ bool_t
+-mount_exportall_1_svc(struct svc_req *rqstp, void *argp, exports *resp)
++mount_exportall_1_svc(struct svc_req *rqstp, void *UNUSED(argp), exports *resp)
+ {
+ 	struct sockaddr_in *addr = nfs_getrpccaller_in(rqstp->rq_xprt);
+ 
+@@ -536,22 +538,21 @@ static void free_exportlist(exports *eli
+ 
+ static void prune_clients(nfs_export *exp, struct exportnode *e)
+ {
+-	struct hostent 	*hp;
++	struct addrinfo *ai = NULL;
+ 	struct groupnode *c, **cp;
+ 
+ 	cp = &e->ex_groups;
+ 	while ((c = *cp) != NULL) {
+ 		if (client_gettype(c->gr_name) == MCL_FQDN
+-				&& (hp = gethostbyname(c->gr_name))) {
+-			hp = hostent_dup(hp);
+-			if (client_check(exp->m_client, hp)) {
++		    && (ai = host_addrinfo(c->gr_name))) {
++			if (client_check(exp->m_client, ai)) {
+ 				*cp = c->gr_next;
+ 				xfree(c->gr_name);
+ 				xfree(c);
+-				xfree (hp);
++				freeaddrinfo(ai);
+ 				continue;
+ 			}
+-			xfree (hp);
++			freeaddrinfo(ai);
+ 		}
+ 		cp = &(c->gr_next);
+ 	}
+@@ -712,8 +713,10 @@ main(int argc, char **argv)
+ 			usage(argv [0], 1);
+ 		}
+ 
+-	/* No more arguments allowed. */
+-	if (optind != argc || !(nfs_version & 0x7))
++	/* No more arguments allowed.
++	 * Require at least one valid version (2, 3, or 4)
++	 */
++	if (optind != argc || !(nfs_version & 0xE))
+ 		usage(argv [0], 1);
+ 
+ 	if (chdir(state_dir)) {
+@@ -761,12 +764,12 @@ main(int argc, char **argv)
+ 	if (new_cache)
+ 		cache_open();
+ 
+-	if (nfs_version & 0x1)
++	if (nfs_version & (0x1 << 1)) {
+ 		rpc_init("mountd", MOUNTPROG, MOUNTVERS,
+ 			 mount_dispatch, port);
+-	if (nfs_version & (0x1 << 1))
+ 		rpc_init("mountd", MOUNTPROG, MOUNTVERS_POSIX,
+ 			 mount_dispatch, port);
++	}
+ 	if (nfs_version & (0x1 << 2))
+ 		rpc_init("mountd", MOUNTPROG, MOUNTVERS_NFSV3,
+ 			 mount_dispatch, port);
+diff -up nfs-utils-1.2.2/utils/mountd/rmtab.c.orig nfs-utils-1.2.2/utils/mountd/rmtab.c
+--- nfs-utils-1.2.2/utils/mountd/rmtab.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mountd/rmtab.c	2010-09-09 11:02:27.399996000 -0400
+@@ -133,8 +133,7 @@ mountlist_del(char *hname, const char *p
+ void
+ mountlist_del_all(struct sockaddr_in *sin)
+ {
+-	struct in_addr	addr = sin->sin_addr;
+-	struct hostent	*hp;
++	char		*hostname;
+ 	struct rmtabent	*rep;
+ 	nfs_export	*exp;
+ 	FILE		*fp;
+@@ -142,11 +141,13 @@ mountlist_del_all(struct sockaddr_in *si
+ 
+ 	if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0)
+ 		return;
+-	if (!(hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET))) {
+-		xlog(L_ERROR, "can't get hostname of %s", inet_ntoa(addr));
++	hostname = host_canonname((struct sockaddr *)sin);
++	if (hostname == NULL) {
++		char buf[INET_ADDRSTRLEN];
++		xlog(L_ERROR, "can't get hostname of %s",
++			host_ntop((struct sockaddr *)sin, buf, sizeof(buf)));
+ 		goto out_unlock;
+ 	}
+-	hp = hostent_dup (hp);
+ 
+ 	if (!setrmtabent("r"))
+ 		goto out_free;
+@@ -155,7 +156,7 @@ mountlist_del_all(struct sockaddr_in *si
+ 		goto out_close;
+ 
+ 	while ((rep = getrmtabent(1, NULL)) != NULL) {
+-		if (strcmp(rep->r_client, hp->h_name) == 0 &&
++		if (strcmp(rep->r_client, hostname) == 0 &&
+ 		    (exp = auth_authenticate("umountall", sin, rep->r_path)))
+ 			continue;
+ 		fputrmtabent(fp, rep, NULL);
+@@ -168,7 +169,7 @@ mountlist_del_all(struct sockaddr_in *si
+ out_close:
+ 	endrmtabent();	/* close & unlink */
+ out_free:
+-	free (hp);
++	free(hostname);
+ out_unlock:
+ 	xfunlock(lockid);
+ }
+diff -up nfs-utils-1.2.2/utils/mount/network.c.orig nfs-utils-1.2.2/utils/mount/network.c
+--- nfs-utils-1.2.2/utils/mount/network.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mount/network.c	2010-09-09 11:02:27.327022000 -0400
+@@ -53,6 +53,7 @@
+ #include "parse_opt.h"
+ #include "network.h"
+ #include "conffile.h"
++#include "nfslib.h"
+ 
+ #define PMAP_TIMEOUT	(10)
+ #define CONNECT_TIMEOUT	(20)
+@@ -82,6 +83,7 @@ static const char *nfs_nfs_pgmtbl[] = {
+ static const char *nfs_transport_opttbl[] = {
+ 	"udp",
+ 	"tcp",
++	"rdma",
+ 	"proto",
+ 	NULL,
+ };
+@@ -857,7 +859,14 @@ int nfs_advise_umount(const struct socka
+ 		return 0;
+ 	}
+ 
+-	client->cl_auth = authunix_create_default();
++	client->cl_auth = nfs_authsys_create();
++	if (client->cl_auth == NULL) {
++		if (verbose)
++			nfs_error(_("%s: Failed to create RPC auth handle"),
++				progname);
++		CLNT_DESTROY(client);
++		return 0;
++	}
+ 
+ 	res = CLNT_CALL(client, MOUNTPROC_UMNT,
+ 			(xdrproc_t)xdr_dirpath, (caddr_t)argp,
+@@ -957,8 +966,10 @@ CLIENT *mnt_openclnt(clnt_addr_t *mnt_se
+ 	}
+ 	if (clnt) {
+ 		/* try to mount hostname:dirname */
+-		clnt->cl_auth = authunix_create_default();
+-		return clnt;
++		clnt->cl_auth = nfs_authsys_create();
++		if (clnt->cl_auth)
++			return clnt;
++		CLNT_DESTROY(clnt);
+ 	}
+ 	return NULL;
+ }
+@@ -1203,6 +1214,8 @@ nfs_nfs_program(struct mount_options *op
+ 			return 1;
+ 		}
+ 	case PO_BAD_VALUE:
++		nfs_error(_("%s: invalid value for 'nfsprog=' option"),
++				progname);
+ 		return 0;
+ 	}
+ 
+@@ -1242,9 +1255,12 @@ nfs_nfs_version(struct mount_options *op
+ 			}
+ 			return 0;
+ 		case PO_NOT_FOUND:
+-			nfs_error(_("%s: option parsing error\n"),
++			nfs_error(_("%s: parsing error on 'vers=' option\n"),
+ 					progname);
++			return 0;
+ 		case PO_BAD_VALUE:
++			nfs_error(_("%s: invalid value for 'vers=' option"),
++					progname);
+ 			return 0;
+ 		}
+ 	case 4: /* nfsvers */
+@@ -1256,9 +1272,12 @@ nfs_nfs_version(struct mount_options *op
+ 			}
+ 			return 0;
+ 		case PO_NOT_FOUND:
+-			nfs_error(_("%s: option parsing error\n"),
++			nfs_error(_("%s: parsing error on 'nfsvers=' option\n"),
+ 					progname);
++			return 0;
+ 		case PO_BAD_VALUE:
++			nfs_error(_("%s: invalid value for 'nfsvers=' option"),
++					progname);
+ 			return 0;
+ 		}
+ 	}
+@@ -1289,11 +1308,16 @@ nfs_nfs_protocol(struct mount_options *o
+ 	case 1: /* tcp */
+ 		*protocol = IPPROTO_TCP;
+ 		return 1;
+-	case 2: /* proto */
++	case 2: /* rdma */
++		*protocol = NFSPROTO_RDMA;
++		return 1;
++	case 3: /* proto */
+ 		option = po_get(options, "proto");
+ 		if (option != NULL) {
+ 			if (!nfs_get_proto(option, &family, protocol)) {
+ 				errno = EPROTONOSUPPORT;
++				nfs_error(_("%s: Failed to find '%s' protocol"), 
++					progname, option);
+ 				return 0;
+ 			}
+ 			return 1;
+@@ -1327,6 +1351,8 @@ nfs_nfs_port(struct mount_options *optio
+ 			return 1;
+ 		}
+ 	case PO_BAD_VALUE:
++		nfs_error(_("%s: invalid value for 'port=' option"),
++				progname);
+ 		return 0;
+ 	}
+ 
+@@ -1342,7 +1368,7 @@ nfs_nfs_port(struct mount_options *optio
+ sa_family_t	config_default_family = AF_UNSPEC;
+ 
+ static int
+-nfs_verify_family(sa_family_t family)
++nfs_verify_family(sa_family_t UNUSED(family))
+ {
+ 	return 1;
+ }
+@@ -1374,14 +1400,20 @@ int nfs_nfs_proto_family(struct mount_op
+ 	switch (po_rightmost(options, nfs_transport_opttbl)) {
+ 	case 0:	/* udp */
+ 	case 1: /* tcp */
++	case 2: /* rdma */
+ 		/* for compatibility; these are always AF_INET */
+ 		*family = AF_INET;
+ 		return 1;
+-	case 2: /* proto */
++	case 3: /* proto */
+ 		option = po_get(options, "proto");
+ 		if (option != NULL &&
+-		    !nfs_get_proto(option, &tmp_family, &protocol))
+-			goto out_err;
++		    !nfs_get_proto(option, &tmp_family, &protocol)) {
++
++			nfs_error(_("%s: Failed to find '%s' protocol"), 
++				progname, option);
++			errno = EPROTONOSUPPORT;
++			return 0;
++		}
+ 	}
+ 
+ 	if (!nfs_verify_family(tmp_family))
+@@ -1414,6 +1446,8 @@ nfs_mount_program(struct mount_options *
+ 			return 1;
+ 		}
+ 	case PO_BAD_VALUE:
++		nfs_error(_("%s: invalid value for 'mountprog=' option"),
++				progname);
+ 		return 0;
+ 	}
+ 
+@@ -1443,6 +1477,8 @@ nfs_mount_version(struct mount_options *
+ 			return 1;
+ 		}
+ 	case PO_BAD_VALUE:
++		nfs_error(_("%s: invalid value for 'mountvers=' option"),
++				progname);
+ 		return 0;
+ 	}
+ 
+@@ -1469,6 +1505,8 @@ nfs_mount_protocol(struct mount_options 
+ 	if (option != NULL) {
+ 		if (!nfs_get_proto(option, &family, protocol)) {
+ 			errno = EPROTONOSUPPORT;
++			nfs_error(_("%s: Failed to find '%s' protocol"), 
++				progname, option);
+ 			return 0;
+ 		}
+ 		return 1;
+@@ -1501,6 +1539,8 @@ nfs_mount_port(struct mount_options *opt
+ 			return 1;
+ 		}
+ 	case PO_BAD_VALUE:
++		nfs_error(_("%s: invalid value for 'mountport=' option"),
++				progname);
+ 		return 0;
+ 	}
+ 
+@@ -1526,8 +1566,12 @@ int nfs_mount_proto_family(struct mount_
+ 
+ 	option = po_get(options, "mountproto");
+ 	if (option != NULL) {
+-		if (!nfs_get_proto(option, &tmp_family, &protocol))
++		if (!nfs_get_proto(option, &tmp_family, &protocol)) {
++			nfs_error(_("%s: Failed to find '%s' protocol"), 
++				progname, option);
++			errno = EPROTONOSUPPORT;
+ 			goto out_err;
++		}
+ 		if (!nfs_verify_family(tmp_family))
+ 			goto out_err;
+ 		*family = tmp_family;
+diff -up nfs-utils-1.2.2/utils/mount/nfs4mount.c.orig nfs-utils-1.2.2/utils/mount/nfs4mount.c
+--- nfs-utils-1.2.2/utils/mount/nfs4mount.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mount/nfs4mount.c	2010-09-09 11:02:27.339022000 -0400
+@@ -146,7 +146,7 @@ static int fill_ipv4_sockaddr(const char
+ 				progname, hostname);
+ 		return -1;
+ 	}
+-	if (hp->h_length > sizeof(struct in_addr)) {
++	if (hp->h_length > (int)sizeof(struct in_addr)) {
+ 		nfs_error(_("%s: got bad hp->h_length"), progname);
+ 		hp->h_length = sizeof(struct in_addr);
+ 	}
+diff -up nfs-utils-1.2.2/utils/mount/nfs.man.orig nfs-utils-1.2.2/utils/mount/nfs.man
+--- nfs-utils-1.2.2/utils/mount/nfs.man.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mount/nfs.man	2010-09-09 11:02:27.333022000 -0400
+@@ -3,8 +3,6 @@
+ .SH NAME
+ nfs \- fstab format and options for the
+ .B nfs
+-and
+-.B nfs4
+ file systems
+ .SH SYNOPSIS
+ .I /etc/fstab
+@@ -71,14 +69,10 @@ for details on specifying raw IPv6 addre
+ .P
+ The
+ .I fstype
+-field contains either "nfs" (for version 2 or version 3 NFS mounts)
+-or "nfs4" (for NFS version 4 mounts).
++field contains "nfs", for whatever version of the protocol.
+ The
+ .B nfs
+-and
+-.B nfs4
+-file system types share similar mount options,
+-which are described below.
++allow several mount options, which are described below.
+ .SH "MOUNT OPTIONS"
+ Refer to
+ .BR mount (8)
+@@ -89,14 +83,8 @@ specify any mount options, use the gener
+ in
+ .IR /etc/fstab .
+ .DT
+-.SS "Valid options for either the nfs or nfs4 file system type"
+-These options are valid to use when mounting either
+-.B nfs
+-or
+-.B nfs4
+-file system types.
+-They imply the same behavior
+-and have the same default for both file system types.
++.SS "Options supported by all versions"
++These options are valid to use with any NFS version.
+ .TP 1.5i
+ .BR soft " / " hard
+ Determines the recovery behavior of the NFS client
+@@ -476,11 +464,9 @@ by other clients, but can impact applica
+ .IP
+ The DATA AND METADATA COHERENCE section contains a
+ detailed discussion of these trade-offs.
+-.SS "Valid options for the nfs file system type"
++.SS "Options for versions 2 and 3 only"
+ Use these options, along with the options in the above subsection,
+-for mounting the
+-.B nfs
+-file system type.
++for NFSv2/v3 only. They will be ignored for newer versions.
+ .TP 1.5i
+ .BI proto= netid
+ The transport protocol name and protocol family the NFS client uses
+@@ -495,7 +481,10 @@ command,
+ .I netid
+ is a valid netid listed in
+ .IR /etc/netconfig .
+-Otherwise,
++The value "rdma" may also be specified.
++If the
++.B mount.nfs
++command does not have TI-RPC support, then
+ .I netid
+ is one of "tcp," "udp," or "rdma," and only IPv4 may be used.
+ .IP
+@@ -537,6 +526,12 @@ option is an alternative to specifying
+ .BR proto=tcp.
+ It is included for compatibility with other operating systems.
+ .TP 1.5i
++.B rdma
++The
++.B rdma
++option is an alternative to specifying
++.BR proto=rdma.
++.TP 1.5i
+ .BI port= n
+ The numeric value of the server's NFS service port.
+ If the server's NFS service is not available on the specified port,
+@@ -623,14 +618,9 @@ in such cases.
+ .TP 1.5i
+ .BI nfsvers= n
+ The NFS protocol version number used to contact the server's NFS service.
+-The Linux client supports version 2 and version 3 of the NFS protocol
+-when using the file system type
+-.BR nfs .
+-If the server does not support the requested version,
+-the mount request fails.
+-If this option is not specified, the client attempts to use version 3,
+-but negotiates the NFS version with the server if version 3 support
+-is not available.
++If the server does not support the requested version, the mount request fails.
++If this option is not specified, the client negociate a suitable version with
++the server, trying version 4 first, version 3 second, and version 2 last.
+ .TP 1.5i
+ .BI vers= n
+ This option is an alternative to the
+@@ -727,11 +717,9 @@ If this option is not specified, the NFS
+ on NFS version 3 mounts to read small directories.
+ Some applications perform better if the client uses only READDIR requests
+ for all directories.
+-.SS "Valid options for the nfs4 file system type"
++.SS "Options for version 4 only"
+ Use these options, along with the options in the first subsection above,
+-for mounting the
+-.B nfs4
+-file system type.
++for NFSv4 only. They will be ignored with older versions.
+ .TP 1.5i
+ .BI proto= netid
+ The transport protocol name and protocol family the NFS client uses
+@@ -828,6 +816,13 @@ In the presence of multiple client netwo
+ special routing policies,
+ or atypical network topologies,
+ the exact address to use for callbacks may be nontrivial to determine.
++.SH nfs4 FILE SYSTEM TYPE
++The
++.BR nfs4
++file system type is an old syntax for specifying NFSv4 usage. It can still 
++be used with all NFSv4-specific and common options, excepted the
++.B nfsvers
++mount option.
+ .SH MOUNT CONFIGURATION FILE
+ If the mount command is configured to do so, all of the mount options 
+ described in the previous section can also be configured in the 
+@@ -849,12 +844,11 @@ file system type and specify the
+ .B nfsvers=3
+ mount option.
+ To mount using NFS version 4,
+-use the
+-.B nfs4
+-file system type.
+-The
+-.B nfsvers
+-mount option is not supported for the
++use either the
++.B nfs
++file system type, with the
++.B nfsvers=4
++mount option, or the 
+ .B nfs4
+ file system type.
+ .P
+diff -up nfs-utils-1.2.2/utils/mount/nfsmount.c.orig nfs-utils-1.2.2/utils/mount/nfsmount.c
+--- nfs-utils-1.2.2/utils/mount/nfsmount.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mount/nfsmount.c	2010-09-09 11:02:27.344025000 -0400
+@@ -510,8 +510,12 @@ nfsmount(const char *spec, const char *n
+ 	int val;
+ 	static int doonce = 0;
+ 
+-	clnt_addr_t mnt_server = { &mounthost, };
+-	clnt_addr_t nfs_server = { &hostname, };
++	clnt_addr_t mnt_server = { 
++		.hostname = &mounthost 
++	};
++	clnt_addr_t nfs_server = { 
++		.hostname = &hostname 
++	};
+ 	struct sockaddr_in *nfs_saddr = &nfs_server.saddr;
+ 	struct pmap  *mnt_pmap = &mnt_server.pmap,
+ 		     *nfs_pmap = &nfs_server.pmap;
+diff -up nfs-utils-1.2.2/utils/mount/nfsumount.c.orig nfs-utils-1.2.2/utils/mount/nfsumount.c
+--- nfs-utils-1.2.2/utils/mount/nfsumount.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mount/nfsumount.c	2010-09-09 11:02:27.350022000 -0400
+@@ -179,10 +179,8 @@ static int nfs_umount_do_umnt(struct mou
+ 	struct pmap nfs_pmap, mnt_pmap;
+ 	sa_family_t family;
+ 
+-	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) {
+-		nfs_error(_("%s: bad mount options"), progname);
++	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
+ 		return EX_FAIL;
+-	}
+ 
+ 	/* Skip UMNT call for vers=4 mounts */
+ 	if (nfs_pmap.pm_vers == 4)
+diff -up nfs-utils-1.2.2/utils/mount/stropts.c.orig nfs-utils-1.2.2/utils/mount/stropts.c
+--- nfs-utils-1.2.2/utils/mount/stropts.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/mount/stropts.c	2010-09-09 11:02:27.355022000 -0400
+@@ -302,11 +302,6 @@ static int nfs_set_version(struct nfsmou
+ 
+ 	if (strncmp(mi->type, "nfs4", 4) == 0)
+ 		mi->version = 4;
+-	else {
+-		char *option = po_get(mi->options, "proto");
+-		if (option && strcmp(option, "rdma") == 0)
+-			mi->version = 3;
+-	}
+ 
+ 	/*
+ 	 * If we still don't know, check for version-specific
+@@ -490,14 +485,18 @@ nfs_rewrite_pmap_mount_options(struct mo
+ 	union nfs_sockaddr mnt_address;
+ 	struct sockaddr *mnt_saddr = &mnt_address.sa;
+ 	socklen_t mnt_salen = sizeof(mnt_address);
++	unsigned long protocol;
+ 	struct pmap mnt_pmap;
+-	char *option;
+ 
+ 	/*
+-	 * Skip option negotiation for proto=rdma mounts.
++	 * Version and transport negotiation is not required
++	 * and does not work for RDMA mounts.
+ 	 */
+-	option = po_get(options, "proto");
+-	if (option && strcmp(option, "rdma") == 0)
++	if (!nfs_nfs_protocol(options, &protocol)) {
++		errno = EINVAL;
++		return 0;
++	}
++	if (protocol == NFSPROTO_RDMA)
+ 		goto out;
+ 
+ 	/*
+@@ -538,7 +537,10 @@ nfs_rewrite_pmap_mount_options(struct mo
+ 
+ 	if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap,
+ 					mnt_saddr, &mnt_pmap)) {
+-		errno = EINVAL;
++		if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO)
++			errno = EPROTONOSUPPORT;
++		else
++			errno = EINVAL;
+ 		return 0;
+ 	}
+ 
+@@ -586,18 +588,21 @@ static int nfs_do_mount_v3v2(struct nfsm
+ 		errno = ENOMEM;
+ 		return result;
+ 	}
+-
++	errno = 0;
+ 	if (!nfs_append_addr_option(sap, salen, options)) {
+-		errno = EINVAL;
++		if (errno == 0)
++			errno = EINVAL;
+ 		goto out_fail;
+ 	}
+ 
+ 	if (!nfs_fix_mounthost_option(options, mi->hostname)) {
+-		errno = EINVAL;
++		if (errno == 0)
++			errno = EINVAL;
+ 		goto out_fail;
+ 	}
+ 	if (!mi->fake && !nfs_verify_lock_option(options)) {
+-		errno = EINVAL;
++		if (errno == 0)
++			errno = EINVAL;
+ 		goto out_fail;
+ 	}
+ 
+@@ -799,6 +804,7 @@ static int nfs_is_permanent_error(int er
+ 	case ESTALE:
+ 	case ETIMEDOUT:
+ 	case ECONNREFUSED:
++	case EHOSTUNREACH:
+ 		return 0;	/* temporary */
+ 	default:
+ 		return 1;	/* permanent */
+diff -up nfs-utils-1.2.2/utils/nfsd/nfssvc.c.orig nfs-utils-1.2.2/utils/nfsd/nfssvc.c
+--- nfs-utils-1.2.2/utils/nfsd/nfssvc.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/nfsd/nfssvc.c	2010-09-09 11:02:27.414978000 -0400
+@@ -181,7 +181,7 @@ nfssvc_setfds(const struct addrinfo *hin
+ 		}
+ 
+ 		snprintf(buf, sizeof(buf), "%d\n", sockfd); 
+-		if (write(fd, buf, strlen(buf)) != strlen(buf)) {
++		if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
+ 			/*
+ 			 * this error may be common on older kernels that don't
+ 			 * support IPv6, so turn into a debug message.
+@@ -251,7 +251,7 @@ nfssvc_setvers(unsigned int ctlbits, int
+ 	}
+ 	xlog(D_GENERAL, "Writing version string to kernel: %s", buf);
+ 	snprintf(ptr+off, sizeof(buf) - off, "\n");
+-	if (write(fd, buf, strlen(buf)) != strlen(buf))
++	if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf))
+ 		xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno);
+ 
+ 	close(fd);
+@@ -277,7 +277,7 @@ nfssvc_threads(unsigned short port, cons
+ 		snprintf(buf, sizeof(buf), "%d\n", nrservs);
+ 		n = write(fd, buf, strlen(buf));
+ 		close(fd);
+-		if (n != strlen(buf))
++		if (n != (ssize_t)strlen(buf))
+ 			return -1;
+ 		else
+ 			return 0;
+diff -up nfs-utils-1.2.2/utils/nfsstat/nfsstat.c.orig nfs-utils-1.2.2/utils/nfsstat/nfsstat.c
+--- nfs-utils-1.2.2/utils/nfsstat/nfsstat.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/nfsstat/nfsstat.c	2010-09-09 11:02:27.419973000 -0400
+@@ -791,7 +791,7 @@ print_callstats(const char *hdr, const c
+ {
+ 	unsigned long long	total;
+ 	unsigned long long	pct;
+-	int		i, j;
++	unsigned int		i, j;
+ 
+ 	fputs(hdr, stdout);
+ 	for (i = 0, total = 0; i < nr; i++)
+@@ -816,7 +816,7 @@ print_callstats_list(const char *hdr, co
+ 		 	unsigned int *callinfo, unsigned int nr)
+ {
+ 	unsigned long long	calltotal;
+-	int			i;
++	unsigned int			i;
+ 
+ 	for (i = 0, calltotal = 0; i < nr; i++) {
+ 		calltotal += callinfo[i];
+@@ -1118,7 +1118,7 @@ unpause(int sig)
+ 	time_diff = difftime(endtime, starttime);
+ 	minutes = time_diff / 60;
+ 	seconds = (int)time_diff % 60;
+-	printf("Signal received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", minutes, seconds);
++	printf("Signal %d received; displaying (only) statistics gathered over the last %d minutes, %d seconds:\n\n", sig, minutes, seconds);
+ }
+ 
+ static void
+diff -up nfs-utils-1.2.2/utils/showmount/showmount.c.orig nfs-utils-1.2.2/utils/showmount/showmount.c
+--- nfs-utils-1.2.2/utils/showmount/showmount.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/showmount/showmount.c	2010-09-09 11:02:27.436957000 -0400
+@@ -194,7 +194,13 @@ int main(int argc, char **argv)
+ 	}
+ 
+ 	mclient = nfs_get_mount_client(hostname, mount_vers_tbl[vers]);
+-	mclient->cl_auth = authunix_create_default();
++	mclient->cl_auth = nfs_authsys_create();
++	if (mclient->cl_auth == NULL) {
++		fprintf(stderr, "%s: unable to create RPC auth handle.\n",
++				program_name);
++		clnt_destroy(mclient);
++		exit(1);
++	}
+ 	total_timeout.tv_sec = TOTAL_TIMEOUT;
+ 	total_timeout.tv_usec = 0;
+ 
+diff -up nfs-utils-1.2.2/utils/statd/hostname.c.orig nfs-utils-1.2.2/utils/statd/hostname.c
+--- nfs-utils-1.2.2/utils/statd/hostname.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/statd/hostname.c	2010-09-09 11:02:27.441960000 -0400
+@@ -212,7 +212,9 @@ statd_canonical_name(const char *hostnam
+ 					buf, (socklen_t)sizeof(buf));
+ 		freeaddrinfo(ai);
+ 		if (!result)
+-			return NULL;
++			/* OK to use presentation address,
++			 * if no reverse map exists */
++			return strdup(hostname);
+ 		return strdup(buf);
+ 	}
+ 
+diff -up nfs-utils-1.2.2/utils/statd/sm-notify.c.orig nfs-utils-1.2.2/utils/statd/sm-notify.c
+--- nfs-utils-1.2.2/utils/statd/sm-notify.c.orig	2010-02-18 07:35:00.000000000 -0500
++++ nfs-utils-1.2.2/utils/statd/sm-notify.c	2010-09-09 11:02:27.447957000 -0400
+@@ -54,7 +54,7 @@ struct nsm_host {
+ 	uint32_t		xid;
+ };
+ 
+-static char		nsm_hostname[256];
++static char		nsm_hostname[SM_MAXSTRLEN + 1];
+ static int		nsm_state;
+ static int		nsm_family = AF_INET;
+ static int		opt_debug = 0;
+@@ -412,12 +412,33 @@ usage:		fprintf(stderr,
+ 		}
+ 	}
+ 
+-	if (opt_srcaddr) {
+-		strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1);
+-	} else
+-	if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) {
+-		xlog(L_ERROR, "Failed to obtain name of local host: %m");
+-		exit(1);
++	if (opt_srcaddr != NULL) {
++		struct addrinfo *ai = NULL;
++		struct addrinfo hint = {
++			.ai_family	= AF_UNSPEC,
++			.ai_flags	= AI_NUMERICHOST,
++		};
++
++		if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai))
++			/* not a presentation address - use it */
++			strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname));
++		else {
++			/* was a presentation address - look it up in
++			 * /etc/hosts, so it can be used for my_name */
++			int error;
++
++			freeaddrinfo(ai);
++			hint.ai_flags = AI_CANONNAME;
++			error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai);
++			if (error != 0) {
++				xlog(L_ERROR, "Bind address %s is unusable: %s",
++						opt_srcaddr, gai_strerror(error));
++				exit(1);
++			}
++			strncpy(nsm_hostname, ai->ai_canonname,
++							sizeof(nsm_hostname));
++			freeaddrinfo(ai);
++		}
+ 	}
+ 
+ 	(void)nsm_retire_monitored_hosts();
+@@ -535,6 +556,8 @@ notify(const int sock)
+ static int
+ notify_host(int sock, struct nsm_host *host)
+ {
++	const char *my_name = (opt_srcaddr != NULL ?
++					nsm_hostname : host->my_name);
+ 	struct sockaddr *sap;
+ 	socklen_t salen;
+ 
+@@ -580,8 +603,8 @@ notify_host(int sock, struct nsm_host *h
+ 		host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS);
+ 	else
+ 		host->xid = nsm_xmit_notify(sock, sap, salen,
+-				SM_PROG, nsm_hostname, nsm_state);
+-	
++					SM_PROG, my_name, nsm_state);
++
+ 	return 0;
+ }
+ 
+@@ -611,15 +634,28 @@ recv_rpcbind_reply(struct sockaddr *sap,
+ }
+ 
+ /*
+- * Successful NOTIFY call. Server returns void, so nothing
+- * we need to do here.
++ * Successful NOTIFY call. Server returns void.
++ *
++ * Try sending another SM_NOTIFY with an unqualified "my_name"
++ * argument.  Reuse the port number.  If "my_name" is already
++ * unqualified, we're done.
+  */
+ static void
+ recv_notify_reply(struct nsm_host *host)
+ {
+-	xlog(D_GENERAL, "Host %s notified successfully", host->name);
++	char *dot = strchr(host->my_name, '.');
+ 
+-	smn_forget_host(host);
++	if (dot != NULL) {
++		*dot = '\0';
++		host->send_next = time(NULL);
++		host->xid = 0;
++		if (host->timeout >= NSM_MAX_TIMEOUT / 4)
++			host->timeout = NSM_MAX_TIMEOUT / 4;
++		insert_host(host);
++	} else {
++		xlog(D_GENERAL, "Host %s notified successfully", host->name);
++		smn_forget_host(host);
++	}
+ }
+ 
+ /*
+diff -up nfs-utils-1.2.2/utils/statd/sm-notify.man.orig nfs-utils-1.2.2/utils/statd/sm-notify.man
+--- nfs-utils-1.2.2/utils/statd/sm-notify.man.orig	2010-09-09 11:01:45.327752000 -0400
++++ nfs-utils-1.2.2/utils/statd/sm-notify.man	2010-09-09 11:02:27.452960000 -0400
+@@ -97,11 +97,9 @@ It uses the
+ string as the destination.
+ To identify which host has rebooted, the
+ .B sm-notify
+-command normally sends the results of
+-.BR gethostname (3)
+-as the
++command normally sends
+ .I my_name
+-string.
++string recorded when that remote was monitored.
+ The remote
+ .B rpc.statd
+ matches incoming SM_NOTIFY requests using this string,
+@@ -202,15 +200,22 @@ argument to use when sending SM_NOTIFY r
+ If this option is not specified,
+ .B sm-notify
+ uses a wildcard address as the transport bind address,
+-and uses the results of
+-.BR gethostname (3)
+-as the
++and uses the
++.I my_name
++recorded when the remote was monitored as the
+ .I mon_name
+-argument.
++argument when sending SM_NOTIFY requests.
+ .IP
+ The
+ .I ipaddr
+ form can be expressed as either an IPv4 or an IPv6 presentation address.
++If the
++.I ipaddr
++form is used, the
++.B sm-notify
++command converts this address to a hostname for use as the
++.I mon_name
++argument when sending SM_NOTIFY requests.
+ .IP
+ This option can be useful in multi-homed configurations where
+ the remote requires notification from a specific network address.
+@@ -252,13 +257,6 @@ consistent
+ The hostname the client uses to mount the server should match the server's
+ .I mon_name
+ in SM_NOTIFY requests it sends
+-.IP
+-The use of network addresses as a
+-.I mon_name
+-or a
+-.I my_name
+-string should be avoided when
+-interoperating with non-Linux NFS implementations.
+ .PP
+ Unmounting an NFS file system does not necessarily stop
+ either the NFS client or server from monitoring each other.
+diff -up nfs-utils-1.2.2/utils/statd/statd.man.orig nfs-utils-1.2.2/utils/statd/statd.man
+--- nfs-utils-1.2.2/utils/statd/statd.man.orig	2010-09-09 11:01:45.333750000 -0400
++++ nfs-utils-1.2.2/utils/statd/statd.man	2010-09-09 11:02:27.457960000 -0400
+@@ -100,11 +100,9 @@ It uses the
+ string as the destination.
+ To identify which host has rebooted, the
+ .B sm-notify
+-command normally sends the results of
+-.BR gethostname (3)
+-as the
++command sends the
+ .I my_name
+-string.
++string recorded when that remote was monitored.
+ The remote
+ .B rpc.statd
+ matches incoming SM_NOTIFY requests using this string,
+@@ -292,7 +290,6 @@ man pages.
+ .SH ADDITIONAL NOTES
+ Lock recovery after a reboot is critical to maintaining data integrity
+ and preventing unnecessary application hangs.
+-.PP
+ To help
+ .B rpc.statd
+ match SM_NOTIFY requests to NLM requests, a number of best practices
+@@ -309,13 +306,6 @@ consistent
+ The hostname the client uses to mount the server should match the server's
+ .I mon_name
+ in SM_NOTIFY requests it sends
+-.IP
+-The use of network addresses as a
+-.I mon_name
+-or a
+-.I my_name
+-string should be avoided when
+-interoperating with non-Linux NFS implementations.
+ .PP
+ Unmounting an NFS file system does not necessarily stop
+ either the NFS client or server from monitoring each other.
diff --git a/nfs-utils.spec b/nfs-utils.spec
index 8ad17c2..67cac40 100644
--- a/nfs-utils.spec
+++ b/nfs-utils.spec
@@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser
 Name: nfs-utils
 URL: http://sourceforge.net/projects/nfs
 Version: 1.2.2
-Release: 6%{?dist}
+Release: 7%{?dist}
 Epoch: 1
 
 # group all 32bit related archs
@@ -18,7 +18,7 @@ Source13: rpcgssd.init
 Source14: rpcsvcgssd.init
 Source15: nfs.sysconfig
 
-Patch001: nfs-utils-1-2-3-rc4.patch
+Patch001: nfs-utils-1-2-3-rc5.patch
 
 Patch100: nfs-utils-1.2.1-statdpath-man.patch
 Patch101: nfs-utils-1.2.2-statdpath.patch
@@ -251,6 +251,9 @@ fi
 %attr(4755,root,root)   /sbin/umount.nfs4
 
 %changelog
+* Thu Sep  9 2010 Steve Dickson <steved at redhat.com> 1.2.2-7
+- Update to upstream RC release: nfs-utils-1-2-3-rc5
+
 * Tue Jun 22 2010 Steve Dickson <steved at redhat.com> 1.2.2-6
 - Update to upstream RC release: nfs-utils-1-2-3-rc4
 


More information about the scm-commits mailing list