From 9e655dd5c7827aba02cd58026b4315b090e3cbf0 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Wed, 6 Apr 2011 12:58:56 -0400 Subject: [PATCH] Updated to latest upstream release: nfs-utils-1-2-4-rc7 Enabled the libmount code. Signed-off-by: Steve Dickson --- nfs-utils-1.2.4-rc5.patch | 2436 ------------------- nfs-utils-1.2.4-rc7.patch | 4687 +++++++++++++++++++++++++++++++++++++ nfs-utils.spec | 17 +- 3 files changed, 4698 insertions(+), 2442 deletions(-) delete mode 100644 nfs-utils-1.2.4-rc5.patch create mode 100644 nfs-utils-1.2.4-rc7.patch diff --git a/nfs-utils-1.2.4-rc5.patch b/nfs-utils-1.2.4-rc5.patch deleted file mode 100644 index 4782bb7..0000000 --- a/nfs-utils-1.2.4-rc5.patch +++ /dev/null @@ -1,2436 +0,0 @@ -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 2011-01-14 13:27:17.497605500 -0500 -+++ nfs-utils-1.2.3/aclocal/keyutils.m4 2011-01-14 13:27:17.497605500 -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 2011-01-14 13:27:17.498605703 -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 2011-01-14 13:22:07.094642705 -0500 -+++ nfs-utils-1.2.3/configure.ac 2011-01-14 13:27:17.498605703 -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 2011-01-14 13:27:17.497605500 -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 2011-01-14 13:27:17.499605906 -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 2011-01-14 13:27:17.500606109 -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 2011-01-14 13:27:17.500606109 -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 2011-01-14 13:27:17.501606312 -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 2011-01-14 13:27:17.502606515 -0500 -+++ nfs-utils-1.2.3/support/nfs/atomicio.c 2011-01-14 13:27:17.502606515 -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 2011-01-14 13:27:17.502606516 -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 2011-01-14 13:22:07.097643314 -0500 -+++ nfs-utils-1.2.3/support/nfs/exports.c 2011-01-14 13:27:17.503606719 -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 2011-01-14 13:27:17.502606515 -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/rpcdispatch.c.orig nfs-utils-1.2.3/support/nfs/rpcdispatch.c ---- nfs-utils-1.2.3/support/nfs/rpcdispatch.c.orig 2010-09-28 08:24:16.000000000 -0400 -+++ nfs-utils-1.2.3/support/nfs/rpcdispatch.c 2011-01-14 13:27:17.503606719 -0500 -@@ -37,6 +37,11 @@ rpc_dispatch(struct svc_req *rqstp, SVCX - return; - } - -+ if (dtable->nproc <= rqstp->rq_proc) { -+ svcerr_noproc(transp); -+ return; -+ } -+ - dent = dtable->entries + rqstp->rq_proc; - - if (dent->func == NULL) { -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 2011-01-14 13:27:17.505607123 -0500 -+++ nfs-utils-1.2.3/support/nfs/strlcat.c 2011-01-14 13:27:17.505607123 -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 2011-01-14 13:27:17.505607123 -0500 -+++ nfs-utils-1.2.3/support/nfs/strlcpy.c 2011-01-14 13:27:17.506607326 -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 2011-01-14 13:27:17.506607326 -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/support/nsm/file.c.orig nfs-utils-1.2.3/support/nsm/file.c ---- nfs-utils-1.2.3/support/nsm/file.c.orig 2011-01-14 13:22:07.094642705 -0500 -+++ nfs-utils-1.2.3/support/nsm/file.c 2011-01-14 13:27:17.507607529 -0500 -@@ -127,7 +127,7 @@ exact_error_check(const ssize_t len, con - * containing an appropriate pathname, or NULL if an error - * occurs. Caller must free the returned result with free(3). - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - static char * - nsm_make_record_pathname(const char *directory, const char *hostname) - { -@@ -175,7 +175,7 @@ nsm_make_record_pathname(const char *dir - * containing an appropriate pathname, or NULL if an error - * occurs. Caller must free the returned result with free(3). - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - static char * - nsm_make_pathname(const char *directory) - { -@@ -205,7 +205,7 @@ nsm_make_pathname(const char *directory) - * containing an appropriate pathname, or NULL if an error - * occurs. Caller must free the returned result with free(3). - */ --__attribute_malloc__ -+__attribute__((__malloc__)) - static char * - nsm_make_temp_pathname(const char *pathname) - { -@@ -422,7 +422,7 @@ nsm_drop_privileges(const int pidfd) - */ - if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) { - xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m"); -- return 0; -+ return false; - } - - if (setgroups(0, NULL) == -1) { -@@ -569,9 +569,8 @@ nsm_retire_monitored_hosts(void) - - while ((de = readdir(dir)) != NULL) { - char *src, *dst; -+ struct stat stb; - -- if (de->d_type != (unsigned char)DT_REG) -- continue; - if (de->d_name[0] == '.') - continue; - -@@ -581,6 +580,20 @@ nsm_retire_monitored_hosts(void) - continue; - } - -+ /* NB: not all file systems fill in d_type correctly */ -+ if (lstat(src, &stb) == -1) { -+ xlog_warn("Bad monitor file %s, skipping: %m", -+ de->d_name); -+ free(src); -+ continue; -+ } -+ if (!S_ISREG(stb.st_mode)) { -+ xlog(D_GENERAL, "Skipping non-regular file %s", -+ de->d_name); -+ free(src); -+ continue; -+ } -+ - dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name); - if (dst == NULL) { - free(src); -@@ -635,7 +648,7 @@ nsm_priv_to_hex(const char *priv, char * - /* - * Returns the length in bytes of the created record. - */ --__attribute_noinline__ -+__attribute__((__noinline__)) - static size_t - nsm_create_monitor_record(char *buf, const size_t buflen, - const struct sockaddr *sap, const struct mon *m) -@@ -785,7 +798,7 @@ out: - return result; - } - --__attribute_noinline__ -+__attribute__((__noinline__)) - static _Bool - nsm_parse_line(char *line, struct sockaddr_in *sin, struct mon *m) - { -@@ -847,7 +860,7 @@ nsm_read_line(const char *hostname, cons - } - - /* -- * Given a filename, reads data from a file under NSM_MONITOR_DIR -+ * Given a filename, reads data from a file under "directory" - * and invokes @func so caller can populate their in-core - * database with this data. - */ -@@ -864,10 +877,15 @@ nsm_load_host(const char *directory, con - if (path == NULL) - goto out_err; - -- if (stat(path, &stb) == -1) { -+ if (lstat(path, &stb) == -1) { - xlog(L_ERROR, "Failed to stat %s: %m", path); - goto out_freepath; - } -+ if (!S_ISREG(stb.st_mode)) { -+ xlog(D_GENERAL, "Skipping non-regular file %s", -+ path); -+ goto out_freepath; -+ } - - f = fopen(path, "r"); - if (f == NULL) { -@@ -914,8 +932,6 @@ nsm_load_dir(const char *directory, nsm_ - } - - while ((de = readdir(dir)) != NULL) { -- if (de->d_type != (unsigned char)DT_REG) -- continue; - if (de->d_name[0] == '.') - continue; - -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 2011-01-14 13:27:17.508607732 -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 2011-01-14 13:27:17.509607935 -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/gssd/gss_util.c.orig nfs-utils-1.2.3/utils/gssd/gss_util.c ---- nfs-utils-1.2.3/utils/gssd/gss_util.c.orig 2010-09-28 08:24:16.000000000 -0400 -+++ nfs-utils-1.2.3/utils/gssd/gss_util.c 2011-01-14 13:27:17.509607936 -0500 -@@ -138,6 +138,83 @@ display_status_1(char *m, u_int32_t code - } - } - #endif -+static char * -+gss_display_error(OM_uint32 status) -+{ -+ char *error = NULL; -+ -+ switch(status) { -+ case GSS_S_COMPLETE: -+ error = "GSS_S_COMPLETE"; -+ break; -+ case GSS_S_CALL_INACCESSIBLE_READ: -+ error = "GSS_S_CALL_INACCESSIBLE_READ"; -+ break; -+ case GSS_S_CALL_INACCESSIBLE_WRITE: -+ error = "GSS_S_CALL_INACCESSIBLE_WRITE"; -+ break; -+ case GSS_S_CALL_BAD_STRUCTURE: -+ error = "GSS_S_CALL_BAD_STRUCTURE"; -+ break; -+ case GSS_S_BAD_MECH: -+ error = "GSS_S_BAD_MECH"; -+ break; -+ case GSS_S_BAD_NAME: -+ error = "GSS_S_BAD_NAME"; -+ break; -+ case GSS_S_BAD_NAMETYPE: -+ error = "GSS_S_BAD_NAMETYPE"; -+ break; -+ case GSS_S_BAD_BINDINGS: -+ error = "GSS_S_BAD_BINDINGS"; -+ break; -+ case GSS_S_BAD_STATUS: -+ error = "GSS_S_BAD_STATUS"; -+ break; -+ case GSS_S_BAD_SIG: -+ error = "GSS_S_BAD_SIG"; -+ break; -+ case GSS_S_NO_CRED: -+ error = "GSS_S_NO_CRED"; -+ break; -+ case GSS_S_NO_CONTEXT: -+ error = "GSS_S_NO_CONTEXT"; -+ break; -+ case GSS_S_DEFECTIVE_TOKEN: -+ error = "GSS_S_DEFECTIVE_TOKEN"; -+ break; -+ case GSS_S_DEFECTIVE_CREDENTIAL: -+ error = "GSS_S_DEFECTIVE_CREDENTIAL"; -+ break; -+ case GSS_S_CREDENTIALS_EXPIRED: -+ error = "GSS_S_CREDENTIALS_EXPIRED"; -+ break; -+ case GSS_S_CONTEXT_EXPIRED: -+ error = "GSS_S_CONTEXT_EXPIRED"; -+ break; -+ case GSS_S_FAILURE: -+ error = "GSS_S_FAILURE"; -+ break; -+ case GSS_S_BAD_QOP: -+ error = "GSS_S_BAD_QOP"; -+ break; -+ case GSS_S_UNAUTHORIZED: -+ error = "GSS_S_UNAUTHORIZED"; -+ break; -+ case GSS_S_UNAVAILABLE: -+ error = "GSS_S_UNAVAILABLE"; -+ break; -+ case GSS_S_DUPLICATE_ELEMENT: -+ error = "GSS_S_DUPLICATE_ELEMENT"; -+ break; -+ case GSS_S_NAME_NOT_MN: -+ error = "GSS_S_NAME_NOT_MN"; -+ break; -+ default: -+ error = "Not defined"; -+ } -+ return error; -+} - - static void - display_status_2(char *m, u_int32_t major, u_int32_t minor, const gss_OID mech) -@@ -175,8 +252,8 @@ display_status_2(char *m, u_int32_t majo - - if (major == GSS_S_CREDENTIALS_EXPIRED) - msg_verbosity = 1; -- printerr(msg_verbosity, "ERROR: GSS-API: error in %s(): %s - %s\n", -- m, maj, min); -+ printerr(msg_verbosity, "ERROR: GSS-API: error in %s(): %s (%s) - %s(%s)\n", -+ m, gss_display_error(major), maj, min); - - if (maj_gss_buf.length != 0) - (void) gss_release_buffer(&min_stat1, &maj_gss_buf); -diff -up nfs-utils-1.2.3/utils/gssd/svcgssd.c.orig nfs-utils-1.2.3/utils/gssd/svcgssd.c ---- nfs-utils-1.2.3/utils/gssd/svcgssd.c.orig 2010-09-28 08:24:16.000000000 -0400 -+++ nfs-utils-1.2.3/utils/gssd/svcgssd.c 2011-01-14 13:27:17.509607936 -0500 -@@ -267,6 +267,7 @@ main(int argc, char *argv[]) - if (!fg) - release_parent(); - -+ nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ - gssd_run(); - printerr(0, "gssd_run returned!\n"); - abort(); -diff -up nfs-utils-1.2.3/utils/gssd/svcgssd_proc.c.orig nfs-utils-1.2.3/utils/gssd/svcgssd_proc.c ---- nfs-utils-1.2.3/utils/gssd/svcgssd_proc.c.orig 2010-09-28 08:24:16.000000000 -0400 -+++ nfs-utils-1.2.3/utils/gssd/svcgssd_proc.c 2011-01-14 13:27:17.510608139 -0500 -@@ -241,7 +241,7 @@ get_ids(gss_name_t client_name, gss_OID - "file for name '%s'\n", sname); - goto out_free; - } -- nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ -+ - res = nfs4_gss_princ_to_ids(secname, sname, &uid, &gid); - if (res < 0) { - /* -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 2011-01-14 13:27:17.513608747 -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 2011-01-14 13:27:17.512608544 -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 2011-01-14 13:27:17.509607935 -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 2011-01-14 13:27:17.521610371 -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 2011-01-14 13:27:17.522610574 -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 2011-01-14 13:27:17.513608747 -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 2011-01-14 13:27:17.514608950 -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 2011-01-14 13:27:17.515609153 -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 2011-01-14 13:27:17.514608950 -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 2011-01-14 13:27:17.516609356 -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 2011-01-14 13:27:17.518609762 -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 2011-01-14 13:27:17.518609762 -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 2011-01-14 13:27:17.519609965 -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 2011-01-14 13:27:17.520610168 -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 2011-01-14 13:27:17.521610371 -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 2011-01-14 13:27:17.523610776 -0500 -+++ nfs-utils-1.2.3/utils/nfsidmap/Makefile.am 2011-01-14 13:27:17.523610776 -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 2011-01-14 13:27:17.523610776 -0500 -+++ nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.c 2011-01-14 13:27:17.523610776 -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 2011-01-14 13:27:17.523610777 -0500 -+++ nfs-utils-1.2.3/utils/nfsidmap/nfsidmap.man 2011-01-14 13:27:17.532612603 -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 2011-01-14 13:27:17.532612603 -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 2011-01-14 13:27:17.541614429 -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 2011-01-14 13:27:17.541614430 -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 2011-01-14 13:22:07.100643922 -0500 -+++ nfs-utils-1.2.3/utils/statd/sm-notify.c 2011-01-14 13:27:17.543614834 -0500 -@@ -37,8 +37,9 @@ - #include "nsm.h" - #include "nfsrpc.h" - --#ifndef HAVE_DECL_AI_ADDRCONFIG --#define AI_ADDRCONFIG 0 -+/* glibc before 2.3.4 */ -+#ifndef AI_NUMERICSERV -+#define AI_NUMERICSERV 0 - #endif - - #define NSM_TIMEOUT 2 -@@ -81,7 +82,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, - }; -@@ -257,6 +257,7 @@ smn_bind_address(const char *srcaddr, co - if (srcaddr == NULL) - hint.ai_flags |= AI_PASSIVE; - -+ /* Do not allow "node" and "service" parameters both to be NULL */ - if (srcport == NULL) - error = getaddrinfo(srcaddr, "", &hint, &ai); - else diff --git a/nfs-utils-1.2.4-rc7.patch b/nfs-utils-1.2.4-rc7.patch new file mode 100644 index 0000000..e691e25 --- /dev/null +++ b/nfs-utils-1.2.4-rc7.patch @@ -0,0 +1,4687 @@ +diff --git a/.gitignore b/.gitignore +index 4bff9e3..f5b5cf0 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -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 --git a/aclocal/keyutils.m4 b/aclocal/keyutils.m4 +new file mode 100644 +index 0000000..84bc112 +--- /dev/null ++++ b/aclocal/keyutils.m4 +@@ -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 --git a/aclocal/libnfsidmap.m4 b/aclocal/libnfsidmap.m4 +index cfcde2f..4faa923 100644 +--- a/aclocal/libnfsidmap.m4 ++++ b/aclocal/libnfsidmap.m4 +@@ -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 --git a/configure.ac b/configure.ac +index 3058be6..d8972e4 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -132,11 +132,20 @@ AC_ARG_ENABLE(mount, + enable_mount=$enableval, + enable_mount=yes) + AM_CONDITIONAL(CONFIG_MOUNT, [test "$enable_mount" = "yes"]) ++ ++if test "$enable_mount" = yes; then ++ AC_ARG_ENABLE(libmount-mount, ++ [AC_HELP_STRING([--enable-libmount-mount], ++ [Link mount.nfs with libmount (EXPERIMENTAL)])], ++ enable_libmount=yes, ++ enable_libmount=no) ++fi ++ + 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@:>@])], +@@ -247,6 +256,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 +@@ -279,6 +294,13 @@ AC_SUBST(LIBCRYPT) + AC_SUBST(LIBBSD) + AC_SUBST(LIBBLKID) + ++if test "$enable_libmount" != no; then ++ AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed])) ++ AC_CHECK_HEADER(libmount/libmount.h, , AC_MSG_ERROR([Cannot find libmount header file libmount/libmount.h])) ++fi ++AM_CONDITIONAL(CONFIG_LIBMOUNT, [test "$enable_libmount" = "yes"]) ++AC_SUBST(LIBMOUNT) ++ + if test "$enable_gss" = yes; then + dnl 'gss' requires getnameinfo - at least for gssd_proc.c + AC_CHECK_FUNC([getnameinfo], , [AC_MSG_ERROR([GSSAPI support requires 'getnameinfo' function])]) +@@ -435,6 +457,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 --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/exportfs.h b/support/include/exportfs.h +index 3cf1ee8..01e87dd 100644 +--- a/support/include/exportfs.h ++++ b/support/include/exportfs.h +@@ -100,6 +100,7 @@ typedef struct mexport { + } nfs_export; + + #define HASH_TABLE_SIZE 1021 ++#define DEFAULT_TTL (30 * 60) + + typedef struct _exp_hash_entry { + nfs_export * p_first; +diff --git a/support/include/nfslib.h b/support/include/nfslib.h +index 3db5bec..73f3c20 100644 +--- a/support/include/nfslib.h ++++ b/support/include/nfslib.h +@@ -25,6 +25,12 @@ + #ifndef _PATH_EXPORTS + #define _PATH_EXPORTS "/etc/exports" + #endif ++#ifndef _PATH_EXPORTS_D ++#define _PATH_EXPORTS_D "/etc/exports.d" ++#endif ++#ifndef _EXT_EXPORT ++#define _EXT_EXPORT ".exports" ++#endif + #ifndef _PATH_IDMAPDCONF + #define _PATH_IDMAPDCONF "/etc/idmapd.conf" + #endif +@@ -89,6 +95,7 @@ struct exportent { + char * e_fslocdata; + char * e_uuid; + struct sec_entry e_secinfo[SECFLAVOR_COUNT+1]; ++ unsigned int e_ttl; + }; + + struct rmtabent { +@@ -163,6 +170,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/include/rpcmisc.h b/support/include/rpcmisc.h +index c5847fa..0b06457 100644 +--- a/support/include/rpcmisc.h ++++ b/support/include/rpcmisc.h +@@ -31,7 +31,7 @@ struct rpc_dentry { + + struct rpc_dtable { + struct rpc_dentry *entries; +- int nproc; ++ rpcproc_t nproc; + }; + + #define dtable_ent(func, vers, arg_type, res_type) \ +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/conffile.c b/support/nfs/conffile.c +index 24640f4..fa0dc6b 100644 +--- a/support/nfs/conffile.c ++++ b/support/nfs/conffile.c +@@ -251,6 +251,7 @@ conf_parse_line(int trans, char *line, size_t sz) + } + /* Strip off any blanks before ']' */ + val = line; ++ j=0; + while (*val && !isblank(*val)) + val++, j++; + if (*val) +@@ -271,9 +272,9 @@ conf_parse_line(int trans, char *line, size_t sz) + 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 --git a/support/nfs/exports.c b/support/nfs/exports.c +index a93941c..6acb2b6 100644 +--- a/support/nfs/exports.c ++++ b/support/nfs/exports.c +@@ -107,6 +107,7 @@ static void init_exportent (struct exportent *ee, int fromkernel) + ee->e_nsquids = 0; + ee->e_nsqgids = 0; + ee->e_uuid = NULL; ++ ee->e_ttl = DEFAULT_TTL; + } + + struct exportent * +@@ -332,6 +333,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/rpcdispatch.c b/support/nfs/rpcdispatch.c +index 984c646..f7c27c9 100644 +--- a/support/nfs/rpcdispatch.c ++++ b/support/nfs/rpcdispatch.c +@@ -32,7 +32,12 @@ rpc_dispatch(struct svc_req *rqstp, SVCXPRT *transp, + return; + } + dtable += (rqstp->rq_vers - 1); +- if (((int)rqstp->rq_proc) > dtable->nproc) { ++ if (rqstp->rq_proc > dtable->nproc) { ++ svcerr_noproc(transp); ++ return; ++ } ++ ++ if (dtable->nproc <= rqstp->rq_proc) { + svcerr_noproc(transp); + return; + } +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/support/nsm/file.c b/support/nsm/file.c +index f4baeb9..98b47bf 100644 +--- a/support/nsm/file.c ++++ b/support/nsm/file.c +@@ -126,7 +126,7 @@ exact_error_check(const ssize_t len, const size_t buflen) + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +-__attribute_malloc__ ++__attribute__((__malloc__)) + static char * + nsm_make_record_pathname(const char *directory, const char *hostname) + { +@@ -174,7 +174,7 @@ nsm_make_record_pathname(const char *directory, const char *hostname) + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +-__attribute_malloc__ ++__attribute__((__malloc__)) + static char * + nsm_make_pathname(const char *directory) + { +@@ -204,7 +204,7 @@ nsm_make_pathname(const char *directory) + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +-__attribute_malloc__ ++__attribute__((__malloc__)) + static char * + nsm_make_temp_pathname(const char *pathname) + { +@@ -421,7 +421,7 @@ nsm_drop_privileges(const int pidfd) + */ + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) { + xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m"); +- return 0; ++ return false; + } + + if (setgroups(0, NULL) == -1) { +@@ -568,9 +568,8 @@ nsm_retire_monitored_hosts(void) + + while ((de = readdir(dir)) != NULL) { + char *src, *dst; ++ struct stat stb; + +- if (de->d_type != (unsigned char)DT_REG) +- continue; + if (de->d_name[0] == '.') + continue; + +@@ -580,6 +579,20 @@ nsm_retire_monitored_hosts(void) + continue; + } + ++ /* NB: not all file systems fill in d_type correctly */ ++ if (lstat(src, &stb) == -1) { ++ xlog_warn("Bad monitor file %s, skipping: %m", ++ de->d_name); ++ free(src); ++ continue; ++ } ++ if (!S_ISREG(stb.st_mode)) { ++ xlog(D_GENERAL, "Skipping non-regular file %s", ++ de->d_name); ++ free(src); ++ continue; ++ } ++ + dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name); + if (dst == NULL) { + free(src); +@@ -634,7 +647,7 @@ nsm_priv_to_hex(const char *priv, char *buf, const size_t buflen) + /* + * Returns the length in bytes of the created record. + */ +-__attribute_noinline__ ++__attribute__((__noinline__)) + static size_t + nsm_create_monitor_record(char *buf, const size_t buflen, + const struct sockaddr *sap, const struct mon *m) +@@ -784,7 +797,7 @@ out: + return result; + } + +-__attribute_noinline__ ++__attribute__((__noinline__)) + static _Bool + nsm_parse_line(char *line, struct sockaddr_in *sin, struct mon *m) + { +@@ -846,7 +859,7 @@ nsm_read_line(const char *hostname, const time_t timestamp, char *line, + } + + /* +- * Given a filename, reads data from a file under NSM_MONITOR_DIR ++ * Given a filename, reads data from a file under "directory" + * and invokes @func so caller can populate their in-core + * database with this data. + */ +@@ -863,10 +876,15 @@ nsm_load_host(const char *directory, const char *filename, nsm_populate_t func) + if (path == NULL) + goto out_err; + +- if (stat(path, &stb) == -1) { ++ if (lstat(path, &stb) == -1) { + xlog(L_ERROR, "Failed to stat %s: %m", path); + goto out_freepath; + } ++ if (!S_ISREG(stb.st_mode)) { ++ xlog(D_GENERAL, "Skipping non-regular file %s", ++ path); ++ goto out_freepath; ++ } + + f = fopen(path, "r"); + if (f == NULL) { +@@ -913,8 +931,6 @@ nsm_load_dir(const char *directory, nsm_populate_t func) + } + + while ((de = readdir(dir)) != NULL) { +- if (de->d_type != (unsigned char)DT_REG) +- continue; + if (de->d_name[0] == '.') + continue; + +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/Makefile.am b/utils/Makefile.am +index 8665183..a0ea116 100644 +--- a/utils/Makefile.am ++++ b/utils/Makefile.am +@@ -4,6 +4,9 @@ OPTDIRS = + + if CONFIG_NFSV4 + OPTDIRS += idmapd ++if CONFIG_NFSIDMAP ++OPTDIRS += nfsidmap ++endif + endif + + if CONFIG_GSS +diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c +index b78957f..b107c7c 100644 +--- a/utils/exportfs/exportfs.c ++++ b/utils/exportfs/exportfs.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #include "sockaddr.h" + #include "misc.h" +@@ -41,6 +42,7 @@ static void error(nfs_export *exp, int err); + static void usage(const char *progname); + static void validate_export(nfs_export *exp); + static int matchhostname(const char *hostname1, const char *hostname2); ++static void export_d_read(const char *dname); + + int + main(int argc, char **argv) +@@ -127,8 +129,10 @@ main(int argc, char **argv) + return 0; + } + } +- if (f_export && ! f_ignore) ++ if (f_export && ! f_ignore) { + export_read(_PATH_EXPORTS); ++ export_d_read(_PATH_EXPORTS_D); ++ } + if (f_export) { + if (f_all) + export_all(f_verbose); +@@ -246,7 +250,7 @@ static void + exportfs(char *arg, char *options, int verbose) + { + struct exportent *eep; +- nfs_export *exp; ++ nfs_export *exp = NULL; + struct addrinfo *ai = NULL; + char *path; + char *hname = arg; +@@ -485,6 +489,59 @@ out: + return result; + } + ++/* Based on mnt_table_parse_dir() in ++ util-linux-ng/shlibs/mount/src/tab_parse.c */ ++static void ++export_d_read(const char *dname) ++{ ++ int n = 0, i; ++ struct dirent **namelist = NULL; ++ ++ ++ n = scandir(dname, &namelist, NULL, versionsort); ++ if (n < 0) ++ xlog(L_NOTICE, "scandir %s: %s\n", dname, strerror(errno)); ++ else if (n == 0) ++ return; ++ ++ for (i = 0; i < n; i++) { ++ struct dirent *d = namelist[i]; ++ size_t namesz; ++ char fname[PATH_MAX + 1]; ++ int fname_len; ++ ++ ++ if (d->d_type != DT_UNKNOWN ++ && d->d_type != DT_REG ++ && d->d_type != DT_LNK) ++ continue; ++ if (*d->d_name == '.') ++ continue; ++ ++#define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) ++ namesz = strlen(d->d_name); ++ if (!namesz ++ || namesz < _EXT_EXPORT_SIZ + 1 ++ || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), ++ _EXT_EXPORT)) ++ continue; ++ ++ fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name); ++ if (fname_len > PATH_MAX) { ++ xlog(L_WARNING, "Too long file name: %s in %s\n", d->d_name, dname); ++ continue; ++ } ++ ++ export_read(fname); ++ } ++ ++ for (i = 0; i < n; i++) ++ free(namelist[i]); ++ free(namelist); ++ ++ return; ++} ++ + static char + dumpopt(char c, char *fmt, ...) + { +diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man +index 089f75b..364f247 100644 +--- a/utils/exportfs/exportfs.man ++++ b/utils/exportfs/exportfs.man +@@ -37,11 +37,15 @@ when a client sends an NFS MOUNT request. + .PP + Normally the master export table is initialized with the contents of + .I /etc/exports ++and files under ++.I /etc/exports.d + by invoking + .BR "exportfs -a" . + However, a system administrator can choose to add or delete + exports without modifying + .I /etc/exports ++or files under ++.I /etc/exports.d + by using the + .B exportfs + command. +@@ -92,17 +96,24 @@ Specify a list of export options in the same manner as in + .B -i + Ignore the + .I /etc/exports +-file. Only default options and options given on the command line are used. ++file and files under ++.I /etc/exports.d ++directory. Only default options and options given on the command line are used. + .TP + .B -r + Reexport all directories, synchronizing + .I /var/lib/nfs/etab + with +-.IR /etc/exports . ++.IR /etc/exports ++and files under ++.IR /etc/exports.d . + This option removes entries in + .I /var/lib/nfs/etab + which have been deleted from +-.I /etc/exports, and removes any entries from the ++.I /etc/exports ++or files under ++.IR /etc/exports.d , ++and removes any entries from the + kernel export table which are no longer valid. + .TP + .B -u +@@ -130,6 +141,8 @@ when adding new entries to the export table. When using + .BR "exportfs -a" , + all exports listed in + .I /etc/exports ++and files under ++.I /etc/exports.d + are added to + .IR /var/lib/nfs/etab . + The kernel's export table is also updated as needed. +@@ -149,7 +162,9 @@ several sources. + The default export options are + .BR sync,ro,root_squash,wdelay . + These can be overridden by entries in +-.IR /etc/exports . ++.IR /etc/exports ++or files under ++.IR /etc/exports.d . + .PP + A system administrator may override options from these sources using the + .B -o +@@ -188,6 +203,8 @@ to display the export options for each export. + .SH EXAMPLES + The following adds all directories listed in + .I /etc/exports ++and files under ++.I /etc/exports.d + to + .I /var/lib/nfs/etab + and pushes the resulting export entries into the kernel: +@@ -215,7 +232,9 @@ directory: + .fi + .PP + To unexport all exports listed in +-.IR /etc/exports : ++.IR /etc/exports ++and files under ++.IR /etc/exports.d : + .PP + .nf + .B "# exportfs -au +@@ -238,6 +257,13 @@ if they themselves are no longer valid they will be removed. + .I /etc/exports + input file listing exports, export options, and access control lists + .TP 2.5i ++.I /etc/exports.d ++directory where extra input files are stored. ++.B Note: ++only files that end with ++.I .exports ++are used. ++.TP 2.5i + .I /var/lib/nfs/etab + master table of exports + .TP 2.5i +diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man +index c726dd9..85e25d4 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 +@@ -456,6 +444,24 @@ export entry for + .B /home/joe + in the example section below, which maps all requests to uid 150 (which + is supposedly that of user joe). ++.SS Extra Export Tables ++After reading ++.I /etc/exports ++.B exportfs ++reads files under ++.I /etc/exports.d. ++directory as extra export tables. ++.B exportfs ++regards only a file which name is ended with ++.I .exports ++and ++not started with ++.I . ++as an extra export file. A file which name ++is not met this condition is just ignored. ++The format for extra export tables is the same as ++.I /etc/exports ++. + .IP + .SH EXAMPLE + .PP +@@ -501,6 +507,7 @@ all three mounts with the `sync' option enabled. + '''entry. + .SH FILES + /etc/exports ++/etc/exports.d + .SH SEE ALSO + .BR exportfs (8), + .BR netgroup (5), +diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am +index 95a2bd0..d7888ad 100644 +--- a/utils/gssd/Makefile.am ++++ b/utils/gssd/Makefile.am +@@ -51,7 +51,9 @@ svcgssd_SOURCES = \ + svcgssd_main_loop.c \ + svcgssd_mech2file.c \ + svcgssd_proc.c \ ++ svcgssd_krb5.c \ + \ ++ svcgssd_krb5.h \ + svcgssd.h + + svcgssd_LDADD = \ +diff --git a/utils/gssd/gss_util.c b/utils/gssd/gss_util.c +index 8fe1e9b..ca27d61 100644 +--- a/utils/gssd/gss_util.c ++++ b/utils/gssd/gss_util.c +@@ -138,6 +138,83 @@ display_status_1(char *m, u_int32_t code, int type, const gss_OID mech) + } + } + #endif ++static char * ++gss_display_error(OM_uint32 status) ++{ ++ char *error = NULL; ++ ++ switch(status) { ++ case GSS_S_COMPLETE: ++ error = "GSS_S_COMPLETE"; ++ break; ++ case GSS_S_CALL_INACCESSIBLE_READ: ++ error = "GSS_S_CALL_INACCESSIBLE_READ"; ++ break; ++ case GSS_S_CALL_INACCESSIBLE_WRITE: ++ error = "GSS_S_CALL_INACCESSIBLE_WRITE"; ++ break; ++ case GSS_S_CALL_BAD_STRUCTURE: ++ error = "GSS_S_CALL_BAD_STRUCTURE"; ++ break; ++ case GSS_S_BAD_MECH: ++ error = "GSS_S_BAD_MECH"; ++ break; ++ case GSS_S_BAD_NAME: ++ error = "GSS_S_BAD_NAME"; ++ break; ++ case GSS_S_BAD_NAMETYPE: ++ error = "GSS_S_BAD_NAMETYPE"; ++ break; ++ case GSS_S_BAD_BINDINGS: ++ error = "GSS_S_BAD_BINDINGS"; ++ break; ++ case GSS_S_BAD_STATUS: ++ error = "GSS_S_BAD_STATUS"; ++ break; ++ case GSS_S_BAD_SIG: ++ error = "GSS_S_BAD_SIG"; ++ break; ++ case GSS_S_NO_CRED: ++ error = "GSS_S_NO_CRED"; ++ break; ++ case GSS_S_NO_CONTEXT: ++ error = "GSS_S_NO_CONTEXT"; ++ break; ++ case GSS_S_DEFECTIVE_TOKEN: ++ error = "GSS_S_DEFECTIVE_TOKEN"; ++ break; ++ case GSS_S_DEFECTIVE_CREDENTIAL: ++ error = "GSS_S_DEFECTIVE_CREDENTIAL"; ++ break; ++ case GSS_S_CREDENTIALS_EXPIRED: ++ error = "GSS_S_CREDENTIALS_EXPIRED"; ++ break; ++ case GSS_S_CONTEXT_EXPIRED: ++ error = "GSS_S_CONTEXT_EXPIRED"; ++ break; ++ case GSS_S_FAILURE: ++ error = "GSS_S_FAILURE"; ++ break; ++ case GSS_S_BAD_QOP: ++ error = "GSS_S_BAD_QOP"; ++ break; ++ case GSS_S_UNAUTHORIZED: ++ error = "GSS_S_UNAUTHORIZED"; ++ break; ++ case GSS_S_UNAVAILABLE: ++ error = "GSS_S_UNAVAILABLE"; ++ break; ++ case GSS_S_DUPLICATE_ELEMENT: ++ error = "GSS_S_DUPLICATE_ELEMENT"; ++ break; ++ case GSS_S_NAME_NOT_MN: ++ error = "GSS_S_NAME_NOT_MN"; ++ break; ++ default: ++ error = "Not defined"; ++ } ++ return error; ++} + + static void + display_status_2(char *m, u_int32_t major, u_int32_t minor, const gss_OID mech) +@@ -175,8 +252,8 @@ display_status_2(char *m, u_int32_t major, u_int32_t minor, const gss_OID mech) + + if (major == GSS_S_CREDENTIALS_EXPIRED) + msg_verbosity = 1; +- printerr(msg_verbosity, "ERROR: GSS-API: error in %s(): %s - %s\n", +- m, maj, min); ++ printerr(msg_verbosity, "ERROR: GSS-API: error in %s(): %s (%s) - %s(%s)\n", ++ m, gss_display_error(major), maj, min); + + if (maj_gss_buf.length != 0) + (void) gss_release_buffer(&min_stat1, &maj_gss_buf); +@@ -199,20 +276,25 @@ gssd_acquire_cred(char *server_name, const gss_OID oid) + u_int32_t ignore_maj_stat, ignore_min_stat; + gss_buffer_desc pbuf; + +- name.value = (void *)server_name; +- name.length = strlen(server_name); ++ /* If server_name is NULL, get cred for GSS_C_NO_NAME */ ++ if (server_name == NULL) { ++ target_name = GSS_C_NO_NAME; ++ } else { ++ name.value = (void *)server_name; ++ name.length = strlen(server_name); + +- maj_stat = gss_import_name(&min_stat, &name, +- oid, +- &target_name); ++ maj_stat = gss_import_name(&min_stat, &name, ++ oid, ++ &target_name); + +- if (maj_stat != GSS_S_COMPLETE) { +- pgsserr("gss_import_name", maj_stat, min_stat, g_mechOid); +- return (FALSE); ++ if (maj_stat != GSS_S_COMPLETE) { ++ pgsserr("gss_import_name", maj_stat, min_stat, g_mechOid); ++ return (FALSE); ++ } + } + +- maj_stat = gss_acquire_cred(&min_stat, target_name, 0, +- GSS_C_NULL_OID_SET, GSS_C_ACCEPT, ++ maj_stat = gss_acquire_cred(&min_stat, target_name, GSS_C_INDEFINITE, ++ GSS_C_NO_OID_SET, GSS_C_ACCEPT, + &gssd_creds, NULL, NULL); + + if (maj_stat != GSS_S_COMPLETE) { +diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man +index 0a23cd6..073379d 100644 +--- a/utils/gssd/gssd.man ++++ b/utils/gssd/gssd.man +@@ -53,6 +53,8 @@ To be more consistent with other implementations, we now look for + specific keytab entries. The search order for keytabs to be used + for "machine credentials" is now: + .br ++ $@ ++.br + root/@ + .br + nfs/@ +@@ -64,6 +66,9 @@ for "machine credentials" is now: + nfs/@ + .br + host/@ ++.IP ++If this search order does not use the correct key then provide a ++keytab file that contains only correct keys. + .TP + .B -p path + Tells +diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c +index c301d46..41328c9 100644 +--- a/utils/gssd/gssd_proc.c ++++ b/utils/gssd/gssd_proc.c +@@ -1245,7 +1245,7 @@ handle_gssd_upcall(struct clnt_info *clp) + goto out; + if (sscanf(p, "enctypes=%s", enctypes) != 1) { + printerr(0, "WARNING: handle_gssd_upcall: " +- "failed to parse target name " ++ "failed to parse encryption types " + "in upcall string '%s'\n", lbuf); + goto out; + } +diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c +index f071600..4b13fa1 100644 +--- a/utils/gssd/krb5_util.c ++++ b/utils/gssd/krb5_util.c +@@ -768,6 +768,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, + krb5_error_code code; + char **realmnames = NULL; + char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST]; ++ char myhostad[NI_MAXHOST+1]; + int i, j, retval; + char *default_realm = NULL; + char *realm; +@@ -789,6 +790,14 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, + printerr(1, "%s while getting local hostname\n", k5err); + goto out; + } ++ ++ /* Compute the active directory machine name HOST$ */ ++ strcpy(myhostad, myhostname); ++ for (i = 0; myhostad[i] != 0; ++i) ++ myhostad[i] = toupper(myhostad[i]); ++ myhostad[i] = '$'; ++ myhostad[i+1] = 0; ++ + retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); + if (retval) + goto out; +@@ -833,32 +842,47 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, + if (strcmp(realm, default_realm) == 0) + tried_default = 1; + for (j = 0; svcnames[j] != NULL; j++) { +- code = krb5_build_principal_ext(context, &princ, +- strlen(realm), +- realm, +- strlen(svcnames[j]), +- svcnames[j], +- strlen(myhostname), +- myhostname, +- NULL); ++ char spn[300]; ++ ++ /* ++ * The special svcname "$" means 'try the active ++ * directory machine account' ++ */ ++ if (strcmp(svcnames[j],"$") == 0) { ++ snprintf(spn, sizeof(spn), "%s@%s", myhostad, realm); ++ code = krb5_build_principal_ext(context, &princ, ++ strlen(realm), ++ realm, ++ strlen(myhostad), ++ myhostad, ++ NULL); ++ } else { ++ snprintf(spn, sizeof(spn), "%s/%s@%s", ++ svcnames[j], myhostname, realm); ++ code = krb5_build_principal_ext(context, &princ, ++ strlen(realm), ++ realm, ++ strlen(svcnames[j]), ++ svcnames[j], ++ strlen(myhostname), ++ myhostname, ++ NULL); ++ } ++ + if (code) { + k5err = gssd_k5_err_msg(context, code); +- printerr(1, "%s while building principal for " +- "'%s/%s@%s'\n", k5err, svcnames[j], +- myhostname, realm); ++ printerr(1, "%s while building principal for '%s'\n", ++ k5err, spn); + continue; + } + code = krb5_kt_get_entry(context, kt, princ, 0, 0, kte); + krb5_free_principal(context, princ); + if (code) { + k5err = gssd_k5_err_msg(context, code); +- printerr(3, "%s while getting keytab entry for " +- "'%s/%s@%s'\n", k5err, svcnames[j], +- myhostname, realm); ++ printerr(3, "%s while getting keytab entry for '%s'\n", ++ k5err, spn); + } else { +- printerr(3, "Success getting keytab entry for " +- "'%s/%s@%s'\n", +- svcnames[j], myhostname, realm); ++ printerr(3, "Success getting keytab entry for '%s'\n",spn); + retval = 0; + goto out; + } +@@ -870,6 +894,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, + */ + for (j = 0; svcnames[j] != NULL; j++) { + int found = 0; ++ if (strcmp(svcnames[j],"$") == 0) ++ continue; + code = gssd_search_krb5_keytab(context, kt, realm, + svcnames[j], &found, kte); + if (!code && found) { +@@ -1160,7 +1186,7 @@ gssd_refresh_krb5_machine_credential(char *hostname, + krb5_keytab kt = NULL;; + int retval = 0; + char *k5err = NULL; +- const char *svcnames[4] = { "root", "nfs", "host", NULL }; ++ const char *svcnames[5] = { "$", "root", "nfs", "host", NULL }; + + /* + * If a specific service name was specified, use it. +diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c +index 9b463f3..1afff9e 100644 +--- a/utils/gssd/svcgssd.c ++++ b/utils/gssd/svcgssd.c +@@ -262,11 +262,19 @@ main(int argc, char *argv[]) + "/etc/krb5.keytab?\n"); + exit(1); + } ++ } else { ++ status = gssd_acquire_cred(NULL, ++ (const gss_OID)GSS_C_NT_HOSTBASED_SERVICE); ++ if (status == FALSE) { ++ printerr(0, "unable to obtain nameless credentials\n"); ++ exit(1); ++ } + } + + if (!fg) + release_parent(); + ++ nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ + gssd_run(); + printerr(0, "gssd_run returned!\n"); + abort(); +diff --git a/utils/gssd/svcgssd_krb5.c b/utils/gssd/svcgssd_krb5.c +new file mode 100644 +index 0000000..fc67a6f +--- /dev/null ++++ b/utils/gssd/svcgssd_krb5.c +@@ -0,0 +1,200 @@ ++/* ++ * COPYRIGHT (c) 2011 ++ * The Regents of the University of Michigan ++ * ALL RIGHTS RESERVED ++ * ++ * Permission is granted to use, copy, create derivative works ++ * and redistribute this software and such derivative works ++ * for any purpose, so long as the name of The University of ++ * Michigan is not used in any advertising or publicity ++ * pertaining to the use of distribution of this software ++ * without specific, written prior authorization. If the ++ * above copyright notice or any other identification of the ++ * University of Michigan is included in any copy of any ++ * portion of this software, then the disclaimer below must ++ * also be included. ++ * ++ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION ++ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY ++ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF ++ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ++ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ++ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE ++ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR ++ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING ++ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN ++ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGES. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif /* HAVE_CONFIG_H */ ++ ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE ++#endif ++ ++#include ++#include ++#include ++#include ++ ++#include "gss_util.h" ++#include "gss_oids.h" ++#include "err_util.h" ++#include "svcgssd_krb5.h" ++ ++#define MYBUFLEN 1024 ++ ++char *supported_enctypes_filename = "/proc/fs/nfsd/supported_krb5_enctypes"; ++int parsed_num_enctypes = 0; ++krb5_enctype *parsed_enctypes = NULL; ++char *cached_enctypes = NULL; ++ ++/*==========================*/ ++/*=== Internal routines ===*/ ++/*==========================*/ ++ ++/* ++ * Parse the supported encryption type information ++ */ ++static int ++parse_enctypes(char *enctypes) ++{ ++ int n = 0; ++ char *curr, *comma; ++ int i; ++ ++ /* Don't parse the same string over and over... */ ++ if (cached_enctypes && strcmp(cached_enctypes, enctypes) == 0) ++ return 0; ++ ++ /* Free any existing cached_enctypes */ ++ free(cached_enctypes); ++ ++ if (parsed_enctypes != NULL) { ++ free(parsed_enctypes); ++ parsed_enctypes = NULL; ++ parsed_num_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 ((parsed_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) { ++ parsed_enctypes[i++] = atoi(curr); ++ comma = strchr(curr, ','); ++ if (comma == NULL) ++ break; ++ } ++ ++ parsed_num_enctypes = n; ++ if ((cached_enctypes = malloc(strlen(enctypes)+1))) ++ strcpy(cached_enctypes, enctypes); ++ ++ return 0; ++} ++ ++static void ++get_kernel_supported_enctypes(void) ++{ ++ FILE *s_e; ++ int ret; ++ char buffer[MYBUFLEN + 1]; ++ ++ memset(buffer, '\0', sizeof(buffer)); ++ ++ s_e = fopen(supported_enctypes_filename, "r"); ++ if (s_e == NULL) ++ goto out_clean_parsed; ++ ++ ret = fread(buffer, 1, MYBUFLEN, s_e); ++ if (ret < 0) { ++ fclose(s_e); ++ goto out_clean_parsed; ++ } ++ fclose(s_e); ++ if (parse_enctypes(buffer)) { ++ goto out_clean_parsed; ++ } ++out: ++ return; ++ ++out_clean_parsed: ++ if (parsed_enctypes != NULL) { ++ free(parsed_enctypes); ++ parsed_num_enctypes = 0; ++ } ++ goto out; ++} ++ ++/*==========================*/ ++/*=== External routines ===*/ ++/*==========================*/ ++ ++/* ++ * Get encryption types supported by the kernel, and then ++ * call gss_krb5_set_allowable_enctypes() to limit the ++ * encryption types negotiated. ++ * ++ * Returns: ++ * 0 => all went well ++ * -1 => there was an error ++ */ ++ ++int ++svcgssd_limit_krb5_enctypes(void) ++{ ++#ifdef HAVE_SET_ALLOWABLE_ENCTYPES ++ u_int maj_stat, min_stat; ++ krb5_enctype default_enctypes[] = { ENCTYPE_DES_CBC_CRC, ++ ENCTYPE_DES_CBC_MD5, ++ ENCTYPE_DES_CBC_MD4 }; ++ int default_num_enctypes = ++ sizeof(default_enctypes) / sizeof(default_enctypes[0]); ++ krb5_enctype *enctypes; ++ int num_enctypes; ++ ++ get_kernel_supported_enctypes(); ++ ++ if (parsed_enctypes != NULL) { ++ enctypes = parsed_enctypes; ++ num_enctypes = parsed_num_enctypes; ++ } else { ++ enctypes = default_enctypes; ++ num_enctypes = default_num_enctypes; ++ } ++ ++ maj_stat = gss_set_allowable_enctypes(&min_stat, gssd_creds, ++ &krb5oid, num_enctypes, enctypes); ++ if (maj_stat != GSS_S_COMPLETE) { ++ printerr(1, "WARNING: gss_set_allowable_enctypes failed\n"); ++ pgsserr("svcgssd_limit_krb5_enctypes: gss_set_allowable_enctypes", ++ maj_stat, min_stat, &krb5oid); ++ return -1; ++ } ++#endif ++ return 0; ++} +diff --git a/utils/gssd/svcgssd_krb5.h b/utils/gssd/svcgssd_krb5.h +new file mode 100644 +index 0000000..07d5eb9 +--- /dev/null ++++ b/utils/gssd/svcgssd_krb5.h +@@ -0,0 +1,36 @@ ++/* ++ * COPYRIGHT (c) 2011 ++ * The Regents of the University of Michigan ++ * ALL RIGHTS RESERVED ++ * ++ * Permission is granted to use, copy, create derivative works ++ * and redistribute this software and such derivative works ++ * for any purpose, so long as the name of The University of ++ * Michigan is not used in any advertising or publicity ++ * pertaining to the use of distribution of this software ++ * without specific, written prior authorization. If the ++ * above copyright notice or any other identification of the ++ * University of Michigan is included in any copy of any ++ * portion of this software, then the disclaimer below must ++ * also be included. ++ * ++ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION ++ * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY ++ * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF ++ * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ++ * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ++ * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE ++ * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR ++ * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING ++ * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN ++ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGES. ++ */ ++ ++#ifndef SVCGSSD_KRB5_H ++#define SVCGSSD_KRB5_H ++ ++int svcgssd_limit_krb5_enctypes(void); ++ ++#endif /* SVCGSSD_KRB5_H */ +diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c +index 3894078..7a916d7 100644 +--- a/utils/gssd/svcgssd_proc.c ++++ b/utils/gssd/svcgssd_proc.c +@@ -57,6 +57,7 @@ + #include "err_util.h" + #include "context.h" + #include "gss_oids.h" ++#include "svcgssd_krb5.h" + + extern char * mech2file(gss_OID mech); + #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel" +@@ -241,7 +242,7 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred) + "file for name '%s'\n", sname); + goto out_free; + } +- nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ ++ + res = nfs4_gss_princ_to_ids(secname, sname, &uid, &gid); + if (res < 0) { + /* +@@ -443,6 +444,10 @@ handle_nullreq(FILE *f) { + memcpy(&ctx, in_handle.value, in_handle.length); + } + ++ if (svcgssd_limit_krb5_enctypes()) { ++ goto out_err; ++ } ++ + maj_stat = gss_accept_sec_context(&min_stat, &ctx, gssd_creds, + &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name, + &mech, &out_tok, &ret_flags, NULL, NULL); +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/Makefile.am b/utils/mount/Makefile.am +index 299384a..056293c 100644 +--- a/utils/mount/Makefile.am ++++ b/utils/mount/Makefile.am +@@ -9,17 +9,17 @@ man5_MANS = nfs.man + + sbin_PROGRAMS = mount.nfs + EXTRA_DIST = nfsmount.x $(man8_MANS) $(man5_MANS) +-mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \ ++mount_common = error.c network.c fstab.c token.c \ + parse_opt.c parse_dev.c \ + nfsmount.c nfs4mount.c stropts.c\ + nfsumount.c \ + mount_constants.h error.h network.h fstab.h token.h \ + parse_opt.h parse_dev.h \ + nfs4_mount.h nfs_mount4.h stropts.h version.h \ +- mount_config.h ++ mount_config.h utils.c utils.h + + if MOUNT_CONFIG +-mount_nfs_SOURCES += configfile.c ++mount_common += configfile.c + man5_MANS += nfsmount.conf.man + EXTRA_DIST += nfsmount.conf + endif +@@ -27,6 +27,15 @@ endif + mount_nfs_LDADD = ../../support/nfs/libnfs.a \ + ../../support/export/libexport.a + ++mount_nfs_SOURCES = $(mount_common) ++ ++if CONFIG_LIBMOUNT ++mount_nfs_SOURCES += mount_libmount.c ++mount_nfs_LDADD += $(LIBMOUNT) ++else ++mount_nfs_SOURCES += mount.c ++endif ++ + MAINTAINERCLEANFILES = Makefile.in + + install-exec-hook: +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..f3f0a83 100644 +--- a/utils/mount/mount.c ++++ b/utils/mount/mount.c +@@ -47,7 +47,7 @@ + #include "mount.h" + #include "error.h" + #include "stropts.h" +-#include "version.h" ++#include "utils.h" + + char *progname; + int nfs_mount_data_version; +@@ -150,49 +150,6 @@ static const struct opt_map opt_map[] = { + static void parse_opts(const char *options, int *flags, char **extra_opts); + + /* +- * Choose the version of the nfs_mount_data structure that is appropriate +- * for the kernel that is doing the mount. +- * +- * NFS_MOUNT_VERSION: maximum version supported by these sources +- * nfs_mount_data_version: maximum version supported by the running kernel +- */ +-static void discover_nfs_mount_data_version(void) +-{ +- unsigned int kernel_version = linux_version_code(); +- +- if (kernel_version) { +- if (kernel_version < MAKE_VERSION(2, 1, 32)) +- nfs_mount_data_version = 1; +- else if (kernel_version < MAKE_VERSION(2, 2, 18)) +- nfs_mount_data_version = 3; +- else if (kernel_version < MAKE_VERSION(2, 3, 0)) +- nfs_mount_data_version = 4; +- else if (kernel_version < MAKE_VERSION(2, 3, 99)) +- nfs_mount_data_version = 3; +- else if (kernel_version < MAKE_VERSION(2, 6, 3)) +- nfs_mount_data_version = 4; +- else +- nfs_mount_data_version = 6; +- } +- if (nfs_mount_data_version > NFS_MOUNT_VERSION) +- nfs_mount_data_version = NFS_MOUNT_VERSION; +- else +- if (kernel_version > MAKE_VERSION(2, 6, 22)) +- string++; +-} +- +-static void print_one(char *spec, char *node, char *type, char *opts) +-{ +- if (!verbose) +- return; +- +- if (opts) +- printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts); +- else +- printf(_("%s on %s type %s\n"), spec, node, type); +-} +- +-/* + * Build a canonical mount option string for /etc/mtab. + */ + static char *fix_opts_string(int flags, const char *extra_opts) +@@ -209,7 +166,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 +181,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 +216,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 +241,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,23 +284,7 @@ static int add_mtab(char *spec, char *mount_point, char *fstype, + return result; + } + +-void mount_usage(void) +-{ +- printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"), +- progname); +- printf(_("options:\n")); +- printf(_("\t-r\t\tMount file system readonly\n")); +- printf(_("\t-v\t\tVerbose\n")); +- printf(_("\t-V\t\tPrint version\n")); +- printf(_("\t-w\t\tMount file system read-write\n")); +- printf(_("\t-f\t\tFake mount, do not actually mount\n")); +- printf(_("\t-n\t\tDo not update /etc/mtab\n")); +- printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n")); +- printf(_("\t-h\t\tPrint this help\n")); +- 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 +318,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); +@@ -397,26 +344,6 @@ static void parse_opts(const char *options, int *flags, char **extra_opts) + } + } + +-static int chk_mountpoint(char *mount_point) +-{ +- struct stat sb; +- +- if (stat(mount_point, &sb) < 0){ +- mount_error(NULL, mount_point, errno); +- return 1; +- } +- if (S_ISDIR(sb.st_mode) == 0){ +- mount_error(NULL, mount_point, ENOTDIR); +- return 1; +- } +- if (access(mount_point, X_OK) < 0) { +- mount_error(NULL, mount_point, errno); +- return 1; +- } +- +- return 0; +-} +- + static int try_mount(char *spec, char *mount_point, int flags, + char *fs_type, char **extra_opts, char *mount_opts, + int fake, int bg) +@@ -441,9 +368,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[]) +@@ -455,7 +380,7 @@ int main(int argc, char *argv[]) + + progname = basename(argv[0]); + +- discover_nfs_mount_data_version(); ++ nfs_mount_data_version = discover_nfs_mount_data_version(&string); + + if(!strncmp(progname, "umount", strlen("umount"))) + exit(nfsumount(argc, argv)); +diff --git a/utils/mount/mount_config.h b/utils/mount/mount_config.h +index 3023306..69ffd1e 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(__attribute__ ((unused)) char *program) { } + +-inline char *mount_config_opts(char *spec, +- char *mount_point, char *mount_opts) ++static inline char *mount_config_opts(__attribute__ ((unused)) char *spec, ++ __attribute__ ((unused)) 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/mount_libmount.c b/utils/mount/mount_libmount.c +new file mode 100644 +index 0000000..6dd6484 +--- /dev/null ++++ b/utils/mount/mount_libmount.c +@@ -0,0 +1,413 @@ ++/* ++ * mount_libmount.c -- Linux NFS [u]mount based on libmount ++ * ++ * Copyright (C) 2011 Karel Zak ++ * ++ * This program 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, or (at your option) ++ * any later version. ++ * ++ * This program 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 this program; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 021110-1307, USA. ++ * ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "nls.h" ++#include "mount_config.h" ++ ++#include "nfs_mount.h" ++#include "nfs4_mount.h" ++#include "stropts.h" ++#include "version.h" ++#include "xcommon.h" ++ ++#include "error.h" ++#include "utils.h" ++ ++char *progname; ++int nfs_mount_data_version; ++int verbose; ++int sloppy; ++int string; ++int nomtab; ++ ++#define FOREGROUND (0) ++#define BACKGROUND (1) ++ ++/* ++ * Store mount options to mtab (or /dev/.mount/utab), called from mount.nfs. ++ * ++ * Note that on systems without /etc/mtab the fs-specific options are not ++ * managed by libmount at all. We have to use "mount attributes" that are ++ * private for mount. helpers. ++ */ ++static void store_mount_options(struct libmnt_fs *fs, const char *opts) ++{ ++ mnt_fs_set_fs_options(fs, opts); /* for mtab */ ++ mnt_fs_set_attributes(fs, opts); /* for non-mtab systems */ ++} ++ ++/* ++ * Retrieve mount options from mtab (or /dev/.mount/utab) called from umount.nfs. ++ * ++ * The result can passed to free(). ++ */ ++char *retrieve_mount_options(struct libmnt_fs *fs) ++{ ++ const char *opts; ++ ++ if (!fs) ++ return NULL; ++ ++ opts = mnt_fs_get_attributes(fs); /* /dev/.mount/utab */ ++ if (opts) ++ return strdup(opts); ++ ++ return mnt_fs_strdup_options(fs); /* /etc/mtab */ ++} ++ ++static int try_mount(struct libmnt_context *cxt, int bg) ++{ ++ struct libmnt_fs *fs; ++ const char *p; ++ char *src = NULL, *tgt = NULL, *type = NULL, *opts = NULL; ++ unsigned long flags = 0; ++ int fake, ret = 0; ++ ++ fs = mnt_context_get_fs(cxt); ++ ++ /* libmount returns read-only pointers (const char) ++ * so, reallocate for nfsmount() functions. ++ */ ++ if ((p = mnt_fs_get_source(fs))) /* spec */ ++ src = strdup(p); ++ if ((p = mnt_fs_get_target(fs))) /* mountpoint */ ++ tgt = strdup(p); ++ if ((p = mnt_fs_get_fstype(fs))) /* FS type */ ++ type = strdup(p); ++ if ((p = mnt_fs_get_fs_options(fs))) /* mount options */ ++ opts = strdup(p); ++ ++ mnt_context_get_mflags(cxt, &flags); /* mount(2) flags */ ++ fake = mnt_context_is_fake(cxt); ++ ++ if (string) ++ ret = nfsmount_string(src, tgt, type, flags, &opts, fake, bg); ++ ++ else if (strcmp(type, "nfs4") == 0) ++ ret = nfs4mount(src, tgt, flags, &opts, fake, bg); ++ else ++ ret = nfsmount(src, tgt, flags, &opts, fake, bg); ++ ++ /* Store mount options if not called with mount --no-mtab */ ++ if (!ret && !mnt_context_is_nomtab(cxt)) ++ store_mount_options(fs, opts); ++ ++ free(src); ++ free(tgt); ++ free(type); ++ free(opts); ++ ++ return ret; ++} ++ ++/* returns: error = -1, success = 0 , unknown = 1 */ ++static int is_vers4(struct libmnt_context *cxt) ++{ ++ struct libmnt_fs *fs = mnt_context_get_fs(cxt); ++ struct libmnt_table *tb = NULL; ++ const char *src = mnt_context_get_source(cxt), ++ *tgt = mnt_context_get_target(cxt); ++ int rc = 1; ++ ++ if (!src || !tgt) ++ return -1; ++ ++ if (!mnt_fs_is_kernel(fs)) { ++ struct libmnt_table *tb = mnt_new_table_from_file("/proc/mounts"); ++ ++ if (!tb) ++ return -1; ++ fs = mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD); ++ } ++ ++ if (fs) { ++ const char *type = mnt_fs_get_fstype(fs); ++ if (type && strcmp(type, "nfs4") == 0) ++ rc = 0; ++ } ++ mnt_free_table(tb); ++ return rc; ++} ++ ++static int umount_main(struct libmnt_context *cxt, int argc, char **argv) ++{ ++ int rc, c; ++ char *spec = NULL, *opts = NULL; ++ ++ static const struct option longopts[] = { ++ { "force", 0, 0, 'f' }, ++ { "help", 0, 0, 'h' }, ++ { "no-mtab", 0, 0, 'n' }, ++ { "verbose", 0, 0, 'v' }, ++ { "read-only", 0, 0, 'r' }, ++ { "lazy", 0, 0, 'l' }, ++ { "types", 1, 0, 't' }, ++ { NULL, 0, 0, 0 } ++ }; ++ ++ mnt_context_init_helper(cxt, MNT_ACT_UMOUNT, 0); ++ ++ while ((c = getopt_long (argc, argv, "fvnrlh", longopts, NULL)) != -1) { ++ ++ rc = mnt_context_helper_setopt(cxt, c, optarg); ++ if (rc == 0) /* valid option */ ++ continue; ++ if (rc < 0) /* error (probably ENOMEM) */ ++ goto err; ++ /* rc==1 means unknow option */ ++ umount_usage(); ++ return EX_USAGE; ++ } ++ ++ if (optind < argc) ++ spec = argv[optind++]; ++ ++ if (!spec || (*spec != '/' && strchr(spec,':') == NULL)) { ++ nfs_error(_("%s: no mount point provided"), progname); ++ return EX_USAGE; ++ } ++ ++ if (mnt_context_set_target(cxt, spec)) ++ goto err; ++ if (mnt_context_set_fstype_pattern(cxt, "nfs,nfs4")) /* restrict filesystems */ ++ goto err; ++ ++ /* read mtab/fstab, evaluate permissions, etc. */ ++ rc = mnt_context_prepare_umount(cxt); ++ if (rc) { ++ nfs_error(_("%s: failed to prepare umount: %s\n"), ++ progname, strerror(-rc)); ++ goto err; ++ } ++ ++ opts = retrieve_mount_options(mnt_context_get_fs(cxt)); ++ ++ if (!mnt_context_is_lazy(cxt)) { ++ if (opts) { ++ /* we have full FS description (e.g. from mtab or /proc) */ ++ switch (is_vers4(cxt)) { ++ 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(mnt_context_get_source(cxt), opts); ++ break; ++ case 1: /* unknown */ ++ break; ++ default: /* error */ ++ goto err; ++ } ++ } else ++ /* strange, no entry in mtab or /proc not mounted */ ++ nfs_umount23(spec, "tcp,v3"); ++ } ++ ++ rc = mnt_context_do_umount(cxt); /* call umount(2) syscall */ ++ mnt_context_finalize_mount(cxt); /* mtab update */ ++ ++ if (rc && !mnt_context_get_status(cxt)) { ++ /* mnt_context_do_umount() returns errno if umount(2) failed */ ++ umount_error(rc, spec); ++ goto err; ++ } ++ ++ free(opts); ++ return EX_SUCCESS; ++err: ++ free(opts); ++ return EX_FAIL; ++} ++ ++static int mount_main(struct libmnt_context *cxt, int argc, char **argv) ++{ ++ int rc, c; ++ struct libmnt_fs *fs; ++ char *spec = NULL, *mount_point = NULL, *opts = NULL; ++ ++ static const struct option longopts[] = { ++ { "fake", 0, 0, 'f' }, ++ { "help", 0, 0, 'h' }, ++ { "no-mtab", 0, 0, 'n' }, ++ { "read-only", 0, 0, 'r' }, ++ { "ro", 0, 0, 'r' }, ++ { "verbose", 0, 0, 'v' }, ++ { "version", 0, 0, 'V' }, ++ { "read-write", 0, 0, 'w' }, ++ { "rw", 0, 0, 'w' }, ++ { "options", 1, 0, 'o' }, ++ { "sloppy", 0, 0, 's' }, ++ { NULL, 0, 0, 0 } ++ }; ++ ++ mount_config_init(progname); ++ mnt_context_init_helper(cxt, MNT_ACT_MOUNT, 0); ++ ++ while ((c = getopt_long(argc, argv, "fhnrVvwo:s", longopts, NULL)) != -1) { ++ ++ rc = mnt_context_helper_setopt(cxt, c, optarg); ++ if (rc == 0) /* valid option */ ++ continue; ++ if (rc < 0) /* error (probably ENOMEM) */ ++ goto err; ++ /* rc==1 means unknow option */ ++ switch (c) { ++ case 'V': ++ printf("%s: ("PACKAGE_STRING")\n", progname); ++ return EX_SUCCESS; ++ case 'h': ++ default: ++ mount_usage(); ++ return EX_USAGE; ++ } ++ } ++ ++ if (optind < argc) ++ spec = argv[optind++]; ++ if (optind < argc) ++ mount_point = argv[optind++]; ++ ++ if (!mount_point) { ++ nfs_error(_("%s: no mount point provided"), progname); ++ goto err; ++ } ++ if (!spec) { ++ nfs_error(_("%s: no mount spec provided"), progname); ++ goto err; ++ } ++ ++ if (geteuid() != 0) { ++ nfs_error(_("%s: not installed setuid - " ++ "\"user\" NFS mounts not supported."), progname); ++ goto err; ++ } ++ ++ verbose = mnt_context_is_verbose(cxt); ++ sloppy = mnt_context_is_sloppy(cxt); ++ nomtab = mnt_context_is_nomtab(cxt); ++ ++ if (strcmp(progname, "mount.nfs4") == 0) ++ mnt_context_set_fstype(cxt, "nfs4"); ++ else ++ mnt_context_set_fstype(cxt, "nfs"); /* default */ ++ ++ rc = mnt_context_set_source(cxt, spec); ++ if (!rc) ++ mnt_context_set_target(cxt, mount_point); ++ if (rc) { ++ nfs_error(_("%s: failed to set spec or mountpoint: %s"), ++ progname, strerror(errno)); ++ goto err; ++ } ++ ++ mount_point = mnt_resolve_path(mount_point, ++ mnt_context_get_cache(cxt)); ++ ++ if (chk_mountpoint(mount_point)) ++ goto err; ++ /* ++ * Concatenate mount options from the configuration file ++ */ ++ fs = mnt_context_get_fs(cxt); ++ if (fs) { ++ opts = mnt_fs_strdup_options(fs); ++ ++ opts = mount_config_opts(spec, mount_point, opts); ++ mnt_fs_set_options(fs, opts); ++ } ++ ++ rc = mnt_context_prepare_mount(cxt); ++ if (rc) { ++ nfs_error(_("%s: failed to prepare mount: %s\n"), ++ progname, strerror(-rc)); ++ goto err; ++ } ++ ++ rc = try_mount(cxt, FOREGROUND); ++ ++ if (rc == EX_BG) { ++ printf(_("%s: backgrounding \"%s\"\n"), ++ progname, mnt_context_get_source(cxt)); ++ printf(_("%s: mount options: \"%s\"\n"), ++ progname, opts); ++ ++ fflush(stdout); ++ ++ if (daemon(0, 0)) { ++ nfs_error(_("%s: failed to start " ++ "background process: %s\n"), ++ progname, strerror(errno)); ++ exit(EX_FAIL); ++ } ++ ++ rc = try_mount(cxt, BACKGROUND); ++ ++ if (verbose && rc) ++ printf(_("%s: giving up \"%s\"\n"), ++ progname, mnt_context_get_source(cxt)); ++ } ++ ++ mnt_context_set_syscall_status(cxt, rc == EX_SUCCESS ? 0 : -1); ++ mnt_context_finalize_mount(cxt); /* mtab update */ ++ return rc; ++err: ++ return EX_FAIL; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ struct libmnt_context *cxt; ++ int rc; ++ ++ mnt_init_debug(0); ++ cxt = mnt_new_context(); ++ if (!cxt) { ++ nfs_error(_("Can't initilize libmount: %s"), ++ strerror(errno)); ++ rc = EX_FAIL; ++ goto done; ++ } ++ ++ progname = basename(argv[0]); ++ nfs_mount_data_version = discover_nfs_mount_data_version(&string); ++ ++ if(strncmp(progname, "umount", 6) == 0) ++ rc = umount_main(cxt, argc, argv); ++ else ++ rc = mount_main(cxt, argc, argv); ++done: ++ mnt_free_context(cxt); ++ return rc; ++} +diff --git a/utils/mount/network.c b/utils/mount/network.c +index d612427..d1f91dc 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; +@@ -1095,7 +1095,7 @@ static int nfs_ca_sockname(const struct sockaddr *sap, const socklen_t salen, + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ANY_INIT, + }; +- int sock; ++ int sock, result = 0; + + sock = socket(sap->sa_family, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) +@@ -1103,28 +1103,26 @@ 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) { +- close(sock); +- return 0; +- } ++ if (bind(sock, SAFE_SOCKADDR(&sin), sizeof(sin)) < 0) ++ goto out; + break; + case AF_INET6: +- if (bind(sock, (struct sockaddr *)&sin6, sizeof(sin6)) < 0) { +- close(sock); +- return 0; +- } ++ if (bind(sock, SAFE_SOCKADDR(&sin6), sizeof(sin6)) < 0) ++ goto out; + break; + default: + errno = EAFNOSUPPORT; +- return 0; ++ goto out; + } + +- if (connect(sock, sap, salen) < 0) { +- close(sock); +- return 0; +- } ++ if (connect(sock, sap, salen) < 0) ++ goto out; + +- return !getsockname(sock, buf, buflen); ++ result = !getsockname(sock, buf, buflen); ++ ++out: ++ close(sock); ++ return result; + } + + /* +@@ -1346,7 +1344,7 @@ nfs_nfs_port(struct mount_options *options, unsigned long *port) + case PO_NOT_FOUND: + break; + case PO_FOUND: +- if (tmp >= 1 && tmp <= 65535) { ++ if (tmp >= 0 && tmp <= 65535) { + *port = tmp; + return 1; + } +@@ -1518,7 +1516,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; + } + + /* +@@ -1534,7 +1536,7 @@ nfs_mount_port(struct mount_options *options, unsigned long *port) + case PO_NOT_FOUND: + break; + case PO_FOUND: +- if (tmp >= 1 && tmp <= 65535) { ++ if (tmp >= 0 && tmp <= 65535) { + *port = tmp; + return 1; + } +@@ -1622,3 +1624,71 @@ int nfs_options2pmap(struct mount_options *options, + + return 1; + } ++ ++/* ++ * Discover mount server's hostname/address by examining mount options ++ * ++ * Returns a pointer to a string that the caller must free, on ++ * success; otherwise NULL is returned. ++ */ ++static char *nfs_umount_hostname(struct mount_options *options, ++ char *hostname) ++{ ++ char *option; ++ ++ option = po_get(options, "mountaddr"); ++ if (option) ++ goto out; ++ option = po_get(options, "mounthost"); ++ if (option) ++ goto out; ++ option = po_get(options, "addr"); ++ if (option) ++ goto out; ++ ++ return hostname; ++ ++out: ++ free(hostname); ++ return strdup(option); ++} ++ ++ ++/* ++ * Returns EX_SUCCESS if mount options and device name have been ++ * parsed successfully; otherwise EX_FAIL. ++ */ ++int nfs_umount_do_umnt(struct mount_options *options, ++ char **hostname, char **dirname) ++{ ++ union nfs_sockaddr address; ++ struct sockaddr *sap = &address.sa; ++ socklen_t salen = sizeof(address); ++ struct pmap nfs_pmap, mnt_pmap; ++ sa_family_t family; ++ ++ if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) ++ return EX_FAIL; ++ ++ /* Skip UMNT call for vers=4 mounts */ ++ if (nfs_pmap.pm_vers == 4) ++ return EX_SUCCESS; ++ ++ *hostname = nfs_umount_hostname(options, *hostname); ++ if (!*hostname) { ++ nfs_error(_("%s: out of memory"), progname); ++ return EX_FAIL; ++ } ++ ++ if (!nfs_mount_proto_family(options, &family)) ++ return 0; ++ if (!nfs_lookup(*hostname, family, sap, &salen)) ++ /* nfs_lookup reports any errors */ ++ return EX_FAIL; ++ ++ if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0) ++ /* nfs_advise_umount reports any errors */ ++ return EX_FAIL; ++ ++ return EX_SUCCESS; ++} +diff --git a/utils/mount/network.h b/utils/mount/network.h +index 2a3a110..81c6f22 100644 +--- a/utils/mount/network.h ++++ b/utils/mount/network.h +@@ -75,4 +75,7 @@ int nfs_advise_umount(const struct sockaddr *, const socklen_t, + CLIENT *mnt_openclnt(clnt_addr_t *, int *); + void mnt_closeclnt(CLIENT *, int); + ++int nfs_umount_do_umnt(struct mount_options *options, ++ char **hostname, char **dirname); ++ + #endif /* _NFS_UTILS_MOUNT_NETWORK_H */ +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..8cd2852 100644 +--- a/utils/mount/nfsumount.c ++++ b/utils/mount/nfsumount.c +@@ -31,11 +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" ++#include "utils.h" ++ ++#define MOUNTSFILE "/proc/mounts" ++#define LINELEN (4096) + + #if !defined(MNT_FORCE) + /* dare not try to include -- lots of errors */ +@@ -109,7 +114,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 +132,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); +@@ -135,110 +140,88 @@ static int del_mtab(const char *spec, const char *node) + } + + /* +- * Discover mount server's hostname/address by examining mount options +- * +- * Returns a pointer to a string that the caller must free, on +- * success; otherwise NULL is returned. +- */ +-static char *nfs_umount_hostname(struct mount_options *options, +- char *hostname) +-{ +- char *option; +- +- option = po_get(options, "mountaddr"); +- if (option) +- goto out; +- option = po_get(options, "mounthost"); +- if (option) +- goto out; +- option = po_get(options, "addr"); +- if (option) +- goto out; +- +- return hostname; +- +-out: +- free(hostname); +- return strdup(option); +-} +- +-/* +- * Returns EX_SUCCESS if mount options and device name have been +- * parsed successfully; otherwise EX_FAIL. +- */ +-static int nfs_umount_do_umnt(struct mount_options *options, +- char **hostname, char **dirname) +-{ +- union { +- struct sockaddr sa; +- struct sockaddr_in s4; +- struct sockaddr_in6 s6; +- } address; +- struct sockaddr *sap = &address.sa; +- socklen_t salen = sizeof(address); +- struct pmap nfs_pmap, mnt_pmap; +- sa_family_t family; +- +- if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) +- return EX_FAIL; +- +- /* Skip UMNT call for vers=4 mounts */ +- if (nfs_pmap.pm_vers == 4) +- return EX_SUCCESS; +- +- *hostname = nfs_umount_hostname(options, *hostname); +- if (!*hostname) { +- nfs_error(_("%s: out of memory"), progname); +- return EX_FAIL; +- } +- +- if (!nfs_mount_proto_family(options, &family)) +- return 0; +- if (!nfs_lookup(*hostname, family, sap, &salen)) +- /* nfs_lookup reports any errors */ +- return EX_FAIL; +- +- if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0) +- /* nfs_advise_umount reports any errors */ +- return EX_FAIL; +- +- return EX_SUCCESS; +-} +- +-/* +- * Pick up certain mount options used during the original mount +- * from /etc/mtab. The basics include the server's IP address and +- * the server pathname of the share to unregister. ++ * Detect NFSv4 mounts. + * +- * These options might also describe the mount port, mount protocol +- * version, and transport protocol used to punch through a firewall. +- * We will need this information to get through the firewall again +- * to do the umount. ++ * Consult /proc/mounts to determine if the mount point ++ * is an NFSv4 mount. The kernel is authoritative about ++ * what type of mount this is. + * +- * Note that option parsing failures won't necessarily cause the +- * umount request to fail. Those values will be left zero in the +- * pmap tuple. If the GETPORT call later fails to disambiguate them, +- * then we fail. ++ * Returns 1 if "mc" is an NFSv4 mount, zero if not, and ++ * -1 if some error occurred. + */ +-static int nfs_umount23(const char *devname, char *string) ++static int nfs_umount_is_vers4(const struct mntentchn *mc) + { +- char *hostname, *dirname; +- struct mount_options *options; +- int result = EX_FAIL; ++ char buffer[LINELEN], *next; ++ int retval; ++ FILE *f; ++ ++ if ((f = fopen(MOUNTSFILE, "r")) == NULL) { ++ fprintf(stderr, "%s: %s\n", ++ MOUNTSFILE, strerror(errno)); ++ return -1; ++ } + +- if (!nfs_parse_devname(devname, &hostname, &dirname)) +- return EX_USAGE; ++ 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; ++ } + +- options = po_split(string); +- if (options) { +- result = nfs_umount_do_umnt(options, &hostname, &dirname); +- po_destroy(options); +- } else +- nfs_error(_("%s: option parsing error"), progname); ++ goto out_nfs; ++ } ++ if (retval == -1) ++ fprintf(stderr, "%s was not found in %s\n", ++ mc->m.mnt_dir, MOUNTSFILE); + +- free(hostname); +- free(dirname); +- return result; ++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[] = +@@ -251,17 +234,6 @@ static struct option umount_longopts[] = + { NULL, 0, 0, 0 } + }; + +-static void umount_usage(void) +-{ +- printf(_("usage: %s dir [-fvnrlh]\n"), progname); +- printf(_("options:\n\t-f\t\tforce unmount\n")); +- printf(_("\t-v\tverbose\n")); +- printf(_("\t-n\tDo not update /etc/mtab\n")); +- printf(_("\t-r\tremount\n")); +- printf(_("\t-l\tlazy unmount\n")); +- printf(_("\t-h\tprint this help\n\n")); +-} +- + int nfsumount(int argc, char *argv[]) + { + int c, ret; +@@ -362,16 +334,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..f1aa503 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 +@@ -114,7 +110,7 @@ static void nfs_default_version(struct nfsmount_info *mi) + } + } + #else +-inline void nfs_default_version(struct nfsmount_info *mi) {} ++inline void nfs_default_version(__attribute__ ((unused)) struct nfsmount_info *mi) {} + #endif /* MOUNT_CONFIG */ + + /* +@@ -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)); +@@ -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 --git a/utils/mount/utils.c b/utils/mount/utils.c +new file mode 100644 +index 0000000..298db39 +--- /dev/null ++++ b/utils/mount/utils.c +@@ -0,0 +1,175 @@ ++/* ++ * Copyright (C) 2010 Karel Zak ++ * ++ * This program 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, or (at your option) ++ * any later version. ++ * ++ * This program 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 this program; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 021110-1307, USA. ++ * ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sockaddr.h" ++#include "nfs_mount.h" ++#include "nls.h" ++#include "xcommon.h" ++#include "version.h" ++#include "error.h" ++#include "utils.h" ++#include "mount.h" ++#include "network.h" ++#include "parse_dev.h" ++ ++extern int verbose; ++extern char *progname; ++ ++/* ++ * Choose the version of the nfs_mount_data structure that is appropriate ++ * for the kernel that is doing the mount. ++ * ++ * NFS_MOUNT_VERSION: maximum version supported by these sources ++ * nfs_mount_data_version: maximum version supported by the running kernel ++ */ ++int discover_nfs_mount_data_version(int *string_ver) ++{ ++ unsigned int kernel_version = linux_version_code(); ++ int ver = 0; ++ ++ *string_ver = 0; ++ ++ if (kernel_version) { ++ if (kernel_version < MAKE_VERSION(2, 1, 32)) ++ ver = 1; ++ else if (kernel_version < MAKE_VERSION(2, 2, 18)) ++ ver = 3; ++ else if (kernel_version < MAKE_VERSION(2, 3, 0)) ++ ver = 4; ++ else if (kernel_version < MAKE_VERSION(2, 3, 99)) ++ ver = 3; ++ else if (kernel_version < MAKE_VERSION(2, 6, 3)) ++ ver = 4; ++ else ++ ver = 6; ++ } ++ if (ver > NFS_MOUNT_VERSION) ++ ver = NFS_MOUNT_VERSION; ++ else ++ if (kernel_version > MAKE_VERSION(2, 6, 22)) ++ (*string_ver)++; ++ ++ return ver; ++} ++ ++void print_one(char *spec, char *node, char *type, char *opts) ++{ ++ if (!verbose) ++ return; ++ ++ if (opts) ++ printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts); ++ else ++ printf(_("%s on %s type %s\n"), spec, node, type); ++} ++ ++void mount_usage(void) ++{ ++ printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"), ++ progname); ++ printf(_("options:\n")); ++ printf(_("\t-r\t\tMount file system readonly\n")); ++ printf(_("\t-v\t\tVerbose\n")); ++ printf(_("\t-V\t\tPrint version\n")); ++ printf(_("\t-w\t\tMount file system read-write\n")); ++ printf(_("\t-f\t\tFake mount, do not actually mount\n")); ++ printf(_("\t-n\t\tDo not update /etc/mtab\n")); ++ printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n")); ++ printf(_("\t-h\t\tPrint this help\n")); ++ printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n")); ++} ++ ++void umount_usage(void) ++{ ++ printf(_("usage: %s dir [-fvnrlh]\n"), progname); ++ printf(_("options:\n\t-f\t\tforce unmount\n")); ++ printf(_("\t-v\tverbose\n")); ++ printf(_("\t-n\tDo not update /etc/mtab\n")); ++ printf(_("\t-r\tremount\n")); ++ printf(_("\t-l\tlazy unmount\n")); ++ printf(_("\t-h\tprint this help\n\n")); ++} ++ ++int chk_mountpoint(const char *mount_point) ++{ ++ struct stat sb; ++ ++ if (stat(mount_point, &sb) < 0){ ++ mount_error(NULL, mount_point, errno); ++ return 1; ++ } ++ if (S_ISDIR(sb.st_mode) == 0){ ++ mount_error(NULL, mount_point, ENOTDIR); ++ return 1; ++ } ++ if (access(mount_point, X_OK) < 0) { ++ mount_error(NULL, mount_point, errno); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Pick up certain mount options used during the original mount ++ * from /etc/mtab. The basics include the server's IP address and ++ * the server pathname of the share to unregister. ++ * ++ * These options might also describe the mount port, mount protocol ++ * version, and transport protocol used to punch through a firewall. ++ * We will need this information to get through the firewall again ++ * to do the umount. ++ * ++ * Note that option parsing failures won't necessarily cause the ++ * umount request to fail. Those values will be left zero in the ++ * pmap tuple. If the GETPORT call later fails to disambiguate them, ++ * then we fail. ++ */ ++int nfs_umount23(const char *devname, char *string) ++{ ++ char *hostname = NULL, *dirname = NULL; ++ struct mount_options *options; ++ int result = EX_FAIL; ++ ++ if (!nfs_parse_devname(devname, &hostname, &dirname)) ++ return EX_USAGE; ++ ++ options = po_split(string); ++ if (options) { ++ result = nfs_umount_do_umnt(options, &hostname, &dirname); ++ po_destroy(options); ++ } else ++ nfs_error(_("%s: option parsing error"), progname); ++ ++ free(hostname); ++ free(dirname); ++ return result; ++} +diff --git a/utils/mount/utils.h b/utils/mount/utils.h +new file mode 100644 +index 0000000..3fcd504 +--- /dev/null ++++ b/utils/mount/utils.h +@@ -0,0 +1,36 @@ ++/* ++ * utils.h -- misc utils for mount and umount ++ * ++ * Copyright (C) 2010 Karel Zak ++ * ++ * This program 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. ++ * ++ * This program 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 this program; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 021110-1307, USA. ++ * ++ */ ++ ++#ifndef _NFS_UTILS_MOUNT_UTILS_H ++#define _NFS_UTILS_MOUNT_UTILS_H ++ ++#include "parse_opt.h" ++ ++int discover_nfs_mount_data_version(int *string_ver); ++void print_one(char *spec, char *node, char *type, char *opts); ++void mount_usage(void); ++void umount_usage(void); ++int chk_mountpoint(const char *mount_point); ++ ++int nfs_umount23(const char *devname, char *string); ++ ++#endif /* !_NFS_UTILS_MOUNT_UTILS_H */ +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/cache.c b/utils/mountd/cache.c +index f70f4d6..1d6e953 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -114,7 +114,7 @@ static void auth_unix_ip(FILE *f) + + qword_print(f, "nfsd"); + qword_print(f, ipaddr); +- qword_printint(f, time(0)+30*60); ++ qword_printuint(f, time(0) + DEFAULT_TTL); + if (use_ipaddr) + qword_print(f, ipaddr); + else if (client) +@@ -161,7 +161,7 @@ static void auth_unix_gid(FILE *f) + } + } + qword_printuint(f, uid); +- qword_printuint(f, time(0)+30*60); ++ qword_printuint(f, time(0) + DEFAULT_TTL); + if (rv >= 0) { + qword_printuint(f, ngroups); + for (i=0; ie_path) != 0; + int flag_mask = different_fs ? ~NFSEXP_FSID : ~0; + ++ qword_printuint(f, time(0) + exp->e_ttl); + qword_printint(f, exp->e_flags & flag_mask); + qword_printint(f, exp->e_anonuid); + qword_printint(f, exp->e_anongid); +@@ -667,7 +667,8 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex + qword_print(f, "uuid"); + qword_printhex(f, u, 16); + } +- } ++ } else ++ qword_printuint(f, time(0) + DEFAULT_TTL); + return qword_eol(f); + } + +@@ -874,8 +875,8 @@ int cache_process_req(fd_set *readfds) + + /* + * Give IP->domain and domain+path->options to kernel +- * % echo nfsd $IP $[now+30*60] $domain > /proc/net/rpc/auth.unix.ip/channel +- * % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel ++ * % echo nfsd $IP $[now+DEFAULT_TTL] $domain > /proc/net/rpc/auth.unix.ip/channel ++ * % echo $domain $path $[now+DEFAULT_TTL] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel + */ + + static int cache_export_ent(char *domain, struct exportent *exp, char *path) +@@ -955,7 +956,7 @@ int cache_export(nfs_export *exp, char *path) + qword_print(f, "nfsd"); + qword_print(f, + host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf))); +- qword_printint(f, time(0)+30*60); ++ qword_printuint(f, time(0) + exp->m_export.e_ttl); + 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 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/mountd/rmtab.c b/utils/mountd/rmtab.c +index d339296..527377f 100644 +--- a/utils/mountd/rmtab.c ++++ b/utils/mountd/rmtab.c +@@ -205,6 +205,7 @@ mountlist_list(void) + } + if (stb.st_mtime != last_mtime) { + mountlist_freeall(mlist); ++ mlist = NULL; + last_mtime = stb.st_mtime; + + setrmtabent("r"); +diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c +index 7fd6af3..c33a5a9 100644 +--- a/utils/mountd/v4root.c ++++ b/utils/mountd/v4root.c +@@ -144,8 +144,11 @@ static int v4root_add_parents(nfs_export *exp) + char *ptr; + + path = strdup(exp->m_export.e_path); +- if (!path) ++ if (!path) { ++ xlog(L_WARNING, "v4root_add_parents: Unable to create " ++ "pseudo export for '%s'", exp->m_export.e_path); + return -ENOMEM; ++ } + for (ptr = path + 1; ptr; ptr = strchr(ptr, '/')) { + int ret; + char saved; +@@ -173,7 +176,7 @@ void + v4root_set() + { + nfs_export *exp; +- int i, ret; ++ int i; + + if (!v4root_needed) + return; +@@ -189,7 +192,7 @@ v4root_set() + */ + continue; + +- ret = v4root_add_parents(exp); ++ v4root_add_parents(exp); + /* XXX: error handling! */ + } + } +diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am +new file mode 100644 +index 0000000..f837b91 +--- /dev/null ++++ b/utils/nfsidmap/Makefile.am +@@ -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 --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c +new file mode 100644 +index 0000000..2d87381 +--- /dev/null ++++ b/utils/nfsidmap/nfsidmap.c +@@ -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 --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man +new file mode 100644 +index 0000000..6c1a2d4 +--- /dev/null ++++ b/utils/nfsidmap/nfsidmap.man +@@ -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 --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c +index bacef8e..f31bb81 100644 +--- a/utils/nfsstat/nfsstat.c ++++ b/utils/nfsstat/nfsstat.c +@@ -46,7 +46,7 @@ static unsigned int cltproc3info[CLTPROC3_SZ+2], + 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_prt) + 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_prt) + } + } + 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_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(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 --git a/utils/nfsstat/nfsstat.man b/utils/nfsstat/nfsstat.man +index 52215a9..cd573b0 100644 +--- a/utils/nfsstat/nfsstat.man ++++ b/utils/nfsstat/nfsstat.man +@@ -30,10 +30,12 @@ Print only NFS v2 statistics. The default is to only print information + 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 --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..1f490b0 100644 +--- a/utils/statd/sm-notify.c ++++ b/utils/statd/sm-notify.c +@@ -34,8 +34,9 @@ + #include "nsm.h" + #include "nfsrpc.h" + +-#ifndef HAVE_DECL_AI_ADDRCONFIG +-#define AI_ADDRCONFIG 0 ++/* glibc before 2.3.4 */ ++#ifndef AI_NUMERICSERV ++#define AI_NUMERICSERV 0 + #endif + + #define NSM_TIMEOUT 2 +@@ -78,7 +79,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, + }; +@@ -253,6 +253,7 @@ smn_bind_address(const char *srcaddr, const char *srcport) + if (srcaddr == NULL) + hint.ai_flags |= AI_PASSIVE; + ++ /* Do not allow "node" and "service" parameters both to be NULL */ + if (srcport == NULL) + error = getaddrinfo(srcaddr, "", &hint, &ai); + else +diff --git a/utils/statd/statd.man b/utils/statd/statd.man +index ca00e24..b72236c 100644 +--- a/utils/statd/statd.man ++++ b/utils/statd/statd.man +@@ -12,7 +12,7 @@ + .SH NAME + rpc.statd \- NSM service daemon + .SH SYNOPSIS +-.BI "rpc.statd [-dh?FLNvVw] [-H " prog "] [-n " my-name "] [-o " outgoing-port "] [-p " listener-port "] [-P " path " ] ++.BI "rpc.statd [-dh?FLNvV] [-H " prog "] [-n " my-name "] [-o " outgoing-port "] [-p " listener-port "] [-P " path " ] + .SH DESCRIPTION + File locks are not part of persistent file system state. + Lock state is thus lost when a host reboots. diff --git a/nfs-utils.spec b/nfs-utils.spec index 7b7fe62..3c47769 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: 11%{?dist} +Release: 12%{?dist} Epoch: 1 # group all 32bit related archs @@ -17,7 +17,7 @@ Source13: rpcgssd.init Source14: rpcsvcgssd.init Source15: nfs.sysconfig -Patch001: nfs-utils-1.2.4-rc6.patch +Patch001: nfs-utils-1.2.4-rc7.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.2-statdpath.patch @@ -50,11 +50,11 @@ BuildRequires: libgssglue-devel libevent-devel libcap-devel BuildRequires: libnfsidmap-devel libtirpc-devel libblkid-devel BuildRequires: krb5-libs >= 1.4 autoconf >= 2.57 openldap-devel >= 2.2 BuildRequires: automake, libtool, glibc-headers -BuildRequires: krb5-devel, tcp_wrappers-devel +BuildRequires: krb5-devel, tcp_wrappers-devel, libmount-devel Requires(pre): shadow-utils >= 4.0.3-25 Requires(pre): /sbin/chkconfig /sbin/nologin Requires: libnfsidmap libgssglue libevent -Requires: libtirpc libblkid libcap +Requires: libtirpc libblkid libcap libmount %description The nfs-utils package provides a daemon for the kernel NFS server and @@ -100,9 +100,10 @@ CFLAGS="`echo $RPM_OPT_FLAGS $ARCH_OPT_FLAGS $PIE -D_FILE_OFFSET_BITS=64`" --enable-mountconfig \ --enable-ipv6 \ --enable-nfsv41 \ - --with-statdpath=/var/lib/nfs/statd + --with-statdpath=/var/lib/nfs/statd \ + --enable-libmount-mount -make all +make %{?_smp_mflags} all %install rm -rf $RPM_BUILD_ROOT @@ -253,6 +254,10 @@ fi %attr(4755,root,root) /sbin/umount.nfs4 %changelog +* Wed Apr 6 2011 Steve Dickson 1.2.3-12 +- Updated to latest upstream release: nfs-utils-1-2-4-rc6 +- Enabled the libmount code. + * Mon Mar 7 2011 Steve Dickson 1.2.3-11 - Updated to latest upstream release: nfs-utils-1-2-4-rc6