diff --git a/nfs-utils-1-2-3-rc4.patch b/nfs-utils-1-2-3-rc4.patch deleted file mode 100644 index deb5d4f..0000000 --- a/nfs-utils-1-2-3-rc4.patch +++ /dev/null @@ -1,4340 +0,0 @@ -diff --git a/aclocal/libcap.m4 b/aclocal/libcap.m4 -index eabe507..68a624c 100644 ---- a/aclocal/libcap.m4 -+++ b/aclocal/libcap.m4 -@@ -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 --git a/autogen.sh b/autogen.sh -old mode 100644 -new mode 100755 -diff --git a/configure.ac b/configure.ac -index b7520d8..d90a88f 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -81,7 +81,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"]) -@@ -425,6 +425,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 --git a/support/export/client.c b/support/export/client.c -index 6236561..dc01067 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -17,7 +17,7 @@ - #include - #include - #include --#include "xmalloc.h" -+ - #include "misc.h" - #include "nfslib.h" - #include "exportfs.h" -@@ -28,58 +28,140 @@ - #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_netmask(nfs_client *clp, const char *slash) -+{ -+ struct sockaddr_in sin = { -+ .sin_family = AF_INET, -+ }; -+ -+ if (strchr(slash + 1, '.') != NULL) -+ sin.sin_addr.s_addr = inet_addr(slash + 1); -+ else { -+ int prefixlen = atoi(slash + 1); -+ if (0 < prefixlen && prefixlen <= 32) -+ sin.sin_addr.s_addr = -+ htonl((uint32_t)~0 << (32 - prefixlen)); -+ else -+ goto out_badprefix; -+ } -+ -+ set_addrlist_in(clp, 1, &sin); -+ return 1; -+ -+out_badprefix: -+ xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname); -+ return 0; -+} -+ -+static int -+init_subnetwork(nfs_client *clp) -+{ -+ struct sockaddr_in sin = { -+ .sin_family = AF_INET, -+ }; -+ static char slash32[] = "/32"; -+ char *cp; -+ -+ cp = strchr(clp->m_hostname, '/'); -+ if (cp == NULL) -+ cp = slash32; -+ -+ *cp = '\0'; -+ sin.sin_addr.s_addr = inet_addr(clp->m_hostname); -+ set_addrlist_in(clp, 0, &sin); -+ *cp = '/'; -+ -+ return init_netmask(clp, cp); -+} -+ -+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 +169,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 +231,10 @@ client_release(nfs_client *clp) - clp->m_count--; - } - -+/** -+ * client_freeall - deallocate all nfs_client records -+ * -+ */ - void - client_freeall(void) - { -@@ -205,57 +245,45 @@ client_freeall(void) - head = clientlist + i; - while (*head) { - *head = (clp = *head)->m_next; -- xfree(clp->m_hostname); -- xfree(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 -+ client_free(clp); - } - } -- 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 +291,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 +299,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 +324,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 +338,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); -@@ -339,105 +372,211 @@ add_name(char *old, char *add) - return new; - } - -+static _Bool -+addrs_match4(const struct sockaddr *sa1, const struct sockaddr *sa2) -+{ -+ const struct sockaddr_in *si1 = (const struct sockaddr_in *)sa1; -+ const struct sockaddr_in *si2 = (const struct sockaddr_in *)sa2; -+ -+ return si1->sin_addr.s_addr == si2->sin_addr.s_addr; -+} -+ -+static _Bool -+addrs_match(const struct sockaddr *sa1, const struct sockaddr *sa2) -+{ -+ if (sa1->sa_family == sa2->sa_family) -+ switch (sa1->sa_family) { -+ case AF_INET: -+ return addrs_match4(sa1, sa2); -+ } -+ -+ return false; -+} -+ - /* -- * 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 (addrs_match(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; -- } -- -- /* 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; -- } -- -- /* 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 = '.'; -- -- 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); -+ } -+ -+ 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 --client_checkaddr(nfs_client *clp, struct in_addr addr) -+check_netgroup(const nfs_client *clp, const struct addrinfo *ai) - { -- int i; -+ const char *netgroup = clp->m_hostname + 1; -+ const char *hname = ai->ai_canonname; -+ struct addrinfo *tmp = NULL; -+ struct hostent *hp; -+ int i, match; -+ char *dot; -+ -+ /* First, try to match the hostname without -+ * splitting off the domain */ -+ if (innetgr(netgroup, hname, NULL, NULL)) -+ return 1; - -- 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) -+ /* 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)) - return 1; -- } -+ } -+ -+ /* If hname is ip address convert to FQDN */ -+ tmp = host_pton(hname); -+ if (tmp != NULL) { -+ freeaddrinfo(tmp); -+ if (innetgr(netgroup, hname, NULL, NULL)) -+ return 1; -+ } -+ -+ /* Okay, strip off the domain (if we have one) */ -+ dot = strchr(hname, '.'); -+ if (dot == NULL) - return 0; -+ -+ *dot = '\0'; -+ match = innetgr(netgroup, hname, NULL, NULL); -+ *dot = '.'; -+ -+ return match; -+} -+#else /* !HAVE_INNETGR */ -+static int -+check_netgroup(__attribute__((unused)) const nfs_client *clp, -+ __attribute__((unused)) const struct addrinfo *ai) -+{ -+ 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: -+ 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) - { -diff --git a/support/export/export.c b/support/export/export.c -index 2943466..f528603 100644 ---- a/support/export/export.c -+++ b/support/export/export.c -@@ -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_export *exp, struct exportent *eep) - } - } - --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 *clp, struct exportent *nep) - * 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 hostent *hp) - 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 hostent *hp) - - 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 *path) - } - - 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 *hp, char *path) - 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 *hp, char *path) - 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 *path) - - /* 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 *path) - 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, int canonical) - } - - 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 --git a/support/export/hostname.c b/support/export/hostname.c -index 8a23a89..232e040 100644 ---- a/support/export/hostname.c -+++ b/support/export/hostname.c -@@ -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 . - */ - - #ifdef HAVE_CONFIG_H - #include - #endif - --/* --#define TEST --*/ -- - #include --#include --#include --#include - #include --#include --#ifdef TEST --#define xmalloc malloc --#else --#include "xmalloc.h" --#include "misc.h" --#endif -+#include -+#include -+#include -+ -+#include "sockaddr.h" -+#include "exportfs.h" - --#define ALIGNMENT sizeof (char *) -+#ifndef HAVE_DECL_AI_ADDRCONFIG -+#define AI_ADDRCONFIG 0 -+#endif - --static int --align (int len, int al) -+#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 */ -+ -+/** -+ * 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) -+{ -+ socklen_t salen = sockaddr_size(sap); -+ int error; -+ -+ memset(buf, 0, buflen); -+ -+ 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); -+ } - --struct hostent * --get_hostent (const char *addr, int len, int type) -+ return buf; -+} -+#else /* !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; -- -- return cp; -+ const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap; -+ -+ 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 */ - --struct hostent * --hostent_dup (struct hostent *hp) -+/** -+ * 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) - { -- 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; -- -- return cp; -+ 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; -+ -+ 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 NULL; - } - --static int --is_hostname(const char *sp) -+/** -+ * 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) - { -- if (*sp == '\0' || *sp == '@') -- return 0; -- -- for (; *sp; sp++) -- { -- if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/') -- return 0; -- if (*sp == '\\' && sp[1]) -- sp++; -- } -- -- return 1; -+ 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; -+ } -+ -+ return NULL; - } - --int --matchhostname (const char *h1, const char *h2) -+/** -+ * 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) - { -- struct hostent *hp1, *hp2; -- int status; -- -- if (strcasecmp (h1, h2) == 0) -- return 1; -- -- if (!is_hostname (h1) || !is_hostname (h2)) -- return 0; -- -- 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; -- } -+ 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; -+ } -+ -+ 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; -- -- 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"); --} -+ memset(buf, 0, sizeof(buf)); -+ if (inet_ntop(AF_INET, (char *)addr, buf, -+ (socklen_t)sizeof(buf)) == NULL) -+ return NULL; - --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; -+ ai = host_pton(buf); -+ -+ /* -+ * 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 --git a/support/export/nfsctl.c b/support/export/nfsctl.c -index e2877b9..3b9876a 100644 ---- a/support/export/nfsctl.c -+++ b/support/export/nfsctl.c -@@ -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, nfs_client *clp) - 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; - } - -diff --git a/support/export/rmtab.c b/support/export/rmtab.c -index b49e1aa..31c0f50 100644 ---- a/support/export/rmtab.c -+++ b/support/export/rmtab.c -@@ -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 --git a/support/include/exportfs.h b/support/include/exportfs.h -index 470b2ec..3cf1ee8 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -10,6 +10,8 @@ - #define EXPORTFS_H - - #include -+ -+#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_MAXTYPES]; - 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 --git a/support/include/misc.h b/support/include/misc.h -index 9a1b25d..bc5ba23 100644 ---- a/support/include/misc.h -+++ b/support/include/misc.h -@@ -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 --git a/support/include/nfslib.h b/support/include/nfslib.h -index 537a31e..e44cf8f 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -152,6 +152,8 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen); - 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); - -diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h -index 4db35ab..6ebefca 100644 ---- a/support/include/nfsrpc.h -+++ b/support/include/nfsrpc.h -@@ -160,4 +160,7 @@ extern int nfs_rpc_ping(const struct sockaddr *sap, - 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 --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c -index bdf5d84..55fa45d 100644 ---- a/support/nfs/cacheio.c -+++ b/support/nfs/cacheio.c -@@ -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) -diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c -index a28abf3..ca789a3 100644 ---- a/support/nfs/rmtab.c -+++ b/support/nfs/rmtab.c -@@ -19,6 +19,18 @@ - #include - #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 *pos) - 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 *pos) - 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 --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c -index 0e20824..c14efe8 100644 ---- a/support/nfs/rpc_socket.c -+++ b/support/nfs/rpc_socket.c -@@ -557,3 +557,24 @@ rpcprog_t nfs_getrpcbyname(const rpcprog_t program, const char *table[]) - - 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 --git a/support/nsm/file.c b/support/nsm/file.c -index d469219..f4baeb9 100644 ---- a/support/nsm/file.c -+++ b/support/nsm/file.c -@@ -67,7 +67,9 @@ - #endif - - #include -+#ifdef HAVE_SYS_CAPABILITY_H - #include -+#endif - #include - #include - -@@ -347,6 +349,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"); -@@ -362,6 +365,7 @@ nsm_clear_capabilities(void) - } - - (void)cap_free(caps); -+#endif - return true; - } - -diff --git a/tests/t0001-statd-basic-mon-unmon.sh b/tests/t0001-statd-basic-mon-unmon.sh -old mode 100644 -new mode 100755 -diff --git a/tools/Makefile.am b/tools/Makefile.am -index db15346..f2ce282 100644 ---- a/tools/Makefile.am -+++ b/tools/Makefile.am -@@ -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 --git a/tools/mountstats/Makefile.am b/tools/mountstats/Makefile.am -new file mode 100644 -index 0000000..ca617a2 ---- /dev/null -+++ b/tools/mountstats/Makefile.am -@@ -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 --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man -new file mode 100644 -index 0000000..0de31b7 ---- /dev/null -+++ b/tools/mountstats/mountstats.man -@@ -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 [" "] " " [ " "]" -+.SH DESCRIPTION -+The -+.B mountstats -+command displays NFS client statisitics on each given -+.I -+.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 -diff --git a/tools/nfs-iostat/Makefile.am b/tools/nfs-iostat/Makefile.am -new file mode 100644 -index 0000000..30f4054 ---- /dev/null -+++ b/tools/nfs-iostat/Makefile.am -@@ -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 --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py -index 2d0b143..1207674 100644 ---- a/tools/nfs-iostat/nfs-iostat.py -+++ b/tools/nfs-iostat/nfs-iostat.py -@@ -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 --git a/tools/nfs-iostat/nfsiostat.man b/tools/nfs-iostat/nfsiostat.man -new file mode 100644 -index 0000000..99e04fb ---- /dev/null -+++ b/tools/nfs-iostat/nfsiostat.man -@@ -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 [[" "] [" "]] [" "][" "] -+.SH DESCRIPTION -+The -+.B nfsiostat -+command displays NFS client per-mount statisitics. -+.TP -+ -+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 -+ -+If the -+.I -+parameter is -+specified, the value of -+.I -+determines the number of reports generated at -+. -+seconds apart. if the interval parameter is -+specified without the -+.I -+parameter, the command generates reports continuously. -+.TP -+ -+Define below -+.TP -+ -+If one or more -+.I -+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 -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index 331e57e..edc1625 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -36,6 +37,7 @@ static void dump(int verbose); - static void error(nfs_export *exp, int err); - static void usage(void); - static void validate_export(nfs_export *exp); -+static int matchhostname(const char *hostname1, const char *hostname2); - - int - main(int argc, char **argv) -@@ -232,7 +234,7 @@ exportfs(char *arg, char *options, int verbose) - { - struct exportent *eep; - nfs_export *exp; -- struct hostent *hp = NULL; -+ struct addrinfo *ai = NULL; - char *path; - char *hname = arg; - int htype; -@@ -245,32 +247,21 @@ exportfs(char *arg, char *options, int verbose) - 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 +271,16 @@ exportfs(char *arg, char *options, int verbose) - 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; -@@ -302,10 +295,9 @@ unexportfs(char *arg, int verbose) - } - - 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 +333,7 @@ unexportfs(char *arg, int verbose) - exp->m_mayexport = 0; - } - -- if (hp) free (hp); -+ freeaddrinfo(ai); - } - - static int can_test(void) -@@ -431,6 +423,82 @@ validate_export(nfs_export *exp) - } - } - -+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, ...) -diff --git a/utils/gssd/context.h b/utils/gssd/context.h -index be47f9c..c9cb0bd 100644 ---- a/utils/gssd/context.h -+++ b/utils/gssd/context.h -@@ -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 --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c -index 4a682ae..b87bf76 100644 ---- a/utils/gssd/context_lucid.c -+++ b/utils/gssd/context_lucid.c -@@ -42,6 +42,7 @@ - #include - #include - #include -+#include - - #include - -@@ -119,15 +120,13 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, - * 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,100 @@ 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 (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 +264,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime) - 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 +286,20 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime) - 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 +309,8 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime) - } - - 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 +320,7 @@ out_err: - printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); - return -1; - } -+ -+ -+ - #endif /* HAVE_LUCID_CONTEXT_SUPPORT */ -diff --git a/utils/gssd/context_mit.c b/utils/gssd/context_mit.c -index 709a903..f9cbb02 100644 ---- a/utils/gssd/context_mit.c -+++ b/utils/gssd/context_mit.c -@@ -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 - #include - #include -+#include - #include - #include - #include -@@ -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,120 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime) - { - 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; -+ 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 --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index be4fb11..a55418b 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -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) -@@ -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 --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index 1295f57..dccbeb6 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -292,61 +292,6 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d) - 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. -@@ -1304,3 +1249,68 @@ gssd_k5_get_default_realm(char **def_realm) - - 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, 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]); -+ 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 --git a/utils/mount/network.c b/utils/mount/network.c -index 8dc183a..ffb18ab 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -857,7 +857,14 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, - 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 +964,10 @@ CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock) - } - 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 +1212,8 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program) - return 1; - } - case PO_BAD_VALUE: -+ nfs_error(_("%s: invalid value for 'nfsprog=' option"), -+ progname); - return 0; - } - -@@ -1242,9 +1253,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) - } - 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 +1270,12 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) - } - 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; - } - } -@@ -1294,6 +1311,8 @@ nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol) - 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 +1346,8 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port) - return 1; - } - case PO_BAD_VALUE: -+ nfs_error(_("%s: invalid value for 'port=' option"), -+ progname); - return 0; - } - -@@ -1380,8 +1401,13 @@ int nfs_nfs_proto_family(struct mount_options *options, - case 2: /* 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 +1440,8 @@ nfs_mount_program(struct mount_options *options, unsigned long *program) - return 1; - } - case PO_BAD_VALUE: -+ nfs_error(_("%s: invalid value for 'mountprog=' option"), -+ progname); - return 0; - } - -@@ -1443,6 +1471,8 @@ nfs_mount_version(struct mount_options *options, unsigned long *version) - return 1; - } - case PO_BAD_VALUE: -+ nfs_error(_("%s: invalid value for 'mountvers=' option"), -+ progname); - return 0; - } - -@@ -1469,6 +1499,8 @@ nfs_mount_protocol(struct mount_options *options, unsigned long *protocol) - 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 +1533,8 @@ nfs_mount_port(struct mount_options *options, unsigned long *port) - return 1; - } - case PO_BAD_VALUE: -+ nfs_error(_("%s: invalid value for 'mountport=' option"), -+ progname); - return 0; - } - -@@ -1526,8 +1560,12 @@ int nfs_mount_proto_family(struct mount_options *options, - - 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 --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c -index 9d798a2..1514340 100644 ---- a/utils/mount/nfsumount.c -+++ b/utils/mount/nfsumount.c -@@ -179,10 +179,8 @@ static int nfs_umount_do_umnt(struct mount_options *options, - 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 --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 9b8c38f..0241400 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -538,7 +538,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options) - - 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 +589,21 @@ static int nfs_do_mount_v3v2(struct nfsmount_info *mi, - 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 +805,7 @@ static int nfs_is_permanent_error(int error) - case ESTALE: - case ETIMEDOUT: - case ECONNREFUSED: -+ case EHOSTUNREACH: - return 0; /* temporary */ - default: - return 1; /* permanent */ -diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c -index 13eba70..04487e5 100644 ---- a/utils/mountd/auth.c -+++ b/utils/mountd/auth.c -@@ -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 sockaddr_in *caller, struct hostent *hp, - - /* 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, struct sockaddr_in *caller, - - 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, struct sockaddr_in *caller, - 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, struct sockaddr_in *caller, - } - - 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 sockaddr_in *caller, char *path) - 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 sockaddr_in *caller, char *path) - 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 sockaddr_in *caller, char *path) - - 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 --git a/utils/mountd/cache.c b/utils/mountd/cache.c -index d63e10a..9e1b164 100644 ---- a/utils/mountd/cache.c -+++ b/utils/mountd/cache.c -@@ -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; im_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,8 +587,7 @@ 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; -@@ -600,13 +652,13 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex - 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 *domain, char *path, struct exportent *ex - 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, char *path) - 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 *dom, char *path, struct hostent *he) - - 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); - } - - -@@ -863,6 +920,7 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path) - - 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 *path) - 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 --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index a0a1f2d..6571454 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -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); - } -@@ -536,22 +536,21 @@ static void free_exportlist(exports *elist) - - 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 +711,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 +762,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 --git a/utils/mountd/rmtab.c b/utils/mountd/rmtab.c -index 19b22ee..ba0fcf6 100644 ---- a/utils/mountd/rmtab.c -+++ b/utils/mountd/rmtab.c -@@ -133,8 +133,7 @@ mountlist_del(char *hname, const char *path) - 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 *sin) - - 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 *sin) - 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 *sin) - out_close: - endrmtabent(); /* close & unlink */ - out_free: -- free (hp); -+ free(hostname); - out_unlock: - xfunlock(lockid); - } -diff --git a/utils/showmount/showmount.c b/utils/showmount/showmount.c -index f567093..394f528 100644 ---- a/utils/showmount/showmount.c -+++ b/utils/showmount/showmount.c -@@ -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 --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c -index 3259a3e..437e37a 100644 ---- a/utils/statd/sm-notify.c -+++ b/utils/statd/sm-notify.c -@@ -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 *host) - 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, struct nsm_host *host, XDR *xdr) - } - - /* -- * 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 --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man -index 163713e..7a1cbfa 100644 ---- a/utils/statd/sm-notify.man -+++ b/utils/statd/sm-notify.man -@@ -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 requests. - 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 --git a/utils/statd/statd.man b/utils/statd/statd.man -index ffc5e95..ca00e24 100644 ---- a/utils/statd/statd.man -+++ b/utils/statd/statd.man -@@ -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-1-2-3-rc5.patch b/nfs-utils-1-2-3-rc5.patch deleted file mode 100644 index 504ab01..0000000 --- a/nfs-utils-1-2-3-rc5.patch +++ /dev/null @@ -1,5668 +0,0 @@ -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 - #include - #include --#include "xmalloc.h" -+#include -+ -+#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 . - */ - - #ifdef HAVE_CONFIG_H - #include - #endif - --/* --#define TEST --*/ -- - #include --#include --#include --#include - #include --#include --#ifdef TEST --#define xmalloc malloc --#else --#include "xmalloc.h" --#include "misc.h" --#endif -+#include -+#include -+#include - --#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 -+ -+#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 - - /* -+ * 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 - #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 -+#ifdef HAVE_SYS_CAPABILITY_H - #include -+#endif - #include - #include - -@@ -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 [" "] " " [ " "]" -+.SH DESCRIPTION -+The -+.B mountstats -+command displays NFS client statisitics on each given -+.I -+.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 -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 [[" "] [" "]] [" "][" "] -+.SH DESCRIPTION -+The -+.B nfsiostat -+command displays NFS client per-mount statisitics. -+.TP -+ -+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 -+ -+If the -+.I -+parameter is -+specified, the value of -+.I -+determines the number of reports generated at -+. -+seconds apart. if the interval parameter is -+specified without the -+.I -+parameter, the command generates reports continuously. -+.TP -+ -+Define below -+.TP -+ -+If one or more -+.I -+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 -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 - #endif - -+#include -+#include - #include - #include - #include -+#include - #include - #include - #include - #include -+#include - #include - #include --#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 - #include - #include -+#include - - #include - -@@ -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 - #include - #include -+#include - #include - #include - #include -@@ -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; im_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-1-2-3-rc6.patch b/nfs-utils-1-2-3-rc6.patch deleted file mode 100644 index 019b92a..0000000 --- a/nfs-utils-1-2-3-rc6.patch +++ /dev/null @@ -1,6521 +0,0 @@ -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-16 16:29:35.224032527 -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-16 15:40:15.598012398 -0400 -+++ nfs-utils-1.2.2/configure.ac 2010-09-16 16:29:35.224032527 -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-16 16:29:35.225032543 -0400 -@@ -17,7 +17,9 @@ - #include - #include - #include --#include "xmalloc.h" -+#include -+ -+#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-16 16:29:35.226032506 -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-16 16:29:35.227032188 -0400 -@@ -1,315 +1,376 @@ - /* -- * 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 . - */ - - #ifdef HAVE_CONFIG_H - #include - #endif - --/* --#define TEST --*/ -- - #include --#include --#include --#include - #include --#include --#ifdef TEST --#define xmalloc malloc --#else --#include "xmalloc.h" --#include "misc.h" -+#include -+#include -+#include -+ -+#include "sockaddr.h" -+#include "exportfs.h" -+ -+#ifndef HAVE_DECL_AI_ADDRCONFIG -+#define AI_ADDRCONFIG 0 - #endif - --#define ALIGNMENT sizeof (char *) -+/** -+ * 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) -+{ -+ socklen_t salen = nfs_sockaddr_length(sap); -+ int error; -+ -+ memset(buf, 0, buflen); -+ -+ 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); -+ } - --static int --align (int len, int al) -+ return buf; -+} -+#else /* !HAVE_GETNAMEINFO */ -+char * -+host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) - { -- int i; -- i = len % al; -- if (i) -- len += al - i; -- return len; -+ const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap; -+ -+ 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 */ - --struct hostent * --get_hostent (const char *addr, int len, int type) -+/** -+ * 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) - { -- 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; -+ 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, inet4; -+ -+ /* -+ * 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. -+ */ -+ inet4 = 1; -+ if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0) -+ inet4 = 0; -+ -+ error = getaddrinfo(paddr, NULL, &hint, &ai); -+ switch (error) { -+ case 0: -+ if (!inet4 && ai->ai_addr->sa_family == AF_INET) { -+ freeaddrinfo(ai); -+ break; -+ } -+ 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 cp; -+ return NULL; - } - --struct hostent * --hostent_dup (struct hostent *hp) -+/** -+ * 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) - { -- 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; -+ struct addrinfo *ai = NULL; -+ struct addrinfo hint = { -+#ifdef IPV6_SUPPORTED -+ .ai_family = AF_UNSPEC, -+#else -+ .ai_family = AF_INET, -+#endif -+ /* 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; -+ } - -- return cp; -+ return NULL; - } - --static int --is_hostname(const char *sp) -+/** -+ * 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) - { -- if (*sp == '\0' || *sp == '@') -- return 0; -+ socklen_t salen = nfs_sockaddr_length(sap); -+ char buf[NI_MAXHOST]; -+ int error; -+ -+ if (salen == 0) { -+ xlog(D_GENERAL, "%s: unsupported address family %d", -+ __func__, sap->sa_family); -+ return NULL; -+ } - -- for (; *sp; sp++) -- { -- if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/') -- return 0; -- if (*sp == '\\' && sp[1]) -- sp++; -- } -+ 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; -+ } - -- return 1; -+ return strdup(buf); - } -- --int --matchhostname (const char *h1, const char *h2) -+#else /* !HAVE_GETNAMEINFO */ -+__attribute_malloc__ -+char * -+host_canonname(const struct sockaddr *sap) - { -- struct hostent *hp1, *hp2; -- int status; -+ const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap; -+ const struct in_addr *addr = &sin->sin_addr; -+ struct hostent *hp; - -- if (strcasecmp (h1, h2) == 0) -- return 1; -- -- if (!is_hostname (h1) || !is_hostname (h2)) -- return 0; -+ if (sap->sa_family != AF_INET) -+ 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; -- } -- } -- } -- else -- status = 0; -+ hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET); -+ if (hp == NULL) -+ return NULL; - -- free (hp1); -- return status; -+ 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 addrinfo *ai; -+ char *hostname; - -- struct hostent *reverse; -- struct hostent *forward; -- char **sp; -- -- 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 = nfs_sockaddr_length(sap); -+ char buf[INET6_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-16 16:29:35.228032467 -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-16 16:29:35.228032467 -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-16 16:29:35.229229714 -0400 -@@ -10,6 +10,8 @@ - #define EXPORTFS_H - - #include -+ -+#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-16 16:29:35.229229714 -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-16 16:29:35.230230090 -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; -@@ -134,9 +134,12 @@ int nfsaddclient(struct nfsctl_client - int nfsdelclient(struct nfsctl_client *clp); - int nfsexport(struct nfsctl_export *exp); - int nfsunexport(struct nfsctl_export *exp); --struct nfs_fh_len * getfh_old(struct sockaddr *addr, dev_t dev, ino_t ino); --struct nfs_fh_len * getfh(struct sockaddr *addr, const char *); --struct nfs_fh_len * getfh_size(struct sockaddr *addr, const char *, int size); -+ -+struct nfs_fh_len * getfh_old(const struct sockaddr_in *sin, -+ const dev_t dev, const ino_t ino); -+struct nfs_fh_len * getfh(const struct sockaddr_in *sin, const char *path); -+struct nfs_fh_len * getfh_size(const struct sockaddr_in *sin, -+ const char *path, int const size); - - void qword_print(FILE *f, char *str); - void qword_printhex(FILE *f, char *str, int slen); -@@ -152,10 +155,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-16 16:29:35.230230090 -0400 -@@ -27,6 +27,12 @@ - #include - - /* -+ * 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-16 16:29:35.231240528 -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-16 16:29:35.232229968 -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-16 16:29:35.232229968 -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/getfh.c.orig nfs-utils-1.2.2/support/nfs/getfh.c ---- nfs-utils-1.2.2/support/nfs/getfh.c.orig 2010-02-18 07:35:00.000000000 -0500 -+++ nfs-utils-1.2.2/support/nfs/getfh.c 2010-09-16 16:29:35.233230434 -0400 -@@ -19,60 +19,112 @@ - #include - #include "nfslib.h" - -+/** -+ * getfh_old - ask the kernel for an NFSv2 file handle via nfsctl() -+ * @sin: pointer to IPv4 address of a client -+ * @dev: device number of device where requested object resides -+ * @ino: inode number of requested object -+ * -+ * Returns a pointer to an NFSv2 file handle, or NULL if some error -+ * occurred. errno is set to reflect the specifics of the error. -+ */ - struct nfs_fh_len * --getfh_old (struct sockaddr *addr, dev_t dev, ino_t ino) -+getfh_old(const struct sockaddr_in *sin, const dev_t dev, const ino_t ino) - { - union nfsctl_res res; - struct nfsctl_arg arg; - static struct nfs_fh_len rfh; - -+ if (sin->sin_family != AF_INET) { -+ errno = EAFNOSUPPORT; -+ return NULL; -+ } -+ -+ memset(&arg, 0, sizeof(arg)); -+ memset(&res, 0, sizeof(res)); -+ - arg.ca_version = NFSCTL_VERSION; - arg.ca_getfh.gf_version = 2; /* obsolete */ - arg.ca_getfh.gf_dev = dev; - arg.ca_getfh.gf_ino = ino; -- memcpy(&arg.ca_getfh.gf_addr, addr, sizeof(struct sockaddr_in)); -+ memcpy(&arg.ca_getfh.gf_addr, sin, sizeof(*sin)); - - if (nfsctl(NFSCTL_GETFH, &arg, &res) < 0) - return NULL; - -+ memset(&rfh, 0, sizeof(rfh)); - rfh.fh_size = 32; - memcpy(rfh.fh_handle, &res.cr_getfh, 32); - return &rfh; - } - -+/** -+ * getfh - ask the kernel for an NFSv2 file handle via nfsctl() -+ * @sin: pointer to IPv4 address of a client -+ * @path: pointer to a '\0'-terminated ASCII string containing an pathname -+ * -+ * Returns a pointer to an NFSv2 file handle, or NULL if some error -+ * occurred. errno is set to reflect the specifics of the error. -+ */ - struct nfs_fh_len * --getfh(struct sockaddr *addr, const char *path) -+getfh(const struct sockaddr_in *sin, const char *path) - { - static union nfsctl_res res; - struct nfsctl_arg arg; - static struct nfs_fh_len rfh; - -+ if (sin->sin_family != AF_INET) { -+ errno = EAFNOSUPPORT; -+ return NULL; -+ } -+ -+ memset(&arg, 0, sizeof(arg)); -+ memset(&res, 0, sizeof(res)); -+ - arg.ca_version = NFSCTL_VERSION; - arg.ca_getfd.gd_version = 2; /* obsolete */ - strncpy(arg.ca_getfd.gd_path, path, - sizeof(arg.ca_getfd.gd_path) - 1); - arg.ca_getfd.gd_path[sizeof (arg.ca_getfd.gd_path) - 1] = '\0'; -- memcpy(&arg.ca_getfd.gd_addr, addr, sizeof(struct sockaddr_in)); -+ memcpy(&arg.ca_getfd.gd_addr, sin, sizeof(*sin)); - - if (nfsctl(NFSCTL_GETFD, &arg, &res) < 0) - return NULL; - -+ memset(&rfh, 0, sizeof(rfh)); - rfh.fh_size = 32; - memcpy(rfh.fh_handle, &res.cr_getfh, 32); - return &rfh; - } - -+/** -+ * getfh_size - ask the kernel for a file handle via nfsctl() -+ * @sin: pointer to IPv4 address of a client -+ * @path: pointer to a '\0'-terminated ASCII string containing an pathname -+ * @size: maximum size, in bytes, of the returned file handle -+ * -+ * Returns a pointer to an NFSv3 file handle, or NULL if some error -+ * occurred. errno is set to reflect the specifics of the error. -+ */ - struct nfs_fh_len * --getfh_size(struct sockaddr *addr, const char *path, int size) -+getfh_size(const struct sockaddr_in *sin, const char *path, const int size) - { - static union nfsctl_res res; - struct nfsctl_arg arg; - -+ if (sin->sin_family != AF_INET) { -+ errno = EAFNOSUPPORT; -+ return NULL; -+ } -+ -+ memset(&arg, 0, sizeof(arg)); -+ memset(&res, 0, sizeof(res)); -+ - arg.ca_version = NFSCTL_VERSION; - strncpy(arg.ca_getfs.gd_path, path, - sizeof(arg.ca_getfs.gd_path) - 1); - arg.ca_getfs.gd_path[sizeof (arg.ca_getfs.gd_path) - 1] = '\0'; -- memcpy(&arg.ca_getfs.gd_addr, addr, sizeof(struct sockaddr_in)); -+ memcpy(&arg.ca_getfs.gd_addr, sin, sizeof(*sin)); - arg.ca_getfs.gd_maxlen = size; - - if (nfsctl(NFSCTL_GETFS, &arg, &res) < 0) -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-16 16:29:35.234229813 -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-16 16:29:35.234229813 -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-16 16:29:35.235219822 -0400 -@@ -19,6 +19,18 @@ - #include - #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-16 16:29:35.236229903 -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-16 16:29:35.237240603 -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-16 16:29:35.236229903 -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-16 16:29:35.237240603 -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-16 15:40:15.598012398 -0400 -+++ nfs-utils-1.2.2/support/nsm/file.c 2010-09-16 16:29:35.238240456 -0400 -@@ -67,7 +67,9 @@ - #endif - - #include -+#ifdef HAVE_SYS_CAPABILITY_H - #include -+#endif - #include - #include - -@@ -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-16 16:29:35.239219806 -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-16 16:29:35.239219806 -0400 -+++ nfs-utils-1.2.2/tools/mountstats/Makefile.am 2010-09-16 16:29:35.239219806 -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-16 16:29:35.240054628 -0400 -+++ nfs-utils-1.2.2/tools/mountstats/mountstats.man 2010-09-16 16:29:35.240054628 -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 [" "] " " [ " "]" -+.SH DESCRIPTION -+The -+.B mountstats -+command displays NFS client statisitics on each given -+.I -+.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 -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-16 16:29:35.240054628 -0400 -+++ nfs-utils-1.2.2/tools/nfs-iostat/Makefile.am 2010-09-16 16:29:35.240054628 -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-16 16:29:35.241239795 -0400 -+++ nfs-utils-1.2.2/tools/nfs-iostat/nfsiostat.man 2010-09-16 16:29:35.241239795 -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 [[" "] [" "]] [" "][" "] -+.SH DESCRIPTION -+The -+.B nfsiostat -+command displays NFS client per-mount statisitics. -+.TP -+ -+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 -+ -+If the -+.I -+parameter is -+specified, the value of -+.I -+determines the number of reports generated at -+. -+seconds apart. if the interval parameter is -+specified without the -+.I -+parameter, the command generates reports continuously. -+.TP -+ -+Define below -+.TP -+ -+If one or more -+.I -+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 -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-16 16:29:35.241239795 -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-16 16:29:35.242230383 -0400 -@@ -12,20 +12,24 @@ - #include - #endif - -+#include -+#include - #include - #include - #include -+#include - #include - #include - #include - #include -+#include - #include - #include --#include "xmalloc.h" -+ -+#include "sockaddr.h" - #include "misc.h" - #include "nfslib.h" - #include "exportfs.h" --#include "xmalloc.h" - #include "xlog.h" - - static void export_all(int verbose); -@@ -34,13 +38,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 +56,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 +92,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 +115,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 +247,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 +256,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 +284,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 +302,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 +345,7 @@ unexportfs(char *arg, int verbose) - exp->m_mayexport = 0; - } - -- if (hp) free (hp); -+ freeaddrinfo(ai); - } - - static int can_test(void) -@@ -393,14 +397,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 +415,75 @@ 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 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 (nfs_compare_sockaddr(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 +585,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-16 16:29:35.243229775 -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-16 16:29:35.243229775 -0400 -@@ -42,6 +42,7 @@ - #include - #include - #include -+#include - - #include - -@@ -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-16 16:29:35.244230359 -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 - #include - #include -+#include - #include - #include - #include -@@ -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-16 16:29:35.245220304 -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-16 16:29:35.245220304 -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-16 16:29:35.246249932 -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-16 16:29:35.247230807 -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-16 16:29:35.248210613 -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-16 16:29:35.248210613 -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-16 16:29:35.249273951 -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-16 16:29:35.250239931 -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-16 16:29:35.250239931 -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 = "", -+ .ic_id = "Server", -+ .ic_path = IC_IDNAME_CHAN, -+ .ic_fd = -1, -+ .ic_dirfd = -1, -+ .ic_scanned = 0 -+}, -+{ -+ .ic_which = IC_NAMEID, -+ .ic_clid = "", -+ .ic_id = "Server", -+ .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-16 16:29:35.251230426 -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-16 16:29:35.257230538 -0400 -@@ -15,6 +15,8 @@ - #include - #include - #include -+ -+#include "sockaddr.h" - #include "misc.h" - #include "nfslib.h" - #include "exportfs.h" -@@ -110,13 +112,16 @@ 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(const struct sockaddr *caller, struct addrinfo *ai, -+ enum auth_error *error) - { -+ char buf[INET6_ADDRSTRLEN]; - char *n; - - if (use_ipaddr) -- return strdup(inet_ntoa(caller->sin_addr)); -- n = client_compose(hp); -+ return strdup(host_ntop(caller, buf, sizeof(buf))); -+ n = client_compose(ai); - *error = unknown_host; - if (!n) - return NULL; -@@ -128,8 +133,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(const struct sockaddr *caller, -+ const char *path, struct addrinfo *ai, - enum auth_error *error) - { - nfs_export *exp; -@@ -137,12 +142,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(&my_client, 0, caller); - my_exp.m_client = &my_client; - - exp = NULL; -@@ -152,7 +157,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 +171,18 @@ auth_authenticate_newcache(char *what, s - } - - static nfs_export * --auth_authenticate_internal(char *what, struct sockaddr_in *caller, -- char *path, struct hostent *hp, -- enum auth_error *error) -+auth_authenticate_internal(const struct sockaddr *caller, const 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; - } -@@ -187,7 +192,7 @@ auth_authenticate_internal(char *what, s - return NULL; - } - if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) && -- ntohs(caller->sin_port) >= IPPORT_RESERVED) { -+ nfs_get_port(caller) >= IPPORT_RESERVED) { - *error = illegal_port; - return NULL; - } -@@ -197,18 +202,19 @@ auth_authenticate_internal(char *what, s - } - - nfs_export * --auth_authenticate(char *what, struct sockaddr_in *caller, char *path) -+auth_authenticate(const char *what, const struct sockaddr *caller, -+ const char *path) - { - nfs_export *exp = NULL; - char epath[MAXPATHLEN+1]; - char *p = NULL; -- struct hostent *hp = NULL; -- struct in_addr addr = caller->sin_addr; -+ char buf[INET6_ADDRSTRLEN]; -+ struct addrinfo *ai = NULL; - enum auth_error error = bad_path; - -- if (path [0] != '/') { -- xlog(L_WARNING, "bad path in %s request from %s: \"%s\"", -- what, inet_ntoa(addr), path); -+ if (path[0] != '/') { -+ xlog(L_WARNING, "Bad path in %s request from %s: \"%s\"", -+ what, host_ntop(caller, buf, sizeof(buf)), path); - return exp; - } - -@@ -216,14 +222,13 @@ 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(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. */ -@@ -236,41 +241,40 @@ auth_authenticate(char *what, struct soc - switch (error) { - case bad_path: - xlog(L_WARNING, "bad path in %s request from %s: \"%s\"", -- what, inet_ntoa(addr), path); -+ what, host_ntop(caller, buf, sizeof(buf)), path); - break; - - case unknown_host: - xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host", -- what, inet_ntoa(addr), path, epath); -+ what, host_ntop(caller, buf, sizeof(buf)), path, epath); - break; - - 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)); -+ xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %u", -+ what, ai->ai_canonname, path, epath, nfs_get_port(caller)); - 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); -+ xlog(L_NOTICE, "authenticated %s request from %s:%u for %s (%s)", -+ what, ai->ai_canonname, nfs_get_port(caller), 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); -+ xlog(L_NOTICE, "%s request from %s:%u for %s (%s) gave %d", -+ what, ai->ai_canonname, nfs_get_port(caller), -+ 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-16 16:29:35.258229814 -0400 -@@ -37,6 +37,11 @@ - #include "blkid/blkid.h" - #endif - -+/* -+ * Invoked by RPC service loop -+ */ -+void cache_set_fds(fd_set *fdset); -+int cache_process_req(fd_set *readfds); - - enum nfsd_fsid { - FSID_DEV = 0, -@@ -57,14 +62,14 @@ enum nfsd_fsid { - * Record is terminated with newline. - * - */ --int cache_export_ent(char *domain, struct exportent *exp, char *p); -+static int cache_export_ent(char *domain, struct exportent *exp, char *p); - - - char *lbuf = NULL; - int lbuflen = 0; - extern int use_ipaddr; - --void auth_unix_ip(FILE *f) -+static void auth_unix_ip(FILE *f) - { - /* requests are - * class IP-ADDR -@@ -75,10 +80,10 @@ void auth_unix_ip(FILE *f) - */ - char *cp; - char class[20]; -- char ipaddr[20]; -+ char ipaddr[INET6_ADDRSTRLEN]; - 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; - -@@ -90,20 +95,23 @@ void auth_unix_ip(FILE *f) - strcmp(class, "nfsd") != 0) - return; - -- if (qword_get(&cp, ipaddr, 20) <= 0) -+ if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 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,18 +122,17 @@ 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) -+static void auth_unix_gid(FILE *f) - { - /* Request are - * uid - * 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 +143,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 +160,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; imnt_dir; - } - --void nfsd_fh(FILE *f) -+static void nfsd_fh(FILE *f) - { - /* request are: - * domain fsidtype fsid -@@ -294,8 +345,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 +448,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 +512,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 +592,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 +653,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 +671,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 +686,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 +710,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; -@@ -687,7 +747,7 @@ static nfs_export *lookup_export(char *d - return found; - } - --void nfsd_export(FILE *f) -+static void nfsd_export(FILE *f) - { - /* requests are: - * domain path -@@ -698,9 +758,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 +780,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 +805,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,14 +814,19 @@ 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; -+ -+/** -+ * cache_open - prepare communications channels with kernel RPC caches -+ * -+ */ - void cache_open(void) - { - int i; -@@ -772,6 +839,10 @@ void cache_open(void) - } - } - -+/** -+ * cache_set_fds - prepare cache file descriptors for one iteration of the service loop -+ * @fdset: pointer to fd_set to prepare -+ */ - void cache_set_fds(fd_set *fdset) - { - int i; -@@ -781,6 +852,10 @@ void cache_set_fds(fd_set *fdset) - } - } - -+/** -+ * cache_process_req - process any active cache file descriptors during service loop iteration -+ * @fdset: pointer to fd_set to examine for activity -+ */ - int cache_process_req(fd_set *readfds) - { - int i; -@@ -803,7 +878,7 @@ int cache_process_req(fd_set *readfds) - * % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel - */ - --int cache_export_ent(char *domain, struct exportent *exp, char *path) -+static int cache_export_ent(char *domain, struct exportent *exp, char *path) - { - int err; - FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w"); -@@ -824,8 +899,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) -@@ -861,8 +936,14 @@ int cache_export_ent(char *domain, struc - return err; - } - -+/** -+ * cache_export - Inform kernel of a new nfs_export -+ * @exp: target nfs_export -+ * @path: NUL-terminated C string containing export path -+ */ - int cache_export(nfs_export *exp, char *path) - { -+ char buf[INET6_ADDRSTRLEN]; - int err; - FILE *f; - -@@ -870,8 +951,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); -@@ -883,7 +966,14 @@ int cache_export(nfs_export *exp, char * - return err; - } - --/* Get a filehandle. -+/** -+ * cache_get_filehandle - given an nfs_export, get its root filehandle -+ * @exp: target nfs_export -+ * @len: length of requested file handle -+ * @p: NUL-terminated C string containing export path -+ * -+ * Returns pointer to NFS file handle of root directory of export -+ * - * { - * echo $domain $path $length - * read filehandle <&0 -@@ -917,4 +1007,3 @@ cache_get_filehandle(nfs_export *exp, in - fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE); - return &fh; - } -- -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-16 16:29:35.259209794 -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-16 16:29:35.260229826 -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-16 16:29:35.260229826 -0400 -@@ -28,10 +28,6 @@ - #include "rpcmisc.h" - #include "pseudoflavors.h" - --extern void cache_open(void); --extern struct nfs_fh_len *cache_get_filehandle(nfs_export *exp, int len, char *p); --extern int cache_export(nfs_export *exp, char *path); -- - extern void my_svc_run(void); - - static void usage(const char *, int exitcode); -@@ -80,10 +76,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,17 +188,28 @@ 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 *rqstp, void *UNUSED(argp), -+ void *UNUSED(resp)) - { -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); -+ char buf[INET6_ADDRSTRLEN]; -+ -+ xlog(D_CALL, "Received NULL request from %s", -+ host_ntop(sap, buf, sizeof(buf))); -+ - return 1; - } - - bool_t - mount_mnt_1_svc(struct svc_req *rqstp, dirpath *path, fhstatus *res) - { -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); -+ char buf[INET6_ADDRSTRLEN]; - struct nfs_fh_len *fh; - -- xlog(D_CALL, "MNT1(%s) called", *path); -+ xlog(D_CALL, "Received MNT1(%s) request from %s", *path, -+ host_ntop(sap, buf, sizeof(buf))); -+ - fh = get_rootfh(rqstp, path, NULL, &res->fhs_status, 0); - if (fh) - memcpy(&res->fhstatus_u.fhs_fhandle, fh->fh_handle, 32); -@@ -210,23 +217,27 @@ 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); -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); -+ char buf[INET6_ADDRSTRLEN]; -+ -+ xlog(D_CALL, "Received DUMP request from %s", -+ host_ntop(sap, buf, sizeof(buf))); - -- xlog(D_CALL, "dump request from %s.", inet_ntoa(addr->sin_addr)); - *res = mountlist_list(); - - return 1; - } - - 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); -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); - nfs_export *exp; - char *p = *argp; - char rpath[MAXPATHLEN+1]; -+ char buf[INET6_ADDRSTRLEN]; - - if (*p == '\0') - p = "/"; -@@ -236,41 +247,57 @@ mount_umnt_1_svc(struct svc_req *rqstp, - p = rpath; - } - -- if (!(exp = auth_authenticate("unmount", sin, p))) { -+ xlog(D_CALL, "Received UMNT(%s) request from %s", p, -+ host_ntop(sap, buf, sizeof(buf))); -+ -+ exp = auth_authenticate("unmount", sap, p); -+ if (exp == NULL) - return 1; -- } - -- mountlist_del(inet_ntoa(sin->sin_addr), p); -+ mountlist_del(host_ntop(sap, buf, sizeof(buf)), p); - return 1; - } - - 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)) - { -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); -+ char buf[INET6_ADDRSTRLEN]; -+ -+ xlog(D_CALL, "Received UMNTALL request from %s", -+ host_ntop(sap, buf, sizeof(buf))); -+ - /* Reload /etc/xtab if necessary */ - auth_reload(); - -- mountlist_del_all(nfs_getrpccaller_in(rqstp->rq_xprt)); -+ mountlist_del_all(nfs_getrpccaller(rqstp->rq_xprt)); - return 1; - } - - 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); -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); -+ char buf[INET6_ADDRSTRLEN]; -+ -+ xlog(D_CALL, "Received EXPORT request from %s.", -+ host_ntop(sap, buf, sizeof(buf))); - -- xlog(D_CALL, "export request from %s.", inet_ntoa(addr->sin_addr)); - *resp = get_exportlist(); - - return 1; - } - - 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); -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); -+ char buf[INET6_ADDRSTRLEN]; -+ -+ xlog(D_CALL, "Received EXPORTALL request from %s.", -+ host_ntop(sap, buf, sizeof(buf))); - -- xlog(D_CALL, "exportall request from %s.", inet_ntoa(addr->sin_addr)); - *resp = get_exportlist(); - - return 1; -@@ -290,11 +317,12 @@ mount_exportall_1_svc(struct svc_req *rq - bool_t - mount_pathconf_2_svc(struct svc_req *rqstp, dirpath *path, ppathcnf *res) - { -- struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); - struct stat stb; - nfs_export *exp; - char rpath[MAXPATHLEN+1]; - char *p = *path; -+ char buf[INET6_ADDRSTRLEN]; - - memset(res, 0, sizeof(*res)); - -@@ -310,11 +338,14 @@ mount_pathconf_2_svc(struct svc_req *rqs - p = rpath; - } - -+ xlog(D_CALL, "Received PATHCONF(%s) request from %s", p, -+ host_ntop(sap, buf, sizeof(buf))); -+ - /* Now authenticate the intruder... */ -- exp = auth_authenticate("pathconf", sin, p); -- if (!exp) { -+ exp = auth_authenticate("pathconf", sap, p); -+ if (exp == NULL) - return 1; -- } else if (stat(p, &stb) < 0) { -+ else if (stat(p, &stb) < 0) { - xlog(L_WARNING, "can't stat exported dir %s: %s", - p, strerror(errno)); - return 1; -@@ -374,11 +405,15 @@ static void set_authflavors(struct mount - bool_t - mount_mnt_3_svc(struct svc_req *rqstp, dirpath *path, mountres3 *res) - { -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); - struct mountres3_ok *ok = &res->mountres3_u.mountinfo; -+ char buf[INET6_ADDRSTRLEN]; - nfs_export *exp; - struct nfs_fh_len *fh; - -- xlog(D_CALL, "MNT3(%s) called", *path); -+ xlog(D_CALL, "Received MNT3(%s) request from %s", *path, -+ host_ntop(sap, buf, sizeof(buf))); -+ - fh = get_rootfh(rqstp, path, &exp, &res->fhs_status, 1); - if (!fh) - return 1; -@@ -393,12 +428,13 @@ static struct nfs_fh_len * - get_rootfh(struct svc_req *rqstp, dirpath *path, nfs_export **expret, - mountstat3 *error, int v3) - { -- struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); -+ struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); - struct stat stb, estb; - nfs_export *exp; - struct nfs_fh_len *fh; - char rpath[MAXPATHLEN+1]; - char *p = *path; -+ char buf[INET6_ADDRSTRLEN]; - - if (*p == '\0') - p = "/"; -@@ -413,8 +449,8 @@ get_rootfh(struct svc_req *rqstp, dirpat - } - - /* Now authenticate the intruder... */ -- exp = auth_authenticate("mount", sin, p); -- if (!exp) { -+ exp = auth_authenticate("mount", sap, p); -+ if (exp == NULL) { - *error = NFSERR_ACCES; - return NULL; - } -@@ -482,13 +518,13 @@ get_rootfh(struct svc_req *rqstp, dirpat - xtab_append(exp); - - if (v3) -- fh = getfh_size ((struct sockaddr *) sin, p, 64); -+ fh = getfh_size((struct sockaddr_in *)sap, p, 64); - if (!v3 || (fh == NULL && errno == EINVAL)) { - /* We first try the new nfs syscall. */ -- fh = getfh ((struct sockaddr *) sin, p); -+ fh = getfh((struct sockaddr_in *)sap, p); - if (fh == NULL && errno == EINVAL) - /* Let's try the old one. */ -- fh = getfh_old ((struct sockaddr *) sin, -+ fh = getfh_old((struct sockaddr_in *)sap, - stb.st_dev, stb.st_ino); - } - if (fh == NULL && !did_export) { -@@ -503,7 +539,7 @@ get_rootfh(struct svc_req *rqstp, dirpat - } - } - *error = NFS_OK; -- mountlist_add(inet_ntoa(sin->sin_addr), p); -+ mountlist_add(host_ntop(sap, buf, sizeof(buf)), p); - if (expret) - *expret = exp; - return fh; -@@ -536,22 +572,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 +747,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 +798,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/mountd.h.orig nfs-utils-1.2.2/utils/mountd/mountd.h ---- nfs-utils-1.2.2/utils/mountd/mountd.h.orig 2010-02-18 07:35:00.000000000 -0500 -+++ nfs-utils-1.2.2/utils/mountd/mountd.h 2010-09-16 16:29:35.261220190 -0400 -@@ -41,14 +41,19 @@ bool_t mount_mnt_3_svc(struct svc_req * - void mount_dispatch(struct svc_req *, SVCXPRT *); - void auth_init(char *export_file); - unsigned int auth_reload(void); --nfs_export * auth_authenticate(char *what, struct sockaddr_in *sin, -- char *path); -+nfs_export * auth_authenticate(const char *what, -+ const struct sockaddr *caller, -+ const char *path); - void auth_export(nfs_export *exp); - - void mountlist_add(char *host, const char *path); - void mountlist_del(char *host, const char *path); --void mountlist_del_all(struct sockaddr_in *sin); -+void mountlist_del_all(const struct sockaddr *sap); - mountlist mountlist_list(void); - -+void cache_open(void); -+struct nfs_fh_len * -+ cache_get_filehandle(nfs_export *exp, int len, char *p); -+int cache_export(nfs_export *exp, char *path); - - #endif /* MOUNTD_H */ -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-16 16:29:35.261220190 -0400 -@@ -16,7 +16,7 @@ - #include - #include - #include --#include "xmalloc.h" -+ - #include "misc.h" - #include "exportfs.h" - #include "xio.h" -@@ -131,22 +131,22 @@ mountlist_del(char *hname, const char *p - } - - void --mountlist_del_all(struct sockaddr_in *sin) -+mountlist_del_all(const struct sockaddr *sap) - { -- struct in_addr addr = sin->sin_addr; -- struct hostent *hp; -+ char *hostname; - struct rmtabent *rep; -- nfs_export *exp; - FILE *fp; - int lockid; - - 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(sap); -+ if (hostname == NULL) { -+ char buf[INET6_ADDRSTRLEN]; -+ xlog(L_ERROR, "can't get hostname of %s", -+ host_ntop(sap, buf, sizeof(buf))); - goto out_unlock; - } -- hp = hostent_dup (hp); - - if (!setrmtabent("r")) - goto out_free; -@@ -155,8 +155,8 @@ 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 && -- (exp = auth_authenticate("umountall", sin, rep->r_path))) -+ if (strcmp(rep->r_client, hostname) == 0 && -+ auth_authenticate("umountall", sap, rep->r_path) != NULL) - continue; - fputrmtabent(fp, rep, NULL); - } -@@ -168,11 +168,23 @@ mountlist_del_all(struct sockaddr_in *si - out_close: - endrmtabent(); /* close & unlink */ - out_free: -- free (hp); -+ free(hostname); - out_unlock: - xfunlock(lockid); - } - -+static void -+mountlist_freeall(mountlist list) -+{ -+ while (list != NULL) { -+ mountlist m = list; -+ list = m->ml_next; -+ free(m->ml_hostname); -+ free(m->ml_directory); -+ free(m); -+ } -+} -+ - mountlist - mountlist_list(void) - { -@@ -182,8 +194,6 @@ mountlist_list(void) - struct rmtabent *rep; - struct stat stb; - int lockid; -- struct in_addr addr; -- struct hostent *he; - - if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0) - return NULL; -@@ -194,26 +204,41 @@ mountlist_list(void) - return NULL; - } - if (stb.st_mtime != last_mtime) { -- while (mlist) { -- mlist = (m = mlist)->ml_next; -- xfree(m->ml_hostname); -- xfree(m->ml_directory); -- xfree(m); -- } -+ mountlist_freeall(mlist); - last_mtime = stb.st_mtime; - - setrmtabent("r"); - while ((rep = getrmtabent(1, NULL)) != NULL) { -- m = (mountlist) xmalloc(sizeof(*m)); -- -- if (reverse_resolve && -- inet_aton((const char *) rep->r_client, &addr) && -- (he = gethostbyaddr(&addr, sizeof(addr), AF_INET))) -- m->ml_hostname = xstrdup(he->h_name); -- else -- m->ml_hostname = xstrdup(rep->r_client); -+ m = calloc(1, sizeof(*m)); -+ if (m == NULL) { -+ mountlist_freeall(mlist); -+ mlist = NULL; -+ xlog(L_ERROR, "%s: memory allocation failed", -+ __func__); -+ break; -+ } -+ -+ if (reverse_resolve) { -+ struct addrinfo *ai; -+ ai = host_pton(rep->r_client); -+ if (ai != NULL) { -+ m->ml_hostname = host_canonname(ai->ai_addr); -+ freeaddrinfo(ai); -+ } -+ } -+ if (m->ml_hostname == NULL) -+ m->ml_hostname = strdup(rep->r_client); -+ -+ m->ml_directory = strdup(rep->r_path); -+ -+ if (m->ml_hostname == NULL || m->ml_directory == NULL) { -+ mountlist_freeall(mlist); -+ mlist = NULL; -+ xlog(L_ERROR, "%s: memory allocation failed", -+ __func__); -+ break; -+ } - -- m->ml_directory = xstrdup(rep->r_path); - m->ml_next = mlist; - mlist = m; - } -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-16 16:29:35.252229853 -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-16 16:29:35.254210443 -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-16 16:29:35.253220019 -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-16 16:29:35.255249968 -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-16 16:29:35.255249968 -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-16 16:29:35.256219797 -0400 -@@ -302,11 +302,16 @@ 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; -- } -+ -+ /* -+ * Before 2.6.32, the kernel NFS client didn't -+ * support "-t nfs vers=4" mounts, so NFS version -+ * 4 cannot be included when autonegotiating -+ * while running on those kernels. -+ */ -+ if (mi->version == 0 && -+ linux_version_code() <= MAKE_VERSION(2, 6, 31)) -+ mi->version = 3; - - /* - * If we still don't know, check for version-specific -@@ -490,14 +495,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 +547,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 +598,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; - } - -@@ -741,6 +756,47 @@ static int nfs_try_mount_v4(struct nfsmo - } - - /* -+ * Handle NFS version and transport protocol -+ * autonegotiation. -+ * -+ * When no version or protocol is specified on the -+ * command line, mount.nfs negotiates with the server -+ * to determine appropriate settings for the new -+ * mount point. -+ * -+ * Returns TRUE if successful, otherwise FALSE. -+ * "errno" is set to reflect the individual error. -+ */ -+static int nfs_autonegotiate(struct nfsmount_info *mi) -+{ -+ int result; -+ -+ result = nfs_try_mount_v4(mi); -+ if (result) -+ return result; -+ -+ switch (errno) { -+ case EPROTONOSUPPORT: -+ /* A clear indication that the server or our -+ * client does not support NFS version 4. */ -+ goto fall_back; -+ case ENOENT: -+ /* Legacy Linux servers don't export an NFS -+ * version 4 pseudoroot. */ -+ goto fall_back; -+ case EPERM: -+ /* Linux servers prior to 2.6.25 may return -+ * EPERM when NFS version 4 is not supported. */ -+ goto fall_back; -+ default: -+ return result; -+ } -+ -+fall_back: -+ return nfs_try_mount_v3v2(mi); -+} -+ -+/* - * This is a single pass through the fg/bg loop. - * - * Returns TRUE if successful, otherwise FALSE. -@@ -752,20 +808,8 @@ static int nfs_try_mount(struct nfsmount - - switch (mi->version) { - case 0: -- if (linux_version_code() > MAKE_VERSION(2, 6, 31)) { -- errno = 0; -- result = nfs_try_mount_v4(mi); -- if (errno != EPROTONOSUPPORT) { -- /* -- * To deal with legacy Linux servers that don't -- * automatically export a pseudo root, retry -- * ENOENT errors using version 3. And for -- * Linux servers prior to 2.6.25, retry EPERM -- */ -- if (errno != ENOENT && errno != EPERM) -- break; -- } -- } -+ result = nfs_autonegotiate(mi); -+ break; - case 2: - case 3: - result = nfs_try_mount_v3v2(mi); -@@ -799,6 +843,7 @@ static int nfs_is_permanent_error(int er - case ESTALE: - case ETIMEDOUT: - case ECONNREFUSED: -+ case EHOSTUNREACH: - return 0; /* temporary */ - default: - return 1; /* permanent */ -@@ -922,6 +967,26 @@ static int nfsmount_bg(struct nfsmount_i - } - - /* -+ * Usually all that is needed for an NFS remount is to change -+ * generic mount options like "sync" or "ro". These generic -+ * options are controlled by mi->flags, not by text-based -+ * options, and no contact with the server is needed. -+ * -+ * Take care with the /etc/mtab entry for this mount; just -+ * calling update_mtab() will change an "-t nfs -o vers=4" -+ * mount to an "-t nfs -o remount" mount, and that will -+ * confuse umount.nfs. -+ * -+ * Returns a valid mount command exit code. -+ */ -+static int nfs_remount(struct nfsmount_info *mi) -+{ -+ if (nfs_sys_mount(mi, mi->options)) -+ return EX_SUCCESS; -+ return EX_FAIL; -+} -+ -+/* - * Process mount options and try a mount system call. - * - * Returns a valid mount command exit code. -@@ -937,6 +1002,12 @@ static int nfsmount_start(struct nfsmoun - if (!nfs_validate_options(mi)) - return EX_FAIL; - -+ /* -+ * Avoid retry and negotiation logic when remounting -+ */ -+ if (mi->flags & MS_REMOUNT) -+ return nfs_remount(mi); -+ - if (po_rightmost(mi->options, nfs_background_opttbl) == 0) - return nfsmount_bg(mi); - else -@@ -953,6 +1024,8 @@ static int nfsmount_start(struct nfsmoun - * (input and output argument) - * @fake: flag indicating whether to carry out the whole operation - * @child: one if this is a mount daemon (bg) -+ * -+ * Returns a valid mount command exit code. - */ - int nfsmount_string(const char *spec, const char *node, const char *type, - int flags, char **extra_opts, int fake, int child) -diff -up nfs-utils-1.2.2/utils/nfsd/nfsd.c.orig nfs-utils-1.2.2/utils/nfsd/nfsd.c ---- nfs-utils-1.2.2/utils/nfsd/nfsd.c.orig 2010-02-18 07:35:00.000000000 -0500 -+++ nfs-utils-1.2.2/utils/nfsd/nfsd.c 2010-09-16 16:29:35.262240028 -0400 -@@ -246,6 +246,9 @@ main(int argc, char **argv) - exit(1); - } - -+ /* make sure nfsdfs is mounted if it's available */ -+ nfssvc_mount_nfsdfs(progname); -+ - /* can only change number of threads if nfsd is already up */ - if (nfssvc_inuse()) { - socket_up = 1; -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-16 16:29:35.263239998 -0400 -@@ -15,9 +15,11 @@ - #include - #include - #include -+#include - #include - #include - #include -+#include - - #include "nfslib.h" - #include "xlog.h" -@@ -31,9 +33,13 @@ - */ - #undef IPV6_SUPPORTED - --#define NFSD_PORTS_FILE "/proc/fs/nfsd/portlist" --#define NFSD_VERS_FILE "/proc/fs/nfsd/versions" --#define NFSD_THREAD_FILE "/proc/fs/nfsd/threads" -+#ifndef NFSD_FS_DIR -+#define NFSD_FS_DIR "/proc/fs/nfsd" -+#endif -+ -+#define NFSD_PORTS_FILE NFSD_FS_DIR "/portlist" -+#define NFSD_VERS_FILE NFSD_FS_DIR "/versions" -+#define NFSD_THREAD_FILE NFSD_FS_DIR "/threads" - - /* - * declaring a common static scratch buffer here keeps us from having to -@@ -44,6 +50,46 @@ - char buf[128]; - - /* -+ * Using the "new" interfaces for nfsd requires that /proc/fs/nfsd is -+ * actually mounted. Make an attempt to mount it here if it doesn't appear -+ * to be. If the mount attempt fails, no big deal -- fall back to using nfsctl -+ * instead. -+ */ -+void -+nfssvc_mount_nfsdfs(char *progname) -+{ -+ int err; -+ struct stat statbuf; -+ -+ err = stat(NFSD_THREAD_FILE, &statbuf); -+ if (err == 0) -+ return; -+ -+ if (errno != ENOENT) { -+ xlog(L_ERROR, "Unable to stat %s: errno %d (%m)", -+ NFSD_THREAD_FILE, errno); -+ return; -+ } -+ -+ /* -+ * this call can return an error if modprobe is set up to automatically -+ * mount nfsdfs when nfsd.ko is plugged in. So, ignore the return -+ * code from it and just check for the "threads" file afterward. -+ */ -+ system("/bin/mount -t nfsd nfsd " NFSD_FS_DIR " >/dev/null 2>&1"); -+ -+ err = stat(NFSD_THREAD_FILE, &statbuf); -+ if (err == 0) -+ return; -+ -+ xlog(L_WARNING, "Unable to access " NFSD_FS_DIR " errno %d (%m)." -+ "\nPlease try, as root, 'mount -t nfsd nfsd " NFSD_FS_DIR -+ "' and then restart %s to correct the problem", errno, progname); -+ -+ return; -+} -+ -+/* - * Are there already sockets configured? If not, then it is safe to try to - * open some and pass them through. - * -@@ -181,7 +227,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 +297,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 +323,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/nfsd/nfssvc.h.orig nfs-utils-1.2.2/utils/nfsd/nfssvc.h ---- nfs-utils-1.2.2/utils/nfsd/nfssvc.h.orig 2010-02-18 07:35:00.000000000 -0500 -+++ nfs-utils-1.2.2/utils/nfsd/nfssvc.h 2010-09-16 16:29:35.263239998 -0400 -@@ -20,6 +20,7 @@ - * - */ - -+void nfssvc_mount_nfsdfs(char *progname); - int nfssvc_inuse(void); - int nfssvc_set_sockets(const int family, const unsigned int protobits, - const char *host, const char *port); -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-16 16:29:35.264239903 -0400 -@@ -31,7 +31,7 @@ enum { - SRVPROC3_SZ = 22, - CLTPROC3_SZ = 22, - SRVPROC4_SZ = 2, -- CLTPROC4_SZ = 48, -+ CLTPROC4_SZ = 49, - SRVPROC4OPS_SZ = 59, - }; - -@@ -118,6 +118,7 @@ static const char * nfscltproc4name[CLTP - "remove", "rename", "link", "symlink", "create", "pathconf", - "statfs", "readlink", "readdir", "server_caps", "delegreturn", "getacl", - "setacl", "fs_locations", -+ "rel_lkowner", - /* nfsv4.1 client ops */ - "exchange_id", - "create_ses", -@@ -791,7 +792,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 +817,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 +1119,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-16 16:29:35.264239903 -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-16 16:29:35.265220019 -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-16 16:29:35.266239946 -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-16 15:40:15.595012524 -0400 -+++ nfs-utils-1.2.2/utils/statd/sm-notify.man 2010-09-16 16:29:35.266239946 -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-16 15:40:15.595012524 -0400 -+++ nfs-utils-1.2.2/utils/statd/statd.man 2010-09-16 16:29:35.267229816 -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-1.2.4-rc1.patch b/nfs-utils-1.2.4-rc1.patch deleted file mode 100644 index 849b533..0000000 --- a/nfs-utils-1.2.4-rc1.patch +++ /dev/null @@ -1,1378 +0,0 @@ -diff --git a/support/export/client.c b/support/export/client.c -index dbfc2b1..ba2db8f 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -178,6 +178,7 @@ out_badprefix: - static int - init_netmask6(nfs_client *UNUSED(clp), const char *UNUSED(slash)) - { -+ return 0; - } - #endif /* IPV6_SUPPORTED */ - -diff --git a/support/export/export.c b/support/export/export.c -index f528603..4fda30a 100644 ---- a/support/export/export.c -+++ b/support/export/export.c -@@ -38,6 +38,7 @@ export_free(nfs_export *exp) - xfree(exp->m_export.e_sqgids); - free(exp->m_export.e_mountpoint); - free(exp->m_export.e_fslocdata); -+ free(exp->m_export.e_uuid); - - xfree(exp->m_export.e_hostname); - xfree(exp); -diff --git a/support/include/nfslib.h b/support/include/nfslib.h -index 3db5bec..53ece0e 100644 ---- a/support/include/nfslib.h -+++ b/support/include/nfslib.h -@@ -163,6 +163,12 @@ void closeall(int min); - int svctcp_socket (u_long __number, int __reuse); - int svcudp_socket (u_long __number); - -+/* Misc shared code prototypes */ -+size_t strlcat(char *, const char *, size_t); -+size_t strlcpy(char *, const char *, size_t); -+ssize_t atomicio(ssize_t (*f) (int, void*, size_t), -+ int, void *, size_t); -+ - - #define UNUSED(x) UNUSED_ ## x __attribute__((unused)) - -diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am -index 60400b2..05c2fc4 100644 ---- a/support/nfs/Makefile.am -+++ b/support/nfs/Makefile.am -@@ -5,7 +5,7 @@ libnfs_a_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ - xlog.c xcommon.c wildmat.c nfsclient.c \ - nfsexport.c getfh.c nfsctl.c rpc_socket.c getport.c \ - svc_socket.c cacheio.c closeall.c nfs_mntent.c conffile.c \ -- svc_create.c -+ svc_create.c atomicio.c strlcpy.c strlcat.c - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/support/nfs/atomicio.c b/support/nfs/atomicio.c -new file mode 100644 -index 0000000..5e760e6 ---- /dev/null -+++ b/support/nfs/atomicio.c -@@ -0,0 +1,54 @@ -+/* -+ * Copyright (c) 2002 Marius Aamodt Eriksen -+ * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include -+#include -+#include -+ -+/* -+ * ensure all of data on socket comes through. f==read || f==write -+ */ -+ssize_t atomicio(ssize_t(*f) (int, void *, size_t), int fd, void *_s, size_t n) -+{ -+ char *s = _s; -+ ssize_t res, pos = 0; -+ -+ while ((ssize_t)n > pos) { -+ res = (f) (fd, s + pos, n - pos); -+ switch (res) { -+ case -1: -+ if (errno == EINTR || errno == EAGAIN) -+ continue; -+ case 0: -+ if (pos != 0) -+ return pos; -+ return res; -+ default: -+ pos += res; -+ } -+ } -+ return pos; -+} -diff --git a/support/nfs/exports.c b/support/nfs/exports.c -index a93941c..1744ed6 100644 ---- a/support/nfs/exports.c -+++ b/support/nfs/exports.c -@@ -332,6 +332,8 @@ dupexportent(struct exportent *dst, struct exportent *src) - dst->e_mountpoint = strdup(src->e_mountpoint); - if (src->e_fslocdata) - dst->e_fslocdata = strdup(src->e_fslocdata); -+ if (src->e_uuid) -+ dst->e_uuid = strdup(src->e_uuid); - dst->e_hostname = NULL; - } - -diff --git a/support/nfs/strlcat.c b/support/nfs/strlcat.c -new file mode 100644 -index 0000000..daedd7a ---- /dev/null -+++ b/support/nfs/strlcat.c -@@ -0,0 +1,76 @@ -+/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ -+ -+/* -+ * Copyright (c) 1998 Todd C. Miller -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#if defined(LIBC_SCCS) && !defined(lint) -+static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"; -+#endif /* LIBC_SCCS and not lint */ -+ -+#include -+#include -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif /* HAVE_CONFIG_H */ -+ -+/* -+ * Appends src to string dst of size siz (unlike strncat, siz is the -+ * full size of dst, not space left). At most siz-1 characters -+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)). -+ * Returns strlen(src) + MIN(siz, strlen(initial dst)). -+ * If retval >= siz, truncation occurred. -+ */ -+size_t -+strlcat(char *dst, -+ const char *src, -+ size_t siz) -+{ -+ register char *d = dst; -+ register const char *s = src; -+ register size_t n = siz; -+ size_t dlen; -+ -+ /* Find the end of dst and adjust bytes left but don't go past end */ -+ while (n-- != 0 && *d != '\0') -+ d++; -+ dlen = d - dst; -+ n = siz - dlen; -+ -+ if (n == 0) -+ return(dlen + strlen(s)); -+ while (*s != '\0') { -+ if (n != 1) { -+ *d++ = *s; -+ n--; -+ } -+ s++; -+ } -+ *d = '\0'; -+ -+ return(dlen + (s - src)); /* count does not include NUL */ -+} -diff --git a/support/nfs/strlcpy.c b/support/nfs/strlcpy.c -new file mode 100644 -index 0000000..a2653ee ---- /dev/null -+++ b/support/nfs/strlcpy.c -@@ -0,0 +1,72 @@ -+/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ -+ -+/* -+ * Copyright (c) 1998 Todd C. Miller -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. The name of the author may not be used to endorse or promote products -+ * derived from this software without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#if defined(LIBC_SCCS) && !defined(lint) -+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; -+#endif /* LIBC_SCCS and not lint */ -+ -+#include -+#include -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif /* HAVE_CONFIG_H */ -+ -+/* -+ * Copy src to string dst of size siz. At most siz-1 characters -+ * will be copied. Always NUL terminates (unless siz == 0). -+ * Returns strlen(src); if retval >= siz, truncation occurred. -+ */ -+size_t -+strlcpy(char *dst, -+ const char *src, -+ size_t siz) -+{ -+ register char *d = dst; -+ register const char *s = src; -+ register size_t n = siz; -+ -+ /* Copy as many bytes as will fit */ -+ if (n != 0 && --n != 0) { -+ do { -+ if ((*d++ = *s++) == 0) -+ break; -+ } while (--n != 0); -+ } -+ -+ /* Not enough room in dst, add NUL and traverse rest of src */ -+ if (n == 0) { -+ if (siz != 0) -+ *d = '\0'; /* NUL-terminate dst */ -+ while (*s++) -+ ; -+ } -+ -+ return(s - src - 1); /* count does not include NUL */ -+} -diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c -index 59ba505..b3f75ed 100644 ---- a/support/nfs/svc_create.c -+++ b/support/nfs/svc_create.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -41,11 +42,68 @@ - #include "tcpwrapper.h" - #endif - -+#include "sockaddr.h" - #include "rpcmisc.h" - #include "xlog.h" - - #ifdef HAVE_LIBTIRPC - -+#define SVC_CREATE_XPRT_CACHE_SIZE (8) -+static SVCXPRT *svc_create_xprt_cache[SVC_CREATE_XPRT_CACHE_SIZE] = { NULL, }; -+ -+/* -+ * Cache an SVC xprt, in case there are more programs or versions to -+ * register against it. -+ */ -+static void -+svc_create_cache_xprt(SVCXPRT *xprt) -+{ -+ unsigned int i; -+ -+ /* Check if we've already got this one... */ -+ for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) -+ if (svc_create_xprt_cache[i] == xprt) -+ return; -+ -+ /* No, we don't. Cache it. */ -+ for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) -+ if (svc_create_xprt_cache[i] == NULL) { -+ svc_create_xprt_cache[i] = xprt; -+ return; -+ } -+ -+ xlog(L_ERROR, "%s: Failed to cache an xprt", __func__); -+} -+ -+/* -+ * Find a previously cached SVC xprt structure with the given bind address -+ * and transport semantics. -+ * -+ * Returns pointer to a cached SVC xprt. -+ * -+ * If no matching SVC XPRT can be found, NULL is returned. -+ */ -+static SVCXPRT * -+svc_create_find_xprt(const struct sockaddr *bindaddr, const struct netconfig *nconf) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) { -+ SVCXPRT *xprt = svc_create_xprt_cache[i]; -+ struct sockaddr *sap; -+ -+ if (xprt == NULL) -+ continue; -+ if (strcmp(nconf->nc_netid, xprt->xp_netid) != 0) -+ continue; -+ sap = (struct sockaddr *)xprt->xp_ltaddr.buf; -+ if (!nfs_compare_sockaddr(bindaddr, sap)) -+ continue; -+ return xprt; -+ } -+ return NULL; -+} -+ - /* - * Set up an appropriate bind address, given @port and @nconf. - * -@@ -98,17 +156,113 @@ svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) - return ai; - } - -+/* -+ * Create a listener socket on a specific bindaddr, and set -+ * special socket options to allow it to share the same port -+ * as other listeners. -+ * -+ * Returns an open, bound, and possibly listening network -+ * socket on success. -+ * -+ * Otherwise returns -1 if some error occurs. -+ */ -+static int -+svc_create_sock(const struct sockaddr *sap, socklen_t salen, -+ struct netconfig *nconf) -+{ -+ int fd, type, protocol; -+ int one = 1; -+ -+ switch(nconf->nc_semantics) { -+ case NC_TPI_CLTS: -+ type = SOCK_DGRAM; -+ break; -+ case NC_TPI_COTS_ORD: -+ type = SOCK_STREAM; -+ break; -+ default: -+ xlog(D_GENERAL, "%s: Unrecognized bind address semantics: %u", -+ __func__, nconf->nc_semantics); -+ return -1; -+ } -+ -+ if (strcmp(nconf->nc_proto, NC_UDP) == 0) -+ protocol = (int)IPPROTO_UDP; -+ else if (strcmp(nconf->nc_proto, NC_TCP) == 0) -+ protocol = (int)IPPROTO_TCP; -+ else { -+ xlog(D_GENERAL, "%s: Unrecognized bind address protocol: %s", -+ __func__, nconf->nc_proto); -+ return -1; -+ } -+ -+ fd = socket((int)sap->sa_family, type, protocol); -+ if (fd == -1) { -+ xlog(L_ERROR, "Could not make a socket: (%d) %m", -+ errno); -+ return -1; -+ } -+ -+#ifdef IPV6_SUPPORTED -+ if (sap->sa_family == AF_INET6) { -+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, -+ &one, sizeof(one)) == -1) { -+ xlog(L_ERROR, "Failed to set IPV6_V6ONLY: (%d) %m", -+ errno); -+ (void)close(fd); -+ return -1; -+ } -+ } -+#endif /* IPV6_SUPPORTED */ -+ -+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, -+ &one, sizeof(one)) == -1) { -+ xlog(L_ERROR, "Failed to set SO_REUSEADDR: (%d) %m", -+ errno); -+ (void)close(fd); -+ return -1; -+ } -+ -+ if (bind(fd, sap, salen) == -1) { -+ xlog(L_ERROR, "Could not bind socket: (%d) %m", -+ errno); -+ (void)close(fd); -+ return -1; -+ } -+ -+ if (nconf->nc_semantics == NC_TPI_COTS_ORD) -+ if (listen(fd, SOMAXCONN) == -1) { -+ xlog(L_ERROR, "Could not listen on socket: (%d) %m", -+ errno); -+ (void)close(fd); -+ return -1; -+ } -+ -+ return fd; -+} -+ -+/* -+ * The simple case is allowing the TI-RPC library to create a -+ * transport itself, given just the bind address and transport -+ * semantics. -+ * -+ * Our local xprt cache is ignored in this path, since the -+ * caller is not interested in sharing listeners or ports, and -+ * the library automatically avoids ports already in use. -+ * -+ * Returns the count of started listeners (one or zero). -+ */ - static unsigned int --svc_create_nconf(const char *name, const rpcprog_t program, -+svc_create_nconf_rand_port(const char *name, const rpcprog_t program, - const rpcvers_t version, - void (*dispatch)(struct svc_req *, SVCXPRT *), -- const uint16_t port, struct netconfig *nconf) -+ struct netconfig *nconf) - { - struct t_bind bindaddr; - struct addrinfo *ai; - SVCXPRT *xprt; - -- ai = svc_create_bindaddr(nconf, port); -+ ai = svc_create_bindaddr(nconf, 0); - if (ai == NULL) - return 0; - -@@ -119,7 +273,7 @@ svc_create_nconf(const char *name, const rpcprog_t program, - freeaddrinfo(ai); - if (xprt == NULL) { - xlog(D_GENERAL, "Failed to create listener xprt " -- "(%s, %u, %s)", name, version, nconf->nc_netid); -+ "(%s, %u, %s)", name, version, nconf->nc_netid); - return 0; - } - -@@ -133,6 +287,93 @@ svc_create_nconf(const char *name, const rpcprog_t program, - return 1; - } - -+/* -+ * If a port is specified on the command line, that port value will be -+ * the same for all listeners created here. Create each listener -+ * socket in advance and set SO_REUSEADDR, rather than allowing the -+ * RPC library to create the listeners for us on a randomly chosen -+ * port via svc_tli_create(RPC_ANYFD). -+ * -+ * Some callers want to listen for more than one RPC version using the -+ * same port number. For example, mountd could want to listen for MNT -+ * version 1, 2, and 3 requests. This means mountd must use the same -+ * set of listener sockets for multiple RPC versions, since, on one -+ * system, you can't have two listener sockets with the exact same -+ * bind address (and port) and transport protocol. -+ * -+ * To accomplish this, this function caches xprts as they are created. -+ * This cache is checked to see if a previously created xprt can be -+ * used, before creating a new xprt for this [program, version]. If -+ * there is a cached xprt with the same bindaddr and transport -+ * semantics, we simply register the new version with that xprt, -+ * rather than creating a fresh xprt for it. -+ * -+ * The xprt cache implemented here is local to a process. Two -+ * separate RPC daemons can not share a set of listeners. -+ * -+ * Returns the count of started listeners (one or zero). -+ */ -+static unsigned int -+svc_create_nconf_fixed_port(const char *name, const rpcprog_t program, -+ const rpcvers_t version, -+ void (*dispatch)(struct svc_req *, SVCXPRT *), -+ const uint16_t port, struct netconfig *nconf) -+{ -+ struct addrinfo *ai; -+ SVCXPRT *xprt; -+ -+ ai = svc_create_bindaddr(nconf, port); -+ if (ai == NULL) -+ return 0; -+ -+ xprt = svc_create_find_xprt(ai->ai_addr, nconf); -+ if (xprt == NULL) { -+ int fd; -+ -+ fd = svc_create_sock(ai->ai_addr, ai->ai_addrlen, nconf); -+ if (fd == -1) -+ goto out_free; -+ -+ xprt = svc_tli_create(fd, nconf, NULL, 0, 0); -+ if (xprt == NULL) { -+ xlog(D_GENERAL, "Failed to create listener xprt " -+ "(%s, %u, %s)", name, version, nconf->nc_netid); -+ (void)close(fd); -+ goto out_free; -+ } -+ } -+ -+ if (!svc_reg(xprt, program, version, dispatch, nconf)) { -+ /* svc_reg(3) destroys @xprt in this case */ -+ xlog(D_GENERAL, "Failed to register (%s, %u, %s)", -+ name, version, nconf->nc_netid); -+ goto out_free; -+ } -+ -+ svc_create_cache_xprt(xprt); -+ -+ freeaddrinfo(ai); -+ return 1; -+ -+out_free: -+ freeaddrinfo(ai); -+ return 0; -+} -+ -+static unsigned int -+svc_create_nconf(const char *name, const rpcprog_t program, -+ const rpcvers_t version, -+ void (*dispatch)(struct svc_req *, SVCXPRT *), -+ const uint16_t port, struct netconfig *nconf) -+{ -+ if (port != 0) -+ return svc_create_nconf_fixed_port(name, program, -+ version, dispatch, port, nconf); -+ -+ return svc_create_nconf_rand_port(name, program, -+ version, dispatch, nconf); -+} -+ - /** - * nfs_svc_create - start up RPC svc listeners - * @name: C string containing name of new service -@@ -145,8 +386,7 @@ svc_create_nconf(const char *name, const rpcprog_t program, - * the RPC dispatcher. Returns the number of started network transports. - */ - unsigned int --nfs_svc_create(__attribute__((unused)) char *name, -- const rpcprog_t program, const rpcvers_t version, -+nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, - void (*dispatch)(struct svc_req *, SVCXPRT *), - const uint16_t port) - { -diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am -index 4218048..4328e41 100644 ---- a/utils/idmapd/Makefile.am -+++ b/utils/idmapd/Makefile.am -@@ -11,12 +11,8 @@ EXTRA_DIST = \ - idmapd.conf - - idmapd_SOURCES = \ -- atomicio.c \ - idmapd.c \ -- strlcat.c \ -- strlcpy.c \ - \ -- cfg.h \ - nfs_idmap.h \ - queue.h - -diff --git a/utils/idmapd/atomicio.c b/utils/idmapd/atomicio.c -deleted file mode 100644 -index 1fb1ff9..0000000 ---- a/utils/idmapd/atomicio.c -+++ /dev/null -@@ -1,64 +0,0 @@ --/* -- * Copyright (c) 2002 Marius Aamodt Eriksen -- * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. -- * All rights reserved. -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions -- * are met: -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. Redistributions in binary form must reproduce the above copyright -- * notice, this list of conditions and the following disclaimer in the -- * documentation and/or other materials provided with the distribution. -- * -- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- */ -- --#include --#include --#include -- --#ifdef HAVE_CONFIG_H --#include "config.h" --#endif /* HAVE_CONFIG_H */ -- --/* -- * ensure all of data on socket comes through. f==read || f==write -- */ --ssize_t --atomicio( -- ssize_t (*f) (int, void*, size_t), -- int fd, -- void *_s, -- size_t n) --{ -- char *s = _s; -- ssize_t res; -- size_t pos = 0; -- -- while (n > pos) { -- res = (f) (fd, s + pos, n - pos); -- switch (res) { -- case -1: -- if (errno == EINTR || errno == EAGAIN) -- continue; -- case 0: -- if (pos != 0) -- return (pos); -- return (res); -- default: -- pos += res; -- } -- } -- return (pos); --} -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index b76607a..76a56ef 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -158,10 +158,6 @@ static int nfsdopenone(struct idmap_client *); - static void nfsdreopen_one(struct idmap_client *); - static void nfsdreopen(void); - --size_t strlcat(char *, const char *, size_t); --size_t strlcpy(char *, const char *, size_t); --ssize_t atomicio(ssize_t (*f) (int, void*, size_t), -- int, void *, size_t); - void mydaemon(int, int); - void release_parent(void); - -diff --git a/utils/idmapd/strlcat.c b/utils/idmapd/strlcat.c -deleted file mode 100644 -index daedd7a..0000000 ---- a/utils/idmapd/strlcat.c -+++ /dev/null -@@ -1,76 +0,0 @@ --/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ -- --/* -- * Copyright (c) 1998 Todd C. Miller -- * All rights reserved. -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions -- * are met: -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. Redistributions in binary form must reproduce the above copyright -- * notice, this list of conditions and the following disclaimer in the -- * documentation and/or other materials provided with the distribution. -- * 3. The name of the author may not be used to endorse or promote products -- * derived from this software without specific prior written permission. -- * -- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- */ -- --#if defined(LIBC_SCCS) && !defined(lint) --static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"; --#endif /* LIBC_SCCS and not lint */ -- --#include --#include -- --#ifdef HAVE_CONFIG_H --#include "config.h" --#endif /* HAVE_CONFIG_H */ -- --/* -- * Appends src to string dst of size siz (unlike strncat, siz is the -- * full size of dst, not space left). At most siz-1 characters -- * will be copied. Always NUL terminates (unless siz <= strlen(dst)). -- * Returns strlen(src) + MIN(siz, strlen(initial dst)). -- * If retval >= siz, truncation occurred. -- */ --size_t --strlcat(char *dst, -- const char *src, -- size_t siz) --{ -- register char *d = dst; -- register const char *s = src; -- register size_t n = siz; -- size_t dlen; -- -- /* Find the end of dst and adjust bytes left but don't go past end */ -- while (n-- != 0 && *d != '\0') -- d++; -- dlen = d - dst; -- n = siz - dlen; -- -- if (n == 0) -- return(dlen + strlen(s)); -- while (*s != '\0') { -- if (n != 1) { -- *d++ = *s; -- n--; -- } -- s++; -- } -- *d = '\0'; -- -- return(dlen + (s - src)); /* count does not include NUL */ --} -diff --git a/utils/idmapd/strlcpy.c b/utils/idmapd/strlcpy.c -deleted file mode 100644 -index a2653ee..0000000 ---- a/utils/idmapd/strlcpy.c -+++ /dev/null -@@ -1,72 +0,0 @@ --/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ -- --/* -- * Copyright (c) 1998 Todd C. Miller -- * All rights reserved. -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions -- * are met: -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. Redistributions in binary form must reproduce the above copyright -- * notice, this list of conditions and the following disclaimer in the -- * documentation and/or other materials provided with the distribution. -- * 3. The name of the author may not be used to endorse or promote products -- * derived from this software without specific prior written permission. -- * -- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- */ -- --#if defined(LIBC_SCCS) && !defined(lint) --static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; --#endif /* LIBC_SCCS and not lint */ -- --#include --#include -- --#ifdef HAVE_CONFIG_H --#include "config.h" --#endif /* HAVE_CONFIG_H */ -- --/* -- * Copy src to string dst of size siz. At most siz-1 characters -- * will be copied. Always NUL terminates (unless siz == 0). -- * Returns strlen(src); if retval >= siz, truncation occurred. -- */ --size_t --strlcpy(char *dst, -- const char *src, -- size_t siz) --{ -- register char *d = dst; -- register const char *s = src; -- register size_t n = siz; -- -- /* Copy as many bytes as will fit */ -- if (n != 0 && --n != 0) { -- do { -- if ((*d++ = *s++) == 0) -- break; -- } while (--n != 0); -- } -- -- /* Not enough room in dst, add NUL and traverse rest of src */ -- if (n == 0) { -- if (siz != 0) -- *d = '\0'; /* NUL-terminate dst */ -- while (*s++) -- ; -- } -- -- return(s - src - 1); /* count does not include NUL */ --} -diff --git a/utils/mount/fstab.c b/utils/mount/fstab.c -index 051fa38..a742e64 100644 ---- a/utils/mount/fstab.c -+++ b/utils/mount/fstab.c -@@ -364,19 +364,22 @@ lock_mtab (void) { - /* Repeat until it was us who made the link */ - while (!we_created_lockfile) { - struct flock flock; -- int errsv, j; -+ int j; - - j = link(linktargetfile, MOUNTED_LOCK); -- errsv = errno; - -- if (j == 0) -- we_created_lockfile = 1; -+ { -+ int errsv = errno; - -- if (j < 0 && errsv != EEXIST) { -- (void) unlink(linktargetfile); -- die (EX_FILEIO, _("can't link lock file %s: %s " -- "(use -n flag to override)"), -- MOUNTED_LOCK, strerror (errsv)); -+ if (j == 0) -+ we_created_lockfile = 1; -+ -+ if (j < 0 && errsv != EEXIST) { -+ (void) unlink(linktargetfile); -+ die (EX_FILEIO, _("can't link lock file %s: %s " -+ "(use -n flag to override)"), -+ MOUNTED_LOCK, strerror (errsv)); -+ } - } - - lockfile_fd = open (MOUNTED_LOCK, O_WRONLY); -@@ -414,7 +417,7 @@ lock_mtab (void) { - } - (void) unlink(linktargetfile); - } else { -- static int tries = 0; -+ static int retries = 0; - - /* Someone else made the link. Wait. */ - alarm(LOCK_TIMEOUT); -@@ -428,10 +431,10 @@ lock_mtab (void) { - alarm(0); - /* Limit the number of iterations - maybe there - still is some old /etc/mtab~ */ -- ++tries; -- if (tries % 200 == 0) -+ ++retries; -+ if (retries % 200 == 0) - usleep(30); -- if (tries > 100000) { -+ if (retries > 100000) { - (void) unlink(linktargetfile); - close(lockfile_fd); - die (EX_FILEIO, _("Cannot create link %s\n" -diff --git a/utils/mount/mount.c b/utils/mount/mount.c -index 82b9169..b4da21f 100644 ---- a/utils/mount/mount.c -+++ b/utils/mount/mount.c -@@ -209,7 +209,7 @@ static char *fix_opts_string(int flags, const char *extra_opts) - } - if (flags & MS_USERS) - new_opts = xstrconcat3(new_opts, ",users", ""); -- -+ - for (om = opt_map; om->opt != NULL; om++) { - if (om->skip) - continue; -@@ -281,7 +281,7 @@ static int add_mtab(char *spec, char *mount_point, char *fstype, - ment.mnt_fsname = spec; - ment.mnt_dir = mount_point; - ment.mnt_type = fstype; -- ment.mnt_opts = fix_opts_string(flags, opts); -+ ment.mnt_opts = fix_opts_string(flags & ~MS_NOMTAB, opts); - ment.mnt_freq = freq; - ment.mnt_passno = pass; - -@@ -321,7 +321,7 @@ static int add_mtab(char *spec, char *mount_point, char *fstype, - return result; - } - --void mount_usage(void) -+static void mount_usage(void) - { - printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"), - progname); -@@ -337,7 +337,7 @@ void mount_usage(void) - printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n")); - } - --static void parse_opt(const char *opt, int *mask, char *extra_opts, int len) -+static void parse_opt(const char *opt, int *mask, char *extra_opts, size_t len) - { - const struct opt_map *om; - -@@ -371,7 +371,7 @@ static void parse_opts(const char *options, int *flags, char **extra_opts) - if (options != NULL) { - char *opts = xstrdup(options); - char *opt, *p; -- int len = strlen(opts) + 1; /* include room for a null */ -+ size_t len = strlen(opts) + 1; /* include room for a null */ - int open_quote = 0; - - *extra_opts = xmalloc(len); -diff --git a/utils/mount/mount_config.h b/utils/mount/mount_config.h -index 3023306..e86b4ba 100644 ---- a/utils/mount/mount_config.h -+++ b/utils/mount/mount_config.h -@@ -1,7 +1,7 @@ --#ifndef _LINUX_MOUNT__CONFIG_H --#define _LINUX_MOUNT_CONFIG__H -+#ifndef _LINUX_MOUNT_CONFIG_H -+#define _LINUX_MOUNT_CONFIG_H - /* -- * mount_config.h -- mount configuration file routines -+ * mount_config.h -- mount configuration file routines - * Copyright (C) 2008 Red Hat, Inc - * - * This program is free software; you can redistribute it and/or modify -@@ -16,15 +16,13 @@ - * - */ - --inline void mount_config_init(char *); -- - #ifdef MOUNT_CONFIG - #include "conffile.h" - #include "xlog.h" - - extern char *conf_get_mntopts(char *, char *, char *); - --inline void mount_config_init(char *program) -+static inline void mount_config_init(char *program) - { - xlog_open(program); - /* -@@ -32,19 +30,22 @@ inline void mount_config_init(char *program) - */ - conf_init(); - } --inline char *mount_config_opts(char *spec, -+ -+static inline char *mount_config_opts(char *spec, - char *mount_point, char *mount_opts) - { - return conf_get_mntopts(spec, mount_point, mount_opts); - } -+ - #else /* MOUNT_CONFIG */ - --inline void mount_config_init(char *program) { } -+static inline void mount_config_init(char *program) { } - --inline char *mount_config_opts(char *spec, -+static inline char *mount_config_opts(char *spec, - char *mount_point, char *mount_opts) - { - return mount_opts; - } - #endif /* MOUNT_CONFIG */ --#endif -+ -+#endif /* _LINUX_MOUNT_CONFIG_H */ -diff --git a/utils/mount/mount_constants.h b/utils/mount/mount_constants.h -index cbfb099..4d050d8 100644 ---- a/utils/mount/mount_constants.h -+++ b/utils/mount/mount_constants.h -@@ -64,4 +64,8 @@ if we have a stack or plain mount - mount atop of it, forming a stack. */ - #define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ - #endif - -+/* Generic options that are prevented from appearing -+ * in the options field in /etc/mtab. */ -+#define MS_NOMTAB (MS_REMOUNT) -+ - #endif /* _NFS_UTILS_MOUNT_CONSTANTS_H */ -diff --git a/utils/mount/network.c b/utils/mount/network.c -index d612427..5b515c3 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -59,6 +59,8 @@ - #define CONNECT_TIMEOUT (20) - #define MOUNT_TIMEOUT (30) - -+#define SAFE_SOCKADDR(x) (struct sockaddr *)(char *)(x) -+ - extern int nfs_mount_data_version; - extern char *progname; - extern int verbose; -@@ -428,12 +430,12 @@ static int get_socket(struct sockaddr_in *saddr, unsigned int p_prot, - if (bindresvport(so, &laddr) < 0) - goto err_bindresvport; - } else { -- cc = bind(so, (struct sockaddr *)&laddr, namelen); -+ cc = bind(so, SAFE_SOCKADDR(&laddr), namelen); - if (cc < 0) - goto err_bind; - } - if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) { -- cc = connect_to(so, (struct sockaddr *)saddr, namelen, -+ cc = connect_to(so, SAFE_SOCKADDR(saddr), namelen, - timeout); - if (cc < 0) - goto err_connect; -@@ -756,11 +758,12 @@ int nfs_probe_bothports(const struct sockaddr *mnt_saddr, - */ - int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) - { -- return nfs_probe_bothports((struct sockaddr *)&mnt_server->saddr, -- sizeof(mnt_server->saddr), -+ struct sockaddr *mnt_addr = SAFE_SOCKADDR(&mnt_server->saddr); -+ struct sockaddr *nfs_addr = SAFE_SOCKADDR(&nfs_server->saddr); -+ -+ return nfs_probe_bothports(mnt_addr, sizeof(mnt_server->saddr), - &mnt_server->pmap, -- (struct sockaddr *)&nfs_server->saddr, -- sizeof(nfs_server->saddr), -+ nfs_addr, sizeof(nfs_server->saddr), - &nfs_server->pmap); - } - -@@ -772,7 +775,7 @@ static int nfs_probe_statd(void) - }; - rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); - -- return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr), -+ return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr), - program, (rpcvers_t)1, IPPROTO_UDP); - } - -@@ -901,7 +904,7 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, - */ - int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp) - { -- struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr; -+ struct sockaddr *sap = SAFE_SOCKADDR(&mnt_server->saddr); - socklen_t salen = sizeof(mnt_server->saddr); - struct pmap *pmap = &mnt_server->pmap; - CLIENT *clnt; -@@ -1011,11 +1014,11 @@ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog, - struct sockaddr_in *caddr) - { - CLIENT *clnt = NULL; -- int sock, stat; -+ int sock, status; - static char clnt_res; - struct sockaddr dissolve; - -- rpc_createerr.cf_stat = stat = 0; -+ rpc_createerr.cf_stat = status = 0; - sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE); - if (sock == RPC_ANYSOCK) { - if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) { -@@ -1058,18 +1061,18 @@ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog, - return 0; - } - memset(&clnt_res, 0, sizeof(clnt_res)); -- stat = clnt_call(clnt, NULLPROC, -+ status = clnt_call(clnt, NULLPROC, - (xdrproc_t)xdr_void, (caddr_t)NULL, - (xdrproc_t)xdr_void, (caddr_t)&clnt_res, - TIMEOUT); -- if (stat) { -+ if (status) { - clnt_geterr(clnt, &rpc_createerr.cf_error); -- rpc_createerr.cf_stat = stat; -+ rpc_createerr.cf_stat = status; - } - clnt_destroy(clnt); - close(sock); - -- if (stat == RPC_SUCCESS) -+ if (status == RPC_SUCCESS) - return 1; - else - return 0; -@@ -1103,13 +1106,13 @@ static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen, - - switch (sap->sa_family) { - case AF_INET: -- if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { -+ if (bind(sock, SAFE_SOCKADDR(&sin), sizeof(sin)) < 0) { - close(sock); - return 0; - } - break; - case AF_INET6: -- if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) { -+ if (bind(sock, SAFE_SOCKADDR(&sin6), sizeof(sin6)) < 0) { - close(sock); - return 0; - } -@@ -1518,7 +1521,11 @@ nfs_mount_protocol(struct mount_options *options, unsigned long *protocol) - * set @protocol to zero. The pmap protocol value will - * be filled in later by an rpcbind query in this case. - */ -- return nfs_nfs_protocol(options, protocol); -+ if (!nfs_nfs_protocol(options, protocol)) -+ return 0; -+ if (*protocol == NFSPROTO_RDMA) -+ *protocol = IPPROTO_TCP; -+ return 1; - } - - /* -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index d2a4c5f..01bc712 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -619,7 +619,7 @@ in such cases. - .BI nfsvers= n - The NFS protocol version number used to contact the server's NFS service. - 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 -+If this option is not specified, the client negotiates a suitable version with - the server, trying version 4 first, version 3 second, and version 2 last. - .TP 1.5i - .BI vers= n -diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c -index 1514340..02d40ff 100644 ---- a/utils/mount/nfsumount.c -+++ b/utils/mount/nfsumount.c -@@ -31,12 +31,16 @@ - #include "nls.h" - - #include "mount_constants.h" -+#include "nfs_mount.h" - #include "mount.h" - #include "error.h" - #include "network.h" - #include "parse_opt.h" - #include "parse_dev.h" - -+#define MOUNTSFILE "/proc/mounts" -+#define LINELEN (4096) -+ - #if !defined(MNT_FORCE) - /* dare not try to include -- lots of errors */ - #define MNT_FORCE 1 -@@ -109,7 +113,7 @@ static int del_mtab(const char *spec, const char *node) - res = try_remount(spec, node); - if (res) - goto writemtab; -- return 0; -+ return EX_SUCCESS; - } else - umnt_err = errno; - } -@@ -127,7 +131,7 @@ static int del_mtab(const char *spec, const char *node) - } - - if (res >= 0) -- return 0; -+ return EX_SUCCESS; - - if (umnt_err) - umount_error(umnt_err, node); -@@ -241,6 +245,91 @@ static int nfs_umount23(const char *devname, char *string) - return result; - } - -+/* -+ * Detect NFSv4 mounts. -+ * -+ * Consult /proc/mounts to determine if the mount point -+ * is an NFSv4 mount. The kernel is authoritative about -+ * what type of mount this is. -+ * -+ * Returns 1 if "mc" is an NFSv4 mount, zero if not, and -+ * -1 if some error occurred. -+ */ -+static int nfs_umount_is_vers4(const struct mntentchn *mc) -+{ -+ char buffer[LINELEN], *next; -+ int retval; -+ FILE *f; -+ -+ if ((f = fopen(MOUNTSFILE, "r")) == NULL) { -+ fprintf(stderr, "%s: %s\n", -+ MOUNTSFILE, strerror(errno)); -+ return -1; -+ } -+ -+ retval = -1; -+ while (fgets(buffer, sizeof(buffer), f) != NULL) { -+ char *device, *mntdir, *type, *flags; -+ struct mount_options *options; -+ char *line = buffer; -+ -+ next = strchr(line, '\n'); -+ if (next != NULL) -+ *next = '\0'; -+ -+ device = strtok(line, " \t"); -+ if (device == NULL) -+ continue; -+ mntdir = strtok(NULL, " \t"); -+ if (mntdir == NULL) -+ continue; -+ if (strcmp(device, mc->m.mnt_fsname) != 0 && -+ strcmp(mntdir, mc->m.mnt_dir) != 0) -+ continue; -+ -+ type = strtok(NULL, " \t"); -+ if (type == NULL) -+ continue; -+ if (strcmp(type, "nfs4") == 0) -+ goto out_nfs4; -+ -+ flags = strtok(NULL, " \t"); -+ if (flags == NULL) -+ continue; -+ options = po_split(flags); -+ if (options != NULL) { -+ unsigned long version; -+ int rc; -+ -+ rc = nfs_nfs_version(options, &version); -+ po_destroy(options); -+ if (rc && version == 4) -+ goto out_nfs4; -+ } -+ -+ goto out_nfs; -+ } -+ if (retval == -1) -+ fprintf(stderr, "%s was not found in %s\n", -+ mc->m.mnt_dir, MOUNTSFILE); -+ -+out: -+ fclose(f); -+ return retval; -+ -+out_nfs4: -+ if (verbose) -+ fprintf(stderr, "NFSv4 mount point detected\n"); -+ retval = 1; -+ goto out; -+ -+out_nfs: -+ if (verbose) -+ fprintf(stderr, "Legacy NFS mount point detected\n"); -+ retval = 0; -+ goto out; -+} -+ - static struct option umount_longopts[] = - { - { "force", 0, 0, 'f' }, -@@ -362,16 +451,25 @@ int nfsumount(int argc, char *argv[]) - } - } - -- ret = 0; -+ ret = EX_SUCCESS; - if (mc) { -- if (!lazy && strcmp(mc->m.mnt_type, "nfs4") != 0) -- /* We ignore the error from nfs_umount23. -- * If the actual umount succeeds (in del_mtab), -- * we don't want to signal an error, as that -- * could cause /sbin/mount to retry! -- */ -- nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts); -- ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir) ?: ret; -+ if (!lazy) { -+ switch (nfs_umount_is_vers4(mc)) { -+ case 0: -+ /* We ignore the error from nfs_umount23. -+ * If the actual umount succeeds (in del_mtab), -+ * we don't want to signal an error, as that -+ * could cause /sbin/mount to retry! -+ */ -+ nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts); -+ break; -+ case 1: -+ break; -+ default: -+ return EX_FAIL; -+ } -+ } -+ ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir); - } else if (*spec != '/') { - if (!lazy) - ret = nfs_umount23(spec, "tcp,v3"); -diff --git a/utils/mount/parse_opt.c b/utils/mount/parse_opt.c -index f0918f7..ab869d9 100644 ---- a/utils/mount/parse_opt.c -+++ b/utils/mount/parse_opt.c -@@ -508,7 +508,7 @@ po_found_t po_get_numeric(struct mount_options *options, char *keyword, long *va - int po_rightmost(struct mount_options *options, const char *keys[]) - { - struct mount_option *option; -- unsigned int i; -+ int i; - - if (options) { - for (option = options->tail; option; option = option->prev) { -diff --git a/utils/mount/version.h b/utils/mount/version.h -index 46552a1..af61a6f 100644 ---- a/utils/mount/version.h -+++ b/utils/mount/version.h -@@ -42,9 +42,9 @@ static inline unsigned int linux_version_code(void) - if (uname(&my_utsname)) - return 0; - -- p = atoi(strtok(my_utsname.release, ".")); -- q = atoi(strtok(NULL, ".")); -- r = atoi(strtok(NULL, ".")); -+ p = (unsigned int)atoi(strtok(my_utsname.release, ".")); -+ q = (unsigned int)atoi(strtok(NULL, ".")); -+ r = (unsigned int)atoi(strtok(NULL, ".")); - return MAKE_VERSION(p, q, r); - } - diff --git a/nfs-utils-1.2.4-rc2.patch b/nfs-utils-1.2.4-rc2.patch new file mode 100644 index 0000000..7d1e219 --- /dev/null +++ b/nfs-utils-1.2.4-rc2.patch @@ -0,0 +1,1845 @@ +diff --git a/configure.ac b/configure.ac +index 3058be6..5408e85 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -136,7 +136,7 @@ AC_ARG_ENABLE(tirpc, + [AC_HELP_STRING([--enable-tirpc], + [enable use of TI-RPC @<:@default=yes@:>@])], + enable_tirpc=$enableval, +- enable_tirpc='yes') ++ enable_tirpc='') + AC_ARG_ENABLE(ipv6, + [AC_HELP_STRING([--enable-ipv6], + [enable support for IPv6 @<:@default=no@:>@])], +diff --git a/support/export/client.c b/support/export/client.c +index dbfc2b1..ba2db8f 100644 +--- a/support/export/client.c ++++ b/support/export/client.c +@@ -178,6 +178,7 @@ out_badprefix: + static int + init_netmask6(nfs_client *UNUSED(clp), const char *UNUSED(slash)) + { ++ return 0; + } + #endif /* IPV6_SUPPORTED */ + +diff --git a/support/export/export.c b/support/export/export.c +index f528603..4fda30a 100644 +--- a/support/export/export.c ++++ b/support/export/export.c +@@ -38,6 +38,7 @@ export_free(nfs_export *exp) + xfree(exp->m_export.e_sqgids); + free(exp->m_export.e_mountpoint); + free(exp->m_export.e_fslocdata); ++ free(exp->m_export.e_uuid); + + xfree(exp->m_export.e_hostname); + xfree(exp); +diff --git a/support/export/hostname.c b/support/export/hostname.c +index 3c55ce7..efcb75c 100644 +--- a/support/export/hostname.c ++++ b/support/export/hostname.c +@@ -30,10 +30,6 @@ + #include "sockaddr.h" + #include "exportfs.h" + +-#ifndef HAVE_DECL_AI_ADDRCONFIG +-#define AI_ADDRCONFIG 0 +-#endif +- + /** + * host_ntop - generate presentation address given a sockaddr + * @sap: pointer to socket address +@@ -170,7 +166,7 @@ host_addrinfo(const char *hostname) + #endif + /* don't return duplicates */ + .ai_protocol = (int)IPPROTO_UDP, +- .ai_flags = AI_ADDRCONFIG | AI_CANONNAME, ++ .ai_flags = AI_CANONNAME, + }; + int error; + +diff --git a/support/include/nfslib.h b/support/include/nfslib.h +index 3db5bec..53ece0e 100644 +--- a/support/include/nfslib.h ++++ b/support/include/nfslib.h +@@ -163,6 +163,12 @@ void closeall(int min); + int svctcp_socket (u_long __number, int __reuse); + int svcudp_socket (u_long __number); + ++/* Misc shared code prototypes */ ++size_t strlcat(char *, const char *, size_t); ++size_t strlcpy(char *, const char *, size_t); ++ssize_t atomicio(ssize_t (*f) (int, void*, size_t), ++ int, void *, size_t); ++ + + #define UNUSED(x) UNUSED_ ## x __attribute__((unused)) + +diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am +index 60400b2..05c2fc4 100644 +--- a/support/nfs/Makefile.am ++++ b/support/nfs/Makefile.am +@@ -5,7 +5,7 @@ libnfs_a_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ + xlog.c xcommon.c wildmat.c nfsclient.c \ + nfsexport.c getfh.c nfsctl.c rpc_socket.c getport.c \ + svc_socket.c cacheio.c closeall.c nfs_mntent.c conffile.c \ +- svc_create.c ++ svc_create.c atomicio.c strlcpy.c strlcat.c + + MAINTAINERCLEANFILES = Makefile.in + +diff --git a/support/nfs/atomicio.c b/support/nfs/atomicio.c +new file mode 100644 +index 0000000..5e760e6 +--- /dev/null ++++ b/support/nfs/atomicio.c +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2002 Marius Aamodt Eriksen ++ * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++ ++/* ++ * ensure all of data on socket comes through. f==read || f==write ++ */ ++ssize_t atomicio(ssize_t(*f) (int, void *, size_t), int fd, void *_s, size_t n) ++{ ++ char *s = _s; ++ ssize_t res, pos = 0; ++ ++ while ((ssize_t)n > pos) { ++ res = (f) (fd, s + pos, n - pos); ++ switch (res) { ++ case -1: ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ case 0: ++ if (pos != 0) ++ return pos; ++ return res; ++ default: ++ pos += res; ++ } ++ } ++ return pos; ++} +diff --git a/support/nfs/exports.c b/support/nfs/exports.c +index a93941c..1744ed6 100644 +--- a/support/nfs/exports.c ++++ b/support/nfs/exports.c +@@ -332,6 +332,8 @@ dupexportent(struct exportent *dst, struct exportent *src) + dst->e_mountpoint = strdup(src->e_mountpoint); + if (src->e_fslocdata) + dst->e_fslocdata = strdup(src->e_fslocdata); ++ if (src->e_uuid) ++ dst->e_uuid = strdup(src->e_uuid); + dst->e_hostname = NULL; + } + +diff --git a/support/nfs/strlcat.c b/support/nfs/strlcat.c +new file mode 100644 +index 0000000..daedd7a +--- /dev/null ++++ b/support/nfs/strlcat.c +@@ -0,0 +1,76 @@ ++/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ ++ ++/* ++ * Copyright (c) 1998 Todd C. Miller ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if defined(LIBC_SCCS) && !defined(lint) ++static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"; ++#endif /* LIBC_SCCS and not lint */ ++ ++#include ++#include ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif /* HAVE_CONFIG_H */ ++ ++/* ++ * Appends src to string dst of size siz (unlike strncat, siz is the ++ * full size of dst, not space left). At most siz-1 characters ++ * will be copied. Always NUL terminates (unless siz <= strlen(dst)). ++ * Returns strlen(src) + MIN(siz, strlen(initial dst)). ++ * If retval >= siz, truncation occurred. ++ */ ++size_t ++strlcat(char *dst, ++ const char *src, ++ size_t siz) ++{ ++ register char *d = dst; ++ register const char *s = src; ++ register size_t n = siz; ++ size_t dlen; ++ ++ /* Find the end of dst and adjust bytes left but don't go past end */ ++ while (n-- != 0 && *d != '\0') ++ d++; ++ dlen = d - dst; ++ n = siz - dlen; ++ ++ if (n == 0) ++ return(dlen + strlen(s)); ++ while (*s != '\0') { ++ if (n != 1) { ++ *d++ = *s; ++ n--; ++ } ++ s++; ++ } ++ *d = '\0'; ++ ++ return(dlen + (s - src)); /* count does not include NUL */ ++} +diff --git a/support/nfs/strlcpy.c b/support/nfs/strlcpy.c +new file mode 100644 +index 0000000..a2653ee +--- /dev/null ++++ b/support/nfs/strlcpy.c +@@ -0,0 +1,72 @@ ++/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ ++ ++/* ++ * Copyright (c) 1998 Todd C. Miller ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if defined(LIBC_SCCS) && !defined(lint) ++static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; ++#endif /* LIBC_SCCS and not lint */ ++ ++#include ++#include ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif /* HAVE_CONFIG_H */ ++ ++/* ++ * Copy src to string dst of size siz. At most siz-1 characters ++ * will be copied. Always NUL terminates (unless siz == 0). ++ * Returns strlen(src); if retval >= siz, truncation occurred. ++ */ ++size_t ++strlcpy(char *dst, ++ const char *src, ++ size_t siz) ++{ ++ register char *d = dst; ++ register const char *s = src; ++ register size_t n = siz; ++ ++ /* Copy as many bytes as will fit */ ++ if (n != 0 && --n != 0) { ++ do { ++ if ((*d++ = *s++) == 0) ++ break; ++ } while (--n != 0); ++ } ++ ++ /* Not enough room in dst, add NUL and traverse rest of src */ ++ if (n == 0) { ++ if (siz != 0) ++ *d = '\0'; /* NUL-terminate dst */ ++ while (*s++) ++ ; ++ } ++ ++ return(s - src - 1); /* count does not include NUL */ ++} +diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c +index 59ba505..b3f75ed 100644 +--- a/support/nfs/svc_create.c ++++ b/support/nfs/svc_create.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -41,11 +42,68 @@ + #include "tcpwrapper.h" + #endif + ++#include "sockaddr.h" + #include "rpcmisc.h" + #include "xlog.h" + + #ifdef HAVE_LIBTIRPC + ++#define SVC_CREATE_XPRT_CACHE_SIZE (8) ++static SVCXPRT *svc_create_xprt_cache[SVC_CREATE_XPRT_CACHE_SIZE] = { NULL, }; ++ ++/* ++ * Cache an SVC xprt, in case there are more programs or versions to ++ * register against it. ++ */ ++static void ++svc_create_cache_xprt(SVCXPRT *xprt) ++{ ++ unsigned int i; ++ ++ /* Check if we've already got this one... */ ++ for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) ++ if (svc_create_xprt_cache[i] == xprt) ++ return; ++ ++ /* No, we don't. Cache it. */ ++ for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) ++ if (svc_create_xprt_cache[i] == NULL) { ++ svc_create_xprt_cache[i] = xprt; ++ return; ++ } ++ ++ xlog(L_ERROR, "%s: Failed to cache an xprt", __func__); ++} ++ ++/* ++ * Find a previously cached SVC xprt structure with the given bind address ++ * and transport semantics. ++ * ++ * Returns pointer to a cached SVC xprt. ++ * ++ * If no matching SVC XPRT can be found, NULL is returned. ++ */ ++static SVCXPRT * ++svc_create_find_xprt(const struct sockaddr *bindaddr, const struct netconfig *nconf) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) { ++ SVCXPRT *xprt = svc_create_xprt_cache[i]; ++ struct sockaddr *sap; ++ ++ if (xprt == NULL) ++ continue; ++ if (strcmp(nconf->nc_netid, xprt->xp_netid) != 0) ++ continue; ++ sap = (struct sockaddr *)xprt->xp_ltaddr.buf; ++ if (!nfs_compare_sockaddr(bindaddr, sap)) ++ continue; ++ return xprt; ++ } ++ return NULL; ++} ++ + /* + * Set up an appropriate bind address, given @port and @nconf. + * +@@ -98,17 +156,113 @@ svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) + return ai; + } + ++/* ++ * Create a listener socket on a specific bindaddr, and set ++ * special socket options to allow it to share the same port ++ * as other listeners. ++ * ++ * Returns an open, bound, and possibly listening network ++ * socket on success. ++ * ++ * Otherwise returns -1 if some error occurs. ++ */ ++static int ++svc_create_sock(const struct sockaddr *sap, socklen_t salen, ++ struct netconfig *nconf) ++{ ++ int fd, type, protocol; ++ int one = 1; ++ ++ switch(nconf->nc_semantics) { ++ case NC_TPI_CLTS: ++ type = SOCK_DGRAM; ++ break; ++ case NC_TPI_COTS_ORD: ++ type = SOCK_STREAM; ++ break; ++ default: ++ xlog(D_GENERAL, "%s: Unrecognized bind address semantics: %u", ++ __func__, nconf->nc_semantics); ++ return -1; ++ } ++ ++ if (strcmp(nconf->nc_proto, NC_UDP) == 0) ++ protocol = (int)IPPROTO_UDP; ++ else if (strcmp(nconf->nc_proto, NC_TCP) == 0) ++ protocol = (int)IPPROTO_TCP; ++ else { ++ xlog(D_GENERAL, "%s: Unrecognized bind address protocol: %s", ++ __func__, nconf->nc_proto); ++ return -1; ++ } ++ ++ fd = socket((int)sap->sa_family, type, protocol); ++ if (fd == -1) { ++ xlog(L_ERROR, "Could not make a socket: (%d) %m", ++ errno); ++ return -1; ++ } ++ ++#ifdef IPV6_SUPPORTED ++ if (sap->sa_family == AF_INET6) { ++ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, ++ &one, sizeof(one)) == -1) { ++ xlog(L_ERROR, "Failed to set IPV6_V6ONLY: (%d) %m", ++ errno); ++ (void)close(fd); ++ return -1; ++ } ++ } ++#endif /* IPV6_SUPPORTED */ ++ ++ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, ++ &one, sizeof(one)) == -1) { ++ xlog(L_ERROR, "Failed to set SO_REUSEADDR: (%d) %m", ++ errno); ++ (void)close(fd); ++ return -1; ++ } ++ ++ if (bind(fd, sap, salen) == -1) { ++ xlog(L_ERROR, "Could not bind socket: (%d) %m", ++ errno); ++ (void)close(fd); ++ return -1; ++ } ++ ++ if (nconf->nc_semantics == NC_TPI_COTS_ORD) ++ if (listen(fd, SOMAXCONN) == -1) { ++ xlog(L_ERROR, "Could not listen on socket: (%d) %m", ++ errno); ++ (void)close(fd); ++ return -1; ++ } ++ ++ return fd; ++} ++ ++/* ++ * The simple case is allowing the TI-RPC library to create a ++ * transport itself, given just the bind address and transport ++ * semantics. ++ * ++ * Our local xprt cache is ignored in this path, since the ++ * caller is not interested in sharing listeners or ports, and ++ * the library automatically avoids ports already in use. ++ * ++ * Returns the count of started listeners (one or zero). ++ */ + static unsigned int +-svc_create_nconf(const char *name, const rpcprog_t program, ++svc_create_nconf_rand_port(const char *name, const rpcprog_t program, + const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), +- const uint16_t port, struct netconfig *nconf) ++ struct netconfig *nconf) + { + struct t_bind bindaddr; + struct addrinfo *ai; + SVCXPRT *xprt; + +- ai = svc_create_bindaddr(nconf, port); ++ ai = svc_create_bindaddr(nconf, 0); + if (ai == NULL) + return 0; + +@@ -119,7 +273,7 @@ svc_create_nconf(const char *name, const rpcprog_t program, + freeaddrinfo(ai); + if (xprt == NULL) { + xlog(D_GENERAL, "Failed to create listener xprt " +- "(%s, %u, %s)", name, version, nconf->nc_netid); ++ "(%s, %u, %s)", name, version, nconf->nc_netid); + return 0; + } + +@@ -133,6 +287,93 @@ svc_create_nconf(const char *name, const rpcprog_t program, + return 1; + } + ++/* ++ * If a port is specified on the command line, that port value will be ++ * the same for all listeners created here. Create each listener ++ * socket in advance and set SO_REUSEADDR, rather than allowing the ++ * RPC library to create the listeners for us on a randomly chosen ++ * port via svc_tli_create(RPC_ANYFD). ++ * ++ * Some callers want to listen for more than one RPC version using the ++ * same port number. For example, mountd could want to listen for MNT ++ * version 1, 2, and 3 requests. This means mountd must use the same ++ * set of listener sockets for multiple RPC versions, since, on one ++ * system, you can't have two listener sockets with the exact same ++ * bind address (and port) and transport protocol. ++ * ++ * To accomplish this, this function caches xprts as they are created. ++ * This cache is checked to see if a previously created xprt can be ++ * used, before creating a new xprt for this [program, version]. If ++ * there is a cached xprt with the same bindaddr and transport ++ * semantics, we simply register the new version with that xprt, ++ * rather than creating a fresh xprt for it. ++ * ++ * The xprt cache implemented here is local to a process. Two ++ * separate RPC daemons can not share a set of listeners. ++ * ++ * Returns the count of started listeners (one or zero). ++ */ ++static unsigned int ++svc_create_nconf_fixed_port(const char *name, const rpcprog_t program, ++ const rpcvers_t version, ++ void (*dispatch)(struct svc_req *, SVCXPRT *), ++ const uint16_t port, struct netconfig *nconf) ++{ ++ struct addrinfo *ai; ++ SVCXPRT *xprt; ++ ++ ai = svc_create_bindaddr(nconf, port); ++ if (ai == NULL) ++ return 0; ++ ++ xprt = svc_create_find_xprt(ai->ai_addr, nconf); ++ if (xprt == NULL) { ++ int fd; ++ ++ fd = svc_create_sock(ai->ai_addr, ai->ai_addrlen, nconf); ++ if (fd == -1) ++ goto out_free; ++ ++ xprt = svc_tli_create(fd, nconf, NULL, 0, 0); ++ if (xprt == NULL) { ++ xlog(D_GENERAL, "Failed to create listener xprt " ++ "(%s, %u, %s)", name, version, nconf->nc_netid); ++ (void)close(fd); ++ goto out_free; ++ } ++ } ++ ++ if (!svc_reg(xprt, program, version, dispatch, nconf)) { ++ /* svc_reg(3) destroys @xprt in this case */ ++ xlog(D_GENERAL, "Failed to register (%s, %u, %s)", ++ name, version, nconf->nc_netid); ++ goto out_free; ++ } ++ ++ svc_create_cache_xprt(xprt); ++ ++ freeaddrinfo(ai); ++ return 1; ++ ++out_free: ++ freeaddrinfo(ai); ++ return 0; ++} ++ ++static unsigned int ++svc_create_nconf(const char *name, const rpcprog_t program, ++ const rpcvers_t version, ++ void (*dispatch)(struct svc_req *, SVCXPRT *), ++ const uint16_t port, struct netconfig *nconf) ++{ ++ if (port != 0) ++ return svc_create_nconf_fixed_port(name, program, ++ version, dispatch, port, nconf); ++ ++ return svc_create_nconf_rand_port(name, program, ++ version, dispatch, nconf); ++} ++ + /** + * nfs_svc_create - start up RPC svc listeners + * @name: C string containing name of new service +@@ -145,8 +386,7 @@ svc_create_nconf(const char *name, const rpcprog_t program, + * the RPC dispatcher. Returns the number of started network transports. + */ + unsigned int +-nfs_svc_create(__attribute__((unused)) char *name, +- const rpcprog_t program, const rpcvers_t version, ++nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), + const uint16_t port) + { +diff --git a/tests/nsm_client/nsm_client.c b/tests/nsm_client/nsm_client.c +index 0d1159a..0fa3422 100644 +--- a/tests/nsm_client/nsm_client.c ++++ b/tests/nsm_client/nsm_client.c +@@ -205,7 +205,7 @@ nsm_client_get_rpcclient(const char *node) + { + unsigned short port; + struct addrinfo *ai; +- struct addrinfo hints = { .ai_flags = AI_ADDRCONFIG }; ++ struct addrinfo hints = { }; + int err; + CLIENT *client = NULL; + +diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man +index c726dd9..4e3edc5 100644 +--- a/utils/exportfs/exports.man ++++ b/utils/exportfs/exports.man +@@ -145,7 +145,9 @@ storage (see + .IR async + above). + +-In releases of nfs-utils up to and including 1.0.0, this option was the ++In releases of nfs-utils up to and including 1.0.0, the ++.I async ++option was the + default. In all releases after 1.0.0, + .I sync + is the default, and +@@ -375,20 +377,6 @@ If the client asks for alternative locations for the export point, it + will be given this list of alternatives. (Note that actual replication + of the filesystem must be handled elsewhere.) + +-.TP +-.IR refer= path@host[+host][:path@host[+host]] +-A client referencing the export point will be directed to choose from +-the given list an alternative location for the filesystem. +-(Note that the server must have a mountpoint here, though a different +-filesystem is not required; so, for example, +-.IR "mount --bind" " /path /path" +-is sufficient.) +-.TP +-.IR replicas= path@host[+host][:path@host[+host]] +-If the client asks for alternative locations for the export point, it +-will be given this list of alternatives. (Note that actual replication +-of the filesystem must be handled elsewhere.) +- + .SS User ID Mapping + .PP + .B nfsd +diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am +index 4218048..4328e41 100644 +--- a/utils/idmapd/Makefile.am ++++ b/utils/idmapd/Makefile.am +@@ -11,12 +11,8 @@ EXTRA_DIST = \ + idmapd.conf + + idmapd_SOURCES = \ +- atomicio.c \ + idmapd.c \ +- strlcat.c \ +- strlcpy.c \ + \ +- cfg.h \ + nfs_idmap.h \ + queue.h + +diff --git a/utils/idmapd/atomicio.c b/utils/idmapd/atomicio.c +deleted file mode 100644 +index 1fb1ff9..0000000 +--- a/utils/idmapd/atomicio.c ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* +- * Copyright (c) 2002 Marius Aamodt Eriksen +- * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * +- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- */ +- +-#include +-#include +-#include +- +-#ifdef HAVE_CONFIG_H +-#include "config.h" +-#endif /* HAVE_CONFIG_H */ +- +-/* +- * ensure all of data on socket comes through. f==read || f==write +- */ +-ssize_t +-atomicio( +- ssize_t (*f) (int, void*, size_t), +- int fd, +- void *_s, +- size_t n) +-{ +- char *s = _s; +- ssize_t res; +- size_t pos = 0; +- +- while (n > pos) { +- res = (f) (fd, s + pos, n - pos); +- switch (res) { +- case -1: +- if (errno == EINTR || errno == EAGAIN) +- continue; +- case 0: +- if (pos != 0) +- return (pos); +- return (res); +- default: +- pos += res; +- } +- } +- return (pos); +-} +diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c +index b76607a..76a56ef 100644 +--- a/utils/idmapd/idmapd.c ++++ b/utils/idmapd/idmapd.c +@@ -158,10 +158,6 @@ static int nfsdopenone(struct idmap_client *); + static void nfsdreopen_one(struct idmap_client *); + static void nfsdreopen(void); + +-size_t strlcat(char *, const char *, size_t); +-size_t strlcpy(char *, const char *, size_t); +-ssize_t atomicio(ssize_t (*f) (int, void*, size_t), +- int, void *, size_t); + void mydaemon(int, int); + void release_parent(void); + +diff --git a/utils/idmapd/strlcat.c b/utils/idmapd/strlcat.c +deleted file mode 100644 +index daedd7a..0000000 +--- a/utils/idmapd/strlcat.c ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ +- +-/* +- * Copyright (c) 1998 Todd C. Miller +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 3. The name of the author may not be used to endorse or promote products +- * derived from this software without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- */ +- +-#if defined(LIBC_SCCS) && !defined(lint) +-static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"; +-#endif /* LIBC_SCCS and not lint */ +- +-#include +-#include +- +-#ifdef HAVE_CONFIG_H +-#include "config.h" +-#endif /* HAVE_CONFIG_H */ +- +-/* +- * Appends src to string dst of size siz (unlike strncat, siz is the +- * full size of dst, not space left). At most siz-1 characters +- * will be copied. Always NUL terminates (unless siz <= strlen(dst)). +- * Returns strlen(src) + MIN(siz, strlen(initial dst)). +- * If retval >= siz, truncation occurred. +- */ +-size_t +-strlcat(char *dst, +- const char *src, +- size_t siz) +-{ +- register char *d = dst; +- register const char *s = src; +- register size_t n = siz; +- size_t dlen; +- +- /* Find the end of dst and adjust bytes left but don't go past end */ +- while (n-- != 0 && *d != '\0') +- d++; +- dlen = d - dst; +- n = siz - dlen; +- +- if (n == 0) +- return(dlen + strlen(s)); +- while (*s != '\0') { +- if (n != 1) { +- *d++ = *s; +- n--; +- } +- s++; +- } +- *d = '\0'; +- +- return(dlen + (s - src)); /* count does not include NUL */ +-} +diff --git a/utils/idmapd/strlcpy.c b/utils/idmapd/strlcpy.c +deleted file mode 100644 +index a2653ee..0000000 +--- a/utils/idmapd/strlcpy.c ++++ /dev/null +@@ -1,72 +0,0 @@ +-/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ +- +-/* +- * Copyright (c) 1998 Todd C. Miller +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 3. The name of the author may not be used to endorse or promote products +- * derived from this software without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- */ +- +-#if defined(LIBC_SCCS) && !defined(lint) +-static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; +-#endif /* LIBC_SCCS and not lint */ +- +-#include +-#include +- +-#ifdef HAVE_CONFIG_H +-#include "config.h" +-#endif /* HAVE_CONFIG_H */ +- +-/* +- * Copy src to string dst of size siz. At most siz-1 characters +- * will be copied. Always NUL terminates (unless siz == 0). +- * Returns strlen(src); if retval >= siz, truncation occurred. +- */ +-size_t +-strlcpy(char *dst, +- const char *src, +- size_t siz) +-{ +- register char *d = dst; +- register const char *s = src; +- register size_t n = siz; +- +- /* Copy as many bytes as will fit */ +- if (n != 0 && --n != 0) { +- do { +- if ((*d++ = *s++) == 0) +- break; +- } while (--n != 0); +- } +- +- /* Not enough room in dst, add NUL and traverse rest of src */ +- if (n == 0) { +- if (siz != 0) +- *d = '\0'; /* NUL-terminate dst */ +- while (*s++) +- ; +- } +- +- return(s - src - 1); /* count does not include NUL */ +-} +diff --git a/utils/mount/fstab.c b/utils/mount/fstab.c +index 051fa38..a742e64 100644 +--- a/utils/mount/fstab.c ++++ b/utils/mount/fstab.c +@@ -364,19 +364,22 @@ lock_mtab (void) { + /* Repeat until it was us who made the link */ + while (!we_created_lockfile) { + struct flock flock; +- int errsv, j; ++ int j; + + j = link(linktargetfile, MOUNTED_LOCK); +- errsv = errno; + +- if (j == 0) +- we_created_lockfile = 1; ++ { ++ int errsv = errno; + +- if (j < 0 && errsv != EEXIST) { +- (void) unlink(linktargetfile); +- die (EX_FILEIO, _("can't link lock file %s: %s " +- "(use -n flag to override)"), +- MOUNTED_LOCK, strerror (errsv)); ++ if (j == 0) ++ we_created_lockfile = 1; ++ ++ if (j < 0 && errsv != EEXIST) { ++ (void) unlink(linktargetfile); ++ die (EX_FILEIO, _("can't link lock file %s: %s " ++ "(use -n flag to override)"), ++ MOUNTED_LOCK, strerror (errsv)); ++ } + } + + lockfile_fd = open (MOUNTED_LOCK, O_WRONLY); +@@ -414,7 +417,7 @@ lock_mtab (void) { + } + (void) unlink(linktargetfile); + } else { +- static int tries = 0; ++ static int retries = 0; + + /* Someone else made the link. Wait. */ + alarm(LOCK_TIMEOUT); +@@ -428,10 +431,10 @@ lock_mtab (void) { + alarm(0); + /* Limit the number of iterations - maybe there + still is some old /etc/mtab~ */ +- ++tries; +- if (tries % 200 == 0) ++ ++retries; ++ if (retries % 200 == 0) + usleep(30); +- if (tries > 100000) { ++ if (retries > 100000) { + (void) unlink(linktargetfile); + close(lockfile_fd); + die (EX_FILEIO, _("Cannot create link %s\n" +diff --git a/utils/mount/mount.c b/utils/mount/mount.c +index 82b9169..a19af53 100644 +--- a/utils/mount/mount.c ++++ b/utils/mount/mount.c +@@ -209,7 +209,7 @@ static char *fix_opts_string(int flags, const char *extra_opts) + } + if (flags & MS_USERS) + new_opts = xstrconcat3(new_opts, ",users", ""); +- ++ + for (om = opt_map; om->opt != NULL; om++) { + if (om->skip) + continue; +@@ -224,6 +224,20 @@ static char *fix_opts_string(int flags, const char *extra_opts) + return new_opts; + } + ++static void ++init_mntent(struct mntent *mnt, char *fsname, char *dir, char *type, ++ int flags, char *opts) ++{ ++ mnt->mnt_fsname = fsname; ++ mnt->mnt_dir = dir; ++ mnt->mnt_type = type; ++ mnt->mnt_opts = fix_opts_string(flags & ~MS_NOMTAB, opts); ++ ++ /* these are always zero for NFS */ ++ mnt->mnt_freq = 0; ++ mnt->mnt_passno = 0; ++} ++ + /* Create mtab with a root entry. */ + static void + create_mtab (void) { +@@ -245,11 +259,8 @@ create_mtab (void) { + if ((fstab = getfsfile ("/")) || (fstab = getfsfile ("root"))) { + char *extra_opts; + parse_opts (fstab->m.mnt_opts, &flags, &extra_opts); +- mnt.mnt_dir = "/"; +- mnt.mnt_fsname = xstrdup(fstab->m.mnt_fsname); +- mnt.mnt_type = fstab->m.mnt_type; +- mnt.mnt_opts = fix_opts_string (flags, extra_opts); +- mnt.mnt_freq = mnt.mnt_passno = 0; ++ init_mntent(&mnt, xstrdup(fstab->m.mnt_fsname), "/", ++ fstab->m.mnt_type, flags, extra_opts); + free(extra_opts); + + if (nfs_addmntent (mfp, &mnt) == 1) { +@@ -273,17 +284,12 @@ create_mtab (void) { + } + + static int add_mtab(char *spec, char *mount_point, char *fstype, +- int flags, char *opts, int freq, int pass) ++ int flags, char *opts) + { + struct mntent ment; + int result = EX_SUCCESS; + +- ment.mnt_fsname = spec; +- ment.mnt_dir = mount_point; +- ment.mnt_type = fstype; +- ment.mnt_opts = fix_opts_string(flags, opts); +- ment.mnt_freq = freq; +- ment.mnt_passno = pass; ++ init_mntent(&ment, spec, mount_point, fstype, flags, opts); + + if (!nomtab && mtab_does_not_exist()) { + if (verbose > 1) +@@ -321,7 +327,7 @@ static int add_mtab(char *spec, char *mount_point, char *fstype, + return result; + } + +-void mount_usage(void) ++static void mount_usage(void) + { + printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"), + progname); +@@ -337,7 +343,7 @@ void mount_usage(void) + printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n")); + } + +-static void parse_opt(const char *opt, int *mask, char *extra_opts, int len) ++static void parse_opt(const char *opt, int *mask, char *extra_opts, size_t len) + { + const struct opt_map *om; + +@@ -371,7 +377,7 @@ static void parse_opts(const char *options, int *flags, char **extra_opts) + if (options != NULL) { + char *opts = xstrdup(options); + char *opt, *p; +- int len = strlen(opts) + 1; /* include room for a null */ ++ size_t len = strlen(opts) + 1; /* include room for a null */ + int open_quote = 0; + + *extra_opts = xmalloc(len); +@@ -441,9 +447,7 @@ static int try_mount(char *spec, char *mount_point, int flags, + if (!fake) + print_one(spec, mount_point, fs_type, mount_opts); + +- ret = add_mtab(spec, mount_point, fs_type, flags, *extra_opts, +- 0, 0 /* these are always zero for NFS */ ); +- return ret; ++ return add_mtab(spec, mount_point, fs_type, flags, *extra_opts); + } + + int main(int argc, char *argv[]) +diff --git a/utils/mount/mount_config.h b/utils/mount/mount_config.h +index 3023306..e86b4ba 100644 +--- a/utils/mount/mount_config.h ++++ b/utils/mount/mount_config.h +@@ -1,7 +1,7 @@ +-#ifndef _LINUX_MOUNT__CONFIG_H +-#define _LINUX_MOUNT_CONFIG__H ++#ifndef _LINUX_MOUNT_CONFIG_H ++#define _LINUX_MOUNT_CONFIG_H + /* +- * mount_config.h -- mount configuration file routines ++ * mount_config.h -- mount configuration file routines + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify +@@ -16,15 +16,13 @@ + * + */ + +-inline void mount_config_init(char *); +- + #ifdef MOUNT_CONFIG + #include "conffile.h" + #include "xlog.h" + + extern char *conf_get_mntopts(char *, char *, char *); + +-inline void mount_config_init(char *program) ++static inline void mount_config_init(char *program) + { + xlog_open(program); + /* +@@ -32,19 +30,22 @@ inline void mount_config_init(char *program) + */ + conf_init(); + } +-inline char *mount_config_opts(char *spec, ++ ++static inline char *mount_config_opts(char *spec, + char *mount_point, char *mount_opts) + { + return conf_get_mntopts(spec, mount_point, mount_opts); + } ++ + #else /* MOUNT_CONFIG */ + +-inline void mount_config_init(char *program) { } ++static inline void mount_config_init(char *program) { } + +-inline char *mount_config_opts(char *spec, ++static inline char *mount_config_opts(char *spec, + char *mount_point, char *mount_opts) + { + return mount_opts; + } + #endif /* MOUNT_CONFIG */ +-#endif ++ ++#endif /* _LINUX_MOUNT_CONFIG_H */ +diff --git a/utils/mount/mount_constants.h b/utils/mount/mount_constants.h +index cbfb099..4d050d8 100644 +--- a/utils/mount/mount_constants.h ++++ b/utils/mount/mount_constants.h +@@ -64,4 +64,8 @@ if we have a stack or plain mount - mount atop of it, forming a stack. */ + #define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ + #endif + ++/* Generic options that are prevented from appearing ++ * in the options field in /etc/mtab. */ ++#define MS_NOMTAB (MS_REMOUNT) ++ + #endif /* _NFS_UTILS_MOUNT_CONSTANTS_H */ +diff --git a/utils/mount/network.c b/utils/mount/network.c +index d612427..21a7a2c 100644 +--- a/utils/mount/network.c ++++ b/utils/mount/network.c +@@ -59,6 +59,8 @@ + #define CONNECT_TIMEOUT (20) + #define MOUNT_TIMEOUT (30) + ++#define SAFE_SOCKADDR(x) (struct sockaddr *)(char *)(x) ++ + extern int nfs_mount_data_version; + extern char *progname; + extern int verbose; +@@ -208,9 +210,6 @@ int nfs_lookup(const char *hostname, const sa_family_t family, + { + struct addrinfo *gai_results; + struct addrinfo gai_hint = { +-#ifdef HAVE_DECL_AI_ADDRCONFIG +- .ai_flags = AI_ADDRCONFIG, +-#endif /* HAVE_DECL_AI_ADDRCONFIG */ + .ai_family = family, + }; + socklen_t len = *salen; +@@ -428,12 +427,12 @@ static int get_socket(struct sockaddr_in *saddr, unsigned int p_prot, + if (bindresvport(so, &laddr) < 0) + goto err_bindresvport; + } else { +- cc = bind(so, (struct sockaddr *)&laddr, namelen); ++ cc = bind(so, SAFE_SOCKADDR(&laddr), namelen); + if (cc < 0) + goto err_bind; + } + if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) { +- cc = connect_to(so, (struct sockaddr *)saddr, namelen, ++ cc = connect_to(so, SAFE_SOCKADDR(saddr), namelen, + timeout); + if (cc < 0) + goto err_connect; +@@ -756,11 +755,12 @@ int nfs_probe_bothports(const struct sockaddr *mnt_saddr, + */ + int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) + { +- return nfs_probe_bothports((struct sockaddr *)&mnt_server->saddr, +- sizeof(mnt_server->saddr), ++ struct sockaddr *mnt_addr = SAFE_SOCKADDR(&mnt_server->saddr); ++ struct sockaddr *nfs_addr = SAFE_SOCKADDR(&nfs_server->saddr); ++ ++ return nfs_probe_bothports(mnt_addr, sizeof(mnt_server->saddr), + &mnt_server->pmap, +- (struct sockaddr *)&nfs_server->saddr, +- sizeof(nfs_server->saddr), ++ nfs_addr, sizeof(nfs_server->saddr), + &nfs_server->pmap); + } + +@@ -772,7 +772,7 @@ static int nfs_probe_statd(void) + }; + rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); + +- return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr), ++ return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr), + program, (rpcvers_t)1, IPPROTO_UDP); + } + +@@ -901,7 +901,7 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, + */ + int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp) + { +- struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr; ++ struct sockaddr *sap = SAFE_SOCKADDR(&mnt_server->saddr); + socklen_t salen = sizeof(mnt_server->saddr); + struct pmap *pmap = &mnt_server->pmap; + CLIENT *clnt; +@@ -1011,11 +1011,11 @@ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog, + struct sockaddr_in *caddr) + { + CLIENT *clnt = NULL; +- int sock, stat; ++ int sock, status; + static char clnt_res; + struct sockaddr dissolve; + +- rpc_createerr.cf_stat = stat = 0; ++ rpc_createerr.cf_stat = status = 0; + sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE); + if (sock == RPC_ANYSOCK) { + if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) { +@@ -1058,18 +1058,18 @@ int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog, + return 0; + } + memset(&clnt_res, 0, sizeof(clnt_res)); +- stat = clnt_call(clnt, NULLPROC, ++ status = clnt_call(clnt, NULLPROC, + (xdrproc_t)xdr_void, (caddr_t)NULL, + (xdrproc_t)xdr_void, (caddr_t)&clnt_res, + TIMEOUT); +- if (stat) { ++ if (status) { + clnt_geterr(clnt, &rpc_createerr.cf_error); +- rpc_createerr.cf_stat = stat; ++ rpc_createerr.cf_stat = status; + } + clnt_destroy(clnt); + close(sock); + +- if (stat == RPC_SUCCESS) ++ if (status == RPC_SUCCESS) + return 1; + else + return 0; +@@ -1103,13 +1103,13 @@ static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen, + + switch (sap->sa_family) { + case AF_INET: +- if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { ++ if (bind(sock, SAFE_SOCKADDR(&sin), sizeof(sin)) < 0) { + close(sock); + return 0; + } + break; + case AF_INET6: +- if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) { ++ if (bind(sock, SAFE_SOCKADDR(&sin6), sizeof(sin6)) < 0) { + close(sock); + return 0; + } +@@ -1518,7 +1518,11 @@ nfs_mount_protocol(struct mount_options *options, unsigned long *protocol) + * set @protocol to zero. The pmap protocol value will + * be filled in later by an rpcbind query in this case. + */ +- return nfs_nfs_protocol(options, protocol); ++ if (!nfs_nfs_protocol(options, protocol)) ++ return 0; ++ if (*protocol == NFSPROTO_RDMA) ++ *protocol = IPPROTO_TCP; ++ return 1; + } + + /* +diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man +index 55d4b55..be91a25 100644 +--- a/utils/mount/nfs.man ++++ b/utils/mount/nfs.man +@@ -69,10 +69,9 @@ for details on specifying raw IPv6 addresses. + .P + The + .I fstype +-field contains "nfs", for whatever version of the protocol. +-The +-.B nfs +-allow several mount options, which are described below. ++field contains "nfs". Use of the "nfs4" fstype in ++.I /etc/fstab ++is deprecated. + .SH "MOUNT OPTIONS" + Refer to + .BR mount (8) +@@ -464,9 +463,9 @@ by other clients, but can impact application and server performance. + .IP + The DATA AND METADATA COHERENCE section contains a + detailed discussion of these trade-offs. +-.SS "Options for versions 2 and 3 only" ++.SS "Options for NFS versions 2 and 3 only" + Use these options, along with the options in the above subsection, +-for NFSv2/v3 only. They will be ignored for newer versions. ++for NFS versions 2 and 3 only. + .TP 1.5i + .BI proto= netid + The transport protocol name and protocol family the NFS client uses +@@ -619,7 +618,7 @@ in such cases. + .BI nfsvers= n + The NFS protocol version number used to contact the server's NFS service. + 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 ++If this option is not specified, the client negotiates a suitable version with + the server, trying version 4 first, version 3 second, and version 2 last. + .TP 1.5i + .BI vers= n +@@ -717,9 +716,53 @@ If this option is not specified, the NFS client uses READDIRPLUS requests + on NFS version 3 mounts to read small directories. + Some applications perform better if the client uses only READDIR requests + for all directories. +-.SS "Options for version 4 only" ++.TP 1.5i ++.BR local_lock= mechanism ++Specifies whether to use local locking for any or both of the flock and the ++POSIX locking mechanisms. ++.I mechanism ++can be one of ++.BR all , ++.BR flock , ++.BR posix , ++or ++.BR none . ++This option is supported in kernels 2.6.37 and later. ++.IP ++The Linux NFS client provides a way to make locks local. This means, the ++applications can lock files, but such locks provide exclusion only against ++other applications running on the same client. Remote applications are not ++affected by these locks. ++.IP ++If this option is not specified, or if ++.B none ++is specified, the client assumes that the locks are not local. ++.IP ++If ++.BR all ++is specified, the client assumes that both flock and POSIX locks are local. ++.IP ++If ++.BR flock ++is specified, the client assumes that only flock locks are local and uses ++NLM sideband protocol to lock files when POSIX locks are used. ++.IP ++If ++.BR posix ++is specified, the client assumes that POSIX locks are local and uses NLM ++sideband protocol to lock files when flock locks are used. ++.IP ++To support legacy flock behavior similar to that of NFS clients < 2.6.12, use ++'local_lock=flock'. This option is required when exporting NFS mounts via ++Samba as Samba maps Windows share mode locks as flock. Since NFS clients > ++2.6.12 implement flock by emulating POSIX locks, this will result in ++conflicting locks. ++.IP ++NOTE: When used together, the 'local_lock' mount option will be overridden ++by 'nolock'/'lock' mount option. ++.SS "Options for NFS version 4 only" + Use these options, along with the options in the first subsection above, +-for NFSv4 only. They will be ignored with older versions. ++for NFS version 4 and newer. + .TP 1.5i + .BI proto= netid + The transport protocol name and protocol family the NFS client uses +@@ -1480,32 +1523,54 @@ of Access Control Lists that are semantically richer than POSIX ACLs. + NFS version 4 ACLs are not fully compatible with POSIX ACLs; as such, + some translation between the two is required + in an environment that mixes POSIX ACLs and NFS version 4. +-.SH FILES +-.TP 1.5i +-.I /etc/fstab +-file system table +-.SH BUGS +-The generic +-.B remount +-option is not fully supported. +-Generic options, such as +-.BR rw " and " ro +-can be modified using the +-.B remount +-option, +-but NFS-specific options are not all supported. ++.SH "THE REMOUNT OPTION" ++Generic mount options such as ++.BR rw " and " sync ++can be modified on NFS mount points using the ++.BR remount ++option. ++See ++.BR mount (8) ++for more information on generic mount options. ++.P ++With few exceptions, NFS-specific options ++are not able to be modified during a remount. + The underlying transport or NFS version + cannot be changed by a remount, for example. ++.P + Performing a remount on an NFS file system mounted with the + .B noac + option may have unintended consequences. + The + .B noac +-option is a mixture of a generic option, ++option is a combination of the generic option + .BR sync , +-and an NFS-specific option ++and the NFS-specific option + .BR actimeo=0 . ++.SS "Unmounting after a remount" ++For mount points that use NFS versions 2 or 3, the NFS umount subcommand ++depends on knowing the original set of mount options used to perform the ++MNT operation. ++These options are stored on disk by the NFS mount subcommand, ++and can be erased by a remount. + .P ++To ensure that the saved mount options are not erased during a remount, ++specify either the local mount directory, or the server hostname and ++export pathname, but not both, during a remount. For example, ++.P ++.NF ++.TA 2.5i ++ mount -o remount,ro /mnt ++.FI ++.P ++merges the mount option ++.B ro ++with the mount options already saved on disk for the NFS server mounted at /mnt. ++.SH FILES ++.TP 1.5i ++.I /etc/fstab ++file system table ++.SH BUGS + Before 2.4.7, the Linux NFS client did not support NFS over TCP. + .P + Before 2.4.20, the Linux NFS client used a heuristic +diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c +index 1514340..02d40ff 100644 +--- a/utils/mount/nfsumount.c ++++ b/utils/mount/nfsumount.c +@@ -31,12 +31,16 @@ + #include "nls.h" + + #include "mount_constants.h" ++#include "nfs_mount.h" + #include "mount.h" + #include "error.h" + #include "network.h" + #include "parse_opt.h" + #include "parse_dev.h" + ++#define MOUNTSFILE "/proc/mounts" ++#define LINELEN (4096) ++ + #if !defined(MNT_FORCE) + /* dare not try to include -- lots of errors */ + #define MNT_FORCE 1 +@@ -109,7 +113,7 @@ static int del_mtab(const char *spec, const char *node) + res = try_remount(spec, node); + if (res) + goto writemtab; +- return 0; ++ return EX_SUCCESS; + } else + umnt_err = errno; + } +@@ -127,7 +131,7 @@ static int del_mtab(const char *spec, const char *node) + } + + if (res >= 0) +- return 0; ++ return EX_SUCCESS; + + if (umnt_err) + umount_error(umnt_err, node); +@@ -241,6 +245,91 @@ static int nfs_umount23(const char *devname, char *string) + return result; + } + ++/* ++ * Detect NFSv4 mounts. ++ * ++ * Consult /proc/mounts to determine if the mount point ++ * is an NFSv4 mount. The kernel is authoritative about ++ * what type of mount this is. ++ * ++ * Returns 1 if "mc" is an NFSv4 mount, zero if not, and ++ * -1 if some error occurred. ++ */ ++static int nfs_umount_is_vers4(const struct mntentchn *mc) ++{ ++ char buffer[LINELEN], *next; ++ int retval; ++ FILE *f; ++ ++ if ((f = fopen(MOUNTSFILE, "r")) == NULL) { ++ fprintf(stderr, "%s: %s\n", ++ MOUNTSFILE, strerror(errno)); ++ return -1; ++ } ++ ++ retval = -1; ++ while (fgets(buffer, sizeof(buffer), f) != NULL) { ++ char *device, *mntdir, *type, *flags; ++ struct mount_options *options; ++ char *line = buffer; ++ ++ next = strchr(line, '\n'); ++ if (next != NULL) ++ *next = '\0'; ++ ++ device = strtok(line, " \t"); ++ if (device == NULL) ++ continue; ++ mntdir = strtok(NULL, " \t"); ++ if (mntdir == NULL) ++ continue; ++ if (strcmp(device, mc->m.mnt_fsname) != 0 && ++ strcmp(mntdir, mc->m.mnt_dir) != 0) ++ continue; ++ ++ type = strtok(NULL, " \t"); ++ if (type == NULL) ++ continue; ++ if (strcmp(type, "nfs4") == 0) ++ goto out_nfs4; ++ ++ flags = strtok(NULL, " \t"); ++ if (flags == NULL) ++ continue; ++ options = po_split(flags); ++ if (options != NULL) { ++ unsigned long version; ++ int rc; ++ ++ rc = nfs_nfs_version(options, &version); ++ po_destroy(options); ++ if (rc && version == 4) ++ goto out_nfs4; ++ } ++ ++ goto out_nfs; ++ } ++ if (retval == -1) ++ fprintf(stderr, "%s was not found in %s\n", ++ mc->m.mnt_dir, MOUNTSFILE); ++ ++out: ++ fclose(f); ++ return retval; ++ ++out_nfs4: ++ if (verbose) ++ fprintf(stderr, "NFSv4 mount point detected\n"); ++ retval = 1; ++ goto out; ++ ++out_nfs: ++ if (verbose) ++ fprintf(stderr, "Legacy NFS mount point detected\n"); ++ retval = 0; ++ goto out; ++} ++ + static struct option umount_longopts[] = + { + { "force", 0, 0, 'f' }, +@@ -362,16 +451,25 @@ int nfsumount(int argc, char *argv[]) + } + } + +- ret = 0; ++ ret = EX_SUCCESS; + if (mc) { +- if (!lazy && strcmp(mc->m.mnt_type, "nfs4") != 0) +- /* We ignore the error from nfs_umount23. +- * If the actual umount succeeds (in del_mtab), +- * we don't want to signal an error, as that +- * could cause /sbin/mount to retry! +- */ +- nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts); +- ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir) ?: ret; ++ if (!lazy) { ++ switch (nfs_umount_is_vers4(mc)) { ++ case 0: ++ /* We ignore the error from nfs_umount23. ++ * If the actual umount succeeds (in del_mtab), ++ * we don't want to signal an error, as that ++ * could cause /sbin/mount to retry! ++ */ ++ nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts); ++ break; ++ case 1: ++ break; ++ default: ++ return EX_FAIL; ++ } ++ } ++ ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir); + } else if (*spec != '/') { + if (!lazy) + ret = nfs_umount23(spec, "tcp,v3"); +diff --git a/utils/mount/parse_opt.c b/utils/mount/parse_opt.c +index f0918f7..ab869d9 100644 +--- a/utils/mount/parse_opt.c ++++ b/utils/mount/parse_opt.c +@@ -508,7 +508,7 @@ po_found_t po_get_numeric(struct mount_options *options, char *keyword, long *va + int po_rightmost(struct mount_options *options, const char *keys[]) + { + struct mount_option *option; +- unsigned int i; ++ int i; + + if (options) { + for (option = options->tail; option; option = option->prev) { +diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c +index 50a1a2a..ac81616 100644 +--- a/utils/mount/stropts.c ++++ b/utils/mount/stropts.c +@@ -49,10 +49,6 @@ + #include "parse_dev.h" + #include "conffile.h" + +-#ifndef HAVE_DECL_AI_ADDRCONFIG +-#define AI_ADDRCONFIG 0 +-#endif +- + #ifndef NFS_PROGRAM + #define NFS_PROGRAM (100003) + #endif +@@ -123,10 +119,12 @@ inline void nfs_default_version(struct nfsmount_info *mi) {} + * Returns a time_t timeout timestamp, in seconds. + */ + static time_t nfs_parse_retry_option(struct mount_options *options, +- unsigned int timeout_minutes) ++ const time_t default_timeout) + { ++ time_t timeout_minutes; + long tmp; + ++ timeout_minutes = default_timeout; + switch (po_get_numeric(options, "retry", &tmp)) { + case PO_NOT_FOUND: + break; +@@ -135,6 +133,7 @@ static time_t nfs_parse_retry_option(struct mount_options *options, + timeout_minutes = tmp; + break; + } ++ /*FALLTHROUGH*/ + case PO_BAD_VALUE: + if (verbose) + nfs_error(_("%s: invalid retry timeout was specified; " +@@ -142,7 +141,7 @@ static time_t nfs_parse_retry_option(struct mount_options *options, + break; + } + +- return time(NULL) + (time_t)(timeout_minutes * 60); ++ return time(NULL) + (timeout_minutes * 60); + } + + /* +@@ -343,7 +342,6 @@ static int nfs_validate_options(struct nfsmount_info *mi) + { + struct addrinfo hint = { + .ai_protocol = (int)IPPROTO_UDP, +- .ai_flags = AI_ADDRCONFIG, + }; + sa_family_t family; + int error; +@@ -570,16 +568,18 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts) + char *options = NULL; + int result; + ++ if (mi->fake) ++ return 1; ++ + if (po_join(opts, &options) == PO_FAILED) { + errno = EIO; + return 0; + } + +- if (mi->fake) +- return 1; +- + result = mount(mi->spec, mi->node, mi->type, + mi->flags & ~(MS_USER|MS_USERS), options); ++ free(options); ++ + if (verbose && result) { + int save = errno; + nfs_error(_("%s: mount(2): %s"), progname, strerror(save)); +diff --git a/utils/mount/version.h b/utils/mount/version.h +index 46552a1..af61a6f 100644 +--- a/utils/mount/version.h ++++ b/utils/mount/version.h +@@ -42,9 +42,9 @@ static inline unsigned int linux_version_code(void) + if (uname(&my_utsname)) + return 0; + +- p = atoi(strtok(my_utsname.release, ".")); +- q = atoi(strtok(NULL, ".")); +- r = atoi(strtok(NULL, ".")); ++ p = (unsigned int)atoi(strtok(my_utsname.release, ".")); ++ q = (unsigned int)atoi(strtok(NULL, ".")); ++ r = (unsigned int)atoi(strtok(NULL, ".")); + return MAKE_VERSION(p, q, r); + } + +diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c +index d309950..035624c 100644 +--- a/utils/mountd/mountd.c ++++ b/utils/mountd/mountd.c +@@ -99,12 +99,9 @@ static int version_any(void) + static void + unregister_services (void) + { +- if (version2()) { +- nfs_svc_unregister(MOUNTPROG, MOUNTVERS); +- nfs_svc_unregister(MOUNTPROG, MOUNTVERS_POSIX); +- } +- if (version3()) +- nfs_svc_unregister(MOUNTPROG, MOUNTVERS_NFSV3); ++ nfs_svc_unregister(MOUNTPROG, MOUNTVERS); ++ nfs_svc_unregister(MOUNTPROG, MOUNTVERS_POSIX); ++ nfs_svc_unregister(MOUNTPROG, MOUNTVERS_NFSV3); + } + + static void +@@ -840,6 +837,7 @@ main(int argc, char **argv) + if (new_cache) + cache_open(); + ++ unregister_services(); + if (version2()) { + listeners += nfs_svc_create("mountd", MOUNTPROG, + MOUNTVERS, mount_dispatch, port); +diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man +index 4bb96e8..016a357 100644 +--- a/utils/mountd/mountd.man ++++ b/utils/mountd/mountd.man +@@ -106,11 +106,11 @@ This option can be used to request that + .B rpc.mountd + do not offer certain versions of NFS. The current version of + .B rpc.mountd +-can support both NFS version 2 and the newer version 3. If the +-NFS kernel module was compiled without support for NFSv3, ++can support both NFS version 2, 3 and 4. If the ++either one of these version should not be offered, + .B rpc.mountd + must be invoked with the option +-.B "\-\-no-nfs-version 3" . ++.B "\-\-no-nfs-version " . + .TP + .B \-n " or " \-\-no-tcp + Don't advertise TCP for mount. +diff --git a/utils/statd/hostname.c b/utils/statd/hostname.c +index 38f2265..616a3cb 100644 +--- a/utils/statd/hostname.c ++++ b/utils/statd/hostname.c +@@ -39,10 +39,6 @@ + #include "statd.h" + #include "xlog.h" + +-#ifndef HAVE_DECL_AI_ADDRCONFIG +-#define AI_ADDRCONFIG 0 +-#endif +- + /** + * statd_present_address - convert sockaddr to presentation address + * @sap: pointer to socket address to convert +diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c +index 437e37a..b7f4371 100644 +--- a/utils/statd/sm-notify.c ++++ b/utils/statd/sm-notify.c +@@ -34,10 +34,6 @@ + #include "nsm.h" + #include "nfsrpc.h" + +-#ifndef HAVE_DECL_AI_ADDRCONFIG +-#define AI_ADDRCONFIG 0 +-#endif +- + #define NSM_TIMEOUT 2 + #define NSM_MAX_TIMEOUT 120 /* don't make this too big */ + +@@ -78,7 +74,6 @@ smn_lookup(const char *name) + { + struct addrinfo *ai = NULL; + struct addrinfo hint = { +- .ai_flags = AI_ADDRCONFIG, + .ai_family = (nsm_family == AF_INET ? AF_INET: AF_UNSPEC), + .ai_protocol = (int)IPPROTO_UDP, + }; diff --git a/nfs-utils-1.2.4-rc3.patch b/nfs-utils-1.2.4-rc3.patch new file mode 100644 index 0000000..35046d7 --- /dev/null +++ b/nfs-utils-1.2.4-rc3.patch @@ -0,0 +1,2167 @@ +diff -up nfs-utils-1.2.3/aclocal/keyutils.m4.orig nfs-utils-1.2.3/aclocal/keyutils.m4 +--- nfs-utils-1.2.3/aclocal/keyutils.m4.orig 2010-11-29 11:18:44.168551958 -0500 ++++ nfs-utils-1.2.3/aclocal/keyutils.m4 2010-11-29 11:18:44.168551958 -0500 +@@ -0,0 +1,11 @@ ++dnl Checks for keyutils library and headers ++dnl ++AC_DEFUN([AC_KEYUTILS], [ ++ ++ dnl Check for libkeyutils; do not add to LIBS if found ++ AC_CHECK_LIB([keyutils], [keyctl_instantiate], [LIBKEYUTILS=-lkeyutils], ,) ++ AC_SUBST(LIBKEYUTILS) ++ ++ AC_CHECK_HEADERS([keyutils.h], , ++ [AC_MSG_ERROR([keyutils.h header not found.])]) ++])dnl +diff -up nfs-utils-1.2.3/aclocal/libnfsidmap.m4.orig nfs-utils-1.2.3/aclocal/libnfsidmap.m4 +--- nfs-utils-1.2.3/aclocal/libnfsidmap.m4.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/aclocal/libnfsidmap.m4 2010-11-29 11:18:44.168551958 -0500 +@@ -14,4 +14,8 @@ AC_DEFUN([AC_LIBNFSIDMAP], [ + [AC_DEFINE([HAVE_NFS4_SET_DEBUG], 1, + [Define to 1 if you have the `nfs4_set_debug' function.])]) + ++ dnl only enable nfsidmap when libnfsidmap supports it ++ AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid], [enable_nfsidmap=yes], ++ [enable_nfsidmap=no]) ++ + ])dnl +diff -up nfs-utils-1.2.3/configure.ac.orig nfs-utils-1.2.3/configure.ac +--- nfs-utils-1.2.3/configure.ac.orig 2010-11-29 11:17:26.902868938 -0500 ++++ nfs-utils-1.2.3/configure.ac 2010-11-29 11:18:44.169551941 -0500 +@@ -144,7 +144,7 @@ AC_ARG_ENABLE(tirpc, + [AC_HELP_STRING([--enable-tirpc], + [enable use of TI-RPC @<:@default=yes@:>@])], + enable_tirpc=$enableval, +- enable_tirpc='yes') ++ enable_tirpc='') + AC_ARG_ENABLE(ipv6, + [AC_HELP_STRING([--enable-ipv6], + [enable support for IPv6 @<:@default=no@:>@])], +@@ -255,6 +255,12 @@ if test "$enable_nfsv4" = yes; then + dnl check for nfsidmap libraries and headers + AC_LIBNFSIDMAP + ++ dnl enable nfsidmap when its support by libnfsidmap ++ AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$enable_nfsidmap" = "yes"]) ++ ++ dnl check for the keyutils libraries and headers ++ AC_KEYUTILS ++ + dnl librpcsecgss already has a dependency on libgssapi, + dnl but we need to make sure we get the right version + if test "$enable_gss" = yes; then +@@ -446,6 +452,7 @@ AC_CONFIG_FILES([ + utils/mountd/Makefile + utils/nfsd/Makefile + utils/nfsstat/Makefile ++ utils/nfsidmap/Makefile + utils/showmount/Makefile + utils/statd/Makefile + tests/Makefile +diff -up nfs-utils-1.2.3/.gitignore.orig nfs-utils-1.2.3/.gitignore +--- nfs-utils-1.2.3/.gitignore.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/.gitignore 2010-11-29 11:18:44.168551958 -0500 +@@ -64,6 +64,7 @@ tests/nsm_client/nlm_sm_inter.h + tests/nsm_client/nlm_sm_inter_clnt.c + tests/nsm_client/nlm_sm_inter_svc.c + tests/nsm_client/nlm_sm_inter_xdr.c ++utils/nfsidmap/nfsidmap + # cscope database files + cscope.* + # generic editor backup et al +diff -up nfs-utils-1.2.3/support/export/client.c.orig nfs-utils-1.2.3/support/export/client.c +--- nfs-utils-1.2.3/support/export/client.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/support/export/client.c 2010-11-29 11:18:44.170551927 -0500 +@@ -178,6 +178,7 @@ out_badprefix: + static int + init_netmask6(nfs_client *UNUSED(clp), const char *UNUSED(slash)) + { ++ return 0; + } + #endif /* IPV6_SUPPORTED */ + +diff -up nfs-utils-1.2.3/support/export/export.c.orig nfs-utils-1.2.3/support/export/export.c +--- nfs-utils-1.2.3/support/export/export.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/support/export/export.c 2010-11-29 11:18:44.170551927 -0500 +@@ -38,6 +38,7 @@ export_free(nfs_export *exp) + xfree(exp->m_export.e_sqgids); + free(exp->m_export.e_mountpoint); + free(exp->m_export.e_fslocdata); ++ free(exp->m_export.e_uuid); + + xfree(exp->m_export.e_hostname); + xfree(exp); +diff -up nfs-utils-1.2.3/support/export/hostname.c.orig nfs-utils-1.2.3/support/export/hostname.c +--- nfs-utils-1.2.3/support/export/hostname.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/support/export/hostname.c 2010-11-29 11:18:44.171551914 -0500 +@@ -30,10 +30,6 @@ + #include "sockaddr.h" + #include "exportfs.h" + +-#ifndef HAVE_DECL_AI_ADDRCONFIG +-#define AI_ADDRCONFIG 0 +-#endif +- + /** + * host_ntop - generate presentation address given a sockaddr + * @sap: pointer to socket address +@@ -170,7 +166,7 @@ host_addrinfo(const char *hostname) + #endif + /* don't return duplicates */ + .ai_protocol = (int)IPPROTO_UDP, +- .ai_flags = AI_ADDRCONFIG | AI_CANONNAME, ++ .ai_flags = AI_CANONNAME, + }; + int error; + +diff -up nfs-utils-1.2.3/support/include/nfslib.h.orig nfs-utils-1.2.3/support/include/nfslib.h +--- nfs-utils-1.2.3/support/include/nfslib.h.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/support/include/nfslib.h 2010-11-29 11:18:44.172551902 -0500 +@@ -163,6 +163,12 @@ void closeall(int min); + int svctcp_socket (u_long __number, int __reuse); + int svcudp_socket (u_long __number); + ++/* Misc shared code prototypes */ ++size_t strlcat(char *, const char *, size_t); ++size_t strlcpy(char *, const char *, size_t); ++ssize_t atomicio(ssize_t (*f) (int, void*, size_t), ++ int, void *, size_t); ++ + + #define UNUSED(x) UNUSED_ ## x __attribute__((unused)) + +diff -up nfs-utils-1.2.3/support/nfs/atomicio.c.orig nfs-utils-1.2.3/support/nfs/atomicio.c +--- nfs-utils-1.2.3/support/nfs/atomicio.c.orig 2010-11-29 11:18:44.173551890 -0500 ++++ nfs-utils-1.2.3/support/nfs/atomicio.c 2010-11-29 11:18:44.173551890 -0500 +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2002 Marius Aamodt Eriksen ++ * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++ ++/* ++ * ensure all of data on socket comes through. f==read || f==write ++ */ ++ssize_t atomicio(ssize_t(*f) (int, void *, size_t), int fd, void *_s, size_t n) ++{ ++ char *s = _s; ++ ssize_t res, pos = 0; ++ ++ while ((ssize_t)n > pos) { ++ res = (f) (fd, s + pos, n - pos); ++ switch (res) { ++ case -1: ++ if (errno == EINTR || errno == EAGAIN) ++ continue; ++ case 0: ++ if (pos != 0) ++ return pos; ++ return res; ++ default: ++ pos += res; ++ } ++ } ++ return pos; ++} +diff -up nfs-utils-1.2.3/support/nfs/conffile.c.orig nfs-utils-1.2.3/support/nfs/conffile.c +--- nfs-utils-1.2.3/support/nfs/conffile.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/support/nfs/conffile.c 2010-11-29 11:18:44.174551888 -0500 +@@ -271,9 +271,9 @@ conf_parse_line(int trans, char *line, s + if (ptr == NULL) + return; + line = ++ptr; +- while (*ptr && *ptr != '"') ++ while (*ptr && *ptr != '"' && *ptr != ']') + ptr++; +- if (*ptr == '\0') { ++ if (*ptr == '\0' || *ptr == ']') { + xlog_warn("config file error: line %d: " + "non-matched '\"', ignoring until next section", ln); + } else { +diff -up nfs-utils-1.2.3/support/nfs/exports.c.orig nfs-utils-1.2.3/support/nfs/exports.c +--- nfs-utils-1.2.3/support/nfs/exports.c.orig 2010-11-29 11:17:26.906868973 -0500 ++++ nfs-utils-1.2.3/support/nfs/exports.c 2010-11-29 11:18:44.174551888 -0500 +@@ -332,6 +332,8 @@ dupexportent(struct exportent *dst, stru + dst->e_mountpoint = strdup(src->e_mountpoint); + if (src->e_fslocdata) + dst->e_fslocdata = strdup(src->e_fslocdata); ++ if (src->e_uuid) ++ dst->e_uuid = strdup(src->e_uuid); + dst->e_hostname = NULL; + } + +diff -up nfs-utils-1.2.3/support/nfs/Makefile.am.orig nfs-utils-1.2.3/support/nfs/Makefile.am +--- nfs-utils-1.2.3/support/nfs/Makefile.am.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/support/nfs/Makefile.am 2010-11-29 11:18:44.172551902 -0500 +@@ -5,7 +5,7 @@ libnfs_a_SOURCES = exports.c rmtab.c xio + xlog.c xcommon.c wildmat.c nfsclient.c \ + nfsexport.c getfh.c nfsctl.c rpc_socket.c getport.c \ + svc_socket.c cacheio.c closeall.c nfs_mntent.c conffile.c \ +- svc_create.c ++ svc_create.c atomicio.c strlcpy.c strlcat.c + + MAINTAINERCLEANFILES = Makefile.in + +diff -up nfs-utils-1.2.3/support/nfs/strlcat.c.orig nfs-utils-1.2.3/support/nfs/strlcat.c +--- nfs-utils-1.2.3/support/nfs/strlcat.c.orig 2010-11-29 11:18:44.175551873 -0500 ++++ nfs-utils-1.2.3/support/nfs/strlcat.c 2010-11-29 11:18:44.175551873 -0500 +@@ -0,0 +1,76 @@ ++/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ ++ ++/* ++ * Copyright (c) 1998 Todd C. Miller ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if defined(LIBC_SCCS) && !defined(lint) ++static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"; ++#endif /* LIBC_SCCS and not lint */ ++ ++#include ++#include ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif /* HAVE_CONFIG_H */ ++ ++/* ++ * Appends src to string dst of size siz (unlike strncat, siz is the ++ * full size of dst, not space left). At most siz-1 characters ++ * will be copied. Always NUL terminates (unless siz <= strlen(dst)). ++ * Returns strlen(src) + MIN(siz, strlen(initial dst)). ++ * If retval >= siz, truncation occurred. ++ */ ++size_t ++strlcat(char *dst, ++ const char *src, ++ size_t siz) ++{ ++ register char *d = dst; ++ register const char *s = src; ++ register size_t n = siz; ++ size_t dlen; ++ ++ /* Find the end of dst and adjust bytes left but don't go past end */ ++ while (n-- != 0 && *d != '\0') ++ d++; ++ dlen = d - dst; ++ n = siz - dlen; ++ ++ if (n == 0) ++ return(dlen + strlen(s)); ++ while (*s != '\0') { ++ if (n != 1) { ++ *d++ = *s; ++ n--; ++ } ++ s++; ++ } ++ *d = '\0'; ++ ++ return(dlen + (s - src)); /* count does not include NUL */ ++} +diff -up nfs-utils-1.2.3/support/nfs/strlcpy.c.orig nfs-utils-1.2.3/support/nfs/strlcpy.c +--- nfs-utils-1.2.3/support/nfs/strlcpy.c.orig 2010-11-29 11:18:44.175551873 -0500 ++++ nfs-utils-1.2.3/support/nfs/strlcpy.c 2010-11-29 11:18:44.175551873 -0500 +@@ -0,0 +1,72 @@ ++/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ ++ ++/* ++ * Copyright (c) 1998 Todd C. Miller ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The name of the author may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ++ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ++ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ++ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ++ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ++ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ++ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#if defined(LIBC_SCCS) && !defined(lint) ++static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; ++#endif /* LIBC_SCCS and not lint */ ++ ++#include ++#include ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif /* HAVE_CONFIG_H */ ++ ++/* ++ * Copy src to string dst of size siz. At most siz-1 characters ++ * will be copied. Always NUL terminates (unless siz == 0). ++ * Returns strlen(src); if retval >= siz, truncation occurred. ++ */ ++size_t ++strlcpy(char *dst, ++ const char *src, ++ size_t siz) ++{ ++ register char *d = dst; ++ register const char *s = src; ++ register size_t n = siz; ++ ++ /* Copy as many bytes as will fit */ ++ if (n != 0 && --n != 0) { ++ do { ++ if ((*d++ = *s++) == 0) ++ break; ++ } while (--n != 0); ++ } ++ ++ /* Not enough room in dst, add NUL and traverse rest of src */ ++ if (n == 0) { ++ if (siz != 0) ++ *d = '\0'; /* NUL-terminate dst */ ++ while (*s++) ++ ; ++ } ++ ++ return(s - src - 1); /* count does not include NUL */ ++} +diff -up nfs-utils-1.2.3/support/nfs/svc_create.c.orig nfs-utils-1.2.3/support/nfs/svc_create.c +--- nfs-utils-1.2.3/support/nfs/svc_create.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/support/nfs/svc_create.c 2010-11-29 11:18:44.176551853 -0500 +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -41,11 +42,68 @@ + #include "tcpwrapper.h" + #endif + ++#include "sockaddr.h" + #include "rpcmisc.h" + #include "xlog.h" + + #ifdef HAVE_LIBTIRPC + ++#define SVC_CREATE_XPRT_CACHE_SIZE (8) ++static SVCXPRT *svc_create_xprt_cache[SVC_CREATE_XPRT_CACHE_SIZE] = { NULL, }; ++ ++/* ++ * Cache an SVC xprt, in case there are more programs or versions to ++ * register against it. ++ */ ++static void ++svc_create_cache_xprt(SVCXPRT *xprt) ++{ ++ unsigned int i; ++ ++ /* Check if we've already got this one... */ ++ for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) ++ if (svc_create_xprt_cache[i] == xprt) ++ return; ++ ++ /* No, we don't. Cache it. */ ++ for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) ++ if (svc_create_xprt_cache[i] == NULL) { ++ svc_create_xprt_cache[i] = xprt; ++ return; ++ } ++ ++ xlog(L_ERROR, "%s: Failed to cache an xprt", __func__); ++} ++ ++/* ++ * Find a previously cached SVC xprt structure with the given bind address ++ * and transport semantics. ++ * ++ * Returns pointer to a cached SVC xprt. ++ * ++ * If no matching SVC XPRT can be found, NULL is returned. ++ */ ++static SVCXPRT * ++svc_create_find_xprt(const struct sockaddr *bindaddr, const struct netconfig *nconf) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) { ++ SVCXPRT *xprt = svc_create_xprt_cache[i]; ++ struct sockaddr *sap; ++ ++ if (xprt == NULL) ++ continue; ++ if (strcmp(nconf->nc_netid, xprt->xp_netid) != 0) ++ continue; ++ sap = (struct sockaddr *)xprt->xp_ltaddr.buf; ++ if (!nfs_compare_sockaddr(bindaddr, sap)) ++ continue; ++ return xprt; ++ } ++ return NULL; ++} ++ + /* + * Set up an appropriate bind address, given @port and @nconf. + * +@@ -98,17 +156,113 @@ svc_create_bindaddr(struct netconfig *nc + return ai; + } + ++/* ++ * Create a listener socket on a specific bindaddr, and set ++ * special socket options to allow it to share the same port ++ * as other listeners. ++ * ++ * Returns an open, bound, and possibly listening network ++ * socket on success. ++ * ++ * Otherwise returns -1 if some error occurs. ++ */ ++static int ++svc_create_sock(const struct sockaddr *sap, socklen_t salen, ++ struct netconfig *nconf) ++{ ++ int fd, type, protocol; ++ int one = 1; ++ ++ switch(nconf->nc_semantics) { ++ case NC_TPI_CLTS: ++ type = SOCK_DGRAM; ++ break; ++ case NC_TPI_COTS_ORD: ++ type = SOCK_STREAM; ++ break; ++ default: ++ xlog(D_GENERAL, "%s: Unrecognized bind address semantics: %u", ++ __func__, nconf->nc_semantics); ++ return -1; ++ } ++ ++ if (strcmp(nconf->nc_proto, NC_UDP) == 0) ++ protocol = (int)IPPROTO_UDP; ++ else if (strcmp(nconf->nc_proto, NC_TCP) == 0) ++ protocol = (int)IPPROTO_TCP; ++ else { ++ xlog(D_GENERAL, "%s: Unrecognized bind address protocol: %s", ++ __func__, nconf->nc_proto); ++ return -1; ++ } ++ ++ fd = socket((int)sap->sa_family, type, protocol); ++ if (fd == -1) { ++ xlog(L_ERROR, "Could not make a socket: (%d) %m", ++ errno); ++ return -1; ++ } ++ ++#ifdef IPV6_SUPPORTED ++ if (sap->sa_family == AF_INET6) { ++ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, ++ &one, sizeof(one)) == -1) { ++ xlog(L_ERROR, "Failed to set IPV6_V6ONLY: (%d) %m", ++ errno); ++ (void)close(fd); ++ return -1; ++ } ++ } ++#endif /* IPV6_SUPPORTED */ ++ ++ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, ++ &one, sizeof(one)) == -1) { ++ xlog(L_ERROR, "Failed to set SO_REUSEADDR: (%d) %m", ++ errno); ++ (void)close(fd); ++ return -1; ++ } ++ ++ if (bind(fd, sap, salen) == -1) { ++ xlog(L_ERROR, "Could not bind socket: (%d) %m", ++ errno); ++ (void)close(fd); ++ return -1; ++ } ++ ++ if (nconf->nc_semantics == NC_TPI_COTS_ORD) ++ if (listen(fd, SOMAXCONN) == -1) { ++ xlog(L_ERROR, "Could not listen on socket: (%d) %m", ++ errno); ++ (void)close(fd); ++ return -1; ++ } ++ ++ return fd; ++} ++ ++/* ++ * The simple case is allowing the TI-RPC library to create a ++ * transport itself, given just the bind address and transport ++ * semantics. ++ * ++ * Our local xprt cache is ignored in this path, since the ++ * caller is not interested in sharing listeners or ports, and ++ * the library automatically avoids ports already in use. ++ * ++ * Returns the count of started listeners (one or zero). ++ */ + static unsigned int +-svc_create_nconf(const char *name, const rpcprog_t program, ++svc_create_nconf_rand_port(const char *name, const rpcprog_t program, + const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), +- const uint16_t port, struct netconfig *nconf) ++ struct netconfig *nconf) + { + struct t_bind bindaddr; + struct addrinfo *ai; + SVCXPRT *xprt; + +- ai = svc_create_bindaddr(nconf, port); ++ ai = svc_create_bindaddr(nconf, 0); + if (ai == NULL) + return 0; + +@@ -119,7 +273,7 @@ svc_create_nconf(const char *name, const + freeaddrinfo(ai); + if (xprt == NULL) { + xlog(D_GENERAL, "Failed to create listener xprt " +- "(%s, %u, %s)", name, version, nconf->nc_netid); ++ "(%s, %u, %s)", name, version, nconf->nc_netid); + return 0; + } + +@@ -133,6 +287,93 @@ svc_create_nconf(const char *name, const + return 1; + } + ++/* ++ * If a port is specified on the command line, that port value will be ++ * the same for all listeners created here. Create each listener ++ * socket in advance and set SO_REUSEADDR, rather than allowing the ++ * RPC library to create the listeners for us on a randomly chosen ++ * port via svc_tli_create(RPC_ANYFD). ++ * ++ * Some callers want to listen for more than one RPC version using the ++ * same port number. For example, mountd could want to listen for MNT ++ * version 1, 2, and 3 requests. This means mountd must use the same ++ * set of listener sockets for multiple RPC versions, since, on one ++ * system, you can't have two listener sockets with the exact same ++ * bind address (and port) and transport protocol. ++ * ++ * To accomplish this, this function caches xprts as they are created. ++ * This cache is checked to see if a previously created xprt can be ++ * used, before creating a new xprt for this [program, version]. If ++ * there is a cached xprt with the same bindaddr and transport ++ * semantics, we simply register the new version with that xprt, ++ * rather than creating a fresh xprt for it. ++ * ++ * The xprt cache implemented here is local to a process. Two ++ * separate RPC daemons can not share a set of listeners. ++ * ++ * Returns the count of started listeners (one or zero). ++ */ ++static unsigned int ++svc_create_nconf_fixed_port(const char *name, const rpcprog_t program, ++ const rpcvers_t version, ++ void (*dispatch)(struct svc_req *, SVCXPRT *), ++ const uint16_t port, struct netconfig *nconf) ++{ ++ struct addrinfo *ai; ++ SVCXPRT *xprt; ++ ++ ai = svc_create_bindaddr(nconf, port); ++ if (ai == NULL) ++ return 0; ++ ++ xprt = svc_create_find_xprt(ai->ai_addr, nconf); ++ if (xprt == NULL) { ++ int fd; ++ ++ fd = svc_create_sock(ai->ai_addr, ai->ai_addrlen, nconf); ++ if (fd == -1) ++ goto out_free; ++ ++ xprt = svc_tli_create(fd, nconf, NULL, 0, 0); ++ if (xprt == NULL) { ++ xlog(D_GENERAL, "Failed to create listener xprt " ++ "(%s, %u, %s)", name, version, nconf->nc_netid); ++ (void)close(fd); ++ goto out_free; ++ } ++ } ++ ++ if (!svc_reg(xprt, program, version, dispatch, nconf)) { ++ /* svc_reg(3) destroys @xprt in this case */ ++ xlog(D_GENERAL, "Failed to register (%s, %u, %s)", ++ name, version, nconf->nc_netid); ++ goto out_free; ++ } ++ ++ svc_create_cache_xprt(xprt); ++ ++ freeaddrinfo(ai); ++ return 1; ++ ++out_free: ++ freeaddrinfo(ai); ++ return 0; ++} ++ ++static unsigned int ++svc_create_nconf(const char *name, const rpcprog_t program, ++ const rpcvers_t version, ++ void (*dispatch)(struct svc_req *, SVCXPRT *), ++ const uint16_t port, struct netconfig *nconf) ++{ ++ if (port != 0) ++ return svc_create_nconf_fixed_port(name, program, ++ version, dispatch, port, nconf); ++ ++ return svc_create_nconf_rand_port(name, program, ++ version, dispatch, nconf); ++} ++ + /** + * nfs_svc_create - start up RPC svc listeners + * @name: C string containing name of new service +@@ -145,8 +386,7 @@ svc_create_nconf(const char *name, const + * the RPC dispatcher. Returns the number of started network transports. + */ + unsigned int +-nfs_svc_create(__attribute__((unused)) char *name, +- const rpcprog_t program, const rpcvers_t version, ++nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), + const uint16_t port) + { +diff -up nfs-utils-1.2.3/tests/nsm_client/nsm_client.c.orig nfs-utils-1.2.3/tests/nsm_client/nsm_client.c +--- nfs-utils-1.2.3/tests/nsm_client/nsm_client.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/tests/nsm_client/nsm_client.c 2010-11-29 11:18:44.177551833 -0500 +@@ -205,7 +205,7 @@ nsm_client_get_rpcclient(const char *nod + { + unsigned short port; + struct addrinfo *ai; +- struct addrinfo hints = { .ai_flags = AI_ADDRCONFIG }; ++ struct addrinfo hints = { }; + int err; + CLIENT *client = NULL; + +diff -up nfs-utils-1.2.3/utils/exportfs/exports.man.orig nfs-utils-1.2.3/utils/exportfs/exports.man +--- nfs-utils-1.2.3/utils/exportfs/exports.man.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/exportfs/exports.man 2010-11-29 11:18:48.351597145 -0500 +@@ -145,7 +145,9 @@ storage (see + .IR async + above). + +-In releases of nfs-utils up to and including 1.0.0, this option was the ++In releases of nfs-utils up to and including 1.0.0, the ++.I async ++option was the + default. In all releases after 1.0.0, + .I sync + is the default, and +@@ -375,20 +377,6 @@ If the client asks for alternative locat + will be given this list of alternatives. (Note that actual replication + of the filesystem must be handled elsewhere.) + +-.TP +-.IR refer= path@host[+host][:path@host[+host]] +-A client referencing the export point will be directed to choose from +-the given list an alternative location for the filesystem. +-(Note that the server must have a mountpoint here, though a different +-filesystem is not required; so, for example, +-.IR "mount --bind" " /path /path" +-is sufficient.) +-.TP +-.IR replicas= path@host[+host][:path@host[+host]] +-If the client asks for alternative locations for the export point, it +-will be given this list of alternatives. (Note that actual replication +-of the filesystem must be handled elsewhere.) +- + .SS User ID Mapping + .PP + .B nfsd +diff -up nfs-utils-1.2.3/utils/idmapd/idmapd.c.orig nfs-utils-1.2.3/utils/idmapd/idmapd.c +--- nfs-utils-1.2.3/utils/idmapd/idmapd.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/idmapd/idmapd.c 2010-11-29 11:18:48.353596932 -0500 +@@ -158,10 +158,6 @@ static int nfsdopenone(struct idmap_clie + static void nfsdreopen_one(struct idmap_client *); + static void nfsdreopen(void); + +-size_t strlcat(char *, const char *, size_t); +-size_t strlcpy(char *, const char *, size_t); +-ssize_t atomicio(ssize_t (*f) (int, void*, size_t), +- int, void *, size_t); + void mydaemon(int, int); + void release_parent(void); + +diff -up nfs-utils-1.2.3/utils/idmapd/Makefile.am.orig nfs-utils-1.2.3/utils/idmapd/Makefile.am +--- nfs-utils-1.2.3/utils/idmapd/Makefile.am.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/idmapd/Makefile.am 2010-11-29 11:18:48.352597045 -0500 +@@ -11,12 +11,8 @@ EXTRA_DIST = \ + idmapd.conf + + idmapd_SOURCES = \ +- atomicio.c \ + idmapd.c \ +- strlcat.c \ +- strlcpy.c \ + \ +- cfg.h \ + nfs_idmap.h \ + queue.h + +diff -up nfs-utils-1.2.3/utils/Makefile.am.orig nfs-utils-1.2.3/utils/Makefile.am +--- nfs-utils-1.2.3/utils/Makefile.am.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/Makefile.am 2010-11-29 11:18:48.351597145 -0500 +@@ -4,6 +4,9 @@ OPTDIRS = + + if CONFIG_NFSV4 + OPTDIRS += idmapd ++if CONFIG_NFSIDMAP ++OPTDIRS += nfsidmap ++endif + endif + + if CONFIG_GSS +diff -up nfs-utils-1.2.3/utils/mountd/mountd.c.orig nfs-utils-1.2.3/utils/mountd/mountd.c +--- nfs-utils-1.2.3/utils/mountd/mountd.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mountd/mountd.c 2010-11-29 11:18:48.362595959 -0500 +@@ -99,12 +99,9 @@ static int version_any(void) + static void + unregister_services (void) + { +- if (version2()) { +- nfs_svc_unregister(MOUNTPROG, MOUNTVERS); +- nfs_svc_unregister(MOUNTPROG, MOUNTVERS_POSIX); +- } +- if (version3()) +- nfs_svc_unregister(MOUNTPROG, MOUNTVERS_NFSV3); ++ nfs_svc_unregister(MOUNTPROG, MOUNTVERS); ++ nfs_svc_unregister(MOUNTPROG, MOUNTVERS_POSIX); ++ nfs_svc_unregister(MOUNTPROG, MOUNTVERS_NFSV3); + } + + static void +@@ -840,6 +837,7 @@ main(int argc, char **argv) + if (new_cache) + cache_open(); + ++ unregister_services(); + if (version2()) { + listeners += nfs_svc_create("mountd", MOUNTPROG, + MOUNTVERS, mount_dispatch, port); +diff -up nfs-utils-1.2.3/utils/mountd/mountd.man.orig nfs-utils-1.2.3/utils/mountd/mountd.man +--- nfs-utils-1.2.3/utils/mountd/mountd.man.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mountd/mountd.man 2010-11-29 11:18:48.362595959 -0500 +@@ -106,11 +106,11 @@ This option can be used to request that + .B rpc.mountd + do not offer certain versions of NFS. The current version of + .B rpc.mountd +-can support both NFS version 2 and the newer version 3. If the +-NFS kernel module was compiled without support for NFSv3, ++can support both NFS version 2, 3 and 4. If the ++either one of these version should not be offered, + .B rpc.mountd + must be invoked with the option +-.B "\-\-no-nfs-version 3" . ++.B "\-\-no-nfs-version " . + .TP + .B \-n " or " \-\-no-tcp + Don't advertise TCP for mount. +diff -up nfs-utils-1.2.3/utils/mount/fstab.c.orig nfs-utils-1.2.3/utils/mount/fstab.c +--- nfs-utils-1.2.3/utils/mount/fstab.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/fstab.c 2010-11-29 11:18:48.354596817 -0500 +@@ -364,19 +364,22 @@ lock_mtab (void) { + /* Repeat until it was us who made the link */ + while (!we_created_lockfile) { + struct flock flock; +- int errsv, j; ++ int j; + + j = link(linktargetfile, MOUNTED_LOCK); +- errsv = errno; + +- if (j == 0) +- we_created_lockfile = 1; ++ { ++ int errsv = errno; + +- if (j < 0 && errsv != EEXIST) { +- (void) unlink(linktargetfile); +- die (EX_FILEIO, _("can't link lock file %s: %s " +- "(use -n flag to override)"), +- MOUNTED_LOCK, strerror (errsv)); ++ if (j == 0) ++ we_created_lockfile = 1; ++ ++ if (j < 0 && errsv != EEXIST) { ++ (void) unlink(linktargetfile); ++ die (EX_FILEIO, _("can't link lock file %s: %s " ++ "(use -n flag to override)"), ++ MOUNTED_LOCK, strerror (errsv)); ++ } + } + + lockfile_fd = open (MOUNTED_LOCK, O_WRONLY); +@@ -414,7 +417,7 @@ lock_mtab (void) { + } + (void) unlink(linktargetfile); + } else { +- static int tries = 0; ++ static int retries = 0; + + /* Someone else made the link. Wait. */ + alarm(LOCK_TIMEOUT); +@@ -428,10 +431,10 @@ lock_mtab (void) { + alarm(0); + /* Limit the number of iterations - maybe there + still is some old /etc/mtab~ */ +- ++tries; +- if (tries % 200 == 0) ++ ++retries; ++ if (retries % 200 == 0) + usleep(30); +- if (tries > 100000) { ++ if (retries > 100000) { + (void) unlink(linktargetfile); + close(lockfile_fd); + die (EX_FILEIO, _("Cannot create link %s\n" +diff -up nfs-utils-1.2.3/utils/mount/mount_config.h.orig nfs-utils-1.2.3/utils/mount/mount_config.h +--- nfs-utils-1.2.3/utils/mount/mount_config.h.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/mount_config.h 2010-11-29 11:18:48.355596703 -0500 +@@ -1,7 +1,7 @@ +-#ifndef _LINUX_MOUNT__CONFIG_H +-#define _LINUX_MOUNT_CONFIG__H ++#ifndef _LINUX_MOUNT_CONFIG_H ++#define _LINUX_MOUNT_CONFIG_H + /* +- * mount_config.h -- mount configuration file routines ++ * mount_config.h -- mount configuration file routines + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify +@@ -16,15 +16,13 @@ + * + */ + +-inline void mount_config_init(char *); +- + #ifdef MOUNT_CONFIG + #include "conffile.h" + #include "xlog.h" + + extern char *conf_get_mntopts(char *, char *, char *); + +-inline void mount_config_init(char *program) ++static inline void mount_config_init(char *program) + { + xlog_open(program); + /* +@@ -32,19 +30,22 @@ inline void mount_config_init(char *prog + */ + conf_init(); + } +-inline char *mount_config_opts(char *spec, ++ ++static inline char *mount_config_opts(char *spec, + char *mount_point, char *mount_opts) + { + return conf_get_mntopts(spec, mount_point, mount_opts); + } ++ + #else /* MOUNT_CONFIG */ + +-inline void mount_config_init(char *program) { } ++static inline void mount_config_init(char *program) { } + +-inline char *mount_config_opts(char *spec, ++static inline char *mount_config_opts(char *spec, + char *mount_point, char *mount_opts) + { + return mount_opts; + } + #endif /* MOUNT_CONFIG */ +-#endif ++ ++#endif /* _LINUX_MOUNT_CONFIG_H */ +diff -up nfs-utils-1.2.3/utils/mount/mount_constants.h.orig nfs-utils-1.2.3/utils/mount/mount_constants.h +--- nfs-utils-1.2.3/utils/mount/mount_constants.h.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/mount_constants.h 2010-11-29 11:18:48.355596703 -0500 +@@ -64,4 +64,8 @@ if we have a stack or plain mount - moun + #define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ + #endif + ++/* Generic options that are prevented from appearing ++ * in the options field in /etc/mtab. */ ++#define MS_NOMTAB (MS_REMOUNT) ++ + #endif /* _NFS_UTILS_MOUNT_CONSTANTS_H */ +diff -up nfs-utils-1.2.3/utils/mount/mount.c.orig nfs-utils-1.2.3/utils/mount/mount.c +--- nfs-utils-1.2.3/utils/mount/mount.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/mount.c 2010-11-29 11:18:48.354596817 -0500 +@@ -209,7 +209,7 @@ static char *fix_opts_string(int flags, + } + if (flags & MS_USERS) + new_opts = xstrconcat3(new_opts, ",users", ""); +- ++ + for (om = opt_map; om->opt != NULL; om++) { + if (om->skip) + continue; +@@ -224,6 +224,20 @@ static char *fix_opts_string(int flags, + return new_opts; + } + ++static void ++init_mntent(struct mntent *mnt, char *fsname, char *dir, char *type, ++ int flags, char *opts) ++{ ++ mnt->mnt_fsname = fsname; ++ mnt->mnt_dir = dir; ++ mnt->mnt_type = type; ++ mnt->mnt_opts = fix_opts_string(flags & ~MS_NOMTAB, opts); ++ ++ /* these are always zero for NFS */ ++ mnt->mnt_freq = 0; ++ mnt->mnt_passno = 0; ++} ++ + /* Create mtab with a root entry. */ + static void + create_mtab (void) { +@@ -245,11 +259,8 @@ create_mtab (void) { + if ((fstab = getfsfile ("/")) || (fstab = getfsfile ("root"))) { + char *extra_opts; + parse_opts (fstab->m.mnt_opts, &flags, &extra_opts); +- mnt.mnt_dir = "/"; +- mnt.mnt_fsname = xstrdup(fstab->m.mnt_fsname); +- mnt.mnt_type = fstab->m.mnt_type; +- mnt.mnt_opts = fix_opts_string (flags, extra_opts); +- mnt.mnt_freq = mnt.mnt_passno = 0; ++ init_mntent(&mnt, xstrdup(fstab->m.mnt_fsname), "/", ++ fstab->m.mnt_type, flags, extra_opts); + free(extra_opts); + + if (nfs_addmntent (mfp, &mnt) == 1) { +@@ -273,17 +284,12 @@ create_mtab (void) { + } + + static int add_mtab(char *spec, char *mount_point, char *fstype, +- int flags, char *opts, int freq, int pass) ++ int flags, char *opts) + { + struct mntent ment; + int result = EX_SUCCESS; + +- ment.mnt_fsname = spec; +- ment.mnt_dir = mount_point; +- ment.mnt_type = fstype; +- ment.mnt_opts = fix_opts_string(flags, opts); +- ment.mnt_freq = freq; +- ment.mnt_passno = pass; ++ init_mntent(&ment, spec, mount_point, fstype, flags, opts); + + if (!nomtab && mtab_does_not_exist()) { + if (verbose > 1) +@@ -321,7 +327,7 @@ static int add_mtab(char *spec, char *mo + return result; + } + +-void mount_usage(void) ++static void mount_usage(void) + { + printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"), + progname); +@@ -337,7 +343,7 @@ void mount_usage(void) + printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n")); + } + +-static void parse_opt(const char *opt, int *mask, char *extra_opts, int len) ++static void parse_opt(const char *opt, int *mask, char *extra_opts, size_t len) + { + const struct opt_map *om; + +@@ -371,7 +377,7 @@ static void parse_opts(const char *optio + if (options != NULL) { + char *opts = xstrdup(options); + char *opt, *p; +- int len = strlen(opts) + 1; /* include room for a null */ ++ size_t len = strlen(opts) + 1; /* include room for a null */ + int open_quote = 0; + + *extra_opts = xmalloc(len); +@@ -441,9 +447,7 @@ static int try_mount(char *spec, char *m + if (!fake) + print_one(spec, mount_point, fs_type, mount_opts); + +- ret = add_mtab(spec, mount_point, fs_type, flags, *extra_opts, +- 0, 0 /* these are always zero for NFS */ ); +- return ret; ++ return add_mtab(spec, mount_point, fs_type, flags, *extra_opts); + } + + int main(int argc, char *argv[]) +diff -up nfs-utils-1.2.3/utils/mount/network.c.orig nfs-utils-1.2.3/utils/mount/network.c +--- nfs-utils-1.2.3/utils/mount/network.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/network.c 2010-11-29 11:18:48.357596482 -0500 +@@ -59,6 +59,8 @@ + #define CONNECT_TIMEOUT (20) + #define MOUNT_TIMEOUT (30) + ++#define SAFE_SOCKADDR(x) (struct sockaddr *)(char *)(x) ++ + extern int nfs_mount_data_version; + extern char *progname; + extern int verbose; +@@ -208,9 +210,6 @@ int nfs_lookup(const char *hostname, con + { + struct addrinfo *gai_results; + struct addrinfo gai_hint = { +-#ifdef HAVE_DECL_AI_ADDRCONFIG +- .ai_flags = AI_ADDRCONFIG, +-#endif /* HAVE_DECL_AI_ADDRCONFIG */ + .ai_family = family, + }; + socklen_t len = *salen; +@@ -428,12 +427,12 @@ static int get_socket(struct sockaddr_in + if (bindresvport(so, &laddr) < 0) + goto err_bindresvport; + } else { +- cc = bind(so, (struct sockaddr *)&laddr, namelen); ++ cc = bind(so, SAFE_SOCKADDR(&laddr), namelen); + if (cc < 0) + goto err_bind; + } + if (type == SOCK_STREAM || (conn && type == SOCK_DGRAM)) { +- cc = connect_to(so, (struct sockaddr *)saddr, namelen, ++ cc = connect_to(so, SAFE_SOCKADDR(saddr), namelen, + timeout); + if (cc < 0) + goto err_connect; +@@ -756,11 +755,12 @@ int nfs_probe_bothports(const struct soc + */ + int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) + { +- return nfs_probe_bothports((struct sockaddr *)&mnt_server->saddr, +- sizeof(mnt_server->saddr), ++ struct sockaddr *mnt_addr = SAFE_SOCKADDR(&mnt_server->saddr); ++ struct sockaddr *nfs_addr = SAFE_SOCKADDR(&nfs_server->saddr); ++ ++ return nfs_probe_bothports(mnt_addr, sizeof(mnt_server->saddr), + &mnt_server->pmap, +- (struct sockaddr *)&nfs_server->saddr, +- sizeof(nfs_server->saddr), ++ nfs_addr, sizeof(nfs_server->saddr), + &nfs_server->pmap); + } + +@@ -772,7 +772,7 @@ static int nfs_probe_statd(void) + }; + rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); + +- return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr), ++ return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr), + program, (rpcvers_t)1, IPPROTO_UDP); + } + +@@ -901,7 +901,7 @@ int nfs_advise_umount(const struct socka + */ + int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp) + { +- struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr; ++ struct sockaddr *sap = SAFE_SOCKADDR(&mnt_server->saddr); + socklen_t salen = sizeof(mnt_server->saddr); + struct pmap *pmap = &mnt_server->pmap; + CLIENT *clnt; +@@ -1011,11 +1011,11 @@ int clnt_ping(struct sockaddr_in *saddr, + struct sockaddr_in *caddr) + { + CLIENT *clnt = NULL; +- int sock, stat; ++ int sock, status; + static char clnt_res; + struct sockaddr dissolve; + +- rpc_createerr.cf_stat = stat = 0; ++ rpc_createerr.cf_stat = status = 0; + sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE); + if (sock == RPC_ANYSOCK) { + if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) { +@@ -1058,18 +1058,18 @@ int clnt_ping(struct sockaddr_in *saddr, + return 0; + } + memset(&clnt_res, 0, sizeof(clnt_res)); +- stat = clnt_call(clnt, NULLPROC, ++ status = clnt_call(clnt, NULLPROC, + (xdrproc_t)xdr_void, (caddr_t)NULL, + (xdrproc_t)xdr_void, (caddr_t)&clnt_res, + TIMEOUT); +- if (stat) { ++ if (status) { + clnt_geterr(clnt, &rpc_createerr.cf_error); +- rpc_createerr.cf_stat = stat; ++ rpc_createerr.cf_stat = status; + } + clnt_destroy(clnt); + close(sock); + +- if (stat == RPC_SUCCESS) ++ if (status == RPC_SUCCESS) + return 1; + else + return 0; +@@ -1103,13 +1103,13 @@ static int nfs_ca_sockname(const struct + + switch (sap->sa_family) { + case AF_INET: +- if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { ++ if (bind(sock, SAFE_SOCKADDR(&sin), sizeof(sin)) < 0) { + close(sock); + return 0; + } + break; + case AF_INET6: +- if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) { ++ if (bind(sock, SAFE_SOCKADDR(&sin6), sizeof(sin6)) < 0) { + close(sock); + return 0; + } +@@ -1518,7 +1518,11 @@ nfs_mount_protocol(struct mount_options + * set @protocol to zero. The pmap protocol value will + * be filled in later by an rpcbind query in this case. + */ +- return nfs_nfs_protocol(options, protocol); ++ if (!nfs_nfs_protocol(options, protocol)) ++ return 0; ++ if (*protocol == NFSPROTO_RDMA) ++ *protocol = IPPROTO_TCP; ++ return 1; + } + + /* +diff -up nfs-utils-1.2.3/utils/mount/nfs.man.orig nfs-utils-1.2.3/utils/mount/nfs.man +--- nfs-utils-1.2.3/utils/mount/nfs.man.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/nfs.man 2010-11-29 11:18:48.358596373 -0500 +@@ -69,10 +69,9 @@ for details on specifying raw IPv6 addre + .P + The + .I fstype +-field contains "nfs", for whatever version of the protocol. +-The +-.B nfs +-allow several mount options, which are described below. ++field contains "nfs". Use of the "nfs4" fstype in ++.I /etc/fstab ++is deprecated. + .SH "MOUNT OPTIONS" + Refer to + .BR mount (8) +@@ -464,9 +463,9 @@ by other clients, but can impact applica + .IP + The DATA AND METADATA COHERENCE section contains a + detailed discussion of these trade-offs. +-.SS "Options for versions 2 and 3 only" ++.SS "Options for NFS versions 2 and 3 only" + Use these options, along with the options in the above subsection, +-for NFSv2/v3 only. They will be ignored for newer versions. ++for NFS versions 2 and 3 only. + .TP 1.5i + .BI proto= netid + The transport protocol name and protocol family the NFS client uses +@@ -619,7 +618,7 @@ in such cases. + .BI nfsvers= n + The NFS protocol version number used to contact the server's NFS service. + 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 ++If this option is not specified, the client negotiates a suitable version with + the server, trying version 4 first, version 3 second, and version 2 last. + .TP 1.5i + .BI vers= n +@@ -717,9 +716,53 @@ 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 "Options for version 4 only" ++.TP 1.5i ++.BR local_lock= mechanism ++Specifies whether to use local locking for any or both of the flock and the ++POSIX locking mechanisms. ++.I mechanism ++can be one of ++.BR all , ++.BR flock , ++.BR posix , ++or ++.BR none . ++This option is supported in kernels 2.6.37 and later. ++.IP ++The Linux NFS client provides a way to make locks local. This means, the ++applications can lock files, but such locks provide exclusion only against ++other applications running on the same client. Remote applications are not ++affected by these locks. ++.IP ++If this option is not specified, or if ++.B none ++is specified, the client assumes that the locks are not local. ++.IP ++If ++.BR all ++is specified, the client assumes that both flock and POSIX locks are local. ++.IP ++If ++.BR flock ++is specified, the client assumes that only flock locks are local and uses ++NLM sideband protocol to lock files when POSIX locks are used. ++.IP ++If ++.BR posix ++is specified, the client assumes that POSIX locks are local and uses NLM ++sideband protocol to lock files when flock locks are used. ++.IP ++To support legacy flock behavior similar to that of NFS clients < 2.6.12, use ++'local_lock=flock'. This option is required when exporting NFS mounts via ++Samba as Samba maps Windows share mode locks as flock. Since NFS clients > ++2.6.12 implement flock by emulating POSIX locks, this will result in ++conflicting locks. ++.IP ++NOTE: When used together, the 'local_lock' mount option will be overridden ++by 'nolock'/'lock' mount option. ++.SS "Options for NFS version 4 only" + Use these options, along with the options in the first subsection above, +-for NFSv4 only. They will be ignored with older versions. ++for NFS version 4 and newer. + .TP 1.5i + .BI proto= netid + The transport protocol name and protocol family the NFS client uses +@@ -1480,32 +1523,54 @@ of Access Control Lists that are semanti + NFS version 4 ACLs are not fully compatible with POSIX ACLs; as such, + some translation between the two is required + in an environment that mixes POSIX ACLs and NFS version 4. +-.SH FILES +-.TP 1.5i +-.I /etc/fstab +-file system table +-.SH BUGS +-The generic +-.B remount +-option is not fully supported. +-Generic options, such as +-.BR rw " and " ro +-can be modified using the +-.B remount +-option, +-but NFS-specific options are not all supported. ++.SH "THE REMOUNT OPTION" ++Generic mount options such as ++.BR rw " and " sync ++can be modified on NFS mount points using the ++.BR remount ++option. ++See ++.BR mount (8) ++for more information on generic mount options. ++.P ++With few exceptions, NFS-specific options ++are not able to be modified during a remount. + The underlying transport or NFS version + cannot be changed by a remount, for example. ++.P + Performing a remount on an NFS file system mounted with the + .B noac + option may have unintended consequences. + The + .B noac +-option is a mixture of a generic option, ++option is a combination of the generic option + .BR sync , +-and an NFS-specific option ++and the NFS-specific option + .BR actimeo=0 . ++.SS "Unmounting after a remount" ++For mount points that use NFS versions 2 or 3, the NFS umount subcommand ++depends on knowing the original set of mount options used to perform the ++MNT operation. ++These options are stored on disk by the NFS mount subcommand, ++and can be erased by a remount. ++.P ++To ensure that the saved mount options are not erased during a remount, ++specify either the local mount directory, or the server hostname and ++export pathname, but not both, during a remount. For example, + .P ++.NF ++.TA 2.5i ++ mount -o remount,ro /mnt ++.FI ++.P ++merges the mount option ++.B ro ++with the mount options already saved on disk for the NFS server mounted at /mnt. ++.SH FILES ++.TP 1.5i ++.I /etc/fstab ++file system table ++.SH BUGS + Before 2.4.7, the Linux NFS client did not support NFS over TCP. + .P + Before 2.4.20, the Linux NFS client used a heuristic +diff -up nfs-utils-1.2.3/utils/mount/nfsumount.c.orig nfs-utils-1.2.3/utils/mount/nfsumount.c +--- nfs-utils-1.2.3/utils/mount/nfsumount.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/nfsumount.c 2010-11-29 11:18:48.359596267 -0500 +@@ -31,12 +31,16 @@ + #include "nls.h" + + #include "mount_constants.h" ++#include "nfs_mount.h" + #include "mount.h" + #include "error.h" + #include "network.h" + #include "parse_opt.h" + #include "parse_dev.h" + ++#define MOUNTSFILE "/proc/mounts" ++#define LINELEN (4096) ++ + #if !defined(MNT_FORCE) + /* dare not try to include -- lots of errors */ + #define MNT_FORCE 1 +@@ -109,7 +113,7 @@ static int del_mtab(const char *spec, co + res = try_remount(spec, node); + if (res) + goto writemtab; +- return 0; ++ return EX_SUCCESS; + } else + umnt_err = errno; + } +@@ -127,7 +131,7 @@ static int del_mtab(const char *spec, co + } + + if (res >= 0) +- return 0; ++ return EX_SUCCESS; + + if (umnt_err) + umount_error(umnt_err, node); +@@ -241,6 +245,91 @@ static int nfs_umount23(const char *devn + return result; + } + ++/* ++ * Detect NFSv4 mounts. ++ * ++ * Consult /proc/mounts to determine if the mount point ++ * is an NFSv4 mount. The kernel is authoritative about ++ * what type of mount this is. ++ * ++ * Returns 1 if "mc" is an NFSv4 mount, zero if not, and ++ * -1 if some error occurred. ++ */ ++static int nfs_umount_is_vers4(const struct mntentchn *mc) ++{ ++ char buffer[LINELEN], *next; ++ int retval; ++ FILE *f; ++ ++ if ((f = fopen(MOUNTSFILE, "r")) == NULL) { ++ fprintf(stderr, "%s: %s\n", ++ MOUNTSFILE, strerror(errno)); ++ return -1; ++ } ++ ++ retval = -1; ++ while (fgets(buffer, sizeof(buffer), f) != NULL) { ++ char *device, *mntdir, *type, *flags; ++ struct mount_options *options; ++ char *line = buffer; ++ ++ next = strchr(line, '\n'); ++ if (next != NULL) ++ *next = '\0'; ++ ++ device = strtok(line, " \t"); ++ if (device == NULL) ++ continue; ++ mntdir = strtok(NULL, " \t"); ++ if (mntdir == NULL) ++ continue; ++ if (strcmp(device, mc->m.mnt_fsname) != 0 && ++ strcmp(mntdir, mc->m.mnt_dir) != 0) ++ continue; ++ ++ type = strtok(NULL, " \t"); ++ if (type == NULL) ++ continue; ++ if (strcmp(type, "nfs4") == 0) ++ goto out_nfs4; ++ ++ flags = strtok(NULL, " \t"); ++ if (flags == NULL) ++ continue; ++ options = po_split(flags); ++ if (options != NULL) { ++ unsigned long version; ++ int rc; ++ ++ rc = nfs_nfs_version(options, &version); ++ po_destroy(options); ++ if (rc && version == 4) ++ goto out_nfs4; ++ } ++ ++ goto out_nfs; ++ } ++ if (retval == -1) ++ fprintf(stderr, "%s was not found in %s\n", ++ mc->m.mnt_dir, MOUNTSFILE); ++ ++out: ++ fclose(f); ++ return retval; ++ ++out_nfs4: ++ if (verbose) ++ fprintf(stderr, "NFSv4 mount point detected\n"); ++ retval = 1; ++ goto out; ++ ++out_nfs: ++ if (verbose) ++ fprintf(stderr, "Legacy NFS mount point detected\n"); ++ retval = 0; ++ goto out; ++} ++ + static struct option umount_longopts[] = + { + { "force", 0, 0, 'f' }, +@@ -362,16 +451,25 @@ int nfsumount(int argc, char *argv[]) + } + } + +- ret = 0; ++ ret = EX_SUCCESS; + if (mc) { +- if (!lazy && strcmp(mc->m.mnt_type, "nfs4") != 0) +- /* We ignore the error from nfs_umount23. +- * If the actual umount succeeds (in del_mtab), +- * we don't want to signal an error, as that +- * could cause /sbin/mount to retry! +- */ +- nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts); +- ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir) ?: ret; ++ if (!lazy) { ++ switch (nfs_umount_is_vers4(mc)) { ++ case 0: ++ /* We ignore the error from nfs_umount23. ++ * If the actual umount succeeds (in del_mtab), ++ * we don't want to signal an error, as that ++ * could cause /sbin/mount to retry! ++ */ ++ nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts); ++ break; ++ case 1: ++ break; ++ default: ++ return EX_FAIL; ++ } ++ } ++ ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir); + } else if (*spec != '/') { + if (!lazy) + ret = nfs_umount23(spec, "tcp,v3"); +diff -up nfs-utils-1.2.3/utils/mount/parse_opt.c.orig nfs-utils-1.2.3/utils/mount/parse_opt.c +--- nfs-utils-1.2.3/utils/mount/parse_opt.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/parse_opt.c 2010-11-29 11:18:48.359596267 -0500 +@@ -508,7 +508,7 @@ po_found_t po_get_numeric(struct mount_o + int po_rightmost(struct mount_options *options, const char *keys[]) + { + struct mount_option *option; +- unsigned int i; ++ int i; + + if (options) { + for (option = options->tail; option; option = option->prev) { +diff -up nfs-utils-1.2.3/utils/mount/stropts.c.orig nfs-utils-1.2.3/utils/mount/stropts.c +--- nfs-utils-1.2.3/utils/mount/stropts.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/stropts.c 2010-11-29 11:18:48.360596162 -0500 +@@ -49,10 +49,6 @@ + #include "parse_dev.h" + #include "conffile.h" + +-#ifndef HAVE_DECL_AI_ADDRCONFIG +-#define AI_ADDRCONFIG 0 +-#endif +- + #ifndef NFS_PROGRAM + #define NFS_PROGRAM (100003) + #endif +@@ -123,10 +119,12 @@ inline void nfs_default_version(struct n + * Returns a time_t timeout timestamp, in seconds. + */ + static time_t nfs_parse_retry_option(struct mount_options *options, +- unsigned int timeout_minutes) ++ const time_t default_timeout) + { ++ time_t timeout_minutes; + long tmp; + ++ timeout_minutes = default_timeout; + switch (po_get_numeric(options, "retry", &tmp)) { + case PO_NOT_FOUND: + break; +@@ -135,6 +133,7 @@ static time_t nfs_parse_retry_option(str + timeout_minutes = tmp; + break; + } ++ /*FALLTHROUGH*/ + case PO_BAD_VALUE: + if (verbose) + nfs_error(_("%s: invalid retry timeout was specified; " +@@ -142,7 +141,7 @@ static time_t nfs_parse_retry_option(str + break; + } + +- return time(NULL) + (time_t)(timeout_minutes * 60); ++ return time(NULL) + (timeout_minutes * 60); + } + + /* +@@ -343,7 +342,6 @@ static int nfs_validate_options(struct n + { + struct addrinfo hint = { + .ai_protocol = (int)IPPROTO_UDP, +- .ai_flags = AI_ADDRCONFIG, + }; + sa_family_t family; + int error; +@@ -570,16 +568,18 @@ static int nfs_sys_mount(struct nfsmount + char *options = NULL; + int result; + ++ if (mi->fake) ++ return 1; ++ + if (po_join(opts, &options) == PO_FAILED) { + errno = EIO; + return 0; + } + +- if (mi->fake) +- return 1; +- + result = mount(mi->spec, mi->node, mi->type, + mi->flags & ~(MS_USER|MS_USERS), options); ++ free(options); ++ + if (verbose && result) { + int save = errno; + nfs_error(_("%s: mount(2): %s"), progname, strerror(save)); +@@ -650,7 +650,7 @@ out_fail: + static int nfs_try_mount_v3v2(struct nfsmount_info *mi) + { + struct addrinfo *ai; +- int ret; ++ int ret = 0; + + for (ai = mi->address; ai != NULL; ai = ai->ai_next) { + ret = nfs_do_mount_v3v2(mi, ai->ai_addr, ai->ai_addrlen); +@@ -737,7 +737,7 @@ out_fail: + static int nfs_try_mount_v4(struct nfsmount_info *mi) + { + struct addrinfo *ai; +- int ret; ++ int ret = 0; + + for (ai = mi->address; ai != NULL; ai = ai->ai_next) { + ret = nfs_do_mount_v4(mi, ai->ai_addr, ai->ai_addrlen); +diff -up nfs-utils-1.2.3/utils/mount/version.h.orig nfs-utils-1.2.3/utils/mount/version.h +--- nfs-utils-1.2.3/utils/mount/version.h.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/mount/version.h 2010-11-29 11:18:48.361596059 -0500 +@@ -42,9 +42,9 @@ static inline unsigned int linux_version + if (uname(&my_utsname)) + return 0; + +- p = atoi(strtok(my_utsname.release, ".")); +- q = atoi(strtok(NULL, ".")); +- r = atoi(strtok(NULL, ".")); ++ p = (unsigned int)atoi(strtok(my_utsname.release, ".")); ++ q = (unsigned int)atoi(strtok(NULL, ".")); ++ r = (unsigned int)atoi(strtok(NULL, ".")); + return MAKE_VERSION(p, q, r); + } + +diff -up nfs-utils-1.2.3/utils/nfsidmap/Makefile.am.orig nfs-utils-1.2.3/utils/nfsidmap/Makefile.am +--- nfs-utils-1.2.3/utils/nfsidmap/Makefile.am.orig 2010-11-29 11:18:48.363595859 -0500 ++++ nfs-utils-1.2.3/utils/nfsidmap/Makefile.am 2010-11-29 11:18:48.363595859 -0500 +@@ -0,0 +1,9 @@ ++## Process this file with automake to produce Makefile.in ++ ++man8_MANS = nfsidmap.man ++ ++sbin_PROGRAMS = nfsidmap ++nfsidmap_SOURCES = nfsidmap.c ++nfsidmap_LDADD = -lnfsidmap -lkeyutils ++ ++MAINTAINERCLEANFILES = Makefile.in +diff -up nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.c.orig nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.c +--- nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.c.orig 2010-11-29 11:18:48.363595859 -0500 ++++ nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.c 2010-11-29 11:18:48.363595859 -0500 +@@ -0,0 +1,118 @@ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* gcc nfsidmap.c -o nfsidmap -l nfsidmap -l keyutils */ ++ ++#define MAX_ID_LEN 11 ++#define IDMAP_NAMESZ 128 ++#define USER 1 ++#define GROUP 0 ++ ++ ++/* ++ * Find either a user or group id based on the name@domain string ++ */ ++int id_lookup(char *name_at_domain, key_serial_t key, int type) ++{ ++ char id[MAX_ID_LEN]; ++ uid_t uid = 0; ++ gid_t gid = 0; ++ int rc; ++ ++ if (type == USER) { ++ rc = nfs4_owner_to_uid(name_at_domain, &uid); ++ sprintf(id, "%u", uid); ++ } else { ++ rc = nfs4_group_owner_to_gid(name_at_domain, &gid); ++ sprintf(id, "%u", gid); ++ } ++ ++ if (rc == 0) ++ rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); ++ ++ return rc; ++} ++ ++/* ++ * Find the name@domain string from either a user or group id ++ */ ++int name_lookup(char *id, key_serial_t key, int type) ++{ ++ char name[IDMAP_NAMESZ]; ++ char domain[NFS4_MAX_DOMAIN_LEN]; ++ uid_t uid; ++ gid_t gid; ++ int rc; ++ ++ rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); ++ if (rc != 0) { ++ rc = -1; ++ goto out; ++ } ++ ++ if (type == USER) { ++ uid = atoi(id); ++ rc = nfs4_uid_to_name(uid, domain, name, IDMAP_NAMESZ); ++ } else { ++ gid = atoi(id); ++ rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ); ++ } ++ ++ if (rc == 0) ++ rc = keyctl_instantiate(key, &name, strlen(name), 0); ++ ++out: ++ return rc; ++} ++ ++int main(int argc, char **argv) ++{ ++ char *arg; ++ char *value; ++ char *type; ++ int rc = 1; ++ int timeout = 600; ++ key_serial_t key; ++ ++ if (argc < 3) ++ return 1; ++ ++ arg = malloc(sizeof(char) * strlen(argv[2]) + 1); ++ strcpy(arg, argv[2]); ++ type = strtok(arg, ":"); ++ value = strtok(NULL, ":"); ++ ++ if (argc == 4) { ++ timeout = atoi(argv[3]); ++ if (timeout < 0) ++ timeout = 0; ++ } ++ ++ key = strtol(argv[1], NULL, 10); ++ ++ if (strcmp(type, "uid") == 0) ++ rc = id_lookup(value, key, USER); ++ else if (strcmp(type, "gid") == 0) ++ rc = id_lookup(value, key, GROUP); ++ else if (strcmp(type, "user") == 0) ++ rc = name_lookup(value, key, USER); ++ else if (strcmp(type, "group") == 0) ++ rc = name_lookup(value, key, GROUP); ++ ++ /* Set timeout to 5 (600 seconds) minutes */ ++ if (rc == 0) ++ keyctl_set_timeout(key, timeout); ++ ++ free(arg); ++ return rc; ++} +diff -up nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.man.orig nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.man +--- nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.man.orig 2010-11-29 11:18:48.364595762 -0500 ++++ nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.man 2010-11-29 11:18:48.364595762 -0500 +@@ -0,0 +1,60 @@ ++.\" ++.\"@(#)nfsidmap(8) - The NFS idmapper upcall program ++.\" ++.\" Copyright (C) 2010 Bryan Schumaker ++.TH nfsidmap 5 "1 October 2010" ++.SH NAME ++nfsidmap \- The NFS idmapper upcall program ++.SH DESCRIPTION ++The file ++.I /usr/sbin/nfsidmap ++is used by the NFS idmapper to translate user and group ids into names, and to ++translate user and group names into ids. Idmapper uses request-key to perform ++the upcall and cache the result. ++.I /usr/sbin/nfsidmap ++should only be called by request-key, and will perform the translation and ++initialize a key with the resulting information. ++.PP ++NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this ++feature. ++.SH CONFIGURING ++The file ++.I /etc/request-key.conf ++will need to be modified so ++.I /sbin/request-key ++can properly direct the upcall. The following line should be added before a call ++to keyctl negate: ++.PP ++create nfs_idmap * * /usr/sbin/nfsidmap %k %d 600 ++.PP ++This will direct all nfs_idmap requests to the program ++.I /usr/sbin/nfsidmap ++The last parameter, 600, defines how many seconds into the future the key will ++expire. This is an optional parameter for ++.I /usr/sbin/nfsidmap ++and will default to 600 seconds when not specified. ++.PP ++The idmapper system uses four key descriptions: ++.PP ++ uid: Find the UID for the given user ++.br ++ gid: Find the GID for the given group ++.br ++ user: Find the user name for the given UID ++.br ++ group: Find the group name for the given GID ++.PP ++You can choose to handle any of these individually, rather than using the ++generic upcall program. If you would like to use your own program for a uid ++lookup then you would edit your request-key.conf so it looks similar to this: ++.PP ++create nfs_idmap uid:* * /some/other/program %k %d 600 ++.br ++create nfs_idmap * * /usr/sbin/nfsidmap %k %d 600 ++.PP ++Notice that the new line was added above the line for the generic program. ++request-key will find the first matching line and run the corresponding program. ++In this case, /some/other/program will handle all uid lookups, and ++/usr/sbin/nfsidmap will handle gid, user, and group lookups. ++.SH AUTHOR ++Bryan Schumaker, +diff -up nfs-utils-1.2.3/utils/nfsstat/nfsstat.c.orig nfs-utils-1.2.3/utils/nfsstat/nfsstat.c +--- nfs-utils-1.2.3/utils/nfsstat/nfsstat.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/nfsstat/nfsstat.c 2010-11-29 11:18:48.365595665 -0500 +@@ -46,7 +46,7 @@ static unsigned int cltproc3info[CLTPROC + static unsigned int srvproc4info[SRVPROC4_SZ+2], + srvproc4info_old[SRVPROC4_SZ+2]; /* NFSv4 call counts ([0] == 2) */ + static unsigned int cltproc4info[CLTPROC4_SZ+2], +- cltproc4info_old[CLTPROC4_SZ+2]; /* NFSv4 call counts ([0] == 48) */ ++ cltproc4info_old[CLTPROC4_SZ+2]; /* NFSv4 call counts ([0] == 49) */ + static unsigned int srvproc4opsinfo[SRVPROC4OPS_SZ+2], + srvproc4opsinfo_old[SRVPROC4OPS_SZ+2]; /* NFSv4 call counts ([0] == 59) */ + static unsigned int srvnetinfo[5], srvnetinfo_old[5]; /* 0 # of received packets +@@ -221,8 +221,8 @@ DECLARE_CLT(cltinfo); + DECLARE_CLT(cltinfo, _old); + + static void print_all_stats(int, int, int); +-static void print_server_stats(int, int); +-static void print_client_stats(int, int); ++static void print_server_stats(int); ++static void print_client_stats(int); + static void print_stats_list(int, int, int); + static void print_numbers(const char *, unsigned int *, + unsigned int); +@@ -239,7 +239,7 @@ static int mounts(const char *); + + static void get_stats(const char *, struct statinfo *, int *, int, + int); +-static int has_stats(const unsigned int *); ++static int has_stats(const unsigned int *, int); + static int has_rpcstats(const unsigned int *, int); + static void diff_stats(struct statinfo *, struct statinfo *, int); + static void unpause(int); +@@ -468,7 +468,7 @@ main(int argc, char **argv) + pause(); + } + +- if (opt_since || opt_sleep) { ++ if (opt_since || (opt_sleep && !sleep_time)) { + if (opt_srv) { + get_stats(NFSSRVSTAT, serverinfo_tmp, &opt_srv, opt_clt, 1); + diff_stats(serverinfo_tmp, serverinfo, 1); +@@ -516,16 +516,16 @@ main(int argc, char **argv) + static void + print_all_stats (int opt_srv, int opt_clt, int opt_prt) + { +- print_server_stats(opt_srv, opt_prt); +- print_client_stats(opt_clt, opt_prt); ++ if (opt_srv) ++ print_server_stats(opt_prt); ++ ++ if (opt_clt) ++ print_client_stats(opt_prt); + } + + static void +-print_server_stats(int opt_srv, int opt_prt) ++print_server_stats(int opt_prt) + { +- if (!opt_srv) +- return; +- + if (opt_prt & PRNT_NET) { + if (opt_sleep && !has_rpcstats(srvnetinfo, 4)) { + } else { +@@ -582,31 +582,29 @@ print_server_stats(int opt_srv, int opt_ + printf("\n"); + } + if (opt_prt & PRNT_CALLS) { ++ int has_v2_stats = has_stats(srvproc2info, SRVPROC2_SZ+2); ++ int has_v3_stats = has_stats(srvproc3info, SRVPROC3_SZ+2); ++ int has_v4_stats = has_stats(srvproc4info, SRVPROC4_SZ+2); ++ + if ((opt_prt & PRNT_V2) || +- ((opt_prt & PRNT_AUTO) && has_stats(srvproc2info))) { +- if (opt_sleep && !has_stats(srvproc2info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v2_stats)) { ++ if (!opt_sleep || has_v2_stats) { + print_callstats(LABEL_srvproc2, + nfsv2name, srvproc2info + 1, + sizeof(nfsv2name)/sizeof(char *)); + } + } + if ((opt_prt & PRNT_V3) || +- ((opt_prt & PRNT_AUTO) && has_stats(srvproc3info))) { +- if (opt_sleep && !has_stats(srvproc3info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v3_stats)) { ++ if (!opt_sleep || has_v3_stats) { + print_callstats(LABEL_srvproc3, + nfsv3name, srvproc3info + 1, + sizeof(nfsv3name)/sizeof(char *)); + } + } + if ((opt_prt & PRNT_V4) || +- ((opt_prt & PRNT_AUTO) && has_stats(srvproc4info))) { +- if (opt_sleep && !has_stats(srvproc4info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v4_stats)) { ++ if (!opt_sleep || has_v4_stats) { + print_callstats( LABEL_srvproc4, + nfssrvproc4name, srvproc4info + 1, + sizeof(nfssrvproc4name)/sizeof(char *)); +@@ -618,11 +616,8 @@ print_server_stats(int opt_srv, int opt_ + } + } + static void +-print_client_stats(int opt_clt, int opt_prt) ++print_client_stats(int opt_prt) + { +- if (!opt_clt) +- return; +- + if (opt_prt & PRNT_NET) { + if (opt_sleep && !has_rpcstats(cltnetinfo, 4)) { + ; +@@ -644,31 +639,28 @@ print_client_stats(int opt_clt, int opt_ + } + } + if (opt_prt & PRNT_CALLS) { ++ int has_v2_stats = has_stats(cltproc2info, CLTPROC2_SZ+2); ++ int has_v3_stats = has_stats(cltproc3info, CLTPROC3_SZ+2); ++ int has_v4_stats = has_stats(cltproc4info, CLTPROC4_SZ+2); + if ((opt_prt & PRNT_V2) || +- ((opt_prt & PRNT_AUTO) && has_stats(cltproc2info))) { +- if (opt_sleep && !has_stats(cltproc2info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v2_stats)) { ++ if (!opt_sleep || has_v2_stats) { + print_callstats(LABEL_cltproc2, + nfsv2name, cltproc2info + 1, + sizeof(nfsv2name)/sizeof(char *)); + } + } + if ((opt_prt & PRNT_V3) || +- ((opt_prt & PRNT_AUTO) && has_stats(cltproc3info))) { +- if (opt_sleep && !has_stats(cltproc3info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v3_stats)) { ++ if (!opt_sleep || has_v3_stats) { + print_callstats(LABEL_cltproc3, + nfsv3name, cltproc3info + 1, + sizeof(nfsv3name)/sizeof(char *)); + } + } + if ((opt_prt & PRNT_V4) || +- ((opt_prt & PRNT_AUTO) && has_stats(cltproc4info))) { +- if (opt_sleep && !has_stats(cltproc4info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v4_stats)) { ++ if (!opt_sleep || has_v4_stats) { + print_callstats(LABEL_cltproc4, + nfscltproc4name, cltproc4info + 1, + sizeof(nfscltproc4name)/sizeof(char *)); +@@ -681,34 +673,28 @@ static void + print_clnt_list(int opt_prt) + { + if (opt_prt & PRNT_CALLS) { ++ int has_v2_stats = has_stats(cltproc2info, CLTPROC2_SZ+2); ++ int has_v3_stats = has_stats(cltproc3info, CLTPROC3_SZ+2); ++ int has_v4_stats = has_stats(cltproc4info, CLTPROC4_SZ+2); + if ((opt_prt & PRNT_V2) || +- ((opt_prt & PRNT_AUTO) && has_stats(cltproc2info))) { +- if (opt_sleep && !has_stats(cltproc2info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v2_stats)) { ++ if (!opt_sleep || has_v2_stats) { + print_callstats_list("nfs v2 client", + nfsv2name, cltproc2info + 1, + sizeof(nfsv2name)/sizeof(char *)); + } + } + if ((opt_prt & PRNT_V3) || +- ((opt_prt & PRNT_AUTO) && has_stats(cltproc3info))) { +- if (opt_sleep && !has_stats(cltproc3info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v3_stats)) { ++ if (!opt_sleep || has_v3_stats) { + print_callstats_list("nfs v3 client", + nfsv3name, cltproc3info + 1, + sizeof(nfsv3name)/sizeof(char *)); + } + } + if ((opt_prt & PRNT_V4) || +- ((opt_prt & PRNT_AUTO) && has_stats(cltproc4info))) { +- if (opt_sleep && !has_stats(cltproc4info)) { +- ; +- } else { +- print_callstats_list("nfs v4 ops", +- nfssrvproc4opname, srvproc4opsinfo + 1, +- sizeof(nfssrvproc4opname)/sizeof(char *)); ++ ((opt_prt & PRNT_AUTO) && has_v4_stats)) { ++ if (!opt_sleep || has_v4_stats) { + print_callstats_list("nfs v4 client", + nfscltproc4name, cltproc4info + 1, + sizeof(nfscltproc4name)/sizeof(char *)); +@@ -720,32 +706,32 @@ static void + print_serv_list(int opt_prt) + { + if (opt_prt & PRNT_CALLS) { ++ int has_v2_stats = has_stats(srvproc2info, SRVPROC2_SZ+2); ++ int has_v3_stats = has_stats(srvproc3info, SRVPROC3_SZ+2); ++ int has_v4_stats = has_stats(srvproc4info, SRVPROC4_SZ+2); + if ((opt_prt & PRNT_V2) || +- ((opt_prt & PRNT_AUTO) && has_stats(srvproc2info))) { +- if (opt_sleep && !has_stats(srvproc2info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v2_stats)) { ++ if (!opt_sleep || has_v2_stats) { + print_callstats_list("nfs v2 server", + nfsv2name, srvproc2info + 1, + sizeof(nfsv2name)/sizeof(char *)); + } + } + if ((opt_prt & PRNT_V3) || +- ((opt_prt & PRNT_AUTO) && has_stats(srvproc3info))) { +- if (opt_sleep && !has_stats(srvproc3info)) { +- ; +- } else { ++ ((opt_prt & PRNT_AUTO) && has_v3_stats)) { ++ if (!opt_sleep || has_v3_stats) { + print_callstats_list("nfs v3 server", + nfsv3name, srvproc3info + 1, + sizeof(nfsv3name)/sizeof(char *)); + } + } + if ((opt_prt & PRNT_V4) || +- ((opt_prt & PRNT_AUTO) && has_stats(srvproc4opsinfo))) { +- if (opt_sleep && !has_stats(srvproc4info)) { +- ; +- } else { +- print_callstats_list("nfs v4 ops", ++ ((opt_prt & PRNT_AUTO) && has_v4_stats)) { ++ if (!opt_sleep || has_v4_stats) { ++ print_callstats_list("nfs v4 server", ++ nfssrvproc4name, srvproc4info + 1, ++ sizeof(nfssrvproc4name)/sizeof(char *)); ++ print_callstats_list("nfs v4 servop", + nfssrvproc4opname, srvproc4opsinfo + 1, + sizeof(nfssrvproc4opname)/sizeof(char *)); + } +@@ -1054,9 +1040,9 @@ out: + * there are stats if the sum's greater than the entry-count. + */ + static int +-has_stats(const unsigned int *info) ++has_stats(const unsigned int *info, int nr) + { +- return (info[0] && info[info[0] + 1] > info[0]); ++ return (info[0] && info[nr-1] > info[0]); + } + static int + has_rpcstats(const unsigned int *info, int size) +diff -up nfs-utils-1.2.3/utils/nfsstat/nfsstat.man.orig nfs-utils-1.2.3/utils/nfsstat/nfsstat.man +--- nfs-utils-1.2.3/utils/nfsstat/nfsstat.man.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/nfsstat/nfsstat.man 2010-11-29 11:18:48.366595571 -0500 +@@ -30,10 +30,12 @@ Print only NFS v2 statistics. The defaul + about the versions of \fBNFS\fR that have non-zero counts. + .TP + .B \-3 +-Print only NFS v3 statistics. ++Print only NFS v3 statistics. The default is to only print information ++about the versions of \fBNFS\fR that have non-zero counts. + .TP + .B \-4 +-Print only NFS v4 statistics. ++Print only NFS v4 statistics. The default is to only print information ++about the versions of \fBNFS\fR that have non-zero counts. + .TP + .B \-m, \-\-mounts + Print information about each of the mounted \fBNFS\fR file systems. +diff -up nfs-utils-1.2.3/utils/statd/hostname.c.orig nfs-utils-1.2.3/utils/statd/hostname.c +--- nfs-utils-1.2.3/utils/statd/hostname.c.orig 2010-09-28 08:24:16.000000000 -0400 ++++ nfs-utils-1.2.3/utils/statd/hostname.c 2010-11-29 11:18:48.366595571 -0500 +@@ -39,10 +39,6 @@ + #include "statd.h" + #include "xlog.h" + +-#ifndef HAVE_DECL_AI_ADDRCONFIG +-#define AI_ADDRCONFIG 0 +-#endif +- + /** + * statd_present_address - convert sockaddr to presentation address + * @sap: pointer to socket address to convert +diff -up nfs-utils-1.2.3/utils/statd/sm-notify.c.orig nfs-utils-1.2.3/utils/statd/sm-notify.c +--- nfs-utils-1.2.3/utils/statd/sm-notify.c.orig 2010-11-29 11:17:26.908868990 -0500 ++++ nfs-utils-1.2.3/utils/statd/sm-notify.c 2010-11-29 11:18:48.367595478 -0500 +@@ -37,10 +37,6 @@ + #include "nsm.h" + #include "nfsrpc.h" + +-#ifndef HAVE_DECL_AI_ADDRCONFIG +-#define AI_ADDRCONFIG 0 +-#endif +- + #define NSM_TIMEOUT 2 + #define NSM_MAX_TIMEOUT 120 /* don't make this too big */ + +@@ -81,7 +77,6 @@ smn_lookup(const char *name) + { + struct addrinfo *ai = NULL; + struct addrinfo hint = { +- .ai_flags = AI_ADDRCONFIG, + .ai_family = (nsm_family == AF_INET ? AF_INET: AF_UNSPEC), + .ai_protocol = (int)IPPROTO_UDP, + }; diff --git a/nfs-utils.spec b/nfs-utils.spec index b830f5b..5acadea 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.3 -Release: 2%{?dist} +Release: 3%{?dist} Epoch: 1 # group all 32bit related archs @@ -17,8 +17,7 @@ Source13: rpcgssd.init Source14: rpcsvcgssd.init Source15: nfs.sysconfig -Patch001: nfs-utils-1.2.4-rc1.patch -Patch002: nfs-utils-1.2.3-export-manpage.patch +Patch001: nfs-utils-1.2.4-rc3.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.2-statdpath.patch @@ -73,7 +72,6 @@ This package also contains the mount.nfs and umount.nfs program. %setup -q %patch001 -p1 -%patch002 -p1 %patch100 -p1 %patch101 -p1 @@ -254,6 +252,9 @@ fi %attr(4755,root,root) /sbin/umount.nfs4 %changelog +* Mon Nov 29 2010 Steve Dickson 1.2.3-3 +- Updated to latest upstream release: nfs-utils-1-2-4-rc3 + * Fri Oct 15 2010 Steve Dickson 1.2.3-2 - Initscripts do not conform to LSB specification (bz 621562) - sm-notify needs to call res_init() before each try (bz 625531)